1*260e9a87SYuri Pankov /* $Id: mdoc.c,v 1.238 2015/02/12 13:00:52 schwarze Exp $ */
295c635efSGarrett D'Amore /*
395c635efSGarrett D'Amore * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*260e9a87SYuri Pankov * Copyright (c) 2010, 2012-2015 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 #include "config.h"
1995c635efSGarrett D'Amore
2095c635efSGarrett D'Amore #include <sys/types.h>
2195c635efSGarrett D'Amore
2295c635efSGarrett D'Amore #include <assert.h>
23*260e9a87SYuri Pankov #include <ctype.h>
2495c635efSGarrett D'Amore #include <stdarg.h>
2595c635efSGarrett D'Amore #include <stdio.h>
2695c635efSGarrett D'Amore #include <stdlib.h>
2795c635efSGarrett D'Amore #include <string.h>
2895c635efSGarrett D'Amore #include <time.h>
2995c635efSGarrett D'Amore
3095c635efSGarrett D'Amore #include "mdoc.h"
3195c635efSGarrett D'Amore #include "mandoc.h"
32*260e9a87SYuri Pankov #include "mandoc_aux.h"
3395c635efSGarrett D'Amore #include "libmdoc.h"
3495c635efSGarrett D'Amore #include "libmandoc.h"
3595c635efSGarrett D'Amore
36*260e9a87SYuri Pankov const char *const __mdoc_macronames[MDOC_MAX + 1] = {
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 "Xr", "%A", "%B", "%D",
4895c635efSGarrett D'Amore "%I", "%J", "%N", "%O",
4995c635efSGarrett D'Amore "%P", "%R", "%T", "%V",
5095c635efSGarrett D'Amore "Ac", "Ao", "Aq", "At",
5195c635efSGarrett D'Amore "Bc", "Bf", "Bo", "Bq",
5295c635efSGarrett D'Amore "Bsx", "Bx", "Db", "Dc",
5395c635efSGarrett D'Amore "Do", "Dq", "Ec", "Ef",
5495c635efSGarrett D'Amore "Em", "Eo", "Fx", "Ms",
5595c635efSGarrett D'Amore "No", "Ns", "Nx", "Ox",
5695c635efSGarrett D'Amore "Pc", "Pf", "Po", "Pq",
5795c635efSGarrett D'Amore "Qc", "Ql", "Qo", "Qq",
5895c635efSGarrett D'Amore "Re", "Rs", "Sc", "So",
5995c635efSGarrett D'Amore "Sq", "Sm", "Sx", "Sy",
6095c635efSGarrett D'Amore "Tn", "Ux", "Xc", "Xo",
6195c635efSGarrett D'Amore "Fo", "Fc", "Oo", "Oc",
6295c635efSGarrett D'Amore "Bk", "Ek", "Bt", "Hf",
6395c635efSGarrett D'Amore "Fr", "Ud", "Lb", "Lp",
6495c635efSGarrett D'Amore "Lk", "Mt", "Brq", "Bro",
6595c635efSGarrett D'Amore "Brc", "%C", "Es", "En",
6695c635efSGarrett D'Amore "Dx", "%Q", "br", "sp",
67*260e9a87SYuri Pankov "%U", "Ta", "ll", "text",
6895c635efSGarrett D'Amore };
6995c635efSGarrett D'Amore
7095c635efSGarrett D'Amore const char *const __mdoc_argnames[MDOC_ARG_MAX] = {
7195c635efSGarrett D'Amore "split", "nosplit", "ragged",
7295c635efSGarrett D'Amore "unfilled", "literal", "file",
7395c635efSGarrett D'Amore "offset", "bullet", "dash",
7495c635efSGarrett D'Amore "hyphen", "item", "enum",
7595c635efSGarrett D'Amore "tag", "diag", "hang",
7695c635efSGarrett D'Amore "ohang", "inset", "column",
7795c635efSGarrett D'Amore "width", "compact", "std",
7895c635efSGarrett D'Amore "filled", "words", "emphasis",
7995c635efSGarrett D'Amore "symbolic", "nested", "centered"
8095c635efSGarrett D'Amore };
8195c635efSGarrett D'Amore
8295c635efSGarrett D'Amore const char * const *mdoc_macronames = __mdoc_macronames;
8395c635efSGarrett D'Amore const char * const *mdoc_argnames = __mdoc_argnames;
8495c635efSGarrett D'Amore
8595c635efSGarrett D'Amore static void mdoc_node_free(struct mdoc_node *);
8695c635efSGarrett D'Amore static void mdoc_node_unlink(struct mdoc *,
8795c635efSGarrett D'Amore struct mdoc_node *);
8895c635efSGarrett D'Amore static void mdoc_free1(struct mdoc *);
8995c635efSGarrett D'Amore static void mdoc_alloc1(struct mdoc *);
9095c635efSGarrett D'Amore static struct mdoc_node *node_alloc(struct mdoc *, int, int,
9195c635efSGarrett D'Amore enum mdoct, enum mdoc_type);
92*260e9a87SYuri Pankov static void node_append(struct mdoc *, struct mdoc_node *);
9395c635efSGarrett D'Amore static int mdoc_ptext(struct mdoc *, int, char *, int);
9495c635efSGarrett D'Amore static int mdoc_pmacro(struct mdoc *, int, char *, int);
9595c635efSGarrett D'Amore
96*260e9a87SYuri Pankov
9795c635efSGarrett D'Amore const struct mdoc_node *
mdoc_node(const struct mdoc * mdoc)98698f87a4SGarrett D'Amore mdoc_node(const struct mdoc *mdoc)
9995c635efSGarrett D'Amore {
10095c635efSGarrett D'Amore
101698f87a4SGarrett D'Amore return(mdoc->first);
10295c635efSGarrett D'Amore }
10395c635efSGarrett D'Amore
10495c635efSGarrett D'Amore const struct mdoc_meta *
mdoc_meta(const struct mdoc * mdoc)105698f87a4SGarrett D'Amore mdoc_meta(const struct mdoc *mdoc)
10695c635efSGarrett D'Amore {
10795c635efSGarrett D'Amore
108698f87a4SGarrett D'Amore return(&mdoc->meta);
10995c635efSGarrett D'Amore }
11095c635efSGarrett D'Amore
11195c635efSGarrett D'Amore /*
11295c635efSGarrett D'Amore * Frees volatile resources (parse tree, meta-data, fields).
11395c635efSGarrett D'Amore */
11495c635efSGarrett D'Amore static void
mdoc_free1(struct mdoc * mdoc)11595c635efSGarrett D'Amore mdoc_free1(struct mdoc *mdoc)
11695c635efSGarrett D'Amore {
11795c635efSGarrett D'Amore
11895c635efSGarrett D'Amore if (mdoc->first)
11995c635efSGarrett D'Amore mdoc_node_delete(mdoc, mdoc->first);
12095c635efSGarrett D'Amore free(mdoc->meta.msec);
121*260e9a87SYuri Pankov free(mdoc->meta.vol);
122*260e9a87SYuri Pankov free(mdoc->meta.arch);
12395c635efSGarrett D'Amore free(mdoc->meta.date);
124*260e9a87SYuri Pankov free(mdoc->meta.title);
125*260e9a87SYuri Pankov free(mdoc->meta.os);
126*260e9a87SYuri Pankov free(mdoc->meta.name);
12795c635efSGarrett D'Amore }
12895c635efSGarrett D'Amore
12995c635efSGarrett D'Amore /*
13095c635efSGarrett D'Amore * Allocate all volatile resources (parse tree, meta-data, fields).
13195c635efSGarrett D'Amore */
13295c635efSGarrett D'Amore static void
mdoc_alloc1(struct mdoc * mdoc)13395c635efSGarrett D'Amore mdoc_alloc1(struct mdoc *mdoc)
13495c635efSGarrett D'Amore {
13595c635efSGarrett D'Amore
13695c635efSGarrett D'Amore memset(&mdoc->meta, 0, sizeof(struct mdoc_meta));
13795c635efSGarrett D'Amore mdoc->flags = 0;
13895c635efSGarrett D'Amore mdoc->lastnamed = mdoc->lastsec = SEC_NONE;
13995c635efSGarrett D'Amore mdoc->last = mandoc_calloc(1, sizeof(struct mdoc_node));
14095c635efSGarrett D'Amore mdoc->first = mdoc->last;
14195c635efSGarrett D'Amore mdoc->last->type = MDOC_ROOT;
14295c635efSGarrett D'Amore mdoc->last->tok = MDOC_MAX;
14395c635efSGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD;
14495c635efSGarrett D'Amore }
14595c635efSGarrett D'Amore
14695c635efSGarrett D'Amore /*
14795c635efSGarrett D'Amore * Free up volatile resources (see mdoc_free1()) then re-initialises the
14895c635efSGarrett D'Amore * data with mdoc_alloc1(). After invocation, parse data has been reset
14995c635efSGarrett D'Amore * and the parser is ready for re-invocation on a new tree; however,
15095c635efSGarrett D'Amore * cross-parse non-volatile data is kept intact.
15195c635efSGarrett D'Amore */
15295c635efSGarrett D'Amore void
mdoc_reset(struct mdoc * mdoc)15395c635efSGarrett D'Amore mdoc_reset(struct mdoc *mdoc)
15495c635efSGarrett D'Amore {
15595c635efSGarrett D'Amore
15695c635efSGarrett D'Amore mdoc_free1(mdoc);
15795c635efSGarrett D'Amore mdoc_alloc1(mdoc);
15895c635efSGarrett D'Amore }
15995c635efSGarrett D'Amore
16095c635efSGarrett D'Amore /*
16195c635efSGarrett D'Amore * Completely free up all volatile and non-volatile parse resources.
16295c635efSGarrett D'Amore * After invocation, the pointer is no longer usable.
16395c635efSGarrett D'Amore */
16495c635efSGarrett D'Amore void
mdoc_free(struct mdoc * mdoc)16595c635efSGarrett D'Amore mdoc_free(struct mdoc *mdoc)
16695c635efSGarrett D'Amore {
16795c635efSGarrett D'Amore
16895c635efSGarrett D'Amore mdoc_free1(mdoc);
16995c635efSGarrett D'Amore free(mdoc);
17095c635efSGarrett D'Amore }
17195c635efSGarrett D'Amore
17295c635efSGarrett D'Amore /*
17395c635efSGarrett D'Amore * Allocate volatile and non-volatile parse resources.
17495c635efSGarrett D'Amore */
17595c635efSGarrett D'Amore struct mdoc *
mdoc_alloc(struct roff * roff,struct mparse * parse,const char * defos,int quick)176*260e9a87SYuri Pankov mdoc_alloc(struct roff *roff, struct mparse *parse,
177*260e9a87SYuri Pankov const char *defos, int quick)
17895c635efSGarrett D'Amore {
17995c635efSGarrett D'Amore struct mdoc *p;
18095c635efSGarrett D'Amore
18195c635efSGarrett D'Amore p = mandoc_calloc(1, sizeof(struct mdoc));
18295c635efSGarrett D'Amore
18395c635efSGarrett D'Amore p->parse = parse;
184698f87a4SGarrett D'Amore p->defos = defos;
185*260e9a87SYuri Pankov p->quick = quick;
18695c635efSGarrett D'Amore p->roff = roff;
18795c635efSGarrett D'Amore
18895c635efSGarrett D'Amore mdoc_hash_init();
18995c635efSGarrett D'Amore mdoc_alloc1(p);
19095c635efSGarrett D'Amore return(p);
19195c635efSGarrett D'Amore }
19295c635efSGarrett D'Amore
193*260e9a87SYuri Pankov void
mdoc_endparse(struct mdoc * mdoc)194698f87a4SGarrett D'Amore mdoc_endparse(struct mdoc *mdoc)
19595c635efSGarrett D'Amore {
19695c635efSGarrett D'Amore
197*260e9a87SYuri Pankov mdoc_macroend(mdoc);
19895c635efSGarrett D'Amore }
19995c635efSGarrett D'Amore
200*260e9a87SYuri Pankov void
mdoc_addeqn(struct mdoc * mdoc,const struct eqn * ep)201698f87a4SGarrett D'Amore mdoc_addeqn(struct mdoc *mdoc, const struct eqn *ep)
20295c635efSGarrett D'Amore {
20395c635efSGarrett D'Amore struct mdoc_node *n;
20495c635efSGarrett D'Amore
205698f87a4SGarrett D'Amore n = node_alloc(mdoc, ep->ln, ep->pos, MDOC_MAX, MDOC_EQN);
20695c635efSGarrett D'Amore n->eqn = ep;
207*260e9a87SYuri Pankov if (ep->ln > mdoc->last->line)
208*260e9a87SYuri Pankov n->flags |= MDOC_LINE;
209*260e9a87SYuri Pankov node_append(mdoc, n);
210698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING;
21195c635efSGarrett D'Amore }
21295c635efSGarrett D'Amore
213*260e9a87SYuri Pankov void
mdoc_addspan(struct mdoc * mdoc,const struct tbl_span * sp)214698f87a4SGarrett D'Amore mdoc_addspan(struct mdoc *mdoc, const struct tbl_span *sp)
21595c635efSGarrett D'Amore {
21695c635efSGarrett D'Amore struct mdoc_node *n;
21795c635efSGarrett D'Amore
218698f87a4SGarrett D'Amore n = node_alloc(mdoc, sp->line, 0, MDOC_MAX, MDOC_TBL);
21995c635efSGarrett D'Amore n->span = sp;
220*260e9a87SYuri Pankov node_append(mdoc, n);
221698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING;
22295c635efSGarrett D'Amore }
22395c635efSGarrett D'Amore
22495c635efSGarrett D'Amore /*
22595c635efSGarrett D'Amore * Main parse routine. Parses a single line -- really just hands off to
22695c635efSGarrett D'Amore * the macro (mdoc_pmacro()) or text parser (mdoc_ptext()).
22795c635efSGarrett D'Amore */
22895c635efSGarrett D'Amore int
mdoc_parseln(struct mdoc * mdoc,int ln,char * buf,int offs)229698f87a4SGarrett D'Amore mdoc_parseln(struct mdoc *mdoc, int ln, char *buf, int offs)
23095c635efSGarrett D'Amore {
23195c635efSGarrett D'Amore
232*260e9a87SYuri Pankov if (mdoc->last->type != MDOC_EQN || ln > mdoc->last->line)
233698f87a4SGarrett D'Amore mdoc->flags |= MDOC_NEWLINE;
23495c635efSGarrett D'Amore
23595c635efSGarrett D'Amore /*
23695c635efSGarrett D'Amore * Let the roff nS register switch SYNOPSIS mode early,
23795c635efSGarrett D'Amore * such that the parser knows at all times
23895c635efSGarrett D'Amore * whether this mode is on or off.
23995c635efSGarrett D'Amore * Note that this mode is also switched by the Sh macro.
24095c635efSGarrett D'Amore */
241698f87a4SGarrett D'Amore if (roff_getreg(mdoc->roff, "nS"))
242698f87a4SGarrett D'Amore mdoc->flags |= MDOC_SYNOPSIS;
24395c635efSGarrett D'Amore else
244698f87a4SGarrett D'Amore mdoc->flags &= ~MDOC_SYNOPSIS;
24595c635efSGarrett D'Amore
246698f87a4SGarrett D'Amore return(roff_getcontrol(mdoc->roff, buf, &offs) ?
247698f87a4SGarrett D'Amore mdoc_pmacro(mdoc, ln, buf, offs) :
248698f87a4SGarrett D'Amore mdoc_ptext(mdoc, ln, buf, offs));
24995c635efSGarrett D'Amore }
25095c635efSGarrett D'Amore
251*260e9a87SYuri Pankov void
mdoc_macro(MACRO_PROT_ARGS)25295c635efSGarrett D'Amore mdoc_macro(MACRO_PROT_ARGS)
25395c635efSGarrett D'Amore {
25495c635efSGarrett D'Amore assert(tok < MDOC_MAX);
25595c635efSGarrett D'Amore
256*260e9a87SYuri Pankov if (mdoc->flags & MDOC_PBODY) {
257*260e9a87SYuri Pankov if (tok == MDOC_Dt) {
258*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_DT_LATE,
259*260e9a87SYuri Pankov mdoc->parse, line, ppos,
260*260e9a87SYuri Pankov "Dt %s", buf + *pos);
261*260e9a87SYuri Pankov return;
26295c635efSGarrett D'Amore }
263*260e9a87SYuri Pankov } else if ( ! (mdoc_macros[tok].flags & MDOC_PROLOGUE)) {
264*260e9a87SYuri Pankov if (mdoc->meta.title == NULL) {
265*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_DT_NOTITLE,
266*260e9a87SYuri Pankov mdoc->parse, line, ppos, "%s %s",
267*260e9a87SYuri Pankov mdoc_macronames[tok], buf + *pos);
268*260e9a87SYuri Pankov mdoc->meta.title = mandoc_strdup("UNTITLED");
269*260e9a87SYuri Pankov }
270698f87a4SGarrett D'Amore if (NULL == mdoc->meta.vol)
271698f87a4SGarrett D'Amore mdoc->meta.vol = mandoc_strdup("LOCAL");
272698f87a4SGarrett D'Amore mdoc->flags |= MDOC_PBODY;
27395c635efSGarrett D'Amore }
274*260e9a87SYuri Pankov (*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf);
27595c635efSGarrett D'Amore }
27695c635efSGarrett D'Amore
27795c635efSGarrett D'Amore
278*260e9a87SYuri Pankov static void
node_append(struct mdoc * mdoc,struct mdoc_node * p)27995c635efSGarrett D'Amore node_append(struct mdoc *mdoc, struct mdoc_node *p)
28095c635efSGarrett D'Amore {
28195c635efSGarrett D'Amore
28295c635efSGarrett D'Amore assert(mdoc->last);
28395c635efSGarrett D'Amore assert(mdoc->first);
28495c635efSGarrett D'Amore assert(MDOC_ROOT != p->type);
28595c635efSGarrett D'Amore
28695c635efSGarrett D'Amore switch (mdoc->next) {
287*260e9a87SYuri Pankov case MDOC_NEXT_SIBLING:
28895c635efSGarrett D'Amore mdoc->last->next = p;
28995c635efSGarrett D'Amore p->prev = mdoc->last;
29095c635efSGarrett D'Amore p->parent = mdoc->last->parent;
29195c635efSGarrett D'Amore break;
292*260e9a87SYuri Pankov case MDOC_NEXT_CHILD:
29395c635efSGarrett D'Amore mdoc->last->child = p;
29495c635efSGarrett D'Amore p->parent = mdoc->last;
29595c635efSGarrett D'Amore break;
29695c635efSGarrett D'Amore default:
29795c635efSGarrett D'Amore abort();
29895c635efSGarrett D'Amore /* NOTREACHED */
29995c635efSGarrett D'Amore }
30095c635efSGarrett D'Amore
30195c635efSGarrett D'Amore p->parent->nchild++;
30295c635efSGarrett D'Amore
30395c635efSGarrett D'Amore /*
30495c635efSGarrett D'Amore * Copy over the normalised-data pointer of our parent. Not
30595c635efSGarrett D'Amore * everybody has one, but copying a null pointer is fine.
30695c635efSGarrett D'Amore */
30795c635efSGarrett D'Amore
30895c635efSGarrett D'Amore switch (p->type) {
309*260e9a87SYuri Pankov case MDOC_BODY:
310698f87a4SGarrett D'Amore if (ENDBODY_NOT != p->end)
311698f87a4SGarrett D'Amore break;
31295c635efSGarrett D'Amore /* FALLTHROUGH */
313*260e9a87SYuri Pankov case MDOC_TAIL:
31495c635efSGarrett D'Amore /* FALLTHROUGH */
315*260e9a87SYuri Pankov case MDOC_HEAD:
31695c635efSGarrett D'Amore p->norm = p->parent->norm;
31795c635efSGarrett D'Amore break;
31895c635efSGarrett D'Amore default:
31995c635efSGarrett D'Amore break;
32095c635efSGarrett D'Amore }
32195c635efSGarrett D'Amore
322*260e9a87SYuri Pankov mdoc_valid_pre(mdoc, p);
32395c635efSGarrett D'Amore
32495c635efSGarrett D'Amore switch (p->type) {
325*260e9a87SYuri Pankov case MDOC_HEAD:
32695c635efSGarrett D'Amore assert(MDOC_BLOCK == p->parent->type);
32795c635efSGarrett D'Amore p->parent->head = p;
32895c635efSGarrett D'Amore break;
329*260e9a87SYuri Pankov case MDOC_TAIL:
33095c635efSGarrett D'Amore assert(MDOC_BLOCK == p->parent->type);
33195c635efSGarrett D'Amore p->parent->tail = p;
33295c635efSGarrett D'Amore break;
333*260e9a87SYuri Pankov case MDOC_BODY:
33495c635efSGarrett D'Amore if (p->end)
33595c635efSGarrett D'Amore break;
33695c635efSGarrett D'Amore assert(MDOC_BLOCK == p->parent->type);
33795c635efSGarrett D'Amore p->parent->body = p;
33895c635efSGarrett D'Amore break;
33995c635efSGarrett D'Amore default:
34095c635efSGarrett D'Amore break;
34195c635efSGarrett D'Amore }
34295c635efSGarrett D'Amore
34395c635efSGarrett D'Amore mdoc->last = p;
34495c635efSGarrett D'Amore
34595c635efSGarrett D'Amore switch (p->type) {
346*260e9a87SYuri Pankov case MDOC_TBL:
34795c635efSGarrett D'Amore /* FALLTHROUGH */
348*260e9a87SYuri Pankov case MDOC_TEXT:
349*260e9a87SYuri Pankov mdoc_valid_post(mdoc);
35095c635efSGarrett D'Amore break;
35195c635efSGarrett D'Amore default:
35295c635efSGarrett D'Amore break;
35395c635efSGarrett D'Amore }
35495c635efSGarrett D'Amore }
35595c635efSGarrett D'Amore
35695c635efSGarrett D'Amore static struct mdoc_node *
node_alloc(struct mdoc * mdoc,int line,int pos,enum mdoct tok,enum mdoc_type type)357698f87a4SGarrett D'Amore node_alloc(struct mdoc *mdoc, int line, int pos,
35895c635efSGarrett D'Amore enum mdoct tok, enum mdoc_type type)
35995c635efSGarrett D'Amore {
36095c635efSGarrett D'Amore struct mdoc_node *p;
36195c635efSGarrett D'Amore
36295c635efSGarrett D'Amore p = mandoc_calloc(1, sizeof(struct mdoc_node));
363698f87a4SGarrett D'Amore p->sec = mdoc->lastsec;
36495c635efSGarrett D'Amore p->line = line;
36595c635efSGarrett D'Amore p->pos = pos;
36695c635efSGarrett D'Amore p->tok = tok;
36795c635efSGarrett D'Amore p->type = type;
36895c635efSGarrett D'Amore
36995c635efSGarrett D'Amore /* Flag analysis. */
37095c635efSGarrett D'Amore
371698f87a4SGarrett D'Amore if (MDOC_SYNOPSIS & mdoc->flags)
37295c635efSGarrett D'Amore p->flags |= MDOC_SYNPRETTY;
37395c635efSGarrett D'Amore else
37495c635efSGarrett D'Amore p->flags &= ~MDOC_SYNPRETTY;
375698f87a4SGarrett D'Amore if (MDOC_NEWLINE & mdoc->flags)
37695c635efSGarrett D'Amore p->flags |= MDOC_LINE;
377698f87a4SGarrett D'Amore mdoc->flags &= ~MDOC_NEWLINE;
37895c635efSGarrett D'Amore
37995c635efSGarrett D'Amore return(p);
38095c635efSGarrett D'Amore }
38195c635efSGarrett D'Amore
382*260e9a87SYuri Pankov void
mdoc_tail_alloc(struct mdoc * mdoc,int line,int pos,enum mdoct tok)383698f87a4SGarrett D'Amore mdoc_tail_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
38495c635efSGarrett D'Amore {
38595c635efSGarrett D'Amore struct mdoc_node *p;
38695c635efSGarrett D'Amore
387698f87a4SGarrett D'Amore p = node_alloc(mdoc, line, pos, tok, MDOC_TAIL);
388*260e9a87SYuri Pankov node_append(mdoc, p);
389698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD;
39095c635efSGarrett D'Amore }
39195c635efSGarrett D'Amore
392*260e9a87SYuri Pankov struct mdoc_node *
mdoc_head_alloc(struct mdoc * mdoc,int line,int pos,enum mdoct tok)393698f87a4SGarrett D'Amore mdoc_head_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
39495c635efSGarrett D'Amore {
39595c635efSGarrett D'Amore struct mdoc_node *p;
39695c635efSGarrett D'Amore
397698f87a4SGarrett D'Amore assert(mdoc->first);
398698f87a4SGarrett D'Amore assert(mdoc->last);
399698f87a4SGarrett D'Amore p = node_alloc(mdoc, line, pos, tok, MDOC_HEAD);
400*260e9a87SYuri Pankov node_append(mdoc, p);
401698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD;
402*260e9a87SYuri Pankov return(p);
40395c635efSGarrett D'Amore }
40495c635efSGarrett D'Amore
405*260e9a87SYuri Pankov struct mdoc_node *
mdoc_body_alloc(struct mdoc * mdoc,int line,int pos,enum mdoct tok)406698f87a4SGarrett D'Amore mdoc_body_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
40795c635efSGarrett D'Amore {
40895c635efSGarrett D'Amore struct mdoc_node *p;
40995c635efSGarrett D'Amore
410698f87a4SGarrett D'Amore p = node_alloc(mdoc, line, pos, tok, MDOC_BODY);
411*260e9a87SYuri Pankov node_append(mdoc, p);
412698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD;
413*260e9a87SYuri Pankov return(p);
41495c635efSGarrett D'Amore }
41595c635efSGarrett D'Amore
416*260e9a87SYuri Pankov struct mdoc_node *
mdoc_endbody_alloc(struct mdoc * mdoc,int line,int pos,enum mdoct tok,struct mdoc_node * body,enum mdoc_endbody end)417698f87a4SGarrett D'Amore mdoc_endbody_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok,
41895c635efSGarrett D'Amore struct mdoc_node *body, enum mdoc_endbody end)
41995c635efSGarrett D'Amore {
42095c635efSGarrett D'Amore struct mdoc_node *p;
42195c635efSGarrett D'Amore
422*260e9a87SYuri Pankov body->flags |= MDOC_ENDED;
423*260e9a87SYuri Pankov body->parent->flags |= MDOC_ENDED;
424698f87a4SGarrett D'Amore p = node_alloc(mdoc, line, pos, tok, MDOC_BODY);
425*260e9a87SYuri Pankov p->body = body;
426698f87a4SGarrett D'Amore p->norm = body->norm;
42795c635efSGarrett D'Amore p->end = end;
428*260e9a87SYuri Pankov node_append(mdoc, p);
429698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING;
430*260e9a87SYuri Pankov return(p);
43195c635efSGarrett D'Amore }
43295c635efSGarrett D'Amore
433*260e9a87SYuri Pankov struct mdoc_node *
mdoc_block_alloc(struct mdoc * mdoc,int line,int pos,enum mdoct tok,struct mdoc_arg * args)434698f87a4SGarrett D'Amore mdoc_block_alloc(struct mdoc *mdoc, int line, int pos,
43595c635efSGarrett D'Amore enum mdoct tok, struct mdoc_arg *args)
43695c635efSGarrett D'Amore {
43795c635efSGarrett D'Amore struct mdoc_node *p;
43895c635efSGarrett D'Amore
439698f87a4SGarrett D'Amore p = node_alloc(mdoc, line, pos, tok, MDOC_BLOCK);
44095c635efSGarrett D'Amore p->args = args;
44195c635efSGarrett D'Amore if (p->args)
44295c635efSGarrett D'Amore (args->refcnt)++;
44395c635efSGarrett D'Amore
44495c635efSGarrett D'Amore switch (tok) {
445*260e9a87SYuri Pankov case MDOC_Bd:
44695c635efSGarrett D'Amore /* FALLTHROUGH */
447*260e9a87SYuri Pankov case MDOC_Bf:
44895c635efSGarrett D'Amore /* FALLTHROUGH */
449*260e9a87SYuri Pankov case MDOC_Bl:
45095c635efSGarrett D'Amore /* FALLTHROUGH */
451*260e9a87SYuri Pankov case MDOC_En:
452*260e9a87SYuri Pankov /* FALLTHROUGH */
453*260e9a87SYuri Pankov case MDOC_Rs:
45495c635efSGarrett D'Amore p->norm = mandoc_calloc(1, sizeof(union mdoc_data));
45595c635efSGarrett D'Amore break;
45695c635efSGarrett D'Amore default:
45795c635efSGarrett D'Amore break;
45895c635efSGarrett D'Amore }
459*260e9a87SYuri Pankov node_append(mdoc, p);
460698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD;
461*260e9a87SYuri Pankov return(p);
46295c635efSGarrett D'Amore }
46395c635efSGarrett D'Amore
464*260e9a87SYuri Pankov void
mdoc_elem_alloc(struct mdoc * mdoc,int line,int pos,enum mdoct tok,struct mdoc_arg * args)465698f87a4SGarrett D'Amore mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos,
46695c635efSGarrett D'Amore enum mdoct tok, struct mdoc_arg *args)
46795c635efSGarrett D'Amore {
46895c635efSGarrett D'Amore struct mdoc_node *p;
46995c635efSGarrett D'Amore
470698f87a4SGarrett D'Amore p = node_alloc(mdoc, line, pos, tok, MDOC_ELEM);
47195c635efSGarrett D'Amore p->args = args;
47295c635efSGarrett D'Amore if (p->args)
47395c635efSGarrett D'Amore (args->refcnt)++;
47495c635efSGarrett D'Amore
47595c635efSGarrett D'Amore switch (tok) {
476*260e9a87SYuri Pankov case MDOC_An:
47795c635efSGarrett D'Amore p->norm = mandoc_calloc(1, sizeof(union mdoc_data));
47895c635efSGarrett D'Amore break;
47995c635efSGarrett D'Amore default:
48095c635efSGarrett D'Amore break;
48195c635efSGarrett D'Amore }
482*260e9a87SYuri Pankov node_append(mdoc, p);
483698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD;
48495c635efSGarrett D'Amore }
48595c635efSGarrett D'Amore
486*260e9a87SYuri Pankov void
mdoc_word_alloc(struct mdoc * mdoc,int line,int pos,const char * p)487698f87a4SGarrett D'Amore mdoc_word_alloc(struct mdoc *mdoc, int line, int pos, const char *p)
48895c635efSGarrett D'Amore {
48995c635efSGarrett D'Amore struct mdoc_node *n;
49095c635efSGarrett D'Amore
491698f87a4SGarrett D'Amore n = node_alloc(mdoc, line, pos, MDOC_MAX, MDOC_TEXT);
492698f87a4SGarrett D'Amore n->string = roff_strdup(mdoc->roff, p);
493*260e9a87SYuri Pankov node_append(mdoc, n);
494698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING;
49595c635efSGarrett D'Amore }
49695c635efSGarrett D'Amore
497698f87a4SGarrett D'Amore void
mdoc_word_append(struct mdoc * mdoc,const char * p)498698f87a4SGarrett D'Amore mdoc_word_append(struct mdoc *mdoc, const char *p)
499698f87a4SGarrett D'Amore {
500698f87a4SGarrett D'Amore struct mdoc_node *n;
501698f87a4SGarrett D'Amore char *addstr, *newstr;
502698f87a4SGarrett D'Amore
503698f87a4SGarrett D'Amore n = mdoc->last;
504698f87a4SGarrett D'Amore addstr = roff_strdup(mdoc->roff, p);
505*260e9a87SYuri Pankov mandoc_asprintf(&newstr, "%s %s", n->string, addstr);
506698f87a4SGarrett D'Amore free(addstr);
507698f87a4SGarrett D'Amore free(n->string);
508698f87a4SGarrett D'Amore n->string = newstr;
509698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING;
510698f87a4SGarrett D'Amore }
51195c635efSGarrett D'Amore
51295c635efSGarrett D'Amore static void
mdoc_node_free(struct mdoc_node * p)51395c635efSGarrett D'Amore mdoc_node_free(struct mdoc_node *p)
51495c635efSGarrett D'Amore {
51595c635efSGarrett D'Amore
51695c635efSGarrett D'Amore if (MDOC_BLOCK == p->type || MDOC_ELEM == p->type)
51795c635efSGarrett D'Amore free(p->norm);
51895c635efSGarrett D'Amore if (p->string)
51995c635efSGarrett D'Amore free(p->string);
52095c635efSGarrett D'Amore if (p->args)
52195c635efSGarrett D'Amore mdoc_argv_free(p->args);
52295c635efSGarrett D'Amore free(p);
52395c635efSGarrett D'Amore }
52495c635efSGarrett D'Amore
52595c635efSGarrett D'Amore static void
mdoc_node_unlink(struct mdoc * mdoc,struct mdoc_node * n)526698f87a4SGarrett D'Amore mdoc_node_unlink(struct mdoc *mdoc, struct mdoc_node *n)
52795c635efSGarrett D'Amore {
52895c635efSGarrett D'Amore
52995c635efSGarrett D'Amore /* Adjust siblings. */
53095c635efSGarrett D'Amore
53195c635efSGarrett D'Amore if (n->prev)
53295c635efSGarrett D'Amore n->prev->next = n->next;
53395c635efSGarrett D'Amore if (n->next)
53495c635efSGarrett D'Amore n->next->prev = n->prev;
53595c635efSGarrett D'Amore
53695c635efSGarrett D'Amore /* Adjust parent. */
53795c635efSGarrett D'Amore
53895c635efSGarrett D'Amore if (n->parent) {
53995c635efSGarrett D'Amore n->parent->nchild--;
54095c635efSGarrett D'Amore if (n->parent->child == n)
54195c635efSGarrett D'Amore n->parent->child = n->prev ? n->prev : n->next;
54295c635efSGarrett D'Amore if (n->parent->last == n)
54395c635efSGarrett D'Amore n->parent->last = n->prev ? n->prev : NULL;
54495c635efSGarrett D'Amore }
54595c635efSGarrett D'Amore
54695c635efSGarrett D'Amore /* Adjust parse point, if applicable. */
54795c635efSGarrett D'Amore
548698f87a4SGarrett D'Amore if (mdoc && mdoc->last == n) {
54995c635efSGarrett D'Amore if (n->prev) {
550698f87a4SGarrett D'Amore mdoc->last = n->prev;
551698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING;
55295c635efSGarrett D'Amore } else {
553698f87a4SGarrett D'Amore mdoc->last = n->parent;
554698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD;
55595c635efSGarrett D'Amore }
55695c635efSGarrett D'Amore }
55795c635efSGarrett D'Amore
558698f87a4SGarrett D'Amore if (mdoc && mdoc->first == n)
559698f87a4SGarrett D'Amore mdoc->first = NULL;
56095c635efSGarrett D'Amore }
56195c635efSGarrett D'Amore
56295c635efSGarrett D'Amore void
mdoc_node_delete(struct mdoc * mdoc,struct mdoc_node * p)563698f87a4SGarrett D'Amore mdoc_node_delete(struct mdoc *mdoc, struct mdoc_node *p)
56495c635efSGarrett D'Amore {
56595c635efSGarrett D'Amore
56695c635efSGarrett D'Amore while (p->child) {
56795c635efSGarrett D'Amore assert(p->nchild);
568698f87a4SGarrett D'Amore mdoc_node_delete(mdoc, p->child);
56995c635efSGarrett D'Amore }
57095c635efSGarrett D'Amore assert(0 == p->nchild);
57195c635efSGarrett D'Amore
572698f87a4SGarrett D'Amore mdoc_node_unlink(mdoc, p);
57395c635efSGarrett D'Amore mdoc_node_free(p);
57495c635efSGarrett D'Amore }
57595c635efSGarrett D'Amore
576*260e9a87SYuri Pankov void
mdoc_node_relink(struct mdoc * mdoc,struct mdoc_node * p)577698f87a4SGarrett D'Amore mdoc_node_relink(struct mdoc *mdoc, struct mdoc_node *p)
578698f87a4SGarrett D'Amore {
579698f87a4SGarrett D'Amore
580698f87a4SGarrett D'Amore mdoc_node_unlink(mdoc, p);
581*260e9a87SYuri Pankov node_append(mdoc, p);
582698f87a4SGarrett D'Amore }
583698f87a4SGarrett D'Amore
58495c635efSGarrett D'Amore /*
58595c635efSGarrett D'Amore * Parse free-form text, that is, a line that does not begin with the
58695c635efSGarrett D'Amore * control character.
58795c635efSGarrett D'Amore */
58895c635efSGarrett D'Amore static int
mdoc_ptext(struct mdoc * mdoc,int line,char * buf,int offs)589698f87a4SGarrett D'Amore mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
59095c635efSGarrett D'Amore {
59195c635efSGarrett D'Amore char *c, *ws, *end;
59295c635efSGarrett D'Amore struct mdoc_node *n;
59395c635efSGarrett D'Amore
594698f87a4SGarrett D'Amore assert(mdoc->last);
595698f87a4SGarrett D'Amore n = mdoc->last;
59695c635efSGarrett D'Amore
59795c635efSGarrett D'Amore /*
59895c635efSGarrett D'Amore * Divert directly to list processing if we're encountering a
59995c635efSGarrett D'Amore * columnar MDOC_BLOCK with or without a prior MDOC_BLOCK entry
60095c635efSGarrett D'Amore * (a MDOC_BODY means it's already open, in which case we should
60195c635efSGarrett D'Amore * process within its context in the normal way).
60295c635efSGarrett D'Amore */
60395c635efSGarrett D'Amore
604*260e9a87SYuri Pankov if (n->tok == MDOC_Bl && n->type == MDOC_BODY &&
605*260e9a87SYuri Pankov n->end == ENDBODY_NOT && n->norm->Bl.type == LIST_column) {
60695c635efSGarrett D'Amore /* `Bl' is open without any children. */
607698f87a4SGarrett D'Amore mdoc->flags |= MDOC_FREECOL;
608*260e9a87SYuri Pankov mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf);
609*260e9a87SYuri Pankov return(1);
61095c635efSGarrett D'Amore }
61195c635efSGarrett D'Amore
61295c635efSGarrett D'Amore if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
61395c635efSGarrett D'Amore NULL != n->parent &&
61495c635efSGarrett D'Amore MDOC_Bl == n->parent->tok &&
61595c635efSGarrett D'Amore LIST_column == n->parent->norm->Bl.type) {
61695c635efSGarrett D'Amore /* `Bl' has block-level `It' children. */
617698f87a4SGarrett D'Amore mdoc->flags |= MDOC_FREECOL;
618*260e9a87SYuri Pankov mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf);
619*260e9a87SYuri Pankov return(1);
62095c635efSGarrett D'Amore }
62195c635efSGarrett D'Amore
62295c635efSGarrett D'Amore /*
62395c635efSGarrett D'Amore * Search for the beginning of unescaped trailing whitespace (ws)
62495c635efSGarrett D'Amore * and for the first character not to be output (end).
62595c635efSGarrett D'Amore */
62695c635efSGarrett D'Amore
62795c635efSGarrett D'Amore /* FIXME: replace with strcspn(). */
62895c635efSGarrett D'Amore ws = NULL;
62995c635efSGarrett D'Amore for (c = end = buf + offs; *c; c++) {
63095c635efSGarrett D'Amore switch (*c) {
63195c635efSGarrett D'Amore case ' ':
63295c635efSGarrett D'Amore if (NULL == ws)
63395c635efSGarrett D'Amore ws = c;
63495c635efSGarrett D'Amore continue;
63595c635efSGarrett D'Amore case '\t':
63695c635efSGarrett D'Amore /*
63795c635efSGarrett D'Amore * Always warn about trailing tabs,
63895c635efSGarrett D'Amore * even outside literal context,
63995c635efSGarrett D'Amore * where they should be put on the next line.
64095c635efSGarrett D'Amore */
64195c635efSGarrett D'Amore if (NULL == ws)
64295c635efSGarrett D'Amore ws = c;
64395c635efSGarrett D'Amore /*
64495c635efSGarrett D'Amore * Strip trailing tabs in literal context only;
64595c635efSGarrett D'Amore * outside, they affect the next line.
64695c635efSGarrett D'Amore */
647698f87a4SGarrett D'Amore if (MDOC_LITERAL & mdoc->flags)
64895c635efSGarrett D'Amore continue;
64995c635efSGarrett D'Amore break;
65095c635efSGarrett D'Amore case '\\':
65195c635efSGarrett D'Amore /* Skip the escaped character, too, if any. */
65295c635efSGarrett D'Amore if (c[1])
65395c635efSGarrett D'Amore c++;
65495c635efSGarrett D'Amore /* FALLTHROUGH */
65595c635efSGarrett D'Amore default:
65695c635efSGarrett D'Amore ws = NULL;
65795c635efSGarrett D'Amore break;
65895c635efSGarrett D'Amore }
65995c635efSGarrett D'Amore end = c + 1;
66095c635efSGarrett D'Amore }
66195c635efSGarrett D'Amore *end = '\0';
66295c635efSGarrett D'Amore
66395c635efSGarrett D'Amore if (ws)
664*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
665*260e9a87SYuri Pankov line, (int)(ws-buf), NULL);
66695c635efSGarrett D'Amore
667*260e9a87SYuri Pankov if (buf[offs] == '\0' && ! (mdoc->flags & MDOC_LITERAL)) {
668*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_FI_BLANK, mdoc->parse,
669*260e9a87SYuri Pankov line, (int)(c - buf), NULL);
67095c635efSGarrett D'Amore
67195c635efSGarrett D'Amore /*
67295c635efSGarrett D'Amore * Insert a `sp' in the case of a blank line. Technically,
67395c635efSGarrett D'Amore * blank lines aren't allowed, but enough manuals assume this
67495c635efSGarrett D'Amore * behaviour that we want to work around it.
67595c635efSGarrett D'Amore */
676*260e9a87SYuri Pankov mdoc_elem_alloc(mdoc, line, offs, MDOC_sp, NULL);
677698f87a4SGarrett D'Amore mdoc->next = MDOC_NEXT_SIBLING;
678*260e9a87SYuri Pankov mdoc_valid_post(mdoc);
679*260e9a87SYuri Pankov return(1);
68095c635efSGarrett D'Amore }
68195c635efSGarrett D'Amore
682*260e9a87SYuri Pankov mdoc_word_alloc(mdoc, line, offs, buf+offs);
68395c635efSGarrett D'Amore
684*260e9a87SYuri Pankov if (mdoc->flags & MDOC_LITERAL)
68595c635efSGarrett D'Amore return(1);
68695c635efSGarrett D'Amore
68795c635efSGarrett D'Amore /*
68895c635efSGarrett D'Amore * End-of-sentence check. If the last character is an unescaped
68995c635efSGarrett D'Amore * EOS character, then flag the node as being the end of a
69095c635efSGarrett D'Amore * sentence. The front-end will know how to interpret this.
69195c635efSGarrett D'Amore */
69295c635efSGarrett D'Amore
69395c635efSGarrett D'Amore assert(buf < end);
69495c635efSGarrett D'Amore
695*260e9a87SYuri Pankov if (mandoc_eos(buf+offs, (size_t)(end-buf-offs)))
696698f87a4SGarrett D'Amore mdoc->last->flags |= MDOC_EOS;
69795c635efSGarrett D'Amore return(1);
69895c635efSGarrett D'Amore }
69995c635efSGarrett D'Amore
70095c635efSGarrett D'Amore /*
70195c635efSGarrett D'Amore * Parse a macro line, that is, a line beginning with the control
70295c635efSGarrett D'Amore * character.
70395c635efSGarrett D'Amore */
70495c635efSGarrett D'Amore static int
mdoc_pmacro(struct mdoc * mdoc,int ln,char * buf,int offs)705698f87a4SGarrett D'Amore mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
70695c635efSGarrett D'Amore {
707*260e9a87SYuri Pankov struct mdoc_node *n;
708*260e9a87SYuri Pankov const char *cp;
70995c635efSGarrett D'Amore enum mdoct tok;
71095c635efSGarrett D'Amore int i, sv;
71195c635efSGarrett D'Amore char mac[5];
71295c635efSGarrett D'Amore
71395c635efSGarrett D'Amore sv = offs;
71495c635efSGarrett D'Amore
71595c635efSGarrett D'Amore /*
71695c635efSGarrett D'Amore * Copy the first word into a nil-terminated buffer.
717*260e9a87SYuri Pankov * Stop when a space, tab, escape, or eoln is encountered.
71895c635efSGarrett D'Amore */
71995c635efSGarrett D'Amore
72095c635efSGarrett D'Amore i = 0;
721*260e9a87SYuri Pankov while (i < 4 && strchr(" \t\\", buf[offs]) == NULL)
72295c635efSGarrett D'Amore mac[i++] = buf[offs++];
72395c635efSGarrett D'Amore
72495c635efSGarrett D'Amore mac[i] = '\0';
72595c635efSGarrett D'Amore
726*260e9a87SYuri Pankov tok = (i > 1 && i < 4) ? mdoc_hash_find(mac) : MDOC_MAX;
72795c635efSGarrett D'Amore
728*260e9a87SYuri Pankov if (tok == MDOC_MAX) {
729*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_MACRO, mdoc->parse,
730*260e9a87SYuri Pankov ln, sv, buf + sv - 1);
73195c635efSGarrett D'Amore return(1);
73295c635efSGarrett D'Amore }
73395c635efSGarrett D'Amore
734*260e9a87SYuri Pankov /* Skip a leading escape sequence or tab. */
73595c635efSGarrett D'Amore
736*260e9a87SYuri Pankov switch (buf[offs]) {
737*260e9a87SYuri Pankov case '\\':
738*260e9a87SYuri Pankov cp = buf + offs + 1;
739*260e9a87SYuri Pankov mandoc_escape(&cp, NULL, NULL);
740*260e9a87SYuri Pankov offs = cp - buf;
741*260e9a87SYuri Pankov break;
742*260e9a87SYuri Pankov case '\t':
74395c635efSGarrett D'Amore offs++;
744*260e9a87SYuri Pankov break;
745*260e9a87SYuri Pankov default:
746*260e9a87SYuri Pankov break;
747*260e9a87SYuri Pankov }
74895c635efSGarrett D'Amore
74995c635efSGarrett D'Amore /* Jump to the next non-whitespace word. */
75095c635efSGarrett D'Amore
75195c635efSGarrett D'Amore while (buf[offs] && ' ' == buf[offs])
75295c635efSGarrett D'Amore offs++;
75395c635efSGarrett D'Amore
75495c635efSGarrett D'Amore /*
75595c635efSGarrett D'Amore * Trailing whitespace. Note that tabs are allowed to be passed
75695c635efSGarrett D'Amore * into the parser as "text", so we only warn about spaces here.
75795c635efSGarrett D'Amore */
75895c635efSGarrett D'Amore
75995c635efSGarrett D'Amore if ('\0' == buf[offs] && ' ' == buf[offs - 1])
760*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
761*260e9a87SYuri Pankov ln, offs - 1, NULL);
76295c635efSGarrett D'Amore
76395c635efSGarrett D'Amore /*
76495c635efSGarrett D'Amore * If an initial macro or a list invocation, divert directly
76595c635efSGarrett D'Amore * into macro processing.
76695c635efSGarrett D'Amore */
76795c635efSGarrett D'Amore
768698f87a4SGarrett D'Amore if (NULL == mdoc->last || MDOC_It == tok || MDOC_El == tok) {
769*260e9a87SYuri Pankov mdoc_macro(mdoc, tok, ln, sv, &offs, buf);
77095c635efSGarrett D'Amore return(1);
77195c635efSGarrett D'Amore }
77295c635efSGarrett D'Amore
773698f87a4SGarrett D'Amore n = mdoc->last;
774698f87a4SGarrett D'Amore assert(mdoc->last);
77595c635efSGarrett D'Amore
77695c635efSGarrett D'Amore /*
77795c635efSGarrett D'Amore * If the first macro of a `Bl -column', open an `It' block
77895c635efSGarrett D'Amore * context around the parsed macro.
77995c635efSGarrett D'Amore */
78095c635efSGarrett D'Amore
781*260e9a87SYuri Pankov if (n->tok == MDOC_Bl && n->type == MDOC_BODY &&
782*260e9a87SYuri Pankov n->end == ENDBODY_NOT && n->norm->Bl.type == LIST_column) {
783698f87a4SGarrett D'Amore mdoc->flags |= MDOC_FREECOL;
784*260e9a87SYuri Pankov mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf);
78595c635efSGarrett D'Amore return(1);
78695c635efSGarrett D'Amore }
78795c635efSGarrett D'Amore
78895c635efSGarrett D'Amore /*
78995c635efSGarrett D'Amore * If we're following a block-level `It' within a `Bl -column'
79095c635efSGarrett D'Amore * context (perhaps opened in the above block or in ptext()),
79195c635efSGarrett D'Amore * then open an `It' block context around the parsed macro.
79295c635efSGarrett D'Amore */
79395c635efSGarrett D'Amore
79495c635efSGarrett D'Amore if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
79595c635efSGarrett D'Amore NULL != n->parent &&
79695c635efSGarrett D'Amore MDOC_Bl == n->parent->tok &&
79795c635efSGarrett D'Amore LIST_column == n->parent->norm->Bl.type) {
798698f87a4SGarrett D'Amore mdoc->flags |= MDOC_FREECOL;
799*260e9a87SYuri Pankov mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf);
80095c635efSGarrett D'Amore return(1);
80195c635efSGarrett D'Amore }
80295c635efSGarrett D'Amore
80395c635efSGarrett D'Amore /* Normal processing of a macro. */
80495c635efSGarrett D'Amore
805*260e9a87SYuri Pankov mdoc_macro(mdoc, tok, ln, sv, &offs, buf);
806*260e9a87SYuri Pankov
807*260e9a87SYuri Pankov /* In quick mode (for mandocdb), abort after the NAME section. */
808*260e9a87SYuri Pankov
809*260e9a87SYuri Pankov if (mdoc->quick && MDOC_Sh == tok &&
810*260e9a87SYuri Pankov SEC_NAME != mdoc->last->sec)
811*260e9a87SYuri Pankov return(2);
81295c635efSGarrett D'Amore
81395c635efSGarrett D'Amore return(1);
81495c635efSGarrett D'Amore }
81595c635efSGarrett D'Amore
81695c635efSGarrett D'Amore enum mdelim
mdoc_isdelim(const char * p)81795c635efSGarrett D'Amore mdoc_isdelim(const char *p)
81895c635efSGarrett D'Amore {
81995c635efSGarrett D'Amore
82095c635efSGarrett D'Amore if ('\0' == p[0])
82195c635efSGarrett D'Amore return(DELIM_NONE);
82295c635efSGarrett D'Amore
82395c635efSGarrett D'Amore if ('\0' == p[1])
82495c635efSGarrett D'Amore switch (p[0]) {
825*260e9a87SYuri Pankov case '(':
82695c635efSGarrett D'Amore /* FALLTHROUGH */
827*260e9a87SYuri Pankov case '[':
82895c635efSGarrett D'Amore return(DELIM_OPEN);
829*260e9a87SYuri Pankov case '|':
83095c635efSGarrett D'Amore return(DELIM_MIDDLE);
831*260e9a87SYuri Pankov case '.':
83295c635efSGarrett D'Amore /* FALLTHROUGH */
833*260e9a87SYuri Pankov case ',':
83495c635efSGarrett D'Amore /* FALLTHROUGH */
835*260e9a87SYuri Pankov case ';':
83695c635efSGarrett D'Amore /* FALLTHROUGH */
837*260e9a87SYuri Pankov case ':':
83895c635efSGarrett D'Amore /* FALLTHROUGH */
839*260e9a87SYuri Pankov case '?':
84095c635efSGarrett D'Amore /* FALLTHROUGH */
841*260e9a87SYuri Pankov case '!':
84295c635efSGarrett D'Amore /* FALLTHROUGH */
843*260e9a87SYuri Pankov case ')':
84495c635efSGarrett D'Amore /* FALLTHROUGH */
845*260e9a87SYuri Pankov case ']':
84695c635efSGarrett D'Amore return(DELIM_CLOSE);
84795c635efSGarrett D'Amore default:
84895c635efSGarrett D'Amore return(DELIM_NONE);
84995c635efSGarrett D'Amore }
85095c635efSGarrett D'Amore
85195c635efSGarrett D'Amore if ('\\' != p[0])
85295c635efSGarrett D'Amore return(DELIM_NONE);
85395c635efSGarrett D'Amore
85495c635efSGarrett D'Amore if (0 == strcmp(p + 1, "."))
85595c635efSGarrett D'Amore return(DELIM_CLOSE);
856698f87a4SGarrett D'Amore if (0 == strcmp(p + 1, "fR|\\fP"))
85795c635efSGarrett D'Amore return(DELIM_MIDDLE);
85895c635efSGarrett D'Amore
85995c635efSGarrett D'Amore return(DELIM_NONE);
86095c635efSGarrett D'Amore }
861*260e9a87SYuri Pankov
862*260e9a87SYuri Pankov void
mdoc_deroff(char ** dest,const struct mdoc_node * n)863*260e9a87SYuri Pankov mdoc_deroff(char **dest, const struct mdoc_node *n)
864*260e9a87SYuri Pankov {
865*260e9a87SYuri Pankov char *cp;
866*260e9a87SYuri Pankov size_t sz;
867*260e9a87SYuri Pankov
868*260e9a87SYuri Pankov if (MDOC_TEXT != n->type) {
869*260e9a87SYuri Pankov for (n = n->child; n; n = n->next)
870*260e9a87SYuri Pankov mdoc_deroff(dest, n);
871*260e9a87SYuri Pankov return;
872*260e9a87SYuri Pankov }
873*260e9a87SYuri Pankov
874*260e9a87SYuri Pankov /* Skip leading whitespace. */
875*260e9a87SYuri Pankov
876*260e9a87SYuri Pankov for (cp = n->string; '\0' != *cp; cp++)
877*260e9a87SYuri Pankov if (0 == isspace((unsigned char)*cp))
878*260e9a87SYuri Pankov break;
879*260e9a87SYuri Pankov
880*260e9a87SYuri Pankov /* Skip trailing whitespace. */
881*260e9a87SYuri Pankov
882*260e9a87SYuri Pankov for (sz = strlen(cp); sz; sz--)
883*260e9a87SYuri Pankov if (0 == isspace((unsigned char)cp[sz-1]))
884*260e9a87SYuri Pankov break;
885*260e9a87SYuri Pankov
886*260e9a87SYuri Pankov /* Skip empty strings. */
887*260e9a87SYuri Pankov
888*260e9a87SYuri Pankov if (0 == sz)
889*260e9a87SYuri Pankov return;
890*260e9a87SYuri Pankov
891*260e9a87SYuri Pankov if (NULL == *dest) {
892*260e9a87SYuri Pankov *dest = mandoc_strndup(cp, sz);
893*260e9a87SYuri Pankov return;
894*260e9a87SYuri Pankov }
895*260e9a87SYuri Pankov
896*260e9a87SYuri Pankov mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp);
897*260e9a87SYuri Pankov free(*dest);
898*260e9a87SYuri Pankov *dest = cp;
899*260e9a87SYuri Pankov }
900