xref: /titanic_44/usr/src/cmd/mandoc/man_macro.c (revision 698f87a48e2e945bfe5493ce168e0d0ae1cedd5c)
1*698f87a4SGarrett D'Amore /*	$Id: man_macro.c,v 1.79 2013/12/25 00:50:05 schwarze Exp $ */
295c635efSGarrett D'Amore /*
395c635efSGarrett D'Amore  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*698f87a4SGarrett D'Amore  * Copyright (c) 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
5*698f87a4SGarrett D'Amore  * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
695c635efSGarrett D'Amore  *
795c635efSGarrett D'Amore  * Permission to use, copy, modify, and distribute this software for any
895c635efSGarrett D'Amore  * purpose with or without fee is hereby granted, provided that the above
995c635efSGarrett D'Amore  * copyright notice and this permission notice appear in all copies.
1095c635efSGarrett D'Amore  *
1195c635efSGarrett D'Amore  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1295c635efSGarrett D'Amore  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1395c635efSGarrett D'Amore  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1495c635efSGarrett D'Amore  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1595c635efSGarrett D'Amore  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1695c635efSGarrett D'Amore  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1795c635efSGarrett D'Amore  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1895c635efSGarrett D'Amore  */
1995c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H
2095c635efSGarrett D'Amore #include "config.h"
2195c635efSGarrett D'Amore #endif
2295c635efSGarrett D'Amore 
2395c635efSGarrett D'Amore #include <assert.h>
2495c635efSGarrett D'Amore #include <ctype.h>
2595c635efSGarrett D'Amore #include <stdlib.h>
2695c635efSGarrett D'Amore #include <string.h>
2795c635efSGarrett D'Amore 
2895c635efSGarrett D'Amore #include "man.h"
2995c635efSGarrett D'Amore #include "mandoc.h"
3095c635efSGarrett D'Amore #include "libmandoc.h"
3195c635efSGarrett D'Amore #include "libman.h"
3295c635efSGarrett D'Amore 
3395c635efSGarrett D'Amore enum	rew {
3495c635efSGarrett D'Amore 	REW_REWIND,
3595c635efSGarrett D'Amore 	REW_NOHALT,
3695c635efSGarrett D'Amore 	REW_HALT
3795c635efSGarrett D'Amore };
3895c635efSGarrett D'Amore 
3995c635efSGarrett D'Amore static	int		 blk_close(MACRO_PROT_ARGS);
4095c635efSGarrett D'Amore static	int		 blk_exp(MACRO_PROT_ARGS);
4195c635efSGarrett D'Amore static	int		 blk_imp(MACRO_PROT_ARGS);
4295c635efSGarrett D'Amore static	int		 in_line_eoln(MACRO_PROT_ARGS);
4395c635efSGarrett D'Amore static	int		 man_args(struct man *, int,
4495c635efSGarrett D'Amore 				int *, char *, char **);
4595c635efSGarrett D'Amore 
4695c635efSGarrett D'Amore static	int		 rew_scope(enum man_type,
4795c635efSGarrett D'Amore 				struct man *, enum mant);
4895c635efSGarrett D'Amore static	enum rew	 rew_dohalt(enum mant, enum man_type,
4995c635efSGarrett D'Amore 				const struct man_node *);
5095c635efSGarrett D'Amore static	enum rew	 rew_block(enum mant, enum man_type,
5195c635efSGarrett D'Amore 				const struct man_node *);
5295c635efSGarrett D'Amore static	void		 rew_warn(struct man *,
5395c635efSGarrett D'Amore 				struct man_node *, enum mandocerr);
5495c635efSGarrett D'Amore 
5595c635efSGarrett D'Amore const	struct man_macro __man_macros[MAN_MAX] = {
5695c635efSGarrett D'Amore 	{ in_line_eoln, MAN_NSCOPED }, /* br */
5795c635efSGarrett D'Amore 	{ in_line_eoln, MAN_BSCOPE }, /* TH */
5895c635efSGarrett D'Amore 	{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SH */
5995c635efSGarrett D'Amore 	{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SS */
6095c635efSGarrett D'Amore 	{ blk_imp, MAN_BSCOPE | MAN_SCOPED | MAN_FSCOPED }, /* TP */
6195c635efSGarrett D'Amore 	{ blk_imp, MAN_BSCOPE }, /* LP */
6295c635efSGarrett D'Amore 	{ blk_imp, MAN_BSCOPE }, /* PP */
6395c635efSGarrett D'Amore 	{ blk_imp, MAN_BSCOPE }, /* P */
6495c635efSGarrett D'Amore 	{ blk_imp, MAN_BSCOPE }, /* IP */
6595c635efSGarrett D'Amore 	{ blk_imp, MAN_BSCOPE }, /* HP */
6695c635efSGarrett D'Amore 	{ in_line_eoln, MAN_SCOPED }, /* SM */
6795c635efSGarrett D'Amore 	{ in_line_eoln, MAN_SCOPED }, /* SB */
6895c635efSGarrett D'Amore 	{ in_line_eoln, 0 }, /* BI */
6995c635efSGarrett D'Amore 	{ in_line_eoln, 0 }, /* IB */
7095c635efSGarrett D'Amore 	{ in_line_eoln, 0 }, /* BR */
7195c635efSGarrett D'Amore 	{ in_line_eoln, 0 }, /* RB */
7295c635efSGarrett D'Amore 	{ in_line_eoln, MAN_SCOPED }, /* R */
7395c635efSGarrett D'Amore 	{ in_line_eoln, MAN_SCOPED }, /* B */
7495c635efSGarrett D'Amore 	{ in_line_eoln, MAN_SCOPED }, /* I */
7595c635efSGarrett D'Amore 	{ in_line_eoln, 0 }, /* IR */
7695c635efSGarrett D'Amore 	{ in_line_eoln, 0 }, /* RI */
7795c635efSGarrett D'Amore 	{ in_line_eoln, MAN_NSCOPED }, /* na */
7895c635efSGarrett D'Amore 	{ in_line_eoln, MAN_NSCOPED }, /* sp */
7995c635efSGarrett D'Amore 	{ in_line_eoln, MAN_BSCOPE }, /* nf */
8095c635efSGarrett D'Amore 	{ in_line_eoln, MAN_BSCOPE }, /* fi */
8195c635efSGarrett D'Amore 	{ blk_close, 0 }, /* RE */
82*698f87a4SGarrett D'Amore 	{ blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* RS */
8395c635efSGarrett D'Amore 	{ in_line_eoln, 0 }, /* DT */
8495c635efSGarrett D'Amore 	{ in_line_eoln, 0 }, /* UC */
8595c635efSGarrett D'Amore 	{ in_line_eoln, 0 }, /* PD */
8695c635efSGarrett D'Amore 	{ in_line_eoln, 0 }, /* AT */
8795c635efSGarrett D'Amore 	{ in_line_eoln, 0 }, /* in */
8895c635efSGarrett D'Amore 	{ in_line_eoln, 0 }, /* ft */
8995c635efSGarrett D'Amore 	{ in_line_eoln, 0 }, /* OP */
90*698f87a4SGarrett D'Amore 	{ in_line_eoln, MAN_BSCOPE }, /* EX */
91*698f87a4SGarrett D'Amore 	{ in_line_eoln, MAN_BSCOPE }, /* EE */
92*698f87a4SGarrett D'Amore 	{ blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* UR */
93*698f87a4SGarrett D'Amore 	{ blk_close, 0 }, /* UE */
9495c635efSGarrett D'Amore };
9595c635efSGarrett D'Amore 
9695c635efSGarrett D'Amore const	struct man_macro * const man_macros = __man_macros;
9795c635efSGarrett D'Amore 
9895c635efSGarrett D'Amore 
9995c635efSGarrett D'Amore /*
10095c635efSGarrett D'Amore  * Warn when "n" is an explicit non-roff macro.
10195c635efSGarrett D'Amore  */
10295c635efSGarrett D'Amore static void
rew_warn(struct man * man,struct man_node * n,enum mandocerr er)103*698f87a4SGarrett D'Amore rew_warn(struct man *man, struct man_node *n, enum mandocerr er)
10495c635efSGarrett D'Amore {
10595c635efSGarrett D'Amore 
10695c635efSGarrett D'Amore 	if (er == MANDOCERR_MAX || MAN_BLOCK != n->type)
10795c635efSGarrett D'Amore 		return;
10895c635efSGarrett D'Amore 	if (MAN_VALID & n->flags)
10995c635efSGarrett D'Amore 		return;
11095c635efSGarrett D'Amore 	if ( ! (MAN_EXPLICIT & man_macros[n->tok].flags))
11195c635efSGarrett D'Amore 		return;
11295c635efSGarrett D'Amore 
11395c635efSGarrett D'Amore 	assert(er < MANDOCERR_FATAL);
114*698f87a4SGarrett D'Amore 	man_nmsg(man, n, er);
11595c635efSGarrett D'Amore }
11695c635efSGarrett D'Amore 
11795c635efSGarrett D'Amore 
11895c635efSGarrett D'Amore /*
11995c635efSGarrett D'Amore  * Rewind scope.  If a code "er" != MANDOCERR_MAX has been provided, it
12095c635efSGarrett D'Amore  * will be used if an explicit block scope is being closed out.
12195c635efSGarrett D'Amore  */
12295c635efSGarrett D'Amore int
man_unscope(struct man * man,const struct man_node * to,enum mandocerr er)123*698f87a4SGarrett D'Amore man_unscope(struct man *man, const struct man_node *to,
12495c635efSGarrett D'Amore 		enum mandocerr er)
12595c635efSGarrett D'Amore {
12695c635efSGarrett D'Amore 	struct man_node	*n;
12795c635efSGarrett D'Amore 
12895c635efSGarrett D'Amore 	assert(to);
12995c635efSGarrett D'Amore 
130*698f87a4SGarrett D'Amore 	man->next = MAN_NEXT_SIBLING;
13195c635efSGarrett D'Amore 
13295c635efSGarrett D'Amore 	/* LINTED */
133*698f87a4SGarrett D'Amore 	while (man->last != to) {
13495c635efSGarrett D'Amore 		/*
13595c635efSGarrett D'Amore 		 * Save the parent here, because we may delete the
136*698f87a4SGarrett D'Amore 		 * man->last node in the post-validation phase and reset
137*698f87a4SGarrett D'Amore 		 * it to man->last->parent, causing a step in the closing
13895c635efSGarrett D'Amore 		 * out to be lost.
13995c635efSGarrett D'Amore 		 */
140*698f87a4SGarrett D'Amore 		n = man->last->parent;
141*698f87a4SGarrett D'Amore 		rew_warn(man, man->last, er);
142*698f87a4SGarrett D'Amore 		if ( ! man_valid_post(man))
14395c635efSGarrett D'Amore 			return(0);
144*698f87a4SGarrett D'Amore 		man->last = n;
145*698f87a4SGarrett D'Amore 		assert(man->last);
14695c635efSGarrett D'Amore 	}
14795c635efSGarrett D'Amore 
148*698f87a4SGarrett D'Amore 	rew_warn(man, man->last, er);
149*698f87a4SGarrett D'Amore 	if ( ! man_valid_post(man))
15095c635efSGarrett D'Amore 		return(0);
15195c635efSGarrett D'Amore 
15295c635efSGarrett D'Amore 	return(1);
15395c635efSGarrett D'Amore }
15495c635efSGarrett D'Amore 
15595c635efSGarrett D'Amore 
15695c635efSGarrett D'Amore static enum rew
rew_block(enum mant ntok,enum man_type type,const struct man_node * n)15795c635efSGarrett D'Amore rew_block(enum mant ntok, enum man_type type, const struct man_node *n)
15895c635efSGarrett D'Amore {
15995c635efSGarrett D'Amore 
16095c635efSGarrett D'Amore 	if (MAN_BLOCK == type && ntok == n->parent->tok &&
16195c635efSGarrett D'Amore 			MAN_BODY == n->parent->type)
16295c635efSGarrett D'Amore 		return(REW_REWIND);
16395c635efSGarrett D'Amore 	return(ntok == n->tok ? REW_HALT : REW_NOHALT);
16495c635efSGarrett D'Amore }
16595c635efSGarrett D'Amore 
16695c635efSGarrett D'Amore 
16795c635efSGarrett D'Amore /*
16895c635efSGarrett D'Amore  * There are three scope levels: scoped to the root (all), scoped to the
16995c635efSGarrett D'Amore  * section (all less sections), and scoped to subsections (all less
17095c635efSGarrett D'Amore  * sections and subsections).
17195c635efSGarrett D'Amore  */
17295c635efSGarrett D'Amore static enum rew
rew_dohalt(enum mant tok,enum man_type type,const struct man_node * n)17395c635efSGarrett D'Amore rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n)
17495c635efSGarrett D'Amore {
17595c635efSGarrett D'Amore 	enum rew	 c;
17695c635efSGarrett D'Amore 
17795c635efSGarrett D'Amore 	/* We cannot progress beyond the root ever. */
17895c635efSGarrett D'Amore 	if (MAN_ROOT == n->type)
17995c635efSGarrett D'Amore 		return(REW_HALT);
18095c635efSGarrett D'Amore 
18195c635efSGarrett D'Amore 	assert(n->parent);
18295c635efSGarrett D'Amore 
18395c635efSGarrett D'Amore 	/* Normal nodes shouldn't go to the level of the root. */
18495c635efSGarrett D'Amore 	if (MAN_ROOT == n->parent->type)
18595c635efSGarrett D'Amore 		return(REW_REWIND);
18695c635efSGarrett D'Amore 
18795c635efSGarrett D'Amore 	/* Already-validated nodes should be closed out. */
18895c635efSGarrett D'Amore 	if (MAN_VALID & n->flags)
18995c635efSGarrett D'Amore 		return(REW_NOHALT);
19095c635efSGarrett D'Amore 
19195c635efSGarrett D'Amore 	/* First: rewind to ourselves. */
192*698f87a4SGarrett D'Amore 	if (type == n->type && tok == n->tok) {
193*698f87a4SGarrett D'Amore 		if (MAN_EXPLICIT & man_macros[n->tok].flags)
194*698f87a4SGarrett D'Amore 			return(REW_HALT);
195*698f87a4SGarrett D'Amore 		else
19695c635efSGarrett D'Amore 			return(REW_REWIND);
197*698f87a4SGarrett D'Amore 	}
19895c635efSGarrett D'Amore 
19995c635efSGarrett D'Amore 	/*
20095c635efSGarrett D'Amore 	 * Next follow the implicit scope-smashings as defined by man.7:
20195c635efSGarrett D'Amore 	 * section, sub-section, etc.
20295c635efSGarrett D'Amore 	 */
20395c635efSGarrett D'Amore 
20495c635efSGarrett D'Amore 	switch (tok) {
20595c635efSGarrett D'Amore 	case (MAN_SH):
20695c635efSGarrett D'Amore 		break;
20795c635efSGarrett D'Amore 	case (MAN_SS):
20895c635efSGarrett D'Amore 		/* Rewind to a section, if a block. */
20995c635efSGarrett D'Amore 		if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
21095c635efSGarrett D'Amore 			return(c);
21195c635efSGarrett D'Amore 		break;
21295c635efSGarrett D'Amore 	case (MAN_RS):
213*698f87a4SGarrett D'Amore 		/* Preserve empty paragraphs before RS. */
214*698f87a4SGarrett D'Amore 		if (0 == n->nchild && (MAN_P == n->tok ||
215*698f87a4SGarrett D'Amore 		    MAN_PP == n->tok || MAN_LP == n->tok))
216*698f87a4SGarrett D'Amore 			return(REW_HALT);
21795c635efSGarrett D'Amore 		/* Rewind to a subsection, if a block. */
21895c635efSGarrett D'Amore 		if (REW_NOHALT != (c = rew_block(MAN_SS, type, n)))
21995c635efSGarrett D'Amore 			return(c);
22095c635efSGarrett D'Amore 		/* Rewind to a section, if a block. */
22195c635efSGarrett D'Amore 		if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
22295c635efSGarrett D'Amore 			return(c);
22395c635efSGarrett D'Amore 		break;
22495c635efSGarrett D'Amore 	default:
22595c635efSGarrett D'Amore 		/* Rewind to an offsetter, if a block. */
22695c635efSGarrett D'Amore 		if (REW_NOHALT != (c = rew_block(MAN_RS, type, n)))
22795c635efSGarrett D'Amore 			return(c);
22895c635efSGarrett D'Amore 		/* Rewind to a subsection, if a block. */
22995c635efSGarrett D'Amore 		if (REW_NOHALT != (c = rew_block(MAN_SS, type, n)))
23095c635efSGarrett D'Amore 			return(c);
23195c635efSGarrett D'Amore 		/* Rewind to a section, if a block. */
23295c635efSGarrett D'Amore 		if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
23395c635efSGarrett D'Amore 			return(c);
23495c635efSGarrett D'Amore 		break;
23595c635efSGarrett D'Amore 	}
23695c635efSGarrett D'Amore 
23795c635efSGarrett D'Amore 	return(REW_NOHALT);
23895c635efSGarrett D'Amore }
23995c635efSGarrett D'Amore 
24095c635efSGarrett D'Amore 
24195c635efSGarrett D'Amore /*
24295c635efSGarrett D'Amore  * Rewinding entails ascending the parse tree until a coherent point,
24395c635efSGarrett D'Amore  * for example, the `SH' macro will close out any intervening `SS'
24495c635efSGarrett D'Amore  * scopes.  When a scope is closed, it must be validated and actioned.
24595c635efSGarrett D'Amore  */
24695c635efSGarrett D'Amore static int
rew_scope(enum man_type type,struct man * man,enum mant tok)247*698f87a4SGarrett D'Amore rew_scope(enum man_type type, struct man *man, enum mant tok)
24895c635efSGarrett D'Amore {
24995c635efSGarrett D'Amore 	struct man_node	*n;
25095c635efSGarrett D'Amore 	enum rew	 c;
25195c635efSGarrett D'Amore 
25295c635efSGarrett D'Amore 	/* LINTED */
253*698f87a4SGarrett D'Amore 	for (n = man->last; n; n = n->parent) {
25495c635efSGarrett D'Amore 		/*
25595c635efSGarrett D'Amore 		 * Whether we should stop immediately (REW_HALT), stop
25695c635efSGarrett D'Amore 		 * and rewind until this point (REW_REWIND), or keep
25795c635efSGarrett D'Amore 		 * rewinding (REW_NOHALT).
25895c635efSGarrett D'Amore 		 */
25995c635efSGarrett D'Amore 		c = rew_dohalt(tok, type, n);
26095c635efSGarrett D'Amore 		if (REW_HALT == c)
26195c635efSGarrett D'Amore 			return(1);
26295c635efSGarrett D'Amore 		if (REW_REWIND == c)
26395c635efSGarrett D'Amore 			break;
26495c635efSGarrett D'Amore 	}
26595c635efSGarrett D'Amore 
26695c635efSGarrett D'Amore 	/*
26795c635efSGarrett D'Amore 	 * Rewind until the current point.  Warn if we're a roff
26895c635efSGarrett D'Amore 	 * instruction that's mowing over explicit scopes.
26995c635efSGarrett D'Amore 	 */
27095c635efSGarrett D'Amore 	assert(n);
27195c635efSGarrett D'Amore 
272*698f87a4SGarrett D'Amore 	return(man_unscope(man, n, MANDOCERR_MAX));
27395c635efSGarrett D'Amore }
27495c635efSGarrett D'Amore 
27595c635efSGarrett D'Amore 
27695c635efSGarrett D'Amore /*
27795c635efSGarrett D'Amore  * Close out a generic explicit macro.
27895c635efSGarrett D'Amore  */
27995c635efSGarrett D'Amore /* ARGSUSED */
28095c635efSGarrett D'Amore int
blk_close(MACRO_PROT_ARGS)28195c635efSGarrett D'Amore blk_close(MACRO_PROT_ARGS)
28295c635efSGarrett D'Amore {
28395c635efSGarrett D'Amore 	enum mant	 	 ntok;
28495c635efSGarrett D'Amore 	const struct man_node	*nn;
28595c635efSGarrett D'Amore 
28695c635efSGarrett D'Amore 	switch (tok) {
28795c635efSGarrett D'Amore 	case (MAN_RE):
28895c635efSGarrett D'Amore 		ntok = MAN_RS;
28995c635efSGarrett D'Amore 		break;
290*698f87a4SGarrett D'Amore 	case (MAN_UE):
291*698f87a4SGarrett D'Amore 		ntok = MAN_UR;
292*698f87a4SGarrett D'Amore 		break;
29395c635efSGarrett D'Amore 	default:
29495c635efSGarrett D'Amore 		abort();
29595c635efSGarrett D'Amore 		/* NOTREACHED */
29695c635efSGarrett D'Amore 	}
29795c635efSGarrett D'Amore 
298*698f87a4SGarrett D'Amore 	for (nn = man->last->parent; nn; nn = nn->parent)
299*698f87a4SGarrett D'Amore 		if (ntok == nn->tok && MAN_BLOCK == nn->type)
30095c635efSGarrett D'Amore 			break;
30195c635efSGarrett D'Amore 
302*698f87a4SGarrett D'Amore 	if (NULL == nn) {
303*698f87a4SGarrett D'Amore 		man_pmsg(man, line, ppos, MANDOCERR_NOSCOPE);
304*698f87a4SGarrett D'Amore 		if ( ! rew_scope(MAN_BLOCK, man, MAN_PP))
30595c635efSGarrett D'Amore 			return(0);
306*698f87a4SGarrett D'Amore 	} else
307*698f87a4SGarrett D'Amore 		man_unscope(man, nn, MANDOCERR_MAX);
30895c635efSGarrett D'Amore 
30995c635efSGarrett D'Amore 	return(1);
31095c635efSGarrett D'Amore }
31195c635efSGarrett D'Amore 
31295c635efSGarrett D'Amore 
31395c635efSGarrett D'Amore /* ARGSUSED */
31495c635efSGarrett D'Amore int
blk_exp(MACRO_PROT_ARGS)31595c635efSGarrett D'Amore blk_exp(MACRO_PROT_ARGS)
31695c635efSGarrett D'Amore {
317*698f87a4SGarrett D'Amore 	struct man_node	*n;
31895c635efSGarrett D'Amore 	int		 la;
31995c635efSGarrett D'Amore 	char		*p;
32095c635efSGarrett D'Amore 
321*698f87a4SGarrett D'Amore 	/* Close out prior implicit scopes. */
32295c635efSGarrett D'Amore 
323*698f87a4SGarrett D'Amore 	if ( ! rew_scope(MAN_BLOCK, man, tok))
32495c635efSGarrett D'Amore 		return(0);
325*698f87a4SGarrett D'Amore 
326*698f87a4SGarrett D'Amore 	if ( ! man_block_alloc(man, line, ppos, tok))
327*698f87a4SGarrett D'Amore 		return(0);
328*698f87a4SGarrett D'Amore 	if ( ! man_head_alloc(man, line, ppos, tok))
32995c635efSGarrett D'Amore 		return(0);
33095c635efSGarrett D'Amore 
33195c635efSGarrett D'Amore 	for (;;) {
33295c635efSGarrett D'Amore 		la = *pos;
333*698f87a4SGarrett D'Amore 		if ( ! man_args(man, line, pos, buf, &p))
33495c635efSGarrett D'Amore 			break;
335*698f87a4SGarrett D'Amore 		if ( ! man_word_alloc(man, line, la, p))
33695c635efSGarrett D'Amore 			return(0);
33795c635efSGarrett D'Amore 	}
33895c635efSGarrett D'Amore 
339*698f87a4SGarrett D'Amore 	assert(man);
34095c635efSGarrett D'Amore 	assert(tok != MAN_MAX);
34195c635efSGarrett D'Amore 
342*698f87a4SGarrett D'Amore 	for (n = man->last; n; n = n->parent) {
343*698f87a4SGarrett D'Amore 		if (n->tok != tok)
344*698f87a4SGarrett D'Amore 			continue;
345*698f87a4SGarrett D'Amore 		assert(MAN_HEAD == n->type);
346*698f87a4SGarrett D'Amore 		man_unscope(man, n, MANDOCERR_MAX);
347*698f87a4SGarrett D'Amore 		break;
348*698f87a4SGarrett D'Amore 	}
349*698f87a4SGarrett D'Amore 
350*698f87a4SGarrett D'Amore 	return(man_body_alloc(man, line, ppos, tok));
35195c635efSGarrett D'Amore }
35295c635efSGarrett D'Amore 
35395c635efSGarrett D'Amore 
35495c635efSGarrett D'Amore 
35595c635efSGarrett D'Amore /*
35695c635efSGarrett D'Amore  * Parse an implicit-block macro.  These contain a MAN_HEAD and a
35795c635efSGarrett D'Amore  * MAN_BODY contained within a MAN_BLOCK.  Rules for closing out other
35895c635efSGarrett D'Amore  * scopes, such as `SH' closing out an `SS', are defined in the rew
35995c635efSGarrett D'Amore  * routines.
36095c635efSGarrett D'Amore  */
36195c635efSGarrett D'Amore /* ARGSUSED */
36295c635efSGarrett D'Amore int
blk_imp(MACRO_PROT_ARGS)36395c635efSGarrett D'Amore blk_imp(MACRO_PROT_ARGS)
36495c635efSGarrett D'Amore {
36595c635efSGarrett D'Amore 	int		 la;
36695c635efSGarrett D'Amore 	char		*p;
36795c635efSGarrett D'Amore 	struct man_node	*n;
36895c635efSGarrett D'Amore 
36995c635efSGarrett D'Amore 	/* Close out prior scopes. */
37095c635efSGarrett D'Amore 
371*698f87a4SGarrett D'Amore 	if ( ! rew_scope(MAN_BODY, man, tok))
37295c635efSGarrett D'Amore 		return(0);
373*698f87a4SGarrett D'Amore 	if ( ! rew_scope(MAN_BLOCK, man, tok))
37495c635efSGarrett D'Amore 		return(0);
37595c635efSGarrett D'Amore 
37695c635efSGarrett D'Amore 	/* Allocate new block & head scope. */
37795c635efSGarrett D'Amore 
378*698f87a4SGarrett D'Amore 	if ( ! man_block_alloc(man, line, ppos, tok))
37995c635efSGarrett D'Amore 		return(0);
380*698f87a4SGarrett D'Amore 	if ( ! man_head_alloc(man, line, ppos, tok))
38195c635efSGarrett D'Amore 		return(0);
38295c635efSGarrett D'Amore 
383*698f87a4SGarrett D'Amore 	n = man->last;
38495c635efSGarrett D'Amore 
38595c635efSGarrett D'Amore 	/* Add line arguments. */
38695c635efSGarrett D'Amore 
38795c635efSGarrett D'Amore 	for (;;) {
38895c635efSGarrett D'Amore 		la = *pos;
389*698f87a4SGarrett D'Amore 		if ( ! man_args(man, line, pos, buf, &p))
39095c635efSGarrett D'Amore 			break;
391*698f87a4SGarrett D'Amore 		if ( ! man_word_alloc(man, line, la, p))
39295c635efSGarrett D'Amore 			return(0);
39395c635efSGarrett D'Amore 	}
39495c635efSGarrett D'Amore 
39595c635efSGarrett D'Amore 	/* Close out head and open body (unless MAN_SCOPE). */
39695c635efSGarrett D'Amore 
39795c635efSGarrett D'Amore 	if (MAN_SCOPED & man_macros[tok].flags) {
39895c635efSGarrett D'Amore 		/* If we're forcing scope (`TP'), keep it open. */
39995c635efSGarrett D'Amore 		if (MAN_FSCOPED & man_macros[tok].flags) {
400*698f87a4SGarrett D'Amore 			man->flags |= MAN_BLINE;
40195c635efSGarrett D'Amore 			return(1);
402*698f87a4SGarrett D'Amore 		} else if (n == man->last) {
403*698f87a4SGarrett D'Amore 			man->flags |= MAN_BLINE;
40495c635efSGarrett D'Amore 			return(1);
40595c635efSGarrett D'Amore 		}
40695c635efSGarrett D'Amore 	}
40795c635efSGarrett D'Amore 
408*698f87a4SGarrett D'Amore 	if ( ! rew_scope(MAN_HEAD, man, tok))
40995c635efSGarrett D'Amore 		return(0);
410*698f87a4SGarrett D'Amore 	return(man_body_alloc(man, line, ppos, tok));
41195c635efSGarrett D'Amore }
41295c635efSGarrett D'Amore 
41395c635efSGarrett D'Amore 
41495c635efSGarrett D'Amore /* ARGSUSED */
41595c635efSGarrett D'Amore int
in_line_eoln(MACRO_PROT_ARGS)41695c635efSGarrett D'Amore in_line_eoln(MACRO_PROT_ARGS)
41795c635efSGarrett D'Amore {
41895c635efSGarrett D'Amore 	int		 la;
41995c635efSGarrett D'Amore 	char		*p;
42095c635efSGarrett D'Amore 	struct man_node	*n;
42195c635efSGarrett D'Amore 
422*698f87a4SGarrett D'Amore 	if ( ! man_elem_alloc(man, line, ppos, tok))
42395c635efSGarrett D'Amore 		return(0);
42495c635efSGarrett D'Amore 
425*698f87a4SGarrett D'Amore 	n = man->last;
42695c635efSGarrett D'Amore 
42795c635efSGarrett D'Amore 	for (;;) {
42895c635efSGarrett D'Amore 		la = *pos;
429*698f87a4SGarrett D'Amore 		if ( ! man_args(man, line, pos, buf, &p))
43095c635efSGarrett D'Amore 			break;
431*698f87a4SGarrett D'Amore 		if ( ! man_word_alloc(man, line, la, p))
43295c635efSGarrett D'Amore 			return(0);
43395c635efSGarrett D'Amore 	}
43495c635efSGarrett D'Amore 
43595c635efSGarrett D'Amore 	/*
436*698f87a4SGarrett D'Amore 	 * Append MAN_EOS in case the last snipped argument
437*698f87a4SGarrett D'Amore 	 * ends with a dot, e.g. `.IR syslog (3).'
438*698f87a4SGarrett D'Amore 	 */
439*698f87a4SGarrett D'Amore 
440*698f87a4SGarrett D'Amore 	if (n != man->last &&
441*698f87a4SGarrett D'Amore 	    mandoc_eos(man->last->string, strlen(man->last->string), 0))
442*698f87a4SGarrett D'Amore 		man->last->flags |= MAN_EOS;
443*698f87a4SGarrett D'Amore 
444*698f87a4SGarrett D'Amore 	/*
44595c635efSGarrett D'Amore 	 * If no arguments are specified and this is MAN_SCOPED (i.e.,
44695c635efSGarrett D'Amore 	 * next-line scoped), then set our mode to indicate that we're
44795c635efSGarrett D'Amore 	 * waiting for terms to load into our context.
44895c635efSGarrett D'Amore 	 */
44995c635efSGarrett D'Amore 
450*698f87a4SGarrett D'Amore 	if (n == man->last && MAN_SCOPED & man_macros[tok].flags) {
45195c635efSGarrett D'Amore 		assert( ! (MAN_NSCOPED & man_macros[tok].flags));
452*698f87a4SGarrett D'Amore 		man->flags |= MAN_ELINE;
45395c635efSGarrett D'Amore 		return(1);
45495c635efSGarrett D'Amore 	}
45595c635efSGarrett D'Amore 
45695c635efSGarrett D'Amore 	/* Set ignorable context, if applicable. */
45795c635efSGarrett D'Amore 
45895c635efSGarrett D'Amore 	if (MAN_NSCOPED & man_macros[tok].flags) {
45995c635efSGarrett D'Amore 		assert( ! (MAN_SCOPED & man_macros[tok].flags));
460*698f87a4SGarrett D'Amore 		man->flags |= MAN_ILINE;
46195c635efSGarrett D'Amore 	}
46295c635efSGarrett D'Amore 
463*698f87a4SGarrett D'Amore 	assert(MAN_ROOT != man->last->type);
464*698f87a4SGarrett D'Amore 	man->next = MAN_NEXT_SIBLING;
46595c635efSGarrett D'Amore 
46695c635efSGarrett D'Amore 	/*
46795c635efSGarrett D'Amore 	 * Rewind our element scope.  Note that when TH is pruned, we'll
46895c635efSGarrett D'Amore 	 * be back at the root, so make sure that we don't clobber as
46995c635efSGarrett D'Amore 	 * its sibling.
47095c635efSGarrett D'Amore 	 */
47195c635efSGarrett D'Amore 
472*698f87a4SGarrett D'Amore 	for ( ; man->last; man->last = man->last->parent) {
473*698f87a4SGarrett D'Amore 		if (man->last == n)
47495c635efSGarrett D'Amore 			break;
475*698f87a4SGarrett D'Amore 		if (man->last->type == MAN_ROOT)
47695c635efSGarrett D'Amore 			break;
477*698f87a4SGarrett D'Amore 		if ( ! man_valid_post(man))
47895c635efSGarrett D'Amore 			return(0);
47995c635efSGarrett D'Amore 	}
48095c635efSGarrett D'Amore 
481*698f87a4SGarrett D'Amore 	assert(man->last);
48295c635efSGarrett D'Amore 
48395c635efSGarrett D'Amore 	/*
48495c635efSGarrett D'Amore 	 * Same here regarding whether we're back at the root.
48595c635efSGarrett D'Amore 	 */
48695c635efSGarrett D'Amore 
487*698f87a4SGarrett D'Amore 	if (man->last->type != MAN_ROOT && ! man_valid_post(man))
48895c635efSGarrett D'Amore 		return(0);
48995c635efSGarrett D'Amore 
49095c635efSGarrett D'Amore 	return(1);
49195c635efSGarrett D'Amore }
49295c635efSGarrett D'Amore 
49395c635efSGarrett D'Amore 
49495c635efSGarrett D'Amore int
man_macroend(struct man * man)495*698f87a4SGarrett D'Amore man_macroend(struct man *man)
49695c635efSGarrett D'Amore {
49795c635efSGarrett D'Amore 
498*698f87a4SGarrett D'Amore 	return(man_unscope(man, man->first, MANDOCERR_SCOPEEXIT));
49995c635efSGarrett D'Amore }
50095c635efSGarrett D'Amore 
50195c635efSGarrett D'Amore static int
man_args(struct man * man,int line,int * pos,char * buf,char ** v)502*698f87a4SGarrett D'Amore man_args(struct man *man, int line, int *pos, char *buf, char **v)
50395c635efSGarrett D'Amore {
50495c635efSGarrett D'Amore 	char	 *start;
50595c635efSGarrett D'Amore 
50695c635efSGarrett D'Amore 	assert(*pos);
50795c635efSGarrett D'Amore 	*v = start = buf + *pos;
50895c635efSGarrett D'Amore 	assert(' ' != *start);
50995c635efSGarrett D'Amore 
51095c635efSGarrett D'Amore 	if ('\0' == *start)
51195c635efSGarrett D'Amore 		return(0);
51295c635efSGarrett D'Amore 
513*698f87a4SGarrett D'Amore 	*v = mandoc_getarg(man->parse, v, line, pos);
51495c635efSGarrett D'Amore 	return(1);
51595c635efSGarrett D'Amore }
516