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