From 832c354a05df96c3ec9730b9dcbaa75ee666c3c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Ankarstr=C3=B6m?= Date: Tue, 20 Jul 2021 10:16:25 +0200 Subject: Convert hyphens to en dashes, warn if field unused --- Makefile | 2 +- example.t | 4 +- fref.lex | 152 ++++++++++++++++++++++++++++++++------------------------------ 3 files changed, 83 insertions(+), 75 deletions(-) diff --git a/Makefile b/Makefile index 92211b0..a84614a 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,3 @@ fref: fref.lex lex fref.lex - cc -O2 -o fref lex.yy.c -lfl + cc -std=c89 -O2 -o fref lex.yy.c -lfl diff --git a/example.t b/example.t index dd84a75..26775e4 100644 --- a/example.t +++ b/example.t @@ -1,3 +1,5 @@ +.\" $ export LC_ALL=en_US.UTF-8 +.\" $ ./fref example.pdf .SH References .XP @@ -10,7 +12,7 @@ References %pp 110-123 %ad http://www.example.com/b1887.pdf .XP -%au de Courtenay, J. Baudouin +%au Baudouin de Courtenay, J. %au Author, Fake Extra %da 1972 %ti The Difference between Phonetics and Psychophonetics diff --git a/fref.lex b/fref.lex index bc26dc7..91ea0e0 100644 --- a/fref.lex +++ b/fref.lex @@ -5,6 +5,8 @@ * one (like troff itself). This allows for a larger number of fields. */ +%x ENTRY + #include #include @@ -13,49 +15,62 @@ #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) /* internet address */ \ + 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("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 */ struct entry { - int a; /* Number of authors. */ + #define DO(s,n,m) char n[MAX]; + DO_ENTRIES + #undef DO + int a; /* number of authors */ char au[MAX][MAX]; /* author */ - char ad[MAX]; /* internet address */ - char bo[MAX]; /* book */ - char ci[MAX]; /* city */ - char da[MAX]; /* date (year) */ - char ed[MAX]; /* editor */ - char jo[MAX]; /* journal */ - char la[MAX]; /* label */ - char no[MAX]; /* TODO: issue number */ - char pp[MAX]; /* pages */ - char pu[MAX]; /* publisher */ - char se[MAX]; /* TODO: series */ - char ti[MAX]; /* title */ - char tr[MAX]; /* translator */ - char vo[MAX]; /* volume */ - char xx[MAX]; /* extra information */ } e; -%s ENTRY %% -^%.*\n field(yytext); BEGIN(ENTRY); -^[^%] entry(); ECHO; BEGIN(0); -<> entry(); yyterminate(); +\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 = argv[0]; - e.a = 0; + name = strrchr(argv[0], '/'); + if(name) name++; + else name = argv[0]; + + memset(&e, 0, sizeof(e)); yylex(); } @@ -63,28 +78,15 @@ main(int argc, char *argv[0]) void field(char *t) { - -#define AS(a,b) if(strncmp(t, a, 2) == 0 && (t += 3)){ strcpy(b, t); return; } - 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++]); - AS("ad",e.ad); - AS("bo",e.bo); - AS("ci",e.ci); - AS("da",e.da); - AS("ed",e.ed); - AS("jo",e.jo); - AS("la",e.la); - AS("no",e.no); - AS("pp",e.pp); - AS("pu",e.pu); - AS("se",e.se); - AS("ti",e.ti); - AS("tr",e.tr); - AS("vo",e.vo); - AS("xx",e.xx); +#define DO(s,n,m) AS(s,m) + DO_ENTRIES +#undef DO fprintf(stderr, "%s: unrecognized field %%%.2s\n", name, t); exit(1); @@ -127,9 +129,18 @@ harvard() }else pf("\\fI%\\fP", e.ti); - /* Print volume, pages. */ + /* Print volume. */ pf(", "VOL" %", e.vo); - pf(", "PP" %", e.pp); + + /* 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. */ @@ -144,32 +155,22 @@ harvard() /* Print internet address. */ pf(AVAIL"%\n", e.ad); -#define CL(a) *a = 0 - + /* Clear entries. */ e.a = 0; - CL(e.ad); - CL(e.bo); - CL(e.ci); - CL(e.da); - CL(e.ed); - CL(e.jo); - CL(e.la); - CL(e.no); - CL(e.pp); - CL(e.pu); - CL(e.se); - CL(e.ti); - CL(e.tr); - CL(e.vo); - CL(e.xx); +#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. */ +/* Print formatted text if given fields are non-empty. Clear fields. */ int pf(char *fmt, ...) { - char *buf, *p; - int n, sz; + char *buf, *p, **fs; + int i, n, sz; va_list ap; /* Count given fields. */ @@ -177,24 +178,29 @@ pf(char *fmt, ...) if(*p == '%') n++; - /* Allocate enough memory to fit the given fields. */ - sz = strlen(fmt)+n*MAX+1; - if(!(buf = malloc(sz))) + /* Allocate memory. */ + if(!(fs = malloc(n))) err(1, "malloc"); + /* Verify that no field is empty. */ va_start(ap, fmt); - for(; *fmt; 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 '%': - p = va_arg(ap, char *); - if(!p || !*p) - return 0; - strncat(buf, p, sz-1); + printf("%s", fs[i]); + fs[i++][0] = 0; break; default: - strncat(buf, fmt, 1); + putchar(*fmt); } - printf("%s", buf); - va_end(ap); return 1; } -- cgit v1.2.3