2 * NEATREFER - A REFER CLONE FOR NEATROFF
4 * Copyright (C) 2011-2016 Ali Gholami Rudi <ali at rudi dot ir>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 #define NREFS (1 << 14)
26 #define LEN(a) (sizeof(a) / sizeof((a)[0]))
29 char *keys
[128]; /* reference keys */
30 char *auth
[128]; /* authors */
31 int id
; /* allocated reference id */
35 static struct ref refs
[NREFS
]; /* all references in refer database */
37 static struct ref
*cites
[NREFS
]; /* cited references */
38 static int cites_n
= 1;
39 static int inserted
; /* number of inserted references */
40 static int multiref
; /* allow specifying multiple references */
41 static int accumulate
; /* accumulate all references */
42 static char *refmac
; /* citation macro name */
43 static FILE *refdb
; /* the database file */
45 #define ref_label(ref) ((ref)->keys['L'])
47 /* the next input line */
48 static char *lnget(void)
50 static char buf
[1024];
51 return fgets(buf
, sizeof(buf
), stdin
);
54 /* write an output line */
55 static void lnput(char *s
, int n
)
57 write(1, s
, n
>= 0 ? n
: strlen(s
));
60 /* the next refer database input line */
61 static char *dbget(void)
63 static char buf
[1024];
64 return refdb
? fgets(buf
, sizeof(buf
), refdb
) : NULL
;
67 static char *sdup(char *s
)
69 char *e
= strchr(s
, '\n') ? strchr(s
, '\n') : strchr(s
, '\0');
78 /* read a single refer record */
79 static void db_ref(struct ref
*ref
, char *ln
)
82 if (ln
[0] == '%' && ln
[1] >= 'A' && ln
[1] <= 'Z') {
84 while (isspace((unsigned char) *r
))
87 ref
->auth
[ref
->nauth
++] = sdup(r
);
89 ref
->keys
[(unsigned char) ln
[1]] = sdup(r
);
91 } while ((ln
= dbget()) && ln
[0] != '\n');
94 /* parse a refer-style bib file and fill refs[] */
95 static int db_parse(void)
98 while ((ln
= dbget()))
100 db_ref(&refs
[refs_n
++], ln
);
104 static char fields
[] = "LTABRJDVNPITO";
105 static char fields_flag
[] = "OP";
106 static char *kinds
[] = {"Other", "Article", "Book", "In book", "Report"};
108 static int ref_kind(struct ref
*r
)
121 /* print the given reference */
122 static void ref_ins(struct ref
*ref
, int id
)
126 int kind
= ref_kind(ref
);
128 s
+= sprintf(s
, ".ds [F %d\n", id
);
129 s
+= sprintf(s
, ".]-\n");
131 s
+= sprintf(s
, ".ds [A ");
132 for (j
= 0; j
< ref
->nauth
; j
++)
133 s
+= sprintf(s
, "%s%s", j
? ", " : "", ref
->auth
[j
]);
134 s
+= sprintf(s
, "\n");
136 for (j
= 'B'; j
<= 'Z'; j
++) {
137 char *val
= ref
->keys
[j
];
138 if (!val
|| !strchr(fields
, j
))
140 s
+= sprintf(s
, ".ds [%c %s\n", j
, val
? val
: "");
141 if (strchr(fields_flag
, j
))
142 s
+= sprintf(s
, ".nr [%c 1\n", j
);
144 s
+= sprintf(s
, ".][ %d %s\n", kind
, kinds
[kind
]);
148 /* print all references */
149 static void ref_all(void)
153 for (i
= 1; i
< cites_n
; i
++)
154 ref_ins(cites
[i
], i
);
158 static int intcmp(void *v1
, void *v2
)
160 return *(int *) v1
- *(int *) v2
;
163 /* the given label was referenced; add it to cites[] */
164 static int refer_seen(char *label
)
167 for (i
= 0; i
< refs_n
; i
++)
168 if (ref_label(&refs
[i
]) && !strcmp(label
, ref_label(&refs
[i
])))
173 refs
[i
].id
= cites_n
++;
174 cites
[refs
[i
].id
] = &refs
[i
];
179 /* replace .[ .] macros with reference numbers */
180 static void refer_cite(char *s
)
187 while (!nid
|| multiref
) {
189 while (*s
&& strchr(" \t\n,", (unsigned char) *s
))
191 while (*s
&& !strchr(" \t\n,]", (unsigned char) *s
))
194 if (!strcmp("$LIST$", label
)) {
198 id
[nid
] = refer_seen(label
);
200 fprintf(stderr
, "refer: <%s> not found\n", label
);
203 if (!*s
|| *s
== '\n' || *s
== ']')
206 /* sort references for cleaner reference intervals */
207 qsort(id
, nid
, sizeof(id
[0]), (void *) intcmp
);
211 /* reading reference intervals */
212 while (i
< nid
&& id
[i
] == id
[i
- 1] + 1)
215 sprintf(msg
+ strlen(msg
), ",");
217 sprintf(msg
+ strlen(msg
), "%d", id
[beg
]);
219 sprintf(msg
+ strlen(msg
), "%d%s%d",
220 id
[beg
], beg
< i
- 2 ? "\\-" : ",", id
[i
- 1]);
224 for (i
= 0; i
< nid
; i
++)
225 ref_ins(cites
[id
[i
]], ++inserted
);
228 static int startswith(char *r
, char *s
)
236 static int slen(char *s
, int delim
)
238 char *r
= strchr(s
, delim
);
239 return r
? r
- s
: strchr(s
, '\0') - s
;
242 static void refer(void)
246 sprintf(refsig
, "*[%s ", refmac
? refmac
: "cite");
247 while ((ln
= lnget())) {
248 if (ln
[0] == '.' && ln
[1] == '[') {
249 lnput(ln
+ 2, slen(ln
+ 2, '\n'));
250 if ((ln
= lnget())) {
252 while (ln
&& (ln
[0] != '.' || ln
[1] != ']'))
261 while ((r
= strchr(r
, '\\'))) {
263 if (!startswith(r
, refsig
))
277 "Usage neatrefer [options] <input >output\n"
279 "\t-p bib \tspecify the database file\n"
280 "\t-e \taccumulate references\n"
281 "\t-m \tmerge multiple references in a single .[/.] block\n"
282 "\t-o xy \tinline citation macro (\\*[xy label])\n";
284 int main(int argc
, char *argv
[])
287 for (i
= 1; i
< argc
; i
++) {
288 switch (argv
[i
][0] == '-' ? argv
[i
][1] : 'h') {
296 refdb
= fopen(argv
[i
][2] ? argv
[i
] + 2 : argv
[++i
], "r");
304 refmac
= argv
[i
][2] ? argv
[i
] + 2 : argv
[++i
];
312 for (i
= 0; i
< refs_n
; i
++)
313 for (j
= 0; j
< LEN(refs
[i
].keys
); j
++)
315 free(refs
[i
].keys
[j
]);
316 for (i
= 0; i
< refs_n
; i
++)
317 for (j
= 0; j
< LEN(refs
[i
].auth
); j
++)
319 free(refs
[i
].auth
[j
]);