#ifndef lint static char sccsid[] = "@(#)bibargs.c 2.13 05/27/93"; #endif not lint /* Authored by: Tim Budd, University of Arizona, 1983. 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 read argument strings for bib and listrefs do name formatting, printing lines, other actions common to both */ # include # include # include "bib.h" # define LINELENGTH 1024 # define MAXDEFS 500 /* maximum number of defined words */ /* global variables */ char bibfname[120]; /* file name currently being read */ int biblineno; /* line number currently being referenced */ int abbrev = false; /* automatically abbreviate names */ int capsmcap = false; /* print names in caps small caps (CACM form)*/ int TibOption = false; /* expect files in TiB format */ int TibxOption = false; /* to create files for bib2tib */ 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 max_klen = 6; /* max size of key */ int sort = false; /* sort references ? (default no) */ int foot = false; /* footnoted references ? (default endnotes) */ int doacite = true; /* place citations ? */ int redefWarning = false; /* warnings on attempted redefs ? */ 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[400]; /* private file name */ int personal = false; /* personal file given ? (default no) */ char citetemplate[80] = "1"; /* citation template */ struct wordinfo words[MAXDEFS]; /* defined words */ struct wordinfo *wordhash[HASHSIZE]; struct wordinfo *wordsearch(); int wordtop = 0; /* number of defined words */ char letterSeen[128]; /* keeps track of keyletters * so we know whether to emit a .ds * or a .as /* */ /* where output goes */ extern FILE *tfd; /* reference file information */ extern struct refinfo refinfo[]; extern char reffile[]; #ifndef INCORE extern FILE *rfd; #endif not INCORE extern int numrefs; extern char *programName; char *usageArr[] = { "-aa abbreviate authors' first names", "-arN reverse first N authors' names; no N, do all", "-ax print authors' last names in Caps-Small", "-cS use template S for citations", "-d change the default directory", "-ea abbreviate editors' first names", "-ex print editors' last names in Caps-Small", "-erN reverse first N editors' names; no N, do all", "-f dump reference after citation for footnotes", "-iFILE process FILE (e.g. a file of definitions)", "-h hyphenate sequences of citations (turns on -o)", "-nS turn off options; S is composed of the option letters 'afhosx'", "-pFILE search these FILEs (comma separated list) instead of INDEX", "-R print warnings when duplicate definitions of names are ignored", "-sS sort references according to template S", "-tTYPE use the style TYPE", "-Tib expect files to be in TiB format (which see)", "-Tibx write a file for converting bib to TiB-style |macros|", "", 0 }; void usageErr(argv0, opt, str) char *argv0; char *opt; char *str; { char **p; fprintf(stderr, "Illegal invocation of %s. Acceptable options:\n", argv0); fprintf(stderr, "Argument: %s\n", opt); fprintf(stderr, "Problem: %s\n", str); for (p = usageArr; *p != 0; p++) { fprintf(stderr, " %s\n", *p); } } /* bibwarning - print out a warning message */ /*VARARGS1*/ bibwarning(msg, a1, a2) char *msg; { fprintf(stderr,"%s: `%s', line %d: ", programName, bibfname, biblineno); fprintf(stderr, msg, a1, a2); fprintf(stderr, "\n"); } /* 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; TibxOption = false; newbibdir(BMACLIB); programName = argv[0]; for (i = 1; i < argc; i++) if (argv[i][0] == '-') switch(argv[i][1]) { case 'a': for (p = &argv[i][2]; *p; p++) if (*p == 'a' || *p == 0) abbrev = true; else if (*p == 'x') capsmcap = true; else if (*p == 'r') { if (*(p+1)) numrev = atoi(p+1); else numrev = 1000; break; } break; case 'c': if (argv[i][2] == 0) error("citation string expected for 'c'"); else for (p = citetemplate,q = &argv[i][2]; *p++ = *q++; ); break; case 'd': if (argv[i][2]) p = &argv[i][2]; else { /* take next arg */ i++; p = argv[i]; } newbibdir(p); 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': CASE_f: foot = true; hyphen = false; break; case 'i': CASE_i: if (argv[i][2]) p = &argv[i][2]; else { /* take next arg */ i++; p = argv[i]; } incfile(p); break; case 'l': if (argv[i][2]){ max_klen = atoi(&argv[i][2]); if (max_klen > REFSIZE) error("too long key size"); } else { error("-l needs a numeric value"); } 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') redefWarning = false; else if (*p == 'r') numrev = 0; else if (*p == 's') sort = false; else if (*p == 'x') capsmcap = false; else if (*p == 'v') doacite = true; 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': redefWarning = true; break; case 'r': if (argv[i][2] == 0) /* synonym -ar */ 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 't': style = false; goto CASE_i; case 'T': if (strcmp("Tib", &(argv[i][1])) == 0) TibOption = true; else if (strcmp("Tibx",&(argv[i][1])) == 0) TibxOption = true; else { usageErr(argv[0], argv[i], "Did you want the Tib option?"); error("'%s' invalid switch", argv[i]); } break; case 'v': doacite = false; goto CASE_f; case 'x': capsmcap = true; /* synonym for -ax */ break; case 0: if (style) { /* no style command given, take default */ style = false; incfile( defstyle ); } strcpy(bibfname,""); rdtext(stdin); numfiles++; break; default: usageErr(argv[0], argv[i], "Invalid switch"); error("'%c' invalid switch", argv[i][1]); } else { /* file name */ numfiles++; if (style) { style = false; incfile( defstyle ); } fd = fopen(argv[i], "r"); if (fd == NULL) { error("can't open file %s", argv[i]); } else { strcpy(bibfname, argv[i]); rdtext(fd); fclose(fd); } } if (style) incfile( defstyle ); if (TibxOption) { /* Emits m4 macros that allow easy transformation of old bib-style bibliographic databases into tib-style. The primary problem (although not the only one) is the change of |macro| calls. */ reg struct wordinfo *wp; FILE *outf; outf = fopen("bib.m4.in","w"); for (i=0; iwi_hp) { fprintf(outf,"define(%s,|%s__m4_|)dnl\n",wp->wi_word,wp->wi_word); } } fclose(outf); } return(numfiles); } newbibdir(name) char *name; { strreplace(COMFILE, BMACLIB, name); strreplace(DEFSTYLE, BMACLIB, name); strcpy(BMACLIB, name); wordrestuff("BMACLIB", BMACLIB); fprintf(tfd, ".ds l] %s\n", BMACLIB); } /* incfile - read in an included file */ incfile(np) char *np; { char name[120]; FILE *fd; char *p, line[LINELENGTH], dline[LINELENGTH], word[80], *tfgets(); int i, getwrd(); strcpy(line, bibfname); /* temporary save in case of errors */ /* first try ./ */ strcpy(bibfname, np); fd = fopen(bibfname, "r"); /* try BMACLIB/ */ if (fd == NULL && *np != '/') { strcpy(name, BMACLIB); strcat(name, "/"); strcat(name, np); strcpy(bibfname, name); fd = fopen(bibfname, "r"); } /* try BMACLIB/tibmacs/ */ if (TibOption && fd == NULL && *np != '/') { strcpy(name, BMACLIB); strcat(name, "/tibmacs/"); strcat(name, np); strcpy(bibfname, name); fd = fopen(bibfname, "r"); } /* try BMACLIB/bibmacs/ */ if (!TibOption && fd == NULL && *np != '/') { strcpy(name, BMACLIB); strcat(name, "/bibmacs/"); strcat(name, np); strcpy(bibfname, name); fd = fopen(bibfname, "r"); } /* try ./bib. */ if (fd == NULL && *np != '/') { strcpy(name, "bib."); strcat(name, np); strcpy(bibfname, name); fd = fopen(bibfname, "r"); } /* try BMACLIB/bib. */ if (fd == NULL && *np != '/') { strcpy(name,BMACLIB); strcat(name, "/bib."); strcat(name, np); strcpy(bibfname, name); fd = fopen(bibfname, "r"); } if (fd == NULL) { /* unsave old name */ strcpy(bibfname, line); bibwarning("%s: can't find", np); exit(1); } /* now go off and process file */ biblineno = 1; while (tfgets(line, LINELENGTH, fd) != NULL) { biblineno++; switch(line[0]) { case '#': break; case 'A': for (p = &line[1]; *p; p++) if (*p == 'A' || *p == '\0') abbrev = true; else if (*p == 'X') capsmcap = true; else if (*p == 'R') { if (*(p+1)) numrev = atoi(p+1); else numrev = 1000; break; } 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"); if (wordsearch(word)) { /* already there-toss rest of def.*/ if (redefWarning) bibwarning("Attempted redefine of %s ignored.",word); while(line[strlen(line)-1] == '\\' ) { if (tfgets(line, LINELENGTH, fd) == NULL) break; } break; } for (p = &line[i]; isspace(*p); p++) ; for (strcpy(dline, p); dline[strlen(dline)-1] == '\\'; ){ dline[strlen(dline)-1] = '\n'; if (tfgets(line, LINELENGTH, fd) == NULL) break; strcat(dline, line); } wordstuff(word, 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) /* this is now replaced by AR */ 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; /* this is now replace by AX */ break; default: fprintf(tfd,"%s\n",line); while (fgets(line, LINELENGTH, fd) != NULL) fputs(line, tfd); return; } } /* close up */ fclose(fd); } /* error - report unrecoverable error message */ /*VARARGS1*/ error(str, a1, a2) char *str; { bibwarning(str, a1, a2); /* * clean up temp files and exit */ cleanup(1); } #ifndef INCORE #ifdef READWRITE /* ** fixrfd( mode ) -- re-opens the rfd file to be read or write, ** depending on the mode. Uses a static int to save the current mode ** and avoid unnecessary re-openings. */ fixrfd( mode ) register int mode; { static int cur_mode = WRITE; /* rfd open for writing initially */ if (mode != cur_mode) { rfd = freopen(reffile, ((mode == READ)? "r" : "a"), rfd); cur_mode = mode; if (rfd == NULL) error("Hell! Couldn't re-open reference file %s", reffile); } } #endif #endif not INCORE /* tfgets - fgets which trims off newline */ char *tfgets(line, n, ptr) char line[]; int n; FILE *ptr; { reg 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) reg char in[], out[]; reg int i; { int j; j = 0; while (isspace(in[i])) i++; if (in[i] != '\0') while (in[i] != '\0' && !isspace(in[i])) 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); } /* isword - see if character is legit word char */ #define iswordc(c) (isalnum(c) || c == '&' || c == '_') expand(line) char *line; { char line2[REFSIZE], word[REFSIZE]; reg struct wordinfo *wp; reg char *p, *q, *w; q = line2; if (TibOption) { /* expand only macro names in |name| vertical bars; name must exist */ for (p = line; *p != '\0'; /* VOID */ ) { if (*p == '|') { p++; w = word; while (*p != '|' && *p != '\0' && !isspace(*p)) { *w++ = *p++; } *w = '\0'; /* skip second '|', if present */ if (*p++ != '|') { --p; bibwarning("Unbalanced |macro| bars\n"); } else if ((wp = wordsearch(word)) != 0) { strcpy(word, wp->wi_def); if (wp->wi_expanding) { bibwarning("Recursive definition for |%s|\n", word); } else { wp->wi_expanding = true; expand(word); wp->wi_expanding = false; } } else { char errword[REFSIZE]; bibwarning("word |%s| not defined\n", word); strcpy(errword, "?"); strcat(errword, word); strcat(errword, "?"); wordstuff(word, errword); strcpy(word, errword); } for (w = word; *w != '\0'; *q++ = *w++); } else { *q++ = *p++; } } } else { for (p = line; *p != '\0'; /*VOID*/){ if (isalnum(*p)) { for (w = word; *p && iswordc(*p); ) *w++ = *p++; *w = 0; if (wp = wordsearch(word)){ if (wp->wi_expanding) bibwarning("Recursive definition for %s\n", word); else { strcpy(word, wp->wi_def); wp->wi_expanding = true; expand(word); wp->wi_expanding = false; } } for (w = word; *w != '\0'; *q++ = *w++); } else if (*p == '\\' && *(p+1) != '\0') { *q++ = *p++; *q++ = *p++; } else { *q++ = *p++; } } } *q = 0; strcpy(line, line2); } /* wordstuff- save a word and its definition, building a hash table */ wordstuff(word, def) char *word, *def; { int i; if (wordtop >= MAXDEFS) error("too many definitions, max of %d", MAXDEFS); words[wordtop].wi_length = strlen(word); words[wordtop].wi_word = word ? walloc(word) : NULL; words[wordtop].wi_def = def ? walloc(def) : NULL; i = strhash(word); words[wordtop].wi_expanding = false; words[wordtop].wi_hp = wordhash[i]; wordhash[i] = &words[wordtop]; wordtop++; } struct wordinfo *wordsearch(word) char *word; { reg int lg; reg struct wordinfo *wp; lg = strlen(word); for (wp = wordhash[strhash(word)]; wp; wp = wp->wi_hp){ if (wp->wi_length == lg && (strcmp(wp->wi_word, word) == 0)){ return(wp); } } return(0); } /* wordrestuff - save a word and its definition, but replace any existing * definition; this could be more efficient, but it is only used to * redefine BMACLIB at the present. -ads 8/88 */ wordrestuff(word, def) char *word, *def; { struct wordinfo *wp = wordsearch(word); if (wp == NULL) wordstuff(word, def); else { if (wp->wi_word != NULL) free(wp->wi_word); if (wp->wi_def != NULL) free(wp->wi_def); wp->wi_length = strlen(word); wp->wi_word = word ? walloc(word) : NULL; wp->wi_def = def ? walloc(def) : NULL; wp->wi_expanding = false; } } int strhash(str) reg char *str; { reg int value = 0; for (value = 0; *str; value <<= 2, value += *str++)/*VOID*/; value %= HASHSIZE; if (value < 0) value += HASHSIZE; return(value); } /* rdref - read text for an already cited reference */ rdref(p, ref) struct refinfo *p; char ref[REFSIZE]; { ref[0] = 0; #ifndef INCORE #ifdef READWRITE fixrfd( READ ); /* fix access mode of rfd, if nec. */ #endif fseek(rfd, p->ri_pos, 0); fread(ref, p->ri_length, 1, rfd); #else INCORE strcpy(ref, p->ri_ref); #endif INCORE } /* wrref - write text for a new reference */ wrref(p, ref) struct refinfo *p; char ref[REFSIZE]; { #ifndef INCORE #ifdef READWRITE fixrfd( WRITE ); /* fix access mode of rfd, if nec. */ #else fseek(rfd, p->ri_pos, 0); /* go to end of rfd */ #endif fwrite(ref, p->ri_length, 1, rfd); #else INCORE p->ri_ref = walloc(ref); #endif INCORE } /* breakname - break a name into first and last name */ breakname(line, first, last) char line[], first[], last[]; { reg char *t, *f, *q, *r, *p; 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--); f++; } /* first name is start to f, last name is q to t */ for (r = first, p = line; 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) reg char str1[], str2[]; { reg int j, i; 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) reg char *p, *q; { while (*p++ = *q++) ; return(--p); } /* rcomp - reference comparison routine for qsort utility */ int rcomp(ap, bp) struct refinfo *ap, *bp; { char ref1[REFSIZE], ref2[REFSIZE], field1[MAXFIELD], field2[MAXFIELD]; reg char *p, *q; char *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 standard citation strings, using citetemplate currently in effect */ makecites() { char ref[REFSIZE], tempcite[100], *malloc(); reg int i; for (i = 0; i < numrefs; i++) { rdref(&refinfo[i], ref); bldcite(tempcite, i, ref); refinfo[i].ri_cite = malloc(2 + strlen(tempcite)); if (refinfo[i].ri_cite == NULL) error("out of storage"); strcpy(refinfo[i].ri_cite, tempcite); } } /* bldcite - build a single citation string */ bldcite(cp, i, ref) char *cp, ref[]; int i; { reg char *p, *q, *fp; char c; char field[REFSIZE]; char *getfield(), *aabet(), *aabetlast(), *fullaabet(), *multfull(); 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)) { /* field name */ q = getfield(p-1, field, ref); if (q != 0) { p = q; for (fp = field; *fp; ) *cp++ = *fp++; } } else if (c == '1') { /* numeric order */ sprintf(field,"%d",1 + i); for (fp = field; *fp; ) *cp++ = *fp++; } else if (c == '2') /* alternate alphabetic */ cp = aabet(cp, ref); else if (c == '3') /* Astrophysical Journal style*/ cp = multfull(cp, ref, 3); else if (c == '4') /* Computing Surveys style*/ cp = multfull(cp, ref, 2); else if (c == '8') /* Full alphabetic */ cp = fullaabet(cp, ref); else if (c == '9') /* Last name of Senior Author*/ cp = aabetlast(cp, ref); else if (c == '0') { /* print nothing */ for (fp = field; *fp; ) *cp++ = *fp++; } else if (c == '{') { /* other information */ 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; } /* alternate alphabetic citation style - if 1 author - first three letters of last name if 2 authors - first two letters of first, followed by first letter of seond if 3 or more authors - first letter of first three authors */ char *aabet(cp, ref) char *cp, ref[]; { char field[REFSIZE], temp[100]; reg char *np, *fp; int j, getname(); 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]; } } return(cp); } /* alternate alphabetic citation style - first two characters of last names of all authors up to max_klen characters. */ char *fullaabet(cp, ref) char *cp, ref[]; { char field[REFSIZE], temp[100]; reg char *fp; char *lastcp; int getname(); int i; lastcp = cp + max_klen; for (i= 1; getname(i, field, temp, ref); i++) { for (fp = field; *fp && (fp < &(field[3])); ) if (cp > lastcp) break; else if (isalpha(*fp)) *cp++ = *fp++; else fp++; } return(cp); } /* alternate alphabetic citation style - entire last name of senior author */ char *aabetlast(cp, ref) char *cp, ref[]; { char field[REFSIZE], temp[100]; reg char *fp; int getname(); if (getname(1, field, temp, ref)) { for (fp = field; *fp; ) *cp++ = *fp++; } return(cp); } /* Multiple full authors last names (1, 2 or 3 full names). If maxauthors<3 if 1 author - last name date if 2 authors - last name and last name date if 3 or more authors - last name et al. date If maxauthors>=3 if 1 author - last name date if 2 authors - last name and last name date if 3 authors - last name, last name and last name date if 4 or more authors - last name et al. date */ char *multfull(cp, ref, maxauthors) char *cp, ref[]; int maxauthors; { char name1[100], name2[100], name3[100], temp[100]; reg char *fp; int getname(); if (getname(1, name1, temp, ref)) { for (fp = name1; *fp; ) *cp++ = *fp++; if (((maxauthors >= 3) && (getname(4, name3, temp, ref))) || ((maxauthors < 3) && (getname(3, name3, temp, ref)))) { for (fp = " \\*(e]"; *fp; ) *cp++ = *fp++; } else if (getname(2, name2, temp, ref)) { if (getname(3, name3, temp, ref)) { for (fp = "\\*(c]"; *fp; ) *cp++ = *fp++; for (fp = name2; *fp; ) *cp++ = *fp++; for (fp = "\\*(m]"; *fp; ) *cp++ = *fp++; for (fp = name3; *fp; ) *cp++ = *fp++; } else { for (fp = "\\*(n]"; *fp; ) *cp++ = *fp++; for (fp = name2; *fp; ) *cp++ = *fp++; } } } return(cp); } /* getfield - get a single field from reference */ char *getfield(ptr, field, ref) char *ptr, field[], ref[]; { reg char *p, *q; char temp[100]; int n, len, i, getname(); field[0] = 0; if (*ptr == 'A') getname(1, field, temp, ref); else for (p = ref; *p != '\0'; p++) if (*p == '%' && *(p+1) == *ptr) { for (p = p + 2; isspace(*p); p++) ; for (q = field; (*p != '\n') && (*p != '\0'); ) *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[]; { reg char *p; int m; m = n; 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); } } if (n == m) /* no authors, try editors */ for (p = ref; *p; p++) if (*p == '%' & *(p+1) == 'E') { n--; if (n == 0) { for (p = p + 2; *p == ' '; p++) ; breakname(p, first, last) ; return(true); } } if (n == m) { /* no editors, either, try institution */ first[0] = last[0] = '\0'; getfield("I", last, ref); if (last[0] != '\0') return(true); } return(false); } /* disambiguate - compare adjacent citation strings, and if equal, add single character disambiguators */ disambiguate() { reg int i, j; char adstr; for (i = 0; i < numrefs-1; i = j) { j = i + 1; if (strcmp(refinfo[i].ri_cite, refinfo[j].ri_cite)==0) { adstr = 'a'; for(j = i+1; j