This is mifparse.c in view mode; [Download] [Up]
/* mifparse.c * cm, 17 Dec 90 * * parser module for miftobib program. * entry points: * mif_parse(): main engine to parse entire file, extracting Bib markers. * * HISTORY * 29 May 92, neek: added bibdirs[] for @include support for relative 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> #define VAR_BIBFILES "BibFiles" #define VAR_BIBFORMAT "BibStyle" #define BF_NOTBIBXREF -1 #define BF_BIBXREF 0 #define BF_FIRSTBIBXREF 1 #define BF_NEXTBIBXREF 2 #define BF_LASTBIBXREF 3 char *BibVars[] = { VAR_BIBFILES, VAR_BIBFORMAT, 0 }; char *rindex(); char *linestart(); char *end_statement(); /* bibliography database files specified by user in * Frame variable "BibFiles" */ extern char *bibfiles[]; /* pathnames of bib files*/ extern char *bibdirs[]; /* dir names of bib files*/ extern char *bibstyle; /* format to be used, ie 'cacm', etc. */ static char tmpbuf[1024]; /* buffer a mif statement here. */ /* parse mif input stream, look for Bib Markers, * remove any existing Xrefs associated w/ this marker, * insert new Xref Bibliography statements. * we take pains here to recognize 'adjacent' bib markers in * the input stream, so as to be able to output the citations * as either [1][2] or [1,2], depending on how the user * specifies their First Bibliographic, Next Bibliographic, * Last Bibliographic, and Bibliographic Reference formats * in frame. */ mif_parse(bibfile) char *bibfile; { char line[512]; short adjmarkers; /* count of adjacent bib markers found. */ static char prevkey[256], *curkey; char *isbibmarker(); /* make sure this is a MIF file. */ mif_gets(F_MIF, line); if( !linestart( line, "<MIFFile " )) err( FATAL, "<%s> is not a legal .mif file\n", mif_filename(F_MIF)); mif_writeln( O_TMP, line ); /* write MIF identifier line. */ /* get to the variables, the first point * of interest. */ while( mif_gets(F_MIF, line) ) { mif_writeln( O_TMP, line ); if( linestart( line, "<VariableFormats " )) { proc_variables(); break; } } /* next test to make sure there are Bibliography * Xref formats. */ while( mif_gets(F_MIF, line)) { mif_writeln( O_TMP, line ); if( linestart( line, "<XRefFormats " )) { proc_xrefformats(); break; } } if( !line ) err( FATAL, "No TextFlow statements in %s\n", mif_filename(F_MIF) ); /* get down to TextFlow statement where * the action is. */ while( mif_gets(F_MIF, line) ) { mif_writeln( O_TMP, line ); if( linestart( line, "<TextFlow " )) break; } if( !line ) err( FATAL, "No TexFlow statements in %s\n", mif_filename(F_MIF) ); /* now the fun part, * search for Bib Markers & Xrefs in the rest of the file. * detect adjacent Bib markers so as to format w/ commas if * need be. */ adjmarkers = 0; curkey = NULL; prevkey[0] = 0; while(mif_gets(F_MIF, line)) { if( linestart( line, "<Marker " )) { curkey = isbibmarker(); if( curkey ) { adjmarkers++; if( prevkey[0] ) output_bibxref(bibfile, prevkey, adjmarkers, 0); strcpy(prevkey,curkey); } else { if( prevkey[0] ) output_bibxref(bibfile, prevkey, adjmarkers, 1); prevkey[0] = 0; adjmarkers=0; } mif_writeln( O_TMP, line ); mif_writeln(O_TMP, tmpbuf); } else if( linestart( line, "<XRef " ) ) { if( isbibxref() == BF_NOTBIBXREF ) { if( prevkey[0] ) { output_bibxref(bibfile, prevkey, adjmarkers, 1); prevkey[0] = 0; adjmarkers=0; } mif_writeln( O_TMP, line ); mif_writeln(O_TMP, tmpbuf); } } else { if( prevkey[0] ) { output_bibxref(bibfile, prevkey, adjmarkers, 1); prevkey[0] = 0; adjmarkers=0; } mif_writeln( O_TMP, line ); } } return(1); } /* insert bibliography Xref statement into output stream. * The type of bib xref statement reflects whether it * is immediately adjacent to other bibliography markers. */ output_bibxref( bibfile, markerkey, adjacent, final ) char *bibfile; char *markerkey; register short adjacent; short final; { char buf[256]; register char *mtype; char lcase[128]; if( final ) { if( adjacent > 1 ) mtype = MIF_LASTBIBXREF; else mtype = MIF_BIBXREF; } else { if( adjacent > 2 ) mtype = MIF_NEXTBIBXREF; else mtype = MIF_FIRSTBIBXREF; } mif_writeln(O_TMP, " <XRef " ); sprintf( buf, " <XRefName `%s'>", mtype); mif_writeln( O_TMP, buf ); strtoupper( lcase, markerkey ); sprintf( buf, " <XRefSrcText `%s'>", lcase); mif_writeln( O_TMP, buf ); sprintf( buf, " <XRefSrcFile `%s'>", bibfile); mif_writeln( O_TMP, buf ); mif_writeln( O_TMP, " > # end of XRef" ); mif_writeln( O_TMP, " <XRefEnd >" ); } /* get next token from line read in mif file * return NULL at end of line. */ static char * mif_gettok(lp) char **lp; { static char token[128]; register char *cp, *tp; register char c; unsigned char done; tp = token; for( done=0, cp = *lp; !done; ) { c = *cp++; if( c == 0 || c == '#' ) if( tp == token ) return( NULL ); /* eof */ else break; if( isalnum(c) ) { *tp++ = c; continue; } if( isspace(c) ) if( tp == token ) continue; else break; /* quoted string ? return entire string. */ if( (c == '`') && (tp == token) ) { while( *cp ) { if( *cp == '\'' ) { cp++; break; } if( *cp != '\\' ) *tp++ = *cp; cp++; } break; } /* special cases */ switch(c) { case '<': case '>': if( tp == token ) *tp++ = c; else cp--; done++; break; default: *tp++ = c; break; } } *tp = 0; *lp = cp; /* return current place in line. */ return( token ); /* and the token retrieved */ } /* process Xref's found in mif file, see if Bibliographic Reference. * buffer the entire Xref statement, because if it is * a bib reference that was generated earlier by this program, * we will exclude it. */ isbibxref() { register char *tok; char line[512]; register char *tp=tmpbuf; char *lp; int rval=0; while( mif_gets(F_MIF, line)) { strcpy(tp, line); tp+=strlen(line); *tp++ = '\n'; if( lp=linestart( line, "<XRefName " )) break; } tok = mif_gettok(&lp); rval = xreftype( tok ); /* pass by the rest of the Bib Xref */ while(mif_gets(F_MIF, line)) { if( rval == BF_NOTBIBXREF) { strcpy(tp, line); tp+=strlen(line); *tp++ = '\n'; } if(linestart( line, "<XRefEnd " )) break; } *--tp = 0; return(rval); } static xreftype(tok) register char *tok; { int rval; register char *cp; /* "(First|Last|Next) Bibliographic Reference" */ if( (cp = rindex(tok, 'B')) && streq( cp, MIF_BIBXREF )) { /* return the type of Bibliographic Ref */ if( cp == tok ) rval = BF_BIBXREF; else if( *tok == 'F' ) rval = BF_FIRSTBIBXREF; else if( *tok == 'N' ) rval = BF_NEXTBIBXREF; else if( *tok == 'L' ) rval = BF_LASTBIBXREF; else rval = BF_NOTBIBXREF; } else rval = BF_NOTBIBXREF; return(rval); } /* process mif variables, searching for relevant * Bibliography settings: * BibFiles filename,filename,... * BibStyle fcacm * and continue to write whate is read to tmpfile */ static proc_variables() { register char *tok; char line[512]; char *lp; int bibvar = -1; /* type of Bib variable */ short depth=1; static char style[128]; while((depth>0) && mif_gets(F_MIF, line)) { mif_writeln( O_TMP, line ); lp=line; if( linestart( line, "<VariableFormat " )) depth++; else if( lp = linestart( line, "<VariableName " )) { tok = mif_gettok(&lp); bibvar = isbibvar( tok ); } else if( lp = linestart( line, "<VariableDef " )) { tok = mif_gettok(&lp); if( bibvar == BV_BIBFILES ) parse_bibfiles(tok); else if( bibvar == BV_BIBFORMAT ) { if( !bibstyle ) { strcpy(style, tok); bibstyle = tok; } } bibvar = -1; } else if( linestart( line, "> " )) depth--; } init_bibstyle( bibstyle ); } /* process XRefFormats section of input file. * look for "{First,Next,Last,} Bibliographic Reference" * format statements. Delete the current ones if there, and * add new ones. */ static proc_xrefformats() { char line[256]; int depth=1; while(mif_gets(F_MIF, line)) { if( linestart( line, "> " )) /* "> # end of XRefFormats" */ break; if( linestart( line, "<XRefFormat " )) if(isbibxrefformat() == BF_NOTBIBXREF ) { /* if not a bibliography format, write it. */ mif_writeln( O_TMP, line ); mif_writeln( O_TMP, tmpbuf ); } } /* write out the correct bibliography formats. */ create_xrefformats(); mif_writeln( O_TMP, line ); /* > # end of XRefFormats */ } /* argify a (possibly) comma separated list * of filenames, merge into bibfiles[] array. * While we're here, also enter the list of directories * these files are from, in separate list, for searching * any @include files specified as relative file names in * the bibliographies. */ static parse_bibfiles( filelist ) register char *filelist; { register char *cp, *slash; register char **bfp, **bdp; int done; if( ! *filelist ) return; for(cp=filelist, done=0; !done; cp++ ) { if( *cp == 0 ) done++; if( *cp==',' || *cp == 0) { *cp=0; for( bfp=bibfiles, bdp=bibdirs; *bfp; bfp++, bdp++ ) if( streq( filelist, *bfp )) break; if( !*bfp ) { if( access( filelist, R_OK ) < 0) err( FATAL, "Cannot access bibfile <%s> to read\n", filelist ); *bfp = getmem( strlen( filelist ) + 1 ); *bdp = getmem( strlen( filelist ) + 1 ); strcpy( *bfp, filelist ); strcpy( *bdp, filelist ); if( slash = rindex( *bdp, '/' ) ) *(slash+1) = 0; filelist = cp+1; } } } } /* determine if the current variable name is * anything we're intersted in. */ int isbibvar( var ) register char *var; { register i; for( i=0; BibVars[i]; i++ ) if( streq( BibVars[i], var )) return( i ); return( -1 ); } /* process a marker statement * syntax: * <Marker * <MType N> * <MText string> * > * we've already read the '<Marker' line. */ static char * isbibmarker() { register char *tok; char line[512]; char *lp; static char text[256]; char *tp; int marker_type=0; char mtype, mtext; int depth=1; mtype = mtext = 0; tp = tmpbuf; while( !(mtype && mtext) && (depth>0) && mif_gets(F_MIF,line)) { strcpy(tp, line); tp+=strlen(line); *tp++ = '\n'; lp = line; while( (depth>0) && (tok = mif_gettok(&lp))) { if( tokeq( tok, '#')) break; if( tokeq(tok,'<')) depth++; else if( tokeq( tok, '>' )) depth--; else if( streq( tok, "MType" )) { tok = mif_gettok(&lp); marker_type = atoi( tok ); if( marker_type != bib_markertype ) { tp = end_statement(tp); return(NULL); } mtype++; } else if( mtype && streq( tok, "MText" )) { if( tok = mif_gettok(&lp)) { if( !*tok ) /* no text in bib marker */ { err( WARN, "%s: Bib Marker Text incomplete, line %d\n", mif_filename(F_MIF), mif_lineno(F_MIF)); tp = end_statement(tp); return(NULL); } strcpy( text, tok ); mtext++; } } /* don't need MCurrPage... */ } } /* get to close of Marker if not there already. */ if( depth>0 ) tp = end_statement(tp); if( !(mtext && mtype )) { err( WARN, "%s: Bib Marker statement incomplete, line %d\n", mif_filename(F_MIF), mif_lineno(F_MIF)); return(NULL); } store_xrefkey( text ); return( text ); } /* buffer an xref format statement in tmpbuf * return whether its a bibxref format or not. */ isbibxrefformat() { register char *tok; char line[512]; char *lp; char *tp; int rval = BF_NOTBIBXREF; tp = tmpbuf; while( mif_gets(F_MIF,line)) { strcpy(tp, line); tp+=strlen(line); *tp++ = '\n'; if( linestart( line, "> " )) break; if( lp = linestart( line, "<XRefName " )) { tok = mif_gettok(&lp); rval = xreftype(tok); } } *--tp = 0; return(rval); } /* get to closing bracket of current statement. * buffer what is read w/ newlines to tp. */ static char * end_statement(tp) register char *tp; { char line[512]; while( mif_gets(F_MIF,line)) { strcpy(tp, line); tp+=strlen(line); *tp++ = '\n'; if( linestart( line, "> " )) break; } *(tp-1) = 0; return( tp ); } /* if pat matches the first token of line, * return a pointer to the byte past pat in line, * else return NULL. */ char * linestart(line, pat) register char *line; register char *pat; { int n = strlen(pat); while( *line && isspace( *line )) line++; if( strneq( line, pat, n)) return( line+n ); return( NULL ); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.