/***********************************************************************/ /* 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 #include #include "edf.h" /* prototypes */ static int tohex(char c); static Error set_lines(struct finfo *fp); #define COMMENTCHAR '#' /* rest of current input line ignored */ #if 1 /* use the macros for performance instead of a func call */ #define input() (pp->byteoffset++, getc(fp->fd)) #define pushback(c) (ungetc(c, fp->fd), --pp->byteoffset) #else /* i was using these until i got the above macros to work - the comma * was screwing things up until i parenthesized them. */ static char input(FILE *fp, int *offset) { *offset++; return getc(fp); } static void pushback(char c, FILE *fp, int *offset) { ungetc(c, fp); *offset--; } #endif /* * return the next token from the input stream. * * input is a pointer to a file structure, which contains an open file * pointer, current offset into the buffer, current lineno and input buffer. * * output is a pointer to a token structure, which contains a flag to * distinquish different classes of input (numbers, keywords, variables and * errors), and the token value which is interpeted differently depending on * the class of the input. * * CODE WHICH NEEDS TO BE ADDED: * support for [ x y z ] three vector numbers (also [x,y,z]?) * \\ at end of line to continue strings */ Error _dxflexinput(struct finfo *fp) { char nextc, *cp; int value; int incomment = 0; struct tinfo *tp; struct pinfo *pp; /* things for number conversions. */ int onesign, onedot, oneexp; int isfloat, isdouble; char *pokehere; int done; double fvalue; if (!fp) return ERROR; tp = &fp->t; pp = &fp->p; /* if you are already at the end of the header or end of file, * don't read further */ if (tp->class == ENDOFHEADER) return OK; if (tp->class == KEYWORD && tp->token.id == KW_END) return OK; /* clear tempbuf count, and keep track of what line we started on. */ pp->incount = 0; _dxfsetprevline(fp); /* get the next token from the input file. */ while(1) { /* next character */ nextc = input(); /* end of input? */ if (feof(fp->fd)) { tp->class = ENDOFHEADER; return OK; } /* new line? */ if (nextc == '\n') { fp->p.lineno++; /* set byteoffset vs. line num here */ if (fp->p.lineno > fp->p.l.lcount) set_lines(fp); incomment = 0; /* return at start of next line? */ if (pp->tonextline) { tp->class = PUNCT; tp->subclass = NEWLINE; return OK; } continue; } /* already in a comment? */ if (incomment) continue; /* start of a new comment? */ if (nextc == COMMENTCHAR) { incomment = 1; continue; } /* other whitespace? */ if (isspace(nextc)) continue; /* binary? */ if (!isprint(nextc)) { pushback(nextc); tp->class = NOTASCII; return OK; } /* comma or semicolon? * (can be used as number separators) */ if (nextc == ',' || nextc == ';') { if (pp->skippunct) continue; tp->class = PUNCT; tp->subclass = (nextc == ',') ? COMMA : SEMICOLON; return OK; } /* quoted string? * copy until matching close quote. multiline strings must have * newlines escaped. \c and \Xxx and \ooo char codes are ok. */ if (nextc == '"' || nextc == '\'') { /* skip first char (the delimiter) and get the first one from * the string. */ pp->delim = nextc; cp = pp->inbuf; nextc = input(); /* until matching delimiter or the buffer fills, read chars */ while ((nextc != pp->delim) && (cp < &pp->inbuf[MAXBUF-1])) { /* escape */ if (nextc == '\\') { int i; uint num; char tc; switch (nextc = input()) { /* standard ascii escape chars */ case 'a': *cp++ = '\a'; break; case 'b': *cp++ = '\b'; break; case 'f': *cp++ = '\f'; break; case 'n': *cp++ = '\n'; break; case 'r': *cp++ = '\r'; break; case 't': *cp++ = '\t'; break; case 'v': *cp++ = '\v'; break; case '\\': *cp++ = '\\'; break; case '"': *cp++ = '"'; break; case '\'': *cp++ = '\''; break; case '?': *cp++ = '?'; break; /* hex codes - 0, 1 or 2 digits */ case 'x': tc = input(); if (!isxdigit(tc)) { pushback(tc); *cp++ = 'x'; break; } num = tohex(tc); tc = input(); if (!isxdigit(tc)) pushback(tc); else { num <<= 4; num += tohex(tc); } *cp++ = (char)num; break; /* octal codes - 1, 2 or 3 digits */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': num = (uint)(nextc) - (uint)'0'; for (i=0; i<2; i++) { tc = input(); if (!isdigit(tc) || tc == '8' || tc == '9') pushback(tc); else { num <<= 3; num += (uint)(tc) - (uint)'0'; } } *cp++ = (char)num; break; /* end of file */ case (char)EOF: goto endofquote; /* escaped end of line */ case '\n': fp->p.lineno++; /* set byteoffset vs. line num here */ if (fp->p.lineno > fp->p.l.lcount) set_lines(fp); break; /* any other char */ default: *cp++ = nextc; break; } } else if (nextc == (char)EOF) goto endofquote; else if (nextc == '\n') goto endofquote; else *cp++ = nextc; /* read next input char */ nextc = input(); } /* terminate string in buffer */ *cp = '\0'; endofquote: /* if the current character isn't the close delimiter, * there is an error. */ if(nextc != pp->delim) { tp->class = LEXERROR; if (cp >= &pp->inbuf[MAXBUF-1]) tp->subclass = BADLENGTH; else tp->subclass = BADQUOTE; return ERROR; } /* if you just want the string without putting it in the * dictionary (like for string data arrays), return ok * but with an invalid dictionary id. before you call * this routine again you must get the data from the token * buffer because it will get overwritten by the next string. * also set char count here because the string data routine * needs it. */ if (pp->nodict) { tp->class = STRING; tp->token.id = BADINDEX; pp->incount = cp - pp->inbuf; /* plus or minus? */ return OK; } value = _dxfputdict(fp->d, pp->inbuf); if(value != BADINDEX) { tp->class = STRING; tp->token.id = value; return OK; } tp->class = LEXERROR; tp->subclass = BADINPUT; return ERROR; } /* other delimited string? */ #if 0 /* there are currently no other delimiters defined, but if we * end up needing brackets or parens, here's where the code goes. */ if (nextc == '<' || nextc == '(' || nextc == '[' || nextc == '{') { switch (nextc) { case '<': pp->delim = '>'; tp->subclass = ANGLE; break; case '(': pp->delim = ')'; tp->subclass = PAREN; break; case '[': pp->delim = ']'; tp->subclass = SQUARE; break; case '{': pp->delim = '}'; tp->subclass = CURLY; break; } /* skip first char (the delimiter) and get the first one from * the string. */ pp->delim = nextc; cp = pp->inbuf; nextc = input(); /* until matching delimiter or the buffer fills, read chars */ while ((nextc != pp->delim) && (cp < &pp->inbuf[MAXBUF-1])) { *cp++ = nextc; if (nextc == '\n') { fp->p.lineno++; /* set byteoffset vs. line num here */ if (fp->p.lineno > fp->p.l.lcount) set_lines(fp); } nextc = input(); } *cp = '\0'; if (nextc != pp->delim) { tp->class = LEXERROR; tp->subclass = BADBRACKET; return ERROR; } if (pp->nodict) { tp->class = BRACKET; tp->token.id = BADINDEX; pp->incount = cp - pp->inbuf; return OK; } /* change this to make the class whatever the inside of the * (), {}, <> or [] means. */ value = _dxfputdict(fp->d, pp->inbuf); if(value != BADINDEX) { tp->class = BRACKET; /* the subclass has already been set above */ tp->token.id = value; return OK; } tp->class = LEXERROR; tp->subclass = BADINPUT; return ERROR; } #endif /* here it starts to get tricky. up to now i know what a token * is by looking at the first character. but identifiers can * start with a number. if the first char is a number, try to * parse it as a number until you get something which isn't * legal as a number. here's where knowing if you are looking * for a string, number or either would be helpful. */ /* here's where con ed shut off the power on me and i lost * about a page of editing. drat them. */ #define Is(c) (nextc == c) #define IsNot(c) (nextc != c) /* number? (base 10 only, but exponential notation is ok). */ if (isdigit(nextc) || Is('-') || Is('+') || Is('.')) { onesign = 0; onedot = 0; oneexp = 0; isfloat = 0; isdouble = 0; pokehere = NULL; done = 0; fvalue = 0.0; /* if the next thing should be a string, don't try to parse * it as number - go directly to the string code. */ if (pp->mustmatch == STRING) goto notnum; cp = pp->inbuf; while (!done) { switch (nextc) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; case '-': case '+': if (onesign) { tp->class = LEXERROR; tp->subclass = BADNUMBER; return ERROR; } onesign++; break; case '.': if (onedot) { tp->class = LEXERROR; tp->subclass = BADNUMBER; return ERROR; } onedot++; isfloat++; break; case 'd': case 'D': pokehere = cp; isdouble++; /* fall thru */ case 'e': case 'E': if (oneexp) { tp->class = LEXERROR; tp->subclass = BADNUMBER; return ERROR; } oneexp++; onesign = 0; isfloat++; break; default: done++; continue; } *cp++ = nextc; nextc = input(); } /* if there is something which is part of the string but is * not a digit, this must not be a number. reset the ptr * and try again. */ /* NEEDS FIX !!! should be isalpha? */ if (!isspace(nextc)) { /* allow a few things besides whitespace to terminate the #. * anything else is assumed to be part of an unquoted string. */ if (IsNot(COMMENTCHAR) && IsNot(',') && IsNot(';') && IsNot((char)EOF)) { *cp++ = nextc; pp->incount = cp - pp->inbuf; nextc = pp->inbuf[0]; goto notnum; } } pushback(nextc); *cp = '\0'; /* if we don't care about the value, don't do the conversion. */ if (pp->skipnum) { tp->class = NUMBER; return OK; } tp->class = NUMBER; if (isfloat) { if (isdouble) *pokehere = 'e'; fvalue = atof(pp->inbuf); if (!isdouble && ((fabs(fvalue) == 0.0) || ((fabs(fvalue) > DXD_MIN_FLOAT) && (fabs(fvalue) < DXD_MAX_FLOAT)))) { tp->token.f = (float)fvalue; tp->subclass = FLOAT; } else { tp->token.d = fvalue; tp->subclass = DOUBLE; } } else { value = atoi(pp->inbuf); tp->token.i = value; tp->subclass = INTEGER; } return OK; } notnum: /* keyword or unquoted string? */ if (isprint(nextc)) { int bc = 1; /* since we can get here from a partially parsed number, * this has to be able to get the next char either from * the token buffer or from the input file. */ cp = &pp->inbuf[pp->incount > 0 ? pp->incount-1 : 0]; while (!isspace(nextc) && (cp < &pp->inbuf[MAXBUF-1])) { if (Is(',')) break; if (bc < pp->incount) { nextc = pp->inbuf[bc]; bc++; } else { *cp++ = nextc; nextc = input(); } } *cp = '\0'; if (cp >= &pp->inbuf[MAXBUF-1]) { pushback(nextc); tp->class = LEXERROR; tp->subclass = BADLENGTH; return ERROR; } /* put the separator character back for next time */ pushback(nextc); /* check for keyword; return keyword id */ value = _dxfiskeyword(fp->d, pp->inbuf); if (value != KW_NULL) { tp->token.id = value; tp->class = KEYWORD; /* some special case code here for end of header */ if (value == KW_END) { while (nextc != '\n') { if (feof(fp->fd) || !isprint(nextc)) break; nextc = input(); } /* eat the newline */ if (nextc == '\n') input(); } return OK; } if (pp->nodict) { tp->class = IDENTIFIER; tp->token.id = BADINDEX; return OK; } /* a filename, perhaps. */ /* string identifier - add it to the dictionary */ value = _dxfputdict(fp->d, pp->inbuf); if (value != BADINDEX) { tp->class = IDENTIFIER; tp->token.id = value; return OK; } /* not a keyword or identifier we recognize - return error */ tp->class = LEXERROR; tp->subclass = BADINPUT; return ERROR; } /* not anything we recognize - return error. don't try to skip it * or recover. */ tp->class = LEXERROR; tp->subclass = BADINPUT; return ERROR; } /* notreached */ } /* debug and errors */ char *_dxfprtoken(struct tinfo *t, struct dict *d) { static char cbuf[512]; switch(t->class) { case ENDOFHEADER: sprintf(cbuf, "end of input"); break; case NUMBER: switch(t->subclass) { case INTEGER: sprintf(cbuf, "integer: %d", t->token.i); break; case FLOAT: sprintf(cbuf, "float: %f", t->token.f); break; case DOUBLE: sprintf(cbuf, "double: %g", t->token.d); break; case CHAR: sprintf(cbuf, "byte: %x", (unsigned int)t->token.c); break; default: sprintf(cbuf, "bad number"); break; } break; case KEYWORD: sprintf(cbuf, "keyword '%s'", _dxflookkeyword(t->token.id)); break; case IDENTIFIER: sprintf(cbuf, "string '%s'", _dxfdictname(d, t->token.id)); break; case STRING: sprintf(cbuf, "string '%s'", _dxfdictname(d, t->token.id)); break; case LEXERROR: switch(t->subclass) { case BADINPUT: sprintf(cbuf, "bad input"); break; case BADQUOTE: sprintf(cbuf, "missing quote"); break; case BADNUMBER: sprintf(cbuf, "bad number"); break; case BADCOMMA: sprintf(cbuf, "multiple commas"); break; case BADBRACKET: sprintf(cbuf, "missing bracket"); break; case BADLENGTH: sprintf(cbuf, "line too long"); break; default: sprintf(cbuf, "unknown error"); break; } break; default: sprintf(cbuf, "bad input"); break; } return cbuf; } /* initialise the parsing routine. */ Error _dxfinitparse(struct finfo *f) { f->p.inbuf = (char *)DXAllocateLocal(MAXBUF); if (!f->p.inbuf) return ERROR; f->p.lineno = 1; /* init line buffer here? */ return _dxflexinput(f); } /* reset to start of file. */ Error _dxfresetparse(struct finfo *f) { fseek(f->fd, 0, 0); f->p.lineno = 1; f->t.class = -1; return _dxflexinput(f); } /* reset to a specific byte offset. */ Error _dxfsetparse(struct finfo *f, long byteoffset, int lines, int lineno) { fseek(f->fd, byteoffset, 0); if (lines) f->p.lineno = lineno; f->t.class = -1; return _dxflexinput(f); } /* clean up any mem allocated for pinfo struct. */ void _dxfdeleteparse(struct finfo *f) { if (!f) return; if (f->p.inbuf) DXFree(f->p.inbuf); /* free line buffer here */ } /* set the type of the next thing to be parsed. */ void _dxfsetnexttype(struct finfo *f, int type) { f->p.mustmatch = type; } /* set the type of the next thing to be parsed. */ void _dxfsetskipnum(struct finfo *f, int type) { f->p.skipnum = type; } /* set the starting line number of the current object definition * (used for error messages) */ void _dxfsetstartline(struct finfo *f) { f->p.startlineno = f->p.lineno; } int _dxfgetstartline(struct finfo *f) { return f->p.startlineno; } void _dxfsetprevline(struct finfo *f) { f->p.prevlineno = f->p.lineno; } int _dxfgetprevline(struct finfo *f) { return f->p.prevlineno; } int _dxfgetlineno(struct finfo *f) { return f->p.lineno; } void _dxfsetdictstringmode(struct finfo *f, int value) { f->p.nodict = value; } Error _dxfgetstringnodict(struct finfo *f) { return get_string(f, NULL); } char *_dxfgetstringinfo(struct finfo *f, int *len) { int i, class; next_class(f, &class); if (class != STRING) return NULL; if (len) *len = f->p.incount; return f->p.inbuf; } /* only skips whitespace and returns after the next newline */ Error _dxfnextline(struct finfo *f) { int rc; f->p.tonextline = 1; rc = _dxflexinput(f); f->p.tonextline = 0; return rc; } Error _dxfendnotascii(struct finfo *f) { return _dxflexinput(f); } /* * set offset of end of header -- first character after the newline * following the 'end' keyword. */ Error _dxfset_headerend(struct finfo *f) { f->headerend = ftell(f->fd); return OK; } static Error set_lines(struct finfo *f) { return OK; } /* token info stuff */ /* return the info about the current token without reading ahead. * sets class, subclass and id if the pointers are not null. */ Error _dxfnexttoken(struct finfo *f, int *class, int *subclass, int *id) { #if DEBUG_MSG if (DXQueryDebug("T")) DXDebug("T", "last token = %s", _dxfprtoken(&f->t, f->d)); #endif if (class) *class = f->t.class; if (subclass) *subclass = f->t.subclass; if (id) *id = f->t.token.id; return f->t.class == LEXERROR ? ERROR : OK; } /* return OK if all the input parms specified match. * does NOT read ahead. */ Error _dxfisnexttoken(struct finfo *f, int *class, int *subclass, int *id) { #if DEBUG_MSG if (DXQueryDebug("T")) DXDebug("T", "last token = %s", _dxfprtoken(&f->t, f->d)); #endif if (class && *class != f->t.class) return ERROR; if (subclass && *subclass != f->t.subclass) return ERROR; if (id && *id != f->t.token.id) return ERROR; return OK; } /* return id of next thing if the classes and subclasses match. * (in contrast to the next routine which should be used if any * subclass is ok and you just need to know what it is) */ Error _dxfmatchsaysub(struct finfo *f, int class, int subclass, int *id) { Error rc = OK; #if DEBUG_MSG if (DXQueryDebug("T")) { DXDebug("T", "looking for class %d, subclass %d", class, subclass); DXDebug("T", "last token = %s", _dxfprtoken(&f->t, f->d)); } #endif if ((f->t.class == class) && (f->t.subclass == subclass)) { if (id) *id = f->t.token.id; rc = _dxflexinput(f); return rc; } return ERROR; } /* return subclass and id of next thing if the class matches. * (in contrast to the previous routine which should be used if you * only expect a specific subclass here). */ Error _dxfmatchanysub(struct finfo *f, int class, int *subclass, int *id) { Error rc = OK; #if DEBUG_MSG if (DXQueryDebug("T")) { DXDebug("T", "looking for class %d", class); DXDebug("T", "last token = %s", _dxfprtoken(&f->t, f->d)); } #endif if (f->t.class == class) { if (subclass) *subclass = f->t.subclass; if (id) *id = f->t.token.id; rc = _dxflexinput(f); return rc; } return ERROR; } /* return subclass and numeric value */ Error _dxfmatchnumber(struct finfo *f, int *subclass, Token *id) { Error rc = OK; #if DEBUG_MSG if (DXQueryDebug("T")) { DXDebug("T", "looking for number"); DXDebug("T", "last token = %s", _dxfprtoken(&f->t, f->d)); } #endif if (f->t.class == NUMBER) { if (subclass) *subclass = f->t.subclass; if (id) *id = f->t.token; rc = _dxflexinput(f); return rc; } return ERROR; } /* return ok if next thing matches both class and id match. * parse ahead unless noparse flag is set. */ Error _dxfmatchid(struct finfo *f, int class, int id, int noparse) { Error rc = OK; #if DEBUG_MSG if (DXQueryDebug("T")) { DXDebug("T", "looking for class %d, id %d", class, id); DXDebug("T", "last token = %s", _dxfprtoken(&f->t, f->d)); } #endif if ((f->t.class == class) && (f->t.token.id == id)) { if (!noparse) rc = _dxflexinput(f); return rc; } return ERROR; } /* read tokens until either another object keyword or end keyword or error. */ Error _dxfskip_object(struct finfo *f) { Error rc = OK; #if DEBUG_MSG if (DXQueryDebug("T")) { DXDebug("T", "looking for next object token"); DXDebug("T", "last token = %s", _dxfprtoken(&f->t, f->d)); } #endif f->p.skipnum = 1; while (rc != ERROR) { if (f->t.class != KEYWORD && f->t.class != ENDOFHEADER) { rc = _dxflexinput(f); continue; } if (f->t.class == ENDOFHEADER) { f->p.skipnum = 0; return OK; } if (f->t.token.id != KW_OBJECT && f->t.token.id != KW_END) { rc = _dxflexinput(f); continue; } f->p.skipnum = 0; return rc; } f->p.skipnum = 0; return ERROR; } /* read tokens until either another object keyword or * attribute keyword or end keyword or error. */ Error _dxfskip_object_or_attr(struct finfo *f) { Error rc = OK; #if DEBUG_MSG if (DXQueryDebug("T")) { DXDebug("T", "looking for next object or attribute token"); DXDebug("T", "last token = %s", _dxfprtoken(&f->t, f->d)); } #endif f->p.skipnum = 1; while (rc != ERROR) { if (f->t.class != KEYWORD && f->t.class != ENDOFHEADER) { rc = _dxflexinput(f); continue; } if (f->t.class == ENDOFHEADER) { f->p.skipnum = 0; return OK; } if (f->t.token.id != KW_OBJECT && f->t.token.id != KW_ATTRIBUTE && f->t.token.id != KW_END) { rc = _dxflexinput(f); continue; } f->p.skipnum = 0; return rc; } f->p.skipnum = 0; return ERROR; } /* some routines to promote ints to floats, chars to ints, etc. */ Error _dxfmatchbyte(struct finfo *f, byte *cp) { Error rc = OK; #if DEBUG_MSG if (DXQueryDebug("T")) { DXDebug("T", "looking for a byte"); DXDebug("T", "last token = %s", _dxfprtoken(&f->t, f->d)); } #endif if(f->t.class == NUMBER && f->t.subclass == INTEGER) { if (f->t.token.i > DXD_MAX_BYTE || f->t.token.i < DXD_MIN_BYTE) return ERROR; *cp = (byte)f->t.token.i; rc = _dxflexinput(f); return rc; } return ERROR; } Error _dxfmatchubyte(struct finfo *f, ubyte *cp) { Error rc = OK; #if DEBUG_MSG if (DXQueryDebug("T")) { DXDebug("T", "looking for an unsigned byte"); DXDebug("T", "last token = %s", _dxfprtoken(&f->t, f->d)); } #endif if(f->t.class == NUMBER && f->t.subclass == INTEGER) { if (f->t.token.i > DXD_MAX_UBYTE || f->t.token.i < 0) return ERROR; *cp = (ubyte)f->t.token.i; rc = _dxflexinput(f); return rc; } return ERROR; } Error _dxfmatchshort(struct finfo *f, short *sip) { Error rc = OK; #if DEBUG_MSG if (DXQueryDebug("T")) { DXDebug("T", "looking for a short int"); DXDebug("T", "last token = %s", _dxfprtoken(&f->t, f->d)); } #endif if(f->t.class == NUMBER && f->t.subclass == INTEGER) { if (f->t.token.i > DXD_MAX_SHORT || f->t.token.i < DXD_MIN_SHORT) return ERROR; *sip = (short)f->t.token.i; rc = _dxflexinput(f); return rc; } return ERROR; } Error _dxfmatchushort(struct finfo *f, ushort *sip) { Error rc = OK; #if DEBUG_MSG if (DXQueryDebug("T")) { DXDebug("T", "looking for an unsigned short int"); DXDebug("T", "last token = %s", _dxfprtoken(&f->t, f->d)); } #endif if(f->t.class == NUMBER && f->t.subclass == INTEGER) { if (f->t.token.i > DXD_MAX_USHORT || f->t.token.i < 0) return ERROR; *sip = (short)f->t.token.i; rc = _dxflexinput(f); return rc; } return ERROR; } Error _dxfmatchint(struct finfo *f, int *ip) { Error rc = OK; #if DEBUG_MSG if (DXQueryDebug("T")) { DXDebug("T", "looking for an integer"); DXDebug("T", "last token = %s", _dxfprtoken(&f->t, f->d)); } #endif if(f->t.class == NUMBER && f->t.subclass == INTEGER) { *ip = f->t.token.i; rc = _dxflexinput(f); return rc; } return ERROR; } Error _dxfmatchuint(struct finfo *f, uint *ip) { Error rc = OK; #if DEBUG_MSG if (DXQueryDebug("T")) { DXDebug("T", "looking for an unsigned integer"); DXDebug("T", "last token = %s", _dxfprtoken(&f->t, f->d)); } #endif if(f->t.class == NUMBER && f->t.subclass == INTEGER) { *ip = (uint)f->t.token.i; rc = _dxflexinput(f); return rc; } return ERROR; } Error _dxfmatchfloat(struct finfo *f, float *fp) { Error rc = OK; #if DEBUG_MSG if (DXQueryDebug("T")) { DXDebug("T", "looking for a float"); DXDebug("T", "last token = %s", _dxfprtoken(&f->t, f->d)); } #endif if(f->t.class == NUMBER && f->t.subclass == FLOAT) { *fp = f->t.token.f; rc = _dxflexinput(f); return rc; } if(f->t.class == NUMBER && f->t.subclass == INTEGER) { *fp = (float)f->t.token.i; rc = _dxflexinput(f); return rc; } return ERROR; } Error _dxfmatchdouble(struct finfo *f, double *dp) { Error rc = OK; #if DEBUG_MSG if (DXQueryDebug("T")) { DXDebug("T", "looking for a double"); DXDebug("T", "last token = %s", _dxfprtoken(&f->t, f->d)); } #endif if(f->t.class == NUMBER && f->t.subclass == DOUBLE) { *dp = f->t.token.d; rc = _dxflexinput(f); return rc; } if(f->t.class == NUMBER && f->t.subclass == FLOAT) { *dp = (double)f->t.token.f; rc = _dxflexinput(f); return rc; } if(f->t.class == NUMBER && f->t.subclass == INTEGER) { *dp = (double)f->t.token.i; rc = _dxflexinput(f); return rc; } return ERROR; } /* check 'c' before calling this with isxdigit() because this does no * error checking. */ static int tohex(char c) { /* A-F */ if (isupper(c)) return 10 + (uint)(c) - (uint)'A'; /* a-f */ if (islower(c)) return 10 + (uint)(c) - (uint)'a'; /* 0-9 */ return (uint)(c) - (uint)'0'; }