budd (12/08/82)
echo x - alpha.seek.c cat >alpha.seek.c <<'!Funky!Stuff!' # # include "stdio.h" # include "ctype.h" # include "streams.h" # define nexttry ((high+low)/2) /* alpha_seek(stream, word, s_size, fold) seeks the first line in stream that is at least word. assumes that stream is a sorted file of lines. (last char must be \n) if fold, assumes that word is lowercase and folds stream to lowercase. s_size = size of stream returns 1 if word = line, 0 o.w. */ int alpha_seek(stream, word, s_size, fold) FILE *stream; char *word; long int s_size; int fold; { long int high, low, mid; /* point to beginning of a line in stream */ int ans; /* line(low) < word <= line(high) */ char line[maxstr]; /* initialize low (return if first line >= word) */ low= 0L; pos(low); getline(stream, line); if (fold) foldline(line); ans= strcmp(line,word); if ( ans >= 0) { pos(low); return(ans==0); } /* initialize high to "line" after last line */ high= s_size; mid= nextline(stream, nexttry ); while (mid < high ) { getline(stream,line); if (fold) foldline(line); if (strcmp(line,word) < 0) low= mid; else high= mid; mid= nextline(stream, nexttry ); } /* linear search from low to high */ low= nextline(stream,low); for(;;) { if (low>=high) break; getline(stream,line); if (fold) foldline(line); ans=strcmp(line,word); if (ans>=0) break; low= ftell(stream); } pos(low); if (low=high) return(0); else return(ans==0); } /* foldline(p): change all uppercase to lowercase in string p */ foldline(p) char *p; { for (; *p!=NULL; p++) { if (isupper(*p)) *p = tolower(*p); } } !Funky!Stuff! echo x - bib.c cat >bib.c <<'!Funky!Stuff!' /* 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"); } !Funky!Stuff! echo x - bib.h cat >bib.h <<'!Funky!Stuff!' /* various arguments for bib and listrefs processors */ /* constants */ # define true 1 # define false 0 # define err -1 # define REFSIZE 1024 /* maximum size of reference string */ /* reference citation marker genrated in pass 1 */ # define CITEMARK (char) 02 # define CITEEND (char) 03 /* file names */ /* output of invert, input file for references */ # define INDXFILE "INDEX" /* pass1 reference collection file */ # define TMPREFFILE "/usr/tmp/bibrXXXXXX" /* pass2 text collection file */ # define TMPTEXTFILE "/usr/tmp/bibpXXXXXX" /* temp file used in invert */ # define INVTEMPFILE "/usr/tmp/invertXXXXXX" /* common words */ # define COMFILE "/usr/lib/bmac/common" /* default system dictionary */ # define SYSINDEX "/usr/dict/papers/INDEX" /* where macro libraries live */ # define BMACLIB "/usr/lib/bmac" /* default style of references */ # define DEFSTYLE "/usr/lib/bmac/bib.stdsn" /* size limits */ /* maximum number of characters in common file */ # define MAXCOMM 300 char *malloc(); !Funky!Stuff! echo x - bibargs.c cat >bibargs.c <<'!Funky!Stuff!' /* read argument strings for bib and listrefs do name formatting, printing lines, other actions common to both */ # include <stdio.h> # include <ctype.h> # include "bib.h" # define LINELENGTH 1024 # define MAXDEFS 500 /* maximum number of defined words */ /* global variables */ int abbrev = false; /* automatically abbreviate names */ int capsmcap = false; /* print names in caps small caps (CACM form)*/ int numrev = 0; /* number of authors names to reverse */ int edabbrev = false; /* abbreviate editors names ? */ int edcapsmcap = false; /* print editors in cap small caps */ int ednumrev = 0; /* number of editors to reverse */ int sort = false; /* sort references ? (default no) */ int foot = false; /* footnoted references ? (default endnotes) */ int hyphen = false; /* hypenate contiguous references */ int ordcite = true; /* order multiple citations */ char sortstr[80] = "1"; /* sorting template */ char trailstr[80] = ""; /* trailing characters to output */ char pfile[120]; /* private file name */ int personal = false; /* personal file given ? (default no) */ char citetemplate[80] = "1"; /* citation template */ char *words[MAXDEFS]; /* defined words */ char *defs[MAXDEFS]; /* defined word definitions */ int wordtop = -1; /* top of defined words array */ /* where output goes */ extern FILE *tfd; /* doargs - read command argument line for both bib and listrefs set switch values call rdtext on file arguments, after dumping default style file if no alternative style is given */ int doargs(argc, argv, defstyle) int argc; char **argv, defstyle[]; { int numfiles, i, style; char *p, *q, *walloc(); FILE *fd; numfiles = 0; style = true; words[0] = walloc("BMACLIB"); defs[0] = walloc(BMACLIB); wordtop++; fputs(".ds l] ",tfd); fputs(BMACLIB, tfd); fputs("\n", tfd); for (i = 1; i < argc; i++) if (argv[i][0] == '-') switch(argv[i][1]) { case 'a': abbrev = true; break; case 'c': if (argv[i][2] == 0) error("citation string expected"); else for (p = citetemplate,q = &argv[i][2]; *p++ = *q++; ); break; case 'e': for (p = &argv[i][2]; *p; p++) if (*p == 'a') edabbrev = true; else if (*p == 'x') edcapsmcap = true; else if (*p == 'r') { if (*(p+1)) ednumrev = atoi(p+1); else ednumrev = 1000; break; } break; case 'f': foot = true; hyphen = false; break; case 'h': hyphen = ordcite = true; break; case 'n': for (p = &argv[i][2]; *p; p++) if (*p == 'a') abbrev = false; else if (*p == 'f') foot = false; else if (*p == 'h') hyphen = false; else if (*p == 'o') ordcite = false; else if (*p == 'r') numrev = 0; else if (*p == 's') sort = false; else if (*p == 'x') capsmcap = false; break; case 'o': ordcite = true; break; case 'p': if (argv[i][2]) p = &argv[i][2]; else { /* take next arg */ i++; p = argv[i]; } strcpy(pfile, p); personal = true; break; case 'r': if (argv[i][2] == 0) numrev = 1000; else numrev = atoi(&argv[i][2]); break; case 's': sort = true; if (argv[i][2]) for (p = sortstr,q = &argv[i][2]; *p++ = *q++; ); break; case 'i': case 't': if (argv[i][1] == 't') style = false; if (argv[i][2]) p = &argv[i][2]; else { /* take next arg */ i++; p = argv[i]; } incfile(p); break; case 'x': capsmcap = true; break; case 0: if (style) { /* no style command given, take default */ style = false; incfile( defstyle ); } rdtext(stdin); numfiles++; break; default: fputs(argv[i], stderr); error(": invalid switch"); } else { /* file name */ numfiles++; if (style) { style = false; incfile( defstyle ); } fd = fopen(argv[i], "r"); if (fd == NULL) { fputs(argv[i], stderr); error(": can't open"); } else { rdtext(fd); fclose(fd); } } if (style) incfile( defstyle ); return(numfiles); } /* incfile - read in an included file */ incfile(np) char *np; { char name[120]; FILE *fd; fd = fopen(np, "r"); if (fd == NULL && *np != '/') { strcpy(name, "bib."); strcat(name, np); fd = fopen(name, "r"); } if (fd == NULL && *np != '/') { strcpy(name,BMACLIB); strcat(name, "/bib."); strcat(name, np); fd = fopen(name, "r"); } if (fd == NULL) { fprintf(stderr,"%s", np); error(": can't open"); } setswitch(fd); fclose(fd); } /* error - report unrecoverable error message */ error(str) char str[]; { fputs(str, stderr); putc('\n', stderr); exit(1); } /* tfgets - fgets which trims off newline */ char *tfgets(line, n, ptr) char line[]; int n; FILE *ptr; { char *p; p = fgets(line, n, ptr); if (p == NULL) return(NULL); else for (p = line; *p; p++) if (*p == '\n') *p = 0; return(line); } /* getwrd - place next word from in[i] into out */ int getwrd(in, i, out) char in[], out[]; int i; { int j; j = 0; while (in[i] == ' ' || in[i] == '\n' || in[i] == '\t') i++; if (in[i]) while (in[i] && in[i] != ' ' && in[i] != '\t' && in[i] != '\n') out[j++] = in[i++]; else i = 0; /* signals end of in[i..] */ out[j] = 0; return (i); } /* walloc - allocate enough space for a word */ char *walloc(word) char *word; { char *i, *malloc(); i = malloc(1 + strlen(word)); if (i == NULL) error("out of storage"); strcpy(i, word); return(i); } /* setswitch - set document switch settings from format file */ setswitch(fp) FILE *fp; { char *p, line[LINELENGTH], dline[LINELENGTH], word[80]; int i, j, getwrd(); while (tfgets(line, LINELENGTH, fp) != NULL) switch(line[0]) { case '#': break; case 'A': abbrev = true; break; case 'C': for (p = &line[1]; *p == ' '; p++) ; strcpy(citetemplate, p); break; case 'D': if ((i = getwrd(line, 1, word)) == 0) error("word expected in definition"); for (j = 0; j <= wordtop; j++) if (strcmp(word, words[j]) == 0) break; if (j > wordtop) { if ((j = ++wordtop) > MAXDEFS) error("too many defintions"); words[wordtop] = walloc(word); } for (p = &line[i]; *p == ' '; p++) ; for (strcpy(dline, p); dline[strlen(dline)-1] == '\\'; ){ dline[strlen(dline)-1] = '\n'; if (tfgets(line, LINELENGTH, fp) == NULL) break; strcat(dline, line); } defs[j] = walloc(dline); break; case 'E': for (p = &line[1]; *p; p++) if (*p == 'A') edabbrev = true; else if (*p == 'X') edcapsmcap = true; else if (*p == 'R') { if (*(p+1)) ednumrev = atoi(p+1); else ednumrev = 1000; break; } break; case 'F': foot = true; hyphen = false; break; case 'I': for (p = &line[1]; *p == ' '; p++); expand(p); incfile(p); break; case 'H': hyphen = ordcite = true; break; case 'O': ordcite = true; break; case 'R': if (line[1] == 0) numrev = 1000; else numrev = atoi(&line[1]); break; case 'S': sort = true; for (p = &line[1]; *p == ' '; p++) ; strcpy(sortstr, p); break; case 'T': for (p = &line[1]; *p == ' '; p++) ; strcpy(trailstr, p); break; case 'X': capsmcap = true; break; default: fprintf(tfd,"%s\n",line); while (fgets(line, LINELENGTH, fp) != NULL) fputs(line, tfd); return; } return; } /* isword - see if character is legit word char */ int iswordc(c) char c; { if (isalnum(c) || c == '&' || c == '_') return(true); return(false); } /* expand - expand reference, replacing defined words */ expand(line) char *line; { char line2[REFSIZE], word[LINELENGTH], *p, *q, *w; int replaced, i; replaced = true; while (replaced) { replaced = false; p = line; q = line2; while (*p) { if (isalnum(*p)) { for (w = word; *p && iswordc(*p); ) *w++ = *p++; *w = 0; for (i = 0; i <= wordtop; i++) if (strcmp(word, words[i]) == 0) { strcpy(word, defs[i]); replaced = true; break; } for (w = word; *w; ) *q++ = *w++; } else *q++ = *p++; } *q = 0; p = line; q = line2; while (*p++ = *q++); } } /* breakname - break a name into first and last name */ breakname(line, first, last) char line[], first[], last[]; { char *p, *q, *r, *t, *f; for (t = line; *t != '\n'; t++); for (t--; isspace(*t); t--); /* now strip off last name */ for (q = t; isspace(*q) == 0 || ((*q == ' ') & (*(q-1) == '\\')); q--) if (q == line) break; f = q; if (q != line) q++; for (; isspace(*f); f--); /* first name is start to f, last name is q to t */ for (r = first, p = line, f++; p != f; ) *r++ = *p++; *r = 0; for (r = last, p = q, t++; q != t; ) *r++ = *q++; *r = 0; } /* match - see if string1 is a substring of string2 (case independent)*/ int match(str1, str2) char str1[], str2[]; { int i, j; char a, b; for (i = 0; str2[i]; i++) { for (j = 0; str1[j]; j++) { if (isupper(a = str2[i+j])) a = (a - 'A') + 'a'; if (isupper(b = str1[j])) b = (b - 'A') + 'a'; if (a != b) break; } if (str1[j] == 0) return(true); } return(false); } /* scopy - append a copy of one string to another */ char *scopy(p, q) char *p, *q; { while (*p++ = *q++) ; return(--p); } /* bldname - build a name field doing abbreviations, reversals, and caps/small caps */ bldname(first, last, name, reverse) char *first, *last, name[]; int reverse; { char newfirst[120], newlast[120], *p, *q, *f, *l, *scopy(); int flag; if (abbrev) { p = first; q = newfirst; flag = false; while (*p) { while (*p == ' ') p++; if (*p == 0) break; if (isupper(*p)) { if (flag) q = scopy(q, "\\*(a]"); flag = true; *q++ = *p; *q++ = '.'; } if (*++p == '.') p++; else while (*p != 0 && ! isspace(*p)) p++; } *q = 0; f = newfirst; } else f = first; if (capsmcap) { p = last; q = newlast; flag = 0; /* 1 - printing cap, 2 - printing small */ while (*p) if (islower(*p)) { if (flag != 2) q = scopy(q, "\\s-2"); flag = 2; *q++ = (*p++ - 'a') + 'A'; } else { if (flag == 2) q = scopy(q,"\\s+2"); flag = 1; *q++ = *p++; } if (flag == 2) q = scopy(q, "\\s+2"); *q = 0; l = newlast; } else l = last; if (reverse) sprintf(name, "%s, %s\n", l, f); else sprintf(name, "%s %s\n", f, l); } /* prtauth - print author or editor field */ prtauth(c, line, num, max, ofd, abbrev, capsmcap, numrev) char c, *line; int num, max, abbrev, capsmcap, numrev; FILE *ofd; { char first[LINELENGTH], last[LINELENGTH]; if (num <= numrev || abbrev || capsmcap) { breakname(line, first, last); bldname(first, last, line, num <= numrev); } if (num == 1) fprintf(ofd,".ds [%c %s", c, line); else if (num < max) fprintf(ofd,".as [%c \\*(c]%s", c, line); else if (max == 2) fprintf(ofd,".as [%c \\*(n]%s", c, line); else fprintf(ofd,".as [%c \\*(m]%s", c, line); if (num == max && index(trailstr, c)) fprintf(ofd,".ds ]%c %c\n", c, line[strlen(line)-2]); } /* doline - actually print out a line of reference information */ doline(c, line, numauths, maxauths, numeds, maxeds, ofd) char c, *line; int numauths, maxauths, numeds, maxeds; FILE *ofd; { switch(c) { case 'A': prtauth(c, line, numauths, maxauths, ofd, abbrev, capsmcap, numrev); break; case 'E': prtauth(c, line, numeds, maxeds, ofd, edabbrev, edcapsmcap, ednumrev); if (numeds == maxeds) fprintf(ofd,".nr [E %d\n", maxeds); break; case 'P': if (index(line, '-')) fprintf(ofd,".nr [P 1\n"); else fprintf(ofd,".nr [P 0\n"); fprintf(ofd,".ds [P %s",line); if (index(trailstr, 'P')) fprintf(ofd,".ds ]P %c\n",line[strlen(line)-2]); break; case 'F': case 'K': break; default: fprintf(ofd,".ds [%c %s", c, line); if (index(trailstr, c)) fprintf(ofd,".ds ]%c %c\n", c, line[strlen(line)-2]); } } !Funky!Stuff! echo x - invert.c cat >invert.c <<'!Funky!Stuff!' # /* input: records of lines, separated by blank lines output: key:file1 start/length ... start/length:file2 start/length ... */ # include "stdio.h" # include "streams.h" # include "bib.h" # define isnull(x) (*(x) == NULL) # define makelow(c) ('A'<=(c) && (c)<='Z' ? (c)-'A'+'a' : c) int max_kcnt = 100; /* max number of keys */ int max_klen = 6; /* max length of keys */ char *ignore = /* string of line starts to ignore */ "CNOPVX"; char *common = /* name of file of common words */ COMFILE; char *INDEX= /* name of output file */ INDXFILE; char *tmpfile = /* name of temporary file */ INVTEMPFILE; int silent = 0; /* 0 => statistics printed */ /* 1 => no statisitics printed */ char *sort_it = "sort -u +0 -1 +1 -2 +2n -3 +3n %s -o %s"; char sortcmd[maxstr]; int argc; char **argv; main(argcount,arglist) int argcount; char **arglist; { char *filename; FILE *input, *output; long int start,length; char word[maxstr]; int kcnt; char tag_line[maxstr]; long int records = 0; /* number of records read */ long int keys = 0; /* number of keys read (occurences) */ long int distinct; /* number of distinct keys */ long int shorten(); argc= argcount-1; argv= arglist+1; mktemp(tmpfile); output= fopen(tmpfile,"w"); for ( flags() ; argc>0 ; argc--, argv++ ,flags() ) { /* open input file */ filename= *argv; input= fopen(filename,"r"); if (input==NULL) { fprintf(stderr, "invert: error in open of %s\n", filename); continue; } start= 0L; length= 0L; for(;;) /* each record */ { /* find start of next record (exit if none) */ start= nextrecord(input,start+length); if (start==EOF) break; records++; kcnt= 0; length= recsize(input,start); sprintf(tag_line, " %s %D %D\n", filename, start, length); while (ftell(input) < start+length && kcnt < max_kcnt) { getword(input,word,ignore); makekey(word,max_klen,common); if (!isnull(word)) { fputs(word,output); fputs(tag_line,output); kcnt++; keys++; } } } fclose(input); } fclose(output); sprintf(sortcmd, sort_it, tmpfile, tmpfile); system(sortcmd); distinct = shorten(tmpfile,INDEX); if( silent == 0 ) fprintf(stderr, "%D documents %D distinct keys %D key occurrences\n", records, distinct, keys); } /* Flag Meaning Default -ki Keys per record 100 -li max Length of keys 6 -%str ignore lines that begin with %x CNOPVX where x is in str str is a seq of chars -cfile file contains Common words /usr/src/local/bib/common do not use common words as keys -pfile name of output file INDEX -s do not print statistics statistics printed */ # define operand (strlen(*argv+2)==0 ? (argv++,argc--,*argv) : *argv+2) flags() { for (; argc>0 && *argv[0]=='-'; argc--,argv++) { switch ((*argv)[1]) { case 'k': max_kcnt= atoi(operand); break; case 'l': max_klen= atoi(operand); break; case 'c': common= operand; break; case '%': ignore= *argv+2; break; case 'p': INDEX= operand; break; case 's': silent= 1; break; default: fprintf(stderr, "unknown flag '%s'\n", *argv); } } } /* shorten(inf,outf): file "inf" consists of lines of the form: key file start length sorted by key and file. replace lines with the same key with one line of the form: key:file1 start/length ... start/length:file2 start/length ... rename as file "outf" returns number of lines in output */ long shorten(inf,outf) char *inf, *outf; { FILE *in, *out; char line[maxstr]; char key[maxstr], newkey[maxstr], file[maxstr], newfile[maxstr]; long int start, length; long int lines = 0; in= fopen(inf, "r"); out= fopen(outf, "w"); if (in==NULL || out==NULL) { fprintf(stderr, "invert: error in opening file for compression\n"); return(0); } getline(in,line); sscanf(line,"%s%s%D%D", key, file, &start, &length); fprintf(out, "%s :%s %D/%D", key, file, start, length); for ( getline(in, line) ; !feof(in); getline(in, line)) { sscanf(line,"%s%s%D%D", newkey, newfile, &start, &length); if (strcmp(key,newkey)!=0) { strcpy(key, newkey); strcpy(file, newfile); fprintf(out, "\n%s :%s %D/%D", key, file, start, length); lines++; } else if (strcmp(file,newfile)!=0) { strcpy(file,newfile); fprintf(out, ":%s %D/%D", file, start, length); } else fprintf(out, " %D/%D", start, length); } fprintf(out, "\n"); lines++; fclose(in); fclose(out); unlink(inf); return (lines); } !Funky!Stuff! echo x - listrefs.c cat >listrefs.c <<'!Funky!Stuff!' /* list all documents in ref index file */ # include <stdio.h> # include <ctype.h> # include "bib.h" # include "streams.h" # define MAXLINE 250 FILE *tfd; int count = 1; char refs[REFSIZE], *rp; main(argc, argv) int argc; char **argv; { tfd = stdout; doargs(argc, argv, "/usr/lib/bmac/bib.list"); exit(0); } /* rdtext - process a file */ rdtext(ifile) FILE *ifile; { long int start, length; int i, numauths, numeds; char *p, c; start = length = 0L; for (;;) { start = nextrecord(ifile, start + length); if (start == EOF) break; length = recsize(ifile, start); /* count number of authors */ numauths = numeds = 0; p = refs; for (i = length; i > 0; i--) if ((*p++ = getc(ifile)) == '%') { i--; c = *p++ = getc(ifile); if (c == 'A') numauths++; else if (c == 'E') numeds++; } *p = 0; expand(refs); rp = refs; dumpref(stdout, numauths, numeds); } } /* get a line from reference file */ char refgets(line) char line[]; { char c, *p; if (*rp == 0) return(0); for (p = line;;) { while ((c = *rp++) != '\n') if (c == 0) return(0); else *p++ = c; c = *rp; if (c == 0) break; if (c == '.' || c == '%' || c == '\n') break; *p++ = ' '; } *p++ = '\n'; *p = 0; return(' '); } /* dump reference */ dumpref(ofile, maxauths, maxeds) FILE *ofile; int maxauths, maxeds; { char line[250], *p; int numauths, numeds; fprintf(tfd, ".[-\n"); fprintf(tfd, ".ds [F %d\n", count++); numauths = numeds = 0; while (refgets(line) != 0) { if (line[0] == '\n') break; else if (line[0] == '.') fprintf(ofile, "%s\n", line); else { if (line[0] == '%') { for (p = &line[2]; isspace(*p); p++); if (line[1] == 'A') numauths++; else if (line[1] == 'E') numeds++; doline(line[1], p, numauths, maxauths, numeds, maxeds, ofile); } } } fprintf(tfd, ".][\n"); } !Funky!Stuff! echo x - locate.c cat >locate.c <<'!Funky!Stuff!' # # include "stdio.h" # include "streams.h" # include "ctype.h" # define maxrefs 200 struct reftype{ char reffile[20]; long int start, length; }; char *malloc(); char *rindex(); char *stripkeys(); int fetchref(); /* locate(keys, name, max_klen, common): Returns a string containing all references pointed to by name that contain all keys in keys. Common is name of common word file. Pointer returned comes from malloc. Use free to return storage. NB A zero length string returned if nothing is found. A NULL pointer indicates an error accessing the file "name". */ char *locate(keys,name,max_klen,common) char *keys, *name, *common; int max_klen; /* max key length */ { static char oldname[maxstr] = ""; /* oldname is name of stream index */ static FILE *index = NULL; static long int i_size; /* size of index */ static char oldtext[maxstr]; /* oldtext is the path to stream */ static FILE *text = NULL; /* text. if it is a relative */ static int pathlen; /* path, it is relative to index */ /* directory. */ /* oldname[0..pathlen-1] is index */ /* directory */ int len; char key[maxstr]; /* refs[i] is a line of index for */ struct reftype refs[maxrefs]; /* all keys up to key */ int refcnt, copied, comp; /* refcnt = # of refs */ /* copied = # of refs copied */ /* comp = # of refs compared */ struct reftype ref; char str[maxstr]; int more; long int ans; int i,j; unsigned total; char *allrefs, *next; /* all refs (separated by null line)*/ char *p; /* open index */ if (strcmp(oldname,name)!=0) { if (index) fclose(index); if (text) fclose(text); strcpy(oldname,name); strcpy(oldtext,""); /* determine pathlen */ p= rindex(oldname, '/'); if (p!=NULL) pathlen= p-oldname+1; else pathlen= 0; index= fopen(oldname,"r"); if (index==NULL) { fprintf(stderr, "locate: cannot open %s\n", oldname); strcpy(oldname, ""); return(NULL); } else { fseek(index,0L,2); /* seeks last newline */ i_size= ftell(index); } } /* load references to first key */ keys= stripkeys(keys,key, max_klen, common); if (*key==NULL) { fprintf(stderr,"locate: no keys for citation\n"); allrefs = malloc(1); if (allrefs==NULL) { fprintf(stderr, "locate: insufficient space for references\n"); exit(1); } *allrefs= NULL; return(allrefs); } len= strlen(key); strcat(key," "); alpha_seek(index, key, i_size, 0); key[len]= NULL; /* strip blank off */ refcnt= 0; fscanf(index,"%s ", str); if (strcmp(str,key) == 0) { str[0]= NULL; while (refcnt < maxrefs && fetchref(index, str, &ref) ) { refs[refcnt]= ref; refcnt++; } } if (refcnt==maxrefs) fprintf(stderr, "locate: first key (%s) matched too many refs\n", key); /* intersect the reference sets for remaining keys with first set */ while (*keys!=NULL) { keys= stripkeys(keys, key, max_klen, common); if (*key==NULL) continue; len= strlen(key); strcat(key," "); alpha_seek(index, key, i_size, 0); key[len]= NULL; fscanf(index,"%s ", str); if (strcmp(str,key) != 0) refcnt= 0; /* no matching refs */ copied= 0; comp= 0; more= fetchref(index, str, &ref); while (comp < refcnt && more) { /* ans= ref-refs[comp] */ ans= strcmp(ref.reffile, refs[comp].reffile); if (ans==0) ans= ref.start-refs[comp].start; if (ans==0) ans= ref.length-refs[comp].length; if (ans<0) more= fetchref(index, str, &ref); if (ans==0) { refs[copied]= refs[comp]; comp++; copied++; more= fetchref(index, str, &ref);} if (ans>0) comp++; } refcnt= copied; } total= 0; for (i=0; i<refcnt; i++) total += refs[i].length+1; allrefs= malloc(total+1); if (allrefs==NULL) { fprintf(stderr, "locate: insufficient space for references\n"); exit(1); } /* copy refs into allrefs */ next= allrefs; for (i=0; i<refcnt; i++) { /* open text */ if (strcmp(oldtext,refs[i].reffile) != 0) { strcpy(oldtext,refs[i].reffile); if (oldtext[0]=='/') { /* absolute path */ strcpy(str,oldtext); } else { /* relative name */ strncpy(str, oldname, pathlen); str[pathlen]= NULL; strcat(str, oldtext); } if (text) fclose(text); text= fopen(str, "r"); if (text==NULL) { fprintf(stderr, "locate: cannot open %s\n", str); strcpy(oldtext, ""); return(NULL); } } fseek(text, refs[i].start, 0); for (j=0; j<refs[i].length; j++) *next++ = getc(text); *next++ = '\n'; } *next = NULL; return(allrefs); } /* stripkeys(line,key,max_klen, common): assigns to key the first key in line and returns a pointer to the position following the key */ char *stripkeys(line,key,max_klen,common) char *line, *key; int max_klen; char *common; { char *p; do { while (isspace(*line)) line++; p= key; while (*line!=NULL && !isspace(*line)) { *p++ = *line++; } *p= NULL; makekey(key, max_klen, common); } while (*key==NULL && *line!=NULL); return(line); } /* read a reference pair from stream into *ref. if file not given, use oldfile. return 1 if pair found, 0 ow. */ int fetchref(stream, oldfile, ref) FILE *stream; char *oldfile; struct reftype *ref; { char cntl; fscanf(stream, "%c", &cntl); if (cntl=='\n') {return (0);} if (cntl==':') fscanf(stream, "%s", oldfile); strcpy(ref->reffile, oldfile); fscanf(stream, "%D/%D", &ref->start, &ref->length); return(1); } !Funky!Stuff! echo x - lookup.c cat >lookup.c <<'!Funky!Stuff!' # include "stdio.h" # include "streams.h" # include "bib.h" char *locate(); int max_klen = 6; /* max length of keys */ char *common = /* name of file of common words */ COMFILE; char INDEX[maxstr] = /* name of index file */ INDXFILE; int argc; char **argv; main(argcount,arglist) int argcount; char **arglist; { char *refs; char keys[maxstr]; char *p,*q; char one_index[maxstr]; argc= argcount-1; argv= arglist+1; flags(); /* add SYSINDEX to search path. all names are comma terminated */ strcat(INDEX, ","); strcat(INDEX, SYSINDEX); strcat(INDEX, ","); while (fgets(keys,maxstr,stdin)!=NULL) { for (p = one_index, q = INDEX; *q != 0 ; q++) if (*q == ',' ) { *p = 0; refs = locate(keys, one_index, max_klen, common); if( refs==NULL ) { fprintf(stderr, "%s removed from index list.\n", one_index); /* delete this file name (shift remainder on top) */ strcpy(q-strlen(one_index),q+1); q = q-strlen(one_index)-1; } if (refs!=NULL && *refs!=NULL) break; p = one_index; } else *p++ = *q; if (refs==NULL || *refs==NULL) printf("No references found.\n"); else printf("%s", refs); if (refs!=NULL) free(refs); } exit(0); } # define operand (strlen(*argv+2)==0 ? (argv++,argc--,*argv) : *argv+2) flags() { for (; argc>0 && *argv[0]=='-'; argc--,argv++) { switch ((*argv)[1]) { case 'l': max_klen= atoi(operand); break; case 'c': common= operand; break; case 'p': strcpy(INDEX,operand); break; default: fprintf(stderr, "unknown flag '%s'\n", *argv); } } } !Funky!Stuff! echo x - makekey.c cat >makekey.c <<'!Funky!Stuff!' # # include "stdio.h" # include "ctype.h" # include "bib.h" char commlist[MAXCOMM]= /* list of strings of common words */ ""; int firsttime = 1; /* makekey(p,max_klen,common): compresses *p into a key folds upper to lower case. ignores non-alphanumeric drops keys of length <= 1. drops words in common (name of file of words, one per line) (first call determines common for all later calls) */ makekey(p,max_klen,common) char *p; int max_klen; /* max key length */ char *common; { register char *from, *to, *stop; if (firsttime) {firsttime= 0; load_comm(common); } from= p; to= p; stop= max_klen+p; while (*from != NULL && to < stop) { if (islower(*from)) *to++ = *from++; else if (isdigit(*from)) *to++ = *from++; else if (isupper(*from)) { *to++ = tolower(*from); from++; } else from++; } *to= NULL; if (to<=p+1 || lookup(commlist, p) ) *p= NULL; } /* list is a string of null terminated strings, final string is null. p is a null terminated string. return 1 if p is a string in list, 0 ow. */ int lookup(list,p) char *list, *p; { int len; len= strlen(list); while (len!=0 && strcmp(list,p)!=0) { list += (len+1); len= strlen(list); } return(len!=0); } /* read file common into commlist */ load_comm(common) char *common; { FILE *commfile; /* stream of common words */ char *p, *stop; commfile= fopen(common,"r"); if (commfile==NULL) fprintf(stderr, "cannot open '%s'\n", common); else { /* read commfile into commlist */ p= commlist; stop= commlist+MAXCOMM-1; while (p<stop && ((*p= getc(commfile))!=EOF)) { if (*p=='\n') *p= NULL; p++; } if (*p==EOF) *p= NULL; else { fprintf(stderr, "invert: too many common words\n"); commlist[0]= NULL; } fclose(commfile); } } !Funky!Stuff! echo x - streams.c cat >streams.c <<'!Funky!Stuff!' # # include "stdio.h" # include "streams.h" # include "ctype.h" /* getword(stream,p,ignore): read next sequence of nonspaces on current line into *p. null if no more words on current line. %x (x in ignore) terminates line. all words of the form %a are returned as null. *p is a null terminated string (char p[maxstr]). */ getword(stream,p,ignore) FILE *stream; char *p, *ignore; { char c; char *oldp, *stop; oldp= p; stop= p+maxstr-1; do{ c= getc(stream); } while (isspace(c) && c!='\n'); while (!isspace(c)) { *p= c; if (p < stop) p++; c= getc(stream); } *p= NULL; if (oldp[0]=='%') { oldp[0]= NULL; if (index(ignore, oldp[1]) != NULL) while (c!='\n') c=getc(stream); } } /* recsize(stream,start): returns length of record beginning at start (record ends at blank line or eof) assumes and retains stream positioned at start */ long int recsize(stream,start) FILE *stream; long int start; { char c; /* length = # of chars from start to beginning */ long int length; /* of current line. c in current line. */ int nonspaces; /* nonspaces = # of nonspaces in current line. */ nonspaces= 0; c= getc(stream); length= 0L; while ( (c!='\n' || nonspaces!=0) && c!=EOF) { if (c=='\n') { length= ftell(stream)-start; nonspaces= 0; } else if (!isspace(c)) nonspaces++; c= getc(stream); } pos(start); return(length); } /* nextrecord(stream,x): seeks in stream for first non-blank line at or after char x in stream. seeks to eof if x is past last record. x is the index of a character in the file (not eof). returns position in stream. (returns EOF, if seeks to EOF) */ long int nextrecord(stream,x) FILE *stream; long int x; { long int start; /* position of the beginning of the line */ char c; /* containing c */ pos(x); start= x; /* find start of first non-blank record */ for(;;) { c= getc(stream); if (c=='\n') start= ftell(stream); else if (!isspace(c)) break; } if (feof(stream)) { pos(start); start= EOF; } else pos(start); return(start); } /* nextline(stream,x): seeks in stream after first newline at or after char x in stream. seeks to eof if x is in last line. x is the index of a character in the file (not eof). returns position in stream */ long int nextline(stream,x) FILE *stream; long int x; { pos(x); while (getc(stream)!='\n') ; return(ftell(stream)); } /* printline(stream): copies stream up to a newline */ printline(stream) FILE *stream; { char c; while ((c=getc(stream)) != '\n' && c!=EOF) putchar(c); putchar('\n'); } /* getline(stream,p): store in *p next chars in stream up to \n advance stream past \n. limit of maxstr-1 chars may be stored at p. */ getline(stream,p) FILE *stream; char *p; { char *stop; stop= p+maxstr-1; while ( (*p= getc(stream)) != '\n' && *p!=EOF) if (p<stop) p++; *p= NULL; } !Funky!Stuff! echo x - streams.h cat >streams.h <<'!Funky!Stuff!' # long int nextrecord(), recsize(), nextline(); # define maxstr 256 # define pos(x) fseek(stream,x,0) !Funky!Stuff! echo x - makefile cat >makefile <<'!Funky!Stuff!' .c.o: cc -g -c $*.c INVo = invert.o streams.o makekey.o INVc = invert.c streams.c makekey.c LOOKo = lookup.o locate.o alpha.seek.o streams.o makekey.o LOOKc = lookup.c locate.c alpha.seek.c streams.c makekey.c NEWBIBo = newbib.o newbibargs.o locate.o alpha.seek.o streams.o makekey.o BIBo = bib.o bibargs.o locate.o alpha.seek.o streams.o makekey.o BIBc = bib.c bibargs.c locate.c alpha.seek.c streams.c makekey.c LISTo = listrefs.o bibargs.o streams.o makekey.o NEWLISTo = listrefs.o newbibargs.o streams.o makekey.o LISTc = listrefs.c bibargs.c streams.c makekey.c all: invert lookup listrefs bib invert: $(INVo) cc -g $(INVo) -o invert invert.lint: $(INVc) bib.h streams.h lint $(INVc) >invert.lint lookup: $(LOOKo) cc -g $(LOOKo) -o lookup lookup.lint: $(LOOKc) bib.h streams.h lint $(LOOKc) >lookup.lint newbib: $(NEWBIBo) cc -g $(NEWBIBo) -o newbib bib: $(BIBo) cc -g $(BIBo) -o bib bib.lint: $(BIBc) bib.h streams.h lint $(BIBc) >bib.lint listrefs: $(LISTo) cc -g $(LISTo) -o listrefs newlisttrefs: $(NEWLISTo) cc -g $(NEWLISTo) -o newlistrefs listrefs.lint: $(LISTc) bib.h streams.h lint $(LISTc) >listrefs.lint bib.o: bib.h bibargs.o: bib.h listrefs.o: bib.h invert.o: streams.h bib.h locate.o: streams.h bib.h makekey.o: bib.h alpha.seek.o: streams.h streams.o: streams.h doc: bib -topenn bibdoc | tbl | vtroff -mtr clean: rm *.o !Funky!Stuff!