#include #include #include #include typedef struct Bibent Bibent; enum { Nfields = 100, Ntoks = 256, }; #define Skipchars "{\"}" struct Bibent { int nfields; char* tag[Nfields]; char* val[Nfields]; }; static char* lastln; static char* eatcomment(char* ln) { char* p; char* sp; if (ln == nil) return nil; p = strchr(ln, '%'); if (p) *p = 0; for(sp = ln; sp && *sp && (*sp == ' '||*sp == '\t'); sp++) ; if (sp != ln){ sp = strdup(sp); free(ln); return sp; } return ln; } static char* getln(Biobuf* bin) { char* ln; if (lastln){ ln = lastln; lastln = nil; } else ln = eatcomment(Brdstr(bin, '\n', 1)); return ln; } static void ungetln(char* ln) { lastln = ln; } static int skiptobib(Biobuf* bin) { char* ln; while(ln = getln(bin)){ if (strchr(ln, '@')) break; free(ln); } if (ln != nil){ ungetln(ln); return 1; } return 0; } enum { Author = 0, }; static struct { char* bib; char* ref; } tags[] = { "author", "%A", "title", "%T", "journal", "%J", "month", "%D", "year", "%Y", "volume", "%V", "number", "%N", "pages", "%P", "keyword", "%K", "booktitle", "%B", "comment", "#", "address", "%C", "date", "%D", "organization", "%I", "publisher", "%I", "institution", "%I", "school", "%I", "abstract", "#", "key", "%K", }; static int tagid(char* tname) { int i; for (i = 0; i < nelem(tags); i++) if (strcmp(tags[i].bib, tname) == 0) return i; return -1; } static void printbibent(Bibent* be) { int i, t; char* a; char* s; for(i = 0; i < be->nfields; i++){ t = tagid(be->tag[i]); switch(t){ case Author: a = s = be->val[i]; while(s && *s){ s = strstr(a, " and "); if (s){ *s = 0; s+=5; while(*s && (*s == ' ' || *s == '\t')) s++; } print("%s %s\n", tags[Author].ref, a); a = s; } break; default: if (t < 0) print("#%s:\t%s\n", be->tag[i], be->val[i]); else print("%s %s\n", tags[t].ref, be->val[i]); } } print("\n"); } static void freebibent(Bibent* be) { int i; for (i = 0; i < be->nfields; i++){ free(be->tag[i]); free(be->val[i]); } free(be); } static char* cleanbibval(char* old) { char* n; char* np; char* op; if (!old) return strdup(""); if (*old == 0) return old; op = old; n = malloc(strlen(old)+1); for(np = n; *old; old++){ if (strchr(Skipchars, *old)) continue; *np++ = *old; } *np = 0; while(np > n && (np[-1] == ' ' || np[-1] == '\t')) *--np = 0; if (np > n && np[-1] == ',') *--np = 0; free(op); return n; } static int readbibtag(Biobuf* bin, Bibent* be) { char* eq; char* t; char* ln; char* s; while(ln = getln(bin)){ if (strchr(ln, '@')){ ungetln(ln); return 0; } eq = strchr(ln, '='); if (!eq){ free(ln); // skip down to next tag continue; // (a comment?) } for (t = ln; *t && (*t == ' ' || *t == '\t'); t++) ; *eq++ = 0; while(*eq && (*eq == ' ' || *eq == '\t')) eq++; s = strchr(t, ' '); if (s) *s = 0; s = strchr(t, '\t'); if (s) *s = 0; for (s = t; *s; s++) *s = tolower(*s); be->tag[be->nfields] = strdup(t); be->val[be->nfields] = strdup(eq); be->nfields++; free(ln); return 1; } return 0; } static int readbibfield(Biobuf* bin, Bibent* be) { int fid; char* nf; char* ln; fid = be->nfields; if (!readbibtag(bin, be)) return 0; while(ln = getln(bin)){ if (strchr(ln, '@') || strchr(ln, '=')){ ungetln(ln); goto done; } nf = smprint("%s %s", be->val[fid], ln); free(be->val[fid]); free(ln); be->val[fid] = nf; } done: be->val[fid] = cleanbibval(be->val[fid]); return 1; } static Bibent* readbibentry(Biobuf* bin, Bibent* be) { char* ln; ln = getln(bin); if (ln == nil || !strchr(ln, '@')){ freebibent(be); return nil; } while(readbibfield(bin, be)) ; return be; } static Bibent* readbibent(Biobuf* bin) { Bibent* be; be = malloc(sizeof(Bibent)); memset(be, 0, sizeof(be)); if (!skiptobib(bin)) goto fail; // no more entries be = readbibentry(bin, be); return be; fail: freebibent(be); return nil; } static void readbibfile(Biobuf* bin) { Bibent* be; while(be = readbibent(bin)){ printbibent(be); freebibent(be); } } void main(int argc, char*argv[]) { Biobuf* bin; Biobuf bsin; ARGBEGIN{ default: fprint(2, "usage: %s file...\n", argv0); exits("usage"); } ARGEND; if (argc == 0){ Binit(&bsin, 0, OREAD); readbibfile(&bsin); Bterm(&bsin); } else { for(; argc--; argv++){ if((bin = Bopen(*argv, OREAD)) == nil) sysfatal("%s cannot open - %r\n", *argv); readbibfile(bin); Bterm(bin); } } exits(nil); }