xref: /original-bsd/contrib/bib/src/bibargs.c (revision 9087ff44)
1 #ifndef lint
2 static char sccsid[] = "@(#)bibargs.c	2.9	06/11/85";
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[120];             /* 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(), *fullaabet(), *astro();
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);
756 	 else if (c == '8')			/* Full alphabetic */
757 	    cp = fullaabet(cp, ref);
758          else if (c == '9')                     /* Last name of Senior Author*/
759             cp = aabetlast(cp, ref);
760 	 else if (c == '0') {			/* print nothing */
761             for (fp = field; *fp; )
762                *cp++ = *fp++;
763             }
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[];
796 {  char field[REFSIZE], temp[100];
797    reg char *np, *fp;
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       }
813 return(cp);
814 }
815 
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 
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];
848    reg char	*fp;
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 
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[];
865 {  char name1[100], name2[100], name3[100], temp[100];
866    reg char *fp;
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     }
895 return(cp);
896 }
897 
898 /* getfield - get a single field from reference */
899    char *getfield(ptr, field, ref)
900    char *ptr, field[], ref[];
901 {  reg	char *p, *q;
902    char	temp[100];
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[];
958 {  reg char *p;
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()
996 {  reg int i, j;
997 	char adstr;
998 
999    for (i = 0; i < numrefs-1; i = j) {
1000       j = i + 1;
1001       if (strcmp(refinfo[i].ri_cite, refinfo[j].ri_cite)==0) {
1002          adstr = 'a';
1003          for(j = i+1;
1004 	     j<numrefs && strcmp(refinfo[i].ri_cite,refinfo[j].ri_cite) == 0;
1005 	     j++) {
1006             adstr = 'a' + (j-i);
1007 	    refinfo[j].ri_disambig[0] = adstr;
1008             }
1009 	 refinfo[i].ri_disambig[0] = 'a';
1010          }
1011      }
1012   for (i = 0; i < numrefs; i++){
1013 	strcat(refinfo[i].ri_cite, refinfo[i].ri_disambig);
1014   }
1015 }
1016 
1017 
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 {
1025    char newfirst[120], newlast[120];
1026    reg char *p, *q, *f, *l;
1027    char *scopy();
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)) {
1040             if (flag)           /* between initial gap */
1041                q = scopy(q, "\\*(a]");
1042             flag = true;
1043             *q++ = *p;
1044             q = scopy(q, "\\*(p]");
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 
1082    if (f[0] == 0)
1083       sprintf(name, "%s\n", l);
1084    else if (reverse)
1085       sprintf(name, "%s\\*(b]%s\n", l, f);
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 
1151 /* dumpref - dump reference number i */
1152    dumpref(i, ofd)
1153    int i;
1154    FILE *ofd;
1155 {  char ref[REFSIZE], line[REFSIZE];
1156    reg char *p, *q;
1157    char *from;
1158    int numauths, maxauths, numeds, maxeds;
1159 
1160    rdref(&refinfo[i], ref);
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");
1168    fprintf(ofd, ".ds [F %s\n", refinfo[i].ri_cite);
1169 #ifndef INCORE
1170    fseek(rfd, (long)refinfo[i].ri_pos, 0);
1171    while (fgets(line, REFSIZE, rfd) != NULL) {
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:;
1200    fprintf(ofd,".][\n");
1201 }
1202