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

Api/Function failing.

Started by Waterspark63, 30 August 2018 - 04:11 AM
Waterspark63 #1
Posted 30 August 2018 - 06:11 AM
So I am working on a password check for my computer, and I keep getting a 'attempt to index ? (a nil value)', I have a function thats being called when that appears:


function CheckPassword()
term.clear()
printCentered(math.floor(h/2) -4, " ___________________ ")
printCentered(math.floor(h/2) -3, "|   Login Screen	|")
printCentered(math.floor(h/2) -2, "|___________________|")
printCentered(math.floor(h/2) -1, "")
write("User: "..name)
printCentered(math.floor(h/2) +0, "")
write("Pass: ")
local input2 = read()
if input2 == password then
  term.clear()
  sleep(1)
  printCentered(math.floor(h/2) +0, "Password Accepted.")
  printCentered(math.floor(h/2) +1, "Welcome back Water.")
  sleep(1)
  term.clear()
  shell.run("cd", "/home/water/desktop/")
  shell.run("menu")
end

I saw on another post that apparently you can't use shell.run in a function, they said to use os.run instead, how would I use it in this situation?
Post: http://www.computerc...ellrun-problem/

e
dit: name and password are declared outside the function
Edited on 30 August 2018 - 04:12 AM
osmarks #2
Posted 30 August 2018 - 08:04 AM
You can use shell.run in functions. Anyway, this would be more helpful with the rest of the code. Also, please indent.
Nothy #3
Posted 30 August 2018 - 08:16 AM
Could you post the full code, please?
Bomb Bloke #4
Posted 30 August 2018 - 11:50 AM
I keep getting a 'attempt to index ? (a nil value)'

That error will be accompanied by a number which indicates the line that triggered it. It's rather difficult to troubleshoot your code if you don't at least point that line out.

I saw on another post that apparently you can't use shell.run in a function

That's not what was said - rather, you can't use it from within the code of an API. Functions and APIs aren't at all the same thing! If you're not writing something you intend to process through os.loadAPI(), then that limitation isn't relevant.
Edited on 30 August 2018 - 09:51 AM
EveryOS #5
Posted 30 August 2018 - 12:29 PM
However, if you are writing an OS (and it appears you are), I would recommend not using shell.run or os.loadAPI

BTW, if you loadfile-d that file, than that may be the problem
Waterspark63 #6
Posted 30 August 2018 - 03:33 PM
Well, the function is in a api, anyway, heres the full code, and I have modified it a bit, but still the same problem, and it says its the line with shell.run("cd", "/home..etc…"):
And EveryOS, then how do you recommend doing it?
Function/API File:

local w,h = term.getSize()
function printCentered (y,s)
  local x = math.floor((w - string.len(s)) / 2)
  term.setCursorPos(x,y)
  term.clearLine()
  print(s)
end

local file = fs.open("/system/settings/users/water-usersettings", "r")
local settings = textutils.unserialize(file.readAll())
file.close()

function CheckPassword()
  term.clear()
  printCentered(math.floor(h/2) -4, " ___________________ ")
  printCentered(math.floor(h/2) -3, "|   Login Screen	|")
  printCentered(math.floor(h/2) -2, "|___________________|")

  printCentered(math.floor(h/2) -1, "")
  write("User: "..settings[1])
  printCentered(math.floor(h/2) +1, "")
  write("Pass: ")
  local input2 = read()
  if input2 == settings[2] then
	term.clear()
	sleep(1)

	printCentered(math.floor(h/2) +0, "Password Accepted.")
	printCentered(math.floor(h/2) +1, "Welcome back Water.")
	sleep(1)
	term.clear()

	shell.run("cd", "/home/"..settings[1].."/desktop/")
	shell.run("menu")
  end
end

The 'login' file:

local w,h = term.getSize()
function printCentered (y,s)
local x = math.floor((w - string.len(s)) / 2)
term.setCursorPos(x,y)
term.clearLine()
print(s)
end

shell.run("cd", "/")
os.loadAPI("/system/software/utils/mainutils")
term.clear()

printCentered(math.floor(h/2) +0, "Loading Login Screen...")
sleep(2)

printCentered(math.floor(h/2) -4, " ___________________ ")
printCentered(math.floor(h/2) -3, "|   Login Screen	|")
printCentered(math.floor(h/2) -2, "|___________________|")

printCentered(math.floor(h/2) +0, "")
write("User: ")
inputlogin = read()
local file = fs.open("/home/userlist", "r")
local users = textutils.unserialize(file.readAll())
file.close()

for i=1,#users do
  if users[i] == inputlogin then
	os.loadAPI("/home/"..users[i].."/userutils")
	userutils.CheckPassword()
  else
	term.clear()
	sleep(1)
	printCentered(math.floor(h/2) +0, "Username "..inputlogin.." was not found!")
	sleep(1)
	shell.run("/system/software/user/login")
  end
end

Edited on 30 August 2018 - 01:36 PM
EveryOS #7
Posted 30 August 2018 - 03:53 PM
I'm generally a fan of loadfile

--Instead of shell.run
loadfile("blah/blah", _G)(param1, param2, ...)
--Instead of os.loadAPI
local blah = loadfile("blah/blah", _G)()

Your problem could probably be fixed with this code:

_G["shell"] = shell
Paste that at the beginning of your login file
Nothy #8
Posted 30 August 2018 - 04:24 PM
shell is not available in APIs you load with os.loadAPI()
Waterspark63 #9
Posted 30 August 2018 - 05:01 PM
Thank you EveryOS, your idea worked. (_G["shell"] = shell)
EveryOS #10
Posted 30 August 2018 - 09:22 PM
You are welcome

I still recommend you switch to loadfile
Lyqyd #11
Posted 01 September 2018 - 09:52 PM
Thank you EveryOS, your idea worked. (_G["shell"] = shell)

This is a bad idea. There is a very good reason that the shell "API" isn't available to global-level things like APIs, and that's because there's no way to know which shell is the right one to use. It probably won't hurt in this specific use case, but it must be stated that this is extremely bad practice. Any API that really, truly, needs access to the shell functions should have the appropriate instance of the shell table passed to it by the caller, and should make no attempt to store that instance.

Using loadfile instead of built-in functions is also silly when it isn't strictly necessary.
EveryOS #12
Posted 05 September 2018 - 04:00 PM
Thank you EveryOS, your idea worked. (_G["shell"] = shell)

This is a bad idea. There is a very good reason that the shell "API" isn't available to global-level things like APIs, and that's because there's no way to know which shell is the right one to use. It probably won't hurt in this specific use case, but it must be stated that this is extremely bad practice. Any API that really, truly, needs access to the shell functions should have the appropriate instance of the shell table passed to it by the caller, and should make no attempt to store that instance.

Using loadfile instead of built-in functions is also silly when it isn't strictly necessary.

Require was not available in earlier CC versions, and os.loadAPI has many quirks I don't like, e.g. it is global, and you can't enter parameters, and I prefer to return a table rather than modifying _ENV
Edited on 05 September 2018 - 02:01 PM
Lupus590 #13
Posted 05 September 2018 - 06:07 PM
Require was not available in earlier CC versions, and os.loadAPI has many quirks I don't like, e.g. it is global, and you can't enter parameters, and I prefer to return a table rather than modifying _ENV

http://www.computercraft.info/forums2/index.php?/topic/24015-cc-require-standards-compatible-require-for-computercraft/
EveryOS #14
Posted 05 September 2018 - 08:02 PM
Then you need extra files
Lyqyd #15
Posted 06 September 2018 - 02:32 AM
Require was not available in earlier CC versions, and os.loadAPI has many quirks I don't like, e.g. it is global, and you can't enter parameters, and I prefer to return a table rather than modifying _ENV

That's fine, but you personally not liking the "quirks" is not justification for proselytizing against using built-in functionality or intended design. If a question specifically asks for support using loadfile(), fine; advocating it without prompting is not helpful or useful advice.