Tcl Language Usage Questions And Answers

INTRODUCTION

This FAQ file is intended to address some of the most commonly asked questions regarding the Tcl programming language. It is hoped that by addressing these here in this document, that the postings to comp.lang.tcl will be of a less repetitive and more informative nature. It is also hoped that via this and other available resources, more and more people will be able to utilize Tcl and Tcl based applications.

This FAQ is maintained by Joe Moss (joe@morton.rain.com) and is posted monthly to comp.lang.tcl and news.answers and can also be obtained from the Tcl archive at ftp.aud.alcatel.com (198.64.191.10) in the /tcl/docs directory or via the World Wide Web as http://route.psg.com/tcl.html.

Note that this FAQ deals with Tcl, not with Tk. For Tk Toolkit Q&As see the FAQ posting by Thomas J. Accardo (tja@cpu.com) (see the question below, entitled "Where can I get further info about Tcl" for pointers to other Tcl FAQs). However, there is some inevitable overlap. Some of the most commonly asked questions about usage of the Tk widgets are due to mis-understandings of how the Tcl interpreter works. These issues may still be addressed here. Also, some examples of Tcl usage may involve the use of the Tk widgets.

Questions and Answers about the use of non-Tk related extensions (such as Extended Tcl and Expect, but not TkX, expectk, BLT, etc.) are also appropriate here.

The source of this document is now maintained in HTML. It is then run through a couple of scripts (written in Tcl, of course) to automagically add question numbers, generate the Index of Questions, and add the From and Subject lines to the text version. The version available via the WWW will be updated whenever there are changes, while the ASCII text version will be generated and posted only once a month.

Last modified: Wed Mar 08 01:13:54 PST 1995


Index of Questions:

General Information:

Programming Related Questions and Answers:

Platform specific and portability related questions:


General Information:

Q1- Where can I get further info about Tcl?

The newsgroup comp.lang.tcl is for discussion of the Tcl language and packages based on it. There are several FAQ documents related to Tcl available from ftp.aud.alcatel.com in the /tcl/docs directory that provide further information and pointers to yet more reading material, both on-line and in print. They can also be accessed via the World Wide Web: http://www.cis.ohio-state.edu/hypertext/faq/usenet/tcl-faq/top.html

Two other good starting points, if you are surfing the Web for information, are: http://www.sco.com/IXI/of_interest/tcl/Tcl.html and http://web.cs.ualberta.ca/%7Ewade/HyperTcl/.

Of course, the source distribution itself includes a great deal of documentation. The latest version is 7.3, with the 7.4b2 beta release also available. Both can be obtained from: ftp://ftp.cs.berkeley.edu/ucb/tcl/.

Q2- Where can I find help getting Tcl to work on my machine?

Look in the Tcl distribution for the file called porting.notes. This will contain a collection of notes that various people have provided about porting Tcl to various machines and operating systems. There is also a file called README which should be read FIRST - before doing anything else with the code (this should always be one's first step with any package).

There are also several questions and answers related to building the interpreter on various platforms at the end of this document.

Q3- How can I combine Tcl and C?

Tcl was intended to be used along with C code. Because of this, there are several ways to combine the two. Here is a list of some of them (with man page references for further info):

The last two do not provide nearly the same level of integration as those near the top of the list, but they are necessary if you do not have access to the source code.

There is plenty of documentation available that explains this in further detail. See the TclCommandWriting man page, included with Extended Tcl or available via the WWW at http://psg.com/~joem/CmdWrite.html

See also part two of Larry's Tcl FAQ and the Tcl Bibliography for other references.

In addition to all the ways possible with standard Tcl, several extensions add others, notably via pseudo-ttys with expect, and via X event, file event, timer, and idle callback handlers with Tk. Also check out Embedded Tk, available from ftp://ftp.std.com/pub/drh/

Q4- How do I combine several extensions to provide all the features I want?

The simple answer is to create a custom Tcl_AppInit function to call the Init procedures for each of the desired extensions. This can be done by copying the tclAppInit.c (tkAppInit.c for Tk apps) file from Tcl source distribution, modifying it, and then linking your Tcl_AppInit function with the Tcl library. For example, the standard Tcl_AppInit looks like this:

    int
    Tcl_AppInit(interp)
        Tcl_Interp *interp; /* Interpreter for application. */
    {
        /* ... */

        if (Tcl_Init(interp) == TCL_ERROR) {
            return TCL_ERROR;
        }

        /* ... */
    }

In order to add the foo extension, you would add a call to the foo init function, like this:

    int
    Tcl_AppInit(interp)
        Tcl_Interp *interp; /* Interpreter for application. */
    {
        /* ... */

        if (Tcl_Init(interp) == TCL_ERROR) {
            return TCL_ERROR;
        }

        if (Foo_Init(interp) == TCL_ERROR) {
            return TCL_ERROR;
        }

        /* ... */
    }

For more information, see the Tcl_AppInit man page and the tclAppInit.c file.

The more complete answer is that the simple answer doesn't always work. Many extensions require more extensive modifications and the way to combine them depends on the specific extensions involved.

If you wish to include Extended Tcl, you should start with the Tcl_AppInit function that comes with it. Also make sure when you link the program that you include the Extended Tcl library before the standard Tcl library, for example:

    cc -o mytclsh mytclXAppInit.c -ltclx -ltcl ...

or for an interpreter including the Tk extensions:

    cc -o mywish mytkXAppInit.c -ltkx -ltk -ltclx -ltcl ...

On the positive side, there are also several packages available that can aid in combining extensions, such as Make-A-Wish, or extensions that include configuration files for combining them with other popular extensions. For example, several extensions written by Sven Delmas allow you to specify options to configure to generate a Makefile that will build an interpreter containing the specified extensions. See part four of Larry Virden's FAQ for the location of these and other packages.

Q5- What about dynamic loading?

The issue of dynamic loading appears fairly often in comp.lang.tcl and yes, the ideal method of combining extensions would be to use dynamic loading, but the standard Tcl distribution does not currently support it.

The syntax of the load command has pretty much already been worked out. It is just a matter of implementing it on a large number of platforms (this is something that is definately platform dependent).

Here is an excerpt from a message, dated 14 Jul 1993, written by John Ousterhout on the subject:

At the [1993 Tcl] workshop we decided to standardize on a simple Tcl command interface for dynamic loading. The command syntax will be as follows:

        load <file>

where <file> is the name of a dynamically-loadable object file such as libtcl.so. The syntax of these names may vary from system to system according to local custom, but part of the name should be the package prefix for the package, such as tcl in the above example.

The load command must load the given object file, pick the package prefix out of the file name, then invoke the procedure <prefix>_Init, where <prefix> is the package prefix with the first letter capitalized, e.g. Tcl_Init or Dp_Init or Tclx_Init. Each loadable package must contain an initialization procedure that takes a single argument that is a (Tcl_Interp *):

        int Dp_Init(Tcl_Interp *interp);
The init procedure adds all of that package's Tcl commands into the interpreter, plus performs any other package-specific initialization. It returns a standard Tcl completion code and leaves an error message or result value in the interpreter, which is returned as the result of the load command.

Implementations for certain platforms are already available, check the software catalog (parts four and five of Larry Virden's FAQ) for details (e.g. the Shells package) and also see the paper by Kevin Kenny from the 1994 Tcl workshop proceedings available from http://crdis1.ge.com/papers/gecrd/mtl/mdip/tcl94/00header.html. Hopefully soon this will become part of the standard distribution.

Q6- How do I create a stand alone program in case Tcl isn't installed?

Earle Lowe (lowee@cpsc.ucalgary.ca) has replied that:

If you want to create a stand-alone program that will run anywhere regardless of the presence/absence of TCL/Tk, than you need to go through some more work.

Basically, this involves converting the TCL init files to C strings, and then rather than calling Tcl_Init() and Tk_Init(), you call Tcl_Eval() with the converted C strings as arguments.

I suggest getting the wish_compiler package by Alexei Rodriguez (alexei@cis.ufl.edu) from ftp://ftp.aud.alcatel.com/tcl/code/wish_compiler.shar.gz

This package contains a tcl2c converter, and instructions as to its use.

With some Makefile magic, you can use using TCL/Tk as intended (as an interpreted language using some version of wish) and when the code works, you can create a stand-alone compiled program.

Another option that is now available is "Embedded Tk". You can get it from ftp://ftp.std.com/pub/drh/

Q7- How do I make my script executable regardless of the location of tclsh?

Or how can I automatically pass my script through tclsh without specifying a fixed path?

There are several tricks you can use, but the most common is to make use of the fact that, in Tcl, the backslash character works as a line continuation indicator, even within comments. So instead of:

	#! /usr/local/bin/tclsh

	puts "Hello World"
You could use:
	#! /bin/sh
	# The next line is executed by /bin/sh, but not Tcl \
	  exec tclsh $0 ${1+"$@"}

	puts "Hello World"
and the script will run regardless of where tclsh is located (as long as it is in one of the directories in the user's PATH).

Q8- Why isn't <some extension> part of the standard distribution?

Often people ask why some language extension that they use often (in fact, they may find it indispensible) isn't merged into the core language.

It must be remembered that a lot of people use Tcl on widely differing systems and in vastly different ways. Also, Tcl was originally intended as an embedded language that would provide the minimal programming constructs and framework upon which a programmer could base the scripting language for their application.

Having said that, the core Tcl language has grown over the years. Some of the added features have come from extensions written by others. When the capabilities provided by extensions are deemed to be of sufficient value to all users of Tcl, John has added them to the base language. Some examples are associative arrays, the file I/O commands (and file handles), and the unknown procedure, all of which appeared in Extended Tcl before becoming part of standard Tcl. Tk 4.0 will contain (and Tk4.0b2 does now contain) the equivalent functionality of the addinput and photo widget extensions that were written by others for Tcl 7.x/Tk 3.x.


Programming Related Questions and Answers:

Q9- How can I create/use association lists or property lists?

Use arrays or Extended Tcl keyed lists.

For example, if you did a:

    keylset ttyFields ttyName tty1a
    keylset ttyFields baudRate 57600
    keylset ttyFields parity strip

And then an echo $ttyFields, you'd get:

    {ttyName tty1a} {baudRate 57600} {parity strip}

Or using arrays:

    set ttyFields(ttyName)  tty1a
    set ttyFields(baudRate) 57600
    set ttyFields(parity)   strip

Q10- How can I generate a random number in Tcl?

Extended Tcl includes a command named random to do this. For example, to generate a random number between 0 and 9 inclusive:

    set random_number [random 10]

It also has a srandom command to seed the random number generator.

Several pseudo-random number generator functions, written in straight Tcl, have been posted to comp.lang.tcl, see Larry's tcl-faq/part4 for a list.

To get a value you can use as a seed, you might try one (or a combination) of these:

    [pid]
    [file atime /dev/kmem]
    [getclock]        (Extended Tcl only)

Q11- How can I call one proc with the multi parameter value returned by another proc?

Assuming y requires multiple args and x returns multiple words, use Tcl's eval command:

    eval y [x]

Q12- How can I pass an array into a proc?

Use upvar rather than try to use global variables when possible. If the function is event driven, you are forced to use global variables.

    # print elements of an array
    proc show_array arrayName {
        upvar $arrayName myArray

        foreach element [array names myArray] {
           puts stdout "${arrayName}($element) =  $myArray($element)"
        }
    }

    set arval(0) zero
    set arval(1) one
    show_array arval

To return an array from a procedures, just take the array name in as an argument, as above. Any changes you make in the array will be made in the parent's array as well.

Extended Tcl introduces a concept called keyed lists which are arrays made out of lists of key-value pairs and can be passed by value to routines, over networks, etc.

Q13- How can I run an external command and read its output via a pipe?

For example, to grep a pattern out of a range of files, one might do:

Karl Lehenbauer (karl@NeoSoft.com) writes:

    set files [glob /home/cole/stats/*]

    proc parseInfo { site } {
       global files

    #
    # site is chosen from a listbox earlier
    #
       set in [open [concat "|/usr/bin/grep $site $files"] r]

       while {[gets $in line]>-1} {
          puts stderr $line
       }
       catch {close $in}
    }

One thing: the matching strings are not returned in directory order.

But what if I want to check the return code AND use the output of the command? Kevin B. Kenny (kennykb@dssv01.crd.ge.com) writes:

    if [catch {exec ls} data] {
        # The exec got an error, and $errorCode has its termination status
    } else {
        # The exec succeeded
    }
    # In any case, `data' contains all the output from the child process.

Note that Karl Lehenbauer (karl@NeoSoft.com) adds that errorCode will be a list containing three elements, the string "CHILDSTATUS", the process ID of the child, and the exit status of the child.

Q14- How can I delete a procedure from within a script?

Rename the procedure to have no name, for example:

    rename procedureName ""

Q15- How can I get more than 7 digits of double precision?

In Tcl 7.x, set the global variable tcl_precision to a value in the range 1-17. For example:
    % expr 4*atan(1)
    3.14159
    % set tcl_precision 0
    can't set "tcl_precision": improper value for precision
    % set tcl_precision 3
    3
    % expr 4*atan(1)
    3.14
    % set tcl_precision 16
    16
    % expr 4*atan(1)
    3.141592653589793
    % set tcl_precision 18
    can't set "tcl_precision": improper value for precision

In Tcl 6.x, you must modify the tclExpr.c module to use %lf instead of %g.

Q16- How can I grab the command line when a non-built-in call is made?

The procedure unknown is called automatically with arguments containing the command and its arguments for any command that couldn't be found. In fact, Tcl and Extended Tcl use this feature to provide demand loaded commands, and even entire libraries. Also, when using the "tclsh" or "tcl" shells interactively, the unknown procedure enables the shell to run external programs (i.e. without typing "exec" first).

So by modifying the unknown procedure you can provide your own extended functionality, or even remove the demand loading capability if you so desire.

Q17- How can I get or set an environment variable?

By using something like the following.

    set olddisplay $env(DISPLAY)
    set env(DISPLAY) unix:0

Thanks to Joel Fine (joel@cs.berkeley.edu) for the answer.

You can also check if an environment variable exists, like this:

    if [info exists env(VARNAME)] {
        # okay, it's there use it
        set value $env(VARNAME)
    } else {
        # the environment var isn't set, use a default
        set value "the default value"
    }

Q18- How can I use numbers with leading zeroes?

Dave Morriss was having problems because he was trying to do something like:

    set index [expr [exec date +%W]%[llength $pop_server_list]]

but during the 8th and 9th week of the year, he got errors, since 08 and 09 are not valid octal numbers. Actually, Tcl first tries to interpret numbers starting with a zero as an octal number, but if that fails (i.e. because of invalid octal digits like 8 and 9), the value is then interpreted as a floating point value; the % (modulo) function only operates on integer values.

Some of the solutions provided were:

From George A. Howlett (george.howlett@att.com), we got:

    set wknum [format "%g" [exec date +%W]]
    set index [expr [exec $wknum%[llength $pop_server_list]]

From Fred Feirtag (feirtag@wave.nrl.navy.mil):

    set index [expr (1[exec date +%W]-100)%[llength $pop_server_list]]

From Dan R. Schenck (schendr@Texaco.com):

    set index [expr [string trimleft [exec date +%W] 0]%[llength \
             $pop_server_list]]

Jay Goldberg (jayg@accessware.com) points out that while all of the above work in this case (dealing with a date) they don't work in the general case.

Instead you can use the statement:

    regsub 0+(.+) orig_string \\1 new_string

to strip off leading zeros. So, applying this to the example above:

    regsub 0+(.+) [exec date +%W] \\1 weeknum
    set index [expr $weeknum%[llength $pop_server_list]]

Q19- How can I find the command line arguments to my application?

The program name is assigned to the global variable argv0 and any arguments to it are placed in the global variable argv as a list. The variable argc is set to the number of elements in the list argv. As an example:

    #! /usr/local/bin/tclsh

    if { $argc != 2 } {
	puts stderr "$argv0: Usage: $argv0 <infile> <outfile>"
	exit 1
    }

    set infile  [lindex $argv 0]
    set outfile [lindex $argv 1]

Q20- How can I put comments in my script, e.g. in a case statement?

You can't have comments where you have them. Move the comments inside of the { for the case that you want. Your code should read:

    case 1 {
      -1    {
            #
            # Cannot find information sought
            #
            exit 2
            }
       0    {
            #
            # Error in arguments
            #
            exit 1
            }
       default    {
            #
            # Desired information found
            #
            exit 0
            }
    }

Thanks to Gerald W. Lester (gwlester@cpu.com).

Q21- How can I input and output binary data?

With Extended Tcl you can safely do stuff like:

    set infp [open "|compress -dc $fileName"]
    set outfp [open "|gzip -c $newFileName" w]

    copyfile $infp $outfp

Thanks to Karl Lehenbauer (karl@NeoSoft.com) for the code example.

A method of handling binary data one character at a time using standard Tcl can be found in: ftp.aud.alcatel.com:/tcl/code/binary-io-hack.shar.gz

There are also two different extensions available that enable the handling of binary data: tclbin and BinarIO. The former is better for handling structured data, while the latter works better for binary data streams.

Q22- How can I trap signals, and perform other more Unix specific functions?

Extended Tcl offers many of these types of functions. For instance, extended Tcl has the signal command:

signal action siglist [command]

where action is one of "default", "ignore", "error", "trap", "get", plus the POSIX "block" and "unblock" actions (available only on POSIX systems, of course). Siglist is a list of either the symbolic or numeric Unix signal (the SIG prefix is optional). Command is your error handler (or a simple {puts stdout "Don't press *that* key!"} :-)

trap does what you expect, and I find error and get to be extremely useful in interactive programs which demand keyboard traversal.

Extended Tcl also has things like fork, etc.

Answer by Brad Morrison (brad@NeoSoft.com).

Q23- How can I do a double indirect? - Why doesn't $$var work?

There is one and only one level of substitution possible with every pass through the interpreter. Also, when doing variable substitution, the interpreter finds the dollar sign and then takes everything following it up until the next invalid character (where invalid is defined as anything other than a letter, digit, or underscore) as the name of the variable - well, that is, unless it finds array notation or the ${varname} form.

In the case of $$var, the character after the first dollar sign is an invalid character (another dollar sign), so there is no variable name and variable substitution is not performed (the dollar sign is left as is) and scanning starts again for any dollar signs and a following variable name. It is immediately found at that second dollar sign, the substitution is performed, and scanning for dollar signs resumes with whatever was after the variable name. Since there isn't anything else, substition is done for this pass through the interpreter (remember it's only done once).

The eval command runs it's arguments through the interpreter, so you could use eval to cause a second pass through the interpreter, and thus, have $$var work:

    % set a 5
    5
    % set var a
    a
    % puts $$var              # This doesn't work
    $a
    % eval puts $$var         # This does  - but it's dangerous
    5

However, if the contents of var contain any special characters (e.g. whitespace, semicolon) you'll run into problems.

A better method is to take advantage of the behaviour of the set command when given only one argument, and combine command substitution with variable substitution:

    % puts [set $var]         # This works safely
    5

or, in fact, you could use just command substitution (which is performed once for each [ ] pair):

    % puts [set [set var]]    # as does this
    5

Q24- How can I get quoted strings to work the way I want?

A long article dealing with the issues can be found at ftp://ftp.aud.alcatel.com/tcl/docs/README.programmer.gz

Here are some short answers:

Q. I'm trying to build up a command for later execution but am having trouble with variable values that include whitespace or special characters.

A. The safest way to build up commands is to use the list command so that you can keep track of the list structure. Avoid using double quotes because you can end up with an extra trip through the evaluator. We'll illustrate this with a command to create a button that prints out the label on the button when you click it.

Wrong answer #1:
    button $myname -text $label -command "puts stdout $label"
Why? because if $label has whitespace then the puts command will be passed the wrong number of arguments. If $label has $ or [ ] characters, they will be interpreted instead of printed.
Good answer #2:
    button $myname -text $label -command [list puts stdout $label]
Why? because list will properly quote the value of $label

Q. I'm trying to build up a command for later execution but am having trouble getting some variables to evaluate now, and some to evaluate later when the command is run.

A. The cleanest way to do this is to define a procedure that hides the use of the variables at run time, and then build up a call to that procedure using the list command as described previously. (You can even define the procedure on the fly. It will have global scope even it if is created within another procedure.)

Wrong answer #1:
    button $myname -text $label -command \
        [list puts stdout $ArrayOfDynamicStuff($label)]
Why? The array value will be substituted when the button is created, not later on when the button is clicked. Also, note that the command is executed at the global scope, so it is not necessary to include a "global ArrayOfDynamicStuff" in the command.
Wrong answer #2 (backquotes and list):
    button $myname -text $label -command \
        [list puts stdout \$ArrayOfDynamicStuff($label)]
Why? Here the list command and the backquote of $ are fighting with each other. The command ends up being something like:
    puts stdout {$ArrayOfDynamicStuff(foo)}
which prevents the substitution of the value of the array element.
Dubious answer #3 (backquotes and double-quotes):
    button $myname -text $label -command \
        "puts stdout \$ArrayOfDynamicStuff($label)"
Why? This only works if the value of $label has no special characters or whitespace.
Clean answer #4 (proc):
    proc doit { i } {
        global ArrayOfDynamicStuff
        puts stdout $ArrayOfDynamicStuff($i)
    }
    button $myname -text $label -command [list doit $label]
Why? Using little TCL procs for your button commands is a good habit because it eliminates most needs for fancy quoting, and it makes it easier to tweak the button command later on.

Q. I'm trying to pass along a variable number of args to another procedure but I'm having trouble getting the $args to expand right.

A. Avoid using eval and double quotes because that results in an extra trip through the interpreter. The eval command will do a concat of its arguments if there are more than one, so that pretty much eliminates the need to group things with double quotes. Let's extend the button example:

Wrong answer #1:
    proc mybutton { myname label args } {
        button $myname -text $label -command [list puts stdout $label] $args
    }
Why? All the extra arguments to mybutton are grouped into one list element that is but into the value of $args. However, the button command expects to see individual arguments, not a sub-list.
Wrong answer #2:
    proc mybutton { myname label args } {
        eval "button $myname -text $label -command [list puts stdout $label] $args"
    }
Why? The double quotes allow expansion of $label as well as $args, so if $label has any whitespace, the button command will be malformed
Good answer #3:
    proc mybutton { myname label args } {
        set cmd {button $myname -text $label -command [list puts stdout $label]}
        eval $cmd $args
    }
Why? Eval will first concatenate its two arguments and then run the result through the interpreter. Think of this as stripping off the outer curly braces from $cmd and $arg and making a single list with all the elements of both. $label will be evaluated exactly once, so the puts command will remain good, and whatever went into args will also be processed exactly one time.

Q. Why do I get a syntax error in an if/while/for statement?

A. You may have written something like

    wish: set foo bar
    wish: if {$foo == bar} {puts stdout bar}
    syntax error in expression "$foo == bar"

in which bar is interpreted as neither a string nor a variable, since strings as operands in expressions MUST be surrounded by double quotes or braces.

Change to

    wish: if {$foo == "bar"} {puts stdout bar}

or

    wish: if {$foo == {bar}} {puts stdout bar}

always in expressions, depending on if you want expansion performed or not.

Contributed by Jesper Blommaskog (d9jesper@dtek.chalmers.se).

Q25- How can I share procedures between multiple tcl applications?

Rather than sourcing the files explicitly, build a tcl library:

Step 1. Put the files in a common directory

Step 2. Build the tclIndex for the "library". I use a Makefile with a convention like:

    install.index:
        (cd ${DESTDIR}/tclscripts/lib; \
        echo 'source /usr/local/lib/tcl/init.tcl;\
        auto_mkindex . *.tk' | tcl ; exit 0)

Step 3. Modify your tcl scripts to reference the library:

e.g.:

    # local additions
    lappend auto_path /usr/local/lib/tcl_local $env(RDS_TCL_SCRIPTS)/lib

Now, as soon as your script tried to reference a procedure in the library, the "unknown" command autoloads the procedure for you.

Contributed by Joe VanAndel (vanandel@ncar.ucar.edu).

Q26- How can I get items inserted into a list?

A user asked why

    linsert $list 0 ..

did not result in .. being inserted into list.

Jesper Blommaskog (d9jesper@dtek.chalmers.se) replied:

When doing list operations other than lappend, you must save the returned value. This applies to list, lindex, lrange, and lreplace at least.

In this example, you would perhaps want to do something like:

    set list [ linsert $list 0 .. ] 

Q27- How can I perform a non-blocking read on a file identifier?

From Frank Smith (frank@arraysystems.nstn.ns.ca) we are told that if you have Extended Tcl, you can

    read $fileId [fstat $fileId size]

This will read only the number of bytes currently available on fileId and consequently will not block.

Q28- How can I read and write from a pipe without locking up?

The stdio package has an optimization for speed that buffers characters so that you can avoid un-necessary system calls. This isn't very good for interactive use so stdio changes it's behaviour if the file is a terminal. When you write to a pipe you are not writing to a terminal and so your output is buffered, similarly when the program at the other end of the pipe writes its response it is also buffered. The end result is the programs at both end of the pipe stall waiting for input. It is possible to force the buffers to be written using flush in Tcl and fflush() in C, often though, you don't have control over the program at the other end of the pipeline and in that case your only solution is to use a pseudo-teletype (pty). Unfortunately this isn't all that easy.

While this isn't directly supported in Tcl, the spawn command in expect opens a pty and starts a command.

Q29- How can I find what version I am running?

Well, there is no one answer to this. Tcl itself will tell you it's version if you type:

    info tclversion

On the other hand, to get the Tk version, you must use:

    puts $tk_version

Other extensions use other means (for example, Extended Tcl uses "infox version" to return it's version number).

Q30- How can I use variables to hold array names?

Eric Bleeker (ericbl@paramount.nikhefk.nikhef.nl) has written:

You may have written something like:
    % set foo "bar baz"
    bar baz
    % foreach aap $foo {
        set $aap(1) "something"
    }
    can't read "aap(1)": variable isn't array
This means Tcl tries to substitute the array element aap(1) which doesn't exist. To fix this use:
    % foreach aap $foo {
        set [set aap](1) "something"
    }
In this case two arrays bar and baz are created.

An alternative format is:

    % foreach aap $foo {
        set ${aap}(1) "something"
    }

Platform specific and portability related questions:

Q31- How can I create shared Tcl/Tk libraries on AIX

Dov Grobgeld (dov@menora.weizmann.ac.il) provided info on creating Tcl and Tk shared libraries under AIX 3.1.5:

For Tcl:
    cc -o tkshar.o *.o -bE:tclshar.exp -bM:SRE -berok -lX11 -lm
    ar r libtclshr tclshar.o
For Tk:
    cc -o tkshar.o *.o -bE:tkshar.exp -bM:SRE -berok -Ltcl -lX11 -lm -ltclshr
    ar r libtkshr tkshar.o
where tckshar.exp and tkshar.exp had lists of the external functions.

There are also problems with fonts on AIX and the IBM. A patch is needed from IBM to fix the X server so that fonts are working

Q32- Has anyone gotten Tcl to compile under HP-UX?

See the porting notes. Also, be aware that there have been some reports of Configure assuming that you should use the compatibility version of opendir() and that you have no dirent.h . This causes glob-ing to fail, as well as TclX's readdir, etc.

Changing tcl7.3 to remove the opendir compatibility file and removing the -DNO_DIRENT, -DUSE_DIRENT2 fixed it all up.

Q33- Has anyone gotten Tcl to compile under VMS?

Information from John Kimball (jkimball@src.honeywell.com) on May 4, 1993 was that he had gotten Tcl 6.7 and Tk 3.2 ported to VMS 5.5. See the catalog for the file information.

Q34- What does it take to get Tcl to compile under SCO Unix?

Add a "#undef select" to tkEvent.c, and remove the reference to TK_EXCEPTION around line 460 of main.c.

Tk uses its own scheme for allocating the border colors for its 3D widgets, which causes problems when running TK on a system with "PseudoColor" display class, and a 16-cell colormap.

If you can't go to eight bitplanes, you can instead start the server with a "-static" (Xsco) or "-analog" (Xsight) option, making the display class become "StaticColor". This makes the entire colormap read-only, and it will return the color that most closely maps to the desired color as possible.

This information is from Keith Amann (Keith_Amann@stortek.com).

Q35- Why do I get format and scan errors when I run tclTest?

That's a problem (scanf/printf) many systems seem to have. Don't worry too much about it - just don't use these 'advanced' features. If you're hacking C, you'll have the same problems.

For instance, printf("%Ng", double_value) and strtod("+",&terminal) produce incorrect results.

Q36- Why do I get lots of errors under Irix 4.0.1 when I run tclTest?

There's a bug in the 4.0.1 optimizer that's fixed in 4.0.2. Compile tclVar.c using -O0 (no optimization).

Q37- Does anyone else have problems with Tcl on a Cray?

See the porting notes for a set of changes mentioned. Also, Booker C. Bense (benseb@grumpy.sdsc.edu) reports that version 3.0.1.6 has some real problems with char pointers, causing Tcl to crash. Using version 3.0.2.1, things are much better, except for a minor formatting problem and serious problems with scan.

Q38- How do I install Tcl 7.1/Tk 3.4 on NeXTSTEP 3.1?

I have indicated in the past that this particular question seems to generate controversy - I have replaced previous explanations with the latest msg from someone who sounds authoritative...

From: Robert Nicholson (robert@steffi.demon.co.uk)

This is for TCL7.1 and TK3.4

This is a variation on Thomas Funke's entry.

Q39- Installing TCL7.1 on NeXT

To install tcl7.1 on NeXTSTEP 3.1 you must:

At this point you probably want to rename the all calls to strtod and tmpnam to something else in order to distinguish them from those that are supplied in the NeXT libraries libsys_a.a. You can do this by adding the following line to AC_FLAGS

    -Dstrtod=newstrtod -Dtmpnam=newtmpnam

and renaming the names of the definitions in the appropriate compat/*.c files.

To check everything is working correctly open a tclsh

    % expr {"0" == "+"} 
    0

Using the wrong strtod function will cause this test to return 1 which is a serious error. Ignore the precision errors.

Q40- Installing TK3.4 on NEXTSTEP 3.1

There is a call to strtod in TK3.4 so you should link against ../tcl-7.1/compat/strtod.o and apply the -Dstrtod=newstrtod to AC_FLAGS in Tk also.

Note:Tk's raise test will fail when running the tvtwm window manager. Changing to either twm or even better fvwm ensures that this test will succeed.

Q41- Why can't I print the draft of the Tcl/Tk book?

From John Ousterhout (John.Ousterhout@Eng.Sun.COM):

Here's my form letter that seems to explain most of the problems people have had printing parts of the book:

Some old versions of the Transcript spooler software cannot properly handle encapsulated Postscript files within another Postscript file when they do page reversal. They tend to garble the page structure of the file, causing an error at the point of the first EPS file. Part II of the Tcl book has lots of EPS files embedded in it, one for each screen dump. If your printer cannot print this file I suggest checking to see if page reversal is enabled for your printer. If so, try asking your local system wizard to disable it for you; this should allow the file to print. Or, find some other way to dump the Postscript file directly to the printer without going through the spooling software (e.g. perhaps you can simply cat it to the printer's serial port).

Others have suggested:

The embedded pictures have CR as the line separator instead of LF and this may be causing the problem. Try translating them to LFs ...

    tr '\015' '\012' <book.p2.ps >fixedbook.p2.ps

and:

This is not the original poster's problem but in countries using A4 paper and on a particular printer, the Dataproducts LZR1260E, the frame size causes the printing to be stretched vertically. This happens with other Framemaker generated documents by the way. A PS interpreter bug no doubt. The fix is to edit the dimensions for A4 paper. This shell script does both fixes.

    #!/bin/sh
    cat $1 | tr '\015' '\012' | sed '/FMDOCUMENT$/s/612 792/595 842/'

Q42- Why am I getting errors on my SGI Indigo workstation?

From Gordon Lack (gml4410@ggr.co.uk) we are told that the SGI c compiler has some bugs with variable arguments.

tclVar.c must be compiled with -O0 at IRIX C 4.0.1 because of a compiler bug with varargs.

Done by placing specific rule into Makefile.

    # GGR SG needs -O0 for varargs at 4.0.1

    CC_SWITCHES0 =  -O0 -I. -I${SRC_DIR} ${AC_FLAGS} ${MATH_FLAGS} \
          ${GENERIC_FLAGS} ${PROTO_FLAGS} ${MEM_DEBUG_FLAGS} \
          -DTCL_LIBRARY=\"${TCL_LIBRARY}\"

    tclVar.o: tclVar.c
          $(CC) -c $(CC_SWITCHES0) $<

Peter Neelin (neelin@pet.mni.mcgill.ca) also noted that:

I get tclX 7.3a to compile on an SGI (irix 4.0.5) with the following changes to the Config.mk file:

    71c71
    < CFLAGS=-cckr -D__GNU_LIBRARY__
    ---
    > #CFLAGS=
    106,107c106,107
    < TCL_PLUS_BUILD=TCL_PLUS
    < CCPLUS=g++
    ---
    > #TCL_PLUS_BUILD=TCL_PLUS
    > CCPLUS=CC
    191,193c191
    < MAN_DIR_SEPARATOR=
    < 
    < LIBOBJS=strftime.o
    ---
    > #MAN_DIR_SEPARATOR=.

The -D__GNU_LIBRARY solves the srandom problem and I think that the -cckr gets around the prototype error with waitpid (it's crude, but it works). I've forgotten why I needed the strftime.

If you want the version of Config.mk that worked for me, send me mail.

Q43- How do I build expect on Solaris 2.3?

From Jeff Abramson (jra@hrcms.jazz.att.com) we are told that,

using either SunPro cc 2.0.1 or gcc 2.5.8 with no problems. For SunPro I do:
    CC=cc ./configure --prefix=directory_of_your_choice
    make CC=cc

For gcc I do:

    CC="gcc -fwritable-strings" ./configure \
        --prefix=directory_of_your_choice
    make CC="gcc -fwritable-strings"

Q44- How do I port Tcl and Tk to a Sequent?

From Andrew Swan (aswan@soda.berkeley.edu) we find:

For both Tcl and Tk, I used gcc rather than the Sequent cc which is not ansi.

For Tcl, there were a couple of problems with the math library. First, the Sequent math library doesn't include the 'fmod' function. I got the source for fmod from ftp.uu.net, put it in the compat subdirectory, and added it to the Makefile. fmod also wanted functions 'isnan' and 'finite' but I just commented those out since I don't believe tcl supports infinity and nan.

The other problem with the math library was that it has two copies of the 'tanh' function in it. This is easy to fix by using "ar" to separate the library in to object files and then reconstruct it, leaving one of the copies of tanh out.

With those changes, Tcl compiled cleanly and passed all the tests except the scanning tests. Apparently, the *scanf functions are broken in Dynix. The problem is with recognizing the end of octal numbers, and I just let this problem go. Fixing it would probably involve finding source to the *scanf functions and including it.

To compile Tk, I had to make a new version of stddef.h including things like wchar_t. I just copied it in to another include directory and put that directory first and then tweaked the copy. Tk also had the math library problem (tanh). Other than those, however, everything compiled cleanly and passed all the tests.

Q45- How do I get around the symbol table full msg in AU/X 3.0?

After getting things compiled on AU/X, you have to be sure to do the links with the -A {factor} arguments which expand the default table allocations. {factor} is the amount by which the compiler multiplies the default allocation. Try -A 2. Contact Walter B. Kulecz, PhD. (wkulecz@medics.jsc.nasa.gov) for more details of his port.

Q46- How do I compile Tcl on MS-DOS, MacOS, or other non-UNIX system?

Refer to Larry Virden's FAQ (see tcl-faq/part1) or (see tcl-faq/part4) for details concerning tools, finished ports, or mailing lists relating to this topic.

Q47- How do I get Tcl to compile on my QNX system?

Steve Furr (furr@qnx.com) indicates:

For the record, to get TCL to work under QNX, I had to:

Q48- Why do I get the error message "Command not found" when I try to run a Tcl script?

The script probably starts with a #! that is followed by a path to the Tcl interpreter that is too long for your system. Many Unix systems are limited 32 characters in this regard. So, something like this will fail:

	#! /usr/home/homedir/very/long/path/tclsh

	# rest of script
You can either shorten the path by moving the tclsh executable to a different directory or by using symbolic links. Another option is to not specify the path at all. See the question "How do I make my script executable regardless of the location of tclsh?" for an example of how to do this.

End of FAQ