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