1241675Suqs/*	$Id: man.c,v 1.115 2012/01/03 15:16:24 kristaps Exp $ */
2241675Suqs/*
3241675Suqs * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4241675Suqs *
5241675Suqs * Permission to use, copy, modify, and distribute this software for any
6241675Suqs * purpose with or without fee is hereby granted, provided that the above
7241675Suqs * copyright notice and this permission notice appear in all copies.
8241675Suqs *
9241675Suqs * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10241675Suqs * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11241675Suqs * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12241675Suqs * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13241675Suqs * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14241675Suqs * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15241675Suqs * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16241675Suqs */
17241675Suqs#ifdef HAVE_CONFIG_H
18241675Suqs#include "config.h"
19241675Suqs#endif
20241675Suqs
21241675Suqs#include <sys/types.h>
22241675Suqs
23241675Suqs#include <assert.h>
24241675Suqs#include <stdarg.h>
25241675Suqs#include <stdlib.h>
26241675Suqs#include <stdio.h>
27241675Suqs#include <string.h>
28241675Suqs
29241675Suqs#include "man.h"
30241675Suqs#include "mandoc.h"
31241675Suqs#include "libman.h"
32241675Suqs#include "libmandoc.h"
33241675Suqs
34241675Suqsconst	char *const __man_macronames[MAN_MAX] = {
35241675Suqs	"br",		"TH",		"SH",		"SS",
36241675Suqs	"TP", 		"LP",		"PP",		"P",
37241675Suqs	"IP",		"HP",		"SM",		"SB",
38241675Suqs	"BI",		"IB",		"BR",		"RB",
39241675Suqs	"R",		"B",		"I",		"IR",
40241675Suqs	"RI",		"na",		"sp",		"nf",
41241675Suqs	"fi",		"RE",		"RS",		"DT",
42241675Suqs	"UC",		"PD",		"AT",		"in",
43241675Suqs	"ft",		"OP"
44241675Suqs	};
45241675Suqs
46241675Suqsconst	char * const *man_macronames = __man_macronames;
47241675Suqs
48241675Suqsstatic	struct man_node	*man_node_alloc(struct man *, int, int,
49241675Suqs				enum man_type, enum mant);
50241675Suqsstatic	int		 man_node_append(struct man *,
51241675Suqs				struct man_node *);
52241675Suqsstatic	void		 man_node_free(struct man_node *);
53241675Suqsstatic	void		 man_node_unlink(struct man *,
54241675Suqs				struct man_node *);
55241675Suqsstatic	int		 man_ptext(struct man *, int, char *, int);
56241675Suqsstatic	int		 man_pmacro(struct man *, int, char *, int);
57241675Suqsstatic	void		 man_free1(struct man *);
58241675Suqsstatic	void		 man_alloc1(struct man *);
59241675Suqsstatic	int		 man_descope(struct man *, int, int);
60241675Suqs
61241675Suqs
62241675Suqsconst struct man_node *
63241675Suqsman_node(const struct man *m)
64241675Suqs{
65241675Suqs
66241675Suqs	assert( ! (MAN_HALT & m->flags));
67241675Suqs	return(m->first);
68241675Suqs}
69241675Suqs
70241675Suqs
71241675Suqsconst struct man_meta *
72241675Suqsman_meta(const struct man *m)
73241675Suqs{
74241675Suqs
75241675Suqs	assert( ! (MAN_HALT & m->flags));
76241675Suqs	return(&m->meta);
77241675Suqs}
78241675Suqs
79241675Suqs
80241675Suqsvoid
81241675Suqsman_reset(struct man *man)
82241675Suqs{
83241675Suqs
84241675Suqs	man_free1(man);
85241675Suqs	man_alloc1(man);
86241675Suqs}
87241675Suqs
88241675Suqs
89241675Suqsvoid
90241675Suqsman_free(struct man *man)
91241675Suqs{
92241675Suqs
93241675Suqs	man_free1(man);
94241675Suqs	free(man);
95241675Suqs}
96241675Suqs
97241675Suqs
98241675Suqsstruct man *
99241675Suqsman_alloc(struct roff *roff, struct mparse *parse)
100241675Suqs{
101241675Suqs	struct man	*p;
102241675Suqs
103241675Suqs	p = mandoc_calloc(1, sizeof(struct man));
104241675Suqs
105241675Suqs	man_hash_init();
106241675Suqs	p->parse = parse;
107241675Suqs	p->roff = roff;
108241675Suqs
109241675Suqs	man_alloc1(p);
110241675Suqs	return(p);
111241675Suqs}
112241675Suqs
113241675Suqs
114241675Suqsint
115241675Suqsman_endparse(struct man *m)
116241675Suqs{
117241675Suqs
118241675Suqs	assert( ! (MAN_HALT & m->flags));
119241675Suqs	if (man_macroend(m))
120241675Suqs		return(1);
121241675Suqs	m->flags |= MAN_HALT;
122241675Suqs	return(0);
123241675Suqs}
124241675Suqs
125241675Suqs
126241675Suqsint
127241675Suqsman_parseln(struct man *m, int ln, char *buf, int offs)
128241675Suqs{
129241675Suqs
130241675Suqs	m->flags |= MAN_NEWLINE;
131241675Suqs
132241675Suqs	assert( ! (MAN_HALT & m->flags));
133241675Suqs
134241675Suqs	return (mandoc_getcontrol(buf, &offs) ?
135241675Suqs			man_pmacro(m, ln, buf, offs) :
136241675Suqs			man_ptext(m, ln, buf, offs));
137241675Suqs}
138241675Suqs
139241675Suqs
140241675Suqsstatic void
141241675Suqsman_free1(struct man *man)
142241675Suqs{
143241675Suqs
144241675Suqs	if (man->first)
145241675Suqs		man_node_delete(man, man->first);
146241675Suqs	if (man->meta.title)
147241675Suqs		free(man->meta.title);
148241675Suqs	if (man->meta.source)
149241675Suqs		free(man->meta.source);
150241675Suqs	if (man->meta.date)
151241675Suqs		free(man->meta.date);
152241675Suqs	if (man->meta.vol)
153241675Suqs		free(man->meta.vol);
154241675Suqs	if (man->meta.msec)
155241675Suqs		free(man->meta.msec);
156241675Suqs}
157241675Suqs
158241675Suqs
159241675Suqsstatic void
160241675Suqsman_alloc1(struct man *m)
161241675Suqs{
162241675Suqs
163241675Suqs	memset(&m->meta, 0, sizeof(struct man_meta));
164241675Suqs	m->flags = 0;
165241675Suqs	m->last = mandoc_calloc(1, sizeof(struct man_node));
166241675Suqs	m->first = m->last;
167241675Suqs	m->last->type = MAN_ROOT;
168241675Suqs	m->last->tok = MAN_MAX;
169241675Suqs	m->next = MAN_NEXT_CHILD;
170241675Suqs}
171241675Suqs
172241675Suqs
173241675Suqsstatic int
174241675Suqsman_node_append(struct man *man, struct man_node *p)
175241675Suqs{
176241675Suqs
177241675Suqs	assert(man->last);
178241675Suqs	assert(man->first);
179241675Suqs	assert(MAN_ROOT != p->type);
180241675Suqs
181241675Suqs	switch (man->next) {
182241675Suqs	case (MAN_NEXT_SIBLING):
183241675Suqs		man->last->next = p;
184241675Suqs		p->prev = man->last;
185241675Suqs		p->parent = man->last->parent;
186241675Suqs		break;
187241675Suqs	case (MAN_NEXT_CHILD):
188241675Suqs		man->last->child = p;
189241675Suqs		p->parent = man->last;
190241675Suqs		break;
191241675Suqs	default:
192241675Suqs		abort();
193241675Suqs		/* NOTREACHED */
194241675Suqs	}
195241675Suqs
196241675Suqs	assert(p->parent);
197241675Suqs	p->parent->nchild++;
198241675Suqs
199241675Suqs	if ( ! man_valid_pre(man, p))
200241675Suqs		return(0);
201241675Suqs
202241675Suqs	switch (p->type) {
203241675Suqs	case (MAN_HEAD):
204241675Suqs		assert(MAN_BLOCK == p->parent->type);
205241675Suqs		p->parent->head = p;
206241675Suqs		break;
207241675Suqs	case (MAN_TAIL):
208241675Suqs		assert(MAN_BLOCK == p->parent->type);
209241675Suqs		p->parent->tail = p;
210241675Suqs		break;
211241675Suqs	case (MAN_BODY):
212241675Suqs		assert(MAN_BLOCK == p->parent->type);
213241675Suqs		p->parent->body = p;
214241675Suqs		break;
215241675Suqs	default:
216241675Suqs		break;
217241675Suqs	}
218241675Suqs
219241675Suqs	man->last = p;
220241675Suqs
221241675Suqs	switch (p->type) {
222241675Suqs	case (MAN_TBL):
223241675Suqs		/* FALLTHROUGH */
224241675Suqs	case (MAN_TEXT):
225241675Suqs		if ( ! man_valid_post(man))
226241675Suqs			return(0);
227241675Suqs		break;
228241675Suqs	default:
229241675Suqs		break;
230241675Suqs	}
231241675Suqs
232241675Suqs	return(1);
233241675Suqs}
234241675Suqs
235241675Suqs
236241675Suqsstatic struct man_node *
237241675Suqsman_node_alloc(struct man *m, int line, int pos,
238241675Suqs		enum man_type type, enum mant tok)
239241675Suqs{
240241675Suqs	struct man_node *p;
241241675Suqs
242241675Suqs	p = mandoc_calloc(1, sizeof(struct man_node));
243241675Suqs	p->line = line;
244241675Suqs	p->pos = pos;
245241675Suqs	p->type = type;
246241675Suqs	p->tok = tok;
247241675Suqs
248241675Suqs	if (MAN_NEWLINE & m->flags)
249241675Suqs		p->flags |= MAN_LINE;
250241675Suqs	m->flags &= ~MAN_NEWLINE;
251241675Suqs	return(p);
252241675Suqs}
253241675Suqs
254241675Suqs
255241675Suqsint
256241675Suqsman_elem_alloc(struct man *m, int line, int pos, enum mant tok)
257241675Suqs{
258241675Suqs	struct man_node *p;
259241675Suqs
260241675Suqs	p = man_node_alloc(m, line, pos, MAN_ELEM, tok);
261241675Suqs	if ( ! man_node_append(m, p))
262241675Suqs		return(0);
263241675Suqs	m->next = MAN_NEXT_CHILD;
264241675Suqs	return(1);
265241675Suqs}
266241675Suqs
267241675Suqs
268241675Suqsint
269241675Suqsman_tail_alloc(struct man *m, int line, int pos, enum mant tok)
270241675Suqs{
271241675Suqs	struct man_node *p;
272241675Suqs
273241675Suqs	p = man_node_alloc(m, line, pos, MAN_TAIL, tok);
274241675Suqs	if ( ! man_node_append(m, p))
275241675Suqs		return(0);
276241675Suqs	m->next = MAN_NEXT_CHILD;
277241675Suqs	return(1);
278241675Suqs}
279241675Suqs
280241675Suqs
281241675Suqsint
282241675Suqsman_head_alloc(struct man *m, int line, int pos, enum mant tok)
283241675Suqs{
284241675Suqs	struct man_node *p;
285241675Suqs
286241675Suqs	p = man_node_alloc(m, line, pos, MAN_HEAD, tok);
287241675Suqs	if ( ! man_node_append(m, p))
288241675Suqs		return(0);
289241675Suqs	m->next = MAN_NEXT_CHILD;
290241675Suqs	return(1);
291241675Suqs}
292241675Suqs
293241675Suqs
294241675Suqsint
295241675Suqsman_body_alloc(struct man *m, int line, int pos, enum mant tok)
296241675Suqs{
297241675Suqs	struct man_node *p;
298241675Suqs
299241675Suqs	p = man_node_alloc(m, line, pos, MAN_BODY, tok);
300241675Suqs	if ( ! man_node_append(m, p))
301241675Suqs		return(0);
302241675Suqs	m->next = MAN_NEXT_CHILD;
303241675Suqs	return(1);
304241675Suqs}
305241675Suqs
306241675Suqs
307241675Suqsint
308241675Suqsman_block_alloc(struct man *m, int line, int pos, enum mant tok)
309241675Suqs{
310241675Suqs	struct man_node *p;
311241675Suqs
312241675Suqs	p = man_node_alloc(m, line, pos, MAN_BLOCK, tok);
313241675Suqs	if ( ! man_node_append(m, p))
314241675Suqs		return(0);
315241675Suqs	m->next = MAN_NEXT_CHILD;
316241675Suqs	return(1);
317241675Suqs}
318241675Suqs
319241675Suqsint
320241675Suqsman_word_alloc(struct man *m, int line, int pos, const char *word)
321241675Suqs{
322241675Suqs	struct man_node	*n;
323241675Suqs
324241675Suqs	n = man_node_alloc(m, line, pos, MAN_TEXT, MAN_MAX);
325241675Suqs	n->string = roff_strdup(m->roff, word);
326241675Suqs
327241675Suqs	if ( ! man_node_append(m, n))
328241675Suqs		return(0);
329241675Suqs
330241675Suqs	m->next = MAN_NEXT_SIBLING;
331241675Suqs	return(1);
332241675Suqs}
333241675Suqs
334241675Suqs
335241675Suqs/*
336241675Suqs * Free all of the resources held by a node.  This does NOT unlink a
337241675Suqs * node from its context; for that, see man_node_unlink().
338241675Suqs */
339241675Suqsstatic void
340241675Suqsman_node_free(struct man_node *p)
341241675Suqs{
342241675Suqs
343241675Suqs	if (p->string)
344241675Suqs		free(p->string);
345241675Suqs	free(p);
346241675Suqs}
347241675Suqs
348241675Suqs
349241675Suqsvoid
350241675Suqsman_node_delete(struct man *m, struct man_node *p)
351241675Suqs{
352241675Suqs
353241675Suqs	while (p->child)
354241675Suqs		man_node_delete(m, p->child);
355241675Suqs
356241675Suqs	man_node_unlink(m, p);
357241675Suqs	man_node_free(p);
358241675Suqs}
359241675Suqs
360241675Suqsint
361241675Suqsman_addeqn(struct man *m, const struct eqn *ep)
362241675Suqs{
363241675Suqs	struct man_node	*n;
364241675Suqs
365241675Suqs	assert( ! (MAN_HALT & m->flags));
366241675Suqs
367241675Suqs	n = man_node_alloc(m, ep->ln, ep->pos, MAN_EQN, MAN_MAX);
368241675Suqs	n->eqn = ep;
369241675Suqs
370241675Suqs	if ( ! man_node_append(m, n))
371241675Suqs		return(0);
372241675Suqs
373241675Suqs	m->next = MAN_NEXT_SIBLING;
374241675Suqs	return(man_descope(m, ep->ln, ep->pos));
375241675Suqs}
376241675Suqs
377241675Suqsint
378241675Suqsman_addspan(struct man *m, const struct tbl_span *sp)
379241675Suqs{
380241675Suqs	struct man_node	*n;
381241675Suqs
382241675Suqs	assert( ! (MAN_HALT & m->flags));
383241675Suqs
384241675Suqs	n = man_node_alloc(m, sp->line, 0, MAN_TBL, MAN_MAX);
385241675Suqs	n->span = sp;
386241675Suqs
387241675Suqs	if ( ! man_node_append(m, n))
388241675Suqs		return(0);
389241675Suqs
390241675Suqs	m->next = MAN_NEXT_SIBLING;
391241675Suqs	return(man_descope(m, sp->line, 0));
392241675Suqs}
393241675Suqs
394241675Suqsstatic int
395241675Suqsman_descope(struct man *m, int line, int offs)
396241675Suqs{
397241675Suqs	/*
398241675Suqs	 * Co-ordinate what happens with having a next-line scope open:
399241675Suqs	 * first close out the element scope (if applicable), then close
400241675Suqs	 * out the block scope (also if applicable).
401241675Suqs	 */
402241675Suqs
403241675Suqs	if (MAN_ELINE & m->flags) {
404241675Suqs		m->flags &= ~MAN_ELINE;
405241675Suqs		if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX))
406241675Suqs			return(0);
407241675Suqs	}
408241675Suqs
409241675Suqs	if ( ! (MAN_BLINE & m->flags))
410241675Suqs		return(1);
411241675Suqs	m->flags &= ~MAN_BLINE;
412241675Suqs
413241675Suqs	if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX))
414241675Suqs		return(0);
415241675Suqs	return(man_body_alloc(m, line, offs, m->last->tok));
416241675Suqs}
417241675Suqs
418241675Suqsstatic int
419241675Suqsman_ptext(struct man *m, int line, char *buf, int offs)
420241675Suqs{
421241675Suqs	int		 i;
422241675Suqs
423241675Suqs	/* Literal free-form text whitespace is preserved. */
424241675Suqs
425241675Suqs	if (MAN_LITERAL & m->flags) {
426241675Suqs		if ( ! man_word_alloc(m, line, offs, buf + offs))
427241675Suqs			return(0);
428241675Suqs		return(man_descope(m, line, offs));
429241675Suqs	}
430241675Suqs
431241675Suqs	/* Pump blank lines directly into the backend. */
432241675Suqs
433241675Suqs	for (i = offs; ' ' == buf[i]; i++)
434241675Suqs		/* Skip leading whitespace. */ ;
435241675Suqs
436241675Suqs	if ('\0' == buf[i]) {
437241675Suqs		/* Allocate a blank entry. */
438241675Suqs		if ( ! man_word_alloc(m, line, offs, ""))
439241675Suqs			return(0);
440241675Suqs		return(man_descope(m, line, offs));
441241675Suqs	}
442241675Suqs
443241675Suqs	/*
444241675Suqs	 * Warn if the last un-escaped character is whitespace. Then
445241675Suqs	 * strip away the remaining spaces (tabs stay!).
446241675Suqs	 */
447241675Suqs
448241675Suqs	i = (int)strlen(buf);
449241675Suqs	assert(i);
450241675Suqs
451241675Suqs	if (' ' == buf[i - 1] || '\t' == buf[i - 1]) {
452241675Suqs		if (i > 1 && '\\' != buf[i - 2])
453241675Suqs			man_pmsg(m, line, i - 1, MANDOCERR_EOLNSPACE);
454241675Suqs
455241675Suqs		for (--i; i && ' ' == buf[i]; i--)
456241675Suqs			/* Spin back to non-space. */ ;
457241675Suqs
458241675Suqs		/* Jump ahead of escaped whitespace. */
459241675Suqs		i += '\\' == buf[i] ? 2 : 1;
460241675Suqs
461241675Suqs		buf[i] = '\0';
462241675Suqs	}
463241675Suqs
464241675Suqs	if ( ! man_word_alloc(m, line, offs, buf + offs))
465241675Suqs		return(0);
466241675Suqs
467241675Suqs	/*
468241675Suqs	 * End-of-sentence check.  If the last character is an unescaped
469241675Suqs	 * EOS character, then flag the node as being the end of a
470241675Suqs	 * sentence.  The front-end will know how to interpret this.
471241675Suqs	 */
472241675Suqs
473241675Suqs	assert(i);
474241675Suqs	if (mandoc_eos(buf, (size_t)i, 0))
475241675Suqs		m->last->flags |= MAN_EOS;
476241675Suqs
477241675Suqs	return(man_descope(m, line, offs));
478241675Suqs}
479241675Suqs
480241675Suqsstatic int
481241675Suqsman_pmacro(struct man *m, int ln, char *buf, int offs)
482241675Suqs{
483241675Suqs	int		 i, ppos;
484241675Suqs	enum mant	 tok;
485241675Suqs	char		 mac[5];
486241675Suqs	struct man_node	*n;
487241675Suqs
488241675Suqs	if ('"' == buf[offs]) {
489241675Suqs		man_pmsg(m, ln, offs, MANDOCERR_BADCOMMENT);
490241675Suqs		return(1);
491241675Suqs	} else if ('\0' == buf[offs])
492241675Suqs		return(1);
493241675Suqs
494241675Suqs	ppos = offs;
495241675Suqs
496241675Suqs	/*
497241675Suqs	 * Copy the first word into a nil-terminated buffer.
498241675Suqs	 * Stop copying when a tab, space, or eoln is encountered.
499241675Suqs	 */
500241675Suqs
501241675Suqs	i = 0;
502241675Suqs	while (i < 4 && '\0' != buf[offs] &&
503241675Suqs			' ' != buf[offs] && '\t' != buf[offs])
504241675Suqs		mac[i++] = buf[offs++];
505241675Suqs
506241675Suqs	mac[i] = '\0';
507241675Suqs
508241675Suqs	tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX;
509241675Suqs
510241675Suqs	if (MAN_MAX == tok) {
511241675Suqs		mandoc_vmsg(MANDOCERR_MACRO, m->parse, ln,
512241675Suqs				ppos, "%s", buf + ppos - 1);
513241675Suqs		return(1);
514241675Suqs	}
515241675Suqs
516241675Suqs	/* The macro is sane.  Jump to the next word. */
517241675Suqs
518241675Suqs	while (buf[offs] && ' ' == buf[offs])
519241675Suqs		offs++;
520241675Suqs
521241675Suqs	/*
522241675Suqs	 * Trailing whitespace.  Note that tabs are allowed to be passed
523241675Suqs	 * into the parser as "text", so we only warn about spaces here.
524241675Suqs	 */
525241675Suqs
526241675Suqs	if ('\0' == buf[offs] && ' ' == buf[offs - 1])
527241675Suqs		man_pmsg(m, ln, offs - 1, MANDOCERR_EOLNSPACE);
528241675Suqs
529241675Suqs	/*
530241675Suqs	 * Remove prior ELINE macro, as it's being clobbered by a new
531241675Suqs	 * macro.  Note that NSCOPED macros do not close out ELINE
532241675Suqs	 * macros---they don't print text---so we let those slip by.
533241675Suqs	 */
534241675Suqs
535241675Suqs	if ( ! (MAN_NSCOPED & man_macros[tok].flags) &&
536241675Suqs			m->flags & MAN_ELINE) {
537241675Suqs		n = m->last;
538241675Suqs		assert(MAN_TEXT != n->type);
539241675Suqs
540241675Suqs		/* Remove repeated NSCOPED macros causing ELINE. */
541241675Suqs
542241675Suqs		if (MAN_NSCOPED & man_macros[n->tok].flags)
543241675Suqs			n = n->parent;
544241675Suqs
545241675Suqs		mandoc_vmsg(MANDOCERR_LINESCOPE, m->parse, n->line,
546241675Suqs		    n->pos, "%s breaks %s", man_macronames[tok],
547241675Suqs		    man_macronames[n->tok]);
548241675Suqs
549241675Suqs		man_node_delete(m, n);
550241675Suqs		m->flags &= ~MAN_ELINE;
551241675Suqs	}
552241675Suqs
553241675Suqs	/*
554241675Suqs	 * Remove prior BLINE macro that is being clobbered.
555241675Suqs	 */
556241675Suqs	if ((m->flags & MAN_BLINE) &&
557241675Suqs	    (MAN_BSCOPE & man_macros[tok].flags)) {
558241675Suqs		n = m->last;
559241675Suqs
560241675Suqs		/* Might be a text node like 8 in
561241675Suqs		 * .TP 8
562241675Suqs		 * .SH foo
563241675Suqs		 */
564241675Suqs		if (MAN_TEXT == n->type)
565241675Suqs			n = n->parent;
566241675Suqs
567241675Suqs		/* Remove element that didn't end BLINE, if any. */
568241675Suqs		if ( ! (MAN_BSCOPE & man_macros[n->tok].flags))
569241675Suqs			n = n->parent;
570241675Suqs
571241675Suqs		assert(MAN_HEAD == n->type);
572241675Suqs		n = n->parent;
573241675Suqs		assert(MAN_BLOCK == n->type);
574241675Suqs		assert(MAN_SCOPED & man_macros[n->tok].flags);
575241675Suqs
576241675Suqs		mandoc_vmsg(MANDOCERR_LINESCOPE, m->parse, n->line,
577241675Suqs		    n->pos, "%s breaks %s", man_macronames[tok],
578241675Suqs		    man_macronames[n->tok]);
579241675Suqs
580241675Suqs		man_node_delete(m, n);
581241675Suqs		m->flags &= ~MAN_BLINE;
582241675Suqs	}
583241675Suqs
584241675Suqs	/*
585241675Suqs	 * Save the fact that we're in the next-line for a block.  In
586241675Suqs	 * this way, embedded roff instructions can "remember" state
587241675Suqs	 * when they exit.
588241675Suqs	 */
589241675Suqs
590241675Suqs	if (MAN_BLINE & m->flags)
591241675Suqs		m->flags |= MAN_BPLINE;
592241675Suqs
593241675Suqs	/* Call to handler... */
594241675Suqs
595241675Suqs	assert(man_macros[tok].fp);
596241675Suqs	if ( ! (*man_macros[tok].fp)(m, tok, ln, ppos, &offs, buf))
597241675Suqs		goto err;
598241675Suqs
599241675Suqs	/*
600241675Suqs	 * We weren't in a block-line scope when entering the
601241675Suqs	 * above-parsed macro, so return.
602241675Suqs	 */
603241675Suqs
604241675Suqs	if ( ! (MAN_BPLINE & m->flags)) {
605241675Suqs		m->flags &= ~MAN_ILINE;
606241675Suqs		return(1);
607241675Suqs	}
608241675Suqs	m->flags &= ~MAN_BPLINE;
609241675Suqs
610241675Suqs	/*
611241675Suqs	 * If we're in a block scope, then allow this macro to slip by
612241675Suqs	 * without closing scope around it.
613241675Suqs	 */
614241675Suqs
615241675Suqs	if (MAN_ILINE & m->flags) {
616241675Suqs		m->flags &= ~MAN_ILINE;
617241675Suqs		return(1);
618241675Suqs	}
619241675Suqs
620241675Suqs	/*
621241675Suqs	 * If we've opened a new next-line element scope, then return
622241675Suqs	 * now, as the next line will close out the block scope.
623241675Suqs	 */
624241675Suqs
625241675Suqs	if (MAN_ELINE & m->flags)
626241675Suqs		return(1);
627241675Suqs
628241675Suqs	/* Close out the block scope opened in the prior line.  */
629241675Suqs
630241675Suqs	assert(MAN_BLINE & m->flags);
631241675Suqs	m->flags &= ~MAN_BLINE;
632241675Suqs
633241675Suqs	if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX))
634241675Suqs		return(0);
635241675Suqs	return(man_body_alloc(m, ln, ppos, m->last->tok));
636241675Suqs
637241675Suqserr:	/* Error out. */
638241675Suqs
639241675Suqs	m->flags |= MAN_HALT;
640241675Suqs	return(0);
641241675Suqs}
642241675Suqs
643241675Suqs/*
644241675Suqs * Unlink a node from its context.  If "m" is provided, the last parse
645241675Suqs * point will also be adjusted accordingly.
646241675Suqs */
647241675Suqsstatic void
648241675Suqsman_node_unlink(struct man *m, struct man_node *n)
649241675Suqs{
650241675Suqs
651241675Suqs	/* Adjust siblings. */
652241675Suqs
653241675Suqs	if (n->prev)
654241675Suqs		n->prev->next = n->next;
655241675Suqs	if (n->next)
656241675Suqs		n->next->prev = n->prev;
657241675Suqs
658241675Suqs	/* Adjust parent. */
659241675Suqs
660241675Suqs	if (n->parent) {
661241675Suqs		n->parent->nchild--;
662241675Suqs		if (n->parent->child == n)
663241675Suqs			n->parent->child = n->prev ? n->prev : n->next;
664241675Suqs	}
665241675Suqs
666241675Suqs	/* Adjust parse point, if applicable. */
667241675Suqs
668241675Suqs	if (m && m->last == n) {
669241675Suqs		/*XXX: this can occur when bailing from validation. */
670241675Suqs		/*assert(NULL == n->next);*/
671241675Suqs		if (n->prev) {
672241675Suqs			m->last = n->prev;
673241675Suqs			m->next = MAN_NEXT_SIBLING;
674241675Suqs		} else {
675241675Suqs			m->last = n->parent;
676241675Suqs			m->next = MAN_NEXT_CHILD;
677241675Suqs		}
678241675Suqs	}
679241675Suqs
680241675Suqs	if (m && m->first == n)
681241675Suqs		m->first = NULL;
682241675Suqs}
683241675Suqs
684241675Suqsconst struct mparse *
685241675Suqsman_mparse(const struct man *m)
686241675Suqs{
687241675Suqs
688241675Suqs	assert(m && m->parse);
689241675Suqs	return(m->parse);
690241675Suqs}
691