This is the new home of the egghelp.org community forum.
All data has been migrated (including user logins/passwords) to a new phpBB version.


For more information, see this announcement post. Click the X in the top right-corner of this box to dismiss this message.

[SOLVED] Set Variable to Line in File / Write Variable

Help for those learning Tcl or writing their own scripts.
Post Reply
S
Seka
Voice
Posts: 18
Joined: Tue Apr 19, 2011 10:21 pm

[SOLVED] Set Variable to Line in File / Write Variable

Post by Seka »

I am pretty sure I know how to write a variable to a line in a file. My goal here is to use an outside file to "record" the state of a variable, so that if the bot resets it doesn't forget what the variable was set to the last time it accessed the script.

Let me explain.

I need to increment the value of a variable, in order for the bot to know what change to make on which day, in the course of eleven days. I just realized that by initializing the variable the way I do in the script, that if the bot dies or resets the CONF, it will start the variable from scratch.

So, every time I increment the variable, I want to write the value to a file. Then, pull that value from that file, each time the bot needs it for the script. Thus, avoiding repeating the same action two or more days in a row.

What I need:

I can't quite figure out the code to set a variable to a line in a file, then after the variable is increased an increment, overwrite that file line with the new value.

I'd really appreciated some help with this!

Thank you.
Last edited by Seka on Tue Apr 26, 2011 1:49 pm, edited 1 time in total.
w
willyw
Revered One
Posts: 1209
Joined: Thu Jan 15, 2009 12:55 am

Post by willyw »

There is some very helpful info on file operations, here:

http://forum.egghelp.org/viewtopic.php?t=6885


Probably more than what you need.... it sounds like you need to write only one line, with one number on it, to the file.

You might also find some useful info here:
http://www.tcl.tk/man/tcl8.5/TclCmd/open.htm#M7
or close to there.
http://www.tcl.tk/man/tcl8.5/TclCmd/open.htm


The main page is:
http://www.tcl.tk/man/tcl8.5/TclCmd/contents.htm

I hope this helps.
n
nml375
Revered One
Posts: 2860
Joined: Fri Aug 04, 2006 2:09 pm

Post by nml375 »

There are a few ways of doing this..
However, I'd probably settle with restoring the value when your eggdrop is restarted, rather than everytime the variable is read.

One of the simplest ways of doing this, is actually to have your code write a script that sets the value.. then all you need to do is add a "source restore.tcl" to your config-file

Code: Select all

...
#assuming variable is named "state"
set fd [open "restore.tcl" "WRONLY CREAT TRUNC"]
puts $fd [list set state $state]
close $fd
...
The above code writes a single line to the file restore.tcl, containing a (safe) set command to restore the value of "state". It should be fairly trivial to embed in your current code.

Other ways would be to just write the value to the file, and restore it by opening the file with read-access, reading the line, and restoring the value of the variable using the read value..

Code: Select all

...
#assuming variable is named "state"
set fd [open "restore" "WRONLY CREAT TRUNC"]
puts $fd $state
close $fd
...
if {[catch {open "restore" "RDONLY"} fd]} {
  #unable to open file, does not exist?
  putlog "Error restoring state: $fd"
  return
} else {
  set ::state [gets $fd]
  close $fd
}
...
NML_375
S
Seka
Voice
Posts: 18
Joined: Tue Apr 19, 2011 10:21 pm

Post by Seka »

Thank you both for the quick responses. I was able to rig something together, using the documentation.

nml375,

It looks like what you're suggesting could significantly lower the amount of code in my primary script.

My question is this, though. If I need to increment the value of the variable and store it in several different scenarios, would I need to repeat that code snippet throughout the script?

Example:

Code: Select all

pub example{nick host channel text} {
if {$state == 1} {
putserv "TOPIC $channel :It is day 1!"
incr $state
} elseif {$state == 2} {
putserv "TOPIC $channel :It is day 2!"
set $state 1
}
}
Would your snippet be repeated after the "incr $state" in each expression?

Edit:

The proc is actually a time bind, but I just used the above code as an example.
n
nml375
Revered One
Posts: 2860
Joined: Fri Aug 04, 2006 2:09 pm

Post by nml375 »

The first problem with the code you posted, is that state is a local variable. The script-solution I mentioned "only" works with global variables (it could be made to work with local variables as well, but the hazzle really isn't worth it.. just use a global variable instead..)

Assuming we use a globalspace variable ::state instead; the posted code would only need one instance of the "save-code", provided that we add it at the end of the "example" proc, that we place the code at the end of the proc, and that we do not exit the proc prematurely (no return statements, etc).

Code: Select all

pub example {nick host handle channel text} {
  if {$::state == 1} {
    putserv "TOPIC $channel :It is day 1!"
    incr ::state
  } elseif {$::state == 2} {
    putserv "TOPIC $channel :It is day 2!"
    set ::state 1
  }
  set fd [open "restore.tcl" "WRONLY CREAT TRUNC"]
  puts $fd [list set state $::state]
  close $fd
}
Btw, I fixed the issues where you use variable substitutions unintentinally: set $state 1 =>set state 1; incr $state => incr state
NML_375
S
Seka
Voice
Posts: 18
Joined: Tue Apr 19, 2011 10:21 pm

Post by Seka »

Ok. So, here's what I've got. It is untested, so far.

Let me know if I need to change anything, please:

Code: Select all

set channel "#Bot_Test"

# Open the TCL with the variable?
set fd [open "restore" "WRONLY CREAT TRUNC"]
puts $fd $rpday
close $fd 

# Execute every day at midnight?
bind time - "00 00 * * *" tchange

# Execute the proc.
proc tchange {min hour day month year} {
global channel
if {$::rpday == 1} {
putquick "TOPIC $channel :It is Day 1!"
incr ::rpday
} elseif {$::rpday == 2} {
putquick "TOPIC $channel :It is Day 2!"
incr ::rpday
} elseif {$::rpday == 3} {
putquick "TOPIC $channel :It is Day 3!"
incr ::rpday
} elseif {$::rpday == 4} {
putquick "TOPIC $channel :It is Day 4!"
incr ::rpday
} elseif {$::rpday == 5} {
putquick "TOPIC $channel :It is Day 5!"
incr ::rpday
} elseif {$::rpday == 6} {
putquick "TOPIC $channel :It is Day 6!"
incr ::rpday
} elseif {$::rpday == 7} {
putquick "TOPIC $channel :It is Day 7!"
incr ::rpday
} elseif {$::rpday == 8} {
putquick "TOPIC $channel :It is Day 8!"
incr ::rpday
} elseif {$::rpday == 9} {
putquick "TOPIC $channel :It is Day 9!"
incr ::rpday
} elseif {$::rpday == 10} {
putquick "TOPIC $channel :It is Day 10!"
incr ::rpday
} elseif {$::rpday == 11} {
putquick "TOPIC $channel :It is Day 11!"
set ::rpday 1
}
  set fd [open "rpday.tcl" "WRONLY CREAT TRUNC"]
  puts $fd [list set state $::rpday]
  close $fd 
}
}
Also, do I need to create the "rpday.tcl" script in advance, or just enter the "source/rpday.tcl" entry in the bots conf?
what should the contents of that script look like, so that the variable can be read properly?
n
nml375
Revered One
Posts: 2860
Joined: Fri Aug 04, 2006 2:09 pm

Post by nml375 »

Please indent your code properly when posting, it makes spotting issues such as the extra } in your code that much easier to spot... not to mention reading the code.

First, since you named your variable rpday, not state, you'll have to change that in the save-code as well..
Also, if you go with the script-solution, you don't need to write the value to "restore"; I'd suggest you only use one or the other to avoid confusion, not both..

Also a hint, since you're building such many states on a single expression (variable), I'd considder using switch instead of those stacked if/elseif/else's...

Finally, as for reading the generated rpday.tcl upon startup; I'd use a catch-statement - just so I wouldn't have to bother making sure the file is always created (yes, I'm lazy). I'll even add a default value in case there was an error loading the file...

Code: Select all

if {[catch {source rpday.tcl} err]} {
  set ::rpday 1
}

set ::rpchan "#Bot_Test"

bind time - "00 00 * * *" tchange
proc tchange {min hour day month year} {
  global rpchan

  switch -exact -- $::rpday {
    1 {putquick "TOPIC $::rpchan :It is Day One!"}
    2 {putquick "TOPIC $::rpchan :It is Day Two!"}

    #... and so on...
    #until the default case, which maches if none of the above does...
    default {
      putquick "TOPIC $::rpchan :It is Day Eleven!"
      set ::rpday 0
    }
  }
  incr ::rpday
  set fd [open "rpday.tcl" "WRONLY CREAT TRUNC"]
  puts $fd [list set ::rpday $::rpday]
  close $fd
}
Edit: Corrected missing "incr ::rpday"
Edit: Corrected missing edit note...
Last edited by nml375 on Fri Apr 29, 2011 10:00 am, edited 2 times in total.
NML_375
S
Seka
Voice
Posts: 18
Joined: Tue Apr 19, 2011 10:21 pm

Post by Seka »

Looks like that is going to do it. I just need to format my topic a little better. I can't figure out how to keep the script from thinking that the brackets in the topic are code.

Thanks for your help, NML!
n
nml375
Revered One
Posts: 2860
Joined: Fri Aug 04, 2006 2:09 pm

Post by nml375 »

Escape them as \[ \]
NML_375
S
Seka
Voice
Posts: 18
Joined: Tue Apr 19, 2011 10:21 pm

Post by Seka »

Awesome.

Solved.

Thanks again!
S
Seka
Voice
Posts: 18
Joined: Tue Apr 19, 2011 10:21 pm

Post by Seka »

Code: Select all

if {[catch {source rpday.tcl} err]} {
  set ::rpday 1
}

set ::rpchan "#Bot_Test"

bind time - "00 00 * * *" tchange
proc tchange {min hour day month year} {
  global rpchan

  switch -exact -- $::rpday {
    1 {putquick "TOPIC $::rpchan :It is Day One!"}
    2 {putquick "TOPIC $::rpchan :It is Day Two!"}

    #... and so on...
    #until the default case, which maches if none of the above does...
    default {
      putquick "TOPIC $::rpchan :It is Day Eleven!"
      set ::rpday 0
    }
  }
  set fd [open "rpday.tcl" "WRONLY CREAT TRUNC"]
  puts $fd [list set ::rpday $::rpday]
  close $fd
}
It looks like the above script is stuck on the first entry in the "switch" statement. As it stands, at midnight, the topic is always changed to "It is Day One!" and never anything else in the list.
n
nml375
Revered One
Posts: 2860
Joined: Fri Aug 04, 2006 2:09 pm

Post by nml375 »

Sorry, seems I forgot to increase the value of rpday at the end of the proc.. I'll update my previous post to correct the issue in a sec..
NML_375
Post Reply