xref: /titanic_50/usr/src/cmd/mandoc/man.c (revision 95c635efb7c3b86efc493e0447eaec7aecca3f0f)
1*95c635efSGarrett D'Amore /*	$Id: man.c,v 1.115 2012/01/03 15:16:24 kristaps Exp $ */
2*95c635efSGarrett D'Amore /*
3*95c635efSGarrett D'Amore  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*95c635efSGarrett D'Amore  *
5*95c635efSGarrett D'Amore  * Permission to use, copy, modify, and distribute this software for any
6*95c635efSGarrett D'Amore  * purpose with or without fee is hereby granted, provided that the above
7*95c635efSGarrett D'Amore  * copyright notice and this permission notice appear in all copies.
8*95c635efSGarrett D'Amore  *
9*95c635efSGarrett D'Amore  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10*95c635efSGarrett D'Amore  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*95c635efSGarrett D'Amore  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12*95c635efSGarrett D'Amore  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*95c635efSGarrett D'Amore  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*95c635efSGarrett D'Amore  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15*95c635efSGarrett D'Amore  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*95c635efSGarrett D'Amore  */
17*95c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H
18*95c635efSGarrett D'Amore #include "config.h"
19*95c635efSGarrett D'Amore #endif
20*95c635efSGarrett D'Amore 
21*95c635efSGarrett D'Amore #include <sys/types.h>
22*95c635efSGarrett D'Amore 
23*95c635efSGarrett D'Amore #include <assert.h>
24*95c635efSGarrett D'Amore #include <stdarg.h>
25*95c635efSGarrett D'Amore #include <stdlib.h>
26*95c635efSGarrett D'Amore #include <stdio.h>
27*95c635efSGarrett D'Amore #include <string.h>
28*95c635efSGarrett D'Amore 
29*95c635efSGarrett D'Amore #include "man.h"
30*95c635efSGarrett D'Amore #include "mandoc.h"
31*95c635efSGarrett D'Amore #include "libman.h"
32*95c635efSGarrett D'Amore #include "libmandoc.h"
33*95c635efSGarrett D'Amore 
34*95c635efSGarrett D'Amore const	char *const __man_macronames[MAN_MAX] = {
35*95c635efSGarrett D'Amore 	"br",		"TH",		"SH",		"SS",
36*95c635efSGarrett D'Amore 	"TP", 		"LP",		"PP",		"P",
37*95c635efSGarrett D'Amore 	"IP",		"HP",		"SM",		"SB",
38*95c635efSGarrett D'Amore 	"BI",		"IB",		"BR",		"RB",
39*95c635efSGarrett D'Amore 	"R",		"B",		"I",		"IR",
40*95c635efSGarrett D'Amore 	"RI",		"na",		"sp",		"nf",
41*95c635efSGarrett D'Amore 	"fi",		"RE",		"RS",		"DT",
42*95c635efSGarrett D'Amore 	"UC",		"PD",		"AT",		"in",
43*95c635efSGarrett D'Amore 	"ft",		"OP"
44*95c635efSGarrett D'Amore 	};
45*95c635efSGarrett D'Amore 
46*95c635efSGarrett D'Amore const	char * const *man_macronames = __man_macronames;
47*95c635efSGarrett D'Amore 
48*95c635efSGarrett D'Amore static	struct man_node	*man_node_alloc(struct man *, int, int,
49*95c635efSGarrett D'Amore 				enum man_type, enum mant);
50*95c635efSGarrett D'Amore static	int		 man_node_append(struct man *,
51*95c635efSGarrett D'Amore 				struct man_node *);
52*95c635efSGarrett D'Amore static	void		 man_node_free(struct man_node *);
53*95c635efSGarrett D'Amore static	void		 man_node_unlink(struct man *,
54*95c635efSGarrett D'Amore 				struct man_node *);
55*95c635efSGarrett D'Amore static	int		 man_ptext(struct man *, int, char *, int);
56*95c635efSGarrett D'Amore static	int		 man_pmacro(struct man *, int, char *, int);
57*95c635efSGarrett D'Amore static	void		 man_free1(struct man *);
58*95c635efSGarrett D'Amore static	void		 man_alloc1(struct man *);
59*95c635efSGarrett D'Amore static	int		 man_descope(struct man *, int, int);
60*95c635efSGarrett D'Amore 
61*95c635efSGarrett D'Amore 
62*95c635efSGarrett D'Amore const struct man_node *
63*95c635efSGarrett D'Amore man_node(const struct man *m)
64*95c635efSGarrett D'Amore {
65*95c635efSGarrett D'Amore 
66*95c635efSGarrett D'Amore 	assert( ! (MAN_HALT & m->flags));
67*95c635efSGarrett D'Amore 	return(m->first);
68*95c635efSGarrett D'Amore }
69*95c635efSGarrett D'Amore 
70*95c635efSGarrett D'Amore 
71*95c635efSGarrett D'Amore const struct man_meta *
72*95c635efSGarrett D'Amore man_meta(const struct man *m)
73*95c635efSGarrett D'Amore {
74*95c635efSGarrett D'Amore 
75*95c635efSGarrett D'Amore 	assert( ! (MAN_HALT & m->flags));
76*95c635efSGarrett D'Amore 	return(&m->meta);
77*95c635efSGarrett D'Amore }
78*95c635efSGarrett D'Amore 
79*95c635efSGarrett D'Amore 
80*95c635efSGarrett D'Amore void
81*95c635efSGarrett D'Amore man_reset(struct man *man)
82*95c635efSGarrett D'Amore {
83*95c635efSGarrett D'Amore 
84*95c635efSGarrett D'Amore 	man_free1(man);
85*95c635efSGarrett D'Amore 	man_alloc1(man);
86*95c635efSGarrett D'Amore }
87*95c635efSGarrett D'Amore 
88*95c635efSGarrett D'Amore 
89*95c635efSGarrett D'Amore void
90*95c635efSGarrett D'Amore man_free(struct man *man)
91*95c635efSGarrett D'Amore {
92*95c635efSGarrett D'Amore 
93*95c635efSGarrett D'Amore 	man_free1(man);
94*95c635efSGarrett D'Amore 	free(man);
95*95c635efSGarrett D'Amore }
96*95c635efSGarrett D'Amore 
97*95c635efSGarrett D'Amore 
98*95c635efSGarrett D'Amore struct man *
99*95c635efSGarrett D'Amore man_alloc(struct roff *roff, struct mparse *parse)
100*95c635efSGarrett D'Amore {
101*95c635efSGarrett D'Amore 	struct man	*p;
102*95c635efSGarrett D'Amore 
103*95c635efSGarrett D'Amore 	p = mandoc_calloc(1, sizeof(struct man));
104*95c635efSGarrett D'Amore 
105*95c635efSGarrett D'Amore 	man_hash_init();
106*95c635efSGarrett D'Amore 	p->parse = parse;
107*95c635efSGarrett D'Amore 	p->roff = roff;
108*95c635efSGarrett D'Amore 
109*95c635efSGarrett D'Amore 	man_alloc1(p);
110*95c635efSGarrett D'Amore 	return(p);
111*95c635efSGarrett D'Amore }
112*95c635efSGarrett D'Amore 
113*95c635efSGarrett D'Amore 
114*95c635efSGarrett D'Amore int
115*95c635efSGarrett D'Amore man_endparse(struct man *m)
116*95c635efSGarrett D'Amore {
117*95c635efSGarrett D'Amore 
118*95c635efSGarrett D'Amore 	assert( ! (MAN_HALT & m->flags));
119*95c635efSGarrett D'Amore 	if (man_macroend(m))
120*95c635efSGarrett D'Amore 		return(1);
121*95c635efSGarrett D'Amore 	m->flags |= MAN_HALT;
122*95c635efSGarrett D'Amore 	return(0);
123*95c635efSGarrett D'Amore }
124*95c635efSGarrett D'Amore 
125*95c635efSGarrett D'Amore 
126*95c635efSGarrett D'Amore int
127*95c635efSGarrett D'Amore man_parseln(struct man *m, int ln, char *buf, int offs)
128*95c635efSGarrett D'Amore {
129*95c635efSGarrett D'Amore 
130*95c635efSGarrett D'Amore 	m->flags |= MAN_NEWLINE;
131*95c635efSGarrett D'Amore 
132*95c635efSGarrett D'Amore 	assert( ! (MAN_HALT & m->flags));
133*95c635efSGarrett D'Amore 
134*95c635efSGarrett D'Amore 	return (mandoc_getcontrol(buf, &offs) ?
135*95c635efSGarrett D'Amore 			man_pmacro(m, ln, buf, offs) :
136*95c635efSGarrett D'Amore 			man_ptext(m, ln, buf, offs));
137*95c635efSGarrett D'Amore }
138*95c635efSGarrett D'Amore 
139*95c635efSGarrett D'Amore 
140*95c635efSGarrett D'Amore static void
141*95c635efSGarrett D'Amore man_free1(struct man *man)
142*95c635efSGarrett D'Amore {
143*95c635efSGarrett D'Amore 
144*95c635efSGarrett D'Amore 	if (man->first)
145*95c635efSGarrett D'Amore 		man_node_delete(man, man->first);
146*95c635efSGarrett D'Amore 	if (man->meta.title)
147*95c635efSGarrett D'Amore 		free(man->meta.title);
148*95c635efSGarrett D'Amore 	if (man->meta.source)
149*95c635efSGarrett D'Amore 		free(man->meta.source);
150*95c635efSGarrett D'Amore 	if (man->meta.date)
151*95c635efSGarrett D'Amore 		free(man->meta.date);
152*95c635efSGarrett D'Amore 	if (man->meta.vol)
153*95c635efSGarrett D'Amore 		free(man->meta.vol);
154*95c635efSGarrett D'Amore 	if (man->meta.msec)
155*95c635efSGarrett D'Amore 		free(man->meta.msec);
156*95c635efSGarrett D'Amore }
157*95c635efSGarrett D'Amore 
158*95c635efSGarrett D'Amore 
159*95c635efSGarrett D'Amore static void
160*95c635efSGarrett D'Amore man_alloc1(struct man *m)
161*95c635efSGarrett D'Amore {
162*95c635efSGarrett D'Amore 
163*95c635efSGarrett D'Amore 	memset(&m->meta, 0, sizeof(struct man_meta));
164*95c635efSGarrett D'Amore 	m->flags = 0;
165*95c635efSGarrett D'Amore 	m->last = mandoc_calloc(1, sizeof(struct man_node));
166*95c635efSGarrett D'Amore 	m->first = m->last;
167*95c635efSGarrett D'Amore 	m->last->type = MAN_ROOT;
168*95c635efSGarrett D'Amore 	m->last->tok = MAN_MAX;
169*95c635efSGarrett D'Amore 	m->next = MAN_NEXT_CHILD;
170*95c635efSGarrett D'Amore }
171*95c635efSGarrett D'Amore 
172*95c635efSGarrett D'Amore 
173*95c635efSGarrett D'Amore static int
174*95c635efSGarrett D'Amore man_node_append(struct man *man, struct man_node *p)
175*95c635efSGarrett D'Amore {
176*95c635efSGarrett D'Amore 
177*95c635efSGarrett D'Amore 	assert(man->last);
178*95c635efSGarrett D'Amore 	assert(man->first);
179*95c635efSGarrett D'Amore 	assert(MAN_ROOT != p->type);
180*95c635efSGarrett D'Amore 
181*95c635efSGarrett D'Amore 	switch (man->next) {
182*95c635efSGarrett D'Amore 	case (MAN_NEXT_SIBLING):
183*95c635efSGarrett D'Amore 		man->last->next = p;
184*95c635efSGarrett D'Amore 		p->prev = man->last;
185*95c635efSGarrett D'Amore 		p->parent = man->last->parent;
186*95c635efSGarrett D'Amore 		break;
187*95c635efSGarrett D'Amore 	case (MAN_NEXT_CHILD):
188*95c635efSGarrett D'Amore 		man->last->child = p;
189*95c635efSGarrett D'Amore 		p->parent = man->last;
190*95c635efSGarrett D'Amore 		break;
191*95c635efSGarrett D'Amore 	default:
192*95c635efSGarrett D'Amore 		abort();
193*95c635efSGarrett D'Amore 		/* NOTREACHED */
194*95c635efSGarrett D'Amore 	}
195*95c635efSGarrett D'Amore 
196*95c635efSGarrett D'Amore 	assert(p->parent);
197*95c635efSGarrett D'Amore 	p->parent->nchild++;
198*95c635efSGarrett D'Amore 
199*95c635efSGarrett D'Amore 	if ( ! man_valid_pre(man, p))
200*95c635efSGarrett D'Amore 		return(0);
201*95c635efSGarrett D'Amore 
202*95c635efSGarrett D'Amore 	switch (p->type) {
203*95c635efSGarrett D'Amore 	case (MAN_HEAD):
204*95c635efSGarrett D'Amore 		assert(MAN_BLOCK == p->parent->type);
205*95c635efSGarrett D'Amore 		p->parent->head = p;
206*95c635efSGarrett D'Amore 		break;
207*95c635efSGarrett D'Amore 	case (MAN_TAIL):
208*95c635efSGarrett D'Amore 		assert(MAN_BLOCK == p->parent->type);
209*95c635efSGarrett D'Amore 		p->parent->tail = p;
210*95c635efSGarrett D'Amore 		break;
211*95c635efSGarrett D'Amore 	case (MAN_BODY):
212*95c635efSGarrett D'Amore 		assert(MAN_BLOCK == p->parent->type);
213*95c635efSGarrett D'Amore 		p->parent->body = p;
214*95c635efSGarrett D'Amore 		break;
215*95c635efSGarrett D'Amore 	default:
216*95c635efSGarrett D'Amore 		break;
217*95c635efSGarrett D'Amore 	}
218*95c635efSGarrett D'Amore 
219*95c635efSGarrett D'Amore 	man->last = p;
220*95c635efSGarrett D'Amore 
221*95c635efSGarrett D'Amore 	switch (p->type) {
222*95c635efSGarrett D'Amore 	case (MAN_TBL):
223*95c635efSGarrett D'Amore 		/* FALLTHROUGH */
224*95c635efSGarrett D'Amore 	case (MAN_TEXT):
225*95c635efSGarrett D'Amore 		if ( ! man_valid_post(man))
226*95c635efSGarrett D'Amore 			return(0);
227*95c635efSGarrett D'Amore 		break;
228*95c635efSGarrett D'Amore 	default:
229*95c635efSGarrett D'Amore 		break;
230*95c635efSGarrett D'Amore 	}
231*95c635efSGarrett D'Amore 
232*95c635efSGarrett D'Amore 	return(1);
233*95c635efSGarrett D'Amore }
234*95c635efSGarrett D'Amore 
235*95c635efSGarrett D'Amore 
236*95c635efSGarrett D'Amore static struct man_node *
237*95c635efSGarrett D'Amore man_node_alloc(struct man *m, int line, int pos,
238*95c635efSGarrett D'Amore 		enum man_type type, enum mant tok)
239*95c635efSGarrett D'Amore {
240*95c635efSGarrett D'Amore 	struct man_node *p;
241*95c635efSGarrett D'Amore 
242*95c635efSGarrett D'Amore 	p = mandoc_calloc(1, sizeof(struct man_node));
243*95c635efSGarrett D'Amore 	p->line = line;
244*95c635efSGarrett D'Amore 	p->pos = pos;
245*95c635efSGarrett D'Amore 	p->type = type;
246*95c635efSGarrett D'Amore 	p->tok = tok;
247*95c635efSGarrett D'Amore 
248*95c635efSGarrett D'Amore 	if (MAN_NEWLINE & m->flags)
249*95c635efSGarrett D'Amore 		p->flags |= MAN_LINE;
250*95c635efSGarrett D'Amore 	m->flags &= ~MAN_NEWLINE;
251*95c635efSGarrett D'Amore 	return(p);
252*95c635efSGarrett D'Amore }
253*95c635efSGarrett D'Amore 
254*95c635efSGarrett D'Amore 
255*95c635efSGarrett D'Amore int
256*95c635efSGarrett D'Amore man_elem_alloc(struct man *m, int line, int pos, enum mant tok)
257*95c635efSGarrett D'Amore {
258*95c635efSGarrett D'Amore 	struct man_node *p;
259*95c635efSGarrett D'Amore 
260*95c635efSGarrett D'Amore 	p = man_node_alloc(m, line, pos, MAN_ELEM, tok);
261*95c635efSGarrett D'Amore 	if ( ! man_node_append(m, p))
262*95c635efSGarrett D'Amore 		return(0);
263*95c635efSGarrett D'Amore 	m->next = MAN_NEXT_CHILD;
264*95c635efSGarrett D'Amore 	return(1);
265*95c635efSGarrett D'Amore }
266*95c635efSGarrett D'Amore 
267*95c635efSGarrett D'Amore 
268*95c635efSGarrett D'Amore int
269*95c635efSGarrett D'Amore man_tail_alloc(struct man *m, int line, int pos, enum mant tok)
270*95c635efSGarrett D'Amore {
271*95c635efSGarrett D'Amore 	struct man_node *p;
272*95c635efSGarrett D'Amore 
273*95c635efSGarrett D'Amore 	p = man_node_alloc(m, line, pos, MAN_TAIL, tok);
274*95c635efSGarrett D'Amore 	if ( ! man_node_append(m, p))
275*95c635efSGarrett D'Amore 		return(0);
276*95c635efSGarrett D'Amore 	m->next = MAN_NEXT_CHILD;
277*95c635efSGarrett D'Amore 	return(1);
278*95c635efSGarrett D'Amore }
279*95c635efSGarrett D'Amore 
280*95c635efSGarrett D'Amore 
281*95c635efSGarrett D'Amore int
282*95c635efSGarrett D'Amore man_head_alloc(struct man *m, int line, int pos, enum mant tok)
283*95c635efSGarrett D'Amore {
284*95c635efSGarrett D'Amore 	struct man_node *p;
285*95c635efSGarrett D'Amore 
286*95c635efSGarrett D'Amore 	p = man_node_alloc(m, line, pos, MAN_HEAD, tok);
287*95c635efSGarrett D'Amore 	if ( ! man_node_append(m, p))
288*95c635efSGarrett D'Amore 		return(0);
289*95c635efSGarrett D'Amore 	m->next = MAN_NEXT_CHILD;
290*95c635efSGarrett D'Amore 	return(1);
291*95c635efSGarrett D'Amore }
292*95c635efSGarrett D'Amore 
293*95c635efSGarrett D'Amore 
294*95c635efSGarrett D'Amore int
295*95c635efSGarrett D'Amore man_body_alloc(struct man *m, int line, int pos, enum mant tok)
296*95c635efSGarrett D'Amore {
297*95c635efSGarrett D'Amore 	struct man_node *p;
298*95c635efSGarrett D'Amore 
299*95c635efSGarrett D'Amore 	p = man_node_alloc(m, line, pos, MAN_BODY, tok);
300*95c635efSGarrett D'Amore 	if ( ! man_node_append(m, p))
301*95c635efSGarrett D'Amore 		return(0);
302*95c635efSGarrett D'Amore 	m->next = MAN_NEXT_CHILD;
303*95c635efSGarrett D'Amore 	return(1);
304*95c635efSGarrett D'Amore }
305*95c635efSGarrett D'Amore 
306*95c635efSGarrett D'Amore 
307*95c635efSGarrett D'Amore int
308*95c635efSGarrett D'Amore man_block_alloc(struct man *m, int line, int pos, enum mant tok)
309*95c635efSGarrett D'Amore {
310*95c635efSGarrett D'Amore 	struct man_node *p;
311*95c635efSGarrett D'Amore 
312*95c635efSGarrett D'Amore 	p = man_node_alloc(m, line, pos, MAN_BLOCK, tok);
313*95c635efSGarrett D'Amore 	if ( ! man_node_append(m, p))
314*95c635efSGarrett D'Amore 		return(0);
315*95c635efSGarrett D'Amore 	m->next = MAN_NEXT_CHILD;
316*95c635efSGarrett D'Amore 	return(1);
317*95c635efSGarrett D'Amore }
318*95c635efSGarrett D'Amore 
319*95c635efSGarrett D'Amore int
320*95c635efSGarrett D'Amore man_word_alloc(struct man *m, int line, int pos, const char *word)
321*95c635efSGarrett D'Amore {
322*95c635efSGarrett D'Amore 	struct man_node	*n;
323*95c635efSGarrett D'Amore 
324*95c635efSGarrett D'Amore 	n = man_node_alloc(m, line, pos, MAN_TEXT, MAN_MAX);
325*95c635efSGarrett D'Amore 	n->string = roff_strdup(m->roff, word);
326*95c635efSGarrett D'Amore 
327*95c635efSGarrett D'Amore 	if ( ! man_node_append(m, n))
328*95c635efSGarrett D'Amore 		return(0);
329*95c635efSGarrett D'Amore 
330*95c635efSGarrett D'Amore 	m->next = MAN_NEXT_SIBLING;
331*95c635efSGarrett D'Amore 	return(1);
332*95c635efSGarrett D'Amore }
333*95c635efSGarrett D'Amore 
334*95c635efSGarrett D'Amore 
335*95c635efSGarrett D'Amore /*
336*95c635efSGarrett D'Amore  * Free all of the resources held by a node.  This does NOT unlink a
337*95c635efSGarrett D'Amore  * node from its context; for that, see man_node_unlink().
338*95c635efSGarrett D'Amore  */
339*95c635efSGarrett D'Amore static void
340*95c635efSGarrett D'Amore man_node_free(struct man_node *p)
341*95c635efSGarrett D'Amore {
342*95c635efSGarrett D'Amore 
343*95c635efSGarrett D'Amore 	if (p->string)
344*95c635efSGarrett D'Amore 		free(p->string);
345*95c635efSGarrett D'Amore 	free(p);
346*95c635efSGarrett D'Amore }
347*95c635efSGarrett D'Amore 
348*95c635efSGarrett D'Amore 
349*95c635efSGarrett D'Amore void
350*95c635efSGarrett D'Amore man_node_delete(struct man *m, struct man_node *p)
351*95c635efSGarrett D'Amore {
352*95c635efSGarrett D'Amore 
353*95c635efSGarrett D'Amore 	while (p->child)
354*95c635efSGarrett D'Amore 		man_node_delete(m, p->child);
355*95c635efSGarrett D'Amore 
356*95c635efSGarrett D'Amore 	man_node_unlink(m, p);
357*95c635efSGarrett D'Amore 	man_node_free(p);
358*95c635efSGarrett D'Amore }
359*95c635efSGarrett D'Amore 
360*95c635efSGarrett D'Amore int
361*95c635efSGarrett D'Amore man_addeqn(struct man *m, const struct eqn *ep)
362*95c635efSGarrett D'Amore {
363*95c635efSGarrett D'Amore 	struct man_node	*n;
364*95c635efSGarrett D'Amore 
365*95c635efSGarrett D'Amore 	assert( ! (MAN_HALT & m->flags));
366*95c635efSGarrett D'Amore 
367*95c635efSGarrett D'Amore 	n = man_node_alloc(m, ep->ln, ep->pos, MAN_EQN, MAN_MAX);
368*95c635efSGarrett D'Amore 	n->eqn = ep;
369*95c635efSGarrett D'Amore 
370*95c635efSGarrett D'Amore 	if ( ! man_node_append(m, n))
371*95c635efSGarrett D'Amore 		return(0);
372*95c635efSGarrett D'Amore 
373*95c635efSGarrett D'Amore 	m->next = MAN_NEXT_SIBLING;
374*95c635efSGarrett D'Amore 	return(man_descope(m, ep->ln, ep->pos));
375*95c635efSGarrett D'Amore }
376*95c635efSGarrett D'Amore 
377*95c635efSGarrett D'Amore int
378*95c635efSGarrett D'Amore man_addspan(struct man *m, const struct tbl_span *sp)
379*95c635efSGarrett D'Amore {
380*95c635efSGarrett D'Amore 	struct man_node	*n;
381*95c635efSGarrett D'Amore 
382*95c635efSGarrett D'Amore 	assert( ! (MAN_HALT & m->flags));
383*95c635efSGarrett D'Amore 
384*95c635efSGarrett D'Amore 	n = man_node_alloc(m, sp->line, 0, MAN_TBL, MAN_MAX);
385*95c635efSGarrett D'Amore 	n->span = sp;
386*95c635efSGarrett D'Amore 
387*95c635efSGarrett D'Amore 	if ( ! man_node_append(m, n))
388*95c635efSGarrett D'Amore 		return(0);
389*95c635efSGarrett D'Amore 
390*95c635efSGarrett D'Amore 	m->next = MAN_NEXT_SIBLING;
391*95c635efSGarrett D'Amore 	return(man_descope(m, sp->line, 0));
392*95c635efSGarrett D'Amore }
393*95c635efSGarrett D'Amore 
394*95c635efSGarrett D'Amore static int
395*95c635efSGarrett D'Amore man_descope(struct man *m, int line, int offs)
396*95c635efSGarrett D'Amore {
397*95c635efSGarrett D'Amore 	/*
398*95c635efSGarrett D'Amore 	 * Co-ordinate what happens with having a next-line scope open:
399*95c635efSGarrett D'Amore 	 * first close out the element scope (if applicable), then close
400*95c635efSGarrett D'Amore 	 * out the block scope (also if applicable).
401*95c635efSGarrett D'Amore 	 */
402*95c635efSGarrett D'Amore 
403*95c635efSGarrett D'Amore 	if (MAN_ELINE & m->flags) {
404*95c635efSGarrett D'Amore 		m->flags &= ~MAN_ELINE;
405*95c635efSGarrett D'Amore 		if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX))
406*95c635efSGarrett D'Amore 			return(0);
407*95c635efSGarrett D'Amore 	}
408*95c635efSGarrett D'Amore 
409*95c635efSGarrett D'Amore 	if ( ! (MAN_BLINE & m->flags))
410*95c635efSGarrett D'Amore 		return(1);
411*95c635efSGarrett D'Amore 	m->flags &= ~MAN_BLINE;
412*95c635efSGarrett D'Amore 
413*95c635efSGarrett D'Amore 	if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX))
414*95c635efSGarrett D'Amore 		return(0);
415*95c635efSGarrett D'Amore 	return(man_body_alloc(m, line, offs, m->last->tok));
416*95c635efSGarrett D'Amore }
417*95c635efSGarrett D'Amore 
418*95c635efSGarrett D'Amore static int
419*95c635efSGarrett D'Amore man_ptext(struct man *m, int line, char *buf, int offs)
420*95c635efSGarrett D'Amore {
421*95c635efSGarrett D'Amore 	int		 i;
422*95c635efSGarrett D'Amore 
423*95c635efSGarrett D'Amore 	/* Literal free-form text whitespace is preserved. */
424*95c635efSGarrett D'Amore 
425*95c635efSGarrett D'Amore 	if (MAN_LITERAL & m->flags) {
426*95c635efSGarrett D'Amore 		if ( ! man_word_alloc(m, line, offs, buf + offs))
427*95c635efSGarrett D'Amore 			return(0);
428*95c635efSGarrett D'Amore 		return(man_descope(m, line, offs));
429*95c635efSGarrett D'Amore 	}
430*95c635efSGarrett D'Amore 
431*95c635efSGarrett D'Amore 	/* Pump blank lines directly into the backend. */
432*95c635efSGarrett D'Amore 
433*95c635efSGarrett D'Amore 	for (i = offs; ' ' == buf[i]; i++)
434*95c635efSGarrett D'Amore 		/* Skip leading whitespace. */ ;
435*95c635efSGarrett D'Amore 
436*95c635efSGarrett D'Amore 	if ('\0' == buf[i]) {
437*95c635efSGarrett D'Amore 		/* Allocate a blank entry. */
438*95c635efSGarrett D'Amore 		if ( ! man_word_alloc(m, line, offs, ""))
439*95c635efSGarrett D'Amore 			return(0);
440*95c635efSGarrett D'Amore 		return(man_descope(m, line, offs));
441*95c635efSGarrett D'Amore 	}
442*95c635efSGarrett D'Amore 
443*95c635efSGarrett D'Amore 	/*
444*95c635efSGarrett D'Amore 	 * Warn if the last un-escaped character is whitespace. Then
445*95c635efSGarrett D'Amore 	 * strip away the remaining spaces (tabs stay!).
446*95c635efSGarrett D'Amore 	 */
447*95c635efSGarrett D'Amore 
448*95c635efSGarrett D'Amore 	i = (int)strlen(buf);
449*95c635efSGarrett D'Amore 	assert(i);
450*95c635efSGarrett D'Amore 
451*95c635efSGarrett D'Amore 	if (' ' == buf[i - 1] || '\t' == buf[i - 1]) {
452*95c635efSGarrett D'Amore 		if (i > 1 && '\\' != buf[i - 2])
453*95c635efSGarrett D'Amore 			man_pmsg(m, line, i - 1, MANDOCERR_EOLNSPACE);
454*95c635efSGarrett D'Amore 
455*95c635efSGarrett D'Amore 		for (--i; i && ' ' == buf[i]; i--)
456*95c635efSGarrett D'Amore 			/* Spin back to non-space. */ ;
457*95c635efSGarrett D'Amore 
458*95c635efSGarrett D'Amore 		/* Jump ahead of escaped whitespace. */
459*95c635efSGarrett D'Amore 		i += '\\' == buf[i] ? 2 : 1;
460*95c635efSGarrett D'Amore 
461*95c635efSGarrett D'Amore 		buf[i] = '\0';
462*95c635efSGarrett D'Amore 	}
463*95c635efSGarrett D'Amore 
464*95c635efSGarrett D'Amore 	if ( ! man_word_alloc(m, line, offs, buf + offs))
465*95c635efSGarrett D'Amore 		return(0);
466*95c635efSGarrett D'Amore 
467*95c635efSGarrett D'Amore 	/*
468*95c635efSGarrett D'Amore 	 * End-of-sentence check.  If the last character is an unescaped
469*95c635efSGarrett D'Amore 	 * EOS character, then flag the node as being the end of a
470*95c635efSGarrett D'Amore 	 * sentence.  The front-end will know how to interpret this.
471*95c635efSGarrett D'Amore 	 */
472*95c635efSGarrett D'Amore 
473*95c635efSGarrett D'Amore 	assert(i);
474*95c635efSGarrett D'Amore 	if (mandoc_eos(buf, (size_t)i, 0))
475*95c635efSGarrett D'Amore 		m->last->flags |= MAN_EOS;
476*95c635efSGarrett D'Amore 
477*95c635efSGarrett D'Amore 	return(man_descope(m, line, offs));
478*95c635efSGarrett D'Amore }
479*95c635efSGarrett D'Amore 
480*95c635efSGarrett D'Amore static int
481*95c635efSGarrett D'Amore man_pmacro(struct man *m, int ln, char *buf, int offs)
482*95c635efSGarrett D'Amore {
483*95c635efSGarrett D'Amore 	int		 i, ppos;
484*95c635efSGarrett D'Amore 	enum mant	 tok;
485*95c635efSGarrett D'Amore 	char		 mac[5];
486*95c635efSGarrett D'Amore 	struct man_node	*n;
487*95c635efSGarrett D'Amore 
488*95c635efSGarrett D'Amore 	if ('"' == buf[offs]) {
489*95c635efSGarrett D'Amore 		man_pmsg(m, ln, offs, MANDOCERR_BADCOMMENT);
490*95c635efSGarrett D'Amore 		return(1);
491*95c635efSGarrett D'Amore 	} else if ('\0' == buf[offs])
492*95c635efSGarrett D'Amore 		return(1);
493*95c635efSGarrett D'Amore 
494*95c635efSGarrett D'Amore 	ppos = offs;
495*95c635efSGarrett D'Amore 
496*95c635efSGarrett D'Amore 	/*
497*95c635efSGarrett D'Amore 	 * Copy the first word into a nil-terminated buffer.
498*95c635efSGarrett D'Amore 	 * Stop copying when a tab, space, or eoln is encountered.
499*95c635efSGarrett D'Amore 	 */
500*95c635efSGarrett D'Amore 
501*95c635efSGarrett D'Amore 	i = 0;
502*95c635efSGarrett D'Amore 	while (i < 4 && '\0' != buf[offs] &&
503*95c635efSGarrett D'Amore 			' ' != buf[offs] && '\t' != buf[offs])
504*95c635efSGarrett D'Amore 		mac[i++] = buf[offs++];
505*95c635efSGarrett D'Amore 
506*95c635efSGarrett D'Amore 	mac[i] = '\0';
507*95c635efSGarrett D'Amore 
508*95c635efSGarrett D'Amore 	tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX;
509*95c635efSGarrett D'Amore 
510*95c635efSGarrett D'Amore 	if (MAN_MAX == tok) {
511*95c635efSGarrett D'Amore 		mandoc_vmsg(MANDOCERR_MACRO, m->parse, ln,
512*95c635efSGarrett D'Amore 				ppos, "%s", buf + ppos - 1);
513*95c635efSGarrett D'Amore 		return(1);
514*95c635efSGarrett D'Amore 	}
515*95c635efSGarrett D'Amore 
516*95c635efSGarrett D'Amore 	/* The macro is sane.  Jump to the next word. */
517*95c635efSGarrett D'Amore 
518*95c635efSGarrett D'Amore 	while (buf[offs] && ' ' == buf[offs])
519*95c635efSGarrett D'Amore 		offs++;
520*95c635efSGarrett D'Amore 
521*95c635efSGarrett D'Amore 	/*
522*95c635efSGarrett D'Amore 	 * Trailing whitespace.  Note that tabs are allowed to be passed
523*95c635efSGarrett D'Amore 	 * into the parser as "text", so we only warn about spaces here.
524*95c635efSGarrett D'Amore 	 */
525*95c635efSGarrett D'Amore 
526*95c635efSGarrett D'Amore 	if ('\0' == buf[offs] && ' ' == buf[offs - 1])
527*95c635efSGarrett D'Amore 		man_pmsg(m, ln, offs - 1, MANDOCERR_EOLNSPACE);
528*95c635efSGarrett D'Amore 
529*95c635efSGarrett D'Amore 	/*
530*95c635efSGarrett D'Amore 	 * Remove prior ELINE macro, as it's being clobbered by a new
531*95c635efSGarrett D'Amore 	 * macro.  Note that NSCOPED macros do not close out ELINE
532*95c635efSGarrett D'Amore 	 * macros---they don't print text---so we let those slip by.
533*95c635efSGarrett D'Amore 	 */
534*95c635efSGarrett D'Amore 
535*95c635efSGarrett D'Amore 	if ( ! (MAN_NSCOPED & man_macros[tok].flags) &&
536*95c635efSGarrett D'Amore 			m->flags & MAN_ELINE) {
537*95c635efSGarrett D'Amore 		n = m->last;
538*95c635efSGarrett D'Amore 		assert(MAN_TEXT != n->type);
539*95c635efSGarrett D'Amore 
540*95c635efSGarrett D'Amore 		/* Remove repeated NSCOPED macros causing ELINE. */
541*95c635efSGarrett D'Amore 
542*95c635efSGarrett D'Amore 		if (MAN_NSCOPED & man_macros[n->tok].flags)
543*95c635efSGarrett D'Amore 			n = n->parent;
544*95c635efSGarrett D'Amore 
545*95c635efSGarrett D'Amore 		mandoc_vmsg(MANDOCERR_LINESCOPE, m->parse, n->line,
546*95c635efSGarrett D'Amore 		    n->pos, "%s breaks %s", man_macronames[tok],
547*95c635efSGarrett D'Amore 		    man_macronames[n->tok]);
548*95c635efSGarrett D'Amore 
549*95c635efSGarrett D'Amore 		man_node_delete(m, n);
550*95c635efSGarrett D'Amore 		m->flags &= ~MAN_ELINE;
551*95c635efSGarrett D'Amore 	}
552*95c635efSGarrett D'Amore 
553*95c635efSGarrett D'Amore 	/*
554*95c635efSGarrett D'Amore 	 * Remove prior BLINE macro that is being clobbered.
555*95c635efSGarrett D'Amore 	 */
556*95c635efSGarrett D'Amore 	if ((m->flags & MAN_BLINE) &&
557*95c635efSGarrett D'Amore 	    (MAN_BSCOPE & man_macros[tok].flags)) {
558*95c635efSGarrett D'Amore 		n = m->last;
559*95c635efSGarrett D'Amore 
560*95c635efSGarrett D'Amore 		/* Might be a text node like 8 in
561*95c635efSGarrett D'Amore 		 * .TP 8
562*95c635efSGarrett D'Amore 		 * .SH foo
563*95c635efSGarrett D'Amore 		 */
564*95c635efSGarrett D'Amore 		if (MAN_TEXT == n->type)
565*95c635efSGarrett D'Amore 			n = n->parent;
566*95c635efSGarrett D'Amore 
567*95c635efSGarrett D'Amore 		/* Remove element that didn't end BLINE, if any. */
568*95c635efSGarrett D'Amore 		if ( ! (MAN_BSCOPE & man_macros[n->tok].flags))
569*95c635efSGarrett D'Amore 			n = n->parent;
570*95c635efSGarrett D'Amore 
571*95c635efSGarrett D'Amore 		assert(MAN_HEAD == n->type);
572*95c635efSGarrett D'Amore 		n = n->parent;
573*95c635efSGarrett D'Amore 		assert(MAN_BLOCK == n->type);
574*95c635efSGarrett D'Amore 		assert(MAN_SCOPED & man_macros[n->tok].flags);
575*95c635efSGarrett D'Amore 
576*95c635efSGarrett D'Amore 		mandoc_vmsg(MANDOCERR_LINESCOPE, m->parse, n->line,
577*95c635efSGarrett D'Amore 		    n->pos, "%s breaks %s", man_macronames[tok],
578*95c635efSGarrett D'Amore 		    man_macronames[n->tok]);
579*95c635efSGarrett D'Amore 
580*95c635efSGarrett D'Amore 		man_node_delete(m, n);
581*95c635efSGarrett D'Amore 		m->flags &= ~MAN_BLINE;
582*95c635efSGarrett D'Amore 	}
583*95c635efSGarrett D'Amore 
584*95c635efSGarrett D'Amore 	/*
585*95c635efSGarrett D'Amore 	 * Save the fact that we're in the next-line for a block.  In
586*95c635efSGarrett D'Amore 	 * this way, embedded roff instructions can "remember" state
587*95c635efSGarrett D'Amore 	 * when they exit.
588*95c635efSGarrett D'Amore 	 */
589*95c635efSGarrett D'Amore 
590*95c635efSGarrett D'Amore 	if (MAN_BLINE & m->flags)
591*95c635efSGarrett D'Amore 		m->flags |= MAN_BPLINE;
592*95c635efSGarrett D'Amore 
593*95c635efSGarrett D'Amore 	/* Call to handler... */
594*95c635efSGarrett D'Amore 
595*95c635efSGarrett D'Amore 	assert(man_macros[tok].fp);
596*95c635efSGarrett D'Amore 	if ( ! (*man_macros[tok].fp)(m, tok, ln, ppos, &offs, buf))
597*95c635efSGarrett D'Amore 		goto err;
598*95c635efSGarrett D'Amore 
599*95c635efSGarrett D'Amore 	/*
600*95c635efSGarrett D'Amore 	 * We weren't in a block-line scope when entering the
601*95c635efSGarrett D'Amore 	 * above-parsed macro, so return.
602*95c635efSGarrett D'Amore 	 */
603*95c635efSGarrett D'Amore 
604*95c635efSGarrett D'Amore 	if ( ! (MAN_BPLINE & m->flags)) {
605*95c635efSGarrett D'Amore 		m->flags &= ~MAN_ILINE;
606*95c635efSGarrett D'Amore 		return(1);
607*95c635efSGarrett D'Amore 	}
608*95c635efSGarrett D'Amore 	m->flags &= ~MAN_BPLINE;
609*95c635efSGarrett D'Amore 
610*95c635efSGarrett D'Amore 	/*
611*95c635efSGarrett D'Amore 	 * If we're in a block scope, then allow this macro to slip by
612*95c635efSGarrett D'Amore 	 * without closing scope around it.
613*95c635efSGarrett D'Amore 	 */
614*95c635efSGarrett D'Amore 
615*95c635efSGarrett D'Amore 	if (MAN_ILINE & m->flags) {
616*95c635efSGarrett D'Amore 		m->flags &= ~MAN_ILINE;
617*95c635efSGarrett D'Amore 		return(1);
618*95c635efSGarrett D'Amore 	}
619*95c635efSGarrett D'Amore 
620*95c635efSGarrett D'Amore 	/*
621*95c635efSGarrett D'Amore 	 * If we've opened a new next-line element scope, then return
622*95c635efSGarrett D'Amore 	 * now, as the next line will close out the block scope.
623*95c635efSGarrett D'Amore 	 */
624*95c635efSGarrett D'Amore 
625*95c635efSGarrett D'Amore 	if (MAN_ELINE & m->flags)
626*95c635efSGarrett D'Amore 		return(1);
627*95c635efSGarrett D'Amore 
628*95c635efSGarrett D'Amore 	/* Close out the block scope opened in the prior line.  */
629*95c635efSGarrett D'Amore 
630*95c635efSGarrett D'Amore 	assert(MAN_BLINE & m->flags);
631*95c635efSGarrett D'Amore 	m->flags &= ~MAN_BLINE;
632*95c635efSGarrett D'Amore 
633*95c635efSGarrett D'Amore 	if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX))
634*95c635efSGarrett D'Amore 		return(0);
635*95c635efSGarrett D'Amore 	return(man_body_alloc(m, ln, ppos, m->last->tok));
636*95c635efSGarrett D'Amore 
637*95c635efSGarrett D'Amore err:	/* Error out. */
638*95c635efSGarrett D'Amore 
639*95c635efSGarrett D'Amore 	m->flags |= MAN_HALT;
640*95c635efSGarrett D'Amore 	return(0);
641*95c635efSGarrett D'Amore }
642*95c635efSGarrett D'Amore 
643*95c635efSGarrett D'Amore /*
644*95c635efSGarrett D'Amore  * Unlink a node from its context.  If "m" is provided, the last parse
645*95c635efSGarrett D'Amore  * point will also be adjusted accordingly.
646*95c635efSGarrett D'Amore  */
647*95c635efSGarrett D'Amore static void
648*95c635efSGarrett D'Amore man_node_unlink(struct man *m, struct man_node *n)
649*95c635efSGarrett D'Amore {
650*95c635efSGarrett D'Amore 
651*95c635efSGarrett D'Amore 	/* Adjust siblings. */
652*95c635efSGarrett D'Amore 
653*95c635efSGarrett D'Amore 	if (n->prev)
654*95c635efSGarrett D'Amore 		n->prev->next = n->next;
655*95c635efSGarrett D'Amore 	if (n->next)
656*95c635efSGarrett D'Amore 		n->next->prev = n->prev;
657*95c635efSGarrett D'Amore 
658*95c635efSGarrett D'Amore 	/* Adjust parent. */
659*95c635efSGarrett D'Amore 
660*95c635efSGarrett D'Amore 	if (n->parent) {
661*95c635efSGarrett D'Amore 		n->parent->nchild--;
662*95c635efSGarrett D'Amore 		if (n->parent->child == n)
663*95c635efSGarrett D'Amore 			n->parent->child = n->prev ? n->prev : n->next;
664*95c635efSGarrett D'Amore 	}
665*95c635efSGarrett D'Amore 
666*95c635efSGarrett D'Amore 	/* Adjust parse point, if applicable. */
667*95c635efSGarrett D'Amore 
668*95c635efSGarrett D'Amore 	if (m && m->last == n) {
669*95c635efSGarrett D'Amore 		/*XXX: this can occur when bailing from validation. */
670*95c635efSGarrett D'Amore 		/*assert(NULL == n->next);*/
671*95c635efSGarrett D'Amore 		if (n->prev) {
672*95c635efSGarrett D'Amore 			m->last = n->prev;
673*95c635efSGarrett D'Amore 			m->next = MAN_NEXT_SIBLING;
674*95c635efSGarrett D'Amore 		} else {
675*95c635efSGarrett D'Amore 			m->last = n->parent;
676*95c635efSGarrett D'Amore 			m->next = MAN_NEXT_CHILD;
677*95c635efSGarrett D'Amore 		}
678*95c635efSGarrett D'Amore 	}
679*95c635efSGarrett D'Amore 
680*95c635efSGarrett D'Amore 	if (m && m->first == n)
681*95c635efSGarrett D'Amore 		m->first = NULL;
682*95c635efSGarrett D'Amore }
683*95c635efSGarrett D'Amore 
684*95c635efSGarrett D'Amore const struct mparse *
685*95c635efSGarrett D'Amore man_mparse(const struct man *m)
686*95c635efSGarrett D'Amore {
687*95c635efSGarrett D'Amore 
688*95c635efSGarrett D'Amore 	assert(m && m->parse);
689*95c635efSGarrett D'Amore 	return(m->parse);
690*95c635efSGarrett D'Amore }
691