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

Not entirely sure what's wrong here...

Started by skwerlman, 16 March 2014 - 04:21 AM
skwerlman #1
Posted 16 March 2014 - 05:21 AM
So I have a API that needs to know which directory it's in. To find this, I run a command on the first line:

local dirName = shell.dir()

For some reason, when I run this program, I get:
apiName.lua:1: attempt to index ? (a nil value)

When I try shell.dir() in the lua program, it works fine. What am I doing wrong?

EDIT: I think I figured it out. Correct me if I'm wrong, but it looks like when you use os.loadAPI(), it's not being loaded in a particular folder, so shell.dir() doesn't work right. (And/or doesn't exist?)
Edited on 16 March 2014 - 04:24 AM
theoriginalbit #2
Posted 16 March 2014 - 05:29 AM
not quite. basically what it is is that whenever you load an api with os.loadAPI it does not get a reference to the shell API, only your main program gets that, you can however supply the API to your own so that you can use it.

Example main program (startup)

os.loadAPI("api")
api.setShell(shell)
api.doSomething()

Example API (api)

local shell

function setShell( t )
  shell = t
end

function doSomething()
  print("The current shell directory is: ", shell.dir())
end
skwerlman #3
Posted 16 March 2014 - 05:46 AM
not quite. basically what it is is that whenever you load an api with os.loadAPI it does not get a reference to the shell API, only your main program gets that, you can however supply the API to your own so that you can use it.

Example main program (startup)

os.loadAPI("api")
api.setShell(shell)
api.doSomething()

Example API (api)

local shell

function setShell( t )
  shell = t
end

function doSomething()
  print("The current shell directory is: ", shell.dir())
end

Thanks. It's a shame that there's no easier way to do that.
theoriginalbit #4
Posted 16 March 2014 - 06:04 AM
Thanks. It's a shame that there's no easier way to do that.
well you could also do your own custom implementation of os.loadAPI to actually add in a reference to shell.
Lyqyd #5
Posted 16 March 2014 - 07:32 AM
Could always try getfenv(2).shell.dir(), if you can guarantee that your API will only be called by programs with the shell "API" in their environment. If it starts getting called by other API functions or something, all bets are off.

The advantage to this method is that if multiple shells are instantiated, this will always get the "correct" one.
skwerlman #6
Posted 16 March 2014 - 10:24 PM
Well, I implemented that first method, but now when I call load it, it doesn't seem to be loaded properly:


os.loadAPI(shell.dir()..'test.sys/api/apiName.lua')
print(apiName or 'nil')

prints 'nil' instead of 'tablexxxxxx'

Any idea as to what's wrong?
CometWolf #7
Posted 16 March 2014 - 10:59 PM
I've never tried loading an api with a dot in it's name, but i suspect that might cause problems. Try removing it.
theoriginalbit #8
Posted 17 March 2014 - 02:24 AM
yeah it causes problems. I've made a os.loadAPI function which fixes the problem with extensions


function loadAPI(path)
  local name = string.match(fs.getName(path), "(%a+)%.?.-")
  local env = setmetatable({}, { __index = _G })
  local func, err = loadfile(path)
  if not func then
	return false, printError(err)
  end
  setfenv(func, env)
  func()
  local api = {}
  for k,v in pairs(env) do
	api[k] =  v
  end
  _G[name] = api
  return true
end

and if you want to add the reference to the shell for it change the line

local env = setmetatable({}, { __index = _G })
to

local env = setmetatable({shell = shell}, { __index = _G })
Edited on 17 March 2014 - 01:24 AM
skwerlman #9
Posted 17 March 2014 - 07:20 AM
yeah it causes problems. I've made a os.loadAPI function which fixes the problem with extensions


function loadAPI(path)
  local name = string.match(fs.getName(path), "(%a+)%.?.-")
  local env = setmetatable({}, { __index = _G })
  local func, err = loadfile(path)
  if not func then
	return false, printError(err)
  end
  setfenv(func, env)
  func()
  local api = {}
  for k,v in pairs(env) do
	api[k] =  v
  end
  _G[name] = api
  return true
end

and if you want to add the reference to the shell for it change the line

local env = setmetatable({}, { __index = _G })
to

local env = setmetatable({shell = shell}, { __index = _G })

Thanks so much for all the help!