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

This is ref.c in view mode; [Download] [Up]

/* ref.c
 * cm, 10 jan 90
 * Frame bibliography module which reads in the 
 * desired bibliography style definition file, parses it into 
 * execution trees, and the functions to execute the tree when parsing the
 * actual bibliography to produce mif output from the bib data found.
 */

/*
 * 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>
#include <ref.h>
	

#define True	1
#define False 	0

/* note: the following States should correspond to
 * their indeces into the funcs[] table below
 */
#define R_END			-1
#define R_BEGIN			0
#define R_GETREC 		1
#define R_GETRECBODY		2
#define R_GETFIELD		3
#define R_GETFIELDVAL		4
#define R_GETFIELDSEP		5
#define R_ENDFIELD		6
#define R_ENDREC		7
#define R_GETDEFINE		8
#define R_GETMANDATORY		9
#define R_GETOPTIONAL		10

/* field flow control tokens */
#define C_IF	1		/* @if */
#define C_ELSE  2		/* @else */
#define C_ELIF	3		/* @elif */
#define C_ENDIF 4		/* @endif */
#define C_CMD	5		/* @i, @b, @n, etc */
#define C_NONE	6		/* illegal syntax */

#define R_OPENPAREN		'('
#define R_CLOSEPAREN		')'


extern char *reftypes[];
extern char *bibstyle;
extern int  new_para;
int	f_getdefine();

static int	r_begin(), r_getrec(), r_getrecbody(),
		r_getfield(), r_getfieldval(), r_getfieldsep(), 
		r_endfield(), r_endrec(), r_getdefine(), r_getmandatory(),
		r_getoptional();

static int	(*funcs[])() =
{
	r_begin,
	r_getrec,
	r_getrecbody,
	r_getfield,
	r_getfieldval,
	r_getfieldsep,
	r_endfield,
	r_endrec,
	r_getdefine,
	r_getmandatory,
	r_getoptional,
};

/* execution tree routines */
int rf_test();		/* test whether specified field present in bib ent */
int rf_prtfield();	/* output the contents of the specified bib field */
int rf_prtlit();	/* output the specified literal chars. */
int rf_chfont();	/* output change font command. */
int rf_newline();	/* output line break */
int rf_true();		/* pass-thru function, always true */


/* static globals */
static RefEnt *rep;	/* -> current reference style */
static ExecEnt *exroot;	/* current head of field exec tree */

static char *lp;	/* current place in current input line */
static char token[1024]; /* build current token here. */
static char buf[1024];
static char pgfstarted; 

char *font_statement();


/* return 1 on success, 0 on failure 
 */
ref_parse()
{
	register int state;
	char	name[256];
	char	orig[256];
	
	sprintf( name, "%s/%s.style", fmbibdir,  bibstyle );
	strcpy( orig, name );
	
	if( access(name, R_OK )  == -1 )
	{
	    sprintf(name, "%s/%s.style", FMCONTRIBDIR, bibstyle);
	    if( access( name, R_OK )  == -1 )
	    {
	        sprintf(name, "%s/%s", fmbibdir, FMBIBSTYLEFILE );
	        if( access( name, R_OK )  == -1 )
			{
	           sprintf(name, "%s/%s", FMCONTRIBDIR, FMBIBSTYLEFILE );
	           if( access( name, R_OK )  == -1 )
					err(FATAL, "Can't find usable %s file.\n", 
						name );
			}
	    }
	}	

	if( ! mif_open( F_REF, name ))
		err( FATAL, "Can't open %s.\n", name );
	else if( strcmp( name, orig ))
		err( WARN, "Using %s as MIF style file.\n", name );
	
	state = R_BEGIN;

	while( state != R_END )
	{
		state = funcs[state]();
	}
	mif_close( F_REF );
	return(1);
}



/* get next token from 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  refdelimeters)
 */
static char *
ref_gettok(delim)
	register char *delim;
{
	register char	c;
	register char *cp, *tp;

	tp = token;

	while(1)
	{	
		if( ! (cp = mif_getc(F_REF)) )
			if( tp == token )
				return( NULL );		/* eof */
			else
				break;

		c = *cp;

		if( delim )
		{
			if(c == *delim )
			{
				if( tp == token )
					return( NULL );
				mif_ungetc(F_REF);
				break;
			}
			if( c == '\\' )	/* esc. quote */
			{
				if( ! (cp = mif_getc(F_REF)) )
					return( NULL );		/* eof */
				else
				{
					*tp++ = *cp;
					continue;
				}
			}	
		}
		else
		{
			/* check for comments, if found, eat to eol */
			if( c == '#' )
			{
				while( cp = mif_getc(F_REF) )
					if( ! *cp )
						break;	
				if( tp == token ) 
				{
					if( !cp ) 
						return(NULL);
					else
						continue;
				}
				break;
			}
			if( isspace(c) || c == 0)
			{
				if( tp == token )
					continue;
				else
					break;
			}
	
			/* special cases */
			if( isrefdelimeter(c) )
			{
				if( tp != token )
					mif_ungetc(F_REF);
				else
					*tp++ = c;
				break;
			}
		}
		*tp++ = c;
	}
	*tp = 0;
	return( token );
}


			
static 
isrefdelimeter(c)
	char c;
{
	/* refstyle token delimeters */
	static char refdelims[] = {
			'{', '}', '(', ')', '"', '<', '>', ',', '@', '=', '|', 0,
	};
	register char *cp; 

	for(cp=refdelims; *cp; cp++ )
		if( *cp == c )
			return( *cp );

	return( 0 );
}


/*********
 * parse/state routines
 ********/

static
r_begin()
{
	return( R_GETREC );	
}

static
r_getrec()
{
	RefType	rtype;
	char lcase[256];

	while( 1 )
	{
		lp = ref_gettok(0);
		if( !lp ) 
			return (R_END);
		if( tokeq(lp, '@') )
		{
			lp = ref_gettok(0);
			if(( rtype = reftype(lp)) >= 0 )
			{
				rep = new_refent();
				rep->re_type = rtype;
				return( R_GETRECBODY );
			}	
			else
			{	/* @string macros */
				strtolower( lcase, lp );
				if( streq( lcase, "string" ))
					return(R_GETDEFINE);
			}
		}
	}
}


static
r_getrecbody()
{
	lp = ref_gettok(0);
	if( !lp ) 
	{
		err( WARN,"%s: syntax, line %d\n", 
			mif_filename(F_REF), mif_lineno(F_REF) );
		return (R_END);
	}

	if( !tokeq( lp, R_OPENPAREN))
		err( WARN,"%s: expecting '{', line %d\n", 
			mif_filename(F_REF), mif_lineno(F_REF) );
	return( R_GETFIELD );
}


static
r_getfield()
{

	lp =  ref_gettok(0);

	if( !lp ) 
	{
		err( WARN,"%s: syntax, line %d\n", 
			mif_filename(F_REF), mif_lineno(F_REF) );
		return( R_ENDREC );
	}

	if( tokeq( lp, R_CLOSEPAREN ))
		return( R_ENDREC );

	/* look for @mandatory or @optional directives */
	if( tokeq( lp, '@' ))
	{
		if( !(lp =  ref_gettok(0)))
		{
			err( WARN,"%s: syntax, line %d\n", 
				mif_filename(F_REF), mif_lineno(F_REF) );
			return( R_ENDREC );
		}
		if( streq( lp, "mandatory" ))
			return( R_GETMANDATORY );
		else if( streq( lp, "optional" ))
			return( R_GETOPTIONAL );
		else
		{
			err( WARN, "%s: illegal field name (%s), line %d\n",
				mif_filename(F_REF), lp, mif_lineno(F_REF));
			return( R_GETFIELDSEP );
		}
	}

	/* create root of new exectree */
	exroot = new_execent();

	if( tokeq( lp, '*' ))	/* non-field, forces execution on 'true' */
	{
		exroot->ex_func = rf_true;
		exroot->ex_arg =  (char *)1;
	}
	else
	{
		if((int)(exroot->ex_arg = (char *) fldtype(lp)) < 0 )
		{
			err( WARN, "%s: illegal field name (%s), line %d\n",
				mif_filename(F_REF), lp, mif_lineno(F_REF));
			free( exroot );
			return( R_GETFIELDSEP );
		}
		exroot->ex_func = rf_test;
	}
	return( R_GETFIELDVAL );
}


#define FS_PARSE	0
#define FS_DONE		1
static int		depth;
static char		fldstate;


static
r_getfieldval()
{

	/* start recursive function to parse and insert
	 * fields into the current exectree.
	 */
	depth=0;
	fldstate = FS_PARSE;
	return( do_exectree( exroot, True ));
}
	

static
do_exectree( exp, tf )
	register ExecEnt *exp;		/* root of current exectree */
	int	tf;			/* insert as a  true or false subtree */
{
	
	register ExecEnt *newp, *np;
	short	first=True;
	register ExecEnt **insertp;

	np = exp;

	while( 1 )
	{
		if( fldstate == FS_DONE )
			return( R_ENDFIELD);

		lp =  ref_gettok(0);

		if( !lp ) 
		{
			err( WARN,"%s: no end of record, line %d\n", 
				mif_filename(F_REF), mif_lineno(F_REF) );
			return( R_END );
		}

		if( tokeq( lp, ',' ))
		{
			if( depth )
			{
				err( WARN,"%s: unexpected end of field, line %d\n", 
					mif_filename(F_REF), mif_lineno(F_REF) );
				depth=0;
			}
			fldstate = FS_DONE;
			return( R_ENDFIELD );
		}
		else if( tokeq( lp, R_CLOSEPAREN ))
		{
			if( depth )
				err( WARN,"%s: unexpected end of field, line %d\n", 
					mif_filename(F_REF), mif_lineno(F_REF) );
			return( R_ENDFIELD );
		}

		/* create new ExecEnt node.*/
		newp = new_execent();

		if( first )	/* insert under t/f */
		{
			first = False;
			insertp = tf ? &(np->ex_true) : &(np->ex_false);
		}
		else	
			insertp = &(np->ex_next);	
		
		if( tokeq( lp, '<' )) 	/* print field contents */
		{
			lp =  ref_gettok(">");
			if( !lp ) 
			{
				err( WARN,"%s: syntax error, line %d\n", 
					mif_filename(F_REF), mif_lineno(F_REF) );
				return( R_END );
			}
			else
			{
				newp->ex_func = rf_prtfield;
				if( tokeq( lp, '@' ) )	/* print the tested field */
					newp->ex_arg = exp->ex_arg;
				else if((int)(newp->ex_arg = (char *) fldtype(lp)) < 0 )
				{
					err( WARN, "%s: illegal field name (%s), line %d\n",
					mif_filename(F_REF), lp, mif_lineno(F_REF));
					return( R_GETFIELDSEP );
				}
				*insertp = newp;
				np = newp;
			}
			/* eat '>' */
			lp = ref_gettok(0);
		}
		else if tokeq( lp, '"' )	/* print literal string */
		{
			lp =  ref_gettok("\"");
			if( !lp ) 
			{
				err( WARN,"%s: syntax error, line %d\n", 
					mif_filename(F_REF), mif_lineno(F_REF) );
				return( R_END );
			}
			else
			{
				newp->ex_func = rf_prtlit;
				newp->ex_arg = getmem( strlen(lp)+1);
				strcpy( newp->ex_arg, lp ); 
				*insertp = newp;
				np = newp;
			}

			/* eat '"' */
			lp = ref_gettok(0);
		}
		else if tokeq( lp, '@' )	/* command */
		{
			lp =  ref_gettok(0);
			if( !lp ) 
			{
				err( WARN,"%s: syntax error, line %d\n", 
					mif_filename(F_REF), mif_lineno(F_REF) );
				return( R_END );
			}
		 	switch( get_atcmd( newp, lp ) ) {

			   case C_CMD:	 /* get_atcmd filled populated newp */
				*insertp = newp;
				np = newp;
				break;

			   case C_IF:
				depth++;
				newp->ex_func = rf_test;
				if( !(lp = ref_gettok(0)))
				{
					err( WARN,"%s: syntax error, line %d\n", 
					   mif_filename(F_REF), mif_lineno(F_REF) );
					return( R_END );
				}
				if((int)(newp->ex_arg = (char *) fldtype(lp)) < 0 )
				{
				   err( WARN, "%s: illegal field name (%s), line %d\n",
					mif_filename(F_REF), lp, mif_lineno(F_REF));
				   return( R_GETFIELDSEP );
				}
				*insertp = newp;
				np = newp;
	
				/* a new 'if' statement means a new 'True' exec
				 * sub-tree under the current node.
				 */
				do_exectree( np, True );
				break;

			   case C_ELIF:
				depth++;
				newp->ex_func = rf_test;
				if( !(lp = ref_gettok(0)))
				{
					err( WARN,"%s: syntax error, line %d\n", 
					   mif_filename(F_REF), mif_lineno(F_REF) );
					return( R_END );
				}
				if((int)(newp->ex_arg = (char *) fldtype(lp)) < 0 )
				{
				   err( WARN, "%s: illegal field name (%s), line %d\n",
					mif_filename(F_REF), lp, mif_lineno(F_REF));
				   return( R_GETFIELDSEP );
				}
				exp->ex_false = newp;
				np = newp;
	
				/* a new 'if' statement means a new 'True' exec
				 * sub-tree under the current root node.
				 */
				do_exectree( np, True );
				break;

			   case C_ELSE:
				/* a new 'else' statement means a new 'False' exec
				 * sub-tree under the root of the current subtree.
				 */
				depth++;
				do_exectree(exp, False );
				break;

			   case C_ENDIF:
				depth--;
				if( depth < 0 )
					err( WARN,"%s: @endif missing @if, line %d\n", 
					   mif_filename(F_REF), mif_lineno(F_REF) );
				/* doesn't matter value of this return, since 
				 * we should be returning to an inner do_exectree().
				 */
				return(R_END);

			   case C_NONE:
				err( WARN,"%s: bad @ command, line %d\n", 
					mif_filename(F_REF), mif_lineno(F_REF) );
				return( R_GETFIELDSEP );
			    } /* switch */
		}
		else		/* unknown token */
			err( WARN, "%s: illegal syntax (%s), line %d\n",
				mif_filename(F_REF), lp, mif_lineno(F_REF));

	}  /* while */
}
	

get_atcmd( np, cp )
	register ExecEnt *np;
	char *cp;
{
	register i;
	static char atcmds[] = { 'i','r','b','u','n', 0 };
	static int (*atfuncs[])() = {
		rf_chfont, rf_chfont, rf_chfont, rf_chfont,
		rf_newline, 0 };
	static  int atargs[] = { F_ITALIC, F_REGULAR, F_BOLD,
		F_UNDERLINE, 0, 0 };

	if( *(cp+1) == 0 )
	{
	   for( i=0; atcmds[i]; i++ )
		if( atcmds[i] == *cp )
		{
			np->ex_func = atfuncs[i];
			np->ex_arg  = (char *) atargs[i];
			return(C_CMD);
		}
	    return(C_NONE);
	}
	else
	{
		/* try 'if', 'else', 'endif' control structs. */
		if( streq( lp, "if" ))
			return( C_IF );
		else if( streq(  lp, "else" ))
			return( C_ELSE );
		else if( streq(  lp, "elif" ))
			return( C_ELIF );
		else if( streq( lp, "endif" ))
			return( C_ENDIF );
		else
			return( C_NONE );
	}
}


static 
r_getfieldsep()
{
	while( 1 )
	{
		if( !(lp =  ref_gettok(0)))
		{
			err( WARN,"%s: no end of record, line %d\n", 
				mif_filename(F_REF), mif_lineno(F_REF) );
			return( R_END );
		}
		if( tokeq(lp, ',') || tokeq( lp, R_CLOSEPAREN) || (*lp == 0))
			return( R_ENDFIELD );
	}
}


static 
r_getmandatory()
{
	return( get_fldlist(&rep->re_mandatory));	
}

static 
r_getoptional()
{
	return( get_fldlist(&rep->re_optional));	
}

static 
get_fldlist(listp)
	RefFldList **listp;
{
	RefFldList *flp, *altfp;
	FldType	crrntfld;

	if( !(lp =  ref_gettok(0)))
	{
		err( WARN,"%s: no end of record, line %d\n", 
			mif_filename(F_REF), mif_lineno(F_REF) );
		return( R_END );
	}
	if( !tokeq(lp, R_OPENPAREN))
	{
		err( WARN,"%s: expecting %c, line %d\n", 
			mif_filename(F_REF), R_OPENPAREN, mif_lineno(F_REF) );
		return( R_GETFIELDSEP );
	}
		
	*listp = flp = new_fldlist();

	while( 1 )
	{
		if( !(lp =  ref_gettok(0)))
		{
			err( WARN,"%s: no end of record, line %d\n", 
				mif_filename(F_REF), mif_lineno(F_REF) );
			return( R_END );
		}

		if( tokeq( lp, R_CLOSEPAREN ))
			return( R_GETFIELD );

		if( tokeq( lp, ',' ) )
			continue;

		if(tokeq( lp, '|' ))
		{
			REMFLD( flp->fl_flds, crrntfld );	
			altfp = get_altflds( crrntfld );
			insert_altflds( flp, altfp );
			continue;
		}
			
		if((crrntfld = fldtype(lp)) < 0 )
		{
			err( WARN, "%s: illegal field name (%s), line %d\n",
				mif_filename(F_REF), lp, mif_lineno(F_REF));
			continue;
		}
		ADDFLD( flp->fl_flds, crrntfld );
	}
}


static 
RefFldList *
get_altflds( firstfld )
	FldType firstfld;
{
	RefFldList 	*flp;
	FldType		crrntfld;

	flp = new_fldlist();
	ADDFLD( flp->fl_flds, firstfld );
	
	while(1)
	{
		if( !(lp =  ref_gettok(0)))
		{
			err( WARN,"%s: no end of record, line %d\n", 
				mif_filename(F_REF), mif_lineno(F_REF) );
			break;
		}

		if( tokeq( lp, ',') || tokeq( lp, R_CLOSEPAREN ))
			break;

		if(tokeq( lp, '|' ))
			continue;
			
		if((crrntfld = fldtype(lp)) < 0 )
		{
			err( WARN, "%s: illegal field name (%s), line %d\n",
				mif_filename(F_REF), lp, mif_lineno(F_REF));
			continue;
		}
		ADDFLD( flp->fl_flds, crrntfld );
	}
	return( flp );
}
	
		
			

	

	
static
r_endfield()
{
	/* link this field's exectree into ref type */
	store_exectree( rep, exroot );

	return( R_GETFIELD );
}


/* store the record just parsed
 */
static
r_endrec()
{
	store_refent( rep );
	return( R_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.
 */
static
r_getdefine()
{
	register char *lp;
	char *endval;
	char	key[256];

	/* get open brace */
	lp = ref_gettok(0);
	if( !lp ) 
	{
		err( WARN,"%s: syntax error, line %d\n", 
			mif_filename(F_REF), mif_lineno(F_REF) );
		return( R_GETREC );
	}
	if( !(endval = get_opp_brace( lp )))
	{	
		err( WARN,"%s: expecting open brace, line %d\n", 
			mif_filename(F_REF), mif_lineno(F_REF) );
		return( R_GETREC );
	}

	while( !tokeq( lp, *endval ))
	{
		
		/* get key */
		lp = ref_gettok(0);
		if( !lp ) 
		{
		    err( WARN,"%s: syntax error, line %d\n", 
			mif_filename(F_REF), mif_lineno(F_REF) );
		    return( R_GETREC );
		}
		strcpy(key, lp );
	
		/* get to string */
		while( lp = ref_gettok(0))
		{
			if( !lp ) 
			{
			    err( WARN,"%s: syntax error, line %d\n", 
				mif_filename(F_REF), mif_lineno(F_REF) );
			    return( R_GETREC );
			}
			if( tokeq( lp, '"' ))
			    break;
			if( tokeq( lp, *endval ))
			{
			    err( WARN,"%s: syntax error, line %d\n", 
				mif_filename(F_REF), mif_lineno(F_REF) );
			    return( R_GETREC );
			}
		}

		/* get quoted string */
		if( !(lp = ref_gettok("\"")))
		{
		    err( WARN,"%s: unterminated quoted string, line %d\n", 
			mif_filename(F_REF), mif_lineno(F_REF) );
		    return( R_GETREC );
		}
		/* store it away. */
		store_bibdef( key, lp );
	
		lp = ref_gettok(0);	/* close quote */
		lp = ref_gettok(0);	/* either endval or comma  */
	}

	/* go on with your life. */
	return( R_GETREC );
}

/****************
 * execution routines to produce bib output 
 ****************

/* test whether this field exists in the current
 * bibliography entry. return true/false accordingly.
 */
rf_test( ep, bp )
	ExecEnt *ep;
	BibEnt *bp;
{
	register FldType fld =  (FldType)ep->ex_arg;	
	register long rollcall = bp->be_rollcall;

	return( (int) FLDPRESENT(rollcall, fld));
}


/* output the contents of the specified field from 
 * the bibliography reference.
 */
rf_prtfield( ep, bp)
	ExecEnt *ep;
	BibEnt	*bp;
{
	register FldType fld =  (FldType)ep->ex_arg;	
	register long rollcall = bp->be_rollcall;
	register BibField *bf;

	if( !(bf = find_bibfield( bp, fld))) return(1);
	if( new_para )
	{
		mif_pgfbegin( bp );
		new_para = 0;
	}
	mif_string( O_BIB, bf->bf_val );
	return(1);
}

/* output a literal string.
 */
rf_prtlit( ep, bp )
	register ExecEnt *ep;
	BibEnt	*bp;
{
	if( new_para )
	{
		mif_pgfbegin( bp );
		new_para = 0;
	}
	mif_string( O_BIB, ep->ex_arg);
	return(1);
}


/* output change font command. 
 */
rf_chfont( ep, bp )
	register ExecEnt *ep;
	BibEnt	*bp;
{
	if( new_para )
	{
		mif_pgfbegin( bp );
		new_para = 0;
	}
	if( current_font != (short) ep->ex_arg)
		mif_chfont(O_BIB, (short) ep->ex_arg);
	return(1);
}


/* output a line break command.
 */
rf_newline( useless, arg )
{
	mif_linebreak( O_BIB );
	return(1);
}

	
/* function which is always true */
rf_true( useless,  arg )
{
	return(1);
}

/*********************
 * mif output routines
 *********************/

/* output a string as a mif command, replace single quote "'",
 * w/ "\'", and open/close double quotes w/ smartquotes.
 */

mif_string( type, str )
	int	type;
	char 	*str;
{
	static short q_left = 1;	/* keep track of smart quotes. */
	register char *sp, *dp;	
	static short first=1;
	static len;
	static char strbuf[1024];
	static char lastchar = 0;	

	if( !str || !*str)
		return;

	if( first )
	{
		first=0;
		strcpy( strbuf, "      <String `");
		len = strlen(strbuf);
	}

	/* don't mistakenly replicate double punctuation marks
  	 * from string to string.  For example, if authors field
 	 * ends in a period because his bibligraphy uses intials,
	 * placing a period after this field will print a double
	 * period.
	 */ 	
	if( *str == lastchar )
		str++;

	for( sp=str, dp = strbuf+len; *sp; sp++, dp++ )
	{
		if( *sp == '\'' )
			*dp++ = '\\';
		else if( *sp == '"' )
		{
			if(  q_left )
			{
				q_left = 0;
				strcpy( dp, "\\xd2 " );	/* open */
				dp += 4;
			}
			else
			{
				q_left = 1;
				strcpy( dp, "\\xd3 " ); /* close */
				dp += 4;
			}
			continue;
		}
		*dp = *sp;
	}
	for( sp--; isspace(*sp); sp-- )
		;
	lastchar = *sp;

	*dp++ = '\'';
	*dp++ = '>';
	*dp++ = 0;
	mif_writeln( O_BIB, strbuf); 
}


/* output a mif change font cmd. 
 */
mif_chfont( type, font )
	int	type;
	int	font;
{
	sprintf( buf, "      <Font \n%s      > \n",
		font_statement( font ));		
	mif_write( type, buf );
	current_font = font;
}

/* output a mif line break. 
 */
mif_linebreak( type )
{
	/* for now, output space, since frame's doing the formatting.
	 */
	mif_writeln( type, "      <String ` '>");
}

mif_pgfbegin( bep )
	BibEnt *bep;
{
	mif_write(O_BIB, "  <Para \n" );
	prt_tag( bep );	 	/*  <PgfTag .... > */
	mif_write( O_BIB, "    <ParaLine \n" );	
	sprintf( buf, "      <Marker \n       <MType 9> \n       <MText `%s'> \n      > # end of Marker\n",
		bep->be_xref);
	mif_write(O_BIB, buf );

	/* generate the reference string depending on the style */
	prt_refstring(bep);

	pgfstarted=1;	
}


mif_pgfend(bep)
	BibEnt *bep;
{
	/* it is possible that no fields were found present, and
	 * that a paragraph has not been started. If so, just return.
	 */
	if( !pgfstarted ) 
	{
		err( WARN, "No valid bid data to write <%s> cross ref\n",
			bep->be_xref );
		return;
	}
	mif_write( O_BIB, "   > # end of ParaLine\n  > # end of Para \n" );
	pgfstarted=0;
}

mif_beginbibdoc()
{
	char bibtemplate[256];
	char orig[256];
	char 	*bib_templatefile();

	/* copy the correct template for the format of the doc. */
	sprintf(bibtemplate, "%s/%s.tmpl", fmbibdir, bib_templatefile() );
	strcpy( orig, bibtemplate );

	if( access( bibtemplate, R_OK )  == -1 )
	{
	    sprintf(bibtemplate, "%s/%s.tmpl", FMCONTRIBDIR, bib_templatefile() );
	    if( access( bibtemplate, R_OK )  == -1 )
	    {
	        sprintf(bibtemplate, "%s/%s", fmbibdir, FMBIBTEMPLATEFILE );
	        if( access( bibtemplate, R_OK )  == -1 )
		{
	           sprintf(bibtemplate, "%s/%s", FMCONTRIBDIR, FMBIBTEMPLATEFILE );
	           if( access( bibtemplate, R_OK )  == -1 )
			err(FATAL, "Can't find usable bib template (%s)\n", 
					bib_templatefile() );
		}
	    }
	}	
	if( ! copy_bibtemplate(  bibtemplate ) )
	 	err(FATAL, "Could not copy <%s> template\n", bibtemplate );

	if( strcmp(bibtemplate, orig ))
		err( WARN, "Using %s as template file.\n", bibtemplate );

	current_font = F_REGULAR;
}

mif_endbibdoc()
{
	mif_write( O_BIB, "> #end of TextFlow\n# End of MIFfile\n" );
}


/* execute a single exec tree using the field values from
 * the specified bib entry.
 */
exec_tree( root, bep  )
	ExecEnt *root;
	register BibEnt  *bep;	
{
	register ExecEnt *ep;

	if( root == NULL )
		return;

	if(root->ex_func == rf_test)
	{
		if( rf_test(root, bep) )
			ep = root->ex_true;
		else
			ep = root->ex_false;
			
	}
	else if(root->ex_func == rf_true)
	{
		ep = root->ex_true;
	}
	else
	{
		err( WARN,"exec_tree(): corrupted.\n");
		return;
	}

	for( ;ep; ep = ep->ex_next )
	{
		if(ep->ex_func == rf_test)
			exec_tree( ep, bep );
		else
			ep->ex_func( ep, bep );
	}
}


char *
font_statement( n )
{
	static char *fontstat[] = {
 "        <FTag `'>\n        <FAngle `Regular'>\n",
 "        <FTag `Emphasis'>\n        <FAngle `Italic'>\n",
 "        <FTag `Emphasis'>\n        <FAngle `Regular'>\n        <FWeight `Bold'>\n",	
 "        <FTag `Emphasis'>\n        <FAngle `Regular'>\n        <FUnderline Yes>\n",	
 	};
	return(fontstat[n-1]);
}


#ifdef DEBUG

/************
 *  debugging..
 ************/

char *
prt_execent(exp)
	register ExecEnt *exp;
{
	static char ret[128];
	if( exp->ex_func == rf_test )
		sprintf(ret,"TEST( %s )", fldname(exp->ex_arg));
	else if( exp->ex_func == rf_prtfield )
		sprintf(ret,"PRINT_FIELD( %s )", fldname(exp->ex_arg));
	else if( exp->ex_func == rf_prtlit )
		sprintf(ret,"PRINT_LITERAL( %s )", exp->ex_arg);
	else if( exp->ex_func == rf_chfont )
		sprintf(ret,"CHANGE_FONT( %s )", fontname(exp->ex_arg));
	else if( exp->ex_func == rf_newline )
		strcpy( ret, "NEWLINE()");
	else if( exp->ex_func == rf_true )
		strcpy( ret, "ALWAYS()" );
	else
		strcpy( ret, "UNKNOWN_FUNC ???" );

	return( ret );
}

/* generated mif output. modules.
 */
char *
fontname(n)
{
	static char *fonts[] = {
		"Regular", "Italic", "Bold", "Underline" 
	};
	return(fonts[n-1]);
}

#endif DEBUG

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.