An Overview of the Tcl C Library
The Tcl_Main and Tcl_AppInit procedures are illustrated by Example 44-13 on page 630. They provide a standard framework for creating main programs that embed a Tcl interpreter.
The Tcl_InitStubs procedure must be called during initialization by an extension that has been linked against the Tcl stub library, which is described on page 647. Tcl_InitStubs is illustrated in Example 44-1 on page 610.
Creating and Deleting Interpreters
A Tcl interpreter is created and deleted with the Tcl_CreateInterp and Tcl_DeleteInterp procedures. You can find out if a interpreter is in the process of being deleted with the Tcl_InterpDeleted call. You can register a callback to occur when the interpreter is deleted with Tcl_CallWhenDeleted. Unregister the callback with Tcl_DontCallWhenDeleted.
Slave interpreters are created and manipulated with Tcl_CreateSlave, Tcl_GetSlave, Tcl_GetSlaves, Tcl_GetMaster, Tcl_CreateAlias, Tcl_CreateAliasObj, Tcl_GetAlias, Tcl_GetAliasObj, Tcl_GetAliases, Tcl_GetInterpPath, Tcl_IsSafe, Tcl_MakeSafe, Tcl_ExposeCommand, and Tcl_HideCommand.
Creating and Deleting Commands
Register a new Tcl command with Tcl_CreateCommand, and delete a command with Tcl_DeleteCommand. The Tcl_DeleteCommandFromToken procedure is useful if you need to delete a command that gets renamed. The Tcl_GetCommandInfo and Tcl_SetCommandInfo procedures query and modify the procedure that implements a Tcl command and the ClientData that is associated with the command. The command that uses the Tcl_Obj interface is created with Tcl_CreateObjCommand. Command procedures are illustrated in Chapter 44.
Dynamic Loading and Packages
Tcl_PkgRequire checks a dependency on another package. Tcl_PkgProvide declares that a package is provided by a library. These are equivalent to the package require and package provide Tcl commands. The Tcl_PkgPresent procedure returns the version number of the package, if it is loaded. Tcl_PkgProvideExx, Tcl_PkgRequireEx, and Tcl_PkgPresentEx let you set and query the clientData associated with the package. The Tcl_StaticPackage call is used by statically linked packages so scripts can load them into slave interpreters. The Tcl_FindExecuatable searches the system to determine the absolute file name of the program being run. Once this has been done, Tcl_GetNameOfExecutable can be used to get the cached value of the program name.
Managing the Result String
The result string is managed through the Tcl_SetResult, Tcl_AppendResult, Tcl_AppendElement, Tcl_GetStringResult, and Tcl_ResetResult procedures. The object interface is provided by Tcl_SetObjResult and Tcl_GetObjResult.
Error information is managed with the Tcl_AddErrorInfo, Tcl_AddObjErrorInfo, Tcl_SetErrorCode, and Tcl_PosixError procedures. The Tcl_WrongNumArgs generates a standard error message. The Tcl_SetErrno and Tcl_GetErrno provide platform-independent access to the errno global variable that stores POSIX error codes.
The Tcl_Alloc, Tcl_Realloc, and Tcl_Free procedures provide platform and compiler independent functions to allocation and free heap storage. Use these instead of alloc, realloc, and free. The Tcl_Preserve and Tcl_Release procedures work in concert with Tcl_EventuallyFree to guard data structures against premature deallocation. These are described on page 627.
You can chop a list up into its elements with Tcl_SplitList, which returns an array of strings. You can create a list out of an array of strings with Tcl_Merge. This behaves like the list command in that it will add syntax to the strings so that the list structure has one element for each of the strings. The Tcl_ScanElement and Tcl_ConvertElement procedures are used by Tcl_Merge. The object interface to lists is provided by Tcl_NewListObj, Tcl_SetListObj, Tcl_ListObjIndex, Tcl_ListObjAppendList, Tcl_ListObjAppendElement, Tcl_ListObjGetElements, Tcl_ListObjLength, and Tcl_ListObjReplace.
If you are reading commands, you can test for a complete command with Tcl_CommandComplete. You can do backslash substitutions with Tcl_Backslash. A more formal Tcl parser is provided by these procedures: Tcl_ParseCommand, Tcl_ParseExpr, Tcl_ParseBraces, Tcl_ParseQuotedString, Tcl_ParseVarName, and Tcl_FreeParse. The result of the parse is a sequence of tokens, which you can evaluate with Tcl_EvalTokens.
The Tcl_OpenCommandChannel procedure does all the work of setting up a pipeline between processes. It handles file redirection and implements all the syntax supported by the exec and open commands.
If the command pipeline is run in the background, then a list of process identifiers is returned. You can detach these processes with Tcl_DetachPids, and you can clean up after them with Tcl_ReapDetachedProcs.
Tracing the Actions of the Tcl Interpreter
There are several procedures that let you trace the execution of the Tcl interpreter and provide control over its behavior. The Tcl_CreateTrace registers a procedure that is called before the execution of each Tcl command. Remove the registration with Tcl_DeleteTrace.
You can trace modifications and accesses to Tcl variables with Tcl_TraceVar and Tcl_TraceVar2. The second form is used with array elements. Remove the traces with Tcl_UntraceVar and Tcl_UntraceVar2. You can query the traces on variables with Tcl_VarTraceInfo and Tcl_VarTraceInfo2.
Evaluating Tcl Commands
There is a large family of procedure that evaluate Tcl commands. Tcl_Eval evaluates a string as a Tcl command. Tcl_VarEval takes a variable number of string arguments and concatenates them before evaluation. The Tcl_EvalFile command reads commands from a file. Tcl_GlobalEval evaluates a string at the global scope. The Tcl_EvalEx procedure takes flags. The TCL_GLOBAL_EVAL flag causes evaluation at the global scope. The TCL_EVAL_DIRECT flags does evaluation without first compiling the script to byte codes.
Tcl_EvalObj and Tcl_GlobalEvalObj provide an object interface. Their argument is a script object that gets compiled into byte codes and cached. Use these procedures if you plan to execute the same script several times. The Tcl_EvalObjEx procedure takes the evaluation flags described above. The Tcl_EvalObjv procedure takes an array of Tcl_Obj that represent the command and its arguments.Unlike the other procedures, Tcl_EvalObjv does not do sub-stitutionson the arguments to the command.
If you are implementing an interactive command interpreter and want to use the history facility, then call Tcl_RecordAndEval or Tcl_RecordAndEval. This records the command on the history list and then behaves like Tcl_GlobalEval.
You can set the recursion limit of the interpreter with Tcl_SetRecursionLimit. If you are implementing a new control structure, you may need to use the Tcl_AllowExceptions procedure. This makes it acceptable for Tcl_Eval and friends to return something other than TCL_OK and TCL_ERROR.
If you want to evaluate a Tcl command without modifying the current interpreter result and error information, use Tcl_SaveResult, Tcl_RestoreResult, and Tcl_DiscardResult.
Reporting Script Errors
If your widget makes a callback into the script level, what do you do when the callback returns an error? Use the Tcl_BackgroundError procedure that invokes the standard bgerror procedure to report the error to the user.
Manipulating Tcl Variables
You can set a Tcl variable with Tcl_SetVar and Tcl_SetVar2. These two procedures assign a string value, and the second form is used for array elements. The Tcl_SetVar2Ex procedure assigns a Tcl_Obj value to the variable, and it can be used with array elements. You can retrieve the value of a Tcl variable with Tcl_GetVar and Tcl_GetVar2. The Tcl_GetVar2Ex procedure returns a Tcl_Obj value instead of a string. In the rare case that you have the name of the variable in a Tcl_Obj instead of a simple string, you must use Tcl_ObjSetVar2 procedure and Tcl_ObjGetVar2. You can delete variables with Tcl_UnsetVar and Tcl_UnsetVar2.
You can link a Tcl variable and a C variable together with Tcl_LinkVar and break the relationship with Tcl_UnlinkVar. Setting the Tcl variable modifies the C variable, and reading the Tcl variable returns the value of the C variable. If you need to modify the Tcl variable directly, use Tcl_UpdateLinkedVar.
Use the Tcl_UpVar and Tcl_UpVar2 procedures to link Tcl variables from different scopes together. You may need to do this if your command takes the name of a variable as an argument as opposed to a value. These procedures are used in the implementation of the upvar Tcl command.
The Tcl expression evaluator is available through the Tcl_ExprLong, Tcl_ExprDouble, Tcl_ExprBoolean, and Tcl_ExprString procedures. These all use the same evaluator, but they differ in how they return their result. The object interface to expressions is implemented with Tcl_ExprLongObj, Tcl_ExprDoubleObj, Tcl_ExprBooleanObj, and Tcl_ExprObj. You can register the implementation of new math functions by using the Tcl_CreateMathFunc procedure.
You can convert strings into numbers with the Tcl_GetInt, Tcl_GetDouble, and Tcl_GetBoolean procedures. The Tcl_PrintDouble procedure converts a floating point number to a string. Tcl uses it anytime it must do this conversion.
Tcl 8.0 uses dual-ported objects instead of strings to improve execution efficiency. The basic interface to objects is provided by Tcl_NewObj, Tl_DuplicateObj, Tcl_IncrRefCount, Tcl_DecrRefCount, and Tcl_IsShared. Example 44-5 on page 618 and Example 44-15 on page 636 illustrate some of these procedures. You can define new object types. The interface consists of Tcl_RegisterObjType, Tcl_GetObjType, Tcl_AppendAllObjTypes, and Tcl_ConvertToType.
Primitive Object Types
The basic Tcl object types are boolean, integer, double precision real, and string. The types provide procedures for creating objects, setting values, and getting values: Tcl_NewBooleanObj, Tcl_SetBooleanObj, Tcl_GetBooleanFromObj, Tcl_NewDoubleObj, Tcl_SetDoubleObj, Tcl_GetDoubleFromObj, Tcl_NewIntObj, Tcl_GetIntFromObj, Tcl_SetIntObj, Tcl_NewLongObj, Tcl_GetLongFromObj, and Tcl_SetLongObj.
String Object Types
The Tcl_Obj values are used to store strings in different encodings. The natural string value in a Tcl_Obj is UTF-8 encoded. There can also be Unicode (i.e., 16-bit characters) or ByteArray (i.e., 8-bit characters) format strings stored in a Tcl_Obj. Conversions among these string types are done automatically. However, certain operations work best with a particular string encoding, and the Tcl_Obj value is useful for caching an efficient representation.
These procedures operate on string objects with the UTF-8 encoding: Tcl_NewStringObj, Tcl_SetStringObj, Tcl_GetString, Tcl_GetStringFromObj, Tcl_AppendToObj, and Tcl_AppendStringsToObj. These procedures operate on Unicode strings: Tcl_NewUnicodeObj, Tcl_SetUnicodeObj, Tcl_AppendUnicodeToObj, Tcl_GetUnicode, Tcl_GetRange, and Tcl_GetUniChar. The Tcl_AppendObjToObj preserves the existing representation (e.g., Unicode or UTF-8) of the string being appended to.
The Tcl_GetCharLength returns the length in characters of the string. Tcl_SetObjLength procedure sets the storage size of the string in bytes, which is generally different than the character length. This can be used to over allocate a string in preparation for creating a large one.
The Tcl_Concat and Tcl_ConcatObj procedures operate like the concat Tcl command. Its input are an array of strings (for Tcl_Concat) or Tcl_Obj values (for Tcl_ConcatObj). They trim leading and trailing white space from each one, and concatenate them together into one string with a single space character between each value.
ByteArrays for Binary Data
The ByteArray Tcl_Obj type is used to store arbitrary binary data. It is simply an array of 8-bit bytes. These are its procedures: Tcl_NewByteArrayObj, Tcl_SetByteArrayObj, Tcl_GetByteArrayFromObj, and Tcl_SetByteArray-Length.
The Tcl dynamic string package is designed for strings that get built up incrementally. You will need to use dynamic strings if you use the Tcl_TranslateFileName procedure. The procedures in the package are Tcl_DStringInit, Tcl_DStringAppend, Tcl_DStringAppendElement, Tcl_DStringStartSublist, Tcl_DStringEndSublist, Tcl_DStringLength, Tcl_DStringValue, Tcl_DStringSetLength, Tcl_DStringFree, Tcl_DString-Result, and Tcl_DStringGetResult. Dynamic strings are explained in more detail on page 628.
Character Set Encodings
The procedures that convert strings between character set encodings use an abstract handle on a particular encoding. The Tcl_GetEncoding and Tcl_FreeEncoding procedures allocate and release these handles. Tcl_SetSystemEncoding is called by Tcl to set the encoding for the current system. Tcl_CreateEncoding creates a new encoding. The Tcl_GetEncodingName and Tcl_GetEncodingNames procedures query the available encodings. The encodings are stored in files in default location, which you query and set with Tcl_GetDefaultEncodingDir and Tcl_SetDefaultEncodingDir.
There are three sets of procedures that translate strings between encodings. The easiest to use are Tcl_ExternalToUtfDString and Tcl_UtfToExternalDString, which put the result into a Tcl_DString. These are built on top of Tcl_ExternalToUtf and Tcl_UtfToExternal, which are harder to use because they have to deal with partial conversions at the end of the buffer. The Tcl_WinTCharToUtf and Tcl_WinUtfToTChar procedures are for use with Windows TChar type, which is an 8-bit character on Windows 98 and a 16-bit Unicode character on Windows N/T.
There are many utility procedures for operating on Unicode and UTF-8 strings: Tcl_UniChar, Tcl_UniCharToUtf, Tcl_UtfToUniChar, Tcl_UniCharToUtfDString, Tcl_UtfToUniCharDString, Tcl_UniCharLen, Tcl_UniCharNcmp, Tcl_UtfCharComplete, Tcl_NumUtfChars, Tcl_UtfFindFirst, Tcl_UtfFindLast, Tcl_UtfNext, Tcl_UtfPrev, Tcl_UniCharAtIndex, Tcl_UtfAtIndex, and Tcl_UtfBackslash.
These procedures convert Unicode characters to different cases: Tcl_UniCharToUpper, Tcl_UniCharToLower, and Tcl_UniCharToTitle. These procedures convert strings: Tcl_UtfToUpper, Tcl_UtfToLower, Tcl_UtfToTitle.
AssocData for per Interpreter Data Structures
If your extension needs to store information that is not associated with any particular command, you can associate it with an interpreter with AssocData. The Tcl_SetAssocData registers a string-valued key for a data structure. The Tcl_GetAssocData gets the data for a key, and Tcl_DeleteAssocData removes the key and pointer. The registration also includes a callback that is made when the interpreter is deleted. This is a layer on top of the hash table package described next.
Tcl has a nice hash table package that automatically grows the hash table data structures as more elements are added to the table. Because everything is a string, you may need to set up a hash table that maps from a string-valued key to an internal data structure. The procedures in the package are Tcl_InitHashTable, Tcl_DeleteHashTable, Tcl_CreateHashEntry, Tcl_Delete-HashEntry, Tcl_FindHashEntry, Tcl_GetHashValue, Tcl_SetHashValue, Tcl_GetHashKey, Tcl_FirstHashEntry, Tcl_NextHashEntry, and Tcl_HashStats. Hash tables are used in the blob command example presented in Chapter 44.
The Tcl_GetIndexFromObj provides a way to look up keywords in a table. It returns the index of the table entry that matches a keyword. It is designed to work with options on a Tcl command. It is illustrated in Example 44-8 on page 622.
Regular Expressions and String Matching
The regular expression library used by Tcl is exported through the Tcl_RegExpMatch, Tcl_RegExpCompile, Tcl_RegExpExec, and Tcl_RegExpRange procedures. The Tcl_Obj version of this interface uses the Tcl_RegExpMatchObj, Tcl_GetRegExpFromObj, Tcl_RegExpExecObj and Tcl_GetRegExpInfo procedures. The string match function is available through the Tcl_StringMatch and Tcl_StringCaseMatch procedures.
Event Loop Implementation
The event loop is implemented by the notifier that manages a set of event sources and a queue of pending events. The tclsh and wish applications already manage the event loop for you. The simplest interface is provided by Tcl_DoOneEvent. In some cases you may need to implement new event sources. Use Tcl_CreateEventSource and Tcl_DeleteEventSource to create and destroy an event source. An event source manipulates the events queue with Tcl_QueueEvent, Tcl_DeleteEvents, and Tcl_SetMaxBlockTime.
Each thread runs a notifier. You can enqueue events for another thread's notifier with Tcl_ThreadQueueEvent. After you do this, you must signal the other thread with Tcl_ThreadAlert. The ID of the current thread is returned from Tcl_GetCurrentThread.
The notifier is implemented with a public API so that you can replace the API with a new implementation for custom situations. This API consists of Tcl_InitNotifier, Tcl_FinalizeNotifier, Tcl_WaitForEvent, Tcl_Alert-Notifier, Tcl_Sleep, Tcl_CreateFileHandler, and Tcl_DeleteFileHandler.
If you want to integrate Tcl's event loop with an external one, such as the Xt event loop used by Motif, then you can use the following procedures: Tcl_WaitForEvent, Tcl_SetTimer, Tcl_ServiceAll, Tcl_ServiceEvent, Tcl_GetServiceMode, and Tcl_SetServiceMode. There is an example application of this in the unix/xtTest.c file.
Use Tcl_CreateFileHandler to register handlers for I/O streams. You set up the handlers to be called when the I/O stream is ready for reading or writing, or both. File handlers are called after window event handlers. Use Tcl_DeleteFileHandler to remove the handler.
Tcl_CreateFileHandler is UNIX specific because UNIX has a unified handle for files, sockets, pipes, and devices. On Windows and the Macintosh there are different system APIs to wait for events from these different classes of I/O objects. These differences are hidden by the channel drivers for sockets and pipes. For non-standard devices, the best thing to do is create a channel driver and event source for them.
Register a callback to occur at some time in the future with Tcl_CreateTimerHandler. The handler is called only once. If you need to delete the handler before it gets called, use Tcl_DeleteTimerHandler.
If there are no outstanding events, the Tk makes idle callbacks before waiting for new events to arrive. In general, Tk widgets queue their display routines to be called at idle time. Use Tcl_DoWhenIdle to queue an idle callback, and use Tcl_CancelIdleCall to remove the callback from the queue. The Tcl_Sleep procedure delays execution for a specified number of milliseconds.
The Tcl I/O subsystem provides buffering and works with the event loop to provide event-driven I/O. The interface consists of Tcl_OpenFileChannel, Tcl_OpenCommandChannel, Tcl_MakeFileChannel, Tcl_GetOpenFile, Tcl_RegisterChannel, Tcl_UnregisterChannel, Tcl_Close, Tcl_Read, Tcl_ReadChars, Tcl_Gets, Tcl_Write, Tcl_WriteObj, Tcl_WriteChars, Tcl_Flush, Tcl_Seek, Tcl_Tell, Tcl_Eof, Tcl_GetsObj, Tcl_InputBlocked, Tcl_InputBuffered, Tcl_GetChannelOption, and Tcl_SetChannelOption.
I/O Channel Drivers
Tcl provides an extensible I/O subsystem. You can implement a new channel (i.e., for a UDP network socket) by providing a Tcl command to create the channel and registering a set of callbacks that are used by the standard Tcl I/O commands like puts, gets, and close. The interface to channels consists of these procedures: Tcl_CreateChannel, Tcl_GetChannel, Tcl_GetChannelType, Tcl_GetChannelInstanceData, Tcl_GetChannelName, Tcl_GetChannelHandle, Tcl_GetChannelMode, Tcl_BadChannelOption, Tcl_GetChannelBufferSize, Tcl_SetDefaultTranslation, Tcl_SetChannelBufferSize, and Tcl_NotifyChannel.
The Tcl_CreateChannelHandler and Tcl_DeleteChannelHandler are used in the interface to the main event loop. The Tcl_CreateCloseHandler and Tcl_DeleteCloseHandler set and delete a callback that occurs when a channel is closed. The Tcl_GetStdChannel and Tcl_SetStdChannel are used to manipulate the standard input and standard output channels of your application.
Network sockets are created with Tcl_OpenTcpClient, and Tcl_OpenTcpServer. The Tcl_MakeTcpClientChannel provides a platform-independent way to create a Tcl channel structure for a socket connection.
The Tcl_StackChannel, Tcl_UnstackChannel, and Tcl_GetStackedChannel procedures support layering of I/O channels. This can be used to push compression or encryption processing modules onto I/O channels.
Manipulating File Names
The Tcl_SplitPath, Tcl_JoinPath, and Tcl_GetPathType procedures provide the implementation for the file split, file join, and file pathtype Tcl commands that are used to manipulate file names in a platform-independent manner. The Tcl_TranslateFileName procedure converts a file name to native syntax. It also expands (~) in file names into user home directories.
Examining the File System
The Tcl_Stat and Tcl_Access functions are thin layers on top of the UNIX stat and access system calls. Tcl_Stat returns information about a file, and Tcl_Access checks access permissions. The Tcl_Chdir procedure changes the current working directory, and Tcl_GetCwd returns the current working directory. These procedures are cross-platform, plus they support hooks used by TclPro Wrapper to store files inside an executable.
The Tcl library is thread safe. It uses the following procedures to serialize access to its data structures: Tcl_MutexLock, Tcl_MutexUnlock, Tcl_ConditionWait, and Tcl_ConditionNotify. Thread local storage is provided by Tcl_GetThreadData. All of these procedures are self-initializing so there are no explicit initialization calls.
The Tcl_CreateThreadExitHandler procedure registers a procedure that is called when a thread is terminated. In particular, it can clean up thread local storage. Use Tcl_DeleteThreadExitHandler to remove a registration.
Tcl_FinalizeThread is called when a thread is exiting to clean up state. Currently the thread creation API is still private (TclpCreateThread), and script-level access to threads is provided by an extension.
Working with Signals
Tcl provides a simple package for safely dealing with signals and other asynchronous events. You register a handler for an event with Tcl_AsyncCreate. When the event occurs, you mark the handler as ready with Tcl_AsyncMark. When the Tcl interpreter is at a safe point, it uses Tcl_AsyncReady to determine which handlers are ready, and then it uses Tcl_AsyncInvoke to call them. Your application can call Tcl_AsyncInvoke, too. Use Tcl_AsyncDelete to unregister a handler.
The Tcl_Exit procedure terminates the application. The Tcl_Finalize procedure cleans up Tcl's memory usage and calls exit handlers, but it does not exit. This is necessary when unloading the Tcl DLL. The Tcl_CreateExitHandler and Tcl_DeleteExitHandler set up callbacks that occur when Tcl_Exit is called.