/***********************************************************************/
/* Open Visualization Data Explorer                                    */
/* (C) Copyright IBM Corp. 1989,1999                                   */
/* ALL RIGHTS RESERVED                                                 */
/* This code licensed under the                                        */
/*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
/***********************************************************************/

#include <dxconfig.h>

 
 
 
/*
 * internal data structs for processing external data format.
 */

/* constants.
 */ 
#define MAXNEST	 20             /* max number of nested include files */
#define MAXBUF	 1024           /* max length of a single input token */
#define MAXRANK  50             /* max rank for data items */
#define MAXTERMS 100		/* max terms in mesh or product array */
 
/* as objects are created, they are added to a linked list of objects,
 *  with an id associated with each.  
 */
struct objlist {
    int id;                     /* unique per input file */
    Object o;                   /* if != NULL, actual object */
    char *name;                 /* if named, the name */
    int oused;                  /* whether object is really used in the file */
    int odelete;                /* what to do with object when done */
    int nrefs;                  /* size of following list */
    struct objlist **refs;      /* list of objects referenced by this one */
    struct objlist *next;       /* linked list of all objects in file */
    struct getby *gp;           /* if a remote id, the info for remote */
};
 
/* odelete values.
 *  what to do at the end when deleting the dictionary.  this is used to
 *  keep the top level objects without monkeying with the ref counts.
 */
#define OBJ_CANDELETE  0
#define OBJ_NODELETE   1

 
/* oused values
 *  in onepass, all objects are created at the time they are encountered,
 *  and at the end all unreferenced objects are deleted.
 *  in twopass, all objects are identified as being referenced or not and
 *  in the second pass the unused objects are not created.
 */
#define OBJ_UNUSED      0
#define OBJ_USED        1
 
 
#define NAMEATTR "name"


/* local object id (same file), remote file id or either
 */
#define ID_LOCAL	1
#define ID_REMOTE	2
#define ID_EITHER	3
 

/*
 * dictionary section
 */

/* blocksize for local memory allocates 
 */
#define LOCALSTORBLOCK  8192
 
/* dictionary entry for variable name -> unique identifier
 */
struct dinfo {
    PseudoKey key;	/* psuedokey based on string contents */
    char *contents;	/* actual key value */
    int type;		/* class of token */
    int value;		/* system generated id for object aliases */
};

/* dictionary entry for keyword -> identifier
 */
struct kinfo {
    PseudoKey key;	/* psuedokey based on string contents */
    char *contents;	/* actual key value */
    int value;		/* keyword token id */
};

struct localstor {
    int bytesleft;		/* bytes are left to be allocated; 0==full */
    int nextbyte;		/* next available byte in block */
    struct localstor *next;	/* next block like this; NULL for end */
    char contents[LOCALSTORBLOCK];	/* actual local storage */
};

struct dict {
    HashTable dicttab;			/* hash table for user strings */
    HashTable keytab;			/* hash table for keywords */
    struct localstor *localdict;	/* local storage for strings */
    int nextid;                         /* unique system-allocated ids */
};
 
/* object ids - either user defined or generated by the system.
 */
#define USER_ID(x)	((x+1) << 1)
#define SYS_ID(x)	((x+1) << 1 | 1)

 
/*
 * return by name vs. return by number
 */
struct getby {
    char *fname;                /* remote filename, if needed - must free */
    int which;			/* import by name or by number */
    int num;                    /* single number */
    char **namelist;		/* null terminated namelist (uses buf) */
    int *numlist;		/* -1 terminated numlist (uses buf) */
    Pointer *gbuf;              /* storage for lists - must free */
    int seriesflag;		/* which of start/end/delta has been set */
    int serieslim[3];		/* start/end/delta frame numbers */
};

/*
 * values for 'which'
 */ 
#define GETBY_NONE     0    /* not set yet */
#define GETBY_NAME     1    /* named object list */
#define GETBY_NUM      2    /* single object number or byte offset */
#define GETBY_NUMLIST  3    /* object number list */
#define GETBY_LINES    4    /* line number offset */
#define GETBY_ID       5    /* internal dictionary id */
#define GETBY_ALLNAMES 6    /* all named objects */

/*
 * series limit flags
 */
#define SL_START  0x0001
#define SL_END    0x0002
#define SL_DELTA  0x0004
 

/* ascii-input-line-number to byte-offset-in-file translation list.
 *
 *  could be used both ways (for finding a line number given a byte offset),
 *  but right now it's being used for converting a line number to a byte
 *  offset in the file so 'data line #' can be used to say where the
 *  ascii data starts in a file.  i don't know how to count lines when
 *  there is binary data follows.  praps the default for export ascii should 
 *  be line nos and for binary should be bytes.
 */
struct lines {
    int bytesalloc;     /* allocation size is maxlcount * sizeof(int) */
    int lcount;   	/* current max line count */
    int *linelist;	/* byte offset of each line from top of file */
};

 
/*
 * structure the input tokenizer (lexinput) routine returns.
 */
typedef union {
    int id;
    unsigned char c;
    int i;
    float f;
    double d;
} Token;

struct tinfo {
    int class;          /* see list below */
    int subclass;       /* more specific */
    Token token;        /* value.  type depends on class and context */
};
 
/* token class:                    subclass:            token value:    */
#define NUMBER          1	/* number type          numeric value   */
#define KEYWORD         2	/* none                 keyword id      */
#define BRACKET         3	/* bracket type         dictionary id   */
#define STRING          4	/* none                 dictionary id   */
#define LEXERROR        5	/* error type           none            */
#define NOTASCII        6	/* none                 none            */
#define ALIAS           7	/* object id            dictionary id   */
#define PUNCT           8	/* punctuation type     none            */
#define IDENTIFIER      9       /* none                 dictionary id   */
#define ENDOFHEADER    10       /* none                 none            */
 
/* subclasses of number */
#define INTEGER	        1
#define FLOAT           2
#define DOUBLE          3
#define CHAR            4
 
/* subclasses of bracketed strings - not currently used */
#define PAREN           1
#define SQUARE          2
#define CURLY           3
#define ANGLE           4

/* subclasses of error */
#define BADINPUT        -1
#define BADQUOTE        -2
#define BADNUMBER       -3
#define BADCOMMA	-4
#define BADBRACKET	-5
#define BADLENGTH       -6
 
/* subclasses of punctuation */
#define COMMA            1
#define SEMICOLON        2
#define COLON            3
#define NEWLINE          4
#define OTHER            9
#define UNKNOWN         -1

/* info about how to parse.
 *
 * maybe this is going to need code for 'identifier' in the mustmatch 
 *  section so that file,number or file,name will parse as one dictionary
 *  entry and get one identifier.
 *
 */
struct pinfo {
    int tonextline;     /* return at start of next line */
    int skippunct;      /* punctuation (separators) are ok to skip */
    int mustmatch;      /* if the next token type is known already */

    int nbytes;   	/* for skip, skip count */
    int nodict;         /* for string data, don't put in dictionary */
    int skipnum;        /* for numeric data, don't do the conversion */

    char *inbuf;	/* one token input buffer */
    int incount;        /* number of characters in that buffer */

    char delim;         /* current delimiter (squote, dquote, bracket, etc) */
    int byteoffset;     /* current byte offset */
    int lineno;		/* current line offset */
    int prevlineno;	/* line offset when parse was started */
    int startlineno;	/* line number where current object defn starts */
    struct lines l;     /* bytes offset to line number struct */

    /* plus what?  */
};


 
/*
 * one of these structures per open input file
 */
struct finfo {
    char *fname;	/* input filename */
    FILE *fd;		/* fopen file descriptor */
    struct getby gb;    /* list of objects to import, and series limits */
    struct tinfo t;     /* current input token */
    struct pinfo p;     /* current parse state */
    int recurse;	/* recurse level for included files */
    int dformat;        /* default data format flags */
    int denorm_fp;	/* i860 binary data only: zero'd denormalized floats */
    int bad_fp;		/* i860 binary data only: zero'd NaN and Infinities */
    int onepass;	/* set if we can't seek backwards (eg it's a socket) */
    int headerend;      /* byte offset of end of header section */
    HashTable ht;	/* hash table for objects by objectid */
    struct objlist *ol; /* list of all objects created or referenced */
    struct dict *d;     /* dictionary for this file */
    int activity;       /* whether we are making objects or just parsing ids */
    Object curobj;      /* object currently under construction */
    int curid;          /* id of current object */
};

/* 
 * data file format flags 
 */
#define D_BYTES   0x0007
#define D_MSB	  0x0001
#define D_LSB     0x0002
#define D_NATIVE  0x0004

#define D_FORMATS 0x0070
#define D_IEEE    0x0010
#define D_XDR     0x0020
#define D_TEXT    0x0040

#define D_FILES   0x0700
#define D_FOLLOWS 0x0100
#define D_ONE     0x0200
#define D_TWO     0x0400


/* activity flag options:
 *
 * two pass:
 *  identifying which objects use others and which ones are actually
 *  going to be imported.  filling byte offset/line number table.
 *  skipping binary data follows arrays.
 *
 *  making the used objects
 * 
 * one pass:
 *  making all objects and discarding unused ones at the end
 */
#define IDENTIFY_OBJS   1
#define MAKE_USED_OBJS  2
#define MAKE_ALL_OBJS   3

 
/*
 * object list ptr and object id from that list.
 */
struct objectid {
    struct objlist *ol;
    int id;
};
 
/* 
 * keywords for dictionary
 */ 
    
/* used in keyword list below.  good words > 0, errors < 0 */
#define KW_OBJECT       1
#define KW_GROUP        2
#define KW_ARRAY        3
#define KW_FIELD        4
#define KW_STRING       5
#define KW_TRANSFORM    6
#define KW_MATRIX       7
#define KW_LIGHT        8
#define KW_CLIPPED      9
#define KW_SCREEN       10
#define KW_FILE         11
#define KW_ALIAS        12
#define KW_SERIES       13
#define KW_ATTRIBUTE    14
#define KW_VALUE        15
#define KW_COMPONENT    16
#define KW_MEMBER       17
#define KW_CLASS        18
#define KW_TYPE         19
#define KW_CHAR         20
#define KW_SHORT        21
#define KW_INTEGER      22
/* #define              23 */
#define KW_HYPER        24
#define KW_FLOAT        25
#define KW_DOUBLE       26
#define KW_CATEGORY     27
#define KW_REAL         28
#define KW_COMPLEX      29
#define KW_QUATERNION   30
#define KW_RANK         31
#define KW_SHAPE        32
#define KW_COUNT        33
/* #define              34 */
#define KW_DATA         35
#define KW_XDR          36
#define KW_ASCII        37
#define KW_IEEE		38
#define KW_FOLLOWS      39
#define KW_REGULARARRAY 40
#define KW_PRODUCTARRAY 41
#define KW_MESHARRAY    42
#define KW_PATHARRAY    43
#define KW_CAMERA       44
#define KW_DIRECTION    45
#define KW_LOCATION     46
#define KW_POSITION     47
#define KW_SIZE         48
#define KW_COLOR        49
#define KW_COMPOSITE    50
#define KW_NAME         51
#define KW_XFORM        52
#define KW_OF           53
#define KW_BY           54
#define KW_TIMES	55
#define KW_PLUS		56
#define KW_TERM		57
#define KW_ORIGIN	58
#define KW_DELTAS	59
#define KW_GRID		60
#define KW_GRIDPOSITIONS   61
#define KW_GRIDCONNECTIONS 62 
#define KW_DISTANT	63
#define KW_LOCAL	64
#define KW_FROM		65
#define KW_TO		66
#define KW_WIDTH	67
#define KW_HEIGHT	68
#define KW_RESOLUTION	69
#define KW_ASPECT	70
#define KW_UP		71
#define KW_NUMBER	72
#define KW_MSB		73
#define KW_LSB		74
#define KW_MODE		75
#define KW_BINARY	76
#define KW_MESHOFFSETS  77
#define KW_DEFAULT      78
#define KW_LINES        79
#define KW_ANGLE        80
#define KW_AMBIENT      81
#define KW_WORLD        82
#define KW_VIEWPORT     83
#define KW_PIXEL        84
#define KW_BEHIND       85
#define KW_INSIDE       86
#define KW_INFRONT      87
#define KW_STATIONARY   88
#define KW_ORTHOGRAPHIC 89
#define KW_PERSPECTIVE  90
#define KW_NAMED	91
#define KW_CONSTANTARRAY 92
#define KW_SIGNED       93
#define KW_UNSIGNED     94
#define KW_MULTIGRID    95
/* add more here, and match with dict struct */
#define KW_END        9999
#define KW_NULL		-1

 
/* bad return from dictionary lookup */
#define BADINDEX  0



/* force correct casts swab routines */
/* these use the (destination, source, ... ) parm order */
#define SWAB(x,y,z)  _dxfByteSwap((void *)x, (void*)y, (int)(z)/2, TYPE_SHORT)
#define SWAW(x,y,z)  _dxfByteSwap((void *)x, (void*)y, (int)(z)/4, TYPE_INT)
#define SWAD(x,y,z)  _dxfByteSwap((void *)x, (void*)y, (int)(z)/8, TYPE_DOUBLE)

/* Byte order */
typedef enum {
        BO_UNKNOWN = 1,
        BO_MSB = 2,
        BO_LSB = 3
} ByteOrder;

extern Error _dxfByteSwap(void *, void*, int, Type);
extern ByteOrder _dxfLocalByteOrder(void);
#define LOCAL_BYTEORDER   _dxfLocalByteOrder()




/* shorthand for common routines.  should these be real entry points?
 * these are going to be more efficient but make debugging more complicated.
 */
#define next_class(f, class)       _dxfnexttoken(f, class, NULL, NULL)
#define next_subclass(f, subclass) _dxfnexttoken(f, NULL, subclass, NULL)
#define next_id(f, id)             _dxfnexttoken(f, NULL, NULL, id)
#define next_token(f, class, subclass, id) _dxfnexttoken(f, class, subclass, id)
#define nextkeywordis(f, keyword)  _dxfmatchid(f, KEYWORD, keyword, 1)
#define next_string(f)             _dxfisnexttoken(f, STRING, NULL, NULL)

#define skipkeyword(f)		   _dxfmatchanysub(f, KEYWORD, NULL, NULL)
#define match_keyword(f, keyword)  _dxfmatchid(f, KEYWORD, keyword, 0)
#define match_punct(f, type)       _dxfmatchsaysub(f, PUNCT, type, NULL)

#define get_keyword(f, keyword) _dxfmatchanysub(f, KEYWORD, NULL, keyword)
#define get_string(f, string)   _dxfmatchanysub(f, STRING, NULL, string)
#define get_punct(f, type)      _dxfmatchanysub(f, PUNCT, type, NULL)
#define get_ident(f, id)        _dxfmatchanysub(f, IDENTIFIER, NULL, id)

#define get_number(f, type, val) _dxfmatchnumber(f, type, val)

#define get_byte(f, val)        _dxfmatchbyte(f, val)
#define get_ubyte(f, val)       _dxfmatchubyte(f, val)
#define get_short(f, val)       _dxfmatchshort(f, val)
#define get_ushort(f, val)      _dxfmatchushort(f, val)
#define get_int(f, val)         _dxfmatchint(f, val)
#define get_uint(f, val)        _dxfmatchuint(f, val)
#define get_float(f, val)       _dxfmatchfloat(f, val)
#define get_double(f, val)      _dxfmatchdouble(f, val)



/* prototypes
 */

extern Error  _dxfinitparse(struct finfo *f);
extern Error  _dxfresetparse(struct finfo *f);
extern void   _dxfdeleteparse(struct finfo *f);
extern void   _dxfsetstartline(struct finfo *f);
extern int    _dxfgetstartline(struct finfo *f);
extern void   _dxfsetprevline(struct finfo *f);
extern int    _dxfgetprevline(struct finfo *f);
extern int    _dxfgetlineno(struct finfo *f);
extern Error  _dxfnextline(struct finfo *f);
extern Error  _dxfendnotascii(struct finfo *f);
extern void   _dxfsetnexttype(struct finfo *f, int type);
extern void   _dxfsetskipnum(struct finfo *f, int type);
extern void   _dxfsetdictstringmode(struct finfo *f, int value);
extern char * _dxfgetstringinfo(struct finfo *f, int *len);
extern Error  _dxfgetstringnodict(struct finfo *f);
extern Error  _dxfset_headerend(struct finfo *f);
extern Error  _dxfsetparse(struct finfo *f, long byteoffset, int lines, int lineno);

extern Error  _dxfnexttoken(struct finfo *f, int *class, int *subclass, int *id);
extern Error  _dxfisnexttoken(struct finfo *f, int *class, int *subclass, int *id);
extern Error  _dxfmatchbyte(struct finfo *f, byte *p);
extern Error  _dxfmatchubyte(struct finfo *f, ubyte *p);
extern Error  _dxfmatchshort(struct finfo *f, short *p);
extern Error  _dxfmatchushort(struct finfo *f, ushort *p);
extern Error  _dxfmatchint(struct finfo *f, int *p);
extern Error  _dxfmatchuint(struct finfo *f, uint *p);
extern Error  _dxfmatchfloat(struct finfo *f, float *p);
extern Error  _dxfmatchdouble(struct finfo *f, double *p);

extern Error  _dxfmatchsaysub(struct finfo *f, int class, int subclass, int *id);
extern Error  _dxfmatchanysub(struct finfo *f, int class, int *subclass, int *id);
extern Error  _dxfmatchnumber(struct finfo *f, int *subclass, Token *id);
extern Error  _dxfmatchid(struct finfo *f, int class, int id, int noparse);

extern Error  _dxfinitfinfo(struct finfo *f);
extern void   _dxffreefinfo(struct finfo *f);
extern void   _dxfdupfinfo(struct finfo *f1, struct finfo *f2); 

extern int    _dxfiskeyword(struct dict *d, char *word);
extern char * _dxflookkeyword(int id);

extern Error  _dxfinitdict(struct dict *d);
extern Error  _dxfdeletedict(struct dict *d);
extern int    _dxfputdict(struct dict *d, char *word);
extern int    _dxflookdict(struct dict *d, char *word);
extern char * _dxfdictname(struct dict *d, int slot);
extern Error  _dxfgetdictinfo(struct dict *d, int slot, int *type, int *value);
extern Error  _dxfsetdictalias(struct dict *d, int slot, int *value);
extern Error  _dxfgetdictalias(struct dict *d, int alias, int *value);
extern int    _dxfgetuniqueid(struct dict *d);

extern FILE * _dxfopen_dxfile(char *inname, char *auxname, char **outname, 
			      char *ext);
extern Error  _dxfclose_dxfile(FILE *fptr, char *filename);
extern Error  _dxfparse_file(struct finfo *f, Object *retobj);

extern Error  _dxfreadarray_binary(struct finfo *f, Array a, int format);
extern Error  _dxfreadarray_xdr(FILE *fd, Array a);
extern Error  _dxfreadarray_text(struct finfo *f, Array a);
extern Error  _dxfskiparray_binary(struct finfo *f, int items, int itemsize);
extern Error  _dxfskiparray_xdr(FILE *fd, int items, int itemsize);
extern Error  _dxfskiparray_text(struct finfo *f, int items, Type t);
extern Error  _dxfreadoffset(struct finfo *f, Array a, int offset, int type);
extern Error  _dxfreadremote(struct finfo *f, Array a, int id, int type);

extern Error  _dxfinitobjlist(struct finfo *f);
extern Error  _dxfdeleteobjlist(struct finfo *f);
extern Error  _dxfaddobjlist(struct finfo *f, int id, Object o, char *name, 
			     int start);
extern Error  _dxflookobjlist(struct finfo *f, int id, Object *o, char **name);
struct getby **_dxfgetobjgb(struct finfo *f, int id);
extern Error  _dxfsetobjptr(struct finfo *f, int id, Object o);
extern Error  _dxfsetobjused(struct finfo *f, int id);
extern Error  _dxfisobjused(struct finfo *f, int id);
extern Error  _dxfobjusesobj(struct finfo *f, int id, int refd_id);

extern Object _dxfnamedobjlist(struct finfo *f, char **namelist);
extern Object _dxfmarknamedobjlist(struct finfo *f, char **namelist);
extern Object _dxfnumberedobjlist(struct finfo *f, int *numlist, int idflag);
extern Object _dxfmarknumberedobjlist(struct finfo *f, int *numlist, int idflag);

extern Error  _dxflexinput(struct finfo *fp);
extern char * _dxfprtoken(struct tinfo *t, struct dict *d);

extern Error  _dxfskip_object(struct finfo *fp);
extern Error  _dxfskip_object_or_attr(struct finfo *fp);

 
/* utility routines 
 */
extern Error _dxfValidate(Field f);
extern Error DXColorNameToRGB(char *, RGBColor *);
 

#if !defined(DXD_STANDARD_IEEE)
/*
 * Floating point denormalization checks for machines which don't support
 * IEEE denormalized floating point values.
 */
extern void _dxfdouble_denorm(int *, int , int *, int *);
extern void _dxffloat_denorm(int *, int , int *, int *);
#endif 

/* should debugging messages be compiled in?  0=no, 1=yes
 */

#define DEBUG_MSG 0
