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.