BSD 4_4 release
[unix-history] / usr / src / contrib / bib / src / bib.c
index 9af40ca..e072eb5 100644 (file)
@@ -1,15 +1,31 @@
+#ifndef lint
+static char sccsid[] = "@(#)bib.c      2.11    5/27/93";
+#endif not lint
 /*
 /*
-   bib - bibliographic formatter
-         timothy a. budd, 1/82
-         lookup routines supplied by gary levin 2/82
-         reworked several new features added, 11/82.
-*/
+        Bib - bibliographic formatter
+
+        Authored by: Tim Budd, University of Arizona, 1983.
+                lookup routines written by gary levin 2/82
+
+                version 7/4/83
+
+        Various modifications suggested by:
+                David Cherveny - Duke University Medical Center
+                Phil Garrison - UC Berkeley
+                M. J. Hawley - Yale University
+
+              version 8/23/1988
+        
+        Adapted to use TiB style macro calls (i.e. |macro|)
+              A. Dain Samples
+
+                                                        */
+
 # include <stdio.h>
 # include <ctype.h>
 # include "bib.h"
 
 # define HUNTSIZE 512                /* maximum size of hunt string         */
 # include <stdio.h>
 # include <ctype.h>
 # include "bib.h"
 
 # define HUNTSIZE 512                /* maximum size of hunt string         */
-# define MAXFIELD 250                /* maximum field length                */
 # define MAXREFS  300                /* maximum number of references        */
 # define MAXATONCE 35                /* maximum references at one location  */
 
 # define MAXREFS  300                /* maximum number of references        */
 # define MAXATONCE 35                /* maximum references at one location  */
 
 
 /* global variables */
    FILE *rfd;                   /* reference temporary file              */
 
 /* global variables */
    FILE *rfd;                   /* reference temporary file              */
+#ifndef INCORE
    char reffile[] = TMPREFFILE ;/* temporary file (see bib.h)            */
    char reffile[] = TMPREFFILE ;/* temporary file (see bib.h)            */
-   long int refspos[MAXREFS];   /* reference seek positions              */
+#endif not INCORE
+   struct refinfo refinfo[MAXREFS];    /* reference information */
+   struct refinfo *refssearch();
+   struct refinfo *refshash[HASHSIZE];
    long int rend = 1;           /* last position in rfd (first char unused)*/
    long int rend = 1;           /* last position in rfd (first char unused)*/
-   int numrefs = -1;            /* number of references generated so far */
+   int numrefs = 0;            /* number of references generated so far */
    FILE *tfd;                   /* output of pass 1 of file(s)           */
    FILE *tfd;                   /* output of pass 1 of file(s)           */
-   char tmpfile[] = TMPTEXTFILE ; /* output of pass 1                    */
-   char common[] = COMFILE ;    /* common word file                      */
-   char *citestr[MAXREFS];      /* citation strings                      */
+   char bibtmpfile[] = TMPTEXTFILE ; /* output of pass 1                    */
+   char *common = COMFILE;       /* common word file                      */
    int  findex = false;         /* can we read the file INDEX ?          */
 
    int  findex = false;         /* can we read the file INDEX ?          */
 
+char *programName;
+
 /* global variables in bibargs */
 /* global variables in bibargs */
-   extern int foot, sort, personal;
-   extern int hyphen, ordcite;
-   extern char sortstr[], pfile[], citetemplate[];
-   char *bibfname;             /* file name currently reading */
-   char *biblineno;            /* line number in that file */
+   extern int foot, doacite, sort, max_klen, personal;
+   extern int hyphen, ordcite, biblineno;
+   extern char sortstr[], pfile[], citetemplate[], bibfname[];
+   extern int TibOption;
 
 
+#include <signal.h>
 
 main(argc, argv)
    int argc;
    char **argv;
 {  int rcomp();
 
 main(argc, argv)
    int argc;
    char **argv;
 {  int rcomp();
+   int intr();
 
    /* the file INDEX in the current directory is the default index,
       if it is present */
 
 
    /* the file INDEX in the current directory is the default index,
       if it is present */
 
+   InitDirectory(BMACLIB,N_BMACLIB);
+   InitDirectory(COMFILE,N_COMFILE);
+   InitDirectory(DEFSTYLE,N_DEFSTYLE);
+
+   signal(SIGINT, intr);
    rfd = fopen( INDXFILE , "r");
    if (rfd != NULL) {
       findex = true;
       fclose(rfd);
       }
 
    rfd = fopen( INDXFILE , "r");
    if (rfd != NULL) {
       findex = true;
       fclose(rfd);
       }
 
+#ifndef INCORE
    /* open temporaries, reffile will contain references collected in
    /* open temporaries, reffile will contain references collected in
-      pass 1, and tmpfile will contain text.
+      pass 1, and bibtmpfile will contain text.
    */
    mktemp(reffile);
    rfd = fopen(reffile,"w+");
    if (rfd == NULL)
    */
    mktemp(reffile);
    rfd = fopen(reffile,"w+");
    if (rfd == NULL)
-      error("can't open temporary reference file");
-   mktemp(tmpfile);
-   tfd = fopen(tmpfile,"w");
+      error("can't open temporary reference file, %s", reffile);
+   putc('x', rfd);      /* put garbage in first position (not used) */
+#endif not INCORE
+   mktemp(bibtmpfile);
+   tfd = fopen(bibtmpfile,"w");
    if (tfd == NULL)
    if (tfd == NULL)
-      error("can't open temporary output file");
+      error("can't open temporary output file, %s", bibtmpfile);
 
     /*
        pass1 - read files, looking for citations
                arguments are read by doargs (bibargs.c)
     */
 
 
     /*
        pass1 - read files, looking for citations
                arguments are read by doargs (bibargs.c)
     */
 
-   if (doargs(argc, argv, DEFSTYLE ) == 0){
-      bibfname = "<stdin>";
+   if (doargs(argc, argv, DEFSTYLE ) == 0) { /* may not return */
+      strcpy(bibfname, "<stdin>");
       rdtext(stdin);
       rdtext(stdin);
-   }
+      }
 
    /*
     sort references, make citations, add disambiguating characters
    */
 
    if (sort)
 
    /*
     sort references, make citations, add disambiguating characters
    */
 
    if (sort)
-      qsort(refspos, numrefs+1, sizeof(long), rcomp);
-   makecites(citestr);
+      qsort(refinfo, numrefs, sizeof(struct refinfo), rcomp);
+   makecites();
    disambiguate();
 
    /*
    disambiguate();
 
    /*
@@ -87,25 +117,32 @@ main(argc, argv)
    */
 
    fclose(tfd);
    */
 
    fclose(tfd);
-   tfd = fopen(tmpfile,"r");
+   tfd = fopen(bibtmpfile,"r");
    if (tfd == NULL)
    if (tfd == NULL)
-      error("can't open temporary output file for reading");
-
+      error("can't open temporary output file %s for reading", bibtmpfile);
    /*
    pass 2 - reread files, replacing references
    */
    /*
    pass 2 - reread files, replacing references
    */
-
    pass2(tfd, stdout);
    pass2(tfd, stdout);
-
-   /*
-   clean up
-   */
-
+   cleanup(0);
+}
+/* interrupt processing */
+intr()
+{
+   cleanup(1);
+}
+/* clean up and exit */
+cleanup(val)
+{
    fclose(tfd);
    fclose(tfd);
+#ifndef INCORE
    fclose(rfd);
    fclose(rfd);
-   unlink(tmpfile);
    unlink(reffile);
    unlink(reffile);
-   exit(0);
+#endif INCORE
+#ifndef DEBUG
+   unlink(bibtmpfile);
+#endif DEBUG
+   exit(val);
 }
 
 /* rdtext - read and process a text file, looking for [. commands */
 }
 
 /* rdtext - read and process a text file, looking for [. commands */
@@ -113,117 +150,71 @@ main(argc, argv)
    FILE *fd;
 {  char lastc, c, d;
 
    FILE *fd;
 {  char lastc, c, d;
 
-   biblineno = 0;
-   lastc = 0;
+   lastc = '\0';
+   biblineno = 1;
    while (getch(c, fd) != EOF)
       if (c == '[' || c == '{')
          if (getch(d, fd) == '.') { /* found a reference */
             if (c == '{') { if (lastc) putc(lastc, tfd);}
             else
    while (getch(c, fd) != EOF)
       if (c == '[' || c == '{')
          if (getch(d, fd) == '.') { /* found a reference */
             if (c == '{') { if (lastc) putc(lastc, tfd);}
             else
-              switch (lastc) {
-              case ' ': fputs("\\*([<", tfd);
-                        break;
-               case '.': fputs("\\*([.", tfd);
-                        break;
-               case ',': fputs("\\*([,", tfd);
-                        break;
-               case '?': fputs("\\*([?", tfd);
-                        break;
-               case ':': fputs("\\*([:", tfd);
-                        break;
-               case ';': fputs("\\*([;", tfd);
-                        break;
-               case '!': fputs("\\*([!", tfd);
-                        break;
-               case '"': fputs("\\*([\"", tfd);
-                        break;
-               case '\'': fputs("\\*(['", tfd);
-                        break;
-              default : putc(lastc, tfd);
-                        break;
-              }
+               switch (lastc) {
+                  case '\0': break;
+                  case ' ': fputs("\\*([<", tfd); break;
+                  case '.': case ',': case '?': case ':':
+                  case ';': case '!': case '"': case '\'':
+                            fputs("\\*([", tfd);  /* fall through */
+                  default:  putc(lastc, tfd); break;
+                  }
             rdcite(fd, c);
             if (c == '[')
             rdcite(fd, c);
             if (c == '[')
-              switch (lastc) {
-              case ' ': fputs("\\*(<]", tfd);
-                        break;
-               case '.': fputs("\\*(.]", tfd);
-                        break;
-               case ',': fputs("\\*(,]", tfd);
-                        break;
-               case '?': fputs("\\*(?]", tfd);
-                        break;
-               case ':': fputs("\\*(:]", tfd);
-                        break;
-               case ';': fputs("\\*(;]", tfd);
-                        break;
-               case '!': fputs("\\*(!]", tfd);
-                        break;
-               case '"': fputs("\\*(\"]", tfd);
-                        break;
-               case '\'': fputs("\\*(']", tfd);
-                        break;
-              }
-            lastc = 0;
+               switch (lastc) {
+                  case '\0': break;
+                  case ' ': fputs("\\*(>]", tfd); break;
+                  case '.': case ',': case '?': case ':':
+                  case ';': case '!': case '"': case '\'':
+                            fprintf(tfd,"\\*(%c]", lastc); break;
+                  }
+            lastc = '\0';
             }
          else {
             }
          else {
-            if (lastc) putc(lastc, tfd);
+            if (lastc != '\0') putc(lastc, tfd);
             ungetc(d, fd);
             lastc = c;
             }
       else {
             ungetc(d, fd);
             lastc = c;
             }
       else {
-         if (lastc) putc(lastc, tfd);
+         if (lastc != '\0') putc(lastc, tfd);
          lastc = c;
          lastc = c;
-        if (c == '\n')
-               biblineno++;
+         if (c == '\n') biblineno++;
          }
          }
-   if (lastc) putc(lastc, tfd);
+   if (lastc != '\0') putc(lastc, tfd);
 }
 
 /* rdcite - read citation information inside a [. command */
    rdcite(fd, ch)
    FILE *fd;
    char ch;
 }
 
 /* rdcite - read citation information inside a [. command */
    rdcite(fd, ch)
    FILE *fd;
    char ch;
-{  long int n, getref();
+{  int getref();
    char huntstr[HUNTSIZE], c, info[HUNTSIZE];
 
    if (ch == '[')
    char huntstr[HUNTSIZE], c, info[HUNTSIZE];
 
    if (ch == '[')
-      fputs("\\*([[", tfd);
+      if (doacite) fputs("\\*([[", tfd);
    else
    else
-      fputs("\\*([{", tfd);
+      if (doacite) fputs("\\*([{", tfd);
    huntstr[0] = info[0] = 0;
    while (getch(c, fd) != EOF)
       switch (c) {
          case ',':
    huntstr[0] = info[0] = 0;
    while (getch(c, fd) != EOF)
       switch (c) {
          case ',':
-            n = getref(huntstr);
-            if (n > 0)
-               fprintf(tfd, "%c%ld%c%s%c", CITEMARK, n, CITEMARK, info, CITEEND);
-            else
-               fprintf(tfd, "%c0%c%s%s%c", CITEMARK, CITEMARK,
-                                           huntstr, info, CITEEND);
+           citemark(info, huntstr, "");
             huntstr[0] = info[0] = 0;
             break;
             huntstr[0] = info[0] = 0;
             break;
-
          case '.':
             while (getch(c, fd) == '.') ;
             if (c == ']') {
          case '.':
             while (getch(c, fd) == '.') ;
             if (c == ']') {
-               n = getref(huntstr);
-               if (n > 0)
-                  fprintf(tfd, "%c%ld%c%s%c\\*(]]", CITEMARK, n,
-                                                  CITEMARK, info, CITEEND);
-               else
-                  fprintf(tfd, "%c0%c%s%s%c\\*(]]", CITEMARK, CITEMARK,
-                                              huntstr, info, CITEEND);
+              citemark(info, huntstr, "\\*(]]");
                return;
                }
             else if (c == '}') {
                return;
                }
             else if (c == '}') {
-               n = getref(huntstr);
-               if (n > 0)
-                  fprintf(tfd, "%c%ld%c%s%c\\*(}]", CITEMARK, n,
-                                                    CITEMARK, info, CITEEND);
-               else
-                  fprintf(tfd, "%c0%c%s%s%c\\*(}]", CITEMARK, CITEMARK,
-                                              huntstr, info, CITEEND);
+              citemark(info, huntstr, "\\*(}]");
                return;
                }
             else
                return;
                }
             else
@@ -233,14 +224,14 @@ main(argc, argv)
          case '{':
             while (getch(c, fd) != '}')
                if (c == EOF) {
          case '{':
             while (getch(c, fd) != '}')
                if (c == EOF) {
-                  fprintf(stderr, "Error: ill formed reference\n");
-                  exit(1);
+                  error("ill formed reference");
                   }
                 else
                   addc(info, c);
             break;
 
          case '\n':
                   }
                 else
                   addc(info, c);
             break;
 
          case '\n':
+            biblineno++;
          case '\t':
             c = ' ';   /* fall through */
 
          case '\t':
             c = ' ';   /* fall through */
 
@@ -249,91 +240,158 @@ main(argc, argv)
          }
    error("end of file reading citation");
 }
          }
    error("end of file reading citation");
 }
+char   ncitetemplate[64];
+int    changecite;
+citemark(info, huntstr, tail)
+       char *info, *huntstr, *tail;
+{
+       char c = CITEMARK;
+        long int  n;
+       /*
+        *      getref sets ncitetemplate as a side effect
+        */
+       n = getref(huntstr);
+       if (ncitetemplate[0]){
+               fprintf(tfd, "%c%s%c", FMTSTART, ncitetemplate, FMTEND);
+               ncitetemplate[0] = 0;
+       }
+       fprintf(tfd, "%c%d%c%s%c%s", c ,n, c, info, CITEEND, doacite?tail:"");
+
+}
 
 /* addc - add a character to hunt string */
 
 /* addc - add a character to hunt string */
-   addc(huntstr, c)
+addc(huntstr, c)
    char huntstr[HUNTSIZE], c;
 {  int  i;
 
    i = strlen(huntstr);
    if (i > HUNTSIZE)
    char huntstr[HUNTSIZE], c;
 {  int  i;
 
    i = strlen(huntstr);
    if (i > HUNTSIZE)
-      error("citation too long");
+      error("citation too long, max of %d", HUNTSIZE);
    huntstr[i] = c;
    huntstr[i+1] = 0;
 }
 
    huntstr[i] = c;
    huntstr[i+1] = 0;
 }
 
-/* getref - if an item was already referenced, return its pointer in
-                the reference file, otherwise create a new entry */
-   long int getref(huntstr)
+/* getref - if an item was already referenced, return its reference index
+                otherwise create a new entry */
+int getref(huntstr)
    char huntstr[HUNTSIZE];
    char huntstr[HUNTSIZE];
-{  char rf[REFSIZE], ref[REFSIZE], *r, *hunt();
-   int  i, match(), getwrd();
-
-   r = hunt(huntstr);
+{  char rf[REFSIZE], *r, *hunt();
+   int match(), getwrd();
+   char        *realhstr;
+   int hash;
+   struct refinfo *rp;
+   int lg;
+
+   realhstr = huntstr;
+   if (strncmp(huntstr, "$C$", 3) == 0){
+       char *from, *to;
+       changecite++;
+       for(from = huntstr + 3, to = ncitetemplate; *from; from++, to++){
+               switch(*from){
+               case '\0':
+               case ' ':
+               case '\n':
+               case '\t':      goto outcopy;
+               default:        *to = *from;
+               }
+       }
+   outcopy: ;
+       *to = 0;
+       *from = 0;
+       realhstr = from + 1;
+   }
+   r = hunt(realhstr);
    if (r != NULL) {
    if (r != NULL) {
-      /* exapand defined string */
+      /* expand defined string */
       strcpy(rf, r);
       free(r);
       expand(rf);
       strcpy(rf, r);
       free(r);
       expand(rf);
-
       /* see if reference has already been cited */
       /* see if reference has already been cited */
-
-      if (foot == false)
-         for (i = 0; i <= numrefs; i++) {
-             rdref(refspos[i], ref);
-             if (strcmp(ref, rf) == 0)
-                return(refspos[i]);
-          }
-
+      if (foot == false && (rp = refssearch(rf))){
+               return(rp - refinfo);
+      }
       /* didn't match any existing reference, create new one */
       /* didn't match any existing reference, create new one */
-
-      numrefs++;
-      refspos[numrefs] = rend;
-      fseek(rfd, rend, 0);
-      i = strlen(rf) + 1;
-      fwrite(rf, 1, i, rfd);
-      rend = rend + i;
-      return(refspos[numrefs]);
+      if (numrefs >= MAXREFS)
+       error("too many references, max of %d", MAXREFS);
+      hash = strhash(rf);
+      lg = strlen(rf) + 1;
+      refinfo[numrefs].ri_pos = rend;
+      refinfo[numrefs].ri_length = lg;
+      refinfo[numrefs].ri_hp = refshash[hash];
+      refinfo[numrefs].ri_n = numrefs;
+      refshash[hash] = &refinfo[numrefs];
+      wrref(&refinfo[numrefs], rf);
+      return(numrefs++);
       }
    else {
       }
    else {
-      bibwarning("no reference matching %s\n", huntstr);
-      return( (long) -1 );
+      bibwarning("no reference matching %s\n", realhstr);
+      return(-1);
       }
 }
 
       }
 }
 
-/* rdref - read text for an already cited reference */
-   rdref(i, ref)
-   long int  i;
-   char ref[REFSIZE];
+struct refinfo *refssearch(rf)
+   char *rf;
 {
 {
-   ref[0] = 0;
-   fseek(rfd, i, 0);
-   fread(ref, 1, REFSIZE, rfd);
+   char ref[REFSIZE];
+   reg int i;
+   int lg;
+   reg struct refinfo *rp;
+   lg = strlen(rf) + 1;
+   for (rp = refshash[strhash(rf)]; rp; rp = rp->ri_hp){
+            if (rp->ri_length == lg){
+                    rdref(rp, ref);
+                    if (strcmp(ref, rf) == 0)
+                       return(rp);
+            }
+   }
+   return(0);
 }
 }
-
 /* hunt - hunt for reference from either personal or system index */
 /* hunt - hunt for reference from either personal or system index */
-   char *hunt(huntstr)
+/* the old versions would stop at the first index file where a citation
+ * matched.  This is NOT what is desired.  I have changed it so that it still
+ * returns the first citation found, but also reports the existence of
+ * duplicate entries in an INDEX file as well as across INDEX files.
+ * Also, we do NOT assume that the SYSINDEX has been Tib'd.  Therefore,
+ * if tib style expansion is in effect, the SYSINDEX is not searched.
+ * (Besides which, on Sun systems at least, the SYSINDEX files are
+ * created by refer, not bib, so we can't use them very effectively
+ * anyway.  Besides which again, everything in SYSINDEX is in our
+ * local files anyway.)
+ *                   - ads 8/88
+ */
+char *hunt(huntstr)
    char huntstr[];
    char huntstr[];
-{  char *fhunt(), *r, *p, *q, fname[120];
+{  char *found, *fhunt(), *r, *tp, *sp, fname[120];
 
 
+   found = NULL;
    if (personal) {
    if (personal) {
-      for (p = fname, q = pfile; ; q++)
-         if (*q == ',' || *q == 0) {
-            *p = 0;
-            if ((r = fhunt(fname, huntstr)) != NULL)
-               return(r);
-            else if (*q == 0)
+      for (tp = fname, sp = pfile; ; sp++)
+         if (*sp == ',' || *sp == '\0') {
+            *tp = '\0';
+            if ((r = fhunt(fname, huntstr)) != NULL) {
+               if (found != NULL) {
+                   /* we need an option to suppress this message -ads 5/89 */
+                   bibwarning("multiple INDEX files match citation %s\n",
+                                                       huntstr);
+                   return (found);
+                   }
+               found = r;
+               }
+            if (*sp == '\0')
                break;
                break;
-            p = fname;
+            tp = fname;
             }
             }
-         else *p++ = *q;
+         else *tp++ = *sp;
+      if (found != NULL) return (found);
       }
    else if (findex) {
       }
    else if (findex) {
-      if ((r = fhunt( INDXFILE , huntstr)) != NULL)
+      if ((r = fhunt(INDXFILE , huntstr)) != NULL)
          return(r);
       }
          return(r);
       }
-   if ((r = fhunt(SYSINDEX , huntstr)) != NULL)
-      return(r);
+   if (!TibOption) {
+      if ((r = fhunt(SYSINDEX , huntstr)) != NULL)
+        return(r);
+      }
    return(NULL);
 }
 
    return(NULL);
 }
 
@@ -342,7 +400,7 @@ main(argc, argv)
    char file[], huntstr[];
 {  char *p, *r, *locate();
 
    char file[], huntstr[];
 {  char *p, *r, *locate();
 
-   r = locate(huntstr, file, 6, common);
+   r = locate(huntstr, file, max_klen, common);
 
    if (r == NULL)
       return(NULL);  /* error */
 
    if (r == NULL)
       return(NULL);  /* error */
@@ -353,7 +411,7 @@ main(argc, argv)
       if (*p == '\n')
          if (*(p+1) == '\n') { /* end */
             if (*(p+2) != 0)
       if (*p == '\n')
          if (*(p+1) == '\n') { /* end */
             if (*(p+2) != 0)
-               bibwarning("multiple references match %s\n", huntstr);
+               bibwarning("multiple references match %s\n",huntstr);
             *(p+1) = 0;
             break;
             }
             *(p+1) = 0;
             break;
             }
@@ -361,259 +419,14 @@ main(argc, argv)
             *p = ' ';
    return(r);
 }
             *p = ' ';
    return(r);
 }
-
-/* rcomp - reference comparison routine for qsort utility */
-   int rcomp(ap, bp)
-   long int *ap, *bp;
-{  char ref1[REFSIZE], ref2[REFSIZE], field1[MAXFIELD], field2[MAXFIELD];
-   char *p, *q, *getfield();
-   int  neg, res;
-   int  fields_found;
-
-   rdref(*ap, ref1);
-   rdref(*bp, ref2);
-   for (p = sortstr; *p; p = q) {
-      if (*p == '-') {
-         p++;
-         neg = true;
-         }
-      else
-         neg = false;
-      q = getfield(p, field1, ref1);
-      fields_found = true;
-      if (q == 0) {
-        res = 1;
-        fields_found = false;
-      } else if (strcmp (field1, "") == 0) {   /* field not found */
-         if (*p == 'A') {
-            getfield("F", field1, ref1);
-           if (strcmp (field1, "") == 0) {
-               getfield("I", field1, ref1);
-              if (strcmp (field1, "") == 0) {
-                 res = 1;
-                 fields_found = false;
-              }
-           }
-        } else {
-           res = 1;
-           fields_found = false;
-        }
-      }
-
-      if (getfield(p, field2, ref2) == 0) {
-        res = -1;
-        fields_found = false;
-      } else if (strcmp (field2, "") == 0) {   /* field not found */
-         if (*p == 'A') {
-            getfield("F", field2, ref2);
-           if (strcmp (field2, "") == 0) {
-               getfield("I", field2, ref2);
-              if (strcmp (field2, "") == 0) {
-                 res = -1;
-                 fields_found = false;
-              }
-           }
-        } else {
-           res = -1;
-           fields_found = false;
-        }
-      }
-      if (fields_found) {
-         if (*p == 'A') {
-            if (isupper(field1[0]))
-               field1[0] -= 'A' - 'a';
-            if (isupper(field2[0]))
-               field2[0] -= 'A' - 'a';
-            }
-         res = strcmp(field1, field2);
-         }
-      if (neg)
-         res = - res;
-      if (res != 0)
-         break;
-      }
-   if (res == 0)
-      if (ap < bp)
-         res = -1;
-      else
-         res = 1;
-   return(res);
-}
-
-/* makecites - make citation strings */
-   makecites(citestr)
-   char *citestr[];
-{  char ref[REFSIZE], tempcite[100], *malloc();
-   int  i;
-
-   for (i = 0; i <= numrefs; i++) {
-      rdref(refspos[i], ref);
-      bldcite(tempcite, i, ref);
-      citestr[i] = malloc(2 + strlen(tempcite)); /* leave room for disambig */
-      if (citestr[i] == NULL)
-         error("out of storage");
-      strcpy(citestr[i], tempcite);
-      }
-}
-
-/* bldcite - build a single citation string */
-   bldcite(cp, i, ref)
-   char *cp, ref[];
-   int  i;
-{  char *p, *q, c, *fp, *np, field[REFSIZE], temp[100], *getfield();
-   int  j;
-
-   getfield("F", field, ref);
-   if (field[0] != 0)
-      for (p = field; *p; p++)
-         *cp++ = *p;
-   else {
-      p = citetemplate;
-      field[0] = 0;
-      while (c = *p++)
-         if (isalpha(c)) {
-            q = getfield(p-1, field, ref);
-            if (q != 0) {
-               p = q;
-               for (fp = field; *fp; )
-                  *cp++ = *fp++;
-               }
-            }
-         else if (c == '1') {
-            sprintf(field,"%d",1 + i);
-            for (fp = field; *fp; )
-               *cp++ = *fp++;
-            }
-         else if (c == '2') {
-            if (getname(1, field, temp, ref)) {
-               np = cp;
-               fp = field;
-               for (j = 1; j <= 3; j++)
-                  if (*fp != 0)
-                     *cp++ = *fp++;
-               if (getname(2, field, temp, ref))
-                  np[2] = field[0];
-               if (getname(3, field, temp, ref)) {
-                  np[1] = np[2];
-                  np[2] = field[0];
-                  }
-               }
-            }
-         else if (c == '{') {
-            while (*p ^= '}')
-               if (*p == 0)
-                  error("unexpected end of citation template");
-               else
-                  *cp++ = *p++;
-            p++;
-            }
-         else if (c == '<') {
-            while (*p ^= '>')
-               if (*p == 0)
-                  error("unexpected end of citation template");
-               else
-                  *cp++ = *p++;
-            p++;
-            }
-         else if (c != '@')
-            *cp++ = c;
-      }
-   *cp++ = 0;
-}
-
-/* getfield - get a single field from reference */
-   char *getfield(ptr, field, ref)
-   char *ptr, field[], ref[];
-{  char *p, *q, temp[100];
-   int  n, len, i, getname();
-
-   field[0] = 0;
-   if (*ptr == 'A')
-      getname(1, field, temp, ref);
-   else
-      for (p = ref; *p; p++)
-         if (*p == '%' && *(p+1) == *ptr) {
-            for (p = p + 2; *p == ' '; p++)
-               ;
-            for (q = field; *p != '\n'; )
-               *q++ = *p++;
-            *q = 0;
-            break;
-            }
-   n = 0;
-   len = strlen(field);
-   if (*++ptr == '-') {
-      for (ptr++; isdigit(*ptr); ptr++)
-         n = 10 * n + (*ptr - '0');
-      if (n > len)
-         n = 0;
-      else
-         n = len - n;
-      for (i = 0; field[i] = field[i+n]; i++)
-         ;
-      }
-   else if (isdigit(*ptr)) {
-      for (; isdigit(*ptr); ptr++)
-         n = 10 * n + (*ptr - '0');
-      if (n > len)
-         n = len;
-      field[n] = 0;
-      }
-
-   if (*ptr == 'u') {
-      ptr++;
-      for (p = field; *p; p++)
-         if (islower(*p))
-            *p = (*p - 'a') + 'A';
-      }
-   else if (*ptr == 'l') {
-      ptr++;
-      for (p = field; *p; p++)
-         if (isupper(*p))
-            *p = (*p - 'A') + 'a';
-      }
-   return(ptr);
-}
-
-/* getname - get the nth name field from reference, breaking into
-             first and last names */
-   int getname(n, last, first, ref)
-   int  n;
-   char last[], first[], ref[];
-{  char *p;
-
-   for (p = ref; *p; p++)
-      if (*p == '%' & (*(p+1) == 'A' || *(p+1) == 'E')) {
-         n--;
-         if (n == 0) {
-            for (p = p + 2; *p == ' '; p++) ;
-            breakname(p, first, last) ;
-            return(true);
-            }
-         }
-   return(false);
-}
-
-/* disambiguate - compare adjacent citation strings, and if equal, add
-                  single character disambiguators */
-   disambiguate()
-{  int i, j;
-   char adstr[2];
-
-   for (i = 0; i < numrefs; i = j) {
-      j = i + 1;
-      if (strcmp(citestr[i], citestr[j])==0) {
-         adstr[0] = 'a'; adstr[1] = 0;
-         for (j = i+1; strcmp(citestr[i],citestr[j]) == 0; j++) {
-            adstr[0] = 'a' + (j-i);
-            strcat(citestr[j], adstr);
-            if (j == numrefs)
-               break;
-            }
-         adstr[0] = 'a';
-         strcat(citestr[i], adstr);
-         }
-     }
+struct cite{
+       int     num;
+       char    *info;
+};
+citesort(p1, p2)
+       struct cite *p1, *p2;
+{
+       return(p1->num - p2->num);
 }
 
 /* putrefs - gather contiguous references together, sort them if called
 }
 
 /* putrefs - gather contiguous references together, sort them if called
@@ -621,84 +434,117 @@ main(argc, argv)
 int putrefs(ifd, ofd, footrefs, fn)
 FILE *ifd, *ofd;
 int  fn, footrefs[];
 int putrefs(ifd, ofd, footrefs, fn)
 FILE *ifd, *ofd;
 int  fn, footrefs[];
-{  int  citenums[MAXATONCE];   /* reference numbers */
-   char *citeinfo[MAXATONCE];  /* reference information */
-   char infoword[HUNTSIZE];    /* information line */
-   int  rtop, n, i, j;         /* number of citations being dumped */
-   char c, *p, *walloc();
-
-/* first gather contiguous references together, and order them if
-   required      */
-
-   rtop = -1;
-   do {
-      n = 0;
-      while (isdigit(getch(c, ifd)))
-         n = 10 * n + (c - '0');
-      if (c ^= CITEMARK)
-         error("inconsistant citation found in pass two");
-      if (n == 0) {     /* reference not found */
-         rtop++;
-         j = rtop;
-         citenums[j] = -1;
-         citeinfo[j] = 0;
-         }
-      else {
-         for (i = 0; i <= numrefs; i++)
-            if (refspos[i] == n) { /* its the ith item in reference list */
-               rtop++;
-               j = rtop;
-               if (ordcite)
-                  for ( ; j > 0 && citenums[j-1] > i; j--) {
-                     citenums[j] = citenums[j-1];
-                     citeinfo[j] = citeinfo[j-1];
-                     }
-               citenums[j] = i;
-               citeinfo[j] = 0;
-               break;
-               }
-         if (i > numrefs)
-            error("citation not found in pass two");
-         }
-      if (getch(c, ifd) != CITEEND) {
-         for (p = infoword; c != CITEEND ; ) {
-            *p++ = c;
-            getch(c, ifd);
-            }
-         *p = 0;
-         citeinfo[j] = walloc(infoword);
-         }
-      getch(c, ifd);
-      }  while (c == CITEMARK);
-   ungetc(c, ifd);
-
-   /* now dump out values */
-   for (i = 0; i <= rtop; i++) {
-      if (citenums[i] >= 0)
-         fputs(citestr[citenums[i]], ofd);
-      if (citeinfo[i]) {
-         fputs(citeinfo[i], ofd);
-         free(citeinfo[i]);
-         }
-      if (hyphen) {
-         for (j = 1; j + i <= rtop && citenums[i+j] == citenums[i] + j; j++);
-         if (j + i > rtop) j = rtop;
-         else j = j + i - 1;
-         }
-      else
-         j = i;
-      if (j > i + 1) {
-         fputs("\\*(]-", ofd);
-         i = j - 1;
-         }
-      else if (i != rtop)
-         fputs("\\*(],", ofd);
-      if (foot) {
-         fn++;
-         footrefs[fn] = citenums[i];
-         }
-      }
-   return(fn);
+{
+       struct cite cites[MAXATONCE];
+       char    infoword[HUNTSIZE];    /* information line */
+       reg     int i;
+       reg     char *p;
+       reg     int  ncites, n, j;         /* number of citations being dumped */
+       char    c, *walloc();
+       int neg;
+       /*
+        * first gather contiguous references together,
+        * and order them if required     
+        */
+
+       ncites = 0;
+       do {
+               neg = 1;
+               n = 0;
+               do{
+                       getch(c, ifd);
+                       if (isdigit(c))
+                               n = 10 * n + (c - '0');
+                       else if (c == '-')
+                               neg *= -1;
+                       else if (c == CITEMARK)
+                               break;
+                       else
+                               error("bad cite char 0%03o in pass two",c);
+               } while(1);
+               if (neg < 0) {     /* reference not found */
+                       cites[ncites].num = -1;
+                       cites[ncites].info = 0;
+                       ncites++;
+               } else {
+                       /*
+                        * Find reference n in the references
+                        */
+                       int i;
+                       for (i = 0; i < numrefs; i++){
+                               if (refinfo[i].ri_n == n){
+                                       cites[ncites].num = i;
+                                       cites[ncites].info = 0;
+                                       ncites++;
+                                       break;
+                               }
+                       }
+                       if (i == numrefs)
+                               error("citation %d not found in pass 2", n);
+               }
+               if (getch(c, ifd) != CITEEND) {
+                       for (p = infoword; c != CITEEND ; ) {
+                               *p++ = c;
+                               getch(c, ifd);
+                       }
+                       *p = 0;
+                       cites[ncites-1].info = walloc(infoword);
+               }
+               getch(c, ifd);
+       } while (c == CITEMARK);
+       ungetc(c, ifd);
+       if (ordcite)
+               qsort(cites, ncites, sizeof(struct cite), citesort);
+
+       /* now dump out values */
+       for (i = 0; i < ncites; i++) {
+               if (cites[i].num >= 0) {
+                       if (changecite){
+                               char tempcite[128];
+                               char ref[REFSIZE];
+                               struct refinfo *p;
+                               /*
+                                * rebuild the citation string,
+                                * using the current template in effect
+                                */
+                               p = &refinfo[cites[i].num];
+                               rdref(p, ref);
+                               bldcite(tempcite, cites[i].num, ref);
+                               strcat(tempcite, p->ri_disambig);
+                               if (doacite) fputs(tempcite, ofd);
+                       } else {
+                               if (doacite) fputs(refinfo[cites[i].num].ri_cite, ofd);
+                       }
+                       if (!doacite) fputs("\\&", ofd);
+               }
+               if (cites[i].info) {
+                       if (doacite) fputs(cites[i].info, ofd);
+                       if (!doacite) fputs("\\&", ofd);
+                       free(cites[i].info);
+               }
+               if (hyphen) {
+                       for (j = 1;
+                            j + i <= ncites && cites[i+j].num == cites[i].num + j;
+                            j++)/*VOID*/;
+                       if (j + i > ncites)
+                               j = ncites;
+                       else
+                               j = j + i - 1;
+               } else {
+                       j = i;
+               }
+               if (j > i + 1) {
+                       fputs("\\*(]-", ofd);
+                       i = j - 1;
+               } else if (i != ncites - 1) {
+                       fputs("\\*(],", ofd);
+               }
+               if (foot) {
+                       fn++;
+                       footrefs[fn] = cites[i].num;
+               }
+       }
+       return(fn);
 }
 
 /* pass2 - read pass 1 files entering citation */
 }
 
 /* pass2 - read pass 1 files entering citation */
@@ -724,60 +570,33 @@ int  fn, footrefs[];
                   while (echoc(c, ifd, ofd) != '\n')
                      ;
                   dumped = true;
                   while (echoc(c, ifd, ofd) != '\n')
                      ;
                   dumped = true;
-                  for (i = 0; i <= numrefs; i++)
+                  for (i = 0; i < numrefs; i++){
                      dumpref(i, ofd);
                      dumpref(i, ofd);
+                 }
                   getch(c, ifd);
                   }
          }
                   getch(c, ifd);
                   }
          }
-      if (c == CITEMARK)
+      if (c == FMTSTART)
+        changefmt(ifd);
+      else if (c == CITEMARK)
          fn = putrefs(ifd, ofd, footrefs, fn);
       else if (c != EOF)
          putc(c, ofd);
       }
    if (dumped == false)
          fn = putrefs(ifd, ofd, footrefs, fn);
       else if (c != EOF)
          putc(c, ofd);
       }
    if (dumped == false)
-      bibwarning("Warning: references never dumped\n", (char *)0);
-}
-
-
-/* dumpref - dump reference number i */
-   dumpref(i, ofd)
-   int i;
-   FILE *ofd;
-{  char ref[REFSIZE], *p, line[REFSIZE];
-   int numauths, maxauths, numeds, maxeds;
-
-   rdref(refspos[i], ref);
-   maxauths = maxeds = 0;
-   numauths = numeds = 0;
-   for (p = ref; *p; p++)
-      if (*p == '%')
-         if (*(p+1) == 'A') maxauths++;
-         else if (*(p+1) == 'E') maxeds++;
-   fprintf(ofd, ".[-\n");
-   fprintf(ofd, ".ds [F %s\n",citestr[i]);
-   fseek(rfd, (long) refspos[i], 0);
-   while (fgets(line, REFSIZE, rfd) != NULL) {
-      if (line[0] == 0)        break;
-      else if (line[0] == '.') fprintf(ofd,"%s",line);
-      else {
-         if (line[0] == '%') {
-            for (p = &line[2]; *p == ' '; p++);
-            if (line[1] == 'A')       numauths++;
-            else if (line[1] == 'E')  numeds++;
-
-            doline(line[1], p, numauths, maxauths, numeds, maxeds, ofd);
-            }
-         }
-      }
-   fprintf(ofd,".][\n");
+      bibwarning("Warning: references never dumped\n","");
 }
 /*
 }
 /*
- *     print out a warning message
+ *     change citation format
  */
  */
-bibwarning(msg, arg)
-       char    *msg;
-       char    *arg;
+changefmt(ifd)
+       FILE    *ifd;
 {
 {
-       fprintf(stderr, "`%s', line %d: ", bibfname, biblineno);
-       fprintf(stderr, msg, arg);
+       char    c;
+       char    *to;
+       to = ncitetemplate;
+       while (getch(c, ifd) != FMTEND)
+               *to++ = c;
+       *to = 0;
+       strcpy(citetemplate, ncitetemplate);
 }
 }