uplevel
Commanduplevel ?level? arg ...The
uplevel
command executes arg ... as a Tcl
script in the calling context. If level is given, it
specifies the context in which to execute arg ... in the same
manner as upvar
.
proc myset {var value} { uplevel set $var $value }
uplevel
is used to create new control structures; most Tcl
commands that take a Tcl scipt as an argument need to use
uplevel
to execute the script in the calling context. See
below for examples.
set foo Error: can't read "foo": no such variable
$ megatcl -c "while 1 {if 1 {set foo}}" Error: can't read "foo": no such variable can't read "foo": no such variable while executing "set foo" invoked from within "if 1 {set foo}" ("while" body line 1) invoked from within "while 1 {if 1 {set foo}}" $The stack trace indicates the nesting of the erroneous command within contriol structures (like
while
and if
) and
also within procedure bodys. If an error occurs deep within several
levels of procedure invocations, the stack trace can be very long.
While the stack trace is useful during debugging, it's probably not
desirable for a production program. You can turn off the stack trace
with the -n
argument to the megatcl
(or
Extended Tcl) interpreter:
$ megatcl -n -c "while 1 {if 1 {set foo}}" Error: can't read "foo": no such variable $You can do this on the
#!
line in your script:
#!/local/bin/megatcl -nf
error
command.
error
Commanderror message ?info? ?code?This command takes one mandatory argument, the error message; when invoked, it generates an error condition and terminates execution.
if ![regexp {^[0-9]+$} $num] { error "num must be numeric" }
error
takes two optional arguments which we will discuss
later.
catch
Commandcatch body ?var?The body argument to
catch
is a Tcl script,
which catch
executes. If an error occurs withing the
script, it does not terminate execution; instead, catch returns 1
to indicate that an error occurred. If no error occurs, catch returns
0.
In this simple form, catch
can be used to ignore errors, or
to test for them. Here's an example of using catch
to
implement a version of the info exists
command:
proc varexists {var} { upvar $var v if [catch {set v}] { return 0 } else { return 1 } }Or more compactly:
proc varexists {var} { upvar $var v expr ![catch {set v}] }
catch
takes an optional argument var, which
serves two purposes:
open
command can generate an error if a
file to be opened for reading doesn't exist. You might think that the
solution is to use file exists
first, but open can fail for
many other reasons (improper permissions, etc). Tcl's error message
might be just the thing you want in this case, but you may want to
continue execution or try to open another file. For this you need
catch
:
if [catch {open $file r} result] { # error! puts stderr "Warning: $result" } else { set fp $result }
return
condition, generated by the
return
command.
continue
condition, generated by the
continue
command.
break
condition, generated by the
break
command.catch
command will catch all of these exceptions. How
can you distinguish them? catch
returns a different
non-zero numeric code for each of them. See page 122 in
Ousterhout.
catch {return hey!} => 2For most purposes, you can simply treat any non-zero exception as an error condition; the only time you need to worry about the distinction is when you're writing very fancy control structures.
In addition the standard exceptions, Tcl lets you define your own. See
the try
command.
signal
command.
signal
Commandsignal action siglist ?command?The action argument can be one of:
default
, which specifies the OS's default action for
that signal;
ignore
, which causes the signal to be ignored;
error
, which causes the signal to be converted to a Tcl
error condition;
trap
, which allows the Tcl command to be
associated with the signal. command is executed in the
global context; an occurrence of the string %S
in
command will be replaced with the signal name (use
%%
to get a percent sign);
get
, which returns the current settings for all
signals.For example, the Unix signal 15 (SIGTERM) is the canonical signal to
terminate a program; it's sent to all processes by the OS when the
system is going down, for example. Signal 1 (SIGHUP) is the hangup
signal, sent when a dial up or network connection is dropped. You may
want to be sure to be able to perform some cleanup actions upon receipt
of these signals; assuming you have a proc called cleanup
that does what's necessary, you can arrange for it to be called as
follows:
signal trap [list SIGTERM SIGHUP] cleanup
kill
Commandkill ?-pgroup? ?signal? idlistThe Extended Tcl
kill
command allows you to send Unix
signals to other processes (including yourself). signal is
the signal number or name of the signal you want to send (SIGTERM is the
default), and idlist is a list of process id's.
alarm
Commandalarm secondsThe Extended Tcl
alarm
command arranges for the kernel to
send your process a SIGALRM (signal 14) in seconds seconds
(this is a floating point value, so seconds may be
fractional). If seconds is 0.0, any previous alarm request
is cancelled. The alarm
command returns the number of
seconds left in the previous alarm.
alarm
can be used in conjunction with signal
to generate timeouts. See the timeout
command below.
errdefault
Commanderrdefault code ?default?This command executes the Tcl script code, returning its result if there is no error. If there is an error, default is returned (or the empty string, if default isn't specified).
proc errdefault {code {default ""}} { if [catch {uplevel 1 $code} result] { return $default } else { return $result } } set fp [errdefault {open $file r} stdin]
unwindProtect
CommandunwindProtect body protectedThe
unwindProtect
command is modelled after a similar
command in Lisp. It executes the script body, guaranteeing
that the script protected will be executed afterward even if
an error occurs in body. Note that
unwindProtect
doesn't catch the error, it passes it on
after executing protected.
A classic use of unwindProtect
is to close files even if an
error occurs in processing:
foreach file $filelist { if [catch {open $file} result] { puts stderr "Warning: $result" } else { set fp $result unwindProtect { # process file here... } { catch {close $fp} } } }If there are several hundred files in
filelist
, and there
were errors in processing many of them, we would run out of file
descriptors if it weren't for unwindProtect
.
timeout
Commandtimeout seconds bodyThe
timeout
command executes the script body
with a timeout of seconds: if body doesn't finish
execution within the specified time frame, it is interrupted and a
TIMEOUT error is generated. timeout
uses the SIGALRM alarm
signal. timeout
is often useful in network programming,
where long delays can occur.
catch { timeout 30 { lassign [server_open $host $port] read write } }