BSD 4_3 release
[unix-history] / usr / contrib / bib / src / bibargs.c
CommitLineData
d3ce25cd 1#ifndef lint
95f51977 2static char sccsid[] = "@(#)bibargs.c 2.10 11/22/85";
d3ce25cd 3#endif not lint
f0a950c2 4/*
db589048
GL
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
15
f0a950c2
GL
16 read argument strings for bib and listrefs
17 do name formatting, printing lines, other actions common to both
18 */
19# include <stdio.h>
20# include <ctype.h>
21# include "bib.h"
22# define LINELENGTH 1024
23# define MAXDEFS 500 /* maximum number of defined words */
24
25/* global variables */
db589048
GL
26 char bibfname[120]; /* file name currently being read */
27 int biblineno; /* line number currently being referenced */
f0a950c2
GL
28 int abbrev = false; /* automatically abbreviate names */
29 int capsmcap = false; /* print names in caps small caps (CACM form)*/
30 int numrev = 0; /* number of authors names to reverse */
31 int edabbrev = false; /* abbreviate editors names ? */
32 int edcapsmcap = false; /* print editors in cap small caps */
33 int ednumrev = 0; /* number of editors to reverse */
ccbea45a 34 int max_klen = 6; /* max size of key */
f0a950c2
GL
35 int sort = false; /* sort references ? (default no) */
36 int foot = false; /* footnoted references ? (default endnotes) */
4e880a3e 37 int doacite = true; /* place citations ? */
f0a950c2
GL
38 int hyphen = false; /* hypenate contiguous references */
39 int ordcite = true; /* order multiple citations */
40 char sortstr[80] = "1"; /* sorting template */
41 char trailstr[80] = ""; /* trailing characters to output */
c3076612 42 char pfile[400]; /* private file name */
f0a950c2
GL
43 int personal = false; /* personal file given ? (default no) */
44 char citetemplate[80] = "1"; /* citation template */
dca84ce7
RH
45 struct wordinfo words[MAXDEFS]; /* defined words */
46 struct wordinfo *wordhash[HASHSIZE];
47 struct wordinfo *wordsearch();
48 int wordtop = 0; /* number of defined words */
f0a950c2
GL
49
50/* where output goes */
51 extern FILE *tfd;
db589048 52/* reference file information */
dca84ce7 53 extern struct refinfo refinfo[];
db589048 54 extern char reffile[];
dca84ce7 55#ifndef INCORE
db589048 56 extern FILE *rfd;
dca84ce7 57#endif not INCORE
db589048 58 extern int numrefs;
f0a950c2
GL
59
60/* doargs - read command argument line for both bib and listrefs
61 set switch values
62 call rdtext on file arguments, after dumping
63 default style file if no alternative style is given
64*/
65 int doargs(argc, argv, defstyle)
66 int argc;
67 char **argv, defstyle[];
68{ int numfiles, i, style;
69 char *p, *q, *walloc();
70 FILE *fd;
71
72 numfiles = 0;
73 style = true;
857232a7 74 newbibdir(BMACLIB);
f0a950c2
GL
75
76 for (i = 1; i < argc; i++)
77 if (argv[i][0] == '-')
78 switch(argv[i][1]) {
857232a7
RH
79 case 'd':
80 if (argv[i][2])
81 p = &argv[i][2];
82 else { /* take next arg */
83 i++;
84 p = argv[i];
85 }
86 newbibdir(p);
db589048
GL
87 case 'a': for (p = &argv[i][2]; *p; p++)
88 if (*p == 'a' || *p == 0)
b9b4916e
GL
89 abbrev = true;
90 else if (*p == 'x')
91 capsmcap = true;
92 else if (*p == 'r') {
93 if (*(p+1))
94 numrev = atoi(p+1);
95 else
96 numrev = 1000;
97 break;
98 }
f0a950c2
GL
99 break;
100
101 case 'c': if (argv[i][2] == 0)
dca84ce7 102 error("citation string expected for 'c'");
f0a950c2
GL
103 else
104 for (p = citetemplate,q = &argv[i][2]; *p++ = *q++; );
105 break;
106
107 case 'e': for (p = &argv[i][2]; *p; p++)
108 if (*p == 'a')
109 edabbrev = true;
110 else if (*p == 'x')
111 edcapsmcap = true;
112 else if (*p == 'r') {
113 if (*(p+1))
114 ednumrev = atoi(p+1);
115 else
116 ednumrev = 1000;
117 break;
118 }
119 break;
120
ccbea45a
GL
121 case 'l': if (argv[i][2]){
122 max_klen = atoi(&argv[i][2]);
123 if (max_klen > REFSIZE)
124 error("too long key size");
125 } else {
126 error("-l needs a numeric value");
127 }
128 break;
129
4e880a3e
RH
130 case 'v': doacite = false;
131 /*FALLTHROUGH*/
f0a950c2
GL
132 case 'f': foot = true;
133 hyphen = false;
134 break;
135
136 case 'h': hyphen = ordcite = true;
137 break;
138
139 case 'n': for (p = &argv[i][2]; *p; p++)
140 if (*p == 'a')
141 abbrev = false;
4e880a3e
RH
142 else if (*p == 'v')
143 doacite = true;
f0a950c2
GL
144 else if (*p == 'f')
145 foot = false;
146 else if (*p == 'h')
147 hyphen = false;
148 else if (*p == 'o')
149 ordcite = false;
150 else if (*p == 'r')
151 numrev = 0;
152 else if (*p == 's')
153 sort = false;
154 else if (*p == 'x')
155 capsmcap = false;
156 break;
157
158 case 'o': ordcite = true;
159 break;
160
161 case 'p': if (argv[i][2])
162 p = &argv[i][2];
163 else { /* take next arg */
164 i++;
165 p = argv[i];
166 }
167 strcpy(pfile, p);
168 personal = true;
169 break;
170
db589048 171 case 'r': if (argv[i][2] == 0) /* this is now replaced by -ar */
f0a950c2
GL
172 numrev = 1000;
173 else
174 numrev = atoi(&argv[i][2]);
175 break;
176
177 case 's': sort = true;
178 if (argv[i][2])
179 for (p = sortstr,q = &argv[i][2]; *p++ = *q++; );
180 break;
181
db589048
GL
182 case 't': style = false; /* fall through */
183 case 'i': if (argv[i][2])
f0a950c2
GL
184 p = &argv[i][2];
185 else { /* take next arg */
186 i++;
187 p = argv[i];
188 }
189 incfile(p);
190 break;
191
db589048 192 case 'x': capsmcap = true; /* this is now replaced by -ax */
f0a950c2
GL
193 break;
194
195 case 0: if (style) { /* no style command given, take default */
196 style = false;
197 incfile( defstyle );
198 }
db589048 199 strcpy(bibfname,"<stdin>");
f0a950c2
GL
200 rdtext(stdin);
201 numfiles++;
202 break;
203
204 default: fputs(argv[i], stderr);
dca84ce7 205 error("'%c' invalid switch", argv[i][1]);
f0a950c2
GL
206 }
207 else { /* file name */
208 numfiles++;
209 if (style) {
210 style = false;
211 incfile( defstyle );
212 }
213 fd = fopen(argv[i], "r");
214 if (fd == NULL) {
dca84ce7 215 error("can't open file %s", argv[i]);
f0a950c2
GL
216 }
217 else {
db589048 218 strcpy(bibfname, argv[i]);
f0a950c2
GL
219 rdtext(fd);
220 fclose(fd);
221 }
222 }
223
224 if (style) incfile( defstyle );
225 return(numfiles);
226
227}
228
857232a7
RH
229newbibdir(name)
230 char *name;
231{
232 strreplace(COMFILE, BMACLIB, name);
233 strreplace(DEFSTYLE, BMACLIB, name);
234 strcpy(BMACLIB, name);
235 wordstuff("BMACLIB", BMACLIB);
236 fprintf(tfd, ".ds l] %s\n", BMACLIB);
237}
238
f0a950c2
GL
239/* incfile - read in an included file */
240incfile(np)
241 char *np;
242{ char name[120];
243 FILE *fd;
db589048 244 char *p, line[LINELENGTH], dline[LINELENGTH], word[80], *tfgets();
20e80ec2 245 int i, getwrd();
f0a950c2 246
db589048 247 strcpy(bibfname, np);
f0a950c2
GL
248 fd = fopen(np, "r");
249 if (fd == NULL && *np != '/') {
250 strcpy(name, "bib.");
251 strcat(name, np);
db589048 252 strcpy(bibfname, name);
f0a950c2
GL
253 fd = fopen(name, "r");
254 }
255 if (fd == NULL && *np != '/') {
256 strcpy(name,BMACLIB);
257 strcat(name, "/bib.");
258 strcat(name, np);
db589048 259 strcpy(bibfname, name);
f0a950c2
GL
260 fd = fopen(name, "r");
261 }
262 if (fd == NULL) {
db589048
GL
263 bibwarning("%s: can't open", np);
264 exit(1);
f0a950c2 265 }
f0a950c2 266
db589048
GL
267 /* now go off and process file */
268 biblineno = 1;
269 while (tfgets(line, LINELENGTH, fd) != NULL) {
270 biblineno++;
f0a950c2
GL
271 switch(line[0]) {
272
273 case '#': break;
274
b9b4916e 275 case 'A': for (p = &line[1]; *p; p++)
db589048 276 if (*p == 'A' || *p == '\0')
b9b4916e
GL
277 abbrev = true;
278 else if (*p == 'X')
279 capsmcap = true;
280 else if (*p == 'R') {
281 if (*(p+1))
282 numrev = atoi(p+1);
283 else
284 numrev = 1000;
285 break;
286 }
f0a950c2
GL
287 break;
288
289 case 'C': for (p = &line[1]; *p == ' '; p++) ;
290 strcpy(citetemplate, p);
291 break;
292
293 case 'D': if ((i = getwrd(line, 1, word)) == 0)
294 error("word expected in definition");
a486c0ef
GL
295 if (wordsearch(word)) { /* already there-toss rest of def.*/
296 while(line[strlen(line)-1] == '\\' ) {
297 if (tfgets(line, LINELENGTH, fd) == NULL) break;
298 }
dca84ce7 299 break;
a486c0ef 300 }
f0a950c2
GL
301 for (p = &line[i]; *p == ' '; p++) ;
302 for (strcpy(dline, p); dline[strlen(dline)-1] == '\\'; ){
303 dline[strlen(dline)-1] = '\n';
db589048 304 if (tfgets(line, LINELENGTH, fd) == NULL) break;
f0a950c2
GL
305 strcat(dline, line);
306 }
dca84ce7 307 wordstuff(word, dline);
f0a950c2
GL
308 break;
309
310 case 'E': for (p = &line[1]; *p; p++)
311 if (*p == 'A')
312 edabbrev = true;
313 else if (*p == 'X')
314 edcapsmcap = true;
315 else if (*p == 'R') {
316 if (*(p+1))
317 ednumrev = atoi(p+1);
318 else
319 ednumrev = 1000;
320 break;
321 }
322 break;
323
324 case 'F': foot = true;
325 hyphen = false;
326 break;
327
328 case 'I': for (p = &line[1]; *p == ' '; p++);
329 expand(p);
330 incfile(p);
331 break;
332
333 case 'H': hyphen = ordcite = true;
334 break;
335
336 case 'O': ordcite = true;
337 break;
338
db589048 339 case 'R': if (line[1] == 0) /* this is now replaced by AR */
f0a950c2
GL
340 numrev = 1000;
341 else
342 numrev = atoi(&line[1]);
343 break;
344
345 case 'S': sort = true;
346 for (p = &line[1]; *p == ' '; p++) ;
347 strcpy(sortstr, p);
348 break;
349
350 case 'T': for (p = &line[1]; *p == ' '; p++) ;
351 strcpy(trailstr, p);
352 break;
353
db589048 354 case 'X': capsmcap = true; /* this is now replace by AX */
f0a950c2
GL
355 break;
356
357 default: fprintf(tfd,"%s\n",line);
db589048 358 while (fgets(line, LINELENGTH, fd) != NULL)
f0a950c2
GL
359 fputs(line, tfd);
360 return;
361 }
db589048
GL
362
363 }
364 /* close up */
365 fclose(fd);
366}
367
368/* bibwarning - print out a warning message */
dca84ce7
RH
369 /*VARARGS1*/
370 bibwarning(msg, a1, a2)
371 char *msg;
db589048
GL
372{
373 fprintf(stderr,"`%s', line %d: ", bibfname, biblineno);
dca84ce7 374 fprintf(stderr, msg, a1, a2);
857232a7 375 fprintf(stderr, "\n");
db589048
GL
376}
377
378/* error - report unrecoverable error message */
dca84ce7
RH
379 /*VARARGS1*/
380 error(str, a1, a2)
381 char *str;
db589048 382{
dca84ce7
RH
383 bibwarning(str, a1, a2);
384 /*
385 * clean up temp files and exit
386 */
387 cleanup(1);
db589048
GL
388}
389
dca84ce7 390#ifndef INCORE
db589048
GL
391#ifdef READWRITE
392/*
393** fixrfd( mode ) -- re-opens the rfd file to be read or write,
394** depending on the mode. Uses a static int to save the current mode
395** and avoid unnecessary re-openings.
396*/
397fixrfd( mode )
398register int mode;
399{
400 static int cur_mode = WRITE; /* rfd open for writing initially */
401
402 if (mode != cur_mode)
403 {
404 rfd = freopen(reffile, ((mode == READ)? "r" : "a"), rfd);
405 cur_mode = mode;
406 if (rfd == NULL)
dca84ce7
RH
407 error("Hell! Couldn't re-open reference file %s",
408 reffile);
db589048
GL
409 }
410}
411#endif
dca84ce7 412#endif not INCORE
db589048
GL
413
414
415/* tfgets - fgets which trims off newline */
416 char *tfgets(line, n, ptr)
417 char line[];
418 int n;
419 FILE *ptr;
dca84ce7 420{ reg char *p;
db589048
GL
421
422 p = fgets(line, n, ptr);
423 if (p == NULL)
424 return(NULL);
425 else
426 for (p = line; *p; p++)
427 if (*p == '\n')
428 *p = 0;
429 return(line);
430}
431
432/* getwrd - place next word from in[i] into out */
433int getwrd(in, i, out)
dca84ce7
RH
434 reg char in[], out[];
435 reg int i;
db589048
GL
436{ int j;
437
438 j = 0;
439 while (in[i] == ' ' || in[i] == '\n' || in[i] == '\t')
440 i++;
441 if (in[i])
442 while (in[i] && in[i] != ' ' && in[i] != '\t' && in[i] != '\n')
443 out[j++] = in[i++];
444 else
445 i = 0; /* signals end of in[i..] */
446 out[j] = 0;
447 return (i);
448}
449
450/* walloc - allocate enough space for a word */
451char *walloc(word)
452 char *word;
453{ char *i, *malloc();
454 i = malloc(1 + strlen(word));
455 if (i == NULL)
456 error("out of storage");
457 strcpy(i, word);
458 return(i);
f0a950c2
GL
459}
460
461/* isword - see if character is legit word char */
462int iswordc(c)
463char c;
464{
465 if (isalnum(c) || c == '&' || c == '_')
466 return(true);
467 return(false);
468}
f0a950c2
GL
469 expand(line)
470 char *line;
dca84ce7
RH
471{ char line2[REFSIZE], word[LINELENGTH];
472 reg struct wordinfo *wp;
473 reg char *p, *q, *w;
dca84ce7
RH
474
475 q = line2;
476 for (p = line; *p; /*VOID*/){
477 if (isalnum(*p)) {
478 for (w = word; *p && iswordc(*p); ) *w++ = *p++;
479 *w = 0;
480 if (wp = wordsearch(word)){
481 strcpy(word, wp->wi_def);
482 expand(word);
483 }
484 strcpy(q, word);
485 q += strlen(q);
486 } else {
487 *q++ = *p++;
488 }
489 }
490 *q = 0;
491 strcpy(line, line2);
492}
493
494/* wordstuff- save a word and its definition, building a hash table */
495 wordstuff(word, def)
496 char *word, *def;
497{
498 int i;
499 if (wordtop >= MAXDEFS)
500 error("too many definitions, max of %d", MAXDEFS);
501 words[wordtop].wi_length = strlen(word);
502 words[wordtop].wi_word = word ? walloc(word) : 0;
503 words[wordtop].wi_def = def ? walloc(def) : 0;
504 i = strhash(word);
505 words[wordtop].wi_hp = wordhash[i];
506 wordhash[i] = &words[wordtop];
507 wordtop++;
508}
509 struct wordinfo *wordsearch(word)
510 char *word;
511{
dca84ce7
RH
512 reg int lg;
513 reg struct wordinfo *wp;
514 lg = strlen(word);
515 for (wp = wordhash[strhash(word)]; wp; wp = wp->wi_hp){
516 if (wp->wi_length == lg && (strcmp(wp->wi_word, word) == 0)){
517 return(wp);
518 }
519 }
520 return(0);
521}
522
523 int strhash(str)
524 reg char *str;
525{
526 reg int value = 0;
527 for (value = 0; *str; value <<= 2, value += *str++)/*VOID*/;
528 value %= HASHSIZE;
529 if (value < 0)
530 value += HASHSIZE;
531 return(value);
f0a950c2
GL
532}
533
db589048 534/* rdref - read text for an already cited reference */
dca84ce7
RH
535 rdref(p, ref)
536 struct refinfo *p;
db589048
GL
537 char ref[REFSIZE];
538{
539 ref[0] = 0;
dca84ce7 540#ifndef INCORE
db589048
GL
541#ifdef READWRITE
542 fixrfd( READ ); /* fix access mode of rfd, if nec. */
543#endif
dca84ce7
RH
544 fseek(rfd, p->ri_pos, 0);
545 fread(ref, p->ri_length, 1, rfd);
546#else INCORE
547 strcpy(ref, p->ri_ref);
548#endif INCORE
549}
550
551/* wrref - write text for a new reference */
552 wrref(p, ref)
553 struct refinfo *p;
554 char ref[REFSIZE];
555{
556#ifndef INCORE
557#ifdef READWRITE
558 fixrfd( WRITE ); /* fix access mode of rfd, if nec. */
559#else
560 fseek(rfd, p->ri_pos, 0); /* go to end of rfd */
561#endif
562 fwrite(ref, p->ri_length, 1, rfd);
563#else INCORE
564 p->ri_ref = walloc(ref);
565#endif INCORE
db589048
GL
566}
567
f0a950c2
GL
568/* breakname - break a name into first and last name */
569 breakname(line, first, last)
570 char line[], first[], last[];
dca84ce7 571{ reg char *t, *f, *q, *r, *p;
f0a950c2
GL
572
573 for (t = line; *t != '\n'; t++);
574 for (t--; isspace(*t); t--);
575
576 /* now strip off last name */
577 for (q = t; isspace(*q) == 0 || ((*q == ' ') & (*(q-1) == '\\')); q--)
578 if (q == line)
579 break;
580 f = q;
db589048 581 if (q != line) {
f0a950c2 582 q++;
db589048
GL
583 for (; isspace(*f); f--);
584 f++;
585 }
f0a950c2
GL
586
587 /* first name is start to f, last name is q to t */
588
db589048 589 for (r = first, p = line; p != f; )
f0a950c2
GL
590 *r++ = *p++;
591 *r = 0;
592 for (r = last, p = q, t++; q != t; )
593 *r++ = *q++;
594 *r = 0;
db589048 595
f0a950c2
GL
596}
597
598/* match - see if string1 is a substring of string2 (case independent)*/
599 int match(str1, str2)
dca84ce7
RH
600 reg char str1[], str2[];
601{ reg int j, i;
f0a950c2
GL
602 char a, b;
603
604 for (i = 0; str2[i]; i++) {
605 for (j = 0; str1[j]; j++) {
606 if (isupper(a = str2[i+j]))
607 a = (a - 'A') + 'a';
608 if (isupper(b = str1[j]))
609 b = (b - 'A') + 'a';
610 if (a != b)
611 break;
612 }
613 if (str1[j] == 0)
614 return(true);
615 }
616 return(false);
617}
618
619/* scopy - append a copy of one string to another */
620 char *scopy(p, q)
dca84ce7 621 reg char *p, *q;
f0a950c2
GL
622{
623 while (*p++ = *q++)
624 ;
625 return(--p);
626}
627
db589048
GL
628/* rcomp - reference comparison routine for qsort utility */
629 int rcomp(ap, bp)
dca84ce7 630 struct refinfo *ap, *bp;
db589048 631{ char ref1[REFSIZE], ref2[REFSIZE], field1[MAXFIELD], field2[MAXFIELD];
dca84ce7
RH
632 reg char *p, *q;
633 char *getfield();
db589048
GL
634 int neg, res;
635 int fields_found;
636
dca84ce7
RH
637 rdref(ap, ref1);
638 rdref(bp, ref2);
db589048
GL
639 for (p = sortstr; *p; p = q) {
640 if (*p == '-') {
641 p++;
642 neg = true;
643 }
644 else
645 neg = false;
646 q = getfield(p, field1, ref1);
647 fields_found = true;
648 if (q == 0) {
649 res = 1;
650 fields_found = false;
651 } else if (strcmp (field1, "") == 0) { /* field not found */
652 if (*p == 'A') {
653 getfield("F", field1, ref1);
654 if (strcmp (field1, "") == 0) {
655 getfield("I", field1, ref1);
656 if (strcmp (field1, "") == 0) {
657 res = 1;
658 fields_found = false;
659 }
660 }
661 } else {
662 res = 1;
663 fields_found = false;
664 }
665 }
666
667 if (getfield(p, field2, ref2) == 0) {
668 res = -1;
669 fields_found = false;
670 } else if (strcmp (field2, "") == 0) { /* field not found */
671 if (*p == 'A') {
672 getfield("F", field2, ref2);
673 if (strcmp (field2, "") == 0) {
674 getfield("I", field2, ref2);
675 if (strcmp (field2, "") == 0) {
676 res = -1;
677 fields_found = false;
678 }
679 }
680 } else {
681 res = -1;
682 fields_found = false;
683 }
684 }
685 if (fields_found) {
686 if (*p == 'A') {
687 if (isupper(field1[0]))
688 field1[0] -= 'A' - 'a';
689 if (isupper(field2[0]))
690 field2[0] -= 'A' - 'a';
691 }
692 res = strcmp(field1, field2);
693 }
694 if (neg)
695 res = - res;
696 if (res != 0)
697 break;
698 }
699 if (res == 0)
700 if (ap < bp)
701 res = -1;
702 else
703 res = 1;
704 return(res);
705}
706
20e80ec2 707/* makecites - make standard citation strings, using citetemplate currently in effect */
dca84ce7 708 makecites()
db589048 709{ char ref[REFSIZE], tempcite[100], *malloc();
dca84ce7 710 reg int i;
db589048 711
dca84ce7
RH
712 for (i = 0; i < numrefs; i++) {
713 rdref(&refinfo[i], ref);
db589048 714 bldcite(tempcite, i, ref);
20e80ec2 715 refinfo[i].ri_cite = malloc(2 + strlen(tempcite));
dca84ce7 716 if (refinfo[i].ri_cite == NULL)
db589048 717 error("out of storage");
dca84ce7 718 strcpy(refinfo[i].ri_cite, tempcite);
db589048
GL
719 }
720}
721
722/* bldcite - build a single citation string */
723 bldcite(cp, i, ref)
724 char *cp, ref[];
725 int i;
dca84ce7
RH
726{ reg char *p, *q, *fp;
727 char c;
728 char field[REFSIZE];
ccbea45a 729 char *getfield(), *aabet(), *aabetlast(), *fullaabet(), *astro();
db589048
GL
730
731 getfield("F", field, ref);
732 if (field[0] != 0)
733 for (p = field; *p; p++)
734 *cp++ = *p;
735 else {
736 p = citetemplate;
737 field[0] = 0;
738 while (c = *p++) {
739 if (isalpha(c)) { /* field name */
740 q = getfield(p-1, field, ref);
741 if (q != 0) {
742 p = q;
743 for (fp = field; *fp; )
744 *cp++ = *fp++;
745 }
746 }
747 else if (c == '1') { /* numeric order */
748 sprintf(field,"%d",1 + i);
749 for (fp = field; *fp; )
750 *cp++ = *fp++;
751 }
752 else if (c == '2') /* alternate alphabetic */
753 cp = aabet(cp, ref);
754 else if (c == '3') /* Astrophysical Journal style*/
755 cp = astro(cp, ref);
ccbea45a
GL
756 else if (c == '8') /* Full alphabetic */
757 cp = fullaabet(cp, ref);
30ec19d9
RH
758 else if (c == '9') /* Last name of Senior Author*/
759 cp = aabetlast(cp, ref);
4e880a3e
RH
760 else if (c == '0') { /* print nothing */
761 for (fp = field; *fp; )
762 *cp++ = *fp++;
763 }
db589048
GL
764/* else if (c == '4') here is how to add new styles */
765 else if (c == '{') { /* other information */
766 while (*p != '}')
767 if (*p == 0)
768 error("unexpected end of citation template");
769 else
770 *cp++ = *p++;
771 p++;
772 }
773 else if (c == '<') {
774 while (*p != '>') {
775 if (*p == 0)
776 error("unexpected end of citation template");
777 else
778 *cp++ = *p++;
779 }
780 p++;
781 }
782 else if (c != '@')
783 *cp++ = c;
784 }
785 }
786 *cp++ = 0;
787}
788
789/* alternate alphabetic citation style -
790 if 1 author - first three letters of last name
791 if 2 authors - first two letters of first, followed by first letter of
792 seond
793 if 3 or more authors - first letter of first three authors */
794 char *aabet(cp, ref)
795 char *cp, ref[];
dca84ce7
RH
796{ char field[REFSIZE], temp[100];
797 reg char *np, *fp;
db589048
GL
798 int j, getname();
799
800 if (getname(1, field, temp, ref)) {
801 np = cp;
802 fp = field;
803 for (j = 1; j <= 3; j++)
804 if (*fp != 0)
805 *cp++ = *fp++;
806 if (getname(2, field, temp, ref))
807 np[2] = field[0];
808 if (getname(3, field, temp, ref)) {
809 np[1] = np[2];
810 np[2] = field[0];
811 }
812 }
813return(cp);
814}
815
ccbea45a
GL
816/* alternate alphabetic citation style -
817 first two characters of last names of all authors
818 up to max_klen characters.
819*/
820 char *fullaabet(cp, ref)
821 char *cp, ref[];
822{ char field[REFSIZE], temp[100];
823 reg char *fp;
824 char *lastcp;
825 int getname();
826 int i;
827
828 lastcp = cp + max_klen;
829 for (i= 1; getname(i, field, temp, ref); i++) {
830 for (fp = field; *fp && (fp < &(field[3])); )
831 if (cp > lastcp)
832 break;
833 else if (isalpha(*fp))
834 *cp++ = *fp++;
835 else
836 fp++;
837 }
838 return(cp);
839}
840
841
30ec19d9
RH
842/* alternate alphabetic citation style -
843 entire last name of senior author
844*/
845 char *aabetlast(cp, ref)
846 char *cp, ref[];
847{ char field[REFSIZE], temp[100];
dca84ce7 848 reg char *fp;
30ec19d9
RH
849 int getname();
850
851 if (getname(1, field, temp, ref)) {
852 for (fp = field; *fp; )
853 *cp++ = *fp++;
854 }
855 return(cp);
856}
857
db589048
GL
858/* Astrophysical Journal style
859 if 1 author - last name date
860 if 2 authors - last name and last name date
861 if 3 authors - last name, last name and last name date
862 if 4 or more authors - last name et al. date */
863 char *astro(cp, ref)
864 char *cp, ref[];
dca84ce7
RH
865{ char name1[100], name2[100], name3[100], temp[100];
866 reg char *fp;
db589048
GL
867 int getname();
868
869 if (getname(1, name1, temp, ref)) {
870 for (fp = name1; *fp; )
871 *cp++ = *fp++;
872 if (getname(4, name3, temp, ref)) {
873 for (fp = " et al."; *fp; )
874 *cp++ = *fp++;
875 }
876 else if (getname(2, name2, temp, ref)) {
877 if (getname(3, name3, temp, ref)) {
878 for (fp = "\\*(c]"; *fp; )
879 *cp++ = *fp++;
880 for (fp = name2; *fp; )
881 *cp++ = *fp++;
882 for (fp = "\\*(m]"; *fp; )
883 *cp++ = *fp++;
884 for (fp = name3; *fp; )
885 *cp++ = *fp++;
886 }
887 else {
888 for (fp = "\\*(n]"; *fp; )
889 *cp++ = *fp++;
890 for (fp = name2; *fp; )
891 *cp++ = *fp++;
892 }
893 }
894 }
895return(cp);
896}
897
898/* getfield - get a single field from reference */
899 char *getfield(ptr, field, ref)
900 char *ptr, field[], ref[];
dca84ce7
RH
901{ reg char *p, *q;
902 char temp[100];
db589048
GL
903 int n, len, i, getname();
904
905 field[0] = 0;
906 if (*ptr == 'A')
907 getname(1, field, temp, ref);
908 else
909 for (p = ref; *p; p++)
910 if (*p == '%' && *(p+1) == *ptr) {
911 for (p = p + 2; *p == ' '; p++)
912 ;
913 for (q = field; (*p != '\n') && (*p != '\0'); )
914 *q++ = *p++;
915 *q = 0;
916 break;
917 }
918 n = 0;
919 len = strlen(field);
920 if (*++ptr == '-') {
921 for (ptr++; isdigit(*ptr); ptr++)
922 n = 10 * n + (*ptr - '0');
923 if (n > len)
924 n = 0;
925 else
926 n = len - n;
927 for (i = 0; field[i] = field[i+n]; i++)
928 ;
929 }
930 else if (isdigit(*ptr)) {
931 for (; isdigit(*ptr); ptr++)
932 n = 10 * n + (*ptr - '0');
933 if (n > len)
934 n = len;
935 field[n] = 0;
936 }
937
938 if (*ptr == 'u') {
939 ptr++;
940 for (p = field; *p; p++)
941 if (islower(*p))
942 *p = (*p - 'a') + 'A';
943 }
944 else if (*ptr == 'l') {
945 ptr++;
946 for (p = field; *p; p++)
947 if (isupper(*p))
948 *p = (*p - 'A') + 'a';
949 }
950 return(ptr);
951}
952
953/* getname - get the nth name field from reference, breaking into
954 first and last names */
955 int getname(n, last, first, ref)
956 int n;
957 char last[], first[], ref[];
dca84ce7 958{ reg char *p;
db589048
GL
959 int m;
960
961 m = n;
962 for (p = ref; *p; p++)
963 if (*p == '%' & *(p+1) == 'A') {
964 n--;
965 if (n == 0) {
966 for (p = p + 2; *p == ' '; p++) ;
967 breakname(p, first, last) ;
968 return(true);
969 }
970 }
971
972 if (n == m) /* no authors, try editors */
973 for (p = ref; *p; p++)
974 if (*p == '%' & *(p+1) == 'E') {
975 n--;
976 if (n == 0) {
977 for (p = p + 2; *p == ' '; p++) ;
978 breakname(p, first, last) ;
979 return(true);
980 }
981 }
982
983 if (n == m) { /* no editors, either, try institution */
984 first[0] = last[0] = '\0';
985 getfield("I", last, ref);
986 if (last[0] != '\0')
987 return(true);
988 }
989
990 return(false);
991}
992
993/* disambiguate - compare adjacent citation strings, and if equal, add
994 single character disambiguators */
995 disambiguate()
dca84ce7 996{ reg int i, j;
20e80ec2 997 char adstr;
db589048 998
a486c0ef 999 for (i = 0; i < numrefs-1; i = j) {
db589048 1000 j = i + 1;
dca84ce7 1001 if (strcmp(refinfo[i].ri_cite, refinfo[j].ri_cite)==0) {
20e80ec2 1002 adstr = 'a';
a486c0ef
GL
1003 for(j = i+1;
1004 j<numrefs && strcmp(refinfo[i].ri_cite,refinfo[j].ri_cite) == 0;
1005 j++) {
20e80ec2 1006 adstr = 'a' + (j-i);
20e80ec2 1007 refinfo[j].ri_disambig[0] = adstr;
db589048 1008 }
20e80ec2 1009 refinfo[i].ri_disambig[0] = 'a';
db589048
GL
1010 }
1011 }
20e80ec2
RH
1012 for (i = 0; i < numrefs; i++){
1013 strcat(refinfo[i].ri_cite, refinfo[i].ri_disambig);
1014 }
db589048
GL
1015}
1016
1017
f0a950c2
GL
1018/* bldname - build a name field
1019 doing abbreviations, reversals, and caps/small caps
1020*/
1021 bldname(first, last, name, reverse)
1022 char *first, *last, name[];
1023 int reverse;
1024{
dca84ce7
RH
1025 char newfirst[120], newlast[120];
1026 reg char *p, *q, *f, *l;
1027 char *scopy();
f0a950c2
GL
1028 int flag;
1029
1030 if (abbrev) {
1031 p = first;
1032 q = newfirst;
1033 flag = false;
1034 while (*p) {
1035 while (*p == ' ')
1036 p++;
1037 if (*p == 0)
1038 break;
1039 if (isupper(*p)) {
db589048 1040 if (flag) /* between initial gap */
f0a950c2
GL
1041 q = scopy(q, "\\*(a]");
1042 flag = true;
1043 *q++ = *p;
db589048 1044 q = scopy(q, "\\*(p]");
f0a950c2
GL
1045 }
1046 if (*++p == '.')
1047 p++;
1048 else while (*p != 0 && ! isspace(*p))
1049 p++;
1050 }
1051 *q = 0;
1052 f = newfirst;
1053 }
1054 else
1055 f = first;
1056
1057 if (capsmcap) {
1058 p = last;
1059 q = newlast;
1060 flag = 0; /* 1 - printing cap, 2 - printing small */
1061 while (*p)
1062 if (islower(*p)) {
1063 if (flag != 2)
1064 q = scopy(q, "\\s-2");
1065 flag = 2;
1066 *q++ = (*p++ - 'a') + 'A';
1067 }
1068 else {
1069 if (flag == 2)
1070 q = scopy(q,"\\s+2");
1071 flag = 1;
1072 *q++ = *p++;
1073 }
1074 if (flag == 2)
1075 q = scopy(q, "\\s+2");
1076 *q = 0;
1077 l = newlast;
1078 }
1079 else
1080 l = last;
1081
db589048
GL
1082 if (f[0] == 0)
1083 sprintf(name, "%s\n", l);
1084 else if (reverse)
1085 sprintf(name, "%s\\*(b]%s\n", l, f);
f0a950c2
GL
1086 else
1087 sprintf(name, "%s %s\n", f, l);
1088}
1089
1090/* prtauth - print author or editor field */
1091 prtauth(c, line, num, max, ofd, abbrev, capsmcap, numrev)
1092 char c, *line;
1093 int num, max, abbrev, capsmcap, numrev;
1094 FILE *ofd;
1095{ char first[LINELENGTH], last[LINELENGTH];
1096
1097 if (num <= numrev || abbrev || capsmcap) {
1098 breakname(line, first, last);
1099 bldname(first, last, line, num <= numrev);
1100 }
1101 if (num == 1)
1102 fprintf(ofd,".ds [%c %s", c, line);
1103 else if (num < max)
1104 fprintf(ofd,".as [%c \\*(c]%s", c, line);
1105 else if (max == 2)
1106 fprintf(ofd,".as [%c \\*(n]%s", c, line);
1107 else
1108 fprintf(ofd,".as [%c \\*(m]%s", c, line);
1109 if (num == max && index(trailstr, c))
1110 fprintf(ofd,".ds ]%c %c\n", c, line[strlen(line)-2]);
1111}
1112
1113/* doline - actually print out a line of reference information */
1114 doline(c, line, numauths, maxauths, numeds, maxeds, ofd)
1115 char c, *line;
1116 int numauths, maxauths, numeds, maxeds;
1117 FILE *ofd;
1118{
1119
1120 switch(c) {
1121 case 'A':
1122 prtauth(c, line, numauths, maxauths, ofd, abbrev, capsmcap, numrev);
1123 break;
1124
1125 case 'E':
1126 prtauth(c, line, numeds, maxeds, ofd, edabbrev, edcapsmcap, ednumrev);
1127 if (numeds == maxeds)
1128 fprintf(ofd,".nr [E %d\n", maxeds);
1129 break;
1130
1131 case 'P':
1132 if (index(line, '-'))
1133 fprintf(ofd,".nr [P 1\n");
1134 else
1135 fprintf(ofd,".nr [P 0\n");
1136 fprintf(ofd,".ds [P %s",line);
1137 if (index(trailstr, 'P'))
1138 fprintf(ofd,".ds ]P %c\n",line[strlen(line)-2]);
1139 break;
1140
1141 case 'F':
1142 case 'K': break;
1143
1144 default:
1145 fprintf(ofd,".ds [%c %s", c, line);
1146 if (index(trailstr, c))
1147 fprintf(ofd,".ds ]%c %c\n", c, line[strlen(line)-2]);
1148 }
1149}
1150
db589048
GL
1151/* dumpref - dump reference number i */
1152 dumpref(i, ofd)
1153 int i;
1154 FILE *ofd;
dca84ce7
RH
1155{ char ref[REFSIZE], line[REFSIZE];
1156 reg char *p, *q;
1157 char *from;
db589048
GL
1158 int numauths, maxauths, numeds, maxeds;
1159
dca84ce7 1160 rdref(&refinfo[i], ref);
db589048
GL
1161 maxauths = maxeds = 0;
1162 numauths = numeds = 0;
1163 for (p = ref; *p; p++)
1164 if (*p == '%')
1165 if (*(p+1) == 'A') maxauths++;
1166 else if (*(p+1) == 'E') maxeds++;
1167 fprintf(ofd, ".[-\n");
dca84ce7
RH
1168 fprintf(ofd, ".ds [F %s\n", refinfo[i].ri_cite);
1169#ifndef INCORE
1170 fseek(rfd, (long)refinfo[i].ri_pos, 0);
db589048 1171 while (fgets(line, REFSIZE, rfd) != NULL) {
dca84ce7
RH
1172#else INCORE
1173 for (q = line, from = refinfo[i].ri_ref; *from; /*VOID*/) { /*} */
1174 if (*from == '\n'){
1175 *q++ = '\n';
1176 *q = 0;
1177 q = line;
1178 from++;
1179 } else {
1180 *q++ = *from++;
1181 continue;
1182 }
1183#endif INCORE
1184 switch(line[0]){
1185 case 0:
1186 goto doneref;
1187 case '.':
1188 fprintf(ofd, "%s", line);
1189 break;
1190 case '%':
1191 switch(line[1]){
1192 case 'A': numauths++; break;
1193 case 'E': numeds++; break;
1194 }
1195 for (p = &line[2]; *p == ' '; p++) /*VOID*/;
1196 doline(line[1], p, numauths, maxauths, numeds, maxeds, ofd);
1197 }
1198 }
1199 doneref:;
db589048
GL
1200 fprintf(ofd,".][\n");
1201}