|
|
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.