This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Lignum's profile picture

[1.6.4][1.58] Shell API doesn't exist in an API

Started by Lignum, 06 March 2014 - 01:26 PM
Lignum #1
Posted 06 March 2014 - 02:26 PM
This bug occurs in ComputerCraft version 1.58. It may also occur in previous versions.

The Shell API seems to completely disappear when used in an API.

Example:

function testShell()
   print(tostring(shell))
   print(shell.resolve("afile"))
end

testShell()

This works fine.
Output:

table: 2e12568d
afile

But if one decides to turn this simple program into an API…

function testShell()
   print(tostring(shell))
   print(shell.resolve("afile"))
end

… and uses it like this (assuming the file above is called testapi)…

os.loadAPI("testapi")
testapi.testShell()
os.unloadAPI("testapi")

the output will be:

nil
testapi:3: attempt to index ? (a nil value)
CometWolf #2
Posted 06 March 2014 - 02:51 PM
I don't know if this is intentional behavior or not, but i do know why it happens and how you can work around it
os.loadAPI is defined as followes

function os.loadAPI( _sPath )
local sName = fs.getName( _sPath )
if tAPIsLoading[sName] == true then
  printError( "API "..sName.." is already being loaded" )
  return false
end
tAPIsLoading[sName] = true

local tEnv = {}
setmetatable( tEnv, { __index = _G } )
local fnAPI, err = loadfile( _sPath )
if fnAPI then
  setfenv( fnAPI, tEnv )
  fnAPI()
else
  printError( err )
		tAPIsLoading[sName] = nil
  return false
end

local tAPI = {}
for k,v in pairs( tEnv ) do
  tAPI[k] =  v
end

_G[sName] = tAPI
tAPIsLoading[sName] = nil
return true
end
Note that it uses loadfile to load the API, sets it's environment to _G, then executes it. The shell table is not in _G, and thus it does not have acess to it.

It's been a while since i screwed around with this, but i think adding this above the part where you load the API, or hell any code that executes prior, should fix it.

_G.shell = shell
Alternatively, you might have to perform a deep copy on the shell table, but i doubt it.

Also, making _G inherit shell might work aswell.

setmetatable(_G,{__index = shell})
This however, is entirely untested
Edited on 06 March 2014 - 03:57 PM
Lignum #3
Posted 06 March 2014 - 03:21 PM
I don't know if this is intentional behavior or not, but i do know why it happens and how you can work aorund it
os.loadAPI is defined as followes

...
Note that it uses loadfile to load the API, sets it's environment to _G, then executes it. The shell table is not in _G, and thus it does not have acess to it.

That makes sense.

It's been a while since i screwed around with this, but i think adding this above the part where you load the API, or hell any code that executes prior, should fix it.

_G.shell = shell
Thanks! That seems to be a valid workaround. It would still be better to have this fixed officially, though.
Lyqyd #4
Posted 06 March 2014 - 03:37 PM
As far as I know, this is intended behavior, not a bug. Since there can be multiple different shell instances/layers, you would always want the API to use the instance available to the function calling it. For that reason, you should pass the shell instance to the API if it actually needs it.