Objective-Everything Release 5.  Copyright ©1994-1998 by TipTop Software, Inc.  All Rights Reserved.

  Integration with C

Objective-Tcl facilitates direct and seamless interaction with compiled C code and data structures.

All Objective-Tcl procedures live in the objtcl:: namespace.  This namespace is, by default, imported into global namespace so that you normally do not have to prefix ObjTcl commands with objtcl::

All C symbols normally live in the c:: namespace.  By default, all the symbols in the C namespace can be directly accessed in the global namespace.

The Objective-Everything system maintains a global table of type names and symbol names.  When the system starts up, it loads these tables from the module directories of each module that is loaded: Mod.framework/Resources/Mod.cfun, where, Mod is ObjCore, ObjAppKit, ObjTcl, ObjPy, etc.  In addition, any user-specific definitions provided in ~/.AppInfo/Objective/User.cfun will be automatically loaded at startup as well.  At runtime, you can explicitly load any additional definitions.

NOTE: ObjTcl gives you full and unrestricted access to C.  Although ObjTcl by default does check for invalid memory access and such, just like in C, be careful not to crash the system.

All of the examples below are executed in an AppKit interactor.  To run an AppKit interactor, simply double-click on ObjShell.app.  Alternatively, run objtclsh, type appkit::run, and then click Objective->Interact->Interactor and select "Tcl".  This is only relevant because some examples below operate on the $NSApp object which is non-existent or nil if the appkit is not running, or invoke the NSRunAlertPanel() function.

Type System

In Objective-Tcl, you use the standard C/ObjC syntax to specify types.  All C/ObjC types are supported.

cdef stuff

Declare/define C stuff, i.e., types, functions, globals, classes, categories, protocols, etc., using the C/ObjC syntax.

Example:

 tcl% cdef { 
 %-->   struct mystruct { 
 %-->     int anInt; 
 %-->     double aDouble; 
 %-->     id anObject; 
 %-->     char *aString; 
 %-->     NSArray *anArray; 
 %-->   }; 
 %-->   typedef struct mystruct *xyz; 
 %-->   double cos(double); 
 %-->   extern int errno; 
 > } 

This registers "struct mystruct" and type "xyz" in the global C type table.  It also registers function "cos" and global "errno" with the specified prototypes in the global symbol table.

tencode type

Returns extended ObjC type encoding for the given type.

Example:

 tcl% tencode char 
 c 
 tcl% tencode {char *} 
 * 
 tcl% tencode NSRect 
 {?="origin"{?="x"f"y"f}"size"{?="width"f"height"f}} 
 tcl% tencode {union { int x; char *y; float d;}} 
 ("x"i"y"*"d"f) 
 tcl% tencode {int func(double dbl, float flt)} 
 <"func"i"dbl"d"flt"f> 
 tcl% tencode xyz 
 ^{mystruct="anInt"i"aDouble"d"anObject"@"aString"*"anArray"@} 
 tcl% tencode {struct mystruct} 
 {mystruct="anInt"i"aDouble"d"anObject"@"aString"*"anArray"@} 
 tcl% tencode cos 
tdecode encoding

Returns extended ObjC type encoding for the given type.

Example:

 tcl% tdecode {{?="origin"{?="x"f"y"f}"size"{?="width"f"height"f}}} 
 NSRect 
 tcl% tdecode r* 
 const STR 
 tcl% tdecode [tencode {struct mystruct}] 
 struct mystruct 
texpand type

Returns expanded type.

Example:

 tcl% texpand NSRect 
 struct { 
   struct { 
     float x; 
     float y; 
   } origin; 
   struct { 
     float width; 
     float height; 
   } size; 
 } 
sizeof type

Returns byte size of type.

Example:

 tcl% sizeof NSRect 
 16 
alignof type

Returns byte alignment of type.

Example:

 tcl% alignof NSRect 
 4 

C Data

In ObjTcl, C data is represented by the C datum type.  Every C datum has two properties: type and address.  Use typeof and addrof procedures to get these properties respectively.  There are two main C datum subtypes: pointer datum and function datum.

ObjTcl C datum type is represented as a Tcl string of the form type@address where type is the datum's extended type encoding, and address is the datum's address.

Pointer Datum

A pointer datum represents a value stored in memory.

ptr name

Returns the datum which is registered in the global symbol table with name.  This is really an identity function.

Example: NSApp is registered in the global C symbol table.

 tcl% ptr NSApp 
 NSApp 
 tcl% typeof [ptr NSApp] 
 id 
 tcl% addrof [ptr NSApp] 
 0x62598a4 
ptr datum

Creates a duplicate of the datum.

ptr type address
ptr type datum

Creates and returns a datum of specified type with specified address.  Address can be symbolic, or given as another datum.  If the address is given as a datum ptr essentially casts the datum to the specified type.

Example: NSApp is registered in the global C symbol table.

 # NULL pointer of type int 
 tcl% set p [ptr int 0x0] 
 ^i@0x0 
 tcl% typeof $p 
 int 
 tcl% addrof $p 
 0x0 
 # Cast NSApp to int pointer 
 tcl% set a [ptr int NSApp] 
 ^i@NSApp 
 tcl% typeof $a 
 int 
 tcl% addrof $a 
 0x62598a4 
ptr object

Casts object to datum.  This essentially is an identity operation since objects are C data.

Example:

 tcl% set app [NSApplication sharedApplication] 
 @TTApplication@a795c 
 tcl% set app_as_ptr [ptr $app] 
 @TTApplication@a795c 
 tcl% typeof $app_as_ptr 
 struct { 
 Class isa; 
 id _nextResponder; 
 NSEvent* _currentEvent; 
 ... 
 } 
 # or, simply: 
 tcl% typeof $app 
 ... 
ptr &val

Tcl values which have '&' as the first character are treated as C data of type char[n], where n is the length of the Tcl string value, and the address being a pointer to the actual second character of the Tcl string.  This is sometimes useful as a shortcut if you need a static character buffer; you don't need to malloc the data, you just use the storage allocated for the Tcl value itself.  Be careful when you use this because when the Tcl value is gone, the C datum that it represented will point into deallocated memory.

 tcl% set buf "&01234567890123456789" 
 &01234567890123456789 
 tcl% typeof $buf 
 char [21] 
 tcl% addrof $buf 
 0x118d39 
 tcl% store $buf "Hello World!" 
 tcl% set buf 
 &Hello World\03456789 
 tcl% fetch $buf 
 Hello World!\03456789 

The NULL pointer

NULL

The NULL procedure returns a special, unique NULL value which acts just like [ptr void 0x0], but it has no printable representation.  This value is returned as a result of invoking a C function or method which returns a NULL value.

thenullp datum

Tests whether the datum is the special NULL value.

Example:

 tcl% NULL 
 tcl% thenullp [ptr void 0x0] 
 0 
 tcl% thenullp [NULL] 
 1 
 tcl% typeof [NULL] 
 void 
 tcl% addrof [NULL] 
 0x0 

Allocation, deallocation, offset

malloc type ?cnt?

Allocates cnt items of the specified type and returns a pointer datum to the allocated memory.

realloc ptr ?cnt?

Reallocates pointer datum to hold cnt items

free ptr

Frees memory pointed to by ptr.

offset ptr ?cnt?

Pointer arithmetic: offset pointer.

Value access

fetch ptr ?idx? ptr

Fetches (dereferences) the value pointed to by ptr.  Index idx can be used to specify subdatum.
You can also fetch the value of the (entire) ptr datum by "calling" the datum.

The index is a list specifying a path to a subdatum.  Each element of the list can be:

&
the datum itself
*
dereferences the pointer datum.
name
accesses element name of the structure or union datum.  name must be a valid element name for the structure/union.
i
where i is an integer. pointer datum: dereferences the datum at the offset. array datum: access the i-th array element. structure/union datum: access i-th struct/union element.

store ptr ?idx? val

Stores value val into the specified (sub)datum.

Example:

 # Allocate a NSRect, store a value in it, read some values 
 tcl% set p [malloc NSRect] 
 ^{?="origin"{?="x"f"y"f}"size"{?="width"f"height"f}}@0x56174 
 tcl% store $p {{1 2} {3 4}} 
 tcl% fetch $p 
 {1.0 2.0} {3.0 4.0} 
 tcl% fetch $p origin 
 1.0 2.0 
 tcl% fetch $p {size width} 
 3.0 
 tcl% fetch $p {1 0} 
 3.0 
 # Reallocate p; access the second element 
 tcl% set p [realloc $p 2] 
 ^{?="origin"{?="x"f"y"f}"size"{?="width"f"height"f}}@0x56174 
 tcl% set p2 [offset $p 1] 
 ^{?="origin"{?="x"f"y"f}"size"{?="width"f"height"f}}@0x56184 
 tcl% store $p2 {{5 6} {7 8}} 
 # Free p 
 tcl% set p [free $p] 
 ^{?="origin"{?="x"f"y"f}"size"{?="width"f"height"f}}@0x0 
 # Store/fetch index 
 tcl% set q [malloc {NSPoint [5]}] 
 ^[5{?="x"f"y"f}]@0x561a8 
 tcl% texpand [typeof $q] 
 struct { 
   float x; 
   float y; 
 } [5] 
 tcl% store $q {2 x} 123 
 tcl% fetch $q 
 {0.0 0.0} {0.0 0.0} {123.0 0.0} {0.0 0.0} {0.0 0.0} 
 # & operator returns the item address 
 tcl% fetch $q & 
 ^[5{?="x"f"y"f}]@0x561a8 
 # I.e., this is $q itself 
 # Get the address of q[2].y:  q2y=&(q[2].y); 
 tcl% set q2y [fetch $q {2 y &}] 
 ^f@0x561bc 
 tcl% store $q2y {456} 
 tcl% $q 
 {0.0 0.0} {0.0 0.0} {123.0 456.0} {0.0 0.0} {0.0 0.0} 
 tcl% set q [free $q] 
 ^[5{?="x"f"y"f}]@0x0 
 tcl% set app [NSApplication sharedApplication] 
 @TTApplication@a795c 
 # Fetch all instance variables of an object at once 
 tcl% fetch $app 
 TTApplication nil @NSEvent@15bfc8 @NSConcreteMutableArray@a1210 ... 
 # Get a pointer to an instance variable 
 tcl% set currentEventPtr [fetch $app {_currentEvent &}] 
 ^@'NSEvent'@0xa7964 
 # Get the value pointed to 
 tcl% fetch $currentEventPtr 
 @NSEvent@147904 
 tcl% * [fetch $currentEventPtr] 
 NSEvent: type=KeyDown loc=(0,0) time=... 

C Function Datum

C function datum is used to invoke a C function

fun name

Returns a function which is registered in the global symbol table with name.  This is really an identity function.

Example:

 tcl% typeof [fun NSBeep] 
 void ()() 
fun function

Creates a duplicate of the function.

fun type address fun type datum

Creates and returns a function of specified type with specified entry point address.  Address can be symbolic, or given as another datum.  If the address is given as a datum fun essentially casts the datum to the specified function type.

Example:

 tcl% set pf [fun {void printf(const char *format, int x, char *y)} printf] 
 <"printf"v"format"r*"x"i"y"*>@printf 
 tcl% call $pf "Hello World!!  int=%d, char*=%s\n" 123 "abc" 
 # stdout:  Hello World!!  int=123, char*=abc 
fun object selector

Casts a method into a function.

Example:

 tcl% set mm [fun $app mainMenu] 
 <"mainMenu"@"self"@"_cmd":>@0x6081b20 
 tcl% typeof $mm 
 id mainMenu(id self, SEL _cmd) 
 tcl% call $mm $app mainMenu 
 @NSMenu@b01e8 
 tcl% [$mm $app mainMenu] setTitle: "Hello" 
call fun args...
fun args...

Invokes a function with arguments.

Example:

 tcl% cos 1 
 0.540302305868 
 tcl% NSRunAlertPanel "ObjTcl" "Hello World!" [nil] [nil] [nil] 
 1 

Registering data

defglob name ?ptr?

Defines a global datum with name, and makes it available as a Tcl global variable.

Example:

 tcl% defglob NSApp 
 tcl% set NSApp 
 @TTApplication@a795c 
 tcl% defglob NSApp_as_int [ptr int NSApp] 
 tcl% addrof NSApp 
 0x62598a4 
 tcl% addrof NSApp_as_int 
 0x62598a4 
 tcl% typeof NSApp_as_int 
 int 
 tcl% addrof $NSApp 
 0xa795c 
 tcl% format "0x%x" $NSApp_as_int 
 0xa795c 
defconst name type value

Defines a global constant with name and associated value, and makes it available as a Tcl global variable

Example:

 tcl% defconst MyRect NSRect {{12 34} {56 78}} 
 tcl% puts [MyRect] 
 {12.0 34.0} {56.0 78.0} 
defun name fun

Defines a function with name.

Example:  Make alert be an alias for NSRunAlertPanel

 tcl% defun alert NSRunAlertPanel 

Type Conversion

Tcl uses the "everything is a string" type model.  In ObjTcl, types are used for instance variable, global variable, method and function prototype declaration.  ObjTcl automatically converts from primitive C/ObjC types to Tcl values and vice versa when required.  This conversion occurs:

The type table in the previous section lists the conversion functions that are used when converting from Tcl string values to ObjC type values and vice versa. Here is a description of what each type conversion does.

Object conversion

Tcl->C: If the Tcl string value represents an object or a class, that's the result of conversion.  If the object does not directly represent the object the following will happen:  If the autoconversion is OFF, an exception is raised.  If autoconversion is ON (the default behavior), the Tcl string value will be converted to an NSString.
C->Tcl: A Tcl string value representing the object is the result of conversion.  In addition, the object is registered with the Objective-Everything system, and the system will detect when the object becomes invalid.

String conversion:

Tcl->C: Tcl values map to strings directly, with the exception that the ObjTcl [NULL] value is converted to NULL string.
C->Tcl: C strings map to Tcl values directly, with the exception that the NULL C string value  is converted to the [NULL] ObjTcl value.

Selector conversion:

Tcl->C: Tcl string value is mapped to ObjC SEL type using the standard sel_getName() function.  [NULL] Tcl values are mapped to NULL selectors
C->Tcl: ObjC SEL type is directly converted to Tcl string value using the sel_getUid() function.  NULL selectors are converted to the [NULL] Tcl value.

Integer number conversion:

Note that C char type is treated as an 8-bit integer.  You may use the ord ObjTcl procedure to convert ASCII characters to corresponding integer values.  C bitfields are also treated as integer numbers.

Tcl->C: The standard Tcl "to-integer" conversion is used.
C->Tcl: The standard integer-to-string conversion is used.

Tcl string C int
0xff 255
'A' 65
123 123
yes 1
no 0

Real number conversion:

Tcl->C: The standard Tcl "to-double" conversion is used.
C->Tcl: The standard double-to-string conversion is used.

Pointer conversion:

Tcl->C: The ObjTcl C datum type is converted to the C pointer by taking the address of the datum.
C->Tcl: C pointers are converted to the ObjTcl C datum type with the corresponding type and address.

Structure conversion:

C structs are represented as Tcl lists (i.e., struct elements correspond to Tcl list elements)  For example: struct { int x=123; float y=4.5; }; is represented as {123 4.5}.

Tcl->C: Each element of the Tcl list representing the structure is converted to the coresponding structure element.
C->Tcl: Elements of the C structure are converted to Tcl values and packed into a Tcl list.

Union conversion:

C unions are represented as Tcl lists.  The first element of the list is used to indicate which element value the second element of the list is representing.  If the first element is -1, the rest of the list contains all the union elements.

Tcl->C: Based on what the first element of the list is, appropriate conversion is performed.  For example, consider:

 union { int x; float y; } u; 

Storing {0 123} into u is equivalent to u.x=123;
Storing {1 4.5} is equivalent to u.y=4.5;
Storing {-1 123 4.5} is eqivalent to u.x=123; u.y=4.5;

C->Tcl: This conversion yields a list with -1 as the first element, followed by Tcl values corresponding to each union value.

Array conversion:

C arrays are represented as Tcl lists (i.e., array elements correspond to Tcl list elements).  For example: int x[3]={1,2,3}; is simply represented as {1 2 3}.

Tcl->C: Each element of the Tcl list is converted to the corresponding array element.
C->Tcl: Elements of the C array are converted to Tcl values and packed into a Tcl list.


[previous][contents][next]