This is bib.c in view mode; [Download] [Up]
/* bib.c * cm, 19 Dec 90 * * module for processing bibliography database files used * for generating FrameMaker bibliographies. * * entry points: * bib_parse(): engine to open, read, parse bib files. * * HISTORY * 29 May 92, neek: added support for @include macro in bib files. */ /* * Copyright (c) 1991 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ #include <stdio.h> #include <ctype.h> #include <sys/file.h> #include <mif.h> #include <bib.h> #define MAXLINE 300 #define MAXFIELDTYPES 200 extern char *bibfiles[]; /* list of bibliography files */ extern char *bibdirs[]; /* directories of the above */ static int f_begin(), f_getrec(), f_getrecbody(), f_getxref(), f_getfield_sep(), f_getfield(), f_endrec(); int f_getdefine(); int f_include(); static RefType crrnt_reftype; /* note: the following States should correspond to * their indeces into the funcs[] table below */ #define S_END -1 #define S_BEGIN 0 #define S_GETREC 1 #define S_GETRECBODY 2 #define S_GETXREF 3 #define S_GETFIELDSEP 4 #define S_GETFIELD 5 #define S_ENDREC 6 #define S_GETDEFINE 7 #define S_INCLUDE 8 static int (*funcs[])() = { f_begin, f_getrec, f_getrecbody, f_getxref, f_getfield_sep, f_getfield, f_endrec, f_getdefine, f_include, }; /* keywords associated w/ RefTypes above, keep the order... */ char *reftypes[] = { "article", "book", "booklet", "conference", "inbook", "incollection", "inproceedings", "manual", "mastersthesis", "misc", "phdthesis", "proceedings", "techreport", "unpublished", 0 }; int n_reftypes; /* # entries in reftypes[] */ static char *reffields[] = { "address", "annote", "author", "booktitle", "chapter", "date", "edition", "editor", "editors", "fullauthor", "fullorganization", "howpublished", "institution", "journal", "key", "meeting", "month", "note", "number", "organization", "pages", "publisher", "school", "series", "title", "type", "year", "volume", 0 }; int n_reffields; /* # entries in reffields[] */ static BibEnt *bep; /* current bibentry */ static char *lp; /* current place in current input line */ static char *closerec; /* close record token, either ")", "}", etc. */ static char token[1024]; /* build current token here. */ bib_init() { register n; int strsort(); for( n=0; reftypes[n]; n++ ) ; n_reftypes = n; qsort( reftypes, n_reftypes, sizeof( char *), strsort ); for( n=0; reffields[n]; n++ ) ; n_reffields = n; qsort( reffields, n_reffields, sizeof( char *), strsort ); } /* return 1 on success, 0 on failure */ bib_parse() { register char **cp; for( cp=bibfiles; *cp; cp++ ) { if( debug ) err(WARN, "Processing Bibfile: %s\n", *cp ); bib_process(*cp); } return(1); } bib_process(filename) char *filename; { int state; if(! mif_open( F_BIB, filename)) exit(1); if( debug ) err( WARN, "bib_process(): processing %s\n", filename ); state = S_BEGIN; while( state != S_END ) { state = funcs[state](); } mif_close( F_BIB ); } /* get next token from mif file * return NULL at end of file. * if 'delim' is non-zero, it points to a char. * to use as the end delimeter of the current token, else * use the default (spaces and bibdelimeters) */ static char * bib_gettok(delim) register char *delim; { register char *cp, *tp; register char c; tp = token; while(1) { if( ! (cp = mif_getc(F_BIB)) ) if( tp == token ) return( NULL ); /* eof */ else break; c = *cp; if( delim ) { if(c == *delim ) { if( tp == token ) return( NULL ); mif_ungetc(F_BIB); break; } /* allow user to input strings across newlines */ if( c == 0 ) { *tp++ = ' '; while(cp = mif_getc(F_BIB)) if( !isspace(*cp)) { mif_ungetc(F_BIB); break; } if( !cp ) return( NULL ); continue; } } else { if( isspace(c) || c == 0) { if( tp == token ) continue; else break; } /* special cases */ if( isbibdelimeter(c) ) { if( tp != token ) mif_ungetc(F_BIB); else *tp++ = c; break; } } *tp++ = c; } *tp = 0; return( token ); } static isbibdelimeter(c) char c; { /* bibligraphy token delimeters */ static char bibdelims[] = { '{', '}', '(', ')', '[', ']', '"', '<', '>', ',', '@', '=', 0 }; register char *cp; for(cp=bibdelims; *cp; cp++ ) if( *cp == c ) return( *cp ); return( 0 ); } /********* * parse/state routines ********/ static f_begin() { return( S_GETREC ); } static f_getrec() { char lcase[MAXLINE]; RefType rtype; while( 1 ) { lp = bib_gettok(0); if( !lp ) return (S_END); if( tokeq(lp, BIB_AT )) { lp = bib_gettok(0); if(( rtype = reftype(lp)) >= 0 ) { crrnt_reftype = (RefType)rtype; return( S_GETRECBODY ); } else { /* @string or @include macros */ strtolower( lcase, lp ); if( streq( lcase, "string" )) return(S_GETDEFINE); else if( streq( lcase, "include" )) return(S_INCLUDE); } } } } static f_getrecbody() { while( 1 ) { lp = bib_gettok(0); if( !lp ) { err( WARN,"%s: syntax, line %d\n", mif_filename(F_BIB), mif_lineno(F_BIB) ); return (S_END); } /* if open brace, define closing brace */ if( closerec = get_opp_brace(lp) ) return( S_GETXREF ); lp++; } } static f_getxref() { char lcase[256]; lp = bib_gettok(0); if( !lp || tokeq( lp, *closerec)) { err( WARN,"%s: syntax, line %d\n", mif_filename(F_BIB), mif_lineno(F_BIB) ); if( !lp ) return (S_END); return( S_GETREC ); } /* See if this key was used in any of the * .mif documents being read. If not, we don't * need this reference. Remember, these keys are * case insensitive. */ strtoupper( lcase, lp ); if( verify ) store_xrefkey( lcase ); if( !(bep = find_bibent(lcase))) { return( S_GETREC ); } bep->be_reftype = crrnt_reftype; /* if this key has been entered multiple times in * bibliographies, only accept the first instance. */ if (bep->be_found) { if( verbose || verify ) err( WARN,"Multiple entries for <%s> found in bib dbase, using first.\n", lp); return( S_GETREC ); } bep->be_found = 1; return( S_GETFIELDSEP ); } static f_getfield_sep() { while( 1 ) { lp = bib_gettok(0); if( !lp ) { err( WARN,"%s: expecting end of record, line %d\n", mif_filename(F_BIB), mif_lineno(F_BIB) ); return (S_END); } if( tokeq( lp, *closerec )) return( S_ENDREC ); if( tokeq( lp, BIB_FIELDSEP )) return( S_GETFIELD ); } } static f_getfield() { FldType ftype; char *value, *get_fldval(); lp = bib_gettok(0); if( !lp ) { err( WARN,"%s: syntax, line %d\n", mif_filename(F_BIB), mif_lineno(F_BIB) ); } if( tokeq( lp, *closerec )) return( S_ENDREC ); if(( ftype = fldtype(lp)) < 0 ) { if( verbose || verify ) err( WARN, "%s: illegal field name (%s), line %d\n", mif_filename(F_BIB), lp, mif_lineno(F_BIB)); /* eat the '=' */ if( !(lp = bib_gettok(0))) { err( WARN,"%s: syntax, line %d\n", mif_filename(F_BIB), mif_lineno(F_BIB) ); return( S_END ); } if( !get_fldval() ) /* eat the value */ return( S_END ); return( S_GETFIELDSEP ); } /* eat the '=' */ lp = bib_gettok(0); if( !lp ) { err( WARN,"%s: syntax, line %d\n", mif_filename(F_BIB), mif_lineno(F_BIB) ); } if( ! tokeq( lp, BIB_EQUALS)) { err( WARN,"%s: field=<%s>, expected '=', got (%s), line %d\n", mif_filename(F_BIB), fldname(ftype), lp, mif_lineno(F_BIB) ); if( tokeq( lp, BIB_FIELDSEP) ) return( S_GETFIELD ); return( S_GETFIELDSEP ); } /* get the field value */ if( !(value = get_fldval())) return( S_END ); store_bibfield( bep, ftype, value ); return( S_GETFIELDSEP ); } /* reached end of a Bib record. */ static f_endrec() { /* enter this bibent into sorted list. */ sort_bibent(bep); if( verify ) verify_bibent( bep ); return( S_GETREC ); } /* read @string macro, include the definition. * note: these can be read in from either the bibliography database, * or the .style files. since the bibliography db's are read in first, * these will take precedence if duplicate keys are found. */ f_getdefine() { register char *lp; char *endval; char key[256]; /* get open brace */ lp = bib_gettok(0); if( !lp ) { err( WARN,"%s: syntax error, line %d\n", mif_filename(F_BIB), mif_lineno(F_BIB) ); return( S_GETREC ); } if( !(endval = get_opp_brace( lp ))) { err( WARN,"%s: expecting open brace, line %d\n", mif_filename(F_BIB), mif_lineno(F_BIB) ); return( S_GETREC ); } /* get key */ lp = bib_gettok(0); if( !lp ) { err( WARN,"%s: syntax error, line %d\n", mif_filename(F_BIB), mif_lineno(F_BIB) ); return( S_GETREC ); } strcpy(key, lp ); /* get to string */ while( lp = bib_gettok(0)) { if( !lp ) { err( WARN,"%s: syntax error, line %d\n", mif_filename(F_BIB), mif_lineno(F_BIB) ); return( S_GETREC ); } if( tokeq( lp, '"' )) break; if( tokeq( lp, *endval )) { err( WARN,"%s: syntax error, line %d\n", mif_filename(F_BIB), mif_lineno(F_BIB) ); return( S_GETREC ); } } /* get quoted string */ if( !(lp = bib_gettok("\""))) { err( WARN,"%s: unterminated quoted string, line %d\n", mif_filename(F_BIB), mif_lineno(F_BIB) ); return( S_GETREC ); } /* store it away. */ store_bibdef( key, lp ); /* go on with your life. */ return( S_GETREC ); } /* process @include macros. * Correct syntax should be: * @include[file.name] * if file.name is relative, it searches the directories specified * for the bibliography files, and the current directory. The brackets * can also be curely braces or parens. */ f_include() { register char *lp; char *endval; char include_file[256]; char *resolve_include_file(); char *include_path; /* get open brace */ lp = bib_gettok(0); if( !lp ) { err( WARN,"%s: syntax error, line %d\n", mif_filename(F_BIB), mif_lineno(F_BIB) ); return( S_GETREC ); } if( !(endval = get_opp_brace( lp ))) { err( WARN,"%s: expecting open brace, line %d\n", mif_filename(F_BIB), mif_lineno(F_BIB) ); return( S_GETREC ); } /* get include_file */ lp = bib_gettok(0); if( !lp ) { err( WARN,"%s: syntax error, line %d\n", mif_filename(F_BIB), mif_lineno(F_BIB) ); return( S_GETREC ); } if( tokeq( lp, '"' )) { lp = bib_gettok(0); if( !lp ) { err( WARN,"%s: syntax error, line %d\n", mif_filename(F_BIB), mif_lineno(F_BIB) ); return( S_GETREC ); } } strcpy(include_file, lp ); if( !(include_path = resolve_include_file(include_file)) ) { err( WARN, "Cannot find include file: <%s>\n", include_file ); return( S_GETREC ); } /* push the current F_BIB stream onto a stack, * and replace it w/ the current include file. */ if( ! mif_push_readcontext(F_BIB)) { err( WARN, "Can't open <%s>, too many nested include files\n", include_path ); return( S_GETREC ); } /* replace it w/ the current include file */ bib_process(include_path); /* put the previous entity being read back as the * current input. */ if( ! mif_pop_readcontext(F_BIB)) { err( WARN, "Corrupted streams stack ptr!!\n" ); return( S_GETREC ); } return( S_GETREC ); } /* try to locate relative filename */ char * resolve_include_file( fname ) char *fname; { register i; static char pathname[256]; if( ! (fname && *fname )) return( NULL ); if( *fname == '/' ) return( fname ); /* try current directory first */ if( access( fname, R_OK ) == 0) return( fname ); for(i=0; bibdirs[i]; i++ ) { /* these should all end in '/' */ strcpy( pathname, bibdirs[i] ); strcat( pathname, fname ); if( access( pathname, R_OK ) == 0) return( pathname ); } return( NULL ); } static char * get_fldval() { register char *lp; register char *endval; register char *def; /* get open quote (possibly) */ lp = bib_gettok(0); if( !lp ) { err( WARN,"%s: expecting field value, line %d\n", mif_filename(F_BIB), mif_lineno(F_BIB) ); return( (char *)0 ); } if( endval = get_opp_brace( lp )) { /* get quoted string */ if( !(lp = bib_gettok(endval))) { err( WARN,"%s: unterminated (or empty) quoted string, line %d\n", mif_filename(F_BIB), mif_lineno(F_BIB) ); return( (char *)0 ); } } else /* if not a quoted string, it may be an expandable macro def */ if( def = find_bibdef( lp )) lp = def; return( lp ); } char * get_opp_brace(lp) register char *lp; { static char *openbr[] = {"\"", "{", "[", "<", "(", 0 }; static char *closebr[] = {"\"", "}", "]", ">",")", 0 }; register i; for(i=0; openbr[i]; i++ ) if( tokeq( lp, *openbr[i] )) return(closebr[i]); return( NULL ); } /* return fldtype (index into reffields[]) if it * exists, otherwise return -1. NOTE: this depends * on reffields being sorted in alphanumeric order. */ FldType fldtype( lp ) char *lp; { register int i; register char *cp; int cmp; char lcase[128]; strtolower( lcase, lp ); for(i=0; cp = reffields[i]; i++ ) { if( (cmp = strcmp( lcase, cp )) == 0) return( (FldType) i ); if( cmp < 0 ) break; } return((FldType) -1); } char * fldname( n ) register FldType n; { return( reffields[n] ); } char * refname( n ) register RefType n; { return( reftypes[n] ); } /* return reftype (index into reftypes[]) if it * exists, otherwise return -1. NOTE: this depends * on reftypes[] being sorted in alphanumeric order. */ RefType reftype( lp ) char *lp; { register int i; register char *cp; int cmp; char lcase[128]; strtolower( lcase, lp ); for(i=0; cp = reftypes[i]; i++ ) { if((cmp = strcmp( lcase, cp )) == 0) return( (RefType) i ); if( cmp < 0 ) break; } return((RefType)-1); } /* change all chars from src to lower case * and place in pre-allocated memory location dst. */ strtolower( dst, src ) register char *dst; register char *src; { for( ; *src; src++, dst++ ) *dst = isupper( *src ) ? tolower(*src) : *src; *dst=0; } /* change all chars from src to upper case * and place in pre-allocated memory location dst. */ strtoupper( dst, src ) register char *dst; register char *src; { for( ; *src; src++, dst++ ) *dst = islower( *src ) ? toupper(*src) : *src; *dst=0; } /* routine for qsort */ strsort( s1, s2 ) register char **s1, **s2; { return( strcmp(*s1, *s2) ); } print_valid_pubtypes() { register char **cp; register n; printf( "\nValid Pulication Types:\n"); for( n=0, cp=reftypes; *cp; cp++ ) { if( n == 0 ) printf( "\t" ); printf( "%s ", *cp ); n++; if( n>5 ) { printf("\n" ); n=0; } } printf("\n"); } print_valid_fields() { register char **cp; register n; printf( "\nValid Reference Fields:\n"); for( n=0, cp=reffields; *cp; cp++ ) { if( n == 0 ) printf( "\t" ); printf( "%s ", *cp ); n++; if( n>5 ) { printf("\n" ); n=0; } } printf("\n"); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.