xref: /titanic_41/usr/src/cmd/mandoc/man_macro.c (revision ffb8ebfab4941f959e7caea93ecfb348cfa3515e)
1*ffb8ebfaSGarrett D'Amore /*	$Id: man_macro.c,v 1.79 2013/12/25 00:50:05 schwarze Exp $ */
232a712daSGarrett D'Amore /*
332a712daSGarrett D'Amore  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*ffb8ebfaSGarrett D'Amore  * Copyright (c) 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
5*ffb8ebfaSGarrett D'Amore  * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
632a712daSGarrett D'Amore  *
732a712daSGarrett D'Amore  * Permission to use, copy, modify, and distribute this software for any
832a712daSGarrett D'Amore  * purpose with or without fee is hereby granted, provided that the above
932a712daSGarrett D'Amore  * copyright notice and this permission notice appear in all copies.
1032a712daSGarrett D'Amore  *
1132a712daSGarrett D'Amore  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1232a712daSGarrett D'Amore  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1332a712daSGarrett D'Amore  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1432a712daSGarrett D'Amore  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1532a712daSGarrett D'Amore  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1632a712daSGarrett D'Amore  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1732a712daSGarrett D'Amore  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1832a712daSGarrett D'Amore  */
1932a712daSGarrett D'Amore #ifdef HAVE_CONFIG_H
2032a712daSGarrett D'Amore #include "config.h"
2132a712daSGarrett D'Amore #endif
2232a712daSGarrett D'Amore 
2332a712daSGarrett D'Amore #include <assert.h>
2432a712daSGarrett D'Amore #include <ctype.h>
2532a712daSGarrett D'Amore #include <stdlib.h>
2632a712daSGarrett D'Amore #include <string.h>
2732a712daSGarrett D'Amore 
2832a712daSGarrett D'Amore #include "man.h"
2932a712daSGarrett D'Amore #include "mandoc.h"
3032a712daSGarrett D'Amore #include "libmandoc.h"
3132a712daSGarrett D'Amore #include "libman.h"
3232a712daSGarrett D'Amore 
3332a712daSGarrett D'Amore enum	rew {
3432a712daSGarrett D'Amore 	REW_REWIND,
3532a712daSGarrett D'Amore 	REW_NOHALT,
3632a712daSGarrett D'Amore 	REW_HALT
3732a712daSGarrett D'Amore };
3832a712daSGarrett D'Amore 
3932a712daSGarrett D'Amore static	int		 blk_close(MACRO_PROT_ARGS);
4032a712daSGarrett D'Amore static	int		 blk_exp(MACRO_PROT_ARGS);
4132a712daSGarrett D'Amore static	int		 blk_imp(MACRO_PROT_ARGS);
4232a712daSGarrett D'Amore static	int		 in_line_eoln(MACRO_PROT_ARGS);
4332a712daSGarrett D'Amore static	int		 man_args(struct man *, int,
4432a712daSGarrett D'Amore 				int *, char *, char **);
4532a712daSGarrett D'Amore 
4632a712daSGarrett D'Amore static	int		 rew_scope(enum man_type,
4732a712daSGarrett D'Amore 				struct man *, enum mant);
4832a712daSGarrett D'Amore static	enum rew	 rew_dohalt(enum mant, enum man_type,
4932a712daSGarrett D'Amore 				const struct man_node *);
5032a712daSGarrett D'Amore static	enum rew	 rew_block(enum mant, enum man_type,
5132a712daSGarrett D'Amore 				const struct man_node *);
5232a712daSGarrett D'Amore static	void		 rew_warn(struct man *,
5332a712daSGarrett D'Amore 				struct man_node *, enum mandocerr);
5432a712daSGarrett D'Amore 
5532a712daSGarrett D'Amore const	struct man_macro __man_macros[MAN_MAX] = {
5632a712daSGarrett D'Amore 	{ in_line_eoln, MAN_NSCOPED }, /* br */
5732a712daSGarrett D'Amore 	{ in_line_eoln, MAN_BSCOPE }, /* TH */
5832a712daSGarrett D'Amore 	{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SH */
5932a712daSGarrett D'Amore 	{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SS */
6032a712daSGarrett D'Amore 	{ blk_imp, MAN_BSCOPE | MAN_SCOPED | MAN_FSCOPED }, /* TP */
6132a712daSGarrett D'Amore 	{ blk_imp, MAN_BSCOPE }, /* LP */
6232a712daSGarrett D'Amore 	{ blk_imp, MAN_BSCOPE }, /* PP */
6332a712daSGarrett D'Amore 	{ blk_imp, MAN_BSCOPE }, /* P */
6432a712daSGarrett D'Amore 	{ blk_imp, MAN_BSCOPE }, /* IP */
6532a712daSGarrett D'Amore 	{ blk_imp, MAN_BSCOPE }, /* HP */
6632a712daSGarrett D'Amore 	{ in_line_eoln, MAN_SCOPED }, /* SM */
6732a712daSGarrett D'Amore 	{ in_line_eoln, MAN_SCOPED }, /* SB */
6832a712daSGarrett D'Amore 	{ in_line_eoln, 0 }, /* BI */
6932a712daSGarrett D'Amore 	{ in_line_eoln, 0 }, /* IB */
7032a712daSGarrett D'Amore 	{ in_line_eoln, 0 }, /* BR */
7132a712daSGarrett D'Amore 	{ in_line_eoln, 0 }, /* RB */
7232a712daSGarrett D'Amore 	{ in_line_eoln, MAN_SCOPED }, /* R */
7332a712daSGarrett D'Amore 	{ in_line_eoln, MAN_SCOPED }, /* B */
7432a712daSGarrett D'Amore 	{ in_line_eoln, MAN_SCOPED }, /* I */
7532a712daSGarrett D'Amore 	{ in_line_eoln, 0 }, /* IR */
7632a712daSGarrett D'Amore 	{ in_line_eoln, 0 }, /* RI */
7732a712daSGarrett D'Amore 	{ in_line_eoln, MAN_NSCOPED }, /* na */
7832a712daSGarrett D'Amore 	{ in_line_eoln, MAN_NSCOPED }, /* sp */
7932a712daSGarrett D'Amore 	{ in_line_eoln, MAN_BSCOPE }, /* nf */
8032a712daSGarrett D'Amore 	{ in_line_eoln, MAN_BSCOPE }, /* fi */
8132a712daSGarrett D'Amore 	{ blk_close, 0 }, /* RE */
82*ffb8ebfaSGarrett D'Amore 	{ blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* RS */
8332a712daSGarrett D'Amore 	{ in_line_eoln, 0 }, /* DT */
8432a712daSGarrett D'Amore 	{ in_line_eoln, 0 }, /* UC */
8532a712daSGarrett D'Amore 	{ in_line_eoln, 0 }, /* PD */
8632a712daSGarrett D'Amore 	{ in_line_eoln, 0 }, /* AT */
8732a712daSGarrett D'Amore 	{ in_line_eoln, 0 }, /* in */
8832a712daSGarrett D'Amore 	{ in_line_eoln, 0 }, /* ft */
8932a712daSGarrett D'Amore 	{ in_line_eoln, 0 }, /* OP */
90*ffb8ebfaSGarrett D'Amore 	{ in_line_eoln, MAN_BSCOPE }, /* EX */
91*ffb8ebfaSGarrett D'Amore 	{ in_line_eoln, MAN_BSCOPE }, /* EE */
92*ffb8ebfaSGarrett D'Amore 	{ blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* UR */
93*ffb8ebfaSGarrett D'Amore 	{ blk_close, 0 }, /* UE */
9432a712daSGarrett D'Amore };
9532a712daSGarrett D'Amore 
9632a712daSGarrett D'Amore const	struct man_macro * const man_macros = __man_macros;
9732a712daSGarrett D'Amore 
9832a712daSGarrett D'Amore 
9932a712daSGarrett D'Amore /*
10032a712daSGarrett D'Amore  * Warn when "n" is an explicit non-roff macro.
10132a712daSGarrett D'Amore  */
10232a712daSGarrett D'Amore static void
rew_warn(struct man * man,struct man_node * n,enum mandocerr er)103*ffb8ebfaSGarrett D'Amore rew_warn(struct man *man, struct man_node *n, enum mandocerr er)
10432a712daSGarrett D'Amore {
10532a712daSGarrett D'Amore 
10632a712daSGarrett D'Amore 	if (er == MANDOCERR_MAX || MAN_BLOCK != n->type)
10732a712daSGarrett D'Amore 		return;
10832a712daSGarrett D'Amore 	if (MAN_VALID & n->flags)
10932a712daSGarrett D'Amore 		return;
11032a712daSGarrett D'Amore 	if ( ! (MAN_EXPLICIT & man_macros[n->tok].flags))
11132a712daSGarrett D'Amore 		return;
11232a712daSGarrett D'Amore 
11332a712daSGarrett D'Amore 	assert(er < MANDOCERR_FATAL);
114*ffb8ebfaSGarrett D'Amore 	man_nmsg(man, n, er);
11532a712daSGarrett D'Amore }
11632a712daSGarrett D'Amore 
11732a712daSGarrett D'Amore 
11832a712daSGarrett D'Amore /*
11932a712daSGarrett D'Amore  * Rewind scope.  If a code "er" != MANDOCERR_MAX has been provided, it
12032a712daSGarrett D'Amore  * will be used if an explicit block scope is being closed out.
12132a712daSGarrett D'Amore  */
12232a712daSGarrett D'Amore int
man_unscope(struct man * man,const struct man_node * to,enum mandocerr er)123*ffb8ebfaSGarrett D'Amore man_unscope(struct man *man, const struct man_node *to,
12432a712daSGarrett D'Amore 		enum mandocerr er)
12532a712daSGarrett D'Amore {
12632a712daSGarrett D'Amore 	struct man_node	*n;
12732a712daSGarrett D'Amore 
12832a712daSGarrett D'Amore 	assert(to);
12932a712daSGarrett D'Amore 
130*ffb8ebfaSGarrett D'Amore 	man->next = MAN_NEXT_SIBLING;
13132a712daSGarrett D'Amore 
13232a712daSGarrett D'Amore 	/* LINTED */
133*ffb8ebfaSGarrett D'Amore 	while (man->last != to) {
13432a712daSGarrett D'Amore 		/*
13532a712daSGarrett D'Amore 		 * Save the parent here, because we may delete the
136*ffb8ebfaSGarrett D'Amore 		 * man->last node in the post-validation phase and reset
137*ffb8ebfaSGarrett D'Amore 		 * it to man->last->parent, causing a step in the closing
13832a712daSGarrett D'Amore 		 * out to be lost.
13932a712daSGarrett D'Amore 		 */
140*ffb8ebfaSGarrett D'Amore 		n = man->last->parent;
141*ffb8ebfaSGarrett D'Amore 		rew_warn(man, man->last, er);
142*ffb8ebfaSGarrett D'Amore 		if ( ! man_valid_post(man))
14332a712daSGarrett D'Amore 			return(0);
144*ffb8ebfaSGarrett D'Amore 		man->last = n;
145*ffb8ebfaSGarrett D'Amore 		assert(man->last);
14632a712daSGarrett D'Amore 	}
14732a712daSGarrett D'Amore 
148*ffb8ebfaSGarrett D'Amore 	rew_warn(man, man->last, er);
149*ffb8ebfaSGarrett D'Amore 	if ( ! man_valid_post(man))
15032a712daSGarrett D'Amore 		return(0);
15132a712daSGarrett D'Amore 
15232a712daSGarrett D'Amore 	return(1);
15332a712daSGarrett D'Amore }
15432a712daSGarrett D'Amore 
15532a712daSGarrett D'Amore 
15632a712daSGarrett D'Amore static enum rew
rew_block(enum mant ntok,enum man_type type,const struct man_node * n)15732a712daSGarrett D'Amore rew_block(enum mant ntok, enum man_type type, const struct man_node *n)
15832a712daSGarrett D'Amore {
15932a712daSGarrett D'Amore 
16032a712daSGarrett D'Amore 	if (MAN_BLOCK == type && ntok == n->parent->tok &&
16132a712daSGarrett D'Amore 			MAN_BODY == n->parent->type)
16232a712daSGarrett D'Amore 		return(REW_REWIND);
16332a712daSGarrett D'Amore 	return(ntok == n->tok ? REW_HALT : REW_NOHALT);
16432a712daSGarrett D'Amore }
16532a712daSGarrett D'Amore 
16632a712daSGarrett D'Amore 
16732a712daSGarrett D'Amore /*
16832a712daSGarrett D'Amore  * There are three scope levels: scoped to the root (all), scoped to the
16932a712daSGarrett D'Amore  * section (all less sections), and scoped to subsections (all less
17032a712daSGarrett D'Amore  * sections and subsections).
17132a712daSGarrett D'Amore  */
17232a712daSGarrett D'Amore static enum rew
rew_dohalt(enum mant tok,enum man_type type,const struct man_node * n)17332a712daSGarrett D'Amore rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n)
17432a712daSGarrett D'Amore {
17532a712daSGarrett D'Amore 	enum rew	 c;
17632a712daSGarrett D'Amore 
17732a712daSGarrett D'Amore 	/* We cannot progress beyond the root ever. */
17832a712daSGarrett D'Amore 	if (MAN_ROOT == n->type)
17932a712daSGarrett D'Amore 		return(REW_HALT);
18032a712daSGarrett D'Amore 
18132a712daSGarrett D'Amore 	assert(n->parent);
18232a712daSGarrett D'Amore 
18332a712daSGarrett D'Amore 	/* Normal nodes shouldn't go to the level of the root. */
18432a712daSGarrett D'Amore 	if (MAN_ROOT == n->parent->type)
18532a712daSGarrett D'Amore 		return(REW_REWIND);
18632a712daSGarrett D'Amore 
18732a712daSGarrett D'Amore 	/* Already-validated nodes should be closed out. */
18832a712daSGarrett D'Amore 	if (MAN_VALID & n->flags)
18932a712daSGarrett D'Amore 		return(REW_NOHALT);
19032a712daSGarrett D'Amore 
19132a712daSGarrett D'Amore 	/* First: rewind to ourselves. */
192*ffb8ebfaSGarrett D'Amore 	if (type == n->type && tok == n->tok) {
193*ffb8ebfaSGarrett D'Amore 		if (MAN_EXPLICIT & man_macros[n->tok].flags)
194*ffb8ebfaSGarrett D'Amore 			return(REW_HALT);
195*ffb8ebfaSGarrett D'Amore 		else
19632a712daSGarrett D'Amore 			return(REW_REWIND);
197*ffb8ebfaSGarrett D'Amore 	}
19832a712daSGarrett D'Amore 
19932a712daSGarrett D'Amore 	/*
20032a712daSGarrett D'Amore 	 * Next follow the implicit scope-smashings as defined by man.7:
20132a712daSGarrett D'Amore 	 * section, sub-section, etc.
20232a712daSGarrett D'Amore 	 */
20332a712daSGarrett D'Amore 
20432a712daSGarrett D'Amore 	switch (tok) {
20532a712daSGarrett D'Amore 	case (MAN_SH):
20632a712daSGarrett D'Amore 		break;
20732a712daSGarrett D'Amore 	case (MAN_SS):
20832a712daSGarrett D'Amore 		/* Rewind to a section, if a block. */
20932a712daSGarrett D'Amore 		if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
21032a712daSGarrett D'Amore 			return(c);
21132a712daSGarrett D'Amore 		break;
21232a712daSGarrett D'Amore 	case (MAN_RS):
213*ffb8ebfaSGarrett D'Amore 		/* Preserve empty paragraphs before RS. */
214*ffb8ebfaSGarrett D'Amore 		if (0 == n->nchild && (MAN_P == n->tok ||
215*ffb8ebfaSGarrett D'Amore 		    MAN_PP == n->tok || MAN_LP == n->tok))
216*ffb8ebfaSGarrett D'Amore 			return(REW_HALT);
21732a712daSGarrett D'Amore 		/* Rewind to a subsection, if a block. */
21832a712daSGarrett D'Amore 		if (REW_NOHALT != (c = rew_block(MAN_SS, type, n)))
21932a712daSGarrett D'Amore 			return(c);
22032a712daSGarrett D'Amore 		/* Rewind to a section, if a block. */
22132a712daSGarrett D'Amore 		if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
22232a712daSGarrett D'Amore 			return(c);
22332a712daSGarrett D'Amore 		break;
22432a712daSGarrett D'Amore 	default:
22532a712daSGarrett D'Amore 		/* Rewind to an offsetter, if a block. */
22632a712daSGarrett D'Amore 		if (REW_NOHALT != (c = rew_block(MAN_RS, type, n)))
22732a712daSGarrett D'Amore 			return(c);
22832a712daSGarrett D'Amore 		/* Rewind to a subsection, if a block. */
22932a712daSGarrett D'Amore 		if (REW_NOHALT != (c = rew_block(MAN_SS, type, n)))
23032a712daSGarrett D'Amore 			return(c);
23132a712daSGarrett D'Amore 		/* Rewind to a section, if a block. */
23232a712daSGarrett D'Amore 		if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
23332a712daSGarrett D'Amore 			return(c);
23432a712daSGarrett D'Amore 		break;
23532a712daSGarrett D'Amore 	}
23632a712daSGarrett D'Amore 
23732a712daSGarrett D'Amore 	return(REW_NOHALT);
23832a712daSGarrett D'Amore }
23932a712daSGarrett D'Amore 
24032a712daSGarrett D'Amore 
24132a712daSGarrett D'Amore /*
24232a712daSGarrett D'Amore  * Rewinding entails ascending the parse tree until a coherent point,
24332a712daSGarrett D'Amore  * for example, the `SH' macro will close out any intervening `SS'
24432a712daSGarrett D'Amore  * scopes.  When a scope is closed, it must be validated and actioned.
24532a712daSGarrett D'Amore  */
24632a712daSGarrett D'Amore static int
rew_scope(enum man_type type,struct man * man,enum mant tok)247*ffb8ebfaSGarrett D'Amore rew_scope(enum man_type type, struct man *man, enum mant tok)
24832a712daSGarrett D'Amore {
24932a712daSGarrett D'Amore 	struct man_node	*n;
25032a712daSGarrett D'Amore 	enum rew	 c;
25132a712daSGarrett D'Amore 
25232a712daSGarrett D'Amore 	/* LINTED */
253*ffb8ebfaSGarrett D'Amore 	for (n = man->last; n; n = n->parent) {
25432a712daSGarrett D'Amore 		/*
25532a712daSGarrett D'Amore 		 * Whether we should stop immediately (REW_HALT), stop
25632a712daSGarrett D'Amore 		 * and rewind until this point (REW_REWIND), or keep
25732a712daSGarrett D'Amore 		 * rewinding (REW_NOHALT).
25832a712daSGarrett D'Amore 		 */
25932a712daSGarrett D'Amore 		c = rew_dohalt(tok, type, n);
26032a712daSGarrett D'Amore 		if (REW_HALT == c)
26132a712daSGarrett D'Amore 			return(1);
26232a712daSGarrett D'Amore 		if (REW_REWIND == c)
26332a712daSGarrett D'Amore 			break;
26432a712daSGarrett D'Amore 	}
26532a712daSGarrett D'Amore 
26632a712daSGarrett D'Amore 	/*
26732a712daSGarrett D'Amore 	 * Rewind until the current point.  Warn if we're a roff
26832a712daSGarrett D'Amore 	 * instruction that's mowing over explicit scopes.
26932a712daSGarrett D'Amore 	 */
27032a712daSGarrett D'Amore 	assert(n);
27132a712daSGarrett D'Amore 
272*ffb8ebfaSGarrett D'Amore 	return(man_unscope(man, n, MANDOCERR_MAX));
27332a712daSGarrett D'Amore }
27432a712daSGarrett D'Amore 
27532a712daSGarrett D'Amore 
27632a712daSGarrett D'Amore /*
27732a712daSGarrett D'Amore  * Close out a generic explicit macro.
27832a712daSGarrett D'Amore  */
27932a712daSGarrett D'Amore /* ARGSUSED */
28032a712daSGarrett D'Amore int
blk_close(MACRO_PROT_ARGS)28132a712daSGarrett D'Amore blk_close(MACRO_PROT_ARGS)
28232a712daSGarrett D'Amore {
28332a712daSGarrett D'Amore 	enum mant	 	 ntok;
28432a712daSGarrett D'Amore 	const struct man_node	*nn;
28532a712daSGarrett D'Amore 
28632a712daSGarrett D'Amore 	switch (tok) {
28732a712daSGarrett D'Amore 	case (MAN_RE):
28832a712daSGarrett D'Amore 		ntok = MAN_RS;
28932a712daSGarrett D'Amore 		break;
290*ffb8ebfaSGarrett D'Amore 	case (MAN_UE):
291*ffb8ebfaSGarrett D'Amore 		ntok = MAN_UR;
292*ffb8ebfaSGarrett D'Amore 		break;
29332a712daSGarrett D'Amore 	default:
29432a712daSGarrett D'Amore 		abort();
29532a712daSGarrett D'Amore 		/* NOTREACHED */
29632a712daSGarrett D'Amore 	}
29732a712daSGarrett D'Amore 
298*ffb8ebfaSGarrett D'Amore 	for (nn = man->last->parent; nn; nn = nn->parent)
299*ffb8ebfaSGarrett D'Amore 		if (ntok == nn->tok && MAN_BLOCK == nn->type)
30032a712daSGarrett D'Amore 			break;
30132a712daSGarrett D'Amore 
302*ffb8ebfaSGarrett D'Amore 	if (NULL == nn) {
303*ffb8ebfaSGarrett D'Amore 		man_pmsg(man, line, ppos, MANDOCERR_NOSCOPE);
304*ffb8ebfaSGarrett D'Amore 		if ( ! rew_scope(MAN_BLOCK, man, MAN_PP))
30532a712daSGarrett D'Amore 			return(0);
306*ffb8ebfaSGarrett D'Amore 	} else
307*ffb8ebfaSGarrett D'Amore 		man_unscope(man, nn, MANDOCERR_MAX);
30832a712daSGarrett D'Amore 
30932a712daSGarrett D'Amore 	return(1);
31032a712daSGarrett D'Amore }
31132a712daSGarrett D'Amore 
31232a712daSGarrett D'Amore 
31332a712daSGarrett D'Amore /* ARGSUSED */
31432a712daSGarrett D'Amore int
blk_exp(MACRO_PROT_ARGS)31532a712daSGarrett D'Amore blk_exp(MACRO_PROT_ARGS)
31632a712daSGarrett D'Amore {
317*ffb8ebfaSGarrett D'Amore 	struct man_node	*n;
31832a712daSGarrett D'Amore 	int		 la;
31932a712daSGarrett D'Amore 	char		*p;
32032a712daSGarrett D'Amore 
321*ffb8ebfaSGarrett D'Amore 	/* Close out prior implicit scopes. */
32232a712daSGarrett D'Amore 
323*ffb8ebfaSGarrett D'Amore 	if ( ! rew_scope(MAN_BLOCK, man, tok))
32432a712daSGarrett D'Amore 		return(0);
325*ffb8ebfaSGarrett D'Amore 
326*ffb8ebfaSGarrett D'Amore 	if ( ! man_block_alloc(man, line, ppos, tok))
327*ffb8ebfaSGarrett D'Amore 		return(0);
328*ffb8ebfaSGarrett D'Amore 	if ( ! man_head_alloc(man, line, ppos, tok))
32932a712daSGarrett D'Amore 		return(0);
33032a712daSGarrett D'Amore 
33132a712daSGarrett D'Amore 	for (;;) {
33232a712daSGarrett D'Amore 		la = *pos;
333*ffb8ebfaSGarrett D'Amore 		if ( ! man_args(man, line, pos, buf, &p))
33432a712daSGarrett D'Amore 			break;
335*ffb8ebfaSGarrett D'Amore 		if ( ! man_word_alloc(man, line, la, p))
33632a712daSGarrett D'Amore 			return(0);
33732a712daSGarrett D'Amore 	}
33832a712daSGarrett D'Amore 
339*ffb8ebfaSGarrett D'Amore 	assert(man);
34032a712daSGarrett D'Amore 	assert(tok != MAN_MAX);
34132a712daSGarrett D'Amore 
342*ffb8ebfaSGarrett D'Amore 	for (n = man->last; n; n = n->parent) {
343*ffb8ebfaSGarrett D'Amore 		if (n->tok != tok)
344*ffb8ebfaSGarrett D'Amore 			continue;
345*ffb8ebfaSGarrett D'Amore 		assert(MAN_HEAD == n->type);
346*ffb8ebfaSGarrett D'Amore 		man_unscope(man, n, MANDOCERR_MAX);
347*ffb8ebfaSGarrett D'Amore 		break;
348*ffb8ebfaSGarrett D'Amore 	}
349*ffb8ebfaSGarrett D'Amore 
350*ffb8ebfaSGarrett D'Amore 	return(man_body_alloc(man, line, ppos, tok));
35132a712daSGarrett D'Amore }
35232a712daSGarrett D'Amore 
35332a712daSGarrett D'Amore 
35432a712daSGarrett D'Amore 
35532a712daSGarrett D'Amore /*
35632a712daSGarrett D'Amore  * Parse an implicit-block macro.  These contain a MAN_HEAD and a
35732a712daSGarrett D'Amore  * MAN_BODY contained within a MAN_BLOCK.  Rules for closing out other
35832a712daSGarrett D'Amore  * scopes, such as `SH' closing out an `SS', are defined in the rew
35932a712daSGarrett D'Amore  * routines.
36032a712daSGarrett D'Amore  */
36132a712daSGarrett D'Amore /* ARGSUSED */
36232a712daSGarrett D'Amore int
blk_imp(MACRO_PROT_ARGS)36332a712daSGarrett D'Amore blk_imp(MACRO_PROT_ARGS)
36432a712daSGarrett D'Amore {
36532a712daSGarrett D'Amore 	int		 la;
36632a712daSGarrett D'Amore 	char		*p;
36732a712daSGarrett D'Amore 	struct man_node	*n;
36832a712daSGarrett D'Amore 
36932a712daSGarrett D'Amore 	/* Close out prior scopes. */
37032a712daSGarrett D'Amore 
371*ffb8ebfaSGarrett D'Amore 	if ( ! rew_scope(MAN_BODY, man, tok))
37232a712daSGarrett D'Amore 		return(0);
373*ffb8ebfaSGarrett D'Amore 	if ( ! rew_scope(MAN_BLOCK, man, tok))
37432a712daSGarrett D'Amore 		return(0);
37532a712daSGarrett D'Amore 
37632a712daSGarrett D'Amore 	/* Allocate new block & head scope. */
37732a712daSGarrett D'Amore 
378*ffb8ebfaSGarrett D'Amore 	if ( ! man_block_alloc(man, line, ppos, tok))
37932a712daSGarrett D'Amore 		return(0);
380*ffb8ebfaSGarrett D'Amore 	if ( ! man_head_alloc(man, line, ppos, tok))
38132a712daSGarrett D'Amore 		return(0);
38232a712daSGarrett D'Amore 
383*ffb8ebfaSGarrett D'Amore 	n = man->last;
38432a712daSGarrett D'Amore 
38532a712daSGarrett D'Amore 	/* Add line arguments. */
38632a712daSGarrett D'Amore 
38732a712daSGarrett D'Amore 	for (;;) {
38832a712daSGarrett D'Amore 		la = *pos;
389*ffb8ebfaSGarrett D'Amore 		if ( ! man_args(man, line, pos, buf, &p))
39032a712daSGarrett D'Amore 			break;
391*ffb8ebfaSGarrett D'Amore 		if ( ! man_word_alloc(man, line, la, p))
39232a712daSGarrett D'Amore 			return(0);
39332a712daSGarrett D'Amore 	}
39432a712daSGarrett D'Amore 
39532a712daSGarrett D'Amore 	/* Close out head and open body (unless MAN_SCOPE). */
39632a712daSGarrett D'Amore 
39732a712daSGarrett D'Amore 	if (MAN_SCOPED & man_macros[tok].flags) {
39832a712daSGarrett D'Amore 		/* If we're forcing scope (`TP'), keep it open. */
39932a712daSGarrett D'Amore 		if (MAN_FSCOPED & man_macros[tok].flags) {
400*ffb8ebfaSGarrett D'Amore 			man->flags |= MAN_BLINE;
40132a712daSGarrett D'Amore 			return(1);
402*ffb8ebfaSGarrett D'Amore 		} else if (n == man->last) {
403*ffb8ebfaSGarrett D'Amore 			man->flags |= MAN_BLINE;
40432a712daSGarrett D'Amore 			return(1);
40532a712daSGarrett D'Amore 		}
40632a712daSGarrett D'Amore 	}
40732a712daSGarrett D'Amore 
408*ffb8ebfaSGarrett D'Amore 	if ( ! rew_scope(MAN_HEAD, man, tok))
40932a712daSGarrett D'Amore 		return(0);
410*ffb8ebfaSGarrett D'Amore 	return(man_body_alloc(man, line, ppos, tok));
41132a712daSGarrett D'Amore }
41232a712daSGarrett D'Amore 
41332a712daSGarrett D'Amore 
41432a712daSGarrett D'Amore /* ARGSUSED */
41532a712daSGarrett D'Amore int
in_line_eoln(MACRO_PROT_ARGS)41632a712daSGarrett D'Amore in_line_eoln(MACRO_PROT_ARGS)
41732a712daSGarrett D'Amore {
41832a712daSGarrett D'Amore 	int		 la;
41932a712daSGarrett D'Amore 	char		*p;
42032a712daSGarrett D'Amore 	struct man_node	*n;
42132a712daSGarrett D'Amore 
422*ffb8ebfaSGarrett D'Amore 	if ( ! man_elem_alloc(man, line, ppos, tok))
42332a712daSGarrett D'Amore 		return(0);
42432a712daSGarrett D'Amore 
425*ffb8ebfaSGarrett D'Amore 	n = man->last;
42632a712daSGarrett D'Amore 
42732a712daSGarrett D'Amore 	for (;;) {
42832a712daSGarrett D'Amore 		la = *pos;
429*ffb8ebfaSGarrett D'Amore 		if ( ! man_args(man, line, pos, buf, &p))
43032a712daSGarrett D'Amore 			break;
431*ffb8ebfaSGarrett D'Amore 		if ( ! man_word_alloc(man, line, la, p))
43232a712daSGarrett D'Amore 			return(0);
43332a712daSGarrett D'Amore 	}
43432a712daSGarrett D'Amore 
43532a712daSGarrett D'Amore 	/*
436*ffb8ebfaSGarrett D'Amore 	 * Append MAN_EOS in case the last snipped argument
437*ffb8ebfaSGarrett D'Amore 	 * ends with a dot, e.g. `.IR syslog (3).'
438*ffb8ebfaSGarrett D'Amore 	 */
439*ffb8ebfaSGarrett D'Amore 
440*ffb8ebfaSGarrett D'Amore 	if (n != man->last &&
441*ffb8ebfaSGarrett D'Amore 	    mandoc_eos(man->last->string, strlen(man->last->string), 0))
442*ffb8ebfaSGarrett D'Amore 		man->last->flags |= MAN_EOS;
443*ffb8ebfaSGarrett D'Amore 
444*ffb8ebfaSGarrett D'Amore 	/*
44532a712daSGarrett D'Amore 	 * If no arguments are specified and this is MAN_SCOPED (i.e.,
44632a712daSGarrett D'Amore 	 * next-line scoped), then set our mode to indicate that we're
44732a712daSGarrett D'Amore 	 * waiting for terms to load into our context.
44832a712daSGarrett D'Amore 	 */
44932a712daSGarrett D'Amore 
450*ffb8ebfaSGarrett D'Amore 	if (n == man->last && MAN_SCOPED & man_macros[tok].flags) {
45132a712daSGarrett D'Amore 		assert( ! (MAN_NSCOPED & man_macros[tok].flags));
452*ffb8ebfaSGarrett D'Amore 		man->flags |= MAN_ELINE;
45332a712daSGarrett D'Amore 		return(1);
45432a712daSGarrett D'Amore 	}
45532a712daSGarrett D'Amore 
45632a712daSGarrett D'Amore 	/* Set ignorable context, if applicable. */
45732a712daSGarrett D'Amore 
45832a712daSGarrett D'Amore 	if (MAN_NSCOPED & man_macros[tok].flags) {
45932a712daSGarrett D'Amore 		assert( ! (MAN_SCOPED & man_macros[tok].flags));
460*ffb8ebfaSGarrett D'Amore 		man->flags |= MAN_ILINE;
46132a712daSGarrett D'Amore 	}
46232a712daSGarrett D'Amore 
463*ffb8ebfaSGarrett D'Amore 	assert(MAN_ROOT != man->last->type);
464*ffb8ebfaSGarrett D'Amore 	man->next = MAN_NEXT_SIBLING;
46532a712daSGarrett D'Amore 
46632a712daSGarrett D'Amore 	/*
46732a712daSGarrett D'Amore 	 * Rewind our element scope.  Note that when TH is pruned, we'll
46832a712daSGarrett D'Amore 	 * be back at the root, so make sure that we don't clobber as
46932a712daSGarrett D'Amore 	 * its sibling.
47032a712daSGarrett D'Amore 	 */
47132a712daSGarrett D'Amore 
472*ffb8ebfaSGarrett D'Amore 	for ( ; man->last; man->last = man->last->parent) {
473*ffb8ebfaSGarrett D'Amore 		if (man->last == n)
47432a712daSGarrett D'Amore 			break;
475*ffb8ebfaSGarrett D'Amore 		if (man->last->type == MAN_ROOT)
47632a712daSGarrett D'Amore 			break;
477*ffb8ebfaSGarrett D'Amore 		if ( ! man_valid_post(man))
47832a712daSGarrett D'Amore 			return(0);
47932a712daSGarrett D'Amore 	}
48032a712daSGarrett D'Amore 
481*ffb8ebfaSGarrett D'Amore 	assert(man->last);
48232a712daSGarrett D'Amore 
48332a712daSGarrett D'Amore 	/*
48432a712daSGarrett D'Amore 	 * Same here regarding whether we're back at the root.
48532a712daSGarrett D'Amore 	 */
48632a712daSGarrett D'Amore 
487*ffb8ebfaSGarrett D'Amore 	if (man->last->type != MAN_ROOT && ! man_valid_post(man))
48832a712daSGarrett D'Amore 		return(0);
48932a712daSGarrett D'Amore 
49032a712daSGarrett D'Amore 	return(1);
49132a712daSGarrett D'Amore }
49232a712daSGarrett D'Amore 
49332a712daSGarrett D'Amore 
49432a712daSGarrett D'Amore int
man_macroend(struct man * man)495*ffb8ebfaSGarrett D'Amore man_macroend(struct man *man)
49632a712daSGarrett D'Amore {
49732a712daSGarrett D'Amore 
498*ffb8ebfaSGarrett D'Amore 	return(man_unscope(man, man->first, MANDOCERR_SCOPEEXIT));
49932a712daSGarrett D'Amore }
50032a712daSGarrett D'Amore 
50132a712daSGarrett D'Amore static int
man_args(struct man * man,int line,int * pos,char * buf,char ** v)502*ffb8ebfaSGarrett D'Amore man_args(struct man *man, int line, int *pos, char *buf, char **v)
50332a712daSGarrett D'Amore {
50432a712daSGarrett D'Amore 	char	 *start;
50532a712daSGarrett D'Amore 
50632a712daSGarrett D'Amore 	assert(*pos);
50732a712daSGarrett D'Amore 	*v = start = buf + *pos;
50832a712daSGarrett D'Amore 	assert(' ' != *start);
50932a712daSGarrett D'Amore 
51032a712daSGarrett D'Amore 	if ('\0' == *start)
51132a712daSGarrett D'Amore 		return(0);
51232a712daSGarrett D'Amore 
513*ffb8ebfaSGarrett D'Amore 	*v = mandoc_getarg(man->parse, v, line, pos);
51432a712daSGarrett D'Amore 	return(1);
51532a712daSGarrett D'Amore }
516