ftp.nice.ch/pub/next/text/framemaker/fmbib.1.3.s.tar.gz#/mifparse.c

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.