OTcl C API (Version 0.96, September 95)

Overview

This reference page describes the C application programmer interface (API) for manipulating OTcl classes and objects. See otclAppInit.c for an example of a Timer class written in C; Timer is included in the shells if the symbol TESTCAPI is defined.

OTcl's C API is designed to complement the OTcl language in much the same way that Tcl allows commands written in C to be added to an interpreter. It is a minimal interface, suitable for migrating methods to C for performance, or for manipulating complex (ie. non-string) data structures. It is not a general package for binding C++ classes and methods to Tcl commands.

See the tutorial for an introduction to Tcl-level programming in OTcl.

Working with the C API

To access the C API, include otcl.h. This header defines the externally visible interfaces, including the data structures required to use them.

Object and Class Structures

Objects and classes are always manipulated through pointers to opaque structures:

struct OTclObject;
struct OTclClass;

Actually, you can cast a class pointer to an object pointer (since all classes are objects too) with no ill-effects, but you shouldn't need to.

Two utility functions convert string names to object and class pointers:

struct OTclObject*
OTclGetObject(Tcl_Interp* in, char* name);

struct OTclClass*
OTclGetClass(Tcl_Interp* in, char* name);

These functions are useful for getting handles to Object and Class (the system provided classes) for use in creating new classes, etc.

Two utility functions convert clientdata to object and class pointers:

struct OTclObject*
OTclAsObject(Tcl_Interp* in, ClientData cd);

struct OTclClass*
OTclAsClass(Tcl_Interp* in, ClientData cd);

These functions are useful within method definitions when you have installed the method to pass the current object via the clientdata; see the section on Methods below. They perform a safe cast.

Initialization

OTcl is initialized for an interpreter with a standard module initialization routine, called from an AppInit or through dynamic loading.

int
Otcl_Init(Tcl_Interp* in);

Calls through the C API must be arranged to occur after OTcl initialization.

Objects and Classes

Objects and classes can be created and destroyed from C as well as Tcl without distinction. That is, classes created in C can be destroyed from Tcl, and vice versa.

Creation

Objects and classes are created in an interpreter through class pointers. Use a pointer to Class to create a generic class, and a pointer to Object to create a generic object.

struct OTclObject* 
OTclCreateObject(Tcl_Interp* in, char* name, struct OTclClass* cl);

struct OTclClass*
OTclCreateClass(Tcl_Interp* in, char* name, struct OTclClass* cl);

Both calls are conceptually equivalent to "cl create name" in Tcl, but return either a pointer value or NULL to indicate failure.

Deletion

Object and classes are deleted from an interpreter through their pointers.

int
OTclDeleteObject(Tcl_Interp* in, struct OTclObject* obj);

int
OTclDeleteClass(Tcl_Interp* in, struct OTclClass* cl);

Both calls are conceptually equivalent to "obj destroy" or "cl destroy", and return a Tcl call code.

Methods

Methods can be added and combined from C as well as from Tcl without distinction. For example, C methods can be called from Tcl transparently, and C methods can combine with Tcl methods automatically.

Interface Conventions

In terms of interface, methods are analogous to Tcl commands, with two important differences.

  1. The argc/argv array is passed in "expanded form", having three extra arguments. argv[0] contains the name of the object, just as Tcl's first argument contains the name of the invoking command. The next three arguments contain values for extra method context variables: self, class, and proc. The remaining arguments (argv[4] and higher) contain the arguments passed to the method.
  2. The clientData may be used to obtain a pointer to the object on behalf of which the method is being invoked. If the method was created with a clientData of NULL, then the dispatcher fills the clientData with an object pointer. Otherwise, the dispatcher passes the specified clientData. To convert the clientData to an object or class pointer, you can use the typed casting functions OTclAsObject and OTclAsClass.

Adding Methods

Two functions add methods to objects and classes, serving as the C equivalent of the proc and instproc methods. The types of the last three arguments are the same as for Tcl commands.

void
OTclAddPMethod(struct OTclObject* obj, char* nm, Tcl_CmdProc* proc,
	       ClientData cd, Tcl_CmdDeleteProc* dp);

void
OTclAddIMethod(struct OTclClass* cl, char* nm, Tcl_CmdProc* proc,
	       ClientData cd, Tcl_CmdDeleteProc* dp);

Removing Methods

Two functions remove methods from objects and classes. If a deleteProc callback was registered to clean up the method, then it is passed the original non-NULL clientdata. If the original clientdata was NULL, however, then a pointer to the object or class from which the method is being removed is passed instead.

int
OTclRemovePMethod(struct OTclObject* obj, char* nm);

int
OTclRemoveIMethod(struct OTclClass* cl, char* nm);

Combining Methods

An executing methods can be automatically combined with the next-most specific method with the following function. It is equivalent to "obj next ..args..". argc/argv is passed in expanded form, and should carry the context of the currently executing method. It returns a Tcl return code.

int
OTclNextMethod(struct OTclObject* obj, Tcl_Interp* in, int argc, char*argv[]);

Instance Variables

Tcl accessible instance variables (stored as strings) can be manipulated from C. In addition, objects can store a handle to private auxilliary data.

*InstVar

OTclSetInstVar, OTclGetInstVar, and OTclUnsetInstVar mimic Tcl_SetVar, Tcl_GetVar, and Tcl_UnsetVar for instance variables. The return values and codes for parameters such as flgs match Tcl conventions.

char*
OTclSetInstVar(struct OTclObject* obj, Tcl_Interp* in,
	       char* name, char* value, int flgs);
char*
OTclGetInstVar(struct OTclObject* obj, Tcl_Interp* in,
               char* name, int flgs);

int
OTclUnsetInstVar(struct OTclObject* obj, Tcl_Interp* in,
                 char* name, int flgs);

Auxilliary Data

OTclSetObjectData, OTclGetObjectData and OTclUnsetObjectData manipulate private object clientdata, such as a pointer to an auxilliary data region. ObjectData is a per object and per class resource to allow for inheritance. Typically, it is manipulated on behalf of the invoking object in each class method by using the directly associated class. In this manner specializations of a class may each store their own ObjectData.

int
OTclGetObjectData(struct OTclObject* obj,struct OTclClass* cl,
		  ClientData* data);

void
OTclSetObjectData(struct OTclObject* obj, struct OTclClass* cl,
		  ClientData data);

int
OTclUnsetObjectData(struct OTclObject* obj, struct OTclClass* cl);

Get fills the data value passed by reference, and returns 0 or 1 depending on whether the ObjectData existed. If it didn't, then data is filled with NULL. Set overwrites existing ObjectData without error. Unset returns 0 or 1 depending on whether the ObjectData existed.