1 /*
2  * $Id: binio.h,v 1.6 2010-07-03 19:42:31 dhmunro Exp $
3  * Declare structures and functions for arrays of data that have
4  * meaningful interpretations on disk.
5  *
6  * Yorick supports the following data types:
7  *
8  *     char   short   int   long   float   double
9  *     string   pointer   complex   struct(instance)
10  */
11 /* Copyright (c) 2005, The Regents of the University of California.
12  * All rights reserved.
13  * This file is part of yorick (http://yorick.sourceforge.net).
14  * Read the accompanying LICENSE file for details.
15  */
16 
17 #ifndef BINIO_H
18 #define BINIO_H
19 
20 #include "hash.h"
21 
22 /*--------------------------------------------------------------------------*/
23 
24 /* IOStream is a complicated data structure which completely represents
25    a binary I/O stream.  The data in the file(s) can be decribed using
26    the Contents Log (CLOG) language.  Major components of the IOStream
27    are:
28       1. A table of data primitive and compound data types (structTable).
29       2. A table of variables (dataTable), which associate a variable
30          name with its data type, dimensions, and disk address.
31       3. An optional block of history information, detailing the
32          disk addresses (and files, if this is a family of files) of
33          the history records, if there are any.
34       4. An optional list of pointees, associating memory and disk
35          addresses of indirectly referenced data (not explicitly
36          in the dataTable).
37       5. An optional file containing the (plain text) CLOG description
38          of this file.
39       6. The list of cache blocks associated with this file, and the
40          last address read or written (since ftell doesn't know about
41          the cache buffers).
42  */
43 typedef struct IOStream IOStream;
44 
45 /* StructDef is the definition of a data structure, explicating the
46    meaning of data either on disk or in memory, and its relationship to
47    other data types.  All structure definitions representing disk data
48    are "owned" by the IOStream associated with the disk file.  Each
49    disk structure has a "model" data structure representing the
50    memory version of the same data.  A conversion procedure converts
51    from a representation to its model or vice versa -- a feature
52    designed to handle disk data written in a non-native format.
53    (A structure representing data in memory may also have a "model"
54    and a corresponding conversion routine to handle automatic memory-to-
55    memory type conversions.)
56    A StructDef may represent either a primitive data type, or a compound
57    data type consisting of dimensioned members of simpler data types.
58    All data structures have an ASCII name, which is used to make
59    default correspondences between in-memory and on-disk structures.  */
60 typedef struct StructDef StructDef;
61 
62 /* Array is a block of data with a specific data type (specified by
63    a StructDef) and dimensions.  All objects of type pointer must be
64    either 0, or point to the first address of an Array value.
65    An Array represents scalar data if its dimension list is nil.  */
66 typedef struct Array Array;
67 
68 /* Dimension is an element of a linked list of dimensions.  A Dimension
69    list is always from slowest to fastest varying dimension.  Each
70    dimension has an origin (suggested minimum index value) and length.  */
71 typedef struct Dimension Dimension;
72 struct Dimension {
73   Dimension *next;   /* list goes from slowest to fastest varying */
74   long number;       /* length of this dimension */
75   long origin;       /* index of first element along this dimension */
76   int references;    /* reference counter */
77 };
78 
79 /* Member is a data type and dimension list.  The dataTable of an IOStream,
80    the member list of a StructDef, and an Array all consist in part of
81    one or more Member instances.  */
82 typedef struct Member Member;
83 struct Member { /* most general type of x:  base_type x[][]...[][]; */
84   StructDef *base;   /* array base data type */
85   Dimension *dims;   /* array dimension list (may be nil) */
86   long number;       /* of items in array (product of dimensions) */
87 };
88 
89 /* Strider is an element of a linked list of strides through data.  Each
90    Strider consists of a stride (in bytes), a number of "footprints",
91    and an optional Array of type long containing an index list.  */
92 typedef struct Strider Strider;
93 struct Strider {
94   Strider *next;        /* logically next faster varying block */
95   long stride;          /* stride length in bytes */
96   long number;          /* number of strides to take + 1 (# footprints!) */
97   Array *indexList;     /* if !=0, offset list (units of 'stride' bytes) */
98 };
99 
100 /* Operations is a virtual function table for a DataBlock, the
101    container class for Array, StructDef, and IOStream (and others).  */
102 typedef struct Operations Operations;
103 /* The Operations* members depend on the details of Yorick, and are
104    therefore split out to allow this binary file package to be used
105    in non-Yorick based codes.  These three values are explicitly
106    needed:  */
107 PLUG_API Operations *yOpsStruct, *yOpsStream, *yOpsStructDef;
108 
109 /* DataLayout is a complete description of a primitive data type,
110    including byte size, alignment, byte order, and floating point layout
111    (if the type represents a real number).  */
112 typedef struct DataLayout DataLayout;
113 
114 /* FPLayout is a description of the format of a floating point number,
115    detailing the bit addresses and number of bits in the exponent and
116    mantissa.  The StructDefs of an IOStream corresponding to the float
117    and double primitive types must be describable by an FPLayout.  */
118 typedef struct FPLayout FPLayout;
119 
120 /* IOOperations is an additional virtual function table for an IOStream.  */
121 typedef struct IOOperations IOOperations;
122 
123 /* HistoryInfo keeps history record information for an IOStream.  */
124 typedef struct HistoryInfo HistoryInfo;
125 
126 /* PointeeList keeps an association of disk and memory addresses for an
127    IOStream.  This allows multiply referenced pointers to be written
128    only once.  More subtlely, with a PointeeList, the algorithm to
129    write an arbitrarily complex tree of pointers requires a bounded
130    amount of stack space.  */
131 typedef struct PointeeList PointeeList;
132 typedef struct MDinfo MDinfo;  /* for PointeeList */
133 struct PointeeList {
134   int writing;         /* 0 if table keyed to disk address,
135                           1 if keyed to memory address */
136   long nValid;         /* number of valid objects (i.e.- where both
137                           disk data address and m pointer contain
138                           valid data) */
139   HashXTable table;    /* generic hash table for address correspondence */
140   MDinfo *mdInfo;      /* memory-disk correspondence list */
141 };
142 
143 /* CLbuffer describes the state of the binary data description language
144    file associated with an IOStream.  Defined in clog.c.  */
145 typedef struct CLbuffer CLbuffer;
146 
147 /* CacheBlock is required by IOStream, but is opaque here.  See cache.c.  */
148 typedef struct CacheBlock CacheBlock;
149 
150 /*--------------------------------------------------------------------------*/
151 
152 struct IOStream {
153   int references;      /* reference counter */
154   Operations *ops;     /* virtual function table */
155   void *stream;        /* usually the FILE*, but opaque here --
156                           0 indicates file has been closed */
157   char *fullname;      /* filename after YExpandName */
158   int permissions;     /* +1 read permission, +2 write permission
159                           +4 append mode, +8 binary mode,
160                           +16 not seekable, +32 pipe, +64 clog mode
161                        */
162 
163   IOOperations *ioOps; /* virtual functions to read and write file */
164 
165   long blockSize;         /* MUST be a power of 2 minus 1 (default 0x3fff)
166                              all cache blocks will be multiples of
167                              blockSize+1 bytes */
168   CacheBlock *blockList;  /* list of cache blocks for this file,
169                              stored highest to lowest address */
170   long seqAddress;        /* address immediately after last address
171                              actually read or written using YcRead or
172                              YcWrite -- different from ftell(stream)
173                              because of caching */
174 
175   int structAlign;        /* byte offset of any struct in another struct
176                              must be multiple of this (the alignment of
177                              some structs may be more strict than this) */
178   int dataAlign;          /* 0  -- align variables to addresses as if
179                                    the file were a giant struct instance
180                              >0 -- byte offset of any variable in file
181                                    must be a multiple of this
182                              WARNING WARNING WARNING WARNING WARNING
183                              This MUST be 0 in order to correctly write
184                              a PDB file with history records.  */
185 
186   HashTable structTable;  /* table of StructDef names for this file */
187   StructDef **structList; /* corresponding to structTable->names */
188 
189   HashTable dataTable;    /* table of variable names for this file */
190   Member *types;          /* corresponding types and dimensions */
191   long *addresses;        /* corresponding addresses */
192   long nextAddress;       /* next free address (may be end of pointee) */
193   long offset;            /* to be applied to all addresses */
194 
195   HistoryInfo *history;   /* non-0 if there is a history record structure
196                              -- If so, then no changes to the dataTable
197                              (which represents static variables) are
198                              permitted.
199                              Note that this IOStream may be either
200                              history->parent or history->child.  */
201 
202   CLbuffer *contentsLog;  /* if non-0, contains "CLOG" textual equivalent
203                              of structTable, dataTable, and history */
204 
205   PointeeList pointeeList;  /* list of memory<->disk address correspondence
206                                to aid in pointee reads or writes */
207   void (*CloseHook)(IOStream *file);  /* if non-0, called before close */
208 };
209 
210 /* check to see if this is in-memory file created by vopen
211  * return value is the Array* or 0, stream is p_file*
212  */
213 PLUG_API void *y_vopen_file(void *stream);
214 
215 /*--------------------------------------------------------------------------*/
216 
217 /* A Copier copies data of type base from t to s.  If t==s, the Copier
218    must appropriately zero s, releasing pointees if appropriate.  If
219    t==s, non-pointered data should be left unchanged (the Copier is a
220    no-op).  There are only 4 possible Copiers-- CopyX should be used
221    for StructDefs which contain no pointers, CopyS for StructDefs
222    whose members include pointers or strings.  CopyQ is for stringStruct
223    and CopyP is for pointerStruct.  */
224 typedef void Copier(StructDef *base, void *dst, const void *src, long n);
225 PLUG_API Copier CopyX, CopyQ, CopyP, CopyS;
226 
227 /* A Converter converts n objects to or from type base, which will often
228    be a foreign disk file data type.  The conversion is from baseData to
229    modelData if toBase is 0, from modelData to baseData if toBase
230    is non-0.  */
231 typedef void Converter(StructDef *base, void *baseData, void *modelData,
232                        long n, int toBase);
233 PLUG_API Converter ConvertI, ConvertF, ConvertQ, ConvertP, ConvertS;
234 
235 struct StructDef {
236   int references;     /* reference counter */
237   Operations *ops;    /* virtual function table */
238   Operations *dataOps;  /* virtual functions for an instance */
239 
240   long size;            /* size of an instance of this data structure */
241   int alignment;        /* byte address must be multiple of this */
242 
243   HashTable table;      /* rapid name->index and index->name associations */
244   Member *members;      /* members[table->maxEntries] is Member array */
245   long *offsets;        /* byte offsets corresponding to members */
246 
247   Copier *Copy;         /* copy/initialize/delete operation */
248 
249   IOStream *file;       /* non-zero if the data resides on disk
250                            if file!=0, then model!=0 */
251   long index;           /* if file!=0, index in file->structList,
252                            else        index in yStructList */
253 
254   int addressType;      /* 0 -> object is in memory (file==0), and address
255                                 is void*
256                            1 -> object is on disk (file!=0) and address
257                                 is long
258                            2 -> address cannot be meaningfully incremented
259                                 to find members or array elements  */
260 
261   /* The remaining elements are to implement "transparent translation"
262      of this data type into another -- usually to change from disk
263      format to memory format.  */
264   StructDef *model;     /* memory equivalent of disk StructDef
265                            is NEVER 0 when file!=0,
266                            also destination or source type for Convert */
267   Converter *Convert;
268          /* Convert may be 0 if no conversion is required.
269             The order and fpLayout members can be used as a context
270             by Convert.  In particular, fpLayout need not actually point
271             to an FPLayout, as long as the first member of the struct
272             it does point to is a reference counter.  */
273   int order;           /* 1 MSB first, -1 LSB first,
274                           -w for LSW first, MSB first within word size w
275                           w for MSW first, LSB first within word size w */
276   FPLayout *fpLayout;  /* if non-0, used by Export/Import to translate
277                           data format */
278 };
279 
280 /* Nine in-memory data structures are predefined, corresponding with
281    the primitive data types in the C programming language:  */
282 PLUG_API StructDef charStruct;
283 PLUG_API StructDef shortStruct;
284 PLUG_API StructDef intStruct;
285 PLUG_API StructDef longStruct;
286 PLUG_API StructDef floatStruct;
287 PLUG_API StructDef doubleStruct;
288 PLUG_API StructDef stringStruct;   /* char *    always 0-terminated */
289 PLUG_API StructDef pointerStruct;  /* void *    all pointers generic */
290 PLUG_API StructDef complexStruct;  /* struct complex { double re, im; } */
291 /* The indirect types string and pointer are for restricted use only,
292    in the sense that special memory management routines must be used
293    to allocate and free the associated memory.
294    An IOStream structTable always begins with the on-disk analogues
295    of char, short, int, long, float, double, string, and pointer.  */
296 
297 /*--------------------------------------------------------------------------*/
298 
299 /* Every on-disk StructDef in the structList for an IOStream has a
300    counterpart "model" StructDef representing the same data translated
301    into memory format.  As for IOStreams, the first 8 StructDefs in
302    yStructList are always, in order, char, short, int, long, float,
303    double, string, pointer.  The 9th in yStructList is complex.  */
304 
305 PLUG_API HashTable yStructTable;  /* table of StructDef names for memory */
306 PLUG_API StructDef **yStructList; /* corresponding to yStructTable->names */
307 
308 /*--------------------------------------------------------------------------*/
309 
310 /* possibly should do this at configuration time... */
311 #if defined(__i386__) || defined(_WIN32)
312 # define PAD_ARRAY
313 #endif
314 
315 struct Array {
316   int references;   /* reference counter */
317   Operations *ops;  /* virtual function table */
318   Member type;      /* full data type, i.e.-    base_type x[]...[] */
319 #ifdef PAD_ARRAY
320   /* on a pentium, 4-byte aligned doubles are legal, but access is
321    * far slower than to 8-byte aligned doubles
322    * since a Member is 12 bytes long, need to add 4 more here
323    * -- no other platform at this time needs this hack */
324   int pad;
325 #endif
326   union {
327     /* Appropriate member is selected by ops; there are only 10 possible ops,
328        corresponding to char, short, int, long, float, double, complex,
329        string, pointer, and struct instance.
330        Actual array length is determined by type. */
331     char c[1];
332     short s[1];
333     int i[1];
334     long l[1];
335     float f[1];
336     double d[2]; /* also complex */
337     char *q[1];  /* string */
338     void *p[1];
339   } value;
340 };
341 
342 /*--------------------------------------------------------------------------*/
343 
344 /* Each StructDef has an alignment, computed as the alignment of its
345    most restrictively aligned member.  Some compilers/machines impose
346    an additional restriction on all structs, regardless of the most
347    restrictive member, in which case yStructAlign is set to that
348    additional struct alignment restriction.
349 
350    IBM has a crazy special rule for PowerPC architecture, where
351    if the first member of a struct is a double, the struct alignment
352    is 8 instead of 4 (which is otherwise the most restrictive alignment).
353    However, IBM's own C compiler misapplies this rule so that only
354    the size of the struct is padded up to a multiple of 8 while its
355    alignment remains 4.  This is yStructAlign=-1.
356    On PowerPCs, gcc attempts to follow IBMs written rule, and they
357    interpret a struct whose first member is an array of double to
358    *not* get the extra alignment.  This is yStructAlign=-2.
359    See play/any/numfmt.c for more details.
360 
361    It is also possible for a C compiler to require different alignment
362    for an array than for a scalar.  Yorick cannot handle this.
363    Finally, the (hopefully defunct?) hybrid C compiler under the
364    (definitely defunct) NLTSS Cray operating system aligned a scalar
365    char to an address with remainder 7 modulo 8, which is hopeless.  */
366 PLUG_API int yStructAlign;
367 
368 struct DataLayout {
369   int alignment;
370   long size;
371   int order;
372   FPLayout *fpLayout;
373 };
374 
375 /* Foreign formats for floating point data can be handled, provided they
376    fit within the parametrization of the FPLayout struct.
377    Foreign integer formats are described by a simple int (the order
378    member of a StructDef above).  */
379 struct FPLayout {
380   /* Addresses are in bits with 0 128-bit of the most significant byte
381      of the object, 8 the 128-bit of the 2nd most significant byte,
382      and so on until 8*size-1 is the 1-bit of the least significant
383      byte.  The actual storage order of the bytes is given by the
384      order member of the DataLayout.
385      sgnAddr            - bit address of overall sign
386      expAddr, expSize   - bit address and size of exponent
387      manAddr, manSize   - bit address and size of mantissa
388      manNorm            - if non-zero, address of leading 1 in mantissa
389      expBias            - exponent bias
390    */
391   int references;      /* reference counter */
392   int sgnAddr, expAddr, expSize, manAddr, manSize, manNorm;
393   long expBias;
394 };
395 
396 /* Floating point layouts for floats and doubles on this machine */
397 PLUG_API FPLayout *fltLayout, *dblLayout;
398 
399 /*--------------------------------------------------------------------------*/
400 
401 struct IOOperations {
402   /* An IOStream requires the virtual functions Read, Write, Tell,
403      Seek, and SeekEnd, which are similar to the C standard library
404      routines fread, fwrite, ftell, fseek(,,SEEK_SET), and fseek(,,SEEK_END).
405      All 5 routines must be provided, but they may simply call YError if
406      the operation makes no sense.  The Read function should return the
407      number (of objects of size size) actually read if EOF occured before
408      the read was complete; n on success.
409      In all cases, YError should be called if an error is detected,
410      AFTER the error is cleared, on the presumption that the next
411      operation will be valid.  */
412   long (*Read)(IOStream *file, void *buf, long size, long n);
413   void (*Write)(IOStream *file, const void *buf, long size, long n);
414   long (*Tell)(IOStream *file, long offset);
415   void (*Seek)(IOStream *file, long offset);
416   void (*SeekEnd)(IOStream *file, long offset);
417   void (*Close)(IOStream *file);
418 };
419 
420 struct HistoryInfo {
421   IOStream *parent;  /* original file always used for static data */
422   IOStream *child;   /* separate IOStream used for history record traffic
423                         so that child->members[i].base->file has a place
424                         to point which may represent a different file in
425                         a history family starting from the original parent */
426 
427   int nFamily;       /* number of files in this family */
428   char **famNames;   /* used for child->fullname,
429                         famNames[0]==parent->fullname
430                         allocated length is 4*(1 + (nFamily-1)/4) */
431   int fileNumber;    /* 0 to nFamily-1, specifies index of current child */
432   long fileSize;     /* approximate maximum size for a file in family */
433 #define DEFAULT_FILE_SIZE 0x800000
434   int copyParent;    /* non-0 if parent (static variables) is to be copied
435                         when a new file is added to this family */
436 
437   long recordSize;   /* length of one record in bytes (not including
438                         any strings, pointees, or other indirections) */
439   int recordAlign;   /* alignment for records -- either child->dataAlign,
440                         or most restrictive alignment in child->structList
441                         when 1st record was declared
442                         Unlike a StructDef, recordSize is not necessarily
443                         a multiple of recordAlign.  */
444   long nRecords;     /* number of history records of this type */
445   long recNumber;    /* index into ifile and offset
446                         for record represented by child (-1 if none) */
447 
448   /* allocated length of following arrays is 16*(1 + (nRecs-1)/16) */
449   int *ifile;        /* list of indices into famNames */
450   long *offset;      /* list of record byte addresses */
451   double *time;      /* 0 or list of floating point values of records */
452   long *ncyc;        /* 0 or list of integer values of records */
453 };
454 
455 struct MDinfo {
456   void *m;       /* memory address, always an Array->value.c; the
457                     MDinfo owns a reference of the Array */
458   long d;        /* disk address of the pointee header */
459   long data;     /* disk address of the pointee data */
460   StructDef *base;  /* disk StructDef for this data -- this pointer does
461                        NOT own a reference to base */
462 };
463 
464 /*--------------------------------------------------------------------------*/
465 
466 /* fullname is NOT copied and FreeIOStream will do p_free(ios->fullname) */
467 PLUG_API IOStream *NewIOStream(char *fullname, void *stream, int permissions);
468 PLUG_API void FreeIOStream(void *ios);      /* *** Use Unref(ios) *** */
469 
470 PLUG_API StructDef *NewStructDef(IOStream *file, long index);
471 PLUG_API void FreeStructDef(void *base);      /* *** Use Unref(base) *** */
472 
473 PLUG_API Array *NewArray(StructDef *base, Dimension *dims);
474 PLUG_API void FreeArray(void *array);        /* *** Use Unref(array) *** */
475 
476 /* NewTmpArray/ClearTmpArray may be used to get one or two temporary
477    arrays.  Call ClearTmpArray first, then NewTmpArray several times,
478    then ClearTmpArray.  At the third call to NewTmpArray, the Array
479    returned by the first call is Unref'ed; at the fourth call to
480    NewTmpArray, the second is Unref'ed; and so on.  */
481 PLUG_API Array *NewTmpArray(StructDef *base, Dimension *dims);
482 PLUG_API void ClearTmpArray(void);
483 
484 /* NewDimension does NOT do Ref(next) */
485 /* WARNING: NewArray(base, NewDimension(...)) is a memory leak!
486  * need to use ynew_dim() below instead in this context
487  */
488 PLUG_API int yForceOrigin; /* non-zero to ignore stated origin in Dimension
489                             lists, and always assume 1-origin indices */
490 PLUG_API Dimension *NewDimension(long number, long origin, Dimension *next);
491 PLUG_API void FreeDimension(Dimension *dims);
492 
493 PLUG_API Strider *NewStrider(long stride, long number);
494 PLUG_API void FreeStrider(Strider *strider);
495 
496 /*--------------------------------------------------------------------------*/
497 
498 #ifdef NOT_YORICK
499 /* This is the minimal Operations -- a virtual delete function.
500    Without this, the Unref macro is unusable.  */
501 struct Operations {
502   void (*Free)(void *);  /* crucial member for Unref -- first in struct
503                             to allow alternate Operations to be used */
504 };
505 #endif
506 
507 #define Ref(db) ((db)?++(db)->references:0 , (db))
508 #define RefNC(db) (++(db)->references , (db))
509 #define Unref(db) {if ((db) && --(db)->references<0) (db)->ops->Free(db);}
510 #define UnrefNC(db) {if (--(db)->references<0) (db)->ops->Free(db);}
511 
512 PLUG_API long TotalNumber(const Dimension *dims);
513 PLUG_API int CountDims(const Dimension *dims);
514 /* Note-- like NewDimension, CopyDims does NOT do Ref(next) */
515 PLUG_API Dimension *CopyDims(Dimension *dims, Dimension *next, int copyOrigin);
516 
517 /* CopyStrider also does NOT do Ref(next) */
518 PLUG_API Strider *CopyStrider(Strider *strider, Strider *next);
519 
520 /* tmpDims can be used for "protected" scratch space to build dimension
521  * lists.  Before using tmpDims, always call FreeDimension(tmpDims).
522  * ynew_dim() sets tmpDims to the result of NewDimension(), so
523  * it can be used as argument to functions like NewArray which
524  * increment the use counter
525  */
526 PLUG_API Dimension *tmpDims;
527 PLUG_API Dimension *ynew_dim(long n, Dimension *next);
528 
529 /* Given a pointer to data (memory representation of a pointerStruct),
530    return the associated Array.  */
531 PLUG_API void *Pointee(void *pointer);
532 
533 /* StructEqual tests for two structures which are exactly the same.
534    EquivStruct tests whether the file StructDef belonging to an IOStream
535    is equivalent to the mem StructDef belonging to yStructTable.  */
536 PLUG_API int StructEqual(StructDef *l, StructDef *r);
537 PLUG_API int EquivStruct(StructDef *fil, StructDef *mem);
538 
539 /* Adjust the address to a multiple of the alignment (no-op if <2).  */
540 PLUG_API long AlignAdjust(long address, int alignment);
541 
542 /* StructName works for disk or memory based StructDefs,
543    CopyStruct returns the StructDef in file->structTable equivalent
544                to the given base, creating it if necessary */
545 PLUG_API char *StructName(StructDef *base);
546 PLUG_API StructDef *CopyStruct(IOStream *file, StructDef *base);
547 
548 /*--------------------------------------------------------------------------*/
549 
550 /* AddStruct adds an empty data structure to a file structTable,
551    returning the new StructDef.  Returns 0 on error.  If the name
552    is a duplicate, returns 0 to signal error, but the names "string"
553    and "pointer" are excepted from this rule, provided that the
554    associated StructDef has not been referenced.
555    If file==0, the yStructTable is assumed.
556    If n is non-0, it must be the exact length of name --
557    if n is 0, name is presumed 0-terminated.
558    If file->history!=0, the struct is added to the history child.
559    This is illegal after the second history record has begun.  */
560 PLUG_API StructDef *AddStruct(IOStream *file, const char *name, long n);
561 
562 /* AddMember increments references to memType, dims -- offset
563    is computed if input offset<0.  Returns 0 on success, 1 if name is a
564    duplicate, 2 if memType or a sub-structure has a type name conflict
565    in the file which owns base.
566    (If return non-0 memType, dims references NOT incremented).
567    In any case, hashIndex set to index of member in base.
568    In the case of a duplicate name, memType and dims are NOT
569    checked for consistency with the existing member.
570    *******
571    WARNING-- if offset is specified, base->alignment cannot be updated,
572              and the proper alignment must be set by hand  */
573 PLUG_API int AddMember(StructDef *base, long offset, const char *name,
574                      StructDef *memType, Dimension *dims);
575 
576 /* DefinePrimitive is called in lieu of AddMember to define a primitive
577    data type after AddStruct has been called.  If model==0, then must
578    have Convert==0, and DefinePrimitive will try to match the given
579    size, order, and fpLayout to one of char, short, long, float, or
580    double (never int) as best it can.  If model is one of the primitive
581    types (char, short, int, long, float, double, string, or pointer),
582    and size==0, DefinePrimitive will also set Convert appropriately.
583    If order==0 (opaque primitive), a model must be supplied.
584    If non-zero, fpLayout is copied.
585    Returns 0 on success,
586            1 on attempt to redefine char, short, int, long, float, or double
587              to a model other than the default one
588            2 on attempt to alias another type to string or pointer without
589              providing an explicit Converter
590            3 if an opaque type model size differs and no Converter supplied,
591            4 if Converter supplied without a model
592            5 if no model supplied for opaque primitive */
593 PLUG_API int DefinePrimitive(StructDef *base, long size, int alignment,
594                            int addressType, int order, FPLayout *fpLayout,
595                            StructDef *model, Converter *Convert);
596 
597 /* InstallStruct finishes a structure defintion begun with AddStruct
598    and AddMember calls.  If base->file==0, base is added to yStructTable
599    incrementing base->references.
600    If base->file, then an equivalent in-memory model is found for
601    base->model: First, yStructTable table is checked for an
602    in-memory equivalent StructDef of the same name as base.  Failing
603    this, if base is a primitive with non-zero base->order or base->size==1,
604    it is matched to the "closest" of the primitive data types char, short,
605    long, float, or double (never int).  Failing this, an in-memory model
606    is constructed and installed on the spot.
607    In all cases, base->dataOps is set to "validate" the StructDef.
608    If model is non-zero, it is assumed to be the correct model for base.  */
609 PLUG_API void InstallStruct(StructDef *base, StructDef *model);
610 
611 /* If DefInstallHook is non-0, InstallStruct calls it after
612    installing base in yStructTable if base->file!=0 */
613 PLUG_API void (*DefInstallHook)(const char *name, StructDef *base);
614 
615 /* AddVariable increments references to varType, dims -- address
616    is computed if input address<0.  Returns 0 on success, 1 if name is
617    a duplicate, and 2 if the name of varType or one of its sub-structures
618    already belongs to a non-equivalent data structure (in either non-0
619    case varType, dims references NOT incremented).
620    For returns 0 or 1, hashIndex set to index of name in file->dataTable,
621    or file->history->child->dataTable, if file->history!=0.
622    In the case of a duplicate name, varType and dims are NOT
623    checked for consistency with the existing variable.
624    If file->history!=0, the variable is added to the history child
625    (i.e.- it becomes a record variable).  This is illegal after the
626    second history record has begun.  */
627 PLUG_API int AddVariable(IOStream *file, long address, const char *name,
628                        StructDef *varType, Dimension *dims);
629 
630 /* AddHistory adds a history child to an existing IOStream, returning the
631    file->history if successful.  Size is the approximate maximum size of
632    one file in the history family, or 0 for the default (4 Megabytes).  */
633 PLUG_API HistoryInfo *AddHistory(IOStream *file, long size);
634 
635 /* AddRecord adds a record to the HistoryInfo, returning 0 on success.
636    flags is +1 if time exists, +2 if ncyc exists
637    The record is assumed to be in the current history child at the
638    specified address, or at the next available address if address<0.  */
639 PLUG_API int AddRecord(HistoryInfo *history,
640                      int flags, double time, long ncyc, long address);
641 
642 /* AddNextFile adds a new file to the HistoryInfo, returning 0 on
643    success.  If the fullname is 0, the NextFileName function is used.
644    If the create flag is non-0, the file is created (possibly copying
645    the parent data), otherwise the file is expected to exist.  */
646 PLUG_API int AddNextFile(HistoryInfo *history, char *filename, int create);
647 
648 /* Return value must be freed with p_free.
649    Algorithm:
650    (1) Strip directory (if any) from name.
651    (2) If final character is a digit (0-9), it becomes increment character,
652        else the character before the final dot (.) is the increment
653             character (or the final character if there is no dot).
654    (3) If the increment character is not A-Z, a-z, or 0-9, scan backwards
655        through the name until a character in this range is found.
656    (4) Loop:
657          If the increment character is before the beginning of name,
658             or if it is not in the range A-Z, a-z, or 0-9, insert the
659             character "A" and break out of this loop.
660          If it is 9 or z or Z, it becomes 0,
661          else increment it and break out of this loop.
662          Back up so the increment character becomes the previous character.
663  */
664 PLUG_API char *NextFileName(const char *name);
665 
666 /* JumpToTime (JumpToCycle) jumps to the nearest time (ncyc) in the
667    current record sequence to the specified time (ncyc).  Returns 0
668    on success, non-0 on failure.  */
669 PLUG_API int JumpToTime(HistoryInfo *history, double time);
670 PLUG_API int JumpToCycle(HistoryInfo *history, long ncyc);
671 /* JumpRecord returns 0 on success, 1 on recNumber out of range.
672    If recNumber is out of range, there is no current record.  */
673 PLUG_API int JumpRecord(HistoryInfo *history, long recNumber);
674 
675 /*--------------------------------------------------------------------------*/
676 
677 /* Parameters for adjusting caching system -- see cache.c */
678 PLUG_API long yMaxBlockSize, yCacheSize, yCacheTotal, y_block_size_0;
679 PLUG_API int yCacheNumber, yCacheN;
680 
681 /* copy src from 0 to src->nextAddress to dst, return 0 on success */
682 PLUG_API int YCopyFile(IOStream *dst, IOStream *src);
683 
684 /* FlushFile flushes all cache blocks associated with file, optionally
685    discarding them altogether.  */
686 PLUG_API void FlushFile(IOStream *file, int discardCache);
687 
688 /* YcRead and YcWrite are the lowest level read and write primitives for
689    moving data to or from an IOStream.  The addr and len are in bytes.
690    All data goes through the cache buffer system defined in cache.c.  */
691 PLUG_API long YcRead(IOStream *file, void *buf, long addr, long len);
692 PLUG_API void YcWrite(IOStream *file, const void *buf, long addr, long len);
693 
694 /* YRead and YWrite are the high level interface to an IOStream.
695    The base->file MUST be non-zero.  In both cases, the void* is an
696    in-memory buffer holding (or big enough to hold) number objects of size
697    base->model->...->size.  If strider is non-0, number is ignored and
698    the disk data referenced will be described by the strider.  (Use the
699    Scatter and Gather routines from bcast.h to apply a Strider to arrays
700    in memory.)
701    These routines perform any data type conversions necessary to move
702    foreign formats, strings, or pointers to and from disk.  */
703 PLUG_API void YWrite(void *src, long dst, StructDef *base, long number,
704                    const Strider *strider);
705 PLUG_API void YRead(void *dst, long src, StructDef *base, long number,
706                   const Strider *strider);
707 
708 /*--------------------------------------------------------------------------*/
709 
710 /* CLupdate ensures that file->contentsLog exists and is up to date.  */
711 PLUG_API void CLupdate(IOStream *file);
712 
713 /* CLopen checks to see if file has a Clog description appended to it,
714    returning 0 if it does, in which case the file is updated.  */
715 PLUG_API int CLopen(IOStream *file, int familyOK);
716 
717 /* CLclose is suitable for use as a CloseHook -- appends Clog description
718    to end of file and zaps file->contentsLog.  */
719 PLUG_API void CLclose(IOStream *file);
720 
721 /* ZapClogFile frees file->contentsLog, and destroys the associated file.  */
722 PLUG_API void ZapClogFile(IOStream *file);
723 
724 /* FreeClogFile frees file->contentsLog.  */
725 PLUG_API void FreeClogFile(IOStream *file);
726 
727 /* DumpClogFile creates a Contents Log named clogName, describing file.
728    This is completely independent of the file->contentsLog, if any.  */
729 PLUG_API int DumpClogFile(IOStream *file, const char *clogName);
730 
731 /* ReadClogFile reads a Contents Log named clogName and makes file
732    look like the description therein.  (CLopen with a separate file.)
733    This is completely independent of the file->contentsLog, if any.  */
734 PLUG_API int ReadClogFile(IOStream *file, const char *clogName);
735 
736 /* functions to manage file->pointeeList */
737 PLUG_API void ReadPointees(IOStream *file);
738 PLUG_API void WritePointees(IOStream *file);
739 PLUG_API void ClearPointees(IOStream *file, int writing);
740 
741 /* functions to manage FPLayouts */
742 PLUG_API FPLayout *MakeFPLayout(FPLayout *model, long size);
743 PLUG_API void FreeFPLayout(FPLayout *layout);
744 PLUG_API int SameFPLayout(FPLayout *l, FPLayout *m);
745 
746 /* ------------------------------------------------------------------------ */
747 
748 /* YError and YWarning must be supplied by user of binary file package.
749    YError should longjump or exit, YWarning may return.  */
750 PLUG_API void YWarning(const char *msg);
751 PLUG_API void YError(const char *msg);
752 
753 /* ------------------------------------------------------------------------ */
754 
755 #endif
756