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