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