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