7 Commands: Tcl

This is the first part of the SMM++ command index. The commands described here aren't SMM++ commands in particular, but tcl commands, which were made accessible in the SMM++ parser (which is the tcl shell).

Note: Please, don't underestimate the importance of the commands described here! They build up the basis of all scripting: setting/unsetting variables/arrays/lists/strings, various control structures like if/switch/for, various string operations, definition of procedures and much more.

This section will only introduce the most important commands. Further more they will be introduced only very briefly to give you quickly a good overview and basic knowledge, so you can imediatly start scripting. This is the main intention of this chapter. The more you get used to the syntax and want to script more complicated scripts you should refer to the tcl man pages, which are included in the SMM++ documentation. At some point you should in any case have a look at them, as tcl is very powerful and there may be easy solutions for problems, you didn't thought they will be solvable at all. The tcl man pages can be found at Appendix B.

Note: Some commands offer depending on their arguments various ways of usage. The descriptions here may not include all possible ways of their usage. Again, please, refer to Appendix B.

In case of problems with tcl dont hesitate to post on the forum boards or in the mailing list. Others may have encountered the same problems, but for any reason didn't ask. So all would profit from your question.

7.1 Control

7.1.1 ::break

Abort a looping command

Syntax:

::break
Description:
::break
This command is typically invoked inside the body of a looping command such as for or foreach or while. The exception causes the current script to be aborted out to the innermost containing loop command, which then aborts its execution and returns normally.

Example:
    ::set i 0
    ::while {1} {
      ::incr i
      ::smm::showme "$i. loop,..."
      # the next command stops the loop, when i is equal to 10
      ::if {$i==10} { ::break }
    }

7.1.2 ::catch

Evaluate script and trap exceptional returns

Syntax:

::catch script ?varName?
Description:
::catch script ?varName?
The catch command may be used to prevent errors from aborting command interpretation. Catch calls the Tcl interpreter recursively to execute script, and always returns a TCL_OK code, regardless of any errors that might occur while executing script. The return value from catch is a decimal string giving the code returned by the Tcl interpreter after executing script. This will be 0 (TCL_OK) if there were no errors in script; otherwise it will have a non-zero value corresponding to one of the exceptional return codes (see tcl.h for the definitions of code values). If the varName argument is given, then it gives the name of a variable; catch will set the variable to the string returned from script (either a result or an error message).

Note that catch catches all exceptions, including those generated by break and continue as well as errors.

Example:
    ::if {[::catch {::smm::showme "value of a: $a"}]} {
      # The code here will be executed, if an error in the 
      # catched script/command occurs. Here in our case, 
      # this could happen, when no variable a is defined.
      ::smm::showme "There is no variable a defined"
    }

    # you can use catch also without the "if", if you just want
    # to prevent errors to be reported.
    ::catch {::smm::showme "value of a: $a"}

7.1.3 ::continue

Skip to the next iteration of a loop

Syntax:

::continue
Description:
::continue
This command is typically invoked inside the body of a looping command such as for or foreach or while. It causes the current script to be aborted out to the innermost containing loop command, which then continues with the next iteration of the loop.

Example:
    # loop from 0 to 9, just skip 5. loop
    ::for {::set i 0} {$i<10} {::incr i} {
      ::if {$i==5} { ::continue } 
      ::smm::showme "$i. loop,.."
    }

7.1.4 ::error

Generate an error

Syntax:

::error message
Description:
::error message
Raises an error, , which causes command interpretation to be unwound. Message is a string that is returned to the application to indicate what went wrong. Errors can be caught with the catch command in scripts.

Example:
    ::switch -- $pet {
      horse -
      donkey {
        ::tomud "mount $pet"
      }
      default {
        ::error "You cannot mount $pet."
      }
    }    

7.1.5 ::eval

Evaluate a Tcl script

Syntax:

::eval arg ?arg ...?
Description:
::eval arg ?arg ...?
Eval takes one or more arguments, which together comprise a Tcl script containing one or more commands. Eval concatenates all its arguments in the same fashion as the concat command, passes the concatenated string to the Tcl interpreter recursively, and returns the result of that evaluation (or any error generated by it).

Example:
    # this sets the variable a to 5
    ::set com "::set a 5"
    ::eval $com

7.1.6 ::exec

Invoke subprocess(es)

Syntax:

::exec arg ?arg ...?
Description:
::exec arg ?arg ...?
Concatenates all args, executes them in the system shell and returns their output. For more details about exec, please refer to the tcl manual.

Example:
    # this shows all current processes (linux)
    ::smm::showme "current processes:"
    ::smm::showme [::exec ps xau]

7.1.7 ::for

for loop.

Syntax:

::for start test next body
Description:
::for start test next body
For is a looping command, similar in structure to the C for statement.

Example:
    ::for {::set i 0} {$i<10} {::incr i} {
      ::smm::showme "$i. loop,.."
    }

7.1.8 ::foreach

Iterate over all elements in one list (or in more lists, pleae refer to the tcl manual).

Syntax:

::foreach varname list body
Description:
::foreach varname list body
An example makes it easily clear.

Example:
    # the following command
    ::foreach item {sword sword sword armor boots skin} {
      ::tomud "sell $item"
    }
    # sends
    #   sell sword
    #   sell sword
    #   sell sword
    #   sell armor
    #   sell boots
    #   sell skin
    # to the mud.

7.1.9 ::if

Execute scripts conditionally

Syntax:

::if expr1 ?then? body1 elseif expr2 ?then? body2 elseif ... ?else? ?bodyN?
Description:
::if expr1 ?then? body1 elseif expr2 ?then? body2 elseif ... ?else? ?bodyN?
The if command evaluates expr1 as an expression (in the same way that expr evaluates its argument). The value of the expression must be a boolean (a numeric value, where 0 is false and anything is true, or a string value such as true or yes for true and false or no for false); if it is true then body1 is executed by passing it to the Tcl interpreter. Otherwise expr2 is evaluated as an expression and if it is true then body2 is executed, and so on. If none of the expressions evaluates to true then bodyN is executed. The then and else arguments are optional ``noise words'' to make the command easier to read. There may be any number of elseif clauses, including zero. BodyN may also be omitted as long as else is omitted too. The return value from the command is the result of the body script that was executed, or an empty string if none of the expressions was non-zero and there was no bodyN.

Example:
    ::set q 0
    ::if {$q!=0} {
      ::set a [expr 3/$q]
    }

    ::if {1<2} {
      ::smm::showme "1 is smaller"
    } else {
      ::smm::showme "2 is smaller"
    }

    set q 0
    set p 0
    ::if {$q!=0} {
      ::set a [::expr $p/$q]
    } elseif {$p!=0} {
      ::set a [::expr $q/$p]
    } else {
      ::set a 1
    }

    # the last example can be also written as:
    ::set a [::if {$q!=0} { 
               ::expr $p/$q 
             } elseif {$p!=0} {
               ::expr $q/$p
             } else {
               1
             }]

7.1.10 ::proc

Create a Tcl procedure.

Note: This is one of the most important commands for you. It holds the place of the classical "alias" command. The description here is quite lengthly, but as proc is a command of major importance, please, try to understand as much as possible. The examples should make quite a lot things clear; may be you want to have a look at them in parallel.

Syntax:

::proc name args body
Description:
::proc name args body
The proc command creates a new Tcl procedure named name, replacing any existing command or procedure there may have been by that name. Whenever the new command is invoked, the contents of body will be executed by the Tcl interpreter. Args specifies the formal arguments to the procedure. It consists of a list, possibly empty, each of whose elements specifies one argument. Each argument specifier is also a list with either one or two fields. If there is only a single field in the specifier then it is the name of the argument; if there are two fields, then the first is the argument name and the second is its default value.

When name is invoked a local variable will be created for each of the formal arguments to the procedure; its value will be the value of corresponding argument in the invoking command or the argument's default value. Arguments with default values need not be specified in a procedure invocation. However, there must be enough actual arguments for all the formal arguments that don't have defaults, and there must not be any extra actual arguments. There is one special case to permit procedures with variable numbers of arguments. If the last formal argument has the name args, then a call to the procedure may contain more actual arguments than the procedure has formals. In this case, all of the actual arguments starting at the one that would be assigned to args are combined into a list (as if the list command had been used); this combined value is assigned to the local variable args.

When body is being executed, variable names normally refer to local variables, which are created automatically when referenced and deleted when the procedure returns. One local variable is automatically created for each of the procedure's arguments. Global variables can only be accessed by invoking the global command.

The proc command returns an empty string. When a procedure is invoked, the procedure's return value is the value specified in a return command. If the procedure doesn't execute an explicit return, then its return value is the value of the last command executed in the procedure's body. If an error occurs while executing the procedure body, then the procedure-as-a-whole will return that same error.

Example:
    # define a proc with no arguments
    ::proc ga {} { ::tomud "get all" }
    # every time you type 'ga' 'get all' is send to the mud.
    # there is also a shorter version
    ::proc ga {} {get all}

    # define a proc with one argument
    ::proc mm {aTarget} { ::tomud "cast magic missle $aTarget" }
    # e.g.: mm gnome

    # define a proc with 2 arguments
    ::proc gt {aWhat aWhome} {
      ::tomud "get $aWhat from backpack"
      ::tomud "give $aWhat to $aWhome" 
    }
    # e.g.: gt torch fred

    # define the same proc above with a default
    # parameter;lets say Barnie is your best friend
    ::proc gt {aWhat {aWhome "Barnie"}} {
      ::tomud "get $aWhat from backpack"
      ::tomud "give $aWhat to $aWhome" 
    }
    # e.g.: gt torch fred
    # would still give the torch to fred
    # but: gt torch
    # would give the torch to barnie

    # define a proc with  variable number of arguments
    ::proc powersell {args} {
      # args is a list (probably emtpy)
      ::foreach item $args {
        ::tomud "get $item from backpack"
        ::tomud "sell $item"
      }
    }
    # e.g.: powersell sword sword armor torch
    # or:   powersell skin boots

    # define a proc with required and default arguments
    ::proc pgt {aWhome args} {
      # args is a list (probably emtpy)
      # args must always be the last argument
      ::foreach item $args {
        ::tomud "get $item from backpack"
        ::tomud "give $item to $aWhome" 
      }
    }

    # proc using global variables
    # e.g. lets say a global variable 'hp' holds your current
    # number of health points
    ::proc savekill {aTarget} {
      ::variable hp
      ::if {$hp<30} {
        ::smm::showme "Not enough hp!"
        ::return ; # this stops the procedure here
                   # you can also consider raising an error here!
                   #
                   # lets say savekill is used within another proc.
                   # With return all commands after savekill would
                   #  still be executed!
                   # With error they wouldnt. Script execution 
                   #  would be stopped.
      }
      ::tomud "kill $aTarget"
    }

    # proc with return value
    # lets say the global variable 'exp' holds your 
    #   current experience points
    # and the global variable 'expLevel' holds the number of
    #   experience point needed for the next level
    ::proc expneeded {} {
      ::variable exp, expLevel
      ::return [::expr $expLevel - exp]
    }
    # e.g.: ::smm::showme "For next level you need [expneeded] exp."

7.1.11 ::rename

Rename or delete a command/proc/alias

Note: If you dont really understand how the tcl shell works and are unlucky you can build actions for commands, that can destroy parts of your system; e.g. delete files. If you know, that you dont need system or file access, you should delete the commands ::exec, ::file and ::socket. They give you access to your system resources.

Syntax:

::rename oldName newName
Description:
::rename oldName newName
Rename the command that used to be called oldName so that it is now called newName. If newName is an empty string then oldName is deleted. The rename command returns an empty string as result.

Example:
    # delete exec and file command
    ::rename ::exec {}
    ::rename ::file {}

    ::proc ga {} { ::tomud "get all" }
    # if you are even to lazy to type 'ga':
    :rename ga g

7.1.12 ::return

Return from a procedure

Syntax:

::return ?string?
Description:
::return ?string?
Returns directly from a procedure and the return value of the procedure will be string. If no string is specified it will be the empty string.

Example:
    # this procedure always returns 1
    ::proc ret1 {} {
      ::return 1
    }

7.1.13 ::switch

Evaluate one of several scripts, depending on a given value

Note: I put this note here, as you might have some C background and expect switch to be fast. In fact switch is one of the slowest tcl commands. It becomes slower the larger the switch is. You shouldn't hesitate to use switch statements whenever you them, but you should know at least.

Syntax:

::switch ?options? string {pattern body ?pattern body ...?}
Description:
::switch ?options? string {pattern body ?pattern body ...?}
The switch command matches its string argument against each of the pattern arguments in order. As soon as it finds a pattern that matches string it evaluates the following body argument by passing it recursively to the Tcl interpreter and returns the result of that evaluation. If the last pattern argument is default then it matches anything. If no pattern argument matches string and no default is given, then the switch command returns an empty string.

If the initial arguments to switch start with - then they are treated as options. The following options are currently supported:

-exact Use exact matching when comparing string to a pattern. This is the default.
-glob When matching string to the patterns, use glob-style matching (i.e. the same as implemented by the string match command).
-regexp When matching string to the patterns, use regular expression matching (i.e. the same as implemented by the regexp command).
-- Marks the end of options. The argument following this one will be treated as string even if it starts with a -.
If a body is specified as ``-'', it means that the body for the next pattern should also be used as the body for this pattern (if the next pattern also has a body of ``-'' then the body after this is used, and so on). This feature makes it possible to share a single body among several patterns.

Example:
    ::switch abc {
      a - b {::format 1} 
      abc   {::format 2} 
      default {::format 3}
    }
    # will return 2, 

    ::switch -regexp aaab {
      ^a.*b$ -
      b         {::format 1}
      a*        {::format 2}
      default   {::format 3}
    }
    # will return 1, and 

    ::switch xyz {
      a
        -
      b
        {::format 1}
      a*
        {::format 2}
      default
        {::format 3}
    }
    # will return 3. 

    # instead of returning a value and using it, you can 
    # just invoke other commands and dont care about 
    # the return value
    ::set target "Dumbo"
    ::switch -exact -- $target {
      Bambi -
      Dumbo {
        ::tomud "kill $target"
      }
      "Elite Guard" -
      Dragon {
        ::tomud "flee"
      }
      default {
        ::tomud "look at $target"
      }
    }

7.1.14 ::while

Execute script repeatedly as long as a condition is met

Syntax:

::while test body
Description:
::while test body
The while command evaluates test as an expression (in the same way that expr evaluates its argument). The value of the expression must a proper boolean value; if it is a true value then body is executed by passing it to the Tcl interpreter. Once body has been executed then test is evaluated again, and the process repeats until eventually test evaluates to a false boolean value. Continue commands may be executed inside body to terminate the current iteration of the loop, and break commands may be executed inside body to cause immediate termination of the while command. The while command always returns an empty string.

Note: test should almost always be enclosed in braces. If not, variable substitutions will be made before the while command starts executing, which means that variable changes made by the loop body will not be considered in the expression. This is likely to result in an infinite loop. If test is enclosed in braces, variable substitutions are delayed until the expression is evaluated (before each loop iteration), so changes in the variables will be visible. For an example, try the following script with and without the braces around $x<10:

Example:
    ::set x 0
    ::while {$x<10} {
      ::smm::showme "x is $x"
      ::incr x
    }

7.2 Variables

7.2.1 ::array

Manipulate/query array variables

Syntax:

::array exists arrayName
::array names arrayName ?pattern?
::array size arrayName
Description:
::array exists arrayName
Returns 1 if arrayName is an array variable, 0 if there is no variable by that name or if it is a scalar variable.
::array names arrayName ?pattern?
Returns a list containing the names of all of the elements in the array that match pattern (using the glob-style matching rules of string match). If pattern is omitted then the command returns all of the element names in the array. If there are no (matching) elements in the array, or if arrayName isn't the name of an array variable, then an empty string is returned.
::array size arrayName
Returns a decimal string giving the number of elements in the array. If arrayName isn't the name of an array then 0 is returned.

Example:
    # build an array
    ::set cost(jacket) "3 gold"
    ::set cost(sword)  "1 platin"
    ::set cost(bread)  "3 copper"
    # show all known costs
    ::if {[::array exists cost]} {
      ::foreach item [::array names cost] {
        ::smm::showme "$item costs $cost($item)."
      }
    }

7.2.2 ::global

Access global variables

Note: Usually you shouldn't use global, but variable (see below please).

Syntax:

::global varname ?varname ...?
Description:
::global varname ?varname ...?
This command is ignored unless a Tcl procedure is being interpreted. If so then it declares the given varname's to be global variables rather than local ones. Global variables are variables in the global namespace. For the duration of the current procedure (and only while executing in the current procedure), any reference to any of the varnames will refer to the global variable by the same name.

Example:
    ::global a
    ::set a 5
    ::proc f1 {} { 
      # this will cause an error, because in this
      # procedure no variable a is known.
      ::incr a
    }
    ::proc f2 {} { 
      ::global a
      # this is ok, as the variable a is the 
      # one set to 5 (see above).
      ::incr a
    }

7.2.3 ::info

Return information about the state of the Tcl interpreter. There is more to know about the info command; please, refer to the tcl manal pages.

Syntax:

::info exists varName
::info globals ?pattern?
::info procs ?pattern?
::info vars ?pattern?
Description:
::info exists varName
Returns 1 if the variable named varName exists in the current context (either as a global or local variable), returns 0 otherwise.
::info globals ?pattern?
If pattern isn't specified, returns a list of all the names of currently-defined global variables. Global variables are variables in the global namespace. If pattern is specified, only those names matching pattern are returned. Matching is determined using the same rules as for string match.
::info procs ?pattern?
If pattern isn't specified, returns a list of all the names of Tcl command procedures in the current namespace. If pattern is specified, only those procedure names in the current namespace matching pattern are returned. Matching is determined using the same rules as for string match.
::info vars ?pattern?
If pattern isn't specified, returns a list of all the names of currently-visible variables. This includes locals and currently-visible globals. If pattern is specified, only those names matching pattern are returned. Matching is determined using the same rules as for string match.

Example:
    ::set a 1
    ::if {[::info exists a]} {
      ::smm::showme "variable a exists."
    } else {
      ::smm::showme "variable a doesn't exist."
    }

    # one can also query array variables 
    # (not the arrays themself; for quering arrays
    #  please refer to the array command).
    ::set b(3) 1
    ::if {[::info exists b(3)]} {
      ::smm::showme "variable b(3) exists."
    } else {
      ::smm::showme "variable b(3) doesn't exist."
    }    

7.2.4 ::set

Read and write variables

Syntax:

::set varName ?value?
Description:
::set varName ?value?
Returns the value of variable varName. If value is specified, then set the value of varName to value, creating a new variable if one doesn't already exist, and return its value. If varName contains an open parenthesis and ends with a close parenthesis, then it refers to an array element: the characters before the first open parenthesis are the name of the array, and the characters between the parentheses are the index within the array. Otherwise varName refers to a scalar variable.

Example:
    # variables can be numbers or strings
    ::set a 5
    ::set b "Road to Nowhere"
    
    # arrays
    ::set array(1) 5
    ::set array(2) 34

    # array indices may be strings (in principal they always are)
    ::set array(sword) 23

    # tcl arrays are always 1 dimensional, but one can easily 
    #  simulate 2d behaviour
    ::set array(1,1) 24
    ::set array(1,2) 29

    # btw:
    ::set array(1) 5
    ::set array( 1) 23
    # are different variables; 
    # remember? arrays always have string indices

7.2.5 ::unset

Delete variables

Syntax:

::unset name ?name name ...?
Description:
::unset name ?name name ...?
This command removes one or more variables. Each name is a variable name, specified in any of the ways acceptable to the set command. If a name refers to an element of an array then that element is removed without affecting the rest of the array. If a name consists of an array name with no parenthesized index, then the entire array is deleted. The unset command returns an empty string as result. An error occurs if any of the variables doesn't exist, and any variables after the non-existent one are not deleted.

Example:
    # deletes one variable
    ::unset a
    # deletes the variables a, b and c
    ::unset a b c
    # deletes one element from the array
    ::unset array(index)
    # deletes the entire array
    ::unset array

7.2.6 ::variable

create and initialize a variable

Syntax:

::variable name
Description:
::variable name
Use this command to link a variable within a procedure with a global variable. (In reality variable doesnt link to global variables in tcl-sense, but feel free to think so. The variable command is closely related to namespaces)

Example:
    ::set a 5
    ::proc showA {} {
      ::variable a 
      ::smm::showme "Value of a: $a"
    }

7.3 Lists

7.3.1 ::concat

Join lists together

Syntax:

::concat ?arg arg ...?
Description:
::concat ?arg arg ...?
This command treats each argument as a list and concatenates them into a single list. It also eliminates leading and trailing spaces in the arg's and adds a single separator space between arg's. It permits any number of arguments. If no args are supplied, the result is an empty string.

Example:
    # For example, the command 
    ::concat a b {c d e} {f {g h}}
    # will return 
    # a b c d e f {g h}
    # as its result. 

7.3.2 ::join

Create a string by joining together list elements

Syntax:

::join list ?joinString?
Description:
::join list ?joinString?
The list argument must be a valid Tcl list. This command returns the string formed by joining all of the elements of list together with joinString separating each adjacent pair of elements. The joinString argument defaults to a space character.

Example:
    ::set mylist fred barney wilma
    ::set myliststring [::join $mylist --]
    # myliststring has now the following content:
    #  fred--barney--wilma

7.3.3 ::lappend

Append list elements onto a variable

Syntax:

::lappend varName ?value value value ...?
Description:
::lappend varName ?value value value ...?
This command treats the variable given by varName as a list and appends each of the value arguments to that list as a separate element, with spaces between elements. If varName doesn't exist, it is created as a list with elements given by the value arguments. Lappend is similar to append except that the values are appended as list elements rather than raw text.

Example:
    ::set mylist [::list a]
    ::lappend mylist b
    ::lappend mylist c

7.3.4 ::lindex

Retrieve an element from a list

Syntax:

::lindex list index
Description:
::lindex list index
This command treats list as a Tcl list and returns the index'th element from it (0 refers to the first element of the list). In extracting the element, lindex observes the same rules concerning braces and quotes and backslashes as the Tcl command interpreter; however, variable substitution and command substitution do not occur. If index is negative or greater than or equal to the number of elements in value, then an empty string is returned. If index has the value end, it refers to the last element in the list.

Example:
    ::set mylist [::list a b c d e]
    ::set itemFirst [::lindex $mylist 0]
    ::set item2     [::lindex $mylist 1]
    ::set itemEnd   [::lindex $mylist end]

7.3.5 ::linsert

Insert elements into a list

Syntax:

::linsert list index element ?element element ...?
Description:
::linsert list index element ?element element ...?
This command produces a new list from list by inserting all of the element arguments just before the indexth element of list. Each element argument will become a separate element of the new list. If index is less than or equal to zero, then the new elements are inserted at the beginning of the list. If index has the value end, or if it is greater than or equal to the number of elements in the list, then the new elements are appended to the list.

Example:
    ::set mylist [::list a b c d e]
    ::set list2 [::linsert $list 1 X Y]
    # list2 is now: a X Y b c d e

7.3.6 ::list

Create a list

Syntax:

::list ?arg arg ...?
Description:
::list ?arg arg ...?
This command returns a list comprised of all the args, or an empty string if no args are specified. Braces and backslashes get added as necessary, so that the index command may be used on the result to re-extract the original arguments, and also so that eval may be used to execute the resulting list.

Example:
    ::set emptyList [::list]
    ::set someList  [::list a b c]

7.3.7 ::llength

Count the number of elements in a list

Syntax:

::llength list
Description:
::llength list
Treats list as a list and returns a decimal string giving the number of elements in it.

Example:
    ::set mylist [::list a b c]
    ::set n [::llength $mylist]

7.3.8 ::lrange

Return one or more adjacent elements from a list

Syntax:

::lrange list first last
Description:
::lrange list first last
List must be a valid Tcl list. This command will return a new list consisting of elements first through last, inclusive. First or last may be end (or any abbreviation of it) to refer to the last element of the list.

Example:
    ::set mylist [::list a b c d e f]
    ::set mysublist [::lrange $mylist 2 4]
    # mysublist will be: c d e

7.3.9 ::lreplace

Replace elements in a list with new elements

Syntax:

::lreplace list first last ?element element ...?
Description:
::lreplace list first last ?element element ...?
lreplace returns a new list formed by replacing one or more elements of list with the element arguments. First gives the index in list of the first element to be replaced (0 refers to the first element). If first is less than zero then it refers to the first element of list; the element indicated by first must exist in the list. Last gives the index in list of the last element to be replaced. If last is less than first then no elements are deleted; the new elements are simply inserted before first. First or last may be end (or any abbreviation of it) to refer to the last element of the list. The element arguments specify zero or more new arguments to be added to the list in place of those that were deleted. Each element argument will become a separate element of the list. If no element arguments are specified, then the elements between first and last are simply deleted.

Example:
    ::set mylist [::list a b c d e f g h]
    # remove element 'c' from list
    ::set mylist [::lreplace $mylist 2 2]
    # mylist is now: a b d e f g h
    # replace the elements 'd', 'e' and 'f' 
    #  by the elements 'V', 'W', 'X', 'Y' and 'Z'
    ::set mylist [::lreplace $mylist 2 4 V W X Y Z]
    # mylist is now: a b V W X Y Z g h

7.3.10 ::lsearch

See if a list contains a particular element

Syntax:

::lsearch ?mode? list pattern
Description:
::lsearch ?mode? list pattern
This command searches the elements of list to see if one of them matches pattern. If so, the command returns the index of the first matching element. If not, the command returns -1. The mode argument indicates how the elements of the list are to be matched against pattern and it must have one of the following values:
-exact
The list element must contain exactly the same string as pattern.
-glob
Pattern is a glob-style pattern which is matched against each list element using the same rules as the string match command.
-regexp
Pattern is treated as a regular expression and matched against each list element using the same rules as the regexp command.
If mode is omitted then it defaults to -glob.

Example:
    ::set mylist [::list a1 a2 a3 b1 b2 b3]

    # search for exactly an element
    ::set index  [::lsearch -exact $mylist b2]
    ::if {$index<0} {
      ::smm:showme "mylist doesnt contain element b2"
    } 
    
    # search for an element that start with 'b'
    ::set index  [::lsearch $mylist b*]
    ::if {$index<0} {
      ::smm:showme "mylist doesnt contain searched element."
    } else {
      ::set elem [::lindex $mylist $index]
      ::smm:showme "element found: $elem"
    }

7.3.11 ::lsort

Sort the elements of a list. For more detailed information, please refer to the tcl manual pages.

Syntax:

::lsort ?options? list
Description:
::lsort ?options? list
This command sorts the elements of list, returning a new list in sorted order. By default ASCII sorting is used with the result returned in increasing order. However, any of the following options may be specified before list to control the sorting process (unique abbreviations are accepted):
-ascii
Use string comparison with ASCII collation order. This is the default.
-integer
Convert list elements to integers and use integer comparison.
-real
Convert list elements to floating-point values and use floating comparison.
-increasing
Sort the list in increasing order (``smallest'' items first). This is the default.
-decreasing
Sort the list in decreasing order (``largest'' items first).

Example:
    ::set mylist [::list g d a c e f b]
    ::smm::showme "unsorted list: $mylist"
    ::smm::showme "sorted list:   [::lsort $mylist]"

7.3.12 ::split

Split a string into a proper Tcl list

Syntax:

::split string ?splitChars?
Description:
::split string ?splitChars?
Returns a list created by splitting string at each character that is in the splitChars argument. Each element of the result list will consist of the characters from string that lie between instances of the characters in splitChars. Empty list elements will be generated if string contains adjacent characters in splitChars, or if the first or last character of string is in splitChars. If splitChars is an empty string then each character of string becomes a separate element of the result list. SplitChars defaults to the standard white-space characters.

Example:
    ::split "comp.unix.misc" .
    # returns "comp unix misc"

    ::split "Hello world" {}
    # returns "H e l l o { } w o r l d". 

7.4 Strings

7.4.1 ::append

Append to variable

Syntax:

::append varName ?value value value ...?
Description:
::append varName ?value value value ...?
Append all of the value arguments to the current value of variable varName. If varName doesn't exist, it is given a value equal to the concatenation of all the value arguments. This command provides an efficient way to build up long variables incrementally. For example, ``append a $b'' is much more efficient than ``set a $a$b'' if $a is long.

Example:
    ::set a ab     ; # variable a is set to 'ab'
    ::append a cd   ; # variable a is now 'abcd'

7.4.2 ::format

Format a string in the style of sprintf

Syntax:

::format formatString ?arg arg ...?
Description:
::format formatString ?arg arg ...?
This command generates a formatted string in the same way as the ANSI C sprintf procedure (it uses sprintf in its implementation). FormatString indicates how to format the result, using % conversion specifiers as in sprintf, and the additional arguments, if any, provide values to be substituted into the result. The return value from format is the formatted string. For more information, please refer to the tcl manual.

Example:
    ::smm::showme [::format "%5.3f" 3.2]

7.4.3 ::regexp

Match a regular expression against a string. Determines whether the regular expression exp matches part or all of string and returns 1 if it does, 0 if it doesn't. Regular expressions may seem complicated at first sight, but there is nothing more powerful than them.

Syntax:

::regexp ?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...?
Description:
::regexp ?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...?
As I dont want to repeat the regexp manual page, I'll be very brief here. You should really read the regexp manual page.

The only thing I want to say about regular expressions here is to list its special characters. Please follow the examples too, I hope they will make lots of things clear.

\ shields the following character; that means the character following a '\' looses its special meaning.
any single chacter matches exactly this character (a single character is one possibility of an atom)
. matches any character (a '.' is one possibility of an atom)
[chars] Matches any character in the set given by chars. If a sequence of the form x-y appears in chars, then any character between x and y, inclusive, will match. If the chars start with '^' the set of character will be an anti-set. (a character set is an atom too)
( starts a submatch. (a submatch is one possibility of an atom)
) ends a submatch
| separates branches of regular expressions
* matches 0 or more atoms
+ matches 1 or more atoms
? matches 0 or 1 atom
^ means the start of line
$ means the end of line

Example:
    # lets say the variable aStr holds a string

    # usually one uses regexp within an if-statement
    ::if {[::regexp {abc} $aStr]} {
      # do something
    }

    # search for an exact string
    ::regexp {Bambi} $aStr
    ::regexp {Dumbo} $aStr

    # searching for exits (e.g. an automapper implementation)
    # assume, that the exits are sometimes displayed as
    # "-North" and sometimes as "-north" and sometimes as 
    # "-N" and sometimes as "-n"
    # So provide 4 if/regexps to detect this
    ::if {[::regexp {-North} $aStr]} { do something }
    ::if {[::regexp {-north} $aStr]} { do something }
    ::if {[::regexp {-N}     $aStr]} { do something }
    ::if {[::regexp {-n}     $aStr]} { do something }

    # a more efficient and straight on forward implementation
    ::if {[::regexp {-North|-north|-N|-n} $aStr]} { 
      do something 
    }
    # the '|' means or: either match the one or the other 
    #  or the other or the other regular expression

    # if you want to know which one has matched, provide an
    # variable (name 'a'), that will hold what has matched.
    ::if {[::regexp {-North|-north|-N|-n} $aStr a]} { 
      ::smm::showme "$a"
      # a will be either -North, -north, -N or -n
      do something else 
    }


    # ok, now we dense all even more, first we just put two and two
    # expression together:
    ::if {[::regexp {-[nN]orth|-[nN]} $aStr]} { do something }
    # [nN] means a single character (atom) either being a 'n'
    #   or a 'N'
    # BTW: [0-9] means just numbers, [a-z] just lower letters, 
    #   [A-Z] just capital letters, [0-9a-zA-Z] alpha numeric 
    #   characters only

    # and now at last we dense it all together
    ::if {[::regexp {-[nN](orth)?} $aStr]} { do something }
    # the (..) is a submatch (remember: submatches are atoms!)
    #   and the '?' requires 0 or 1 times the atom.

    # ok,.. there is still a bug in it:
    # the expressions above will also match a string like:
    # Dumbo says "------no------"
    # the "-n" match will match it,.. so we will also require a 
    #   space at the end of the match
    ::if {[::regexp {-[nN](orth)? } { do something }


    # using machting variables
    # just one simple example, which will make everything clear 
    # hopefully,..
    ::if {[::regexp {^(.*) tells you "(.*)"$} $aStr dummy who what]} {
      ::tomud "tell $who Dont tell me '$what'!!!"
    }
    # remember the '.' means any character and the '*' mean as 
    # many as matches (till the ' tells you') and the '()'
    # groups them into a submatch, so you get the result back in 
    # a variable. 
    # The '^' means start of string and '$' means end of string.

7.4.4 ::regsub

Perform substitutions based on regular expression pattern matching. There is more information about regsub in the tcl manual pages.

Syntax:

::regsub ?switches? exp string subSpec varName
Description:
::regsub ?switches? exp string subSpec varName
This command matches the regular expression exp against string, and it copies string to the variable whose name is given by varName. If there is a match, then while copying string to varName the portion of string that matched exp is replaced with subSpec. If the initial arguments to regexp start with - then they are treated as switches. The following switches are currently supported:
-all
All ranges in string that match exp are found and substitution is performed for each of these ranges. Without this switch only the first matching range is found and substituted. If -all is specified, then ``&'' and ``\n'' sequences are handled for each substitution using the information from the corresponding match.
-nocase
Upper-case characters in string will be converted to lower-case before matching against exp; however, substitutions specified by subSpec use the original unconverted form of string.
--
Marks the end of switches. The argument following this one will be treated as exp even if it starts with a -.
The command returns a count of the number of matching ranges that were found and replaced. See the manual entry for regexp for details on the interpretation of regular expressions.

Example:
    ::set aStr "This is an expamle string."
    ::regsub {is} $aStr {**IS**} a
    # variable a will be: "Th**IS** is an expamle string."
    ::regsub -all {is} $aStr {**IS**} a
    # variable a will be: "Th**IS** **IS** an expamle string."

7.4.5 ::scan

Parse string using conversion specifiers in the style of sscanf

Syntax:

::scan string format varName ?varName ...?
Description:
::scan string format varName ?varName ...?
This command parses fields from an input string in the same fashion as the ANSI C sscanf procedure and returns a count of the number of conversions performed, or -1 if the end of the input string is reached before any conversions have been performed. String gives the input to be parsed and format indicates how to parse it, using % conversion specifiers as in sscanf. Each varName gives the name of a variable; when a field is scanned from string the result is converted back into a string and assigned to the corresponding variable. For more information please refer to the tcl manual pages.

Example:
    ::set line "Dumbo offers you 5 gold"
    ::scan $line {%s %s %s %d} who dummy1 dummy2 amount
    ::if {$amount<10} {
      ::tomud "tell $who $amount is to less!
    } else {
      ::tomud "tell $who ok!
    }

7.4.6 ::string

Manipulate strings

Syntax:

::string compare string1 string2
::string first string1 string2
::string index string charIndex
::string last string1 string2
::string length string
::string match pattern string
::string range string first last
::string tolower string
::string toupper string
::string trim string ?chars?
::string trimleft string ?chars?
::string trimright string ?chars?
::string wordend string index
::string wordstart string index
Description:
::string compare string1 string2
Perform a character-by-character comparison of strings string1 and string2 in the same way as the C strcmp procedure. Return -1, 0, or 1, depending on whether string1 is lexicographically less than, equal to, or greater than string2.
::string first string1 string2
Search string2 for a sequence of characters that exactly match the characters in string1. If found, return the index of the first character in the first such match within string2. If not found, return -1.
::string index string charIndex
Returns the charIndex'th character of the string argument. A charIndex of 0 corresponds to the first character of the string. If charIndex is less than 0 or greater than or equal to the length of the string then an empty string is returned.
::string last string1 string2
Search string2 for a sequence of characters that exactly match the characters in string1. If found, return the index of the first character in the last such match within string2. If there is no match, then return -1.
::string length string
Returns a decimal string giving the number of characters in string.
::string match pattern string
See if pattern matches string; return 1 if it does, 0 if it doesn't. Matching is done in a fashion similar to that used by the C-shell. For the two strings to match, their contents must be identical except that the following special sequences may appear in pattern:
* Matches any sequence of characters in string, including a null string.
? Matches any single character in string.
[chars] Matches any character in the set given by chars. If a sequence of the form x-y appears in chars, then any character between x and y, inclusive, will match.
\x Matches the single character x. This provides a way of avoiding the special interpretation of the characters *?[]\ in pattern.
::string range string first last
Returns a range of consecutive characters from string, starting with the character whose index is first and ending with the character whose index is last. An index of 0 refers to the first character of the string. An index of end (or any abbreviation of it) refers to the last character of the string. If first is less than zero then it is treated as if it were zero, and if last is greater than or equal to the length of the string then it is treated as if it were end. If first is greater than last then an empty string is returned.
::string tolower string
Returns a value equal to string except that all upper case letters have been converted to lower case.
::string toupper string
Returns a value equal to string except that all lower case letters have been converted to upper case.
::string trim string ?chars?
Returns a value equal to string except that any leading or trailing characters from the set given by chars are removed. If chars is not specified then white space is removed (spaces, tabs, newlines, and carriage returns).
::string trimleft string ?chars?
Returns a value equal to string except that any leading characters from the set given by chars are removed. If chars is not specified then white space is removed (spaces, tabs, newlines, and carriage returns).
::string trimright string ?chars?
Returns a value equal to string except that any trailing characters from the set given by chars are removed. If chars is not specified then white space is removed (spaces, tabs, newlines, and carriage returns).
::string wordend string index
Returns the index of the character just after the last one in the word containing character index of string. A word is considered to be any contiguous range of alphanumeric or underscore characters, or any single character other than these.
::string wordstart string index
Returns the index of the first character in the word containing character index of string. A word is considered to be any contiguous range of alphanumeric or underscore characters, or any single character other than these.

Example:
    ::set a "Hey, Dumbo!"

    # strike all characters
    ::smm::showme [::string toupper $a]

    # check if string contains Dumbo
    ::if {[::string match {*Dumbo*} $a]} {
      ::smm::showme "Ahh,.. a Dumbo string."
    }

7.5 Math

7.5.1 ::expr

Evaluate an (mathematical) expression.

Syntax:

::expr arg ?arg arg ...?
Description:
::expr arg ?arg arg ...?
Concatenates all args and executes the expression. This is the handle for you to calculate mathematical expressions. I urgently advise you to have a look at the tcl manual, as all the possibilities of expr are explained there: e.g. string operations, binary operations, logical operations, etc.,...

Example:
    ::set sum [::expr 1 + 2 + 3 + 4]    

7.5.2 ::incr

Increment the value of a variable

Syntax:

::incr varName ?increment?
Description:
::incr varName ?increment?
Increments the value stored in the variable whose name is varName. The value of the variable must be an integer. If increment is supplied then its value (which must be an integer) is added to the value of variable varName; otherwise 1 is added to varName. The new value is stored as a decimal string in variable varName and also returned as result.

Example:
    ::set a 1
    ::incr a
    ::smm::showme "$a"

    ::set b [::incr a]
    ::smm::showme "$a -- $b"

7.6 Time

7.6.1 ::after

This command delays execution of the script.

Syntax:

::after milliseconds
Description:
::after milliseconds
milliseconds must be an integer giving a time in milliseconds. The command sleeps for ms milliseconds and then returns. While the command is sleeping the application does not respond to events.

Example:
    # stop execution of the script for 5 seconds
    ::after 5000

7.6.2 ::clock

Obtain and manipulate time

Syntax:

::clock clicks
::clock format clockValue
::clock scan dateString
::clock seconds
Description:
::clock clicks
Return a high-resolution time value as a system-dependent integer value. The unit of the value is system-dependent but should be the highest resolution clock available on the system such as a CPU cycle counter. This value should only be used for the relative measurement of elapsed time.
::clock format clockValue
Converts an integer time value, typically returned by clock seconds, clock scan, or the atime, mtime, or ctime options of the file command, to human-readable form. The output format can be controlled via the -format argument. Please refer to the tcl manual.
::clock scan dateString
Convert dateString to an integer clock value (see clock seconds). This command can parse and convert virtually any standard date and/or time string, which can include standard time zone mnemonics. If only a time is specified, the current date is assumed. For detailed information please refer to the tcl manual.
::clock seconds
Return the current date and time as a system-dependent integer value. The unit of the value is seconds, allowing it to be used for relative time calculations. The value is usually defined as total elapsed time from an ``epoch''. You shouldn't assume the value of the epoch.

Example:
    ::set seconds    [::clock seconds]
    ::set timeString [::clock format $seconds]
    ::smm::showme "current time: $timeString"