-
Notifications
You must be signed in to change notification settings - Fork 0
User_Manual:_Code:_io.c
(Return to Code or the User Manual)
io.c contains some simple I/O utilities -- save and restoral of a FLUX arena from an ASCII file, and some miscellany for dumping trees and/or rendering simple drawings to debug the geometry code. The basic I/O interface is also used for generation of new simulation arenas: the simplest way to create a new FLUX interface is to generate a string in the FLUX ASCII data format, and then parse it with the file I/O routines. On the Perl interface side, that is accomplished by the Perl routine str2world.
The ASCII data format is a custom keyword-based format that is intended to be simple to emit and parse. It succeeds in the former, but not necessarily in the latter.
FLUX's ASCII format is supported through two routines in io.c, read_world
and fprint_world
. You can take individual action on a World by feeding lines into the single line parser, footpoint_action
.
int fprint_world(FILE *file, WORLD *world, char *header)
Writes the given WORLD object to the file handle file
, which must be open for writing. If you supply a non-NULL string in header
then it is written to the file before the world
is dumped there.
There is no particularly meaningful return value.
int print_world(WORLD *a, char *header)
Convenience interface to fprint_world
, sends the file to the POSIX standard output.
WORLD *read_world(FILE *file, WORLD *a)
Reads in a complete world from the specified FILE (this is a standard i/o library file handle, which should already be open for reading). If a
is NULL, then a new WORLD object is created. If you feed in an existing WORLD object, then it is updated using the information in the file.
This is the main way to create new WORLDs, and in fact the Perl str2world constructor simply writes its string to a temporary file and calls read_world
on it.
Recent versions of read_world call world_check on the newly created WORLD object before returning it.
char *next_line(FILE *file)
Line snarfer and preparser used by read_world
: strips comments, skips all-comment, all-whitespace, or blank lines.
int footpoint_action(WORLD *world, char *s)
Parses a line from a FLUX dump file and performs the appropriate action on the supplied WORLD. Returns 0 on success, or a cryptic error code on failure. The parser is hand-coded and primitive: it simply checks the first few characters of each word on the line and uses sscanf
to pick out appropriate parameters based on the line.
The main complication comes from the fact that the numeric type (NUM) can be set in the headers to be either double or float (to save memory); this means that the format codes for sscanf
must themselves be generated on-the-fly.
Most errors are thrown by setting "badstr" to contain an error message, which causes the error message to be printed to stderr and the routine to return 2.
Here are some miscellaneous printing routines that come in handy for debugging, but aren't normally used.
void fprint_tree(FILE *file, void *tree, int label_offset, int link_offset, int indent, void ((*printer)()))
This is a tree-walking function that prints all nodes of a tree -- rather like the tree_walker
routine in data.c
. The printer should accept 5 arguments, and be declared like so:
printer(FILE *f, void *object, int indent, int label_offset, int link_offset)
The printer should interpret the object, ASCIIfy it, and print it to the open file handle f
. The indent
is a count of space characters to be printed at the beginning of the line.
void print_tree(void *tree, int label_offset, int link_offset, int indent, void ((*printer)()))
Convenience interface to fprint_tree
, for printing to stdout.
This is a generic printer function for fprint_tree
- it just prints label information for each node in a generic tree.
void fdump_fluxon(FILE *f, FLUXON *foo, int indent)
This is a printer function for fprint_tree
, that prints a whole fluxon and all its vertices. You can also call it with an individual fluxon. (Note that this function omits the later parameters of the printer, and therefore only works on architectures that comply with POSIX, placing the function arguments in order on the stack.)
void fdump_all_fluxon_tree(FILE *f, FLUXON *foo)
Prints out the whole fluxon tree from a world -- you pass in the top fluxon in the tree.
FLUX can emit and restore binary data in machine format, for rapid serialization / restoration of simulation arenas. This code can support a general purpose tag-based binary data format, but currently contains just enough code to support first-stage parallelization.
The binary dump code is intended for fast dump/restore, without (necessarily) being portable across architectures or (in teh case of fluxon_pipe
) even across unrelated processes within a particular machine.
Binary dumps are in a containerized format that includes a series of tagged fields. The content and length of each field are arbitrary. Each field begins with three long integers: a fence (value 0xAB5C155A
), a type code, and a length of the data segment (in bytes). The data segment should be followed immediately by the next field fence. A special field, BD_END
, is used to end the file.
The type codes are defined in io.h, as BD_
mnemonic. The mnemonics should be consecutive integers starting with 1. The macro MD_MAX_TYPENO
should contain the highest allowed type code.
Just open a file descriptor using the open
system call, and start dumping fields to it using these routines. When you are done, call binary_dump_end
and close the descriptor. That is all!
binary_dump_end(int fd)
Writes an end-of-file field. It is your responsibility to close the file descriptor.
binary_dump_fluxon_pipe(int fd, FLUXON *f)
Writes out all the VERTEX information in a particular fluxon, in a suitable format for first-stage parallelization: the information contains actual pointer values, so it is only useful for a related pid (e.g. parent from a fork
call), and even then only if the source process hasn't allocated any new data structures since the fork (and the parent process hasn't deleted any since then).
You can read binary state from a binary dump file by calling binary_read_dumpfile
. It will parse the file and dispatch each field to the appropriate read routine. Individual read routines are not listed here as they match the dump
routines above.
binary_read_dumpfile(int fd, WORLD *w)
Like ASCII .flux
files, binary dump files modify the state of an existing WORLD structure, so you have to pass in not just an open file descriptor (as returned by the open
system call) but also an allocated WORLD structure.
New binary I/O routines should include a dump
routine, a read
routine, a new type code (in io.h
), and a new case:
in binary_read_dumpfile
.
It would be useful to write enough component dumpers to store a complete WORLD object, but that has not (yet) been done. Such a format would require some thought about backwards compatibility in case of code updates.