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