C

Tcl



C.1    Why Tcl?

Tcl is a scripting language which is designed to be embedded in applications. It can be embedded in applications that present command-line interfaces (the Tornado shell, for example) as well as in those that do not (such as the browser). Almost any program can benefit from the inclusion of such a language, because it provides a way for users to combine the program's features in new and unforeseen ways to meet their own needs. Many programs implement a command-line interface that is unique to the particular application. However, application-specific command line interfaces often have weak languages. Tcl holds some promise of unifying application command languages. This has an additional benefit: the more programs use a common language, the easier it is for everyone to learn to use each additional program that incorporates the language.

To encourage widespread adoption, John Ousterhout (the creator of Tcl) has placed the language and its implementation in the public domain.

Tk is often mentioned in conjunction with Tcl. Tk is a graphics library that extends Tcl with graphical-interface facilities. Tornado does not currently use Tk, but you may find Tk useful for your own Tcl applications.



C.2    Introduction to Tcl

Tcl represents all data as ordinary text strings. As you might expect, the string-handling features of Tcl are particularly strong. However, Tcl also provides a full complement of C-like arithmetic operators to manipulate strings that represent numbers.

The examples in the following sections exhibit some of the fundamental mechanisms of the Tcl language, in order to provide some of the flavor of working in Tcl. However, this is only an introduction.

For documentation on all Tcl interfaces in Tornado (as well as on C interfaces), see the Tornado API Programmer's Guide from Wind River.

For the Tcl language itself, the following generally available books are helpful:

  • Ousterhout, John K.: Tcl and the Tk Toolkit (Addison-Wesley, 1994) - The definitive book on Tcl, written by its creator.

  • Welch, Brent: Practical Programming in Tcl and Tk (Prentice Hall, 1995) - Useful both as a quick Tcl reference and as a tutorial.

C.2.1   Tcl Variables

The Tcl set command defines variables. Its result is the current value of the variable, as shown in the following examples:

Table C-1:   Setting Tcl Variables


Tcl Expression
Result

set num 6
6
set y hello
hello
set z "hello world"
hello world
set t $z
hello world
set u "$z $y"
hello world hello
set v {$z $y}    
$z $y

The expressions above also illustrate the use of some special characters in Tcl:

SPACE

" "

$vname

{ }

With a single argument, set gives the current value of a variable:

Table C-2:   Evaluating Tcl Variables


Tcl Expression
Result

set num
6
set z
hello world

C.2.2   Lists in Tcl

Tcl provides special facilities for manipulating lists. In Tcl, a list is just a string, with the list elements delimited by spaces, as shown in the following examples:

Table C-3:   Using Tcl Lists 


Tcl Expression
Result
Description

llength $v
2
Length of list v.
lindex $u 1
world
Second element of list u.
set long "a b c d e f g"
a b c d e f g
Define a longer list.
lrange $long 2 4
c d e
Select elements 2 through 4 of list long.
lreplace $long 2 4 C D E
a b C D E f g
Replace elements 2 through 4 of list long.
set V "{c d e} f {h {i j} k}"
Define a list of lists.
lindex $V 1
f
Some elements of V are singletons.
lindex $V 0
c d e
Some elements of V are lists.

The last examples use curly braces to delimit list items, yielding "lists of lists." This powerful technique, especially combined with recursive command substitution (see C.2.4 Command Substitution), can provide a little of the flavor of Lisp in Tcl programs.

C.2.3   Associative Arrays

Tcl arrays are all associative arrays, using a parenthesized key to select or define a particular element of an array: arrayName(keyString). The keyString may in fact represent a number, giving the effect of ordinary indexed arrays. The following are some examples of expressions involving Tcl arrays:

Table C-4:   Using Tcl Arrays


Tcl Expression
Result
Description

set taskId(tNetTask)
0x4f300
Get element tNetTask of array taskId.
set cpuFamily(5) m68k
m68k
Define array cpuFamily and an
element keyed 5.
set cpuFamily(10) sparc
sparc
Define element keyed 10 of array
cpuFamily.
set cpuId 10
10
Define cpuId, and use it as a key to cpuFamily.
set cpuFamily($cpuId)
sparc

C.2.4   Command Substitution

In Tcl, you can capture the result of the command as text by enclosing the command in square brackets [ ]. The Tcl interpreter substitutes the command result in the same process that is already running, which makes this an efficient operation.

Table C-5:   Examples of Tcl Command Substitution


Tcl Expression
Result

set m [lrange $long 2 4]
c d e
set n [lindex $m 1]
d
set o [lindex [lrange $long 2 4] 1]
d
set x [lindex [lindex $V 2] 1]
i j

The last example selects from a list of lists (defined among the examples in C.2.2 Lists in Tcl). This and the previous example show that you can nest Tcl command substitutions readily. The Tcl interpreter substitutes the most deeply nested command, then continues substituting recursively until it can evaluate the outermost command.

C.2.5   Arithmetic

Tcl has an expr command to evaluate arithmetic expressions. The expr command understands numbers in decimal and hexadecimal, as in the following examples:

Table C-6:   Arithmetic in Tcl


Tcl Expression
Result

expr (2 << 2) + 3
11
expr 0xff00 & 0xf00
3840

C.2.6   I/O, Files, and Formatting

Tcl includes many commands for working with files and for formatted I/O. Tcl also has many facilities for interrogating file directories and attributes. The following examples illustrate some of the possibilities:

Table C-7:   Files and Formatting in Tcl


Tcl Expression
Description

set myfile [open myfile.out w]
Open a file for writing.
puts $myfile [format "%s %d\n" \ 
     "you are number" [expr 3+3]]
Format a string and write it to file.
close $myfile
Close the file.
file exists myfile.out
1
file writable myfile.out
1
file executable myfile.out
0
glob *.o
testCall.o foo.o bar.o

C.2.7   Procedures

Procedure definition in Tcl is straightforward, and resembles many other languages. The command proc builds a procedure from its arguments, which give the procedure name, a list of its arguments, and a sequence of statements for the procedure body. In the body, the return command specifies the result of the procedure. For example, the following defines a procedure to compute the square of a number:

proc square {i} { 
    return [expr $i * $i] 
}

If a procedure's argument list ends with the word args, the result is a procedure that can be called with any number of arguments. All trailing arguments are captured in a list $args. For example, the following procedure calculates the sum of all its arguments:

proc sum {args} { 
    set accum 0 
    foreach item $args { 
        incr accum $item 
    } 
    return $accum 
}

Defined Tcl procedures are called by name, and can be used just like any other Tcl command. The following examples illustrate some possibilities:

Table C-8:   Calling a Tcl Procedure


Tcl Expression
Result

square 4
16
square [sum 1 2 3]
36
set x "squ"
squ
set y "are"
are
$x$y 4
16

The technique illustrated by the last example--constructing a procedure name "on the fly"--is used extensively by Tornado tools to group a set of related procedures. The effect is similar to what can be achieved with function pointers in C.

For example, in Tornado tools, events are represented in Tcl as structured strings. The first element of the string is the name of the event. Tcl scripts that handle events can search for the appropriate procedure to handle a particular event by mapping the event name to a procedure name, and calling that procedure if it exists. The following Tcl script demonstrates this approach:

proc shEventDispatch {event} {  
         set handlerProc "[lindex $event 0]_Handler" 
 
         if {[info procs $handlerProc] != ""} { 
             $handlerProc $event 
         } { 
             #event has no handler--do nothing. 
         } 
}

C.2.8   Control Structures

Tcl provides all the popular control structures: conditionals (if), loops (while, for, and foreach), case statements (switch), and explicit variable-scope control (global, upvar, and uplevel variable declarations). By using these facilities, you can even define your own control structures. While there is nothing mysterious about these facilities, more detailed descriptions are beyond the scope of this summary. For detailed information, see the books cited at the beginning of C.2 Introduction to Tcl.

C.2.9   Tcl Error Handling

Every Tcl procedure, whether built-in or script, normally returns a string. Tcl procedures may signal an error instead: in a defined procedure, this is done with the error command. This starts a process called unwinding. When a procedure signals an error, it passes to its caller a string containing information about the error. Control is passed to the calling procedure. If that procedure did not provide for this possibility by using the Tcl catch command, control is passed to its caller in turn. This recursive unwinding continues until the top level, the Tcl interpreter, is reached.

As control is passed along, any procedure can catch the error and take one of two actions: signal another error and provide error information, or work around the error and return as usual, ending the unwinding process.

At each unwinding step, the Tcl interpreter adds a description of the current execution context to the Tcl variable errorInfo. After unwinding ends, you can display errorInfo to trace error information. Another variable, errorCode, may contain diagnostic information, such as an operating system dependent error code returned by a system call.

C.2.10   Integrating Tcl and C Applications

Tcl is designed to integrate with C applications. The Tcl interpreter itself is distributed as a library, ready to link with other applications. The core of the Tcl integration strategy is to allow each application to add its own commands to the Tcl language. This is accomplished primarily through the subroutine Tcl_CreateCommand( ) in the Tcl interpreter library, which associates a new Tcl command name and a pointer to an application-specific routine. For more details, consult the Tcl books cited at the beginning of C.2 Introduction to Tcl.