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