:TITLE: Substitution without evaluation - format, subst ;# ;# RCSID: $Header: /cvsroot/tcl/tcltutorial/original/Tcl34.lsn,v 1.1 2004/11/04 16:01:14 davidw Exp $ ;# Copyright (c) 1995 Clif Flynt ;# 9300 Fleming Rd. ;# Dexter, MI 48130 ;# clif@cflynt.com ;# See file "NOTICE" for licensing terms. ;# :LESSON_TEXT_START_LEVEL 0: The Tcl interpreter does only one substitution pass during command evaluation. Some situations, such as placing the name of a variable in a variable, require two passes through the substitution phase. In this case, the subst command is useful. It performs a substitution pass without performing any execution of commands except those required for the substitution to occur, ie: commands within [] will be executed, and the results placed in the return string.
The format command can also be used to force some levels of substitution to occur.
If any of the -no... arguments are present, then that set of substitutions will not be done.
NOTE: subst does not honor braces or quotes.
Subst performs a substitution pass without performing any execution of commands except those required for the substitution to occur, ie: commands within [] will be executed, and the results placed in the return string.
In the example code: puts "[subst $$c]\n"
The format command can also be used to force some levels of
substitution to occur.
If any of the -no... arguments are present, then that set of substitutions will not be done.
NOTE: subst does not honor braces or quotes.
In Tcl this concept can be implemented by placing the name of another variable in a variable.
For example:
set a "alpha"
set c a
Now, the variable c contains the name of the variable (a) that
actually contains the data (alpha).
If you were to try and print the value alpha, you might try something like:
puts "$$c"
This won't work. It will print out $a.
This is because Tcl only makes one pass at substitution. If a variable requires two substitution passes, it won't happen.
The subst command is the solution to this problem. When a string is passed to the subst it passes through the normal Tcl substitution phase, and then within subst it is passed through a second substitution phase. The result of the two substitution phases is returned.
The format command can also be used to force some levels of substitution to occur.
Run the example, and follow along with this explanation.
The first line in the example:
set a "alpha"
just assigns a simple string to a variable.
The next line:
set b a
Sets the variable b to contain the name of the variable a.
The next two lines show the results from executing puts with the arguments within braces (no substitution at all) or within quotes (one pass of substitution when Tcl evaluates the command).
The two lines after that show the same arguments, but process the argument with the subst command before evaluating the puts Note that using braces around the argument causes subst to perform a single pass of substitution, just as is done by the Tcl interpreter. If the arguments are enclosed in quotes, then there is a pass of substitution when subst is evaluated, and then within subst, a second pass of substitution occurs. When the string $$b is substituted while evaluating the arguments for the call to subst, it gets substituted with $a, and then within the subst command the string gets substituted with alpha.
The next three lines show two different methods of forcing the second substitution phase to occur. The first example is just using format, and getting no substitution. The next line shows the output of format ($a) being used as the argument to subst. This causes two passes of the substitution to occur, and alpha is output.
The third of these lines shows the puts ... command being evaluated by eval. In this case, the $b is replaced by a when the format command is evaluated. This creates the string:
"puts \"eval after format: $a\""
When that string is passed to eval, another pass of substitutions
occurs, and the $a is replaced with the string alpha.
The final seven lines in this example show how the tempFileName proc
that was defined in the previous two lessons could also be defined
using the format command. The third line of this example,
set cmd [format "%s {global num; incr num;" $cmd], just appends the
string {global num: incr num; to cmd.
The fourth line: set cmd [format {%s return "/tmp/TMP.%s.$num"} $cmd [pid] ]
appends the text return "/tmp/TMP.%s.$num to cmd, and also
substitutes the %s with the return from pid. Because the
format string is within braces, $num is not substituted.
The last line of this example shows the body of the tempFileName proc. This is the same as the body that was created in the previous lessons using the list commands.
If you need to pass the name of an array to a proc, and then access
a value within that array, the format command can be used, as shown in
the last example. If you use a line like it will try to evaluate the value
of the $b index into array a, instead of substituting
$a with the value of a, and $b with the value of
b.
eval [set $a($b) $c]
If any of the -no... arguments are present, then that set of substitutions will not be done.
NOTE: subst does not honor braces or quotes.