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