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
main(argc,argv)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
intr()131 intr()
132 {
133 cleanup(1);
134 }
135 /* clean up and exit */
cleanup(val)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 */
rdtext(fd)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 */
rdcite(fd,ch)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;
citemark(info,huntstr,tail)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 */
addc(huntstr,c)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 */
getref(huntstr)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
refssearch(rf)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 */
hunt(huntstr)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 */
fhunt(file,huntstr)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 */
putrefs(ifd,ofd,footrefs,fn)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 */
pass2(ifd,ofd)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 */
changefmt(ifd)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