pastebin get xWSWHfPM migration
migrate <firstprogram> <secondprogram> <output>
This is a read-only snapshot of the ComputerCraft forums,
taken in April 2020.
Program Migration
Started by mentalr0b123, 02 November 2015 - 02:59 PMPosted 02 November 2015 - 03:59 PM
MIGRATION
—————————————————
@Author = mentalrob
@Version = 1.1 [[There is never be an update]]
@Description = This program migrates first program to second program and write it an output file
@Migration = If you migrate a program to another program, first program will run inside the second program
How it works
——————————————————–
migration <firstprogram> <secondprogram> <outputfile>
Actually This program reads your firstprogram sourcecode and adds the "function progf()" string to the beginning of the sourcecode
It does this function again for secondprogram
And then Program adds sourcecodes
Then adds "parallel.waitForAll()" method end of the sourcecodes
and writing it an output file
Edited on 02 November 2015 - 05:37 PM
Posted 02 November 2015 - 04:47 PM
Very nice! However, I don't quite get why I would need that. Can you give an example?
Posted 02 November 2015 - 05:13 PM
Here is a test program:
———————————————
And here is the output file:
———————————————
If you run this program , shell works but if you send this rednet message -> "shutdown" The computer will shutdown.
Sorry for bad english xd
rednet.open("left")
while true do
id ,msg = rednet.receive()
if msg == "shutdown" then
os.shutdown()
end
end
And here is the shell program in /rom/programs (NOTE : tArgs{…} deleted)
local multishell = multishell
local parentShell = shell
local parentTerm = term.current()
if multishell then
multishell.setTitle( multishell.getCurrent(), "shell" )
end
local bExit = false
local sDir = (parentShell and parentShell.dir()) or ""
local sPath = (parentShell and parentShell.path()) or ".:/rom/programs"
local tAliases = (parentShell and parentShell.aliases()) or {}
local tCompletionInfo = (parentShell and parentShell.getCompletionInfo()) or {}
local tProgramStack = {}
local shell = {}
local tEnv = {
[ "shell" ] = shell,
[ "multishell" ] = multishell,
}
-- Colours
local promptColour, textColour, bgColour
if term.isColour() then
promptColour = colours.yellow
textColour = colours.white
bgColour = colours.black
else
promptColour = colours.white
textColour = colours.white
bgColour = colours.black
end
local function run( _sCommand, ... )
local sPath = shell.resolveProgram( _sCommand )
if sPath ~= nil then
tProgramStack[#tProgramStack + 1] = sPath
if multishell then
multishell.setTitle( multishell.getCurrent(), fs.getName( sPath ) )
end
local result = os.run( tEnv, sPath, ... )
tProgramStack[#tProgramStack] = nil
if multishell then
if #tProgramStack > 0 then
multishell.setTitle( multishell.getCurrent(), fs.getName( tProgramStack[#tProgramStack] ) )
else
multishell.setTitle( multishell.getCurrent(), "shell" )
end
end
return result
else
printError( "No such program" )
return false
end
end
local function tokenise( ... )
local sLine = table.concat( { ... }, " " )
local tWords = {}
local bQuoted = false
for match in string.gmatch( sLine .. "\"", "(.-)\"" ) do
if bQuoted then
table.insert( tWords, match )
else
for m in string.gmatch( match, "[^ \t]+" ) do
table.insert( tWords, m )
end
end
bQuoted = not bQuoted
end
return tWords
end
-- Install shell API
function shell.run( ... )
local tWords = tokenise( ... )
local sCommand = tWords[1]
if sCommand then
return run( sCommand, table.unpack( tWords, 2 ) )
end
return false
end
function shell.exit()
bExit = true
end
function shell.dir()
return sDir
end
function shell.setDir( _sDir )
sDir = _sDir
end
function shell.path()
return sPath
end
function shell.setPath( _sPath )
sPath = _sPath
end
function shell.resolve( _sPath )
local sStartChar = string.sub( _sPath, 1, 1 )
if sStartChar == "/" or sStartChar == "\\" then
return fs.combine( "", _sPath )
else
return fs.combine( sDir, _sPath )
end
end
function shell.resolveProgram( _sCommand )
-- Substitute aliases firsts
if tAliases[ _sCommand ] ~= nil then
_sCommand = tAliases[ _sCommand ]
end
-- If the path is a global path, use it directly
local sStartChar = string.sub( _sCommand, 1, 1 )
if sStartChar == "/" or sStartChar == "\\" then
local sPath = fs.combine( "", _sCommand )
if fs.exists( sPath ) and not fs.isDir( sPath ) then
return sPath
end
return nil
end
-- Otherwise, look on the path variable
for sPath in string.gmatch(sPath, "[^:]+") do
sPath = fs.combine( shell.resolve( sPath ), _sCommand )
if fs.exists( sPath ) and not fs.isDir( sPath ) then
return sPath
end
end
-- Not found
return nil
end
function shell.programs( _bIncludeHidden )
local tItems = {}
-- Add programs from the path
for sPath in string.gmatch(sPath, "[^:]+") do
sPath = shell.resolve( sPath )
if fs.isDir( sPath ) then
local tList = fs.list( sPath )
for n=1,#tList do
local sFile = tList[n]
if not fs.isDir( fs.combine( sPath, sFile ) ) and
(_bIncludeHidden or string.sub( sFile, 1, 1 ) ~= ".") then
tItems[ sFile ] = true
end
end
end
end
-- Sort and return
local tItemList = {}
for sItem, b in pairs( tItems ) do
table.insert( tItemList, sItem )
end
table.sort( tItemList )
return tItemList
end
local function completeProgram( sLine )
if #sLine > 0 and string.sub( sLine, 1, 1 ) == "/" then
-- Add programs from the root
return fs.complete( sLine, "", true, false )
else
local tResults = {}
local tSeen = {}
-- Add aliases
for sAlias, sCommand in pairs( tAliases ) do
if #sAlias > #sLine and string.sub( sAlias, 1, #sLine ) == sLine then
local sResult = string.sub( sAlias, #sLine + 1 )
if not tSeen[ sResult ] then
table.insert( tResults, sResult )
tSeen[ sResult ] = true
end
end
end
-- Add programs from the path
local tPrograms = shell.programs()
for n=1,#tPrograms do
local sProgram = tPrograms[n]
if #sProgram > #sLine and string.sub( sProgram, 1, #sLine ) == sLine then
local sResult = string.sub( sProgram, #sLine + 1 )
if not tSeen[ sResult ] then
table.insert( tResults, sResult )
tSeen[ sResult ] = true
end
end
end
-- Sort and return
table.sort( tResults )
return tResults
end
end
local function completeProgramArgument( sProgram, nArgument, sPart, tPreviousParts )
local tInfo = tCompletionInfo[ sProgram ]
if tInfo then
return tInfo.fnComplete( shell, nArgument, sPart, tPreviousParts )
end
return nil
end
function shell.complete( sLine )
if #sLine > 0 then
local tWords = tokenise( sLine )
local nIndex = #tWords
if string.sub( sLine, #sLine, #sLine ) == " " then
nIndex = nIndex + 1
end
if nIndex == 1 then
local sBit = tWords[1] or ""
local sPath = shell.resolveProgram( sBit )
if tCompletionInfo[ sPath ] then
return { " " }
else
local tResults = completeProgram( sBit )
for n=1,#tResults do
local sResult = tResults[n]
local sPath = shell.resolveProgram( sBit .. sResult )
if tCompletionInfo[ sPath ] then
tResults[n] = sResult .. " "
end
end
return tResults
end
elseif nIndex > 1 then
local sPath = shell.resolveProgram( tWords[1] )
local sPart = tWords[nIndex] or ""
local tPreviousParts = tWords
tPreviousParts[nIndex] = nil
return completeProgramArgument( sPath , nIndex - 1, sPart, tPreviousParts )
end
end
return nil
end
function shell.completeProgram( sProgram )
return completeProgram( sProgram )
end
function shell.setCompletionFunction( sProgram, fnComplete )
tCompletionInfo[ sProgram ] = {
fnComplete = fnComplete
}
end
function shell.getCompletionInfo()
return tCompletionInfo
end
function shell.getRunningProgram()
if #tProgramStack > 0 then
return tProgramStack[#tProgramStack]
end
return nil
end
function shell.setAlias( _sCommand, _sProgram )
tAliases[ _sCommand ] = _sProgram
end
function shell.clearAlias( _sCommand )
tAliases[ _sCommand ] = nil
end
function shell.aliases()
-- Copy aliases
local tCopy = {}
for sAlias, sCommand in pairs( tAliases ) do
tCopy[sAlias] = sCommand
end
return tCopy
end
if multishell then
function shell.openTab( ... )
local tWords = tokenise( ... )
local sCommand = tWords[1]
if sCommand then
local sPath = shell.resolveProgram( sCommand )
if sPath == "rom/programs/shell" then
return multishell.launch( tEnv, sPath, table.unpack( tWords, 2 ) )
elseif sPath ~= nil then
return multishell.launch( tEnv, "rom/programs/shell", sCommand, table.unpack( tWords, 2 ) )
else
printError( "No such program" )
end
end
end
function shell.switchTab( nID )
multishell.setFocus( nID )
end
end
-- "shell"
-- Print the header
term.setBackgroundColor( bgColour )
term.setTextColour( promptColour )
print( os.version() )
term.setTextColour( textColour )
-- Run the startup program
if parentShell == nil then
shell.run( "/rom/startup" )
end
-- Read commands and execute them
local tCommandHistory = {}
while not bExit do
term.redirect( parentTerm )
term.setBackgroundColor( bgColour )
term.setTextColour( promptColour )
write( shell.dir() .. "> " )
term.setTextColour( textColour )
local sLine = read( nil, tCommandHistory, shell.complete )
table.insert( tCommandHistory, sLine )
shell.run( sLine )
end
———————————————
And here is the output file:
———————————————
--[[
THIS PROGRAM IS MIGRATED
]]--
function progf()
rednet.open("left")
while true do
id ,msg = rednet.receive()
if msg == "shutdown" then
os.shutdown()
end
end
end
function progs()
local multishell = multishell
local parentShell = shell
local parentTerm = term.current()
if multishell then
multishell.setTitle( multishell.getCurrent(), "shell" )
end
local bExit = false
local sDir = (parentShell and parentShell.dir()) or ""
local sPath = (parentShell and parentShell.path()) or ".:/rom/programs"
local tAliases = (parentShell and parentShell.aliases()) or {}
local tCompletionInfo = (parentShell and parentShell.getCompletionInfo()) or {}
local tProgramStack = {}
local shell = {}
local tEnv = {
[ "shell" ] = shell,
[ "multishell" ] = multishell,
}
-- Colours
local promptColour, textColour, bgColour
if term.isColour() then
promptColour = colours.yellow
textColour = colours.white
bgColour = colours.black
else
promptColour = colours.white
textColour = colours.white
bgColour = colours.black
end
local function run( _sCommand, ... )
local sPath = shell.resolveProgram( _sCommand )
if sPath ~= nil then
tProgramStack[#tProgramStack + 1] = sPath
if multishell then
multishell.setTitle( multishell.getCurrent(), fs.getName( sPath ) )
end
local result = os.run( tEnv, sPath, ... )
tProgramStack[#tProgramStack] = nil
if multishell then
if #tProgramStack > 0 then
multishell.setTitle( multishell.getCurrent(), fs.getName( tProgramStack[#tProgramStack] ) )
else
multishell.setTitle( multishell.getCurrent(), "shell" )
end
end
return result
else
printError( "No such program" )
return false
end
end
local function tokenise( ... )
local sLine = table.concat( { ... }, " " )
local tWords = {}
local bQuoted = false
for match in string.gmatch( sLine .. "\"", "(.-)\"" ) do
if bQuoted then
table.insert( tWords, match )
else
for m in string.gmatch( match, "[^ \t]+" ) do
table.insert( tWords, m )
end
end
bQuoted = not bQuoted
end
return tWords
end
-- Install shell API
function shell.run( ... )
local tWords = tokenise( ... )
local sCommand = tWords[1]
if sCommand then
return run( sCommand, table.unpack( tWords, 2 ) )
end
return false
end
function shell.exit()
bExit = true
end
function shell.dir()
return sDir
end
function shell.setDir( _sDir )
sDir = _sDir
end
function shell.path()
return sPath
end
function shell.setPath( _sPath )
sPath = _sPath
end
function shell.resolve( _sPath )
local sStartChar = string.sub( _sPath, 1, 1 )
if sStartChar == "/" or sStartChar == "\\" then
return fs.combine( "", _sPath )
else
return fs.combine( sDir, _sPath )
end
end
function shell.resolveProgram( _sCommand )
-- Substitute aliases firsts
if tAliases[ _sCommand ] ~= nil then
_sCommand = tAliases[ _sCommand ]
end
-- If the path is a global path, use it directly
local sStartChar = string.sub( _sCommand, 1, 1 )
if sStartChar == "/" or sStartChar == "\\" then
local sPath = fs.combine( "", _sCommand )
if fs.exists( sPath ) and not fs.isDir( sPath ) then
return sPath
end
return nil
end
-- Otherwise, look on the path variable
for sPath in string.gmatch(sPath, "[^:]+") do
sPath = fs.combine( shell.resolve( sPath ), _sCommand )
if fs.exists( sPath ) and not fs.isDir( sPath ) then
return sPath
end
end
-- Not found
return nil
end
function shell.programs( _bIncludeHidden )
local tItems = {}
-- Add programs from the path
for sPath in string.gmatch(sPath, "[^:]+") do
sPath = shell.resolve( sPath )
if fs.isDir( sPath ) then
local tList = fs.list( sPath )
for n=1,#tList do
local sFile = tList[n]
if not fs.isDir( fs.combine( sPath, sFile ) ) and
(_bIncludeHidden or string.sub( sFile, 1, 1 ) ~= ".") then
tItems[ sFile ] = true
end
end
end
end
-- Sort and return
local tItemList = {}
for sItem, b in pairs( tItems ) do
table.insert( tItemList, sItem )
end
table.sort( tItemList )
return tItemList
end
local function completeProgram( sLine )
if #sLine > 0 and string.sub( sLine, 1, 1 ) == "/" then
-- Add programs from the root
return fs.complete( sLine, "", true, false )
else
local tResults = {}
local tSeen = {}
-- Add aliases
for sAlias, sCommand in pairs( tAliases ) do
if #sAlias > #sLine and string.sub( sAlias, 1, #sLine ) == sLine then
local sResult = string.sub( sAlias, #sLine + 1 )
if not tSeen[ sResult ] then
table.insert( tResults, sResult )
tSeen[ sResult ] = true
end
end
end
-- Add programs from the path
local tPrograms = shell.programs()
for n=1,#tPrograms do
local sProgram = tPrograms[n]
if #sProgram > #sLine and string.sub( sProgram, 1, #sLine ) == sLine then
local sResult = string.sub( sProgram, #sLine + 1 )
if not tSeen[ sResult ] then
table.insert( tResults, sResult )
tSeen[ sResult ] = true
end
end
end
-- Sort and return
table.sort( tResults )
return tResults
end
end
local function completeProgramArgument( sProgram, nArgument, sPart, tPreviousParts )
local tInfo = tCompletionInfo[ sProgram ]
if tInfo then
return tInfo.fnComplete( shell, nArgument, sPart, tPreviousParts )
end
return nil
end
function shell.complete( sLine )
if #sLine > 0 then
local tWords = tokenise( sLine )
local nIndex = #tWords
if string.sub( sLine, #sLine, #sLine ) == " " then
nIndex = nIndex + 1
end
if nIndex == 1 then
local sBit = tWords[1] or ""
local sPath = shell.resolveProgram( sBit )
if tCompletionInfo[ sPath ] then
return { " " }
else
local tResults = completeProgram( sBit )
for n=1,#tResults do
local sResult = tResults[n]
local sPath = shell.resolveProgram( sBit .. sResult )
if tCompletionInfo[ sPath ] then
tResults[n] = sResult .. " "
end
end
return tResults
end
elseif nIndex > 1 then
local sPath = shell.resolveProgram( tWords[1] )
local sPart = tWords[nIndex] or ""
local tPreviousParts = tWords
tPreviousParts[nIndex] = nil
return completeProgramArgument( sPath , nIndex - 1, sPart, tPreviousParts )
end
end
return nil
end
function shell.completeProgram( sProgram )
return completeProgram( sProgram )
end
function shell.setCompletionFunction( sProgram, fnComplete )
tCompletionInfo[ sProgram ] = {
fnComplete = fnComplete
}
end
function shell.getCompletionInfo()
return tCompletionInfo
end
function shell.getRunningProgram()
if #tProgramStack > 0 then
return tProgramStack[#tProgramStack]
end
return nil
end
function shell.setAlias( _sCommand, _sProgram )
tAliases[ _sCommand ] = _sProgram
end
function shell.clearAlias( _sCommand )
tAliases[ _sCommand ] = nil
end
function shell.aliases()
-- Copy aliases
local tCopy = {}
for sAlias, sCommand in pairs( tAliases ) do
tCopy[sAlias] = sCommand
end
return tCopy
end
if multishell then
function shell.openTab( ... )
local tWords = tokenise( ... )
local sCommand = tWords[1]
if sCommand then
local sPath = shell.resolveProgram( sCommand )
if sPath == "rom/programs/shell" then
return multishell.launch( tEnv, sPath, table.unpack( tWords, 2 ) )
elseif sPath ~= nil then
return multishell.launch( tEnv, "rom/programs/shell", sCommand, table.unpack( tWords, 2 ) )
else
printError( "No such program" )
end
end
end
function shell.switchTab( nID )
multishell.setFocus( nID )
end
end
-- "shell"
-- Print the header
term.setBackgroundColor( bgColour )
term.setTextColour( promptColour )
print( os.version() )
term.setTextColour( textColour )
-- Run the startup program
if parentShell == nil then
shell.run( "/rom/startup" )
end
-- Read commands and execute them
local tCommandHistory = {}
while not bExit do
term.redirect( parentTerm )
term.setBackgroundColor( bgColour )
term.setTextColour( promptColour )
write( shell.dir() .. "> " )
term.setTextColour( textColour )
local sLine = read( nil, tCommandHistory, shell.complete )
table.insert( tCommandHistory, sLine )
shell.run( sLine )
end
end
parallel.waitForAll(progf , progs)
If you run this program , shell works but if you send this rednet message -> "shutdown" The computer will shutdown.
Sorry for bad english xd
Edited on 02 November 2015 - 04:19 PM
Posted 02 November 2015 - 05:26 PM
Well, this actually makes me see why its useful. Nice work. tArgs = {…} doesn't work because you have to declare it this way:
You see the … ? These are the important ones.
Psssst: 1300th post!
function progf(...)
--stuff
end
You see the … ? These are the important ones.
Psssst: 1300th post!
Edited on 02 November 2015 - 04:25 PM
Posted 02 November 2015 - 05:39 PM
It is not fixable… I guess…
Posted 02 November 2015 - 05:40 PM
Well, this actually makes me see why its useful. Nice work. tArgs = {…} doesn't work because you have to declare it this way:function progf(...) --stuff end
You see the … ? These are the important ones.
Psssst: 1300th post!
How would you know which program(s) get which arguments?
Posted 02 November 2015 - 05:44 PM
It helps since it won't error when running the code and there is a reference to … Also, there is no way to pass arguments when using the parallel api.
Posted 02 November 2015 - 06:11 PM
It helps since it won't error when running the code and there is a reference to … Also, there is no way to pass arguments when using the parallel api.
There is
function func1(...)
local a = {...}
while true do
print("func1:"..unpack(a))
end
end
function func2()
while true do
print("func2: I don't need arguments")
sleep(0)
end
end
parallel.waitForAll(function()
func1("this ","is ","a ","test")
end,
func2)
Posted 02 November 2015 - 06:17 PM
Yeah, it works, even if it is kinda hacky.
Posted 02 November 2015 - 06:19 PM
test1 program:
test2 program:
———————
output file
—————–
That trouble is hard to solve… If you solve this trouble , post it here x)
function test()
print("test")
end
test()
——————-test2 program:
———————
function test()
print("test2")
end
test()
—————–output file
—————–
--[[
THIS PROGRAM IS MIGRATED
]]--
function progf()
function test()
print("test")
end
test()
end
function progs()
function test()
print("test2")
end
test()
end
parallel.waitForAll(progf , progs)
That trouble is hard to solve… If you solve this trouble , post it here x)
Posted 02 November 2015 - 06:23 PM
Which trouble? Also, add the … in the progf and progs declarations.
Posted 02 November 2015 - 06:29 PM
If sourcecode contains tArgs add function progf(…) ?Which trouble? Also, add the … in the progf and progs declarations.
I will try
Edited on 02 November 2015 - 05:29 PM
Posted 02 November 2015 - 06:31 PM
Add it anyways. Its easier and won't harm.
Posted 02 November 2015 - 06:33 PM
OMG Its worked xD Thanks for it D:Add it anyways. Its easier and won't harm.
Posted 02 November 2015 - 06:37 PM
You're welcome!
Posted 02 November 2015 - 06:38 PM
Updated xD
Posted 02 November 2015 - 08:13 PM
Yeah, it works, even if it is kinda hacky.
//Kinda Off-Topic
If that is "hacky" for you, you could try out my [shameless-self-promote]RandomUtils API[/shameless-self-promote].
local args = {...}
local function func1(...)
--program code
end
local function func2(...)
--other program code
end
parallel.waitForAll(
_.bindn(func1,unpack(args)),
_.bindn(func2,unpack(args))
)
Does that look less hacky for you?
Edited on 02 November 2015 - 07:14 PM
Posted 02 November 2015 - 08:18 PM
Looks even worse. But as long as it works.
Posted 07 November 2015 - 08:38 PM
Maybe you should try an environment trick.test1 program:——————-function test() print("test") end test()
test2 program:
————————————–function test() print("test2") end test()
output file
—————–--[[ THIS PROGRAM IS MIGRATED ]]-- function progf() function test() print("test") end test() end function progs() function test() print("test2") end test() end parallel.waitForAll(progf , progs)
That trouble is hard to solve… If you solve this trouble , post it here x)
Try this:
env1 = getfenv()
env2 = getfenv()
setfenv(func1,env1)
setfenv(func2,env2)
This will isolate the functions, they'll have their custom global vars (but when they ended you'll have to publish these and then probably conflicts will happen. For that you should maybe use two tables and publish global vars there)
Posted 07 November 2015 - 08:54 PM
That wouldn't work since the program only takes the content from the files. Where would it get the env tables from?
Posted 07 November 2015 - 09:10 PM
That wouldn't work since the program only takes the content from the files. Where would it get the env tables from?
getfenv() returns the environment of the current function which is the "main" program. But that would still cause conflicts because getfenv returns a pointer to the env, not a copy of the env. You have to copy (or even "deep copy") the env to get two independent tables.
Posted 07 November 2015 - 09:18 PM
Yeah, but why bother?
Posted 07 November 2015 - 10:02 PM
That wouldn't work since the program only takes the content from the files. Where would it get the env tables from?
getfenv() returns the environment of the current function which is the "main" program. But that would still cause conflicts because getfenv returns a pointer to the env, not a copy of the env. You have to copy (or even "deep copy") the env to get two independent tables.
Or use setmetatable({}, { __index = getfenv() }) to create a descended table.
Posted 08 November 2015 - 09:02 AM
Generate new ones with inheriting _GThat wouldn't work since the program only takes the content from the files. Where would it get the env tables from?
newenv= setmetatable({},{__index = _G})
Or get the current env with getfenv()
Posted 08 November 2015 - 09:03 AM
The question is why? What does this bring?
Posted 08 November 2015 - 09:09 AM
You avoid conflicts:The question is why? What does this bring?
func1 = function()
test = "hi"
for i=1,15 do
coroutine.yield()
end
A = #test
end
func2 = function()
coroutine.yield()
test = 5
end
Posted 08 November 2015 - 09:32 AM
This is why you use locals.
Posted 08 November 2015 - 11:05 AM
But you never know if you migrate some programs, which sometimes aren't yoursThis is why you use locals.
Posted 08 November 2015 - 11:14 AM
Then it's their problem. And to copy tables do this:
Disclaimer: I am not responsible for recursive tables.
local function tablecopy(source,destination)
source = type(source) == "table" and source or {}
for i,v in pairs(source) do
if type(v) == "table" then
destination[i] = {}
tablecopy(source[i],destination[i])
else
destination[i] = v
end
end
end
env1 = tablecopy(getfenv(),{})
env2 = tablecopy(getfenv(),{})
Disclaimer: I am not responsible for recursive tables.
Posted 08 November 2015 - 11:16 AM
No metatable support, no recursion supportThen it's their problem. And to copy tables do this:local function tablecopy(source,destination) source = type(source) == "table" and source or {} for i,v in pairs(source) do if type(v) == "table" then destination[i] = {} tablecopy(source[i],destination[i]) else destination[i] = v end end end env1 = tablecopy(getfenv(),{}) env2 = tablecopy(getfenv(),{})
Disclaimer: I am not responsible for recursive tables.
Edited on 08 November 2015 - 10:18 AM
Posted 08 November 2015 - 11:20 AM
You're actually right.
local function tablecopy(source,destination)
source = type(source) == "table" and source or {}
for i,v in pairs(source) do
if type(v) == "table" then
destination[i] = {}
local mt = getmetatable(v)
if mt and type(mt) == "table" then
setmetatable(destnation[i],mt)
end
tablecopy(v,destination[i])
else
destination[i] = v
end
end
end
env1 = tablecopy(getfenv(),{})
env2 = tablecopy(getfenv(),{})