xref: /titanic_44/usr/src/cmd/mandoc/mdoc.c (revision 698f87a48e2e945bfe5493ce168e0d0ae1cedd5c)
1*698f87a4SGarrett D'Amore /*	$Id: mdoc.c,v 1.206 2013/12/24 19:11:46 schwarze Exp $ */
295c635efSGarrett D'Amore /*
395c635efSGarrett D'Amore  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*698f87a4SGarrett D'Amore  * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
595c635efSGarrett D'Amore  *
695c635efSGarrett D'Amore  * Permission to use, copy, modify, and distribute this software for any
795c635efSGarrett D'Amore  * purpose with or without fee is hereby granted, provided that the above
895c635efSGarrett D'Amore  * copyright notice and this permission notice appear in all copies.
995c635efSGarrett D'Amore  *
1095c635efSGarrett D'Amore  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1195c635efSGarrett D'Amore  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1295c635efSGarrett D'Amore  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1395c635efSGarrett D'Amore  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1495c635efSGarrett D'Amore  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1595c635efSGarrett D'Amore  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1695c635efSGarrett D'Amore  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1795c635efSGarrett D'Amore  */
1895c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H
1995c635efSGarrett D'Amore #include "config.h"
2095c635efSGarrett D'Amore #endif
2195c635efSGarrett D'Amore 
2295c635efSGarrett D'Amore #include <sys/types.h>
2395c635efSGarrett D'Amore 
2495c635efSGarrett D'Amore #include <assert.h>
2595c635efSGarrett D'Amore #include <stdarg.h>
2695c635efSGarrett D'Amore #include <stdio.h>
2795c635efSGarrett D'Amore #include <stdlib.h>
2895c635efSGarrett D'Amore #include <string.h>
2995c635efSGarrett D'Amore #include <time.h>
3095c635efSGarrett D'Amore 
3195c635efSGarrett D'Amore #include "mdoc.h"
3295c635efSGarrett D'Amore #include "mandoc.h"
3395c635efSGarrett D'Amore #include "libmdoc.h"
3495c635efSGarrett D'Amore #include "libmandoc.h"
3595c635efSGarrett D'Amore 
3695c635efSGarrett D'Amore const	char *const __mdoc_macronames[MDOC_MAX] = {
3795c635efSGarrett D'Amore 	"Ap",		"Dd",		"Dt",		"Os",
3895c635efSGarrett D'Amore 	"Sh",		"Ss",		"Pp",		"D1",
3995c635efSGarrett D'Amore 	"Dl",		"Bd",		"Ed",		"Bl",
4095c635efSGarrett D'Amore 	"El",		"It",		"Ad",		"An",
4195c635efSGarrett D'Amore 	"Ar",		"Cd",		"Cm",		"Dv",
4295c635efSGarrett D'Amore 	"Er",		"Ev",		"Ex",		"Fa",
4395c635efSGarrett D'Amore 	"Fd",		"Fl",		"Fn",		"Ft",
4495c635efSGarrett D'Amore 	"Ic",		"In",		"Li",		"Nd",
4595c635efSGarrett D'Amore 	"Nm",		"Op",		"Ot",		"Pa",
4695c635efSGarrett D'Amore 	"Rv",		"St",		"Va",		"Vt",
4795c635efSGarrett D'Amore 	/* LINTED */
4895c635efSGarrett D'Amore 	"Xr",		"%A",		"%B",		"%D",
4995c635efSGarrett D'Amore 	/* LINTED */
5095c635efSGarrett D'Amore 	"%I",		"%J",		"%N",		"%O",
5195c635efSGarrett D'Amore 	/* LINTED */
5295c635efSGarrett D'Amore 	"%P",		"%R",		"%T",		"%V",
5395c635efSGarrett D'Amore 	"Ac",		"Ao",		"Aq",		"At",
5495c635efSGarrett D'Amore 	"Bc",		"Bf",		"Bo",		"Bq",
5595c635efSGarrett D'Amore 	"Bsx",		"Bx",		"Db",		"Dc",
5695c635efSGarrett D'Amore 	"Do",		"Dq",		"Ec",		"Ef",
5795c635efSGarrett D'Amore 	"Em",		"Eo",		"Fx",		"Ms",
5895c635efSGarrett D'Amore 	"No",		"Ns",		"Nx",		"Ox",
5995c635efSGarrett D'Amore 	"Pc",		"Pf",		"Po",		"Pq",
6095c635efSGarrett D'Amore 	"Qc",		"Ql",		"Qo",		"Qq",
6195c635efSGarrett D'Amore 	"Re",		"Rs",		"Sc",		"So",
6295c635efSGarrett D'Amore 	"Sq",		"Sm",		"Sx",		"Sy",
6395c635efSGarrett D'Amore 	"Tn",		"Ux",		"Xc",		"Xo",
6495c635efSGarrett D'Amore 	"Fo",		"Fc",		"Oo",		"Oc",
6595c635efSGarrett D'Amore 	"Bk",		"Ek",		"Bt",		"Hf",
6695c635efSGarrett D'Amore 	"Fr",		"Ud",		"Lb",		"Lp",
6795c635efSGarrett D'Amore 	"Lk",		"Mt",		"Brq",		"Bro",
6895c635efSGarrett D'Amore 	/* LINTED */
6995c635efSGarrett D'Amore 	"Brc",		"%C",		"Es",		"En",
7095c635efSGarrett D'Amore 	/* LINTED */
7195c635efSGarrett D'Amore 	"Dx",		"%Q",		"br",		"sp",
7295c635efSGarrett D'Amore 	/* LINTED */
7395c635efSGarrett D'Amore 	"%U",		"Ta"
7495c635efSGarrett D'Amore 	};
7595c635efSGarrett D'Amore 
7695c635efSGarrett D'Amore const	char *const __mdoc_argnames[MDOC_ARG_MAX] = {
7795c635efSGarrett D'Amore 	"split",		"nosplit",		"ragged",
7895c635efSGarrett D'Amore 	"unfilled",		"literal",		"file",
7995c635efSGarrett D'Amore 	"offset",		"bullet",		"dash",
8095c635efSGarrett D'Amore 	"hyphen",		"item",			"enum",
8195c635efSGarrett D'Amore 	"tag",			"diag",			"hang",
8295c635efSGarrett D'Amore 	"ohang",		"inset",		"column",
8395c635efSGarrett D'Amore 	"width",		"compact",		"std",
8495c635efSGarrett D'Amore 	"filled",		"words",		"emphasis",
8595c635efSGarrett D'Amore 	"symbolic",		"nested",		"centered"
8695c635efSGarrett D'Amore 	};
8795c635efSGarrett D'Amore 
8895c635efSGarrett D'Amore const	char * const *mdoc_macronames = __mdoc_macronames;
8995c635efSGarrett D'Amore const	char * const *mdoc_argnames = __mdoc_argnames;
9095c635efSGarrett D'Amore 
9195c635efSGarrett D'Amore static	void		  mdoc_node_free(struct mdoc_node *);
9295c635efSGarrett D'Amore static	void		  mdoc_node_unlink(struct mdoc *,
9395c635efSGarrett D'Amore 				struct mdoc_node *);
9495c635efSGarrett D'Amore static	void		  mdoc_free1(struct mdoc *);
9595c635efSGarrett D'Amore static	void		  mdoc_alloc1(struct mdoc *);
9695c635efSGarrett D'Amore static	struct mdoc_node *node_alloc(struct mdoc *, int, int,
9795c635efSGarrett D'Amore 				enum mdoct, enum mdoc_type);
9895c635efSGarrett D'Amore static	int		  node_append(struct mdoc *,
9995c635efSGarrett D'Amore 				struct mdoc_node *);
10095c635efSGarrett D'Amore #if 0
10195c635efSGarrett D'Amore static	int		  mdoc_preptext(struct mdoc *, int, char *, int);
10295c635efSGarrett D'Amore #endif
10395c635efSGarrett D'Amore static	int		  mdoc_ptext(struct mdoc *, int, char *, int);
10495c635efSGarrett D'Amore static	int		  mdoc_pmacro(struct mdoc *, int, char *, int);
10595c635efSGarrett D'Amore 
10695c635efSGarrett D'Amore const struct mdoc_node *
mdoc_node(const struct mdoc * mdoc)107*698f87a4SGarrett D'Amore mdoc_node(const struct mdoc *mdoc)
10895c635efSGarrett D'Amore {
10995c635efSGarrett D'Amore 
110*698f87a4SGarrett D'Amore 	assert( ! (MDOC_HALT & mdoc->flags));
111*698f87a4SGarrett D'Amore 	return(mdoc->first);
11295c635efSGarrett D'Amore }
11395c635efSGarrett D'Amore 
11495c635efSGarrett D'Amore 
11595c635efSGarrett D'Amore const struct mdoc_meta *
mdoc_meta(const struct mdoc * mdoc)116*698f87a4SGarrett D'Amore mdoc_meta(const struct mdoc *mdoc)
11795c635efSGarrett D'Amore {
11895c635efSGarrett D'Amore 
119*698f87a4SGarrett D'Amore 	assert( ! (MDOC_HALT & mdoc->flags));
120*698f87a4SGarrett D'Amore 	return(&mdoc->meta);
12195c635efSGarrett D'Amore }
12295c635efSGarrett D'Amore 
12395c635efSGarrett D'Amore 
12495c635efSGarrett D'Amore /*
12595c635efSGarrett D'Amore  * Frees volatile resources (parse tree, meta-data, fields).
12695c635efSGarrett D'Amore  */
12795c635efSGarrett D'Amore static void
mdoc_free1(struct mdoc * mdoc)12895c635efSGarrett D'Amore mdoc_free1(struct mdoc *mdoc)
12995c635efSGarrett D'Amore {
13095c635efSGarrett D'Amore 
13195c635efSGarrett D'Amore 	if (mdoc->first)
13295c635efSGarrett D'Amore 		mdoc_node_delete(mdoc, mdoc->first);
13395c635efSGarrett D'Amore 	if (mdoc->meta.title)
13495c635efSGarrett D'Amore 		free(mdoc->meta.title);
13595c635efSGarrett D'Amore 	if (mdoc->meta.os)
13695c635efSGarrett D'Amore 		free(mdoc->meta.os);
13795c635efSGarrett D'Amore 	if (mdoc->meta.name)
13895c635efSGarrett D'Amore 		free(mdoc->meta.name);
13995c635efSGarrett D'Amore 	if (mdoc->meta.arch)
14095c635efSGarrett D'Amore 		free(mdoc->meta.arch);
14195c635efSGarrett D'Amore 	if (mdoc->meta.vol)
14295c635efSGarrett D'Amore 		free(mdoc->meta.vol);
14395c635efSGarrett D'Amore 	if (mdoc->meta.msec)
14495c635efSGarrett D'Amore 		free(mdoc->meta.msec);
14595c635efSGarrett D'Amore 	if (mdoc->meta.date)
14695c635efSGarrett D'Amore 		free(mdoc->meta.date);
14795c635efSGarrett D'Amore }
14895c635efSGarrett D'Amore 
14995c635efSGarrett D'Amore 
15095c635efSGarrett D'Amore /*
15195c635efSGarrett D'Amore  * Allocate all volatile resources (parse tree, meta-data, fields).
15295c635efSGarrett D'Amore  */
15395c635efSGarrett D'Amore static void
mdoc_alloc1(struct mdoc * mdoc)15495c635efSGarrett D'Amore mdoc_alloc1(struct mdoc *mdoc)
15595c635efSGarrett D'Amore {
15695c635efSGarrett D'Amore 
15795c635efSGarrett D'Amore 	memset(&mdoc->meta, 0, sizeof(struct mdoc_meta));
15895c635efSGarrett D'Amore 	mdoc->flags = 0;
15995c635efSGarrett D'Amore 	mdoc->lastnamed = mdoc->lastsec = SEC_NONE;
16095c635efSGarrett D'Amore 	mdoc->last = mandoc_calloc(1, sizeof(struct mdoc_node));
16195c635efSGarrett D'Amore 	mdoc->first = mdoc->last;
16295c635efSGarrett D'Amore 	mdoc->last->type = MDOC_ROOT;
16395c635efSGarrett D'Amore 	mdoc->last->tok = MDOC_MAX;
16495c635efSGarrett D'Amore 	mdoc->next = MDOC_NEXT_CHILD;
16595c635efSGarrett D'Amore }
16695c635efSGarrett D'Amore 
16795c635efSGarrett D'Amore 
16895c635efSGarrett D'Amore /*
16995c635efSGarrett D'Amore  * Free up volatile resources (see mdoc_free1()) then re-initialises the
17095c635efSGarrett D'Amore  * data with mdoc_alloc1().  After invocation, parse data has been reset
17195c635efSGarrett D'Amore  * and the parser is ready for re-invocation on a new tree; however,
17295c635efSGarrett D'Amore  * cross-parse non-volatile data is kept intact.
17395c635efSGarrett D'Amore  */
17495c635efSGarrett D'Amore void
mdoc_reset(struct mdoc * mdoc)17595c635efSGarrett D'Amore mdoc_reset(struct mdoc *mdoc)
17695c635efSGarrett D'Amore {
17795c635efSGarrett D'Amore 
17895c635efSGarrett D'Amore 	mdoc_free1(mdoc);
17995c635efSGarrett D'Amore 	mdoc_alloc1(mdoc);
18095c635efSGarrett D'Amore }
18195c635efSGarrett D'Amore 
18295c635efSGarrett D'Amore 
18395c635efSGarrett D'Amore /*
18495c635efSGarrett D'Amore  * Completely free up all volatile and non-volatile parse resources.
18595c635efSGarrett D'Amore  * After invocation, the pointer is no longer usable.
18695c635efSGarrett D'Amore  */
18795c635efSGarrett D'Amore void
mdoc_free(struct mdoc * mdoc)18895c635efSGarrett D'Amore mdoc_free(struct mdoc *mdoc)
18995c635efSGarrett D'Amore {
19095c635efSGarrett D'Amore 
19195c635efSGarrett D'Amore 	mdoc_free1(mdoc);
19295c635efSGarrett D'Amore 	free(mdoc);
19395c635efSGarrett D'Amore }
19495c635efSGarrett D'Amore 
19595c635efSGarrett D'Amore 
19695c635efSGarrett D'Amore /*
19795c635efSGarrett D'Amore  * Allocate volatile and non-volatile parse resources.
19895c635efSGarrett D'Amore  */
19995c635efSGarrett D'Amore struct mdoc *
mdoc_alloc(struct roff * roff,struct mparse * parse,char * defos)200*698f87a4SGarrett D'Amore mdoc_alloc(struct roff *roff, struct mparse *parse, char *defos)
20195c635efSGarrett D'Amore {
20295c635efSGarrett D'Amore 	struct mdoc	*p;
20395c635efSGarrett D'Amore 
20495c635efSGarrett D'Amore 	p = mandoc_calloc(1, sizeof(struct mdoc));
20595c635efSGarrett D'Amore 
20695c635efSGarrett D'Amore 	p->parse = parse;
207*698f87a4SGarrett D'Amore 	p->defos = defos;
20895c635efSGarrett D'Amore 	p->roff = roff;
20995c635efSGarrett D'Amore 
21095c635efSGarrett D'Amore 	mdoc_hash_init();
21195c635efSGarrett D'Amore 	mdoc_alloc1(p);
21295c635efSGarrett D'Amore 	return(p);
21395c635efSGarrett D'Amore }
21495c635efSGarrett D'Amore 
21595c635efSGarrett D'Amore 
21695c635efSGarrett D'Amore /*
21795c635efSGarrett D'Amore  * Climb back up the parse tree, validating open scopes.  Mostly calls
21895c635efSGarrett D'Amore  * through to macro_end() in macro.c.
21995c635efSGarrett D'Amore  */
22095c635efSGarrett D'Amore int
mdoc_endparse(struct mdoc * mdoc)221*698f87a4SGarrett D'Amore mdoc_endparse(struct mdoc *mdoc)
22295c635efSGarrett D'Amore {
22395c635efSGarrett D'Amore 
224*698f87a4SGarrett D'Amore 	assert( ! (MDOC_HALT & mdoc->flags));
225*698f87a4SGarrett D'Amore 	if (mdoc_macroend(mdoc))
22695c635efSGarrett D'Amore 		return(1);
227*698f87a4SGarrett D'Amore 	mdoc->flags |= MDOC_HALT;
22895c635efSGarrett D'Amore 	return(0);
22995c635efSGarrett D'Amore }
23095c635efSGarrett D'Amore 
23195c635efSGarrett D'Amore int
mdoc_addeqn(struct mdoc * mdoc,const struct eqn * ep)232*698f87a4SGarrett D'Amore mdoc_addeqn(struct mdoc *mdoc, const struct eqn *ep)
23395c635efSGarrett D'Amore {
23495c635efSGarrett D'Amore 	struct mdoc_node *n;
23595c635efSGarrett D'Amore 
236*698f87a4SGarrett D'Amore 	assert( ! (MDOC_HALT & mdoc->flags));
23795c635efSGarrett D'Amore 
23895c635efSGarrett D'Amore 	/* No text before an initial macro. */
23995c635efSGarrett D'Amore 
240*698f87a4SGarrett D'Amore 	if (SEC_NONE == mdoc->lastnamed) {
241*698f87a4SGarrett D'Amore 		mdoc_pmsg(mdoc, ep->ln, ep->pos, MANDOCERR_NOTEXT);
24295c635efSGarrett D'Amore 		return(1);
24395c635efSGarrett D'Amore 	}
24495c635efSGarrett D'Amore 
245*698f87a4SGarrett D'Amore 	n = node_alloc(mdoc, ep->ln, ep->pos, MDOC_MAX, MDOC_EQN);
24695c635efSGarrett D'Amore 	n->eqn = ep;
24795c635efSGarrett D'Amore 
248*698f87a4SGarrett D'Amore 	if ( ! node_append(mdoc, n))
24995c635efSGarrett D'Amore 		return(0);
25095c635efSGarrett D'Amore 
251*698f87a4SGarrett D'Amore 	mdoc->next = MDOC_NEXT_SIBLING;
25295c635efSGarrett D'Amore 	return(1);
25395c635efSGarrett D'Amore }
25495c635efSGarrett D'Amore 
25595c635efSGarrett D'Amore int
mdoc_addspan(struct mdoc * mdoc,const struct tbl_span * sp)256*698f87a4SGarrett D'Amore mdoc_addspan(struct mdoc *mdoc, const struct tbl_span *sp)
25795c635efSGarrett D'Amore {
25895c635efSGarrett D'Amore 	struct mdoc_node *n;
25995c635efSGarrett D'Amore 
260*698f87a4SGarrett D'Amore 	assert( ! (MDOC_HALT & mdoc->flags));
26195c635efSGarrett D'Amore 
26295c635efSGarrett D'Amore 	/* No text before an initial macro. */
26395c635efSGarrett D'Amore 
264*698f87a4SGarrett D'Amore 	if (SEC_NONE == mdoc->lastnamed) {
265*698f87a4SGarrett D'Amore 		mdoc_pmsg(mdoc, sp->line, 0, MANDOCERR_NOTEXT);
26695c635efSGarrett D'Amore 		return(1);
26795c635efSGarrett D'Amore 	}
26895c635efSGarrett D'Amore 
269*698f87a4SGarrett D'Amore 	n = node_alloc(mdoc, sp->line, 0, MDOC_MAX, MDOC_TBL);
27095c635efSGarrett D'Amore 	n->span = sp;
27195c635efSGarrett D'Amore 
272*698f87a4SGarrett D'Amore 	if ( ! node_append(mdoc, n))
27395c635efSGarrett D'Amore 		return(0);
27495c635efSGarrett D'Amore 
275*698f87a4SGarrett D'Amore 	mdoc->next = MDOC_NEXT_SIBLING;
27695c635efSGarrett D'Amore 	return(1);
27795c635efSGarrett D'Amore }
27895c635efSGarrett D'Amore 
27995c635efSGarrett D'Amore 
28095c635efSGarrett D'Amore /*
28195c635efSGarrett D'Amore  * Main parse routine.  Parses a single line -- really just hands off to
28295c635efSGarrett D'Amore  * the macro (mdoc_pmacro()) or text parser (mdoc_ptext()).
28395c635efSGarrett D'Amore  */
28495c635efSGarrett D'Amore int
mdoc_parseln(struct mdoc * mdoc,int ln,char * buf,int offs)285*698f87a4SGarrett D'Amore mdoc_parseln(struct mdoc *mdoc, int ln, char *buf, int offs)
28695c635efSGarrett D'Amore {
28795c635efSGarrett D'Amore 
288*698f87a4SGarrett D'Amore 	assert( ! (MDOC_HALT & mdoc->flags));
28995c635efSGarrett D'Amore 
290*698f87a4SGarrett D'Amore 	mdoc->flags |= MDOC_NEWLINE;
29195c635efSGarrett D'Amore 
29295c635efSGarrett D'Amore 	/*
29395c635efSGarrett D'Amore 	 * Let the roff nS register switch SYNOPSIS mode early,
29495c635efSGarrett D'Amore 	 * such that the parser knows at all times
29595c635efSGarrett D'Amore 	 * whether this mode is on or off.
29695c635efSGarrett D'Amore 	 * Note that this mode is also switched by the Sh macro.
29795c635efSGarrett D'Amore 	 */
298*698f87a4SGarrett D'Amore 	if (roff_getreg(mdoc->roff, "nS"))
299*698f87a4SGarrett D'Amore 		mdoc->flags |= MDOC_SYNOPSIS;
30095c635efSGarrett D'Amore 	else
301*698f87a4SGarrett D'Amore 		mdoc->flags &= ~MDOC_SYNOPSIS;
30295c635efSGarrett D'Amore 
303*698f87a4SGarrett D'Amore 	return(roff_getcontrol(mdoc->roff, buf, &offs) ?
304*698f87a4SGarrett D'Amore 			mdoc_pmacro(mdoc, ln, buf, offs) :
305*698f87a4SGarrett D'Amore 			mdoc_ptext(mdoc, ln, buf, offs));
30695c635efSGarrett D'Amore }
30795c635efSGarrett D'Amore 
30895c635efSGarrett D'Amore int
mdoc_macro(MACRO_PROT_ARGS)30995c635efSGarrett D'Amore mdoc_macro(MACRO_PROT_ARGS)
31095c635efSGarrett D'Amore {
31195c635efSGarrett D'Amore 	assert(tok < MDOC_MAX);
31295c635efSGarrett D'Amore 
31395c635efSGarrett D'Amore 	/* If we're in the body, deny prologue calls. */
31495c635efSGarrett D'Amore 
31595c635efSGarrett D'Amore 	if (MDOC_PROLOGUE & mdoc_macros[tok].flags &&
316*698f87a4SGarrett D'Amore 			MDOC_PBODY & mdoc->flags) {
317*698f87a4SGarrett D'Amore 		mdoc_pmsg(mdoc, line, ppos, MANDOCERR_BADBODY);
31895c635efSGarrett D'Amore 		return(1);
31995c635efSGarrett D'Amore 	}
32095c635efSGarrett D'Amore 
32195c635efSGarrett D'Amore 	/* If we're in the prologue, deny "body" macros.  */
32295c635efSGarrett D'Amore 
32395c635efSGarrett D'Amore 	if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) &&
324*698f87a4SGarrett D'Amore 			! (MDOC_PBODY & mdoc->flags)) {
325*698f87a4SGarrett D'Amore 		mdoc_pmsg(mdoc, line, ppos, MANDOCERR_BADPROLOG);
326*698f87a4SGarrett D'Amore 		if (NULL == mdoc->meta.msec)
327*698f87a4SGarrett D'Amore 			mdoc->meta.msec = mandoc_strdup("1");
328*698f87a4SGarrett D'Amore 		if (NULL == mdoc->meta.title)
329*698f87a4SGarrett D'Amore 			mdoc->meta.title = mandoc_strdup("UNKNOWN");
330*698f87a4SGarrett D'Amore 		if (NULL == mdoc->meta.vol)
331*698f87a4SGarrett D'Amore 			mdoc->meta.vol = mandoc_strdup("LOCAL");
332*698f87a4SGarrett D'Amore 		if (NULL == mdoc->meta.os)
333*698f87a4SGarrett D'Amore 			mdoc->meta.os = mandoc_strdup("LOCAL");
334*698f87a4SGarrett D'Amore 		if (NULL == mdoc->meta.date)
335*698f87a4SGarrett D'Amore 			mdoc->meta.date = mandoc_normdate
336*698f87a4SGarrett D'Amore 				(mdoc->parse, NULL, line, ppos);
337*698f87a4SGarrett D'Amore 		mdoc->flags |= MDOC_PBODY;
33895c635efSGarrett D'Amore 	}
33995c635efSGarrett D'Amore 
340*698f87a4SGarrett D'Amore 	return((*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf));
34195c635efSGarrett D'Amore }
34295c635efSGarrett D'Amore 
34395c635efSGarrett D'Amore 
34495c635efSGarrett D'Amore static int
node_append(struct mdoc * mdoc,struct mdoc_node * p)34595c635efSGarrett D'Amore node_append(struct mdoc *mdoc, struct mdoc_node *p)
34695c635efSGarrett D'Amore {
34795c635efSGarrett D'Amore 
34895c635efSGarrett D'Amore 	assert(mdoc->last);
34995c635efSGarrett D'Amore 	assert(mdoc->first);
35095c635efSGarrett D'Amore 	assert(MDOC_ROOT != p->type);
35195c635efSGarrett D'Amore 
35295c635efSGarrett D'Amore 	switch (mdoc->next) {
35395c635efSGarrett D'Amore 	case (MDOC_NEXT_SIBLING):
35495c635efSGarrett D'Amore 		mdoc->last->next = p;
35595c635efSGarrett D'Amore 		p->prev = mdoc->last;
35695c635efSGarrett D'Amore 		p->parent = mdoc->last->parent;
35795c635efSGarrett D'Amore 		break;
35895c635efSGarrett D'Amore 	case (MDOC_NEXT_CHILD):
35995c635efSGarrett D'Amore 		mdoc->last->child = p;
36095c635efSGarrett D'Amore 		p->parent = mdoc->last;
36195c635efSGarrett D'Amore 		break;
36295c635efSGarrett D'Amore 	default:
36395c635efSGarrett D'Amore 		abort();
36495c635efSGarrett D'Amore 		/* NOTREACHED */
36595c635efSGarrett D'Amore 	}
36695c635efSGarrett D'Amore 
36795c635efSGarrett D'Amore 	p->parent->nchild++;
36895c635efSGarrett D'Amore 
36995c635efSGarrett D'Amore 	/*
37095c635efSGarrett D'Amore 	 * Copy over the normalised-data pointer of our parent.  Not
37195c635efSGarrett D'Amore 	 * everybody has one, but copying a null pointer is fine.
37295c635efSGarrett D'Amore 	 */
37395c635efSGarrett D'Amore 
37495c635efSGarrett D'Amore 	switch (p->type) {
37595c635efSGarrett D'Amore 	case (MDOC_BODY):
376*698f87a4SGarrett D'Amore 		if (ENDBODY_NOT != p->end)
377*698f87a4SGarrett D'Amore 			break;
37895c635efSGarrett D'Amore 		/* FALLTHROUGH */
37995c635efSGarrett D'Amore 	case (MDOC_TAIL):
38095c635efSGarrett D'Amore 		/* FALLTHROUGH */
38195c635efSGarrett D'Amore 	case (MDOC_HEAD):
38295c635efSGarrett D'Amore 		p->norm = p->parent->norm;
38395c635efSGarrett D'Amore 		break;
38495c635efSGarrett D'Amore 	default:
38595c635efSGarrett D'Amore 		break;
38695c635efSGarrett D'Amore 	}
38795c635efSGarrett D'Amore 
38895c635efSGarrett D'Amore 	if ( ! mdoc_valid_pre(mdoc, p))
38995c635efSGarrett D'Amore 		return(0);
39095c635efSGarrett D'Amore 
39195c635efSGarrett D'Amore 	switch (p->type) {
39295c635efSGarrett D'Amore 	case (MDOC_HEAD):
39395c635efSGarrett D'Amore 		assert(MDOC_BLOCK == p->parent->type);
39495c635efSGarrett D'Amore 		p->parent->head = p;
39595c635efSGarrett D'Amore 		break;
39695c635efSGarrett D'Amore 	case (MDOC_TAIL):
39795c635efSGarrett D'Amore 		assert(MDOC_BLOCK == p->parent->type);
39895c635efSGarrett D'Amore 		p->parent->tail = p;
39995c635efSGarrett D'Amore 		break;
40095c635efSGarrett D'Amore 	case (MDOC_BODY):
40195c635efSGarrett D'Amore 		if (p->end)
40295c635efSGarrett D'Amore 			break;
40395c635efSGarrett D'Amore 		assert(MDOC_BLOCK == p->parent->type);
40495c635efSGarrett D'Amore 		p->parent->body = p;
40595c635efSGarrett D'Amore 		break;
40695c635efSGarrett D'Amore 	default:
40795c635efSGarrett D'Amore 		break;
40895c635efSGarrett D'Amore 	}
40995c635efSGarrett D'Amore 
41095c635efSGarrett D'Amore 	mdoc->last = p;
41195c635efSGarrett D'Amore 
41295c635efSGarrett D'Amore 	switch (p->type) {
41395c635efSGarrett D'Amore 	case (MDOC_TBL):
41495c635efSGarrett D'Amore 		/* FALLTHROUGH */
41595c635efSGarrett D'Amore 	case (MDOC_TEXT):
41695c635efSGarrett D'Amore 		if ( ! mdoc_valid_post(mdoc))
41795c635efSGarrett D'Amore 			return(0);
41895c635efSGarrett D'Amore 		break;
41995c635efSGarrett D'Amore 	default:
42095c635efSGarrett D'Amore 		break;
42195c635efSGarrett D'Amore 	}
42295c635efSGarrett D'Amore 
42395c635efSGarrett D'Amore 	return(1);
42495c635efSGarrett D'Amore }
42595c635efSGarrett D'Amore 
42695c635efSGarrett D'Amore 
42795c635efSGarrett D'Amore static struct mdoc_node *
node_alloc(struct mdoc * mdoc,int line,int pos,enum mdoct tok,enum mdoc_type type)428*698f87a4SGarrett D'Amore node_alloc(struct mdoc *mdoc, int line, int pos,
42995c635efSGarrett D'Amore 		enum mdoct tok, enum mdoc_type type)
43095c635efSGarrett D'Amore {
43195c635efSGarrett D'Amore 	struct mdoc_node *p;
43295c635efSGarrett D'Amore 
43395c635efSGarrett D'Amore 	p = mandoc_calloc(1, sizeof(struct mdoc_node));
434*698f87a4SGarrett D'Amore 	p->sec = mdoc->lastsec;
43595c635efSGarrett D'Amore 	p->line = line;
43695c635efSGarrett D'Amore 	p->pos = pos;
437*698f87a4SGarrett D'Amore 	p->lastline = line;
43895c635efSGarrett D'Amore 	p->tok = tok;
43995c635efSGarrett D'Amore 	p->type = type;
44095c635efSGarrett D'Amore 
44195c635efSGarrett D'Amore 	/* Flag analysis. */
44295c635efSGarrett D'Amore 
443*698f87a4SGarrett D'Amore 	if (MDOC_SYNOPSIS & mdoc->flags)
44495c635efSGarrett D'Amore 		p->flags |= MDOC_SYNPRETTY;
44595c635efSGarrett D'Amore 	else
44695c635efSGarrett D'Amore 		p->flags &= ~MDOC_SYNPRETTY;
447*698f87a4SGarrett D'Amore 	if (MDOC_NEWLINE & mdoc->flags)
44895c635efSGarrett D'Amore 		p->flags |= MDOC_LINE;
449*698f87a4SGarrett D'Amore 	mdoc->flags &= ~MDOC_NEWLINE;
45095c635efSGarrett D'Amore 
45195c635efSGarrett D'Amore 	return(p);
45295c635efSGarrett D'Amore }
45395c635efSGarrett D'Amore 
45495c635efSGarrett D'Amore 
45595c635efSGarrett D'Amore int
mdoc_tail_alloc(struct mdoc * mdoc,int line,int pos,enum mdoct tok)456*698f87a4SGarrett D'Amore mdoc_tail_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
45795c635efSGarrett D'Amore {
45895c635efSGarrett D'Amore 	struct mdoc_node *p;
45995c635efSGarrett D'Amore 
460*698f87a4SGarrett D'Amore 	p = node_alloc(mdoc, line, pos, tok, MDOC_TAIL);
461*698f87a4SGarrett D'Amore 	if ( ! node_append(mdoc, p))
46295c635efSGarrett D'Amore 		return(0);
463*698f87a4SGarrett D'Amore 	mdoc->next = MDOC_NEXT_CHILD;
46495c635efSGarrett D'Amore 	return(1);
46595c635efSGarrett D'Amore }
46695c635efSGarrett D'Amore 
46795c635efSGarrett D'Amore 
46895c635efSGarrett D'Amore int
mdoc_head_alloc(struct mdoc * mdoc,int line,int pos,enum mdoct tok)469*698f87a4SGarrett D'Amore mdoc_head_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
47095c635efSGarrett D'Amore {
47195c635efSGarrett D'Amore 	struct mdoc_node *p;
47295c635efSGarrett D'Amore 
473*698f87a4SGarrett D'Amore 	assert(mdoc->first);
474*698f87a4SGarrett D'Amore 	assert(mdoc->last);
47595c635efSGarrett D'Amore 
476*698f87a4SGarrett D'Amore 	p = node_alloc(mdoc, line, pos, tok, MDOC_HEAD);
477*698f87a4SGarrett D'Amore 	if ( ! node_append(mdoc, p))
47895c635efSGarrett D'Amore 		return(0);
479*698f87a4SGarrett D'Amore 	mdoc->next = MDOC_NEXT_CHILD;
48095c635efSGarrett D'Amore 	return(1);
48195c635efSGarrett D'Amore }
48295c635efSGarrett D'Amore 
48395c635efSGarrett D'Amore 
48495c635efSGarrett D'Amore int
mdoc_body_alloc(struct mdoc * mdoc,int line,int pos,enum mdoct tok)485*698f87a4SGarrett D'Amore mdoc_body_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
48695c635efSGarrett D'Amore {
48795c635efSGarrett D'Amore 	struct mdoc_node *p;
48895c635efSGarrett D'Amore 
489*698f87a4SGarrett D'Amore 	p = node_alloc(mdoc, line, pos, tok, MDOC_BODY);
490*698f87a4SGarrett D'Amore 	if ( ! node_append(mdoc, p))
49195c635efSGarrett D'Amore 		return(0);
492*698f87a4SGarrett D'Amore 	mdoc->next = MDOC_NEXT_CHILD;
49395c635efSGarrett D'Amore 	return(1);
49495c635efSGarrett D'Amore }
49595c635efSGarrett D'Amore 
49695c635efSGarrett D'Amore 
49795c635efSGarrett D'Amore int
mdoc_endbody_alloc(struct mdoc * mdoc,int line,int pos,enum mdoct tok,struct mdoc_node * body,enum mdoc_endbody end)498*698f87a4SGarrett D'Amore mdoc_endbody_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok,
49995c635efSGarrett D'Amore 		struct mdoc_node *body, enum mdoc_endbody end)
50095c635efSGarrett D'Amore {
50195c635efSGarrett D'Amore 	struct mdoc_node *p;
50295c635efSGarrett D'Amore 
503*698f87a4SGarrett D'Amore 	p = node_alloc(mdoc, line, pos, tok, MDOC_BODY);
50495c635efSGarrett D'Amore 	p->pending = body;
505*698f87a4SGarrett D'Amore 	p->norm = body->norm;
50695c635efSGarrett D'Amore 	p->end = end;
507*698f87a4SGarrett D'Amore 	if ( ! node_append(mdoc, p))
50895c635efSGarrett D'Amore 		return(0);
509*698f87a4SGarrett D'Amore 	mdoc->next = MDOC_NEXT_SIBLING;
51095c635efSGarrett D'Amore 	return(1);
51195c635efSGarrett D'Amore }
51295c635efSGarrett D'Amore 
51395c635efSGarrett D'Amore 
51495c635efSGarrett D'Amore int
mdoc_block_alloc(struct mdoc * mdoc,int line,int pos,enum mdoct tok,struct mdoc_arg * args)515*698f87a4SGarrett D'Amore mdoc_block_alloc(struct mdoc *mdoc, int line, int pos,
51695c635efSGarrett D'Amore 		enum mdoct tok, struct mdoc_arg *args)
51795c635efSGarrett D'Amore {
51895c635efSGarrett D'Amore 	struct mdoc_node *p;
51995c635efSGarrett D'Amore 
520*698f87a4SGarrett D'Amore 	p = node_alloc(mdoc, line, pos, tok, MDOC_BLOCK);
52195c635efSGarrett D'Amore 	p->args = args;
52295c635efSGarrett D'Amore 	if (p->args)
52395c635efSGarrett D'Amore 		(args->refcnt)++;
52495c635efSGarrett D'Amore 
52595c635efSGarrett D'Amore 	switch (tok) {
52695c635efSGarrett D'Amore 	case (MDOC_Bd):
52795c635efSGarrett D'Amore 		/* FALLTHROUGH */
52895c635efSGarrett D'Amore 	case (MDOC_Bf):
52995c635efSGarrett D'Amore 		/* FALLTHROUGH */
53095c635efSGarrett D'Amore 	case (MDOC_Bl):
53195c635efSGarrett D'Amore 		/* FALLTHROUGH */
53295c635efSGarrett D'Amore 	case (MDOC_Rs):
53395c635efSGarrett D'Amore 		p->norm = mandoc_calloc(1, sizeof(union mdoc_data));
53495c635efSGarrett D'Amore 		break;
53595c635efSGarrett D'Amore 	default:
53695c635efSGarrett D'Amore 		break;
53795c635efSGarrett D'Amore 	}
53895c635efSGarrett D'Amore 
539*698f87a4SGarrett D'Amore 	if ( ! node_append(mdoc, p))
54095c635efSGarrett D'Amore 		return(0);
541*698f87a4SGarrett D'Amore 	mdoc->next = MDOC_NEXT_CHILD;
54295c635efSGarrett D'Amore 	return(1);
54395c635efSGarrett D'Amore }
54495c635efSGarrett D'Amore 
54595c635efSGarrett D'Amore 
54695c635efSGarrett D'Amore int
mdoc_elem_alloc(struct mdoc * mdoc,int line,int pos,enum mdoct tok,struct mdoc_arg * args)547*698f87a4SGarrett D'Amore mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos,
54895c635efSGarrett D'Amore 		enum mdoct tok, struct mdoc_arg *args)
54995c635efSGarrett D'Amore {
55095c635efSGarrett D'Amore 	struct mdoc_node *p;
55195c635efSGarrett D'Amore 
552*698f87a4SGarrett D'Amore 	p = node_alloc(mdoc, line, pos, tok, MDOC_ELEM);
55395c635efSGarrett D'Amore 	p->args = args;
55495c635efSGarrett D'Amore 	if (p->args)
55595c635efSGarrett D'Amore 		(args->refcnt)++;
55695c635efSGarrett D'Amore 
55795c635efSGarrett D'Amore 	switch (tok) {
55895c635efSGarrett D'Amore 	case (MDOC_An):
55995c635efSGarrett D'Amore 		p->norm = mandoc_calloc(1, sizeof(union mdoc_data));
56095c635efSGarrett D'Amore 		break;
56195c635efSGarrett D'Amore 	default:
56295c635efSGarrett D'Amore 		break;
56395c635efSGarrett D'Amore 	}
56495c635efSGarrett D'Amore 
565*698f87a4SGarrett D'Amore 	if ( ! node_append(mdoc, p))
56695c635efSGarrett D'Amore 		return(0);
567*698f87a4SGarrett D'Amore 	mdoc->next = MDOC_NEXT_CHILD;
56895c635efSGarrett D'Amore 	return(1);
56995c635efSGarrett D'Amore }
57095c635efSGarrett D'Amore 
57195c635efSGarrett D'Amore int
mdoc_word_alloc(struct mdoc * mdoc,int line,int pos,const char * p)572*698f87a4SGarrett D'Amore mdoc_word_alloc(struct mdoc *mdoc, int line, int pos, const char *p)
57395c635efSGarrett D'Amore {
57495c635efSGarrett D'Amore 	struct mdoc_node *n;
57595c635efSGarrett D'Amore 
576*698f87a4SGarrett D'Amore 	n = node_alloc(mdoc, line, pos, MDOC_MAX, MDOC_TEXT);
577*698f87a4SGarrett D'Amore 	n->string = roff_strdup(mdoc->roff, p);
57895c635efSGarrett D'Amore 
579*698f87a4SGarrett D'Amore 	if ( ! node_append(mdoc, n))
58095c635efSGarrett D'Amore 		return(0);
58195c635efSGarrett D'Amore 
582*698f87a4SGarrett D'Amore 	mdoc->next = MDOC_NEXT_SIBLING;
58395c635efSGarrett D'Amore 	return(1);
58495c635efSGarrett D'Amore }
58595c635efSGarrett D'Amore 
586*698f87a4SGarrett D'Amore void
mdoc_word_append(struct mdoc * mdoc,const char * p)587*698f87a4SGarrett D'Amore mdoc_word_append(struct mdoc *mdoc, const char *p)
588*698f87a4SGarrett D'Amore {
589*698f87a4SGarrett D'Amore 	struct mdoc_node	*n;
590*698f87a4SGarrett D'Amore 	char			*addstr, *newstr;
591*698f87a4SGarrett D'Amore 
592*698f87a4SGarrett D'Amore 	n = mdoc->last;
593*698f87a4SGarrett D'Amore 	addstr = roff_strdup(mdoc->roff, p);
594*698f87a4SGarrett D'Amore 	if (-1 == asprintf(&newstr, "%s %s", n->string, addstr)) {
595*698f87a4SGarrett D'Amore 		perror(NULL);
596*698f87a4SGarrett D'Amore 		exit((int)MANDOCLEVEL_SYSERR);
597*698f87a4SGarrett D'Amore 	}
598*698f87a4SGarrett D'Amore 	free(addstr);
599*698f87a4SGarrett D'Amore 	free(n->string);
600*698f87a4SGarrett D'Amore 	n->string = newstr;
601*698f87a4SGarrett D'Amore 	mdoc->next = MDOC_NEXT_SIBLING;
602*698f87a4SGarrett D'Amore }
60395c635efSGarrett D'Amore 
60495c635efSGarrett D'Amore static void
mdoc_node_free(struct mdoc_node * p)60595c635efSGarrett D'Amore mdoc_node_free(struct mdoc_node *p)
60695c635efSGarrett D'Amore {
60795c635efSGarrett D'Amore 
60895c635efSGarrett D'Amore 	if (MDOC_BLOCK == p->type || MDOC_ELEM == p->type)
60995c635efSGarrett D'Amore 		free(p->norm);
61095c635efSGarrett D'Amore 	if (p->string)
61195c635efSGarrett D'Amore 		free(p->string);
61295c635efSGarrett D'Amore 	if (p->args)
61395c635efSGarrett D'Amore 		mdoc_argv_free(p->args);
61495c635efSGarrett D'Amore 	free(p);
61595c635efSGarrett D'Amore }
61695c635efSGarrett D'Amore 
61795c635efSGarrett D'Amore 
61895c635efSGarrett D'Amore static void
mdoc_node_unlink(struct mdoc * mdoc,struct mdoc_node * n)619*698f87a4SGarrett D'Amore mdoc_node_unlink(struct mdoc *mdoc, struct mdoc_node *n)
62095c635efSGarrett D'Amore {
62195c635efSGarrett D'Amore 
62295c635efSGarrett D'Amore 	/* Adjust siblings. */
62395c635efSGarrett D'Amore 
62495c635efSGarrett D'Amore 	if (n->prev)
62595c635efSGarrett D'Amore 		n->prev->next = n->next;
62695c635efSGarrett D'Amore 	if (n->next)
62795c635efSGarrett D'Amore 		n->next->prev = n->prev;
62895c635efSGarrett D'Amore 
62995c635efSGarrett D'Amore 	/* Adjust parent. */
63095c635efSGarrett D'Amore 
63195c635efSGarrett D'Amore 	if (n->parent) {
63295c635efSGarrett D'Amore 		n->parent->nchild--;
63395c635efSGarrett D'Amore 		if (n->parent->child == n)
63495c635efSGarrett D'Amore 			n->parent->child = n->prev ? n->prev : n->next;
63595c635efSGarrett D'Amore 		if (n->parent->last == n)
63695c635efSGarrett D'Amore 			n->parent->last = n->prev ? n->prev : NULL;
63795c635efSGarrett D'Amore 	}
63895c635efSGarrett D'Amore 
63995c635efSGarrett D'Amore 	/* Adjust parse point, if applicable. */
64095c635efSGarrett D'Amore 
641*698f87a4SGarrett D'Amore 	if (mdoc && mdoc->last == n) {
64295c635efSGarrett D'Amore 		if (n->prev) {
643*698f87a4SGarrett D'Amore 			mdoc->last = n->prev;
644*698f87a4SGarrett D'Amore 			mdoc->next = MDOC_NEXT_SIBLING;
64595c635efSGarrett D'Amore 		} else {
646*698f87a4SGarrett D'Amore 			mdoc->last = n->parent;
647*698f87a4SGarrett D'Amore 			mdoc->next = MDOC_NEXT_CHILD;
64895c635efSGarrett D'Amore 		}
64995c635efSGarrett D'Amore 	}
65095c635efSGarrett D'Amore 
651*698f87a4SGarrett D'Amore 	if (mdoc && mdoc->first == n)
652*698f87a4SGarrett D'Amore 		mdoc->first = NULL;
65395c635efSGarrett D'Amore }
65495c635efSGarrett D'Amore 
65595c635efSGarrett D'Amore 
65695c635efSGarrett D'Amore void
mdoc_node_delete(struct mdoc * mdoc,struct mdoc_node * p)657*698f87a4SGarrett D'Amore mdoc_node_delete(struct mdoc *mdoc, struct mdoc_node *p)
65895c635efSGarrett D'Amore {
65995c635efSGarrett D'Amore 
66095c635efSGarrett D'Amore 	while (p->child) {
66195c635efSGarrett D'Amore 		assert(p->nchild);
662*698f87a4SGarrett D'Amore 		mdoc_node_delete(mdoc, p->child);
66395c635efSGarrett D'Amore 	}
66495c635efSGarrett D'Amore 	assert(0 == p->nchild);
66595c635efSGarrett D'Amore 
666*698f87a4SGarrett D'Amore 	mdoc_node_unlink(mdoc, p);
66795c635efSGarrett D'Amore 	mdoc_node_free(p);
66895c635efSGarrett D'Amore }
66995c635efSGarrett D'Amore 
670*698f87a4SGarrett D'Amore int
mdoc_node_relink(struct mdoc * mdoc,struct mdoc_node * p)671*698f87a4SGarrett D'Amore mdoc_node_relink(struct mdoc *mdoc, struct mdoc_node *p)
672*698f87a4SGarrett D'Amore {
673*698f87a4SGarrett D'Amore 
674*698f87a4SGarrett D'Amore 	mdoc_node_unlink(mdoc, p);
675*698f87a4SGarrett D'Amore 	return(node_append(mdoc, p));
676*698f87a4SGarrett D'Amore }
677*698f87a4SGarrett D'Amore 
67895c635efSGarrett D'Amore #if 0
67995c635efSGarrett D'Amore /*
68095c635efSGarrett D'Amore  * Pre-treat a text line.
68195c635efSGarrett D'Amore  * Text lines can consist of equations, which must be handled apart from
68295c635efSGarrett D'Amore  * the regular text.
68395c635efSGarrett D'Amore  * Thus, use this function to step through a line checking if it has any
68495c635efSGarrett D'Amore  * equations embedded in it.
68595c635efSGarrett D'Amore  * This must handle multiple equations AND equations that do not end at
68695c635efSGarrett D'Amore  * the end-of-line, i.e., will re-enter in the next roff parse.
68795c635efSGarrett D'Amore  */
68895c635efSGarrett D'Amore static int
689*698f87a4SGarrett D'Amore mdoc_preptext(struct mdoc *mdoc, int line, char *buf, int offs)
69095c635efSGarrett D'Amore {
69195c635efSGarrett D'Amore 	char		*start, *end;
69295c635efSGarrett D'Amore 	char		 delim;
69395c635efSGarrett D'Amore 
69495c635efSGarrett D'Amore 	while ('\0' != buf[offs]) {
69595c635efSGarrett D'Amore 		/* Mark starting position if eqn is set. */
69695c635efSGarrett D'Amore 		start = NULL;
697*698f87a4SGarrett D'Amore 		if ('\0' != (delim = roff_eqndelim(mdoc->roff)))
69895c635efSGarrett D'Amore 			if (NULL != (start = strchr(buf + offs, delim)))
69995c635efSGarrett D'Amore 				*start++ = '\0';
70095c635efSGarrett D'Amore 
70195c635efSGarrett D'Amore 		/* Parse text as normal. */
702*698f87a4SGarrett D'Amore 		if ( ! mdoc_ptext(mdoc, line, buf, offs))
70395c635efSGarrett D'Amore 			return(0);
70495c635efSGarrett D'Amore 
70595c635efSGarrett D'Amore 		/* Continue only if an equation exists. */
70695c635efSGarrett D'Amore 		if (NULL == start)
70795c635efSGarrett D'Amore 			break;
70895c635efSGarrett D'Amore 
70995c635efSGarrett D'Amore 		/* Read past the end of the equation. */
71095c635efSGarrett D'Amore 		offs += start - (buf + offs);
71195c635efSGarrett D'Amore 		assert(start == &buf[offs]);
71295c635efSGarrett D'Amore 		if (NULL != (end = strchr(buf + offs, delim))) {
71395c635efSGarrett D'Amore 			*end++ = '\0';
71495c635efSGarrett D'Amore 			while (' ' == *end)
71595c635efSGarrett D'Amore 				end++;
71695c635efSGarrett D'Amore 		}
71795c635efSGarrett D'Amore 
71895c635efSGarrett D'Amore 		/* Parse the equation itself. */
719*698f87a4SGarrett D'Amore 		roff_openeqn(mdoc->roff, NULL, line, offs, buf);
72095c635efSGarrett D'Amore 
72195c635efSGarrett D'Amore 		/* Process a finished equation? */
722*698f87a4SGarrett D'Amore 		if (roff_closeeqn(mdoc->roff))
723*698f87a4SGarrett D'Amore 			if ( ! mdoc_addeqn(mdoc, roff_eqn(mdoc->roff)))
72495c635efSGarrett D'Amore 				return(0);
72595c635efSGarrett D'Amore 		offs += (end - (buf + offs));
72695c635efSGarrett D'Amore 	}
72795c635efSGarrett D'Amore 
72895c635efSGarrett D'Amore 	return(1);
72995c635efSGarrett D'Amore }
73095c635efSGarrett D'Amore #endif
73195c635efSGarrett D'Amore 
73295c635efSGarrett D'Amore /*
73395c635efSGarrett D'Amore  * Parse free-form text, that is, a line that does not begin with the
73495c635efSGarrett D'Amore  * control character.
73595c635efSGarrett D'Amore  */
73695c635efSGarrett D'Amore static int
mdoc_ptext(struct mdoc * mdoc,int line,char * buf,int offs)737*698f87a4SGarrett D'Amore mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
73895c635efSGarrett D'Amore {
73995c635efSGarrett D'Amore 	char		 *c, *ws, *end;
74095c635efSGarrett D'Amore 	struct mdoc_node *n;
74195c635efSGarrett D'Amore 
74295c635efSGarrett D'Amore 	/* No text before an initial macro. */
74395c635efSGarrett D'Amore 
744*698f87a4SGarrett D'Amore 	if (SEC_NONE == mdoc->lastnamed) {
745*698f87a4SGarrett D'Amore 		mdoc_pmsg(mdoc, line, offs, MANDOCERR_NOTEXT);
74695c635efSGarrett D'Amore 		return(1);
74795c635efSGarrett D'Amore 	}
74895c635efSGarrett D'Amore 
749*698f87a4SGarrett D'Amore 	assert(mdoc->last);
750*698f87a4SGarrett D'Amore 	n = mdoc->last;
75195c635efSGarrett D'Amore 
75295c635efSGarrett D'Amore 	/*
75395c635efSGarrett D'Amore 	 * Divert directly to list processing if we're encountering a
75495c635efSGarrett D'Amore 	 * columnar MDOC_BLOCK with or without a prior MDOC_BLOCK entry
75595c635efSGarrett D'Amore 	 * (a MDOC_BODY means it's already open, in which case we should
75695c635efSGarrett D'Amore 	 * process within its context in the normal way).
75795c635efSGarrett D'Amore 	 */
75895c635efSGarrett D'Amore 
75995c635efSGarrett D'Amore 	if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
76095c635efSGarrett D'Amore 			LIST_column == n->norm->Bl.type) {
76195c635efSGarrett D'Amore 		/* `Bl' is open without any children. */
762*698f87a4SGarrett D'Amore 		mdoc->flags |= MDOC_FREECOL;
763*698f87a4SGarrett D'Amore 		return(mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf));
76495c635efSGarrett D'Amore 	}
76595c635efSGarrett D'Amore 
76695c635efSGarrett D'Amore 	if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
76795c635efSGarrett D'Amore 			NULL != n->parent &&
76895c635efSGarrett D'Amore 			MDOC_Bl == n->parent->tok &&
76995c635efSGarrett D'Amore 			LIST_column == n->parent->norm->Bl.type) {
77095c635efSGarrett D'Amore 		/* `Bl' has block-level `It' children. */
771*698f87a4SGarrett D'Amore 		mdoc->flags |= MDOC_FREECOL;
772*698f87a4SGarrett D'Amore 		return(mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf));
77395c635efSGarrett D'Amore 	}
77495c635efSGarrett D'Amore 
77595c635efSGarrett D'Amore 	/*
77695c635efSGarrett D'Amore 	 * Search for the beginning of unescaped trailing whitespace (ws)
77795c635efSGarrett D'Amore 	 * and for the first character not to be output (end).
77895c635efSGarrett D'Amore 	 */
77995c635efSGarrett D'Amore 
78095c635efSGarrett D'Amore 	/* FIXME: replace with strcspn(). */
78195c635efSGarrett D'Amore 	ws = NULL;
78295c635efSGarrett D'Amore 	for (c = end = buf + offs; *c; c++) {
78395c635efSGarrett D'Amore 		switch (*c) {
78495c635efSGarrett D'Amore 		case ' ':
78595c635efSGarrett D'Amore 			if (NULL == ws)
78695c635efSGarrett D'Amore 				ws = c;
78795c635efSGarrett D'Amore 			continue;
78895c635efSGarrett D'Amore 		case '\t':
78995c635efSGarrett D'Amore 			/*
79095c635efSGarrett D'Amore 			 * Always warn about trailing tabs,
79195c635efSGarrett D'Amore 			 * even outside literal context,
79295c635efSGarrett D'Amore 			 * where they should be put on the next line.
79395c635efSGarrett D'Amore 			 */
79495c635efSGarrett D'Amore 			if (NULL == ws)
79595c635efSGarrett D'Amore 				ws = c;
79695c635efSGarrett D'Amore 			/*
79795c635efSGarrett D'Amore 			 * Strip trailing tabs in literal context only;
79895c635efSGarrett D'Amore 			 * outside, they affect the next line.
79995c635efSGarrett D'Amore 			 */
800*698f87a4SGarrett D'Amore 			if (MDOC_LITERAL & mdoc->flags)
80195c635efSGarrett D'Amore 				continue;
80295c635efSGarrett D'Amore 			break;
80395c635efSGarrett D'Amore 		case '\\':
80495c635efSGarrett D'Amore 			/* Skip the escaped character, too, if any. */
80595c635efSGarrett D'Amore 			if (c[1])
80695c635efSGarrett D'Amore 				c++;
80795c635efSGarrett D'Amore 			/* FALLTHROUGH */
80895c635efSGarrett D'Amore 		default:
80995c635efSGarrett D'Amore 			ws = NULL;
81095c635efSGarrett D'Amore 			break;
81195c635efSGarrett D'Amore 		}
81295c635efSGarrett D'Amore 		end = c + 1;
81395c635efSGarrett D'Amore 	}
81495c635efSGarrett D'Amore 	*end = '\0';
81595c635efSGarrett D'Amore 
81695c635efSGarrett D'Amore 	if (ws)
817*698f87a4SGarrett D'Amore 		mdoc_pmsg(mdoc, line, (int)(ws-buf), MANDOCERR_EOLNSPACE);
81895c635efSGarrett D'Amore 
819*698f87a4SGarrett D'Amore 	if ('\0' == buf[offs] && ! (MDOC_LITERAL & mdoc->flags)) {
820*698f87a4SGarrett D'Amore 		mdoc_pmsg(mdoc, line, (int)(c-buf), MANDOCERR_NOBLANKLN);
82195c635efSGarrett D'Amore 
82295c635efSGarrett D'Amore 		/*
82395c635efSGarrett D'Amore 		 * Insert a `sp' in the case of a blank line.  Technically,
82495c635efSGarrett D'Amore 		 * blank lines aren't allowed, but enough manuals assume this
82595c635efSGarrett D'Amore 		 * behaviour that we want to work around it.
82695c635efSGarrett D'Amore 		 */
827*698f87a4SGarrett D'Amore 		if ( ! mdoc_elem_alloc(mdoc, line, offs, MDOC_sp, NULL))
82895c635efSGarrett D'Amore 			return(0);
82995c635efSGarrett D'Amore 
830*698f87a4SGarrett D'Amore 		mdoc->next = MDOC_NEXT_SIBLING;
831*698f87a4SGarrett D'Amore 
832*698f87a4SGarrett D'Amore 		return(mdoc_valid_post(mdoc));
83395c635efSGarrett D'Amore 	}
83495c635efSGarrett D'Amore 
835*698f87a4SGarrett D'Amore 	if ( ! mdoc_word_alloc(mdoc, line, offs, buf+offs))
83695c635efSGarrett D'Amore 		return(0);
83795c635efSGarrett D'Amore 
838*698f87a4SGarrett D'Amore 	if (MDOC_LITERAL & mdoc->flags)
83995c635efSGarrett D'Amore 		return(1);
84095c635efSGarrett D'Amore 
84195c635efSGarrett D'Amore 	/*
84295c635efSGarrett D'Amore 	 * End-of-sentence check.  If the last character is an unescaped
84395c635efSGarrett D'Amore 	 * EOS character, then flag the node as being the end of a
84495c635efSGarrett D'Amore 	 * sentence.  The front-end will know how to interpret this.
84595c635efSGarrett D'Amore 	 */
84695c635efSGarrett D'Amore 
84795c635efSGarrett D'Amore 	assert(buf < end);
84895c635efSGarrett D'Amore 
84995c635efSGarrett D'Amore 	if (mandoc_eos(buf+offs, (size_t)(end-buf-offs), 0))
850*698f87a4SGarrett D'Amore 		mdoc->last->flags |= MDOC_EOS;
85195c635efSGarrett D'Amore 
85295c635efSGarrett D'Amore 	return(1);
85395c635efSGarrett D'Amore }
85495c635efSGarrett D'Amore 
85595c635efSGarrett D'Amore 
85695c635efSGarrett D'Amore /*
85795c635efSGarrett D'Amore  * Parse a macro line, that is, a line beginning with the control
85895c635efSGarrett D'Amore  * character.
85995c635efSGarrett D'Amore  */
86095c635efSGarrett D'Amore static int
mdoc_pmacro(struct mdoc * mdoc,int ln,char * buf,int offs)861*698f87a4SGarrett D'Amore mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
86295c635efSGarrett D'Amore {
86395c635efSGarrett D'Amore 	enum mdoct	  tok;
86495c635efSGarrett D'Amore 	int		  i, sv;
86595c635efSGarrett D'Amore 	char		  mac[5];
86695c635efSGarrett D'Amore 	struct mdoc_node *n;
86795c635efSGarrett D'Amore 
86895c635efSGarrett D'Amore 	/* Empty post-control lines are ignored. */
86995c635efSGarrett D'Amore 
87095c635efSGarrett D'Amore 	if ('"' == buf[offs]) {
871*698f87a4SGarrett D'Amore 		mdoc_pmsg(mdoc, ln, offs, MANDOCERR_BADCOMMENT);
87295c635efSGarrett D'Amore 		return(1);
87395c635efSGarrett D'Amore 	} else if ('\0' == buf[offs])
87495c635efSGarrett D'Amore 		return(1);
87595c635efSGarrett D'Amore 
87695c635efSGarrett D'Amore 	sv = offs;
87795c635efSGarrett D'Amore 
87895c635efSGarrett D'Amore 	/*
87995c635efSGarrett D'Amore 	 * Copy the first word into a nil-terminated buffer.
88095c635efSGarrett D'Amore 	 * Stop copying when a tab, space, or eoln is encountered.
88195c635efSGarrett D'Amore 	 */
88295c635efSGarrett D'Amore 
88395c635efSGarrett D'Amore 	i = 0;
88495c635efSGarrett D'Amore 	while (i < 4 && '\0' != buf[offs] &&
88595c635efSGarrett D'Amore 			' ' != buf[offs] && '\t' != buf[offs])
88695c635efSGarrett D'Amore 		mac[i++] = buf[offs++];
88795c635efSGarrett D'Amore 
88895c635efSGarrett D'Amore 	mac[i] = '\0';
88995c635efSGarrett D'Amore 
89095c635efSGarrett D'Amore 	tok = (i > 1 || i < 4) ? mdoc_hash_find(mac) : MDOC_MAX;
89195c635efSGarrett D'Amore 
89295c635efSGarrett D'Amore 	if (MDOC_MAX == tok) {
893*698f87a4SGarrett D'Amore 		mandoc_vmsg(MANDOCERR_MACRO, mdoc->parse,
89495c635efSGarrett D'Amore 				ln, sv, "%s", buf + sv - 1);
89595c635efSGarrett D'Amore 		return(1);
89695c635efSGarrett D'Amore 	}
89795c635efSGarrett D'Amore 
89895c635efSGarrett D'Amore 	/* Disregard the first trailing tab, if applicable. */
89995c635efSGarrett D'Amore 
90095c635efSGarrett D'Amore 	if ('\t' == buf[offs])
90195c635efSGarrett D'Amore 		offs++;
90295c635efSGarrett D'Amore 
90395c635efSGarrett D'Amore 	/* Jump to the next non-whitespace word. */
90495c635efSGarrett D'Amore 
90595c635efSGarrett D'Amore 	while (buf[offs] && ' ' == buf[offs])
90695c635efSGarrett D'Amore 		offs++;
90795c635efSGarrett D'Amore 
90895c635efSGarrett D'Amore 	/*
90995c635efSGarrett D'Amore 	 * Trailing whitespace.  Note that tabs are allowed to be passed
91095c635efSGarrett D'Amore 	 * into the parser as "text", so we only warn about spaces here.
91195c635efSGarrett D'Amore 	 */
91295c635efSGarrett D'Amore 
91395c635efSGarrett D'Amore 	if ('\0' == buf[offs] && ' ' == buf[offs - 1])
914*698f87a4SGarrett D'Amore 		mdoc_pmsg(mdoc, ln, offs - 1, MANDOCERR_EOLNSPACE);
91595c635efSGarrett D'Amore 
91695c635efSGarrett D'Amore 	/*
91795c635efSGarrett D'Amore 	 * If an initial macro or a list invocation, divert directly
91895c635efSGarrett D'Amore 	 * into macro processing.
91995c635efSGarrett D'Amore 	 */
92095c635efSGarrett D'Amore 
921*698f87a4SGarrett D'Amore 	if (NULL == mdoc->last || MDOC_It == tok || MDOC_El == tok) {
922*698f87a4SGarrett D'Amore 		if ( ! mdoc_macro(mdoc, tok, ln, sv, &offs, buf))
92395c635efSGarrett D'Amore 			goto err;
92495c635efSGarrett D'Amore 		return(1);
92595c635efSGarrett D'Amore 	}
92695c635efSGarrett D'Amore 
927*698f87a4SGarrett D'Amore 	n = mdoc->last;
928*698f87a4SGarrett D'Amore 	assert(mdoc->last);
92995c635efSGarrett D'Amore 
93095c635efSGarrett D'Amore 	/*
93195c635efSGarrett D'Amore 	 * If the first macro of a `Bl -column', open an `It' block
93295c635efSGarrett D'Amore 	 * context around the parsed macro.
93395c635efSGarrett D'Amore 	 */
93495c635efSGarrett D'Amore 
93595c635efSGarrett D'Amore 	if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
93695c635efSGarrett D'Amore 			LIST_column == n->norm->Bl.type) {
937*698f87a4SGarrett D'Amore 		mdoc->flags |= MDOC_FREECOL;
938*698f87a4SGarrett D'Amore 		if ( ! mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf))
93995c635efSGarrett D'Amore 			goto err;
94095c635efSGarrett D'Amore 		return(1);
94195c635efSGarrett D'Amore 	}
94295c635efSGarrett D'Amore 
94395c635efSGarrett D'Amore 	/*
94495c635efSGarrett D'Amore 	 * If we're following a block-level `It' within a `Bl -column'
94595c635efSGarrett D'Amore 	 * context (perhaps opened in the above block or in ptext()),
94695c635efSGarrett D'Amore 	 * then open an `It' block context around the parsed macro.
94795c635efSGarrett D'Amore 	 */
94895c635efSGarrett D'Amore 
94995c635efSGarrett D'Amore 	if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
95095c635efSGarrett D'Amore 			NULL != n->parent &&
95195c635efSGarrett D'Amore 			MDOC_Bl == n->parent->tok &&
95295c635efSGarrett D'Amore 			LIST_column == n->parent->norm->Bl.type) {
953*698f87a4SGarrett D'Amore 		mdoc->flags |= MDOC_FREECOL;
954*698f87a4SGarrett D'Amore 		if ( ! mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf))
95595c635efSGarrett D'Amore 			goto err;
95695c635efSGarrett D'Amore 		return(1);
95795c635efSGarrett D'Amore 	}
95895c635efSGarrett D'Amore 
95995c635efSGarrett D'Amore 	/* Normal processing of a macro. */
96095c635efSGarrett D'Amore 
961*698f87a4SGarrett D'Amore 	if ( ! mdoc_macro(mdoc, tok, ln, sv, &offs, buf))
96295c635efSGarrett D'Amore 		goto err;
96395c635efSGarrett D'Amore 
96495c635efSGarrett D'Amore 	return(1);
96595c635efSGarrett D'Amore 
96695c635efSGarrett D'Amore err:	/* Error out. */
96795c635efSGarrett D'Amore 
968*698f87a4SGarrett D'Amore 	mdoc->flags |= MDOC_HALT;
96995c635efSGarrett D'Amore 	return(0);
97095c635efSGarrett D'Amore }
97195c635efSGarrett D'Amore 
97295c635efSGarrett D'Amore enum mdelim
mdoc_isdelim(const char * p)97395c635efSGarrett D'Amore mdoc_isdelim(const char *p)
97495c635efSGarrett D'Amore {
97595c635efSGarrett D'Amore 
97695c635efSGarrett D'Amore 	if ('\0' == p[0])
97795c635efSGarrett D'Amore 		return(DELIM_NONE);
97895c635efSGarrett D'Amore 
97995c635efSGarrett D'Amore 	if ('\0' == p[1])
98095c635efSGarrett D'Amore 		switch (p[0]) {
98195c635efSGarrett D'Amore 		case('('):
98295c635efSGarrett D'Amore 			/* FALLTHROUGH */
98395c635efSGarrett D'Amore 		case('['):
98495c635efSGarrett D'Amore 			return(DELIM_OPEN);
98595c635efSGarrett D'Amore 		case('|'):
98695c635efSGarrett D'Amore 			return(DELIM_MIDDLE);
98795c635efSGarrett D'Amore 		case('.'):
98895c635efSGarrett D'Amore 			/* FALLTHROUGH */
98995c635efSGarrett D'Amore 		case(','):
99095c635efSGarrett D'Amore 			/* FALLTHROUGH */
99195c635efSGarrett D'Amore 		case(';'):
99295c635efSGarrett D'Amore 			/* FALLTHROUGH */
99395c635efSGarrett D'Amore 		case(':'):
99495c635efSGarrett D'Amore 			/* FALLTHROUGH */
99595c635efSGarrett D'Amore 		case('?'):
99695c635efSGarrett D'Amore 			/* FALLTHROUGH */
99795c635efSGarrett D'Amore 		case('!'):
99895c635efSGarrett D'Amore 			/* FALLTHROUGH */
99995c635efSGarrett D'Amore 		case(')'):
100095c635efSGarrett D'Amore 			/* FALLTHROUGH */
100195c635efSGarrett D'Amore 		case(']'):
100295c635efSGarrett D'Amore 			return(DELIM_CLOSE);
100395c635efSGarrett D'Amore 		default:
100495c635efSGarrett D'Amore 			return(DELIM_NONE);
100595c635efSGarrett D'Amore 		}
100695c635efSGarrett D'Amore 
100795c635efSGarrett D'Amore 	if ('\\' != p[0])
100895c635efSGarrett D'Amore 		return(DELIM_NONE);
100995c635efSGarrett D'Amore 
101095c635efSGarrett D'Amore 	if (0 == strcmp(p + 1, "."))
101195c635efSGarrett D'Amore 		return(DELIM_CLOSE);
1012*698f87a4SGarrett D'Amore 	if (0 == strcmp(p + 1, "fR|\\fP"))
101395c635efSGarrett D'Amore 		return(DELIM_MIDDLE);
101495c635efSGarrett D'Amore 
101595c635efSGarrett D'Amore 	return(DELIM_NONE);
101695c635efSGarrett D'Amore }
1017