/* bib - bibliographic formatter timothy a. budd, 1/82 lookup routines supplied by gary levin 2/82 reworked several new features added, 11/82. */ # 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 getch(c,fd) (c = getc(fd)) # define echoc(c,ifd,ofd) (getch(c,ifd) == EOF ? c : putc(c,ofd)) # define testc(c,d,ifd,ofd) (getch(c, ifd) == d ? putc(c, ofd) : 0) /* global variables */ FILE *rfd; /* reference temporary file */ char reffile[] = TMPREFFILE ;/* temporary file (see bib.h) */ long int refspos[MAXREFS]; /* reference seek positions */ long int rend = 1; /* last position in rfd (first char unused)*/ int numrefs = -1; /* number of references generated so far */ 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 */ int findex = false; /* can we read the file INDEX ? */ /* global variables in bibargs */ extern int foot, sort, personal; extern int hyphen, ordcite; extern char sortstr[], pfile[], citetemplate[]; main(argc, argv) int argc; char **argv; { int rcomp(); /* the file INDEX in the current directory is the default index, if it is present */ rfd = fopen( INDXFILE , "r"); if (rfd != NULL) { findex = true; fclose(rfd); } /* open temporaries, reffile will contain references collected in pass 1, and tmpfile will contain text. */ mktemp(reffile); rfd = fopen(reffile,"w+"); if (rfd == NULL) error("can't open temporary reference file"); mktemp(tmpfile); tfd = fopen(tmpfile,"w"); if (tfd == NULL) error("can't open temporary output file"); /* pass1 - read files, looking for citations arguments are read by doargs (bibargs.c) */ if (doargs(argc, argv, DEFSTYLE ) == 0) rdtext(stdin); /* sort references, make citations, add disambiguating characters */ if (sort) qsort(refspos, numrefs+1, sizeof(long), rcomp); makecites(citestr); disambiguate(); /* reopen temporaries */ fclose(tfd); tfd = fopen(tmpfile,"r"); if (tfd == NULL) error("can't open temporary output file for reading"); /* pass 2 - reread files, replacing references */ pass2(tfd, stdout); /* clean up */ fclose(tfd); fclose(rfd); unlink(tmpfile); unlink(reffile); exit(0); } /* rdtext - read and process a text file, looking for [. commands */ rdtext(fd) FILE *fd; { char lastc, c, d; lastc = 0; while (getch(c, fd) != EOF) if (c == '[' || c == '{') if (getch(d, fd) == '.') { /* found a reference */ if (c == '{') { if (lastc) putc(lastc, tfd);} else if (lastc == ' ') fputs("\\*([<", tfd); else if (lastc == '.') fputs("\\*([.", tfd); else if (lastc == ',') fputs("\\*([,", tfd); else if (lastc) putc(lastc, tfd); rdcite(fd, c); if (c == '[') if (lastc == ' ') fputs("\\*(>]", tfd); else if (lastc == '.') fputs("\\*(.]", tfd); else if (lastc == ',') fputs("\\*(,]", tfd); lastc = 0; } else { if (lastc) putc(lastc, tfd); ungetc(d, fd); lastc = c; } else { if (lastc) putc(lastc, tfd); lastc = c; } if (lastc) putc(lastc, tfd); } /* rdcite - read citation information inside a [. command */ rdcite(fd, ch) FILE *fd; char ch; { long int n, getref(); char huntstr[HUNTSIZE], c, info[HUNTSIZE]; if (ch == '[') fputs("\\*([[", tfd); else fputs("\\*([{", tfd); 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); huntstr[0] = info[0] = 0; break; 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); 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); return; } else addc(huntstr, c); break; case '{': while (getch(c, fd) != '}') if (c == EOF) { fprintf(stderr, "Error: ill formed reference\n"); exit(1); } else addc(info, c); break; case '\n': case '\t': c = ' '; /* fall through */ default: addc(huntstr,c); } error("end of file reading citation"); } /* addc - add a character to hunt string */ addc(huntstr, c) char huntstr[HUNTSIZE], c; { int i; i = strlen(huntstr); if (i > HUNTSIZE) error("citation too long"); 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) char huntstr[HUNTSIZE]; { char rf[REFSIZE], ref[REFSIZE], *r, *hunt(); int i, match(), getwrd(); r = hunt(huntstr); if (r != NULL) { /* exapand defined string */ strcpy(rf, r); free(r); expand(rf); /* 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]); } /* 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]); } else { fprintf(stderr,"no reference matching %s\n", huntstr); return( (long) -1 ); } } /* rdref - read text for an already cited reference */ rdref(i, ref) long int i; char ref[REFSIZE]; { ref[0] = 0; fseek(rfd, i, 0); fread(ref, 1, REFSIZE, rfd); } /* hunt - hunt for reference from either personal or system index */ char *hunt(huntstr) char huntstr[]; { char *fhunt(), *r, *p, *q, fname[120]; 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) break; p = fname; } else *p++ = *q; } else if (findex) { if ((r = fhunt( INDXFILE , huntstr)) != NULL) return(r); } if ((r = fhunt(SYSINDEX , huntstr)) != NULL) return(r); return(NULL); } /* fhunt - hunt from a specific file */ char *fhunt(file, huntstr) char file[], huntstr[]; { char *p, *r, *locate(); r = locate(huntstr, file, 6, common); if (r == NULL) return(NULL); /* error */ if (*r == 0) return(NULL); /* no match */ for (p = r; *p; p++) if (*p == '\n') if (*(p+1) == '\n') { /* end */ if (*(p+2) != 0) fprintf(stderr,"multiple references match %s\n",huntstr); *(p+1) = 0; break; } else if (*(p+1) != '%' && *(p+1) != '.') /* unnecessary newline */ *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; 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); if (q == 0) res = 1; else if (getfield(p, field2, ref2) == 0) res = -1; else { 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') { 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); } } } /* putrefs - gather contiguous references together, sort them if called for, hyphenate if necessary, and dump them out */ 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); } /* pass2 - read pass 1 files entering citation */ pass2(ifd, ofd) FILE *ifd, *ofd; { char c; int i, fn, footrefs[25], dumped; fn = -1; dumped = foot; while (getch(c, ifd) != EOF) { while (c == '\n') { putc(c, ofd); if (foot && fn >= 0) { for (i = 0; i <= fn; i++) dumpref(footrefs[i], ofd); fn = -1; } if (testc(c, '.', ifd, ofd)) if (testc(c, '[', ifd, ofd)) if (testc(c, ']', ifd, ofd)) { while (echoc(c, ifd, ofd) != '\n') ; dumped = true; for (i = 0; i <= numrefs; i++) dumpref(i, ofd); getch(c, ifd); } } if (c == CITEMARK) fn = putrefs(ifd, ofd, footrefs, fn); else if (c != EOF) putc(c, ofd); } if (dumped == false) fprintf(stderr,"Warning: references never dumped\n"); } /* 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"); }