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

Os.loadapi() Find Path Of Loaded File

Started by Imred Gemu, 25 August 2013 - 09:07 PM
Imred Gemu #1
Posted 25 August 2013 - 11:07 PM
I am writing program that can be used as either an API or as an executable and I need it to be able to find the absolute path to itself in both cases, I know that if I call shell.getRunningProgram() it will either return the name of the program if it is being executed or error out if it is being loaded, while this is helpful if it is being executed or for telling if it is being executed or loaded, I can't find the name of the program as it is being loaded this way because it errors out, and even if it didn't I assume it would just tell me the name of the program that loaded it based on my understanding of how the shell works. I don't want the person calling the api to have to tell my program where it is located so my question is, does anyone know how to find the absolute path to a program if it is being loaded with os.loadAPI() as opposed to being executed?
jay5476 #2
Posted 26 August 2013 - 01:32 AM
maybe try an overwrite of the function??? i personally havnt tried this myself(its in spoiler)
Spoiler

local tAPIsLoading = {}
os.loadAPI = function( _sPath ) -- overwrite the function
local sName = fs.getName( _sPath ) -- either change this to a global variable by removing local or add
filename = sName -- that you can later grab as a global variable
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

Grim Reaper #3
Posted 26 August 2013 - 01:45 AM
I think that jay5476 has the right idea, but perhaps overwriting the function in the bios.lua file isn't the best way to go about it. Instead, you might want to try overwriting the function at startup or sometime before you try to load your API. You could, for example, create a table to keep track of all APIs which are loaded properly

Off the top of my head, this is what I could come up with:


_G.loadedAPIs = {}

local oldOsLoadAPI = os.loadAPI
os.loadAPI         = function (apiPath)
    _G.loadedAPIs[#_G.loadedAPIs + 1] = apiPath
    local success, errorMessage       = pcall (oldOsLoadAPI, apiPath)

    if not success then
        _G.loadedAPIs[#_G.loadedAPIs] = nil
    end
end

This way, if the api loads properly, the global table 'loadedAPIs' will contain a stack of the APIs which are loaded. When you load your API, you can check the element at loadedAPIs[#loadedAPIs] to get the path of your API.

NOTE: You might also want to overwrite os.unloadAPI to remove the elements from the table.
jay5476 #4
Posted 26 August 2013 - 02:05 AM
would of been better to do

oldLoad = os.loadApi
os.loadApi = function(path)
file = path
return oldLoad()
end
or with a table for all

apis = {}
oldLoad = os.loadAPI
os.loadAPI = function(path)
table.insert(apis, path)
return oldLoad()
end
and yes do unload to eg. (think this works)

oldUnload = os.unloadAPI
os.unloadAPI = function(path)
for k,v in pairs(apis) do
if v == path then
unloaded = k
end
end
table.remove(apis, unloaded)
return oldUnload()
end
wow howd i miss that :/ i also believe grims works too
LBPHacker #5
Posted 26 August 2013 - 03:46 AM
Several answers had been given already, but whatever. I'd just create a new loadAPI and put it into _G. No messing with unloading.
function _G.os.loadAPIEx(path)
    os.loadAPI(path)
    local realName = fs.getName(path)
    _G[realName]._path = path
end
That'll just put a _path variable into the API itself.

-snip-
You return oldLoad and oldUnload there, but don't call them. Most important part out.
KaoS #6
Posted 26 August 2013 - 04:16 AM
Several answers had been given already, but whatever. I'd just create a new loadAPI and put it into _G. No messing with unloading.
function _G.os.loadAPIEx(path)
	os.loadAPI(path)
	local realName = fs.getName(path)
	_G[realName]._path = path
end
That'll just put a _path variable into the API itself.

lolz you gotta local copy it or on line 2 you might end up with a out of bounds error
LBPHacker #7
Posted 26 August 2013 - 04:18 AM
Several answers had been given already, but whatever. I'd just create a new loadAPI and put it into _G. No messing with unloading.
function _G.os.loadAPIEx(path)
	os.loadAPI(path)
	local realName = fs.getName(path)
	_G[realName]._path = path
end
That'll just put a _path variable into the API itself.

lolz you gotta local copy it or on line 2 you might end up with a out of bounds error
Nah. _G.os.loadAPIEx. That's what I mean by "new" os.loadAPI.
KaoS #8
Posted 26 August 2013 - 04:31 AM
derp. I did not see that, my mistake
Imred Gemu #9
Posted 26 August 2013 - 12:34 PM
Was worried that would be most peoples answer, thanks for all your suggestions guys. I have a simpler work around that has less chances of conflicting with other programs who may also want to overwrite the default os.loadAPI(), while the work around is simpler than doing that, It would be a lot more complicated than using something similar to shell.getRunningProgram() except for loaded apis so I just wanted to ask if there was something like that, but since there isn't I'll just go with my alternative. Again thanks so much for all your suggestions!
KaoS #10
Posted 26 August 2013 - 03:47 PM
If you have a more elegant solution please share it with us as many search the ask a pro forum before asking a question and your solution may help them
Imred Gemu #11
Posted 26 August 2013 - 07:49 PM
If you have a more elegant solution please share it with us as many search the ask a pro forum before asking a question and your solution may help them
Unfortunately my alternative only solves the issue in my program that results from not being sure of it's path name, it doesn't allow me to find the path to my program.