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

  Integration with C

Objective-Python facilitates direct and seamless interaction with compiled C code and data structures.  C symbols live in the ObjPy.C namespace.

The Objective-Everything system maintains global tables 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/ObjectiveEverythin/User.cfun will be automatically loaded at startup as well.  See the Resources section for more info. At runtime, you can explicitly load any additional definitions using the cimport command.

NOTE: ObjPy gives you full and unrestricted access to C.  Although ObjPy 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 objpy, type import AppKit; AppKit.run(), and then click Objective->Interact->Interactor and select "Python".  This is only relevant because some examples below invoke the NSRunAlertPanel() function or operate on the NSApp object which is non-existent or nil if the appkit is not running.

C Parser

The C Parser subsystem provides the following two commands:

ObjPy.cdef(stuff[,kwflags])

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

Keyword flags:
out
integer 0/1
no_def
integer 0/1

Example

 py% 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.

Example:

 py% cdef(""" 
 %-> extern double sin(double); 
 %-> 
 %-> @protocol MyProtocol 
 %-> - (void)aMethod; 
 %-> @end 
 %-> 
 %-> @interface NSObject(Add_A_Method) 
 %-> - (NSString*)sayHello; 
 %-> /* ObjPy: 
 %->    return "%s sez hello to you" % self 
 %-> */ 
 %-> @end 
 %-> """, out=1) 
 'sin <"?"d"?"d>\012#@protocol MyProtocol\012#@category NSObject(Add_A_Method)\012' 
 py% C.sin(1) 
 0.841470984808 
 py% print unparse(Protocol.MyProtocol) 
 @protocol MyProtocol 
 // Implemented by: no one 
 // Class methods: none 
 // Instance methods 
 - (void)aMethod; 
 @end 
 py% CGlob.NSApp.sayHello() 
'<TTApplication: 0x8f728> sez hello to you'

Note: The cdef facility is not a full-fledged C compiler: C function bodies, and ObjC method bodies are not parsed.

Note: Mixing multiple-language method implementations in a single category definition is not yet fully supported.

ObjPy.cinclude(stuff [,kwflags])

Parses C/ObjC syntax text from file.

Example:

 py% from ObjPy import * 
py% cinclude('/usr/include/ansi/stdio.h',cpp='')
py% f=C.fopen('/tmp/test','w')
py% C.fprintf(f,'Hello World!\n')
0
py% C.fclose(f)
0

Type System

In ObjPy, Type object is used to represent C/ObjC types.  You use the standard ObjC syntax to specify types.

Type.type
Type(type)

Creates a type object.

Type.tname=type

Defines new type tname.  This is equivalent to typedef in C.

Attributes

type.encoding

Returns type encoding.

type.type 

Returns type description.

type.expand

Returns expanded type description.

type.size

Returns type size.

type.align

Returns type alignment.

type.pretty

Returns prettyfied type description.

Example:

 py% Type.NSRect 
 Type.NSRect 
 py% print Type.NSRect.expand 
 struct { 
   struct { 
     float x; 
     float y; 
   } origin; 
   struct { 
     float width; 
     float height; 
   } size; 
 } 
 py% Type.NSRect.size 
 16 
 py% Type('union { int x; char *y; float d;}').encoding 
 '("x"i"y"*"d"f)' 
 py% Type('struct mystruct').encoding 
 '{mystruct="anInt"i"aDouble"d"anObject"@"aString"*"anArray"@}' 
 py% print Type('union { int x; char *y; float d;}').pretty 
 union { 
   int x; 
   STR y; 
   float d; 
 } 

Methods

type.malloc([cnt])

Allocates memory for cnt items of the specified type.  A C pointer array datum of length cnt is returned.
If cnt is not specified, memory for one item is allocated, and a regular C pointer datum is returned.

type([cnt])

Similar to malloc, except that the C datum object that is returned "owns" the allocated memory.  That is, when the datum is released by Python, malloced memory will be freed.

C Data

In ObjPy C data is represented by the C datum objects.  Every C datum has two properties: type and address.  There are two C datum subtypes: pointer datum and function datum.

C.name

Returns the datum object which is registered in the global C symbol table with name

C.name=datum

Registers datum into global C symbol table with name.  This is equivalent to defining a global symbol (global variable or function) in C.

C(datum)

Clones the datum

C(type, address)
C(type, 'symbol')
C(type, '0x...')

Creates a datum with the specified type and address.

C(type, datum)

Casts datum into type.

C(method)

Casts method into a function datum.

C(object)

Casts object into a pointer datum.

Example:

 py% C.NSApp.type 
 Type.id 
 py% C.NSApp.val 
 <TTApplication: 0x86098> 
 py% app=C.NSApp.val 
 py% app 
 <TTApplication: 0x86098>

 # cast object into pointer datum 
 py% C(app).type 
 Type("""struct { 
   Class isa; 
   id _nextResponder; 
   NSEvent* _currentEvent; 
   ... 
 }""") 
 py% C(app).addr 
 549016 
 py% C(app).val 
 (Class.TTApplication, nil, <NSEvent: 0x99790>, ...) 

 # cast a method into a function datum 
 py% a=Class.NSArray() 
 py% o=Class.NSObject() 
 py% fun=C(o.description) 
 py% fun.type 
 Type("id description(id self, SEL _cmd)") 
 py% a.description() 
 '()' 
 py% fun(a,'description') 
 '<NSConcreteArray: 0x3c7f8>' 

 # cast a function 
 py% pf=C(Type('void ()(char *format, double d, int i, STR x)'),'printf') 
 py% pf('d=%g, i=%d, x=%s\n', 123.45, 678, 'hi') 
 # (the output appears in the shell/console window) 

Datum Attributes

datum.type

Returns datum's type.

datum.addr

Returns datum's memory address.

datum.encoding

Returns datum's type encoding.

datum.size

Returns datum's size.

Pointer Datum

A pointer datum object represents a value stored in memory.   There are two types of pointer data:

Allocation, deallocation, offset

You create a datum by allocating memory to hold item(s) of a certain type.

ptr.realloc([cnt])

Reallocates pointer datum to hold cnt items of whatever the datum's type is.

ptr.free()

Deallocates memory that the pointer points to.

ptr.offset(idx)

Offsets the datum.

Value access

ptr.fetch([idx])
ptr.val

Fetches (dereferences) the value pointed to by ptr.  Index idx can be used to specify subdatum.

If the datum is a simple 1-item datum, then 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.

If the datum is a pointer array datum, then the index must be an integer in range [0:len(ptr)]

ptr.store(v[, idx])
ptr.val=v

Stores value v into the specified (sub)datum.

Example:

 # Allocate a NSRect, store a value in it, read some values 
 # p is a simple 1-element datum 
 py% p=Type.NSRect.malloc() 
 py% p.val=((1,2),(3,4)) 
 py% p.val 
 ((1.0, 2.0), (3.0, 4.0)) 
 py% p.fetch('origin') 
 (1.0, 2.0) 
 py% p.fetch('size.width') 
 3.0 
 py% p.fetch(['size','height']) 
 4.0 
 py% p.fetch('1.0') 
 3.0

 # Reallocate p to be a pointer array datum of length 2 
 py% p.realloc(2) 
 <CDatum: ^{?="origin"{?="x"f"y"f}"size"{?="width"f"height"f}}@0xd4138[2]> 
 py% p[1]=((5,6),(7,8)) 
 py% p.val 
 (((1.0, 2.0), (3.0, 4.0)), ((5.0, 6.0), (7.0, 8.0))) 

 # Free p 
 py% p.free() 
 <CDatum: ^{?="origin"{?="x"f"y"f}"size"{?="width"f"height"f}}@0x0[2]> 

 # allocate 5 NSPoints; q "owns" the malloced memory 
 py% q=Type('NSPoint[5]')() 
 py% print q.type.expand 
 struct { 
 float x; 
 float y; 
 } [5]

 # Store/fetch index 
 py% q.store(123,'2.x') 
 <CDatum*: ^[5{?="x"f"y"f}]@0xd4138> 
 py% q.val 
 ((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 
 py% q.fetch('&') 
 <CDatum: ^[5{?="x"f"y"f}]@0xd4138> 
 py% q 
 <CDatum*: ^[5{?="x"f"y"f}]@0xd4138> 

 # Get the address of q[2].y:  q2y=&(q[2].y); 
 py% q2y=q.fetch('2.y.&') 
 py% q2y.val=456 
 py% q.val 
 ((0.0, 0.0), (0.0, 0.0), (123.0, 456.0), (0.0, 0.0), (0.0, 0.0)) 

 # This will free memory, since q "owns" it 
 py% del q

 py% app=C.NSApplication.sharedApplication()

 # Fetch all instance variables of an object at once 
 py% C(app).val 
 (Class.TTApplication, nil, <NSEvent: 0x1b6924>, ...) 

 # Get a pointer to an instance variable 
 py% currentEventPtr=C(app).fetch('_currentEvent.&') 
 py% currentEventPtr.type 
 Type("NSEvent*") 
 py% currentEventPtr-C(app) 
 2 

 # Get the value pointed to 
 py% currentEventPtr.val 
 <NSEvent: 0x1b6e44> 
 py% print currentEventPtr.val 
 NSEvent: type=KeyDown loc=(0,0) time=... 

Pointer arithmetic

ptr+i

Returns a pointer datum which is i items offset from ptri must be an integer.

ptr-ptr2

Pointer difference.

Pointer array datum

Pointer array data behaves like a Python sequence.

len(ptr)

Pointer array length.

ptr[idx]

Dereferences (fetches) value at index idx.

ptr[idx]=val

Stores value at index idx.

ptr[i:j]

Returns a pointer datum corresponding to the slice.

ptr[i:j]=ptr2

Copies stuff at ptr2 into the pointer array slice.  This is the bcopy operation.

ptr[i:j]=valseq

Stores values in sequence valseq into corresponding elements of the slice.

del ptr[i:j]

Bzero's element values in the slice.

Example:

 py% p=Type.int(10) 
 py% len(p) 
 10 
 py% p[5]=555 
 py% p[2:3]=(123,) 
 py% p[3:5]=[20,21] 
 py% p.val 
 (0, 0, 123, 20, 21, 555, 0, 0, 0, 0) 
 py% q=p[3:3] 
 py% len(q) 
 0 
 py% q.val 
 20 
 py% p[7:10]=p[2:5] 
 py% p.val 
 (0, 0, 123, 20, 21, 555, 0, 123, 20, 21) 

CGlob

You can use CGlob as a convenience for accessing C global variables.

CGlob.name

Same as: C.name.val

CGlob.name=v

Same as: C.name.val=v

C Function Datum

C function datum is used to invoke a C function.

fun(args...)

Invoke a function with arguments.

Example:

 py% C.cos(1) 
 0.540302305868 
 py% C.NSRunAlertPanel('ObjPy', 'Hello World!', nil, nil, nil) 
 1 

[previous][contents][next]