Each major Lens object, the Network, Group, Unit, Block, ExampleSet, Example, and Event, has an extension record defined in extension.h. Most additions to the Lens object structures should be made to the extension record and any code that uses those extensions should be placed in extension.c so that future updates to the other Lens modules can be incorporated painlessly.
The default extension structures look something like this:
typedef struct netExt { char removeMe; } *NetExt;
The field removeMe is just a dummy there to prevent warnings in some compilers. If any fields are added, the dummy should be removed.
Once you plan to make use of an extension structure, you will need to fill in the initialization structure for that extension. When an instance of the main object is created, it will be passed to this function so that the extension can be added. The default initialization functions look something like this:
flag initNetworkExtension(Network N) { FREE(N->ext); return TCL_OK; }
This just takes a network and sets the extension field to NULL (freeing it if it exists). Once some fields are added to the extension, you will want to change it to something like this:
flag initNetworkExtension(Network N) { N->ext = safeCalloc(1, sizeof(struct netExt), "initNetworkExtension:N->ext"); return TCL_OK; }
Remember to use safeMalloc()
or safeCalloc()
,
rather than malloc()
or calloc()
. You can
then initialize extension fields as necessary.
Lens uses a rather complex mechanism for making the C object hierachy
accessible from within the Tcl shell. Each container structure and
primitive data type, such as an int
, will have an ObjInfo
structure defined for it. This describes each field or member of the
object using MemInfo structures. MemInfo structures contain information
such as the name of the field, where it is located in the object, and
whether it is write-protected. ObjInfo and MemInfo are defined in
object.c.
To build an ObjInfo description, a pointer to one is first declared globally, then allocated with newObject(), and then members are added to it with addMember(). When adding to object extensions, global ObjInfo structures will have already been created for you. These are defined in extension.c and are as follows:
ObjInfo RootInfo; ObjInfo NetInfo; ObjInfo GroupInfo; ObjInfo GroupProcInfo; ObjInfo UnitInfo; ObjInfo BlockInfo; ObjInfo LinkInfo; ObjInfo ExampleSetInfo; ObjInfo ExampleInfo; ObjInfo EventInfo; ObjInfo RangeInfo; ObjInfo IntInfo; /* int */ ObjInfo RealInfo; /* real */ ObjInfo FlagInfo; /* flag */ ObjInfo MaskInfo; /* mask */ ObjInfo StringInfo; /* char * */ ObjInfo TclObjInfo; /* TclObj */
Member fields should be added within the functions that have names such
as initNetExtInfo()
and initExSetExtInfo()
.
Here is a sample ObjInfo init function:
int getNetExtRows(void *NX) { return ((NetExt) NX)->rows; } int getNetExtCols(void *NX) { return ((NetExt) NX)->cols; } void initNetExtInfo(void) { NetExt NX; addObj (NetExtInfo, "name", OFFSET(NX, name), TRUE, StringInfo); addObjP (NetExtInfo, "theGroup", OFFSET(NX, theGroup), FALSE, GroupInfo); addSpacer(NetExtInfo); addObj (NetExtInfo, "rows", OFFSET(NX, rows), FALSE, IntInfo); addObj (NetExtInfo, "cols", OFFSET(NX, cols), FALSE, IntInfo); addObjPA (NetExtInfo, "array", OFFSET(NX, array), FALSE, getNetExtRows, UnitInfo); addObjAA (NetExtInfo, "array2", OFFSET(NX, array2), TRUE, getNetExtRows, getNetExtCols, RealInfo); }
The function must begin by declaring a pointer to the type of extension
you are describing, in this case "NetExt NX;
". The rest of
the function will be made up of calls to field-defining functions. The
field-defining functions are as follows:
void addObj(ObjInfo O, char *name, int offset,
flag writable, ObjInfo info)
void addObjP(ObjInfo O, char *name, int offset,
flag writable, ObjInfo info)
void addObjA(ObjInfo O, char *name, int offset,
flag writable, int (*rows)(void *), ObjInfo info)
void addObjPA(ObjInfo O, char *name, int offset,
flag writable, int (*rows)(void *), ObjInfo info)
void addObjAA(ObjInfo O, char *name, int offset,
flag writable, int (*rows)(void *), int (*cols)(void *),
ObjInfo info)
void addObjPAA(ObjInfo O, char *name, int offset,
flag writable, int (*rows)(void *), int (*cols)(void *), ObjInfo
info)
void addSpacer(ObjInfo O)
ObjInfo O
char *name
int offset
flag writable
int (*rows)(void *)
int (*cols)(void *)
ObjInfo info
In the initNetExtInfo()
example above, the first member is
a writable string called name. The second is a pointer to a
group. The third and fourth are write-protected integers. The fifth is
an array of unit pointers with dimension rows. The last field is
a two-dimensional array of writable real numbers.