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.

Working with INI Files

Old posts that have not been replied to for several years.
User avatar
user
 
Posts: 1452
Joined: Tue Mar 18, 2003 9:58 pm
Location: Norway

Post by user »

Darkj wrote:Ok i lost you, that doesn't look for cutomizable, it looks like I'll have to edit code everytime I add more bots, I was trying to avoid that.
You said you wanted to output the bots in pairs, I suggested a way. (not static in any way) Try to understand what that foreach does and you'll see what I mean.
D
Darkj
Halfop
Posts: 86
Joined: Sun Jul 06, 2003 9:58 pm

Post by Darkj »

Well, actually, I asked how to output an INI file (as seen above) to IRC, i just prefered the format of 2 bots per line, whether it still be 10 bots listed.

As for my debugging, it doesn't look like an array is going to work for me with the way the INI file is designed

My ideal method is:

[BotName]
charname=charname
location=location
action=action

the [BotName] being the actual bots name on IRC, char name is the character name in game. But in order for an array to work it looks like, is it needs some general same thing to look for. Which is where I'm stuck, I just wanted a simple list script, didn't realize it was gonna get this complicated.

EDIT: In order to use ini_write properly, the [] sections need to be different names.
User avatar
user
 
Posts: 1452
Joined: Tue Mar 18, 2003 9:58 pm
Location: Norway

Post by user »

Darkj wrote:As for my debugging, it doesn't look like an array is going to work for me with the way the INI file is designed
How about this then?

Code: Select all

foreach {name attr} [parseIni your.ini] {
	array set a $attr
	putserv "PRIVMSG #chan :$name: ($a(charname)) $a(location) ($a(action))"
}
or if you want them sorted, use an array at the first level too, and sort the names like this:

Code: Select all

array set a [parseIni your.ini]
foreach bot [lsort -dict [array names a]] {
	array set b $a($bot)
	putserv "PRIVMSG #chan :$bot: ($b(charname)) $b(location) ($b(action))"
}
If you can't be certain all the attributes exists for every bot, here's a way to provide default values:

Code: Select all

set defaults {
	charname none
	location none
	action none
}
array set a [parseIni your.ini]
foreach bot [lsort -dict [array names a]] {
	array set b [concat $defaults $a($bot)]
	putserv "PRIVMSG #chan :$bot: ($b(charname)) $b(location) ($b(action))"
}
D
Darkj
Halfop
Posts: 86
Joined: Sun Jul 06, 2003 9:58 pm

Post by Darkj »

Actually, I've kind of gone a different route now, and worked a little with the ini_read and ini_write functions. Here is my working code now.

Code: Select all

proc list_bots {nick uhost hand chan args} {
  global nowhere mainchanbots inifilebots
  if {$chan == $mainchanbots} {
  set i 0
  foreach {name value} [parseIni bots.ini] { 
    set check [ini_read bots.ini ${name} location]
    set displayname [ini_read $inifilebots ${name} display]
    set botcharname [ini_read $inifilebots ${name} charname]
    set botloc [ini_read $inifilebots ${name} location]
    set botact [ini_read $inifilebots ${name} action]
    set fs [open bots.tmp a+]
    if {![string match $check $nowhere]} {
      puts $fs "$displayname $botcharname $botloc $botact"
      incr i
    }
    close $fs
  }
  if {$i <= 0} {
    putserv "PRIVMSG $mainchanbots :\<\0032There are currently\003\0034\002 0 \002\003\0032bots logged in.\003\>"
  }
  if {$i > 0} {
    putserv "PRIVMSG $mainchanbots :\<\0032There are currently\003\0034\002 $i \002\003\0032bot\(s\) logged in.\003\>"
  }
  utimer 5 deletefile
  set fs [open bots.tmp r]
    while {![eof $fs]} {
     if {![gets $fs line]} {
       return 0
     } elseif {[lindex $line 2] != $nowhere} {
       set displayname [lindex $line 0]
       set botcharname [lindex $line 1]
       set botloc [lindex $line 2]
       set botact [lrange $line 3 end]
       if {$displayname == ""} {
         close $fs
         return 0
       }
        putserv "PRIVMSG $mainchanbots :\002$displayname\:\002 \(\0032$botcharname\003\) \0034$botloc\003 \(\0036$botact\003\)" 
      }
    } 
  close $fs
  return 0
  }
}
See any typos or mess ups, would be great to know, but this code works exactly the way I want it
User avatar
user
&nbsp;
Posts: 1452
Joined: Tue Mar 18, 2003 9:58 pm
Location: Norway

Post by user »

Darkj wrote:Actually, I've kind of gone a different route now, and worked a little with the ini_read and ini_write functions. Here is my working code now.

...

See any typos or mess ups, would be great to know, but this code works exactly the way I want it
Here's your code with comments added:

Code: Select all

proc list_bots {nick uhost hand chan args} { 
  global nowhere mainchanbots inifilebots
# i took the liberty to rewrite this 'if' a bit..just to make it easier to read (the result is the same)
  if {$chan != $mainchanbots} {return 0}
  set i 0 
  foreach {name value} [parseIni bots.ini] { 
    set check [ini_read bots.ini ${name} location] 
    set displayname [ini_read $inifilebots ${name} display] 
    set botcharname [ini_read $inifilebots ${name} charname] 
    set botloc [ini_read $inifilebots ${name} location] 
    set botact [ini_read $inifilebots ${name} action] 
# you should open the file outside the foreach loop and close it after the end..no point hammering the poor file that way :P
# but why are you writing it to a file in the first place? why not keep the lines in a variable?
    set fs [open bots.tmp a+]
# this 'string match' should be replaced by a 'string equal' I guess.
# Although I don't get the point of ignoring one bot..why is it in the file if you don't want to know about it? And why go through all that hard work in the previous lines just to end up ditching the data gathered?
    if {![string match $check $nowhere]} {
# here you write it as a string, but you later treat it as a list (using 'lindex' on it when reading it back in)
      puts $fs "$displayname $botcharname $botloc $botact" 
      incr i 
    } 
    close $fs 
  }
# the number of bots can be determined without this counter if you use one of the examples from my previous post
  if {$i <= 0} { 
    putserv "PRIVMSG $mainchanbots :\<\0032There are currently\003\0034\002 0 \002\003\0032bots logged in.\003\>" 
  } 
  if {$i > 0} { 
    putserv "PRIVMSG $mainchanbots :\<\0032There are currently\003\0034\002 $i \002\003\0032bot\(s\) logged in.\003\>" 
  }
# using a timer to delete the file doesn't make sense to me...why are you doing it?
  utimer 5 deletefile
  set fs [open bots.tmp r] 
    while {![eof $fs]} { 
     if {![gets $fs line]} {
# danger danger! :P by returning at this point you end up leaving the file channel open and eventually your interpreter will hang because of too many open files
       return 0
# you did this check when creating the file
     } elseif {[lindex $line 2] != $nowhere} {
# using 'lindex' on a string for the next 4 lines (will cause errors if your data contains special chars like [ and {)
       set displayname [lindex $line 0] 
       set botcharname [lindex $line 1] 
       set botloc [lindex $line 2] 
       set botact [lrange $line 3 end] 
# a little late to do this check now? :P
       if {$displayname == ""} { 
         close $fs 
         return 0 
       } 
        putserv "PRIVMSG $mainchanbots :\002$displayname\:\002 \(\0032$botcharname\003\) \0034$botloc\003 \(\0036$botact\003\)" 
      } 
    } 
  close $fs 
  return 0
}
I imagine one of my previous examples would gain a very similar result with HUGE cpu savings and no possible errors, so you should consider at least trying one of them :)
D
Darkj
Halfop
Posts: 86
Joined: Sun Jul 06, 2003 9:58 pm

Post by Darkj »

Code: Select all

  set fs [open bots.tmp r] 
    while {![eof $fs]} { 
     if {![gets $fs line]} { 
       return 0 
     } elseif {[lindex $line 2] != $nowhere} { 
       set displayname [lindex $line 0] 
       set botcharname [lindex $line 1] 
       set botloc [lindex $line 2] 
       set botact [lrange $line 3 end] 
How do I fix that so It doesn't leave the file open?
User avatar
user
&nbsp;
Posts: 1452
Joined: Tue Mar 18, 2003 9:58 pm
Location: Norway

Post by user »

Darkj wrote:How do I fix that so It doesn't leave the file open?
By closing it before you return :P

Here's a better while loop (doing the !eof check and reading in one call:

Code: Select all

while {[gets $fs line]>-1} {
  if {![string len $line]} continue
  # this makes it ignore empty lines and just skip to the next
  # but you don't need that as you create the file and don't write any
  # empty lines to it :)
  
  # insert the rest of your code here
}
D
Darkj
Halfop
Posts: 86
Joined: Sun Jul 06, 2003 9:58 pm

Post by Darkj »

Code: Select all

  set fs [open bots.tmp r]
   while {[gets $fs line]>-1} { 
      if {![string len $line]} continue;
       set displayname [lindex $line 0]
       set botcharname [lindex $line 1]
       set botloc [lindex $line 2]
       set botact [lrange $line 3 end]
       if {$displayname == ""} {
         close $fs
         return 0
       }
       putserv "PRIVMSG $mainchanbots :\002$displayname\:\002 \(\0032$botcharname\003\) \0034$botloc\003 \(\0036$botact\003\)"
       }
     close $fs
   } 
   return 0
}
Hows that?
D
Darkj
Halfop
Posts: 86
Joined: Sun Jul 06, 2003 9:58 pm

Post by Darkj »

i took that if {$displayname == $nowhere} statement out too
User avatar
user
&nbsp;
Posts: 1452
Joined: Tue Mar 18, 2003 9:58 pm
Location: Norway

Post by user »

get rid of the

Code: Select all

if {![string len $line]} continue
too as you don't need it (like I said before)

But why are you still insisting on writing/reading the file?
D
Darkj
Halfop
Posts: 86
Joined: Sun Jul 06, 2003 9:58 pm

Post by Darkj »

Basically I've changed the way I'm doing this

I'm pulling it out of the INI file and dumping in a tmp file, to make for easy formatting, then the bottom of the script is just outputting the file.

This bot is only used between 15-20 people on a private network, so I'm not too concerned with cpu etc.
User avatar
user
&nbsp;
Posts: 1452
Joined: Tue Mar 18, 2003 9:58 pm
Location: Norway

Post by user »

Darkj wrote:Basically I've changed the way I'm doing this

I'm pulling it out of the INI file and dumping in a tmp file, to make for easy formatting, then the bottom of the script is just outputting the file.

This bot is only used between 15-20 people on a private network, so I'm not too concerned with cpu etc.
But 'append'ing/'lappend'ing to a variable would be much easier...and the 3 examples I showed you earlier would just need color codes to be added to produce the exact same output. (saving alot of precious vertical space on your screen while debugging the code ,P)

Code: Select all

bind pub n !test test
proc test {nick uhost hand chan arg} {
	set defaults {charname none location none action none}
	array set a [parseIni your.ini]
	# plural ending (bot(s)) based on the number :P
	putserv "PRIVMSG $chan :There are currently [array size a] bot[expr {[array size a]!=1?"s":""}] logged in."
	foreach bot [lsort -dict [array names a]] {
	   array set b [concat $defaults $a($bot)]
	   putserv "PRIVMSG $chan :$bot: ($b(charname)) $b(location) ($b(action))"
	}
}
D
Darkj
Halfop
Posts: 86
Joined: Sun Jul 06, 2003 9:58 pm

Post by Darkj »

That worked perfectly, well, except the auto counter, but I fixed it up a bit. Thanks for the help user, just glad someone stuck with me even though it was prolly like talkin to a brick wall.

Anyways, thanks alot.

-Darkj
User avatar
user
&nbsp;
Posts: 1452
Joined: Tue Mar 18, 2003 9:58 pm
Location: Norway

Post by user »

Darkj wrote:That worked perfectly, well, except the auto counter.
Do you mean the grammatical errors in the line announcing the number of bots online or the fact that my code didn't subtract the bot(s) you're filtering out?

Here's some code to make the grammar easier:

Code: Select all

# plural proc...
proc plur {num {add s} {add2 ""}} {expr {$num!=1?$add:$add2}}

# test...
foreach i {0 1 32} {
	puts "There[plur $i " are" "'s"] currently $i bot[plur $i] online."
}
# result:
There are currently 0 bots online.
There's currently 1 bot online.
There are currently 32 bots online.
I'm glad you appreciate my suggestions :)
D
Darkj
Halfop
Posts: 86
Joined: Sun Jul 06, 2003 9:58 pm

Post by Darkj »

Code: Select all

proc parseIni {file} { 
   array set arr {} 
   set f [open $file] 
   while {[gets $f l]>-1} { 
      set l [string trim $l] 
      if {[string match {\[*\]} $l]} { 
         set e [string range $l 1 end-1]
      } elseif {[info exists e]&&[string match *?=?* $l]} { 
         regexp {^([^=]+)=(.+)$} $l a a b 
         lappend arr($e) [string trim $a] [string trim $b] 
      }
   } 
   close $f 
   array get arr 
} 
Is that code fine without return's etc? I think this may be a problem.
Locked