How am I supposed to handle errors in Tcl

Purpose: to discuss the variety of coding techniques available in Tcl for handling errors.


There are a number of types of errors that Tcl programs can encounter. I am going to write about one particular one - but Tcl'ers should feel free to add information about handling other types of errors as they have time.

One of the more annoying errors Tcl programers encounter occurs when a program being exec'd terminates with a non-zero exit code. Tcl by default considers that an error condition that should terminate the program. However, there are various programs whose exit codes are in some way significant. One of the first a Unix Tcl programmer usually encounters is the problem that arises when exec-ing grep, the general regular expression printer, which searches through an input file looking for patterns and outputting the lines which match. The exit code from grep indicates either an error, no lines matched, or success.

In this article[L1 ]:

   From: [email protected] (Cameron Laird)
   Subject: Re: grep
   Date: 4 Jul 1999 17:24:32 -0500
   Message-ID: <[email protected]>

Cameron provides us with a tcl idiom for invoking grep or other commands which terminate with non-zero return codes.

  if [catch {exec grep $pattern $file} result] {
    puts "We found nothing."
  } else {
    puts "We found $result."
  }

Of course in real usage, one would replace the "We found nothing" with code to handle the error condition, and the else code would handle a successful condition.

WARNING! The above idiom doesn't indicate what will happen to the command's error messages. This all depends on the command itself. A program executing a command which writes errors to a console or the current tty will find the output appearing. Grep on some platforms writes its error to stderr, which means that neither the program nor the user will see it.


If you have a look at the global variable errorCode when the catch command above indicates that an error was caught, you will find all sorts of useful info available.

If the first word of the list contained within was CHILDSTATUS then you know that the command you ran (grep in this case) exited with some indication of a failure code. The most common case where this happens in our example is when the pattern doesn't exist in the file.

If the first word of the list contained within was NONE (in fact that is the whole of the list) then you know that there was no non-zero exit status - the error is purely due to the fact that some output was generated on stderr.

There are several other possible error codes; see the tclvars(n) manpage for more details.

DKF


DKF: With Tcl 8.6, we can do this all relatively simply through the use of the try command:

try {
    set result [exec grep $pattern $file]
} trap CHILDSTATUS {msg opt} {
    if {[lindex [dict get $opt -errorcode] 2] == 1} {
        # grep has exit code 1 when nothing found
        set result {}
    } else {
        # It's a real error!
        return -options $opt $msg
    }
}

Irritatingly, the CHILDSTATUS exception puts the exit code and the child process id in an order where we can't do the match directly with the trap clause...


See also: