TclCommandWriting - Writing C language extensions to Tcl.
OVERVIEW
This document is intended to help the programmer who
wishes to extend Tcl with C language routines. It should
also be useful to someone wishing to add Tcl to an exist
ing editor, communications program, window manager, etc.
Experienced extension writers may find this manual helpful
in rewriting their applications to use the new Tcl object
system. We assume you are already fluent in the C pro
gramming language and that you have built and installed
Tcl on your machine.
Information on the available C interface routines to Tcl
can be found in the *.3 manual pages in the doc directory
of the baseline Tcl distribution, and in the *.3 manpages
in the doc directory of Extended Tcl.
TCL OBJECT SYSTEM
With the release of Tcl version 8, Tcl has a new system
for managing Tcl values internally. To the Tcl program
mer, the new objects look and act like strings, as before.
But at the C level, these objects can now also hold cached
internal representations of the strings in various native
datatypes. For example, an object containing a string
consisting of an integer, will now maintain a machine-code
integer representation, if an integer representation has
been needed. Using these objects is much more efficient
than using the older-style Tcl strings, although the older
style is still (currently) supported.
Although the object system has almost no effect at all on
how the Tcl programmer uses Tcl, the object system's C
interfaces to strings, integers, lists, etc., have changed
considerably. While converting a package to use the new
system can be a lot of work, the combination of the object
system, which saves Tcl from having to constantly convert
strings to integers and back, etc., and the on-the-fly
bytecode compiler (which keeps Tcl from having to continu
ally reparse code it is to execute) yield Tcl programs
that routinely execute several times more quickly than
with previous versions (Tcl 7 and before), and in some
cases run as much as 2500 (!) times faster than before.
We have chosen, then, to rewrite the Command Writer's man
page, which has been shipping with Extended Tcl for a num
ber of years, to produce this new version based on the new
object system. The old manpage, based on the older
string-oriented routines, will still be included in TclX
releases for now, as it is still relevant to Tcl releases
through version 7, and may be of use to those modify
ing/upgrading packages written for the old model. The old
manual will be dropped from the release once we deem it
legacy interfaces, and all new development should be done
using the new object interfaces, unless backwards compati
bility to pre-Tcl-8 releases is needed.
A SIMPLE C EXTENSION
All C-based Tcl commands are called with four arguments: a
client data pointer, an interpreter pointer, an argument
count and a pointer to an array of Tcl objects containing
the arguments to the command.
A simple C extension to Tcl is now presented, and
described below:
#include "tcl.h"
int App_DumpArgsObjCmd(clientData, interp, objc, objv)
void *clientData;
Tcl_Interp *interp;
int objc;
Tcl_Obj **objv;
{
int i;
int stringLen;
char *stringPtr;
for (i = 1; i < objc; i++) {
stringPtr = Tcl_GetStringFromObj (objv [i], &stringLen);
printf("%s", stringPtr);
if (i < objc - 1) printf(" ");
}
printf("\n");
return TCL_OK;
}
The client data pointer will be described later.
INTERPRETERS
The interpreter pointer is the ``key'' to an interpreter.
It is returned by Tcl_CreateInterp and is used extensively
within Tcl, and will be used by your C extensions. The
data structure pointed to by the interpreter pointer, and
all of the subordinate structures that branch off of it,
make up a Tcl interpreter, which includes all of the cur
rently defined procedures, commands, variables, arrays and
the execution state of that interpreter. (For more infor
mation on creating and deleting interpreters, please exam
ine the CrtInterp(3) manpage in the core Tcl distribution.
For information on creating interpreters that include the
commands provided by Extended Tcl, check out the
TclX_Init(3) manpage of Extended Tcl. For a manual page
describing the user-visible fields of a Tcl interpreter,
please look at Interp(3) in core Tcl.)
The argument count, or object count (objc), and pointer to
an array of pointers to Tcl objects of the command's argu
ments (objv) is handled by your C code, in a manner simi
lar to the one you would use in writing a C main function
-- an argument count and array of pointers works the same
as in a C main call; pointers to the arguments to the
function are contained in the objv array. Similar to a C
main, the first argument (objv[0]) is an object containing
the name the routine was called as (in a C main, the name
the program was invoked as).
In Tcl, however, the array of pointers are not pointers to
character strings (although they were in all version of
Tcl before 8.0).
In the above example, all of the arguments are output with
a space between each one by looping through elements of
the objv array from one to the argument count, objc, and a
newline is output to terminate the line -- a simple
``echo'' command. This example uses printf for simplic
ity. Of course in production code you would want to use
the Tcl filesystem interfaces. See GetFile(3) and friends
for more information.
All arguments from a Tcl call to a Tcl C extension are
passed as Tcl Objects. If your C routine wants to look at
one of those arguments as an integer, you need to make a
call to a routine to fetch the representation of the
object that you need. In the earlier example, for
instance, Tcl_GetStringFromObj is called to obtain a tex
tual representation of an object. Additional routines are
available to fetch the representation of a data element as
other data types. Tcl_GetBooleanFromObj, Tcl_GetDouble
FromObj, Tcl_GetIntFromObj, Tcl_GetLongFromObj, and
Tcl_GetIndexFromObj, fetch object representations of Tcl
strings as booleans, double-precision floating point,
integer, long integer, and lists, among others.
These routines automatically leave an appropriate error
message in the Tcl interpreter's result object and return
TCL_ERROR if a conversion error occurs. (For more infor
mation on these routines, please look at the Object(3)
manpage in the core Tcl distribution.)
RETURNING RESULTS
As you might expect, the API for setting results from C
extensions has changed significantly under the object sys
tem. The old technique of writing small results directory
into the interpreter's result buffer is no longer used,
for example. The notion of having to tell Tcl whether a
result is static or dynamic is also a thing of the past.
Under the object system, results are objects that are set
up by your code, and objects are freed when their
If you program produces a numeric result, it should set
the result object to contain that numeric value. A common
way of doing this is something like...
Tcl_Obj *obj;
obj = Tcl_GetObjResult (interp);
Tcl_SetIntObj (obj, value);
The above code obtains a pointer to the result object (an
object made available to your routine that you're supposed
to store your results into) and sets the integer value
value into it.
Another way to do it would be to set up a new object and
tell Tcl that this object contains the result...
Tcl_Obj *resultObj;
/* create a new object for use as a result */
resultObj = Tcl_NewObj ();
Tcl_SetIntObj (obj, value);
Tcl_SetObjResult (interp, resultObj);
Understanding how results are passed back to Tcl is essen
tial to the C extension writer. Please study the SetOb
jResult(3) manual page in the Tcl distribution for more
information.
VALIDATING ARGUMENTS
It is a design goal of Tcl that no Tcl program be able to
cause Tcl to dump core. It is important that the exten
sion writers, likewise, use the avaiable methods and tools
to make sure that their extensions do not allow unchecked
input, for example, to cause the code to get some kind of
runtime exception.
The object system has simplified, to some degree, the task
of validating arguments, in that the object system auto
matically attempts type conversions as needed, and will
return an error when a type conversion fails.
A simple, but important, check that every C extension
should do is verify that it has the right number of argu
ments.
The act of trying to use, say, a string as an integer,
implicitly performs the type conversion of the string and,
if it doesn't work as an integer, returns TCL_ERROR. The
developer should check for the TCL_ERROR return from all
of the GetXxxFromObj commands, and handle them as
on back to the user, or to an intevening catch, as the
case may be.
You should also check that values are in range (when their
ranges are known), and so forth. When C data structures
need to be handled in Tcl in some form or another, yet the
contents of the data must remain opaque to Tcl, as is usu
ally the case with binary data (although futures releases
of Tcl are expected to have native abilities to read,
write and manipulate binary data instrinsically), handles
need to be used. Handles will be described and examples
presented, later in this doc.
ANOTHER C EXTENSION - THE MAX COMMAND
In the command below, two or more arguments are compared,
and the one with the maximum value is returned, if all
goes well. It is an error if there are fewer than two
arguments (the pointer to the ``max'' command text itself,
objv[0], and a pointer to at least one object to compare
the values of).
int
Tcl_MaxCmd (clientData, interp, objc, objv)
char *clientData;
Tcl_Interp *interp;
int objc;
Tcl_Obj **objv;
{
int maxVal = MININT;
int value, idx;
if (objc < 3)
return TclX_WrongArgs (interp, objv[0],
" num1 num2 [..numN]");
for (idx = 1; idx < objc; idx++) {
if (Tcl_GetIntFromObj (interp, objv[idx], &value) != TCL_OK)
return TCL_ERROR;
if (value > maxVal) {
maxVal = value;
}
}
Tcl_SetIntObj (Tcl_GetObjResult (interp), value);
return TCL_OK;
}
Here we introduce the Extended Tcl helper function
TclX_WrongArgs. This routine makes it easy to create an
error message and error return in response to the common
mistake of being called with a wrong number.
the remaining arguments. If any fail to be converted, we
return a Tcl error. If an interpreter is specified in the
call to Tcl_GetIntFromObj, an appropriate error message
about the conversion failure will be left in the result,
so we do that here.
After examining all of the arguments to find the largest
value, we set the result object to contain that value, and
return TCL_OK.
RETURNING RESULTS
When Tcl-callable functions complete, they should normally
return TCL_OK or TCL_ERROR. TCL_OK is returned when the
command succeeded, and TCL_ERROR is returned when the com
mand has failed in some abnormal way. TCL_ERROR should be
returned for all syntax errors, non-numeric values when
numeric ones were expected, and so forth. Less clear in
some cases is whether Tcl errors should be returned or
whether a function should just return a status value. For
example, end-of-file during a gets returns a status, but
open returns an error if it fails. Errors can be caught
from Tcl programs using the catch command. (See Tcl's
catch(n) and error(n) manual pages.)
Less common return values are TCL_RETURN, TCL_BREAK and
TCL_CONTINUE. These are used if you are adding new con
trol and/or looping structures to Tcl. To see these val
ues in action, examine the source code to Extended Tcl's
loop commands. Tcl's while, for and if commands used to
work in the just same manner, but are now compiled into
bytecode by the bytecode for performance.
ANOTHER C EXTENSION - THE LREVERSE COMMAND
In the command below, a list is passed as an argument, and
a list containing all of the elements of the list in
reverse order is returned. It is an error if anything
other than two arguments are passed (the pointer to the
``lreverse'' command text itself, objv[0], and a pointer
to the list to reverse.
Once lreverse has determined that it has received the cor
rect number of arguments, Tcl_ListObjGetElements is called
to split the list into its own objc count of elements and
objv array of pointers to the list's elements.
lreverse then operates on the array of pointers, swapping
them from lowest to highest, second-lowest to second-high
est, and so forth.
Tcl_ListObjAppendElement is called on successive list ele
ments to build up the new list, which is finally returned
int
Tcl_LreverseObjCmd(notUsed, interp, objc, objv)
ClientData notUsed; /* Not used. */
Tcl_Interp *interp; /* Current interpreter. */
int objc; /* Number of arguments. */
Tcl_Obj **obj; /* Argument strings. */
{
int listObjc, lowListIndex, hiListIndex;
Tcl_Obj **listObjv;
char *temp, *resultList;
Tcl_Obj **newListObjv;
/* Verify argument count. Since we take only one argument, argument
* count must be 2 (command plus one argument).
*/
if (objc != 2)
return TclX_WrongArgs (interp, objv [0], "list");
/* Create an object to handle the new list we're creating */
newListObjv = Tcl_NewObj();
/* Crack the list at objv[1] into its own count and array of object
* pointers.
*/
if (Tcl_ListObjGetElements (interp, objv[1], &listObjc, &listObjv) != TCL_OK) {
return TCL_ERROR;
}
/* For each element in the source list from last to first, append an
* element to the new list.
*/
for (listIndex = listObjc - 1; listIndex >= 0; listIndex--) {
Tcl_ListObjAppendElement (interp, newListObjv, listObjv[listIndex]);
}
FIX: NEED TO RETURN THE LIST.
return TCL_OK;
}
INSTALLING YOUR COMMAND
To install your command into Tcl you must call Tcl_Cre
ateObjCommand, passing it the pointer to the interpreter
you want to install the command into, the name of the com
mand, a pointer to the C function that implements the com
mand, a client data pointer, and a pointer to an optional
callback routine.
The client data pointer and the callback routine will be
described later.
For example, for the max function above (which,
TclX7.4/src directory):
Tcl_CreateCommand (interp, "max", Tcl_MaxCmd, (ClientData)NULL,
(void (*)())NULL);
In the above example, the max function is added to the
specified interpreter. The client data pointer and call
back function pointer are NULL. (For complete information
on Tcl_CreateCommand and its companion routine, Tcl_Com
mandInfo, please examine the CrtCommand(3) command page in
the core Tcl distribution.)
DYNAMIC STRINGS
Dynamic strings are an important abstraction that first
became available with Tcl 7.0. Dynamic strings, or
DStrings, provide a way to build up arbitrarily long
strings through a repeated process of appending informa
tion to them. DStrings reduce the amount of allocating
and copying required to add information to a string. Fur
ther, they simplify the process of doing so.
At first glance, it may seem that the object system super
sedes DStrings. It does not, in that the performance
improvements made possible by the lazy conversion of an
object's representation from one datatype to another does
not come into play much while constructing strings as the
string representation is always available either without
any type conversion or where type conversion would be nec
essary in any case as a string representation of the
object is required when strings are being constructed by
concatenation, etc.
It should be noted, however, that the C level string
manipulation capabilites of objects, such as Tcl_Append
ToObj and Tcl_AppendStringsToObj, are often plenty enough
for what you need to do. For complete information on
dynamic strings, please examine the DString(3) manual page
in the core Tcl distribution. For more on Tcl object's
string-oriented calls, seek Tcl_StringObj(3) in the same
location.
CLIENT DATA
The client data pointer provides a means for Tcl commands
to have data associated with them that is not global to
the C program nor included in the Tcl core. Client data
is essential in a multi-interpreter environment (where a
single program has created and is making use of multiple
Tcl interpreters) for the C routines to maintain any per
manent data they need on a per-interpreter basis. If
needed static data was simply declared static in C, you
will probably have reentrancy problems when you work with
Tcl solves this through the client data mechanism. When
you are about to call Tcl_CreateObjCommand to add a new
command to an interpreter, if your command needs to keep
some read/write data across invocations, you should allo
cate the space, preferably using Tcl_Alloc instead of mal
loc, then pass the address of that space as the ClientData
pointer to Tcl_CreateObjCommand.
When your command is called from Tcl, the ClientData
pointer you passed to Tcl_CreateObjCommand will be passed
to your C routine through the ClientData pointer calling
argument.
Commands that need to share this data with one another can
do so by using the same ClientData pointer when the com
mands are added.
It is important to note that the Tcl extensions in the
tclX8.0.0 directory have had all of their data set up in
this way. Since release 6.2, Extended Tcl has supported
multiple interpreters within one invocation of Tcl.
THEORY OF HANDLES
Sometimes you need to have a data element that isn't read
ily representable as a string within Tcl, for example a
pointer to a complex C data structure. It is not a good
idea to try to pass pointers around within Tcl as strings
by converting them to and from hex or integer representa
tions, for example. It is too easy to mess one up, and
the likely outcome of doing that is a core dump.
Instead we have developed and made use of the concept of
handles. Handles are identifiers a C extension can pass
to, and accept from, Tcl to make the transition between
what your C code knows something as and what name Tcl
knows it by to be as safe and painless as possible. For
example, the I/O system included in Tcl uses file handles.
When you open a file from Tcl, a handle is returned of the
form filen where n is a file number. When you pass the
file handle back to puts, gets, seek, flush and so forth,
they validate the file handle by checking the the file
text is present, then converting the file number to an
integer that they use to look into a data structure of
pointers to Tcl open file structures, which contain a Unix
file descriptor, flags indicating whether or not the file
is currently open, whether the file is a file or a pipe
and so forth.
Handles have proven so useful that, since TclX release
6.1a, general support has been available to help create
and manipulate them. Many of these capabilities have
migrated into baseline Tcl. If you have a similar need,
Handles(3) in Extended Tcl. We recommend that you use a
unique-to-your-package textual handle coupled with a spe
cific identifier and let the handle management routines
validate it when it's passed back. It is much easier to
track down a bug with an implicated handle named something
like file4 or bitmap6 than just 6.
Note that Tcl's object offers another way for complex data
structures to exist in parallel with and underneath Tcl
strings. As of this writing (May 30, 1997) this is fairly
new territory, but things are looking good for the
prospects of using the Tcl object system in this manner,
and for enhancements to the object system that allow even
Tcl objects to have methods in a very straightforward and
simple way.
USING COMMANDS TO DO THE SAME THING, AND MORE
Another handle-like technique, first popularized in the Tk
toolkit, offers handle-like capabilities as well as some
neat additional capabilities. That is to create a new Tcl
command, from C, that uses ClientData to keep a "handle"
on its complex underlying data structure. Then by having
that command look at its second argument for what it is to
do (its sub-functions), you get these nice methods, where
you have several additional sub-commands that don't pol
lute the global namespace and only work on (and are avail
able with) the objects (new commands) they are relevant
to. For example, in Tk, creating a checkbutton (checkbut
ton .b) creates a new Tcl command (.b), that has methods
to configure the button, select, deselect, toggle and
flash it.
A lot of people think this is really the way to go, and I
am pretty much leaning that way myself. If you use the
incr tcl script-level object system for Tcl, objects that
you define in Tcl will be highly compatible in terms of
their command interfaces and configuration management with
objects you create in C using the the command-and-Client
Data technique described here. I believe Tk has some nice
facilities for making this easy for the Tcl programmer.
Itcl certainly does.
TRACKING MEMORY CORRUPTION PROBLEMS
Occasionally you may write code that scribbles past the
end of an allocated piece of memory. This will usually
result in a core dump or memory allocation failure some
time later in the program, often implicating code that is
not actually responsible for the problem (as you start
looking from the point where the error is detected, which
is usually where the later routine has failed).
The memory debugging routines included in Tcl can help
ory debugging routines are now part of baseline Tcl, and
is to our knowledge the largest piece of TclX to drop into
the core without being reengineered first. (You see, sum
mer back in '91, John was sitting in his office in the CS
building at UC Berkeley trying to find a memory leak some
where in Tcl, when he was paid a visit by two long-haired-
yet-polite programmers bearing gifts in the form of the
technology grab-bag known as Extended Tcl. He saw that,
using TclX's malloc routines, Tcl could be prompted to
print the filename and line number of every single memory
allocation that did not have a corresponding free. It was
just what the doctor ordered ;-) See Memory(TCL) for
details.
INSTALLING YOUR EXTENSIONS INTO TCL
To add your extensions to Tcl, you used to have to stati
cally link them, together with any other extensions, into
a single binary executable image. Today, although the
statically linked executable is still an option, most
operating systems, even Microsoft Windows, support shared
libraries, and in most cases, Tcl can now make use of
those shared libraries such that you extensions, and most
others, can now be built a shared libraries that can be
loaded in (using package require) by scripts that need
them. Shared libraries can simplify a Tcl installation,
because only one copy of Tcl is required, rather than a
hodepodge of combinations of applications that you might
have found at a big Tcl site in the previous era.
GNU AUTOCONF
While the build procedure for shared libraries varies from
system to system, most Unix and Unix workalike systems
will figure out the nuances of the compiler and linker
arguments automatically when the configure script is run.
If you are building a package that you plan to make gener
ally available, we strongly recommend that you use GNU
autoconf (ftp://prep.ai.mit.edu/pub/gnu) to set up an
automatic configure script for it. Be forewarned that
autoconf uses some pretty heavy duty shell and sed script
magic to get the job done, and the learning curve can be
pretty steep. Once done and shaken out, though, it's
rewarding to know that your package can build and run on
everything from a notebook to a Cray to a RISC SMP server.
Application-specific startup is accomplished by creating
or editing the Tcl_AppInit function. In Tcl_AppInit you
should add a call to an application-specific init function
which you create. This function should take the address
of the interpreter it should install its commands into,
and it should install those commands with Tcl_CreateCom
mand and do any other application-specific startup that is
necessary.
App_Init, where App is the name of your application. For
example, to add an application named cute one would create
a Cute_Init routine that expected a Tcl_Interp pointer as
an argument, and add the following code to Tcl_AppInit:
if (Cute_Init (interp) == TCL_ERROR) {
return TCL_ERROR;
}
As you can guess from the above example, if your init rou
tine is unable to initialize, it should use Tcl_Appen
dResult to provide some kind of useful error message back
to TclX, then return TCL_ERROR to indicate that an error
occurred. If the routine executed successfully, it should
return TCL_OK.
When you examine Tcl_AppInit, note that there is one call
already there to install an application -- the call to
TclX_Init installs Extended Tcl into the Tcl core.
MAKING APPLICATION INFORMATION VISIBLE FROM EXTENDED TCL
TclX's infox command can return several pieces of informa
tion relevant to Extended Tcl, including the application's
name, descriptive name, patch level and version. Your
application's startup can set these variables to applica
tion-specific values. If it doesn't, they are given
default values for Extended Tcl.
To set these values, first be sure that you include either
tclExtend.h or tclExtdInt.h from the source file that
defines your init routine. This will create external dec
larations for the variables. Then, set the variables in
your init route, for example:
tclAppName = "cute";
tclAppLongName = "Call Unix/Tcl Environment";
tclAppVersion = "2.1";
Note that the default values are set by TclX_Init, so if
you wish to override them, you must call your init routine
in Tcl_AppInit after its call to TclX_Init.
EXTENDED TCL EXIT
When Extended Tcl exits, Tcl_DeleteInterp may be called to
free memory used by Tcl -- normally, this is only called
if TCL_MEM_DEBUG was defined, since Unix will return all
of the allocated memory back to the system, anyway. If
TCL_MEM_DEBUG was defined, it is called so that any memory
that was allocated without ever being freed can be
detected. This greatly reduces the amount of work to
detect and track down memory leaks, a situation where some
ever freeing it, or at least without always freeing it.
It is often necessary for an application to perform spe
cial cleanup functions upon the deletion of an interpreter
as well. To facilitate this activity, Tcl provides the
ability to perform a function callback when an interpreter
is deleted. To arrange for a C function to be called when
the interpreter is deleted, call Tcl_CallWhenDeleted from
your application initialization routine. For details on
how to use this function, read the CallDel(3) manual page
that ships with core Tcl.
EXECUTING TCL CODE FROM YOUR C EXTENSION
Suppose you are in the middle of coding a C extension and
you realize that you need some operation performed, one
that would be simple from Tcl, but possibly excruciating
to do directly in C. Tcl provides a number of C-level
interfaces whereby you can cause Tcl code to be executeed.
The old-style calls are Tcl_Eval, Tcl_VarEval, Tcl_Eval
File and Tcl_GlobalEval. The results of these calls can
be dug out of the interpreter using Tcl_GetStringResult,
if you want a string representation of the result, or
Tcl_GetObjResult if you want the object. (The use of
interp->result to access the result string has been depre
cated.)
The Tcl object system adds Tcl_EvalObj and Tcl_GlobalEval
Obj. The difference here is that we are evaluating an
object, not just a string, and using these routines in
preference to the aforementioned ones can result in a
major performance improvement in your code, when the code
is executed repeatedly (even if it only executes once but
loops several times within itself), as these routines make
it possible for the bytecode compiler to compile the code
being evaluated and save the compiled code with the data
structure, in an implementation-dependent manner.
For more information please consult the EvalObj(3) and
Eval(3) manual pages within the Tcl distribution.
ACCESSING TCL VARIABLES AND ARRAYS FROM YOUR C EXTENSIONS
In addition to the non-object-system ways of reading from
and storing to Tcl variables, using routines such as
Tcl_SetVar2 and Tcl_GetVar2, Tcl variables and arrays can
be read from a C extension as Tcl objects by using the
Tcl_ObjGetVar2 function, and set from C extensions through
the Tcl_ObjSetVar2 function.
Please note that the object versions do not carry forward
analogues to the one-variable-name-argument Tcl_GetVar,
scalar, call the object variable get and set functions
with a NULL second argument. If your variable name might
contain an array reference via a self-contained embedded
array index (i.e., I'm asking Tcl_ObjGetVar2 for "foo(5)"
instead of "foo" "5"), add the TCL_PARSE_PART1 to the
flags in your call.
While the fact that Tcl_ObjGetVar2 retrieves Tcl objects,
rather than strings, is critical for the object system to
be able to provide the performance boosts from "lazy" type
conversion and the binary data capabilities, the arguments
containing the variable name, or the array name and ele
ment name if they've been split out, also must be speci
fied as Tcl objects rather than strings. While this is
useful on occasion, those writing C extensions for Tcl in
the post-object-system era usually have the names avail
able as plain old char * variables, requiring conversion
of the strings to objects before use and account for their
possible destruction afterwards.
To simplify the task in those cases, TclX adds the
TclX_ObjGetVar2S subroutine. It works just like
Tcl_ObjGetVar2, except the one or two variable name argu
ments are specified as strings, and the routine takes care
of making and disposing of object equivalents.
Tcl variables can be unset from C via the Tcl_UnsetVar and
Tcl_UnsetVar2 functions. There are currently (as of 8.0)
no object-system equivalents, so in the rare case where
you have the name of the variable you want unset as an
object instead of a string, you can call Tcl_GetStringFro
mObj to obtain the string representation first.
For complete information on these functions, please refer
to the ObjSetVar(3) and SetVar(3) manual pages in the doc
directory of the core Tcl distribution.
LINKING TCL VARIABLES TO C VARIABLES
Tcl_LinkVar and Tcl_UnlinkVar can be used to automatically
keep Tcl variables synchronized with corresponding C vari
ables. Once a Tcl variable has been linked to a C vari
able with Tcl_LinkVar, anytime the Tcl variable is read,
the value of the C variable is converted (if necessary)
and returned, and when the Tcl variable is written, the C
variable will be updated with the new value.
Tcl_LinkVar uses variable traces to keep the Tcl variable
named by varName in sync with the C variable at the
address given by addr.
Int, double, boolean and char * variables are supported.
You can make your linked variables read only from the Tcl
tinually exist while they are linked, in other words,
linking "automatic" C variables, those created on the
stack while a routine is being executed and destroyed
afterwards, will result in a malfunctioning program at
best and a coredump or more at worst.
For more information, please examine the LinkVar(3) manual
page in the core Tcl distribution.
ADDING NEW MATH FUNCTIONS TO TCL
As of Tcl version 7.0, math functions such as sin, cos,
etc, are directly supported within Tcl expressions. These
obsolete the Extended Tcl commands that provided explicit
commands for these functions for many, many releases,
although procs equivalencing the old TclX commands to the
new math functions are still provided for backwards com
patibility.
New math functions can be added to Tcl, or existing math
functions can be replaced, by calling Tcl_CreateMathFunc.
ACCESSING AND MANIPULATING THE RANDOM NUMBER GENERATOR
Prior to Tcl version 8.0, the Tcl core did not provide
access to a random number generator, but TclX did, through
its random command. As of Tcl version 8.0, access to a
random number generator is provided by baseline Tcl
through the new math functions, rand and srand.
The TclX random command is still available -- it has some
useful capabilities not directly provided by the new base
line functions.
For more information on adding your own math functions to
Tcl, please study the CrtMathFnc(3) manual page in the
core Tcl distribution.
CONVERTING FILENAMES TO NATIVE FORM AND PERFORMING TILDE SUBSTI
TUTIONS
The Tcl_TranslateFileName function is available to C
extension writers to translate filenames to a form suit
able for use by the local operating system. It converts
network names to their native form, and if the name starts
with a ``~'' character, the function returns a new string
where the name is replaced with the home directory of the
given user.
For more information please consult the Translate(3) man
ual page in the core Tcl distribution.
Tcl has a preset recursion limit that limits the maximum
allowable nesting depth of calls within an interpreter.
This is useful for detecting infinite recursions before
other limits such as the process memory limit or, worse,
available swap space on the system, run out.
The default limit is just a guess, however, and applica
tions that make heavy use of recursion may need to call
Tcl_SetRecursionLimit to raise this limit. For more
information, please consult the SetRecLmt(3) manual page
in the core Tcl distribution.
HANDLING SIGNALS FROM TCL EXTENSIONS
If an event such as a signal occurs while a Tcl script is
being executed, it isn't safe to do much in the signal
handling routine -- the Tcl environment cannot be safely
manipulated at this point because it could be in the mid
dle of some operation, such as updating pointers, leaving
the interpreter in an unreliable state.
The only safe approach is to set a flag indicating that
the event occurred, then handle the event later when the
interpreter has returned to a safe state, such as after
the current Tcl command completes.
The Tcl_AsyncCreate, Tcl_AsyncMark, Tcl_AsyncInvoke, and
Tcl_AsyncDelete functions provide a safe mechanism for
dealing with signals and other asynchronous events. For
more information on how to use this capability, please
refer to the Async(3) manual page in the core Tcl distri
bution.
Note that Extended Tcl provides built-in support for man
aging signals in numerous ways, including generating them
with alarm(2) and kill(2), ignoring them, trapping them,
getting, setting, blocking and unblocking them. You can
cause specific code to execute at a safe point after a
signal occurs, or cause a Tcl error backtrace on one's
occurrence. For more information, please examine the TclX
documentation.
PARSING BACKSLASH SEQUENCES
The Tcl_Backslash function is called to parse Tcl back
slash sequences. These backslash sequences are the usual
sort that you see in the C programming language, such as
\n for newline, \r for return, and so forth. Tcl_Back
slash parses a single backslash sequence and returns a
single character corresponding to the backslash sequence.
For more info on this call, look at the Backslash(3) man
ual page in the core Tcl distribution. For information on
language syntax, Tcl(n) in the same distribution.
HASH TABLES
Hash tables provide Tcl with a high-performance facility
for looking up and managing key-value pairs located and
maintained in memory. Tcl uses hash tables internally to
locate procedure definitions, Tcl variables, array ele
ments, file handles and so forth. Tcl makes the hash
table functions accessible to C extension writers as well.
Hash tables grow automatically to maintain efficiency,
rather than exposing the table size to the programmer at
allocation time, which would needlessly add complexity to
Tcl and would be prone to inefficiency due to the need to
guess the number of items that will go into the table, and
the seemingly inevitable growth in amount of data pro
cessed per run over the useful life of the program.
For more information on hash tables, please consult the
Hash(3) manual page in the core Tcl distribution.
TRACING VARIABLE ACCESSES
The C extension writer can arrange to have a C routine
called whenever a Tcl variable is read, written, or unset.
Variable traces are the mechanism by which Tk toolkit wid
gets such as radio and checkbuttons, messages and so forth
update without Tcl programmer intervention when their data
variables are changed. They are also used by the routine
that links Tcl and C variables, Tcl_LinkVar, described
above.
Tcl_TraceVar is called to establish a variable trace.
Entire arrays and individual array elements can be traced
as well. If the programmer already has an array name in
one string and a variable name in another, Tcl_TraceVar2
can be called. Calls are also available to request infor
mation about traces and to delete them.
For more information on variable traces, consult the
TraceVar(3) manual page in the core Tcl distribution.
TRACING TCL EXECUTION
Tcl has the ability to call C routines each time it exe
cutes a Tcl command, up to a specified depth of nesting
levels. The command Tcl_CreateTrace creates an execution
trace; Tcl_DeleteTrace deletes it.
Command tracing is used in Extended Tcl to implement the
cmdtrace Tcl command, a useful command for debugging Tcl
applications.
at the CrtTrace(3) manual pages in the core Tcl distribu
tion.
EVALUATING TCL EXPRESSIONS FROM C
Tcl_ExprLong, Tcl_ExprDouble, Tcl_ExprBool, and
Tcl_ExprString all take string arguments and, when called,
evaluate those strings as Tcl expressions. Depending on
the routine called, the result is either a C long, a dou
ble, a boolean (int with a value of 0 or 1), or a char *
(obtainable through Tcl_GetResult).
To take advantage of the performance gains available
through the bytecode compiler, Tcl_ExprLongObj,
Tcl_ExprDoubleObj, Tcl_ExprBoolObj, and Tcl_ExprObj all
take an object containing an expression to be evaluated
(rather than a string.) The result is that bytecode-com
piled version of the expression will be kept in the
object, alongside the string representation. If the
expression is evaluated again, without being changed, it
does not have to be recompiled... a major performance win.
For complete information on evaluating Tcl expressions
from C, you are invited to examine the ExprLong(3) and
ExprLongObj(3) manpages in the core Tcl distribution.
PATTERN MATCHING
The Tcl_StringMatch function can be called to see if a
string matches a specified pattern. Tcl_StringMatch is
called by the Tcl string match command, so the format for
patterns is identical. The pattern format is similar to
the one used by the C-shell; string(n) describes this for
mat.
More information about Tcl_StringMatch is available in the
StrMatch(3) manpage in the core Tcl distribution.
REGULAR EXPRESSION PATTERN MATCHING
Tcl_RegExpMatch can be called to determine whether a
string matches a regular expression. Tcl_RegExpMatch is
used internally by the regexp Tcl command.
As regular expressions are typically "compiled" before
use, a fairly involved process, Tcl also supports routines
that separate the compilation of an expression from its
use: Tcl_RegExpCompile, Tcl_RegExpExec, and Tcl_RegEx
pRange. If an expression is going to be matched many
times, doing the compile once and caching the compiled
regular expression result, then reusing the cached version
by using Tcl_RegExpExec, can be a significant performance
win.
RegExp(3) manpage in the core Tcl distribution.
MANIPULATING TCL LISTS FROM C EXTENSIONS
The C extension writer often needs to create, manipulate
and decompose Tcl lists. Tcl_SplitList and Tcl_Merge used
to be the only way to parse strings into lists and vice
versa. As of Tcl 8, lists can be parsed and assembled,
object-style, using Tcl_ListObjGetElements and Tcl_SetLis
tObj, and friends. Once again the "win" of using object-
system-based list manipulation, instead of the previous
string based routines, is that the parsing of a string in
an object to a list is cached in the object structure, the
same as with integers and floating point numbers, compiled
procedures, etc. The next time this string needs to be
looked at as a list, if the contents of the string have
not changed, the string does not have to be parsed.
In the author's experience, working with an admittedly
degenerate test whereby we iterated rather inefficiently
across a 6,000-element list, a speedup factor of more than
2500 was obtained over the previous non-object-based ver
sion of Tcl.
For more information on these commands, please consult the
ListObj(3) manual page in the core Tcl distribution.
CONCATENATING STRINGS
Tcl_ConcatObj concatenates the string representation of
zero or more objects into a single new object. The ele
ments of the new string are space-separated. Tcl_Concat
does the same thing for strings, as Tcl_ConcatObj does for
objects.
Concatenating strings is similar to constructing lists
from them, except that Tcl_ConcatObj and Tcl_Concat do not
attempt to make the resulting string into a valid Tcl
list.
Tcl_Concat is documented in the Concat(3) manpage, and
Tcl_ConcatObj in the tringObj manpage, both in the core
Tcl distribution.
DETECTING WHETHER OR NOT YOU HAVE A COMPLETE COMMAND
C routines that collect data to form a command to be
passed to Tcl_Eval often need a way to tell whether they
have a complete command already or whether they need more
data. (Programs that read typed-in Tcl input such as Tcl
shells need this capability, for instance.) Tcl_Command
Complete can be used to tell whether or not you have a
complete command.
distribution.
RECORDING COMMANDS FOR COMMAND HISTORY
Tcl has a history mechanism that is accessed from Tcl
through the history command. If you want your extension
to propagate commands into the command history, you should
call Tcl_RecordAndEvalObj (object system) or Tcl_RecordAn
dEval (old system),
These commands work like Tcl_EvalObj and Tcl_Eval, respec
tively, except that these versions record the command as
well as executing it.
Tcl_RecordAndEval and Tcl_RecordAndEvlObj should only be
called with user-entered top-level commands, since the
history mechanism exists to allow the user to easily
access, edit and reissue previously issued commands.
For complete information on these functions, please exam
ine the RecordEval.3 and RecEvalObj.3 manual pages in the
core Tcl distribution.
CONVERTING FLOATING POINT VALUES TO STRINGS
The Tcl object system's Tcl_GetDoubleFromObj and Tcl_Set
DoubleObj use Tcl objects, rather than the strings used by
Tcl_PrintDouble, and convert, when necessary, an ASCII
string to a double and back again.
These routines ensure that the string output will continue
to be interpretable as a floating point number, rather
than an integer, by always putting a ``.'' or ``e'' into
the string representing the number.
The precision of the output string is controlled by the
Tcl tcl_precision variable.
For complete information on these routines, please examine
DoubleObj(3) and PrintDbl(3) in the core Tcl distribution.
CREATING CHILD PROCESSES AND PIPELINES FROM C
Tcl_OpenCommandChannel provides a C-level interface to the
exec and open commands. The child (or pipeline of chil
dren) can have its standard input, output and error redi
rected from files, variables or pipes. To understand the
meaning of the redirection symbols understood by this
function, look at the exec(n) Tcl command. For complete
information on Tcl_OpenCommandChannel, please examine
OpenFileChnl(3).
On Posix/Unix systems, Tcl filehandles passed to your C
extension can be translated to a Posix FILE * structure
using the Tcl_GetOpenFile function, documented in GetOp
nFl.3.
MANAGING BACKGROUND PROCESS TERMINATION AND CLEANUP
When a Posix system does a fork to create a new process,
the process ID of the child is returned to the caller.
After the child process exits, its process table entry
(and some other data associated with the process) cannot
be reclaimed by the operating system until a call to wait
pid, or one of a couple of other, similar system calls,
has been made by the parent process.
The C extension writer who has created a subprocess, by
whatever mechanism, can turn over responsibility for
detecting the processes' termination and calling waitpid
to obtain its exit status, by calling Tcl_DetachPids on
it.
Tcl_ReapDetachedProcs is the C routine that will detect
the termination of any processes turned over to Tcl, per
mitting the processes to be fully reclaimed by the operat
ing system. It is usually not necessary to call
Tcl_ReapDetachedProcs, as it is called automatically every
time exec is performed.
For complete information on these routines, please look at
DetachPids(3) in the core Tcl distribution.
FOR MORE INFORMATION
In addition to the documentation referenced above, you can
learn a lot by studying the source code of the commands
added by Tcl, Tk and Extended Tcl, etc. The comp.lang.tcl
Usenet newsgroup is read by hundreds of thousands of Tcl
people. A number of Frequently Asked Questions (FAQs)
about Tcl are posted there periodically. The newsgroup is
a good place to ask questions (after you've made sure
they're not already answered in the FAQ ;-)
Finally, if you have interactive Internet access, you can
ftp to ftp://ftp.neosoft.com/pub/tcl, the site for con
tributed Tcl sources. This site contains quite a few
extensions, applications, and so forth, including several
object-oriented extension packages.
If you have access via the world-wide web, check out the
Sun Microsystems site (http://sunscript.sun.com), the con
tributed sources archive website
(http://www.neosoft.com/tcl), and the homepage for
Extended Tcl (http://www.neosoft.com/tclx).
Extended Tcl was created by Karl Lehenbauer
(karl@neosoft.com) and Mark Diekhans (markd@grizzly.com).
Man(1) output converted with
man2html