File:  [Research Unix] / researchv10no / cmd / prefer / pref / prefer.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:21:35 2018 UTC (8 years, 1 month ago) by root
Branches: belllabs, MAIN
CVS tags: researchv10, HEAD
researchv10 Norman

/*
 * prefer - bibligraphy formatter
 *
 *	Marcia Derr
 *	February 26, 1988
 *
 *	input:	(stdin) text containing prefer commands;
 *	output:	(stdout) text with formatted citations and reference list
 */



#include	<stdio.h>
#include	<ctype.h>
#include	<signal.h>
#include	<sys/types.h>
#include	<sys/stat.h>

#ifdef	SVR2			/* for UNIX System V */ 
#include	<fcntl.h>
#define	dup2(fildes, fildes2) close(fildes2);fcntl(fildes, F_DUPFD, fildes2)
#endif

#include	"streams.h"
#include	"bib.h"


/* prefer commands */
#define		REF_CITE	"reference"
#define		REF_STYLE	"reference_style"
#define		REF_PLACE	"reference_placement"
#define		REF_LIST	"reference_list"
#define		REF_DB		"reference_database"
#define		REF_INCLUDE	"reference_include"

/* control words to awk */
#define		LETS_GO		"%LETS_GO"
#define		BEGIN_CITE	"%BEGIN_CITE"
#define		END_CITE	"%END_CITE"
#define		END_LIST	"%END_LIST"
#define		BIBLIO		"%BIBLIO"
#define		WHOLEBIB	"%WHOLEBIB"
#define		DBINCLUDE	"%DBINCLUDE"
#define		TYPE		"%type"
#define		TWOPASS		"%TWOPASS\n"
#define		ALSO		"%also"
#define		ALSOBEGIN	"%also_begin"
#define		ALSOEND		"%also_end"

#define		DSTYLE		"att"		/* default style */
#define		STYLEDIR	"/styles/"	/* style directory */
#define		AWK		"prefawk"	/* special awk version */

#define		PREFERTMP	"/tmp/preferXXXXXX"
#define		MAXTOK		2500
#define		BAR		'|'
#define		SLASH		"/"


char	stylename[maxstr] = "",		/* set by style(), options */
	awkline[MAXTOK];		/* for passing to/from awk */

FILE	*readtext,		/* input text */
	*writetext,		/* output text */
	*readbib,		/* from awk */
	*writebib,		/* to awk */
	*savefile;		/* save original file when diverting to temp */

int	nroff = 0;		/* nroff/troff flag */
int	prmult = 0;		/* print multiple references */
int	rp = 0;			/* released_paper/tm flag */
int	sort = 0;		/* order flag for reference_list */
char	sortkey[maxstr] = "";	/* sort keys (eg adt) */
int	haveeof = 0;		/* flag eof in input file */

char    INDEX[maxstr];		/* name of index file */
char	*DINPUT = BIBFILE;	/* default input file */
char 	*divertname;		/* two pass output is diverted here */
int	pass = 0;		/* indicates how many text passes are required */

int     argc;
char    **argv;

typedef enum {T_OPEN, T_CLOSE, T_COMMAND, T_REFER, T_WORD, T_EOF} TOKEN;
typedef enum {NORMAL, END, BIBLIST} bibflag;
	enum {OK, NONE}	awkstate = NONE;


char	tok[MAXTOK];			/* for get_token */
TOKEN	type;				/* type returned by get_token */
char	right;				/* expected right delimeter */

int	cleanup();
char	*strchr();
char	*libpath();
TOKEN	get_token();
char	*mktemp(),
	*locate(),
	*gulpnl(),
	*realloc(),
	*strtok();

#define	leftdelim {								\
	if((type = get_token(tok,0)) != T_OPEN) {				\
		token_err(type,"Expecting left delimiter, got %s\n",tok);	\
	}									\
	right = getright(*tok);							\
}

#define	rightdelim {								\
	if (type != T_CLOSE)							\
		token_err(type,"Expecting right delimeter, got %s\n",tok);	\
	post_command();							\
}


#define USAGE	"prefer [-p database -s style -n -o key -r] [filename]\n"

#ifdef	_NFILE
#define	FILENUM	_NFILE
#else
#define	FILENUM	20
#endif



/*
 * main - process prefer command line 
 */

main(argcount,arglist)
int argcount;
char **arglist;
{

/*
 * set up signals, get options flags, and process command line arguments;
 * make path names;  setup I/O
 */	
	if(signal(SIGINT, SIG_IGN) != SIG_IGN)
		signal(SIGINT, cleanup);
	signal(SIGQUIT, cleanup);
	argc= argcount-1;
	argv= arglist+1;

	strcpy(stylename,DSTYLE);
	strcpy(INDEX,DINPUT);

	flags();
	strcat(INDEX,".i");

	switch(argc) {
	case 0:
		readtext = stdin;
		break;
	case 1:
		if((readtext = fopen(*argv,"r")) == NULL)
			errexit(1,"error opening textfile %s\n",*argv);
		break;
	default:
		errexit(1,USAGE);
	}
	writetext = stdout;

/*
 * now filter text for prefer commands
 */
	scan_text();
	exit(0);

}


/*
 * get option flags
 *
 * -n	set nroff flag (default troff)
 * -o	set sort flag for listing entire bibliographies (default sequence)
 * -p	pathname of database file (default BIBFILE)
 * -r	set rp (released paper) flag (default tm)
 * -s	set style (default att)
 */

# define    operand     (strlen(*argv+2)==0 ? (argv++,argc--,*argv) : *argv+2)

flags()
{   
    for (; argc>0 && *argv[0]=='-';  argc--,argv++) {
	switch ((*argv)[1]) {   
	    case 'c':
	    case 'l':	fprintf(stderr,USAGE);
			break;
	case 'm':	prmult = 1;
			break;
	    case 'n':	nroff = 1;
			break;
	    case 'o':	sort = 1;
			strcpy(sortkey,operand);
			break;
            case 'p':   strcpy(INDEX,operand);
                        break;
	    case 'r':	rp = 1;
			break;
	    case 's':	strcpy(stylename,operand);
			break;
            default:    errexit(1, USAGE);
        }
    }
}


/*
 * scan_text
 *
 * filter text for prefer commands (beginning with '|') and pass
 * these off to do_command
 */

scan_text()
{
	register int c, lastc;
	char space[maxstr];

	lastc = 0;
	for(;;) {

	/*
	 * if EOF, put out last saved character and space;
	 * finish processing references; close awk
	 */
		if((c = gobble(space)) == EOF) {
			if(lastc) putc(lastc,writetext);
			lastc = 0;
			if(*space) fputs(space, writetext);
			if(awkstate == OK) {
				biblio(END);
				continue;
			}
			break;
		}

	/*
	 * if a '|' then call do_command to process it
	 */
		if(c == BAR) {

			/* checkfor preceding punctuation */

			if(lastc == 0134 && !*space) {	/* backslash */
				putc(lastc,writetext);
				lastc = c;
				continue;
			}
			if(!ismypunct(lastc)) {
				if(lastc) {
					putc(lastc,writetext);
					lastc = 0;
				}
			}
			do_command(lastc,space);
			lastc = 0;
			continue;
		}

		if(lastc) putc(lastc,writetext);
		if(*space) fputs(space,writetext);
		lastc = c;
	}
	if(awkstate != NONE)
		awkclose(readbib,writebib);
}


/*
 * parse and execute prefer commands:
 *	|reference(...)
 *	|reference_style(..)
 *	|reference_database(...)
 *	|reference_list(...)
 *	|reference_placement
 */

do_command(ppunc,white)
int ppunc;	/* punctuation preceding command */
char *white;	/* white space preceding command */
{
	register  int	cite_list,	/* flag "in a citation list" */
			c;		/* for reading characters */
	char		space[maxstr];	/* gobbled space goes here */

/*
 * '|' has already been read; now read command and dispatch
 */
	cite_list = 0;
	for(;;) {

	/*
	 * if space after BAR; finish citation list put out white space and punc
	 */
		c=gobble(space);
		if(*space) {
			if(cite_list) {
				end_citations(ppunc);
			}
			else {
				if(ppunc) putc(ppunc,writetext);
				if(*white) fputs(white,writetext);
			}
			putc(BAR,writetext);
			fputs(space,writetext);
			if(c != EOF) ungetc(c,readtext);
			return;
		}
	/*
	 * at EOF, put out any citation list
	 */
		if(c == EOF) {
			if(cite_list) {	
				end_citations(ppunc);
				cite_list == 0;
			}
			putc(BAR,writetext);
			return;
		}
		else
			ungetc(c,readtext);
			

	/*
	 * process one or more citations
	 */
		get_token(tok,0);
		if(strcmp(tok,REF_CITE) == 0) {
			*white = NULL;
			citation();
			cite_list = 1;
			if((c = gobble(white)) == BAR)
				continue;
			else if (*white || !ismypunct(c)) {
				end_citations(ppunc);
				if(*white) fputs(white,writetext);
				if(c != EOF) ungetc(c,readtext);
			}
			else {
				if(ppunc) putc(ppunc,writetext);
				end_citations(c);
			}
			return;
		}
	
	/*
	 * end a list of citations or if no citation, put out punctuation
	 * and white space
	 */
		if(cite_list)  end_citations(ppunc);
		else if (ppunc) putc(ppunc,writetext);
		if (*white) {
			fputs(white,writetext);
		}
			

	/*
 	 * process style, placement, list, or db commands
	 */
		if(strcmp(tok,REF_STYLE) == 0) {
			style();
			return;
		}

		else if(strcmp(tok,REF_PLACE) == 0) {
			if(awkstate == OK) biblio(NORMAL);
			if(pass != 2) post_command();
			return;
		}

		else if(strcmp(tok,REF_LIST) == 0) {
			bib_list();
			return;
		}

		else if(strcmp(tok,REF_INCLUDE) == 0) {
			dbinclude();
			return;
		}

		else if(strcmp(tok,REF_DB) == 0) {
			database();
			return;
		}

	/*
	 * no command so, put out bar and token
	 */
		else {
			putc(BAR,writetext);
			fputs(tok,writetext);
			return;
		}
	}

}


/*
 * ismypunct - test for puctuation
 */

ismypunct(c)
int c;
{
	switch(c) {
	case '.':
	case ',':
	case ';':
	case ':':
	case '?':
	case '!':
	case '"':
	case '\'':
	case '(':
		return(1);
	default:
		return(0);
	}
}


/*
 * getright - given right delimeter, return left
 */

getright(left)
char left;
{
	switch(left) {
	case '(':
		return(')');
	case '{':
		return('}');
	case '[':
		return(']');
	case '<':
		return('>');
	}
	return(0);
}


/*
 * gobble - gobble up space to the the next non-space character
 *	return space and char
 */

gobble(space)
char *space;			/* gobbled space returned here */
{
	register int c;		/* non-space character returned here */
	register char *t;

	t = space;
	while(isspace(c = mygetc(readtext))) {
		*t++ = c;
	}
	*t = '\0';
	return(c);
}

/*
 * gulp string up thru newline 
 */

char *
gulpnl(space)
char *space;
{
	register char *w;
	for(w=space; *w;) {
		if(*w++ == '\n')
			break;
	}
	return(w);
}		


post_command()
{
	register int c;		/* non-space character returned here */
	while((c = mygetc(readtext)) != EOF) {
		if (c == '\n')
			break;
		else if(!isspace(c)) {
			errexit(1,"prefer command must end with newline\n");
		}
	}
}
	
/*
 * token
 *
 * tokenizer - returns:
 *	T_COMMAND	anything after a |
 *	T_REFER		a line starting with % to next % or right delim
 *	T_WORDS		anthing
 *	T_OPEN		left delimeter
 *	T_CLOSE		right delimeter
 *	T_WORD		anything else (non-space)
 */

TOKEN
get_token(value,right)
char *value;			/* token value */
char right;			/* expected right delimeter */
{
	register int c;		/* current character */
	register char *v;	/* current position in *value */
				/* state of tokenizer */

	enum {BEGIN, ANYTHING, REFER, COMMAND, WORD, ENDREFER, CONTINUE} state;


	if(right == 0) state = BEGIN;
	else state = ANYTHING;
	v = value;

	while((c = mygetc(readtext)) != EOF) {
		switch(state) {

		case BEGIN:
			switch(c) {
			case '|':
				*v = '\0';
				ungetc(c,readtext);
				return(T_COMMAND);
			case '(':
			case '[':
			case '{':
			case '<':
				*v++ = c;
				*v = '\0';
				return(T_OPEN);
			case ' ':
			case '\n':
			case '\t':
				continue;
			default:
				*v++ = c;
				state = COMMAND;
				continue;
			}

		case ANYTHING:
			switch(c) {
			case ' ':
			case '\n':
			case '\t':
				continue;
			case '%':
				*v++ = c;
				state = REFER;
				continue;
			case ')':
			case ']':
			case '}':
			case '>':
				if(c == right) {
					*v++ = c;
					*v = '\0';
					return(T_CLOSE);
				}
			default:
				*v++ = c;
				state = WORD;
				continue;
			}
		
					
		case COMMAND:
			switch(c) {
			case '|':
			case ' ':
			case '\n':
			case '\t':
			case '(':
			case '[':
			case '{':
			case '<':
				*v = '\0';
				ungetc(c,readtext);
				return(T_COMMAND);
			default:
				*v++ = c;
				continue;
			}
	

		case WORD:
			switch(c) {
			case ' ':
			case '\n':
			case '\t':
			case '%':
				*v = '\0';
				ungetc(c,readtext);
				return(T_WORD);
			case ')':
			case ']':
			case '}':
			case '>':
				if(c == right) {
					*v = '\0';
					ungetc(c,readtext);
					return(T_WORD);
				}
			default:
				*v++ = c;
				continue;
			}
			

		case REFER:
			switch(c) {
			case '\n':
				state = ENDREFER;
				continue;
			case '\\':
				state = CONTINUE;
				continue;
			case ')':
			case ']':
			case '}':
			case '>':
				if(c == right) {
					*v++ = '\n';
					*v = '\0';
					ungetc(c,readtext);
					return(T_REFER);
				}
			default:
				*v++ = c;
				continue;
			}

		case CONTINUE:
			state = REFER;
			if(c != '\n') {
				*v++ = '\\';
				*v++ = c;
			}
			continue;
				

		case ENDREFER:
			ungetc(c,readtext);
			if(c == '%') {
				*v++ = '\n';
				*v = '\0';
				return(T_REFER);
			}
			if(!isspace(c)) *v++ = ' ';
			state = REFER;
			continue;
		}
	}
	haveeof++;
	return(T_EOF);
}


/*
 * token_err - print error message and exit
 */ 

token_err(type,s,tok)
TOKEN type;		/* token type in error */
char	*s,		/* error message */
	*tok;		/* error token */
{
	if(type == T_EOF)
		errexit(1, "Unexpected EOF\n");
	else
		errexit(1,s,tok);
}


/*
 * start_awk
 * open awk and handshake to determine one pass or two
 * (listing an entire bibliography is always one pass)
 */

start_awk(bflag)
bibflag bflag;			/* flag complete bibliography listing (as 
					to normal citations and reference list */
{
	char awkcmd[maxstr];	/* line to send to awk */
	struct stat buf;	/* for stating style file */

/*
 * open up awk style script
 * checking to see style is one of the standards or user supplied
 */

	strcpy(awkcmd,stylename);
	if(stat(awkcmd,&buf)) {
		strcpy(awkcmd,libpath(PLIB));
		strcat(awkcmd,STYLEDIR);
		strcat(awkcmd,stylename);
	}
	awkopen(awkcmd,&readbib,&writebib);


/*
 * handshake, sending appropriate flags
 */
	fputs(LETS_GO,writebib);
	if(nroff)
		fputs(" nroff",writebib);
	else
		fputs(" troff",writebib);
	if(rp)
		fputs(" rp",writebib);
	else
		fputs(" tm",writebib);
	putc('\n',writebib);
	fflush(writebib);

/*
 * read back flag from awk that tells 1 pass or 2;
 * divert text to temp file if two pass
 */
	if(fgets(awkcmd,maxstr,readbib) == NULL)
		errexit(1,"start_awk: EOF or error from awk\n");
	if(strcmp(awkcmd,TWOPASS) == 0) {
		if(bflag != BIBLIST) {
			pass = 1;
			savefile = writetext;
			divertname = mktemp(PREFERTMP);
			writetext = fopen(divertname,"w");
		}
	}
	else pass = 0;
	awkstate = OK;
}


/*
 * citation - process |reference():
 *	use search keys to lookup a complete reference in a bibliographic
 *	database; supplement citation with additional %refer lines;
 *	send all this to an awk for formatting
 */

citation()
{
	char	keys[MAXTOK];		/* store keys here */
	int missing;			/* missing flag */

/*
 * signal start of citation to awk
 */
	if(awkstate != OK) start_awk(NORMAL);
	missing = 0;
	if(pass != 2) {
		fputs(BEGIN_CITE,writebib);
		putc('\n',writebib);
	}

/*
 * after left delmeter, get keys and search for corresponding reference
 */
	leftdelim;
	*keys = '\0';
	while((type = get_token(tok,right)) == T_WORD ) {
		strcat(keys,tok);
		strcat(keys," ");
	}
	if(*keys != '\0') {
		missing = getref(keys);
	}

/*
 * send %lines to awk to supplement citation
 */
	if(type == T_REFER) {
		refline();
		while((type = get_token(tok,right)) == T_REFER) {
			refline();
		}
	}

/*
 * get right delimeter and signal the end of citation
 */
	if (type != T_CLOSE)
		token_err(type,"Expecting right delimeter, got %s\n",tok);

	fputs(END_CITE,writebib);
	if (pass == 2)
		putc('2',writebib);
	putc('\n',writebib);
	fflush(writebib);

		/* if two pass, write marker in diverted text */

	if(pass == 1 && missing == 0)
		fprintf(writetext,"|%s[]",REF_CITE);
}


/*
 * pass a %refline to awk, processing %also lines appropriately
 */

refline()
{
	if(strncmp(ALSOBEGIN,tok,strlen(ALSOBEGIN)) == 0) {
		fputs(tok,writebib);
		while((type = get_token(tok,right)) == T_REFER) {
			if(strncmp(ALSOEND,tok,strlen(ALSOEND)) == 0) {
				fputs(tok,writebib);
				fflush(writebib);
				break;
			}
			else if(strncmp(ALSO,tok,strlen(ALSO)) == 0)
				seealso(tok);
			else fputs(tok,writebib);
		}
	}
	else if(strncmp(ALSO,tok,strlen(ALSO)) == 0) {
		fputs(ALSOBEGIN,writebib);
		putc('\n',writebib);
		seealso(tok);
		fputs(ALSOEND,writebib);
		putc('\n',writebib);
		fflush(writebib);
	}
	else
		fputs(tok,writebib);
}


/*
 * get reference corresponding to keywords and send it to awk
 */

int
getref(keys)
char *keys;
{
	char	*ref;			/* points to complete reference */

	if((ref = locate(keys, INDEX)) == NULL) {
		fprintf(stderr,"Can't open database for %s\n",keys);
		fprintf(writebib,"%s not_found\n",TYPE);
		return(1);
	}
	if(*ref != NULL) {
		if(multiple(ref)) {
			fprintf(stderr,"multiple references for %s\n",keys);
		}
		refwrite(ref);
		free(ref);
		return(0);
 
	}
	else {
		fprintf(stderr,"no reference found for %s\n",keys);
		fprintf(writebib,"%s not_found\n",TYPE);
		free(ref);
		return(1);
	}
}


/*
 * check for multiple new references signalled by two newlines in a row
 */

multiple(ref)
char *ref;
{
	register char *s;

	for(s = ref; *s; s++) {
		if (*s == '\n') {
			if(strncmp(s,"\n\n%",3) == 0) {
			if(prmult) fprintf(stderr, "multiple references>>%s<<\n", ref);
				*(++s) = '\0';
				return(1);
			}
		}
	}
	return(0);
}

/*
 * refwrite - write out a single reference to awk
 */ 


refwrite(ref)
char *ref;
{
	register char *s, c;
	char *t, sav;
	int also;

	also = 0;
	for(s = ref; *s; s++) {
		if(*s == '\n') {
			c = *(s+1);
			if((c  != '%') && c) {
				if(!isspace(c)) {
					fputc(' ',writebib);
					continue;
				}
				continue;
			}
		}
		if(*s == '%') {
			if(strncmp(ALSOBEGIN,s,strlen(ALSOBEGIN)) == 0)
				also++;
			else if(strncmp(ALSOEND,s,strlen(ALSOEND)) == 0)
				also--;
			else if(strncmp(ALSO,s,strlen(ALSO)) == 0) {
				for(t = s+1; *t && *t != '%'; ) {
					if(*t++  == '\n')
						if(*t == '\n')
							break;
				}
				sav = *t;
				*t = '\0';
				if(also == 0) {
					fputs(ALSOBEGIN,writebib);
					putc('\n',writebib);
				}
				seealso(s);
				if(also == 0) {
					fputs(ALSOEND,writebib);
					putc('\n',writebib);
				}
				fflush(writebib);
				*t = sav;
				s = t-1;
				continue;
			}
		}
		putc(*s,writebib);
	}
}



/*
 * seealso - hunt for keywords in the "see also list"
 */

seealso(tok)
register char *tok;
{
	char key[MAXTOK];
	register char *k;

	*key = '\0';
	if(k = strtok(tok+strlen(ALSO)+1," \t\n")) {
		strcpy(key,k);
		strcat(key," ");
		while(k = strtok((char *)0," \t\n")) {
			strcat(key,k);
			strcat(key," ");
		}
		if(*key != '\0') {
			getref(key);
		}
	}
	
}
		


/*
 * end_citations - end a list of citations: read back citation
 * list from awk
 */

end_citations(punc)
int punc;	/* punctuation following or preceeding citation list */
{
	register int l, k, j;

	fputs(END_LIST,writebib);
	if(pass == 1)
		putc('1',writebib);
	if(punc)
		fprintf(writebib," %c",(char)punc);
	putc('\n',writebib);
	fflush(writebib);

	while(fgets(awkline,MAXTOK,readbib)) {
		l = strlen(awkline);
		if(l >= (j=strlen(END_LIST)+1)) {
			k = l-j;
			if(strncmp(END_LIST,&awkline[k],j-1) == 0) {
				if(k != 0) {
					awkline[k] = '\0';
					fputs(awkline,writetext);
				}
				return;
			}
		}
		fputs(awkline,writetext);
	}
	errexit(1,"end_citations: EOF or error from awk\n");
}


/*
 * style - process |reference_style()
 * 	select a reference formatting style and set style flags
 */

style()
{

/*
 * get left delimeter, then style name and options, then right delimeter
 */
	leftdelim;
	if ((type = get_token(tok,right)) == T_WORD) {
		if(strcmp(tok,"same")) {
			strcpy(stylename,tok);
		}
		while ((type = get_token(tok,right)) == T_WORD) {
			if(strcmp(tok,"nroff") == 0) {
				nroff = 1;
			}
			else if(strcmp(tok,"troff") == 0) {
				nroff = 0;
			}
			else if(strcmp(tok,"rp") == 0) {
				rp = 1;
			}
			else if(strcmp(tok,"tm") == 0) {
				rp = 0;
			}
			else if(strcmp(tok,"sequence") == 0) {
				sort = 0;
			}
			else if(strcmp(tok,"sort") == 0) {
				sort = 1;
				strcpy(sortkey,tok);
			}
			else {
				sort = 1;
				strcpy(sortkey,tok);
			}
		}
	}
	else {
		token_err(type,"Expecting style name, got %s\n", tok);
	}

	rightdelim;

/*
 * finish previous citations before switching styles
 */
	if(awkstate == OK)
		biblio(END);
}


/*
 * database - process |reference_database
 * 	select a new bibliographic database
 */
 
database()
{

/* 
 * after left delimeter, get name of database, then right delim
 */
	leftdelim;
	if ((type = get_token(tok,right)) != T_WORD) {
		token_err(type,"Expecting name of database file, got %s\n",tok);
	}
	strcpy(INDEX,tok);
	strcat(INDEX,".i");
	type = get_token(tok,right);
	rightdelim;

}


/*
 * bib_list - process |reference_list()
 *	format a bibliographic database
 *	first finish processing for previous citations
 */

bib_list()
{
	static char dbstr[MAXTOK];	/* names of one or more bibs */
	
/*
 * after left delimeter get bibliography name (can skip on second pass),
 * then right delimeter
 */
	leftdelim;
	if(pass != 2) {
		*dbstr = '\0';
		while ((type = get_token(tok,right)) == T_WORD) {
			strcat(dbstr,tok);
			strcat(dbstr," ");
		}
	}
	else type = get_token(tok,right);
	rightdelim;

/* 
 * format any previous citations then put out complete bibliography
 * (unless the second pass has just begun)
 */
	if(awkstate == OK) {
		biblio(BIBLIST);
		if(pass != 2) printbib(dbstr);
	}
	else {
		printbib(dbstr);
	}
}


/*
 * biblio - process reference_placement OR
 *	finish processing citations before EOF, style change, or list command
 */

biblio(bflag)
bibflag bflag;
{

/*
 * signal bibliography to awk
 */
	fputs(BIBLIO,writebib);
	if(pass == 1)
		putc('1',writebib);
	if(bflag == END || bflag == BIBLIST)
		fputs(" no_bib",writebib);
	putc('\n',writebib);
	fflush(writebib);
	
	switch(pass) {

	/*
	 * write out bib mark to diverted text, close, and reopen
	 */
	case 1:
		pass = 2;
		if(bflag != END) {
			putc(BAR,writetext);
			if(bflag == BIBLIST)
				fprintf(writetext,"%s<>",REF_LIST);
			else
				fputs(REF_PLACE,writetext);
			putc('\n',writetext);
		}
		fclose(writetext);
		writetext = savefile;
		savefile = readtext;
		readtext = fopen(divertname,"r");
		haveeof = 0;
		return;

	/*
	 * close and unlink text and resume reading in original file
	 */
	case 2:
		fclose(readtext);
		unlink(divertname);
		readtext = savefile;
		haveeof = 0;
		pass = 0;

	/*
 	 * get formatted bibliography from awk
	 */
	case 0:
		while(fgets(awkline,MAXTOK,readbib)) {
			if(strcmp("%END_BIB\n",awkline) == 0) {
				awkclose(readbib,writebib);
				return;
			}
			fputs(awkline,writetext);
		}
		errexit(1,"biblio: EOF or error from awk\n");
	}
}


/*
 * refread - read a single reference from a bibliography file
 */
char *
refread(bfile)
FILE *bfile;
{
	static char *buf = NULL;
	static unsigned size;
	register char *bp;
	int c, nextc;

	if(buf == NULL) {
		if((buf = malloc(MAXTOK)) == NULL)
			errexit(1, "malloc error in refread\n");
		size = MAXTOK;
	}
	bp = buf;
	while(isspace(c = getc(bfile))) {
	}
	if(c == EOF)
		return(NULL);
	*bp++ = c;
	while(c = getc(bfile)) {
		if(bp-buf == size-1) {
			if((buf = realloc(buf,size+MAXTOK)) == NULL)
				errexit(1, "malloc error in refread\n");
			bp = buf+size-1;
			size += MAXTOK;
		}
		if(c == EOF)
			break;
		*bp++ = c;
		if(c == '\n') {
			if((nextc = getc(bfile)) == '\n') {
				ungetc(nextc,bfile);
				break;
			}
			ungetc(nextc,bfile);
		}
	}

	if(bp == buf)
		return(NULL);
	if(*(bp-1) != '\n')
		*bp++ = '\n';
	*bp = '\0';
	return(buf);
}

		
/*
 * printbib - list one or more bibliographic databases
 */
printbib(bibstr)
char *bibstr;			/* name of database */
{
	register char *bp, *bn;	/* ptrs to bibstr */
	FILE *bib;		/* file ptr to database */
	register char *ref;	/* points to a complete reference */

/*
 * start awk, signalling that this is an entire bib (as opposed to citations)
 */
	start_awk(BIBLIST);

/*
 * for each database; open the file, read each reference,
 * sending BEGIN and END markers
 */
	for(bp = bibstr; *bp; bp = bn) {
		if((bn = strchr(bp,' ')) != NULL)
			*bn++ = '\0';
		else break;
		if((bib = fopen(bp,"r")) == NULL) {
			fprintf(stderr,"cannot open database file %s\n",bp);
			continue;
		}

		strcpy(INDEX,bp);
		strcat(INDEX,".i");

		while(ref = refread(bib)) {
			fputs(BEGIN_CITE,writebib);
			putc('\n',writebib);
			refwrite(ref);
			fputs(END_CITE,writebib);
			putc('\n',writebib);
		}
		fflush(writebib);
		fclose(bib);
	}
	fflush(writebib);

/*
 * signal awk to format the bibliography, read it back, and print it out
 */
	fputs(WHOLEBIB,writebib);
	if(sort) {
		putc(' ',writebib);
		fputs(sortkey,writebib);
	}
	putc('\n',writebib);
	fflush(writebib);

	while(fgets(awkline,MAXTOK,readbib)) {
		if(strcmp("%END_BIB\n",awkline) == 0) {
			awkclose(readbib,writebib);
			return;
		}
		fputs(awkline,writetext);
	}
	errexit(1,"wholebib: EOF or error from awk\n");
}


/*
 * dbinclude - include entries from one or more bibliography databases
 *		in the reference section without citing in the text
 */
dbinclude()
{
	static char dbstr[MAXTOK];	/* names of one or more bibs */
	register char *bp, *bn;	/* ptrs to bibstr */
	FILE *bib;		/* file ptr to database */
	register char *ref;	/* points to a complete reference */
	char saveindex[maxstr];	/* for saving name of current index */
	int includecnt;		/* count number of included biblio entries */
	
/*
 * after left delimeter get bibliography name (or include count on second pass),
 * then right delimeter
 */
	leftdelim;
	*dbstr = '\0';
	while ((type = get_token(tok,right)) == T_WORD) {
		strcat(dbstr,tok);
		strcat(dbstr," ");
	}
	rightdelim;

	if(pass != 2) {
	
		includecnt = 0;
		strcpy(saveindex,INDEX);	/* save the current INDEX and start awk */
		if(awkstate != OK) start_awk(NORMAL);
	/*
	 * for each database; open the file, read each reference,
	 * sending BEGIN and END markers
	 */
		for(bp = dbstr; *bp; bp = bn) {
			if((bn = strchr(bp,' ')) != NULL)
				*bn++ = '\0';
			else break;
			if((bib = fopen(bp,"r")) == NULL) {
				fprintf(stderr,"cannot open database file %s\n",bp);
				continue;
			}

			strcpy(INDEX,bp);
			strcat(INDEX,".i");

			while(ref = refread(bib)) {
				fputs(BEGIN_CITE,writebib);
				putc('\n',writebib);
				refwrite(ref);
				fputs("%no_cite\n",writebib);
				fputs(END_CITE,writebib);
				putc('\n',writebib);
				includecnt++;
			}
			fflush(writebib);
			fclose(bib);
		}
		end_citations('\0');
		strcpy(INDEX,saveindex);
		if(pass == 1) {
			fprintf(writetext,"|%s[%d]\n",REF_INCLUDE,includecnt);
		}
	}
	else {
		fputs(DBINCLUDE,writebib);
		putc(' ',writebib);
		fputs(dbstr,writebib);	/* number of includes */
		putc('\n',writebib);
		fflush(writebib);
	}
}


mygetc(file)
FILE *file;
{
	int c;

	if(haveeof)
		return(EOF);
	else
		if((c = getc(file)) == EOF)
			haveeof++;
		return(c);
}

/*
 * errexit - print error message to stderr, unlink temporary file, exit
 */

errexit(n,s1,s2,s3)
int n;
char *s1;
{
	fprintf(stderr,s1,s2,s3);
	unlink(divertname);
	if(awkstate != NONE)
		awkclose(readbib,writebib);
	exit(n);
}


/*
 * awkopen - open up pipes to awk process
 */

#define	RDR	0
#define	WTR	1

awkopen(awkfile,readawk,writeawk)
char *awkfile;
FILE **readawk,**writeawk;
{
	int
		i,			/* temp for closing fd's not used */
		fromawk[2],		/* pipe file descriptors from awk */
		toawk[2],
		pid			/* pipe file descriptors to awk */
	;
	char	temp[maxstr];

/*
 * *** take care of forming pipes ***
 */
	if (pipe(fromawk) < 0)
		errexit(1, "can't open pipe from awk\n");
	if (pipe(toawk) < 0)
		errexit(1, "can't open pipe to awk\n");

/*
 * *** make awk child ***
 */
	if ((pid = fork()) == 0) {
		close(fromawk[RDR]);
		dup2(fromawk[WTR], 1);
		close(toawk[WTR]);
		dup2(toawk[RDR], 0);
		for (i=3; i<FILENUM; i++)
			close(i);

		strcpy(temp,libpath(PLIB));
		strcat(temp,SLASH);
		strcat(temp,AWK);
/*
		execlp(temp, AWK, "-R", awkfile, 0);
*/
		execlp(temp, AWK, "-f", awkfile, 0);
		errexit(1, "could not exec awk with script %s\n",awkfile);
	}
	if (pid == -1)
		errexit(1, "could not fork awk\n");

/*
 * *** make out stream pointers ***
 */
	close(fromawk[WTR]);
	*readawk = fdopen(fromawk[RDR], "r");
	close(toawk[RDR]);
	*writeawk = fdopen(toawk[WTR], "w");

}


/*
 * awkclose - close pipes to awk
 */

awkclose(read,write)
FILE *read, *write;
{
	fclose(write);
	fclose(read);
	awkstate = NONE;
}


/*
 * cleanup = after signal, get rid of temp file and close awk
 */

cleanup()
{
	signal(SIGINT, SIG_IGN);
	signal(SIGQUIT, SIG_IGN);
	unlink(divertname);
	if(awkstate != NONE)
		awkclose(readbib,writebib);
	exit(1);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.