]> git.cameronkatri.com Git - mandoc.git/blob - roff.c
Removed superfluous structures from rofftree.
[mandoc.git] / roff.c
1 /* $Id: roff.c,v 1.15 2008/11/28 15:25:49 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19 #include <assert.h>
20 #include <ctype.h>
21 #include <err.h>
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <time.h>
27
28 #include "libmdocml.h"
29 #include "private.h"
30
31 /* FIXME: warn if Pp occurs before/after Sh etc. (see mdoc.samples). */
32
33 /* FIXME: warn about "X section only" macros. */
34
35 /* FIXME: warn about empty lists. */
36
37 /* FIXME: ; : } ) (etc.) after text macros? */
38
39 /* FIXME: NAME section needs specific elements. */
40
41 #define ROFF_MAXARG 32
42
43 enum roffd {
44 ROFF_ENTER = 0,
45 ROFF_EXIT
46 };
47
48 enum rofftype {
49 ROFF_COMMENT,
50 ROFF_TEXT,
51 ROFF_LAYOUT,
52 ROFF_SPECIAL
53 };
54
55 #define ROFFCALL_ARGS \
56 int tok, struct rofftree *tree, \
57 const char *argv[], enum roffd type
58
59 struct rofftree;
60
61 struct rofftok {
62 int (*cb)(ROFFCALL_ARGS); /* Callback. */
63 const int *args; /* Args (or NULL). */
64 const int *parents;
65 const int *children;
66 int ctx;
67 enum rofftype type; /* Type of macro. */
68 int flags;
69 #define ROFF_PARSED (1 << 0) /* "Parsed". */
70 #define ROFF_CALLABLE (1 << 1) /* "Callable". */
71 #define ROFF_QUOTES (1 << 2) /* Quoted args. */
72 #define ROFF_SHALLOW (1 << 3) /* Nesting block. */
73 };
74
75 struct roffarg {
76 int flags;
77 #define ROFF_VALUE (1 << 0) /* Has a value. */
78 };
79
80 struct roffnode {
81 int tok; /* Token id. */
82 struct roffnode *parent; /* Parent (or NULL). */
83 };
84
85 struct rofftree {
86 struct roffnode *last; /* Last parsed node. */
87 char *cur;
88
89 time_t date; /* `Dd' results. */
90 char os[64]; /* `Os' results. */
91 char title[64]; /* `Dt' results. */
92 char section[64]; /* `Dt' results. */
93 char volume[64]; /* `Dt' results. */
94
95 int state;
96 #define ROFF_PRELUDE (1 << 1) /* In roff prelude. */
97 #define ROFF_PRELUDE_Os (1 << 2) /* `Os' is parsed. */
98 #define ROFF_PRELUDE_Dt (1 << 3) /* `Dt' is parsed. */
99 #define ROFF_PRELUDE_Dd (1 << 4) /* `Dd' is parsed. */
100 #define ROFF_BODY (1 << 5) /* In roff body. */
101
102 struct roffcb cb;
103 void *arg;
104 };
105
106 static int roff_Dd(ROFFCALL_ARGS);
107 static int roff_Dt(ROFFCALL_ARGS);
108 static int roff_Os(ROFFCALL_ARGS);
109
110 static int roff_layout(ROFFCALL_ARGS);
111 static int roff_text(ROFFCALL_ARGS);
112 static int roff_comment(ROFFCALL_ARGS);
113 static int roff_close(ROFFCALL_ARGS);
114 static int roff_special(ROFFCALL_ARGS);
115
116 static struct roffnode *roffnode_new(int, struct rofftree *);
117 static void roffnode_free(struct rofftree *);
118
119 static void roff_warn(const struct rofftree *,
120 const char *, char *, ...);
121 static void roff_err(const struct rofftree *,
122 const char *, char *, ...);
123
124 static int roffscan(int, const int *);
125 static int rofffindtok(const char *);
126 static int rofffindarg(const char *);
127 static int rofffindcallable(const char *);
128 static int roffargs(const struct rofftree *,
129 int, char *, char **);
130 static int roffargok(int, int);
131 static int roffnextopt(const struct rofftree *,
132 int, const char ***, char **);
133 static int roffparse(struct rofftree *, char *, size_t);
134 static int textparse(const struct rofftree *,
135 const char *, size_t);
136
137
138 static const int roffarg_An[] = { ROFF_Split, ROFF_Nosplit,
139 ROFF_ARGMAX };
140 static const int roffarg_Bd[] = { ROFF_Ragged, ROFF_Unfilled,
141 ROFF_Literal, ROFF_File, ROFF_Offset, ROFF_Filled,
142 ROFF_Compact, ROFF_ARGMAX };
143 static const int roffarg_Bk[] = { ROFF_Words, ROFF_ARGMAX };
144 static const int roffarg_Ex[] = { ROFF_Std, ROFF_ARGMAX };
145 static const int roffarg_Rv[] = { ROFF_Std, ROFF_ARGMAX };
146 static const int roffarg_Bl[] = { ROFF_Bullet, ROFF_Dash,
147 ROFF_Hyphen, ROFF_Item, ROFF_Enum, ROFF_Tag, ROFF_Diag,
148 ROFF_Hang, ROFF_Ohang, ROFF_Inset, ROFF_Column, ROFF_Offset,
149 ROFF_Width, ROFF_Compact, ROFF_ARGMAX };
150 static const int roffarg_St[] = {
151 ROFF_p1003_1_88, ROFF_p1003_1_90, ROFF_p1003_1_96,
152 ROFF_p1003_1_2001, ROFF_p1003_1_2004, ROFF_p1003_1,
153 ROFF_p1003_1b, ROFF_p1003_1b_93, ROFF_p1003_1c_95,
154 ROFF_p1003_1g_2000, ROFF_p1003_2_92, ROFF_p1387_2_95,
155 ROFF_p1003_2, ROFF_p1387_2, ROFF_isoC_90, ROFF_isoC_amd1,
156 ROFF_isoC_tcor1, ROFF_isoC_tcor2, ROFF_isoC_99, ROFF_ansiC,
157 ROFF_ansiC_89, ROFF_ansiC_99, ROFF_ieee754, ROFF_iso8802_3,
158 ROFF_xpg3, ROFF_xpg4, ROFF_xpg4_2, ROFF_xpg4_3, ROFF_xbd5,
159 ROFF_xcu5, ROFF_xsh5, ROFF_xns5, ROFF_xns5_2d2_0,
160 ROFF_xcurses4_2, ROFF_susv2, ROFF_susv3, ROFF_svid4,
161 ROFF_ARGMAX };
162
163 static const int roffchild_Bl[] = { ROFF_It, ROFF_El, ROFF_MAX };
164 static const int roffchild_Fo[] = { ROFF_Fa, ROFF_Fc, ROFF_MAX };
165 static const int roffchild_Oo[] = { ROFF_Op, ROFF_Oc, ROFF_MAX };
166 static const int roffchild_Rs[] = { ROFF_Re, ROFF__A, ROFF__B,
167 ROFF__D, ROFF__I, ROFF__J, ROFF__N, ROFF__O, ROFF__P,
168 ROFF__R, ROFF__T, ROFF__V, ROFF_MAX };
169
170 static const int roffparent_El[] = { ROFF_Bl, ROFF_It, ROFF_MAX };
171 static const int roffparent_Fc[] = { ROFF_Fo, ROFF_Fa, ROFF_MAX };
172 static const int roffparent_Oc[] = { ROFF_Oo, ROFF_Oc, ROFF_MAX };
173 static const int roffparent_It[] = { ROFF_Bl, ROFF_It, ROFF_MAX };
174 static const int roffparent_Re[] = { ROFF_Rs, ROFF_MAX };
175
176 /* Table of all known tokens. */
177 static const struct rofftok tokens[ROFF_MAX] = {
178 {roff_comment, NULL, NULL, NULL, 0, ROFF_COMMENT, 0 }, /* \" */
179 { roff_Dd, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Dd */
180 { roff_Dt, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Dt */
181 { roff_Os, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_QUOTES }, /* Os */
182 { roff_layout, NULL, NULL, NULL, ROFF_Sh, ROFF_LAYOUT, ROFF_PARSED }, /* Sh */
183 { roff_layout, NULL, NULL, NULL, ROFF_Ss, ROFF_LAYOUT, ROFF_PARSED }, /* Ss */
184 { roff_text, NULL, NULL, NULL, ROFF_Pp, ROFF_TEXT, 0 }, /* Pp */
185 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* D1 */
186 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Dl */
187 { roff_layout, roffarg_Bd, NULL, NULL, 0, ROFF_LAYOUT, 0 }, /* Bd */
188 { roff_close, NULL, NULL, NULL, ROFF_Bd, ROFF_LAYOUT, 0 }, /* Ed */
189 { roff_layout, roffarg_Bl, NULL, roffchild_Bl, 0, ROFF_LAYOUT, 0 }, /* Bl */
190 { roff_close, NULL, roffparent_El, NULL, ROFF_Bl, ROFF_LAYOUT, 0 }, /* El */
191 { roff_layout, NULL, roffparent_It, NULL, ROFF_It, ROFF_LAYOUT, ROFF_SHALLOW }, /* It */
192 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Ad */
193 { roff_text, roffarg_An, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* An */
194 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Ar */
195 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_QUOTES }, /* Cd */ /* XXX man.4 only */
196 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Cm */
197 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Dv */ /* XXX needs arg */
198 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Er */ /* XXX needs arg */
199 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Ev */ /* XXX needs arg */
200 { roff_text, roffarg_Ex, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Ex */
201 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Fa */ /* XXX needs arg */
202 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Fd */
203 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Fl */
204 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Fn */ /* XXX needs arg */ /* FIXME */
205 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Ft */
206 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Ic */ /* XXX needs arg */
207 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* In */
208 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Li */
209 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_QUOTES }, /* Nd */
210 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Nm */ /* FIXME */
211 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Op */
212 { NULL, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Ot */ /* XXX deprecated */
213 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Pa */
214 { roff_text, roffarg_Rv, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Rv */
215 { roff_text, roffarg_St, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* St */
216 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Va */
217 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Vt */ /* XXX needs arg */
218 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Xr */ /* XXX needs arg */
219 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* %A */
220 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE}, /* %B */
221 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* %D */
222 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE}, /* %I */
223 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE}, /* %J */
224 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* %N */
225 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* %O */
226 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* %P */
227 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* %R */
228 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* %T */
229 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* %V */
230 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Ac */
231 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Ao */
232 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Aq */
233 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* At */ /* XXX at most 2 args */
234 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Bc */
235 { NULL, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Bf */ /* FIXME */
236 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Bo */
237 { NULL, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Bq */
238 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Bsx */
239 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Bx */
240 {roff_special, NULL, NULL, NULL, 0, ROFF_SPECIAL, 0 }, /* Db */
241 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Dc */
242 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Do */
243 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Dq */
244 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Ec */
245 { NULL, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Ef */ /* FIXME */
246 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Em */ /* XXX needs arg */
247 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Eo */
248 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Fx */
249 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Ms */
250 { NULL, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* No */
251 { NULL, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Ns */
252 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Nx */
253 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Ox */
254 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Pc */
255 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Pf */
256 { roff_text, NULL, NULL, NULL, 0, ROFF_LAYOUT, ROFF_PARSED | ROFF_CALLABLE }, /* Po */
257 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Pq */
258 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Qc */
259 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Ql */
260 { roff_layout, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Qo */
261 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Qq */
262 { roff_close, NULL, roffparent_Re, NULL, ROFF_Rs, ROFF_LAYOUT, 0 }, /* Re */
263 { roff_layout, NULL, NULL, roffchild_Rs, 0, ROFF_LAYOUT, 0 }, /* Rs */
264 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Sc */
265 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* So */
266 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Sq */
267 {roff_special, NULL, NULL, NULL, 0, ROFF_SPECIAL, 0 }, /* Sm */
268 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Sx */
269 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Sy */
270 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Tn */
271 { roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Ux */
272 { NULL, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Xc */
273 { NULL, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Xo */
274 { roff_layout, NULL, NULL, roffchild_Fo, 0, ROFF_LAYOUT, 0 }, /* Fo */
275 { roff_close, NULL, roffparent_Fc, NULL, ROFF_Fo, ROFF_LAYOUT, 0 }, /* Fc */
276 { roff_layout, NULL, NULL, roffchild_Oo, 0, ROFF_LAYOUT, 0 }, /* Oo */
277 { roff_close, NULL, roffparent_Oc, NULL, ROFF_Oo, ROFF_LAYOUT, 0 }, /* Oc */
278 { roff_layout, roffarg_Bk, NULL, NULL, 0, ROFF_LAYOUT, 0 }, /* Bk */
279 { roff_close, NULL, NULL, NULL, ROFF_Bk, ROFF_LAYOUT, 0 }, /* Ek */
280 };
281
282 /* Table of all known token arguments. */
283 static const int tokenargs[ROFF_ARGMAX] = {
284 0, 0, 0, 0,
285 0, ROFF_VALUE, ROFF_VALUE, 0,
286 0, 0, 0, 0,
287 0, 0, 0, 0,
288 0, 0, 0, 0,
289 0, 0, 0, 0,
290 0, 0, 0, 0,
291 0, 0, 0, 0,
292 0, 0, 0, 0,
293 0, 0, 0, 0,
294 0, 0, 0, 0,
295 0, 0, 0, 0,
296 0, 0, 0, 0,
297 0, 0, 0, 0,
298 0, 0, 0, 0,
299 };
300
301 const char *const toknamesp[ROFF_MAX] = {
302 "\\\"", "Dd", "Dt", "Os",
303 "Sh", "Ss", "Pp", "D1",
304 "Dl", "Bd", "Ed", "Bl",
305 "El", "It", "Ad", "An",
306 "Ar", "Cd", "Cm", "Dv",
307 "Er", "Ev", "Ex", "Fa",
308 "Fd", "Fl", "Fn", "Ft",
309 "Ic", "In", "Li", "Nd",
310 "Nm", "Op", "Ot", "Pa",
311 "Rv", "St", "Va", "Vt",
312 "Xr", "\%A", "\%B", "\%D",
313 "\%I", "\%J", "\%N", "\%O",
314 "\%P", "\%R", "\%T", "\%V",
315 "Ac", "Ao", "Aq", "At",
316 "Bc", "Bf", "Bo", "Bq",
317 "Bsx", "Bx", "Db", "Dc",
318 "Do", "Dq", "Ec", "Ef",
319 "Em", "Eo", "Fx", "Ms",
320 "No", "Ns", "Nx", "Ox",
321 "Pc", "Pf", "Po", "Pq",
322 "Qc", "Ql", "Qo", "Qq",
323 "Re", "Rs", "Sc", "So",
324 "Sq", "Sm", "Sx", "Sy",
325 "Tn", "Ux", "Xc", "Xo",
326 "Fo", "Fc", "Oo", "Oc",
327 "Bk", "Ek",
328 };
329
330 const char *const tokargnamesp[ROFF_ARGMAX] = {
331 "split", "nosplit", "ragged",
332 "unfilled", "literal", "file",
333 "offset", "bullet", "dash",
334 "hyphen", "item", "enum",
335 "tag", "diag", "hang",
336 "ohang", "inset", "column",
337 "width", "compact", "std",
338 "p1003.1-88", "p1003.1-90", "p1003.1-96",
339 "p1003.1-2001", "p1003.1-2004", "p1003.1",
340 "p1003.1b", "p1003.1b-93", "p1003.1c-95",
341 "p1003.1g-2000", "p1003.2-92", "p1387.2-95",
342 "p1003.2", "p1387.2", "isoC-90",
343 "isoC-amd1", "isoC-tcor1", "isoC-tcor2",
344 "isoC-99", "ansiC", "ansiC-89",
345 "ansiC-99", "ieee754", "iso8802-3",
346 "xpg3", "xpg4", "xpg4.2",
347 "xpg4.3", "xbd5", "xcu5",
348 "xsh5", "xns5", "xns5.2d2.0",
349 "xcurses4.2", "susv2", "susv3",
350 "svid4", "filled", "words",
351 };
352
353 const char *const *toknames = toknamesp;
354 const char *const *tokargnames = tokargnamesp;
355
356
357 int
358 roff_free(struct rofftree *tree, int flush)
359 {
360 int error;
361 struct roffnode *n;
362
363 error = 0;
364
365 for (n = tree->last; n->parent; n = n->parent)
366 if (tokens[n->tok].ctx == 0) {
367 roff_warn(tree, NULL, "closing explicit scope "
368 "of `%s'", toknames[n->tok]);
369 error = 1;
370 }
371
372 if (0 == error && (ROFF_PRELUDE & tree->state)) {
373 roff_warn(tree, NULL, "prelude never finished");
374 error = 1;
375 }
376
377 while (tree->last)
378 roffnode_free(tree);
379
380 free(tree);
381 return(error ? 0 : 1);
382 }
383
384
385 struct rofftree *
386 roff_alloc(const struct roffcb *cb, void *args)
387 {
388 struct rofftree *tree;
389
390 if (NULL == (tree = calloc(1, sizeof(struct rofftree))))
391 err(1, "calloc");
392
393 tree->state = ROFF_PRELUDE;
394 tree->arg = args;
395
396 (void)memcpy(&tree->cb, cb, sizeof(struct roffcb));
397
398 return(tree);
399 }
400
401
402 int
403 roff_engine(struct rofftree *tree, char *buf, size_t sz)
404 {
405
406 tree->cur = NULL;
407
408 if (0 == sz) {
409 roff_warn(tree, buf, "blank line");
410 return(0);
411 } else if ('.' != *buf)
412 return(textparse(tree, buf, sz));
413
414 return(roffparse(tree, buf, sz));
415 }
416
417
418 static int
419 textparse(const struct rofftree *tree, const char *buf, size_t sz)
420 {
421
422 /* Print text. */
423 return(1);
424 }
425
426
427 static int
428 roffargs(const struct rofftree *tree,
429 int tok, char *buf, char **argv)
430 {
431 int i;
432 char *p;
433
434 assert(tok >= 0 && tok < ROFF_MAX);
435 assert('.' == *buf);
436
437 p = buf;
438
439 /* LINTED */
440 for (i = 0; *buf && i < ROFF_MAXARG; i++) {
441 if ('\"' == *buf) {
442 argv[i] = ++buf;
443 while (*buf && '\"' != *buf)
444 buf++;
445 if (0 == *buf) {
446 roff_err(tree, argv[i], "unclosed "
447 "quote in argument "
448 "list for `%s'",
449 toknames[tok]);
450 return(0);
451 }
452 } else {
453 argv[i] = buf++;
454 while (*buf && ! isspace(*buf))
455 buf++;
456 if (0 == *buf)
457 continue;
458 }
459 *buf++ = 0;
460 while (*buf && isspace(*buf))
461 buf++;
462 }
463
464 assert(i > 0);
465 if (ROFF_MAXARG == i && *buf) {
466 roff_err(tree, p, "too many arguments for `%s'", toknames
467 [tok]);
468 return(0);
469 }
470
471 argv[i] = NULL;
472 return(1);
473 }
474
475
476 /* XXX */
477 static int
478 roffscan(int tok, const int *tokv)
479 {
480
481 if (NULL == tokv)
482 return(1);
483
484 for ( ; ROFF_MAX != *tokv; tokv++)
485 if (tok == *tokv)
486 return(1);
487
488 return(0);
489 }
490
491
492 static int
493 roffparse(struct rofftree *tree, char *buf, size_t sz)
494 {
495 int tok, t;
496 struct roffnode *n;
497 char *argv[ROFF_MAXARG];
498 const char **argvp;
499
500 assert(sz > 0);
501
502 if (ROFF_MAX == (tok = rofffindtok(buf + 1))) {
503 roff_err(tree, buf + 1, "bogus line macro");
504 return(0);
505 } else if (NULL == tokens[tok].cb) {
506 roff_err(tree, buf + 1, "unsupported macro `%s'",
507 toknames[tok]);
508 return(0);
509 } else if (ROFF_COMMENT == tokens[tok].type)
510 return(1);
511
512 if ( ! roffargs(tree, tok, buf, argv))
513 return(0);
514
515 argvp = (const char **)argv;
516
517 /*
518 * Prelude macros break some assumptions, so branch now.
519 */
520
521 if (ROFF_PRELUDE & tree->state) {
522 assert(NULL == tree->last);
523 return((*tokens[tok].cb)(tok, tree, argvp, ROFF_ENTER));
524 } else
525 assert(tree->last);
526
527 assert(ROFF_BODY & tree->state);
528
529 /*
530 * First check that our possible parents and parent's possible
531 * children are satisfied.
532 */
533
534 if ( ! roffscan(tree->last->tok, tokens[tok].parents)) {
535 roff_err(tree, *argvp, "`%s' has invalid parent `%s'",
536 toknames[tok],
537 toknames[tree->last->tok]);
538 return(0);
539 }
540
541 if ( ! roffscan(tok, tokens[tree->last->tok].children)) {
542 roff_err(tree, *argvp, "`%s' is invalid child `%s'",
543 toknames[tree->last->tok],
544 toknames[tok]);
545 return(0);
546 }
547
548 /*
549 * Branch if we're not a layout token.
550 */
551
552 if (ROFF_LAYOUT != tokens[tok].type)
553 return((*tokens[tok].cb)(tok, tree, argvp, ROFF_ENTER));
554
555 /*
556 * Check our scope rules.
557 */
558
559 if (0 == tokens[tok].ctx)
560 return((*tokens[tok].cb)(tok, tree, argvp, ROFF_ENTER));
561
562 /*
563 * First consider implicit-end tags, like as follows:
564 * .Sh SECTION 1
565 * .Sh SECTION 2
566 * In this, we want to close the scope of the NAME section. If
567 * there's an intermediary implicit-end tag, such as
568 * .Sh SECTION 1
569 * .Ss Subsection 1
570 * .Sh SECTION 2
571 * then it must be closed as well.
572 */
573
574 if (tok == tokens[tok].ctx) {
575 /*
576 * First search up to the point where we must close.
577 * If one doesn't exist, then we can open a new scope.
578 */
579
580 for (n = tree->last; n; n = n->parent) {
581 assert(0 == tokens[n->tok].ctx ||
582 n->tok == tokens[n->tok].ctx);
583 if (n->tok == tok)
584 break;
585 if (ROFF_SHALLOW & tokens[tok].flags) {
586 n = NULL;
587 break;
588 }
589 }
590
591 /*
592 * Create a new scope, as no previous one exists to
593 * close out.
594 */
595
596 if (NULL == n)
597 return((*tokens[tok].cb)(tok, tree, argvp, ROFF_ENTER));
598
599 /*
600 * Close out all intermediary scoped blocks, then hang
601 * the current scope from our predecessor's parent.
602 */
603
604 do {
605 t = tree->last->tok;
606 if ( ! (*tokens[t].cb)(t, tree, NULL, ROFF_EXIT))
607 return(0);
608 } while (t != tok);
609
610 return((*tokens[tok].cb)(tok, tree, argvp, ROFF_ENTER));
611 }
612
613 /*
614 * Now consider explicit-end tags, where we want to close back
615 * to a specific tag. Example:
616 * .Bl
617 * .It Item.
618 * .El
619 * In this, the `El' tag closes out the scope of `Bl'.
620 */
621
622 assert(tree->last);
623 assert(tok != tokens[tok].ctx && 0 != tokens[tok].ctx);
624
625 /* LINTED */
626 do {
627 t = tree->last->tok;
628 if ( ! (*tokens[t].cb)(t, tree, NULL, ROFF_EXIT))
629 return(0);
630 } while (t != tokens[tok].ctx);
631
632 assert(tree->last);
633 return(1);
634 }
635
636
637 static int
638 rofffindarg(const char *name)
639 {
640 size_t i;
641
642 /* FIXME: use a table, this is slow but ok for now. */
643
644 /* LINTED */
645 for (i = 0; i < ROFF_ARGMAX; i++)
646 /* LINTED */
647 if (0 == strcmp(name, tokargnames[i]))
648 return((int)i);
649
650 return(ROFF_ARGMAX);
651 }
652
653
654 static int
655 rofffindtok(const char *buf)
656 {
657 char token[4];
658 size_t i;
659
660 for (i = 0; *buf && ! isspace(*buf) && i < 3; i++, buf++)
661 token[i] = *buf;
662
663 if (i == 3)
664 return(ROFF_MAX);
665
666 token[i] = 0;
667
668 /* FIXME: use a table, this is slow but ok for now. */
669
670 /* LINTED */
671 for (i = 0; i < ROFF_MAX; i++)
672 /* LINTED */
673 if (0 == strcmp(toknames[i], token))
674 return((int)i);
675
676 return(ROFF_MAX);
677 }
678
679
680 static int
681 rofffindcallable(const char *name)
682 {
683 int c;
684
685 if (ROFF_MAX == (c = rofffindtok(name)))
686 return(ROFF_MAX);
687 assert(c >= 0 && c < ROFF_MAX);
688 return(ROFF_CALLABLE & tokens[c].flags ? c : ROFF_MAX);
689 }
690
691
692 static struct roffnode *
693 roffnode_new(int tokid, struct rofftree *tree)
694 {
695 struct roffnode *p;
696
697 if (NULL == (p = malloc(sizeof(struct roffnode))))
698 err(1, "malloc");
699
700 p->tok = tokid;
701 p->parent = tree->last;
702 tree->last = p;
703
704 return(p);
705 }
706
707
708 static int
709 roffargok(int tokid, int argid)
710 {
711 const int *c;
712
713 if (NULL == (c = tokens[tokid].args))
714 return(0);
715
716 for ( ; ROFF_ARGMAX != *c; c++)
717 if (argid == *c)
718 return(1);
719
720 return(0);
721 }
722
723
724 static void
725 roffnode_free(struct rofftree *tree)
726 {
727 struct roffnode *p;
728
729 assert(tree->last);
730
731 p = tree->last;
732 tree->last = tree->last->parent;
733 free(p);
734 }
735
736
737 static int
738 roffnextopt(const struct rofftree *tree, int tok,
739 const char ***in, char **val)
740 {
741 const char *arg, **argv;
742 int v;
743
744 *val = NULL;
745 argv = *in;
746 assert(argv);
747
748 if (NULL == (arg = *argv))
749 return(-1);
750 if ('-' != *arg)
751 return(-1);
752
753 if (ROFF_ARGMAX == (v = rofffindarg(arg + 1))) {
754 roff_warn(tree, arg, "argument-like parameter `%s' to "
755 "`%s'", &arg[1], toknames[tok]);
756 return(-1);
757 }
758
759 if ( ! roffargok(tok, v)) {
760 roff_warn(tree, arg, "invalid argument parameter `%s' to "
761 "`%s'", tokargnames[v], toknames[tok]);
762 return(-1);
763 }
764
765 if ( ! (ROFF_VALUE & tokenargs[v]))
766 return(v);
767
768 *in = ++argv;
769
770 if (NULL == *argv) {
771 roff_err(tree, arg, "empty value of `%s' for `%s'",
772 tokargnames[v], toknames[tok]);
773 return(ROFF_ARGMAX);
774 }
775
776 return(v);
777 }
778
779
780 /* ARGSUSED */
781 static int
782 roff_Dd(ROFFCALL_ARGS)
783 {
784
785 if (ROFF_BODY & tree->state) {
786 assert( ! (ROFF_PRELUDE & tree->state));
787 assert(ROFF_PRELUDE_Dd & tree->state);
788 return(roff_text(tok, tree, argv, type));
789 }
790
791 assert(ROFF_PRELUDE & tree->state);
792 assert( ! (ROFF_BODY & tree->state));
793
794 if (ROFF_PRELUDE_Dd & tree->state) {
795 roff_err(tree, *argv, "repeated `Dd' in prelude");
796 return(0);
797 } else if (ROFF_PRELUDE_Dt & tree->state) {
798 roff_err(tree, *argv, "out-of-order `Dd' in prelude");
799 return(0);
800 }
801
802 /* TODO: parse date. */
803
804 assert(NULL == tree->last);
805 tree->state |= ROFF_PRELUDE_Dd;
806
807 return(1);
808 }
809
810
811 /* ARGSUSED */
812 static int
813 roff_Dt(ROFFCALL_ARGS)
814 {
815
816 if (ROFF_BODY & tree->state) {
817 assert( ! (ROFF_PRELUDE & tree->state));
818 assert(ROFF_PRELUDE_Dt & tree->state);
819 return(roff_text(tok, tree, argv, type));
820 }
821
822 assert(ROFF_PRELUDE & tree->state);
823 assert( ! (ROFF_BODY & tree->state));
824
825 if ( ! (ROFF_PRELUDE_Dd & tree->state)) {
826 roff_err(tree, *argv, "out-of-order `Dt' in prelude");
827 return(0);
828 } else if (ROFF_PRELUDE_Dt & tree->state) {
829 roff_err(tree, *argv, "repeated `Dt' in prelude");
830 return(0);
831 }
832
833 /* TODO: parse date. */
834
835 assert(NULL == tree->last);
836 tree->state |= ROFF_PRELUDE_Dt;
837
838 return(1);
839 }
840
841
842 /* ARGSUSED */
843 static int
844 roff_Os(ROFFCALL_ARGS)
845 {
846
847 if (ROFF_EXIT == type) {
848 assert(ROFF_PRELUDE_Os & tree->state);
849 return(roff_layout(tok, tree, argv, type));
850 } else if (ROFF_BODY & tree->state) {
851 assert( ! (ROFF_PRELUDE & tree->state));
852 assert(ROFF_PRELUDE_Os & tree->state);
853 return(roff_text(tok, tree, argv, type));
854 }
855
856 assert(ROFF_PRELUDE & tree->state);
857 if ( ! (ROFF_PRELUDE_Dt & tree->state) ||
858 ! (ROFF_PRELUDE_Dd & tree->state)) {
859 roff_err(tree, *argv, "out-of-order `Os' in prelude");
860 return(0);
861 }
862
863 /* TODO: extract OS. */
864
865 tree->state |= ROFF_PRELUDE_Os;
866 tree->state &= ~ROFF_PRELUDE;
867 tree->state |= ROFF_BODY;
868
869 assert(NULL == tree->last);
870
871 return(roff_layout(tok, tree, argv, type));
872 }
873
874
875 /* ARGSUSED */
876 static int
877 roff_layout(ROFFCALL_ARGS)
878 {
879 int i, c, argcp[ROFF_MAXARG];
880 char *v, *argvp[ROFF_MAXARG];
881
882 if (ROFF_PRELUDE & tree->state) {
883 roff_err(tree, *argv, "`%s' disallowed in prelude",
884 toknames[tok]);
885 return(0);
886 }
887
888 if (ROFF_EXIT == type) {
889 roffnode_free(tree);
890 return((*tree->cb.roffblkout)(tree->arg, tok));
891 }
892
893 i = 0;
894 argv++;
895
896 while (-1 != (c = roffnextopt(tree, tok, &argv, &v))) {
897 if (ROFF_ARGMAX == c)
898 return(0);
899
900 argcp[i] = c;
901 argvp[i] = v;
902 i++;
903 argv++;
904 }
905
906 argcp[i] = ROFF_ARGMAX;
907 argvp[i] = NULL;
908
909 if (NULL == roffnode_new(tok, tree))
910 return(0);
911
912 if ( ! (*tree->cb.roffin)(tree->arg, tok, argcp, argvp))
913 return(0);
914
915 if ( ! (ROFF_PARSED & tokens[tok].flags)) {
916 while (*argv) {
917 if ( ! (*tree->cb.roffdata)
918 (tree->arg, *argv++))
919 return(0);
920 }
921
922 if ( ! ((*tree->cb.roffout)(tree->arg, tok)))
923 return(0);
924 return((*tree->cb.roffblkin)(tree->arg, tok));
925 }
926
927 while (*argv) {
928 if (ROFF_MAX != (c = rofffindcallable(*argv))) {
929 if (NULL == tokens[c].cb) {
930 roff_err(tree, *argv, "unsupported "
931 "macro `%s'",
932 toknames[c]);
933 return(0);
934 }
935 if ( ! (*tokens[c].cb)(c, tree, argv, ROFF_ENTER))
936 return(0);
937 break;
938 }
939
940 if ( ! (*tree->cb.roffdata)(tree->arg, *argv++))
941 return(0);
942 }
943
944 if ( ! ((*tree->cb.roffout)(tree->arg, tok)))
945 return(0);
946 return((*tree->cb.roffblkin)(tree->arg, tok));
947 }
948
949
950 /* ARGSUSED */
951 static int
952 roff_text(ROFFCALL_ARGS)
953 {
954 int i, c, argcp[ROFF_MAXARG];
955 char *v, *argvp[ROFF_MAXARG];
956
957 if (ROFF_PRELUDE & tree->state) {
958 roff_err(tree, *argv, "`%s' disallowed in prelude",
959 toknames[tok]);
960 return(0);
961 }
962
963 i = 0;
964 argv++;
965
966 while (-1 != (c = roffnextopt(tree, tok, &argv, &v))) {
967 if (ROFF_ARGMAX == c)
968 return(0);
969
970 argcp[i] = c;
971 argvp[i] = v;
972 i++;
973 argv++;
974 }
975
976 argcp[i] = ROFF_ARGMAX;
977 argvp[i] = NULL;
978
979 if ( ! (*tree->cb.roffin)(tree->arg, tok, argcp, argvp))
980 return(0);
981
982 if ( ! (ROFF_PARSED & tokens[tok].flags)) {
983 while (*argv) {
984 if ( ! (*tree->cb.roffdata)(tree->arg, *argv++))
985 return(0);
986 }
987 return((*tree->cb.roffout)(tree->arg, tok));
988 }
989
990 while (*argv) {
991 if (ROFF_MAX != (c = rofffindcallable(*argv))) {
992 if (NULL == tokens[c].cb) {
993 roff_err(tree, *argv, "unsupported "
994 "macro `%s'",
995 toknames[c]);
996 return(0);
997 }
998 if ( ! (*tokens[c].cb)(c, tree,
999 argv, ROFF_ENTER))
1000 return(0);
1001 break;
1002 }
1003 if ( ! (*tree->cb.roffdata)(tree->arg, *argv++))
1004 return(0);
1005 }
1006
1007 return((*tree->cb.roffout)(tree->arg, tok));
1008 }
1009
1010
1011 /* ARGSUSED */
1012 static int
1013 roff_comment(ROFFCALL_ARGS)
1014 {
1015
1016 return(1);
1017 }
1018
1019
1020 /* ARGSUSED */
1021 static int
1022 roff_close(ROFFCALL_ARGS)
1023 {
1024
1025 return(1);
1026 }
1027
1028
1029 /* ARGSUSED */
1030 static int
1031 roff_special(ROFFCALL_ARGS)
1032 {
1033
1034 return((*tree->cb.roffspecial)(tree->arg, tok));
1035 }
1036
1037
1038 static void
1039 roff_warn(const struct rofftree *tree, const char *pos, char *fmt, ...)
1040 {
1041 va_list ap;
1042 char buf[128];
1043
1044 va_start(ap, fmt);
1045 (void)vsnprintf(buf, sizeof(buf), fmt, ap);
1046 va_end(ap);
1047
1048 (*tree->cb.roffmsg)(tree->arg,
1049 ROFF_WARN, tree->cur, pos, buf);
1050 }
1051
1052
1053 static void
1054 roff_err(const struct rofftree *tree, const char *pos, char *fmt, ...)
1055 {
1056 va_list ap;
1057 char buf[128];
1058
1059 va_start(ap, fmt);
1060 (void)vsnprintf(buf, sizeof(buf), fmt, ap);
1061 va_end(ap);
1062
1063 (*tree->cb.roffmsg)(tree->arg,
1064 ROFF_ERROR, tree->cur, pos, buf);
1065 }