www.gibmonks.com




  Previous section   Next section

Practical Programming in Tcl & Tk, Third Edition
By Brent B. Welch

Table of Contents
Chapter 13.  Reflection and Debugging


The info Command

Table 13-4 summarizes the info command. The operations are described in more detail later.

Table 13-4. The info command.
info args procedureA list of procedure's arguments.
info body procedureThe commands in the body of procedure.
info cmdcountThe number of commands executed so far.
info commands ?pattern?A list of all commands, or those matching pattern. Includes built-ins and Tcl procedures.
info complete stringTrue if string contains a complete Tcl command.
info default proc arg varTrue if arg has a default parameter value in procedure proc. The default value is stored into var.
info exists variableTrue if variable is defined.
info globals ?pattern?A list of all global variables, or those matching pattern.
info hostnameThe name of the machine. This may be the empty string if networking is not initialized.
info levelThe stack level of the current procedure, or 0 for the global scope.
info level numberA list of the command and its arguments at the specified level of the stack.
info libraryThe pathname of the Tcl library directory.
info loaded ?interp?A list of the libraries loaded into the interpreter named interp, which defaults to the current one.
info locals ?pattern?A list of all local variables, or those matching pattern.
info nameofexecutableThe file name of the program (e.g., of tclsh or wish).
info patchlevelThe release patch level for Tcl.
info procs ?pattern?A list of all Tcl procedures, or those that match pattern.
info scriptThe name of the file being processed, or the empty string.
info sharedlibextensionThe file name suffix of shared libraries.
info tclversionThe version number of Tcl.
info vars ?pattern?A list of all visible variables, or those matching pattern.

Variables

There are three categories of variables: local, global, and visible. Information about these categories is returned by the locals, globals, and vars operations, respectively. The local variables include procedure arguments as well as locally defined variables. The global variables include all variables defined at the global scope. The visible variables include locals, plus any variables made visible via global or upvar commands. A pattern can be specified to limit the returned list of variables to those that match the pattern. The pattern is interpreted according to the rules of string match, which is described on page 48:

info globals auto*
=> auto_index auto_noexec auto_path

Namespaces, which are the topic of the next chapter, partition global variables into different scopes. You query the variables visible in a namespace with:

info vars namespace::*

Remember that a variable may not be defined yet even though a global or upvar command has declared it visible in the current scope. Use the info exists command to test whether a variable or an array element is defined or not. An example is shown on page 90.

Procedures

You can find out everything about a Tcl procedure with the args, body, and default operations. This is illustrated in the following Proc_Show example. The puts commands use the -nonewline flag because the newlines in the procedure body, if any, are retained:

Example 13-2 Printing a procedure definition.
proc Proc_Show {{namepat *}{file stdout}}{
   foreach proc [info procs $namepat] {
      set space ""
      puts -nonewline $file "proc $proc {"
      foreach arg [info args $proc] {
         if [info default $proc $arg value] {
            puts -nonewline $file "$space{$arg $value}"
         } else {
            puts -nonewline $file $space$arg
         }
         set space " "
      }

      # No newline needed because info body may return a
      # value that starts with a newline

      puts -nonewline $file "}{"
      puts -nonewline $file [info body $proc]
      puts $file "}"
   }
}

Example 13-3 is a more elaborate example of procedure introspection that comes from the direct.tcl file, which is part of the Tcl Web Server described in Chapter 18. This code is used to map URL requests and the associated query data directly into Tcl procedure calls. This is discussed in more detail on page 247. The Web server collects Web form data into an array called form. Example 13-3 matches up elements of the form array with procedure arguments, and it collects extra elements into an args parameter. If a form value is missing, then the default argument value or the empty string is used:

Example 13-3 Mapping form data onto procedure arguments.
# cmd is the name of the procedure to invoke
# form is an array containing form values

set cmdOrig $cmd
set params [info args $cmdOrig]

# Match elements of the form array to parameters

foreach arg $params {
   if {![info exists form($arg)]} {
      if {[info default $cmdOrig $arg value]} {
         lappend cmd $value
      } elseif {[string compare $arg "args"] == 0} {
         set needargs yes
      } else {
         lappend cmd {}
      }
   } else {
      lappend cmd $form($arg)
   }
}
# If args is a parameter, then append the form data
# that does not match other parameters as extra parameters

if {[info exists needargs]} {
   foreach {name value} $valuelist {
      if {[lsearch $params $name] < 0} {
         lappend cmd $name $value
      }
   }
}
# Eval the command

set code [catch $cmd result]

The info commands operation returns a list of all commands, which includes both built-in commands defined in C and Tcl procedures. There is no operation that just returns the list of built-in commands. Example 13-4 finds the built-in commands by removing all the procedures from the list of commands.

Example 13-4 Finding built-in commands.
proc Command_Info {{pattern *}}{
   # Create a table of procedures for quick lookup

   foreach p [info procs $pattern] {
      set isproc($p) 1
   }

   # Look for command not in the procedure table
   set result {}
   foreach c [info commands $pattern] {
      if {![info exists isproc($c)]}{
         lappend result $c
      }
   }
   return [lsort $result]
}

The Call Stack

The info level operation returns information about the Tcl evaluation stack, or call stack. The global level is numbered zero. A procedure called from the global level is at level one in the call stack. A procedure it calls is at level two, and so on. The info level command returns the current level number of the stack if no level number is specified.

If a positive level number is specified (e.g., info level 3), then the command returns the procedure name and argument values at that level in the call stack. If a negative level is specified, then it is relative to the current call stack. Relative level -1 is the level of the current procedure's caller, and relative level 0 is the current procedure. The following example prints the call stack. The Call_trace procedure avoids printing information about itself by starting at one less than the current call stack level:

Example 13-5 Getting a trace of the Tcl call stack.
proc Call_Trace {{file stdout}}{
   puts $file "Tcl Call Trace"
   for {set x [expr [info level]-1]}{$x > 0}{incr x -1}{
      puts $file "$x: [info level $x]"
   }
}

Command Evaluation

If you want to know how many Tcl commands are executed, use the info cmdcount command. This counts all commands, not just top-level commands. The counter is never reset, so you need to sample it before and after a test run if you want to know how many commands are executed during a test.

The info complete operation figures out whether a string is a complete Tcl command. This is useful for command interpreters that need to wait until the user has typed in a complete Tcl command before passing it to eval. Example 13-6 defines Command_Process that gets a line of input and builds up a command. When the command is complete, the command is executed at the global scope. Command_Process takes two callbacks as arguments. The inCmd is evaluated to get the line of input, and the outCmd is evaluated to display the results. Chapter 10 describes callbacks why the curly braces are used with eval as they are in this example:

Example 13-6 A procedure to read and evaluate commands.
proc Command_Process {inCmd outCmd}{
   global command
   append command(line) [eval $inCmd]
   if [info complete $command(line)] {
      set code [catch {uplevel #0 $command(line)}result]
      eval $outCmd {$result $code}
      set command(line) {}
   }
}
proc Command_Read {{in stdin}}{
   if [eof $in] {
      if {$in != "stdin"}{
         close $in
      }
      return {}
   }
   return [gets $in]
}
proc Command_Display {file result code}{
   puts stdout $result
}
while {![eof stdin]}{
   Command_Process {Command_Read stdin}\
      {Command_Display stdout}
}

Scripts and the Library

The name of the current script file is returned with the info script command. For example, if you use the source command to read commands from a file, then info script returns the name of that file if it is called during execution of the commands in that script. This is true even if the info script command is called from a procedure that is not defined in the script.

graphics/tip_icon.gif

Use info script to find related files.


I often use info script to source or process files stored in the same directory as the script that is running. A few examples are shown in Example 13-7.

Example 13-7 Using info script to find related files.
# Get the directory containing the current script.
set dir [file dirname [info script]]

# Source a file in the same directory
source [file join $dir helper.tcl]

# Add an adjacent script library directory to auto_path
# The use of ../lib with file join is cross-platform safe.
lappend auto_path [file join $dir ../lib]

The pathname of the Tcl library is stored in the tcl_library variable, and it is also returned by the info library command. While you could put scripts into this directory, it might be better to have a separate directory and use the script library facility described in Chapter 12. This makes it easier to deal with new releases of Tcl and to package up your code if you want other sites to use it.

Version Numbers

Each Tcl release has a version number such as 7.4 or 8.0. This number is returned by the info tclversion command. If you want your script to run on a variety of Tcl releases, you may need to test the version number and take different actions in the case of incompatibilities between releases.

The Tcl release cycle starts with one or two alpha and beta releases before the final release, and there may even be a patch release after that. The info patchlevel command returns a qualified version number, like 8.0b1 for the first beta release of 8.0. We switched from using "p" (e.g., 8.0p2) to a three-level scheme (e.g., 8.0.3) for patch releases. The patch level is zero for the final release (e.g., 8.2.0). In general, you should be prepared for feature changes during the beta cycle, but there should only be bug fixes in the patch releases. Another rule of thumb is that the Tcl script interface remains quite compatible between releases; feature additions are upward compatible.

Execution Environment

The file name of the program being executed is returned with info nameofexecutable. This is more precise than the name in the argv0 variable, which could be a relative name or a name found in a command directory on your command search path. It is still possible for info nameofexecutable to return a relative pathname if the user runs your program as ./foo, for example. The following construct always returns the absolute pathname of the current program. If info nameofexecutable returns an absolute pathname, then the value of the current directory is ignored. The pwd command is described on page 115:

file join [pwd] [info nameofexecutable]

A few operations support dynamic loading of shared libraries, which are described in Chapter 44. The info sharedlibextension returns the file name suffix of dynamic link libraries. The info loaded command returns a list of libraries that have been loaded into an interpreter. Multiple interpreters are described in Chapter 19.


      Previous section   Next section
    Top