|
|
1.1 ! root 1: /* ! 2: * prefer - bibligraphy formatter ! 3: * ! 4: * Marcia Derr ! 5: * February 26, 1988 ! 6: * ! 7: * input: (stdin) text containing prefer commands; ! 8: * output: (stdout) text with formatted citations and reference list ! 9: */ ! 10: ! 11: ! 12: ! 13: #include <stdio.h> ! 14: #include <ctype.h> ! 15: #include <signal.h> ! 16: #include <sys/types.h> ! 17: #include <sys/stat.h> ! 18: ! 19: #ifdef SVR2 /* for UNIX System V */ ! 20: #include <fcntl.h> ! 21: #define dup2(fildes, fildes2) close(fildes2);fcntl(fildes, F_DUPFD, fildes2) ! 22: #endif ! 23: ! 24: #include "streams.h" ! 25: #include "bib.h" ! 26: ! 27: ! 28: /* prefer commands */ ! 29: #define REF_CITE "reference" ! 30: #define REF_STYLE "reference_style" ! 31: #define REF_PLACE "reference_placement" ! 32: #define REF_LIST "reference_list" ! 33: #define REF_DB "reference_database" ! 34: #define REF_INCLUDE "reference_include" ! 35: ! 36: /* control words to awk */ ! 37: #define LETS_GO "%LETS_GO" ! 38: #define BEGIN_CITE "%BEGIN_CITE" ! 39: #define END_CITE "%END_CITE" ! 40: #define END_LIST "%END_LIST" ! 41: #define BIBLIO "%BIBLIO" ! 42: #define WHOLEBIB "%WHOLEBIB" ! 43: #define DBINCLUDE "%DBINCLUDE" ! 44: #define TYPE "%type" ! 45: #define TWOPASS "%TWOPASS\n" ! 46: #define ALSO "%also" ! 47: #define ALSOBEGIN "%also_begin" ! 48: #define ALSOEND "%also_end" ! 49: ! 50: #define DSTYLE "att" /* default style */ ! 51: #define STYLEDIR "/styles/" /* style directory */ ! 52: #define AWK "prefawk" /* special awk version */ ! 53: ! 54: #define PREFERTMP "/tmp/preferXXXXXX" ! 55: #define MAXTOK 2500 ! 56: #define BAR '|' ! 57: #define SLASH "/" ! 58: ! 59: ! 60: char stylename[maxstr] = "", /* set by style(), options */ ! 61: awkline[MAXTOK]; /* for passing to/from awk */ ! 62: ! 63: FILE *readtext, /* input text */ ! 64: *writetext, /* output text */ ! 65: *readbib, /* from awk */ ! 66: *writebib, /* to awk */ ! 67: *savefile; /* save original file when diverting to temp */ ! 68: ! 69: int nroff = 0; /* nroff/troff flag */ ! 70: int prmult = 0; /* print multiple references */ ! 71: int rp = 0; /* released_paper/tm flag */ ! 72: int sort = 0; /* order flag for reference_list */ ! 73: char sortkey[maxstr] = ""; /* sort keys (eg adt) */ ! 74: int haveeof = 0; /* flag eof in input file */ ! 75: ! 76: char INDEX[maxstr]; /* name of index file */ ! 77: char *DINPUT = BIBFILE; /* default input file */ ! 78: char *divertname; /* two pass output is diverted here */ ! 79: int pass = 0; /* indicates how many text passes are required */ ! 80: ! 81: int argc; ! 82: char **argv; ! 83: ! 84: typedef enum {T_OPEN, T_CLOSE, T_COMMAND, T_REFER, T_WORD, T_EOF} TOKEN; ! 85: typedef enum {NORMAL, END, BIBLIST} bibflag; ! 86: enum {OK, NONE} awkstate = NONE; ! 87: ! 88: ! 89: char tok[MAXTOK]; /* for get_token */ ! 90: TOKEN type; /* type returned by get_token */ ! 91: char right; /* expected right delimeter */ ! 92: ! 93: int cleanup(); ! 94: char *strchr(); ! 95: char *libpath(); ! 96: TOKEN get_token(); ! 97: char *mktemp(), ! 98: *locate(), ! 99: *gulpnl(), ! 100: *realloc(), ! 101: *strtok(); ! 102: ! 103: #define leftdelim { \ ! 104: if((type = get_token(tok,0)) != T_OPEN) { \ ! 105: token_err(type,"Expecting left delimiter, got %s\n",tok); \ ! 106: } \ ! 107: right = getright(*tok); \ ! 108: } ! 109: ! 110: #define rightdelim { \ ! 111: if (type != T_CLOSE) \ ! 112: token_err(type,"Expecting right delimeter, got %s\n",tok); \ ! 113: post_command(); \ ! 114: } ! 115: ! 116: ! 117: #define USAGE "prefer [-p database -s style -n -o key -r] [filename]\n" ! 118: ! 119: #ifdef _NFILE ! 120: #define FILENUM _NFILE ! 121: #else ! 122: #define FILENUM 20 ! 123: #endif ! 124: ! 125: ! 126: ! 127: /* ! 128: * main - process prefer command line ! 129: */ ! 130: ! 131: main(argcount,arglist) ! 132: int argcount; ! 133: char **arglist; ! 134: { ! 135: ! 136: /* ! 137: * set up signals, get options flags, and process command line arguments; ! 138: * make path names; setup I/O ! 139: */ ! 140: if(signal(SIGINT, SIG_IGN) != SIG_IGN) ! 141: signal(SIGINT, cleanup); ! 142: signal(SIGQUIT, cleanup); ! 143: argc= argcount-1; ! 144: argv= arglist+1; ! 145: ! 146: strcpy(stylename,DSTYLE); ! 147: strcpy(INDEX,DINPUT); ! 148: ! 149: flags(); ! 150: strcat(INDEX,".i"); ! 151: ! 152: switch(argc) { ! 153: case 0: ! 154: readtext = stdin; ! 155: break; ! 156: case 1: ! 157: if((readtext = fopen(*argv,"r")) == NULL) ! 158: errexit(1,"error opening textfile %s\n",*argv); ! 159: break; ! 160: default: ! 161: errexit(1,USAGE); ! 162: } ! 163: writetext = stdout; ! 164: ! 165: /* ! 166: * now filter text for prefer commands ! 167: */ ! 168: scan_text(); ! 169: exit(0); ! 170: ! 171: } ! 172: ! 173: ! 174: /* ! 175: * get option flags ! 176: * ! 177: * -n set nroff flag (default troff) ! 178: * -o set sort flag for listing entire bibliographies (default sequence) ! 179: * -p pathname of database file (default BIBFILE) ! 180: * -r set rp (released paper) flag (default tm) ! 181: * -s set style (default att) ! 182: */ ! 183: ! 184: # define operand (strlen(*argv+2)==0 ? (argv++,argc--,*argv) : *argv+2) ! 185: ! 186: flags() ! 187: { ! 188: for (; argc>0 && *argv[0]=='-'; argc--,argv++) { ! 189: switch ((*argv)[1]) { ! 190: case 'c': ! 191: case 'l': fprintf(stderr,USAGE); ! 192: break; ! 193: case 'm': prmult = 1; ! 194: break; ! 195: case 'n': nroff = 1; ! 196: break; ! 197: case 'o': sort = 1; ! 198: strcpy(sortkey,operand); ! 199: break; ! 200: case 'p': strcpy(INDEX,operand); ! 201: break; ! 202: case 'r': rp = 1; ! 203: break; ! 204: case 's': strcpy(stylename,operand); ! 205: break; ! 206: default: errexit(1, USAGE); ! 207: } ! 208: } ! 209: } ! 210: ! 211: ! 212: /* ! 213: * scan_text ! 214: * ! 215: * filter text for prefer commands (beginning with '|') and pass ! 216: * these off to do_command ! 217: */ ! 218: ! 219: scan_text() ! 220: { ! 221: register int c, lastc; ! 222: char space[maxstr]; ! 223: ! 224: lastc = 0; ! 225: for(;;) { ! 226: ! 227: /* ! 228: * if EOF, put out last saved character and space; ! 229: * finish processing references; close awk ! 230: */ ! 231: if((c = gobble(space)) == EOF) { ! 232: if(lastc) putc(lastc,writetext); ! 233: lastc = 0; ! 234: if(*space) fputs(space, writetext); ! 235: if(awkstate == OK) { ! 236: biblio(END); ! 237: continue; ! 238: } ! 239: break; ! 240: } ! 241: ! 242: /* ! 243: * if a '|' then call do_command to process it ! 244: */ ! 245: if(c == BAR) { ! 246: ! 247: /* checkfor preceding punctuation */ ! 248: ! 249: if(lastc == 0134 && !*space) { /* backslash */ ! 250: putc(lastc,writetext); ! 251: lastc = c; ! 252: continue; ! 253: } ! 254: if(!ismypunct(lastc)) { ! 255: if(lastc) { ! 256: putc(lastc,writetext); ! 257: lastc = 0; ! 258: } ! 259: } ! 260: do_command(lastc,space); ! 261: lastc = 0; ! 262: continue; ! 263: } ! 264: ! 265: if(lastc) putc(lastc,writetext); ! 266: if(*space) fputs(space,writetext); ! 267: lastc = c; ! 268: } ! 269: if(awkstate != NONE) ! 270: awkclose(readbib,writebib); ! 271: } ! 272: ! 273: ! 274: /* ! 275: * parse and execute prefer commands: ! 276: * |reference(...) ! 277: * |reference_style(..) ! 278: * |reference_database(...) ! 279: * |reference_list(...) ! 280: * |reference_placement ! 281: */ ! 282: ! 283: do_command(ppunc,white) ! 284: int ppunc; /* punctuation preceding command */ ! 285: char *white; /* white space preceding command */ ! 286: { ! 287: register int cite_list, /* flag "in a citation list" */ ! 288: c; /* for reading characters */ ! 289: char space[maxstr]; /* gobbled space goes here */ ! 290: ! 291: /* ! 292: * '|' has already been read; now read command and dispatch ! 293: */ ! 294: cite_list = 0; ! 295: for(;;) { ! 296: ! 297: /* ! 298: * if space after BAR; finish citation list put out white space and punc ! 299: */ ! 300: c=gobble(space); ! 301: if(*space) { ! 302: if(cite_list) { ! 303: end_citations(ppunc); ! 304: } ! 305: else { ! 306: if(ppunc) putc(ppunc,writetext); ! 307: if(*white) fputs(white,writetext); ! 308: } ! 309: putc(BAR,writetext); ! 310: fputs(space,writetext); ! 311: if(c != EOF) ungetc(c,readtext); ! 312: return; ! 313: } ! 314: /* ! 315: * at EOF, put out any citation list ! 316: */ ! 317: if(c == EOF) { ! 318: if(cite_list) { ! 319: end_citations(ppunc); ! 320: cite_list == 0; ! 321: } ! 322: putc(BAR,writetext); ! 323: return; ! 324: } ! 325: else ! 326: ungetc(c,readtext); ! 327: ! 328: ! 329: /* ! 330: * process one or more citations ! 331: */ ! 332: get_token(tok,0); ! 333: if(strcmp(tok,REF_CITE) == 0) { ! 334: *white = NULL; ! 335: citation(); ! 336: cite_list = 1; ! 337: if((c = gobble(white)) == BAR) ! 338: continue; ! 339: else if (*white || !ismypunct(c)) { ! 340: end_citations(ppunc); ! 341: if(*white) fputs(white,writetext); ! 342: if(c != EOF) ungetc(c,readtext); ! 343: } ! 344: else { ! 345: if(ppunc) putc(ppunc,writetext); ! 346: end_citations(c); ! 347: } ! 348: return; ! 349: } ! 350: ! 351: /* ! 352: * end a list of citations or if no citation, put out punctuation ! 353: * and white space ! 354: */ ! 355: if(cite_list) end_citations(ppunc); ! 356: else if (ppunc) putc(ppunc,writetext); ! 357: if (*white) { ! 358: fputs(white,writetext); ! 359: } ! 360: ! 361: ! 362: /* ! 363: * process style, placement, list, or db commands ! 364: */ ! 365: if(strcmp(tok,REF_STYLE) == 0) { ! 366: style(); ! 367: return; ! 368: } ! 369: ! 370: else if(strcmp(tok,REF_PLACE) == 0) { ! 371: if(awkstate == OK) biblio(NORMAL); ! 372: if(pass != 2) post_command(); ! 373: return; ! 374: } ! 375: ! 376: else if(strcmp(tok,REF_LIST) == 0) { ! 377: bib_list(); ! 378: return; ! 379: } ! 380: ! 381: else if(strcmp(tok,REF_INCLUDE) == 0) { ! 382: dbinclude(); ! 383: return; ! 384: } ! 385: ! 386: else if(strcmp(tok,REF_DB) == 0) { ! 387: database(); ! 388: return; ! 389: } ! 390: ! 391: /* ! 392: * no command so, put out bar and token ! 393: */ ! 394: else { ! 395: putc(BAR,writetext); ! 396: fputs(tok,writetext); ! 397: return; ! 398: } ! 399: } ! 400: ! 401: } ! 402: ! 403: ! 404: /* ! 405: * ismypunct - test for puctuation ! 406: */ ! 407: ! 408: ismypunct(c) ! 409: int c; ! 410: { ! 411: switch(c) { ! 412: case '.': ! 413: case ',': ! 414: case ';': ! 415: case ':': ! 416: case '?': ! 417: case '!': ! 418: case '"': ! 419: case '\'': ! 420: case '(': ! 421: return(1); ! 422: default: ! 423: return(0); ! 424: } ! 425: } ! 426: ! 427: ! 428: /* ! 429: * getright - given right delimeter, return left ! 430: */ ! 431: ! 432: getright(left) ! 433: char left; ! 434: { ! 435: switch(left) { ! 436: case '(': ! 437: return(')'); ! 438: case '{': ! 439: return('}'); ! 440: case '[': ! 441: return(']'); ! 442: case '<': ! 443: return('>'); ! 444: } ! 445: return(0); ! 446: } ! 447: ! 448: ! 449: /* ! 450: * gobble - gobble up space to the the next non-space character ! 451: * return space and char ! 452: */ ! 453: ! 454: gobble(space) ! 455: char *space; /* gobbled space returned here */ ! 456: { ! 457: register int c; /* non-space character returned here */ ! 458: register char *t; ! 459: ! 460: t = space; ! 461: while(isspace(c = mygetc(readtext))) { ! 462: *t++ = c; ! 463: } ! 464: *t = '\0'; ! 465: return(c); ! 466: } ! 467: ! 468: /* ! 469: * gulp string up thru newline ! 470: */ ! 471: ! 472: char * ! 473: gulpnl(space) ! 474: char *space; ! 475: { ! 476: register char *w; ! 477: for(w=space; *w;) { ! 478: if(*w++ == '\n') ! 479: break; ! 480: } ! 481: return(w); ! 482: } ! 483: ! 484: ! 485: post_command() ! 486: { ! 487: register int c; /* non-space character returned here */ ! 488: while((c = mygetc(readtext)) != EOF) { ! 489: if (c == '\n') ! 490: break; ! 491: else if(!isspace(c)) { ! 492: errexit(1,"prefer command must end with newline\n"); ! 493: } ! 494: } ! 495: } ! 496: ! 497: /* ! 498: * token ! 499: * ! 500: * tokenizer - returns: ! 501: * T_COMMAND anything after a | ! 502: * T_REFER a line starting with % to next % or right delim ! 503: * T_WORDS anthing ! 504: * T_OPEN left delimeter ! 505: * T_CLOSE right delimeter ! 506: * T_WORD anything else (non-space) ! 507: */ ! 508: ! 509: TOKEN ! 510: get_token(value,right) ! 511: char *value; /* token value */ ! 512: char right; /* expected right delimeter */ ! 513: { ! 514: register int c; /* current character */ ! 515: register char *v; /* current position in *value */ ! 516: /* state of tokenizer */ ! 517: ! 518: enum {BEGIN, ANYTHING, REFER, COMMAND, WORD, ENDREFER, CONTINUE} state; ! 519: ! 520: ! 521: if(right == 0) state = BEGIN; ! 522: else state = ANYTHING; ! 523: v = value; ! 524: ! 525: while((c = mygetc(readtext)) != EOF) { ! 526: switch(state) { ! 527: ! 528: case BEGIN: ! 529: switch(c) { ! 530: case '|': ! 531: *v = '\0'; ! 532: ungetc(c,readtext); ! 533: return(T_COMMAND); ! 534: case '(': ! 535: case '[': ! 536: case '{': ! 537: case '<': ! 538: *v++ = c; ! 539: *v = '\0'; ! 540: return(T_OPEN); ! 541: case ' ': ! 542: case '\n': ! 543: case '\t': ! 544: continue; ! 545: default: ! 546: *v++ = c; ! 547: state = COMMAND; ! 548: continue; ! 549: } ! 550: ! 551: case ANYTHING: ! 552: switch(c) { ! 553: case ' ': ! 554: case '\n': ! 555: case '\t': ! 556: continue; ! 557: case '%': ! 558: *v++ = c; ! 559: state = REFER; ! 560: continue; ! 561: case ')': ! 562: case ']': ! 563: case '}': ! 564: case '>': ! 565: if(c == right) { ! 566: *v++ = c; ! 567: *v = '\0'; ! 568: return(T_CLOSE); ! 569: } ! 570: default: ! 571: *v++ = c; ! 572: state = WORD; ! 573: continue; ! 574: } ! 575: ! 576: ! 577: case COMMAND: ! 578: switch(c) { ! 579: case '|': ! 580: case ' ': ! 581: case '\n': ! 582: case '\t': ! 583: case '(': ! 584: case '[': ! 585: case '{': ! 586: case '<': ! 587: *v = '\0'; ! 588: ungetc(c,readtext); ! 589: return(T_COMMAND); ! 590: default: ! 591: *v++ = c; ! 592: continue; ! 593: } ! 594: ! 595: ! 596: case WORD: ! 597: switch(c) { ! 598: case ' ': ! 599: case '\n': ! 600: case '\t': ! 601: case '%': ! 602: *v = '\0'; ! 603: ungetc(c,readtext); ! 604: return(T_WORD); ! 605: case ')': ! 606: case ']': ! 607: case '}': ! 608: case '>': ! 609: if(c == right) { ! 610: *v = '\0'; ! 611: ungetc(c,readtext); ! 612: return(T_WORD); ! 613: } ! 614: default: ! 615: *v++ = c; ! 616: continue; ! 617: } ! 618: ! 619: ! 620: case REFER: ! 621: switch(c) { ! 622: case '\n': ! 623: state = ENDREFER; ! 624: continue; ! 625: case '\\': ! 626: state = CONTINUE; ! 627: continue; ! 628: case ')': ! 629: case ']': ! 630: case '}': ! 631: case '>': ! 632: if(c == right) { ! 633: *v++ = '\n'; ! 634: *v = '\0'; ! 635: ungetc(c,readtext); ! 636: return(T_REFER); ! 637: } ! 638: default: ! 639: *v++ = c; ! 640: continue; ! 641: } ! 642: ! 643: case CONTINUE: ! 644: state = REFER; ! 645: if(c != '\n') { ! 646: *v++ = '\\'; ! 647: *v++ = c; ! 648: } ! 649: continue; ! 650: ! 651: ! 652: case ENDREFER: ! 653: ungetc(c,readtext); ! 654: if(c == '%') { ! 655: *v++ = '\n'; ! 656: *v = '\0'; ! 657: return(T_REFER); ! 658: } ! 659: if(!isspace(c)) *v++ = ' '; ! 660: state = REFER; ! 661: continue; ! 662: } ! 663: } ! 664: haveeof++; ! 665: return(T_EOF); ! 666: } ! 667: ! 668: ! 669: /* ! 670: * token_err - print error message and exit ! 671: */ ! 672: ! 673: token_err(type,s,tok) ! 674: TOKEN type; /* token type in error */ ! 675: char *s, /* error message */ ! 676: *tok; /* error token */ ! 677: { ! 678: if(type == T_EOF) ! 679: errexit(1, "Unexpected EOF\n"); ! 680: else ! 681: errexit(1,s,tok); ! 682: } ! 683: ! 684: ! 685: /* ! 686: * start_awk ! 687: * open awk and handshake to determine one pass or two ! 688: * (listing an entire bibliography is always one pass) ! 689: */ ! 690: ! 691: start_awk(bflag) ! 692: bibflag bflag; /* flag complete bibliography listing (as ! 693: to normal citations and reference list */ ! 694: { ! 695: char awkcmd[maxstr]; /* line to send to awk */ ! 696: struct stat buf; /* for stating style file */ ! 697: ! 698: /* ! 699: * open up awk style script ! 700: * checking to see style is one of the standards or user supplied ! 701: */ ! 702: ! 703: strcpy(awkcmd,stylename); ! 704: if(stat(awkcmd,&buf)) { ! 705: strcpy(awkcmd,libpath(PLIB)); ! 706: strcat(awkcmd,STYLEDIR); ! 707: strcat(awkcmd,stylename); ! 708: } ! 709: awkopen(awkcmd,&readbib,&writebib); ! 710: ! 711: ! 712: /* ! 713: * handshake, sending appropriate flags ! 714: */ ! 715: fputs(LETS_GO,writebib); ! 716: if(nroff) ! 717: fputs(" nroff",writebib); ! 718: else ! 719: fputs(" troff",writebib); ! 720: if(rp) ! 721: fputs(" rp",writebib); ! 722: else ! 723: fputs(" tm",writebib); ! 724: putc('\n',writebib); ! 725: fflush(writebib); ! 726: ! 727: /* ! 728: * read back flag from awk that tells 1 pass or 2; ! 729: * divert text to temp file if two pass ! 730: */ ! 731: if(fgets(awkcmd,maxstr,readbib) == NULL) ! 732: errexit(1,"start_awk: EOF or error from awk\n"); ! 733: if(strcmp(awkcmd,TWOPASS) == 0) { ! 734: if(bflag != BIBLIST) { ! 735: pass = 1; ! 736: savefile = writetext; ! 737: divertname = mktemp(PREFERTMP); ! 738: writetext = fopen(divertname,"w"); ! 739: } ! 740: } ! 741: else pass = 0; ! 742: awkstate = OK; ! 743: } ! 744: ! 745: ! 746: /* ! 747: * citation - process |reference(): ! 748: * use search keys to lookup a complete reference in a bibliographic ! 749: * database; supplement citation with additional %refer lines; ! 750: * send all this to an awk for formatting ! 751: */ ! 752: ! 753: citation() ! 754: { ! 755: char keys[MAXTOK]; /* store keys here */ ! 756: int missing; /* missing flag */ ! 757: ! 758: /* ! 759: * signal start of citation to awk ! 760: */ ! 761: if(awkstate != OK) start_awk(NORMAL); ! 762: missing = 0; ! 763: if(pass != 2) { ! 764: fputs(BEGIN_CITE,writebib); ! 765: putc('\n',writebib); ! 766: } ! 767: ! 768: /* ! 769: * after left delmeter, get keys and search for corresponding reference ! 770: */ ! 771: leftdelim; ! 772: *keys = '\0'; ! 773: while((type = get_token(tok,right)) == T_WORD ) { ! 774: strcat(keys,tok); ! 775: strcat(keys," "); ! 776: } ! 777: if(*keys != '\0') { ! 778: missing = getref(keys); ! 779: } ! 780: ! 781: /* ! 782: * send %lines to awk to supplement citation ! 783: */ ! 784: if(type == T_REFER) { ! 785: refline(); ! 786: while((type = get_token(tok,right)) == T_REFER) { ! 787: refline(); ! 788: } ! 789: } ! 790: ! 791: /* ! 792: * get right delimeter and signal the end of citation ! 793: */ ! 794: if (type != T_CLOSE) ! 795: token_err(type,"Expecting right delimeter, got %s\n",tok); ! 796: ! 797: fputs(END_CITE,writebib); ! 798: if (pass == 2) ! 799: putc('2',writebib); ! 800: putc('\n',writebib); ! 801: fflush(writebib); ! 802: ! 803: /* if two pass, write marker in diverted text */ ! 804: ! 805: if(pass == 1 && missing == 0) ! 806: fprintf(writetext,"|%s[]",REF_CITE); ! 807: } ! 808: ! 809: ! 810: /* ! 811: * pass a %refline to awk, processing %also lines appropriately ! 812: */ ! 813: ! 814: refline() ! 815: { ! 816: if(strncmp(ALSOBEGIN,tok,strlen(ALSOBEGIN)) == 0) { ! 817: fputs(tok,writebib); ! 818: while((type = get_token(tok,right)) == T_REFER) { ! 819: if(strncmp(ALSOEND,tok,strlen(ALSOEND)) == 0) { ! 820: fputs(tok,writebib); ! 821: fflush(writebib); ! 822: break; ! 823: } ! 824: else if(strncmp(ALSO,tok,strlen(ALSO)) == 0) ! 825: seealso(tok); ! 826: else fputs(tok,writebib); ! 827: } ! 828: } ! 829: else if(strncmp(ALSO,tok,strlen(ALSO)) == 0) { ! 830: fputs(ALSOBEGIN,writebib); ! 831: putc('\n',writebib); ! 832: seealso(tok); ! 833: fputs(ALSOEND,writebib); ! 834: putc('\n',writebib); ! 835: fflush(writebib); ! 836: } ! 837: else ! 838: fputs(tok,writebib); ! 839: } ! 840: ! 841: ! 842: /* ! 843: * get reference corresponding to keywords and send it to awk ! 844: */ ! 845: ! 846: int ! 847: getref(keys) ! 848: char *keys; ! 849: { ! 850: char *ref; /* points to complete reference */ ! 851: ! 852: if((ref = locate(keys, INDEX)) == NULL) { ! 853: fprintf(stderr,"Can't open database for %s\n",keys); ! 854: fprintf(writebib,"%s not_found\n",TYPE); ! 855: return(1); ! 856: } ! 857: if(*ref != NULL) { ! 858: if(multiple(ref)) { ! 859: fprintf(stderr,"multiple references for %s\n",keys); ! 860: } ! 861: refwrite(ref); ! 862: free(ref); ! 863: return(0); ! 864: ! 865: } ! 866: else { ! 867: fprintf(stderr,"no reference found for %s\n",keys); ! 868: fprintf(writebib,"%s not_found\n",TYPE); ! 869: free(ref); ! 870: return(1); ! 871: } ! 872: } ! 873: ! 874: ! 875: /* ! 876: * check for multiple new references signalled by two newlines in a row ! 877: */ ! 878: ! 879: multiple(ref) ! 880: char *ref; ! 881: { ! 882: register char *s; ! 883: ! 884: for(s = ref; *s; s++) { ! 885: if (*s == '\n') { ! 886: if(strncmp(s,"\n\n%",3) == 0) { ! 887: if(prmult) fprintf(stderr, "multiple references>>%s<<\n", ref); ! 888: *(++s) = '\0'; ! 889: return(1); ! 890: } ! 891: } ! 892: } ! 893: return(0); ! 894: } ! 895: ! 896: /* ! 897: * refwrite - write out a single reference to awk ! 898: */ ! 899: ! 900: ! 901: refwrite(ref) ! 902: char *ref; ! 903: { ! 904: register char *s, c; ! 905: char *t, sav; ! 906: int also; ! 907: ! 908: also = 0; ! 909: for(s = ref; *s; s++) { ! 910: if(*s == '\n') { ! 911: c = *(s+1); ! 912: if((c != '%') && c) { ! 913: if(!isspace(c)) { ! 914: fputc(' ',writebib); ! 915: continue; ! 916: } ! 917: continue; ! 918: } ! 919: } ! 920: if(*s == '%') { ! 921: if(strncmp(ALSOBEGIN,s,strlen(ALSOBEGIN)) == 0) ! 922: also++; ! 923: else if(strncmp(ALSOEND,s,strlen(ALSOEND)) == 0) ! 924: also--; ! 925: else if(strncmp(ALSO,s,strlen(ALSO)) == 0) { ! 926: for(t = s+1; *t && *t != '%'; ) { ! 927: if(*t++ == '\n') ! 928: if(*t == '\n') ! 929: break; ! 930: } ! 931: sav = *t; ! 932: *t = '\0'; ! 933: if(also == 0) { ! 934: fputs(ALSOBEGIN,writebib); ! 935: putc('\n',writebib); ! 936: } ! 937: seealso(s); ! 938: if(also == 0) { ! 939: fputs(ALSOEND,writebib); ! 940: putc('\n',writebib); ! 941: } ! 942: fflush(writebib); ! 943: *t = sav; ! 944: s = t-1; ! 945: continue; ! 946: } ! 947: } ! 948: putc(*s,writebib); ! 949: } ! 950: } ! 951: ! 952: ! 953: ! 954: /* ! 955: * seealso - hunt for keywords in the "see also list" ! 956: */ ! 957: ! 958: seealso(tok) ! 959: register char *tok; ! 960: { ! 961: char key[MAXTOK]; ! 962: register char *k; ! 963: ! 964: *key = '\0'; ! 965: if(k = strtok(tok+strlen(ALSO)+1," \t\n")) { ! 966: strcpy(key,k); ! 967: strcat(key," "); ! 968: while(k = strtok((char *)0," \t\n")) { ! 969: strcat(key,k); ! 970: strcat(key," "); ! 971: } ! 972: if(*key != '\0') { ! 973: getref(key); ! 974: } ! 975: } ! 976: ! 977: } ! 978: ! 979: ! 980: ! 981: /* ! 982: * end_citations - end a list of citations: read back citation ! 983: * list from awk ! 984: */ ! 985: ! 986: end_citations(punc) ! 987: int punc; /* punctuation following or preceeding citation list */ ! 988: { ! 989: register int l, k, j; ! 990: ! 991: fputs(END_LIST,writebib); ! 992: if(pass == 1) ! 993: putc('1',writebib); ! 994: if(punc) ! 995: fprintf(writebib," %c",(char)punc); ! 996: putc('\n',writebib); ! 997: fflush(writebib); ! 998: ! 999: while(fgets(awkline,MAXTOK,readbib)) { ! 1000: l = strlen(awkline); ! 1001: if(l >= (j=strlen(END_LIST)+1)) { ! 1002: k = l-j; ! 1003: if(strncmp(END_LIST,&awkline[k],j-1) == 0) { ! 1004: if(k != 0) { ! 1005: awkline[k] = '\0'; ! 1006: fputs(awkline,writetext); ! 1007: } ! 1008: return; ! 1009: } ! 1010: } ! 1011: fputs(awkline,writetext); ! 1012: } ! 1013: errexit(1,"end_citations: EOF or error from awk\n"); ! 1014: } ! 1015: ! 1016: ! 1017: /* ! 1018: * style - process |reference_style() ! 1019: * select a reference formatting style and set style flags ! 1020: */ ! 1021: ! 1022: style() ! 1023: { ! 1024: ! 1025: /* ! 1026: * get left delimeter, then style name and options, then right delimeter ! 1027: */ ! 1028: leftdelim; ! 1029: if ((type = get_token(tok,right)) == T_WORD) { ! 1030: if(strcmp(tok,"same")) { ! 1031: strcpy(stylename,tok); ! 1032: } ! 1033: while ((type = get_token(tok,right)) == T_WORD) { ! 1034: if(strcmp(tok,"nroff") == 0) { ! 1035: nroff = 1; ! 1036: } ! 1037: else if(strcmp(tok,"troff") == 0) { ! 1038: nroff = 0; ! 1039: } ! 1040: else if(strcmp(tok,"rp") == 0) { ! 1041: rp = 1; ! 1042: } ! 1043: else if(strcmp(tok,"tm") == 0) { ! 1044: rp = 0; ! 1045: } ! 1046: else if(strcmp(tok,"sequence") == 0) { ! 1047: sort = 0; ! 1048: } ! 1049: else if(strcmp(tok,"sort") == 0) { ! 1050: sort = 1; ! 1051: strcpy(sortkey,tok); ! 1052: } ! 1053: else { ! 1054: sort = 1; ! 1055: strcpy(sortkey,tok); ! 1056: } ! 1057: } ! 1058: } ! 1059: else { ! 1060: token_err(type,"Expecting style name, got %s\n", tok); ! 1061: } ! 1062: ! 1063: rightdelim; ! 1064: ! 1065: /* ! 1066: * finish previous citations before switching styles ! 1067: */ ! 1068: if(awkstate == OK) ! 1069: biblio(END); ! 1070: } ! 1071: ! 1072: ! 1073: /* ! 1074: * database - process |reference_database ! 1075: * select a new bibliographic database ! 1076: */ ! 1077: ! 1078: database() ! 1079: { ! 1080: ! 1081: /* ! 1082: * after left delimeter, get name of database, then right delim ! 1083: */ ! 1084: leftdelim; ! 1085: if ((type = get_token(tok,right)) != T_WORD) { ! 1086: token_err(type,"Expecting name of database file, got %s\n",tok); ! 1087: } ! 1088: strcpy(INDEX,tok); ! 1089: strcat(INDEX,".i"); ! 1090: type = get_token(tok,right); ! 1091: rightdelim; ! 1092: ! 1093: } ! 1094: ! 1095: ! 1096: /* ! 1097: * bib_list - process |reference_list() ! 1098: * format a bibliographic database ! 1099: * first finish processing for previous citations ! 1100: */ ! 1101: ! 1102: bib_list() ! 1103: { ! 1104: static char dbstr[MAXTOK]; /* names of one or more bibs */ ! 1105: ! 1106: /* ! 1107: * after left delimeter get bibliography name (can skip on second pass), ! 1108: * then right delimeter ! 1109: */ ! 1110: leftdelim; ! 1111: if(pass != 2) { ! 1112: *dbstr = '\0'; ! 1113: while ((type = get_token(tok,right)) == T_WORD) { ! 1114: strcat(dbstr,tok); ! 1115: strcat(dbstr," "); ! 1116: } ! 1117: } ! 1118: else type = get_token(tok,right); ! 1119: rightdelim; ! 1120: ! 1121: /* ! 1122: * format any previous citations then put out complete bibliography ! 1123: * (unless the second pass has just begun) ! 1124: */ ! 1125: if(awkstate == OK) { ! 1126: biblio(BIBLIST); ! 1127: if(pass != 2) printbib(dbstr); ! 1128: } ! 1129: else { ! 1130: printbib(dbstr); ! 1131: } ! 1132: } ! 1133: ! 1134: ! 1135: /* ! 1136: * biblio - process reference_placement OR ! 1137: * finish processing citations before EOF, style change, or list command ! 1138: */ ! 1139: ! 1140: biblio(bflag) ! 1141: bibflag bflag; ! 1142: { ! 1143: ! 1144: /* ! 1145: * signal bibliography to awk ! 1146: */ ! 1147: fputs(BIBLIO,writebib); ! 1148: if(pass == 1) ! 1149: putc('1',writebib); ! 1150: if(bflag == END || bflag == BIBLIST) ! 1151: fputs(" no_bib",writebib); ! 1152: putc('\n',writebib); ! 1153: fflush(writebib); ! 1154: ! 1155: switch(pass) { ! 1156: ! 1157: /* ! 1158: * write out bib mark to diverted text, close, and reopen ! 1159: */ ! 1160: case 1: ! 1161: pass = 2; ! 1162: if(bflag != END) { ! 1163: putc(BAR,writetext); ! 1164: if(bflag == BIBLIST) ! 1165: fprintf(writetext,"%s<>",REF_LIST); ! 1166: else ! 1167: fputs(REF_PLACE,writetext); ! 1168: putc('\n',writetext); ! 1169: } ! 1170: fclose(writetext); ! 1171: writetext = savefile; ! 1172: savefile = readtext; ! 1173: readtext = fopen(divertname,"r"); ! 1174: haveeof = 0; ! 1175: return; ! 1176: ! 1177: /* ! 1178: * close and unlink text and resume reading in original file ! 1179: */ ! 1180: case 2: ! 1181: fclose(readtext); ! 1182: unlink(divertname); ! 1183: readtext = savefile; ! 1184: haveeof = 0; ! 1185: pass = 0; ! 1186: ! 1187: /* ! 1188: * get formatted bibliography from awk ! 1189: */ ! 1190: case 0: ! 1191: while(fgets(awkline,MAXTOK,readbib)) { ! 1192: if(strcmp("%END_BIB\n",awkline) == 0) { ! 1193: awkclose(readbib,writebib); ! 1194: return; ! 1195: } ! 1196: fputs(awkline,writetext); ! 1197: } ! 1198: errexit(1,"biblio: EOF or error from awk\n"); ! 1199: } ! 1200: } ! 1201: ! 1202: ! 1203: /* ! 1204: * refread - read a single reference from a bibliography file ! 1205: */ ! 1206: char * ! 1207: refread(bfile) ! 1208: FILE *bfile; ! 1209: { ! 1210: static char *buf = NULL; ! 1211: static unsigned size; ! 1212: register char *bp; ! 1213: int c, nextc; ! 1214: ! 1215: if(buf == NULL) { ! 1216: if((buf = malloc(MAXTOK)) == NULL) ! 1217: errexit(1, "malloc error in refread\n"); ! 1218: size = MAXTOK; ! 1219: } ! 1220: bp = buf; ! 1221: while(isspace(c = getc(bfile))) { ! 1222: } ! 1223: if(c == EOF) ! 1224: return(NULL); ! 1225: *bp++ = c; ! 1226: while(c = getc(bfile)) { ! 1227: if(bp-buf == size-1) { ! 1228: if((buf = realloc(buf,size+MAXTOK)) == NULL) ! 1229: errexit(1, "malloc error in refread\n"); ! 1230: bp = buf+size-1; ! 1231: size += MAXTOK; ! 1232: } ! 1233: if(c == EOF) ! 1234: break; ! 1235: *bp++ = c; ! 1236: if(c == '\n') { ! 1237: if((nextc = getc(bfile)) == '\n') { ! 1238: ungetc(nextc,bfile); ! 1239: break; ! 1240: } ! 1241: ungetc(nextc,bfile); ! 1242: } ! 1243: } ! 1244: ! 1245: if(bp == buf) ! 1246: return(NULL); ! 1247: if(*(bp-1) != '\n') ! 1248: *bp++ = '\n'; ! 1249: *bp = '\0'; ! 1250: return(buf); ! 1251: } ! 1252: ! 1253: ! 1254: /* ! 1255: * printbib - list one or more bibliographic databases ! 1256: */ ! 1257: printbib(bibstr) ! 1258: char *bibstr; /* name of database */ ! 1259: { ! 1260: register char *bp, *bn; /* ptrs to bibstr */ ! 1261: FILE *bib; /* file ptr to database */ ! 1262: register char *ref; /* points to a complete reference */ ! 1263: ! 1264: /* ! 1265: * start awk, signalling that this is an entire bib (as opposed to citations) ! 1266: */ ! 1267: start_awk(BIBLIST); ! 1268: ! 1269: /* ! 1270: * for each database; open the file, read each reference, ! 1271: * sending BEGIN and END markers ! 1272: */ ! 1273: for(bp = bibstr; *bp; bp = bn) { ! 1274: if((bn = strchr(bp,' ')) != NULL) ! 1275: *bn++ = '\0'; ! 1276: else break; ! 1277: if((bib = fopen(bp,"r")) == NULL) { ! 1278: fprintf(stderr,"cannot open database file %s\n",bp); ! 1279: continue; ! 1280: } ! 1281: ! 1282: strcpy(INDEX,bp); ! 1283: strcat(INDEX,".i"); ! 1284: ! 1285: while(ref = refread(bib)) { ! 1286: fputs(BEGIN_CITE,writebib); ! 1287: putc('\n',writebib); ! 1288: refwrite(ref); ! 1289: fputs(END_CITE,writebib); ! 1290: putc('\n',writebib); ! 1291: } ! 1292: fflush(writebib); ! 1293: fclose(bib); ! 1294: } ! 1295: fflush(writebib); ! 1296: ! 1297: /* ! 1298: * signal awk to format the bibliography, read it back, and print it out ! 1299: */ ! 1300: fputs(WHOLEBIB,writebib); ! 1301: if(sort) { ! 1302: putc(' ',writebib); ! 1303: fputs(sortkey,writebib); ! 1304: } ! 1305: putc('\n',writebib); ! 1306: fflush(writebib); ! 1307: ! 1308: while(fgets(awkline,MAXTOK,readbib)) { ! 1309: if(strcmp("%END_BIB\n",awkline) == 0) { ! 1310: awkclose(readbib,writebib); ! 1311: return; ! 1312: } ! 1313: fputs(awkline,writetext); ! 1314: } ! 1315: errexit(1,"wholebib: EOF or error from awk\n"); ! 1316: } ! 1317: ! 1318: ! 1319: /* ! 1320: * dbinclude - include entries from one or more bibliography databases ! 1321: * in the reference section without citing in the text ! 1322: */ ! 1323: dbinclude() ! 1324: { ! 1325: static char dbstr[MAXTOK]; /* names of one or more bibs */ ! 1326: register char *bp, *bn; /* ptrs to bibstr */ ! 1327: FILE *bib; /* file ptr to database */ ! 1328: register char *ref; /* points to a complete reference */ ! 1329: char saveindex[maxstr]; /* for saving name of current index */ ! 1330: int includecnt; /* count number of included biblio entries */ ! 1331: ! 1332: /* ! 1333: * after left delimeter get bibliography name (or include count on second pass), ! 1334: * then right delimeter ! 1335: */ ! 1336: leftdelim; ! 1337: *dbstr = '\0'; ! 1338: while ((type = get_token(tok,right)) == T_WORD) { ! 1339: strcat(dbstr,tok); ! 1340: strcat(dbstr," "); ! 1341: } ! 1342: rightdelim; ! 1343: ! 1344: if(pass != 2) { ! 1345: ! 1346: includecnt = 0; ! 1347: strcpy(saveindex,INDEX); /* save the current INDEX and start awk */ ! 1348: if(awkstate != OK) start_awk(NORMAL); ! 1349: /* ! 1350: * for each database; open the file, read each reference, ! 1351: * sending BEGIN and END markers ! 1352: */ ! 1353: for(bp = dbstr; *bp; bp = bn) { ! 1354: if((bn = strchr(bp,' ')) != NULL) ! 1355: *bn++ = '\0'; ! 1356: else break; ! 1357: if((bib = fopen(bp,"r")) == NULL) { ! 1358: fprintf(stderr,"cannot open database file %s\n",bp); ! 1359: continue; ! 1360: } ! 1361: ! 1362: strcpy(INDEX,bp); ! 1363: strcat(INDEX,".i"); ! 1364: ! 1365: while(ref = refread(bib)) { ! 1366: fputs(BEGIN_CITE,writebib); ! 1367: putc('\n',writebib); ! 1368: refwrite(ref); ! 1369: fputs("%no_cite\n",writebib); ! 1370: fputs(END_CITE,writebib); ! 1371: putc('\n',writebib); ! 1372: includecnt++; ! 1373: } ! 1374: fflush(writebib); ! 1375: fclose(bib); ! 1376: } ! 1377: end_citations('\0'); ! 1378: strcpy(INDEX,saveindex); ! 1379: if(pass == 1) { ! 1380: fprintf(writetext,"|%s[%d]\n",REF_INCLUDE,includecnt); ! 1381: } ! 1382: } ! 1383: else { ! 1384: fputs(DBINCLUDE,writebib); ! 1385: putc(' ',writebib); ! 1386: fputs(dbstr,writebib); /* number of includes */ ! 1387: putc('\n',writebib); ! 1388: fflush(writebib); ! 1389: } ! 1390: } ! 1391: ! 1392: ! 1393: mygetc(file) ! 1394: FILE *file; ! 1395: { ! 1396: int c; ! 1397: ! 1398: if(haveeof) ! 1399: return(EOF); ! 1400: else ! 1401: if((c = getc(file)) == EOF) ! 1402: haveeof++; ! 1403: return(c); ! 1404: } ! 1405: ! 1406: /* ! 1407: * errexit - print error message to stderr, unlink temporary file, exit ! 1408: */ ! 1409: ! 1410: errexit(n,s1,s2,s3) ! 1411: int n; ! 1412: char *s1; ! 1413: { ! 1414: fprintf(stderr,s1,s2,s3); ! 1415: unlink(divertname); ! 1416: if(awkstate != NONE) ! 1417: awkclose(readbib,writebib); ! 1418: exit(n); ! 1419: } ! 1420: ! 1421: ! 1422: /* ! 1423: * awkopen - open up pipes to awk process ! 1424: */ ! 1425: ! 1426: #define RDR 0 ! 1427: #define WTR 1 ! 1428: ! 1429: awkopen(awkfile,readawk,writeawk) ! 1430: char *awkfile; ! 1431: FILE **readawk,**writeawk; ! 1432: { ! 1433: int ! 1434: i, /* temp for closing fd's not used */ ! 1435: fromawk[2], /* pipe file descriptors from awk */ ! 1436: toawk[2], ! 1437: pid /* pipe file descriptors to awk */ ! 1438: ; ! 1439: char temp[maxstr]; ! 1440: ! 1441: /* ! 1442: * *** take care of forming pipes *** ! 1443: */ ! 1444: if (pipe(fromawk) < 0) ! 1445: errexit(1, "can't open pipe from awk\n"); ! 1446: if (pipe(toawk) < 0) ! 1447: errexit(1, "can't open pipe to awk\n"); ! 1448: ! 1449: /* ! 1450: * *** make awk child *** ! 1451: */ ! 1452: if ((pid = fork()) == 0) { ! 1453: close(fromawk[RDR]); ! 1454: dup2(fromawk[WTR], 1); ! 1455: close(toawk[WTR]); ! 1456: dup2(toawk[RDR], 0); ! 1457: for (i=3; i<FILENUM; i++) ! 1458: close(i); ! 1459: ! 1460: strcpy(temp,libpath(PLIB)); ! 1461: strcat(temp,SLASH); ! 1462: strcat(temp,AWK); ! 1463: /* ! 1464: execlp(temp, AWK, "-R", awkfile, 0); ! 1465: */ ! 1466: execlp(temp, AWK, "-f", awkfile, 0); ! 1467: errexit(1, "could not exec awk with script %s\n",awkfile); ! 1468: } ! 1469: if (pid == -1) ! 1470: errexit(1, "could not fork awk\n"); ! 1471: ! 1472: /* ! 1473: * *** make out stream pointers *** ! 1474: */ ! 1475: close(fromawk[WTR]); ! 1476: *readawk = fdopen(fromawk[RDR], "r"); ! 1477: close(toawk[RDR]); ! 1478: *writeawk = fdopen(toawk[WTR], "w"); ! 1479: ! 1480: } ! 1481: ! 1482: ! 1483: /* ! 1484: * awkclose - close pipes to awk ! 1485: */ ! 1486: ! 1487: awkclose(read,write) ! 1488: FILE *read, *write; ! 1489: { ! 1490: fclose(write); ! 1491: fclose(read); ! 1492: awkstate = NONE; ! 1493: } ! 1494: ! 1495: ! 1496: /* ! 1497: * cleanup = after signal, get rid of temp file and close awk ! 1498: */ ! 1499: ! 1500: cleanup() ! 1501: { ! 1502: signal(SIGINT, SIG_IGN); ! 1503: signal(SIGQUIT, SIG_IGN); ! 1504: unlink(divertname); ! 1505: if(awkstate != NONE) ! 1506: awkclose(readbib,writebib); ! 1507: exit(1); ! 1508: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.