]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/mandoc/roff.c
elfcopy: Provide a size hint when creating the section string table.
[FreeBSD/FreeBSD.git] / contrib / mandoc / roff.c
1 /*      $Id: roff.c,v 1.363 2019/02/06 21:11:43 schwarze Exp $ */
2 /*
3  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
4  * Copyright (c) 2010-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org>
5  *
6  * Permission to use, copy, modify, and 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.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS 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.
17  */
18 #include "config.h"
19
20 #include <sys/types.h>
21
22 #include <assert.h>
23 #include <ctype.h>
24 #include <limits.h>
25 #include <stddef.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "mandoc_aux.h"
32 #include "mandoc_ohash.h"
33 #include "mandoc.h"
34 #include "roff.h"
35 #include "mandoc_parse.h"
36 #include "libmandoc.h"
37 #include "roff_int.h"
38 #include "tbl_parse.h"
39 #include "eqn_parse.h"
40
41 /*
42  * ASCII_ESC is used to signal from roff_getarg() to roff_expand()
43  * that an escape sequence resulted from copy-in processing and
44  * needs to be checked or interpolated.  As it is used nowhere
45  * else, it is defined here rather than in a header file.
46  */
47 #define ASCII_ESC       27
48
49 /* Maximum number of string expansions per line, to break infinite loops. */
50 #define EXPAND_LIMIT    1000
51
52 /* Types of definitions of macros and strings. */
53 #define ROFFDEF_USER    (1 << 1)  /* User-defined. */
54 #define ROFFDEF_PRE     (1 << 2)  /* Predefined. */
55 #define ROFFDEF_REN     (1 << 3)  /* Renamed standard macro. */
56 #define ROFFDEF_STD     (1 << 4)  /* mdoc(7) or man(7) macro. */
57 #define ROFFDEF_ANY     (ROFFDEF_USER | ROFFDEF_PRE | \
58                          ROFFDEF_REN | ROFFDEF_STD)
59 #define ROFFDEF_UNDEF   (1 << 5)  /* Completely undefined. */
60
61 /* --- data types --------------------------------------------------------- */
62
63 /*
64  * An incredibly-simple string buffer.
65  */
66 struct  roffstr {
67         char            *p; /* nil-terminated buffer */
68         size_t           sz; /* saved strlen(p) */
69 };
70
71 /*
72  * A key-value roffstr pair as part of a singly-linked list.
73  */
74 struct  roffkv {
75         struct roffstr   key;
76         struct roffstr   val;
77         struct roffkv   *next; /* next in list */
78 };
79
80 /*
81  * A single number register as part of a singly-linked list.
82  */
83 struct  roffreg {
84         struct roffstr   key;
85         int              val;
86         int              step;
87         struct roffreg  *next;
88 };
89
90 /*
91  * Association of request and macro names with token IDs.
92  */
93 struct  roffreq {
94         enum roff_tok    tok;
95         char             name[];
96 };
97
98 /*
99  * A macro processing context.
100  * More than one is needed when macro calls are nested.
101  */
102 struct  mctx {
103         char            **argv;
104         int              argc;
105         int              argsz;
106 };
107
108 struct  roff {
109         struct roff_man *man; /* mdoc or man parser */
110         struct roffnode *last; /* leaf of stack */
111         struct mctx     *mstack; /* stack of macro contexts */
112         int             *rstack; /* stack of inverted `ie' values */
113         struct ohash    *reqtab; /* request lookup table */
114         struct roffreg  *regtab; /* number registers */
115         struct roffkv   *strtab; /* user-defined strings & macros */
116         struct roffkv   *rentab; /* renamed strings & macros */
117         struct roffkv   *xmbtab; /* multi-byte trans table (`tr') */
118         struct roffstr  *xtab; /* single-byte trans table (`tr') */
119         const char      *current_string; /* value of last called user macro */
120         struct tbl_node *first_tbl; /* first table parsed */
121         struct tbl_node *last_tbl; /* last table parsed */
122         struct tbl_node *tbl; /* current table being parsed */
123         struct eqn_node *last_eqn; /* equation parser */
124         struct eqn_node *eqn; /* active equation parser */
125         int              eqn_inline; /* current equation is inline */
126         int              options; /* parse options */
127         int              mstacksz; /* current size of mstack */
128         int              mstackpos; /* position in mstack */
129         int              rstacksz; /* current size limit of rstack */
130         int              rstackpos; /* position in rstack */
131         int              format; /* current file in mdoc or man format */
132         char             control; /* control character */
133         char             escape; /* escape character */
134 };
135
136 struct  roffnode {
137         enum roff_tok    tok; /* type of node */
138         struct roffnode *parent; /* up one in stack */
139         int              line; /* parse line */
140         int              col; /* parse col */
141         char            *name; /* node name, e.g. macro name */
142         char            *end; /* end-rules: custom token */
143         int              endspan; /* end-rules: next-line or infty */
144         int              rule; /* current evaluation rule */
145 };
146
147 #define ROFF_ARGS        struct roff *r, /* parse ctx */ \
148                          enum roff_tok tok, /* tok of macro */ \
149                          struct buf *buf, /* input buffer */ \
150                          int ln, /* parse line */ \
151                          int ppos, /* original pos in buffer */ \
152                          int pos, /* current pos in buffer */ \
153                          int *offs /* reset offset of buffer data */
154
155 typedef int (*roffproc)(ROFF_ARGS);
156
157 struct  roffmac {
158         roffproc         proc; /* process new macro */
159         roffproc         text; /* process as child text of macro */
160         roffproc         sub; /* process as child of macro */
161         int              flags;
162 #define ROFFMAC_STRUCT  (1 << 0) /* always interpret */
163 };
164
165 struct  predef {
166         const char      *name; /* predefined input name */
167         const char      *str; /* replacement symbol */
168 };
169
170 #define PREDEF(__name, __str) \
171         { (__name), (__str) },
172
173 /* --- function prototypes ------------------------------------------------ */
174
175 static  int              roffnode_cleanscope(struct roff *);
176 static  int              roffnode_pop(struct roff *);
177 static  void             roffnode_push(struct roff *, enum roff_tok,
178                                 const char *, int, int);
179 static  void             roff_addtbl(struct roff_man *, int, struct tbl_node *);
180 static  int              roff_als(ROFF_ARGS);
181 static  int              roff_block(ROFF_ARGS);
182 static  int              roff_block_text(ROFF_ARGS);
183 static  int              roff_block_sub(ROFF_ARGS);
184 static  int              roff_cblock(ROFF_ARGS);
185 static  int              roff_cc(ROFF_ARGS);
186 static  int              roff_ccond(struct roff *, int, int);
187 static  int              roff_char(ROFF_ARGS);
188 static  int              roff_cond(ROFF_ARGS);
189 static  int              roff_cond_text(ROFF_ARGS);
190 static  int              roff_cond_sub(ROFF_ARGS);
191 static  int              roff_ds(ROFF_ARGS);
192 static  int              roff_ec(ROFF_ARGS);
193 static  int              roff_eo(ROFF_ARGS);
194 static  int              roff_eqndelim(struct roff *, struct buf *, int);
195 static  int              roff_evalcond(struct roff *r, int, char *, int *);
196 static  int              roff_evalnum(struct roff *, int,
197                                 const char *, int *, int *, int);
198 static  int              roff_evalpar(struct roff *, int,
199                                 const char *, int *, int *, int);
200 static  int              roff_evalstrcond(const char *, int *);
201 static  int              roff_expand(struct roff *, struct buf *,
202                                 int, int, char);
203 static  void             roff_free1(struct roff *);
204 static  void             roff_freereg(struct roffreg *);
205 static  void             roff_freestr(struct roffkv *);
206 static  size_t           roff_getname(struct roff *, char **, int, int);
207 static  int              roff_getnum(const char *, int *, int *, int);
208 static  int              roff_getop(const char *, int *, char *);
209 static  int              roff_getregn(struct roff *,
210                                 const char *, size_t, char);
211 static  int              roff_getregro(const struct roff *,
212                                 const char *name);
213 static  const char      *roff_getstrn(struct roff *,
214                                 const char *, size_t, int *);
215 static  int              roff_hasregn(const struct roff *,
216                                 const char *, size_t);
217 static  int              roff_insec(ROFF_ARGS);
218 static  int              roff_it(ROFF_ARGS);
219 static  int              roff_line_ignore(ROFF_ARGS);
220 static  void             roff_man_alloc1(struct roff_man *);
221 static  void             roff_man_free1(struct roff_man *);
222 static  int              roff_manyarg(ROFF_ARGS);
223 static  int              roff_noarg(ROFF_ARGS);
224 static  int              roff_nop(ROFF_ARGS);
225 static  int              roff_nr(ROFF_ARGS);
226 static  int              roff_onearg(ROFF_ARGS);
227 static  enum roff_tok    roff_parse(struct roff *, char *, int *,
228                                 int, int);
229 static  int              roff_parsetext(struct roff *, struct buf *,
230                                 int, int *);
231 static  int              roff_renamed(ROFF_ARGS);
232 static  int              roff_return(ROFF_ARGS);
233 static  int              roff_rm(ROFF_ARGS);
234 static  int              roff_rn(ROFF_ARGS);
235 static  int              roff_rr(ROFF_ARGS);
236 static  void             roff_setregn(struct roff *, const char *,
237                                 size_t, int, char, int);
238 static  void             roff_setstr(struct roff *,
239                                 const char *, const char *, int);
240 static  void             roff_setstrn(struct roffkv **, const char *,
241                                 size_t, const char *, size_t, int);
242 static  int              roff_shift(ROFF_ARGS);
243 static  int              roff_so(ROFF_ARGS);
244 static  int              roff_tr(ROFF_ARGS);
245 static  int              roff_Dd(ROFF_ARGS);
246 static  int              roff_TE(ROFF_ARGS);
247 static  int              roff_TS(ROFF_ARGS);
248 static  int              roff_EQ(ROFF_ARGS);
249 static  int              roff_EN(ROFF_ARGS);
250 static  int              roff_T_(ROFF_ARGS);
251 static  int              roff_unsupp(ROFF_ARGS);
252 static  int              roff_userdef(ROFF_ARGS);
253
254 /* --- constant data ------------------------------------------------------ */
255
256 #define ROFFNUM_SCALE   (1 << 0)  /* Honour scaling in roff_getnum(). */
257 #define ROFFNUM_WHITE   (1 << 1)  /* Skip whitespace in roff_evalnum(). */
258
259 const char *__roff_name[MAN_MAX + 1] = {
260         "br",           "ce",           "fi",           "ft",
261         "ll",           "mc",           "nf",
262         "po",           "rj",           "sp",
263         "ta",           "ti",           NULL,
264         "ab",           "ad",           "af",           "aln",
265         "als",          "am",           "am1",          "ami",
266         "ami1",         "as",           "as1",          "asciify",
267         "backtrace",    "bd",           "bleedat",      "blm",
268         "box",          "boxa",         "bp",           "BP",
269         "break",        "breakchar",    "brnl",         "brp",
270         "brpnl",        "c2",           "cc",
271         "cf",           "cflags",       "ch",           "char",
272         "chop",         "class",        "close",        "CL",
273         "color",        "composite",    "continue",     "cp",
274         "cropat",       "cs",           "cu",           "da",
275         "dch",          "Dd",           "de",           "de1",
276         "defcolor",     "dei",          "dei1",         "device",
277         "devicem",      "di",           "do",           "ds",
278         "ds1",          "dwh",          "dt",           "ec",
279         "ecr",          "ecs",          "el",           "em",
280         "EN",           "eo",           "EP",           "EQ",
281         "errprint",     "ev",           "evc",          "ex",
282         "fallback",     "fam",          "fc",           "fchar",
283         "fcolor",       "fdeferlig",    "feature",      "fkern",
284         "fl",           "flig",         "fp",           "fps",
285         "fschar",       "fspacewidth",  "fspecial",     "ftr",
286         "fzoom",        "gcolor",       "hc",           "hcode",
287         "hidechar",     "hla",          "hlm",          "hpf",
288         "hpfa",         "hpfcode",      "hw",           "hy",
289         "hylang",       "hylen",        "hym",          "hypp",
290         "hys",          "ie",           "if",           "ig",
291         "index",        "it",           "itc",          "IX",
292         "kern",         "kernafter",    "kernbefore",   "kernpair",
293         "lc",           "lc_ctype",     "lds",          "length",
294         "letadj",       "lf",           "lg",           "lhang",
295         "linetabs",     "lnr",          "lnrf",         "lpfx",
296         "ls",           "lsm",          "lt",
297         "mediasize",    "minss",        "mk",           "mso",
298         "na",           "ne",           "nh",           "nhychar",
299         "nm",           "nn",           "nop",          "nr",
300         "nrf",          "nroff",        "ns",           "nx",
301         "open",         "opena",        "os",           "output",
302         "padj",         "papersize",    "pc",           "pev",
303         "pi",           "PI",           "pl",           "pm",
304         "pn",           "pnr",          "ps",
305         "psbb",         "pshape",       "pso",          "ptr",
306         "pvs",          "rchar",        "rd",           "recursionlimit",
307         "return",       "rfschar",      "rhang",
308         "rm",           "rn",           "rnn",          "rr",
309         "rs",           "rt",           "schar",        "sentchar",
310         "shc",          "shift",        "sizes",        "so",
311         "spacewidth",   "special",      "spreadwarn",   "ss",
312         "sty",          "substring",    "sv",           "sy",
313         "T&",           "tc",           "TE",
314         "TH",           "tkf",          "tl",
315         "tm",           "tm1",          "tmc",          "tr",
316         "track",        "transchar",    "trf",          "trimat",
317         "trin",         "trnt",         "troff",        "TS",
318         "uf",           "ul",           "unformat",     "unwatch",
319         "unwatchn",     "vpt",          "vs",           "warn",
320         "warnscale",    "watch",        "watchlength",  "watchn",
321         "wh",           "while",        "write",        "writec",
322         "writem",       "xflag",        ".",            NULL,
323         NULL,           "text",
324         "Dd",           "Dt",           "Os",           "Sh",
325         "Ss",           "Pp",           "D1",           "Dl",
326         "Bd",           "Ed",           "Bl",           "El",
327         "It",           "Ad",           "An",           "Ap",
328         "Ar",           "Cd",           "Cm",           "Dv",
329         "Er",           "Ev",           "Ex",           "Fa",
330         "Fd",           "Fl",           "Fn",           "Ft",
331         "Ic",           "In",           "Li",           "Nd",
332         "Nm",           "Op",           "Ot",           "Pa",
333         "Rv",           "St",           "Va",           "Vt",
334         "Xr",           "%A",           "%B",           "%D",
335         "%I",           "%J",           "%N",           "%O",
336         "%P",           "%R",           "%T",           "%V",
337         "Ac",           "Ao",           "Aq",           "At",
338         "Bc",           "Bf",           "Bo",           "Bq",
339         "Bsx",          "Bx",           "Db",           "Dc",
340         "Do",           "Dq",           "Ec",           "Ef",
341         "Em",           "Eo",           "Fx",           "Ms",
342         "No",           "Ns",           "Nx",           "Ox",
343         "Pc",           "Pf",           "Po",           "Pq",
344         "Qc",           "Ql",           "Qo",           "Qq",
345         "Re",           "Rs",           "Sc",           "So",
346         "Sq",           "Sm",           "Sx",           "Sy",
347         "Tn",           "Ux",           "Xc",           "Xo",
348         "Fo",           "Fc",           "Oo",           "Oc",
349         "Bk",           "Ek",           "Bt",           "Hf",
350         "Fr",           "Ud",           "Lb",           "Lp",
351         "Lk",           "Mt",           "Brq",          "Bro",
352         "Brc",          "%C",           "Es",           "En",
353         "Dx",           "%Q",           "%U",           "Ta",
354         NULL,
355         "TH",           "SH",           "SS",           "TP",
356         "TQ",
357         "LP",           "PP",           "P",            "IP",
358         "HP",           "SM",           "SB",           "BI",
359         "IB",           "BR",           "RB",           "R",
360         "B",            "I",            "IR",           "RI",
361         "RE",           "RS",           "DT",           "UC",
362         "PD",           "AT",           "in",
363         "SY",           "YS",           "OP",
364         "EX",           "EE",           "UR",
365         "UE",           "MT",           "ME",           NULL
366 };
367 const   char *const *roff_name = __roff_name;
368
369 static  struct roffmac   roffs[TOKEN_NONE] = {
370         { roff_noarg, NULL, NULL, 0 },  /* br */
371         { roff_onearg, NULL, NULL, 0 },  /* ce */
372         { roff_noarg, NULL, NULL, 0 },  /* fi */
373         { roff_onearg, NULL, NULL, 0 },  /* ft */
374         { roff_onearg, NULL, NULL, 0 },  /* ll */
375         { roff_onearg, NULL, NULL, 0 },  /* mc */
376         { roff_noarg, NULL, NULL, 0 },  /* nf */
377         { roff_onearg, NULL, NULL, 0 },  /* po */
378         { roff_onearg, NULL, NULL, 0 },  /* rj */
379         { roff_onearg, NULL, NULL, 0 },  /* sp */
380         { roff_manyarg, NULL, NULL, 0 },  /* ta */
381         { roff_onearg, NULL, NULL, 0 },  /* ti */
382         { NULL, NULL, NULL, 0 },  /* ROFF_MAX */
383         { roff_unsupp, NULL, NULL, 0 },  /* ab */
384         { roff_line_ignore, NULL, NULL, 0 },  /* ad */
385         { roff_line_ignore, NULL, NULL, 0 },  /* af */
386         { roff_unsupp, NULL, NULL, 0 },  /* aln */
387         { roff_als, NULL, NULL, 0 },  /* als */
388         { roff_block, roff_block_text, roff_block_sub, 0 },  /* am */
389         { roff_block, roff_block_text, roff_block_sub, 0 },  /* am1 */
390         { roff_block, roff_block_text, roff_block_sub, 0 },  /* ami */
391         { roff_block, roff_block_text, roff_block_sub, 0 },  /* ami1 */
392         { roff_ds, NULL, NULL, 0 },  /* as */
393         { roff_ds, NULL, NULL, 0 },  /* as1 */
394         { roff_unsupp, NULL, NULL, 0 },  /* asciify */
395         { roff_line_ignore, NULL, NULL, 0 },  /* backtrace */
396         { roff_line_ignore, NULL, NULL, 0 },  /* bd */
397         { roff_line_ignore, NULL, NULL, 0 },  /* bleedat */
398         { roff_unsupp, NULL, NULL, 0 },  /* blm */
399         { roff_unsupp, NULL, NULL, 0 },  /* box */
400         { roff_unsupp, NULL, NULL, 0 },  /* boxa */
401         { roff_line_ignore, NULL, NULL, 0 },  /* bp */
402         { roff_unsupp, NULL, NULL, 0 },  /* BP */
403         { roff_unsupp, NULL, NULL, 0 },  /* break */
404         { roff_line_ignore, NULL, NULL, 0 },  /* breakchar */
405         { roff_line_ignore, NULL, NULL, 0 },  /* brnl */
406         { roff_noarg, NULL, NULL, 0 },  /* brp */
407         { roff_line_ignore, NULL, NULL, 0 },  /* brpnl */
408         { roff_unsupp, NULL, NULL, 0 },  /* c2 */
409         { roff_cc, NULL, NULL, 0 },  /* cc */
410         { roff_insec, NULL, NULL, 0 },  /* cf */
411         { roff_line_ignore, NULL, NULL, 0 },  /* cflags */
412         { roff_line_ignore, NULL, NULL, 0 },  /* ch */
413         { roff_char, NULL, NULL, 0 },  /* char */
414         { roff_unsupp, NULL, NULL, 0 },  /* chop */
415         { roff_line_ignore, NULL, NULL, 0 },  /* class */
416         { roff_insec, NULL, NULL, 0 },  /* close */
417         { roff_unsupp, NULL, NULL, 0 },  /* CL */
418         { roff_line_ignore, NULL, NULL, 0 },  /* color */
419         { roff_unsupp, NULL, NULL, 0 },  /* composite */
420         { roff_unsupp, NULL, NULL, 0 },  /* continue */
421         { roff_line_ignore, NULL, NULL, 0 },  /* cp */
422         { roff_line_ignore, NULL, NULL, 0 },  /* cropat */
423         { roff_line_ignore, NULL, NULL, 0 },  /* cs */
424         { roff_line_ignore, NULL, NULL, 0 },  /* cu */
425         { roff_unsupp, NULL, NULL, 0 },  /* da */
426         { roff_unsupp, NULL, NULL, 0 },  /* dch */
427         { roff_Dd, NULL, NULL, 0 },  /* Dd */
428         { roff_block, roff_block_text, roff_block_sub, 0 },  /* de */
429         { roff_block, roff_block_text, roff_block_sub, 0 },  /* de1 */
430         { roff_line_ignore, NULL, NULL, 0 },  /* defcolor */
431         { roff_block, roff_block_text, roff_block_sub, 0 },  /* dei */
432         { roff_block, roff_block_text, roff_block_sub, 0 },  /* dei1 */
433         { roff_unsupp, NULL, NULL, 0 },  /* device */
434         { roff_unsupp, NULL, NULL, 0 },  /* devicem */
435         { roff_unsupp, NULL, NULL, 0 },  /* di */
436         { roff_unsupp, NULL, NULL, 0 },  /* do */
437         { roff_ds, NULL, NULL, 0 },  /* ds */
438         { roff_ds, NULL, NULL, 0 },  /* ds1 */
439         { roff_unsupp, NULL, NULL, 0 },  /* dwh */
440         { roff_unsupp, NULL, NULL, 0 },  /* dt */
441         { roff_ec, NULL, NULL, 0 },  /* ec */
442         { roff_unsupp, NULL, NULL, 0 },  /* ecr */
443         { roff_unsupp, NULL, NULL, 0 },  /* ecs */
444         { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT },  /* el */
445         { roff_unsupp, NULL, NULL, 0 },  /* em */
446         { roff_EN, NULL, NULL, 0 },  /* EN */
447         { roff_eo, NULL, NULL, 0 },  /* eo */
448         { roff_unsupp, NULL, NULL, 0 },  /* EP */
449         { roff_EQ, NULL, NULL, 0 },  /* EQ */
450         { roff_line_ignore, NULL, NULL, 0 },  /* errprint */
451         { roff_unsupp, NULL, NULL, 0 },  /* ev */
452         { roff_unsupp, NULL, NULL, 0 },  /* evc */
453         { roff_unsupp, NULL, NULL, 0 },  /* ex */
454         { roff_line_ignore, NULL, NULL, 0 },  /* fallback */
455         { roff_line_ignore, NULL, NULL, 0 },  /* fam */
456         { roff_unsupp, NULL, NULL, 0 },  /* fc */
457         { roff_unsupp, NULL, NULL, 0 },  /* fchar */
458         { roff_line_ignore, NULL, NULL, 0 },  /* fcolor */
459         { roff_line_ignore, NULL, NULL, 0 },  /* fdeferlig */
460         { roff_line_ignore, NULL, NULL, 0 },  /* feature */
461         { roff_line_ignore, NULL, NULL, 0 },  /* fkern */
462         { roff_line_ignore, NULL, NULL, 0 },  /* fl */
463         { roff_line_ignore, NULL, NULL, 0 },  /* flig */
464         { roff_line_ignore, NULL, NULL, 0 },  /* fp */
465         { roff_line_ignore, NULL, NULL, 0 },  /* fps */
466         { roff_unsupp, NULL, NULL, 0 },  /* fschar */
467         { roff_line_ignore, NULL, NULL, 0 },  /* fspacewidth */
468         { roff_line_ignore, NULL, NULL, 0 },  /* fspecial */
469         { roff_line_ignore, NULL, NULL, 0 },  /* ftr */
470         { roff_line_ignore, NULL, NULL, 0 },  /* fzoom */
471         { roff_line_ignore, NULL, NULL, 0 },  /* gcolor */
472         { roff_line_ignore, NULL, NULL, 0 },  /* hc */
473         { roff_line_ignore, NULL, NULL, 0 },  /* hcode */
474         { roff_line_ignore, NULL, NULL, 0 },  /* hidechar */
475         { roff_line_ignore, NULL, NULL, 0 },  /* hla */
476         { roff_line_ignore, NULL, NULL, 0 },  /* hlm */
477         { roff_line_ignore, NULL, NULL, 0 },  /* hpf */
478         { roff_line_ignore, NULL, NULL, 0 },  /* hpfa */
479         { roff_line_ignore, NULL, NULL, 0 },  /* hpfcode */
480         { roff_line_ignore, NULL, NULL, 0 },  /* hw */
481         { roff_line_ignore, NULL, NULL, 0 },  /* hy */
482         { roff_line_ignore, NULL, NULL, 0 },  /* hylang */
483         { roff_line_ignore, NULL, NULL, 0 },  /* hylen */
484         { roff_line_ignore, NULL, NULL, 0 },  /* hym */
485         { roff_line_ignore, NULL, NULL, 0 },  /* hypp */
486         { roff_line_ignore, NULL, NULL, 0 },  /* hys */
487         { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT },  /* ie */
488         { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT },  /* if */
489         { roff_block, roff_block_text, roff_block_sub, 0 },  /* ig */
490         { roff_unsupp, NULL, NULL, 0 },  /* index */
491         { roff_it, NULL, NULL, 0 },  /* it */
492         { roff_unsupp, NULL, NULL, 0 },  /* itc */
493         { roff_line_ignore, NULL, NULL, 0 },  /* IX */
494         { roff_line_ignore, NULL, NULL, 0 },  /* kern */
495         { roff_line_ignore, NULL, NULL, 0 },  /* kernafter */
496         { roff_line_ignore, NULL, NULL, 0 },  /* kernbefore */
497         { roff_line_ignore, NULL, NULL, 0 },  /* kernpair */
498         { roff_unsupp, NULL, NULL, 0 },  /* lc */
499         { roff_unsupp, NULL, NULL, 0 },  /* lc_ctype */
500         { roff_unsupp, NULL, NULL, 0 },  /* lds */
501         { roff_unsupp, NULL, NULL, 0 },  /* length */
502         { roff_line_ignore, NULL, NULL, 0 },  /* letadj */
503         { roff_insec, NULL, NULL, 0 },  /* lf */
504         { roff_line_ignore, NULL, NULL, 0 },  /* lg */
505         { roff_line_ignore, NULL, NULL, 0 },  /* lhang */
506         { roff_unsupp, NULL, NULL, 0 },  /* linetabs */
507         { roff_unsupp, NULL, NULL, 0 },  /* lnr */
508         { roff_unsupp, NULL, NULL, 0 },  /* lnrf */
509         { roff_unsupp, NULL, NULL, 0 },  /* lpfx */
510         { roff_line_ignore, NULL, NULL, 0 },  /* ls */
511         { roff_unsupp, NULL, NULL, 0 },  /* lsm */
512         { roff_line_ignore, NULL, NULL, 0 },  /* lt */
513         { roff_line_ignore, NULL, NULL, 0 },  /* mediasize */
514         { roff_line_ignore, NULL, NULL, 0 },  /* minss */
515         { roff_line_ignore, NULL, NULL, 0 },  /* mk */
516         { roff_insec, NULL, NULL, 0 },  /* mso */
517         { roff_line_ignore, NULL, NULL, 0 },  /* na */
518         { roff_line_ignore, NULL, NULL, 0 },  /* ne */
519         { roff_line_ignore, NULL, NULL, 0 },  /* nh */
520         { roff_line_ignore, NULL, NULL, 0 },  /* nhychar */
521         { roff_unsupp, NULL, NULL, 0 },  /* nm */
522         { roff_unsupp, NULL, NULL, 0 },  /* nn */
523         { roff_nop, NULL, NULL, 0 },  /* nop */
524         { roff_nr, NULL, NULL, 0 },  /* nr */
525         { roff_unsupp, NULL, NULL, 0 },  /* nrf */
526         { roff_line_ignore, NULL, NULL, 0 },  /* nroff */
527         { roff_line_ignore, NULL, NULL, 0 },  /* ns */
528         { roff_insec, NULL, NULL, 0 },  /* nx */
529         { roff_insec, NULL, NULL, 0 },  /* open */
530         { roff_insec, NULL, NULL, 0 },  /* opena */
531         { roff_line_ignore, NULL, NULL, 0 },  /* os */
532         { roff_unsupp, NULL, NULL, 0 },  /* output */
533         { roff_line_ignore, NULL, NULL, 0 },  /* padj */
534         { roff_line_ignore, NULL, NULL, 0 },  /* papersize */
535         { roff_line_ignore, NULL, NULL, 0 },  /* pc */
536         { roff_line_ignore, NULL, NULL, 0 },  /* pev */
537         { roff_insec, NULL, NULL, 0 },  /* pi */
538         { roff_unsupp, NULL, NULL, 0 },  /* PI */
539         { roff_line_ignore, NULL, NULL, 0 },  /* pl */
540         { roff_line_ignore, NULL, NULL, 0 },  /* pm */
541         { roff_line_ignore, NULL, NULL, 0 },  /* pn */
542         { roff_line_ignore, NULL, NULL, 0 },  /* pnr */
543         { roff_line_ignore, NULL, NULL, 0 },  /* ps */
544         { roff_unsupp, NULL, NULL, 0 },  /* psbb */
545         { roff_unsupp, NULL, NULL, 0 },  /* pshape */
546         { roff_insec, NULL, NULL, 0 },  /* pso */
547         { roff_line_ignore, NULL, NULL, 0 },  /* ptr */
548         { roff_line_ignore, NULL, NULL, 0 },  /* pvs */
549         { roff_unsupp, NULL, NULL, 0 },  /* rchar */
550         { roff_line_ignore, NULL, NULL, 0 },  /* rd */
551         { roff_line_ignore, NULL, NULL, 0 },  /* recursionlimit */
552         { roff_return, NULL, NULL, 0 },  /* return */
553         { roff_unsupp, NULL, NULL, 0 },  /* rfschar */
554         { roff_line_ignore, NULL, NULL, 0 },  /* rhang */
555         { roff_rm, NULL, NULL, 0 },  /* rm */
556         { roff_rn, NULL, NULL, 0 },  /* rn */
557         { roff_unsupp, NULL, NULL, 0 },  /* rnn */
558         { roff_rr, NULL, NULL, 0 },  /* rr */
559         { roff_line_ignore, NULL, NULL, 0 },  /* rs */
560         { roff_line_ignore, NULL, NULL, 0 },  /* rt */
561         { roff_unsupp, NULL, NULL, 0 },  /* schar */
562         { roff_line_ignore, NULL, NULL, 0 },  /* sentchar */
563         { roff_line_ignore, NULL, NULL, 0 },  /* shc */
564         { roff_shift, NULL, NULL, 0 },  /* shift */
565         { roff_line_ignore, NULL, NULL, 0 },  /* sizes */
566         { roff_so, NULL, NULL, 0 },  /* so */
567         { roff_line_ignore, NULL, NULL, 0 },  /* spacewidth */
568         { roff_line_ignore, NULL, NULL, 0 },  /* special */
569         { roff_line_ignore, NULL, NULL, 0 },  /* spreadwarn */
570         { roff_line_ignore, NULL, NULL, 0 },  /* ss */
571         { roff_line_ignore, NULL, NULL, 0 },  /* sty */
572         { roff_unsupp, NULL, NULL, 0 },  /* substring */
573         { roff_line_ignore, NULL, NULL, 0 },  /* sv */
574         { roff_insec, NULL, NULL, 0 },  /* sy */
575         { roff_T_, NULL, NULL, 0 },  /* T& */
576         { roff_unsupp, NULL, NULL, 0 },  /* tc */
577         { roff_TE, NULL, NULL, 0 },  /* TE */
578         { roff_Dd, NULL, NULL, 0 },  /* TH */
579         { roff_line_ignore, NULL, NULL, 0 },  /* tkf */
580         { roff_unsupp, NULL, NULL, 0 },  /* tl */
581         { roff_line_ignore, NULL, NULL, 0 },  /* tm */
582         { roff_line_ignore, NULL, NULL, 0 },  /* tm1 */
583         { roff_line_ignore, NULL, NULL, 0 },  /* tmc */
584         { roff_tr, NULL, NULL, 0 },  /* tr */
585         { roff_line_ignore, NULL, NULL, 0 },  /* track */
586         { roff_line_ignore, NULL, NULL, 0 },  /* transchar */
587         { roff_insec, NULL, NULL, 0 },  /* trf */
588         { roff_line_ignore, NULL, NULL, 0 },  /* trimat */
589         { roff_unsupp, NULL, NULL, 0 },  /* trin */
590         { roff_unsupp, NULL, NULL, 0 },  /* trnt */
591         { roff_line_ignore, NULL, NULL, 0 },  /* troff */
592         { roff_TS, NULL, NULL, 0 },  /* TS */
593         { roff_line_ignore, NULL, NULL, 0 },  /* uf */
594         { roff_line_ignore, NULL, NULL, 0 },  /* ul */
595         { roff_unsupp, NULL, NULL, 0 },  /* unformat */
596         { roff_line_ignore, NULL, NULL, 0 },  /* unwatch */
597         { roff_line_ignore, NULL, NULL, 0 },  /* unwatchn */
598         { roff_line_ignore, NULL, NULL, 0 },  /* vpt */
599         { roff_line_ignore, NULL, NULL, 0 },  /* vs */
600         { roff_line_ignore, NULL, NULL, 0 },  /* warn */
601         { roff_line_ignore, NULL, NULL, 0 },  /* warnscale */
602         { roff_line_ignore, NULL, NULL, 0 },  /* watch */
603         { roff_line_ignore, NULL, NULL, 0 },  /* watchlength */
604         { roff_line_ignore, NULL, NULL, 0 },  /* watchn */
605         { roff_unsupp, NULL, NULL, 0 },  /* wh */
606         { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT }, /*while*/
607         { roff_insec, NULL, NULL, 0 },  /* write */
608         { roff_insec, NULL, NULL, 0 },  /* writec */
609         { roff_insec, NULL, NULL, 0 },  /* writem */
610         { roff_line_ignore, NULL, NULL, 0 },  /* xflag */
611         { roff_cblock, NULL, NULL, 0 },  /* . */
612         { roff_renamed, NULL, NULL, 0 },
613         { roff_userdef, NULL, NULL, 0 }
614 };
615
616 /* Array of injected predefined strings. */
617 #define PREDEFS_MAX      38
618 static  const struct predef predefs[PREDEFS_MAX] = {
619 #include "predefs.in"
620 };
621
622 static  int      roffce_lines;  /* number of input lines to center */
623 static  struct roff_node *roffce_node;  /* active request */
624 static  int      roffit_lines;  /* number of lines to delay */
625 static  char    *roffit_macro;  /* nil-terminated macro line */
626
627
628 /* --- request table ------------------------------------------------------ */
629
630 struct ohash *
631 roffhash_alloc(enum roff_tok mintok, enum roff_tok maxtok)
632 {
633         struct ohash    *htab;
634         struct roffreq  *req;
635         enum roff_tok    tok;
636         size_t           sz;
637         unsigned int     slot;
638
639         htab = mandoc_malloc(sizeof(*htab));
640         mandoc_ohash_init(htab, 8, offsetof(struct roffreq, name));
641
642         for (tok = mintok; tok < maxtok; tok++) {
643                 if (roff_name[tok] == NULL)
644                         continue;
645                 sz = strlen(roff_name[tok]);
646                 req = mandoc_malloc(sizeof(*req) + sz + 1);
647                 req->tok = tok;
648                 memcpy(req->name, roff_name[tok], sz + 1);
649                 slot = ohash_qlookup(htab, req->name);
650                 ohash_insert(htab, slot, req);
651         }
652         return htab;
653 }
654
655 void
656 roffhash_free(struct ohash *htab)
657 {
658         struct roffreq  *req;
659         unsigned int     slot;
660
661         if (htab == NULL)
662                 return;
663         for (req = ohash_first(htab, &slot); req != NULL;
664              req = ohash_next(htab, &slot))
665                 free(req);
666         ohash_delete(htab);
667         free(htab);
668 }
669
670 enum roff_tok
671 roffhash_find(struct ohash *htab, const char *name, size_t sz)
672 {
673         struct roffreq  *req;
674         const char      *end;
675
676         if (sz) {
677                 end = name + sz;
678                 req = ohash_find(htab, ohash_qlookupi(htab, name, &end));
679         } else
680                 req = ohash_find(htab, ohash_qlookup(htab, name));
681         return req == NULL ? TOKEN_NONE : req->tok;
682 }
683
684 /* --- stack of request blocks -------------------------------------------- */
685
686 /*
687  * Pop the current node off of the stack of roff instructions currently
688  * pending.
689  */
690 static int
691 roffnode_pop(struct roff *r)
692 {
693         struct roffnode *p;
694         int              inloop;
695
696         p = r->last;
697         inloop = p->tok == ROFF_while;
698         r->last = p->parent;
699         free(p->name);
700         free(p->end);
701         free(p);
702         return inloop;
703 }
704
705 /*
706  * Push a roff node onto the instruction stack.  This must later be
707  * removed with roffnode_pop().
708  */
709 static void
710 roffnode_push(struct roff *r, enum roff_tok tok, const char *name,
711                 int line, int col)
712 {
713         struct roffnode *p;
714
715         p = mandoc_calloc(1, sizeof(struct roffnode));
716         p->tok = tok;
717         if (name)
718                 p->name = mandoc_strdup(name);
719         p->parent = r->last;
720         p->line = line;
721         p->col = col;
722         p->rule = p->parent ? p->parent->rule : 0;
723
724         r->last = p;
725 }
726
727 /* --- roff parser state data management ---------------------------------- */
728
729 static void
730 roff_free1(struct roff *r)
731 {
732         int              i;
733
734         tbl_free(r->first_tbl);
735         r->first_tbl = r->last_tbl = r->tbl = NULL;
736
737         eqn_free(r->last_eqn);
738         r->last_eqn = r->eqn = NULL;
739
740         while (r->mstackpos >= 0)
741                 roff_userret(r);
742
743         while (r->last)
744                 roffnode_pop(r);
745
746         free (r->rstack);
747         r->rstack = NULL;
748         r->rstacksz = 0;
749         r->rstackpos = -1;
750
751         roff_freereg(r->regtab);
752         r->regtab = NULL;
753
754         roff_freestr(r->strtab);
755         roff_freestr(r->rentab);
756         roff_freestr(r->xmbtab);
757         r->strtab = r->rentab = r->xmbtab = NULL;
758
759         if (r->xtab)
760                 for (i = 0; i < 128; i++)
761                         free(r->xtab[i].p);
762         free(r->xtab);
763         r->xtab = NULL;
764 }
765
766 void
767 roff_reset(struct roff *r)
768 {
769         roff_free1(r);
770         r->format = r->options & (MPARSE_MDOC | MPARSE_MAN);
771         r->control = '\0';
772         r->escape = '\\';
773         roffce_lines = 0;
774         roffce_node = NULL;
775         roffit_lines = 0;
776         roffit_macro = NULL;
777 }
778
779 void
780 roff_free(struct roff *r)
781 {
782         int              i;
783
784         roff_free1(r);
785         for (i = 0; i < r->mstacksz; i++)
786                 free(r->mstack[i].argv);
787         free(r->mstack);
788         roffhash_free(r->reqtab);
789         free(r);
790 }
791
792 struct roff *
793 roff_alloc(int options)
794 {
795         struct roff     *r;
796
797         r = mandoc_calloc(1, sizeof(struct roff));
798         r->reqtab = roffhash_alloc(0, ROFF_RENAMED);
799         r->options = options;
800         r->format = options & (MPARSE_MDOC | MPARSE_MAN);
801         r->mstackpos = -1;
802         r->rstackpos = -1;
803         r->escape = '\\';
804         return r;
805 }
806
807 /* --- syntax tree state data management ---------------------------------- */
808
809 static void
810 roff_man_free1(struct roff_man *man)
811 {
812         if (man->meta.first != NULL)
813                 roff_node_delete(man, man->meta.first);
814         free(man->meta.msec);
815         free(man->meta.vol);
816         free(man->meta.os);
817         free(man->meta.arch);
818         free(man->meta.title);
819         free(man->meta.name);
820         free(man->meta.date);
821         free(man->meta.sodest);
822 }
823
824 void
825 roff_state_reset(struct roff_man *man)
826 {
827         man->last = man->meta.first;
828         man->last_es = NULL;
829         man->flags = 0;
830         man->lastsec = man->lastnamed = SEC_NONE;
831         man->next = ROFF_NEXT_CHILD;
832         roff_setreg(man->roff, "nS", 0, '=');
833 }
834
835 static void
836 roff_man_alloc1(struct roff_man *man)
837 {
838         memset(&man->meta, 0, sizeof(man->meta));
839         man->meta.first = mandoc_calloc(1, sizeof(*man->meta.first));
840         man->meta.first->type = ROFFT_ROOT;
841         man->meta.macroset = MACROSET_NONE;
842         roff_state_reset(man);
843 }
844
845 void
846 roff_man_reset(struct roff_man *man)
847 {
848         roff_man_free1(man);
849         roff_man_alloc1(man);
850 }
851
852 void
853 roff_man_free(struct roff_man *man)
854 {
855         roff_man_free1(man);
856         free(man);
857 }
858
859 struct roff_man *
860 roff_man_alloc(struct roff *roff, const char *os_s, int quick)
861 {
862         struct roff_man *man;
863
864         man = mandoc_calloc(1, sizeof(*man));
865         man->roff = roff;
866         man->os_s = os_s;
867         man->quick = quick;
868         roff_man_alloc1(man);
869         roff->man = man;
870         return man;
871 }
872
873 /* --- syntax tree handling ----------------------------------------------- */
874
875 struct roff_node *
876 roff_node_alloc(struct roff_man *man, int line, int pos,
877         enum roff_type type, int tok)
878 {
879         struct roff_node        *n;
880
881         n = mandoc_calloc(1, sizeof(*n));
882         n->line = line;
883         n->pos = pos;
884         n->tok = tok;
885         n->type = type;
886         n->sec = man->lastsec;
887
888         if (man->flags & MDOC_SYNOPSIS)
889                 n->flags |= NODE_SYNPRETTY;
890         else
891                 n->flags &= ~NODE_SYNPRETTY;
892         if ((man->flags & (ROFF_NOFILL | ROFF_NONOFILL)) == ROFF_NOFILL)
893                 n->flags |= NODE_NOFILL;
894         else
895                 n->flags &= ~NODE_NOFILL;
896         if (man->flags & MDOC_NEWLINE)
897                 n->flags |= NODE_LINE;
898         man->flags &= ~MDOC_NEWLINE;
899
900         return n;
901 }
902
903 void
904 roff_node_append(struct roff_man *man, struct roff_node *n)
905 {
906
907         switch (man->next) {
908         case ROFF_NEXT_SIBLING:
909                 if (man->last->next != NULL) {
910                         n->next = man->last->next;
911                         man->last->next->prev = n;
912                 } else
913                         man->last->parent->last = n;
914                 man->last->next = n;
915                 n->prev = man->last;
916                 n->parent = man->last->parent;
917                 break;
918         case ROFF_NEXT_CHILD:
919                 if (man->last->child != NULL) {
920                         n->next = man->last->child;
921                         man->last->child->prev = n;
922                 } else
923                         man->last->last = n;
924                 man->last->child = n;
925                 n->parent = man->last;
926                 break;
927         default:
928                 abort();
929         }
930         man->last = n;
931
932         switch (n->type) {
933         case ROFFT_HEAD:
934                 n->parent->head = n;
935                 break;
936         case ROFFT_BODY:
937                 if (n->end != ENDBODY_NOT)
938                         return;
939                 n->parent->body = n;
940                 break;
941         case ROFFT_TAIL:
942                 n->parent->tail = n;
943                 break;
944         default:
945                 return;
946         }
947
948         /*
949          * Copy over the normalised-data pointer of our parent.  Not
950          * everybody has one, but copying a null pointer is fine.
951          */
952
953         n->norm = n->parent->norm;
954         assert(n->parent->type == ROFFT_BLOCK);
955 }
956
957 void
958 roff_word_alloc(struct roff_man *man, int line, int pos, const char *word)
959 {
960         struct roff_node        *n;
961
962         n = roff_node_alloc(man, line, pos, ROFFT_TEXT, TOKEN_NONE);
963         n->string = roff_strdup(man->roff, word);
964         roff_node_append(man, n);
965         n->flags |= NODE_VALID | NODE_ENDED;
966         man->next = ROFF_NEXT_SIBLING;
967 }
968
969 void
970 roff_word_append(struct roff_man *man, const char *word)
971 {
972         struct roff_node        *n;
973         char                    *addstr, *newstr;
974
975         n = man->last;
976         addstr = roff_strdup(man->roff, word);
977         mandoc_asprintf(&newstr, "%s %s", n->string, addstr);
978         free(addstr);
979         free(n->string);
980         n->string = newstr;
981         man->next = ROFF_NEXT_SIBLING;
982 }
983
984 void
985 roff_elem_alloc(struct roff_man *man, int line, int pos, int tok)
986 {
987         struct roff_node        *n;
988
989         n = roff_node_alloc(man, line, pos, ROFFT_ELEM, tok);
990         roff_node_append(man, n);
991         man->next = ROFF_NEXT_CHILD;
992 }
993
994 struct roff_node *
995 roff_block_alloc(struct roff_man *man, int line, int pos, int tok)
996 {
997         struct roff_node        *n;
998
999         n = roff_node_alloc(man, line, pos, ROFFT_BLOCK, tok);
1000         roff_node_append(man, n);
1001         man->next = ROFF_NEXT_CHILD;
1002         return n;
1003 }
1004
1005 struct roff_node *
1006 roff_head_alloc(struct roff_man *man, int line, int pos, int tok)
1007 {
1008         struct roff_node        *n;
1009
1010         n = roff_node_alloc(man, line, pos, ROFFT_HEAD, tok);
1011         roff_node_append(man, n);
1012         man->next = ROFF_NEXT_CHILD;
1013         return n;
1014 }
1015
1016 struct roff_node *
1017 roff_body_alloc(struct roff_man *man, int line, int pos, int tok)
1018 {
1019         struct roff_node        *n;
1020
1021         n = roff_node_alloc(man, line, pos, ROFFT_BODY, tok);
1022         roff_node_append(man, n);
1023         man->next = ROFF_NEXT_CHILD;
1024         return n;
1025 }
1026
1027 static void
1028 roff_addtbl(struct roff_man *man, int line, struct tbl_node *tbl)
1029 {
1030         struct roff_node        *n;
1031         struct tbl_span         *span;
1032
1033         if (man->meta.macroset == MACROSET_MAN)
1034                 man_breakscope(man, ROFF_TS);
1035         while ((span = tbl_span(tbl)) != NULL) {
1036                 n = roff_node_alloc(man, line, 0, ROFFT_TBL, TOKEN_NONE);
1037                 n->span = span;
1038                 roff_node_append(man, n);
1039                 n->flags |= NODE_VALID | NODE_ENDED;
1040                 man->next = ROFF_NEXT_SIBLING;
1041         }
1042 }
1043
1044 void
1045 roff_node_unlink(struct roff_man *man, struct roff_node *n)
1046 {
1047
1048         /* Adjust siblings. */
1049
1050         if (n->prev)
1051                 n->prev->next = n->next;
1052         if (n->next)
1053                 n->next->prev = n->prev;
1054
1055         /* Adjust parent. */
1056
1057         if (n->parent != NULL) {
1058                 if (n->parent->child == n)
1059                         n->parent->child = n->next;
1060                 if (n->parent->last == n)
1061                         n->parent->last = n->prev;
1062         }
1063
1064         /* Adjust parse point. */
1065
1066         if (man == NULL)
1067                 return;
1068         if (man->last == n) {
1069                 if (n->prev == NULL) {
1070                         man->last = n->parent;
1071                         man->next = ROFF_NEXT_CHILD;
1072                 } else {
1073                         man->last = n->prev;
1074                         man->next = ROFF_NEXT_SIBLING;
1075                 }
1076         }
1077         if (man->meta.first == n)
1078                 man->meta.first = NULL;
1079 }
1080
1081 void
1082 roff_node_relink(struct roff_man *man, struct roff_node *n)
1083 {
1084         roff_node_unlink(man, n);
1085         n->prev = n->next = NULL;
1086         roff_node_append(man, n);
1087 }
1088
1089 void
1090 roff_node_free(struct roff_node *n)
1091 {
1092
1093         if (n->args != NULL)
1094                 mdoc_argv_free(n->args);
1095         if (n->type == ROFFT_BLOCK || n->type == ROFFT_ELEM)
1096                 free(n->norm);
1097         eqn_box_free(n->eqn);
1098         free(n->string);
1099         free(n);
1100 }
1101
1102 void
1103 roff_node_delete(struct roff_man *man, struct roff_node *n)
1104 {
1105
1106         while (n->child != NULL)
1107                 roff_node_delete(man, n->child);
1108         roff_node_unlink(man, n);
1109         roff_node_free(n);
1110 }
1111
1112 void
1113 deroff(char **dest, const struct roff_node *n)
1114 {
1115         char    *cp;
1116         size_t   sz;
1117
1118         if (n->type != ROFFT_TEXT) {
1119                 for (n = n->child; n != NULL; n = n->next)
1120                         deroff(dest, n);
1121                 return;
1122         }
1123
1124         /* Skip leading whitespace. */
1125
1126         for (cp = n->string; *cp != '\0'; cp++) {
1127                 if (cp[0] == '\\' && cp[1] != '\0' &&
1128                     strchr(" %&0^|~", cp[1]) != NULL)
1129                         cp++;
1130                 else if ( ! isspace((unsigned char)*cp))
1131                         break;
1132         }
1133
1134         /* Skip trailing backslash. */
1135
1136         sz = strlen(cp);
1137         if (sz > 0 && cp[sz - 1] == '\\')
1138                 sz--;
1139
1140         /* Skip trailing whitespace. */
1141
1142         for (; sz; sz--)
1143                 if ( ! isspace((unsigned char)cp[sz-1]))
1144                         break;
1145
1146         /* Skip empty strings. */
1147
1148         if (sz == 0)
1149                 return;
1150
1151         if (*dest == NULL) {
1152                 *dest = mandoc_strndup(cp, sz);
1153                 return;
1154         }
1155
1156         mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp);
1157         free(*dest);
1158         *dest = cp;
1159 }
1160
1161 /* --- main functions of the roff parser ---------------------------------- */
1162
1163 /*
1164  * In the current line, expand escape sequences that produce parsable
1165  * input text.  Also check the syntax of the remaining escape sequences,
1166  * which typically produce output glyphs or change formatter state.
1167  */
1168 static int
1169 roff_expand(struct roff *r, struct buf *buf, int ln, int pos, char newesc)
1170 {
1171         struct mctx     *ctx;   /* current macro call context */
1172         char             ubuf[24]; /* buffer to print the number */
1173         struct roff_node *n;    /* used for header comments */
1174         const char      *start; /* start of the string to process */
1175         char            *stesc; /* start of an escape sequence ('\\') */
1176         const char      *esct;  /* type of esccape sequence */
1177         char            *ep;    /* end of comment string */
1178         const char      *stnam; /* start of the name, after "[(*" */
1179         const char      *cp;    /* end of the name, e.g. before ']' */
1180         const char      *res;   /* the string to be substituted */
1181         char            *nbuf;  /* new buffer to copy buf->buf to */
1182         size_t           maxl;  /* expected length of the escape name */
1183         size_t           naml;  /* actual length of the escape name */
1184         size_t           asz;   /* length of the replacement */
1185         size_t           rsz;   /* length of the rest of the string */
1186         int              inaml; /* length returned from mandoc_escape() */
1187         int              expand_count;  /* to avoid infinite loops */
1188         int              npos;  /* position in numeric expression */
1189         int              arg_complete; /* argument not interrupted by eol */
1190         int              quote_args; /* true for \\$@, false for \\$* */
1191         int              done;  /* no more input available */
1192         int              deftype; /* type of definition to paste */
1193         int              rcsid; /* kind of RCS id seen */
1194         enum mandocerr   err;   /* for escape sequence problems */
1195         char             sign;  /* increment number register */
1196         char             term;  /* character terminating the escape */
1197
1198         /* Search forward for comments. */
1199
1200         done = 0;
1201         start = buf->buf + pos;
1202         for (stesc = buf->buf + pos; *stesc != '\0'; stesc++) {
1203                 if (stesc[0] != newesc || stesc[1] == '\0')
1204                         continue;
1205                 stesc++;
1206                 if (*stesc != '"' && *stesc != '#')
1207                         continue;
1208
1209                 /* Comment found, look for RCS id. */
1210
1211                 rcsid = 0;
1212                 if ((cp = strstr(stesc, "$" "OpenBSD")) != NULL) {
1213                         rcsid = 1 << MANDOC_OS_OPENBSD;
1214                         cp += 8;
1215                 } else if ((cp = strstr(stesc, "$" "NetBSD")) != NULL) {
1216                         rcsid = 1 << MANDOC_OS_NETBSD;
1217                         cp += 7;
1218                 }
1219                 if (cp != NULL &&
1220                     isalnum((unsigned char)*cp) == 0 &&
1221                     strchr(cp, '$') != NULL) {
1222                         if (r->man->meta.rcsids & rcsid)
1223                                 mandoc_msg(MANDOCERR_RCS_REP, ln,
1224                                     (int)(stesc - buf->buf) + 1,
1225                                     "%s", stesc + 1);
1226                         r->man->meta.rcsids |= rcsid;
1227                 }
1228
1229                 /* Handle trailing whitespace. */
1230
1231                 ep = strchr(stesc--, '\0') - 1;
1232                 if (*ep == '\n') {
1233                         done = 1;
1234                         ep--;
1235                 }
1236                 if (*ep == ' ' || *ep == '\t')
1237                         mandoc_msg(MANDOCERR_SPACE_EOL,
1238                             ln, (int)(ep - buf->buf), NULL);
1239
1240                 /*
1241                  * Save comments preceding the title macro
1242                  * in the syntax tree.
1243                  */
1244
1245                 if (newesc != ASCII_ESC && r->format == 0) {
1246                         while (*ep == ' ' || *ep == '\t')
1247                                 ep--;
1248                         ep[1] = '\0';
1249                         n = roff_node_alloc(r->man,
1250                             ln, stesc + 1 - buf->buf,
1251                             ROFFT_COMMENT, TOKEN_NONE);
1252                         n->string = mandoc_strdup(stesc + 2);
1253                         roff_node_append(r->man, n);
1254                         n->flags |= NODE_VALID | NODE_ENDED;
1255                         r->man->next = ROFF_NEXT_SIBLING;
1256                 }
1257
1258                 /* Line continuation with comment. */
1259
1260                 if (stesc[1] == '#') {
1261                         *stesc = '\0';
1262                         return ROFF_IGN | ROFF_APPEND;
1263                 }
1264
1265                 /* Discard normal comments. */
1266
1267                 while (stesc > start && stesc[-1] == ' ' &&
1268                     (stesc == start + 1 || stesc[-2] != '\\'))
1269                         stesc--;
1270                 *stesc = '\0';
1271                 break;
1272         }
1273         if (stesc == start)
1274                 return ROFF_CONT;
1275         stesc--;
1276
1277         /* Notice the end of the input. */
1278
1279         if (*stesc == '\n') {
1280                 *stesc-- = '\0';
1281                 done = 1;
1282         }
1283
1284         expand_count = 0;
1285         while (stesc >= start) {
1286                 if (*stesc != newesc) {
1287
1288                         /*
1289                          * If we have a non-standard escape character,
1290                          * escape literal backslashes because all
1291                          * processing in subsequent functions uses
1292                          * the standard escaping rules.
1293                          */
1294
1295                         if (newesc != ASCII_ESC && *stesc == '\\') {
1296                                 *stesc = '\0';
1297                                 buf->sz = mandoc_asprintf(&nbuf, "%s\\e%s",
1298                                     buf->buf, stesc + 1) + 1;
1299                                 start = nbuf + pos;
1300                                 stesc = nbuf + (stesc - buf->buf);
1301                                 free(buf->buf);
1302                                 buf->buf = nbuf;
1303                         }
1304
1305                         /* Search backwards for the next escape. */
1306
1307                         stesc--;
1308                         continue;
1309                 }
1310
1311                 /* If it is escaped, skip it. */
1312
1313                 for (cp = stesc - 1; cp >= start; cp--)
1314                         if (*cp != r->escape)
1315                                 break;
1316
1317                 if ((stesc - cp) % 2 == 0) {
1318                         while (stesc > cp)
1319                                 *stesc-- = '\\';
1320                         continue;
1321                 } else if (stesc[1] != '\0') {
1322                         *stesc = '\\';
1323                 } else {
1324                         *stesc-- = '\0';
1325                         if (done)
1326                                 continue;
1327                         else
1328                                 return ROFF_IGN | ROFF_APPEND;
1329                 }
1330
1331                 /* Decide whether to expand or to check only. */
1332
1333                 term = '\0';
1334                 cp = stesc + 1;
1335                 if (*cp == 'E')
1336                         cp++;
1337                 esct = cp;
1338                 switch (*esct) {
1339                 case '*':
1340                 case '$':
1341                         res = NULL;
1342                         break;
1343                 case 'B':
1344                 case 'w':
1345                         term = cp[1];
1346                         /* FALLTHROUGH */
1347                 case 'n':
1348                         sign = cp[1];
1349                         if (sign == '+' || sign == '-')
1350                                 cp++;
1351                         res = ubuf;
1352                         break;
1353                 default:
1354                         err = MANDOCERR_OK;
1355                         switch(mandoc_escape(&cp, &stnam, &inaml)) {
1356                         case ESCAPE_SPECIAL:
1357                                 if (mchars_spec2cp(stnam, inaml) >= 0)
1358                                         break;
1359                                 /* FALLTHROUGH */
1360                         case ESCAPE_ERROR:
1361                                 err = MANDOCERR_ESC_BAD;
1362                                 break;
1363                         case ESCAPE_UNDEF:
1364                                 err = MANDOCERR_ESC_UNDEF;
1365                                 break;
1366                         case ESCAPE_UNSUPP:
1367                                 err = MANDOCERR_ESC_UNSUPP;
1368                                 break;
1369                         default:
1370                                 break;
1371                         }
1372                         if (err != MANDOCERR_OK)
1373                                 mandoc_msg(err, ln, (int)(stesc - buf->buf),
1374                                     "%.*s", (int)(cp - stesc), stesc);
1375                         stesc--;
1376                         continue;
1377                 }
1378
1379                 if (EXPAND_LIMIT < ++expand_count) {
1380                         mandoc_msg(MANDOCERR_ROFFLOOP,
1381                             ln, (int)(stesc - buf->buf), NULL);
1382                         return ROFF_IGN;
1383                 }
1384
1385                 /*
1386                  * The third character decides the length
1387                  * of the name of the string or register.
1388                  * Save a pointer to the name.
1389                  */
1390
1391                 if (term == '\0') {
1392                         switch (*++cp) {
1393                         case '\0':
1394                                 maxl = 0;
1395                                 break;
1396                         case '(':
1397                                 cp++;
1398                                 maxl = 2;
1399                                 break;
1400                         case '[':
1401                                 cp++;
1402                                 term = ']';
1403                                 maxl = 0;
1404                                 break;
1405                         default:
1406                                 maxl = 1;
1407                                 break;
1408                         }
1409                 } else {
1410                         cp += 2;
1411                         maxl = 0;
1412                 }
1413                 stnam = cp;
1414
1415                 /* Advance to the end of the name. */
1416
1417                 naml = 0;
1418                 arg_complete = 1;
1419                 while (maxl == 0 || naml < maxl) {
1420                         if (*cp == '\0') {
1421                                 mandoc_msg(MANDOCERR_ESC_BAD, ln,
1422                                     (int)(stesc - buf->buf), "%s", stesc);
1423                                 arg_complete = 0;
1424                                 break;
1425                         }
1426                         if (maxl == 0 && *cp == term) {
1427                                 cp++;
1428                                 break;
1429                         }
1430                         if (*cp++ != '\\' || *esct != 'w') {
1431                                 naml++;
1432                                 continue;
1433                         }
1434                         switch (mandoc_escape(&cp, NULL, NULL)) {
1435                         case ESCAPE_SPECIAL:
1436                         case ESCAPE_UNICODE:
1437                         case ESCAPE_NUMBERED:
1438                         case ESCAPE_UNDEF:
1439                         case ESCAPE_OVERSTRIKE:
1440                                 naml++;
1441                                 break;
1442                         default:
1443                                 break;
1444                         }
1445                 }
1446
1447                 /*
1448                  * Retrieve the replacement string; if it is
1449                  * undefined, resume searching for escapes.
1450                  */
1451
1452                 switch (*esct) {
1453                 case '*':
1454                         if (arg_complete) {
1455                                 deftype = ROFFDEF_USER | ROFFDEF_PRE;
1456                                 res = roff_getstrn(r, stnam, naml, &deftype);
1457
1458                                 /*
1459                                  * If not overriden, let \*(.T
1460                                  * through to the formatters.
1461                                  */
1462
1463                                 if (res == NULL && naml == 2 &&
1464                                     stnam[0] == '.' && stnam[1] == 'T') {
1465                                         roff_setstrn(&r->strtab,
1466                                             ".T", 2, NULL, 0, 0);
1467                                         stesc--;
1468                                         continue;
1469                                 }
1470                         }
1471                         break;
1472                 case '$':
1473                         if (r->mstackpos < 0) {
1474                                 mandoc_msg(MANDOCERR_ARG_UNDEF, ln,
1475                                     (int)(stesc - buf->buf), "%.3s", stesc);
1476                                 break;
1477                         }
1478                         ctx = r->mstack + r->mstackpos;
1479                         npos = esct[1] - '1';
1480                         if (npos >= 0 && npos <= 8) {
1481                                 res = npos < ctx->argc ?
1482                                     ctx->argv[npos] : "";
1483                                 break;
1484                         }
1485                         if (esct[1] == '*')
1486                                 quote_args = 0;
1487                         else if (esct[1] == '@')
1488                                 quote_args = 1;
1489                         else {
1490                                 mandoc_msg(MANDOCERR_ARG_NONUM, ln,
1491                                     (int)(stesc - buf->buf), "%.3s", stesc);
1492                                 break;
1493                         }
1494                         asz = 0;
1495                         for (npos = 0; npos < ctx->argc; npos++) {
1496                                 if (npos)
1497                                         asz++;  /* blank */
1498                                 if (quote_args)
1499                                         asz += 2;  /* quotes */
1500                                 asz += strlen(ctx->argv[npos]);
1501                         }
1502                         if (asz != 3) {
1503                                 rsz = buf->sz - (stesc - buf->buf) - 3;
1504                                 if (asz < 3)
1505                                         memmove(stesc + asz, stesc + 3, rsz);
1506                                 buf->sz += asz - 3;
1507                                 nbuf = mandoc_realloc(buf->buf, buf->sz);
1508                                 start = nbuf + pos;
1509                                 stesc = nbuf + (stesc - buf->buf);
1510                                 buf->buf = nbuf;
1511                                 if (asz > 3)
1512                                         memmove(stesc + asz, stesc + 3, rsz);
1513                         }
1514                         for (npos = 0; npos < ctx->argc; npos++) {
1515                                 if (npos)
1516                                         *stesc++ = ' ';
1517                                 if (quote_args)
1518                                         *stesc++ = '"';
1519                                 cp = ctx->argv[npos];
1520                                 while (*cp != '\0')
1521                                         *stesc++ = *cp++;
1522                                 if (quote_args)
1523                                         *stesc++ = '"';
1524                         }
1525                         continue;
1526                 case 'B':
1527                         npos = 0;
1528                         ubuf[0] = arg_complete &&
1529                             roff_evalnum(r, ln, stnam, &npos,
1530                               NULL, ROFFNUM_SCALE) &&
1531                             stnam + npos + 1 == cp ? '1' : '0';
1532                         ubuf[1] = '\0';
1533                         break;
1534                 case 'n':
1535                         if (arg_complete)
1536                                 (void)snprintf(ubuf, sizeof(ubuf), "%d",
1537                                     roff_getregn(r, stnam, naml, sign));
1538                         else
1539                                 ubuf[0] = '\0';
1540                         break;
1541                 case 'w':
1542                         /* use even incomplete args */
1543                         (void)snprintf(ubuf, sizeof(ubuf), "%d",
1544                             24 * (int)naml);
1545                         break;
1546                 }
1547
1548                 if (res == NULL) {
1549                         if (*esct == '*')
1550                                 mandoc_msg(MANDOCERR_STR_UNDEF,
1551                                     ln, (int)(stesc - buf->buf),
1552                                     "%.*s", (int)naml, stnam);
1553                         res = "";
1554                 } else if (buf->sz + strlen(res) > SHRT_MAX) {
1555                         mandoc_msg(MANDOCERR_ROFFLOOP,
1556                             ln, (int)(stesc - buf->buf), NULL);
1557                         return ROFF_IGN;
1558                 }
1559
1560                 /* Replace the escape sequence by the string. */
1561
1562                 *stesc = '\0';
1563                 buf->sz = mandoc_asprintf(&nbuf, "%s%s%s",
1564                     buf->buf, res, cp) + 1;
1565
1566                 /* Prepare for the next replacement. */
1567
1568                 start = nbuf + pos;
1569                 stesc = nbuf + (stesc - buf->buf) + strlen(res);
1570                 free(buf->buf);
1571                 buf->buf = nbuf;
1572         }
1573         return ROFF_CONT;
1574 }
1575
1576 /*
1577  * Parse a quoted or unquoted roff-style request or macro argument.
1578  * Return a pointer to the parsed argument, which is either the original
1579  * pointer or advanced by one byte in case the argument is quoted.
1580  * NUL-terminate the argument in place.
1581  * Collapse pairs of quotes inside quoted arguments.
1582  * Advance the argument pointer to the next argument,
1583  * or to the NUL byte terminating the argument line.
1584  */
1585 char *
1586 roff_getarg(struct roff *r, char **cpp, int ln, int *pos)
1587 {
1588         struct buf       buf;
1589         char            *cp, *start;
1590         int              newesc, pairs, quoted, white;
1591
1592         /* Quoting can only start with a new word. */
1593         start = *cpp;
1594         quoted = 0;
1595         if ('"' == *start) {
1596                 quoted = 1;
1597                 start++;
1598         }
1599
1600         newesc = pairs = white = 0;
1601         for (cp = start; '\0' != *cp; cp++) {
1602
1603                 /*
1604                  * Move the following text left
1605                  * after quoted quotes and after "\\" and "\t".
1606                  */
1607                 if (pairs)
1608                         cp[-pairs] = cp[0];
1609
1610                 if ('\\' == cp[0]) {
1611                         /*
1612                          * In copy mode, translate double to single
1613                          * backslashes and backslash-t to literal tabs.
1614                          */
1615                         switch (cp[1]) {
1616                         case 'a':
1617                         case 't':
1618                                 cp[-pairs] = '\t';
1619                                 pairs++;
1620                                 cp++;
1621                                 break;
1622                         case '\\':
1623                                 newesc = 1;
1624                                 cp[-pairs] = ASCII_ESC;
1625                                 pairs++;
1626                                 cp++;
1627                                 break;
1628                         case ' ':
1629                                 /* Skip escaped blanks. */
1630                                 if (0 == quoted)
1631                                         cp++;
1632                                 break;
1633                         default:
1634                                 break;
1635                         }
1636                 } else if (0 == quoted) {
1637                         if (' ' == cp[0]) {
1638                                 /* Unescaped blanks end unquoted args. */
1639                                 white = 1;
1640                                 break;
1641                         }
1642                 } else if ('"' == cp[0]) {
1643                         if ('"' == cp[1]) {
1644                                 /* Quoted quotes collapse. */
1645                                 pairs++;
1646                                 cp++;
1647                         } else {
1648                                 /* Unquoted quotes end quoted args. */
1649                                 quoted = 2;
1650                                 break;
1651                         }
1652                 }
1653         }
1654
1655         /* Quoted argument without a closing quote. */
1656         if (1 == quoted)
1657                 mandoc_msg(MANDOCERR_ARG_QUOTE, ln, *pos, NULL);
1658
1659         /* NUL-terminate this argument and move to the next one. */
1660         if (pairs)
1661                 cp[-pairs] = '\0';
1662         if ('\0' != *cp) {
1663                 *cp++ = '\0';
1664                 while (' ' == *cp)
1665                         cp++;
1666         }
1667         *pos += (int)(cp - start) + (quoted ? 1 : 0);
1668         *cpp = cp;
1669
1670         if ('\0' == *cp && (white || ' ' == cp[-1]))
1671                 mandoc_msg(MANDOCERR_SPACE_EOL, ln, *pos, NULL);
1672
1673         start = mandoc_strdup(start);
1674         if (newesc == 0)
1675                 return start;
1676
1677         buf.buf = start;
1678         buf.sz = strlen(start) + 1;
1679         buf.next = NULL;
1680         if (roff_expand(r, &buf, ln, 0, ASCII_ESC) & ROFF_IGN) {
1681                 free(buf.buf);
1682                 buf.buf = mandoc_strdup("");
1683         }
1684         return buf.buf;
1685 }
1686
1687
1688 /*
1689  * Process text streams.
1690  */
1691 static int
1692 roff_parsetext(struct roff *r, struct buf *buf, int pos, int *offs)
1693 {
1694         size_t           sz;
1695         const char      *start;
1696         char            *p;
1697         int              isz;
1698         enum mandoc_esc  esc;
1699
1700         /* Spring the input line trap. */
1701
1702         if (roffit_lines == 1) {
1703                 isz = mandoc_asprintf(&p, "%s\n.%s", buf->buf, roffit_macro);
1704                 free(buf->buf);
1705                 buf->buf = p;
1706                 buf->sz = isz + 1;
1707                 *offs = 0;
1708                 free(roffit_macro);
1709                 roffit_lines = 0;
1710                 return ROFF_REPARSE;
1711         } else if (roffit_lines > 1)
1712                 --roffit_lines;
1713
1714         if (roffce_node != NULL && buf->buf[pos] != '\0') {
1715                 if (roffce_lines < 1) {
1716                         r->man->last = roffce_node;
1717                         r->man->next = ROFF_NEXT_SIBLING;
1718                         roffce_lines = 0;
1719                         roffce_node = NULL;
1720                 } else
1721                         roffce_lines--;
1722         }
1723
1724         /* Convert all breakable hyphens into ASCII_HYPH. */
1725
1726         start = p = buf->buf + pos;
1727
1728         while (*p != '\0') {
1729                 sz = strcspn(p, "-\\");
1730                 p += sz;
1731
1732                 if (*p == '\0')
1733                         break;
1734
1735                 if (*p == '\\') {
1736                         /* Skip over escapes. */
1737                         p++;
1738                         esc = mandoc_escape((const char **)&p, NULL, NULL);
1739                         if (esc == ESCAPE_ERROR)
1740                                 break;
1741                         while (*p == '-')
1742                                 p++;
1743                         continue;
1744                 } else if (p == start) {
1745                         p++;
1746                         continue;
1747                 }
1748
1749                 if (isalpha((unsigned char)p[-1]) &&
1750                     isalpha((unsigned char)p[1]))
1751                         *p = ASCII_HYPH;
1752                 p++;
1753         }
1754         return ROFF_CONT;
1755 }
1756
1757 int
1758 roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
1759 {
1760         enum roff_tok    t;
1761         int              e;
1762         int              pos;   /* parse point */
1763         int              spos;  /* saved parse point for messages */
1764         int              ppos;  /* original offset in buf->buf */
1765         int              ctl;   /* macro line (boolean) */
1766
1767         ppos = pos = *offs;
1768
1769         /* Handle in-line equation delimiters. */
1770
1771         if (r->tbl == NULL &&
1772             r->last_eqn != NULL && r->last_eqn->delim &&
1773             (r->eqn == NULL || r->eqn_inline)) {
1774                 e = roff_eqndelim(r, buf, pos);
1775                 if (e == ROFF_REPARSE)
1776                         return e;
1777                 assert(e == ROFF_CONT);
1778         }
1779
1780         /* Expand some escape sequences. */
1781
1782         e = roff_expand(r, buf, ln, pos, r->escape);
1783         if ((e & ROFF_MASK) == ROFF_IGN)
1784                 return e;
1785         assert(e == ROFF_CONT);
1786
1787         ctl = roff_getcontrol(r, buf->buf, &pos);
1788
1789         /*
1790          * First, if a scope is open and we're not a macro, pass the
1791          * text through the macro's filter.
1792          * Equations process all content themselves.
1793          * Tables process almost all content themselves, but we want
1794          * to warn about macros before passing it there.
1795          */
1796
1797         if (r->last != NULL && ! ctl) {
1798                 t = r->last->tok;
1799                 e = (*roffs[t].text)(r, t, buf, ln, pos, pos, offs);
1800                 if ((e & ROFF_MASK) == ROFF_IGN)
1801                         return e;
1802                 e &= ~ROFF_MASK;
1803         } else
1804                 e = ROFF_IGN;
1805         if (r->eqn != NULL && strncmp(buf->buf + ppos, ".EN", 3)) {
1806                 eqn_read(r->eqn, buf->buf + ppos);
1807                 return e;
1808         }
1809         if (r->tbl != NULL && (ctl == 0 || buf->buf[pos] == '\0')) {
1810                 tbl_read(r->tbl, ln, buf->buf, ppos);
1811                 roff_addtbl(r->man, ln, r->tbl);
1812                 return e;
1813         }
1814         if ( ! ctl)
1815                 return roff_parsetext(r, buf, pos, offs) | e;
1816
1817         /* Skip empty request lines. */
1818
1819         if (buf->buf[pos] == '"') {
1820                 mandoc_msg(MANDOCERR_COMMENT_BAD, ln, pos, NULL);
1821                 return ROFF_IGN;
1822         } else if (buf->buf[pos] == '\0')
1823                 return ROFF_IGN;
1824
1825         /*
1826          * If a scope is open, go to the child handler for that macro,
1827          * as it may want to preprocess before doing anything with it.
1828          * Don't do so if an equation is open.
1829          */
1830
1831         if (r->last) {
1832                 t = r->last->tok;
1833                 return (*roffs[t].sub)(r, t, buf, ln, ppos, pos, offs);
1834         }
1835
1836         /* No scope is open.  This is a new request or macro. */
1837
1838         spos = pos;
1839         t = roff_parse(r, buf->buf, &pos, ln, ppos);
1840
1841         /* Tables ignore most macros. */
1842
1843         if (r->tbl != NULL && (t == TOKEN_NONE || t == ROFF_TS ||
1844             t == ROFF_br || t == ROFF_ce || t == ROFF_rj || t == ROFF_sp)) {
1845                 mandoc_msg(MANDOCERR_TBLMACRO,
1846                     ln, pos, "%s", buf->buf + spos);
1847                 if (t != TOKEN_NONE)
1848                         return ROFF_IGN;
1849                 while (buf->buf[pos] != '\0' && buf->buf[pos] != ' ')
1850                         pos++;
1851                 while (buf->buf[pos] == ' ')
1852                         pos++;
1853                 tbl_read(r->tbl, ln, buf->buf, pos);
1854                 roff_addtbl(r->man, ln, r->tbl);
1855                 return ROFF_IGN;
1856         }
1857
1858         /* For now, let high level macros abort .ce mode. */
1859
1860         if (ctl && roffce_node != NULL &&
1861             (t == TOKEN_NONE || t == ROFF_Dd || t == ROFF_EQ ||
1862              t == ROFF_TH || t == ROFF_TS)) {
1863                 r->man->last = roffce_node;
1864                 r->man->next = ROFF_NEXT_SIBLING;
1865                 roffce_lines = 0;
1866                 roffce_node = NULL;
1867         }
1868
1869         /*
1870          * This is neither a roff request nor a user-defined macro.
1871          * Let the standard macro set parsers handle it.
1872          */
1873
1874         if (t == TOKEN_NONE)
1875                 return ROFF_CONT;
1876
1877         /* Execute a roff request or a user defined macro. */
1878
1879         return (*roffs[t].proc)(r, t, buf, ln, spos, pos, offs);
1880 }
1881
1882 /*
1883  * Internal interface function to tell the roff parser that execution
1884  * of the current macro ended.  This is required because macro
1885  * definitions usually do not end with a .return request.
1886  */
1887 void
1888 roff_userret(struct roff *r)
1889 {
1890         struct mctx     *ctx;
1891         int              i;
1892
1893         assert(r->mstackpos >= 0);
1894         ctx = r->mstack + r->mstackpos;
1895         for (i = 0; i < ctx->argc; i++)
1896                 free(ctx->argv[i]);
1897         ctx->argc = 0;
1898         r->mstackpos--;
1899 }
1900
1901 void
1902 roff_endparse(struct roff *r)
1903 {
1904         if (r->last != NULL)
1905                 mandoc_msg(MANDOCERR_BLK_NOEND, r->last->line,
1906                     r->last->col, "%s", roff_name[r->last->tok]);
1907
1908         if (r->eqn != NULL) {
1909                 mandoc_msg(MANDOCERR_BLK_NOEND,
1910                     r->eqn->node->line, r->eqn->node->pos, "EQ");
1911                 eqn_parse(r->eqn);
1912                 r->eqn = NULL;
1913         }
1914
1915         if (r->tbl != NULL) {
1916                 tbl_end(r->tbl, 1);
1917                 r->tbl = NULL;
1918         }
1919 }
1920
1921 /*
1922  * Parse a roff node's type from the input buffer.  This must be in the
1923  * form of ".foo xxx" in the usual way.
1924  */
1925 static enum roff_tok
1926 roff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos)
1927 {
1928         char            *cp;
1929         const char      *mac;
1930         size_t           maclen;
1931         int              deftype;
1932         enum roff_tok    t;
1933
1934         cp = buf + *pos;
1935
1936         if ('\0' == *cp || '"' == *cp || '\t' == *cp || ' ' == *cp)
1937                 return TOKEN_NONE;
1938
1939         mac = cp;
1940         maclen = roff_getname(r, &cp, ln, ppos);
1941
1942         deftype = ROFFDEF_USER | ROFFDEF_REN;
1943         r->current_string = roff_getstrn(r, mac, maclen, &deftype);
1944         switch (deftype) {
1945         case ROFFDEF_USER:
1946                 t = ROFF_USERDEF;
1947                 break;
1948         case ROFFDEF_REN:
1949                 t = ROFF_RENAMED;
1950                 break;
1951         default:
1952                 t = roffhash_find(r->reqtab, mac, maclen);
1953                 break;
1954         }
1955         if (t != TOKEN_NONE)
1956                 *pos = cp - buf;
1957         else if (deftype == ROFFDEF_UNDEF) {
1958                 /* Using an undefined macro defines it to be empty. */
1959                 roff_setstrn(&r->strtab, mac, maclen, "", 0, 0);
1960                 roff_setstrn(&r->rentab, mac, maclen, NULL, 0, 0);
1961         }
1962         return t;
1963 }
1964
1965 /* --- handling of request blocks ----------------------------------------- */
1966
1967 static int
1968 roff_cblock(ROFF_ARGS)
1969 {
1970
1971         /*
1972          * A block-close `..' should only be invoked as a child of an
1973          * ignore macro, otherwise raise a warning and just ignore it.
1974          */
1975
1976         if (r->last == NULL) {
1977                 mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "..");
1978                 return ROFF_IGN;
1979         }
1980
1981         switch (r->last->tok) {
1982         case ROFF_am:
1983                 /* ROFF_am1 is remapped to ROFF_am in roff_block(). */
1984         case ROFF_ami:
1985         case ROFF_de:
1986                 /* ROFF_de1 is remapped to ROFF_de in roff_block(). */
1987         case ROFF_dei:
1988         case ROFF_ig:
1989                 break;
1990         default:
1991                 mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "..");
1992                 return ROFF_IGN;
1993         }
1994
1995         if (buf->buf[pos] != '\0')
1996                 mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos,
1997                     ".. %s", buf->buf + pos);
1998
1999         roffnode_pop(r);
2000         roffnode_cleanscope(r);
2001         return ROFF_IGN;
2002
2003 }
2004
2005 static int
2006 roffnode_cleanscope(struct roff *r)
2007 {
2008         int inloop;
2009
2010         inloop = 0;
2011         while (r->last != NULL) {
2012                 if (--r->last->endspan != 0)
2013                         break;
2014                 inloop += roffnode_pop(r);
2015         }
2016         return inloop;
2017 }
2018
2019 static int
2020 roff_ccond(struct roff *r, int ln, int ppos)
2021 {
2022         if (NULL == r->last) {
2023                 mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "\\}");
2024                 return 0;
2025         }
2026
2027         switch (r->last->tok) {
2028         case ROFF_el:
2029         case ROFF_ie:
2030         case ROFF_if:
2031         case ROFF_while:
2032                 break;
2033         default:
2034                 mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "\\}");
2035                 return 0;
2036         }
2037
2038         if (r->last->endspan > -1) {
2039                 mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "\\}");
2040                 return 0;
2041         }
2042
2043         return roffnode_pop(r) + roffnode_cleanscope(r);
2044 }
2045
2046 static int
2047 roff_block(ROFF_ARGS)
2048 {
2049         const char      *name, *value;
2050         char            *call, *cp, *iname, *rname;
2051         size_t           csz, namesz, rsz;
2052         int              deftype;
2053
2054         /* Ignore groff compatibility mode for now. */
2055
2056         if (tok == ROFF_de1)
2057                 tok = ROFF_de;
2058         else if (tok == ROFF_dei1)
2059                 tok = ROFF_dei;
2060         else if (tok == ROFF_am1)
2061                 tok = ROFF_am;
2062         else if (tok == ROFF_ami1)
2063                 tok = ROFF_ami;
2064
2065         /* Parse the macro name argument. */
2066
2067         cp = buf->buf + pos;
2068         if (tok == ROFF_ig) {
2069                 iname = NULL;
2070                 namesz = 0;
2071         } else {
2072                 iname = cp;
2073                 namesz = roff_getname(r, &cp, ln, ppos);
2074                 iname[namesz] = '\0';
2075         }
2076
2077         /* Resolve the macro name argument if it is indirect. */
2078
2079         if (namesz && (tok == ROFF_dei || tok == ROFF_ami)) {
2080                 deftype = ROFFDEF_USER;
2081                 name = roff_getstrn(r, iname, namesz, &deftype);
2082                 if (name == NULL) {
2083                         mandoc_msg(MANDOCERR_STR_UNDEF,
2084                             ln, (int)(iname - buf->buf),
2085                             "%.*s", (int)namesz, iname);
2086                         namesz = 0;
2087                 } else
2088                         namesz = strlen(name);
2089         } else
2090                 name = iname;
2091
2092         if (namesz == 0 && tok != ROFF_ig) {
2093                 mandoc_msg(MANDOCERR_REQ_EMPTY,
2094                     ln, ppos, "%s", roff_name[tok]);
2095                 return ROFF_IGN;
2096         }
2097
2098         roffnode_push(r, tok, name, ln, ppos);
2099
2100         /*
2101          * At the beginning of a `de' macro, clear the existing string
2102          * with the same name, if there is one.  New content will be
2103          * appended from roff_block_text() in multiline mode.
2104          */
2105
2106         if (tok == ROFF_de || tok == ROFF_dei) {
2107                 roff_setstrn(&r->strtab, name, namesz, "", 0, 0);
2108                 roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0);
2109         } else if (tok == ROFF_am || tok == ROFF_ami) {
2110                 deftype = ROFFDEF_ANY;
2111                 value = roff_getstrn(r, iname, namesz, &deftype);
2112                 switch (deftype) {  /* Before appending, ... */
2113                 case ROFFDEF_PRE: /* copy predefined to user-defined. */
2114                         roff_setstrn(&r->strtab, name, namesz,
2115                             value, strlen(value), 0);
2116                         break;
2117                 case ROFFDEF_REN: /* call original standard macro. */
2118                         csz = mandoc_asprintf(&call, ".%.*s \\$* \\\"\n",
2119                             (int)strlen(value), value);
2120                         roff_setstrn(&r->strtab, name, namesz, call, csz, 0);
2121                         roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0);
2122                         free(call);
2123                         break;
2124                 case ROFFDEF_STD:  /* rename and call standard macro. */
2125                         rsz = mandoc_asprintf(&rname, "__%s_renamed", name);
2126                         roff_setstrn(&r->rentab, rname, rsz, name, namesz, 0);
2127                         csz = mandoc_asprintf(&call, ".%.*s \\$* \\\"\n",
2128                             (int)rsz, rname);
2129                         roff_setstrn(&r->strtab, name, namesz, call, csz, 0);
2130                         free(call);
2131                         free(rname);
2132                         break;
2133                 default:
2134                         break;
2135                 }
2136         }
2137
2138         if (*cp == '\0')
2139                 return ROFF_IGN;
2140
2141         /* Get the custom end marker. */
2142
2143         iname = cp;
2144         namesz = roff_getname(r, &cp, ln, ppos);
2145
2146         /* Resolve the end marker if it is indirect. */
2147
2148         if (namesz && (tok == ROFF_dei || tok == ROFF_ami)) {
2149                 deftype = ROFFDEF_USER;
2150                 name = roff_getstrn(r, iname, namesz, &deftype);
2151                 if (name == NULL) {
2152                         mandoc_msg(MANDOCERR_STR_UNDEF,
2153                             ln, (int)(iname - buf->buf),
2154                             "%.*s", (int)namesz, iname);
2155                         namesz = 0;
2156                 } else
2157                         namesz = strlen(name);
2158         } else
2159                 name = iname;
2160
2161         if (namesz)
2162                 r->last->end = mandoc_strndup(name, namesz);
2163
2164         if (*cp != '\0')
2165                 mandoc_msg(MANDOCERR_ARG_EXCESS,
2166                     ln, pos, ".%s ... %s", roff_name[tok], cp);
2167
2168         return ROFF_IGN;
2169 }
2170
2171 static int
2172 roff_block_sub(ROFF_ARGS)
2173 {
2174         enum roff_tok   t;
2175         int             i, j;
2176
2177         /*
2178          * First check whether a custom macro exists at this level.  If
2179          * it does, then check against it.  This is some of groff's
2180          * stranger behaviours.  If we encountered a custom end-scope
2181          * tag and that tag also happens to be a "real" macro, then we
2182          * need to try interpreting it again as a real macro.  If it's
2183          * not, then return ignore.  Else continue.
2184          */
2185
2186         if (r->last->end) {
2187                 for (i = pos, j = 0; r->last->end[j]; j++, i++)
2188                         if (buf->buf[i] != r->last->end[j])
2189                                 break;
2190
2191                 if (r->last->end[j] == '\0' &&
2192                     (buf->buf[i] == '\0' ||
2193                      buf->buf[i] == ' ' ||
2194                      buf->buf[i] == '\t')) {
2195                         roffnode_pop(r);
2196                         roffnode_cleanscope(r);
2197
2198                         while (buf->buf[i] == ' ' || buf->buf[i] == '\t')
2199                                 i++;
2200
2201                         pos = i;
2202                         if (roff_parse(r, buf->buf, &pos, ln, ppos) !=
2203                             TOKEN_NONE)
2204                                 return ROFF_RERUN;
2205                         return ROFF_IGN;
2206                 }
2207         }
2208
2209         /*
2210          * If we have no custom end-query or lookup failed, then try
2211          * pulling it out of the hashtable.
2212          */
2213
2214         t = roff_parse(r, buf->buf, &pos, ln, ppos);
2215
2216         if (t != ROFF_cblock) {
2217                 if (tok != ROFF_ig)
2218                         roff_setstr(r, r->last->name, buf->buf + ppos, 2);
2219                 return ROFF_IGN;
2220         }
2221
2222         return (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs);
2223 }
2224
2225 static int
2226 roff_block_text(ROFF_ARGS)
2227 {
2228
2229         if (tok != ROFF_ig)
2230                 roff_setstr(r, r->last->name, buf->buf + pos, 2);
2231
2232         return ROFF_IGN;
2233 }
2234
2235 static int
2236 roff_cond_sub(ROFF_ARGS)
2237 {
2238         char            *ep;
2239         int              endloop, irc, rr;
2240         enum roff_tok    t;
2241
2242         irc = ROFF_IGN;
2243         rr = r->last->rule;
2244         endloop = tok != ROFF_while ? ROFF_IGN :
2245             rr ? ROFF_LOOPCONT : ROFF_LOOPEXIT;
2246         if (roffnode_cleanscope(r))
2247                 irc |= endloop;
2248
2249         /*
2250          * If `\}' occurs on a macro line without a preceding macro,
2251          * drop the line completely.
2252          */
2253
2254         ep = buf->buf + pos;
2255         if (ep[0] == '\\' && ep[1] == '}')
2256                 rr = 0;
2257
2258         /*
2259          * The closing delimiter `\}' rewinds the conditional scope
2260          * but is otherwise ignored when interpreting the line.
2261          */
2262
2263         while ((ep = strchr(ep, '\\')) != NULL) {
2264                 switch (ep[1]) {
2265                 case '}':
2266                         memmove(ep, ep + 2, strlen(ep + 2) + 1);
2267                         if (roff_ccond(r, ln, ep - buf->buf))
2268                                 irc |= endloop;
2269                         break;
2270                 case '\0':
2271                         ++ep;
2272                         break;
2273                 default:
2274                         ep += 2;
2275                         break;
2276                 }
2277         }
2278
2279         /*
2280          * Fully handle known macros when they are structurally
2281          * required or when the conditional evaluated to true.
2282          */
2283
2284         t = roff_parse(r, buf->buf, &pos, ln, ppos);
2285         irc |= t != TOKEN_NONE && (rr || roffs[t].flags & ROFFMAC_STRUCT) ?
2286             (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs) :
2287             rr ? ROFF_CONT : ROFF_IGN;
2288         return irc;
2289 }
2290
2291 static int
2292 roff_cond_text(ROFF_ARGS)
2293 {
2294         char            *ep;
2295         int              endloop, irc, rr;
2296
2297         irc = ROFF_IGN;
2298         rr = r->last->rule;
2299         endloop = tok != ROFF_while ? ROFF_IGN :
2300             rr ? ROFF_LOOPCONT : ROFF_LOOPEXIT;
2301         if (roffnode_cleanscope(r))
2302                 irc |= endloop;
2303
2304         /*
2305          * If `\}' occurs on a text line with neither preceding
2306          * nor following characters, drop the line completely.
2307          */
2308
2309         ep = buf->buf + pos;
2310         if (strcmp(ep, "\\}") == 0)
2311                 rr = 0;
2312
2313         /*
2314          * The closing delimiter `\}' rewinds the conditional scope
2315          * but is otherwise ignored when interpreting the line.
2316          */
2317
2318         while ((ep = strchr(ep, '\\')) != NULL) {
2319                 switch (ep[1]) {
2320                 case '}':
2321                         memmove(ep, ep + 2, strlen(ep + 2) + 1);
2322                         if (roff_ccond(r, ln, ep - buf->buf))
2323                                 irc |= endloop;
2324                         break;
2325                 case '\0':
2326                         ++ep;
2327                         break;
2328                 default:
2329                         ep += 2;
2330                         break;
2331                 }
2332         }
2333         if (rr)
2334                 irc |= ROFF_CONT;
2335         return irc;
2336 }
2337
2338 /* --- handling of numeric and conditional expressions -------------------- */
2339
2340 /*
2341  * Parse a single signed integer number.  Stop at the first non-digit.
2342  * If there is at least one digit, return success and advance the
2343  * parse point, else return failure and let the parse point unchanged.
2344  * Ignore overflows, treat them just like the C language.
2345  */
2346 static int
2347 roff_getnum(const char *v, int *pos, int *res, int flags)
2348 {
2349         int      myres, scaled, n, p;
2350
2351         if (NULL == res)
2352                 res = &myres;
2353
2354         p = *pos;
2355         n = v[p] == '-';
2356         if (n || v[p] == '+')
2357                 p++;
2358
2359         if (flags & ROFFNUM_WHITE)
2360                 while (isspace((unsigned char)v[p]))
2361                         p++;
2362
2363         for (*res = 0; isdigit((unsigned char)v[p]); p++)
2364                 *res = 10 * *res + v[p] - '0';
2365         if (p == *pos + n)
2366                 return 0;
2367
2368         if (n)
2369                 *res = -*res;
2370
2371         /* Each number may be followed by one optional scaling unit. */
2372
2373         switch (v[p]) {
2374         case 'f':
2375                 scaled = *res * 65536;
2376                 break;
2377         case 'i':
2378                 scaled = *res * 240;
2379                 break;
2380         case 'c':
2381                 scaled = *res * 240 / 2.54;
2382                 break;
2383         case 'v':
2384         case 'P':
2385                 scaled = *res * 40;
2386                 break;
2387         case 'm':
2388         case 'n':
2389                 scaled = *res * 24;
2390                 break;
2391         case 'p':
2392                 scaled = *res * 10 / 3;
2393                 break;
2394         case 'u':
2395                 scaled = *res;
2396                 break;
2397         case 'M':
2398                 scaled = *res * 6 / 25;
2399                 break;
2400         default:
2401                 scaled = *res;
2402                 p--;
2403                 break;
2404         }
2405         if (flags & ROFFNUM_SCALE)
2406                 *res = scaled;
2407
2408         *pos = p + 1;
2409         return 1;
2410 }
2411
2412 /*
2413  * Evaluate a string comparison condition.
2414  * The first character is the delimiter.
2415  * Succeed if the string up to its second occurrence
2416  * matches the string up to its third occurence.
2417  * Advance the cursor after the third occurrence
2418  * or lacking that, to the end of the line.
2419  */
2420 static int
2421 roff_evalstrcond(const char *v, int *pos)
2422 {
2423         const char      *s1, *s2, *s3;
2424         int              match;
2425
2426         match = 0;
2427         s1 = v + *pos;          /* initial delimiter */
2428         s2 = s1 + 1;            /* for scanning the first string */
2429         s3 = strchr(s2, *s1);   /* for scanning the second string */
2430
2431         if (NULL == s3)         /* found no middle delimiter */
2432                 goto out;
2433
2434         while ('\0' != *++s3) {
2435                 if (*s2 != *s3) {  /* mismatch */
2436                         s3 = strchr(s3, *s1);
2437                         break;
2438                 }
2439                 if (*s3 == *s1) {  /* found the final delimiter */
2440                         match = 1;
2441                         break;
2442                 }
2443                 s2++;
2444         }
2445
2446 out:
2447         if (NULL == s3)
2448                 s3 = strchr(s2, '\0');
2449         else if (*s3 != '\0')
2450                 s3++;
2451         *pos = s3 - v;
2452         return match;
2453 }
2454
2455 /*
2456  * Evaluate an optionally negated single character, numerical,
2457  * or string condition.
2458  */
2459 static int
2460 roff_evalcond(struct roff *r, int ln, char *v, int *pos)
2461 {
2462         const char      *start, *end;
2463         char            *cp, *name;
2464         size_t           sz;
2465         int              deftype, len, number, savepos, istrue, wanttrue;
2466
2467         if ('!' == v[*pos]) {
2468                 wanttrue = 0;
2469                 (*pos)++;
2470         } else
2471                 wanttrue = 1;
2472
2473         switch (v[*pos]) {
2474         case '\0':
2475                 return 0;
2476         case 'n':
2477         case 'o':
2478                 (*pos)++;
2479                 return wanttrue;
2480         case 'e':
2481         case 't':
2482         case 'v':
2483                 (*pos)++;
2484                 return !wanttrue;
2485         case 'c':
2486                 do {
2487                         (*pos)++;
2488                 } while (v[*pos] == ' ');
2489
2490                 /*
2491                  * Quirk for groff compatibility:
2492                  * The horizontal tab is neither available nor unavailable.
2493                  */
2494
2495                 if (v[*pos] == '\t') {
2496                         (*pos)++;
2497                         return 0;
2498                 }
2499
2500                 /* Printable ASCII characters are available. */
2501
2502                 if (v[*pos] != '\\') {
2503                         (*pos)++;
2504                         return wanttrue;
2505                 }
2506
2507                 end = v + ++*pos;
2508                 switch (mandoc_escape(&end, &start, &len)) {
2509                 case ESCAPE_SPECIAL:
2510                         istrue = mchars_spec2cp(start, len) != -1;
2511                         break;
2512                 case ESCAPE_UNICODE:
2513                         istrue = 1;
2514                         break;
2515                 case ESCAPE_NUMBERED:
2516                         istrue = mchars_num2char(start, len) != -1;
2517                         break;
2518                 default:
2519                         istrue = !wanttrue;
2520                         break;
2521                 }
2522                 *pos = end - v;
2523                 return istrue == wanttrue;
2524         case 'd':
2525         case 'r':
2526                 cp = v + *pos + 1;
2527                 while (*cp == ' ')
2528                         cp++;
2529                 name = cp;
2530                 sz = roff_getname(r, &cp, ln, cp - v);
2531                 if (sz == 0)
2532                         istrue = 0;
2533                 else if (v[*pos] == 'r')
2534                         istrue = roff_hasregn(r, name, sz);
2535                 else {
2536                         deftype = ROFFDEF_ANY;
2537                         roff_getstrn(r, name, sz, &deftype);
2538                         istrue = !!deftype;
2539                 }
2540                 *pos = (name + sz) - v;
2541                 return istrue == wanttrue;
2542         default:
2543                 break;
2544         }
2545
2546         savepos = *pos;
2547         if (roff_evalnum(r, ln, v, pos, &number, ROFFNUM_SCALE))
2548                 return (number > 0) == wanttrue;
2549         else if (*pos == savepos)
2550                 return roff_evalstrcond(v, pos) == wanttrue;
2551         else
2552                 return 0;
2553 }
2554
2555 static int
2556 roff_line_ignore(ROFF_ARGS)
2557 {
2558
2559         return ROFF_IGN;
2560 }
2561
2562 static int
2563 roff_insec(ROFF_ARGS)
2564 {
2565
2566         mandoc_msg(MANDOCERR_REQ_INSEC, ln, ppos, "%s", roff_name[tok]);
2567         return ROFF_IGN;
2568 }
2569
2570 static int
2571 roff_unsupp(ROFF_ARGS)
2572 {
2573
2574         mandoc_msg(MANDOCERR_REQ_UNSUPP, ln, ppos, "%s", roff_name[tok]);
2575         return ROFF_IGN;
2576 }
2577
2578 static int
2579 roff_cond(ROFF_ARGS)
2580 {
2581         int      irc;
2582
2583         roffnode_push(r, tok, NULL, ln, ppos);
2584
2585         /*
2586          * An `.el' has no conditional body: it will consume the value
2587          * of the current rstack entry set in prior `ie' calls or
2588          * defaults to DENY.
2589          *
2590          * If we're not an `el', however, then evaluate the conditional.
2591          */
2592
2593         r->last->rule = tok == ROFF_el ?
2594             (r->rstackpos < 0 ? 0 : r->rstack[r->rstackpos--]) :
2595             roff_evalcond(r, ln, buf->buf, &pos);
2596
2597         /*
2598          * An if-else will put the NEGATION of the current evaluated
2599          * conditional into the stack of rules.
2600          */
2601
2602         if (tok == ROFF_ie) {
2603                 if (r->rstackpos + 1 == r->rstacksz) {
2604                         r->rstacksz += 16;
2605                         r->rstack = mandoc_reallocarray(r->rstack,
2606                             r->rstacksz, sizeof(int));
2607                 }
2608                 r->rstack[++r->rstackpos] = !r->last->rule;
2609         }
2610
2611         /* If the parent has false as its rule, then so do we. */
2612
2613         if (r->last->parent && !r->last->parent->rule)
2614                 r->last->rule = 0;
2615
2616         /*
2617          * Determine scope.
2618          * If there is nothing on the line after the conditional,
2619          * not even whitespace, use next-line scope.
2620          * Except that .while does not support next-line scope.
2621          */
2622
2623         if (buf->buf[pos] == '\0' && tok != ROFF_while) {
2624                 r->last->endspan = 2;
2625                 goto out;
2626         }
2627
2628         while (buf->buf[pos] == ' ')
2629                 pos++;
2630
2631         /* An opening brace requests multiline scope. */
2632
2633         if (buf->buf[pos] == '\\' && buf->buf[pos + 1] == '{') {
2634                 r->last->endspan = -1;
2635                 pos += 2;
2636                 while (buf->buf[pos] == ' ')
2637                         pos++;
2638                 goto out;
2639         }
2640
2641         /*
2642          * Anything else following the conditional causes
2643          * single-line scope.  Warn if the scope contains
2644          * nothing but trailing whitespace.
2645          */
2646
2647         if (buf->buf[pos] == '\0')
2648                 mandoc_msg(MANDOCERR_COND_EMPTY,
2649                     ln, ppos, "%s", roff_name[tok]);
2650
2651         r->last->endspan = 1;
2652
2653 out:
2654         *offs = pos;
2655         irc = ROFF_RERUN;
2656         if (tok == ROFF_while)
2657                 irc |= ROFF_WHILE;
2658         return irc;
2659 }
2660
2661 static int
2662 roff_ds(ROFF_ARGS)
2663 {
2664         char            *string;
2665         const char      *name;
2666         size_t           namesz;
2667
2668         /* Ignore groff compatibility mode for now. */
2669
2670         if (tok == ROFF_ds1)
2671                 tok = ROFF_ds;
2672         else if (tok == ROFF_as1)
2673                 tok = ROFF_as;
2674
2675         /*
2676          * The first word is the name of the string.
2677          * If it is empty or terminated by an escape sequence,
2678          * abort the `ds' request without defining anything.
2679          */
2680
2681         name = string = buf->buf + pos;
2682         if (*name == '\0')
2683                 return ROFF_IGN;
2684
2685         namesz = roff_getname(r, &string, ln, pos);
2686         switch (name[namesz]) {
2687         case '\\':
2688                 return ROFF_IGN;
2689         case '\t':
2690                 string = buf->buf + pos + namesz;
2691                 break;
2692         default:
2693                 break;
2694         }
2695
2696         /* Read past the initial double-quote, if any. */
2697         if (*string == '"')
2698                 string++;
2699
2700         /* The rest is the value. */
2701         roff_setstrn(&r->strtab, name, namesz, string, strlen(string),
2702             ROFF_as == tok);
2703         roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0);
2704         return ROFF_IGN;
2705 }
2706
2707 /*
2708  * Parse a single operator, one or two characters long.
2709  * If the operator is recognized, return success and advance the
2710  * parse point, else return failure and let the parse point unchanged.
2711  */
2712 static int
2713 roff_getop(const char *v, int *pos, char *res)
2714 {
2715
2716         *res = v[*pos];
2717
2718         switch (*res) {
2719         case '+':
2720         case '-':
2721         case '*':
2722         case '/':
2723         case '%':
2724         case '&':
2725         case ':':
2726                 break;
2727         case '<':
2728                 switch (v[*pos + 1]) {
2729                 case '=':
2730                         *res = 'l';
2731                         (*pos)++;
2732                         break;
2733                 case '>':
2734                         *res = '!';
2735                         (*pos)++;
2736                         break;
2737                 case '?':
2738                         *res = 'i';
2739                         (*pos)++;
2740                         break;
2741                 default:
2742                         break;
2743                 }
2744                 break;
2745         case '>':
2746                 switch (v[*pos + 1]) {
2747                 case '=':
2748                         *res = 'g';
2749                         (*pos)++;
2750                         break;
2751                 case '?':
2752                         *res = 'a';
2753                         (*pos)++;
2754                         break;
2755                 default:
2756                         break;
2757                 }
2758                 break;
2759         case '=':
2760                 if ('=' == v[*pos + 1])
2761                         (*pos)++;
2762                 break;
2763         default:
2764                 return 0;
2765         }
2766         (*pos)++;
2767
2768         return *res;
2769 }
2770
2771 /*
2772  * Evaluate either a parenthesized numeric expression
2773  * or a single signed integer number.
2774  */
2775 static int
2776 roff_evalpar(struct roff *r, int ln,
2777         const char *v, int *pos, int *res, int flags)
2778 {
2779
2780         if ('(' != v[*pos])
2781                 return roff_getnum(v, pos, res, flags);
2782
2783         (*pos)++;
2784         if ( ! roff_evalnum(r, ln, v, pos, res, flags | ROFFNUM_WHITE))
2785                 return 0;
2786
2787         /*
2788          * Omission of the closing parenthesis
2789          * is an error in validation mode,
2790          * but ignored in evaluation mode.
2791          */
2792
2793         if (')' == v[*pos])
2794                 (*pos)++;
2795         else if (NULL == res)
2796                 return 0;
2797
2798         return 1;
2799 }
2800
2801 /*
2802  * Evaluate a complete numeric expression.
2803  * Proceed left to right, there is no concept of precedence.
2804  */
2805 static int
2806 roff_evalnum(struct roff *r, int ln, const char *v,
2807         int *pos, int *res, int flags)
2808 {
2809         int              mypos, operand2;
2810         char             operator;
2811
2812         if (NULL == pos) {
2813                 mypos = 0;
2814                 pos = &mypos;
2815         }
2816
2817         if (flags & ROFFNUM_WHITE)
2818                 while (isspace((unsigned char)v[*pos]))
2819                         (*pos)++;
2820
2821         if ( ! roff_evalpar(r, ln, v, pos, res, flags))
2822                 return 0;
2823
2824         while (1) {
2825                 if (flags & ROFFNUM_WHITE)
2826                         while (isspace((unsigned char)v[*pos]))
2827                                 (*pos)++;
2828
2829                 if ( ! roff_getop(v, pos, &operator))
2830                         break;
2831
2832                 if (flags & ROFFNUM_WHITE)
2833                         while (isspace((unsigned char)v[*pos]))
2834                                 (*pos)++;
2835
2836                 if ( ! roff_evalpar(r, ln, v, pos, &operand2, flags))
2837                         return 0;
2838
2839                 if (flags & ROFFNUM_WHITE)
2840                         while (isspace((unsigned char)v[*pos]))
2841                                 (*pos)++;
2842
2843                 if (NULL == res)
2844                         continue;
2845
2846                 switch (operator) {
2847                 case '+':
2848                         *res += operand2;
2849                         break;
2850                 case '-':
2851                         *res -= operand2;
2852                         break;
2853                 case '*':
2854                         *res *= operand2;
2855                         break;
2856                 case '/':
2857                         if (operand2 == 0) {
2858                                 mandoc_msg(MANDOCERR_DIVZERO,
2859                                         ln, *pos, "%s", v);
2860                                 *res = 0;
2861                                 break;
2862                         }
2863                         *res /= operand2;
2864                         break;
2865                 case '%':
2866                         if (operand2 == 0) {
2867                                 mandoc_msg(MANDOCERR_DIVZERO,
2868                                         ln, *pos, "%s", v);
2869                                 *res = 0;
2870                                 break;
2871                         }
2872                         *res %= operand2;
2873                         break;
2874                 case '<':
2875                         *res = *res < operand2;
2876                         break;
2877                 case '>':
2878                         *res = *res > operand2;
2879                         break;
2880                 case 'l':
2881                         *res = *res <= operand2;
2882                         break;
2883                 case 'g':
2884                         *res = *res >= operand2;
2885                         break;
2886                 case '=':
2887                         *res = *res == operand2;
2888                         break;
2889                 case '!':
2890                         *res = *res != operand2;
2891                         break;
2892                 case '&':
2893                         *res = *res && operand2;
2894                         break;
2895                 case ':':
2896                         *res = *res || operand2;
2897                         break;
2898                 case 'i':
2899                         if (operand2 < *res)
2900                                 *res = operand2;
2901                         break;
2902                 case 'a':
2903                         if (operand2 > *res)
2904                                 *res = operand2;
2905                         break;
2906                 default:
2907                         abort();
2908                 }
2909         }
2910         return 1;
2911 }
2912
2913 /* --- register management ------------------------------------------------ */
2914
2915 void
2916 roff_setreg(struct roff *r, const char *name, int val, char sign)
2917 {
2918         roff_setregn(r, name, strlen(name), val, sign, INT_MIN);
2919 }
2920
2921 static void
2922 roff_setregn(struct roff *r, const char *name, size_t len,
2923     int val, char sign, int step)
2924 {
2925         struct roffreg  *reg;
2926
2927         /* Search for an existing register with the same name. */
2928         reg = r->regtab;
2929
2930         while (reg != NULL && (reg->key.sz != len ||
2931             strncmp(reg->key.p, name, len) != 0))
2932                 reg = reg->next;
2933
2934         if (NULL == reg) {
2935                 /* Create a new register. */
2936                 reg = mandoc_malloc(sizeof(struct roffreg));
2937                 reg->key.p = mandoc_strndup(name, len);
2938                 reg->key.sz = len;
2939                 reg->val = 0;
2940                 reg->step = 0;
2941                 reg->next = r->regtab;
2942                 r->regtab = reg;
2943         }
2944
2945         if ('+' == sign)
2946                 reg->val += val;
2947         else if ('-' == sign)
2948                 reg->val -= val;
2949         else
2950                 reg->val = val;
2951         if (step != INT_MIN)
2952                 reg->step = step;
2953 }
2954
2955 /*
2956  * Handle some predefined read-only number registers.
2957  * For now, return -1 if the requested register is not predefined;
2958  * in case a predefined read-only register having the value -1
2959  * were to turn up, another special value would have to be chosen.
2960  */
2961 static int
2962 roff_getregro(const struct roff *r, const char *name)
2963 {
2964
2965         switch (*name) {
2966         case '$':  /* Number of arguments of the last macro evaluated. */
2967                 return r->mstackpos < 0 ? 0 : r->mstack[r->mstackpos].argc;
2968         case 'A':  /* ASCII approximation mode is always off. */
2969                 return 0;
2970         case 'g':  /* Groff compatibility mode is always on. */
2971                 return 1;
2972         case 'H':  /* Fixed horizontal resolution. */
2973                 return 24;
2974         case 'j':  /* Always adjust left margin only. */
2975                 return 0;
2976         case 'T':  /* Some output device is always defined. */
2977                 return 1;
2978         case 'V':  /* Fixed vertical resolution. */
2979                 return 40;
2980         default:
2981                 return -1;
2982         }
2983 }
2984
2985 int
2986 roff_getreg(struct roff *r, const char *name)
2987 {
2988         return roff_getregn(r, name, strlen(name), '\0');
2989 }
2990
2991 static int
2992 roff_getregn(struct roff *r, const char *name, size_t len, char sign)
2993 {
2994         struct roffreg  *reg;
2995         int              val;
2996
2997         if ('.' == name[0] && 2 == len) {
2998                 val = roff_getregro(r, name + 1);
2999                 if (-1 != val)
3000                         return val;
3001         }
3002
3003         for (reg = r->regtab; reg; reg = reg->next) {
3004                 if (len == reg->key.sz &&
3005                     0 == strncmp(name, reg->key.p, len)) {
3006                         switch (sign) {
3007                         case '+':
3008                                 reg->val += reg->step;
3009                                 break;
3010                         case '-':
3011                                 reg->val -= reg->step;
3012                                 break;
3013                         default:
3014                                 break;
3015                         }
3016                         return reg->val;
3017                 }
3018         }
3019
3020         roff_setregn(r, name, len, 0, '\0', INT_MIN);
3021         return 0;
3022 }
3023
3024 static int
3025 roff_hasregn(const struct roff *r, const char *name, size_t len)
3026 {
3027         struct roffreg  *reg;
3028         int              val;
3029
3030         if ('.' == name[0] && 2 == len) {
3031                 val = roff_getregro(r, name + 1);
3032                 if (-1 != val)
3033                         return 1;
3034         }
3035
3036         for (reg = r->regtab; reg; reg = reg->next)
3037                 if (len == reg->key.sz &&
3038                     0 == strncmp(name, reg->key.p, len))
3039                         return 1;
3040
3041         return 0;
3042 }
3043
3044 static void
3045 roff_freereg(struct roffreg *reg)
3046 {
3047         struct roffreg  *old_reg;
3048
3049         while (NULL != reg) {
3050                 free(reg->key.p);
3051                 old_reg = reg;
3052                 reg = reg->next;
3053                 free(old_reg);
3054         }
3055 }
3056
3057 static int
3058 roff_nr(ROFF_ARGS)
3059 {
3060         char            *key, *val, *step;
3061         size_t           keysz;
3062         int              iv, is, len;
3063         char             sign;
3064
3065         key = val = buf->buf + pos;
3066         if (*key == '\0')
3067                 return ROFF_IGN;
3068
3069         keysz = roff_getname(r, &val, ln, pos);
3070         if (key[keysz] == '\\' || key[keysz] == '\t')
3071                 return ROFF_IGN;
3072
3073         sign = *val;
3074         if (sign == '+' || sign == '-')
3075                 val++;
3076
3077         len = 0;
3078         if (roff_evalnum(r, ln, val, &len, &iv, ROFFNUM_SCALE) == 0)
3079                 return ROFF_IGN;
3080
3081         step = val + len;
3082         while (isspace((unsigned char)*step))
3083                 step++;
3084         if (roff_evalnum(r, ln, step, NULL, &is, 0) == 0)
3085                 is = INT_MIN;
3086
3087         roff_setregn(r, key, keysz, iv, sign, is);
3088         return ROFF_IGN;
3089 }
3090
3091 static int
3092 roff_rr(ROFF_ARGS)
3093 {
3094         struct roffreg  *reg, **prev;
3095         char            *name, *cp;
3096         size_t           namesz;
3097
3098         name = cp = buf->buf + pos;
3099         if (*name == '\0')
3100                 return ROFF_IGN;
3101         namesz = roff_getname(r, &cp, ln, pos);
3102         name[namesz] = '\0';
3103
3104         prev = &r->regtab;
3105         while (1) {
3106                 reg = *prev;
3107                 if (reg == NULL || !strcmp(name, reg->key.p))
3108                         break;
3109                 prev = &reg->next;
3110         }
3111         if (reg != NULL) {
3112                 *prev = reg->next;
3113                 free(reg->key.p);
3114                 free(reg);
3115         }
3116         return ROFF_IGN;
3117 }
3118
3119 /* --- handler functions for roff requests -------------------------------- */
3120
3121 static int
3122 roff_rm(ROFF_ARGS)
3123 {
3124         const char       *name;
3125         char             *cp;
3126         size_t            namesz;
3127
3128         cp = buf->buf + pos;
3129         while (*cp != '\0') {
3130                 name = cp;
3131                 namesz = roff_getname(r, &cp, ln, (int)(cp - buf->buf));
3132                 roff_setstrn(&r->strtab, name, namesz, NULL, 0, 0);
3133                 roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0);
3134                 if (name[namesz] == '\\' || name[namesz] == '\t')
3135                         break;
3136         }
3137         return ROFF_IGN;
3138 }
3139
3140 static int
3141 roff_it(ROFF_ARGS)
3142 {
3143         int              iv;
3144
3145         /* Parse the number of lines. */
3146
3147         if ( ! roff_evalnum(r, ln, buf->buf, &pos, &iv, 0)) {
3148                 mandoc_msg(MANDOCERR_IT_NONUM,
3149                     ln, ppos, "%s", buf->buf + 1);
3150                 return ROFF_IGN;
3151         }
3152
3153         while (isspace((unsigned char)buf->buf[pos]))
3154                 pos++;
3155
3156         /*
3157          * Arm the input line trap.
3158          * Special-casing "an-trap" is an ugly workaround to cope
3159          * with DocBook stupidly fiddling with man(7) internals.
3160          */
3161
3162         roffit_lines = iv;
3163         roffit_macro = mandoc_strdup(iv != 1 ||
3164             strcmp(buf->buf + pos, "an-trap") ?
3165             buf->buf + pos : "br");
3166         return ROFF_IGN;
3167 }
3168
3169 static int
3170 roff_Dd(ROFF_ARGS)
3171 {
3172         int              mask;
3173         enum roff_tok    t, te;
3174
3175         switch (tok) {
3176         case ROFF_Dd:
3177                 tok = MDOC_Dd;
3178                 te = MDOC_MAX;
3179                 if (r->format == 0)
3180                         r->format = MPARSE_MDOC;
3181                 mask = MPARSE_MDOC | MPARSE_QUICK;
3182                 break;
3183         case ROFF_TH:
3184                 tok = MAN_TH;
3185                 te = MAN_MAX;
3186                 if (r->format == 0)
3187                         r->format = MPARSE_MAN;
3188                 mask = MPARSE_QUICK;
3189                 break;
3190         default:
3191                 abort();
3192         }
3193         if ((r->options & mask) == 0)
3194                 for (t = tok; t < te; t++)
3195                         roff_setstr(r, roff_name[t], NULL, 0);
3196         return ROFF_CONT;
3197 }
3198
3199 static int
3200 roff_TE(ROFF_ARGS)
3201 {
3202         r->man->flags &= ~ROFF_NONOFILL;
3203         if (r->tbl == NULL) {
3204                 mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "TE");
3205                 return ROFF_IGN;
3206         }
3207         if (tbl_end(r->tbl, 0) == 0) {
3208                 r->tbl = NULL;
3209                 free(buf->buf);
3210                 buf->buf = mandoc_strdup(".sp");
3211                 buf->sz = 4;
3212                 *offs = 0;
3213                 return ROFF_REPARSE;
3214         }
3215         r->tbl = NULL;
3216         return ROFF_IGN;
3217 }
3218
3219 static int
3220 roff_T_(ROFF_ARGS)
3221 {
3222
3223         if (NULL == r->tbl)
3224                 mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "T&");
3225         else
3226                 tbl_restart(ln, ppos, r->tbl);
3227
3228         return ROFF_IGN;
3229 }
3230
3231 /*
3232  * Handle in-line equation delimiters.
3233  */
3234 static int
3235 roff_eqndelim(struct roff *r, struct buf *buf, int pos)
3236 {
3237         char            *cp1, *cp2;
3238         const char      *bef_pr, *bef_nl, *mac, *aft_nl, *aft_pr;
3239
3240         /*
3241          * Outside equations, look for an opening delimiter.
3242          * If we are inside an equation, we already know it is
3243          * in-line, or this function wouldn't have been called;
3244          * so look for a closing delimiter.
3245          */
3246
3247         cp1 = buf->buf + pos;
3248         cp2 = strchr(cp1, r->eqn == NULL ?
3249             r->last_eqn->odelim : r->last_eqn->cdelim);
3250         if (cp2 == NULL)
3251                 return ROFF_CONT;
3252
3253         *cp2++ = '\0';
3254         bef_pr = bef_nl = aft_nl = aft_pr = "";
3255
3256         /* Handle preceding text, protecting whitespace. */
3257
3258         if (*buf->buf != '\0') {
3259                 if (r->eqn == NULL)
3260                         bef_pr = "\\&";
3261                 bef_nl = "\n";
3262         }
3263
3264         /*
3265          * Prepare replacing the delimiter with an equation macro
3266          * and drop leading white space from the equation.
3267          */
3268
3269         if (r->eqn == NULL) {
3270                 while (*cp2 == ' ')
3271                         cp2++;
3272                 mac = ".EQ";
3273         } else
3274                 mac = ".EN";
3275
3276         /* Handle following text, protecting whitespace. */
3277
3278         if (*cp2 != '\0') {
3279                 aft_nl = "\n";
3280                 if (r->eqn != NULL)
3281                         aft_pr = "\\&";
3282         }
3283
3284         /* Do the actual replacement. */
3285
3286         buf->sz = mandoc_asprintf(&cp1, "%s%s%s%s%s%s%s", buf->buf,
3287             bef_pr, bef_nl, mac, aft_nl, aft_pr, cp2) + 1;
3288         free(buf->buf);
3289         buf->buf = cp1;
3290
3291         /* Toggle the in-line state of the eqn subsystem. */
3292
3293         r->eqn_inline = r->eqn == NULL;
3294         return ROFF_REPARSE;
3295 }
3296
3297 static int
3298 roff_EQ(ROFF_ARGS)
3299 {
3300         struct roff_node        *n;
3301
3302         if (r->man->meta.macroset == MACROSET_MAN)
3303                 man_breakscope(r->man, ROFF_EQ);
3304         n = roff_node_alloc(r->man, ln, ppos, ROFFT_EQN, TOKEN_NONE);
3305         if (ln > r->man->last->line)
3306                 n->flags |= NODE_LINE;
3307         n->eqn = eqn_box_new();
3308         roff_node_append(r->man, n);
3309         r->man->next = ROFF_NEXT_SIBLING;
3310
3311         assert(r->eqn == NULL);
3312         if (r->last_eqn == NULL)
3313                 r->last_eqn = eqn_alloc();
3314         else
3315                 eqn_reset(r->last_eqn);
3316         r->eqn = r->last_eqn;
3317         r->eqn->node = n;
3318
3319         if (buf->buf[pos] != '\0')
3320                 mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos,
3321                     ".EQ %s", buf->buf + pos);
3322
3323         return ROFF_IGN;
3324 }
3325
3326 static int
3327 roff_EN(ROFF_ARGS)
3328 {
3329         if (r->eqn != NULL) {
3330                 eqn_parse(r->eqn);
3331                 r->eqn = NULL;
3332         } else
3333                 mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "EN");
3334         if (buf->buf[pos] != '\0')
3335                 mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos,
3336                     "EN %s", buf->buf + pos);
3337         return ROFF_IGN;
3338 }
3339
3340 static int
3341 roff_TS(ROFF_ARGS)
3342 {
3343         if (r->tbl != NULL) {
3344                 mandoc_msg(MANDOCERR_BLK_BROKEN, ln, ppos, "TS breaks TS");
3345                 tbl_end(r->tbl, 0);
3346         }
3347         r->man->flags |= ROFF_NONOFILL;
3348         r->tbl = tbl_alloc(ppos, ln, r->last_tbl);
3349         if (r->last_tbl == NULL)
3350                 r->first_tbl = r->tbl;
3351         r->last_tbl = r->tbl;
3352         return ROFF_IGN;
3353 }
3354
3355 static int
3356 roff_noarg(ROFF_ARGS)
3357 {
3358         if (r->man->flags & (MAN_BLINE | MAN_ELINE))
3359                 man_breakscope(r->man, tok);
3360         if (tok == ROFF_brp)
3361                 tok = ROFF_br;
3362         roff_elem_alloc(r->man, ln, ppos, tok);
3363         if (buf->buf[pos] != '\0')
3364                 mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos,
3365                    "%s %s", roff_name[tok], buf->buf + pos);
3366         if (tok == ROFF_nf)
3367                 r->man->flags |= ROFF_NOFILL;
3368         else if (tok == ROFF_fi)
3369                 r->man->flags &= ~ROFF_NOFILL;
3370         r->man->last->flags |= NODE_LINE | NODE_VALID | NODE_ENDED;
3371         r->man->next = ROFF_NEXT_SIBLING;
3372         return ROFF_IGN;
3373 }
3374
3375 static int
3376 roff_onearg(ROFF_ARGS)
3377 {
3378         struct roff_node        *n;
3379         char                    *cp;
3380         int                      npos;
3381
3382         if (r->man->flags & (MAN_BLINE | MAN_ELINE) &&
3383             (tok == ROFF_ce || tok == ROFF_rj || tok == ROFF_sp ||
3384              tok == ROFF_ti))
3385                 man_breakscope(r->man, tok);
3386
3387         if (roffce_node != NULL && (tok == ROFF_ce || tok == ROFF_rj)) {
3388                 r->man->last = roffce_node;
3389                 r->man->next = ROFF_NEXT_SIBLING;
3390         }
3391
3392         roff_elem_alloc(r->man, ln, ppos, tok);
3393         n = r->man->last;
3394
3395         cp = buf->buf + pos;
3396         if (*cp != '\0') {
3397                 while (*cp != '\0' && *cp != ' ')
3398                         cp++;
3399                 while (*cp == ' ')
3400                         *cp++ = '\0';
3401                 if (*cp != '\0')
3402                         mandoc_msg(MANDOCERR_ARG_EXCESS,
3403                             ln, (int)(cp - buf->buf),
3404                             "%s ... %s", roff_name[tok], cp);
3405                 roff_word_alloc(r->man, ln, pos, buf->buf + pos);
3406         }
3407
3408         if (tok == ROFF_ce || tok == ROFF_rj) {
3409                 if (r->man->last->type == ROFFT_ELEM) {
3410                         roff_word_alloc(r->man, ln, pos, "1");
3411                         r->man->last->flags |= NODE_NOSRC;
3412                 }
3413                 npos = 0;
3414                 if (roff_evalnum(r, ln, r->man->last->string, &npos,
3415                     &roffce_lines, 0) == 0) {
3416                         mandoc_msg(MANDOCERR_CE_NONUM,
3417                             ln, pos, "ce %s", buf->buf + pos);
3418                         roffce_lines = 1;
3419                 }
3420                 if (roffce_lines < 1) {
3421                         r->man->last = r->man->last->parent;
3422                         roffce_node = NULL;
3423                         roffce_lines = 0;
3424                 } else
3425                         roffce_node = r->man->last->parent;
3426         } else {
3427                 n->flags |= NODE_VALID | NODE_ENDED;
3428                 r->man->last = n;
3429         }
3430         n->flags |= NODE_LINE;
3431         r->man->next = ROFF_NEXT_SIBLING;
3432         return ROFF_IGN;
3433 }
3434
3435 static int
3436 roff_manyarg(ROFF_ARGS)
3437 {
3438         struct roff_node        *n;
3439         char                    *sp, *ep;
3440
3441         roff_elem_alloc(r->man, ln, ppos, tok);
3442         n = r->man->last;
3443
3444         for (sp = ep = buf->buf + pos; *sp != '\0'; sp = ep) {
3445                 while (*ep != '\0' && *ep != ' ')
3446                         ep++;
3447                 while (*ep == ' ')
3448                         *ep++ = '\0';
3449                 roff_word_alloc(r->man, ln, sp - buf->buf, sp);
3450         }
3451
3452         n->flags |= NODE_LINE | NODE_VALID | NODE_ENDED;
3453         r->man->last = n;
3454         r->man->next = ROFF_NEXT_SIBLING;
3455         return ROFF_IGN;
3456 }
3457
3458 static int
3459 roff_als(ROFF_ARGS)
3460 {
3461         char            *oldn, *newn, *end, *value;
3462         size_t           oldsz, newsz, valsz;
3463
3464         newn = oldn = buf->buf + pos;
3465         if (*newn == '\0')
3466                 return ROFF_IGN;
3467
3468         newsz = roff_getname(r, &oldn, ln, pos);
3469         if (newn[newsz] == '\\' || newn[newsz] == '\t' || *oldn == '\0')
3470                 return ROFF_IGN;
3471
3472         end = oldn;
3473         oldsz = roff_getname(r, &end, ln, oldn - buf->buf);
3474         if (oldsz == 0)
3475                 return ROFF_IGN;
3476
3477         valsz = mandoc_asprintf(&value, ".%.*s \\$@\\\"\n",
3478             (int)oldsz, oldn);
3479         roff_setstrn(&r->strtab, newn, newsz, value, valsz, 0);
3480         roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0);
3481         free(value);
3482         return ROFF_IGN;
3483 }
3484
3485 static int
3486 roff_cc(ROFF_ARGS)
3487 {
3488         const char      *p;
3489
3490         p = buf->buf + pos;
3491
3492         if (*p == '\0' || (r->control = *p++) == '.')
3493                 r->control = '\0';
3494
3495         if (*p != '\0')
3496                 mandoc_msg(MANDOCERR_ARG_EXCESS,
3497                     ln, p - buf->buf, "cc ... %s", p);
3498
3499         return ROFF_IGN;
3500 }
3501
3502 static int
3503 roff_char(ROFF_ARGS)
3504 {
3505         const char      *p, *kp, *vp;
3506         size_t           ksz, vsz;
3507         int              font;
3508
3509         /* Parse the character to be replaced. */
3510
3511         kp = buf->buf + pos;
3512         p = kp + 1;
3513         if (*kp == '\0' || (*kp == '\\' &&
3514              mandoc_escape(&p, NULL, NULL) != ESCAPE_SPECIAL) ||
3515             (*p != ' ' && *p != '\0')) {
3516                 mandoc_msg(MANDOCERR_CHAR_ARG, ln, pos, "char %s", kp);
3517                 return ROFF_IGN;
3518         }
3519         ksz = p - kp;
3520         while (*p == ' ')
3521                 p++;
3522
3523         /*
3524          * If the replacement string contains a font escape sequence,
3525          * we have to restore the font at the end.
3526          */
3527
3528         vp = p;
3529         vsz = strlen(p);
3530         font = 0;
3531         while (*p != '\0') {
3532                 if (*p++ != '\\')
3533                         continue;
3534                 switch (mandoc_escape(&p, NULL, NULL)) {
3535                 case ESCAPE_FONT:
3536                 case ESCAPE_FONTROMAN:
3537                 case ESCAPE_FONTITALIC:
3538                 case ESCAPE_FONTBOLD:
3539                 case ESCAPE_FONTBI:
3540                 case ESCAPE_FONTCW:
3541                 case ESCAPE_FONTPREV:
3542                         font++;
3543                         break;
3544                 default:
3545                         break;
3546                 }
3547         }
3548         if (font > 1)
3549                 mandoc_msg(MANDOCERR_CHAR_FONT,
3550                     ln, (int)(vp - buf->buf), "%s", vp);
3551
3552         /*
3553          * Approximate the effect of .char using the .tr tables.
3554          * XXX In groff, .char and .tr interact differently.
3555          */
3556
3557         if (ksz == 1) {
3558                 if (r->xtab == NULL)
3559                         r->xtab = mandoc_calloc(128, sizeof(*r->xtab));
3560                 assert((unsigned int)*kp < 128);
3561                 free(r->xtab[(int)*kp].p);
3562                 r->xtab[(int)*kp].sz = mandoc_asprintf(&r->xtab[(int)*kp].p,
3563                     "%s%s", vp, font ? "\fP" : "");
3564         } else {
3565                 roff_setstrn(&r->xmbtab, kp, ksz, vp, vsz, 0);
3566                 if (font)
3567                         roff_setstrn(&r->xmbtab, kp, ksz, "\\fP", 3, 1);
3568         }
3569         return ROFF_IGN;
3570 }
3571
3572 static int
3573 roff_ec(ROFF_ARGS)
3574 {
3575         const char      *p;
3576
3577         p = buf->buf + pos;
3578         if (*p == '\0')
3579                 r->escape = '\\';
3580         else {
3581                 r->escape = *p;
3582                 if (*++p != '\0')
3583                         mandoc_msg(MANDOCERR_ARG_EXCESS, ln,
3584                             (int)(p - buf->buf), "ec ... %s", p);
3585         }
3586         return ROFF_IGN;
3587 }
3588
3589 static int
3590 roff_eo(ROFF_ARGS)
3591 {
3592         r->escape = '\0';
3593         if (buf->buf[pos] != '\0')
3594                 mandoc_msg(MANDOCERR_ARG_SKIP,
3595                     ln, pos, "eo %s", buf->buf + pos);
3596         return ROFF_IGN;
3597 }
3598
3599 static int
3600 roff_nop(ROFF_ARGS)
3601 {
3602         while (buf->buf[pos] == ' ')
3603                 pos++;
3604         *offs = pos;
3605         return ROFF_RERUN;
3606 }
3607
3608 static int
3609 roff_tr(ROFF_ARGS)
3610 {
3611         const char      *p, *first, *second;
3612         size_t           fsz, ssz;
3613         enum mandoc_esc  esc;
3614
3615         p = buf->buf + pos;
3616
3617         if (*p == '\0') {
3618                 mandoc_msg(MANDOCERR_REQ_EMPTY, ln, ppos, "tr");
3619                 return ROFF_IGN;
3620         }
3621
3622         while (*p != '\0') {
3623                 fsz = ssz = 1;
3624
3625                 first = p++;
3626                 if (*first == '\\') {
3627                         esc = mandoc_escape(&p, NULL, NULL);
3628                         if (esc == ESCAPE_ERROR) {
3629                                 mandoc_msg(MANDOCERR_ESC_BAD, ln,
3630                                     (int)(p - buf->buf), "%s", first);
3631                                 return ROFF_IGN;
3632                         }
3633                         fsz = (size_t)(p - first);
3634                 }
3635
3636                 second = p++;
3637                 if (*second == '\\') {
3638                         esc = mandoc_escape(&p, NULL, NULL);
3639                         if (esc == ESCAPE_ERROR) {
3640                                 mandoc_msg(MANDOCERR_ESC_BAD, ln,
3641                                     (int)(p - buf->buf), "%s", second);
3642                                 return ROFF_IGN;
3643                         }
3644                         ssz = (size_t)(p - second);
3645                 } else if (*second == '\0') {
3646                         mandoc_msg(MANDOCERR_TR_ODD, ln,
3647                             (int)(first - buf->buf), "tr %s", first);
3648                         second = " ";
3649                         p--;
3650                 }
3651
3652                 if (fsz > 1) {
3653                         roff_setstrn(&r->xmbtab, first, fsz,
3654                             second, ssz, 0);
3655                         continue;
3656                 }
3657
3658                 if (r->xtab == NULL)
3659                         r->xtab = mandoc_calloc(128,
3660                             sizeof(struct roffstr));
3661
3662                 free(r->xtab[(int)*first].p);
3663                 r->xtab[(int)*first].p = mandoc_strndup(second, ssz);
3664                 r->xtab[(int)*first].sz = ssz;
3665         }
3666
3667         return ROFF_IGN;
3668 }
3669
3670 /*
3671  * Implementation of the .return request.
3672  * There is no need to call roff_userret() from here.
3673  * The read module will call that after rewinding the reader stack
3674  * to the place from where the current macro was called.
3675  */
3676 static int
3677 roff_return(ROFF_ARGS)
3678 {
3679         if (r->mstackpos >= 0)
3680                 return ROFF_IGN | ROFF_USERRET;
3681
3682         mandoc_msg(MANDOCERR_REQ_NOMAC, ln, ppos, "return");
3683         return ROFF_IGN;
3684 }
3685
3686 static int
3687 roff_rn(ROFF_ARGS)
3688 {
3689         const char      *value;
3690         char            *oldn, *newn, *end;
3691         size_t           oldsz, newsz;
3692         int              deftype;
3693
3694         oldn = newn = buf->buf + pos;
3695         if (*oldn == '\0')
3696                 return ROFF_IGN;
3697
3698         oldsz = roff_getname(r, &newn, ln, pos);
3699         if (oldn[oldsz] == '\\' || oldn[oldsz] == '\t' || *newn == '\0')
3700                 return ROFF_IGN;
3701
3702         end = newn;
3703         newsz = roff_getname(r, &end, ln, newn - buf->buf);
3704         if (newsz == 0)
3705                 return ROFF_IGN;
3706
3707         deftype = ROFFDEF_ANY;
3708         value = roff_getstrn(r, oldn, oldsz, &deftype);
3709         switch (deftype) {
3710         case ROFFDEF_USER:
3711                 roff_setstrn(&r->strtab, newn, newsz, value, strlen(value), 0);
3712                 roff_setstrn(&r->strtab, oldn, oldsz, NULL, 0, 0);
3713                 roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0);
3714                 break;
3715         case ROFFDEF_PRE:
3716                 roff_setstrn(&r->strtab, newn, newsz, value, strlen(value), 0);
3717                 roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0);
3718                 break;
3719         case ROFFDEF_REN:
3720                 roff_setstrn(&r->rentab, newn, newsz, value, strlen(value), 0);
3721                 roff_setstrn(&r->rentab, oldn, oldsz, NULL, 0, 0);
3722                 roff_setstrn(&r->strtab, newn, newsz, NULL, 0, 0);
3723                 break;
3724         case ROFFDEF_STD:
3725                 roff_setstrn(&r->rentab, newn, newsz, oldn, oldsz, 0);
3726                 roff_setstrn(&r->strtab, newn, newsz, NULL, 0, 0);
3727                 break;
3728         default:
3729                 roff_setstrn(&r->strtab, newn, newsz, NULL, 0, 0);
3730                 roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0);
3731                 break;
3732         }
3733         return ROFF_IGN;
3734 }
3735
3736 static int
3737 roff_shift(ROFF_ARGS)
3738 {
3739         struct mctx     *ctx;
3740         int              levels, i;
3741
3742         levels = 1;
3743         if (buf->buf[pos] != '\0' &&
3744             roff_evalnum(r, ln, buf->buf, &pos, &levels, 0) == 0) {
3745                 mandoc_msg(MANDOCERR_CE_NONUM,
3746                     ln, pos, "shift %s", buf->buf + pos);
3747                 levels = 1;
3748         }
3749         if (r->mstackpos < 0) {
3750                 mandoc_msg(MANDOCERR_REQ_NOMAC, ln, ppos, "shift");
3751                 return ROFF_IGN;
3752         }
3753         ctx = r->mstack + r->mstackpos;
3754         if (levels > ctx->argc) {
3755                 mandoc_msg(MANDOCERR_SHIFT,
3756                     ln, pos, "%d, but max is %d", levels, ctx->argc);
3757                 levels = ctx->argc;
3758         }
3759         if (levels == 0)
3760                 return ROFF_IGN;
3761         for (i = 0; i < levels; i++)
3762                 free(ctx->argv[i]);
3763         ctx->argc -= levels;
3764         for (i = 0; i < ctx->argc; i++)
3765                 ctx->argv[i] = ctx->argv[i + levels];
3766         return ROFF_IGN;
3767 }
3768
3769 static int
3770 roff_so(ROFF_ARGS)
3771 {
3772         char *name, *cp;
3773
3774         name = buf->buf + pos;
3775         mandoc_msg(MANDOCERR_SO, ln, ppos, "so %s", name);
3776
3777         /*
3778          * Handle `so'.  Be EXTREMELY careful, as we shouldn't be
3779          * opening anything that's not in our cwd or anything beneath
3780          * it.  Thus, explicitly disallow traversing up the file-system
3781          * or using absolute paths.
3782          */
3783
3784         if (*name == '/' || strstr(name, "../") || strstr(name, "/..")) {
3785                 mandoc_msg(MANDOCERR_SO_PATH, ln, ppos, ".so %s", name);
3786                 buf->sz = mandoc_asprintf(&cp,
3787                     ".sp\nSee the file %s.\n.sp", name) + 1;
3788                 free(buf->buf);
3789                 buf->buf = cp;
3790                 *offs = 0;
3791                 return ROFF_REPARSE;
3792         }
3793
3794         *offs = pos;
3795         return ROFF_SO;
3796 }
3797
3798 /* --- user defined strings and macros ------------------------------------ */
3799
3800 static int
3801 roff_userdef(ROFF_ARGS)
3802 {
3803         struct mctx      *ctx;
3804         char             *arg, *ap, *dst, *src;
3805         size_t            sz;
3806
3807         /* Initialize a new macro stack context. */
3808
3809         if (++r->mstackpos == r->mstacksz) {
3810                 r->mstack = mandoc_recallocarray(r->mstack,
3811                     r->mstacksz, r->mstacksz + 8, sizeof(*r->mstack));
3812                 r->mstacksz += 8;
3813         }
3814         ctx = r->mstack + r->mstackpos;
3815         ctx->argsz = 0;
3816         ctx->argc = 0;
3817         ctx->argv = NULL;
3818
3819         /*
3820          * Collect pointers to macro argument strings,
3821          * NUL-terminating them and escaping quotes.
3822          */
3823
3824         src = buf->buf + pos;
3825         while (*src != '\0') {
3826                 if (ctx->argc == ctx->argsz) {
3827                         ctx->argsz += 8;
3828                         ctx->argv = mandoc_reallocarray(ctx->argv,
3829                             ctx->argsz, sizeof(*ctx->argv));
3830                 }
3831                 arg = roff_getarg(r, &src, ln, &pos);
3832                 sz = 1;  /* For the terminating NUL. */
3833                 for (ap = arg; *ap != '\0'; ap++)
3834                         sz += *ap == '"' ? 4 : 1;
3835                 ctx->argv[ctx->argc++] = dst = mandoc_malloc(sz);
3836                 for (ap = arg; *ap != '\0'; ap++) {
3837                         if (*ap == '"') {
3838                                 memcpy(dst, "\\(dq", 4);
3839                                 dst += 4;
3840                         } else
3841                                 *dst++ = *ap;
3842                 }
3843                 *dst = '\0';
3844                 free(arg);
3845         }
3846
3847         /* Replace the macro invocation by the macro definition. */
3848
3849         free(buf->buf);
3850         buf->buf = mandoc_strdup(r->current_string);
3851         buf->sz = strlen(buf->buf) + 1;
3852         *offs = 0;
3853
3854         return buf->sz > 1 && buf->buf[buf->sz - 2] == '\n' ?
3855             ROFF_REPARSE | ROFF_USERCALL : ROFF_IGN | ROFF_APPEND;
3856 }
3857
3858 /*
3859  * Calling a high-level macro that was renamed with .rn.
3860  * r->current_string has already been set up by roff_parse().
3861  */
3862 static int
3863 roff_renamed(ROFF_ARGS)
3864 {
3865         char    *nbuf;
3866
3867         buf->sz = mandoc_asprintf(&nbuf, ".%s%s%s", r->current_string,
3868             buf->buf[pos] == '\0' ? "" : " ", buf->buf + pos) + 1;
3869         free(buf->buf);
3870         buf->buf = nbuf;
3871         *offs = 0;
3872         return ROFF_CONT;
3873 }
3874
3875 /*
3876  * Measure the length in bytes of the roff identifier at *cpp
3877  * and advance the pointer to the next word.
3878  */
3879 static size_t
3880 roff_getname(struct roff *r, char **cpp, int ln, int pos)
3881 {
3882         char     *name, *cp;
3883         size_t    namesz;
3884
3885         name = *cpp;
3886         if (*name == '\0')
3887                 return 0;
3888
3889         /* Advance cp to the byte after the end of the name. */
3890
3891         for (cp = name; 1; cp++) {
3892                 namesz = cp - name;
3893                 if (*cp == '\0')
3894                         break;
3895                 if (*cp == ' ' || *cp == '\t') {
3896                         cp++;
3897                         break;
3898                 }
3899                 if (*cp != '\\')
3900                         continue;
3901                 if (cp[1] == '{' || cp[1] == '}')
3902                         break;
3903                 if (*++cp == '\\')
3904                         continue;
3905                 mandoc_msg(MANDOCERR_NAMESC, ln, pos,
3906                     "%.*s", (int)(cp - name + 1), name);
3907                 mandoc_escape((const char **)&cp, NULL, NULL);
3908                 break;
3909         }
3910
3911         /* Read past spaces. */
3912
3913         while (*cp == ' ')
3914                 cp++;
3915
3916         *cpp = cp;
3917         return namesz;
3918 }
3919
3920 /*
3921  * Store *string into the user-defined string called *name.
3922  * To clear an existing entry, call with (*r, *name, NULL, 0).
3923  * append == 0: replace mode
3924  * append == 1: single-line append mode
3925  * append == 2: multiline append mode, append '\n' after each call
3926  */
3927 static void
3928 roff_setstr(struct roff *r, const char *name, const char *string,
3929         int append)
3930 {
3931         size_t   namesz;
3932
3933         namesz = strlen(name);
3934         roff_setstrn(&r->strtab, name, namesz, string,
3935             string ? strlen(string) : 0, append);
3936         roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0);
3937 }
3938
3939 static void
3940 roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
3941                 const char *string, size_t stringsz, int append)
3942 {
3943         struct roffkv   *n;
3944         char            *c;
3945         int              i;
3946         size_t           oldch, newch;
3947
3948         /* Search for an existing string with the same name. */
3949         n = *r;
3950
3951         while (n && (namesz != n->key.sz ||
3952                         strncmp(n->key.p, name, namesz)))
3953                 n = n->next;
3954
3955         if (NULL == n) {
3956                 /* Create a new string table entry. */
3957                 n = mandoc_malloc(sizeof(struct roffkv));
3958                 n->key.p = mandoc_strndup(name, namesz);
3959                 n->key.sz = namesz;
3960                 n->val.p = NULL;
3961                 n->val.sz = 0;
3962                 n->next = *r;
3963                 *r = n;
3964         } else if (0 == append) {
3965                 free(n->val.p);
3966                 n->val.p = NULL;
3967                 n->val.sz = 0;
3968         }
3969
3970         if (NULL == string)
3971                 return;
3972
3973         /*
3974          * One additional byte for the '\n' in multiline mode,
3975          * and one for the terminating '\0'.
3976          */
3977         newch = stringsz + (1 < append ? 2u : 1u);
3978
3979         if (NULL == n->val.p) {
3980                 n->val.p = mandoc_malloc(newch);
3981                 *n->val.p = '\0';
3982                 oldch = 0;
3983         } else {
3984                 oldch = n->val.sz;
3985                 n->val.p = mandoc_realloc(n->val.p, oldch + newch);
3986         }
3987
3988         /* Skip existing content in the destination buffer. */
3989         c = n->val.p + (int)oldch;
3990
3991         /* Append new content to the destination buffer. */
3992         i = 0;
3993         while (i < (int)stringsz) {
3994                 /*
3995                  * Rudimentary roff copy mode:
3996                  * Handle escaped backslashes.
3997                  */
3998                 if ('\\' == string[i] && '\\' == string[i + 1])
3999                         i++;
4000                 *c++ = string[i++];
4001         }
4002
4003         /* Append terminating bytes. */
4004         if (1 < append)
4005                 *c++ = '\n';
4006
4007         *c = '\0';
4008         n->val.sz = (int)(c - n->val.p);
4009 }
4010
4011 static const char *
4012 roff_getstrn(struct roff *r, const char *name, size_t len,
4013     int *deftype)
4014 {
4015         const struct roffkv     *n;
4016         int                      found, i;
4017         enum roff_tok            tok;
4018
4019         found = 0;
4020         for (n = r->strtab; n != NULL; n = n->next) {
4021                 if (strncmp(name, n->key.p, len) != 0 ||
4022                     n->key.p[len] != '\0' || n->val.p == NULL)
4023                         continue;
4024                 if (*deftype & ROFFDEF_USER) {
4025                         *deftype = ROFFDEF_USER;
4026                         return n->val.p;
4027                 } else {
4028                         found = 1;
4029                         break;
4030                 }
4031         }
4032         for (n = r->rentab; n != NULL; n = n->next) {
4033                 if (strncmp(name, n->key.p, len) != 0 ||
4034                     n->key.p[len] != '\0' || n->val.p == NULL)
4035                         continue;
4036                 if (*deftype & ROFFDEF_REN) {
4037                         *deftype = ROFFDEF_REN;
4038                         return n->val.p;
4039                 } else {
4040                         found = 1;
4041                         break;
4042                 }
4043         }
4044         for (i = 0; i < PREDEFS_MAX; i++) {
4045                 if (strncmp(name, predefs[i].name, len) != 0 ||
4046                     predefs[i].name[len] != '\0')
4047                         continue;
4048                 if (*deftype & ROFFDEF_PRE) {
4049                         *deftype = ROFFDEF_PRE;
4050                         return predefs[i].str;
4051                 } else {
4052                         found = 1;
4053                         break;
4054                 }
4055         }
4056         if (r->man->meta.macroset != MACROSET_MAN) {
4057                 for (tok = MDOC_Dd; tok < MDOC_MAX; tok++) {
4058                         if (strncmp(name, roff_name[tok], len) != 0 ||
4059                             roff_name[tok][len] != '\0')
4060                                 continue;
4061                         if (*deftype & ROFFDEF_STD) {
4062                                 *deftype = ROFFDEF_STD;
4063                                 return NULL;
4064                         } else {
4065                                 found = 1;
4066                                 break;
4067                         }
4068                 }
4069         }
4070         if (r->man->meta.macroset != MACROSET_MDOC) {
4071                 for (tok = MAN_TH; tok < MAN_MAX; tok++) {
4072                         if (strncmp(name, roff_name[tok], len) != 0 ||
4073                             roff_name[tok][len] != '\0')
4074                                 continue;
4075                         if (*deftype & ROFFDEF_STD) {
4076                                 *deftype = ROFFDEF_STD;
4077                                 return NULL;
4078                         } else {
4079                                 found = 1;
4080                                 break;
4081                         }
4082                 }
4083         }
4084
4085         if (found == 0 && *deftype != ROFFDEF_ANY) {
4086                 if (*deftype & ROFFDEF_REN) {
4087                         /*
4088                          * This might still be a request,
4089                          * so do not treat it as undefined yet.
4090                          */
4091                         *deftype = ROFFDEF_UNDEF;
4092                         return NULL;
4093                 }
4094
4095                 /* Using an undefined string defines it to be empty. */
4096
4097                 roff_setstrn(&r->strtab, name, len, "", 0, 0);
4098                 roff_setstrn(&r->rentab, name, len, NULL, 0, 0);
4099         }
4100
4101         *deftype = 0;
4102         return NULL;
4103 }
4104
4105 static void
4106 roff_freestr(struct roffkv *r)
4107 {
4108         struct roffkv    *n, *nn;
4109
4110         for (n = r; n; n = nn) {
4111                 free(n->key.p);
4112                 free(n->val.p);
4113                 nn = n->next;
4114                 free(n);
4115         }
4116 }
4117
4118 /* --- accessors and utility functions ------------------------------------ */
4119
4120 /*
4121  * Duplicate an input string, making the appropriate character
4122  * conversations (as stipulated by `tr') along the way.
4123  * Returns a heap-allocated string with all the replacements made.
4124  */
4125 char *
4126 roff_strdup(const struct roff *r, const char *p)
4127 {
4128         const struct roffkv *cp;
4129         char            *res;
4130         const char      *pp;
4131         size_t           ssz, sz;
4132         enum mandoc_esc  esc;
4133
4134         if (NULL == r->xmbtab && NULL == r->xtab)
4135                 return mandoc_strdup(p);
4136         else if ('\0' == *p)
4137                 return mandoc_strdup("");
4138
4139         /*
4140          * Step through each character looking for term matches
4141          * (remember that a `tr' can be invoked with an escape, which is
4142          * a glyph but the escape is multi-character).
4143          * We only do this if the character hash has been initialised
4144          * and the string is >0 length.
4145          */
4146
4147         res = NULL;
4148         ssz = 0;
4149
4150         while ('\0' != *p) {
4151                 assert((unsigned int)*p < 128);
4152                 if ('\\' != *p && r->xtab && r->xtab[(unsigned int)*p].p) {
4153                         sz = r->xtab[(int)*p].sz;
4154                         res = mandoc_realloc(res, ssz + sz + 1);
4155                         memcpy(res + ssz, r->xtab[(int)*p].p, sz);
4156                         ssz += sz;
4157                         p++;
4158                         continue;
4159                 } else if ('\\' != *p) {
4160                         res = mandoc_realloc(res, ssz + 2);
4161                         res[ssz++] = *p++;
4162                         continue;
4163                 }
4164
4165                 /* Search for term matches. */
4166                 for (cp = r->xmbtab; cp; cp = cp->next)
4167                         if (0 == strncmp(p, cp->key.p, cp->key.sz))
4168                                 break;
4169
4170                 if (NULL != cp) {
4171                         /*
4172                          * A match has been found.
4173                          * Append the match to the array and move
4174                          * forward by its keysize.
4175                          */
4176                         res = mandoc_realloc(res,
4177                             ssz + cp->val.sz + 1);
4178                         memcpy(res + ssz, cp->val.p, cp->val.sz);
4179                         ssz += cp->val.sz;
4180                         p += (int)cp->key.sz;
4181                         continue;
4182                 }
4183
4184                 /*
4185                  * Handle escapes carefully: we need to copy
4186                  * over just the escape itself, or else we might
4187                  * do replacements within the escape itself.
4188                  * Make sure to pass along the bogus string.
4189                  */
4190                 pp = p++;
4191                 esc = mandoc_escape(&p, NULL, NULL);
4192                 if (ESCAPE_ERROR == esc) {
4193                         sz = strlen(pp);
4194                         res = mandoc_realloc(res, ssz + sz + 1);
4195                         memcpy(res + ssz, pp, sz);
4196                         break;
4197                 }
4198                 /*
4199                  * We bail out on bad escapes.
4200                  * No need to warn: we already did so when
4201                  * roff_expand() was called.
4202                  */
4203                 sz = (int)(p - pp);
4204                 res = mandoc_realloc(res, ssz + sz + 1);
4205                 memcpy(res + ssz, pp, sz);
4206                 ssz += sz;
4207         }
4208
4209         res[(int)ssz] = '\0';
4210         return res;
4211 }
4212
4213 int
4214 roff_getformat(const struct roff *r)
4215 {
4216
4217         return r->format;
4218 }
4219
4220 /*
4221  * Find out whether a line is a macro line or not.
4222  * If it is, adjust the current position and return one; if it isn't,
4223  * return zero and don't change the current position.
4224  * If the control character has been set with `.cc', then let that grain
4225  * precedence.
4226  * This is slighly contrary to groff, where using the non-breaking
4227  * control character when `cc' has been invoked will cause the
4228  * non-breaking macro contents to be printed verbatim.
4229  */
4230 int
4231 roff_getcontrol(const struct roff *r, const char *cp, int *ppos)
4232 {
4233         int             pos;
4234
4235         pos = *ppos;
4236
4237         if (r->control != '\0' && cp[pos] == r->control)
4238                 pos++;
4239         else if (r->control != '\0')
4240                 return 0;
4241         else if ('\\' == cp[pos] && '.' == cp[pos + 1])
4242                 pos += 2;
4243         else if ('.' == cp[pos] || '\'' == cp[pos])
4244                 pos++;
4245         else
4246                 return 0;
4247
4248         while (' ' == cp[pos] || '\t' == cp[pos])
4249                 pos++;
4250
4251         *ppos = pos;
4252         return 1;
4253 }