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