aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Ankarström <john@ankarstrom.se>2021-07-20 10:16:25 +0200
committerJohn Ankarström <john@ankarstrom.se>2021-07-21 11:19:55 +0200
commit832c354a05df96c3ec9730b9dcbaa75ee666c3c4 (patch)
tree6b4fff3117e17f3eb928deca87005a4318ec5f6f
parentfa547f513fb97828aa87cd5370ff81cf4ecae709 (diff)
downloadfref-832c354a05df96c3ec9730b9dcbaa75ee666c3c4.tar.gz
Convert hyphens to en dashes, warn if field unused
-rw-r--r--Makefile2
-rw-r--r--example.t4
-rw-r--r--fref.lex152
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.t | troff -ms | dpost | ps2pdf - >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 <err.h>
#include <stdarg.h>
@@ -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>^[^%] entry(); ECHO; BEGIN(0);
-<ENTRY><<EOF>> entry(); yyterminate();
+\n lines++; ECHO;
+^%.*\n line = ++lines; field(yytext); BEGIN(ENTRY);
+<ENTRY>^%.*\n lines++; field(yytext);
+<ENTRY>^[^%] entry(); ECHO; BEGIN(0);
+<ENTRY><<EOF>> 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;
}