Sl-Unit 5
Sl-Unit 5
Sl-Unit 5
TCL
TCL Structure,
syntax,
Variables and Data in TCL,
Control Flow,
Data Structures,
input/output,
procedures,
strings,
patterns,
files,
Advance TCL- eval,
source,
exec and uplevel commands,
Name spaces,
trapping errors,
event driven programs,
making applications internet aware,
Nuts and Bolts Internet Programming,
Security Issues,
C Interface.
The current stable version, in February 2008, is 8.5.1 (8.4.18 in the older
8.4 branch). The first major GUI extension that works with TCL is TK, a toolkit
that aims to rapid GUI development. That is why TCL is now more commonly
called TCL/TK. The language features far-reaching introspection, and the
syntax, while simple2, is very different from the Fortran/Algol/C++/Java world.
Although TCL is a string-based language there are quite a few object-oriented
extensions for it like Snit3, incr Tcl4, and XOTcl5 to name a few. TCL is
embeddable: its interpreter is implemented as a library of C procedures that can
easily beincorporated into applications, and each application can extend the
core TCL features with additional commands specific to that application.
Tcl was originally developed as a reusable command language for
experimental computer aided design (CAD) tools. The interpreter is implemented
as a C library that could be linked into any application. It is very easy to add
new functions to the TCL interpreter, so it is an ideal reusable "macro language"
that can be integrated into many applications. However, TCL is a programming
language in its own right, which can be roughly described as a cross-breed
between
Syntax
Syntax is just the rules how a language is structured. A simple syntax of
English could say(Ignoring punctuation for the moment) A text consists of one or
more sentences A sentence consists of one or more words' Simple as this is, it
also describes Tcl's syntax very well - if you say "script" for "text", and
"command" for "sentence". There's also the difference that a Tcl word can again
contain a script or a command. So if {$x < 0} {set x 0} is a command consisting of
three words: if, a condition in braces, a command (also consisting of three
words) in braces. Take this for example is a well-formed Tcl command: it calls
Take (which must have been defined before) with the three arguments "this",
"for", and "example". It is up to the command how it interprets its arguments,
e.g. puts acos(-1) will write the string "acos(-1)" to the stdout channel, and
return the empty string "", while expr acos(-1) will compute the arc cosine of -1
and return 3.14159265359 (an approximation of Pi), or string length acos(-1)
will invoke the string command, which again dispatches to its length sub-
command, whichdetermines the length of the second argument and returns 8.A
Tcl script is a string that is a sequence of commands, separated by newlines or
semicolons. A command is a string that is a list of words, separated by blanks.
The first word is the name of the command; the other wordsare passed to it as
its arguments.
In Tcl, "everything is a command" - even what in other languages would be
called declaration, definition, or control structure. A command can interpret its
arguments in any way it wants -in particular, it can implement a different
language, like expression. A word is a string that is a simple word, or one that
begins with { and ends with the matching } (braces), or one that begins with "
and ends with the matching ". Braced words are not evaluated by the parser. In
quoted words, substitutions can occur before the command is called: $[A-Za-z0-
9_]+
substitutes the value of the given variable. Or, if the variable name contains
characters outside that regular expression, another layer of bracing helps the
parser to get it right
puts "Guten Morgen, ${Schuler}!"
If the code would say $Schuler, this would be parsed as the value of
variable $Sch, immediately followed by the constant string Schüler.(Part of) a
word can be an embedded script: a string in [] brackets whose contents are
evaluated as a script (see above) before the current command is called.In short:
Scripts and commands contain words. Words can again contain scripts and
commands. (This can lead to words more than a page long...)
Arithmetic and logic expressions are not part of the Tcl language itself, but
the language of the expr command (also used in some arguments of the if, for,
while commands) is basically equivalent to C's expressions, with infix operators
and functions.
These local variables cannot be seen elsewhere in the script, and they only
exist while the procedure is being executed. In the "getAvg" procedure above, the
local variables created inthe procedure are "n" "r" and "avg". TCL provides two
commands to change the scope of a variable inside a procedure, the "global"
command and the "upvar" command. The "global" command is used to declare
that one or more variables are not local to any procedure. The value of a global
variable will persist until it is explicitly changed. So, a variable which is declared
with the "global" command can be seen and changed from inside any procedure
which also declares that variable with the "global" command. Variables which
are defined outside of any procedure are automatically global by default. The
TCL "global" command declares that references to a given variable should be
global rather than local. However, the "global" command does not create or set
the variable … this must be done by other means, most commonly by the TCL
"set" command.
The TCL command "info exists" will evaluate to true if the given variable
exists. For example, suppose we wanted to make a version of our procedure
"getAvg" which keeps an internal count of how many times it has been called. In
this version, we use a global variable named "callCount_getAvg" to keep track of
the number of times "getAvg" is called. Because this global variable will actually
be used to store information for the specific use of the "getAvg" procedure, we
need to choose a global variable name which will not be used for a similar
purpose in some other procedure. The first time "getAvg" is called, the global
variable does not yet exist, and must be set to zero.
proc getAvg{ rList } \
{
global callCount_getAvg
if {![info exists callCount_getAvg]} \
{
set callCount_getAvg 0
}
incrcallCount_getAvg
puts "getAvg has been called $callCount_getAvg times"
set n [llength $rList]
if {!$n}
{return 0.0}
set avg 0.0
foreach r $rList \
{
set avg [expr $avg + $r]
}
set avg [expr $avg/double($n)]
return $avg
}
We have already seen that TCL procedures can generate a return value to
pass information back to their caller. And, we have also seen that global
variables can be used to share information between parts of a TCL script, and so
these also serve as a mechanism for returning information to a caller. TCL
includes the "upvar" command as a method for a given procedure to change the
values of variables in the scope of its caller. This provides a way for a procedure
to provide additional information to the caller, besides by using the
procedure'sreturn value.
Control Flow
In Tcl language there are several commands that are used to alter the flow
of a program. When a program is run, its commands are executed from the top
of the source file to the bottom. One by one. This flow can be altered by specific
commands. Commands can be executed multiple times. Some commands are
conditional. They are executed only if a specific condition is met.
The if command
if expr1 ?then? body1 elseif expr2 ?then? body2 elseif ... ?else? ?bodyN?
The then command is optional. We can use it if we think, it will make the
code clearer.
We can use the else command to create a simple branch. If the expression
inside the square brackets following the if command evaluates to false, the
command following the else command is automatically executed.
#!/usr/bin/tclsh
set sex female
if {$sex == "male"}
{
puts "It is a boy"
} else
{
puts "It is a girl”.
}
We can create multiple branches using the elseif command. The elseif
command tests for another condition, if and only if the previous condition was
not met. Note that we can use multiple elseif commands in our tests.
#!/usr/bin/tclsh
# nums.tcl
puts -nonewline "Enter a number: "
flush stdout
set a [gets stdin]
if {$a < 0}
{
puts "the number is negative”.
} elseif { $a == 0 }
{
puts "the number is zero”.
} else
{
puts "the number is positive”.
}
In the above script we have a prompt to enter a value. We test the value if
it is a negative number or positive or if it equals to zero. If the first expression
evaluates to false, the second expression is evaluated. If the previous conditions
were not met, then the body following the else commands would be executed.
$ ./nums.tcl
Enter a number: 2
the number is positive.
$ ./nums.tcl
Enter a number: 0
the numer is zero.
$ ./nums.tcl
Enter a number: -3
the number is negative.
Running the example multiple times.
Switch command
The switch command matches its string argument against each of the
pattern arguments in order. As soon as it finds a pattern that matches the 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.
#!/usr/bin/tclsh
# switch_cmd.tcl
puts -nonewline "Select a top level domain name:"
flush stdout
gets stdin domain
switch $domain
{
us { puts "United States" }
de { puts Germany }
sk{ puts Slovakia }
hu { puts Hungary }
default { puts "unknown" }
}
In our script, we prompt for a domain name. There are several options. If
the value equals for example to us the "United States" string is printed to the
console. If the value does not match to any given value, the default body is
executed, and unknown is printed to the console.
$ ./switch_cmd.tcl
Select a top level domain name:sk
Slovakia
We have entered sk string to the console and the program responded with
Slovakia.
While command:
The while command is a control flow command that allows code to be
executed repeatedly based on a given Boolean condition. The while command
executes the commands inside the block enclosed by curly brackets. The
commands are executed each time the expression is evaluated to true.
#!/usr/bin/tclsh
# whileloop.tcl
set i 0
set sum 0
while { $i< 10 }
{
incr i
incr sum $i
}
puts $sum
The expression inside the curly brackets following the while command is
the second phase, the testing. The commands in the body are executed, until
the expression is evaluated to false.
incri
The last, third phase of the while loop is the updating. The counter is
incremented. Note that improper handling of the while loops may lead to endless
cycles.
FOR command:
When the number of cycles is known before the loop is initiated, we can
use the for command. In this construct we declare a counter variable, which is
automatically increased or decreased in value during each repetition of the loop.
#!/usr/bin/tclsh
for {set i 0} {$i< 10} {incri}
{
puts $i
}
There are three phases. First, we initiate the counter i to zero. This phase
is done only once.
Next comes the condition. If the condition is met, the command inside the
for block is executed. Then comes the third phase; the counter is increased. Now
we repeat phases 2 and 3 until the condition is not met and the for loop is left.
In our case, when the counter i is equal to 10, the for loop stops executing.
$ ./forloop.tcl
0
1
2
3
4
5
6
7
8
9
Here we see the output of the forloop.tcl script.
Data Structures
The list is the basic Tcl data structure. A list is simply an ordered
collection of stuff; numbers, words, strings, or other lists. Even commands in Tcl
are just lists in which the first list entry is the name of a proc, and subsequent
members of the list are the arguments to the proc. Lists can be created in
several way by setting a variable to be a list of values set lst {{item 1} {item 2}
{item 3}} with the split command set lst [split "item 1.item 2.item 3" "."] with the
list command. set lst [list "item 1" "item 2" "item 3"] An individual list member
can be accessed with the index command. The brief description of these
commands is
list ?arg1? ?arg2? ... ?argN?
makes a list of the arguments
split string ?splitChars?
Splits the string into a list of items wherever the splitChars occur in
thecode. SplitChars defaults to being whitespace. Note that if there are two or
more splitChars then each one will be used individually to split the string. In
otherwords: split "1234567" "36" would return the following list: {12 45 7}.lindex
list index
Returns the index'th item from the list.
Note: lists start from 0, not 1, so the first item is at index 0, the second item is
at index 1, and so on.llengthlist.Returns the number of elements in a list.The
items in list can be iterated through using the foreach
command.foreachvarname list body The foreach command will execute the body
code one time for each list item in list. On each pass, varname will contain the
value of the next list item.In reality, the above form of foreach is the simple form,
but the command is quite powerful. It will allow you to take more than one
variable at a time from the list: foreach {a b} $listofpairs{ ... }. You can even take
a variable at a time from multiple lists!
For xample: foreach a $listOfA b $listOfB{ ... }
Examples
set x "a b c"
puts "Item at index 2 of the list {$x} is: [lindex $x 2]\n"
set y [split 7/4/1776 "/"]
puts "We celebrate on the [lindex $y 1]'th day of the [lindex $y 0]'th
month\n"
set z [list puts "arg 2 is $y" ]
puts "A command resembles: $z\n"
set i 0
foreach j $x
{
puts "$j is item number $i in list x"
incr i
}
Concatenates the args into a single list. It also eliminates leading and
trailing spaces in the args and adds a single separator space between args. The
argstoconcat may be either individual elements, or lists. If an arg is already a
list, the contents of that list is concatenatedwith the other args.
lappend list Name ?arg1 arg2 ... argn?
Appends the args to the list listName treating each arg as a list element.
linsert list Name index arg1 ?arg2 ... argn?
Returns a new list with the new list elements inserted just before the
index th element of listName. 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.
lreplace list Name first last ?arg1 ... argn?
Returns a new list with N elements of listName replaced by the args. If
first is less than or equal to 0, lreplace starts replacing from the first element of
the list.If first is greater than the end of the list, or the word end, then lreplace
behaves like lappend. If there are fewer args than the number of
positionsbetween first and last, then the positions for which there are no args
are deleted.
lsetvarName index newValue
The lset command can be used to set elements of a list directly, instead of
using lreplace. Lists in Tcl are the right data structure to use when you have an
arbitrary number of things, and you'd like to access them according to their
order in the list. In C, you would use an array. In Tcl, arrays are associated
arrays - hash tables, as you'll see in the coming sections. If you want to have a
collection of things and refer to the Nth thing (give me the 10th element in this
group of numbers) or go through them in order via foreach. Look at the example
code and pay special attention to the way that sets of characters are grouped
into single listelements.
Example
set b [list a b {c d e} {f {g h}}]
puts "Treated as a list: $b\n"
set b [split "a b {c d e} {f {g h}}"]
puts "Transformed by split: $b\n"
set a [concat a b {c d e} {f {g h}}]
puts "Concated: $a\n"
lappend a {ij K lm} ;
# Note: {ij K lm} is a single element
puts "After lappending: $a\n"
set b [linsert $a 3 "1 2 3"] ;
# "1 2 3" is a single element
puts "After linsert at position 3: $b\n"
set b [lreplace $b 3 5 "AA" "BB"]
puts "After lreplacing 3 positions with 2 values at position 3: $b\n"
More list commands - lsearch, lsort, lrange
Lists can be searched with the lsearch command, sorted with the lsort
command, and a range of list entries can be extracted with the lrange command.
lsort list
Sorts list and returns a new list in the sorted order. By default, it sorts the
list into alphabeticorder. Note that this command returns the sorted list as a
result, instead of sorting the list in place. If you have a list in a variable, the way
to sort it is like so: set lst [lsort $lst]
Example
set list [list {Washington 1789} {Adams 1797} {Jefferson 1801} \
{Madison 1809} {Monroe 1817} {Adams 1825} ]
set x [lsearch $list Washington*]
set y [lsearch $list Madison*]
incr x
incr y -1 ;# Set range to be not-inclusive
set subsetlist [lrange $list $x $y]
puts "The following presidents served between Washington and Madison"
foreach item $subsetlist {
puts "Starting in [lindex $item 1]: President [lindex $item 0] "
}
set x [lsearch $list Madison*]
set srtlist [lsort $list]
set y [lsearch $srtlist Madison*]
puts "\n$x Presidents came before Madison chronologically"
puts "$y Presidents came before Madison alphabetically"
Input / Output
Tcl uses objects called channels to read and write data. The channels can
be created using the open or socket command. There are three standard
channels available to Tcl scripts without explicitly creating them. They are
automatically opened by the OS for each new application. They are stdin, stdout
and stderr. The standard input, stdin, is used by the scripts to read data. The
standard output, stdout, is used by scripts to write data. The standard error,
stderr, is used by scripts to write error messages.In the first example, we will
work with the puts command. It has the following synopsis:
puts ?-nonewline? ?channelId? string
The channelId is the channel where we want to write text. The channelId
is optional. If not specified, the default stdout is assumed.
#!/usr/bin/tclsh
puts "Message 1"
puts stdout "Message 2"
puts stderr "Message 3"
The puts command writes text to the channel.
puts "Message 1"
puts stdout "Message 2"
puts stderr "Message 3"
Procedures
A procedure is a code block containing a series of commands. Procedures
are called functions in many programming languages. It is a good programming
practice for procedures to do only one specific task. Procedures bring modularity
to programs. The proper use of procedures brings the following advantages
1. Reducing duplication of code
2. Decomposing complex problems into simpler pieces
3. Improving clarity of the code
4. Reuse of code
5. Information hiding
There are two basic types of procedures: built-in procedures and user
defined ones. The builtin procedures are part of the Tcl core language. For
instance, the rand(), sin() and exp() are built-in procedures. The user defined
procedures are procedures created with the proc keyword.The proc keyword is
used to create new Tcl commands. The term procedures and commands are
often used interchangeably. We start with a simple example.
#!/usr/bin/tclsh
proc tclver {}
{
set v [info tclversion]
puts "This is Tcl version $v"
}
tclver
In this script, we create a simple tclver procedure. The procedure prints the
version of Tcl language. proc tclver {}
The new procedure is created with the proc command. The {} characters
reveal that the procedure takes no arguments.
{
set v [info tclversion]
puts "This is Tcl version $v"
}
tclver
This is the body of the tclver procedure. It is executed when we execute
the tclver command.
The body of the command lies between the curly brackets.The procedure
is called by specifying its name.
$ ./version.tcl
This is Tcl version 8.6
Sample output.
Procedure arguments:
Here we create a power procedure. The procedure has one argument with an
implicit value. We can call the procedure with one and two arguments.
proc power {a {b 2}} {
set v1 [power 5]
set v2 [power 5 4]
The second argument b has an implicit value 2. If we provide only one
argument, the powerprocedure then returns the value of a to the power 2.We
call the power procedure with one and two arguments. The first line computes
the value of 5 to the power 2. The second line value of 5 to the power 4. Output
of the example.
$ ./implicit.tcl
5^2 is 25
5^4 is 625
Returning multiple values
The return command passes one value to the caller. There is often a need to
return multiple values. In such cases, we can return a list.
#!/usr/bin/tclsh
proc tworandoms {}
{
set r1 [expr round(rand()*10)]
set r2 [expr round(rand()*10)]
return [list $r1 $r2]
}
puts [two randoms]
puts [two randoms]
puts [two randoms]
puts [two randoms]
We have a two randoms procedure. It returns two random integers between 1
and 10. A random integer is computed and set to the r1 variable.
set r1 [expr round(rand()*10)]
return [list $r1 $r2]
Two values are returned with the help of the list command. A sample output.
$ ./tworandoms.tcl
37
13
87
99
Recursion
Recursion, in mathematics and computer science, is a way of defining
functions in which the function being defined is applied within its own
definition. In other words, a recursive function calls itself to do its job.
Recursion is a widely used approach to solve many programming tasks.
Recursion is the fundamental approach in functional languages like Scheme,
OCalm, or Clojure.
Recursion calls have a limit in Tcl. There cannot be more than 1000
recursion calls. A typical example of recursion is the calculation of a factorial.
Factorial n! is the product of all positive integers less than or equal to n.
#!/usr/bin/tclsh
proc factorial n
{
if {$n==0}
{
return 1
}
else
{
return [expr $n * [factorial [expr $n - 1]]]
}
}
# Stack limit between 800 and 1000 levels
puts [factorial 4]
puts [factorial 10]
puts [factorial 18]
Inside the body of the factorial procedure, we call the factorial procedure with a
modified argument. The procedure calls itself.
$ ./recursion.tcl
24
3628800
6402373705728000
These are the results. If we tried to compute the factorial of 100, we would
receive "too many nested evaluations" error.
Scope
A variable declared inside a procedure has a procedure scope. The scope of a
name is the region of a program text within which it is possible to refer to the
entity declared by the name without qualification of the name. A variable which
is declared inside a procedure has a procedure scope; it is also called a local
scope. The variable is then valid only in this procedure.
#!/usr/bin/tclsh
proc test {}
{
puts "inside procedure"
#puts "x is $x"
set x 4
puts "x is $x"
}
Set x 1
puts "outside procedure"
puts "x is $x"
test
puts "outside procedure"
puts "x is $x"
In the preceding example, we have an x variable defined outside and inside of
the test procedure. Inside the test procedure, we define an x variable. The
variable has local scope, valid only inside this procedure.
set x 4
puts "x is $x"
set x 1
puts "outside procedure"
puts "x is $x"