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.