/***********************************************************************/ /* 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 #include #include #include #include #include "edf.h" /* keywords and dictionary code */ /* prototypes */ static char *dictplace(struct dict *d, int len); static Error initkeywords(struct dict *d); static Error putkeyinfo(struct dict *d, char *word, int value); static int strcmp_lc(char *a, char *b); static char *strcpy_lc(char *a, char *b); static PseudoKey hashFunc(char *str); static int hashCompare(Key search, Element matched); #define LONGESTKEY 20 /* set this to longer than the longest keyword */ /* keyword to internal id map */ static struct keywords { char *word; int id; } keywords[] = { { "object", KW_OBJECT }, { "group", KW_GROUP }, { "array", KW_ARRAY }, { "field", KW_FIELD }, { "string", KW_STRING }, { "transform", KW_TRANSFORM }, { "xform", KW_TRANSFORM }, { "matrix", KW_MATRIX }, { "light", KW_LIGHT }, { "clipped", KW_CLIPPED }, { "screen", KW_SCREEN }, { "file", KW_FILE }, { "alias", KW_ALIAS }, { "series", KW_SERIES }, { "attribute", KW_ATTRIBUTE }, { "value", KW_VALUE }, { "component", KW_COMPONENT }, { "member", KW_MEMBER }, { "class", KW_CLASS }, { "type", KW_TYPE }, { "char", KW_CHAR }, { "byte", KW_CHAR }, { "short", KW_SHORT }, { "int", KW_INTEGER }, { "integer", KW_INTEGER }, { "hyper", KW_HYPER }, { "float", KW_FLOAT }, { "double", KW_DOUBLE }, { "category", KW_CATEGORY }, { "real", KW_REAL }, { "complex", KW_COMPLEX }, { "quaternion", KW_QUATERNION }, { "rank", KW_RANK }, { "shape", KW_SHAPE }, { "item", KW_COUNT }, { "items", KW_COUNT }, { "count", KW_COUNT }, { "counts", KW_COUNT }, { "data", KW_DATA }, { "datum", KW_DATA }, { "xdr", KW_XDR }, { "text", KW_ASCII }, { "ieee", KW_IEEE }, { "ascii", KW_ASCII }, { "follows", KW_FOLLOWS }, { "follow", KW_FOLLOWS }, { "regulararray", KW_REGULARARRAY }, { "productarray", KW_PRODUCTARRAY }, { "mesharray", KW_MESHARRAY }, { "path", KW_PATHARRAY }, { "patharray", KW_PATHARRAY }, { "camera", KW_CAMERA }, { "direction", KW_DIRECTION }, { "location", KW_LOCATION }, { "position", KW_POSITION }, { "size", KW_SIZE }, { "color", KW_COLOR }, { "compositefield", KW_COMPOSITE }, { "composite", KW_COMPOSITE }, { "name", KW_NAME }, { "of", KW_OF }, { "by", KW_BY }, { "times", KW_TIMES }, { "plus", KW_PLUS }, { "term", KW_TERM }, { "origin", KW_ORIGIN }, { "origins", KW_ORIGIN }, { "delta", KW_DELTAS }, { "deltas", KW_DELTAS }, { "grid", KW_GRID }, { "gridpositions", KW_GRIDPOSITIONS }, { "gridconnections", KW_GRIDCONNECTIONS }, { "distant", KW_DISTANT }, { "local", KW_LOCAL }, { "from", KW_FROM }, { "to", KW_TO }, { "width", KW_WIDTH }, { "height", KW_HEIGHT }, { "resolution", KW_RESOLUTION }, { "aspect", KW_ASPECT }, { "up", KW_UP }, { "number", KW_NUMBER }, { "msb", KW_MSB }, { "lsb", KW_LSB }, { "mode", KW_MODE }, { "binary", KW_BINARY }, { "meshoffsets", KW_MESHOFFSETS }, { "default", KW_DEFAULT }, { "line", KW_LINES }, { "lines", KW_LINES }, { "angle", KW_ANGLE }, { "ambient", KW_AMBIENT }, { "world", KW_WORLD }, { "viewport", KW_VIEWPORT }, { "pixel", KW_PIXEL }, { "behind", KW_BEHIND }, { "inside", KW_INSIDE }, { "infront", KW_INFRONT }, { "stationary", KW_STATIONARY }, { "orthographic", KW_ORTHOGRAPHIC }, { "perspective", KW_PERSPECTIVE }, { "named", KW_NAMED }, { "constantarray", KW_CONSTANTARRAY }, { "signed", KW_SIGNED }, { "unsigned", KW_UNSIGNED }, { "multigrid", KW_MULTIGRID }, /* add more here, and add #defines for KW_xxx in edf.h */ { "end", KW_END }, { NULL, KW_NULL } }; /* so what was faster? */ #define TIMING 1 /* compare input word to a list of known keywords. return the keyword value * if it matches, else return KW_NULL. */ int _dxfiskeyword(struct dict *d, char *word) { #if TIMING struct kinfo *ki, search; char lcase[LONGESTKEY]; int len, key; if (!d || !word) return BADINDEX; #if DEBUG_MSG DXDebug("D", "looking for %s in keyword dictionary", word); #endif if (strlen(word) >= LONGESTKEY) return KW_NULL; strcpy_lc(lcase, word); search.key = hashFunc(lcase); search.contents = lcase; if ((ki = (struct kinfo *)DXQueryHashElement(d->keytab, (Pointer)&search)) == NULL) return KW_NULL; return ki->value; #else struct keywords *kp = keywords; while(kp->word) { if (!strcmp_lc(word, kp->word)) return kp->id; kp++; } return KW_NULL; #endif } /* return the string associated with the keyword ID. * used for error messages. */ char *_dxflookkeyword(int id) { struct keywords *kp = keywords; /* linear search should be good enough since this is only * used for error messages. */ while(kp->id != KW_NULL) { if (id == kp->id) return kp->word; kp++; } /* not found */ return NULL; } /* add a new keyword to dictionary and set value. */ static Error putkeyinfo(struct dict *d, char *word, int value) { struct kinfo ki; int id; if (!d || !word) return ERROR; #if DEBUG_MSG DXDebug("D", "adding %s to dictionary", word); #endif ki.key = hashFunc(word); ki.contents = dictplace(d, strlen(word)+1); if (!ki.contents) return ERROR; strcpy(ki.contents, word); ki.value = value; if (!DXInsertHashElement(d->keytab, (Pointer)&ki)) return ERROR; #if DEBUG_MSG DXDebug("D", "setting %s to value %d", word, value); #endif return OK; } static Error initkeywords(struct dict *d) { struct keywords *kp = keywords; /* add each keyword to the hash table. */ while (kp->word) { if (!putkeyinfo(d, kp->word, kp->id)) return ERROR; kp++; } return OK; } /* given a string and a lower case string, do a strcmp ignoring the * case of the first string. return 1 if not equal, 0 if equal. */ static int strcmp_lc(char *a, char *b) { if (!a || !b) return 1; while(*a && *b) { if (*a != *b && (!isupper(*a) || tolower(*a) != *b)) return 1; a++, b++; } if (!*a && !*b) return 0; return 1; } /* copy b to a, changing all chars to lower case. return NULL on error. */ static char *strcpy_lc(char *a, char *b) { char *c = a; if (!a || !b) return NULL; while(*b) { *a = (isupper(*b) ? tolower(*b) : *b); a++, b++; } *a = '\0'; return c; } /* * dictionary section. */ static PseudoKey hashFunc(char *str) { unsigned long h = 1; while(*str) h = (17*h + *str++); return (PseudoKey)h; } static int hashCompare(Key search, Element matched) { return (strcmp(((struct dinfo *)search)->contents, ((struct dinfo *)matched)->contents)); } static char *dictplace(struct dict *d, int len) { char *place; struct localstor *ls, *newls; if (len >= LOCALSTORBLOCK) return NULL; ls = d->localdict; if (!ls) return NULL; /* if not enough space is allocated, insert new block at head of list * so d->localstor always contains the block from which allocation * is happening. */ if (ls->bytesleft < len) { newls = (struct localstor *) DXAllocateLocalZero(sizeof(struct localstor)); if (!newls) return NULL; newls->bytesleft = LOCALSTORBLOCK; newls->nextbyte = 0; newls->next = ls; d->localdict = newls; ls = newls; } place = ls->contents + ls->nextbyte; ls->bytesleft -= len; ls->nextbyte += len; return place; } /* allocate dictionary and add known keywords. */ Error _dxfinitdict(struct dict *d) { if (!d) return ERROR; d->dicttab = DXCreateHash(sizeof(struct dinfo), NULL, hashCompare); if (!d->dicttab) goto error; d->keytab = DXCreateHash(sizeof(struct kinfo), NULL, hashCompare); if (!d->keytab) goto error; d->localdict = (struct localstor *) DXAllocateLocalZero(sizeof(struct localstor)); if (!d->localdict) goto error; d->localdict->nextbyte = 0; d->localdict->bytesleft = LOCALSTORBLOCK; d->localdict->next = NULL; d->nextid = 1; if (!initkeywords(d)) goto error; return OK; error: _dxfdeletedict(d); return ERROR; } /* free dictionary */ Error _dxfdeletedict(struct dict *d) { struct localstor *ls, *next; if (!d) return ERROR; if (d->dicttab) { DXDestroyHash(d->dicttab); d->dicttab = NULL; } if (d->keytab) { DXDestroyHash(d->keytab); d->keytab = NULL; } ls = d->localdict; while(ls) { next = ls->next; DXFree((Pointer)ls); ls = next; } d->localdict = NULL; d->nextid = BADINDEX; return OK; } /* add a string to a lookup table. used to support named objects * and aliases. if string is already in table, return id. if not, * create new slot and return id. */ int _dxfputdict(struct dict *d, char *word) { struct dinfo di; int id; if (!d || !word) return BADINDEX; if ((id = _dxflookdict(d, word)) != BADINDEX) return id; #if DEBUG_MSG DXDebug("D", "adding %s to dictionary", word); #endif di.key = hashFunc(word); di.contents = dictplace(d, strlen(word)+1); if (!di.contents) return BADINDEX; strcpy(di.contents, word); di.type = STRING; di.value = 0; if (!DXInsertHashElement(d->dicttab, (Pointer)&di)) return BADINDEX; return _dxflookdict(d, word); } /* look up a string in the lookup table. if not found, return error. */ int _dxflookdict(struct dict *d, char *word) { struct dinfo *di, search; int key; if (!d || !word) return BADINDEX; #if DEBUG_MSG DXDebug("D", "looking for %s in dictionary", word); #endif search.key = hashFunc(word); search.contents = word; if ((di = (struct dinfo *)DXQueryHashElement(d->dicttab, (Pointer)&search)) == NULL) return BADINDEX; return (int)((byte *)di - (byte *)d->dicttab); } /* return the string associated with a dictionary slot. */ char *_dxfdictname(struct dict *d, int slot) { struct dinfo *di; if (!d || !slot) return NULL; di = (struct dinfo *)((byte *)d->dicttab + slot); return di->contents; } /* mark an existing string in the dictionary as an alias for an object. * generate a new unique object id and return it. the SYS_ID() macro * makes sure internally generated numbers don't collide with numbers * assigned to objects by the user. */ Error _dxfsetdictalias(struct dict *d, int slot, int *value) { struct dinfo *di; if (!d || !slot) return ERROR; di = (struct dinfo *)((byte *)d->dicttab + slot); di->type = ALIAS; di->value = SYS_ID(d->nextid); *value = SYS_ID(d->nextid); d->nextid++; #if DEBUG_MSG DXDebug("D", "setting %s to alias value %d", di->contents, di->value); #endif return OK; } /* return the type and value associated with a dictionary slot */ Error _dxfgetdictinfo(struct dict *d, int slot, int *type, int *value) { struct dinfo *di; if (!d || !slot) return ERROR; di = (struct dinfo *)((byte *)d->dicttab + slot); if (type) *type = di->type; if (value) *value = di->value; return OK; } /* return the type and value associated with a dictionary slot * it would be nice if this could be fast somehow. */ Error _dxfgetdictalias(struct dict *d, int alias, int *value) { struct dinfo *di; /* this is hashed on string value, so to look up an alias number * it has to be a linear search. */ if (!DXInitGetNextHashElement(d->dicttab)) return ERROR; while ((di = (struct dinfo *)DXGetNextHashElement(d->dicttab)) != NULL) { if (di->type != ALIAS) continue; if (di->value == alias) { *value = (int)((byte *)di - (byte *)d->dicttab); return OK; } } return ERROR; } /* allocate just a unique id from the dictionary list so we are * guarenteed not to collide with other valid object ids. */ int _dxfgetuniqueid(struct dict *d) { int value; if (!d) return -1; value = SYS_ID(d->nextid); d->nextid++; return value; } /* for debug, print contents of dictionary */ static void prdictinfo(struct dict *d) { struct dinfo *di; struct kinfo *ki; int i; /* dictionary */ i = 0; if (!DXInitGetNextHashElement(d->dicttab)) return; while((di = (struct dinfo *)DXGetNextHashElement(d->dicttab)) != NULL) { DXMessage("%d: %08x %d %d %08x %s", i, di->key, di->type, di->value, (unsigned int)&di->contents, di->contents); i++; } /* keyword table */ i = 0; if (!DXInitGetNextHashElement(d->keytab)) return; while((ki = (struct kinfo *)DXGetNextHashElement(d->keytab)) != NULL) { DXMessage("%d: %08x %d %d %08x %s", i, ki->key, ki->value, (unsigned int)&ki->contents, ki->contents); i++; } return; }