xref: /original-bsd/contrib/bib/src/bib.c (revision 3b6250d9)
1 #ifndef lint
2 static char sccsid[] = "@(#)bib.c	2.10	03/05/87";
3 #endif not lint
4 /*
5         Bib - bibliographic formatter
6 
7         Authored by: Tim Budd, University of Arizona, 1983.
8                 lookup routines written by gary levin 2/82
9 
10                 version 7/4/83
11 
12         Various modifications suggested by:
13                 David Cherveny - Duke University Medical Center
14                 Phil Garrison - UC Berkeley
15                 M. J. Hawley - Yale University
16 
17 
18 
19 
20                                                         */
21 # include <stdio.h>
22 # include <ctype.h>
23 # include "bib.h"
24 
25 # define HUNTSIZE 512                /* maximum size of hunt string         */
26 # define MAXREFS  300                /* maximum number of references        */
27 # define MAXATONCE 35                /* maximum references at one location  */
28 
29 # define getch(c,fd) (c = getc(fd))
30 # define echoc(c,ifd,ofd) (getch(c,ifd) == EOF ? c : putc(c,ofd))
31 # define testc(c,d,ifd,ofd) (getch(c, ifd) == d ? putc(c, ofd) : 0)
32 
33 /* global variables */
34    FILE *rfd;                   /* reference temporary file              */
35 #ifndef INCORE
36    char reffile[] = TMPREFFILE ;/* temporary file (see bib.h)            */
37 #endif not INCORE
38    struct refinfo refinfo[MAXREFS];	/* reference information */
39    struct refinfo *refssearch();
40    struct refinfo *refshash[HASHSIZE];
41    long int rend = 1;           /* last position in rfd (first char unused)*/
42    int numrefs = 0;            /* number of references generated so far */
43    FILE *tfd;                   /* output of pass 1 of file(s)           */
44    char bibtmpfile[] = TMPTEXTFILE ; /* output of pass 1                    */
45    char *common = COMFILE;       /* common word file                      */
46    int  findex = false;         /* can we read the file INDEX ?          */
47 
48 /* global variables in bibargs */
49    extern int foot, doacite, sort, max_klen, personal;
50    extern int hyphen, ordcite, biblineno;
51    extern char sortstr[], pfile[], citetemplate[], bibfname[];
52 
53 #include <signal.h>
54 
55 main(argc, argv)
56    int argc;
57    char **argv;
58 {  int rcomp();
59    int intr();
60 
61    /* the file INDEX in the current directory is the default index,
62       if it is present */
63 
64    strcpy(BMACLIB, N_BMACLIB);
65    strcpy(COMFILE, N_COMFILE);
66    strcpy(DEFSTYLE, N_DEFSTYLE);
67 
68    signal(SIGINT, intr);
69    rfd = fopen( INDXFILE , "r");
70    if (rfd != NULL) {
71       findex = true;
72       fclose(rfd);
73       }
74 
75 #ifndef INCORE
76    /* open temporaries, reffile will contain references collected in
77       pass 1, and bibtmpfile will contain text.
78    */
79    mktemp(reffile);
80    rfd = fopen(reffile,"w+");
81    if (rfd == NULL)
82       error("can't open temporary reference file, %s", reffile);
83    putc('x', rfd);      /* put garbage in first position (not used) */
84 #endif not INCORE
85    mktemp(bibtmpfile);
86    tfd = fopen(bibtmpfile,"w");
87    if (tfd == NULL)
88       error("can't open temporary output file, %s", bibtmpfile);
89 
90     /*
91        pass1 - read files, looking for citations
92                arguments are read by doargs (bibargs.c)
93     */
94 
95    if (doargs(argc, argv, DEFSTYLE ) == 0) {
96       strcpy(bibfname, "<stdin>");
97       rdtext(stdin);
98       }
99 
100    /*
101     sort references, make citations, add disambiguating characters
102    */
103 
104    if (sort)
105       qsort(refinfo, numrefs, sizeof(struct refinfo), rcomp);
106    makecites();
107    disambiguate();
108 
109    /*
110    reopen temporaries
111    */
112 
113    fclose(tfd);
114    tfd = fopen(bibtmpfile,"r");
115    if (tfd == NULL)
116       error("can't open temporary output file %s for reading", bibtmpfile);
117    /*
118    pass 2 - reread files, replacing references
119    */
120    pass2(tfd, stdout);
121    cleanup(0);
122 }
123 /* interrupt processing */
124 intr()
125 {
126    cleanup(1);
127 }
128 /* clean up and exit */
129 cleanup(val)
130 {
131    fclose(tfd);
132 #ifndef INCORE
133    fclose(rfd);
134    unlink(reffile);
135 #endif INCORE
136 #ifndef DEBUG
137    unlink(bibtmpfile);
138 #endif DEBUG
139    exit(val);
140 }
141 
142 /* rdtext - read and process a text file, looking for [. commands */
143    rdtext(fd)
144    FILE *fd;
145 {  char lastc, c, d;
146 
147    lastc = '\0';
148    biblineno = 1;
149    while (getch(c, fd) != EOF)
150       if (c == '[' || c == '{')
151          if (getch(d, fd) == '.') { /* found a reference */
152             if (c == '{') { if (lastc) putc(lastc, tfd);}
153             else
154                switch (lastc) {
155                   case '\0': break;
156                   case ' ': fputs("\\*([<", tfd); break;
157                   case '.': case ',': case '?': case ':':
158                   case ';': case '!': case '"': case '\'':
159                             fputs("\\*([", tfd);  /* fall through */
160                   default:  putc(lastc, tfd); break;
161                   }
162             rdcite(fd, c);
163             if (c == '[')
164                switch (lastc) {
165                   case '\0': break;
166                   case ' ': fputs("\\*(>]", tfd); break;
167                   case '.': case ',': case '?': case ':':
168                   case ';': case '!': case '"': case '\'':
169                             fprintf(tfd,"\\*(%c]", lastc); break;
170                   }
171             lastc = '\0';
172             }
173          else {
174             if (lastc != '\0') putc(lastc, tfd);
175             ungetc(d, fd);
176             lastc = c;
177             }
178       else {
179          if (lastc != '\0') putc(lastc, tfd);
180          lastc = c;
181          if (c == '\n') biblineno++;
182          }
183    if (lastc != '\0') putc(lastc, tfd);
184 }
185 
186 /* rdcite - read citation information inside a [. command */
187    rdcite(fd, ch)
188    FILE *fd;
189    char ch;
190 {  int getref();
191    char huntstr[HUNTSIZE], c, info[HUNTSIZE];
192 
193    if (ch == '[')
194       if (doacite) fputs("\\*([[", tfd);
195    else
196       if (doacite) fputs("\\*([{", tfd);
197    huntstr[0] = info[0] = 0;
198    while (getch(c, fd) != EOF)
199       switch (c) {
200          case ',':
201 	    citemark(info, huntstr, (char *)0);
202             huntstr[0] = info[0] = 0;
203             break;
204          case '.':
205             while (getch(c, fd) == '.') ;
206             if (c == ']') {
207 	       citemark(info, huntstr, "\\*(]]");
208                return;
209                }
210             else if (c == '}') {
211 	       citemark(info, huntstr, "\\*(}]");
212                return;
213                }
214             else
215                addc(huntstr, c);
216             break;
217 
218          case '{':
219             while (getch(c, fd) != '}')
220                if (c == EOF) {
221                   error("ill formed reference");
222                   }
223                 else
224                   addc(info, c);
225             break;
226 
227          case '\n':
228             biblineno++;
229          case '\t':
230             c = ' ';   /* fall through */
231 
232          default:
233             addc(huntstr,c);
234          }
235    error("end of file reading citation");
236 }
237 char	ncitetemplate[64];
238 int	changecite;
239 citemark(info, huntstr, tail)
240 	char *info, *huntstr, *tail;
241 {
242 	char c = CITEMARK;
243         long int  n;
244 	/*
245 	 *	getref sets ncitetemplate as a side effect
246 	 */
247 	n = getref(huntstr);
248 	if (ncitetemplate[0]){
249 		fprintf(tfd, "%c%s%c", FMTSTART, ncitetemplate, FMTEND);
250 		ncitetemplate[0] = 0;
251 	}
252 	if (doacite && (tail != (char *)0))
253 	  fprintf(tfd, "%c%d%c%s%c%s", c ,n, c, info, CITEEND, tail);
254 	else
255 	  fprintf(tfd, "%c%d%c%s%c", c ,n, c, info, CITEEND);
256 
257 }
258 
259 /* addc - add a character to hunt string */
260    addc(huntstr, c)
261    char huntstr[HUNTSIZE], c;
262 {  int  i;
263 
264    i = strlen(huntstr);
265    if (i > HUNTSIZE)
266       error("citation too long, max of %d", HUNTSIZE);
267    huntstr[i] = c;
268    huntstr[i+1] = 0;
269 }
270 /* getref - if an item was already referenced, return its reference index
271                 otherwise create a new entry */
272    int getref(huntstr)
273    char huntstr[HUNTSIZE];
274 {  char rf[REFSIZE], *r, *hunt();
275    int	match(), getwrd();
276    char	*realhstr;
277    int hash;
278    struct refinfo *rp;
279    int	lg;
280 
281    realhstr = huntstr;
282    if (strncmp(huntstr, "$C$", 3) == 0){
283 	char *from, *to;
284 	changecite++;
285 	for(from = huntstr + 3, to = ncitetemplate; *from; from++, to++){
286 		switch(*from){
287 		case '\0':
288 		case ' ':
289 		case '\n':
290 		case '\t':	goto outcopy;
291 		default:	*to = *from;
292 		}
293 	}
294    outcopy: ;
295 	*to = 0;
296 	*from = 0;
297 	realhstr = from + 1;
298    }
299    r = hunt(realhstr);
300    if (r != NULL) {
301       /* expand defined string */
302       strcpy(rf, r);
303       free(r);
304       expand(rf);
305       /* see if reference has already been cited */
306       if (foot == false && (rp = refssearch(rf))){
307 		return(rp - refinfo);
308       }
309       /* didn't match any existing reference, create new one */
310       if (numrefs >= MAXREFS)
311 	error("too many references, max of %d", MAXREFS);
312       hash = strhash(rf);
313       lg = strlen(rf) + 1;
314       refinfo[numrefs].ri_pos = rend;
315       refinfo[numrefs].ri_length = lg;
316       refinfo[numrefs].ri_hp = refshash[hash];
317       refinfo[numrefs].ri_n = numrefs;
318       refshash[hash] = &refinfo[numrefs];
319       wrref(&refinfo[numrefs], rf);
320       return(numrefs++);
321       }
322    else {
323       bibwarning("no reference matching %s\n", realhstr);
324       return(-1);
325       }
326 }
327 struct refinfo *refssearch(rf)
328    char *rf;
329 {
330    char ref[REFSIZE];
331    reg	int i;
332    int	lg;
333    reg	struct refinfo *rp;
334    lg = strlen(rf) + 1;
335    for (rp = refshash[strhash(rf)]; rp; rp = rp->ri_hp){
336 	     if (rp->ri_length == lg){
337 		     rdref(rp, ref);
338 		     if (strcmp(ref, rf) == 0)
339 			return(rp);
340 	     }
341    }
342    return(0);
343 }
344 /* hunt - hunt for reference from either personal or system index */
345    char *hunt(huntstr)
346    char huntstr[];
347 {  char *fhunt(), *r, *p, *q, fname[120];
348 
349    if (personal) {
350       for (p = fname, q = pfile; ; q++)
351          if (*q == ',' || *q == 0) {
352             *p = 0;
353             if ((r = fhunt(fname, huntstr)) != NULL)
354                return(r);
355             else if (*q == 0)
356                break;
357             p = fname;
358             }
359          else *p++ = *q;
360       }
361    else if (findex) {
362       if ((r = fhunt( INDXFILE , huntstr)) != NULL)
363          return(r);
364       }
365    if ((r = fhunt(SYSINDEX , huntstr)) != NULL)
366       return(r);
367    return(NULL);
368 }
369 
370 /* fhunt - hunt from a specific file */
371    char *fhunt(file, huntstr)
372    char file[], huntstr[];
373 {  char *p, *r, *locate();
374 
375    r = locate(huntstr, file, max_klen, common);
376 
377    if (r == NULL)
378       return(NULL);  /* error */
379    if (*r == 0)
380       return(NULL);  /* no match */
381 
382    for (p = r; *p; p++)
383       if (*p == '\n')
384          if (*(p+1) == '\n') { /* end */
385             if (*(p+2) != 0)
386                bibwarning("multiple references match %s\n",huntstr);
387             *(p+1) = 0;
388             break;
389             }
390          else if (*(p+1) != '%' && *(p+1) != '.') /* unnecessary newline */
391             *p = ' ';
392    return(r);
393 }
394 struct cite{
395 	int	num;
396 	char	*info;
397 };
398 citesort(p1, p2)
399 	struct cite *p1, *p2;
400 {
401 	return(p1->num - p2->num);
402 }
403 
404 /* putrefs - gather contiguous references together, sort them if called
405    for, hyphenate if necessary, and dump them out */
406 int putrefs(ifd, ofd, footrefs, fn)
407 FILE *ifd, *ofd;
408 int  fn, footrefs[];
409 {
410 	struct cite cites[MAXATONCE];
411 	char	infoword[HUNTSIZE];    /* information line */
412 	reg	int i;
413 	reg	char *p;
414 	reg	int  ncites, n, j;         /* number of citations being dumped */
415 	char	c, *walloc();
416 	int neg;
417 	/*
418 	 * first gather contiguous references together,
419 	 * and order them if required
420 	 */
421 
422 	ncites = 0;
423 	do {
424 		neg = 1;
425 		n = 0;
426 		do{
427 			getch(c, ifd);
428 			if (isdigit(c))
429 				n = 10 * n + (c - '0');
430 			else if (c == '-')
431 				neg *= -1;
432 			else if (c == CITEMARK)
433 				break;
434 			else
435 				error("bad cite char 0%03o in pass two",c);
436 		} while(1);
437 		if (neg < 0) {     /* reference not found */
438 			cites[ncites].num = -1;
439 			cites[ncites].info = 0;
440 			ncites++;
441 		} else {
442 			/*
443 			 * Find reference n in the references
444 			 */
445 			int i;
446 			for (i = 0; i < numrefs; i++){
447 				if (refinfo[i].ri_n == n){
448 					cites[ncites].num = i;
449 					cites[ncites].info = 0;
450 					ncites++;
451 					break;
452 				}
453 			}
454 			if (i == numrefs)
455 				error("citation	%d not found in pass 2", n);
456 		}
457 		if (getch(c, ifd) != CITEEND) {
458 			for (p = infoword; c != CITEEND ; ) {
459 				*p++ = c;
460 				getch(c, ifd);
461 			}
462 			*p = 0;
463 			cites[ncites-1].info = walloc(infoword);
464 		}
465 		getch(c, ifd);
466 	} while (c == CITEMARK);
467 	ungetc(c, ifd);
468 	if (ordcite)
469 		qsort(cites, ncites, sizeof(struct cite), citesort);
470 
471 	/* now dump out values */
472 	for (i = 0; i < ncites; i++) {
473 		if (cites[i].num >= 0) {
474 			if (changecite){
475 				char tempcite[128];
476 				char ref[REFSIZE];
477 				struct refinfo *p;
478 				/*
479 				 * rebuild the citation string,
480 				 * using the current template in effect
481 				 */
482 				p = &refinfo[cites[i].num];
483 				rdref(p, ref);
484 				bldcite(tempcite, cites[i].num, ref);
485 				strcat(tempcite, p->ri_disambig);
486 				if (doacite) fputs(tempcite, ofd);
487 			} else {
488 				if (doacite) fputs(refinfo[cites[i].num].ri_cite, ofd);
489 			}
490 			if (!doacite) fputs("\\&", ofd);
491 		}
492 		if (cites[i].info) {
493 			if (doacite) fputs(cites[i].info, ofd);
494 			if (!doacite) fputs("\\&", ofd);
495 			free(cites[i].info);
496 		}
497 		if (hyphen) {
498 			for (j = 1;
499 			     j + i <= ncites && cites[i+j].num == cites[i].num + j;
500 			     j++)/*VOID*/;
501 			if (j + i > ncites)
502 				j = ncites;
503 			else
504 				j = j + i - 1;
505 		} else {
506 			j = i;
507 		}
508 		if (j > i + 1) {
509 			fputs("\\*(]-", ofd);
510 			i = j - 1;
511 		} else if (i != ncites - 1) {
512 			fputs("\\*(],", ofd);
513 		}
514 		if (foot) {
515 			fn++;
516 			footrefs[fn] = cites[i].num;
517 		}
518 	}
519 	return(fn);
520 }
521 
522 /* pass2 - read pass 1 files entering citation */
523    pass2(ifd, ofd)
524    FILE *ifd, *ofd;
525 {
526    char c;
527    int  i, fn, footrefs[25], dumped;
528 
529    fn = -1;
530    dumped = foot;
531    while (getch(c, ifd) != EOF) {
532       while (c == '\n') {
533          putc(c, ofd);
534          if (foot && fn >= 0) {
535             for (i = 0; i <= fn; i++)
536                 dumpref(footrefs[i], ofd);
537             fn = -1;
538             }
539          if (testc(c, '.', ifd, ofd))
540             if (testc(c, '[', ifd, ofd))
541                if (testc(c, ']', ifd, ofd)) {
542                   while (echoc(c, ifd, ofd) != '\n')
543                      ;
544                   dumped = true;
545                   for (i = 0; i < numrefs; i++){
546                      dumpref(i, ofd);
547 		  }
548                   getch(c, ifd);
549                   }
550          }
551       if (c == FMTSTART)
552 	 changefmt(ifd);
553       else if (c == CITEMARK)
554          fn = putrefs(ifd, ofd, footrefs, fn);
555       else if (c != EOF)
556          putc(c, ofd);
557       }
558    if (dumped == false)
559       bibwarning("Warning: references never dumped\n","");
560 }
561 /*
562  *	change citation format
563  */
564 changefmt(ifd)
565 	FILE	*ifd;
566 {
567 	char	c;
568 	char	*to;
569 	to = ncitetemplate;
570 	while (getch(c, ifd) != FMTEND)
571 		*to++ = c;
572 	*to = 0;
573 	strcpy(citetemplate, ncitetemplate);
574 }
575