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

[Lua] pcall Not Stopping Terminate + 2 Misc. Questions

Started by Vorsaykal, 25 March 2012 - 10:02 PM
Vorsaykal #1
Posted 26 March 2012 - 12:02 AM
I've been working on a little program that allows me to control computers wirelessly from computers with specific IDs (Basically my computers only), and I've got it working quite well, except I would like to stop CTRL+T from terminating my exposed computer that I wish to be controlled only via rednet.

Code to send commands:

io.write("ID to send to: ")
ID = tonumber(io.read())
io.write("\n")
io.write("Command to send to "..ID..": ")
comm = io.read()
io.write("\n")
rednet.send(ID, comm)
conID, re = rednet.receive(2)
if re == nil then
io.write("Confirmation timed out.\n")
else
io.write(conID..": "..re.."\n)
end

Code to receive commands:

function verifyID(ID)
IDs = fs.open("whitelistedIDs", "r")

inID = tonumber(IDs.readLine())
while inID ~= nil do
  if inID == ID then
   return true
  end
  inID = tonumber(IDs.readLine())
end
end

function doComm(ID, comm, arg)
if comm == "exit" then
  rednet.send(ID, "Terminated.")
  return "exit"
elseif comm == "redstoneOn" then
  rednet.send(ID, arg.." on.")
  redstone.setOutput(arg, true)
elseif comm == "redstoneOff" then
  rednet.send(ID, arg.." off.")
  redstone.setOutput(arg, true)
elseif comm == "print" then
  rednet.send(ID, "Message displayed.")
  print(ID.." says, \""..arg.."\"")
else
  rednet.send(ID, "ERROR: Unknown command.")
end
end
while true do
ID, msg = --[[pcall(]]rednet.receive()--)
space = string.find(msg, " ")
if space ~= nil then
  comm = string.sub(msg, space + 1)
else
  comm = msg
end

if verifyID(ID) == true then
  if doComm(ID, comm, arg) == "exit" then
   return
  end
end
end

This works great, except it can be terminated. To fix this, I changed line 32 of the receive program like so:

ID, msg = rednet.receive()
to

ID, msg = pcall(rednet.receive())

I then proceeded to run my receive code, then ran my send code, send "exit" to ID 6, which was what was running my receive code, and instead of existing the receive code like it did right before when I did the exact same with without pcall, it did not affect the computer running receive, and the computer running send send my print statement saying, "Confirmation timed out.".

Also, I can still terminate my receive code via CTRL+T, so it didn't help with that, and it broke my code, so my first question is: How can I modify my code so it can't be terminated via CTRL+T.

I also have two misc. questions, they have nothing to do with the above, but I figured I'd bundle them here for now, and ask in their own thread if no one mentions them.

Q2: Would it be possible to type "send(6, "Message.") instead of: "send" <Enter> "6" <Enter> "Message." <Enter>? I know I can do this with an API, but I don't want to have to go into the lua shell every time.

Q3: Is there a way I can use io.read() for 5 seconds and if it hasn't read anything in, just move on?

Anyway, thanks for reading, and if you have anything beneficial to share, please do.

~Vorsaykal
Advert #2
Posted 26 March 2012 - 12:18 AM
You're sending the result of your function to pcall.

To fix it:

pcall(myFunction()) -- Doesn't work! you're sending the result of myFunction() to pcall.
pcall(myFunction) -- This works, you're telling pcall to call myFunction.

Note that ctrl-t will cause you to exit your function, though; you can use os.pullEventRaw to overcome this, or something like this:


local pullEvent, pullEventRaw = os.pullEvent, os.pullEventRaw
local bProtected = false
function toggleProtected(:o/>/>
 if b == nil then
  b = not bProtected
 end
 bProtected = b
 if b then
  rawset(os, "pullEvent", pullEventRaw)
 else
  rawset(os, "pullEvent", pullEvent)
 end
 return b
end
Q2: Yes, you can use loadstring().


local f = loadstring("send(1, 'asd')")
f() -- will execute the code passed to loadstring

I wouldn't really recommend using this, though, but for debugging it's useful.

Q3: Yes, but it can get complicated. You could try doing it with parallel.waitForAny, or with a custom read():

*Mildly tested, seems to work fine.

function timedRead(n, r)
 return parallel.waitForAny(function() return read(r) end,
 function()
  local t = os.startTimer(n)
  for sEvent, a, b in os.pullEvent do
   if sEvent == "timer" and a == t then
    return "" -- returning an empty string like read() does, if i remmeber right
   end
  end
 end)
end
Edited by