xref: /original-bsd/contrib/bib/src/bibargs.c (revision 79cf7955)
1 #ifndef lint
2 static char sccsid[] = "@(#)bibargs.c	2.12	11/16/87";
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 
15 
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 */
26    char bibfname[120];          /* file name currently being read            */
27    int  biblineno;              /* line number currently being referenced    */
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              */
34    int	max_klen     = 6;	/* max size of key			     */
35    int  sort         = false;   /* sort references ? (default no)            */
36    int  foot         = false;   /* footnoted references ? (default endnotes) */
37    int  doacite      = true;    /* place citations ? */
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             */
42    char pfile[400];             /* private file name                         */
43    int  personal = false;       /* personal file given ? (default no)        */
44    char citetemplate[80] = "1"; /* citation template                         */
45    struct wordinfo words[MAXDEFS];     /* defined words */
46    struct wordinfo *wordhash[HASHSIZE];
47    struct wordinfo *wordsearch();
48    int  wordtop = 0;           /* number of defined words         */
49 
50 /* where output goes */
51    extern FILE *tfd;
52 /* reference file information */
53    extern struct refinfo refinfo[];
54    extern char reffile[];
55 #ifndef INCORE
56    extern FILE *rfd;
57 #endif not INCORE
58    extern int numrefs;
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;
74    newbibdir(BMACLIB);
75 
76    for (i = 1; i < argc; i++)
77       if (argv[i][0] == '-')
78          switch(argv[i][1]) {
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);
87             case 'a':  for (p = &argv[i][2]; *p; p++)
88                           if (*p == 'a' || *p == 0)
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                               }
99                        break;
100 
101             case 'c':  if (argv[i][2] == 0)
102                           error("citation string expected for 'c'");
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 
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 
130             case 'v':  doacite = false;
131 			/*FALLTHROUGH*/
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;
142                           else if (*p == 'v')
143                              doacite = true;
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 
171             case 'r':  if (argv[i][2] == 0)  /* this is now replaced by -ar */
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 
182             case 't':  style = false;           /* fall through */
183             case 'i':  if (argv[i][2])
184                           p = &argv[i][2];
185                        else { /* take next arg */
186                           i++;
187                           p = argv[i];
188                           }
189                        incfile(p);
190                        break;
191 
192             case 'x':  capsmcap = true; /* this is now replaced by -ax */
193                        break;
194 
195             case 0:    if (style) {  /* no style command given, take default */
196                           style = false;
197                           incfile( defstyle );
198                           }
199                        strcpy(bibfname,"<stdin>");
200                        rdtext(stdin);
201                        numfiles++;
202                        break;
203 
204             default:   fputs(argv[i], stderr);
205                        error("'%c' invalid switch", argv[i][1]);
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) {
215             error("can't open file %s", argv[i]);
216             }
217          else {
218             strcpy(bibfname, argv[i]);
219             rdtext(fd);
220             fclose(fd);
221             }
222          }
223 
224    if (style) incfile( defstyle );
225    return(numfiles);
226 
227 }
228 
229 newbibdir(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 
239 /* incfile - read in an included file  */
240 incfile(np)
241    char *np;
242 {  char name[120];
243    FILE *fd;
244    char *p, line[LINELENGTH], dline[LINELENGTH], word[80], *tfgets();
245    int  i, getwrd();
246 
247    strcpy(bibfname, np);
248    fd = fopen(np, "r");
249    if (fd == NULL && *np != '/') {
250       strcpy(name, "bib.");
251       strcat(name, np);
252       strcpy(bibfname, name);
253       fd = fopen(name, "r");
254       }
255    if (fd == NULL && *np != '/') {
256       strcpy(name,BMACLIB);
257       strcat(name, "/bib.");
258       strcat(name, np);
259       strcpy(bibfname, name);
260       fd = fopen(name, "r");
261       }
262    if (fd == NULL) {
263       bibwarning("%s: can't open", np);
264       exit(1);
265       }
266 
267    /* now go off and process file */
268    biblineno = 1;
269    while (tfgets(line, LINELENGTH, fd) != NULL) {
270       biblineno++;
271       switch(line[0]) {
272 
273          case '#': break;
274 
275          case 'A': for (p = &line[1]; *p; p++)
276                       if (*p == 'A' || *p == '\0')
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                          }
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");
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 			}
299 			break;
300 		   }
301                    for (p = &line[i]; *p == ' '; p++) ;
302                    for (strcpy(dline, p); dline[strlen(dline)-1] == '\\'; ){
303                        dline[strlen(dline)-1] = '\n';
304                        if (tfgets(line, LINELENGTH, fd) == NULL) break;
305                        strcat(dline, line);
306                        }
307 		   wordstuff(word, dline);
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 
339          case 'R': if (line[1] == 0)  /* this is now replaced by AR */
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 
354          case 'X': capsmcap = true;     /* this is now replace by AX */
355                    break;
356 
357          default:  fprintf(tfd,"%s\n",line);
358                    while (fgets(line, LINELENGTH, fd) != NULL)
359                       fputs(line, tfd);
360                    return;
361          }
362 
363    }
364    /* close up */
365    fclose(fd);
366 }
367 
368 /* bibwarning - print out a warning message */
369   /*VARARGS1*/
370   bibwarning(msg, a1, a2)
371   char *msg;
372 {
373   fprintf(stderr,"`%s', line %d: ", bibfname, biblineno);
374   fprintf(stderr, msg, a1, a2);
375   fprintf(stderr, "\n");
376 }
377 
378 /* error - report unrecoverable error message */
379   /*VARARGS1*/
380   error(str, a1, a2)
381   char *str;
382 {
383   bibwarning(str, a1, a2);
384   /*
385    *	clean up temp files and exit
386    */
387   cleanup(1);
388 }
389 
390 #ifndef INCORE
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 */
397 fixrfd( mode )
398 register 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)
407 		      error("Hell!  Couldn't re-open reference file %s",
408 			reffile);
409 	}
410 }
411 #endif
412 #endif not INCORE
413 
414 
415 /* tfgets - fgets which trims off newline */
416    char *tfgets(line, n, ptr)
417    char line[];
418    int  n;
419    FILE *ptr;
420 {  reg char *p;
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 */
433 int getwrd(in, i, out)
434    reg char in[], out[];
435    reg int i;
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 */
451 char *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);
459 }
460 
461 /* isword - see if character is legit word char */
462 int iswordc(c)
463 char c;
464 {
465    if (isalnum(c) || c == '&' || c == '_')
466       return(true);
467    return(false);
468 }
469    expand(line)
470    char *line;
471 {  char line2[REFSIZE], word[LINELENGTH];
472    reg	struct wordinfo *wp;
473    reg	char *p, *q, *w;
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 {
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);
532 }
533 
534 /* rdref - read text for an already cited reference */
535    rdref(p, ref)
536    struct refinfo *p;
537    char ref[REFSIZE];
538 {
539    ref[0] = 0;
540 #ifndef INCORE
541 #ifdef READWRITE
542    fixrfd( READ );                      /* fix access mode of rfd, if nec. */
543 #endif
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
566 }
567 
568 /* breakname - break a name into first and last name */
569    breakname(line, first, last)
570    char line[], first[], last[];
571 {  reg char *t, *f, *q, *r, *p;
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;
581    if (q != line) {
582       q++;
583       for (; isspace(*f); f--);
584       f++;
585       }
586 
587    /* first name is start to f, last name is q to t */
588 
589    for (r = first, p = line; p != f; )
590       *r++ = *p++;
591    *r = 0;
592    for (r = last, p = q, t++; q != t; )
593       *r++ = *q++;
594    *r = 0;
595 
596 }
597 
598 /* match - see if string1 is a substring of string2 (case independent)*/
599    int match(str1, str2)
600    reg char str1[], str2[];
601 {  reg int  j, i;
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)
621    reg char *p, *q;
622 {
623    while (*p++ = *q++)
624       ;
625    return(--p);
626 }
627 
628 /* rcomp - reference comparison routine for qsort utility */
629    int rcomp(ap, bp)
630    struct refinfo *ap, *bp;
631 {  char ref1[REFSIZE], ref2[REFSIZE], field1[MAXFIELD], field2[MAXFIELD];
632    reg	char *p, *q;
633    char *getfield();
634    int  neg, res;
635    int  fields_found;
636 
637    rdref(ap, ref1);
638    rdref(bp, ref2);
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 
707 /* makecites - make standard citation strings, using citetemplate currently in effect */
708    makecites()
709 {  char ref[REFSIZE], tempcite[100], *malloc();
710    reg int  i;
711 
712    for (i = 0; i < numrefs; i++) {
713       rdref(&refinfo[i], ref);
714       bldcite(tempcite, i, ref);
715       refinfo[i].ri_cite = malloc(2 + strlen(tempcite));
716       if (refinfo[i].ri_cite == NULL)
717          error("out of storage");
718       strcpy(refinfo[i].ri_cite, tempcite);
719       }
720 }
721 
722 /* bldcite - build a single citation string */
723    bldcite(cp, i, ref)
724    char *cp, ref[];
725    int  i;
726 {  reg char *p, *q, *fp;
727    char c;
728    char field[REFSIZE];
729    char *getfield(), *aabet(), *aabetlast(),
730         *fullaabet(), *multfull();
731 
732    getfield("F", field, ref);
733    if (field[0] != 0)
734       for (p = field; *p; p++)
735          *cp++ = *p;
736    else {
737       p = citetemplate;
738       field[0] = 0;
739       while (c = *p++) {
740          if (isalpha(c)) {                      /* field name   */
741             q = getfield(p-1, field, ref);
742             if (q != 0) {
743                p = q;
744                for (fp = field; *fp; )
745                   *cp++ = *fp++;
746                }
747             }
748          else if (c == '1') {                   /* numeric  order */
749             sprintf(field,"%d",1 + i);
750             for (fp = field; *fp; )
751                *cp++ = *fp++;
752             }
753          else if (c == '2')                     /* alternate alphabetic */
754             cp = aabet(cp, ref);
755          else if (c == '3')                     /* Astrophysical Journal style*/
756             cp = multfull(cp, ref, 3);
757          else if (c == '4')                     /* Computing Surveys style*/
758             cp = multfull(cp, ref, 2);
759 	 else if (c == '8')			/* Full alphabetic */
760 	    cp = fullaabet(cp, ref);
761          else if (c == '9')                     /* Last name of Senior Author*/
762             cp = aabetlast(cp, ref);
763 	 else if (c == '0') {			/* print nothing */
764             for (fp = field; *fp; )
765                *cp++ = *fp++;
766             }
767 /*       else if (c == '4')          here is how to add new styles */
768          else if (c == '{') {                   /* other information   */
769             while (*p != '}')
770                if (*p == 0)
771                   error("unexpected end of citation template");
772                else
773                   *cp++ = *p++;
774             p++;
775             }
776          else if (c == '<') {
777             while (*p != '>') {
778                if (*p == 0)
779                   error("unexpected end of citation template");
780                else
781                   *cp++ = *p++;
782                }
783             p++;
784             }
785          else if (c != '@')
786             *cp++ = c;
787          }
788       }
789    *cp++ = 0;
790 }
791 
792 /* alternate alphabetic citation style -
793         if 1 author - first three letters of last name
794         if 2 authors - first two letters of first, followed by first letter of
795                                 seond
796         if 3 or more authors - first letter of first three authors */
797    char *aabet(cp, ref)
798    char *cp, ref[];
799 {  char field[REFSIZE], temp[100];
800    reg char *np, *fp;
801    int j, getname();
802 
803    if (getname(1, field, temp, ref)) {
804       np = cp;
805       fp = field;
806       for (j = 1; j <= 3; j++)
807          if (*fp != 0)
808             *cp++ = *fp++;
809       if (getname(2, field, temp, ref))
810          np[2] = field[0];
811       if (getname(3, field, temp, ref)) {
812          np[1] = np[2];
813          np[2] = field[0];
814          }
815       }
816 return(cp);
817 }
818 
819 /* alternate alphabetic citation style -
820 	first two characters of last names of all authors
821 	up to max_klen characters.
822 */
823    char *fullaabet(cp, ref)
824    char *cp, ref[];
825 {  char field[REFSIZE], temp[100];
826    reg char	*fp;
827    char	*lastcp;
828    int getname();
829    int i;
830 
831    lastcp = cp + max_klen;
832    for (i= 1; getname(i, field, temp, ref); i++) {
833       for (fp = field; *fp && (fp < &(field[3])); )
834 	 if (cp > lastcp)
835 	     break;
836          else if (isalpha(*fp))
837 	     *cp++ = *fp++;
838 	 else
839 	     fp++;
840    }
841    return(cp);
842 }
843 
844 
845 /* alternate alphabetic citation style -
846 	entire last name of senior author
847 */
848    char *aabetlast(cp, ref)
849    char *cp, ref[];
850 {  char field[REFSIZE], temp[100];
851    reg char	*fp;
852    int getname();
853 
854    if (getname(1, field, temp, ref)) {
855       for (fp = field; *fp; )
856          *cp++ = *fp++;
857    }
858    return(cp);
859 }
860 
861 /*
862   Multiple full authors last names (1, 2 or 3 full names).
863 
864   If maxauthors<3
865         if 1 author - last name date
866         if 2 authors - last name and last name date
867         if 3 or more authors - last name et al. date
868   If maxauthors>=3
869         if 1 author - last name date
870         if 2 authors - last name and last name date
871         if 3 authors - last name, last name and last name date
872         if 4 or more authors - last name et al. date */
873    char *multfull(cp, ref, maxauthors)
874    char *cp, ref[];
875    int maxauthors;
876 {  char name1[100], name2[100], name3[100], temp[100];
877    reg char *fp;
878    int getname();
879 
880    if (getname(1, name1, temp, ref)) {
881       for (fp = name1; *fp; )
882          *cp++ = *fp++;
883       if (((maxauthors >= 3) && (getname(4, name3, temp, ref)))
884 	  || ((maxauthors < 3) && (getname(3, name3, temp, ref)))) {
885          for (fp = " \\*(e]"; *fp; )
886             *cp++ = *fp++;
887          }
888       else if (getname(2, name2, temp, ref)) {
889          if (getname(3, name3, temp, ref)) {
890             for (fp = "\\*(c]"; *fp; )
891                *cp++ = *fp++;
892             for (fp = name2; *fp; )
893                *cp++ = *fp++;
894             for (fp = "\\*(m]"; *fp; )
895                *cp++ = *fp++;
896             for (fp = name3; *fp; )
897                *cp++ = *fp++;
898             }
899          else {
900             for (fp = "\\*(n]"; *fp; )
901                *cp++ = *fp++;
902             for (fp = name2; *fp; )
903                *cp++ = *fp++;
904             }
905          }
906     }
907 return(cp);
908 }
909 
910 /* getfield - get a single field from reference */
911    char *getfield(ptr, field, ref)
912    char *ptr, field[], ref[];
913 {  reg	char *p, *q;
914    char	temp[100];
915    int  n, len, i, getname();
916 
917    field[0] = 0;
918    if (*ptr == 'A')
919       getname(1, field, temp, ref);
920    else
921       for (p = ref; *p; p++)
922          if (*p == '%' && *(p+1) == *ptr) {
923             for (p = p + 2; *p == ' '; p++)
924                ;
925             for (q = field; (*p != '\n') && (*p != '\0'); )
926                *q++ = *p++;
927             *q = 0;
928             break;
929             }
930    n = 0;
931    len = strlen(field);
932    if (*++ptr == '-') {
933       for (ptr++; isdigit(*ptr); ptr++)
934          n = 10 * n + (*ptr - '0');
935       if (n > len)
936          n = 0;
937       else
938          n = len - n;
939       for (i = 0; field[i] = field[i+n]; i++)
940          ;
941       }
942    else if (isdigit(*ptr)) {
943       for (; isdigit(*ptr); ptr++)
944          n = 10 * n + (*ptr - '0');
945       if (n > len)
946          n = len;
947       field[n] = 0;
948       }
949 
950    if (*ptr == 'u') {
951       ptr++;
952       for (p = field; *p; p++)
953          if (islower(*p))
954             *p = (*p - 'a') + 'A';
955       }
956    else if (*ptr == 'l') {
957       ptr++;
958       for (p = field; *p; p++)
959          if (isupper(*p))
960             *p = (*p - 'A') + 'a';
961       }
962    return(ptr);
963 }
964 
965 /* getname - get the nth name field from reference, breaking into
966              first and last names */
967    int getname(n, last, first, ref)
968    int  n;
969    char last[], first[], ref[];
970 {  reg char *p;
971    int  m;
972 
973    m = n;
974    for (p = ref; *p; p++)
975       if (*p == '%' & *(p+1) == 'A') {
976          n--;
977          if (n == 0) {
978             for (p = p + 2; *p == ' '; p++) ;
979             breakname(p, first, last) ;
980             return(true);
981             }
982          }
983 
984    if (n == m)          /* no authors, try editors */
985       for (p = ref; *p; p++)
986          if (*p == '%' & *(p+1) == 'E') {
987             n--;
988             if (n == 0) {
989                for (p = p + 2; *p == ' '; p++) ;
990                breakname(p, first, last) ;
991                return(true);
992                }
993             }
994 
995    if (n == m) {        /* no editors, either, try institution */
996       first[0] = last[0] = '\0';
997       getfield("I", last, ref);
998       if (last[0] != '\0')
999          return(true);
1000       }
1001 
1002    return(false);
1003 }
1004 
1005 /* disambiguate - compare adjacent citation strings, and if equal, add
1006                   single character disambiguators */
1007    disambiguate()
1008 {  reg int i, j;
1009 	char adstr;
1010 
1011    for (i = 0; i < numrefs-1; i = j) {
1012       j = i + 1;
1013       if (strcmp(refinfo[i].ri_cite, refinfo[j].ri_cite)==0) {
1014          adstr = 'a';
1015          for(j = i+1;
1016 	     j<numrefs && strcmp(refinfo[i].ri_cite,refinfo[j].ri_cite) == 0;
1017 	     j++) {
1018             adstr = 'a' + (j-i);
1019 	    refinfo[j].ri_disambig[0] = adstr;
1020             }
1021 	 refinfo[i].ri_disambig[0] = 'a';
1022          }
1023      }
1024   for (i = 0; i < numrefs; i++){
1025 	strcat(refinfo[i].ri_cite, refinfo[i].ri_disambig);
1026   }
1027 }
1028 
1029 
1030 /* bldname - build a name field
1031              doing abbreviations, reversals, and caps/small caps
1032 */
1033    bldname(first, last, name, reverse)
1034    char *first, *last, name[];
1035    int reverse;
1036 {
1037    char newfirst[120], newlast[120];
1038    reg char *p, *q, *f, *l;
1039    char *scopy();
1040    int  flag;
1041 
1042    if (abbrev) {
1043       p = first;
1044       q = newfirst;
1045       flag = false;
1046       while (*p) {
1047          while (*p == ' ')
1048             p++;
1049          if (*p == 0)
1050             break;
1051          if (isupper(*p)) {
1052             if (flag)           /* between initial gap */
1053                q = scopy(q, "\\*(a]");
1054             flag = true;
1055             *q++ = *p;
1056             q = scopy(q, "\\*(p]");
1057             }
1058          if (*++p == '.')
1059             p++;
1060          else while (*p != 0 && ! isspace(*p))
1061             p++;
1062          }
1063       *q = 0;
1064       f = newfirst;
1065       }
1066    else
1067       f = first;
1068 
1069    if (capsmcap) {
1070       p = last;
1071       q = newlast;
1072       flag = 0;  /* 1 - printing cap, 2 - printing small */
1073       while (*p)
1074          if (islower(*p)) {
1075             if (flag != 2)
1076                q = scopy(q, "\\s-2");
1077             flag = 2;
1078             *q++ = (*p++ - 'a') + 'A';
1079             }
1080          else {
1081             if (flag == 2)
1082                q = scopy(q,"\\s+2");
1083             flag = 1;
1084             *q++ = *p++;
1085             }
1086       if (flag == 2)
1087          q = scopy(q, "\\s+2");
1088       *q = 0;
1089       l = newlast;
1090       }
1091    else
1092       l = last;
1093 
1094    if (f[0] == 0)
1095       sprintf(name, "%s\n", l);
1096    else if (reverse)
1097       sprintf(name, "%s\\*(b]%s\n", l, f);
1098    else
1099       sprintf(name, "%s %s\n", f, l);
1100 }
1101 
1102 /* prtauth - print author or editor field */
1103    prtauth(c, line, num, max, ofd, abbrev, capsmcap, numrev)
1104    char c, *line;
1105    int  num, max, abbrev, capsmcap, numrev;
1106    FILE *ofd;
1107 {  char first[LINELENGTH], last[LINELENGTH];
1108 
1109    if (num <= numrev || abbrev || capsmcap) {
1110       breakname(line, first, last);
1111       bldname(first, last, line, num <= numrev);
1112       }
1113    if (num == 1)
1114       fprintf(ofd,".ds [%c %s", c, line);
1115    else if (num < max)
1116       fprintf(ofd,".as [%c \\*(c]%s", c, line);
1117    else if (max == 2)
1118       fprintf(ofd,".as [%c \\*(n]%s", c, line);
1119    else
1120       fprintf(ofd,".as [%c \\*(m]%s", c, line);
1121    if (num == max && index(trailstr, c))
1122       fprintf(ofd,".ds ]%c %c\n", c, line[strlen(line)-2]);
1123 }
1124 
1125 /* doline - actually print out a line of reference information */
1126    doline(c, line, numauths, maxauths, numeds, maxeds, ofd)
1127    char c, *line;
1128    int numauths, maxauths, numeds, maxeds;
1129    FILE *ofd;
1130 {
1131 
1132    switch(c) {
1133       case 'A':
1134           prtauth(c, line, numauths, maxauths, ofd, abbrev, capsmcap, numrev);
1135           break;
1136 
1137        case 'E':
1138           prtauth(c, line, numeds, maxeds, ofd, edabbrev, edcapsmcap, ednumrev);
1139           if (numeds == maxeds)
1140              fprintf(ofd,".nr [E %d\n", maxeds);
1141           break;
1142 
1143        case 'P':
1144           if (index(line, '-'))
1145              fprintf(ofd,".nr [P 1\n");
1146           else
1147              fprintf(ofd,".nr [P 0\n");
1148           fprintf(ofd,".ds [P %s",line);
1149           if (index(trailstr, 'P'))
1150              fprintf(ofd,".ds ]P %c\n",line[strlen(line)-2]);
1151           break;
1152 
1153        case 'F':
1154        case 'K': break;
1155 
1156        default:
1157           fprintf(ofd,".ds [%c %s", c, line);
1158           if (index(trailstr, c))
1159              fprintf(ofd,".ds ]%c %c\n", c, line[strlen(line)-2]);
1160           }
1161 }
1162 
1163 /* dumpref - dump reference number i */
1164    dumpref(i, ofd)
1165    int i;
1166    FILE *ofd;
1167 {  char ref[REFSIZE], line[REFSIZE];
1168    reg char *p, *q;
1169    char *from;
1170    int numauths, maxauths, numeds, maxeds;
1171 
1172    if ( i < 0 ) ref[0] = 0; /* ref not found */
1173    else {
1174 	   rdref(&refinfo[i], ref);
1175 	   maxauths = maxeds = 0;
1176 	   numauths = numeds = 0;
1177 	   for (p = ref; *p; p++)
1178 	      if (*p == '%')
1179 	         if (*(p+1) == 'A') maxauths++;
1180 	         else if (*(p+1) == 'E') maxeds++;
1181 	   fprintf(ofd, ".[-\n");
1182 	   fprintf(ofd, ".ds [F %s\n", refinfo[i].ri_cite);
1183 #ifndef INCORE
1184 	   fseek(rfd, (long)refinfo[i].ri_pos, 0);
1185 	   while (fgets(line, REFSIZE, rfd) != NULL) {
1186 #else INCORE
1187 	   for (q = line, from = refinfo[i].ri_ref; *from; /*VOID*/) { /*} */
1188 		if (*from == '\n'){
1189 			*q++ = '\n';
1190 			*q = 0;
1191 			q = line;
1192 			from++;
1193 		} else {
1194 			*q++ = *from++;
1195 			continue;
1196 		}
1197 #endif INCORE
1198 		switch(line[0]){
1199 		case 0:
1200 			goto doneref;
1201 		case '.':
1202 			fprintf(ofd, "%s", line);
1203 			break;
1204 		case '%':
1205 			switch(line[1]){
1206 			case 'A':	numauths++;	break;
1207 			case 'E':	numeds++;	break;
1208 			}
1209 			for (p = &line[2]; *p == ' '; p++) /*VOID*/;
1210 			doline(line[1], p, numauths, maxauths, numeds, maxeds, ofd);
1211 		}
1212 	   }
1213 	   doneref:;
1214 	   fprintf(ofd,".][\n");
1215    }
1216 }
1217