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

[Lua][Question] Trying to make a list of sorts

Started by Formis13, 12 December 2012 - 03:46 PM
Formis13 #1
Posted 12 December 2012 - 04:46 PM
On a server I frequent, there's guilds of sorts, and for mine, I'm trying to set up a list of email addresses so I can send out announcements,etc. The problem is that the server resets often and so keeping them saved until I can see them and make a more permanent save elsewhere is not easy. I'm very new to programming, so I'm sure that there's a simple solution to this, but I've been working on this on and off for 3 days and I've still been hitting dead ends. Here's the code in its current form. What am I doing wrong?


--this is where I had most of my problems, I could make the variable and edit it, but the second the server restarted, everything was lost and I had to start from scratch.
local email = {"Emails:"}

function save ()
  local eString=textutils.serialize (email)
  file=fs.open("eList","a")
  file.write(eString)
  file.close()
end

function load ()
  local file=fs.open ("eList","r")
  local eString=file.readAll ()
  file.close()
  local email=textutils.unserialize (eString)
end

while true do
  term.clear()
  term.setCursorPos(1, 1)
  print ("Please enter your email.")
  input = read()

  load ()
  term.clear()
  term.setCursorPos(1, 1)

--I wanted to make it so that if you entered seeEmails, it would display all the addresses inputted.
  if input ~= "seeEmails" then

	table.insert(email, input)
	print ("Thank you, I will add you to the mailing list.")
	sleep (10)

  else

	for i = 1, #email, 2 do
	  if i + 1 > #email then
		print (email[i])
	  else
		print (email[i]..email[i+1])
	  end
	end
  
	io.read()

  end
  save ()
end
Bubba #2
Posted 12 December 2012 - 05:42 PM
Okay there are a few things in here. First, make sure that you're spelling things correctly. In line 4 where you declare the save function you mispelled function as "funtion". Second, I think you might want to change "file=fs.open("eList", "w")" to "file=fs.open("eList", "a")". As it is right now, every time you open the file you will merely be overwriting the file rather than adding on to it. If you run into more problems, let me know and I'll see what I can do.
Formis13 #3
Posted 12 December 2012 - 06:15 PM
Okay there are a few things in here. First, make sure that you're spelling things correctly. In line 4 where you declare the save function you mispelled function as "funtion". Second, I think you might want to change "file=fs.open("eList", "w")" to "file=fs.open("eList", "a")". As it is right now, every time you open the file you will merely be overwriting the file rather than adding on to it. If you run into more problems, let me know and I'll see what I can do.
Thanks, fixed those. But that still doesn't help the problem of the list getting wiped every 2 hours. The emails that get put in still get wiped when the server turns back on. Is there any way to fix this?

I wound up checking eList itself and just had a bunch of tables containing several copies of {[1]="Emails:"} and occasionally having 1 or 2 other variables along with it. Am I just going to have to work with that or can I get it all into one table that I can view with the print(email..email[i+1])?
Bubba #4
Posted 12 December 2012 - 06:38 PM
Hmm. Well you can always try posting the tables to a website with the HTTP api. I'm not very familiar with it but you can check out the wiki. I'm not entirely sure if server resets erase files or not so somebody else would probably need to answer that. I wouldn't think that it would though.
Formis13 #5
Posted 12 December 2012 - 06:49 PM
Alright, I'll take a look. Thank you so much.
dissy #6
Posted 12 December 2012 - 06:58 PM
If a server reset erased files (IE if it was running from a ram disk for speed purposes) then it would also delete the program as well as the data files.

I'm guessing it's in your load/save functions that are blanking the file.

On program start, it initializes one email variable as basically an empty list.
Then it calls load()
load defines a local variable named email (which is not the same variable as email in the rest of the program!)
once load is finished and returns, that second local email variable is now gone. So you are left with only the original empty email variable you defined at the top.
You then call save() which writes that empty variable to the file, overwriting anything in it.

Try removing the "local" keyword before the email variable in the load function.
It might be worth while to make the first email variable a global as well, just to be safe.
Formis13 #7
Posted 12 December 2012 - 07:08 PM
If a server reset erased files (IE if it was running from a ram disk for speed purposes) then it would also delete the program as well as the data files.

I'm guessing it's in your load/save functions that are blanking the file.

On program start, it initializes one email variable as basically an empty list.
Then it calls load()
load defines a local variable named email (which is not the same variable as email in the rest of the program!)
once load is finished and returns, that second local email variable is now gone. So you are left with only the original empty email variable you defined at the top.
You then call save() which writes that empty variable to the file, overwriting anything in it.

Try removing the "local" keyword before the email variable in the load function.
It might be worth while to make the first email variable a global as well, just to be safe.
Well, no, the problem was that it was erasing the variables within the program whenever the computer would reboot for any reason, thus wiping any emails that were saved. Regardless, I'll give that a shot and see what happens.
Formis13 #8
Posted 12 December 2012 - 07:19 PM
Well I tried it, and now when I type seeEmails, the screen comes up entirely blank, and when I check eList, there's multiple copies of the table with /'s everywhere inside the tables. I feel like I somehow did something ridiculously stupid in making those variables global.
dissy #9
Posted 12 December 2012 - 07:27 PM
Well, no, the problem was that it was erasing the variables within the program whenever the computer would reboot for any reason, thus wiping any emails that were saved. Regardless, I'll give that a shot and see what happens.

Yes, all variables are cleared when a program first starts. This is normal.
Your program starts out setting an empty variable, then your load function doesn't change it, and then your save function should write that empty variable to the file.
At this point you have an empty variable in memory, and an empty file, and finally the rest of your program runs.

Perhaps this quick demo will explain better.
first, with local in the function



Next, with the local keyword removed

Formis13 #10
Posted 12 December 2012 - 07:40 PM
Yes, all variables are cleared when a program first starts. This is normal.
Your program starts out setting an empty variable, then your load function doesn't change it, and then your save function should write that empty variable to the file.
At this point you have an empty variable in memory, and an empty file, and finally the rest of your program runs.

Perhaps this quick demo will explain better.
first, with local in the function



Next, with the local keyword removed

Alright, that makes sense. Also I tried just getting rid of the first line and putting it in eList instead, and now it displays the emails properly, but when I reboot the program, I get "startup:28: bad argument: table expected, got string" and a second table shows up in eList instead of the first one just getting edited.
I feel like I'm making progress, but I stil seem to be beating my head against a wall.
dissy #11
Posted 12 December 2012 - 08:01 PM
Alright, that makes sense. Also I tried just getting rid of the first line and putting it in eList instead, and now it displays the emails properly, but when I reboot the program, I get "startup:28: bad argument: table expected, got string" and a second table shows up in eList instead of the first one just getting edited.
I feel like I'm making progress, but I stil seem to be beating my head against a wall.

I'm not sure I understand what you mean by getting rid of the first line and putting it in eList instead.
Could you update the code so I can see the current version?
Your line 28 doesn't match up with what I see as line 28 (which is a comment, followed by an if that you say works correctly)

From the error, I'm guessing it's the line
table.insert(email, input)
as it needs the first argument given to be a table. Did you mean you removed the first line defining email as a table? Because that would cause that ;}
Formis13 #12
Posted 12 December 2012 - 08:07 PM
I'm not sure I understand what you mean by getting rid of the first line and putting it in eList instead.
Could you update the code so I can see the current version?
Your line 28 doesn't match up with what I see as line 28 (which is a comment, followed by an if that you say works correctly)

From the error, I'm guessing it's the line
table.insert(email, input)
as it needs the first argument given to be a table. Did you mean you removed the first line defining email as a table? Because that would cause that ;}


function save ()
  local eString=textutils.serialize (email)
  file=fs.open("eList","a")
  file.write(eString)
  file.close()
end

function load ()
  local file=fs.open ("eList","r")
  local eString=file.readAll ()
  file.close()
  email=textutils.unserialize (eString)
end

while true do

  term.clear()
  term.setCursorPos(1, 1)
  print ("Please enter your email.")
  input = read()

  load ()
  term.clear()
  term.setCursorPos(1, 1)

  if input ~= "seeEmails" then

	table.insert(email, input)
	print ("Thank you, I will add you to the mailing list.")
	sleep (10)

  else

	for i = 1, #email, 2 do
	  if i + 1 > #email then
		print (email[i])
	  else
		print (email[i], " ", email[i+1])
	  end
	end
  
	io.read()

  end
  save ()
end

So yes, table.insert(email, input) is what caused the error, so should I just define email as {} at the first line or something?.
dissy #13
Posted 12 December 2012 - 08:20 PM
So yes, table.insert(email, input) is what caused the error, so should I just define email as {} at the first line or something?.

You'll want the first line as it was before:
local email = {"Emails:"}

That way if you have no eList file you'll get a fresh new empty list, but after load() then email will be replaced with the copy in the eList file. Unless you didn't want that item in there in the first place of course, then yes just an empty list as: local email = {}
dissy #14
Posted 12 December 2012 - 08:27 PM
Actually yea you'll probably want
local email = {}

Without defining keys (as in an array) a table is more just a list with numbered keys.
It doesn't garentee any order that way either.

Your list would end up being similar to:
1 - person@here.com
2 - other@there.com
3 - Emails:
4 - me@home.com

etc

No need for that one non-email to be in the list.


Also, in your save function, you'll probably want to change it from append ("a") to write ("w")
I didn't notice you changed that.

When it saves, it will write a copy of the full table to the file. When it loads, it will put it back into memory.
If you append, each time you call save() it will duplicate all the emails in the list at that moment.
So on first save it would have 2 copies of each email, the next save would have 4 copies, the next 8, and so on.. that would become problematic very quick
Formis13 #15
Posted 12 December 2012 - 08:29 PM
You'll want the first line as it was before:
local email = {"Emails:"}

That way if you have no eList file you'll get a fresh new empty list, but after load() then email will be replaced with the copy in the eList file. Unless you didn't want that item in there in the first place of course, then yes just an empty list as: local email = {}

For some reason, I'm still getting an error on table.insert(email, input) whenever I type something other than seeEmail: "bad argument: table expected, got string"
and when I do type seeEmail, it just makes a second identical table in eList.

EDITED
and with local email = {} it still makes copies of the table whenever I do something, but with slashes everywhere, more and more being added with each copy, making anything besides seeEmail come up with an error and seeEmail just showing a black screen.
dissy #16
Posted 12 December 2012 - 08:35 PM
For some reason, I'm still getting an error on table.insert(email, input) whenever I type something other than seeEmail: "bad argument: table expected, got string"
and when I do type seeEmail, it just makes a second identical table in eList.

Sorry, I edited my post (aparently after you first read it) which mentions the list duplication part.
But I'm not sure why it would give that bad argument error. email = {} makes it a table. It's expecting a table, but that's what it is! So I'm a bit confused on that part of it…
Formis13 #17
Posted 12 December 2012 - 08:38 PM
Sorry, I edited my post (aparently after you first read it) which mentions the list duplication part.
But I'm not sure why it would give that bad argument error. email = {} makes it a table. It's expecting a table, but that's what it is! So I'm a bit confused on that part of it…
Well thank you for your help, but I think it's clear that we're just beating our heads against the wall with this. I appreciate the effort though, I still managed to learn quite a bit through this.
dissy #18
Posted 12 December 2012 - 08:50 PM
How about we go the simpler route and just avoid tables all together?
If you won't be doing any processing other than just displaying the email addresses (or checking the file), you could just add each address as a line in the file. Makes the whole thing much simplier ;}

Something like this perhaps?


while true do
  term.clear()
  term.setCursorPos(1, 1)
  print ("Please enter your email.")
  input = read()
  if input ~= "seeEmails" then
	-- Save an email to a file
	file=fs.open("eList","a")
	file.writeLine(input)
	file.close()

	print ("Thank you, I will add you to the mailing list.")
	sleep (10)

  else
	-- Show current emails, if any
	if fs.exists("eList") then
	  file=fs.open("eList","r")
	  d=file.readAll()
	  file.close()
	  print(d)
	  sleep(10)
	  d=""
	else
	  print("No email file exists.")
	  sleep(10)
   end
  end
end


(Sorry about the indenting, i think notepad++ converted some spaces into tabs on me)
(I think I got the indent thing fixed.. why they hide indent space/tab settings under a language/misc screen i'll never know)
Edited on 12 December 2012 - 08:02 PM
Formis13 #19
Posted 12 December 2012 - 09:07 PM
How about we go the simpler route and just avoid tables all together?
If you won't be doing any processing other than just displaying the email addresses (or checking the file), you could just add each address as a line in the file. Makes the whole thing much simplier ;}

Something like this perhaps?


while true do
  term.clear()
  term.setCursorPos(1, 1)
  print ("Please enter your email.")
  input = read()
  if input ~= "seeEmails" then
	-- Save an email to a file
	file=fs.open("eList","a")
	file.writeLine(input)
	file.close()

	print ("Thank you, I will add you to the mailing list.")
	sleep (10)

  else
	-- Show current emails, if any
	if fs.exists("eList") then
	  file=fs.open("eList","r")
	  d=file.readAll()
	  file.close()
	  print(d)
	  sleep(10)
	  d=""
	else
	  print("No email file exists.")
	  sleep(10)
   end
  end
end


(Sorry about the indenting, i think notepad++ converted some spaces into tabs on me)
(I think I got the indent thing fixed.. why they hide indent space/tab settings under a language/misc screen i'll never know)
You… you… you are beautiful and I love you with all my heart. This is perfect! PERFECT! You made this admittedly overcomplicated program so simple. You are the best.
dissy #20
Posted 12 December 2012 - 09:12 PM
You… you… you are beautiful and I love you with all my heart. This is perfect! PERFECT! You made this admittedly overcomplicated program so simple. You are the best.

Haha thank you, and your quite welcome, I'm glad I could help.