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