...a Python3 script that generates Python3 (saving, loading, fixing types) and C code (alloc, free, write, read, cmp) for given input data structures.
datastructures.py __ Main Script
example/.. __ Example: ImpulseTracker IT File Format
ittech.desc __ datastructures.py input file for IT format
ITTECH.TXT __ original IT file format documentation
it_file.py __ Sample Python3 script that reads IT files.
it_file.h __ Generated C header for IT file data structures.
it_file.c __ Generated C implementations.
datastructures.py creates C and Python code for given binary data structures
Input file format
=================
The input files are plain text files, that contain line by line instructions.
Comments
--------
If the first non-space character on a line is #, then this line is regarded
to be a comment.
> # This line is a comment
Generating Output
-----------------
The following commands generate output
C FILENAME
C FILENAME.c
C FILENAME.h
These three commands all generate the same output to the files FILENAME.c
and FILENAME.h, where FILENAME.h contains the data structure definitions
and function declarations, and where FILENAME.c contains the implementati-
ons of the declared generated functions.
The files will be updated if they already exists, and previously generated
code parts will be replaced if the files already contain generated code.
PY FILENAME
PY FILENAME.py
These two commands both generate the same output to the file FILENAME.py.
The file will be updated if it already exists, and previously generated code
parts will be replaced if the files already contain generated code.
Please note that it is possible to define any number of output files.
Describing Data Structures
--------------------------
Each data structure is describe in a block that starts with
NAME name_of_the_struct
and that ends with
END name_of_the_struct
Optionally, you may specify the keyword
UNSAFE
in order to signal that the code generated for i/o should not write or check
information about the structures fields.
There are four types of data fields that may be specified, and every data
field may be supplied with a list of additional options.
{TYPE} name_of_field {{OPTIONS}}
Declares a member of the structure with a fixed-size data type.
[SIZE] {TYPE} name_of_field {{OPTIONS}}
Declares a fixed-size-array member of the structure, whose elements have a
fixed-size data type.
ARRAY {TYPE} name_of_field {{OPTIONS}}
Declares a member of the structure that is an array of a fixed-size data type.
Arrays contain information about their length and their contents.
The following fixed size data types are recognized:
CHAR interpreted as char
DOUBLE interpreted as double
FLOAT interpreted as float
INT16 interpreted as int16_t
INT32 interpreted as int32_t
INT64 interpreted as int64_t
INT8 interpreted as int8_t
UINT16 interpreted as uint16_t
UINT32 interpreted as uint32_t
UINT64 interpreted as uint64_t
UINT8 interpreted as uint8_t
STRING name_of_field {{OPTIONS}}
Declares a member of the structure that is a string.
STRUCT type_name name_of_field {{OPTIONS}}
Declares a member of the structure that has the type type_name, which will
be initialized with all zeros, and will be regarded as if it would be a poin-
ter to another data structure generated by this tool.
There are a number of options available, which can go in any order after the
field's name.
CI/O
Signals that a string field is stored as a (very unsafe) C style string, i.e.
it is stored without its size first, but instead zero-terminated. The maximum
length of such a string in the C implementation is governed by MAX_CIO_SIZE.
CSAFE
Signals that the fixed-size array terminates in a zero. This is implemented
by forcing the last array item to be zero regardless whether there are other
array items that are zero before. Only applies to [SIZE] ... fields.
NOALLOC
Signals that the field shall not be allocated when the structure is alloced,
instead, the field will be zero'd. Only applies to ARRAY and STRING. STRUCTS
are always zero'd and never initialized by generated code and to the function
name_of_the_structure_alloc().
NOCMP
Signals that the field is not to be used for the the generated comparison
functions.
NOFREE
Signals that the fields contents shall not be freed, only applies to STRUCT,
ARRAY and STRING type fields.
NOI/O
Signals that the field shall not be saved or restored by the generated file
i/o routines.
C Output
--------
The following C code will be generated:
Types
.....
typedef struct t_name_of_the_struct {
...
} s_name_of_the_struct;
typedef s_name_of_the_struct *name_of_the_struct;
Memory Management
.................
name_of_the_struct name_of_the_struct_alloc(...);
Creates a new struct on the heap and fills it with zeros. For each array
member, there is a parameter specifying the desired number of elements.
void name_of_the_struct_free(name_of_the_struct x);
Frees a struct from the heap, also frees the allocated arrays that belong
to the struct.
File I/O
........
name_of_the_struct name_of_the_struct_alloc_from_file(FILE *f);
Creates a new struct on the heap from the contents of the file f, checks
whether the file indeed contains a compatible structure unless UNSAFE was
specified. If the file is incompatible, this routine returns zero.
void name_of_the_struct_write_to_file(name_of_the_struct x, FILE *f);
Writes the contents of the structure x to the file f. Unless UNSAFE is spe-
cified, includes information about the structure's fields first.
Convenience
...........
int name_of_the_struct_cmp(name_of_the_struct l, name_of_the_struct r);
Compares l and r, returns -1 if l is smaller, 1 if r is smaller, and 0 if
l and r are equal.
Python Output
-------------
The following Python code will be generated:
def name_of_the_struct_alloc():
...
Creates a new dictionary object and initializes the member fields according
to the structure definition with default values.
def name_of_the_struct_fix(x):
...
Fixes the contents of a dictionary x to meet the type requirements for the
data structure.
def name_of_the_struct_read(f):
...
Creates a new dictionary object and fills its member fields with the contents
of the file object f.
Usage:
> with open("structure.dat","rb") as f:
> x = name_of_the_struct_read(f)
def name_of_the_struct_write(x, f):
...
Writes the structure from the dictionary x to the file object f.