/* * fref creates troff-formatted references according to specifications * given on standard in. The specification syntax is similar to that of * refer, but differs in that all identifiers are two letters instead of * one (like troff itself). This allows for a larger number of fields. * * To build fref, run the following commands: * $ lex fref.lex * $ cc -std=c89 -O2 -o fref lex.yy.c -lfl */ %x ENTRY #include #include #define MAX 255 /* Max field length. */ /* * The following string constants can be redefined to support * other languages. */ #define AND "och" #define AVAIL "Tillgänglig: " #define ED "red." #define P "s." #define PP "ss." #define TR "Övers." #define VOL "vol." #define DO_ENTRIES \ DO("ad",ad,e.ad) /* Access date. */ \ DO("bo",bo,e.bo) /* Book. */ \ DO("ci",ci,e.ci) /* City. */ \ DO("da",da,e.da) /* Date (year). */ \ DO("ed",ed,e.ed) /* Editor. */ \ DO("hr",hr,e.hr) /* Hypertext reference. */ \ DO("jo",jo,e.jo) /* Journal. */ \ DO("la",la,e.la) /* Label. */ \ DO("no",no,e.no) /* TODO: Issue number. */ \ DO("pp",pp,e.pp) /* Pages. */ \ DO("pu",pu,e.pu) /* Publisher. */ \ DO("se",se,e.se) /* TODO: Series. */ \ DO("ti",ti,e.ti) /* Title. */ \ DO("tr",tr,e.tr) /* Translator. */ \ DO("vo",vo,e.vo) /* Volume. */ \ DO("xx",xx,e.xx) /* Extra information. */ \ /* END */ void field(char *); void entry(void); void harvard(void); int pf(char *, ...); char *name; int line; /* Line at which entry begins. */ int lines = 0; /* Total number of lines. */ /* * e is a struct holding all fields of the current entry. * It is zeroed before each call to entry(). */ struct entry { #define DO(s,n,m) char n[MAX]; DO_ENTRIES #undef DO int a; /* Number of authors. */ char au[MAX][MAX]; /* Authors. */ } e; %% \n lines++; ECHO; ^%.*\n line = ++lines; field(yytext); BEGIN(ENTRY); ^%.*\n lines++; field(yytext); ^[^%] entry(); ECHO; BEGIN(0); <> entry(); yyterminate(); %% void main(int argc, char *argv[0]) { name = strrchr(argv[0], '/'); if(name) name++; else name = argv[0]; memset(&e, 0, sizeof(e)); yylex(); } /* Save entry field. */ void field(char *t) { t++; t[strcspn(t, "\n")] = 0; /* Fill corresponding field. */ #define AS(a,b) if(strncmp(t, a, 2) == 0 && (t += 3)){ strcpy(b, t); return; } AS("au",e.au[e.a++]); #define DO(s,n,m) AS(s,m) DO_ENTRIES #undef DO fprintf(stderr, "%s: unrecognized field %%%.2s at line %d\n", name, t, lines); exit(1); } /* Print formatted entry. */ void entry() { /* * Presently, fref supports only Harvard-style citations, but * allows for future extensions. */ harvard(); } /* Print Harvard-formatted entry. */ void harvard() { int i; /* Print label. */ pf("% = ", e.la); /* Print authors. */ for(i = 0; i < e.a-2; i++) printf("%s, ", e.au[i]); if(i == e.a-2) printf("%s "AND" ", e.au[i++]); if(i == e.a-1) printf("%s", e.au[i]); /* Print date. */ (pf(" (%).\n", e.da) || (e.a ? pf(".\n") : 0)); /* Print title, book/journal. */ if(*e.bo || *e.jo){ pf("%.\n", e.ti); pf("\\fI%\\fP", e.bo ? e.bo : e.jo); pf(" ("ED" %)", e.ed); }else pf("\\fI%\\fP", e.ti); /* Print volume. */ pf(", "VOL" %", e.vo); /* Print pages, converting hyphens to en dashes. */ if(*e.pp){ printf(", %s ", strpbrk(e.pp, ",-") ? PP : P); for(i = 0; i < strlen(e.pp); i++){ if(e.pp[i] == '-') putchar('\\'); putchar(e.pp[i]); } *e.pp = 0; } pf(".\n"); /* Print translator. */ pf(TR" %.\n", e.tr); /* Print city, publisher. */ (pf("%: %.\n", e.ci, e.pu) || pf("%.\n", e.pu)); /* Print other information. */ pf("%.\n", e.xx); /* Print hypertext reference. */ pf(AVAIL"%\n", e.hr); /* Print access date. */ pf("[%]\n", e.ad); /* Clear unused fields. */ e.a = 0; #define DO(s,n,m) \ if(*m) fprintf(stderr, "%s: unused field %%"s" at line %d\n", \ name, line); \ *m = 0; DO_ENTRIES #undef DO } /* Print formatted text if given fields are non-empty. Clear fields. */ int pf(char *fmt, ...) { char *buf, *p, **fs; int i, n, sz; va_list ap; /* Count given fields. */ for(n = 0, p = fmt; *p; p++) if(*p == '%') n++; /* Allocate memory. */ if(!(fs = malloc(n))) err(1, "malloc"); /* Verify that no field is empty. */ va_start(ap, fmt); for(i = 0; i < n; i++){ p = va_arg(ap, char *); if(!p || !*p) return 0; fs[i] = p; } va_end(ap); /* Print fields according to format. */ for(i = 0; *fmt; fmt++) switch(*fmt){ case '%': printf("%s", fs[i]); fs[i++][0] = 0; break; default: putchar(*fmt); } return 1; }