Home | History | Annotate | Line # | Download | only in dist
roff.c revision 1.16
      1 /*	Id: roff.c,v 1.189 2013/12/30 18:44:06 schwarze Exp  */
      2 /*
      3  * Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps (at) bsd.lv>
      4  * Copyright (c) 2010, 2011, 2012, 2013 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 #ifdef HAVE_CONFIG_H
     19 #include "config.h"
     20 #endif
     21 
     22 #include <assert.h>
     23 #include <ctype.h>
     24 #include <stdio.h>
     25 #include <stdlib.h>
     26 #include <string.h>
     27 
     28 #include "mandoc.h"
     29 #include "libroff.h"
     30 #include "libmandoc.h"
     31 
     32 /* Maximum number of nested if-else conditionals. */
     33 #define	RSTACK_MAX	128
     34 
     35 /* Maximum number of string expansions per line, to break infinite loops. */
     36 #define	EXPAND_LIMIT	1000
     37 
     38 enum	rofft {
     39 	ROFF_ad,
     40 	ROFF_am,
     41 	ROFF_ami,
     42 	ROFF_am1,
     43 	ROFF_cc,
     44 	ROFF_de,
     45 	ROFF_dei,
     46 	ROFF_de1,
     47 	ROFF_ds,
     48 	ROFF_el,
     49 	ROFF_fam,
     50 	ROFF_hw,
     51 	ROFF_hy,
     52 	ROFF_ie,
     53 	ROFF_if,
     54 	ROFF_ig,
     55 	ROFF_it,
     56 	ROFF_ne,
     57 	ROFF_nh,
     58 	ROFF_nr,
     59 	ROFF_ns,
     60 	ROFF_ps,
     61 	ROFF_rm,
     62 	ROFF_so,
     63 	ROFF_ta,
     64 	ROFF_tr,
     65 	ROFF_Dd,
     66 	ROFF_TH,
     67 	ROFF_TS,
     68 	ROFF_TE,
     69 	ROFF_T_,
     70 	ROFF_EQ,
     71 	ROFF_EN,
     72 	ROFF_cblock,
     73 	ROFF_ccond,
     74 	ROFF_USERDEF,
     75 	ROFF_MAX
     76 };
     77 
     78 enum	roffrule {
     79 	ROFFRULE_DENY,
     80 	ROFFRULE_ALLOW
     81 };
     82 
     83 /*
     84  * An incredibly-simple string buffer.
     85  */
     86 struct	roffstr {
     87 	char		*p; /* nil-terminated buffer */
     88 	size_t		 sz; /* saved strlen(p) */
     89 };
     90 
     91 /*
     92  * A key-value roffstr pair as part of a singly-linked list.
     93  */
     94 struct	roffkv {
     95 	struct roffstr	 key;
     96 	struct roffstr	 val;
     97 	struct roffkv	*next; /* next in list */
     98 };
     99 
    100 /*
    101  * A single number register as part of a singly-linked list.
    102  */
    103 struct	roffreg {
    104 	struct roffstr	 key;
    105 	int		 val;
    106 	struct roffreg	*next;
    107 };
    108 
    109 struct	roff {
    110 	enum mparset	 parsetype; /* requested parse type */
    111 	struct mparse	*parse; /* parse point */
    112 	struct roffnode	*last; /* leaf of stack */
    113 	enum roffrule	 rstack[RSTACK_MAX]; /* stack of !`ie' rules */
    114 	char		 control; /* control character */
    115 	int		 rstackpos; /* position in rstack */
    116 	struct roffreg	*regtab; /* number registers */
    117 	struct roffkv	*strtab; /* user-defined strings & macros */
    118 	struct roffkv	*xmbtab; /* multi-byte trans table (`tr') */
    119 	struct roffstr	*xtab; /* single-byte trans table (`tr') */
    120 	const char	*current_string; /* value of last called user macro */
    121 	struct tbl_node	*first_tbl; /* first table parsed */
    122 	struct tbl_node	*last_tbl; /* last table parsed */
    123 	struct tbl_node	*tbl; /* current table being parsed */
    124 	struct eqn_node	*last_eqn; /* last equation parsed */
    125 	struct eqn_node	*first_eqn; /* first equation parsed */
    126 	struct eqn_node	*eqn; /* current equation being parsed */
    127 };
    128 
    129 struct	roffnode {
    130 	enum rofft	 tok; /* type of node */
    131 	struct roffnode	*parent; /* up one in stack */
    132 	int		 line; /* parse line */
    133 	int		 col; /* parse col */
    134 	char		*name; /* node name, e.g. macro name */
    135 	char		*end; /* end-rules: custom token */
    136 	int		 endspan; /* end-rules: next-line or infty */
    137 	enum roffrule	 rule; /* current evaluation rule */
    138 };
    139 
    140 #define	ROFF_ARGS	 struct roff *r, /* parse ctx */ \
    141 			 enum rofft tok, /* tok of macro */ \
    142 		 	 char **bufp, /* input buffer */ \
    143 			 size_t *szp, /* size of input buffer */ \
    144 			 int ln, /* parse line */ \
    145 			 int ppos, /* original pos in buffer */ \
    146 			 int pos, /* current pos in buffer */ \
    147 			 int *offs /* reset offset of buffer data */
    148 
    149 typedef	enum rofferr (*roffproc)(ROFF_ARGS);
    150 
    151 struct	roffmac {
    152 	const char	*name; /* macro name */
    153 	roffproc	 proc; /* process new macro */
    154 	roffproc	 text; /* process as child text of macro */
    155 	roffproc	 sub; /* process as child of macro */
    156 	int		 flags;
    157 #define	ROFFMAC_STRUCT	(1 << 0) /* always interpret */
    158 	struct roffmac	*next;
    159 };
    160 
    161 struct	predef {
    162 	const char	*name; /* predefined input name */
    163 	const char	*str; /* replacement symbol */
    164 };
    165 
    166 #define	PREDEF(__name, __str) \
    167 	{ (__name), (__str) },
    168 
    169 static	enum rofft	 roffhash_find(const char *, size_t);
    170 static	void		 roffhash_init(void);
    171 static	void		 roffnode_cleanscope(struct roff *);
    172 static	void		 roffnode_pop(struct roff *);
    173 static	void		 roffnode_push(struct roff *, enum rofft,
    174 				const char *, int, int);
    175 static	enum rofferr	 roff_block(ROFF_ARGS);
    176 static	enum rofferr	 roff_block_text(ROFF_ARGS);
    177 static	enum rofferr	 roff_block_sub(ROFF_ARGS);
    178 static	enum rofferr	 roff_cblock(ROFF_ARGS);
    179 static	enum rofferr	 roff_cc(ROFF_ARGS);
    180 static	enum rofferr	 roff_ccond(ROFF_ARGS);
    181 static	enum rofferr	 roff_cond(ROFF_ARGS);
    182 static	enum rofferr	 roff_cond_text(ROFF_ARGS);
    183 static	enum rofferr	 roff_cond_sub(ROFF_ARGS);
    184 static	enum rofferr	 roff_ds(ROFF_ARGS);
    185 static	enum roffrule	 roff_evalcond(const char *, int *);
    186 static	void		 roff_free1(struct roff *);
    187 static	void		 roff_freereg(struct roffreg *);
    188 static	void		 roff_freestr(struct roffkv *);
    189 static	char		*roff_getname(struct roff *, char **, int, int);
    190 static	int		 roff_getnum(const char *, int *, int *);
    191 static	int		 roff_getop(const char *, int *, char *);
    192 static	int		 roff_getregn(const struct roff *,
    193 				const char *, size_t);
    194 static	const char	*roff_getstrn(const struct roff *,
    195 				const char *, size_t);
    196 static	enum rofferr	 roff_it(ROFF_ARGS);
    197 static	enum rofferr	 roff_line_ignore(ROFF_ARGS);
    198 static	enum rofferr	 roff_nr(ROFF_ARGS);
    199 static	void		 roff_openeqn(struct roff *, const char *,
    200 				int, int, const char *);
    201 static	enum rofft	 roff_parse(struct roff *, const char *, int *);
    202 static	enum rofferr	 roff_parsetext(char **, size_t *, int, int *);
    203 static	enum rofferr	 roff_res(struct roff *,
    204 				char **, size_t *, int, int);
    205 static	enum rofferr	 roff_rm(ROFF_ARGS);
    206 static	void		 roff_setstr(struct roff *,
    207 				const char *, const char *, int);
    208 static	void		 roff_setstrn(struct roffkv **, const char *,
    209 				size_t, const char *, size_t, int);
    210 static	enum rofferr	 roff_so(ROFF_ARGS);
    211 static	enum rofferr	 roff_tr(ROFF_ARGS);
    212 static	enum rofferr	 roff_Dd(ROFF_ARGS);
    213 static	enum rofferr	 roff_TH(ROFF_ARGS);
    214 static	enum rofferr	 roff_TE(ROFF_ARGS);
    215 static	enum rofferr	 roff_TS(ROFF_ARGS);
    216 static	enum rofferr	 roff_EQ(ROFF_ARGS);
    217 static	enum rofferr	 roff_EN(ROFF_ARGS);
    218 static	enum rofferr	 roff_T_(ROFF_ARGS);
    219 static	enum rofferr	 roff_userdef(ROFF_ARGS);
    220 
    221 /* See roffhash_find() */
    222 
    223 #define	ASCII_HI	 126
    224 #define	ASCII_LO	 33
    225 #define	HASHWIDTH	(ASCII_HI - ASCII_LO + 1)
    226 
    227 static	struct roffmac	*hash[HASHWIDTH];
    228 
    229 static	struct roffmac	 roffs[ROFF_MAX] = {
    230 	{ "ad", roff_line_ignore, NULL, NULL, 0, NULL },
    231 	{ "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },
    232 	{ "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
    233 	{ "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
    234 	{ "cc", roff_cc, NULL, NULL, 0, NULL },
    235 	{ "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },
    236 	{ "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
    237 	{ "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
    238 	{ "ds", roff_ds, NULL, NULL, 0, NULL },
    239 	{ "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
    240 	{ "fam", roff_line_ignore, NULL, NULL, 0, NULL },
    241 	{ "hw", roff_line_ignore, NULL, NULL, 0, NULL },
    242 	{ "hy", roff_line_ignore, NULL, NULL, 0, NULL },
    243 	{ "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
    244 	{ "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
    245 	{ "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL },
    246 	{ "it", roff_it, NULL, NULL, 0, NULL },
    247 	{ "ne", roff_line_ignore, NULL, NULL, 0, NULL },
    248 	{ "nh", roff_line_ignore, NULL, NULL, 0, NULL },
    249 	{ "nr", roff_nr, NULL, NULL, 0, NULL },
    250 	{ "ns", roff_line_ignore, NULL, NULL, 0, NULL },
    251 	{ "ps", roff_line_ignore, NULL, NULL, 0, NULL },
    252 	{ "rm", roff_rm, NULL, NULL, 0, NULL },
    253 	{ "so", roff_so, NULL, NULL, 0, NULL },
    254 	{ "ta", roff_line_ignore, NULL, NULL, 0, NULL },
    255 	{ "tr", roff_tr, NULL, NULL, 0, NULL },
    256 	{ "Dd", roff_Dd, NULL, NULL, 0, NULL },
    257 	{ "TH", roff_TH, NULL, NULL, 0, NULL },
    258 	{ "TS", roff_TS, NULL, NULL, 0, NULL },
    259 	{ "TE", roff_TE, NULL, NULL, 0, NULL },
    260 	{ "T&", roff_T_, NULL, NULL, 0, NULL },
    261 	{ "EQ", roff_EQ, NULL, NULL, 0, NULL },
    262 	{ "EN", roff_EN, NULL, NULL, 0, NULL },
    263 	{ ".", roff_cblock, NULL, NULL, 0, NULL },
    264 	{ "\\}", roff_ccond, NULL, NULL, 0, NULL },
    265 	{ NULL, roff_userdef, NULL, NULL, 0, NULL },
    266 };
    267 
    268 const	char *const __mdoc_reserved[] = {
    269 	"Ac", "Ad", "An", "Ao", "Ap", "Aq", "Ar", "At",
    270 	"Bc", "Bd", "Bf", "Bk", "Bl", "Bo", "Bq",
    271 	"Brc", "Bro", "Brq", "Bsx", "Bt", "Bx",
    272 	"Cd", "Cm", "Db", "Dc", "Dd", "Dl", "Do", "Dq",
    273 	"Ds", "Dt", "Dv", "Dx", "D1",
    274 	"Ec", "Ed", "Ef", "Ek", "El", "Em", "em",
    275 	"En", "Eo", "Eq", "Er", "Es", "Ev", "Ex",
    276 	"Fa", "Fc", "Fd", "Fl", "Fn", "Fo", "Fr", "Ft", "Fx",
    277 	"Hf", "Ic", "In", "It", "Lb", "Li", "Lk", "Lp", "LP",
    278 	"Me", "Ms", "Mt", "Nd", "Nm", "No", "Ns", "Nx",
    279 	"Oc", "Oo", "Op", "Os", "Ot", "Ox",
    280 	"Pa", "Pc", "Pf", "Po", "Pp", "PP", "pp", "Pq",
    281 	"Qc", "Ql", "Qo", "Qq", "Or", "Rd", "Re", "Rs", "Rv",
    282 	"Sc", "Sf", "Sh", "SH", "Sm", "So", "Sq",
    283 	"Ss", "St", "Sx", "Sy",
    284 	"Ta", "Tn", "Ud", "Ux", "Va", "Vt", "Xc", "Xo", "Xr",
    285 	"%A", "%B", "%D", "%I", "%J", "%N", "%O",
    286 	"%P", "%Q", "%R", "%T", "%U", "%V",
    287 	NULL
    288 };
    289 
    290 const	char *const __man_reserved[] = {
    291 	"AT", "B", "BI", "BR", "BT", "DE", "DS", "DT",
    292 	"EE", "EN", "EQ", "EX", "HF", "HP", "I", "IB", "IP", "IR",
    293 	"LP", "ME", "MT", "OP", "P", "PD", "PP", "PT",
    294 	"R", "RB", "RE", "RI", "RS", "SB", "SH", "SM", "SS", "SY",
    295 	"TE", "TH", "TP", "TQ", "TS", "T&", "UC", "UE", "UR", "YS",
    296 	NULL
    297 };
    298 
    299 /* Array of injected predefined strings. */
    300 #define	PREDEFS_MAX	 38
    301 static	const struct predef predefs[PREDEFS_MAX] = {
    302 #include "predefs.in"
    303 };
    304 
    305 /* See roffhash_find() */
    306 #define	ROFF_HASH(p)	(p[0] - ASCII_LO)
    307 
    308 static	int	 roffit_lines;  /* number of lines to delay */
    309 static	char	*roffit_macro;  /* nil-terminated macro line */
    310 
    311 static void
    312 roffhash_init(void)
    313 {
    314 	struct roffmac	 *n;
    315 	int		  buc, i;
    316 
    317 	for (i = 0; i < (int)ROFF_USERDEF; i++) {
    318 		assert(roffs[i].name[0] >= ASCII_LO);
    319 		assert(roffs[i].name[0] <= ASCII_HI);
    320 
    321 		buc = ROFF_HASH(roffs[i].name);
    322 
    323 		if (NULL != (n = hash[buc])) {
    324 			for ( ; n->next; n = n->next)
    325 				/* Do nothing. */ ;
    326 			n->next = &roffs[i];
    327 		} else
    328 			hash[buc] = &roffs[i];
    329 	}
    330 }
    331 
    332 /*
    333  * Look up a roff token by its name.  Returns ROFF_MAX if no macro by
    334  * the nil-terminated string name could be found.
    335  */
    336 static enum rofft
    337 roffhash_find(const char *p, size_t s)
    338 {
    339 	int		 buc;
    340 	struct roffmac	*n;
    341 
    342 	/*
    343 	 * libroff has an extremely simple hashtable, for the time
    344 	 * being, which simply keys on the first character, which must
    345 	 * be printable, then walks a chain.  It works well enough until
    346 	 * optimised.
    347 	 */
    348 
    349 	if (p[0] < ASCII_LO || p[0] > ASCII_HI)
    350 		return(ROFF_MAX);
    351 
    352 	buc = ROFF_HASH(p);
    353 
    354 	if (NULL == (n = hash[buc]))
    355 		return(ROFF_MAX);
    356 	for ( ; n; n = n->next)
    357 		if (0 == strncmp(n->name, p, s) && '\0' == n->name[(int)s])
    358 			return((enum rofft)(n - roffs));
    359 
    360 	return(ROFF_MAX);
    361 }
    362 
    363 
    364 /*
    365  * Pop the current node off of the stack of roff instructions currently
    366  * pending.
    367  */
    368 static void
    369 roffnode_pop(struct roff *r)
    370 {
    371 	struct roffnode	*p;
    372 
    373 	assert(r->last);
    374 	p = r->last;
    375 
    376 	r->last = r->last->parent;
    377 	free(p->name);
    378 	free(p->end);
    379 	free(p);
    380 }
    381 
    382 
    383 /*
    384  * Push a roff node onto the instruction stack.  This must later be
    385  * removed with roffnode_pop().
    386  */
    387 static void
    388 roffnode_push(struct roff *r, enum rofft tok, const char *name,
    389 		int line, int col)
    390 {
    391 	struct roffnode	*p;
    392 
    393 	p = mandoc_calloc(1, sizeof(struct roffnode));
    394 	p->tok = tok;
    395 	if (name)
    396 		p->name = mandoc_strdup(name);
    397 	p->parent = r->last;
    398 	p->line = line;
    399 	p->col = col;
    400 	p->rule = p->parent ? p->parent->rule : ROFFRULE_DENY;
    401 
    402 	r->last = p;
    403 }
    404 
    405 
    406 static void
    407 roff_free1(struct roff *r)
    408 {
    409 	struct tbl_node	*tbl;
    410 	struct eqn_node	*e;
    411 	int		 i;
    412 
    413 	while (NULL != (tbl = r->first_tbl)) {
    414 		r->first_tbl = tbl->next;
    415 		tbl_free(tbl);
    416 	}
    417 
    418 	r->first_tbl = r->last_tbl = r->tbl = NULL;
    419 
    420 	while (NULL != (e = r->first_eqn)) {
    421 		r->first_eqn = e->next;
    422 		eqn_free(e);
    423 	}
    424 
    425 	r->first_eqn = r->last_eqn = r->eqn = NULL;
    426 
    427 	while (r->last)
    428 		roffnode_pop(r);
    429 
    430 	roff_freestr(r->strtab);
    431 	roff_freestr(r->xmbtab);
    432 
    433 	r->strtab = r->xmbtab = NULL;
    434 
    435 	roff_freereg(r->regtab);
    436 
    437 	r->regtab = NULL;
    438 
    439 	if (r->xtab)
    440 		for (i = 0; i < 128; i++)
    441 			free(r->xtab[i].p);
    442 
    443 	free(r->xtab);
    444 	r->xtab = NULL;
    445 }
    446 
    447 void
    448 roff_reset(struct roff *r)
    449 {
    450 	int		 i;
    451 
    452 	roff_free1(r);
    453 
    454 	r->control = 0;
    455 
    456 	for (i = 0; i < PREDEFS_MAX; i++)
    457 		roff_setstr(r, predefs[i].name, predefs[i].str, 0);
    458 }
    459 
    460 
    461 void
    462 roff_free(struct roff *r)
    463 {
    464 
    465 	roff_free1(r);
    466 	free(r);
    467 }
    468 
    469 
    470 struct roff *
    471 roff_alloc(enum mparset type, struct mparse *parse)
    472 {
    473 	struct roff	*r;
    474 	int		 i;
    475 
    476 	r = mandoc_calloc(1, sizeof(struct roff));
    477 	r->parsetype = type;
    478 	r->parse = parse;
    479 	r->rstackpos = -1;
    480 
    481 	roffhash_init();
    482 
    483 	for (i = 0; i < PREDEFS_MAX; i++)
    484 		roff_setstr(r, predefs[i].name, predefs[i].str, 0);
    485 
    486 	return(r);
    487 }
    488 
    489 /*
    490  * In the current line, expand user-defined strings ("\*")
    491  * and references to number registers ("\n").
    492  * Also check the syntax of other escape sequences.
    493  */
    494 static enum rofferr
    495 roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
    496 {
    497 	char		 ubuf[12]; /* buffer to print the number */
    498 	const char	*stesc;	/* start of an escape sequence ('\\') */
    499 	const char	*stnam;	/* start of the name, after "[(*" */
    500 	const char	*cp;	/* end of the name, e.g. before ']' */
    501 	const char	*res;	/* the string to be substituted */
    502 	char		*nbuf;	/* new buffer to copy bufp to */
    503 	size_t		 nsz;	/* size of the new buffer */
    504 	size_t		 maxl;  /* expected length of the escape name */
    505 	size_t		 naml;	/* actual length of the escape name */
    506 	int		 expand_count;	/* to avoid infinite loops */
    507 
    508 	expand_count = 0;
    509 
    510 again:
    511 	cp = *bufp + pos;
    512 	while (NULL != (cp = strchr(cp, '\\'))) {
    513 		stesc = cp++;
    514 
    515 		/*
    516 		 * The second character must be an asterisk or an n.
    517 		 * If it isn't, skip it anyway:  It is escaped,
    518 		 * so it can't start another escape sequence.
    519 		 */
    520 
    521 		if ('\0' == *cp)
    522 			return(ROFF_CONT);
    523 
    524 		switch (*cp) {
    525 		case ('*'):
    526 			res = NULL;
    527 			break;
    528 		case ('n'):
    529 			res = ubuf;
    530 			break;
    531 		default:
    532 			if (ESCAPE_ERROR != mandoc_escape(&cp, NULL, NULL))
    533 				continue;
    534 			mandoc_msg
    535 				(MANDOCERR_BADESCAPE, r->parse,
    536 				 ln, (int)(stesc - *bufp), NULL);
    537 			return(ROFF_CONT);
    538 		}
    539 
    540 		cp++;
    541 
    542 		/*
    543 		 * The third character decides the length
    544 		 * of the name of the string or register.
    545 		 * Save a pointer to the name.
    546 		 */
    547 
    548 		switch (*cp) {
    549 		case ('\0'):
    550 			return(ROFF_CONT);
    551 		case ('('):
    552 			cp++;
    553 			maxl = 2;
    554 			break;
    555 		case ('['):
    556 			cp++;
    557 			maxl = 0;
    558 			break;
    559 		default:
    560 			maxl = 1;
    561 			break;
    562 		}
    563 		stnam = cp;
    564 
    565 		/* Advance to the end of the name. */
    566 
    567 		for (naml = 0; 0 == maxl || naml < maxl; naml++, cp++) {
    568 			if ('\0' == *cp) {
    569 				mandoc_msg
    570 					(MANDOCERR_BADESCAPE,
    571 					 r->parse, ln,
    572 					 (int)(stesc - *bufp), NULL);
    573 				return(ROFF_CONT);
    574 			}
    575 			if (0 == maxl && ']' == *cp)
    576 				break;
    577 		}
    578 
    579 		/*
    580 		 * Retrieve the replacement string; if it is
    581 		 * undefined, resume searching for escapes.
    582 		 */
    583 
    584 		if (NULL == res)
    585 			res = roff_getstrn(r, stnam, naml);
    586 		else
    587 			snprintf(ubuf, sizeof(ubuf), "%d",
    588 			    roff_getregn(r, stnam, naml));
    589 
    590 		if (NULL == res) {
    591 			mandoc_msg
    592 				(MANDOCERR_BADESCAPE, r->parse,
    593 				 ln, (int)(stesc - *bufp), NULL);
    594 			res = "";
    595 		}
    596 
    597 		/* Replace the escape sequence by the string. */
    598 
    599 		pos = stesc - *bufp;
    600 
    601 		nsz = *szp + strlen(res) + 1;
    602 		nbuf = mandoc_malloc(nsz);
    603 
    604 		strlcpy(nbuf, *bufp, (size_t)(stesc - *bufp + 1));
    605 		strlcat(nbuf, res, nsz);
    606 		strlcat(nbuf, cp + (maxl ? 0 : 1), nsz);
    607 
    608 		free(*bufp);
    609 
    610 		*bufp = nbuf;
    611 		*szp = nsz;
    612 
    613 		if (EXPAND_LIMIT >= ++expand_count)
    614 			goto again;
    615 
    616 		/* Just leave the string unexpanded. */
    617 		mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, ln, pos, NULL);
    618 		return(ROFF_IGN);
    619 	}
    620 	return(ROFF_CONT);
    621 }
    622 
    623 /*
    624  * Process text streams:
    625  * Convert all breakable hyphens into ASCII_HYPH.
    626  * Decrement and spring input line trap.
    627  */
    628 static enum rofferr
    629 roff_parsetext(char **bufp, size_t *szp, int pos, int *offs)
    630 {
    631 	size_t		 sz;
    632 	const char	*start;
    633 	char		*p;
    634 	int		 isz;
    635 	enum mandoc_esc	 esc;
    636 
    637 	start = p = *bufp + pos;
    638 
    639 	while ('\0' != *p) {
    640 		sz = strcspn(p, "-\\");
    641 		p += sz;
    642 
    643 		if ('\0' == *p)
    644 			break;
    645 
    646 		if ('\\' == *p) {
    647 			/* Skip over escapes. */
    648 			p++;
    649 			esc = mandoc_escape((const char **)(void *)&p, NULL, NULL);
    650 			if (ESCAPE_ERROR == esc)
    651 				break;
    652 			continue;
    653 		} else if (p == start) {
    654 			p++;
    655 			continue;
    656 		}
    657 
    658 		if (isalpha((unsigned char)p[-1]) &&
    659 		    isalpha((unsigned char)p[1]))
    660 			*p = ASCII_HYPH;
    661 		p++;
    662 	}
    663 
    664 	/* Spring the input line trap. */
    665 	if (1 == roffit_lines) {
    666 		isz = asprintf(&p, "%s\n.%s", *bufp, roffit_macro);
    667 		if (-1 == isz) {
    668 			perror(NULL);
    669 			exit((int)MANDOCLEVEL_SYSERR);
    670 		}
    671 		free(*bufp);
    672 		*bufp = p;
    673 		*szp = isz + 1;
    674 		*offs = 0;
    675 		free(roffit_macro);
    676 		roffit_lines = 0;
    677 		return(ROFF_REPARSE);
    678 	} else if (1 < roffit_lines)
    679 		--roffit_lines;
    680 	return(ROFF_CONT);
    681 }
    682 
    683 enum rofferr
    684 roff_parseln(struct roff *r, int ln, char **bufp,
    685 		size_t *szp, int pos, int *offs)
    686 {
    687 	enum rofft	 t;
    688 	enum rofferr	 e;
    689 	int		 ppos, ctl;
    690 
    691 	/*
    692 	 * Run the reserved-word filter only if we have some reserved
    693 	 * words to fill in.
    694 	 */
    695 
    696 	e = roff_res(r, bufp, szp, ln, pos);
    697 	if (ROFF_IGN == e)
    698 		return(e);
    699 	assert(ROFF_CONT == e);
    700 
    701 	ppos = pos;
    702 	ctl = roff_getcontrol(r, *bufp, &pos);
    703 
    704 	/*
    705 	 * First, if a scope is open and we're not a macro, pass the
    706 	 * text through the macro's filter.  If a scope isn't open and
    707 	 * we're not a macro, just let it through.
    708 	 * Finally, if there's an equation scope open, divert it into it
    709 	 * no matter our state.
    710 	 */
    711 
    712 	if (r->last && ! ctl) {
    713 		t = r->last->tok;
    714 		assert(roffs[t].text);
    715 		e = (*roffs[t].text)
    716 			(r, t, bufp, szp, ln, pos, pos, offs);
    717 		assert(ROFF_IGN == e || ROFF_CONT == e);
    718 		if (ROFF_CONT != e)
    719 			return(e);
    720 	}
    721 	if (r->eqn)
    722 		return(eqn_read(&r->eqn, ln, *bufp, ppos, offs));
    723 	if ( ! ctl) {
    724 		if (r->tbl)
    725 			return(tbl_read(r->tbl, ln, *bufp, pos));
    726 		return(roff_parsetext(bufp, szp, pos, offs));
    727 	}
    728 
    729 	/*
    730 	 * If a scope is open, go to the child handler for that macro,
    731 	 * as it may want to preprocess before doing anything with it.
    732 	 * Don't do so if an equation is open.
    733 	 */
    734 
    735 	if (r->last) {
    736 		t = r->last->tok;
    737 		assert(roffs[t].sub);
    738 		return((*roffs[t].sub)
    739 				(r, t, bufp, szp,
    740 				 ln, ppos, pos, offs));
    741 	}
    742 
    743 	/*
    744 	 * Lastly, as we've no scope open, try to look up and execute
    745 	 * the new macro.  If no macro is found, simply return and let
    746 	 * the compilers handle it.
    747 	 */
    748 
    749 	if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos)))
    750 		return(ROFF_CONT);
    751 
    752 	assert(roffs[t].proc);
    753 	return((*roffs[t].proc)
    754 			(r, t, bufp, szp,
    755 			 ln, ppos, pos, offs));
    756 }
    757 
    758 
    759 void
    760 roff_endparse(struct roff *r)
    761 {
    762 
    763 	if (r->last)
    764 		mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
    765 				r->last->line, r->last->col, NULL);
    766 
    767 	if (r->eqn) {
    768 		mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
    769 				r->eqn->eqn.ln, r->eqn->eqn.pos, NULL);
    770 		eqn_end(&r->eqn);
    771 	}
    772 
    773 	if (r->tbl) {
    774 		mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
    775 				r->tbl->line, r->tbl->pos, NULL);
    776 		tbl_end(&r->tbl);
    777 	}
    778 }
    779 
    780 /*
    781  * Parse a roff node's type from the input buffer.  This must be in the
    782  * form of ".foo xxx" in the usual way.
    783  */
    784 static enum rofft
    785 roff_parse(struct roff *r, const char *buf, int *pos)
    786 {
    787 	const char	*mac;
    788 	size_t		 maclen;
    789 	enum rofft	 t;
    790 
    791 	if ('\0' == buf[*pos] || '"' == buf[*pos] ||
    792 			'\t' == buf[*pos] || ' ' == buf[*pos])
    793 		return(ROFF_MAX);
    794 
    795 	/*
    796 	 * We stop the macro parse at an escape, tab, space, or nil.
    797 	 * However, `\}' is also a valid macro, so make sure we don't
    798 	 * clobber it by seeing the `\' as the end of token.
    799 	 */
    800 
    801 	mac = buf + *pos;
    802 	maclen = strcspn(mac + 1, " \\\t\0") + 1;
    803 
    804 	t = (r->current_string = roff_getstrn(r, mac, maclen))
    805 	    ? ROFF_USERDEF : roffhash_find(mac, maclen);
    806 
    807 	*pos += (int)maclen;
    808 
    809 	while (buf[*pos] && ' ' == buf[*pos])
    810 		(*pos)++;
    811 
    812 	return(t);
    813 }
    814 
    815 /* ARGSUSED */
    816 static enum rofferr
    817 roff_cblock(ROFF_ARGS)
    818 {
    819 
    820 	/*
    821 	 * A block-close `..' should only be invoked as a child of an
    822 	 * ignore macro, otherwise raise a warning and just ignore it.
    823 	 */
    824 
    825 	if (NULL == r->last) {
    826 		mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
    827 		return(ROFF_IGN);
    828 	}
    829 
    830 	switch (r->last->tok) {
    831 	case (ROFF_am):
    832 		/* FALLTHROUGH */
    833 	case (ROFF_ami):
    834 		/* FALLTHROUGH */
    835 	case (ROFF_am1):
    836 		/* FALLTHROUGH */
    837 	case (ROFF_de):
    838 		/* ROFF_de1 is remapped to ROFF_de in roff_block(). */
    839 		/* FALLTHROUGH */
    840 	case (ROFF_dei):
    841 		/* FALLTHROUGH */
    842 	case (ROFF_ig):
    843 		break;
    844 	default:
    845 		mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
    846 		return(ROFF_IGN);
    847 	}
    848 
    849 	if ((*bufp)[pos])
    850 		mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
    851 
    852 	roffnode_pop(r);
    853 	roffnode_cleanscope(r);
    854 	return(ROFF_IGN);
    855 
    856 }
    857 
    858 
    859 static void
    860 roffnode_cleanscope(struct roff *r)
    861 {
    862 
    863 	while (r->last) {
    864 		if (--r->last->endspan != 0)
    865 			break;
    866 		roffnode_pop(r);
    867 	}
    868 }
    869 
    870 
    871 /* ARGSUSED */
    872 static enum rofferr
    873 roff_ccond(ROFF_ARGS)
    874 {
    875 
    876 	if (NULL == r->last) {
    877 		mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
    878 		return(ROFF_IGN);
    879 	}
    880 
    881 	switch (r->last->tok) {
    882 	case (ROFF_el):
    883 		/* FALLTHROUGH */
    884 	case (ROFF_ie):
    885 		/* FALLTHROUGH */
    886 	case (ROFF_if):
    887 		break;
    888 	default:
    889 		mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
    890 		return(ROFF_IGN);
    891 	}
    892 
    893 	if (r->last->endspan > -1) {
    894 		mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
    895 		return(ROFF_IGN);
    896 	}
    897 
    898 	if ((*bufp)[pos])
    899 		mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
    900 
    901 	roffnode_pop(r);
    902 	roffnode_cleanscope(r);
    903 	return(ROFF_IGN);
    904 }
    905 
    906 
    907 /* ARGSUSED */
    908 static enum rofferr
    909 roff_block(ROFF_ARGS)
    910 {
    911 	int		sv;
    912 	size_t		sz;
    913 	char		*name;
    914 
    915 	name = NULL;
    916 
    917 	if (ROFF_ig != tok) {
    918 		if ('\0' == (*bufp)[pos]) {
    919 			mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);
    920 			return(ROFF_IGN);
    921 		}
    922 
    923 		/*
    924 		 * Re-write `de1', since we don't really care about
    925 		 * groff's strange compatibility mode, into `de'.
    926 		 */
    927 
    928 		if (ROFF_de1 == tok)
    929 			tok = ROFF_de;
    930 		if (ROFF_de == tok)
    931 			name = *bufp + pos;
    932 		else
    933 			mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos,
    934 			    roffs[tok].name);
    935 
    936 		while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos]))
    937 			pos++;
    938 
    939 		while (isspace((unsigned char)(*bufp)[pos]))
    940 			(*bufp)[pos++] = '\0';
    941 	}
    942 
    943 	roffnode_push(r, tok, name, ln, ppos);
    944 
    945 	/*
    946 	 * At the beginning of a `de' macro, clear the existing string
    947 	 * with the same name, if there is one.  New content will be
    948 	 * added from roff_block_text() in multiline mode.
    949 	 */
    950 
    951 	if (ROFF_de == tok)
    952 		roff_setstr(r, name, "", 0);
    953 
    954 	if ('\0' == (*bufp)[pos])
    955 		return(ROFF_IGN);
    956 
    957 	/* If present, process the custom end-of-line marker. */
    958 
    959 	sv = pos;
    960 	while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos]))
    961 		pos++;
    962 
    963 	/*
    964 	 * Note: groff does NOT like escape characters in the input.
    965 	 * Instead of detecting this, we're just going to let it fly and
    966 	 * to hell with it.
    967 	 */
    968 
    969 	assert(pos > sv);
    970 	sz = (size_t)(pos - sv);
    971 
    972 	if (1 == sz && '.' == (*bufp)[sv])
    973 		return(ROFF_IGN);
    974 
    975 	r->last->end = mandoc_malloc(sz + 1);
    976 
    977 	memcpy(r->last->end, *bufp + sv, sz);
    978 	r->last->end[(int)sz] = '\0';
    979 
    980 	if ((*bufp)[pos])
    981 		mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
    982 
    983 	return(ROFF_IGN);
    984 }
    985 
    986 
    987 /* ARGSUSED */
    988 static enum rofferr
    989 roff_block_sub(ROFF_ARGS)
    990 {
    991 	enum rofft	t;
    992 	int		i, j;
    993 
    994 	/*
    995 	 * First check whether a custom macro exists at this level.  If
    996 	 * it does, then check against it.  This is some of groff's
    997 	 * stranger behaviours.  If we encountered a custom end-scope
    998 	 * tag and that tag also happens to be a "real" macro, then we
    999 	 * need to try interpreting it again as a real macro.  If it's
   1000 	 * not, then return ignore.  Else continue.
   1001 	 */
   1002 
   1003 	if (r->last->end) {
   1004 		for (i = pos, j = 0; r->last->end[j]; j++, i++)
   1005 			if ((*bufp)[i] != r->last->end[j])
   1006 				break;
   1007 
   1008 		if ('\0' == r->last->end[j] &&
   1009 				('\0' == (*bufp)[i] ||
   1010 				 ' ' == (*bufp)[i] ||
   1011 				 '\t' == (*bufp)[i])) {
   1012 			roffnode_pop(r);
   1013 			roffnode_cleanscope(r);
   1014 
   1015 			while (' ' == (*bufp)[i] || '\t' == (*bufp)[i])
   1016 				i++;
   1017 
   1018 			pos = i;
   1019 			if (ROFF_MAX != roff_parse(r, *bufp, &pos))
   1020 				return(ROFF_RERUN);
   1021 			return(ROFF_IGN);
   1022 		}
   1023 	}
   1024 
   1025 	/*
   1026 	 * If we have no custom end-query or lookup failed, then try
   1027 	 * pulling it out of the hashtable.
   1028 	 */
   1029 
   1030 	t = roff_parse(r, *bufp, &pos);
   1031 
   1032 	/*
   1033 	 * Macros other than block-end are only significant
   1034 	 * in `de' blocks; elsewhere, simply throw them away.
   1035 	 */
   1036 	if (ROFF_cblock != t) {
   1037 		if (ROFF_de == tok)
   1038 			roff_setstr(r, r->last->name, *bufp + ppos, 1);
   1039 		return(ROFF_IGN);
   1040 	}
   1041 
   1042 	assert(roffs[t].proc);
   1043 	return((*roffs[t].proc)(r, t, bufp, szp,
   1044 				ln, ppos, pos, offs));
   1045 }
   1046 
   1047 
   1048 /* ARGSUSED */
   1049 static enum rofferr
   1050 roff_block_text(ROFF_ARGS)
   1051 {
   1052 
   1053 	if (ROFF_de == tok)
   1054 		roff_setstr(r, r->last->name, *bufp + pos, 1);
   1055 
   1056 	return(ROFF_IGN);
   1057 }
   1058 
   1059 
   1060 /* ARGSUSED */
   1061 static enum rofferr
   1062 roff_cond_sub(ROFF_ARGS)
   1063 {
   1064 	enum rofft	 t;
   1065 	enum roffrule	 rr;
   1066 	char		*ep;
   1067 
   1068 	rr = r->last->rule;
   1069 	roffnode_cleanscope(r);
   1070 	t = roff_parse(r, *bufp, &pos);
   1071 
   1072 	/*
   1073 	 * Fully handle known macros when they are structurally
   1074 	 * required or when the conditional evaluated to true.
   1075 	 */
   1076 
   1077 	if ((ROFF_MAX != t) &&
   1078 	    (ROFF_ccond == t || ROFFRULE_ALLOW == rr ||
   1079 	     ROFFMAC_STRUCT & roffs[t].flags)) {
   1080 		assert(roffs[t].proc);
   1081 		return((*roffs[t].proc)(r, t, bufp, szp,
   1082 					ln, ppos, pos, offs));
   1083 	}
   1084 
   1085 	/* Always check for the closing delimiter `\}'. */
   1086 
   1087 	ep = &(*bufp)[pos];
   1088 	while (NULL != (ep = strchr(ep, '\\'))) {
   1089 		if ('}' != *(++ep))
   1090 			continue;
   1091 
   1092 		/*
   1093 		 * If we're at the end of line, then just chop
   1094 		 * off the \} and resize the buffer.
   1095 		 * If we aren't, then convert it to spaces.
   1096 		 */
   1097 
   1098 		if ('\0' == *(ep + 1)) {
   1099 			*--ep = '\0';
   1100 			*szp -= 2;
   1101 		} else
   1102 			*(ep - 1) = *ep = ' ';
   1103 
   1104 		roff_ccond(r, ROFF_ccond, bufp, szp,
   1105 				ln, pos, pos + 2, offs);
   1106 		break;
   1107 	}
   1108 	return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
   1109 }
   1110 
   1111 /* ARGSUSED */
   1112 static enum rofferr
   1113 roff_cond_text(ROFF_ARGS)
   1114 {
   1115 	char		*ep;
   1116 	enum roffrule	 rr;
   1117 
   1118 	rr = r->last->rule;
   1119 	roffnode_cleanscope(r);
   1120 
   1121 	ep = &(*bufp)[pos];
   1122 	for ( ; NULL != (ep = strchr(ep, '\\')); ep++) {
   1123 		ep++;
   1124 		if ('}' != *ep)
   1125 			continue;
   1126 		*ep = '&';
   1127 		roff_ccond(r, ROFF_ccond, bufp, szp,
   1128 				ln, pos, pos + 2, offs);
   1129 	}
   1130 	return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
   1131 }
   1132 
   1133 static int
   1134 roff_getnum(const char *v, int *pos, int *res)
   1135 {
   1136 	int p, n;
   1137 
   1138 	p = *pos;
   1139 	n = v[p] == '-';
   1140 	if (n)
   1141 		p++;
   1142 
   1143 	for (*res = 0; isdigit((unsigned char)v[p]); p++)
   1144 		*res += 10 * *res + v[p] - '0';
   1145 	if (p == *pos + n)
   1146 		return 0;
   1147 
   1148 	if (n)
   1149 		*res = -*res;
   1150 
   1151 	*pos = p;
   1152 	return 1;
   1153 }
   1154 
   1155 static int
   1156 roff_getop(const char *v, int *pos, char *res)
   1157 {
   1158 	int e;
   1159 
   1160 	*res = v[*pos];
   1161 	e = v[*pos + 1] == '=';
   1162 
   1163 	switch (*res) {
   1164 	case '=':
   1165 		break;
   1166 	case '>':
   1167 		if (e)
   1168 			*res = 'g';
   1169 		break;
   1170 	case '<':
   1171 		if (e)
   1172 			*res = 'l';
   1173 		break;
   1174 	default:
   1175 		return(0);
   1176 	}
   1177 
   1178 	*pos += 1 + e;
   1179 
   1180 	return(*res);
   1181 }
   1182 
   1183 static enum roffrule
   1184 roff_evalcond(const char *v, int *pos)
   1185 {
   1186 	int	 not, lh, rh;
   1187 	char	 op;
   1188 
   1189 	switch (v[*pos]) {
   1190 	case ('n'):
   1191 		(*pos)++;
   1192 		return(ROFFRULE_ALLOW);
   1193 	case ('e'):
   1194 		/* FALLTHROUGH */
   1195 	case ('o'):
   1196 		/* FALLTHROUGH */
   1197 	case ('t'):
   1198 		(*pos)++;
   1199 		return(ROFFRULE_DENY);
   1200 	case ('!'):
   1201 		(*pos)++;
   1202 		not = 1;
   1203 		break;
   1204 	default:
   1205 		not = 0;
   1206 		break;
   1207 	}
   1208 
   1209 	if (!roff_getnum(v, pos, &lh))
   1210 		return ROFFRULE_DENY;
   1211 	if (!roff_getop(v, pos, &op)) {
   1212 		if (lh < 0)
   1213 			lh = 0;
   1214 		goto out;
   1215 	}
   1216 	if (!roff_getnum(v, pos, &rh))
   1217 		return ROFFRULE_DENY;
   1218 	switch (op) {
   1219 	case 'g':
   1220 		lh = lh >= rh;
   1221 		break;
   1222 	case 'l':
   1223 		lh = lh <= rh;
   1224 		break;
   1225 	case '=':
   1226 		lh = lh == rh;
   1227 		break;
   1228 	case '>':
   1229 		lh = lh > rh;
   1230 		break;
   1231 	case '<':
   1232 		lh = lh < rh;
   1233 		break;
   1234 	default:
   1235 		return ROFFRULE_DENY;
   1236 	}
   1237 out:
   1238 	if (not)
   1239 		lh = !lh;
   1240 	return lh ? ROFFRULE_ALLOW : ROFFRULE_DENY;
   1241 }
   1242 
   1243 /* ARGSUSED */
   1244 static enum rofferr
   1245 roff_line_ignore(ROFF_ARGS)
   1246 {
   1247 
   1248 	return(ROFF_IGN);
   1249 }
   1250 
   1251 /* ARGSUSED */
   1252 static enum rofferr
   1253 roff_cond(ROFF_ARGS)
   1254 {
   1255 
   1256 	roffnode_push(r, tok, NULL, ln, ppos);
   1257 
   1258 	/*
   1259 	 * An `.el' has no conditional body: it will consume the value
   1260 	 * of the current rstack entry set in prior `ie' calls or
   1261 	 * defaults to DENY.
   1262 	 *
   1263 	 * If we're not an `el', however, then evaluate the conditional.
   1264 	 */
   1265 
   1266 	r->last->rule = ROFF_el == tok ?
   1267 		(r->rstackpos < 0 ?
   1268 		 ROFFRULE_DENY : r->rstack[r->rstackpos--]) :
   1269 		roff_evalcond(*bufp, &pos);
   1270 
   1271 	/*
   1272 	 * An if-else will put the NEGATION of the current evaluated
   1273 	 * conditional into the stack of rules.
   1274 	 */
   1275 
   1276 	if (ROFF_ie == tok) {
   1277 		if (r->rstackpos == RSTACK_MAX - 1) {
   1278 			mandoc_msg(MANDOCERR_MEM,
   1279 				r->parse, ln, ppos, NULL);
   1280 			return(ROFF_ERR);
   1281 		}
   1282 		r->rstack[++r->rstackpos] =
   1283 			ROFFRULE_DENY == r->last->rule ?
   1284 			ROFFRULE_ALLOW : ROFFRULE_DENY;
   1285 	}
   1286 
   1287 	/* If the parent has false as its rule, then so do we. */
   1288 
   1289 	if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule)
   1290 		r->last->rule = ROFFRULE_DENY;
   1291 
   1292 	/*
   1293 	 * Determine scope.
   1294 	 * If there is nothing on the line after the conditional,
   1295 	 * not even whitespace, use next-line scope.
   1296 	 */
   1297 
   1298 	if ('\0' == (*bufp)[pos]) {
   1299 		r->last->endspan = 2;
   1300 		goto out;
   1301 	}
   1302 
   1303 	while (' ' == (*bufp)[pos])
   1304 		pos++;
   1305 
   1306 	/* An opening brace requests multiline scope. */
   1307 
   1308 	if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) {
   1309 		r->last->endspan = -1;
   1310 		pos += 2;
   1311 		goto out;
   1312 	}
   1313 
   1314 	/*
   1315 	 * Anything else following the conditional causes
   1316 	 * single-line scope.  Warn if the scope contains
   1317 	 * nothing but trailing whitespace.
   1318 	 */
   1319 
   1320 	if ('\0' == (*bufp)[pos])
   1321 		mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);
   1322 
   1323 	r->last->endspan = 1;
   1324 
   1325 out:
   1326 	*offs = pos;
   1327 	return(ROFF_RERUN);
   1328 }
   1329 
   1330 
   1331 /* ARGSUSED */
   1332 static enum rofferr
   1333 roff_ds(ROFF_ARGS)
   1334 {
   1335 	char		*name, *string;
   1336 
   1337 	/*
   1338 	 * A symbol is named by the first word following the macro
   1339 	 * invocation up to a space.  Its value is anything after the
   1340 	 * name's trailing whitespace and optional double-quote.  Thus,
   1341 	 *
   1342 	 *  [.ds foo "bar  "     ]
   1343 	 *
   1344 	 * will have `bar  "     ' as its value.
   1345 	 */
   1346 
   1347 	string = *bufp + pos;
   1348 	name = roff_getname(r, &string, ln, pos);
   1349 	if ('\0' == *name)
   1350 		return(ROFF_IGN);
   1351 
   1352 	/* Read past initial double-quote. */
   1353 	if ('"' == *string)
   1354 		string++;
   1355 
   1356 	/* The rest is the value. */
   1357 	roff_setstr(r, name, string, 0);
   1358 	return(ROFF_IGN);
   1359 }
   1360 
   1361 void
   1362 roff_setreg(struct roff *r, const char *name, int val, char sign)
   1363 {
   1364 	struct roffreg	*reg;
   1365 
   1366 	/* Search for an existing register with the same name. */
   1367 	reg = r->regtab;
   1368 
   1369 	while (reg && strcmp(name, reg->key.p))
   1370 		reg = reg->next;
   1371 
   1372 	if (NULL == reg) {
   1373 		/* Create a new register. */
   1374 		reg = mandoc_malloc(sizeof(struct roffreg));
   1375 		reg->key.p = mandoc_strdup(name);
   1376 		reg->key.sz = strlen(name);
   1377 		reg->val = 0;
   1378 		reg->next = r->regtab;
   1379 		r->regtab = reg;
   1380 	}
   1381 
   1382 	if ('+' == sign)
   1383 		reg->val += val;
   1384 	else if ('-' == sign)
   1385 		reg->val -= val;
   1386 	else
   1387 		reg->val = val;
   1388 }
   1389 
   1390 int
   1391 roff_getreg(const struct roff *r, const char *name)
   1392 {
   1393 	struct roffreg	*reg;
   1394 
   1395 	for (reg = r->regtab; reg; reg = reg->next)
   1396 		if (0 == strcmp(name, reg->key.p))
   1397 			return(reg->val);
   1398 
   1399 	return(0);
   1400 }
   1401 
   1402 static int
   1403 roff_getregn(const struct roff *r, const char *name, size_t len)
   1404 {
   1405 	struct roffreg	*reg;
   1406 
   1407 	for (reg = r->regtab; reg; reg = reg->next)
   1408 		if (len == reg->key.sz &&
   1409 		    0 == strncmp(name, reg->key.p, len))
   1410 			return(reg->val);
   1411 
   1412 	return(0);
   1413 }
   1414 
   1415 static void
   1416 roff_freereg(struct roffreg *reg)
   1417 {
   1418 	struct roffreg	*old_reg;
   1419 
   1420 	while (NULL != reg) {
   1421 		free(reg->key.p);
   1422 		old_reg = reg;
   1423 		reg = reg->next;
   1424 		free(old_reg);
   1425 	}
   1426 }
   1427 
   1428 /* ARGSUSED */
   1429 static enum rofferr
   1430 roff_nr(ROFF_ARGS)
   1431 {
   1432 	const char	*key;
   1433 	char		*val;
   1434 	size_t		 sz;
   1435 	int		 iv;
   1436 	char		 sign;
   1437 
   1438 	val = *bufp + pos;
   1439 	key = roff_getname(r, &val, ln, pos);
   1440 
   1441 	sign = *val;
   1442 	if ('+' == sign || '-' == sign)
   1443 		val++;
   1444 
   1445 	sz = strspn(val, "0123456789");
   1446 	iv = sz ? mandoc_strntoi(val, sz, 10) : 0;
   1447 
   1448 	roff_setreg(r, key, iv, sign);
   1449 
   1450 	return(ROFF_IGN);
   1451 }
   1452 
   1453 /* ARGSUSED */
   1454 static enum rofferr
   1455 roff_rm(ROFF_ARGS)
   1456 {
   1457 	const char	 *name;
   1458 	char		 *cp;
   1459 
   1460 	cp = *bufp + pos;
   1461 	while ('\0' != *cp) {
   1462 		name = roff_getname(r, &cp, ln, (int)(cp - *bufp));
   1463 		if ('\0' != *name)
   1464 			roff_setstr(r, name, NULL, 0);
   1465 	}
   1466 	return(ROFF_IGN);
   1467 }
   1468 
   1469 /* ARGSUSED */
   1470 static enum rofferr
   1471 roff_it(ROFF_ARGS)
   1472 {
   1473 	char		*cp;
   1474 	size_t		 len;
   1475 	int		 iv;
   1476 
   1477 	/* Parse the number of lines. */
   1478 	cp = *bufp + pos;
   1479 	len = strcspn(cp, " \t");
   1480 	cp[len] = '\0';
   1481 	if ((iv = mandoc_strntoi(cp, len, 10)) <= 0) {
   1482 		mandoc_msg(MANDOCERR_NUMERIC, r->parse,
   1483 				ln, ppos, *bufp + 1);
   1484 		return(ROFF_IGN);
   1485 	}
   1486 	cp += len + 1;
   1487 
   1488 	/* Arm the input line trap. */
   1489 	roffit_lines = iv;
   1490 	roffit_macro = mandoc_strdup(cp);
   1491 	return(ROFF_IGN);
   1492 }
   1493 
   1494 /* ARGSUSED */
   1495 static enum rofferr
   1496 roff_Dd(ROFF_ARGS)
   1497 {
   1498 	const char *const	*cp;
   1499 
   1500 	if (MPARSE_MDOC != r->parsetype)
   1501 		for (cp = __mdoc_reserved; *cp; cp++)
   1502 			roff_setstr(r, *cp, NULL, 0);
   1503 
   1504 	return(ROFF_CONT);
   1505 }
   1506 
   1507 /* ARGSUSED */
   1508 static enum rofferr
   1509 roff_TH(ROFF_ARGS)
   1510 {
   1511 	const char *const	*cp;
   1512 
   1513 	if (MPARSE_MDOC != r->parsetype)
   1514 		for (cp = __man_reserved; *cp; cp++)
   1515 			roff_setstr(r, *cp, NULL, 0);
   1516 
   1517 	return(ROFF_CONT);
   1518 }
   1519 
   1520 /* ARGSUSED */
   1521 static enum rofferr
   1522 roff_TE(ROFF_ARGS)
   1523 {
   1524 
   1525 	if (NULL == r->tbl)
   1526 		mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
   1527 	else
   1528 		tbl_end(&r->tbl);
   1529 
   1530 	return(ROFF_IGN);
   1531 }
   1532 
   1533 /* ARGSUSED */
   1534 static enum rofferr
   1535 roff_T_(ROFF_ARGS)
   1536 {
   1537 
   1538 	if (NULL == r->tbl)
   1539 		mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
   1540 	else
   1541 		tbl_restart(ppos, ln, r->tbl);
   1542 
   1543 	return(ROFF_IGN);
   1544 }
   1545 
   1546 #if 0
   1547 static int
   1548 roff_closeeqn(struct roff *r)
   1549 {
   1550 
   1551 	return(r->eqn && ROFF_EQN == eqn_end(&r->eqn) ? 1 : 0);
   1552 }
   1553 #endif
   1554 
   1555 static void
   1556 roff_openeqn(struct roff *r, const char *name, int line,
   1557 		int offs, const char *buf)
   1558 {
   1559 	struct eqn_node *e;
   1560 	int		 poff;
   1561 
   1562 	assert(NULL == r->eqn);
   1563 	e = eqn_alloc(name, offs, line, r->parse);
   1564 
   1565 	if (r->last_eqn)
   1566 		r->last_eqn->next = e;
   1567 	else
   1568 		r->first_eqn = r->last_eqn = e;
   1569 
   1570 	r->eqn = r->last_eqn = e;
   1571 
   1572 	if (buf) {
   1573 		poff = 0;
   1574 		eqn_read(&r->eqn, line, buf, offs, &poff);
   1575 	}
   1576 }
   1577 
   1578 /* ARGSUSED */
   1579 static enum rofferr
   1580 roff_EQ(ROFF_ARGS)
   1581 {
   1582 
   1583 	roff_openeqn(r, *bufp + pos, ln, ppos, NULL);
   1584 	return(ROFF_IGN);
   1585 }
   1586 
   1587 /* ARGSUSED */
   1588 static enum rofferr
   1589 roff_EN(ROFF_ARGS)
   1590 {
   1591 
   1592 	mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
   1593 	return(ROFF_IGN);
   1594 }
   1595 
   1596 /* ARGSUSED */
   1597 static enum rofferr
   1598 roff_TS(ROFF_ARGS)
   1599 {
   1600 	struct tbl_node	*tbl;
   1601 
   1602 	if (r->tbl) {
   1603 		mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL);
   1604 		tbl_end(&r->tbl);
   1605 	}
   1606 
   1607 	tbl = tbl_alloc(ppos, ln, r->parse);
   1608 
   1609 	if (r->last_tbl)
   1610 		r->last_tbl->next = tbl;
   1611 	else
   1612 		r->first_tbl = r->last_tbl = tbl;
   1613 
   1614 	r->tbl = r->last_tbl = tbl;
   1615 	return(ROFF_IGN);
   1616 }
   1617 
   1618 /* ARGSUSED */
   1619 static enum rofferr
   1620 roff_cc(ROFF_ARGS)
   1621 {
   1622 	const char	*p;
   1623 
   1624 	p = *bufp + pos;
   1625 
   1626 	if ('\0' == *p || '.' == (r->control = *p++))
   1627 		r->control = 0;
   1628 
   1629 	if ('\0' != *p)
   1630 		mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL);
   1631 
   1632 	return(ROFF_IGN);
   1633 }
   1634 
   1635 /* ARGSUSED */
   1636 static enum rofferr
   1637 roff_tr(ROFF_ARGS)
   1638 {
   1639 	const char	*p, *first, *second;
   1640 	size_t		 fsz, ssz;
   1641 	enum mandoc_esc	 esc;
   1642 
   1643 	p = *bufp + pos;
   1644 
   1645 	if ('\0' == *p) {
   1646 		mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL);
   1647 		return(ROFF_IGN);
   1648 	}
   1649 
   1650 	while ('\0' != *p) {
   1651 		fsz = ssz = 1;
   1652 
   1653 		first = p++;
   1654 		if ('\\' == *first) {
   1655 			esc = mandoc_escape(&p, NULL, NULL);
   1656 			if (ESCAPE_ERROR == esc) {
   1657 				mandoc_msg
   1658 					(MANDOCERR_BADESCAPE, r->parse,
   1659 					 ln, (int)(p - *bufp), NULL);
   1660 				return(ROFF_IGN);
   1661 			}
   1662 			fsz = (size_t)(p - first);
   1663 		}
   1664 
   1665 		second = p++;
   1666 		if ('\\' == *second) {
   1667 			esc = mandoc_escape(&p, NULL, NULL);
   1668 			if (ESCAPE_ERROR == esc) {
   1669 				mandoc_msg
   1670 					(MANDOCERR_BADESCAPE, r->parse,
   1671 					 ln, (int)(p - *bufp), NULL);
   1672 				return(ROFF_IGN);
   1673 			}
   1674 			ssz = (size_t)(p - second);
   1675 		} else if ('\0' == *second) {
   1676 			mandoc_msg(MANDOCERR_ARGCOUNT, r->parse,
   1677 					ln, (int)(p - *bufp), NULL);
   1678 			second = " ";
   1679 			p--;
   1680 		}
   1681 
   1682 		if (fsz > 1) {
   1683 			roff_setstrn(&r->xmbtab, first,
   1684 					fsz, second, ssz, 0);
   1685 			continue;
   1686 		}
   1687 
   1688 		if (NULL == r->xtab)
   1689 			r->xtab = mandoc_calloc
   1690 				(128, sizeof(struct roffstr));
   1691 
   1692 		free(r->xtab[(int)*first].p);
   1693 		r->xtab[(int)*first].p = mandoc_strndup(second, ssz);
   1694 		r->xtab[(int)*first].sz = ssz;
   1695 	}
   1696 
   1697 	return(ROFF_IGN);
   1698 }
   1699 
   1700 /* ARGSUSED */
   1701 static enum rofferr
   1702 roff_so(ROFF_ARGS)
   1703 {
   1704 	char *name;
   1705 
   1706 	mandoc_msg(MANDOCERR_SO, r->parse, ln, ppos, NULL);
   1707 
   1708 	/*
   1709 	 * Handle `so'.  Be EXTREMELY careful, as we shouldn't be
   1710 	 * opening anything that's not in our cwd or anything beneath
   1711 	 * it.  Thus, explicitly disallow traversing up the file-system
   1712 	 * or using absolute paths.
   1713 	 */
   1714 
   1715 	name = *bufp + pos;
   1716 	if ('/' == *name || strstr(name, "../") || strstr(name, "/..")) {
   1717 		mandoc_msg(MANDOCERR_SOPATH, r->parse, ln, pos, NULL);
   1718 		return(ROFF_ERR);
   1719 	}
   1720 
   1721 	*offs = pos;
   1722 	return(ROFF_SO);
   1723 }
   1724 
   1725 /* ARGSUSED */
   1726 static enum rofferr
   1727 roff_userdef(ROFF_ARGS)
   1728 {
   1729 	const char	 *arg[9];
   1730 	char		 *cp, *n1, *n2;
   1731 	int		  i;
   1732 
   1733 	/*
   1734 	 * Collect pointers to macro argument strings
   1735 	 * and NUL-terminate them.
   1736 	 */
   1737 	cp = *bufp + pos;
   1738 	for (i = 0; i < 9; i++)
   1739 		arg[i] = '\0' == *cp ? "" :
   1740 		    mandoc_getarg(r->parse, &cp, ln, &pos);
   1741 
   1742 	/*
   1743 	 * Expand macro arguments.
   1744 	 */
   1745 	*szp = 0;
   1746 	n1 = cp = mandoc_strdup(r->current_string);
   1747 	while (NULL != (cp = strstr(cp, "\\$"))) {
   1748 		i = cp[2] - '1';
   1749 		if (0 > i || 8 < i) {
   1750 			/* Not an argument invocation. */
   1751 			cp += 2;
   1752 			continue;
   1753 		}
   1754 
   1755 		*szp = strlen(n1) - 3 + strlen(arg[i]) + 1;
   1756 		n2 = mandoc_malloc(*szp);
   1757 
   1758 		strlcpy(n2, n1, (size_t)(cp - n1 + 1));
   1759 		strlcat(n2, arg[i], *szp);
   1760 		strlcat(n2, cp + 3, *szp);
   1761 
   1762 		cp = n2 + (cp - n1);
   1763 		free(n1);
   1764 		n1 = n2;
   1765 	}
   1766 
   1767 	/*
   1768 	 * Replace the macro invocation
   1769 	 * by the expanded macro.
   1770 	 */
   1771 	free(*bufp);
   1772 	*bufp = n1;
   1773 	if (0 == *szp)
   1774 		*szp = strlen(*bufp) + 1;
   1775 
   1776 	return(*szp > 1 && '\n' == (*bufp)[(int)*szp - 2] ?
   1777 	   ROFF_REPARSE : ROFF_APPEND);
   1778 }
   1779 
   1780 static char *
   1781 roff_getname(struct roff *r, char **cpp, int ln, int pos)
   1782 {
   1783 	char	 *name, *cp;
   1784 
   1785 	name = *cpp;
   1786 	if ('\0' == *name)
   1787 		return(name);
   1788 
   1789 	/* Read until end of name. */
   1790 	for (cp = name; '\0' != *cp && ' ' != *cp; cp++) {
   1791 		if ('\\' != *cp)
   1792 			continue;
   1793 		cp++;
   1794 		if ('\\' == *cp)
   1795 			continue;
   1796 		mandoc_msg(MANDOCERR_NAMESC, r->parse, ln, pos, NULL);
   1797 		*cp = '\0';
   1798 		name = cp;
   1799 	}
   1800 
   1801 	/* Nil-terminate name. */
   1802 	if ('\0' != *cp)
   1803 		*(cp++) = '\0';
   1804 
   1805 	/* Read past spaces. */
   1806 	while (' ' == *cp)
   1807 		cp++;
   1808 
   1809 	*cpp = cp;
   1810 	return(name);
   1811 }
   1812 
   1813 /*
   1814  * Store *string into the user-defined string called *name.
   1815  * In multiline mode, append to an existing entry and append '\n';
   1816  * else replace the existing entry, if there is one.
   1817  * To clear an existing entry, call with (*r, *name, NULL, 0).
   1818  */
   1819 static void
   1820 roff_setstr(struct roff *r, const char *name, const char *string,
   1821 	int multiline)
   1822 {
   1823 
   1824 	roff_setstrn(&r->strtab, name, strlen(name), string,
   1825 			string ? strlen(string) : 0, multiline);
   1826 }
   1827 
   1828 static void
   1829 roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
   1830 		const char *string, size_t stringsz, int multiline)
   1831 {
   1832 	struct roffkv	*n;
   1833 	char		*c;
   1834 	int		 i;
   1835 	size_t		 oldch, newch;
   1836 
   1837 	/* Search for an existing string with the same name. */
   1838 	n = *r;
   1839 
   1840 	while (n && strcmp(name, n->key.p))
   1841 		n = n->next;
   1842 
   1843 	if (NULL == n) {
   1844 		/* Create a new string table entry. */
   1845 		n = mandoc_malloc(sizeof(struct roffkv));
   1846 		n->key.p = mandoc_strndup(name, namesz);
   1847 		n->key.sz = namesz;
   1848 		n->val.p = NULL;
   1849 		n->val.sz = 0;
   1850 		n->next = *r;
   1851 		*r = n;
   1852 	} else if (0 == multiline) {
   1853 		/* In multiline mode, append; else replace. */
   1854 		free(n->val.p);
   1855 		n->val.p = NULL;
   1856 		n->val.sz = 0;
   1857 	}
   1858 
   1859 	if (NULL == string)
   1860 		return;
   1861 
   1862 	/*
   1863 	 * One additional byte for the '\n' in multiline mode,
   1864 	 * and one for the terminating '\0'.
   1865 	 */
   1866 	newch = stringsz + (multiline ? 2u : 1u);
   1867 
   1868 	if (NULL == n->val.p) {
   1869 		n->val.p = mandoc_malloc(newch);
   1870 		*n->val.p = '\0';
   1871 		oldch = 0;
   1872 	} else {
   1873 		oldch = n->val.sz;
   1874 		n->val.p = mandoc_realloc(n->val.p, oldch + newch);
   1875 	}
   1876 
   1877 	/* Skip existing content in the destination buffer. */
   1878 	c = n->val.p + (int)oldch;
   1879 
   1880 	/* Append new content to the destination buffer. */
   1881 	i = 0;
   1882 	while (i < (int)stringsz) {
   1883 		/*
   1884 		 * Rudimentary roff copy mode:
   1885 		 * Handle escaped backslashes.
   1886 		 */
   1887 		if ('\\' == string[i] && '\\' == string[i + 1])
   1888 			i++;
   1889 		*c++ = string[i++];
   1890 	}
   1891 
   1892 	/* Append terminating bytes. */
   1893 	if (multiline)
   1894 		*c++ = '\n';
   1895 
   1896 	*c = '\0';
   1897 	n->val.sz = (int)(c - n->val.p);
   1898 }
   1899 
   1900 static const char *
   1901 roff_getstrn(const struct roff *r, const char *name, size_t len)
   1902 {
   1903 	const struct roffkv *n;
   1904 
   1905 	for (n = r->strtab; n; n = n->next)
   1906 		if (0 == strncmp(name, n->key.p, len) &&
   1907 				'\0' == n->key.p[(int)len])
   1908 			return(n->val.p);
   1909 
   1910 	return(NULL);
   1911 }
   1912 
   1913 static void
   1914 roff_freestr(struct roffkv *r)
   1915 {
   1916 	struct roffkv	 *n, *nn;
   1917 
   1918 	for (n = r; n; n = nn) {
   1919 		free(n->key.p);
   1920 		free(n->val.p);
   1921 		nn = n->next;
   1922 		free(n);
   1923 	}
   1924 }
   1925 
   1926 const struct tbl_span *
   1927 roff_span(const struct roff *r)
   1928 {
   1929 
   1930 	return(r->tbl ? tbl_span(r->tbl) : NULL);
   1931 }
   1932 
   1933 const struct eqn *
   1934 roff_eqn(const struct roff *r)
   1935 {
   1936 
   1937 	return(r->last_eqn ? &r->last_eqn->eqn : NULL);
   1938 }
   1939 
   1940 /*
   1941  * Duplicate an input string, making the appropriate character
   1942  * conversations (as stipulated by `tr') along the way.
   1943  * Returns a heap-allocated string with all the replacements made.
   1944  */
   1945 char *
   1946 roff_strdup(const struct roff *r, const char *p)
   1947 {
   1948 	const struct roffkv *cp;
   1949 	char		*res;
   1950 	const char	*pp;
   1951 	size_t		 ssz, sz;
   1952 	enum mandoc_esc	 esc;
   1953 
   1954 	if (NULL == r->xmbtab && NULL == r->xtab)
   1955 		return(mandoc_strdup(p));
   1956 	else if ('\0' == *p)
   1957 		return(mandoc_strdup(""));
   1958 
   1959 	/*
   1960 	 * Step through each character looking for term matches
   1961 	 * (remember that a `tr' can be invoked with an escape, which is
   1962 	 * a glyph but the escape is multi-character).
   1963 	 * We only do this if the character hash has been initialised
   1964 	 * and the string is >0 length.
   1965 	 */
   1966 
   1967 	res = NULL;
   1968 	ssz = 0;
   1969 
   1970 	while ('\0' != *p) {
   1971 		if ('\\' != *p && r->xtab && r->xtab[(int)*p].p) {
   1972 			sz = r->xtab[(int)*p].sz;
   1973 			res = mandoc_realloc(res, ssz + sz + 1);
   1974 			memcpy(res + ssz, r->xtab[(int)*p].p, sz);
   1975 			ssz += sz;
   1976 			p++;
   1977 			continue;
   1978 		} else if ('\\' != *p) {
   1979 			res = mandoc_realloc(res, ssz + 2);
   1980 			res[ssz++] = *p++;
   1981 			continue;
   1982 		}
   1983 
   1984 		/* Search for term matches. */
   1985 		for (cp = r->xmbtab; cp; cp = cp->next)
   1986 			if (0 == strncmp(p, cp->key.p, cp->key.sz))
   1987 				break;
   1988 
   1989 		if (NULL != cp) {
   1990 			/*
   1991 			 * A match has been found.
   1992 			 * Append the match to the array and move
   1993 			 * forward by its keysize.
   1994 			 */
   1995 			res = mandoc_realloc
   1996 				(res, ssz + cp->val.sz + 1);
   1997 			memcpy(res + ssz, cp->val.p, cp->val.sz);
   1998 			ssz += cp->val.sz;
   1999 			p += (int)cp->key.sz;
   2000 			continue;
   2001 		}
   2002 
   2003 		/*
   2004 		 * Handle escapes carefully: we need to copy
   2005 		 * over just the escape itself, or else we might
   2006 		 * do replacements within the escape itself.
   2007 		 * Make sure to pass along the bogus string.
   2008 		 */
   2009 		pp = p++;
   2010 		esc = mandoc_escape(&p, NULL, NULL);
   2011 		if (ESCAPE_ERROR == esc) {
   2012 			sz = strlen(pp);
   2013 			res = mandoc_realloc(res, ssz + sz + 1);
   2014 			memcpy(res + ssz, pp, sz);
   2015 			break;
   2016 		}
   2017 		/*
   2018 		 * We bail out on bad escapes.
   2019 		 * No need to warn: we already did so when
   2020 		 * roff_res() was called.
   2021 		 */
   2022 		sz = (int)(p - pp);
   2023 		res = mandoc_realloc(res, ssz + sz + 1);
   2024 		memcpy(res + ssz, pp, sz);
   2025 		ssz += sz;
   2026 	}
   2027 
   2028 	res[(int)ssz] = '\0';
   2029 	return(res);
   2030 }
   2031 
   2032 /*
   2033  * Find out whether a line is a macro line or not.
   2034  * If it is, adjust the current position and return one; if it isn't,
   2035  * return zero and don't change the current position.
   2036  * If the control character has been set with `.cc', then let that grain
   2037  * precedence.
   2038  * This is slighly contrary to groff, where using the non-breaking
   2039  * control character when `cc' has been invoked will cause the
   2040  * non-breaking macro contents to be printed verbatim.
   2041  */
   2042 int
   2043 roff_getcontrol(const struct roff *r, const char *cp, int *ppos)
   2044 {
   2045 	int		pos;
   2046 
   2047 	pos = *ppos;
   2048 
   2049 	if (0 != r->control && cp[pos] == r->control)
   2050 		pos++;
   2051 	else if (0 != r->control)
   2052 		return(0);
   2053 	else if ('\\' == cp[pos] && '.' == cp[pos + 1])
   2054 		pos += 2;
   2055 	else if ('.' == cp[pos] || '\'' == cp[pos])
   2056 		pos++;
   2057 	else
   2058 		return(0);
   2059 
   2060 	while (' ' == cp[pos] || '\t' == cp[pos])
   2061 		pos++;
   2062 
   2063 	*ppos = pos;
   2064 	return(1);
   2065 }
   2066