egghelp.org community Forum Index
[ egghelp.org home | forum home ]
egghelp.org community
Discussion of eggdrop bots, shell accounts and tcl scripts.
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Create variable name on the fly

 
Post new topic   Reply to topic    egghelp.org community Forum Index -> Scripting Help
View previous topic :: View next topic  
Author Message
willyw
Revered One


Joined: 15 Jan 2009
Posts: 1175

PostPosted: Sat Apr 04, 2009 3:11 pm    Post subject: Create variable name on the fly Reply with quote

Hello,

Is there a way to create a variable or array name, based on the nick of the user that called the proc that is using the variable or array?

Naming the new var nick-temp would be ok, as I intend to unset it at the end of the proc.

I must be overlooking something....


Thanks
Back to top
View user's profile Send private message
arfer
Master


Joined: 26 Nov 2004
Posts: 436
Location: Manchester, UK

PostPosted: Sat Apr 04, 2009 6:27 pm    Post subject: Reply with quote

You can create a variable with name equal to the value of another variable.

Say for example I set the value of the variable named testnick ($testnick) to arfer, then use it to create a variable named arfer (with value "my nick").

[23:23] <arfer> .tcl set testnick arfer
[23:23] <osmosis> Tcl: arfer
[23:24] <arfer> .tcl set $testnick "my nick"
[23:24] <osmosis> Tcl: my nick
[23:24] <arfer> .tcl set arfer
[23:24] <osmosis> Tcl: my nick

A new variable was created called arfer, with a value "my nick" as evidenced by the final set command above.
_________________
I must have had nothing to do
Back to top
View user's profile Send private message
speechles
Revered One


Joined: 26 Aug 2006
Posts: 1398
Location: emerald triangle, california (coastal redwoods)

PostPosted: Sat Apr 04, 2009 9:24 pm    Post subject: Reply with quote

Quote:
*** n is set to "jim"
<speechles> .set n "jim"
<sp33chy> Ok, set.

*** nick_jim is set to "beam"
<speechles> .set nick_$n "beam"
<sp33chy> Ok, set.

*** show the contents of new variable nick_jim
<speechles> .tcl set nick_jim
<sp33chy> Tcl: beam


setting an array, just use set arrayname($nick) "something"
_________________
speechles' eggdrop tcl archive
Back to top
View user's profile Send private message
willyw
Revered One


Joined: 15 Jan 2009
Posts: 1175

PostPosted: Sun Apr 05, 2009 4:33 pm    Post subject: Reply with quote

speechles wrote:
Quote:
*** n is set to "jim"
<speechles> .set n "jim"
<sp33chy> Ok, set.

*** nick_jim is set to "beam"
<speechles> .set nick_$n "beam"
<sp33chy> Ok, set.

*** show the contents of new variable nick_jim
<speechles> .tcl set nick_jim
<sp33chy> Tcl: beam




Thanks for replying.
I'm not there yet.

Based on your above, and that I want to create the variable based on the nick of the user calling it, I tried this:
Code:

bind pub - !test atest_proc

proc atest_proc {nick uhost handle chan text} {

set nick_$nick "beam"
putserv "privmsg $chan :  nick_$nick is set to $nick_$nick "
}

with great suspicion about what might happen with the last line.
But I didn't even get that far.
When I caused the proc to run, I get this in partyline:
Quote:

Tcl error [atest_proc]: can't read "nick_": no such variable


Next, just to be sure of typos, etc. , I tried this:
Code:

proc atest_proc {nick uhost handle chan text} {

set n "jim"
set nick_$n "beam"
putserv "privmsg $chan :  var named nick_$n is set to $nick_$n "
}

and still get
Quote:

Tcl error [atest_proc]: can't read "nick_": no such variable


Isn't that strange?... that it works from the command line, but not in a procedure?

What do you think?


Quote:

setting an array, just use set arrayname($nick) "something"


Wouldn't that just set an element within the array though?
I need the array name to be based on the nick somehow.


Thanks
Back to top
View user's profile Send private message
willyw
Revered One


Joined: 15 Jan 2009
Posts: 1175

PostPosted: Sun Apr 05, 2009 4:53 pm    Post subject: Reply with quote

arfer wrote:
You can create a variable with name equal to the value of another variable.

Say for example I set the value of the variable named testnick ($testnick) to arfer, then use it to create a variable named arfer (with value "my nick").

[23:23] <arfer> .tcl set testnick arfer
[23:23] <osmosis> Tcl: arfer
[23:24] <arfer> .tcl set $testnick "my nick"
[23:24] <osmosis> Tcl: my nick
[23:24] <arfer> .tcl set arfer
[23:24] <osmosis> Tcl: my nick

A new variable was created called arfer, with a value "my nick" as evidenced by the final set command above.



Not ignoring your post.
Thank you very much for replying too.
I'm still experimenting with this. I think I have a mental block or something as it is easy to lose my place when doing this.
Will let you know if I get it
Back to top
View user's profile Send private message
arfer
Master


Joined: 26 Nov 2004
Posts: 436
Location: Manchester, UK

PostPosted: Sun Apr 05, 2009 4:55 pm    Post subject: Reply with quote

It is the putserv statement that is causing the error, there is nothing wrong with the statement

set nick_$nick "beam"

Apart from it being rather horrendous code

Specifically, it is $nick_$nick that cannot be read. It is not even possible to enclose the name in braces ${nick_$nick} since this prevents the second $ from causing variable substitution.

I'm not sure if there is a solution to your specific method. I would urge you to reconsider what you are doing and why you are doing it. It is rather like having a variable name containing spaces, in that it generally leads to unnecessary difficulties somewhere down the line.

Code:

proc atest_proc {nick uhost handle chan text} {
set $nick "beam"
putserv "privmsg $chan :a variable named $nick has been created with value [subst $$nick]"
}


That code above ought to work but it's very messy. I am beginning to regret answering the original question because this is not something I would do.
_________________
I must have had nothing to do
Back to top
View user's profile Send private message
arfer
Master


Joined: 26 Nov 2004
Posts: 436
Location: Manchester, UK

PostPosted: Sun Apr 05, 2009 5:28 pm    Post subject: Reply with quote

Just to continue with the thread, the 'normal' way of creating a variable dynamically that is dependent on the value of another variable is to use arrays

So within the proc above

Code:

set ar($nick) "beam"


Much safer. The array named 'ar' now contains an element who's name is equal to the value of the variable named nick (ie. $nick), and this array element has a value "beam". It can be referrenced within the proc using $ar($nick).

Arrays also lend themselves to some very useful additional Tcl functions.

For example, if I knew an array element name contained the sequence of characters ARF but didn't know the exact nick it represented (element name) was arfer or the case was lower, I could find it using something like

Code:

set name [array names ar -regexp (?i)ARF]


Declare the array as global within the proc if you wish to use it elsewhere.
_________________
I must have had nothing to do
Back to top
View user's profile Send private message
nml375
Revered One


Joined: 04 Aug 2006
Posts: 2857

PostPosted: Sun Apr 05, 2009 6:44 pm    Post subject: Reply with quote

Just to clarify one thing, that has not been covered in the previous posts...

You are currently dealing with variables in local namespaces (within the procs). These do not persist inbetween invocations of the proc. What you need to do, is to store the data in a variable in a global namespace. There are a few ways of doing this, such as using the global command, or full namespace paths.

I'll give you a few examples, which also shows how to handle the issue described by arfer a few posts up...
Code:

bind pub - !test atest_proc

####### Use global command to link the localspace variable to the globalspace one...
proc atest_proc {nick uhost handle chan text} {
 global "nick_$nick"
 set nick_$nick "beam"
 putserv "privmsg $chan :nick_$nick is set to [set nick_$nick]"
}

####### Use full namespace path
proc atest_proc {nick uhost handle chan text} {
 set ::nick_$nick "beam"
 putserv "privmsg $chan :nick_$nick is set to [set ::nick_$nick]"
}

####### Use the upvar command to link the globalspace variable to "thenick"
proc atest_proc {nick uhost handle chan text} {
 upvar #0 nick_$nick thenick
 set thenick "beam"
 putserv "privmsg $chan :nick_$nick is set to $thenick"
}

####### Use full namespace path along with arrays
proc atest_proc {nick uhost handle chan text} {
 set ::nick_($nick) "beam"
 puserv "privmsg $chan :nick_($nick) is set to $nick_($nick)"
}

_________________
NML_375, idling at #eggdrop@IrcNET
Back to top
View user's profile Send private message
willyw
Revered One


Joined: 15 Jan 2009
Posts: 1175

PostPosted: Sun Apr 05, 2009 6:51 pm    Post subject: Reply with quote

arfer wrote:
It is the putserv statement that is causing the error, there is nothing wrong with the statement

set nick_$nick "beam"



Ah! so it WAS the last line that I suspected. Didn't realize the proc was running that far.

Quote:

Apart from it being rather horrendous code


It even looked odd to me. But I was just trying to make minimal changes and trying to watch results, at this point.

Quote:

Specifically, it is $nick_$nick that cannot be read. It is not even possible to enclose the name in braces ${nick_$nick} since this prevents the second $ from causing variable substitution.

I'm not sure if there is a solution to your specific method. I would urge you to reconsider what you are doing and why you are doing it. It is rather like having a variable name containing spaces, in that it generally leads to unnecessary difficulties somewhere down the line.



I'm getting the feeling that I might be going about trying to accomplish the chore with the wrong ideas right from the start.
I've sent you a pm, that hopefully explains it. I hope you don't mind - just didn't want to drag more ugly code out - yet.


Quote:

Code:

proc atest_proc {nick uhost handle chan text} {
set $nick "beam"
putserv "privmsg $chan :a variable named $nick has been created with value [subst $$nick]"
}


That code above ought to work but it's very messy. I am beginning to regret answering the original question because this is not something I would do.


This is new to me - the subst command. I've just been to the TCL online manual and looked it up, and I really don't 'get it' yet.
I text searched for $$ to and it was not on the page - I was hoping to find an example explaining the way you used it. It was not there. Sad
This has become a side note now - you've made me curious about it. If there is a better way to get my job done, hopefully you'll be able to point me towards it after reading that explanation.

Thanks
Back to top
View user's profile Send private message
willyw
Revered One


Joined: 15 Jan 2009
Posts: 1175

PostPosted: Sun Apr 05, 2009 6:54 pm    Post subject: Reply with quote

arfer wrote:
Just to continue with the thread, the 'normal' way of creating a variable dynamically that is dependent on the value of another variable is to use arrays

So within the proc above

Code:

set ar($nick) "beam"


Much safer. The array named 'ar' now contains an element who's name is equal to the value of the variable named nick (ie. $nick), and this array element has a value "beam". It can be referrenced within the proc using $ar($nick).

Arrays also lend themselves to some very useful additional Tcl functions.

For example, if I knew an array element name contained the sequence of characters ARF but didn't know the exact nick it represented (element name) was arfer or the case was lower, I could find it using something like

Code:

set name [array names ar -regexp (?i)ARF]


Declare the array as global within the proc if you wish to use it elsewhere.



I'd seen this somewhere, already. It won't work, for what I need... I need it the other way around - array name corresponding to nick. Already have all the elements.
Back to top
View user's profile Send private message
willyw
Revered One


Joined: 15 Jan 2009
Posts: 1175

PostPosted: Sun Apr 05, 2009 6:58 pm    Post subject: Reply with quote

nml375 wrote:
Just to clarify one thing, that has not been covered in the previous posts...

You are currently dealing with variables in local namespaces (within the procs). These do not persist inbetween invocations of the proc. What you need to do, ....


Why?

I don't need the variable outside the proc. Above, I'd said, "...as I intend to unset it at the end of the proc. " and now on second thought, that might not even be necessary. I hadn't thought of that.

And thank you for taking time to try to help.
Back to top
View user's profile Send private message
nml375
Revered One


Joined: 04 Aug 2006
Posts: 2857

PostPosted: Sun Apr 05, 2009 7:15 pm    Post subject: Reply with quote

willy,
Sorry, mis-read that line. No need for namespaces then.

The "[set nick_$nick]" approach of reading the variable should help you avoid the error of "can't read nick_: no such variable".
It might be possible to use the upvar trick with 0 level instead of #0, but I have not verified that.
_________________
NML_375, idling at #eggdrop@IrcNET
Back to top
View user's profile Send private message
arfer
Master


Joined: 26 Nov 2004
Posts: 436
Location: Manchester, UK

PostPosted: Sun Apr 05, 2009 7:22 pm    Post subject: Reply with quote

Subst is a command that is used to force variable, command or backslash substitution where it might otherwise fail to occur.

Take the following example :-

[00:15] <arfer> .tcl set a one
[00:15] <Baal> Tcl: one
[00:16] <arfer> .tcl set $a two
[00:16] <Baal> Tcl: two

[00:17] <arfer> .tcl set c $$a
[00:17] <Baal> Tcl: $one
[00:17] <arfer> .tcl set c [subst $$a]
[00:17] <Baal> Tcl: two

$$a resulted in an unexpected return value. Seemingly the innermost $ did not invoke substitution. This was forced by using subst command, yielding the expected result.
_________________
I must have had nothing to do
Back to top
View user's profile Send private message
willyw
Revered One


Joined: 15 Jan 2009
Posts: 1175

PostPosted: Sun Apr 05, 2009 7:31 pm    Post subject: Reply with quote

arfer wrote:
Subst is a command that is used to force variable, command or backslash substitution where it might otherwise fail to occur.

Take the following example :-

[00:15] <arfer> .tcl set a one
[00:15] <Baal> Tcl: one
[00:16] <arfer> .tcl set $a two
[00:16] <Baal> Tcl: two

[00:17] <arfer> .tcl set c $$a
[00:17] <Baal> Tcl: $one
[00:17] <arfer> .tcl set c [subst $$a]
[00:17] <Baal> Tcl: two

$$a resulted in an unexpected return value. Seemingly the innermost $ did not invoke substitution. This was forced by using subst command, yielding the expected result.


Thanks for the explanation. It still makes me do a double take though. Smile

When you get a free moment, please have a look at your pm inbox here, and let me know what you think of what I'm trying to do. Again, I suspect there is a better way, but I need direction to get on the right path.

Thanks
Back to top
View user's profile Send private message
arfer
Master


Joined: 26 Nov 2004
Posts: 436
Location: Manchester, UK

PostPosted: Sun Apr 05, 2009 11:07 pm    Post subject: Reply with quote

In pm, Willyw has asked me for help with code for a playback script. ie. a script that will remember the last few chat lines said on a channel and, if commanded to do so, will play back the lines by notice. In reality, this was the reason for the thread in the first place.

I thought that anybody following the thread may want to play around with and/or improve on the code, so I will paste it here.

Command syntax is !playback (bot flag o required).

Lines said by the bot (perhaps due to output from other scripts) are excluded as are !playback command lines.

The code below is preconfigured to recall the last 5 lines said in the channel #eggTCL.

Rehash/restart will clear the stored memory.

Code:

# *** configuration *** #

set vPlaybackMemory 5
set vPlaybackChannel #eggTCL

# *** code *** #

bind PUB o !playback pPlaybackOutput
bind PUBM - * pPlaybackStore

if {[info exists vPlaybackData]} {unset vPlaybackData}

proc pPlaybackOutput {nick uhost hand channel txt} {
    global vPlaybackData vPlaybackMemory
    for {set x 1} {$x <= $vPlaybackMemory} {incr x} {
        if {[info exists vPlaybackData($x)]} {puthelp "NOTICE $nick :$vPlaybackData($x)"}
    }
    return 0
}

proc pPlaybackPromote {nick channel} {
    if {[isop $nick $channel]} {
      return "<@$nick\>"
    } elseif {[isvoice $nick $channel]} {
      return "<+$nick\>"
    } else {return "<$nick\>"}
}

proc pPlaybackStore {nick uhost handle channel txt} {
    global vPlaybackChannel vPlaybackData vPlaybackMemory
    if {[string equal -nocase $channel $vPlaybackChannel]} {
        if {![string match "!playback*" $txt]} {
            if {![isbotnick $nick]} {
                for {set x 1} {$x < $vPlaybackMemory} {incr x} {
                    if {[info exists vPlaybackData([expr {$x + 1}])]} {set vPlaybackData($x) $vPlaybackData([expr {$x + 1}])}
                }
                set vPlaybackData($vPlaybackMemory) "[pPlaybackPromote $nick $channel] $txt"
            }
        }
    }
    return 0
}


If I were to expand on the script, it would be to include other types of channel activity in the memory. ie. joins/parts/actions/modes etc. Outputting the memory automatically onjoin would probably be mega annoying so I avoided doing that.
_________________
I must have had nothing to do
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    egghelp.org community Forum Index -> Scripting Help All times are GMT - 4 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Forum hosting provided by Reverse.net

Powered by phpBB © 2001, 2005 phpBB Group
subGreen style by ktauber