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