home *** CD-ROM | disk | FTP | other *** search
- /* tfile.c - routines to read a tabular text file
- *
- * 12.Aug.87 jimmc Initial definition
- * 18.Jan.88 jimmc Remove struct defs to tfile.h; lint cleanup
- */
-
- #include <stdio.h>
- #include <varargs.h>
- #include <strings.h>
- #include "xalloc.h"
- #include "tklex.h"
- #include "tfile.h"
-
- #define NIL 0
-
- extern char *index();
-
- static struct {
- char *name;
- int tktype;
- } tktypetable[] = {
- { "i", TkNumber },
- { "s", TkString },
- };
- static int tktypetablesize = sizeof(tktypetable)/sizeof(tktypetable[0]);
-
- static
- EatToParen(tkhandle)
- TkHandle tkhandle;
- {
- int t;
-
- for (t=TkGet(tkhandle);t!=TkEOF&&t!=TkCParen;t=TkGet(tkhandle))
- ; /* EMPTY - scan until EOF or close paren */
- }
-
- static
- TFsymbol *
- FindSymbol(fh,name)
- TFstuff *fh;
- char *name;
- {
- TFsymbol *k;
-
- for (k=fh->symbols;k;k=k->next) {
- if (strcmp(name,k->name)==0) return k;
- }
- return NIL;
- }
-
- static
- TFsymbol *
- NewSymbol(fh,name)
- TFstuff *fh;
- char *name;
- {
- TFsymbol *k;
-
- k = XCALLOC(TFsymbol,1);
- k->next = fh->symbols;
- fh->symbols = k;
- k->name = XALLOC(char,strlen(name)+1);
- strcpy(k->name,name);
- return k;
- }
-
- static
- AddFieldToSymbol(fh,k,s)
- TFstuff *fh; /* in case of errors */
- TFsymbol *k; /* where to add the field name to */
- char *s; /* the field name and type to add */
- {
- char *st;
- TFfiledef *filedef;
- int tktype;
- TFprogdef *progdef;
- TkHandle tkhandle;
- int n;
-
- tkhandle = fh->tkhandle;
- st = index(s,'.'); /* look for type specifier */
- if (!st) {
- fileerror(tkhandle,"no type for field %s",s);
- return;
- }
- *st = 0; /* null terminate the name portion */
- st++; /* point to type itself */
- for (n=0; n<tktypetablesize; n++) {
- if (strcmp(st,tktypetable[n].name)==0) break;
- }
- if (n>=tktypetablesize) {
- fileerror(tkhandle,"bad type code %s for symbol %s",
- st,s);
- /*** abort the scan here? */
- tktype = TkEOF;
- }
- else tktype=tktypetable[n].tktype;
- /*** check for field name conflict */
- filedef = XCALLOC(TFfiledef,1);
- if (k->filedeftail) k->filedeftail->next = filedef;
- k->filedeftail = filedef;
- if (!k->filedef) k->filedef = filedef;
- filedef->fieldname = s;
- filedef->fieldtype = st;
- filedef->tktype = tktype;
- /* correlate against progdef info, set up destaddr */
- for (progdef=k->progdef;progdef;progdef=progdef->next) {
- if (strcmp(progdef->name,s)==0) break;
- }
- if (progdef) { /* if we found the name */
- if (progdef->tktype!=filedef->tktype) {
- fileerror(tkhandle,
- "type mismatch on field %s in table %s",
- filedef->fieldname,k->name);
- /*** what to do about this error? */
- }
- /*** we should really be switching on the tktype here... */
- filedef->destaddr.i = fh->args+progdef->argnum;
- }
- }
-
- static
- TFScanSchema(fh,s) /* reads a schema definition line from the file */
- TFstuff *fh;
- char *s; /* name of the file schema to be defined */
- /* The next token to be read is the open paren */
- {
- TkHandle tkhandle;
- int t;
- TFsymbol *k;
- char *sv;
-
- tkhandle = fh->tkhandle;
- k = FindSymbol(fh,s); /* see if a duplicate definition */
- if (k && k->filedef) {
- fileerror(tkhandle,"Symbol %s redefined",s);
- EatToParen(tkhandle);
- return;
- }
- t = TkGet(tkhandle);
- if (t!=TkOParen) {
- fileerror(tkhandle,"Expected open paren for schema for %s",s);
- EatToParen(tkhandle);
- return;
- }
- if (!k) k = NewSymbol(fh,s);
- t = TkGet(tkhandle);
- while (t==TkString) { /* read until we come to a close paren */
- sv = TkStringValue(tkhandle);
- AddFieldToSymbol(fh,k,sv);
- t = TkGet(tkhandle);
- }
- if (t!=TkCParen) {
- fileerror(tkhandle,"Expected string or close parenthesis");
- EatToParen(tkhandle);
- }
- return;
- }
-
- static
- TFScanData(fh,s) /* reads a data line from the file */
- TFstuff *fh;
- char *s; /* name of the data type to be read */
- /* The open paren has just been read */
- {
- TkHandle tkhandle;
- TFsymbol *k;
- TFfiledef *f;
- int t;
- int i;
-
- tkhandle = fh->tkhandle;
- k = FindSymbol(fh,s);
- if (!k) {
- fileerror(tkhandle,"No definition for symbol %s",s);
- EatToParen(tkhandle);
- return;
- }
- f = k->filedef; /* point to list of fields */
- for (i=0; i<k->progdefcount; i++) fh->args[i]=0;
- t = TkGet(tkhandle);
- while (t!=TkCParen && t!=TkEOF) {
- if (!f) {
- fileerror(tkhandle,"too many fields for type %s",s);
- EatToParen(tkhandle);
- return;
- }
- switch (f->tktype) {
- case TkNumber:
- if (t!=TkNumber) {
- fileerror(tkhandle,
- "expected integer for field %s",
- f->fieldname);
- EatToParen(tkhandle);
- return;
- }
- if (f->destaddr.i)
- *(f->destaddr.i) = TkNumberValue(tkhandle);
- break;
- case TkString:
- if (t!=TkString) {
- fileerror(tkhandle,
- "expected string for field %s",
- f->fieldname);
- EatToParen(tkhandle);
- return;
- }
- if (f->destaddr.s)
- *(f->destaddr.s) = TkStringValue(tkhandle);
- break;
- case TkEOF: /* earlier error */
- break; /* ignore it */
- default: /* should never happen */
- printf("internal error!! line %d, file %s\n",__LINE__,
- __FILE__);
- break;
- }
- f = f->next;
- t = TkGet(tkhandle);
- }
- if (f) {
- fileerror(tkhandle,"not enough fields");
- return;
- }
- /* now call the function as requested */
- t = (*k->funcp)(fh->args[0],fh->args[1],fh->args[2],
- fh->args[3],fh->args[4],fh->args[5],
- fh->args[6],fh->args[7],fh->args[8],
- fh->args[9],fh->args[10],fh->args[11]);
- /*** what does the return value mean? */
- }
-
- static
- int /* returns 0 if no more reading to do */
- TFScanOne(fh) /* read one "line" (terminated by close paren) */
- TFstuff *fh;
- {
- TkHandle tkhandle;
- int t;
- char *s,*s2;
-
- tkhandle = fh->tkhandle;
- t = TkGet(tkhandle);
- if (t==TkEOF) return 0; /* normal completion */
- if (t==TkOParen) { /* another data item of same type as last */
- if (!fh->lasttype) {
- fileerror(tkhandle,"no previous type specified");
- EatToParen(tkhandle);
- return 1;
- }
- TFScanData(fh,fh->lasttype);
- return 1;
- }
- if (t!=TkSymbol) {
- fileerror(tkhandle,"Expected start symbol");
- EatToParen(tkhandle);
- return 1;
- }
- s = TkStringValue(tkhandle); /* same symbol value */
- if (fh->lasttype) free(fh->lasttype);
- fh->lasttype = s;
- t = TkGet(tkhandle);
- if (t==TkOParen) {
- TFScanData(fh,s);
- }
- else if (t==TkSymbol) {
- s2 = TkStringValue(tkhandle);
- if (strcmp(s2,"schema")==0) {
- TFScanSchema(fh,s);
- }
- else {
- fileerror(tkhandle,
- "Bad keyword '%s' after symbol '%s'",s2,s);
- EatToParen(tkhandle);
- }
- free(s2);
- }
- else {
- fileerror(tkhandle,
- "Expected open parenthesis after symbol %s",s);
- EatToParen(tkhandle);
- }
- return 1; /* continue */
- }
-
- int /* returns status code (*** what is it?) */
- TFScan(handle) /* top level file scan */
- TFhandle handle;
- {
- TFstuff *fh;
-
- fh = (TFstuff *)handle;
- if (!fh) {
- printf("No handle for TFScan\n");
- return 0;
- }
-
- while (TFScanOne(fh)) ; /* EMPTY - read until done */
- return 1; /*** what to return? */
- }
-
- /* VARARGS - really varargs3, but lint doesn't understand va_alist */
- TFSetup(va_alist)
- /* args are: handle, name, funcp, args...; null terminates list */
- va_dcl
- {
- va_list v;
- TFhandle handle;
- char *name;
- IFP funcp; /* pointer to func returning int */
- TFstuff *fh;
- TFsymbol *k;
- TFprogdef *p;
- char *fd, *fdtype;
- int n;
- int tktype;
-
- va_start(v);
- handle = va_arg(v,TFhandle);
- name = va_arg(v,char *);
- funcp = va_arg(v,IFP);
- fh = (TFstuff *)handle;
- if (!fh) {
- printf("No handle for TFSetup of %s\n",name);
- goto end; /* do va_end and return */
- }
- k = FindSymbol(fh,name);
- if (k && k->progdef) {
- printf("Symbol %s re-setup\n",name);
- goto end; /* do va_end and return */
- }
- if (!k) k = NewSymbol(fh,name);
- k->funcp = funcp;
- fd = va_arg(v,char *); /* start looking at field defs */
- while (fd) {
- fdtype = index(fd,'.');
- if (!fdtype) {
- printf("no type for field %s in setup %s\n",
- fd,name);
- tktype = TkEOF;
- fdtype = fd+strlen(fd)+1; /* for later sub */
- }
- else {
- fdtype++;
- for (n=0; n<tktypetablesize; n++) {
- if (strcmp(fdtype,tktypetable[n].name)==0)
- break;
- }
- if (n>=tktypetablesize) {
- printf("bad type for field %s in setup %s\n",
- fd,name);
- tktype = TkEOF;
- }
- else tktype=tktypetable[n].tktype;
- }
- /*** eventually we would like to add a constant capability */
- p = XCALLOC(TFprogdef,1);
- p->name = XALLOC(char,fdtype-fd);
- strncpy(p->name,fd,fdtype-fd-1);
- p->name[fdtype-fd-1]=0;
- p->tktype = tktype;
- if (k->progdeftail) k->progdeftail->next = p;
- if (!k->progdef) k->progdef = p;
- k->progdeftail = p;
- if ((p->argnum=k->progdefcount++) > MAXARGS) {
- printf("too many pass-back args for setup %s (max=%d)\n",
- name,MAXARGS);
- }
- fd = va_arg(v,char *);
- }
- end:
- va_end(v);
- }
-
- TFhandle
- TFInit(filename)
- char *filename;
- {
- TFstuff *fh;
- TkHandle tkhandle;
-
- tkhandle = TkInit(filename);
- if (!tkhandle) {
- printf("can't init file %s\n",filename);
- return 0;
- }
- fh = XCALLOC(TFstuff,1);
- fh->tkhandle = tkhandle;
- return (TFhandle)fh;
- }
-
- TFDone(handle)
- TFhandle handle;
- {
- TFstuff *fh;
-
- fh = (TFstuff *)handle;
- if (!fh) {
- printf("No handle for TFDone\n");
- }
- /*** if anything needs to be freed, do it here */
- if (fh->tkhandle) TkDone(fh->tkhandle);
- }
-
- /* end */
-