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
usageErr(argv0,opt,str)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*/
bibwarning(msg,a1,a2)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
doargs(argc,argv,defstyle)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
newbibdir(name)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 */
incfile(np)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*/
error(str,a1,a2)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 */
fixrfd(mode)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 */
tfgets(line,n,ptr)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 */
getwrd(in,i,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 */
walloc(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
expand(line)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 */
wordstuff(word,def)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 }
wordsearch(word)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 */
wordrestuff(word,def)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
strhash(str)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 */
breakname(line,first,last)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)*/
match(str1,str2)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 */
scopy(p,q)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 */
rcomp(ap,bp)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 */
makecites()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 */
bldcite(cp,i,ref)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 */
aabet(cp,ref)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 */
fullaabet(cp,ref)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 */
aabetlast(cp,ref)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 */
multfull(cp,ref,maxauthors)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 */
getfield(ptr,field,ref)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 */
getname(n,last,first,ref)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 */
disambiguate()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 */
bldname(first,last,name,reverse)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 */
prtauth(c,line,num,max,ofd,abbrev,capsmcap,numrev)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 */
doline(c,line,numauths,maxauths,numeds,maxeds,ofd)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 */
dumpref(i,ofd)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