TclX(3tcl)

๐Ÿ“ฆ version 8.6.3, in ubuntu stonking

TclX ๐ŸŒˆ๐Ÿ’…

okay bestie, this is the TclX(3tcl) manual page โ€” the whole extended-Tcl situation, documented in one place. settle in, it's a long one, and we're only on part 1 ๐Ÿซถ


โœจ NAME โœจ

TclX โ€” Extended Tcl: the extended command set for Tcl. it's giving "Tcl but it got a glow-up" ๐Ÿ’–

๐ŸŽ€ SYNOPSIS ๐ŸŽ€

package require Tclx

that's it. that's the whole incantation. slay. โœจ

๐ŸŒธ INTRODUCTION ๐ŸŒธ

so this man page has the docs for every single extension that Extended Tcl (TclX) bolts onto Tcl. TclX levels up what Tcl can do by adding brand new commands to it โ€” and here's the tea โ€” it does not change the syntax of standard Tcl. not even a little. Extended Tcl is a superset of standard Tcl, and it gets built right alongside the standard Tcl sources. no cap.

Extended Tcl was created by Karl Lehenbauer and Mark Diekhans, and it's freely redistributable for any use without license or fee. iconic behavior, honestly. ๐Ÿ‘‘

Available since 1989 (yes bestie, it's been THAT girl for decades), Extended Tcl โ€” also known as TclX โ€” doesn't just add capabilities to Tcl. it has also been the source of many of the capabilities of the baseline Tcl release, including arrays, files, sockets, file events, and date and time handling, among others. main character energy fr fr. ๐ŸŒŸ

Extended Tcl introduces a set of new commands and a user-extensible library of useful Tcl procedures โ€” and any one of those can be automatically loaded the very first time something tries to execute it. lazy-loading before it was cool. ๐Ÿ’…

The command descriptions are separated into several sections:

  • General Commands
  • Debugging and Development Commands
  • Unix Access Commands
  • File Commands
  • Network Programming Support
  • File Scanning Commands
  • Math Commands
  • List Manipulation Commands
  • Keyed Lists
  • String and Character Manipulation Commands
  • XPG/3 Message Catalog Commands
  • Help Facility
  • Tcl Loadable Libraries and Packages

๐Ÿ‘‘ GENERAL COMMANDS ๐Ÿ‘‘

a set of general, useful Tcl commands โ€” includes a command to kick off an interactive session with Tcl, a facility for tracing execution, and a looping command. the little utility squad. ๐Ÿงš


  • dirs โ€” this procedure lists the directories in the directory stack. โœจ

  • commandloop ?-async? ?-interactive on | off | tty? ?-prompt1 cmd? ?-prompt2 cmd? ?-endcommand cmd?

creates an interactive command loop that reads commands from stdin and writes results to stdout. command loops are maybe either be blocking or event oriented. bestie this one is so useful for Tcl scripts that don't normally converse interactively with a user through a Tcl command interpreter, but which sometimes want to enter this mode โ€” maybe for debugging, maybe for user configuration. the command loop terminates on EOF.

the following options are available:

  • -async โ€” a command handler will be associated with stdin. when input is available on stdin, it will be read and accumulated until a full command is available. that command will then be evaluated. an event loop must be entered for input to be read and processed. โš ๏ธ
  • -interactive on | off | tty โ€” enable or disable interactive command mode. in interactive mode, commands are prompted for and the results of comments are printed. the value maybe any boolean value or tty. if tty is used, interactive mode is enabled if stdin is associated with a terminal or terminal emulator. the default is tty. ๐Ÿ’…
  • -prompt1 cmd โ€” if specified, cmd is used is evaluate and its result used for the main command prompt. if not specified, the command in tcl_prompt1 is evaluated to output the prompt. note the difference in behavior โ€” cmd results is used, while tcl_prompt1 outputs. this is to allow for future expansion to command loops that write to other than stdout. โœจ
  • -prompt2 cmd โ€” if specified, cmd is used is evaluate and its result used for the secondary (continuation) command prompt. if not specified, the command in tcl_prompt2 is evaluated to output the prompt.
  • -endcommand cmd โ€” if specified, cmd is evaluated when the command loop terminates.
in interactive mode, the results of set commands with two arguments are not printed.
if SIGINT is configured to generate a Tcl error, it can be used to delete the current command being type without aborting the program in progress. ๐Ÿ˜ญ very "oops never mind" of it

  • coalesce ?-default value? var ?var...?

iterate through one or more specified variable names. the first variable found that actually exists โ€” return the value of that variable. if none of the variable names are found to exist, return the default value. and if none of the variables exist and the default value wasn't specified using -default, it returns the empty string. first-one-wins energy. ๐ŸŒˆ


  • echo ?str ...?

writes zero or more strings to standard output, followed by a newline. simple. cute. does exactly what it says. ๐Ÿ’–


  • infox option

return information about Extended Tcl, or the current application. the following infox command options are available:

  • version โ€” return the version number of Extended Tcl. the version number for Extended Tcl is generated by combining the base version of the standard Tcl code with another number indicating the version of Extended Tcl being used. ๐ŸŽ€
  • patchlevel โ€” return the patchlevel for Extended Tcl.
  • have_fchown โ€” return 1 if the fchown system call is available. this supports the -fileid option on the chown and chgrp commands.
  • have_fchmod โ€” return 1 if the fchmod system call is available. this supports the -fileid option on the chmod command.
  • have_flock โ€” return 1 if the flock command defined, 0 if it is not available.
  • have_fsync โ€” return 1 if the fsync system call is available and the sync command will sync individual files. 0 if it is not available and the sync command will always sync all file buffers.
  • have_ftruncate โ€” return 1 if the ftruncate or chsize system call is available. if it is, the ftruncate command -fileid option maybe used.
  • have_msgcats โ€” return 1 if XPG message catalogs are available, 0 if they are not. the catgets is designed to continue to function without message catalogs, always returning the default string.
  • have_posix_signals โ€” return 1 if Posix signals are available (block and unblock options available for the signal command). 0 is returned if Posix signals are not available.
  • have_signal_restart โ€” return 1 if restartable signals are available (-restart option available for the signal command). 0 is returned if restartable signals are not available.
  • have_truncate โ€” return 1 if the truncate system call is available. if it is, the ftruncate command may truncate by file path.
  • have_waitpid โ€” return 1 if the waitpid system call is available and the wait command has full functionality. 0 if the wait command has limited functionality.
  • appname โ€” return the symbolic application name of the current application linked with the Extended Tcl library. the C variable tclAppName must be set by the application to return an application specific value for this variable.
  • applongname โ€” return a natural language name for the current application. the C variable tclLongAppName must be set by the application to return an application specific value for this variable.
  • appversion โ€” return the version number for the current application. the C variable tclAppVersion must be set by the application to return an application-specific value for this variable.
  • apppatchlevel โ€” return the patchlevel for the current application. the C variable tclAppPatchlevel must be set by the application to return an application-specific value for this variable.

  • for_array_keys var array_name code

this procedure performs a foreach-style loop for each key in the named array. the break and continue statements work as with foreach. so yes bestie, you can bail out mid-loop. ๐Ÿ’…


  • for_recursive_glob var dirlist globlist code

this procedure performs a foreach-style loop over recursively matched files. all directories in dirlist are recursively searched (breadth-first), comparing each file found against the file glob patterns in globlist. for each matched file, the variable var is set to the file path and code is evaluated. symbolic links are not followed. ๐Ÿšซ๐Ÿ”—


  • loop var first limit ?increment? body

loop is a looping command, similar in behavior to the Tcl for statement โ€” except that the loop statement achieves substantially higher performance and is easier to code when the beginning and ending values of a loop are known, and the loop variable is to be incremented by a known, fixed amount every time through the loop. glow-up of a for loop honestly. โœจ

the var argument is the name of a Tcl variable that will contain the loop index. the loop index is set to the value specified by first. the Tcl interpreter is invoked upon body zero or more times, where var is incremented by increment every time through the loop, or by one if increment is not specified. increment can be negative, in which case the loop will count downwards. ๐Ÿ”ป

when var reaches limit, the loop terminates without a subsequent execution of body. for instance, if the original loop parameters would cause loop to terminate โ€” say first was one, limit was zero and increment was not specified or was non-negative โ€” body is not executed at all and loop returns. zero iterations, no problem. ๐Ÿ’€

the first, limit and increment are integer expressions. they are only evaluated once at the beginning of the loop. ๐Ÿซถ

if a continue command is invoked within body then any remaining commands in the current execution of body are skipped, as in the for command. if a break command is invoked within body then the loop command will return immediately. loop returns an empty string. ๐ŸŽ€


more parts coming, bestie โ€” do not close the group chat ๐Ÿ’–

  • popd โ€” this one pops the top directory entry right off the directory stack and makes it your current directory. swoosh. new home unlocked ๐Ÿ’…
  • pushd ?dir? โ€” pushes the current directory onto the directory stack and then cds into the directory you named. If you don't name one? it still pushes the current directory but stays exactly where it is. no moving. ๐Ÿซถ
  • recursive_glob dirlist globlist โ€” returns a list of recursively matched files. Every directory in dirlist gets searched recursively (breadth-first, bestie) and every file it finds gets compared against the file glob patterns in globlist. Symbolic links are not followed. periodt.
  • showproc ?procname ...? โ€” lists the definition of the procedures you name, loading them first if they aren't already loaded. Name zero procedures and you get the definitions of every currently loaded procedure. the entire friend group, exposed. ๐Ÿ’–
  • try_eval code catch ?finally? โ€” evaluates code in the current context.

If an error goes down during that evaluation and catch isn't empty, then catch gets evaluated to handle the error. The result of the command, with the error message living inside it, gets stored in a global variable called errorResult. The global variables errorResult, errorInfo and errorCode get imported into the current scope automatically โ€” there is literally no need to run a global command, it's already done for you. The result of the catch command becomes the result of the try_eval command. And if you want to keep an error going after catch got evaluated, you run this:

error $errorResult $errorCode $errorInfo

If the finally argument is supplied and it's not empty, it gets evaluated after code and catch have both been evaluated. If an error happens while finally is being evaluated, that error becomes the result of the try_eval command. Otherwise the result of either code or catch is preserved, exactly as described above. ๐Ÿฆ‹


๐Ÿ› DEBUGGING AND DEVELOPMENT COMMANDS ๐Ÿ’€

This section is all about the commands and procedures that are useful for developing and debugging Tcl scripts. your little toolbox for when things are โœจnot workingโœจ

  • cmdtrace level | on ?noeval? ?notruncate? ?procs? ?fileid? ?command cmd? โ€” prints a trace statement for all commands executed at depth of level or below (level 1 is the top level). If you say on instead, then all commands at any level get traced. These are the options you can pass:
    • noeval โ€” causes arguments to be printed unevaluated. With noeval the arguments get printed before evaluation. Otherwise they get printed afterwards.

If the command line is longer than 60 characters, it gets truncated to 60 and a "..." gets postpended to show there was more output than got displayed. If an evaluated argument contains a space, the whole argument gets enclosed inside braces ({}) so you can visually tell where one argument stops and the next one starts. ๐ŸŽ€

  • notruncate โ€” disables the truncation of commands and evaluated arguments.
  • procs โ€” turns on tracing of procedure calls only. Commands that aren't procedure calls (i.e. calls to commands written in C, C++ or some object-compatible language) don't get traced when this option is specified. This one is especially useful for greatly reducing the output of cmdtrace while you're debugging.
  • fileid โ€” this is a file id as returned by the open command. If you specify it, the trace output gets written to that file instead of stdout. A stdio buffer flush happens after every single line is written, so the trace can be monitored externally or give you useful info when debugging problems that cause core dumps. ๐Ÿ’€
  • command cmd โ€” calls the specified command cmd on each command execution instead of tracing to a file. See the description of the functionality below. This option may not be specified with a fileid.

The most common use of this command is to turn on tracing to a file during development, so if a failure happens, a trace is already sitting there when you need it. Command tracing slows down the execution of your code, so it should be removed once the code is debugged. This next command enables tracing to a file for the rest of the program:

cmdtrace on [open cmd.log w]

The command option makes a user-specified trace command get called for every command executed. Before evaluation, the following arguments get appended to it:

  • command โ€” a string containing the text of the command, before any argument substitution.
  • argv โ€” a list of the final argument information that will be passed to the command after command, variable and backslash substitution.
  • evalLevel โ€” the Tcl_Eval call level.
  • procLevel โ€” the procedure call level.

Your command should be constructed so it'll still work if additional arguments get added in the future. It's suggested that the command be a proc with the final argument being args.

Tracing gets turned off while the command is being executed. The values of the errorInfo and errorCode variables get saved and restored when the command returns. It's the command's responsibility to preserve all other state.

If an error happens during the execution of the command, an error message gets dumped to stderr and the tracing gets disabled. The underlying mechanism that this functionality is built on does not support returning an error to the interpreter. so like. it just can't.

  • cmdtrace off โ€” turns off all tracing.
  • cmdtrace depth โ€” returns the current maximum trace level, or zero if tracing is disabled.
  • edprocs ?proc...? โ€” writes the named procedures (or all currently defined procedures if you name none) to a temporary file, calls an editor on it (whichever one the EDITOR environment variable says, or vi if none is specified), then sources the file back in if it changed. โœจ
  • profile ?-commands? ?-eval? on, profile off arrayVar โ€” collects a performance profile of a Tcl script. It gathers data at the Tcl procedure level โ€” how many calls a procedure got, plus the amount of real and CPU time used. Time is also collected for the global context. The procedure data gets collected by bucketing it based on the procedure call stack, which lets you figure out how much time is spent in a particular procedure in each of its calling contexts. ๐Ÿ‘‘

The on option enables profile data collection. If the -commands option is specified, data on all commands within a procedure is collected as well as procedures. Multiple occurrences of a command within a procedure are not distinguished, but the data may still be useful for analysis.

The off option turns off profiling and moves the collected data into the array arrayVar. The array is addressed by a list containing the procedure call stack. Element zero is the top of the stack, the procedure that the data is for. The data in each entry is a list consisting of the procedure call count and the real time and CPU time in milliseconds spent in the procedure (but not any procedures it calls). The list is in the form {count real cpu}.

Normally the variable scope stack is what's used when reporting where time is spent, so upleveled code gets reported in the context it was executed in, not the context the uplevel was called in. If you specify -eval, the procedure evaluation (call) stack is used instead of the procedure scope stack, so upleveled code gets reported in the context of the procedure that did the uplevel.

A Tcl procedure called profrep is supplied for reducing the data and producing a report.

On Windows, the profile command only reports elapsed real time. CPU time is not available and gets reported as zero. ๐Ÿ˜ญ
  • profrep profDataVar sortKey ?outFile? ?userTitle? โ€” generates a report from data collected by the profile command. ProfDataVar is the name of the array containing the data returned by profile. SortKey says which data value to sort by, and it should be one of "calls", "cpu" or "real". OutFile is the name of the file to write the report to; if it's omitted, stdout is assumed. UserTitle is an optional title line to add to the output.

Listed with indentation below each procedure or command is the procedure call stack. The first indented line is the procedure that invoked the reported procedure or command. The next line is the procedure that invoked the procedure above it, and so on. If no indented procedures are shown, then the procedure or command was called from the global context. Time actually spent in the global context is listed on a line labeled <global>. Upleveled code is reported in the context that it was executed in, not the context that the uplevel was called in.

  • saveprocs fileName ?proc...? โ€” saves the definition of the named procedure (or all currently defined procedures if none is specified) to the named file. ๐ŸŽ€

๐ŸŒˆ UNIX ACCESS COMMANDS ๐ŸŒˆ

These commands give you access to a whole bunch of basic Unix facilities โ€” process handling, date and time processing, signal handling, and executing commands through the shell. the classics, fr fr ๐Ÿงš

  • alarm seconds โ€” tells the system to send a SIGALRM signal in the specified number of seconds. This is a floating point number, so fractions of a second are fair game. If seconds is 0.0, any previous alarm request is canceled. Only one alarm at a time may be active, and the command returns the number of seconds left in the previous alarm. On systems without the setitimer system call, seconds gets rounded up to an integer number of seconds.
The alarm command is not available on Windows. ๐Ÿ’€
  • execl ?-argv0 argv0? prog ?arglist? โ€” โœจ bestie this is the full send command. It does an execl, meaning it replaces the current program (either Extended Tcl itself, or an application that has Extended Tcl embedded into it) with prog, and passes along the arguments sitting in the list arglist. Like, the old process is gone, no take-backs, periodt.
    • -argv0 โ€” this option specifies that argv0 is what gets passed to the program as argv [0], instead of prog. Little identity swap, iykyk. ๐Ÿ’…
โš ๏ธ Real talk: if you're using execl inside a Tk application and it fails, you may not do anything that accesses the X server, or the X server will hit you with a BadWindow error. And yes, that includes executing the Tk version of the exit command. The suggested way to abort Tk applications after an execl failure is this:
kill [id process]
  • On Windows, where the fork command isn't available, execl starts a new process and returns the process id. ๐Ÿฆ‹
  • chroot dirname โ€” changes the root directory to dirname by invoking the POSIX chroot(2) system call. Honestly kind of iconic and also kind of terrifying. It only succeeds if you're running as root. ๐Ÿ‘‘
  • fork โ€” forks the current Tcl process, fr fr. fork returns zero to the child process, and returns the process number of the child to the parent process. If the fork fails, a Tcl error is generated. ๐Ÿ˜ญ
    • So here's the tea: if an execl is not going to be performed before the child process does output, or if a close and dup sequence is going to be performed on stdout or stderr, then you should issue a flush against stdout, stderr and any other open output file before doing the fork. Otherwise, characters from the parent process that are still chillin' in the buffers will get output by both the parent and the child processes. ๐Ÿ’€
โš ๏ธ And if you're forking in a Tk based application, you must execl before doing any window operations in the child, or you'll catch a BadWindow error from the X server.
  • The fork command is not available on Windows. Sorry babe. ๐ŸŽ€
  • id options โ€” okay so this one is the ID multi-tool: a way to get, set and convert user, group and process ids. It has these options:
    • id user ?name?
    • id userid ?uid? โ€” sets the real and effective user ID to name or uid, if that name (or uid) is valid and permissions allow it. If the name (or uid) isn't specified, the current name (or uid) is returned. ๐Ÿ’–
    • id convert userid uid
    • id convert user name โ€” converts a user ID number to a user name, or the other way around. ๐Ÿ”„
    • id group ?name?
    • id groupid ?gid? โ€” sets the real and effective group ID to name or gid, if that name (or gid) is valid and permissions allow it. If the name (or gid) isn't specified, the current group name (or gid) is returned.
    • id groups
    • id groupids โ€” return the current group access list of the process. The option groups gives you group names, and groupids gives you the id numbers.
    • id convert groupid gid
    • id convert group name โ€” converts a group ID number to a group name, or vice versa.
    • id effective user
    • id effective userid โ€” return the effective user name, or the effective user ID number, respectively.
    • id effective group
    • id effective groupid โ€” return the effective group name, or the effective group ID number, respectively.
    • id effective groupids โ€” return all of the groupids the user is a member of. ๐Ÿซถ
    • id host โ€” return the hostname of the system the program is running on.
    • id process โ€” return the process ID of the current process.
    • id process parent โ€” return the process ID of the parent of the current process.
    • id process group โ€” return the process group ID of the current process.
    • id process group set โ€” set the process group ID of the current process to its process ID.
    • id host โ€” returns the standard host name of the machine the process is executing on. (Yes, it's listed twice in the original, and honestly? Host name so nice they said it twice. ๐Ÿ’)
    • On Windows, only the host and process options are implemented. ๐ŸŒˆ
  • kill ?-pgroup ?signal? idlist โ€” sends a signal to each process in the list idlist, if permitted. signal, if present, is the signal number or the symbolic name of the signal โ€” check the signal system call manual page for those. The leading SIG is optional when you specify the signal by its symbolic name. The default for signo is 15, SIGTERM.
    • -pgroup โ€” if this is specified, the numbers in idlist are taken as process group ids, and the signal gets sent to all of the processes in that process group. A process group id of 0 specifies the current process group. ๐Ÿ‘ฏ
    • On Windows, the kill command is capable of terminating a process, but not of sending an arbitrary signal. ๐Ÿ’…
  • link ?-sym? srcpath destpath โ€” creates a directory entry, destpath, linking it to the existing file srcpath. If -sym is specified, a symbolic link is created rather than a hard link. (The -sym option is only available on systems that support symbolic links, so vibe check your OS first.)
    • The link command is not available on Windows. Use the Tcl 8.4+ file link command instead. โœจ
  • nice ?priorityincr? โ€” change or return the process priority. If priorityincr is omitted, the current priority is returned. If priorityincr is positive, it gets added to the current priority level, up to a system defined maximum (normally 19).
    • Negative priorityincr values cumulatively increase the program's priority, down to a system defined minimum (normally -19). But heads up: increasing priority with negative niceness values will only work for the superuser. ๐Ÿ‘‘
    • The new priority is returned.
    • The nice command is not available on Windows.
  • readdir ?-hidden? dirPath โ€” returns a list containing the contents of the directory dirPath. The directory entries "." and ".." are not returned. ๐Ÿ“
    • On Windows, -hidden maybe be specified to include hidden files in the result. This flag is ignored on Unix systems.
  • signal ?-restart? action siglist ?command? โ€” the whole signal-handling situation, and it's giving main character energy. Read the warning first, bestie:
โš ๏ธ Warning: If signals are being used as an event source (a trap action), rather than generating an error to terminate a task, one must use the -restart option. This causes a blocked system call, such as read or waitpid, to be restarted rather than generate an error. Failure to do this may result in unexpected errors when a signal arrives while in one of these system calls. When available, the -restart option can prevent this problem.
  • -restart โ€” if specified, restart blocking system calls rather than generating an error. The signal will be handled once the Tcl command that issued the system call completes. Heads up though: the -restart option is not available on all operating systems, and using it will generate an error when it isn't supported. Use infox have_signal_restart to check for availability. ๐Ÿ”

So: specify the action to take when a Unix signal is received by Extended Tcl, or by a program that embeds it. Siglist is a list of either the symbolic or numeric Unix signal (the SIG prefix is optional). Action is one of the following things to do when the signal shows up. To specify all modifiable signals, use * โ€” and note that this will not include SIGKILL and SIGSTOP, because they can not be modified. ๐Ÿ’€

  • default โ€” perform the system default action when the signal is received (see the signal system call documentation).
  • ignore โ€” ignore the signal. Not me pretending I didn't see it. ๐Ÿ™ˆ
  • error โ€” generate a catchable Tcl error. It will be as if the command that was running returned an error. The error code will be in the form:
POSIX SIG signame

For the death of child signal, signame will always be SIGCHLD, rather than SIGCLD, to allow writing portable code. ๐Ÿงš

  • trap โ€” when the signal occurs, execute command and continue execution if an error is not returned by command. The command will be executed in the global context. The command will be edited before execution, replacing occurrences of "%S" with the signal name. Occurrences of "%%" result in a single "%". This editing occurs just before the trap command is evaluated. If an error is returned, then follow the standard Tcl error mechanism. Often command will just do an exit. ๐Ÿ’…
  • get โ€” retrieve the current settings of the specified signals. A keyed list will be returned where the keys are one of the specified signals and the values are a list consisting of the action associated with the signal, a 0 if the signal may be delivered (not blocked) and a 1 if it is blocked, and a flag indicating if restarting of system calls is specified. The actions maybe one of default, ignore, error or trap. If the action is trap, the third element is the command associated with the action. The action unknown is returned if a non-Tcl signal handler has been associated with the signal. ๐Ÿ‘€
  • set โ€” set signals from a keyed list in the format returned by the get. For this action, siglist is the keyed list of signal state. Signals with an action of unknown are not modified.
  • block โ€” block the specified signals from being received. (Posix systems only). ๐Ÿšซ
  • unblock โ€” allow the specified signal to be received. Pending signals will not occur. (Posix systems only).

The signal action will remain enabled after the specified signal has occurred. The exception to this is SIGCHLD on systems without Posix signals. For these systems, SIGCHLD is not be automatically re-enabled. After a SIGCHLD signal is received, a call to wait must be performed to retrieve the exit status of the child process before issuing another signal SIGCHLD ... command. For code that is to be portable between both types of systems, use this approach. ๐ŸŒธ

Signals are not processed until after the completion of the Tcl command that is executing when the signal is received. Periodt. If an interactive Tcl shell is running, then the SIGINT will be set to error, and non-interactive Tcl sessions leave SIGINT unchanged from when the process started โ€” normally default for foreground processes and ignore for processes in the background. ๐Ÿ’…

  • sleep seconds โ€” okay bestie, this makes the Extended Tcl process nap for seconds seconds. If seconds is specified as a decimal number, it's truncated to an integer value. ๐Ÿ˜ด๐Ÿ’ค
  • system cmdstr1 ?cmdstr2...? โ€” this one concatenates cmdstr1, cmdstr2 etc with space separators (see the concat command) into a single command, then evaluates that command using the standard system shell. On Unix systems, that's /bin/sh, and on Windows it's command.com. The exit code of the command is returned. ๐Ÿ”ฅ

This command is lowkey different from the exec command because system doesn't return the executed command's standard output as the result string, and system goes through the Unix shell to provide wild card expansion, redirection, etc, as is normal from an sh command line. So if you need shell magic, this is your girl. ๐Ÿšโœจ

  • sync ?fileId? โ€” if fileId is not specified, or if it is and this system does not support the fsync system call, it issues a sync system call to flush all pending disk output. If fileId is specified and the system does support the fsync system call, it issues an fsync on the file corresponding to the specified Tcl fileId to force all pending output to that file out to the disk. ๐Ÿ’พ

If fileId is specified, the file must be writable. A flush will be issued against the fileId before the sync. ๐Ÿšฝ

The infox have_fsync command can be used to determine if "sync fileId" will do a sync or a fsync. iykyk.

  • times โ€” returns a list containing the process and child execution times in the form:
utime stime cutime cstime

Also see the times(2) system call manual page. The values are in milliseconds. โฑ๏ธ

  • umask ?octalmask? โ€” sets file-creation mode mask to the octal value of octalmask. If octalmask is omitted, the current mask is returned. ๐Ÿ”
  • wait ?-nohang? ?-untraced? ?-pgroup? ?pid? โ€” waits for a process created with the execl command to terminate, either due to an untrapped signal or call to exit system call. If the process id pid is specified, they wait on that process, otherwise wait on any child process to terminate. ๐Ÿ‘€

If -nohang is specified, then don't block waiting on a process to terminate. If no process is immediately available, return an empty list. If -untraced is specified then the status of child processes that are stopped, and whose status has not yet been reported since they stopped, are also returned. If -pgroup is specified and pid is not specified, then wait on any child process whose process group ID is they same as the calling process. If pid is specified with -pgroup, then it is take as a process group ID, waiting on any process in that process group to terminate. ๐Ÿซถ

wait returns a list containing three elements: The first element is the process id of the process that terminated. If the process exited normally, the second element is EXIT', and the third contains the numeric exit code. If the process terminated due to a signal, the second element is SIG', and the third contains the signal name. If the process is currently stopped (on systems that support SIGSTP), the second element is STOP', followed by the signal name. ๐Ÿ“

Note that it is possible to wait on processes to terminate that were create in the background with the exec command. However, if any other exec command is executed after the process terminates, then the process status will be reaped by the exec command and will not be available to the wait command. ๐Ÿ’€

On systems without the waitpid system call, the -nohang, -untraced and -pgroup options are not available. The infox have_waitpid command maybe use to determine if this functionality is available. ๐Ÿง

โœจ FILE COMMANDS โœจ

These commands provide extended file access and manipulation. This includes searching ASCII-sorted data files, copying files, duplicating file descriptors, control of file access options, retrieving open file status, and creating pipes with the pipe system call. Also linking files, setting file, process, and user attributes and truncating files. An interface to the select system call is available on Unix systems that support it. ๐Ÿ—‚๏ธ๐Ÿ’–

It should be noted that Tcl file I/O is implemented on top of the stdio library. By default, the file is buffered. When communicating to a process through a pipe, a flush command should be issued to force the data out. Alternatively, the fcntl command may be used to set the buffering mode of a file to line-buffered or unbuffered. ๐Ÿšฐ

  • bsearch fileId key ?retvar? ?compare_proc? โ€” search an opened file fileId containing lines of text sorted into ascending order for a match. Key contains the string to match. If retvar is specified, then the line from the file is returned in retvar, and the command returns 1 if key was found, and 0 if it wasn't. If retvar is not specified or is a null name, then the command returns the line that was found, or an empty string if key wasn't found. ๐Ÿ”

By default, the key is matched against the first white-space separated field in each line. The field is treated as an ASCII string. If compare_proc is specified, then it defines the name of a Tcl procedure to evaluate against each line read from the sorted file during the execution of the bsearch command. Compare_proc takes two arguments, the key and a line extracted from the file. The compare routine should return a number less than zero if the key is less than the line, zero if the key matches the line, or greater than zero if the key is greater than the line. The file must be sorted in ascending order according to the same criteria compare_proc uses to compare the key with the line, or erroneous results will occur. ๐Ÿง 

This command does not work on files containing binary data (bytes of zero). ๐Ÿšซ

  • channelfd channel โ€” get the unix file descriptor, an integer, for channel using the Tcl_GetChannelHandle API. On any error the return value -1. ๐ŸŽฏ

The channelfd command is not available on Windows. ๐ŸชŸโŒ

  • chmod [-fileid] mode filelist โ€” set permissions of each of the files in the list filelist to mode, where mode is an absolute numeric mode or symbolic permissions as in the UNIX chmod(1) command. The numeric mode argument is assumed octal by default (e.g. 733), unless otherwised specified using an explicit radix indicator (e.g. 0d493). ๐Ÿ”ง

If the option -fileid is specified, filelist is a list of open file identifiers rather than a list of file names. This option is not available on all Unix systems. Use the infox have_fchmod command to determine if this functionality is available. ๐Ÿ“‹

The chmod command is not available on Windows. ๐ŸชŸโŒ

  • chown [-fileid] owner | {owner group} filelist โ€” set owner of each file in the list filelist to owner, which can be a user name or numeric user id. If the first parameter is a list, then the owner is set to the first element of the list and the group is set to the second element. Group can be a group name or numeric group id. If group is {}, then the file group will be set to the login group of the specified user. ๐Ÿ‘‘

If the option -fileid is specified, filelist is a list of open file identifiers rather than a list of file names. This option is not available on all Unix systems. Use the infox have_fchown command to determine if this functionality is available. ๐Ÿ“‹

The chown command is not available on Windows. ๐ŸชŸโŒ

  • chgrp [-fileid] group filelist โ€” set the group id of each file in the list filelist to group, which can be either a group name or a numeric group id. ๐Ÿ‘ฅ

If the option -fileid is specified, filelist is a list of open file identifiers rather than a list of file names. This option is not available on all Unix systems. Use the infox have_fchown command to determine if this functionality is available. ๐Ÿ“‹

The chgrp command is not available on Windows. ๐ŸชŸโŒ

  • dup fileId ?targetFileId? โ€” duplicate an open file. A new file id is opened that addresses the same file as fileId. ๐Ÿชž

If targetFileId is specified, the the file is dup to this specified file id. Normally this is stdin, stdout, or stderr. The dup command will handle flushing output and closing this file. The new file will be buffered, if its needs to be unbuffered, use the fcntl command to set it unbuffered. ๐Ÿ’…

If fileId is a number rather than a Tcl file id, then the dup command will bind that file to a Tcl file id. This is useful for accessing files that are passed from the parent process. The argument ?targetFileId? is not valid with this operation. ๐Ÿ”—

On Windows, only stdin, stdout, or stderr or a non-socket file handle number maybe specified for targetFileId. The dup command does not work on sockets on Windows. ๐ŸชŸ๐Ÿ”Œ

  • fcntl fileId attribute ?value? โ€” this command either sets or clears a file option or returns its current value. If value is not specified, then the current value of attribute is returned. All values are boolean. Some attributes maybe only be gotten, not modified. The following attributes may be specified: โš™๏ธ
    • RDONLY โ€” The file is opened for reading only. (Get only) ๐Ÿ“–
    • WRONLY โ€” The file is opened for writing only. (Get only) โœ๏ธ
    • RDWR โ€” The file is opened for reading and writing. (Get only) ๐Ÿ”„
    • READ โ€” If the file is readable. (Get only). ๐Ÿ‘€
    • WRITE โ€” If the file is writable. (Get only). ๐Ÿ–Š๏ธ
    • APPEND โ€” The file is opened for append-only writes. All writes will be forced to the end of the file. (Get or set). โž•
    • NONBLOCK โ€” The file is to be accessed with non-blocking I/O. See the read system call for a description of how it affects the behavior of file reads. ๐Ÿšฆ
    • CLOEXEC โ€” Close the file on an process exec. If the execl command or some other mechanism causes the process to do an exec, the file will be closed if this option is set. ๐Ÿ”’
  • NOBUF โ€” bestie, this file is not buffered, like at all. No buffering for it, periodt. ๐Ÿ’…
  • LINEBUF โ€” output on this file is line buffered โœจ the buffer gets flushed the moment a newline is written, when the buffer fills up, or when input is requested. It's giving considerate. ๐ŸŽ€
  • KEEPALIVE โ€” keeps a socket connection alive ๐Ÿซถ. If SIGPIPE is enabled, then it gets sent when the connection breaks and data is written to the socket. If SIGPIPE is ignored instead, an error comes back on the write. Heads up: this attribute is valid only on sockets. And for the record, SIGPIPE is ignored by default in Tcl.

Okay so real talk: NONBLOCK, NOBUF and LINEBUF are all just hanging around for compatibility with older scripts ๐Ÿ™ˆ โ€” the fconfigure command is the preferred method of getting and setting these attributes. iykyk.

๐Ÿšจ Also: the APPEND and CLOEXEC options are not available on Windows. Not the vibe, but it's the law.

flock

flock options fileId ?start? ?length? ?origin?

This one places a lock ๐Ÿ”’ on all or part of the file specified by fileId. Whether that lock is advisory or mandatory depends on the mode bits of the file. The lock gets placed beginning at relative byte offset start for length bytes. If start or length is omitted or empty, zero is assumed. If length is zero, then the lock always extends to the end of file โ€” even if the file grows ๐Ÿ‘€.

If origin is "start", then the offset is relative to the beginning of the file. If it's "current", it's relative to the current access position in the file. If it's "end", then it's relative to the end-of-file (a negative is before the EOF, a positive is after). If origin is omitted, then start is assumed.

The following options are recognized:

  • -read โ€” place a read lock on the file. Multiple processes may be accessing the file with read-locks ๐Ÿค.
  • -write โ€” place a write lock on the file. Only one process may be accessing a file if there's a write lock ๐Ÿ‘‘.
  • -nowait โ€” if specified, the process will not block if the lock can't be obtained. With this option, the command returns 1 if the lock is obtained and 0 if it isn't.

Peep your system's fcntl system call documentation for the full tea on how file locking actually behaves ๐Ÿต. And if you're locking ranges of a file, it's genuinely best to use unbuffered file access (see the fcntl command).

๐Ÿ’€ flock is not available on Windows 95. It is available on Windows NT.

for_file

for_file var filename code

This procedure implements a loop over the contents of a file ๐ŸŒธ. For each line in filename, it sets var to the line and executes code.

The break and continue commands work exactly like they do with foreach โ€” no notes. ๐Ÿ’…

For example, the command

for_file line /etc/passwd {echo $line}

would echo all the lines in the password file. Ate. ๐Ÿ”ฅ

funlock

funlock fileId ?start? ?length? ?origin?

Removes a lock from a file that was previously placed with the flock command ๐Ÿซถ. The arguments are the same as for flock โ€” go see that command for more details.

๐Ÿ’€ funlock is not available on Windows 95. It is available on Windows NT.

fstat

fstat fileId ?item? | ?stat arrayvar?

Obtain status information about an open file ๐Ÿ”. The following keys are used to identify data items:

  • atime โ€” the time of last access.
  • ctime โ€” the time of last file status change.
  • dev โ€” the device containing a directory for the file. This value uniquely identifies the file system that contains the file.
  • gid โ€” the group ID of the file's group.
  • ino โ€” the inode number. This field uniquely identifies the file in a given file system.
  • mode โ€” the mode of the file (see the mknod system call).
  • mtime โ€” time when the data in the file was last modified.
  • nlink โ€” the number of links to the file.
  • size โ€” the file size in bytes.
  • tty โ€” if the file is associated with a terminal, then 1, otherwise 0.
  • type โ€” the type of the file in symbolic form, which is one of the following values: file, directory, characterSpecial, blockSpecial, fifo, link, or socket.
  • uid โ€” the user ID of the file's owner.

If one of these keys is specified as item, then that data item is returned ๐ŸŽฏ.

If stat arrayvar is specified, then the information is returned in the array arrayvar. Each of the above keys indexes an element of the array containing the data.

If only fileId is specified, the command returns the data as a keyed list โœจ.

The following values may be returned only if explicitly asked for โ€” they will not be returned with the array or keyed list forms ๐Ÿ™…โ€โ™€๏ธ:

  • remotehost โ€” if fileId is a TCP/IP socket connection, then a list is returned with the first element being the remote host IP address. If the remote host name can be found, it's returned as the second element of the list. The remote host IP port number is the third element.
  • localhost โ€” if fileId is a TCP/IP socket connection, then a list is returned with the first element being the local host IP address. If the local host name can be found, it's returned as the second element of the list. The local host IP port number is the third element.

ftruncate

ftruncate [-fileid] file newsize

Truncate a file so it has a length of at most newsize bytes โœ‚๏ธ.

If the option -fileid is specified, then file is an open file identifier, otherwise it's a file path.

โš ๏ธ This command is not available or not fully functional if the underlying operating system support isn't available. The command infox have_truncate will tell you if this command may truncate by file path. The command infox have_ftruncate will tell you if this command may truncate by file id. Always vibe check first ๐Ÿงš.
๐Ÿ’€ The -fileid option is not available on Windows.

lgets

lgets fileId ?varName?

Reads the next Tcl list from the file given by fileId and discards the terminating newline character ๐ŸŒˆ. This is different from the gets command because it reads Tcl lists rather than lines, okay? If the list contains newlines or binary data, then that newline or those bytes of zero get returned as part of the result. Only a newline that is not quoted as part of the list indicates the end of the list. There's no corresponding command for outputting lists, because puts already does that correctly ๐Ÿ’….

If varName is specified, then the line is placed in the variable by that name and the return value is a count of the number of characters read (not including the newline). If the end of the file is reached before reading any characters, then -1 is returned and varName is set to an empty string. If varName is specified and an error occurs, whatever data was read will be returned in the variable โ€” however, the resulting string may not be a valid list ๐Ÿ˜ญ. Not ideal.

If varName is not specified, then the return value will be the line (minus the newline character), or an empty string if the end of the file is reached before reading any characters. An empty string will also be returned if a line contains no characters except the newline, so eof may have to be used to figure out what really happened. Sneaky. ๐Ÿ™ˆ

You can use lgets to read and write lists containing binary data, but translation must be set to lf or the data maybe corrupted. Do not skip that step. ๐Ÿ’€

And yeah โ€” lgets is currently supported on non-blocking files. โœจ

pipe

pipe ?fileId_var_r fileId_var_w?

Create a pipe ๐ŸŽ€. If fileId_var_r and fileId_var_w are specified, then pipe will set the variable named fileId_var_r to contain the fileId of the side of the pipe that was opened for reading, and fileId_var_w will contain the fileId of the side of the pipe that was opened for writing.

If the fileId variables are not specified, then a list containing the read and write fileIds is returned as the result of the command. Easy. ๐Ÿซถ

read_file

read_file ?-nonewline? fileName
read_file fileName numBytes

This procedure reads the file fileName and returns the contents as a string ๐Ÿ“–. If -nonewline is specified, then the last character of the file is discarded if it's a newline. The second form specifies exactly how many bytes will be read and returned โ€” unless there are fewer than numBytes bytes left in the file, in which case all the remaining bytes are returned. Take what you can get. ๐Ÿ’œ

select

select readfileIds ?writefileIds? ?exceptfileIds? ?timeout?

This command lets an Extended Tcl program wait on zero or more files being ready for reading, being ready for writing, having an exceptional condition pending, or waiting for a timeout period to expire โณ. readFileIds, writeFileIds, exceptFileIds are each lists of fileIds, as returned from open, to query. An empty list ({}) may be specified if a category isn't being used.

The files specified by the readFileIds list are checked to see if data is available for reading. The writeFileIds are checked to see if the specified files are clear for writing. The exceptFileIds are checked to see if an exceptional condition has occurred (typically, an error) ๐Ÿ’€. The write and exception checking is most useful on devices, however the read checking is very useful when communicating with multiple processes through pipes. Select considers data pending in the stdio input buffer for read files as being ready for reading โ€” the files do not have to be unbuffered. ๐Ÿฆ‹

Timeout is a floating point timeout value, in seconds. If an empty list is supplied (or the parameter is omitted), then no timeout is set. If the value is zero, then the select command functions as a poll of the files, returning immediately even if none are ready. No waiting around. ๐Ÿ’…

If the timeout period expires with none of the files becoming ready, then the command returns an empty list. Otherwise the command returns a list of three elements, and each of those elements is a list of the fileIds that are ready in the read, write and exception classes. If none are ready in a class, then that element will be the null list. For example:

select {file3 file4 file5} {file6 file7} {} 10.5

could return

...and the pattern list keeps going, like

{file3 file4} {file6} {}

or maybe

file3 {} {}

whatever your little heart desires, bestie ๐Ÿ’–

Heads up for the Windows girlies: on Windows, only sockets can be used with the select command. Pipes, as returned by the open command, are not supported. Not a vibe. ๐Ÿšซ๐ŸชŸ
  • write_file fileName string ?string...? โ€” writes the strings you give it into the file named fileName. That's it, that's the whole job, and it does it flawlessly ๐Ÿ’…

๐ŸŒ NETWORK PROGRAMMING SUPPORT ๐ŸŒ

TclX is here to be the hype squad for Tcl's socket command โ€” it gives you the extra functionality that command doesn't have on its own. The host_info command is your go-to for getting info about a host, whether you know it by name or by IP address. On top of that, fstat and fcntl hand you options for querying and controlling connected sockets. And if you wanna know the host name of the local system, you hit up the id host command. iykyk โœจ

  • host_info option host โ€” pull information about an Internet host. The host argument can be either a host name or an IP address. Iconic flexibility fr fr ๐Ÿฆ‹

The following subcommands are recognized (they go in the option slot):

  • addresses โ€” returns the list of IP addresses for host. ๐Ÿ“‹
  • official_name โ€” returns the official name for host. ๐Ÿ‘‘
  • aliases โ€” returns the list of aliases for host. Quick note bestie: these are IP number aliases, not DNS CNAME aliases โ€” go peek at ifconfig(2) if you want the tea. ๐Ÿซ–

๐Ÿ” FILE SCANNING COMMANDS ๐Ÿ”

Okay so these commands are the moment. They give you a facility to scan files, matching lines of the file against regular expressions and executing Tcl code the second something matches. With this, you can use Tcl to do the sort of file processing that's traditionally done with awk. And honestly? Since Tcl's approach is more declarative, some scripts that are genuinely painful to write in awk are justโ€ฆ simple to code in Tcl. Nature is healing ๐ŸŒธ

File scanning in Tcl centers around the concept of a scan context. A scan context contains one or more match statements, which associate regular expressions to scan for with Tcl code to be executed when those expressions are matched. Cute, organized, no notes ๐Ÿ’…

  • scancontext ?option? โ€” manages file scan contexts. A scan context is a collection of regular expressions and commands to execute when that regular expression matches a line of the file. A context may also have a single default match, to be applied against lines that don't match any of the regular expressions. Multiple scan contexts may be defined, and they may be reused on multiple files. A scan context is identified by a context handle.

The scancontext command takes the following forms:

  • scancontext create โ€” creates a new scan context. You use the scanmatch command to define patterns in the context. A contexthandle is returned, which the Tcl programmer uses to refer to the newly created scan context in calls to the Tcl file scanning commands. โœจ
  • scancontext delete contexthandle โ€” deletes the scan context identified by contexthandle, and frees all of the match statements and compiled regular expressions associated with that context. Poof, gone, bye ๐Ÿ‘‹
  • scancontext copyfile contexthandle ?filehandle? โ€” sets or returns the file handle that unmatched lines are copied to. (See scanfile.)
    • If filehandle is omitted, the copy file handle is returned. ๐ŸŽ€
    • If no copy file is associated with the context, {} is returned.
    • If a file handle is specified, it becomes the copy file for this context.
    • If filehandle is {}, then it removes any copy file specification for the context.
  • scanfile ?-copyfile copyFileId? contexthandle fileId โ€” scans the file specified by fileId, starting from the current file position. It checks all patterns in the scan context specified by contexthandle against it, executing the match commands corresponding to the patterns that matched. ๐ŸŽฏ

If the optional -copyfile argument is specified, the next argument is a file ID to which all lines not matched by any pattern (excluding the default pattern) are to be written. If the copy file is specified with this flag โ€” instead of by using the scancontext copyfile command โ€” the file is disassociated from the scan context at the end of the scan.

Fr fr bestie, this command does not work on files containing binary data (bytes of zero). Like, don't even try it ๐Ÿ’€
  • scanmatch ?-nocase? contexthandle ?regexp? commands โ€” specifies Tcl commands to be evaluated when regexp is matched by a scanfile command. The match is added to the scan context specified by contexthandle. Any number of match statements may be specified for a given context. regexp is a regular expression (see the regexp command). If -nocase is specified as the first argument, the pattern is matched regardless of alphabetic case โ€” case? never heard of her ๐Ÿ”ฅ

If regexp is not specified, then a default match is specified for the scan context. The default match will be executed when a line of the file does not match any of the regular expressions in the current scancontext.

The array matchInfo is available to the Tcl code that is executed when an expression matches (or defaults). It contains information about the file being scanned and where within it the expression was matched. ๐Ÿ“

matchInfo is local to the top level of the match command unless declared global at that level by the Tcl global command. If it is to be used as a global, it must be declared global before scanfile is called (since scanfile sets the matchInfo before the match code is executed, a subsequent global will override the local variable). The following array entries are available:

  • matchInfo(line) โ€” contains the text of the line of the file that was matched. ๐Ÿ“
  • matchInfo(offset) โ€” the byte offset into the file of the first character of the line that was matched.
  • matchInfo(linenum) โ€” the line number of the line that was matched. This is relative to the first line scanned, which is usually, but not necessarily, the first line of the file. The first line is line number one. 1๏ธโƒฃ
  • matchInfo(context) โ€” the context handle of the context that this scan is associated with.
  • matchInfo(handle) โ€” the file id (handle) of the file currently being scanned.
  • matchInfo(copyHandle) โ€” the file id (handle) of the file specified by the -copyfile option. This element does not exist if -copyfile was not specified. ๐Ÿ™ˆ
  • matchInfo(submatch0) โ€” will contain the characters matching the first parenthesized subexpression. The second will be contained in submatch1, etc.
  • matchInfo(subindex0) โ€” will contain a list of the starting and ending indices of the string matching the first parenthesized subexpression. The second will be contained in subindex1, etc.

All scanmatch patterns that match a line will be processed in the order in which their specifications were added to the scan context. The remainder of the scanmatch pattern-command pairs may be skipped for a file line if a continue is executed by the Tcl code of a preceding, matched pattern. โญ๏ธ

If a return is executed in the body of the match command, the scanfile command currently in progress returns, with the value passed to return as its return value. ๐Ÿ


โž— MATH COMMANDS ๐Ÿงฎ

Several extended math commands make many additional math functions available in TclX. On top of that, a whole set of procedures give you command access to the math functions supported by the expr command. Math girlies, this one's for you ๐Ÿ‘‘

The following procedures provide command interfaces to the expr math functions. They take the same arguments as the expr functions and may take expressions as arguments. Slay ๐Ÿ’…

abs         acos        asin       atan2
atan        ceil        cos        cosh
double      exp         floor      fmod
hypot       int         log10      log
pow         round       sin        sinh
sqrt        tan         tanh
  • max num1 ?..numN?
  • expr max(num1, num2)

Returns the argument that has the highest numeric value. Each argument may be any integer or floating point value.

This functionality is also available as a math function max in the Tcl expr command. ๐Ÿ†

  • min num1 ?..numN?
  • expr min(num1, num2)

Returns the argument that has the lowest numeric value. Each argument may be any integer or floating point value.

This functionality is also available as a math function min in the Tcl expr command. ๐Ÿฅ‰

  • random limit | random seed ?seedval? โ€” generates a pseudorandom integer number greater than or equal to zero and less than limit. If seed is specified, then the command resets the random number generator to a starting point derived from seedval. This allows one to reproduce pseudorandom number sequences for testing purposes โ€” reproducibility? obsessed ๐ŸŽฒ If seedval is omitted, then the seed is set to a value based on current system state and the current time, providing a reasonably interesting and ever-changing seed. The main character of seeds, honestly ๐ŸŒˆ

๐Ÿ’– LIST MANIPULATION COMMANDS ๐Ÿ’–

Extended Tcl came through with extra list-manipulation commands and procedures, bestie. Let's get into them ๐Ÿฆ‹


  • intersect lista listb โ€” A procedure that hands you back the logical intersection of two lists. The list it returns? sorted, always. โœจ
  • intersect3 lista listb โ€” The three-way split version, and omg it's giving main character energy. It intersects two lists and returns one list containing three lists inside it:
    1. everything that was in lista but not in listb
    2. the intersection of the two lists
    3. all the elements that were in listb but not in lista

Every one of those returned lists is sorted. ๐Ÿ‘‘

  • lassign list var ?var...? โ€” Assigns successive elements of a list to the variables you name. If you gave it more variable names than there are fields, the leftover variables get set to the empty string. If there's more elements than variables, you get back a list of the unassigned elements. no cap ๐Ÿซถ

For example:

lassign {dave 100 200 {Dave Foo}} name uid gid longName

Assigns name to dave, uid to 100, gid to 200, and longName to Dave Foo. ๐Ÿ’…

  • lcontain list element โ€” Figure out if that element is a list element of list. Contained? You get 1. Not contained? You get 0. periodt.
  • lempty list โ€” Is this list empty? Empty = 1, otherwise 0. It's an alternative to comparing a list against an empty string โ€” except plot twist, it also checks for a string that's all whitespace, which counts as an empty list. ๐ŸŒธ
  • lmatch ?mode? list pattern โ€” Searches the elements of list and returns a list of everything matching pattern. Nothing matched? You get an empty list back, it's fine, we move. ๐Ÿ™ˆ

The mode argument tells it how the list elements get matched against pattern, and it has to be one of these:

  • -exact โ€” the list element must contain exactly the same string as pattern.
  • -glob โ€” pattern is a glob-style pattern matched against each list element using the same rules as the string match command.
  • -regexp โ€” pattern is treated as a regular expression and matched against each list element using the same rules as the regexp command.

Leave mode out and it defaults to -glob.

Heads up bestie: only the -exact comparison works on binary data. ๐Ÿฉท
  • lrmdups list โ€” A procedure that removes duplicate elements from a list. And yes, the returned list is sorted. โœจ
  • lvarcat var string ?string...? โ€” This one treats each string argument as a list, then concatenates them all onto the end of whatever's already inside var, forming one single list. The list gets stored back into var and returned as the result. If var doesn't exist yet? Not a problem, it gets created. ๐Ÿ’–
  • lvarpop var ?indexExpr? ?string? โ€” lvarpop pops (aka deletes) the element at the index given by the expression indexExpr from the list sitting inside the variable var. Omit the index and 0 is assumed. Give it a string and the deleted element gets replaced by that string instead. Either way, the replaced-or-deleted element is what gets returned. So like, lvarpop argv 0 returns the first element of argv and sets argv to contain the rest of the string. iconic behavior ๐ŸŽ€

If the expression indexExpr starts with the string end, then end gets replaced with the index of the last element in the list. If the expression starts with len, then len gets replaced with the length of the list. ๐Ÿฆ‹

  • lvarpush var string ?indexExpr? โ€” lvarpush pushes (aka inserts) string as an element into the list inside the variable var. It inserts the element before position indexExpr in the list. Omit the index and 0 is assumed. If var doesn't exist, it gets created. ๐Ÿซถ

Same deal as above: if the expression indexExpr starts with the string end, then end gets replaced with the index of the last element in the list. If the expression starts with len, then len gets replaced with the length of the list.

Note that a value of end means insert the string before the last element. Don't be caught off guard bestie ๐Ÿ’€
  • union lista listb โ€” A procedure that returns the logical union of the two lists you specified. Any duplicate elements get removed. bye dupes ๐Ÿ‘‹

๐Ÿ”‘ KEYED LISTS ๐Ÿ”‘

Extended Tcl defines a special type of list called a keyed list, and honestly? It's a whole vibe. These lists give you a structured data type built on top of standard Tcl lists โ€” so like, structs in C, but make it Tcl. ๐Ÿ’œ

A keyed list is a list where each element holds a key and value pair. Those pairs are themselves stored as lists, with the key as the first element and the value as the second. These key-value pairs are called fields. Here's what a keyed list looks like:

{{NAME {Frank Zappa}} {JOB {musician and composer}}}

If the variable person held that list above, then keylget person NAME would return {Frank Zappa}. And running this command:

keylset person ID 106

would make person contain:

{{ID 106} {NAME {Frank Zappa}} {JOB {musician and composer}}

Fields can contain subfields, and . is the separator character. Subfields are just fields whose value is another keyed list. So this next list has the top level fields ID and NAME, plus the subfields NAME.FIRST and NAME.LAST:

{ID 106} {NAME {{FIRST Frank} {LAST Zappa}}}

And there is no limit to how deep those subfields can recurse, so you can build truly complex data structures with this. obsessed. ๐ŸŒˆ

Keyed lists get constructed and accessed through a bunch of commands. And important detail: all keyed list management commands take the name of the variable containing the keyed list as an argument (so basically passed by reference), rather than taking the list directly. iykyk ๐Ÿ’…

  • keyldel listvar key โ€” Deletes the field specified by key from the keyed list in the variable listvar. This removes both the key and the value from the keyed list. both gone, no leftovers โœจ
  • keylget listvar ?key? ?retvar | {}? โ€” Returns the value associated with key from the keyed list in the variable listvar. If retvar isn't specified, the value comes back as the result of the command. In that case, if key isn't found in the list, an error results. ๐Ÿ˜ญ

If retvar is specified and key is in the list, the value goes into the variable retvar and the command returns 1 โ€” meaning the key was present within the list. If key isn't in the list, the command returns 0 and retvar stays unchanged. And if you specify {} for retvar, the value is not returned at all โ€” which lets a Tcl programmer check whether a key is present in a keyed list without setting a variable as a side-effect. chef's kiss ๐Ÿซถ

If key is omitted, then you get back a list of all the keys in the keyed list. ๐Ÿ‘‘

  • keylkeys listvar ?key? โ€” Returns a list of the keys in the keyed list inside the variable listvar. If key is specified, then it's the name of a key field whose subfield keys are to be retrieved. ๐Ÿฆ‹
  • keylset listvar key value ?key2 value2 ...? โ€” Sets the value associated with key, in the keyed list contained in the variable listvar, to value. If listvar doesn't exist, it gets created. If key isn't currently in the list, it gets added. If it already exists, value replaces the existing value. And you can specify multiple keywords and values if you want to. slay ๐Ÿ’–

โœจ STRING AND CHARACTER MANIPULATION COMMANDS โœจ

okay bestie these are the glow-up commands for strings ๐Ÿ’– they let you classify characters, flip characters back and forth between character-y and number-y forms, index into a string, find out how long it is, grab a range of characters out of it, duplicate a string a bunch of times, and transliterate a string (basically the Unix tr program but make it fashion ๐Ÿ’…).


  • ccollate ?-local? string1 string2 โ€” compares two strings, periodt. Returns -1 if string1 is less than string2, 0 if they're equal, and 1 if string1 is greater than string2.

If -local is specified, the strings get compared according to the collation environment of the current locale ๐ŸŒ.

heads up bestie: this command does not work with binary or UTF data ๐Ÿ˜ญ
  • cconcat ?string1? ?string2? ?...? โ€” glues all the arguments together and hands you back the resulting string ๐Ÿซถ. Normally the parser does string concatenation on its own, but every so often you just need a command that returns a string โ€” usually when a command is what's required to be evaluated. No separators get inserted between the strings, nope, not one โœจ.

This command is UTF-aware ๐Ÿ’œ

  • cequal string string โ€” compares two strings for equality. Returns 1 if string1 and string2 are identical and 0 if they're not. It's the shortcut for string compare and it dodges all those problems where string expressions accidentally get treated as numbers ๐Ÿ™ˆ (we've all been there).

This command is UTF-aware and it'll also work on binary data ๐Ÿ”ฅ

  • cindex string indexExpr โ€” gives you back the character indexed by the expression indexExpr (zero based, obviously ๐Ÿ’…) from string.

If the expression indexExpr starts with the string end, then end gets replaced with the index of the last character in the string. If the expression starts with len, then len gets replaced with the length of the string.

This command is UTF-aware โœจ

  • clength string โ€” returns the length of string in characters. Literally just a shortcut for:
string length string

This command is UTF-aware ๐Ÿ’–

  • crange string firstExpr lastExpr โ€” returns a range of characters from string, starting at the character indexed by the expression firstExpr (zero-based) all the way until the character indexed by the expression lastExpr ๐ŸŽ€.

If the expression firstExpr or lastExpr starts with the string end, then end gets replaced with the index of the last character in the string. If the expression starts with len, then len gets replaced with the length of the string.

This command is UTF-aware ๐ŸŒธ

  • csubstr string firstExpr lengthExpr โ€” returns a range of characters from string, starting at the character indexed by the expression firstExpr (zero-based) and running for lengthExpr characters ๐Ÿฆ‹.

If the expression firstExpr or lengthExpr starts with the string end, then end gets replaced with the index of the last character in the string. If the expression starts with len, then len gets replaced with the length of the string.

This command is UTF-aware โญ

  • ctoken strvar separators โ€” parses a token out of a character string ๐Ÿงš. The string you're parsing lives in the variable named strvar. The string separators holds all the valid separator characters for tokens in the string. All the leading separators get skipped and the first token is what you get back. And the variable strvar gets modified to contain the remainder of the string that follows the token โ€” so watch out, it's mutating your variable ๐Ÿ‘€.
ngl this one does not work with binary data ๐Ÿšซ
  • ctype ?-failindex var? class string โ€” ctype figures out whether all the characters in string belong to the specified class. It returns 1 if they're all of class, and 0 if they aren't, or if the string is empty (empty string = not it, sorry ๐Ÿ’€). This command also serves as another way (besides format and scan) of converting between an ASCII character and its numeric value. Here are all the ctype commands you've got:
    • ctype ?-failindex var? alnum string โ€” tests that all characters are alphabetic or numeric characters, as defined by the character set ๐Ÿ”ค.
    • ctype ?-failindex var? alpha string โ€” tests that all characters are alphabetic characters, as defined by the character set ๐Ÿ”ก.
    • ctype ?-failindex var? ascii string โ€” tests that all characters are an ASCII character (a non-negative number less than 0200) ๐Ÿ’ป.
    • ctype char number โ€” converts the numeric value, string, to an ASCII character. Number must be in the range 0 through the maximum Unicode values ๐ŸŒˆ.
    • ctype ?-failindex var? cntrl string โ€” tests that all characters are "control characters," as defined by the character set ๐Ÿ‘ป.
    • ctype ?-failindex var? digit string โ€” tests that all characters are valid decimal digits, i.e. 0 through 9 ๐Ÿ”ข.
    • ctype ?-failindex var? graph string โ€” tests that all characters are any character for which ctype print is true, except for space characters ๐Ÿซง.
    • ctype ?-failindex var? lower string โ€” tests that all characters are lowercase letters, as defined by the character set ๐Ÿ”ฝ.
    • ctype ord character โ€” converts a character into its decimal numeric value. The first character of the string gets converted to its numeric Unicode value ๐Ÿ”ขโœจ.
    • ctype ?-failindex var? space string โ€” tests that all characters are either a space, horizontal-tab, carriage return, newline, vertical-tab, or form-feed ๐ŸŒฌ๏ธ.
    • ctype ?-failindex var? print string โ€” tests that all characters are a space, or any character for which ctype alnum or ctype punct is true, or any other "printing character" as defined by the character set ๐Ÿ–จ๏ธ.
    • ctype ?-failindex var? punct string โ€” tests that all characters are made up of any of the characters other than the ones for which alnum, cntrl, or space is true โœ๏ธ.
    • ctype ?-failindex var? upper string โ€” tests that all characters are uppercase letters, as defined by the character set ๐Ÿ”ผ.
    • ctype ?-failindex var? xdigit string โ€” tests that all characters are valid hexadecimal digits, that is 0 through 9, a through f, or A through F ๐Ÿงฎ.

If -failindex is specified, then the index into string of the first character that did not match the class gets returned in var ๐Ÿ‘‘.

  • replicate string countExpr โ€” gives you string, replicated the number of times indicated by the expression countExpr ๐Ÿ”. So yes, it's the copy-paste button but make it a command.

This command is UTF-aware and it'll work with binary data ๐Ÿ’œ

  • translit inrange outrange string โ€” translates the characters in string, swapping characters that show up in inrange for the corresponding character in outrange ๐Ÿ”„. Inrange and outrange can be a list of characters, or a range in the form A-M. For example:
translit a-z A-Z foobar
bestie listen: this command currently only supports characters in the ASCII range โ€” UTF-8 characters outside of this range will generate an error ๐Ÿ˜ญ๐Ÿšซ

๐Ÿ“– XPG/3 MESSAGE CATALOG COMMANDS ๐Ÿ’ฌ

These commands give you a Tcl interface to message catalogs that are compliant with the X/Open Portability Guide, Version 3 (aka XPG/3). Periodt.

So here's the vibe: Tcl programmers can use message catalogs to build applications that are language-independent. With message catalogs, your prompts, your messages, your menus, literally all of it can exist in however many languages you want, and you can tweak them and add brand-new languages without touching a single line of Tcl or C source code. That's the whole point โ€” it majorly eases the maintenance pain of supporting multiple languages. ๐Ÿ’…

A default text message gets passed to the command that fetches entries from the catalogs. This is the iconic move where the Tcl programmer can make catalogs full of messages in all the languages, but still have a set of default messages ready no matter what, so the program just keeps on slaying even when there are no catalogs present at all. โœจ

So the normal approach? Ignore errors on catopen, and then catgets will just hand you the default message that was specified in the call. Simple as that.

The Tcl message catalog commands normally ignore most errors. But if you actually want to detect errors, there's a special option for that. It's normally only used during debugging, to make sure catalogs are actually being used. And if your Unix implementation doesn't have XPG/3 message catalog support at all? Stubs get compiled in that create a version of catgets that always returns the default string. Which means porting software to environments without message catalog support is easy-peasy. ๐Ÿฆ‹

Heads up bestie: message catalogs are global to the process, so an application with multiple Tcl interpreters inside the same process may pass and share message catalog handles. No cap.

๐Ÿš The commands

  • catopen ?-fail | -nofail? catname โ€” Opens the message catalog catname. This can be a relative path name, and if it is, the NLSPATH environment variable gets searched to find an absolute path to the catalog. You get back a handle shaped like msgcatN. Normally errors are ignored, and if catopen fails, you still get a handle โ€” but to an unopened message catalog. (That handle can still be passed to catgets and catclose, and it makes catgets just return the default string, like we said up top.) If you specify -fail, then an error is returned when the open fails. The -nofail option specifies the default behavior of not returning an error when catopen fails to open the specified catalog. And if the handle from a failed catopen is passed to catgets, the default string is what you get. ๐Ÿคทโ™€๏ธ
  • catgets catHandle setnum msgnum defaultstr โ€” Retrieves a message from a message catalog. CatHandle should be a Tcl message catalog handle that catopen returned. Setnum is the message set number, and msgnum is the message number. If the catalog was never opened, or the message set or message number can't be found, then you get the default string, defaultstr, returned. ๐ŸŽ€
  • catclose ?-fail | -nofail? cathandle โ€” Closes the message catalog specified by cathandle. Normally errors are ignored. If -fail is specified, any errors from closing the catalog file get returned. The -nofail option specifies the default behavior of not returning an error. Lowkey important: using -fail only makes sense if you also specified it in the call to catopen. ๐Ÿ‘‘
  • mainloop โ€” This procedure sets up a top-level event loop. Events are processed until there are no more active event sources, at which point the process exits. It's used to build event-oriented programs using the TclX shell, in a style similar to the one you'd use with wish. If the global variable tcl_interactive exists and has a true value, an interactive command handler gets started as well. And if that command handler gets terminated by an EOF, the process will be exited. ๐Ÿ”ฅ

๐Ÿ†˜ HELP FACILITY ๐Ÿ’–

The help facility lets you look up help pages that were extracted from the standard Tcl manual pages and Tcl scripts during Tcl installation. Help files are structured as a multilevel tree of subjects and help pages. They're found by searching directories named help in the directories listed in the auto_path variable. All the files in that list of help directories form a virtual root of the help tree โ€” which is the whole genius of it, because it means multiple applications can provide help trees without having their files live in the same directory. ๐Ÿงš

You can access the help facility two ways: as interactive commands in the Extended Tcl shell, or as an interactive Tk-based program (if you built Extended Tcl with Tk, that is).

To run the Tk-based interactive help program:

tclhelp ?addpaths?

Where addpaths are additional paths to search for help directories. By default, only the auto_path used by tclhelp is searched. That gets you help on Tcl, Extended Tcl and Tk. โœจ

The following interactive Tcl commands and options come with the help package:

  • help โ€” Help with no arguments lists all the help subjects and pages under the current help subject. ๐Ÿ“‹
  • help subject โ€” Displays all the help pages and lower-level subjects (if any exist) under the subject subject.
  • help subject/helppage โ€” Displays the specified help page. The help output gets passed through a simple pager if it goes over 23 lines, pausing and waiting for a return to be entered. If you enter any other character, the output is terminated. ๐Ÿ›‘
  • helpcd ?subject? โ€” Changes the current subject, which is a lot like the Unix current directory. If subject isn't specified, you go back to the top level of the help tree. Help subject path names may also include .. elements. ๐ŸŒธ
  • helppwd โ€” Displays the current help subject.
  • help help | ? โ€” Displays help on the help facility, at any directory level. Very meta of her. ๐Ÿ’…
  • apropos pattern โ€” This command locates subjects by searching their one-line descriptions for a pattern. Apropos is the move when you remember part of the name or description of a command and want to search through the one-line summaries for matching lines. Full regular expressions may be specified (see the regexp command). ๐Ÿ”

๐Ÿ“ฆ TCL LOADABLE LIBRARIES AND PACKAGES ๐ŸŽ€

Extended Tcl supports standard Tcl tclIndex libraries and package libraries. A single package library file can contain multiple independent Tcl packages. And a package is a named collection of related Tcl procedures plus initialization code. โœจ

The package library file is just a regular Unix text file โ€” editable with your favorite text editor, obviously โ€” containing packages of Tcl source code. Its name must have the suffix .tlib. An index file with the same prefix name and the suffix .tndx lives in the same directory as the .tlib file. And the .tndx gets automatically created whenever it's out of date or missing (provided there's write access to the directory). ๐Ÿฆ‹

The variable auto_path contains a list of directories that get searched for libraries. The first time an unknown command trap is taken, the indexes for the libraries are loaded into memory. If auto_path gets changed while a program is running, it will be re-searched. Only the first package of a given name found during the execution of a program is loaded. You can override that with the loadlibindex command. ๐Ÿ‘‘

The start of a package is delimited by:

#@package: package_name proc1 ?..procN?

These lines must start in column one. Everything between the #@package: keyword and the next #@package: keyword, or a #@packend keyword, or the end of the file, becomes part of the named package. The specified procedures, proc1..procN, are the entry points of the package. When a command named in a package specification gets executed and detected as an unknown command, all the code in the specified package will be sourced. That package should define all the procedures named on the package line, define any support procedures the package requires, and do any package-specific initialization. Package declarations can be continued on subsequent lines using standard Tcl backslash line continuations. And the #@packend keyword is useful for making sure only the minimum required section of code gets sourced โ€” so, for example, a big chonky comment block at the beginning of the next file won't get loaded. ๐Ÿ’€

Care should be taken when defining package_name, because the first package found in the path with a given name is the one that gets loaded. Which is actually useful when you're developing a new version of packages installed on the system. ๐Ÿ™ˆ

For example, in a package source file, the presence of this line:

#@package: directory_stack pushd popd dirs

says that the text lines following that line in the package file, up to the next package line or the end of the file, are a package named directory_stack, and that an attempt to execute pushd, popd or dirs when the routine isn't already defined will cause the directory_stack portion of the package file to be loaded. ๐ŸŒˆ

๐ŸŽ€ PACKAGE LIBRARY MANAGEMENT COMMANDS ๐ŸŽ€

okay so bestie, this is the part where TclX lets you build your own lil package libraries, and honestly? it's giving little free library in the front yard but for code ๐Ÿ“šโœจ

There are a bunch of commands for building and managing package libraries. The ones listed here are the ones that are extended versions of the standard Tcl library commands โ€” and also, no cap, all the standard Tcl library management commands and variables are supported too, so nothing you already love goes away ๐Ÿ’–


โœจ the commands โœจ

  • auto_commands ?-loaders? โ€” lists the names of every known loadable procedure and command procedure ๐Ÿ‘‘ And if you pass -loaders, it also hands you back the command that will be executed to load that command. like a little sneak peek at the machinery, iykyk.
  • buildpackageindex libfilelist โ€” builds index files for package libraries. The libfilelist argument is a list of package libraries, and every single name has to end with the suffix .tlib (periodt, no exceptions ๐Ÿ’…). A corresponding .tndx file gets built for each one. Also important: the user must have write access to the directory containing each library, otherwise this is not happening bestie.
  • convert_lib tclIndex packagelib ?ignore? โ€” converts an Ousterhout style tclIndex index file, plus the source files it points to, into a package library called packagelib. If packagelib doesn't already have a .tlib extension, one gets added for you, so don't stress ๐Ÿซถ Any files specified in tclIndex that are in the ignore list get skipped. And heads up: files listed in ignore should just be the base file names, not full paths โ€” don't be out here typing whole directory trees, she's not gonna match them.
  • loadlibindex libfile.tlib โ€” loads the package library index of the library file libfile (which must have the .tlib suffix). Package library indexes along the auto_path get loaded automatically on the first demand_load, so this command exists for when you need to explicitly load libraries that aren't in the path at all. If the index file (with a .tndx suffix) doesn't exist or is out of date, it'll be rebuilt โ€” but only if the user has directory permissions to create it. And here's the dramatic part ๐Ÿ˜ญ if a package with the same name as a package in libfile.tlib has already been loaded, its definition gets overridden by the new package. BUT โ€” and this is a big but โ€” if any procedure has actually been used from the previously defined package, then the procedures from libfile.tlib won't be loaded at all. no takebacks, the vibe check has already happened ๐Ÿ’€
  • auto_packages ?-location? โ€” returns a list of the names of all defined packages. If you throw -location in there, you get a list of pairs, where each pair is the package name plus the .tlib path name, offset, and length of the package inside that library. very detective energy ๐Ÿ”
  • auto_load_file file โ€” sources a file, exactly as the source command does, except it goes searching through auto_path for the file instead of making you spell out the whole location. it's the find-my-friend of file loading ๐Ÿฆ‹
  • searchpath path file โ€” searches all the directories in the specified path (which is a Tcl list) for the specified file. Returns the full path name of the file if she finds it, or an empty string if the requested file could not be found. rude, but honest ๐ŸŒธ

๐Ÿ’œ okay that's the whole dang page ๐Ÿ’œ

and that's a wrap on the whole thing bestie, we made it to the end ๐ŸŽ‰ lowkey emotional. this page is TclX(3tcl) โ€” version 3, from good ol' Tcl โ€” and it's stamped with a date down at the bottom in the footer next to that version, so if you ever need to cite your sources, that's where the receipts live ๐Ÿ“œโœจ now go forth and slay those package libraries fr fr ๐Ÿ’…๐Ÿซถ

๐Ÿ“ฆ where this page comes from