| by Martin Elsman | last modified Feb 03, 2002 |
All the examples in these notes can be run using the
tclsh interpreter. Versions of the tclsh
interpreter exist for both UNIX and Windows. Under UNIX, simply type
tclsh at the shell prompt, which will bring up the tcl
prompt:
%Under Windows, download and run the self-extracting executable tcl823.exe; a
tclsh icon should appear on your desktop. Do not worry
about the gray window that pops up when you click on the icon. Simply
iconize this window; it is of no use to us because we will be
constructing the user interface in HTML.
One Web server that makes the efficient implementation of Web services with tcl possible is AOLserver. AOLserver has a built-in tcl interpreter. The Web publisher implements pages in the tcl programming language, which when interpreted produces HTML code as output. Then, when a client with a browser requests a tcl page, AOLserver interprets the contents of the page and sends the output from interpreting the tcl code back to the client. In this way the Web publisher can program the content of Web pages.
In the following sections, we introduce the tcl language. First, we give an overview of what tcl commands look like. We then proceed with sections on Arithmetics, Variables, Nested Commands, Grouping, Escape Sequences, Comments, Conditionals, While-Loops and For-Loops, Strings, and Procedures.
cmd arg1 arg2 ... argNwhere
cmd is a command identifier and arg1,
arg2, ..., and argN are arguments to the
command. Commands can be typed directly at the tclsh
prompt:
% puts "I'm alive!" I'm aliveHere, the command
puts takes only one argument, the
string "I'm alive!", and prints it. The double-quotes are
needed to group the string as one argument to puts
instead of two (see the section on Grouping, below).
expr:
% expr 3+4 7This
expr command computes the result of adding 3 and
4. When commands are entered at the %-prompt, the tclsh
interpreter prints the result of the command--in this case, 7. There
are several other operators than + that you can use,
including -, *, and /.
set command:
% set age 30 30 % puts "I'm $age years old" I'm 30 years oldThe
set command takes two arguments, the name of the
variable to set and the value to which the variable should be set.
There are several things to notice here. First, because the
set command returns the content of the variable, the
tclsh interpreter prints the value 30. Second, it is
possible to refer to the content of a variable by placing a $-sign in
front of the variable name. Here this feature is used in the argument
to the puts command, in which the value 30 is substituted
for the variable age.
As mentioned earlier, variables can be used to hold values other than
numbers. Here is an example where a variable my_name is
used to hold the name of a person:
% set my_name Martin Martin % puts "$my_name is $age years old" Martin is 30 years oldNotice again that before the string is passed to the
puts
command, the contents of the variables my_name and
age are substituted for the occurrences of
$my_name and $age in the string.
% set expected_time_to_reincarnation [expr 90 - $age] 60Here the
set command is used to set a variable
expected_time_to_reincarnation to the result of
evaluating the nested command [expr 90 - $age]. Notice
that the nested command is evaluated before being passed to the
set command. Because the variable age
contains the value 30, the variable
expected_time_to_reincarnation is set to 90 - 30, which
equals 60. Notice also that variable names can have underscore
(_) characters in them.
% puts Hello; puts World Hello WorldA useful tcl command is the
source command, which reads
tcl commands from a file. Assume that you have a file
hello.tcl in the directory in which you started
tclsh and that this file contains the tcl code
set firstname Martin set lastname Elsman set age 30 set email mael@itu.dk puts "My name is $firstname $lastname and my email address is $email."Using the
source command, it is possible to execute the
commands in the % source hello.tcl My name is Martin Elsman and my email address is mael@itu.dk.
% puts "My name is $firstname"
My name is Martin
% puts {My name is $firstname}
My name is $firstname
In both examples, grouping of characters is needed to treat a sequence
of characters containing spaces as one argument to the
puts command. The difference is that if curly braces are
used to group characters as arguments to a command then elements
within the arguments are not evaluated before the command is
called. Contrary, if double quotes are used to group arguments to a
command then dollar signs and square brackets are interpreted inside
the arguments.
% puts "I can now write characters like \$, \{, \}, \[, \], and \""
I can now write characters like $, {, }, [, ], and "
There are other special characters that you can write using backslash,
like newline (\n) and tab (\t):
% puts "Sale items\ncar\t\$800\nbicycle\t\$200" Sale items car $800 bicycle $200
% # Let's set the variable year % set year 2000 ;# we're in year 2000 2000It is a good habit to always document (with lots of comments) the tcl code that you write; good documentation is critical to understanding other people's code--and sometimes, even your own!
number_of_courses prints a suitable sentence:
set number_of_courses 2
if {$number_of_courses == 0} {
puts "I'm taking no courses this semester"
} elseif {$number_of_courses == 1} {
puts "I'm taking one course this semester"
} else {
puts "I'm taking $number_of_courses courses this semester"
}
In addition to the operator ==, there are several other
operators that can be used in conditionals, including >=,
>, <=, <, and !=.
In principle, the
set email "mael@it.edu"
if { $email == "mael@it.edu" } {
puts "Welcome home Martin"
}
set i 0
while {$i < 3} {
incr i
puts "Soon, I'm a Web programmer..."
}
The while command takes two arguments. It is essential
for this example that both arguments are wrapped in curly braces. The
evaluation of a while-loop results in evaluating the second argument
until the evaluation of the first argument returns 0. For the present
example, the variable i is initially set to 0. Now,
because the first argument to while evaluates to 1
([expr $i < 3] returns 1), the second argument to
while is evaluated as a sequence of commands. This
evaluation results in the variable i to be increased by
one (by the incr command), such that it now has the
value 1. Before the while-loop is evaluated two more times, the string
``Soon, I'm a Web programmer...'' is printed by the puts
command.
With for-loops, it is possible to do exactly the same things that one
can do with while-loops. A for command takes four
arguments. The first argument is a command to be executed before the
loop is entered; this command typically initializes a variable used in
the loop. The second argument is a test, which is executed at each
repetition; if the result of this test is false, the loop is
terminated and evaluation proceeds after the loop. The third argument
is a command, which is executed after each repetition. The fourth argument is the body of
the loop. Here is an example for-loop, which prints a multiplication
table:
# after each repetition, x is increased by one
for {set x 0} {$x<10} {incr x} {
puts "$x times 9 is [expr $x * 9]"
}
See the man pages for for and
while
if you need more information about these commands.
Tcl is well-suited for processing strings; it has a large set of built-in commands for string manipulation.
A string is basically a sequence of characters, so given a string, one can ask about the length of the string:
% set mystring "This is a fairly long string..." This is a fairly long string... % string length $mystring 31This example makes use of the
string command, which
implements many different string-manipulation commands, called
sub-commands. The first argument to the string
command specifies the sub-command. Here, we're interested in the
length sub-command of the string
command. Additional arguments to the string command are
then arguments to the sub-command. The length sub-command
of the string command takes one extra argument, which is
the string of which the length is to be returned. From the example, we
see that the string in the mystring variable is 31
characters long.
Another important string command, which you have in fact already read
about, is the append command. This command is so
important that it is not a sub-command to the string
command, but a real command! The append command takes two
or more arguments. The effect of the append command is to
set the variable to the concatenation of the old content of the
variable and the remaining arguments:
% set myotherstring "This is not" This is not % append myotherstring " a very" " long string" "..." This is not a very long string...Let us use the
append command to write a program that
constructs a HTML page in a variable page and prints out the page:
set page "<html>\n" append page " <head>\n" append page " <title>Hello World</title>\n" append page " </head>\n" append page " <body>\n" append page " Hello World\n" append page " </body>\n" append page "</html>" puts $page
Of course, to get the effect of printing the content of the
variable
puts "<html>
<head>
<title>Hello World</title>
</head>
<body>
Hello World
</body>
</html>"
Here is an example where it is practical to build up a string
dynamically using the
set page "<html><head><title>Hello World</title></head>
<body><center>\n"
set i 1
while { $i < 5 } {
append page "<h$i>Haleluja</h$i>\n"
incr i
}
append page "</center></body></html>"
puts $page
And here is how it looks when a Web browser presents the resulting page:
HalelujaHalelujaHalelujaHaleluja |
In Web applications it is important to be able to compare
strings. Comparisons are necessary, for instance, to act differently
on different user inputs. To compare two strings in tcl, we use the
string compare command. The string compare
command takes two strings as arguments and returns 0 if the strings
are identical. Suppose that some user has registered on your site with
the form variables first_names, last_name,
email, and passwd. Assume also that the
error command sends a reasonable response back to the
user, based on the argument. At-least, we want our program to check
that the form variables are non-empty and that the password is
suitable:
# compare the first_names value to the empty string
if { [string compare $first_names ""] == 0 } {
error "You must provide a first name"
}
# compare the last_name value to the empty string
if { [string compare $last_name ""] == 0 } {
error "You must provide a last name"
}
...
# require a password with at-least four characters
if { [string length $passwd] <= 4 } {
error "You must provide a password with at-last four characters"
}
To learn more about string commands, see the TCL for Web Nerds notes, which
can also tell you how to check that an email address is of the form
something@somethingelse. Also see the string
man page available from http://dev.scriptics.com/man/tcl8.3/TclCmd/contents.htm
for a detailed explanation of the string command.
proc command. Here is a procedure
hyperlink, which takes as argument a string representing
a URL address and returns a string containing HTML code for a
hyperlink to the URL address:
proc hyperlink {url} {
set res "<a href=\""
append res $url "\">" $url "</a>"
return $res
}
The proc command takes three arguments, the name of the
procedure being defined, a list of arguments to the procedure, and the
body of the procedure. Procedure names are case sensitive, as are
variable names, so the procedure name Hyperlink is
different than the procedure name hyperlink. It is good
programming practice to always group procedure argument lists and
procedure bodies in curly braces.
In the example procedure, the variable res is defined
locally within the body of the procedure, which means that the
variable can be accessed only in the body of the procedure. A variable
named res defined outside of the procedure is not
affected by the use of the hyperlink command. The
return command at the end of the procedure body is used
to return the result of the procedure, which in this case is the
string contained in the res variable. The
append command is used to construct the HTML hyper-link,
based on the URL address, which is given as argument to the
procedure.
The following tcl code uses the hyperlink command to
output HTML code with a link to the much popular Google search-engine:
% puts "Google has the URL [hyperlink {http://www.google.com}]"
Google has the URL <a href="http://www.google.com">http://www.google.com</a>
The ability to define procedures allows the programmer to divide a programming task into sub-tasks. These sub-tasks can then be understood and implemented in isolation, maybe by somebody else than the programmer! Procedural abstraction is therefore very important for software engineering; a programming language that does not provide ways of defining procedures scales poorly to the construction and maintenance of large software systems.
Another important aspect of procedural abstraction is that a procedure
defined once can be used in many different contexts. For instance,
notice that in the body of the hyperlink procedure
definition, the command append is used four times, each
time with different arguments.
As another example, consider the following procedure:
proc multi {word n} {
set res ""
while {$n >= 1} {
append res $word
set n [expr $n - 1]
}
return $res
}
The procedure multi takes two arguments,
word and n. When called, the procedure
returns the result of appending n copies of the string
word. Notice the use of the append
command. The append command sets the variable, defined by
the first argument, to the concatenation of the old value and the
remaining arguments, in this case the string contained in the variable
word. Each time around the while-loop, the counter
n is decreased by one. Here is a use of
multi:
% puts "I'm [multi {very } 3]smart!"
I'm very very very smart!