These calls calls can be encapsulated as methods for handling the structure as a "data type" in the Khoros system via a generated define call. Once defined, a type identifier for the structure will be initialized. This type identifier, analagous to the Khoros type identifiers for KINT, KFLOAT, or other data type, is used to identify a variable's data type to various Khoros programs. In particular, once defined, variables of the new structure type can be read and written using the kwrite_generic and kread_generic calls. These calls provide the machine conversion capability necessary to write data in the native format for one architecture and convert the data while it is being read into the native format for a different architecture.
The read and write calls are themselves generated using the Khoros transport calls. Component pieces of the structure are read and written using the kread_generic and kwrite_generic calls. These calls will read and write a structure in pieces, breaking it down field by field.
Pointers are traversed on reading and writing using the kwrite_pointer and kread_pointer calls. The write call manages the addresses of what is being pointed at, ensuring that items being pointed at are not written more than once. The read call then manages the addresses of what is being read, reconnecting pointers to restore the structure as it existed before being written. This capability allows for the storage and retrieval of very complicated structures with cyclic and redundant pointer dependencies.
The specification files, by convention, end with a .x extension. The specifications are syntactically nearly identical to C, with multiple structures allowed per file. The specification files are preprocessed through cpp, so cpp directives such as #include, #ifdef, and #define can be used in the specification file.
Two files are generated from the specification, a header file and a C code file. The naming convention for these files is to prepend io_ to the name of the specification file. Thus, for a specification foobar.x, the files io_foobar.c and io_foobar.h will be generated.
The program takes a toolbox and object name argument. If these are not provided, then the toolbox and object names will be extracted from the local Imakefile. If the specification file is part of a library object, the generated C code file will be generated in that library's source directory , and the generated header file will be added to the library's public include directory. If the specification file is part of any other type of software object, the generated C code and header files will be generated in the software object's source directory. Note that kgenstruct can be used on .x files outside of the context of the Khoros system, in which case the generated C code and header is generated in the local directory.
This program is a ported and heavily modified version of rpcgen. As such, it is capable of parsing nearly all of RPCL, a protocol description language which is an extension of the XDR definition language. In addition to allowing structure specifications, typdefs, enumarations, and constants can also be specified. There can be multiple specifications within a single specification file. C-style comments within the specification are ignored. Lines beginning with "!" are passed through to the header file, without the "!".
Within a structure, there are four types of declarations allowed : simple, fixed arrays, variable arrays, and pointers. These are all identical to C, with the exception of variable arrays. Variable arrays are specified using a "<>" construct. From this, a structure in the header containing a length and variable array pointer is generated.
The following example illustrates a structure specification using several different declarations :
struct foobar {
char id;
int a; /* simple */
float b[10]; /* fixed array */
float c<> /* variable array */
float *d; /* pointer */
kstring name; /* use kstring for strings */
struct foobar *next; /* these can be structures too */
}
The following is generated from that specification in the header file :
extern int KTYPE_FOOBAR;
int kdefine_foobar PROTO((void));
struct foobar {
char id;
int a;
float b[10];
struct {
unsigned int c_len;
float *c_val;
} c;
float *d;
kstring name;
struct foobar *next;
};
As this illustrates, with the exception of variable length arrays, the generated header will be identical to the specification. The structure type identifier that is created is "KTYPE_FOOBAR", the corresponding kdefine_foobar() call is used to initialize that type identifier.
Note that it is important that the defined structure being written is identical to the defined structure being read, otherwise the structure reading will not succeed. To assist in managing various versions of a structure, the ability to specify a version number for a structure has been added. The version number should be specified in the .x file, immediately after the identifier. The following example illustrates this :
struct point version 2.0 {
float x;
float y;
float z;
};
The version is optional. If not specified, the structure will not be versioned. Note that structures stored with a particular version number will only be readable by code defined with the identical version number. Unversioned structures will not match stored versioned structures.
Mutually Inclusive Group; if desired, specify ALL of:
AND