Table of Contents
OpenMCL provides a fairly rich language for defining and specifying foreign data types (this language is derived from CMUCL's "alien type" system.)
In practice, most foreign type definitions are introduced into OpenMCL via its interface database, though it's also possible to define foreign types interactively and/or programmatically.
OpenMCL's foreign type system is "evolving" (a polite word for not-quite-complete): there are some inconsistencies involving package usage, for instance. Symbols used in foreign type specifiers should be keywords, but this convention isn't always enforced.
Foreign type, record, and field names are case-sensitive; OpenMCL uses some escaping conventions to allow keywords to be used to denote these names.
Some foreign types are builtin: keywords denote primitive, builtin types such as the IEEE-double-float type (denoted :DOUBLE-FLOAT), in much the same way as certain symbols(CONS, FIXNUM, etc.) define primitive CL types.
Constructors such as :SIGNED and :UNSIGNED can be used to denote signed and unsigned integer subtypes (analogous to the CL type specifiers SIGNED-BYTE and UNSIGNED-BYTE.) :SIGNED is shorthand for (:SIGNED 32) and :UNSIGNED is shorthand for (:UNSIGNED 32).
Aliases for other (perhaps more complicated) types can be defined via CCL:DEF-FOREIGN-TYPE (sort of like CL:DEFTYPE or the C typedef facility). The type :CHAR is defined as an alias for (:SIGNED 8) under Darwin, or as (:UNSIGNED 8) under LinuxPPC.
The construct (:STRUCT name) can be used to refer to a named structure type; (:UNION name) can be used to refer to a named union type. It isn't necessary to enumerate a structure or union type's fields in order to refer to the type.
If X is a valid foreign type reference, then (:* X) denotes the foreign type "pointer to X". By convention, (:* T) denotes an anonymous pointer type, vaguely equivalent to "void*" in C.
If a fieldlist is a list of lists, each of whose CAR is a foreign field name (keyword) and whose CADR is a foreign type specifier, then (:STRUCT name ,@fieldlist) is a definition of the structure type name, and (:UNION name ,@fieldlist) is a definition of the union type name. Note that it's necessary to define a structure or union type in order to include that type in a structure, union, or array, but only necessary to "refer to" a strucure or union type in order to define a type alias or a pointer type.
If X is a defined foreign type , then (:array X &rest dims) denotes the foreign type "array of X". Although multiple array dimensions are allowed by the :array constructor, only single-dimensioned arrays are (at all) well-supported in OpenMCL.
ccl:def-foreign-type name foreign-type-spec
If name is non-NIL, defines name to be an alias for the foreign type specified by foreign-type-spec. If foreign-type-spec is a named structure or union type, additionally defines that structure or union type.
If name is NIL, foreign-type-spec must be a named foreign struct or union definition, in which case the foreign structure or union definition is put in effect.
[Note that there are separate namespaces for type names and for struct/union names.]
NIL or a keyword; the keyword may contain escaping constructs.
A foreign type specifier, whose syntax is (loosely) defined above.
ccl:make-record typespec &rest initforms
typespec is interpreted as a foreign type specifier or, if a keyword and not a defined foreign type, as the name of a foreign record (struct or union) type. If an appropriate type or record type can't be found at macroexpand time, an error is signalled; otherwise, the type's size is determined and code is generated to heap-allocate and initialize an instance of that type. If typespec denotes a scalar type, initforms can contain a single value that can be coerced to that type; if typespec denotes a record type, initforms should be a list of 0 or more field names and initial values which can be coerced to the type of the specified field. (There isn't a good way to initialize individual fields of an array type, or to initialize record-typed fields of a record type.)
Record fields that aren't explicitly initialized are set to binary 0.
The value of the ccl:make-record form is a MACPTR which encapulates the address of the allocated memory block.
A foreign type specifier or foreign record name.
As described above
rlet (var typespec &rest initforms)* &body body
Executes body in an environment in which each var is bound to a MACPTR encapuslating the address of a stack-allocated foreign memory block, allocated and initialized from typespec and initforms as per ccl:make-record. Returns whatever value(s) body returns.
Record fields that aren't explicitly initialized have unspecified contents.
A symbol (a lisp variable)
A foreign type specifier or foreign record name.
As described above, for ccl:make-record
rletz (var typespec &rest initforms)* &body body
Executes body in an environment in which each var is bound to a MACPTR encapuslating the address of a stack-allocated foreign memory block, allocated and initialized from typespec and initforms as per ccl:make-record.
Returns whatever value(s) body returns.
Unlike rlet, record fields that aren't explicitly initialized are set to binary 0.
A symbol (a lisp variable)
A foreign type specifier or foreign record name.
As described above, for ccl:make-record
pref ptr accessor-form
References an instance of a foreign type (or a component of a foreign type) accessible via ptr.
accessor-form can be a foreign type or record name, or a keyword symbol composed of a foreign type or record name followed by one or more record field names, separated by dots. Individual components of an accessor form may need to follow escaping conventions if the foreign type or field names contain upper-case characters.
Expands into code which references the indicated scalar type or component, or returns a pointer to a composite type.
PREF can be used with SETF.
RREF is a deprecated alternative to PREF. It accepts a :STORAGE keyword and rather loudly ignores it.
a MACPTR.
See above.