1241675Suqs/*	$Id: mdoc_macro.c,v 1.115 2012/01/05 00:43:51 schwarze Exp $ */
2241675Suqs/*
3241675Suqs * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4241675Suqs * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org>
5241675Suqs *
6241675Suqs * Permission to use, copy, modify, and distribute this software for any
7241675Suqs * purpose with or without fee is hereby granted, provided that the above
8241675Suqs * copyright notice and this permission notice appear in all copies.
9241675Suqs *
10241675Suqs * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11241675Suqs * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12241675Suqs * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13241675Suqs * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14241675Suqs * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15241675Suqs * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16241675Suqs * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17241675Suqs */
18241675Suqs#ifdef HAVE_CONFIG_H
19241675Suqs#include "config.h"
20241675Suqs#endif
21241675Suqs
22241675Suqs#include <assert.h>
23241675Suqs#include <ctype.h>
24241675Suqs#include <stdlib.h>
25241675Suqs#include <stdio.h>
26241675Suqs#include <string.h>
27241675Suqs#include <time.h>
28241675Suqs
29241675Suqs#include "mdoc.h"
30241675Suqs#include "mandoc.h"
31241675Suqs#include "libmdoc.h"
32241675Suqs#include "libmandoc.h"
33241675Suqs
34241675Suqsenum	rew {	/* see rew_dohalt() */
35241675Suqs	REWIND_NONE,
36241675Suqs	REWIND_THIS,
37241675Suqs	REWIND_MORE,
38241675Suqs	REWIND_FORCE,
39241675Suqs	REWIND_LATER,
40241675Suqs	REWIND_ERROR
41241675Suqs};
42241675Suqs
43241675Suqsstatic	int	  	blk_full(MACRO_PROT_ARGS);
44241675Suqsstatic	int	  	blk_exp_close(MACRO_PROT_ARGS);
45241675Suqsstatic	int	  	blk_part_exp(MACRO_PROT_ARGS);
46241675Suqsstatic	int	  	blk_part_imp(MACRO_PROT_ARGS);
47241675Suqsstatic	int	  	ctx_synopsis(MACRO_PROT_ARGS);
48241675Suqsstatic	int	  	in_line_eoln(MACRO_PROT_ARGS);
49241675Suqsstatic	int	  	in_line_argn(MACRO_PROT_ARGS);
50241675Suqsstatic	int	  	in_line(MACRO_PROT_ARGS);
51241675Suqsstatic	int	  	obsolete(MACRO_PROT_ARGS);
52241675Suqsstatic	int	  	phrase_ta(MACRO_PROT_ARGS);
53241675Suqs
54241675Suqsstatic	int		dword(struct mdoc *, int, int,
55241675Suqs				const char *, enum mdelim);
56241675Suqsstatic	int	  	append_delims(struct mdoc *,
57241675Suqs				int, int *, char *);
58241675Suqsstatic	enum mdoct	lookup(enum mdoct, const char *);
59241675Suqsstatic	enum mdoct	lookup_raw(const char *);
60241675Suqsstatic	int		make_pending(struct mdoc_node *, enum mdoct,
61241675Suqs				struct mdoc *, int, int);
62241675Suqsstatic	int	  	phrase(struct mdoc *, int, int, char *);
63241675Suqsstatic	enum mdoct 	rew_alt(enum mdoct);
64241675Suqsstatic	enum rew  	rew_dohalt(enum mdoct, enum mdoc_type,
65241675Suqs				const struct mdoc_node *);
66241675Suqsstatic	int	  	rew_elem(struct mdoc *, enum mdoct);
67241675Suqsstatic	int	  	rew_last(struct mdoc *,
68241675Suqs				const struct mdoc_node *);
69241675Suqsstatic	int	  	rew_sub(enum mdoc_type, struct mdoc *,
70241675Suqs				enum mdoct, int, int);
71241675Suqs
72241675Suqsconst	struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
73241675Suqs	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ap */
74241675Suqs	{ in_line_eoln, MDOC_PROLOGUE }, /* Dd */
75241675Suqs	{ in_line_eoln, MDOC_PROLOGUE }, /* Dt */
76241675Suqs	{ in_line_eoln, MDOC_PROLOGUE }, /* Os */
77241675Suqs	{ blk_full, MDOC_PARSED }, /* Sh */
78241675Suqs	{ blk_full, MDOC_PARSED }, /* Ss */
79241675Suqs	{ in_line_eoln, 0 }, /* Pp */
80241675Suqs	{ blk_part_imp, MDOC_PARSED }, /* D1 */
81241675Suqs	{ blk_part_imp, MDOC_PARSED }, /* Dl */
82241675Suqs	{ blk_full, MDOC_EXPLICIT }, /* Bd */
83241675Suqs	{ blk_exp_close, MDOC_EXPLICIT }, /* Ed */
84241675Suqs	{ blk_full, MDOC_EXPLICIT }, /* Bl */
85241675Suqs	{ blk_exp_close, MDOC_EXPLICIT }, /* El */
86241675Suqs	{ blk_full, MDOC_PARSED }, /* It */
87241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */
88241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* An */
89241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */
90241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cd */
91241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */
92241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */
93241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Er */
94241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */
95241675Suqs	{ in_line_eoln, 0 }, /* Ex */
96241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */
97241675Suqs	{ in_line_eoln, 0 }, /* Fd */
98241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */
99241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */
100241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ft */
101241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */
102241675Suqs	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* In */
103241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Li */
104241675Suqs	{ blk_full, 0 }, /* Nd */
105241675Suqs	{ ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */
106241675Suqs	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Op */
107241675Suqs	{ obsolete, 0 }, /* Ot */
108241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */
109241675Suqs	{ in_line_eoln, 0 }, /* Rv */
110241675Suqs	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */
111241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Va */
112241675Suqs	{ ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */
113241675Suqs	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */
114241675Suqs	{ in_line_eoln, 0 }, /* %A */
115241675Suqs	{ in_line_eoln, 0 }, /* %B */
116241675Suqs	{ in_line_eoln, 0 }, /* %D */
117241675Suqs	{ in_line_eoln, 0 }, /* %I */
118241675Suqs	{ in_line_eoln, 0 }, /* %J */
119241675Suqs	{ in_line_eoln, 0 }, /* %N */
120241675Suqs	{ in_line_eoln, 0 }, /* %O */
121241675Suqs	{ in_line_eoln, 0 }, /* %P */
122241675Suqs	{ in_line_eoln, 0 }, /* %R */
123241675Suqs	{ in_line_eoln, 0 }, /* %T */
124241675Suqs	{ in_line_eoln, 0 }, /* %V */
125241675Suqs	{ blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ac */
126241675Suqs	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ao */
127241675Suqs	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Aq */
128241675Suqs	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* At */
129241675Suqs	{ blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Bc */
130241675Suqs	{ blk_full, MDOC_EXPLICIT }, /* Bf */
131241675Suqs	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bo */
132241675Suqs	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Bq */
133241675Suqs	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bsx */
134241675Suqs	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bx */
135241675Suqs	{ in_line_eoln, 0 }, /* Db */
136241675Suqs	{ blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Dc */
137241675Suqs	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Do */
138241675Suqs	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Dq */
139241675Suqs	{ blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ec */
140241675Suqs	{ blk_exp_close, MDOC_EXPLICIT }, /* Ef */
141241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Em */
142241675Suqs	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */
143241675Suqs	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Fx */
144241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ms */
145241675Suqs	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* No */
146241675Suqs	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* Ns */
147241675Suqs	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Nx */
148241675Suqs	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ox */
149241675Suqs	{ blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Pc */
150241675Suqs	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* Pf */
151241675Suqs	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Po */
152241675Suqs	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Pq */
153241675Suqs	{ blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Qc */
154241675Suqs	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Ql */
155241675Suqs	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Qo */
156241675Suqs	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Qq */
157241675Suqs	{ blk_exp_close, MDOC_EXPLICIT }, /* Re */
158241675Suqs	{ blk_full, MDOC_EXPLICIT }, /* Rs */
159241675Suqs	{ blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Sc */
160241675Suqs	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* So */
161241675Suqs	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Sq */
162241675Suqs	{ in_line_eoln, 0 }, /* Sm */
163241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sx */
164241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sy */
165241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */
166241675Suqs	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ux */
167241675Suqs	{ blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Xc */
168241675Suqs	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Xo */
169241675Suqs	{ blk_full, MDOC_EXPLICIT | MDOC_CALLABLE }, /* Fo */
170241675Suqs	{ blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Fc */
171241675Suqs	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Oo */
172241675Suqs	{ blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Oc */
173241675Suqs	{ blk_full, MDOC_EXPLICIT }, /* Bk */
174241675Suqs	{ blk_exp_close, MDOC_EXPLICIT }, /* Ek */
175241675Suqs	{ in_line_eoln, 0 }, /* Bt */
176241675Suqs	{ in_line_eoln, 0 }, /* Hf */
177241675Suqs	{ obsolete, 0 }, /* Fr */
178241675Suqs	{ in_line_eoln, 0 }, /* Ud */
179241675Suqs	{ in_line, 0 }, /* Lb */
180241675Suqs	{ in_line_eoln, 0 }, /* Lp */
181241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lk */
182241675Suqs	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Mt */
183241675Suqs	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Brq */
184241675Suqs	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bro */
185241675Suqs	{ blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Brc */
186241675Suqs	{ in_line_eoln, 0 }, /* %C */
187241675Suqs	{ obsolete, 0 }, /* Es */
188241675Suqs	{ obsolete, 0 }, /* En */
189241675Suqs	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */
190241675Suqs	{ in_line_eoln, 0 }, /* %Q */
191241675Suqs	{ in_line_eoln, 0 }, /* br */
192241675Suqs	{ in_line_eoln, 0 }, /* sp */
193241675Suqs	{ in_line_eoln, 0 }, /* %U */
194241675Suqs	{ phrase_ta, MDOC_CALLABLE | MDOC_PARSED }, /* Ta */
195241675Suqs};
196241675Suqs
197241675Suqsconst	struct mdoc_macro * const mdoc_macros = __mdoc_macros;
198241675Suqs
199241675Suqs
200241675Suqs/*
201241675Suqs * This is called at the end of parsing.  It must traverse up the tree,
202241675Suqs * closing out open [implicit] scopes.  Obviously, open explicit scopes
203241675Suqs * are errors.
204241675Suqs */
205241675Suqsint
206241675Suqsmdoc_macroend(struct mdoc *m)
207241675Suqs{
208241675Suqs	struct mdoc_node *n;
209241675Suqs
210241675Suqs	/* Scan for open explicit scopes. */
211241675Suqs
212241675Suqs	n = MDOC_VALID & m->last->flags ?  m->last->parent : m->last;
213241675Suqs
214241675Suqs	for ( ; n; n = n->parent)
215241675Suqs		if (MDOC_BLOCK == n->type &&
216241675Suqs		    MDOC_EXPLICIT & mdoc_macros[n->tok].flags)
217241675Suqs			mdoc_nmsg(m, n, MANDOCERR_SCOPEEXIT);
218241675Suqs
219241675Suqs	/* Rewind to the first. */
220241675Suqs
221241675Suqs	return(rew_last(m, m->first));
222241675Suqs}
223241675Suqs
224241675Suqs
225241675Suqs/*
226241675Suqs * Look up a macro from within a subsequent context.
227241675Suqs */
228241675Suqsstatic enum mdoct
229241675Suqslookup(enum mdoct from, const char *p)
230241675Suqs{
231241675Suqs
232241675Suqs	if ( ! (MDOC_PARSED & mdoc_macros[from].flags))
233241675Suqs		return(MDOC_MAX);
234241675Suqs	return(lookup_raw(p));
235241675Suqs}
236241675Suqs
237241675Suqs
238241675Suqs/*
239241675Suqs * Lookup a macro following the initial line macro.
240241675Suqs */
241241675Suqsstatic enum mdoct
242241675Suqslookup_raw(const char *p)
243241675Suqs{
244241675Suqs	enum mdoct	 res;
245241675Suqs
246241675Suqs	if (MDOC_MAX == (res = mdoc_hash_find(p)))
247241675Suqs		return(MDOC_MAX);
248241675Suqs	if (MDOC_CALLABLE & mdoc_macros[res].flags)
249241675Suqs		return(res);
250241675Suqs	return(MDOC_MAX);
251241675Suqs}
252241675Suqs
253241675Suqs
254241675Suqsstatic int
255241675Suqsrew_last(struct mdoc *mdoc, const struct mdoc_node *to)
256241675Suqs{
257241675Suqs	struct mdoc_node *n, *np;
258241675Suqs
259241675Suqs	assert(to);
260241675Suqs	mdoc->next = MDOC_NEXT_SIBLING;
261241675Suqs
262241675Suqs	/* LINTED */
263241675Suqs	while (mdoc->last != to) {
264241675Suqs		/*
265241675Suqs		 * Save the parent here, because we may delete the
266241675Suqs		 * m->last node in the post-validation phase and reset
267241675Suqs		 * it to m->last->parent, causing a step in the closing
268241675Suqs		 * out to be lost.
269241675Suqs		 */
270241675Suqs		np = mdoc->last->parent;
271241675Suqs		if ( ! mdoc_valid_post(mdoc))
272241675Suqs			return(0);
273241675Suqs		n = mdoc->last;
274241675Suqs		mdoc->last = np;
275241675Suqs		assert(mdoc->last);
276241675Suqs		mdoc->last->last = n;
277241675Suqs	}
278241675Suqs
279241675Suqs	return(mdoc_valid_post(mdoc));
280241675Suqs}
281241675Suqs
282241675Suqs
283241675Suqs/*
284241675Suqs * For a block closing macro, return the corresponding opening one.
285241675Suqs * Otherwise, return the macro itself.
286241675Suqs */
287241675Suqsstatic enum mdoct
288241675Suqsrew_alt(enum mdoct tok)
289241675Suqs{
290241675Suqs	switch (tok) {
291241675Suqs	case (MDOC_Ac):
292241675Suqs		return(MDOC_Ao);
293241675Suqs	case (MDOC_Bc):
294241675Suqs		return(MDOC_Bo);
295241675Suqs	case (MDOC_Brc):
296241675Suqs		return(MDOC_Bro);
297241675Suqs	case (MDOC_Dc):
298241675Suqs		return(MDOC_Do);
299241675Suqs	case (MDOC_Ec):
300241675Suqs		return(MDOC_Eo);
301241675Suqs	case (MDOC_Ed):
302241675Suqs		return(MDOC_Bd);
303241675Suqs	case (MDOC_Ef):
304241675Suqs		return(MDOC_Bf);
305241675Suqs	case (MDOC_Ek):
306241675Suqs		return(MDOC_Bk);
307241675Suqs	case (MDOC_El):
308241675Suqs		return(MDOC_Bl);
309241675Suqs	case (MDOC_Fc):
310241675Suqs		return(MDOC_Fo);
311241675Suqs	case (MDOC_Oc):
312241675Suqs		return(MDOC_Oo);
313241675Suqs	case (MDOC_Pc):
314241675Suqs		return(MDOC_Po);
315241675Suqs	case (MDOC_Qc):
316241675Suqs		return(MDOC_Qo);
317241675Suqs	case (MDOC_Re):
318241675Suqs		return(MDOC_Rs);
319241675Suqs	case (MDOC_Sc):
320241675Suqs		return(MDOC_So);
321241675Suqs	case (MDOC_Xc):
322241675Suqs		return(MDOC_Xo);
323241675Suqs	default:
324241675Suqs		return(tok);
325241675Suqs	}
326241675Suqs	/* NOTREACHED */
327241675Suqs}
328241675Suqs
329241675Suqs
330241675Suqs/*
331241675Suqs * Rewinding to tok, how do we have to handle *p?
332241675Suqs * REWIND_NONE: *p would delimit tok, but no tok scope is open
333241675Suqs *   inside *p, so there is no need to rewind anything at all.
334241675Suqs * REWIND_THIS: *p matches tok, so rewind *p and nothing else.
335241675Suqs * REWIND_MORE: *p is implicit, rewind it and keep searching for tok.
336241675Suqs * REWIND_FORCE: *p is explicit, but tok is full, force rewinding *p.
337241675Suqs * REWIND_LATER: *p is explicit and still open, postpone rewinding.
338241675Suqs * REWIND_ERROR: No tok block is open at all.
339241675Suqs */
340241675Suqsstatic enum rew
341241675Suqsrew_dohalt(enum mdoct tok, enum mdoc_type type,
342241675Suqs		const struct mdoc_node *p)
343241675Suqs{
344241675Suqs
345241675Suqs	/*
346241675Suqs	 * No matching token, no delimiting block, no broken block.
347241675Suqs	 * This can happen when full implicit macros are called for
348241675Suqs	 * the first time but try to rewind their previous
349241675Suqs	 * instance anyway.
350241675Suqs	 */
351241675Suqs	if (MDOC_ROOT == p->type)
352241675Suqs		return(MDOC_BLOCK == type &&
353241675Suqs		    MDOC_EXPLICIT & mdoc_macros[tok].flags ?
354241675Suqs		    REWIND_ERROR : REWIND_NONE);
355241675Suqs
356241675Suqs	/*
357241675Suqs	 * When starting to rewind, skip plain text
358241675Suqs	 * and nodes that have already been rewound.
359241675Suqs	 */
360241675Suqs	if (MDOC_TEXT == p->type || MDOC_VALID & p->flags)
361241675Suqs		return(REWIND_MORE);
362241675Suqs
363241675Suqs	/*
364241675Suqs	 * The easiest case:  Found a matching token.
365241675Suqs	 * This applies to both blocks and elements.
366241675Suqs	 */
367241675Suqs	tok = rew_alt(tok);
368241675Suqs	if (tok == p->tok)
369241675Suqs		return(p->end ? REWIND_NONE :
370241675Suqs		    type == p->type ? REWIND_THIS : REWIND_MORE);
371241675Suqs
372241675Suqs	/*
373241675Suqs	 * While elements do require rewinding for themselves,
374241675Suqs	 * they never affect rewinding of other nodes.
375241675Suqs	 */
376241675Suqs	if (MDOC_ELEM == p->type)
377241675Suqs		return(REWIND_MORE);
378241675Suqs
379241675Suqs	/*
380241675Suqs	 * Blocks delimited by our target token get REWIND_MORE.
381241675Suqs	 * Blocks delimiting our target token get REWIND_NONE.
382241675Suqs	 */
383241675Suqs	switch (tok) {
384241675Suqs	case (MDOC_Bl):
385241675Suqs		if (MDOC_It == p->tok)
386241675Suqs			return(REWIND_MORE);
387241675Suqs		break;
388241675Suqs	case (MDOC_It):
389241675Suqs		if (MDOC_BODY == p->type && MDOC_Bl == p->tok)
390241675Suqs			return(REWIND_NONE);
391241675Suqs		break;
392241675Suqs	/*
393241675Suqs	 * XXX Badly nested block handling still fails badly
394241675Suqs	 * when one block is breaking two blocks of the same type.
395241675Suqs	 * This is an incomplete and extremely ugly workaround,
396241675Suqs	 * required to let the OpenBSD tree build.
397241675Suqs	 */
398241675Suqs	case (MDOC_Oo):
399241675Suqs		if (MDOC_Op == p->tok)
400241675Suqs			return(REWIND_MORE);
401241675Suqs		break;
402241675Suqs	case (MDOC_Nm):
403241675Suqs		return(REWIND_NONE);
404241675Suqs	case (MDOC_Nd):
405241675Suqs		/* FALLTHROUGH */
406241675Suqs	case (MDOC_Ss):
407241675Suqs		if (MDOC_BODY == p->type && MDOC_Sh == p->tok)
408241675Suqs			return(REWIND_NONE);
409241675Suqs		/* FALLTHROUGH */
410241675Suqs	case (MDOC_Sh):
411241675Suqs		if (MDOC_Nd == p->tok || MDOC_Ss == p->tok ||
412241675Suqs		    MDOC_Sh == p->tok)
413241675Suqs			return(REWIND_MORE);
414241675Suqs		break;
415241675Suqs	default:
416241675Suqs		break;
417241675Suqs	}
418241675Suqs
419241675Suqs	/*
420241675Suqs	 * Default block rewinding rules.
421241675Suqs	 * In particular, always skip block end markers,
422241675Suqs	 * and let all blocks rewind Nm children.
423241675Suqs	 */
424241675Suqs	if (ENDBODY_NOT != p->end || MDOC_Nm == p->tok ||
425241675Suqs	    (MDOC_BLOCK == p->type &&
426241675Suqs	    ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)))
427241675Suqs		return(REWIND_MORE);
428241675Suqs
429241675Suqs	/*
430241675Suqs	 * By default, closing out full blocks
431241675Suqs	 * forces closing of broken explicit blocks,
432241675Suqs	 * while closing out partial blocks
433241675Suqs	 * allows delayed rewinding by default.
434241675Suqs	 */
435241675Suqs	return (&blk_full == mdoc_macros[tok].fp ?
436241675Suqs	    REWIND_FORCE : REWIND_LATER);
437241675Suqs}
438241675Suqs
439241675Suqs
440241675Suqsstatic int
441241675Suqsrew_elem(struct mdoc *mdoc, enum mdoct tok)
442241675Suqs{
443241675Suqs	struct mdoc_node *n;
444241675Suqs
445241675Suqs	n = mdoc->last;
446241675Suqs	if (MDOC_ELEM != n->type)
447241675Suqs		n = n->parent;
448241675Suqs	assert(MDOC_ELEM == n->type);
449241675Suqs	assert(tok == n->tok);
450241675Suqs
451241675Suqs	return(rew_last(mdoc, n));
452241675Suqs}
453241675Suqs
454241675Suqs
455241675Suqs/*
456241675Suqs * We are trying to close a block identified by tok,
457241675Suqs * but the child block *broken is still open.
458241675Suqs * Thus, postpone closing the tok block
459241675Suqs * until the rew_sub call closing *broken.
460241675Suqs */
461241675Suqsstatic int
462241675Suqsmake_pending(struct mdoc_node *broken, enum mdoct tok,
463241675Suqs		struct mdoc *m, int line, int ppos)
464241675Suqs{
465241675Suqs	struct mdoc_node *breaker;
466241675Suqs
467241675Suqs	/*
468241675Suqs	 * Iterate backwards, searching for the block matching tok,
469241675Suqs	 * that is, the block breaking the *broken block.
470241675Suqs	 */
471241675Suqs	for (breaker = broken->parent; breaker; breaker = breaker->parent) {
472241675Suqs
473241675Suqs		/*
474241675Suqs		 * If the *broken block had already been broken before
475241675Suqs		 * and we encounter its breaker, make the tok block
476241675Suqs		 * pending on the inner breaker.
477241675Suqs		 * Graphically, "[A breaker=[B broken=[C->B B] tok=A] C]"
478241675Suqs		 * becomes "[A broken=[B [C->B B] tok=A] C]"
479241675Suqs		 * and finally "[A [B->A [C->B B] A] C]".
480241675Suqs		 */
481241675Suqs		if (breaker == broken->pending) {
482241675Suqs			broken = breaker;
483241675Suqs			continue;
484241675Suqs		}
485241675Suqs
486241675Suqs		if (REWIND_THIS != rew_dohalt(tok, MDOC_BLOCK, breaker))
487241675Suqs			continue;
488241675Suqs		if (MDOC_BODY == broken->type)
489241675Suqs			broken = broken->parent;
490241675Suqs
491241675Suqs		/*
492241675Suqs		 * Found the breaker.
493241675Suqs		 * If another, outer breaker is already pending on
494241675Suqs		 * the *broken block, we must not clobber the link
495241675Suqs		 * to the outer breaker, but make it pending on the
496241675Suqs		 * new, now inner breaker.
497241675Suqs		 * Graphically, "[A breaker=[B broken=[C->A A] tok=B] C]"
498241675Suqs		 * becomes "[A breaker=[B->A broken=[C A] tok=B] C]"
499241675Suqs		 * and finally "[A [B->A [C->B A] B] C]".
500241675Suqs		 */
501241675Suqs		if (broken->pending) {
502241675Suqs			struct mdoc_node *taker;
503241675Suqs
504241675Suqs			/*
505241675Suqs			 * If the breaker had also been broken before,
506241675Suqs			 * it cannot take on the outer breaker itself,
507241675Suqs			 * but must hand it on to its own breakers.
508241675Suqs			 * Graphically, this is the following situation:
509241675Suqs			 * "[A [B breaker=[C->B B] broken=[D->A A] tok=C] D]"
510241675Suqs			 * "[A taker=[B->A breaker=[C->B B] [D->C A] C] D]"
511241675Suqs			 */
512241675Suqs			taker = breaker;
513241675Suqs			while (taker->pending)
514241675Suqs				taker = taker->pending;
515241675Suqs			taker->pending = broken->pending;
516241675Suqs		}
517241675Suqs		broken->pending = breaker;
518241675Suqs		mandoc_vmsg(MANDOCERR_SCOPENEST, m->parse, line, ppos,
519241675Suqs				"%s breaks %s", mdoc_macronames[tok],
520241675Suqs				mdoc_macronames[broken->tok]);
521241675Suqs		return(1);
522241675Suqs	}
523241675Suqs
524241675Suqs	/*
525241675Suqs	 * Found no matching block for tok.
526241675Suqs	 * Are you trying to close a block that is not open?
527241675Suqs	 */
528241675Suqs	return(0);
529241675Suqs}
530241675Suqs
531241675Suqs
532241675Suqsstatic int
533241675Suqsrew_sub(enum mdoc_type t, struct mdoc *m,
534241675Suqs		enum mdoct tok, int line, int ppos)
535241675Suqs{
536241675Suqs	struct mdoc_node *n;
537241675Suqs
538241675Suqs	n = m->last;
539241675Suqs	while (n) {
540241675Suqs		switch (rew_dohalt(tok, t, n)) {
541241675Suqs		case (REWIND_NONE):
542241675Suqs			return(1);
543241675Suqs		case (REWIND_THIS):
544241675Suqs			break;
545241675Suqs		case (REWIND_FORCE):
546241675Suqs			mandoc_vmsg(MANDOCERR_SCOPEBROKEN, m->parse,
547241675Suqs					line, ppos, "%s breaks %s",
548241675Suqs					mdoc_macronames[tok],
549241675Suqs					mdoc_macronames[n->tok]);
550241675Suqs			/* FALLTHROUGH */
551241675Suqs		case (REWIND_MORE):
552241675Suqs			n = n->parent;
553241675Suqs			continue;
554241675Suqs		case (REWIND_LATER):
555241675Suqs			if (make_pending(n, tok, m, line, ppos) ||
556241675Suqs			    MDOC_BLOCK != t)
557241675Suqs				return(1);
558241675Suqs			/* FALLTHROUGH */
559241675Suqs		case (REWIND_ERROR):
560241675Suqs			mdoc_pmsg(m, line, ppos, MANDOCERR_NOSCOPE);
561241675Suqs			return(1);
562241675Suqs		}
563241675Suqs		break;
564241675Suqs	}
565241675Suqs
566241675Suqs	assert(n);
567241675Suqs	if ( ! rew_last(m, n))
568241675Suqs		return(0);
569241675Suqs
570241675Suqs	/*
571241675Suqs	 * The current block extends an enclosing block.
572241675Suqs	 * Now that the current block ends, close the enclosing block, too.
573241675Suqs	 */
574241675Suqs	while (NULL != (n = n->pending)) {
575241675Suqs		if ( ! rew_last(m, n))
576241675Suqs			return(0);
577241675Suqs		if (MDOC_HEAD == n->type &&
578241675Suqs		    ! mdoc_body_alloc(m, n->line, n->pos, n->tok))
579241675Suqs			return(0);
580241675Suqs	}
581241675Suqs
582241675Suqs	return(1);
583241675Suqs}
584241675Suqs
585241675Suqs/*
586241675Suqs * Allocate a word and check whether it's punctuation or not.
587241675Suqs * Punctuation consists of those tokens found in mdoc_isdelim().
588241675Suqs */
589241675Suqsstatic int
590241675Suqsdword(struct mdoc *m, int line,
591241675Suqs		int col, const char *p, enum mdelim d)
592241675Suqs{
593241675Suqs
594241675Suqs	if (DELIM_MAX == d)
595241675Suqs		d = mdoc_isdelim(p);
596241675Suqs
597241675Suqs	if ( ! mdoc_word_alloc(m, line, col, p))
598241675Suqs		return(0);
599241675Suqs
600241675Suqs	if (DELIM_OPEN == d)
601241675Suqs		m->last->flags |= MDOC_DELIMO;
602241675Suqs
603241675Suqs	/*
604241675Suqs	 * Closing delimiters only suppress the preceding space
605241675Suqs	 * when they follow something, not when they start a new
606241675Suqs	 * block or element, and not when they follow `No'.
607241675Suqs	 *
608241675Suqs	 * XXX	Explicitly special-casing MDOC_No here feels
609241675Suqs	 *	like a layering violation.  Find a better way
610241675Suqs	 *	and solve this in the code related to `No'!
611241675Suqs	 */
612241675Suqs
613241675Suqs	else if (DELIM_CLOSE == d && m->last->prev &&
614241675Suqs			m->last->prev->tok != MDOC_No)
615241675Suqs		m->last->flags |= MDOC_DELIMC;
616241675Suqs
617241675Suqs	return(1);
618241675Suqs}
619241675Suqs
620241675Suqsstatic int
621241675Suqsappend_delims(struct mdoc *m, int line, int *pos, char *buf)
622241675Suqs{
623241675Suqs	int		 la;
624241675Suqs	enum margserr	 ac;
625241675Suqs	char		*p;
626241675Suqs
627241675Suqs	if ('\0' == buf[*pos])
628241675Suqs		return(1);
629241675Suqs
630241675Suqs	for (;;) {
631241675Suqs		la = *pos;
632241675Suqs		ac = mdoc_zargs(m, line, pos, buf, &p);
633241675Suqs
634241675Suqs		if (ARGS_ERROR == ac)
635241675Suqs			return(0);
636241675Suqs		else if (ARGS_EOLN == ac)
637241675Suqs			break;
638241675Suqs
639241675Suqs		dword(m, line, la, p, DELIM_MAX);
640241675Suqs
641241675Suqs		/*
642241675Suqs		 * If we encounter end-of-sentence symbols, then trigger
643241675Suqs		 * the double-space.
644241675Suqs		 *
645241675Suqs		 * XXX: it's easy to allow this to propagate outward to
646241675Suqs		 * the last symbol, such that `. )' will cause the
647241675Suqs		 * correct double-spacing.  However, (1) groff isn't
648241675Suqs		 * smart enough to do this and (2) it would require
649241675Suqs		 * knowing which symbols break this behaviour, for
650241675Suqs		 * example, `.  ;' shouldn't propagate the double-space.
651241675Suqs		 */
652241675Suqs		if (mandoc_eos(p, strlen(p), 0))
653241675Suqs			m->last->flags |= MDOC_EOS;
654241675Suqs	}
655241675Suqs
656241675Suqs	return(1);
657241675Suqs}
658241675Suqs
659241675Suqs
660241675Suqs/*
661241675Suqs * Close out block partial/full explicit.
662241675Suqs */
663241675Suqsstatic int
664241675Suqsblk_exp_close(MACRO_PROT_ARGS)
665241675Suqs{
666241675Suqs	struct mdoc_node *body;		/* Our own body. */
667241675Suqs	struct mdoc_node *later;	/* A sub-block starting later. */
668241675Suqs	struct mdoc_node *n;		/* For searching backwards. */
669241675Suqs
670241675Suqs	int	 	 j, lastarg, maxargs, flushed, nl;
671241675Suqs	enum margserr	 ac;
672241675Suqs	enum mdoct	 atok, ntok;
673241675Suqs	char		*p;
674241675Suqs
675241675Suqs	nl = MDOC_NEWLINE & m->flags;
676241675Suqs
677241675Suqs	switch (tok) {
678241675Suqs	case (MDOC_Ec):
679241675Suqs		maxargs = 1;
680241675Suqs		break;
681241675Suqs	default:
682241675Suqs		maxargs = 0;
683241675Suqs		break;
684241675Suqs	}
685241675Suqs
686241675Suqs	/*
687241675Suqs	 * Search backwards for beginnings of blocks,
688241675Suqs	 * both of our own and of pending sub-blocks.
689241675Suqs	 */
690241675Suqs	atok = rew_alt(tok);
691241675Suqs	body = later = NULL;
692241675Suqs	for (n = m->last; n; n = n->parent) {
693241675Suqs		if (MDOC_VALID & n->flags)
694241675Suqs			continue;
695241675Suqs
696241675Suqs		/* Remember the start of our own body. */
697241675Suqs		if (MDOC_BODY == n->type && atok == n->tok) {
698241675Suqs			if (ENDBODY_NOT == n->end)
699241675Suqs				body = n;
700241675Suqs			continue;
701241675Suqs		}
702241675Suqs
703241675Suqs		if (MDOC_BLOCK != n->type || MDOC_Nm == n->tok)
704241675Suqs			continue;
705241675Suqs		if (atok == n->tok) {
706241675Suqs			assert(body);
707241675Suqs
708241675Suqs			/*
709241675Suqs			 * Found the start of our own block.
710241675Suqs			 * When there is no pending sub block,
711241675Suqs			 * just proceed to closing out.
712241675Suqs			 */
713241675Suqs			if (NULL == later)
714241675Suqs				break;
715241675Suqs
716241675Suqs			/*
717241675Suqs			 * When there is a pending sub block,
718241675Suqs			 * postpone closing out the current block
719241675Suqs			 * until the rew_sub() closing out the sub-block.
720241675Suqs			 */
721241675Suqs			make_pending(later, tok, m, line, ppos);
722241675Suqs
723241675Suqs			/*
724241675Suqs			 * Mark the place where the formatting - but not
725241675Suqs			 * the scope - of the current block ends.
726241675Suqs			 */
727241675Suqs			if ( ! mdoc_endbody_alloc(m, line, ppos,
728241675Suqs			    atok, body, ENDBODY_SPACE))
729241675Suqs				return(0);
730241675Suqs			break;
731241675Suqs		}
732241675Suqs
733241675Suqs		/*
734241675Suqs		 * When finding an open sub block, remember the last
735241675Suqs		 * open explicit block, or, in case there are only
736241675Suqs		 * implicit ones, the first open implicit block.
737241675Suqs		 */
738241675Suqs		if (later &&
739241675Suqs		    MDOC_EXPLICIT & mdoc_macros[later->tok].flags)
740241675Suqs			continue;
741241675Suqs		if (MDOC_CALLABLE & mdoc_macros[n->tok].flags)
742241675Suqs			later = n;
743241675Suqs	}
744241675Suqs
745241675Suqs	if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) {
746241675Suqs		/* FIXME: do this in validate */
747241675Suqs		if (buf[*pos])
748241675Suqs			mdoc_pmsg(m, line, ppos, MANDOCERR_ARGSLOST);
749241675Suqs
750241675Suqs		if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
751241675Suqs			return(0);
752241675Suqs		return(rew_sub(MDOC_BLOCK, m, tok, line, ppos));
753241675Suqs	}
754241675Suqs
755241675Suqs	if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
756241675Suqs		return(0);
757241675Suqs
758241675Suqs	if (NULL == later && maxargs > 0)
759241675Suqs		if ( ! mdoc_tail_alloc(m, line, ppos, rew_alt(tok)))
760241675Suqs			return(0);
761241675Suqs
762241675Suqs	for (flushed = j = 0; ; j++) {
763241675Suqs		lastarg = *pos;
764241675Suqs
765241675Suqs		if (j == maxargs && ! flushed) {
766241675Suqs			if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
767241675Suqs				return(0);
768241675Suqs			flushed = 1;
769241675Suqs		}
770241675Suqs
771241675Suqs		ac = mdoc_args(m, line, pos, buf, tok, &p);
772241675Suqs
773241675Suqs		if (ARGS_ERROR == ac)
774241675Suqs			return(0);
775241675Suqs		if (ARGS_PUNCT == ac)
776241675Suqs			break;
777241675Suqs		if (ARGS_EOLN == ac)
778241675Suqs			break;
779241675Suqs
780241675Suqs		ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
781241675Suqs
782241675Suqs		if (MDOC_MAX == ntok) {
783241675Suqs			if ( ! dword(m, line, lastarg, p, DELIM_MAX))
784241675Suqs				return(0);
785241675Suqs			continue;
786241675Suqs		}
787241675Suqs
788241675Suqs		if ( ! flushed) {
789241675Suqs			if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
790241675Suqs				return(0);
791241675Suqs			flushed = 1;
792241675Suqs		}
793241675Suqs		if ( ! mdoc_macro(m, ntok, line, lastarg, pos, buf))
794241675Suqs			return(0);
795241675Suqs		break;
796241675Suqs	}
797241675Suqs
798241675Suqs	if ( ! flushed && ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
799241675Suqs		return(0);
800241675Suqs
801241675Suqs	if ( ! nl)
802241675Suqs		return(1);
803241675Suqs	return(append_delims(m, line, pos, buf));
804241675Suqs}
805241675Suqs
806241675Suqs
807241675Suqsstatic int
808241675Suqsin_line(MACRO_PROT_ARGS)
809241675Suqs{
810241675Suqs	int		 la, scope, cnt, nc, nl;
811241675Suqs	enum margverr	 av;
812241675Suqs	enum mdoct	 ntok;
813241675Suqs	enum margserr	 ac;
814241675Suqs	enum mdelim	 d;
815241675Suqs	struct mdoc_arg	*arg;
816241675Suqs	char		*p;
817241675Suqs
818241675Suqs	nl = MDOC_NEWLINE & m->flags;
819241675Suqs
820241675Suqs	/*
821241675Suqs	 * Whether we allow ignored elements (those without content,
822241675Suqs	 * usually because of reserved words) to squeak by.
823241675Suqs	 */
824241675Suqs
825241675Suqs	switch (tok) {
826241675Suqs	case (MDOC_An):
827241675Suqs		/* FALLTHROUGH */
828241675Suqs	case (MDOC_Ar):
829241675Suqs		/* FALLTHROUGH */
830241675Suqs	case (MDOC_Fl):
831241675Suqs		/* FALLTHROUGH */
832241675Suqs	case (MDOC_Mt):
833241675Suqs		/* FALLTHROUGH */
834241675Suqs	case (MDOC_Nm):
835241675Suqs		/* FALLTHROUGH */
836241675Suqs	case (MDOC_Pa):
837241675Suqs		nc = 1;
838241675Suqs		break;
839241675Suqs	default:
840241675Suqs		nc = 0;
841241675Suqs		break;
842241675Suqs	}
843241675Suqs
844241675Suqs	for (arg = NULL;; ) {
845241675Suqs		la = *pos;
846241675Suqs		av = mdoc_argv(m, line, tok, &arg, pos, buf);
847241675Suqs
848241675Suqs		if (ARGV_WORD == av) {
849241675Suqs			*pos = la;
850241675Suqs			break;
851241675Suqs		}
852241675Suqs		if (ARGV_EOLN == av)
853241675Suqs			break;
854241675Suqs		if (ARGV_ARG == av)
855241675Suqs			continue;
856241675Suqs
857241675Suqs		mdoc_argv_free(arg);
858241675Suqs		return(0);
859241675Suqs	}
860241675Suqs
861241675Suqs	for (cnt = scope = 0;; ) {
862241675Suqs		la = *pos;
863241675Suqs		ac = mdoc_args(m, line, pos, buf, tok, &p);
864241675Suqs
865241675Suqs		if (ARGS_ERROR == ac)
866241675Suqs			return(0);
867241675Suqs		if (ARGS_EOLN == ac)
868241675Suqs			break;
869241675Suqs		if (ARGS_PUNCT == ac)
870241675Suqs			break;
871241675Suqs
872241675Suqs		ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
873241675Suqs
874241675Suqs		/*
875241675Suqs		 * In this case, we've located a submacro and must
876241675Suqs		 * execute it.  Close out scope, if open.  If no
877241675Suqs		 * elements have been generated, either create one (nc)
878241675Suqs		 * or raise a warning.
879241675Suqs		 */
880241675Suqs
881241675Suqs		if (MDOC_MAX != ntok) {
882241675Suqs			if (scope && ! rew_elem(m, tok))
883241675Suqs				return(0);
884241675Suqs			if (nc && 0 == cnt) {
885241675Suqs				if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
886241675Suqs					return(0);
887241675Suqs				if ( ! rew_last(m, m->last))
888241675Suqs					return(0);
889241675Suqs			} else if ( ! nc && 0 == cnt) {
890241675Suqs				mdoc_argv_free(arg);
891241675Suqs				mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY);
892241675Suqs			}
893241675Suqs
894241675Suqs			if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
895241675Suqs				return(0);
896241675Suqs			if ( ! nl)
897241675Suqs				return(1);
898241675Suqs			return(append_delims(m, line, pos, buf));
899241675Suqs		}
900241675Suqs
901241675Suqs		/*
902241675Suqs		 * Non-quote-enclosed punctuation.  Set up our scope, if
903241675Suqs		 * a word; rewind the scope, if a delimiter; then append
904241675Suqs		 * the word.
905241675Suqs		 */
906241675Suqs
907241675Suqs		d = ARGS_QWORD == ac ? DELIM_NONE : mdoc_isdelim(p);
908241675Suqs
909241675Suqs		if (DELIM_NONE != d) {
910241675Suqs			/*
911241675Suqs			 * If we encounter closing punctuation, no word
912241675Suqs			 * has been omitted, no scope is open, and we're
913241675Suqs			 * allowed to have an empty element, then start
914241675Suqs			 * a new scope.  `Ar', `Fl', and `Li', only do
915241675Suqs			 * this once per invocation.  There may be more
916241675Suqs			 * of these (all of them?).
917241675Suqs			 */
918241675Suqs			if (0 == cnt && (nc || MDOC_Li == tok) &&
919241675Suqs					DELIM_CLOSE == d && ! scope) {
920241675Suqs				if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
921241675Suqs					return(0);
922241675Suqs				if (MDOC_Ar == tok || MDOC_Li == tok ||
923241675Suqs						MDOC_Fl == tok)
924241675Suqs					cnt++;
925241675Suqs				scope = 1;
926241675Suqs			}
927241675Suqs			/*
928241675Suqs			 * Close out our scope, if one is open, before
929241675Suqs			 * any punctuation.
930241675Suqs			 */
931241675Suqs			if (scope && ! rew_elem(m, tok))
932241675Suqs				return(0);
933241675Suqs			scope = 0;
934241675Suqs		} else if ( ! scope) {
935241675Suqs			if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
936241675Suqs				return(0);
937241675Suqs			scope = 1;
938241675Suqs		}
939241675Suqs
940241675Suqs		if (DELIM_NONE == d)
941241675Suqs			cnt++;
942241675Suqs
943241675Suqs		if ( ! dword(m, line, la, p, d))
944241675Suqs			return(0);
945241675Suqs
946241675Suqs		/*
947241675Suqs		 * `Fl' macros have their scope re-opened with each new
948241675Suqs		 * word so that the `-' can be added to each one without
949241675Suqs		 * having to parse out spaces.
950241675Suqs		 */
951241675Suqs		if (scope && MDOC_Fl == tok) {
952241675Suqs			if ( ! rew_elem(m, tok))
953241675Suqs				return(0);
954241675Suqs			scope = 0;
955241675Suqs		}
956241675Suqs	}
957241675Suqs
958241675Suqs	if (scope && ! rew_elem(m, tok))
959241675Suqs		return(0);
960241675Suqs
961241675Suqs	/*
962241675Suqs	 * If no elements have been collected and we're allowed to have
963241675Suqs	 * empties (nc), open a scope and close it out.  Otherwise,
964241675Suqs	 * raise a warning.
965241675Suqs	 */
966241675Suqs
967241675Suqs	if (nc && 0 == cnt) {
968241675Suqs		if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
969241675Suqs			return(0);
970241675Suqs		if ( ! rew_last(m, m->last))
971241675Suqs			return(0);
972241675Suqs	} else if ( ! nc && 0 == cnt) {
973241675Suqs		mdoc_argv_free(arg);
974241675Suqs		mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY);
975241675Suqs	}
976241675Suqs
977241675Suqs	if ( ! nl)
978241675Suqs		return(1);
979241675Suqs	return(append_delims(m, line, pos, buf));
980241675Suqs}
981241675Suqs
982241675Suqs
983241675Suqsstatic int
984241675Suqsblk_full(MACRO_PROT_ARGS)
985241675Suqs{
986241675Suqs	int		  la, nl, nparsed;
987241675Suqs	struct mdoc_arg	 *arg;
988241675Suqs	struct mdoc_node *head; /* save of head macro */
989241675Suqs	struct mdoc_node *body; /* save of body macro */
990241675Suqs	struct mdoc_node *n;
991241675Suqs	enum mdoc_type	  mtt;
992241675Suqs	enum mdoct	  ntok;
993241675Suqs	enum margserr	  ac, lac;
994241675Suqs	enum margverr	  av;
995241675Suqs	char		 *p;
996241675Suqs
997241675Suqs	nl = MDOC_NEWLINE & m->flags;
998241675Suqs
999241675Suqs	/* Close out prior implicit scope. */
1000241675Suqs
1001241675Suqs	if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
1002241675Suqs		if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
1003241675Suqs			return(0);
1004241675Suqs		if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
1005241675Suqs			return(0);
1006241675Suqs	}
1007241675Suqs
1008241675Suqs	/*
1009241675Suqs	 * This routine accommodates implicitly- and explicitly-scoped
1010241675Suqs	 * macro openings.  Implicit ones first close out prior scope
1011241675Suqs	 * (seen above).  Delay opening the head until necessary to
1012241675Suqs	 * allow leading punctuation to print.  Special consideration
1013241675Suqs	 * for `It -column', which has phrase-part syntax instead of
1014241675Suqs	 * regular child nodes.
1015241675Suqs	 */
1016241675Suqs
1017241675Suqs	for (arg = NULL;; ) {
1018241675Suqs		la = *pos;
1019241675Suqs		av = mdoc_argv(m, line, tok, &arg, pos, buf);
1020241675Suqs
1021241675Suqs		if (ARGV_WORD == av) {
1022241675Suqs			*pos = la;
1023241675Suqs			break;
1024241675Suqs		}
1025241675Suqs
1026241675Suqs		if (ARGV_EOLN == av)
1027241675Suqs			break;
1028241675Suqs		if (ARGV_ARG == av)
1029241675Suqs			continue;
1030241675Suqs
1031241675Suqs		mdoc_argv_free(arg);
1032241675Suqs		return(0);
1033241675Suqs	}
1034241675Suqs
1035241675Suqs	if ( ! mdoc_block_alloc(m, line, ppos, tok, arg))
1036241675Suqs		return(0);
1037241675Suqs
1038241675Suqs	head = body = NULL;
1039241675Suqs
1040241675Suqs	/*
1041241675Suqs	 * Exception: Heads of `It' macros in `-diag' lists are not
1042241675Suqs	 * parsed, even though `It' macros in general are parsed.
1043241675Suqs	 */
1044241675Suqs	nparsed = MDOC_It == tok &&
1045241675Suqs		MDOC_Bl == m->last->parent->tok &&
1046241675Suqs		LIST_diag == m->last->parent->norm->Bl.type;
1047241675Suqs
1048241675Suqs	/*
1049241675Suqs	 * The `Nd' macro has all arguments in its body: it's a hybrid
1050241675Suqs	 * of block partial-explicit and full-implicit.  Stupid.
1051241675Suqs	 */
1052241675Suqs
1053241675Suqs	if (MDOC_Nd == tok) {
1054241675Suqs		if ( ! mdoc_head_alloc(m, line, ppos, tok))
1055241675Suqs			return(0);
1056241675Suqs		head = m->last;
1057241675Suqs		if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1058241675Suqs			return(0);
1059241675Suqs		if ( ! mdoc_body_alloc(m, line, ppos, tok))
1060241675Suqs			return(0);
1061241675Suqs		body = m->last;
1062241675Suqs	}
1063241675Suqs
1064241675Suqs	ac = ARGS_ERROR;
1065241675Suqs
1066241675Suqs	for ( ; ; ) {
1067241675Suqs		la = *pos;
1068241675Suqs		/* Initialise last-phrase-type with ARGS_PEND. */
1069241675Suqs		lac = ARGS_ERROR == ac ? ARGS_PEND : ac;
1070241675Suqs		ac = mdoc_args(m, line, pos, buf, tok, &p);
1071241675Suqs
1072241675Suqs		if (ARGS_PUNCT == ac)
1073241675Suqs			break;
1074241675Suqs
1075241675Suqs		if (ARGS_ERROR == ac)
1076241675Suqs			return(0);
1077241675Suqs
1078241675Suqs		if (ARGS_EOLN == ac) {
1079241675Suqs			if (ARGS_PPHRASE != lac && ARGS_PHRASE != lac)
1080241675Suqs				break;
1081241675Suqs			/*
1082241675Suqs			 * This is necessary: if the last token on a
1083241675Suqs			 * line is a `Ta' or tab, then we'll get
1084241675Suqs			 * ARGS_EOLN, so we must be smart enough to
1085241675Suqs			 * reopen our scope if the last parse was a
1086241675Suqs			 * phrase or partial phrase.
1087241675Suqs			 */
1088241675Suqs			if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
1089241675Suqs				return(0);
1090241675Suqs			if ( ! mdoc_body_alloc(m, line, ppos, tok))
1091241675Suqs				return(0);
1092241675Suqs			body = m->last;
1093241675Suqs			break;
1094241675Suqs		}
1095241675Suqs
1096241675Suqs		/*
1097241675Suqs		 * Emit leading punctuation (i.e., punctuation before
1098241675Suqs		 * the MDOC_HEAD) for non-phrase types.
1099241675Suqs		 */
1100241675Suqs
1101241675Suqs		if (NULL == head &&
1102241675Suqs				ARGS_PEND != ac &&
1103241675Suqs				ARGS_PHRASE != ac &&
1104241675Suqs				ARGS_PPHRASE != ac &&
1105241675Suqs				ARGS_QWORD != ac &&
1106241675Suqs				DELIM_OPEN == mdoc_isdelim(p)) {
1107241675Suqs			if ( ! dword(m, line, la, p, DELIM_OPEN))
1108241675Suqs				return(0);
1109241675Suqs			continue;
1110241675Suqs		}
1111241675Suqs
1112241675Suqs		/* Open a head if one hasn't been opened. */
1113241675Suqs
1114241675Suqs		if (NULL == head) {
1115241675Suqs			if ( ! mdoc_head_alloc(m, line, ppos, tok))
1116241675Suqs				return(0);
1117241675Suqs			head = m->last;
1118241675Suqs		}
1119241675Suqs
1120241675Suqs		if (ARGS_PHRASE == ac ||
1121241675Suqs				ARGS_PEND == ac ||
1122241675Suqs				ARGS_PPHRASE == ac) {
1123241675Suqs			/*
1124241675Suqs			 * If we haven't opened a body yet, rewind the
1125241675Suqs			 * head; if we have, rewind that instead.
1126241675Suqs			 */
1127241675Suqs
1128241675Suqs			mtt = body ? MDOC_BODY : MDOC_HEAD;
1129241675Suqs			if ( ! rew_sub(mtt, m, tok, line, ppos))
1130241675Suqs				return(0);
1131241675Suqs
1132241675Suqs			/* Then allocate our body context. */
1133241675Suqs
1134241675Suqs			if ( ! mdoc_body_alloc(m, line, ppos, tok))
1135241675Suqs				return(0);
1136241675Suqs			body = m->last;
1137241675Suqs
1138241675Suqs			/*
1139241675Suqs			 * Process phrases: set whether we're in a
1140241675Suqs			 * partial-phrase (this effects line handling)
1141241675Suqs			 * then call down into the phrase parser.
1142241675Suqs			 */
1143241675Suqs
1144241675Suqs			if (ARGS_PPHRASE == ac)
1145241675Suqs				m->flags |= MDOC_PPHRASE;
1146241675Suqs			if (ARGS_PEND == ac && ARGS_PPHRASE == lac)
1147241675Suqs				m->flags |= MDOC_PPHRASE;
1148241675Suqs
1149241675Suqs			if ( ! phrase(m, line, la, buf))
1150241675Suqs				return(0);
1151241675Suqs
1152241675Suqs			m->flags &= ~MDOC_PPHRASE;
1153241675Suqs			continue;
1154241675Suqs		}
1155241675Suqs
1156241675Suqs		ntok = nparsed || ARGS_QWORD == ac ?
1157241675Suqs			MDOC_MAX : lookup(tok, p);
1158241675Suqs
1159241675Suqs		if (MDOC_MAX == ntok) {
1160241675Suqs			if ( ! dword(m, line, la, p, DELIM_MAX))
1161241675Suqs				return(0);
1162241675Suqs			continue;
1163241675Suqs		}
1164241675Suqs
1165241675Suqs		if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
1166241675Suqs			return(0);
1167241675Suqs		break;
1168241675Suqs	}
1169241675Suqs
1170241675Suqs	if (NULL == head) {
1171241675Suqs		if ( ! mdoc_head_alloc(m, line, ppos, tok))
1172241675Suqs			return(0);
1173241675Suqs		head = m->last;
1174241675Suqs	}
1175241675Suqs
1176241675Suqs	if (nl && ! append_delims(m, line, pos, buf))
1177241675Suqs		return(0);
1178241675Suqs
1179241675Suqs	/* If we've already opened our body, exit now. */
1180241675Suqs
1181241675Suqs	if (NULL != body)
1182241675Suqs		goto out;
1183241675Suqs
1184241675Suqs	/*
1185241675Suqs	 * If there is an open (i.e., unvalidated) sub-block requiring
1186241675Suqs	 * explicit close-out, postpone switching the current block from
1187241675Suqs	 * head to body until the rew_sub() call closing out that
1188241675Suqs	 * sub-block.
1189241675Suqs	 */
1190241675Suqs	for (n = m->last; n && n != head; n = n->parent) {
1191241675Suqs		if (MDOC_BLOCK == n->type &&
1192241675Suqs				MDOC_EXPLICIT & mdoc_macros[n->tok].flags &&
1193241675Suqs				! (MDOC_VALID & n->flags)) {
1194241675Suqs			n->pending = head;
1195241675Suqs			return(1);
1196241675Suqs		}
1197241675Suqs	}
1198241675Suqs
1199241675Suqs	/* Close out scopes to remain in a consistent state. */
1200241675Suqs
1201241675Suqs	if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1202241675Suqs		return(0);
1203241675Suqs	if ( ! mdoc_body_alloc(m, line, ppos, tok))
1204241675Suqs		return(0);
1205241675Suqs
1206241675Suqsout:
1207241675Suqs	if ( ! (MDOC_FREECOL & m->flags))
1208241675Suqs		return(1);
1209241675Suqs
1210241675Suqs	if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
1211241675Suqs		return(0);
1212241675Suqs	if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
1213241675Suqs		return(0);
1214241675Suqs
1215241675Suqs	m->flags &= ~MDOC_FREECOL;
1216241675Suqs	return(1);
1217241675Suqs}
1218241675Suqs
1219241675Suqs
1220241675Suqsstatic int
1221241675Suqsblk_part_imp(MACRO_PROT_ARGS)
1222241675Suqs{
1223241675Suqs	int		  la, nl;
1224241675Suqs	enum mdoct	  ntok;
1225241675Suqs	enum margserr	  ac;
1226241675Suqs	char		 *p;
1227241675Suqs	struct mdoc_node *blk; /* saved block context */
1228241675Suqs	struct mdoc_node *body; /* saved body context */
1229241675Suqs	struct mdoc_node *n;
1230241675Suqs
1231241675Suqs	nl = MDOC_NEWLINE & m->flags;
1232241675Suqs
1233241675Suqs	/*
1234241675Suqs	 * A macro that spans to the end of the line.  This is generally
1235241675Suqs	 * (but not necessarily) called as the first macro.  The block
1236241675Suqs	 * has a head as the immediate child, which is always empty,
1237241675Suqs	 * followed by zero or more opening punctuation nodes, then the
1238241675Suqs	 * body (which may be empty, depending on the macro), then zero
1239241675Suqs	 * or more closing punctuation nodes.
1240241675Suqs	 */
1241241675Suqs
1242241675Suqs	if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL))
1243241675Suqs		return(0);
1244241675Suqs
1245241675Suqs	blk = m->last;
1246241675Suqs
1247241675Suqs	if ( ! mdoc_head_alloc(m, line, ppos, tok))
1248241675Suqs		return(0);
1249241675Suqs	if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1250241675Suqs		return(0);
1251241675Suqs
1252241675Suqs	/*
1253241675Suqs	 * Open the body scope "on-demand", that is, after we've
1254241675Suqs	 * processed all our the leading delimiters (open parenthesis,
1255241675Suqs	 * etc.).
1256241675Suqs	 */
1257241675Suqs
1258241675Suqs	for (body = NULL; ; ) {
1259241675Suqs		la = *pos;
1260241675Suqs		ac = mdoc_args(m, line, pos, buf, tok, &p);
1261241675Suqs
1262241675Suqs		if (ARGS_ERROR == ac)
1263241675Suqs			return(0);
1264241675Suqs		if (ARGS_EOLN == ac)
1265241675Suqs			break;
1266241675Suqs		if (ARGS_PUNCT == ac)
1267241675Suqs			break;
1268241675Suqs
1269241675Suqs		if (NULL == body && ARGS_QWORD != ac &&
1270241675Suqs				DELIM_OPEN == mdoc_isdelim(p)) {
1271241675Suqs			if ( ! dword(m, line, la, p, DELIM_OPEN))
1272241675Suqs				return(0);
1273241675Suqs			continue;
1274241675Suqs		}
1275241675Suqs
1276241675Suqs		if (NULL == body) {
1277241675Suqs		       if ( ! mdoc_body_alloc(m, line, ppos, tok))
1278241675Suqs			       return(0);
1279241675Suqs			body = m->last;
1280241675Suqs		}
1281241675Suqs
1282241675Suqs		ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
1283241675Suqs
1284241675Suqs		if (MDOC_MAX == ntok) {
1285241675Suqs			if ( ! dword(m, line, la, p, DELIM_MAX))
1286241675Suqs				return(0);
1287241675Suqs			continue;
1288241675Suqs		}
1289241675Suqs
1290241675Suqs		if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
1291241675Suqs			return(0);
1292241675Suqs		break;
1293241675Suqs	}
1294241675Suqs
1295241675Suqs	/* Clean-ups to leave in a consistent state. */
1296241675Suqs
1297241675Suqs	if (NULL == body) {
1298241675Suqs		if ( ! mdoc_body_alloc(m, line, ppos, tok))
1299241675Suqs			return(0);
1300241675Suqs		body = m->last;
1301241675Suqs	}
1302241675Suqs
1303241675Suqs	for (n = body->child; n && n->next; n = n->next)
1304241675Suqs		/* Do nothing. */ ;
1305241675Suqs
1306241675Suqs	/*
1307241675Suqs	 * End of sentence spacing: if the last node is a text node and
1308241675Suqs	 * has a trailing period, then mark it as being end-of-sentence.
1309241675Suqs	 */
1310241675Suqs
1311241675Suqs	if (n && MDOC_TEXT == n->type && n->string)
1312241675Suqs		if (mandoc_eos(n->string, strlen(n->string), 1))
1313241675Suqs			n->flags |= MDOC_EOS;
1314241675Suqs
1315241675Suqs	/* Up-propagate the end-of-space flag. */
1316241675Suqs
1317241675Suqs	if (n && (MDOC_EOS & n->flags)) {
1318241675Suqs		body->flags |= MDOC_EOS;
1319241675Suqs		body->parent->flags |= MDOC_EOS;
1320241675Suqs	}
1321241675Suqs
1322241675Suqs	/*
1323241675Suqs	 * If there is an open sub-block requiring explicit close-out,
1324241675Suqs	 * postpone closing out the current block
1325241675Suqs	 * until the rew_sub() call closing out the sub-block.
1326241675Suqs	 */
1327241675Suqs	for (n = m->last; n && n != body && n != blk->parent; n = n->parent) {
1328241675Suqs		if (MDOC_BLOCK == n->type &&
1329241675Suqs		    MDOC_EXPLICIT & mdoc_macros[n->tok].flags &&
1330241675Suqs		    ! (MDOC_VALID & n->flags)) {
1331241675Suqs			make_pending(n, tok, m, line, ppos);
1332241675Suqs			if ( ! mdoc_endbody_alloc(m, line, ppos,
1333241675Suqs			    tok, body, ENDBODY_NOSPACE))
1334241675Suqs				return(0);
1335241675Suqs			return(1);
1336241675Suqs		}
1337241675Suqs	}
1338241675Suqs
1339241675Suqs	/*
1340241675Suqs	 * If we can't rewind to our body, then our scope has already
1341241675Suqs	 * been closed by another macro (like `Oc' closing `Op').  This
1342241675Suqs	 * is ugly behaviour nodding its head to OpenBSD's overwhelming
1343241675Suqs	 * crufty use of `Op' breakage.
1344241675Suqs	 */
1345241675Suqs	if (n != body)
1346241675Suqs		mandoc_vmsg(MANDOCERR_SCOPENEST, m->parse, line, ppos,
1347241675Suqs				"%s broken", mdoc_macronames[tok]);
1348241675Suqs
1349241675Suqs	if (n && ! rew_sub(MDOC_BODY, m, tok, line, ppos))
1350241675Suqs		return(0);
1351241675Suqs
1352241675Suqs	/* Standard appending of delimiters. */
1353241675Suqs
1354241675Suqs	if (nl && ! append_delims(m, line, pos, buf))
1355241675Suqs		return(0);
1356241675Suqs
1357241675Suqs	/* Rewind scope, if applicable. */
1358241675Suqs
1359241675Suqs	if (n && ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
1360241675Suqs		return(0);
1361241675Suqs
1362241675Suqs	return(1);
1363241675Suqs}
1364241675Suqs
1365241675Suqs
1366241675Suqsstatic int
1367241675Suqsblk_part_exp(MACRO_PROT_ARGS)
1368241675Suqs{
1369241675Suqs	int		  la, nl;
1370241675Suqs	enum margserr	  ac;
1371241675Suqs	struct mdoc_node *head; /* keep track of head */
1372241675Suqs	struct mdoc_node *body; /* keep track of body */
1373241675Suqs	char		 *p;
1374241675Suqs	enum mdoct	  ntok;
1375241675Suqs
1376241675Suqs	nl = MDOC_NEWLINE & m->flags;
1377241675Suqs
1378241675Suqs	/*
1379241675Suqs	 * The opening of an explicit macro having zero or more leading
1380241675Suqs	 * punctuation nodes; a head with optional single element (the
1381241675Suqs	 * case of `Eo'); and a body that may be empty.
1382241675Suqs	 */
1383241675Suqs
1384241675Suqs	if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL))
1385241675Suqs		return(0);
1386241675Suqs
1387241675Suqs	for (head = body = NULL; ; ) {
1388241675Suqs		la = *pos;
1389241675Suqs		ac = mdoc_args(m, line, pos, buf, tok, &p);
1390241675Suqs
1391241675Suqs		if (ARGS_ERROR == ac)
1392241675Suqs			return(0);
1393241675Suqs		if (ARGS_PUNCT == ac)
1394241675Suqs			break;
1395241675Suqs		if (ARGS_EOLN == ac)
1396241675Suqs			break;
1397241675Suqs
1398241675Suqs		/* Flush out leading punctuation. */
1399241675Suqs
1400241675Suqs		if (NULL == head && ARGS_QWORD != ac &&
1401241675Suqs				DELIM_OPEN == mdoc_isdelim(p)) {
1402241675Suqs			assert(NULL == body);
1403241675Suqs			if ( ! dword(m, line, la, p, DELIM_OPEN))
1404241675Suqs				return(0);
1405241675Suqs			continue;
1406241675Suqs		}
1407241675Suqs
1408241675Suqs		if (NULL == head) {
1409241675Suqs			assert(NULL == body);
1410241675Suqs			if ( ! mdoc_head_alloc(m, line, ppos, tok))
1411241675Suqs				return(0);
1412241675Suqs			head = m->last;
1413241675Suqs		}
1414241675Suqs
1415241675Suqs		/*
1416241675Suqs		 * `Eo' gobbles any data into the head, but most other
1417241675Suqs		 * macros just immediately close out and begin the body.
1418241675Suqs		 */
1419241675Suqs
1420241675Suqs		if (NULL == body) {
1421241675Suqs			assert(head);
1422241675Suqs			/* No check whether it's a macro! */
1423241675Suqs			if (MDOC_Eo == tok)
1424241675Suqs				if ( ! dword(m, line, la, p, DELIM_MAX))
1425241675Suqs					return(0);
1426241675Suqs
1427241675Suqs			if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1428241675Suqs				return(0);
1429241675Suqs			if ( ! mdoc_body_alloc(m, line, ppos, tok))
1430241675Suqs				return(0);
1431241675Suqs			body = m->last;
1432241675Suqs
1433241675Suqs			if (MDOC_Eo == tok)
1434241675Suqs				continue;
1435241675Suqs		}
1436241675Suqs
1437241675Suqs		assert(NULL != head && NULL != body);
1438241675Suqs
1439241675Suqs		ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
1440241675Suqs
1441241675Suqs		if (MDOC_MAX == ntok) {
1442241675Suqs			if ( ! dword(m, line, la, p, DELIM_MAX))
1443241675Suqs				return(0);
1444241675Suqs			continue;
1445241675Suqs		}
1446241675Suqs
1447241675Suqs		if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
1448241675Suqs			return(0);
1449241675Suqs		break;
1450241675Suqs	}
1451241675Suqs
1452241675Suqs	/* Clean-up to leave in a consistent state. */
1453241675Suqs
1454241675Suqs	if (NULL == head)
1455241675Suqs		if ( ! mdoc_head_alloc(m, line, ppos, tok))
1456241675Suqs			return(0);
1457241675Suqs
1458241675Suqs	if (NULL == body) {
1459241675Suqs		if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1460241675Suqs			return(0);
1461241675Suqs		if ( ! mdoc_body_alloc(m, line, ppos, tok))
1462241675Suqs			return(0);
1463241675Suqs	}
1464241675Suqs
1465241675Suqs	/* Standard appending of delimiters. */
1466241675Suqs
1467241675Suqs	if ( ! nl)
1468241675Suqs		return(1);
1469241675Suqs	return(append_delims(m, line, pos, buf));
1470241675Suqs}
1471241675Suqs
1472241675Suqs
1473241675Suqs/* ARGSUSED */
1474241675Suqsstatic int
1475241675Suqsin_line_argn(MACRO_PROT_ARGS)
1476241675Suqs{
1477241675Suqs	int		 la, flushed, j, maxargs, nl;
1478241675Suqs	enum margserr	 ac;
1479241675Suqs	enum margverr	 av;
1480241675Suqs	struct mdoc_arg	*arg;
1481241675Suqs	char		*p;
1482241675Suqs	enum mdoct	 ntok;
1483241675Suqs
1484241675Suqs	nl = MDOC_NEWLINE & m->flags;
1485241675Suqs
1486241675Suqs	/*
1487241675Suqs	 * A line macro that has a fixed number of arguments (maxargs).
1488241675Suqs	 * Only open the scope once the first non-leading-punctuation is
1489241675Suqs	 * found (unless MDOC_IGNDELIM is noted, like in `Pf'), then
1490241675Suqs	 * keep it open until the maximum number of arguments are
1491241675Suqs	 * exhausted.
1492241675Suqs	 */
1493241675Suqs
1494241675Suqs	switch (tok) {
1495241675Suqs	case (MDOC_Ap):
1496241675Suqs		/* FALLTHROUGH */
1497241675Suqs	case (MDOC_No):
1498241675Suqs		/* FALLTHROUGH */
1499241675Suqs	case (MDOC_Ns):
1500241675Suqs		/* FALLTHROUGH */
1501241675Suqs	case (MDOC_Ux):
1502241675Suqs		maxargs = 0;
1503241675Suqs		break;
1504241675Suqs	case (MDOC_Bx):
1505241675Suqs		/* FALLTHROUGH */
1506241675Suqs	case (MDOC_Xr):
1507241675Suqs		maxargs = 2;
1508241675Suqs		break;
1509241675Suqs	default:
1510241675Suqs		maxargs = 1;
1511241675Suqs		break;
1512241675Suqs	}
1513241675Suqs
1514241675Suqs	for (arg = NULL; ; ) {
1515241675Suqs		la = *pos;
1516241675Suqs		av = mdoc_argv(m, line, tok, &arg, pos, buf);
1517241675Suqs
1518241675Suqs		if (ARGV_WORD == av) {
1519241675Suqs			*pos = la;
1520241675Suqs			break;
1521241675Suqs		}
1522241675Suqs
1523241675Suqs		if (ARGV_EOLN == av)
1524241675Suqs			break;
1525241675Suqs		if (ARGV_ARG == av)
1526241675Suqs			continue;
1527241675Suqs
1528241675Suqs		mdoc_argv_free(arg);
1529241675Suqs		return(0);
1530241675Suqs	}
1531241675Suqs
1532241675Suqs	for (flushed = j = 0; ; ) {
1533241675Suqs		la = *pos;
1534241675Suqs		ac = mdoc_args(m, line, pos, buf, tok, &p);
1535241675Suqs
1536241675Suqs		if (ARGS_ERROR == ac)
1537241675Suqs			return(0);
1538241675Suqs		if (ARGS_PUNCT == ac)
1539241675Suqs			break;
1540241675Suqs		if (ARGS_EOLN == ac)
1541241675Suqs			break;
1542241675Suqs
1543241675Suqs		if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
1544241675Suqs				ARGS_QWORD != ac && 0 == j &&
1545241675Suqs				DELIM_OPEN == mdoc_isdelim(p)) {
1546241675Suqs			if ( ! dword(m, line, la, p, DELIM_OPEN))
1547241675Suqs				return(0);
1548241675Suqs			continue;
1549241675Suqs		} else if (0 == j)
1550241675Suqs		       if ( ! mdoc_elem_alloc(m, line, la, tok, arg))
1551241675Suqs			       return(0);
1552241675Suqs
1553241675Suqs		if (j == maxargs && ! flushed) {
1554241675Suqs			if ( ! rew_elem(m, tok))
1555241675Suqs				return(0);
1556241675Suqs			flushed = 1;
1557241675Suqs		}
1558241675Suqs
1559241675Suqs		ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
1560241675Suqs
1561241675Suqs		if (MDOC_MAX != ntok) {
1562241675Suqs			if ( ! flushed && ! rew_elem(m, tok))
1563241675Suqs				return(0);
1564241675Suqs			flushed = 1;
1565241675Suqs			if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
1566241675Suqs				return(0);
1567241675Suqs			j++;
1568241675Suqs			break;
1569241675Suqs		}
1570241675Suqs
1571241675Suqs		if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
1572241675Suqs				ARGS_QWORD != ac &&
1573241675Suqs				! flushed &&
1574241675Suqs				DELIM_NONE != mdoc_isdelim(p)) {
1575241675Suqs			if ( ! rew_elem(m, tok))
1576241675Suqs				return(0);
1577241675Suqs			flushed = 1;
1578241675Suqs		}
1579241675Suqs
1580241675Suqs		if ( ! dword(m, line, la, p, DELIM_MAX))
1581241675Suqs			return(0);
1582241675Suqs		j++;
1583241675Suqs	}
1584241675Suqs
1585241675Suqs	if (0 == j && ! mdoc_elem_alloc(m, line, la, tok, arg))
1586241675Suqs	       return(0);
1587241675Suqs
1588241675Suqs	/* Close out in a consistent state. */
1589241675Suqs
1590241675Suqs	if ( ! flushed && ! rew_elem(m, tok))
1591241675Suqs		return(0);
1592241675Suqs	if ( ! nl)
1593241675Suqs		return(1);
1594241675Suqs	return(append_delims(m, line, pos, buf));
1595241675Suqs}
1596241675Suqs
1597241675Suqs
1598241675Suqsstatic int
1599241675Suqsin_line_eoln(MACRO_PROT_ARGS)
1600241675Suqs{
1601241675Suqs	int		 la;
1602241675Suqs	enum margserr	 ac;
1603241675Suqs	enum margverr	 av;
1604241675Suqs	struct mdoc_arg	*arg;
1605241675Suqs	char		*p;
1606241675Suqs	enum mdoct	 ntok;
1607241675Suqs
1608241675Suqs	assert( ! (MDOC_PARSED & mdoc_macros[tok].flags));
1609241675Suqs
1610241675Suqs	if (tok == MDOC_Pp)
1611241675Suqs		rew_sub(MDOC_BLOCK, m, MDOC_Nm, line, ppos);
1612241675Suqs
1613241675Suqs	/* Parse macro arguments. */
1614241675Suqs
1615241675Suqs	for (arg = NULL; ; ) {
1616241675Suqs		la = *pos;
1617241675Suqs		av = mdoc_argv(m, line, tok, &arg, pos, buf);
1618241675Suqs
1619241675Suqs		if (ARGV_WORD == av) {
1620241675Suqs			*pos = la;
1621241675Suqs			break;
1622241675Suqs		}
1623241675Suqs		if (ARGV_EOLN == av)
1624241675Suqs			break;
1625241675Suqs		if (ARGV_ARG == av)
1626241675Suqs			continue;
1627241675Suqs
1628241675Suqs		mdoc_argv_free(arg);
1629241675Suqs		return(0);
1630241675Suqs	}
1631241675Suqs
1632241675Suqs	/* Open element scope. */
1633241675Suqs
1634241675Suqs	if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
1635241675Suqs		return(0);
1636241675Suqs
1637241675Suqs	/* Parse argument terms. */
1638241675Suqs
1639241675Suqs	for (;;) {
1640241675Suqs		la = *pos;
1641241675Suqs		ac = mdoc_args(m, line, pos, buf, tok, &p);
1642241675Suqs
1643241675Suqs		if (ARGS_ERROR == ac)
1644241675Suqs			return(0);
1645241675Suqs		if (ARGS_EOLN == ac)
1646241675Suqs			break;
1647241675Suqs
1648241675Suqs		ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
1649241675Suqs
1650241675Suqs		if (MDOC_MAX == ntok) {
1651241675Suqs			if ( ! dword(m, line, la, p, DELIM_MAX))
1652241675Suqs				return(0);
1653241675Suqs			continue;
1654241675Suqs		}
1655241675Suqs
1656241675Suqs		if ( ! rew_elem(m, tok))
1657241675Suqs			return(0);
1658241675Suqs		return(mdoc_macro(m, ntok, line, la, pos, buf));
1659241675Suqs	}
1660241675Suqs
1661241675Suqs	/* Close out (no delimiters). */
1662241675Suqs
1663241675Suqs	return(rew_elem(m, tok));
1664241675Suqs}
1665241675Suqs
1666241675Suqs
1667241675Suqs/* ARGSUSED */
1668241675Suqsstatic int
1669241675Suqsctx_synopsis(MACRO_PROT_ARGS)
1670241675Suqs{
1671241675Suqs	int		 nl;
1672241675Suqs
1673241675Suqs	nl = MDOC_NEWLINE & m->flags;
1674241675Suqs
1675241675Suqs	/* If we're not in the SYNOPSIS, go straight to in-line. */
1676241675Suqs	if ( ! (MDOC_SYNOPSIS & m->flags))
1677241675Suqs		return(in_line(m, tok, line, ppos, pos, buf));
1678241675Suqs
1679241675Suqs	/* If we're a nested call, same place. */
1680241675Suqs	if ( ! nl)
1681241675Suqs		return(in_line(m, tok, line, ppos, pos, buf));
1682241675Suqs
1683241675Suqs	/*
1684241675Suqs	 * XXX: this will open a block scope; however, if later we end
1685241675Suqs	 * up formatting the block scope, then child nodes will inherit
1686241675Suqs	 * the formatting.  Be careful.
1687241675Suqs	 */
1688241675Suqs	if (MDOC_Nm == tok)
1689241675Suqs		return(blk_full(m, tok, line, ppos, pos, buf));
1690241675Suqs	assert(MDOC_Vt == tok);
1691241675Suqs	return(blk_part_imp(m, tok, line, ppos, pos, buf));
1692241675Suqs}
1693241675Suqs
1694241675Suqs
1695241675Suqs/* ARGSUSED */
1696241675Suqsstatic int
1697241675Suqsobsolete(MACRO_PROT_ARGS)
1698241675Suqs{
1699241675Suqs
1700241675Suqs	mdoc_pmsg(m, line, ppos, MANDOCERR_MACROOBS);
1701241675Suqs	return(1);
1702241675Suqs}
1703241675Suqs
1704241675Suqs
1705241675Suqs/*
1706241675Suqs * Phrases occur within `Bl -column' entries, separated by `Ta' or tabs.
1707241675Suqs * They're unusual because they're basically free-form text until a
1708241675Suqs * macro is encountered.
1709241675Suqs */
1710241675Suqsstatic int
1711241675Suqsphrase(struct mdoc *m, int line, int ppos, char *buf)
1712241675Suqs{
1713241675Suqs	int		 la, pos;
1714241675Suqs	enum margserr	 ac;
1715241675Suqs	enum mdoct	 ntok;
1716241675Suqs	char		*p;
1717241675Suqs
1718241675Suqs	for (pos = ppos; ; ) {
1719241675Suqs		la = pos;
1720241675Suqs
1721241675Suqs		ac = mdoc_zargs(m, line, &pos, buf, &p);
1722241675Suqs
1723241675Suqs		if (ARGS_ERROR == ac)
1724241675Suqs			return(0);
1725241675Suqs		if (ARGS_EOLN == ac)
1726241675Suqs			break;
1727241675Suqs
1728241675Suqs		ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p);
1729241675Suqs
1730241675Suqs		if (MDOC_MAX == ntok) {
1731241675Suqs			if ( ! dword(m, line, la, p, DELIM_MAX))
1732241675Suqs				return(0);
1733241675Suqs			continue;
1734241675Suqs		}
1735241675Suqs
1736241675Suqs		if ( ! mdoc_macro(m, ntok, line, la, &pos, buf))
1737241675Suqs			return(0);
1738241675Suqs		return(append_delims(m, line, &pos, buf));
1739241675Suqs	}
1740241675Suqs
1741241675Suqs	return(1);
1742241675Suqs}
1743241675Suqs
1744241675Suqs
1745241675Suqs/* ARGSUSED */
1746241675Suqsstatic int
1747241675Suqsphrase_ta(MACRO_PROT_ARGS)
1748241675Suqs{
1749241675Suqs	int		  la;
1750241675Suqs	enum mdoct	  ntok;
1751241675Suqs	enum margserr	  ac;
1752241675Suqs	char		 *p;
1753241675Suqs
1754241675Suqs	/*
1755241675Suqs	 * FIXME: this is overly restrictive: if the `Ta' is unexpected,
1756241675Suqs	 * it should simply error out with ARGSLOST.
1757241675Suqs	 */
1758241675Suqs
1759241675Suqs	if ( ! rew_sub(MDOC_BODY, m, MDOC_It, line, ppos))
1760241675Suqs		return(0);
1761241675Suqs	if ( ! mdoc_body_alloc(m, line, ppos, MDOC_It))
1762241675Suqs		return(0);
1763241675Suqs
1764241675Suqs	for (;;) {
1765241675Suqs		la = *pos;
1766241675Suqs		ac = mdoc_zargs(m, line, pos, buf, &p);
1767241675Suqs
1768241675Suqs		if (ARGS_ERROR == ac)
1769241675Suqs			return(0);
1770241675Suqs		if (ARGS_EOLN == ac)
1771241675Suqs			break;
1772241675Suqs
1773241675Suqs		ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p);
1774241675Suqs
1775241675Suqs		if (MDOC_MAX == ntok) {
1776241675Suqs			if ( ! dword(m, line, la, p, DELIM_MAX))
1777241675Suqs				return(0);
1778241675Suqs			continue;
1779241675Suqs		}
1780241675Suqs
1781241675Suqs		if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
1782241675Suqs			return(0);
1783241675Suqs		return(append_delims(m, line, pos, buf));
1784241675Suqs	}
1785241675Suqs
1786241675Suqs	return(1);
1787241675Suqs}
1788