1 #ifndef lint 2 static char sccsid[] = "@(#)bibargs.c 2.13 05/27/93"; 3 #endif not lint 4 /* 5 Authored by: Tim Budd, University of Arizona, 1983. 6 version 7/4/83 7 8 Various modifications suggested by: 9 David Cherveny - Duke University Medical Center 10 Phil Garrison - UC Berkeley 11 M. J. Hawley - Yale University 12 13 14 version 8/23/1988 15 16 Adapted to use TiB style macro calls (i.e. |macro|) 17 A. Dain Samples 18 19 20 21 22 read argument strings for bib and listrefs 23 do name formatting, printing lines, other actions common to both 24 */ 25 # include <stdio.h> 26 # include <ctype.h> 27 # include "bib.h" 28 # define LINELENGTH 1024 29 # define MAXDEFS 500 /* maximum number of defined words */ 30 31 /* global variables */ 32 char bibfname[120]; /* file name currently being read */ 33 int biblineno; /* line number currently being referenced */ 34 int abbrev = false; /* automatically abbreviate names */ 35 int capsmcap = false; /* print names in caps small caps (CACM form)*/ 36 int TibOption = false; /* expect files in TiB format */ 37 int TibxOption = false; /* to create files for bib2tib */ 38 int numrev = 0; /* number of authors names to reverse */ 39 int edabbrev = false; /* abbreviate editors names ? */ 40 int edcapsmcap = false; /* print editors in cap small caps */ 41 int ednumrev = 0; /* number of editors to reverse */ 42 int max_klen = 6; /* max size of key */ 43 int sort = false; /* sort references ? (default no) */ 44 int foot = false; /* footnoted references ? (default endnotes) */ 45 int doacite = true; /* place citations ? */ 46 int redefWarning = false; /* warnings on attempted redefs ? */ 47 int hyphen = false; /* hypenate contiguous references */ 48 int ordcite = true; /* order multiple citations */ 49 char sortstr[80] = "1"; /* sorting template */ 50 char trailstr[80] = ""; /* trailing characters to output */ 51 char pfile[400]; /* private file name */ 52 int personal = false; /* personal file given ? (default no) */ 53 char citetemplate[80] = "1"; /* citation template */ 54 struct wordinfo words[MAXDEFS]; /* defined words */ 55 struct wordinfo *wordhash[HASHSIZE]; 56 struct wordinfo *wordsearch(); 57 int wordtop = 0; /* number of defined words */ 58 char letterSeen[128]; /* keeps track of keyletters 59 * so we know whether to emit a .ds 60 * or a .as 61 /* */ 62 63 /* where output goes */ 64 extern FILE *tfd; 65 /* reference file information */ 66 extern struct refinfo refinfo[]; 67 extern char reffile[]; 68 #ifndef INCORE 69 extern FILE *rfd; 70 #endif not INCORE 71 extern int numrefs; 72 extern char *programName; 73 74 char *usageArr[] = { 75 "-aa abbreviate authors' first names", 76 "-arN reverse first N authors' names; no N, do all", 77 "-ax print authors' last names in Caps-Small", 78 "-cS use template S for citations", 79 "-d change the default directory", 80 "-ea abbreviate editors' first names", 81 "-ex print editors' last names in Caps-Small", 82 "-erN reverse first N editors' names; no N, do all", 83 "-f dump reference after citation for footnotes", 84 "-iFILE process FILE (e.g. a file of definitions)", 85 "-h hyphenate sequences of citations (turns on -o)", 86 "-nS turn off options; S is composed of the option letters 'afhosx'", 87 "-pFILE search these FILEs (comma separated list) instead of INDEX", 88 "-R print warnings when duplicate definitions of names are ignored", 89 "-sS sort references according to template S", 90 "-tTYPE use the style TYPE", 91 "-Tib expect files to be in TiB format (which see)", 92 "-Tibx write a file for converting bib to TiB-style |macros|", 93 "", 94 0 95 }; 96 97 void 98 usageErr(argv0, opt, str) 99 char *argv0; 100 char *opt; 101 char *str; 102 { 103 char **p; 104 fprintf(stderr, "Illegal invocation of %s. Acceptable options:\n", 105 argv0); 106 fprintf(stderr, "Argument: %s\n", opt); 107 fprintf(stderr, "Problem: %s\n", str); 108 for (p = usageArr; *p != 0; p++) { 109 fprintf(stderr, " %s\n", *p); 110 } 111 } 112 113 /* bibwarning - print out a warning message */ 114 /*VARARGS1*/ 115 bibwarning(msg, a1, a2) 116 char *msg; 117 { 118 fprintf(stderr,"%s: `%s', line %d: ", programName, bibfname, biblineno); 119 fprintf(stderr, msg, a1, a2); 120 fprintf(stderr, "\n"); 121 } 122 123 124 125 /* doargs - read command argument line for both bib and listrefs 126 set switch values 127 call rdtext on file arguments, after dumping 128 default style file if no alternative style is given 129 */ 130 131 int doargs(argc, argv, defstyle) 132 int argc; 133 char **argv, defstyle[]; 134 { int numfiles, i, style; 135 char *p, *q, *walloc(); 136 FILE *fd; 137 138 numfiles = 0; 139 style = true; 140 TibxOption = false; 141 newbibdir(BMACLIB); 142 143 programName = argv[0]; 144 for (i = 1; i < argc; i++) 145 if (argv[i][0] == '-') 146 switch(argv[i][1]) { 147 case 'a': for (p = &argv[i][2]; *p; p++) 148 if (*p == 'a' || *p == 0) 149 abbrev = true; 150 else if (*p == 'x') 151 capsmcap = true; 152 else if (*p == 'r') { 153 if (*(p+1)) 154 numrev = atoi(p+1); 155 else 156 numrev = 1000; 157 break; 158 } 159 break; 160 161 case 'c': if (argv[i][2] == 0) 162 error("citation string expected for 'c'"); 163 else 164 for (p = citetemplate,q = &argv[i][2]; *p++ = *q++; ); 165 break; 166 167 case 'd': if (argv[i][2]) 168 p = &argv[i][2]; 169 else { /* take next arg */ 170 i++; 171 p = argv[i]; 172 } 173 newbibdir(p); 174 break; 175 176 case 'e': for (p = &argv[i][2]; *p; p++) 177 if (*p == 'a') 178 edabbrev = true; 179 else if (*p == 'x') 180 edcapsmcap = true; 181 else if (*p == 'r') { 182 if (*(p+1)) 183 ednumrev = atoi(p+1); 184 else 185 ednumrev = 1000; 186 break; 187 } 188 break; 189 190 case 'f': CASE_f: 191 foot = true; 192 hyphen = false; 193 break; 194 195 case 'i': CASE_i: 196 if (argv[i][2]) 197 p = &argv[i][2]; 198 else { /* take next arg */ 199 i++; 200 p = argv[i]; 201 } 202 incfile(p); 203 break; 204 205 case 'l': if (argv[i][2]){ 206 max_klen = atoi(&argv[i][2]); 207 if (max_klen > REFSIZE) 208 error("too long key size"); 209 } else { 210 error("-l needs a numeric value"); 211 } 212 break; 213 214 case 'h': hyphen = ordcite = true; 215 break; 216 217 case 'n': for (p = &argv[i][2]; *p; p++) 218 if (*p == 'a') 219 abbrev = false; 220 else if (*p == 'f') 221 foot = false; 222 else if (*p == 'h') 223 hyphen = false; 224 else if (*p == 'o') 225 ordcite = false; 226 else if (*p == 'R') 227 redefWarning = false; 228 else if (*p == 'r') 229 numrev = 0; 230 else if (*p == 's') 231 sort = false; 232 else if (*p == 'x') 233 capsmcap = false; 234 else if (*p == 'v') 235 doacite = true; 236 break; 237 238 case 'o': ordcite = true; 239 break; 240 241 case 'p': if (argv[i][2]) 242 p = &argv[i][2]; 243 else { /* take next arg */ 244 i++; 245 p = argv[i]; 246 } 247 strcpy(pfile, p); 248 personal = true; 249 break; 250 251 case 'R': redefWarning = true; 252 break; 253 254 case 'r': if (argv[i][2] == 0) /* synonym -ar */ 255 numrev = 1000; 256 else 257 numrev = atoi(&argv[i][2]); 258 break; 259 260 case 's': sort = true; 261 if (argv[i][2]) 262 for (p = sortstr,q = &argv[i][2]; *p++ = *q++; ); 263 break; 264 265 case 't': style = false; 266 goto CASE_i; 267 268 case 'T': if (strcmp("Tib", &(argv[i][1])) == 0) 269 TibOption = true; 270 else if (strcmp("Tibx",&(argv[i][1])) == 0) 271 TibxOption = true; 272 else { 273 usageErr(argv[0], argv[i], 274 "Did you want the Tib option?"); 275 error("'%s' invalid switch", argv[i]); 276 } 277 break; 278 279 case 'v': doacite = false; 280 goto CASE_f; 281 282 case 'x': capsmcap = true; /* synonym for -ax */ 283 break; 284 285 case 0: if (style) { /* no style command given, take default */ 286 style = false; 287 incfile( defstyle ); 288 } 289 strcpy(bibfname,"<stdin>"); 290 rdtext(stdin); 291 numfiles++; 292 break; 293 294 default: usageErr(argv[0], argv[i], "Invalid switch"); 295 error("'%c' invalid switch", argv[i][1]); 296 } 297 else { /* file name */ 298 numfiles++; 299 if (style) { 300 style = false; 301 incfile( defstyle ); 302 } 303 fd = fopen(argv[i], "r"); 304 if (fd == NULL) { 305 error("can't open file %s", argv[i]); 306 } 307 else { 308 strcpy(bibfname, argv[i]); 309 rdtext(fd); 310 fclose(fd); 311 } 312 } 313 314 if (style) incfile( defstyle ); 315 if (TibxOption) { 316 /* 317 Emits m4 macros that allow easy transformation of old bib-style 318 bibliographic databases into tib-style. The primary problem 319 (although not the only one) is the change of |macro| calls. 320 */ 321 reg struct wordinfo *wp; 322 FILE *outf; 323 outf = fopen("bib.m4.in","w"); 324 for (i=0; i<HASHSIZE; i++) { 325 for (wp = wordhash[i]; wp != NULL; wp = wp->wi_hp) { 326 fprintf(outf,"define(%s,|%s__m4_|)dnl\n",wp->wi_word,wp->wi_word); 327 } 328 } 329 fclose(outf); 330 } 331 return(numfiles); 332 333 } 334 335 newbibdir(name) 336 char *name; 337 { 338 strreplace(COMFILE, BMACLIB, name); 339 strreplace(DEFSTYLE, BMACLIB, name); 340 strcpy(BMACLIB, name); 341 wordrestuff("BMACLIB", BMACLIB); 342 fprintf(tfd, ".ds l] %s\n", BMACLIB); 343 } 344 345 /* incfile - read in an included file */ 346 incfile(np) 347 char *np; 348 { char name[120]; 349 FILE *fd; 350 char *p, line[LINELENGTH], dline[LINELENGTH], word[80], *tfgets(); 351 int i, getwrd(); 352 353 strcpy(line, bibfname); /* temporary save in case of errors */ 354 /* first try ./<yourfile> */ 355 strcpy(bibfname, np); 356 fd = fopen(bibfname, "r"); 357 /* try BMACLIB/<yourfile> */ 358 if (fd == NULL && *np != '/') { 359 strcpy(name, BMACLIB); strcat(name, "/"); strcat(name, np); 360 strcpy(bibfname, name); 361 fd = fopen(bibfname, "r"); 362 } 363 /* try BMACLIB/tibmacs/<yourfile> */ 364 if (TibOption && fd == NULL && *np != '/') { 365 strcpy(name, BMACLIB); strcat(name, "/tibmacs/"); strcat(name, np); 366 strcpy(bibfname, name); 367 fd = fopen(bibfname, "r"); 368 } 369 /* try BMACLIB/bibmacs/<yourfile> */ 370 if (!TibOption && fd == NULL && *np != '/') { 371 strcpy(name, BMACLIB); strcat(name, "/bibmacs/"); strcat(name, np); 372 strcpy(bibfname, name); 373 fd = fopen(bibfname, "r"); 374 } 375 /* try ./bib.<yourfile> */ 376 if (fd == NULL && *np != '/') { 377 strcpy(name, "bib."); strcat(name, np); 378 strcpy(bibfname, name); 379 fd = fopen(bibfname, "r"); 380 } 381 /* try BMACLIB/bib.<yourfile> */ 382 if (fd == NULL && *np != '/') { 383 strcpy(name,BMACLIB); strcat(name, "/bib."); strcat(name, np); 384 strcpy(bibfname, name); 385 fd = fopen(bibfname, "r"); 386 } 387 if (fd == NULL) { 388 /* unsave old name */ 389 strcpy(bibfname, line); 390 bibwarning("%s: can't find", np); 391 exit(1); 392 } 393 394 /* now go off and process file */ 395 biblineno = 1; 396 while (tfgets(line, LINELENGTH, fd) != NULL) { 397 biblineno++; 398 switch(line[0]) { 399 400 case '#': break; 401 402 case 'A': for (p = &line[1]; *p; p++) 403 if (*p == 'A' || *p == '\0') 404 abbrev = true; 405 else if (*p == 'X') 406 capsmcap = true; 407 else if (*p == 'R') { 408 if (*(p+1)) 409 numrev = atoi(p+1); 410 else 411 numrev = 1000; 412 break; 413 } 414 break; 415 416 case 'C': for (p = &line[1]; *p == ' '; p++) ; 417 strcpy(citetemplate, p); 418 break; 419 420 case 'D': if ((i = getwrd(line, 1, word)) == 0) 421 error("word expected in definition"); 422 if (wordsearch(word)) { /* already there-toss rest of def.*/ 423 if (redefWarning) 424 bibwarning("Attempted redefine of %s ignored.",word); 425 while(line[strlen(line)-1] == '\\' ) { 426 if (tfgets(line, LINELENGTH, fd) == NULL) break; 427 } 428 break; 429 } 430 for (p = &line[i]; isspace(*p); p++) ; 431 for (strcpy(dline, p); dline[strlen(dline)-1] == '\\'; ){ 432 dline[strlen(dline)-1] = '\n'; 433 if (tfgets(line, LINELENGTH, fd) == NULL) break; 434 strcat(dline, line); 435 } 436 wordstuff(word, dline); 437 break; 438 439 case 'E': for (p = &line[1]; *p; p++) 440 if (*p == 'A') 441 edabbrev = true; 442 else if (*p == 'X') 443 edcapsmcap = true; 444 else if (*p == 'R') { 445 if (*(p+1)) 446 ednumrev = atoi(p+1); 447 else 448 ednumrev = 1000; 449 break; 450 } 451 break; 452 453 case 'F': foot = true; 454 hyphen = false; 455 break; 456 457 case 'I': for (p = &line[1]; *p == ' '; p++); 458 expand(p); 459 incfile(p); 460 break; 461 462 case 'H': hyphen = ordcite = true; 463 break; 464 465 case 'O': ordcite = true; 466 break; 467 468 case 'R': if (line[1] == 0) /* this is now replaced by AR */ 469 numrev = 1000; 470 else 471 numrev = atoi(&line[1]); 472 break; 473 474 case 'S': sort = true; 475 for (p = &line[1]; *p == ' '; p++) ; 476 strcpy(sortstr, p); 477 break; 478 479 case 'T': for (p = &line[1]; *p == ' '; p++) ; 480 strcpy(trailstr, p); 481 break; 482 483 case 'X': capsmcap = true; /* this is now replace by AX */ 484 break; 485 486 default: fprintf(tfd,"%s\n",line); 487 while (fgets(line, LINELENGTH, fd) != NULL) 488 fputs(line, tfd); 489 return; 490 } 491 492 } 493 /* close up */ 494 fclose(fd); 495 } 496 497 /* error - report unrecoverable error message */ 498 /*VARARGS1*/ 499 error(str, a1, a2) 500 char *str; 501 { 502 bibwarning(str, a1, a2); 503 /* 504 * clean up temp files and exit 505 */ 506 cleanup(1); 507 } 508 509 #ifndef INCORE 510 #ifdef READWRITE 511 /* 512 ** fixrfd( mode ) -- re-opens the rfd file to be read or write, 513 ** depending on the mode. Uses a static int to save the current mode 514 ** and avoid unnecessary re-openings. 515 */ 516 fixrfd( mode ) 517 register int mode; 518 { 519 static int cur_mode = WRITE; /* rfd open for writing initially */ 520 521 if (mode != cur_mode) 522 { 523 rfd = freopen(reffile, ((mode == READ)? "r" : "a"), rfd); 524 cur_mode = mode; 525 if (rfd == NULL) 526 error("Hell! Couldn't re-open reference file %s", 527 reffile); 528 } 529 } 530 #endif 531 #endif not INCORE 532 533 534 /* tfgets - fgets which trims off newline */ 535 char *tfgets(line, n, ptr) 536 char line[]; 537 int n; 538 FILE *ptr; 539 { reg char *p; 540 541 p = fgets(line, n, ptr); 542 if (p == NULL) 543 return(NULL); 544 else 545 for (p = line; *p; p++) 546 if (*p == '\n') 547 *p = 0; 548 return(line); 549 } 550 551 /* getwrd - place next word from in[i] into out */ 552 int getwrd(in, i, out) 553 reg char in[], out[]; 554 reg int i; 555 { int j; 556 557 j = 0; 558 while (isspace(in[i])) 559 i++; 560 if (in[i] != '\0') 561 while (in[i] != '\0' && !isspace(in[i])) 562 out[j++] = in[i++]; 563 else 564 i = 0; /* signals end of in[i..] */ 565 out[j] = 0; 566 return (i); 567 } 568 569 /* walloc - allocate enough space for a word */ 570 char *walloc(word) 571 char *word; 572 { char *i, *malloc(); 573 i = malloc(1 + strlen(word)); 574 if (i == NULL) 575 error("out of storage"); 576 strcpy(i, word); 577 return(i); 578 } 579 580 /* isword - see if character is legit word char */ 581 #define iswordc(c) (isalnum(c) || c == '&' || c == '_') 582 583 expand(line) 584 char *line; 585 { char line2[REFSIZE], word[REFSIZE]; 586 reg struct wordinfo *wp; 587 reg char *p, *q, *w; 588 589 q = line2; 590 if (TibOption) { 591 /* expand only macro names in |name| vertical bars; name must exist */ 592 for (p = line; *p != '\0'; /* VOID */ ) { 593 if (*p == '|') { 594 p++; 595 w = word; 596 while (*p != '|' && *p != '\0' && !isspace(*p)) { *w++ = *p++; } 597 *w = '\0'; 598 /* skip second '|', if present */ 599 if (*p++ != '|') { 600 --p; 601 bibwarning("Unbalanced |macro| bars\n"); 602 } 603 else if ((wp = wordsearch(word)) != 0) { 604 strcpy(word, wp->wi_def); 605 if (wp->wi_expanding) { 606 bibwarning("Recursive definition for |%s|\n", word); 607 } 608 else { 609 wp->wi_expanding = true; 610 expand(word); 611 wp->wi_expanding = false; 612 } 613 } 614 else { 615 char errword[REFSIZE]; 616 bibwarning("word |%s| not defined\n", word); 617 strcpy(errword, "?"); 618 strcat(errword, word); 619 strcat(errword, "?"); 620 wordstuff(word, errword); 621 strcpy(word, errword); 622 } 623 for (w = word; *w != '\0'; *q++ = *w++); 624 } 625 else { 626 *q++ = *p++; 627 } 628 } 629 } 630 else { 631 for (p = line; *p != '\0'; /*VOID*/){ 632 if (isalnum(*p)) { 633 for (w = word; *p && iswordc(*p); ) *w++ = *p++; 634 *w = 0; 635 if (wp = wordsearch(word)){ 636 if (wp->wi_expanding) 637 bibwarning("Recursive definition for %s\n", word); 638 else { 639 strcpy(word, wp->wi_def); 640 wp->wi_expanding = true; 641 expand(word); 642 wp->wi_expanding = false; 643 } 644 } 645 for (w = word; *w != '\0'; *q++ = *w++); 646 } 647 else if (*p == '\\' && *(p+1) != '\0') { 648 *q++ = *p++; 649 *q++ = *p++; 650 } 651 else { 652 *q++ = *p++; 653 } 654 } 655 } 656 *q = 0; 657 strcpy(line, line2); 658 } 659 660 /* wordstuff- save a word and its definition, building a hash table */ 661 wordstuff(word, def) 662 char *word, *def; 663 { 664 int i; 665 if (wordtop >= MAXDEFS) 666 error("too many definitions, max of %d", MAXDEFS); 667 words[wordtop].wi_length = strlen(word); 668 words[wordtop].wi_word = word ? walloc(word) : NULL; 669 words[wordtop].wi_def = def ? walloc(def) : NULL; 670 i = strhash(word); 671 words[wordtop].wi_expanding = false; 672 words[wordtop].wi_hp = wordhash[i]; 673 wordhash[i] = &words[wordtop]; 674 wordtop++; 675 } 676 struct wordinfo *wordsearch(word) 677 char *word; 678 { 679 reg int lg; 680 reg struct wordinfo *wp; 681 lg = strlen(word); 682 for (wp = wordhash[strhash(word)]; wp; wp = wp->wi_hp){ 683 if (wp->wi_length == lg && (strcmp(wp->wi_word, word) == 0)){ 684 return(wp); 685 } 686 } 687 return(0); 688 } 689 /* wordrestuff - save a word and its definition, but replace any existing 690 * definition; this could be more efficient, but it is only used to 691 * redefine BMACLIB at the present. -ads 8/88 692 */ 693 wordrestuff(word, def) 694 char *word, *def; 695 { 696 struct wordinfo *wp = wordsearch(word); 697 if (wp == NULL) wordstuff(word, def); 698 else { 699 if (wp->wi_word != NULL) free(wp->wi_word); 700 if (wp->wi_def != NULL) free(wp->wi_def); 701 wp->wi_length = strlen(word); 702 wp->wi_word = word ? walloc(word) : NULL; 703 wp->wi_def = def ? walloc(def) : NULL; 704 wp->wi_expanding = false; 705 } 706 } 707 708 int strhash(str) 709 reg char *str; 710 { 711 reg int value = 0; 712 for (value = 0; *str; value <<= 2, value += *str++)/*VOID*/; 713 value %= HASHSIZE; 714 if (value < 0) 715 value += HASHSIZE; 716 return(value); 717 } 718 719 /* rdref - read text for an already cited reference */ 720 rdref(p, ref) 721 struct refinfo *p; 722 char ref[REFSIZE]; 723 { 724 ref[0] = 0; 725 #ifndef INCORE 726 #ifdef READWRITE 727 fixrfd( READ ); /* fix access mode of rfd, if nec. */ 728 #endif 729 fseek(rfd, p->ri_pos, 0); 730 fread(ref, p->ri_length, 1, rfd); 731 #else INCORE 732 strcpy(ref, p->ri_ref); 733 #endif INCORE 734 } 735 736 /* wrref - write text for a new reference */ 737 wrref(p, ref) 738 struct refinfo *p; 739 char ref[REFSIZE]; 740 { 741 #ifndef INCORE 742 #ifdef READWRITE 743 fixrfd( WRITE ); /* fix access mode of rfd, if nec. */ 744 #else 745 fseek(rfd, p->ri_pos, 0); /* go to end of rfd */ 746 #endif 747 fwrite(ref, p->ri_length, 1, rfd); 748 #else INCORE 749 p->ri_ref = walloc(ref); 750 #endif INCORE 751 } 752 753 /* breakname - break a name into first and last name */ 754 breakname(line, first, last) 755 char line[], first[], last[]; 756 { reg char *t, *f, *q, *r, *p; 757 758 for (t = line; *t != '\n'; t++); 759 for (t--; isspace(*t); t--); 760 761 /* now strip off last name */ 762 for (q = t; isspace(*q) == 0 || ((*q == ' ') & (*(q-1) == '\\')); q--) 763 if (q == line) 764 break; 765 f = q; 766 if (q != line) { 767 q++; 768 for (; isspace(*f); f--); 769 f++; 770 } 771 772 /* first name is start to f, last name is q to t */ 773 774 for (r = first, p = line; p != f; ) 775 *r++ = *p++; 776 *r = 0; 777 for (r = last, p = q, t++; q != t; ) 778 *r++ = *q++; 779 *r = 0; 780 781 } 782 783 /* match - see if string1 is a substring of string2 (case independent)*/ 784 int match(str1, str2) 785 reg char str1[], str2[]; 786 { reg int j, i; 787 char a, b; 788 789 for (i = 0; str2[i]; i++) { 790 for (j = 0; str1[j]; j++) { 791 if (isupper(a = str2[i+j])) 792 a = (a - 'A') + 'a'; 793 if (isupper(b = str1[j])) 794 b = (b - 'A') + 'a'; 795 if (a != b) 796 break; 797 } 798 if (str1[j] == 0) 799 return(true); 800 } 801 return(false); 802 } 803 804 /* scopy - append a copy of one string to another */ 805 char *scopy(p, q) 806 reg char *p, *q; 807 { 808 while (*p++ = *q++) 809 ; 810 return(--p); 811 } 812 813 /* rcomp - reference comparison routine for qsort utility */ 814 int rcomp(ap, bp) 815 struct refinfo *ap, *bp; 816 { char ref1[REFSIZE], ref2[REFSIZE], field1[MAXFIELD], field2[MAXFIELD]; 817 reg char *p, *q; 818 char *getfield(); 819 int neg, res; 820 int fields_found; 821 822 rdref(ap, ref1); 823 rdref(bp, ref2); 824 for (p = sortstr; *p; p = q) { 825 if (*p == '-') { 826 p++; 827 neg = true; 828 } 829 else 830 neg = false; 831 q = getfield(p, field1, ref1); 832 fields_found = true; 833 if (q == 0) { 834 res = 1; 835 fields_found = false; 836 } else if (strcmp (field1, "") == 0) { /* field not found */ 837 if (*p == 'A') { 838 getfield("F", field1, ref1); 839 if (strcmp (field1, "") == 0) { 840 getfield("I", field1, ref1); 841 if (strcmp (field1, "") == 0) { 842 res = 1; 843 fields_found = false; 844 } 845 } 846 } else { 847 res = 1; 848 fields_found = false; 849 } 850 } 851 852 if (getfield(p, field2, ref2) == 0) { 853 res = -1; 854 fields_found = false; 855 } else if (strcmp (field2, "") == 0) { /* field not found */ 856 if (*p == 'A') { 857 getfield("F", field2, ref2); 858 if (strcmp (field2, "") == 0) { 859 getfield("I", field2, ref2); 860 if (strcmp (field2, "") == 0) { 861 res = -1; 862 fields_found = false; 863 } 864 } 865 } else { 866 res = -1; 867 fields_found = false; 868 } 869 } 870 if (fields_found) { 871 if (*p == 'A') { 872 if (isupper(field1[0])) 873 field1[0] -= 'A' - 'a'; 874 if (isupper(field2[0])) 875 field2[0] -= 'A' - 'a'; 876 } 877 res = strcmp(field1, field2); 878 } 879 if (neg) 880 res = - res; 881 if (res != 0) 882 break; 883 } 884 if (res == 0) 885 if (ap < bp) 886 res = -1; 887 else 888 res = 1; 889 return(res); 890 } 891 892 /* makecites - make standard citation strings, using citetemplate currently in effect */ 893 makecites() 894 { char ref[REFSIZE], tempcite[100], *malloc(); 895 reg int i; 896 897 for (i = 0; i < numrefs; i++) { 898 rdref(&refinfo[i], ref); 899 bldcite(tempcite, i, ref); 900 refinfo[i].ri_cite = malloc(2 + strlen(tempcite)); 901 if (refinfo[i].ri_cite == NULL) 902 error("out of storage"); 903 strcpy(refinfo[i].ri_cite, tempcite); 904 } 905 } 906 907 /* bldcite - build a single citation string */ 908 bldcite(cp, i, ref) 909 char *cp, ref[]; 910 int i; 911 { reg char *p, *q, *fp; 912 char c; 913 char field[REFSIZE]; 914 char *getfield(), *aabet(), *aabetlast(), 915 *fullaabet(), *multfull(); 916 917 getfield("F", field, ref); 918 if (field[0] != 0) 919 for (p = field; *p; p++) 920 *cp++ = *p; 921 else { 922 p = citetemplate; 923 field[0] = 0; 924 while (c = *p++) { 925 if (isalpha(c)) { /* field name */ 926 q = getfield(p-1, field, ref); 927 if (q != 0) { 928 p = q; 929 for (fp = field; *fp; ) 930 *cp++ = *fp++; 931 } 932 } 933 else if (c == '1') { /* numeric order */ 934 sprintf(field,"%d",1 + i); 935 for (fp = field; *fp; ) 936 *cp++ = *fp++; 937 } 938 else if (c == '2') /* alternate alphabetic */ 939 cp = aabet(cp, ref); 940 else if (c == '3') /* Astrophysical Journal style*/ 941 cp = multfull(cp, ref, 3); 942 else if (c == '4') /* Computing Surveys style*/ 943 cp = multfull(cp, ref, 2); 944 else if (c == '8') /* Full alphabetic */ 945 cp = fullaabet(cp, ref); 946 else if (c == '9') /* Last name of Senior Author*/ 947 cp = aabetlast(cp, ref); 948 else if (c == '0') { /* print nothing */ 949 for (fp = field; *fp; ) 950 *cp++ = *fp++; 951 } 952 else if (c == '{') { /* other information */ 953 while (*p != '}') 954 if (*p == 0) 955 error("unexpected end of citation template"); 956 else 957 *cp++ = *p++; 958 p++; 959 } 960 else if (c == '<') { 961 while (*p != '>') { 962 if (*p == 0) 963 error("unexpected end of citation template"); 964 else 965 *cp++ = *p++; 966 } 967 p++; 968 } 969 else if (c != '@') 970 *cp++ = c; 971 } 972 } 973 *cp++ = 0; 974 } 975 976 /* alternate alphabetic citation style - 977 if 1 author - first three letters of last name 978 if 2 authors - first two letters of first, followed by first letter of 979 seond 980 if 3 or more authors - first letter of first three authors */ 981 char *aabet(cp, ref) 982 char *cp, ref[]; 983 { char field[REFSIZE], temp[100]; 984 reg char *np, *fp; 985 int j, getname(); 986 987 if (getname(1, field, temp, ref)) { 988 np = cp; 989 fp = field; 990 for (j = 1; j <= 3; j++) 991 if (*fp != 0) 992 *cp++ = *fp++; 993 if (getname(2, field, temp, ref)) 994 np[2] = field[0]; 995 if (getname(3, field, temp, ref)) { 996 np[1] = np[2]; 997 np[2] = field[0]; 998 } 999 } 1000 return(cp); 1001 } 1002 1003 /* alternate alphabetic citation style - 1004 first two characters of last names of all authors 1005 up to max_klen characters. 1006 */ 1007 char *fullaabet(cp, ref) 1008 char *cp, ref[]; 1009 { char field[REFSIZE], temp[100]; 1010 reg char *fp; 1011 char *lastcp; 1012 int getname(); 1013 int i; 1014 1015 lastcp = cp + max_klen; 1016 for (i= 1; getname(i, field, temp, ref); i++) { 1017 for (fp = field; *fp && (fp < &(field[3])); ) 1018 if (cp > lastcp) 1019 break; 1020 else if (isalpha(*fp)) 1021 *cp++ = *fp++; 1022 else 1023 fp++; 1024 } 1025 return(cp); 1026 } 1027 1028 1029 /* alternate alphabetic citation style - 1030 entire last name of senior author 1031 */ 1032 char *aabetlast(cp, ref) 1033 char *cp, ref[]; 1034 { char field[REFSIZE], temp[100]; 1035 reg char *fp; 1036 int getname(); 1037 1038 if (getname(1, field, temp, ref)) { 1039 for (fp = field; *fp; ) 1040 *cp++ = *fp++; 1041 } 1042 return(cp); 1043 } 1044 1045 /* 1046 Multiple full authors last names (1, 2 or 3 full names). 1047 1048 If maxauthors<3 1049 if 1 author - last name date 1050 if 2 authors - last name and last name date 1051 if 3 or more authors - last name et al. date 1052 If maxauthors>=3 1053 if 1 author - last name date 1054 if 2 authors - last name and last name date 1055 if 3 authors - last name, last name and last name date 1056 if 4 or more authors - last name et al. date */ 1057 char *multfull(cp, ref, maxauthors) 1058 char *cp, ref[]; 1059 int maxauthors; 1060 { char name1[100], name2[100], name3[100], temp[100]; 1061 reg char *fp; 1062 int getname(); 1063 1064 if (getname(1, name1, temp, ref)) { 1065 for (fp = name1; *fp; ) 1066 *cp++ = *fp++; 1067 if (((maxauthors >= 3) && (getname(4, name3, temp, ref))) 1068 || ((maxauthors < 3) && (getname(3, name3, temp, ref)))) { 1069 for (fp = " \\*(e]"; *fp; ) 1070 *cp++ = *fp++; 1071 } 1072 else if (getname(2, name2, temp, ref)) { 1073 if (getname(3, name3, temp, ref)) { 1074 for (fp = "\\*(c]"; *fp; ) 1075 *cp++ = *fp++; 1076 for (fp = name2; *fp; ) 1077 *cp++ = *fp++; 1078 for (fp = "\\*(m]"; *fp; ) 1079 *cp++ = *fp++; 1080 for (fp = name3; *fp; ) 1081 *cp++ = *fp++; 1082 } 1083 else { 1084 for (fp = "\\*(n]"; *fp; ) 1085 *cp++ = *fp++; 1086 for (fp = name2; *fp; ) 1087 *cp++ = *fp++; 1088 } 1089 } 1090 } 1091 return(cp); 1092 } 1093 1094 /* getfield - get a single field from reference */ 1095 char *getfield(ptr, field, ref) 1096 char *ptr, field[], ref[]; 1097 { reg char *p, *q; 1098 char temp[100]; 1099 int n, len, i, getname(); 1100 1101 field[0] = 0; 1102 if (*ptr == 'A') 1103 getname(1, field, temp, ref); 1104 else 1105 for (p = ref; *p != '\0'; p++) 1106 if (*p == '%' && *(p+1) == *ptr) { 1107 for (p = p + 2; isspace(*p); p++) 1108 ; 1109 for (q = field; (*p != '\n') && (*p != '\0'); ) 1110 *q++ = *p++; 1111 *q = 0; 1112 break; 1113 } 1114 n = 0; 1115 len = strlen(field); 1116 if (*++ptr == '-') { 1117 for (ptr++; isdigit(*ptr); ptr++) 1118 n = 10 * n + (*ptr - '0'); 1119 if (n > len) 1120 n = 0; 1121 else 1122 n = len - n; 1123 for (i = 0; field[i] = field[i+n]; i++) 1124 ; 1125 } 1126 else if (isdigit(*ptr)) { 1127 for (; isdigit(*ptr); ptr++) 1128 n = 10 * n + (*ptr - '0'); 1129 if (n > len) 1130 n = len; 1131 field[n] = 0; 1132 } 1133 1134 if (*ptr == 'u') { 1135 ptr++; 1136 for (p = field; *p; p++) 1137 if (islower(*p)) 1138 *p = (*p - 'a') + 'A'; 1139 } 1140 else if (*ptr == 'l') { 1141 ptr++; 1142 for (p = field; *p; p++) 1143 if (isupper(*p)) 1144 *p = (*p - 'A') + 'a'; 1145 } 1146 return(ptr); 1147 } 1148 1149 /* getname - get the nth name field from reference, breaking into 1150 first and last names */ 1151 int getname(n, last, first, ref) 1152 int n; 1153 char last[], first[], ref[]; 1154 { reg char *p; 1155 int m; 1156 1157 m = n; 1158 for (p = ref; *p; p++) 1159 if (*p == '%' & *(p+1) == 'A') { 1160 n--; 1161 if (n == 0) { 1162 for (p = p + 2; *p == ' '; p++) ; 1163 breakname(p, first, last) ; 1164 return(true); 1165 } 1166 } 1167 1168 if (n == m) /* no authors, try editors */ 1169 for (p = ref; *p; p++) 1170 if (*p == '%' & *(p+1) == 'E') { 1171 n--; 1172 if (n == 0) { 1173 for (p = p + 2; *p == ' '; p++) ; 1174 breakname(p, first, last) ; 1175 return(true); 1176 } 1177 } 1178 1179 if (n == m) { /* no editors, either, try institution */ 1180 first[0] = last[0] = '\0'; 1181 getfield("I", last, ref); 1182 if (last[0] != '\0') 1183 return(true); 1184 } 1185 1186 return(false); 1187 } 1188 1189 /* disambiguate - compare adjacent citation strings, and if equal, add 1190 single character disambiguators */ 1191 disambiguate() 1192 { reg int i, j; 1193 char adstr; 1194 1195 for (i = 0; i < numrefs-1; i = j) { 1196 j = i + 1; 1197 if (strcmp(refinfo[i].ri_cite, refinfo[j].ri_cite)==0) { 1198 adstr = 'a'; 1199 for(j = i+1; 1200 j<numrefs && strcmp(refinfo[i].ri_cite,refinfo[j].ri_cite) == 0; 1201 j++) { 1202 adstr = 'a' + (j-i); 1203 refinfo[j].ri_disambig[0] = adstr; 1204 } 1205 refinfo[i].ri_disambig[0] = 'a'; 1206 } 1207 } 1208 for (i = 0; i < numrefs; i++){ 1209 strcat(refinfo[i].ri_cite, refinfo[i].ri_disambig); 1210 } 1211 } 1212 1213 1214 /* bldname - build a name field 1215 doing abbreviations, reversals, and caps/small caps 1216 */ 1217 bldname(first, last, name, reverse) 1218 char *first, *last, name[]; 1219 int reverse; 1220 { 1221 char newfirst[120], newlast[120]; 1222 reg char *p, *q, *f, *l; 1223 char *scopy(); 1224 int flag; 1225 1226 if (abbrev) { 1227 p = first; 1228 q = newfirst; 1229 flag = false; 1230 while (*p) { 1231 while (*p == ' ') 1232 p++; 1233 if (*p == 0) 1234 break; 1235 if (isupper(*p)) { 1236 if (flag) /* between initial gap */ 1237 q = scopy(q, "\\*(a]"); 1238 flag = true; 1239 *q++ = *p; 1240 q = scopy(q, "\\*(p]"); 1241 } 1242 if (*++p == '.') 1243 p++; 1244 else while (*p != 0 && ! isspace(*p)) 1245 p++; 1246 } 1247 *q = 0; 1248 f = newfirst; 1249 } 1250 else 1251 f = first; 1252 1253 if (capsmcap) { 1254 p = last; 1255 q = newlast; 1256 flag = 0; /* 1 - printing cap, 2 - printing small */ 1257 while (*p) 1258 if (islower(*p)) { 1259 if (flag != 2) 1260 q = scopy(q, "\\s-2"); 1261 flag = 2; 1262 *q++ = (*p++ - 'a') + 'A'; 1263 } 1264 else { 1265 if (flag == 2) 1266 q = scopy(q,"\\s+2"); 1267 flag = 1; 1268 *q++ = *p++; 1269 } 1270 if (flag == 2) 1271 q = scopy(q, "\\s+2"); 1272 *q = 0; 1273 l = newlast; 1274 } 1275 else 1276 l = last; 1277 1278 if (f[0] == 0) 1279 sprintf(name, "%s\n", l); 1280 else if (reverse) 1281 sprintf(name, "%s\\*(b]%s\n", l, f); 1282 else 1283 sprintf(name, "%s %s\n", f, l); 1284 } 1285 1286 /* prtauth - print author or editor field */ 1287 prtauth(c, line, num, max, ofd, abbrev, capsmcap, numrev) 1288 char c, *line; 1289 int num, max, abbrev, capsmcap, numrev; 1290 FILE *ofd; 1291 { char first[LINELENGTH], last[LINELENGTH]; 1292 1293 if (num <= numrev || abbrev || capsmcap) { 1294 breakname(line, first, last); 1295 bldname(first, last, line, num <= numrev); 1296 } 1297 if (num == 1) 1298 fprintf(ofd,".ds [%c %s", c, line); 1299 else if (num < max) 1300 fprintf(ofd,".as [%c \\*(c]%s", c, line); 1301 else if (max == 2) 1302 fprintf(ofd,".as [%c \\*(n]%s", c, line); 1303 else 1304 fprintf(ofd,".as [%c \\*(m]%s", c, line); 1305 if (num == max && index(trailstr, c)) 1306 fprintf(ofd,".ds ]%c %c\n", c, line[strlen(line)-2]); 1307 } 1308 1309 /* doline - actually print out a line of reference information */ 1310 doline(c, line, numauths, maxauths, numeds, maxeds, ofd) 1311 char c, *line; 1312 int numauths, maxauths, numeds, maxeds; 1313 FILE *ofd; 1314 { 1315 int appending; 1316 1317 switch(c) { 1318 case 'A': 1319 prtauth(c, line, numauths, maxauths, ofd, abbrev, capsmcap, numrev); 1320 break; 1321 1322 case 'E': 1323 prtauth(c, line, numeds, maxeds, ofd, edabbrev, edcapsmcap, ednumrev); 1324 if (numeds == maxeds) 1325 fprintf(ofd,".nr [E %d\n", maxeds); 1326 break; 1327 1328 case 'P': 1329 if (index(line, '-')) 1330 fprintf(ofd,".nr [P 1\n"); 1331 else 1332 fprintf(ofd,".nr [P 0\n"); 1333 fprintf(ofd,".ds [P %s",line); 1334 if (index(trailstr, 'P')) 1335 fprintf(ofd,".ds ]P %c\n",line[strlen(line)-2]); 1336 break; 1337 1338 case 'F': break; 1339 1340 /* these now accumulate their entries */ 1341 /* defined by official bib documentation */ 1342 case 'K': case 'O': case 'W': 1343 /* not defined by official bib documentation */ 1344 case 'H': case 'L': case 'M': case 'Q': case 'U': case 'X': case 'Y': 1345 case 'Z': 1346 appending = letterSeen[c]; 1347 letterSeen[c] = true; 1348 if (appending) 1349 fprintf(ofd, ".as [%c , %s", c, line); 1350 else 1351 fprintf(ofd, ".ds [%c %s", c, line); 1352 if (index(trailstr, c)) 1353 fprintf(ofd, ".ds ]%c %c\n", c, line[strlen(line) - 2]); 1354 break; 1355 1356 default: 1357 if (!isupper(c)) break; /* ignore what you don't understand */ 1358 fprintf(ofd,".ds [%c %s", c, line); 1359 if (index(trailstr, c)) 1360 fprintf(ofd,".ds ]%c %c\n", c, line[strlen(line)-2]); 1361 } 1362 } 1363 1364 /* dumpref - dump reference number i */ 1365 dumpref(i, ofd) 1366 int i; 1367 FILE *ofd; 1368 { char ref[REFSIZE], line[REFSIZE]; 1369 reg char *p, *q; 1370 char *from; 1371 int numauths, maxauths, numeds, maxeds; 1372 int j; 1373 1374 if ( i < 0 ) ref[0] = 0; /* ref not found */ 1375 else { 1376 rdref(&refinfo[i], ref); 1377 maxauths = maxeds = 0; 1378 numauths = numeds = 0; 1379 for (j=0; j < 128; j++) letterSeen[j] = 0; 1380 for (p = ref; *p; p++) 1381 if (*p == '%') 1382 if (*(p+1) == 'A') maxauths++; 1383 else if (*(p+1) == 'E') maxeds++; 1384 fprintf(ofd, ".[-\n"); 1385 fprintf(ofd, ".ds [F %s\n", refinfo[i].ri_cite); 1386 #ifndef INCORE 1387 fseek(rfd, (long)refinfo[i].ri_pos, 0); 1388 while (fgets(line, REFSIZE, rfd) != NULL) { 1389 #else INCORE 1390 for (q = line, from = refinfo[i].ri_ref; *from; /*VOID*/) { /*} */ 1391 if (*from == '\n'){ 1392 *q++ = '\n'; 1393 *q = 0; 1394 q = line; 1395 from++; 1396 } else { 1397 *q++ = *from++; 1398 continue; 1399 } 1400 #endif INCORE 1401 switch(line[0]){ 1402 case 0: 1403 goto doneref; 1404 case '.': 1405 fprintf(ofd, "%s", line); 1406 break; 1407 case '%': 1408 switch(line[1]){ 1409 case 'A': numauths++; break; 1410 case 'E': numeds++; break; 1411 } 1412 for (p = &line[2]; *p == ' '; p++) /*VOID*/; 1413 doline(line[1], p, numauths, maxauths, numeds, maxeds, ofd); 1414 } 1415 } 1416 doneref:; 1417 fprintf(ofd,".][\n"); 1418 } 1419 } 1420