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