1*ffb8ebfaSGarrett D'Amore /* $Id: man.c,v 1.121 2013/11/10 22:54:40 schwarze Exp $ */
232a712daSGarrett D'Amore /*
332a712daSGarrett D'Amore * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
432a712daSGarrett D'Amore *
532a712daSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any
632a712daSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above
732a712daSGarrett D'Amore * copyright notice and this permission notice appear in all copies.
832a712daSGarrett D'Amore *
932a712daSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1032a712daSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1132a712daSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1232a712daSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1332a712daSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1432a712daSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1532a712daSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1632a712daSGarrett D'Amore */
1732a712daSGarrett D'Amore #ifdef HAVE_CONFIG_H
1832a712daSGarrett D'Amore #include "config.h"
1932a712daSGarrett D'Amore #endif
2032a712daSGarrett D'Amore
2132a712daSGarrett D'Amore #include <sys/types.h>
2232a712daSGarrett D'Amore
2332a712daSGarrett D'Amore #include <assert.h>
2432a712daSGarrett D'Amore #include <stdarg.h>
2532a712daSGarrett D'Amore #include <stdlib.h>
2632a712daSGarrett D'Amore #include <stdio.h>
2732a712daSGarrett D'Amore #include <string.h>
2832a712daSGarrett D'Amore
2932a712daSGarrett D'Amore #include "man.h"
3032a712daSGarrett D'Amore #include "mandoc.h"
3132a712daSGarrett D'Amore #include "libman.h"
3232a712daSGarrett D'Amore #include "libmandoc.h"
3332a712daSGarrett D'Amore
3432a712daSGarrett D'Amore const char *const __man_macronames[MAN_MAX] = {
3532a712daSGarrett D'Amore "br", "TH", "SH", "SS",
3632a712daSGarrett D'Amore "TP", "LP", "PP", "P",
3732a712daSGarrett D'Amore "IP", "HP", "SM", "SB",
3832a712daSGarrett D'Amore "BI", "IB", "BR", "RB",
3932a712daSGarrett D'Amore "R", "B", "I", "IR",
4032a712daSGarrett D'Amore "RI", "na", "sp", "nf",
4132a712daSGarrett D'Amore "fi", "RE", "RS", "DT",
4232a712daSGarrett D'Amore "UC", "PD", "AT", "in",
43*ffb8ebfaSGarrett D'Amore "ft", "OP", "EX", "EE",
44*ffb8ebfaSGarrett D'Amore "UR", "UE"
4532a712daSGarrett D'Amore };
4632a712daSGarrett D'Amore
4732a712daSGarrett D'Amore const char * const *man_macronames = __man_macronames;
4832a712daSGarrett D'Amore
4932a712daSGarrett D'Amore static struct man_node *man_node_alloc(struct man *, int, int,
5032a712daSGarrett D'Amore enum man_type, enum mant);
5132a712daSGarrett D'Amore static int man_node_append(struct man *,
5232a712daSGarrett D'Amore struct man_node *);
5332a712daSGarrett D'Amore static void man_node_free(struct man_node *);
5432a712daSGarrett D'Amore static void man_node_unlink(struct man *,
5532a712daSGarrett D'Amore struct man_node *);
5632a712daSGarrett D'Amore static int man_ptext(struct man *, int, char *, int);
5732a712daSGarrett D'Amore static int man_pmacro(struct man *, int, char *, int);
5832a712daSGarrett D'Amore static void man_free1(struct man *);
5932a712daSGarrett D'Amore static void man_alloc1(struct man *);
6032a712daSGarrett D'Amore static int man_descope(struct man *, int, int);
6132a712daSGarrett D'Amore
6232a712daSGarrett D'Amore
6332a712daSGarrett D'Amore const struct man_node *
man_node(const struct man * man)64*ffb8ebfaSGarrett D'Amore man_node(const struct man *man)
6532a712daSGarrett D'Amore {
6632a712daSGarrett D'Amore
67*ffb8ebfaSGarrett D'Amore assert( ! (MAN_HALT & man->flags));
68*ffb8ebfaSGarrett D'Amore return(man->first);
6932a712daSGarrett D'Amore }
7032a712daSGarrett D'Amore
7132a712daSGarrett D'Amore
7232a712daSGarrett D'Amore const struct man_meta *
man_meta(const struct man * man)73*ffb8ebfaSGarrett D'Amore man_meta(const struct man *man)
7432a712daSGarrett D'Amore {
7532a712daSGarrett D'Amore
76*ffb8ebfaSGarrett D'Amore assert( ! (MAN_HALT & man->flags));
77*ffb8ebfaSGarrett D'Amore return(&man->meta);
7832a712daSGarrett D'Amore }
7932a712daSGarrett D'Amore
8032a712daSGarrett D'Amore
8132a712daSGarrett D'Amore void
man_reset(struct man * man)8232a712daSGarrett D'Amore man_reset(struct man *man)
8332a712daSGarrett D'Amore {
8432a712daSGarrett D'Amore
8532a712daSGarrett D'Amore man_free1(man);
8632a712daSGarrett D'Amore man_alloc1(man);
8732a712daSGarrett D'Amore }
8832a712daSGarrett D'Amore
8932a712daSGarrett D'Amore
9032a712daSGarrett D'Amore void
man_free(struct man * man)9132a712daSGarrett D'Amore man_free(struct man *man)
9232a712daSGarrett D'Amore {
9332a712daSGarrett D'Amore
9432a712daSGarrett D'Amore man_free1(man);
9532a712daSGarrett D'Amore free(man);
9632a712daSGarrett D'Amore }
9732a712daSGarrett D'Amore
9832a712daSGarrett D'Amore
9932a712daSGarrett D'Amore struct man *
man_alloc(struct roff * roff,struct mparse * parse)10032a712daSGarrett D'Amore man_alloc(struct roff *roff, struct mparse *parse)
10132a712daSGarrett D'Amore {
10232a712daSGarrett D'Amore struct man *p;
10332a712daSGarrett D'Amore
10432a712daSGarrett D'Amore p = mandoc_calloc(1, sizeof(struct man));
10532a712daSGarrett D'Amore
10632a712daSGarrett D'Amore man_hash_init();
10732a712daSGarrett D'Amore p->parse = parse;
10832a712daSGarrett D'Amore p->roff = roff;
10932a712daSGarrett D'Amore
11032a712daSGarrett D'Amore man_alloc1(p);
11132a712daSGarrett D'Amore return(p);
11232a712daSGarrett D'Amore }
11332a712daSGarrett D'Amore
11432a712daSGarrett D'Amore
11532a712daSGarrett D'Amore int
man_endparse(struct man * man)116*ffb8ebfaSGarrett D'Amore man_endparse(struct man *man)
11732a712daSGarrett D'Amore {
11832a712daSGarrett D'Amore
119*ffb8ebfaSGarrett D'Amore assert( ! (MAN_HALT & man->flags));
120*ffb8ebfaSGarrett D'Amore if (man_macroend(man))
12132a712daSGarrett D'Amore return(1);
122*ffb8ebfaSGarrett D'Amore man->flags |= MAN_HALT;
12332a712daSGarrett D'Amore return(0);
12432a712daSGarrett D'Amore }
12532a712daSGarrett D'Amore
12632a712daSGarrett D'Amore
12732a712daSGarrett D'Amore int
man_parseln(struct man * man,int ln,char * buf,int offs)128*ffb8ebfaSGarrett D'Amore man_parseln(struct man *man, int ln, char *buf, int offs)
12932a712daSGarrett D'Amore {
13032a712daSGarrett D'Amore
131*ffb8ebfaSGarrett D'Amore man->flags |= MAN_NEWLINE;
13232a712daSGarrett D'Amore
133*ffb8ebfaSGarrett D'Amore assert( ! (MAN_HALT & man->flags));
13432a712daSGarrett D'Amore
135*ffb8ebfaSGarrett D'Amore return (roff_getcontrol(man->roff, buf, &offs) ?
136*ffb8ebfaSGarrett D'Amore man_pmacro(man, ln, buf, offs) :
137*ffb8ebfaSGarrett D'Amore man_ptext(man, ln, buf, offs));
13832a712daSGarrett D'Amore }
13932a712daSGarrett D'Amore
14032a712daSGarrett D'Amore
14132a712daSGarrett D'Amore static void
man_free1(struct man * man)14232a712daSGarrett D'Amore man_free1(struct man *man)
14332a712daSGarrett D'Amore {
14432a712daSGarrett D'Amore
14532a712daSGarrett D'Amore if (man->first)
14632a712daSGarrett D'Amore man_node_delete(man, man->first);
14732a712daSGarrett D'Amore if (man->meta.title)
14832a712daSGarrett D'Amore free(man->meta.title);
14932a712daSGarrett D'Amore if (man->meta.source)
15032a712daSGarrett D'Amore free(man->meta.source);
15132a712daSGarrett D'Amore if (man->meta.date)
15232a712daSGarrett D'Amore free(man->meta.date);
15332a712daSGarrett D'Amore if (man->meta.vol)
15432a712daSGarrett D'Amore free(man->meta.vol);
15532a712daSGarrett D'Amore if (man->meta.msec)
15632a712daSGarrett D'Amore free(man->meta.msec);
15732a712daSGarrett D'Amore }
15832a712daSGarrett D'Amore
15932a712daSGarrett D'Amore
16032a712daSGarrett D'Amore static void
man_alloc1(struct man * man)161*ffb8ebfaSGarrett D'Amore man_alloc1(struct man *man)
16232a712daSGarrett D'Amore {
16332a712daSGarrett D'Amore
164*ffb8ebfaSGarrett D'Amore memset(&man->meta, 0, sizeof(struct man_meta));
165*ffb8ebfaSGarrett D'Amore man->flags = 0;
166*ffb8ebfaSGarrett D'Amore man->last = mandoc_calloc(1, sizeof(struct man_node));
167*ffb8ebfaSGarrett D'Amore man->first = man->last;
168*ffb8ebfaSGarrett D'Amore man->last->type = MAN_ROOT;
169*ffb8ebfaSGarrett D'Amore man->last->tok = MAN_MAX;
170*ffb8ebfaSGarrett D'Amore man->next = MAN_NEXT_CHILD;
17132a712daSGarrett D'Amore }
17232a712daSGarrett D'Amore
17332a712daSGarrett D'Amore
17432a712daSGarrett D'Amore static int
man_node_append(struct man * man,struct man_node * p)17532a712daSGarrett D'Amore man_node_append(struct man *man, struct man_node *p)
17632a712daSGarrett D'Amore {
17732a712daSGarrett D'Amore
17832a712daSGarrett D'Amore assert(man->last);
17932a712daSGarrett D'Amore assert(man->first);
18032a712daSGarrett D'Amore assert(MAN_ROOT != p->type);
18132a712daSGarrett D'Amore
18232a712daSGarrett D'Amore switch (man->next) {
18332a712daSGarrett D'Amore case (MAN_NEXT_SIBLING):
18432a712daSGarrett D'Amore man->last->next = p;
18532a712daSGarrett D'Amore p->prev = man->last;
18632a712daSGarrett D'Amore p->parent = man->last->parent;
18732a712daSGarrett D'Amore break;
18832a712daSGarrett D'Amore case (MAN_NEXT_CHILD):
18932a712daSGarrett D'Amore man->last->child = p;
19032a712daSGarrett D'Amore p->parent = man->last;
19132a712daSGarrett D'Amore break;
19232a712daSGarrett D'Amore default:
19332a712daSGarrett D'Amore abort();
19432a712daSGarrett D'Amore /* NOTREACHED */
19532a712daSGarrett D'Amore }
19632a712daSGarrett D'Amore
19732a712daSGarrett D'Amore assert(p->parent);
19832a712daSGarrett D'Amore p->parent->nchild++;
19932a712daSGarrett D'Amore
20032a712daSGarrett D'Amore if ( ! man_valid_pre(man, p))
20132a712daSGarrett D'Amore return(0);
20232a712daSGarrett D'Amore
20332a712daSGarrett D'Amore switch (p->type) {
20432a712daSGarrett D'Amore case (MAN_HEAD):
20532a712daSGarrett D'Amore assert(MAN_BLOCK == p->parent->type);
20632a712daSGarrett D'Amore p->parent->head = p;
20732a712daSGarrett D'Amore break;
20832a712daSGarrett D'Amore case (MAN_TAIL):
20932a712daSGarrett D'Amore assert(MAN_BLOCK == p->parent->type);
21032a712daSGarrett D'Amore p->parent->tail = p;
21132a712daSGarrett D'Amore break;
21232a712daSGarrett D'Amore case (MAN_BODY):
21332a712daSGarrett D'Amore assert(MAN_BLOCK == p->parent->type);
21432a712daSGarrett D'Amore p->parent->body = p;
21532a712daSGarrett D'Amore break;
21632a712daSGarrett D'Amore default:
21732a712daSGarrett D'Amore break;
21832a712daSGarrett D'Amore }
21932a712daSGarrett D'Amore
22032a712daSGarrett D'Amore man->last = p;
22132a712daSGarrett D'Amore
22232a712daSGarrett D'Amore switch (p->type) {
22332a712daSGarrett D'Amore case (MAN_TBL):
22432a712daSGarrett D'Amore /* FALLTHROUGH */
22532a712daSGarrett D'Amore case (MAN_TEXT):
22632a712daSGarrett D'Amore if ( ! man_valid_post(man))
22732a712daSGarrett D'Amore return(0);
22832a712daSGarrett D'Amore break;
22932a712daSGarrett D'Amore default:
23032a712daSGarrett D'Amore break;
23132a712daSGarrett D'Amore }
23232a712daSGarrett D'Amore
23332a712daSGarrett D'Amore return(1);
23432a712daSGarrett D'Amore }
23532a712daSGarrett D'Amore
23632a712daSGarrett D'Amore
23732a712daSGarrett D'Amore static struct man_node *
man_node_alloc(struct man * man,int line,int pos,enum man_type type,enum mant tok)238*ffb8ebfaSGarrett D'Amore man_node_alloc(struct man *man, int line, int pos,
23932a712daSGarrett D'Amore enum man_type type, enum mant tok)
24032a712daSGarrett D'Amore {
24132a712daSGarrett D'Amore struct man_node *p;
24232a712daSGarrett D'Amore
24332a712daSGarrett D'Amore p = mandoc_calloc(1, sizeof(struct man_node));
24432a712daSGarrett D'Amore p->line = line;
24532a712daSGarrett D'Amore p->pos = pos;
24632a712daSGarrett D'Amore p->type = type;
24732a712daSGarrett D'Amore p->tok = tok;
24832a712daSGarrett D'Amore
249*ffb8ebfaSGarrett D'Amore if (MAN_NEWLINE & man->flags)
25032a712daSGarrett D'Amore p->flags |= MAN_LINE;
251*ffb8ebfaSGarrett D'Amore man->flags &= ~MAN_NEWLINE;
25232a712daSGarrett D'Amore return(p);
25332a712daSGarrett D'Amore }
25432a712daSGarrett D'Amore
25532a712daSGarrett D'Amore
25632a712daSGarrett D'Amore int
man_elem_alloc(struct man * man,int line,int pos,enum mant tok)257*ffb8ebfaSGarrett D'Amore man_elem_alloc(struct man *man, int line, int pos, enum mant tok)
25832a712daSGarrett D'Amore {
25932a712daSGarrett D'Amore struct man_node *p;
26032a712daSGarrett D'Amore
261*ffb8ebfaSGarrett D'Amore p = man_node_alloc(man, line, pos, MAN_ELEM, tok);
262*ffb8ebfaSGarrett D'Amore if ( ! man_node_append(man, p))
26332a712daSGarrett D'Amore return(0);
264*ffb8ebfaSGarrett D'Amore man->next = MAN_NEXT_CHILD;
26532a712daSGarrett D'Amore return(1);
26632a712daSGarrett D'Amore }
26732a712daSGarrett D'Amore
26832a712daSGarrett D'Amore
26932a712daSGarrett D'Amore int
man_tail_alloc(struct man * man,int line,int pos,enum mant tok)270*ffb8ebfaSGarrett D'Amore man_tail_alloc(struct man *man, int line, int pos, enum mant tok)
27132a712daSGarrett D'Amore {
27232a712daSGarrett D'Amore struct man_node *p;
27332a712daSGarrett D'Amore
274*ffb8ebfaSGarrett D'Amore p = man_node_alloc(man, line, pos, MAN_TAIL, tok);
275*ffb8ebfaSGarrett D'Amore if ( ! man_node_append(man, p))
27632a712daSGarrett D'Amore return(0);
277*ffb8ebfaSGarrett D'Amore man->next = MAN_NEXT_CHILD;
27832a712daSGarrett D'Amore return(1);
27932a712daSGarrett D'Amore }
28032a712daSGarrett D'Amore
28132a712daSGarrett D'Amore
28232a712daSGarrett D'Amore int
man_head_alloc(struct man * man,int line,int pos,enum mant tok)283*ffb8ebfaSGarrett D'Amore man_head_alloc(struct man *man, int line, int pos, enum mant tok)
28432a712daSGarrett D'Amore {
28532a712daSGarrett D'Amore struct man_node *p;
28632a712daSGarrett D'Amore
287*ffb8ebfaSGarrett D'Amore p = man_node_alloc(man, line, pos, MAN_HEAD, tok);
288*ffb8ebfaSGarrett D'Amore if ( ! man_node_append(man, p))
28932a712daSGarrett D'Amore return(0);
290*ffb8ebfaSGarrett D'Amore man->next = MAN_NEXT_CHILD;
29132a712daSGarrett D'Amore return(1);
29232a712daSGarrett D'Amore }
29332a712daSGarrett D'Amore
29432a712daSGarrett D'Amore
29532a712daSGarrett D'Amore int
man_body_alloc(struct man * man,int line,int pos,enum mant tok)296*ffb8ebfaSGarrett D'Amore man_body_alloc(struct man *man, int line, int pos, enum mant tok)
29732a712daSGarrett D'Amore {
29832a712daSGarrett D'Amore struct man_node *p;
29932a712daSGarrett D'Amore
300*ffb8ebfaSGarrett D'Amore p = man_node_alloc(man, line, pos, MAN_BODY, tok);
301*ffb8ebfaSGarrett D'Amore if ( ! man_node_append(man, p))
30232a712daSGarrett D'Amore return(0);
303*ffb8ebfaSGarrett D'Amore man->next = MAN_NEXT_CHILD;
30432a712daSGarrett D'Amore return(1);
30532a712daSGarrett D'Amore }
30632a712daSGarrett D'Amore
30732a712daSGarrett D'Amore
30832a712daSGarrett D'Amore int
man_block_alloc(struct man * man,int line,int pos,enum mant tok)309*ffb8ebfaSGarrett D'Amore man_block_alloc(struct man *man, int line, int pos, enum mant tok)
31032a712daSGarrett D'Amore {
31132a712daSGarrett D'Amore struct man_node *p;
31232a712daSGarrett D'Amore
313*ffb8ebfaSGarrett D'Amore p = man_node_alloc(man, line, pos, MAN_BLOCK, tok);
314*ffb8ebfaSGarrett D'Amore if ( ! man_node_append(man, p))
31532a712daSGarrett D'Amore return(0);
316*ffb8ebfaSGarrett D'Amore man->next = MAN_NEXT_CHILD;
31732a712daSGarrett D'Amore return(1);
31832a712daSGarrett D'Amore }
31932a712daSGarrett D'Amore
32032a712daSGarrett D'Amore int
man_word_alloc(struct man * man,int line,int pos,const char * word)321*ffb8ebfaSGarrett D'Amore man_word_alloc(struct man *man, int line, int pos, const char *word)
32232a712daSGarrett D'Amore {
32332a712daSGarrett D'Amore struct man_node *n;
32432a712daSGarrett D'Amore
325*ffb8ebfaSGarrett D'Amore n = man_node_alloc(man, line, pos, MAN_TEXT, MAN_MAX);
326*ffb8ebfaSGarrett D'Amore n->string = roff_strdup(man->roff, word);
32732a712daSGarrett D'Amore
328*ffb8ebfaSGarrett D'Amore if ( ! man_node_append(man, n))
32932a712daSGarrett D'Amore return(0);
33032a712daSGarrett D'Amore
331*ffb8ebfaSGarrett D'Amore man->next = MAN_NEXT_SIBLING;
33232a712daSGarrett D'Amore return(1);
33332a712daSGarrett D'Amore }
33432a712daSGarrett D'Amore
33532a712daSGarrett D'Amore
33632a712daSGarrett D'Amore /*
33732a712daSGarrett D'Amore * Free all of the resources held by a node. This does NOT unlink a
33832a712daSGarrett D'Amore * node from its context; for that, see man_node_unlink().
33932a712daSGarrett D'Amore */
34032a712daSGarrett D'Amore static void
man_node_free(struct man_node * p)34132a712daSGarrett D'Amore man_node_free(struct man_node *p)
34232a712daSGarrett D'Amore {
34332a712daSGarrett D'Amore
34432a712daSGarrett D'Amore if (p->string)
34532a712daSGarrett D'Amore free(p->string);
34632a712daSGarrett D'Amore free(p);
34732a712daSGarrett D'Amore }
34832a712daSGarrett D'Amore
34932a712daSGarrett D'Amore
35032a712daSGarrett D'Amore void
man_node_delete(struct man * man,struct man_node * p)351*ffb8ebfaSGarrett D'Amore man_node_delete(struct man *man, struct man_node *p)
35232a712daSGarrett D'Amore {
35332a712daSGarrett D'Amore
35432a712daSGarrett D'Amore while (p->child)
355*ffb8ebfaSGarrett D'Amore man_node_delete(man, p->child);
35632a712daSGarrett D'Amore
357*ffb8ebfaSGarrett D'Amore man_node_unlink(man, p);
35832a712daSGarrett D'Amore man_node_free(p);
35932a712daSGarrett D'Amore }
36032a712daSGarrett D'Amore
36132a712daSGarrett D'Amore int
man_addeqn(struct man * man,const struct eqn * ep)362*ffb8ebfaSGarrett D'Amore man_addeqn(struct man *man, const struct eqn *ep)
36332a712daSGarrett D'Amore {
36432a712daSGarrett D'Amore struct man_node *n;
36532a712daSGarrett D'Amore
366*ffb8ebfaSGarrett D'Amore assert( ! (MAN_HALT & man->flags));
36732a712daSGarrett D'Amore
368*ffb8ebfaSGarrett D'Amore n = man_node_alloc(man, ep->ln, ep->pos, MAN_EQN, MAN_MAX);
36932a712daSGarrett D'Amore n->eqn = ep;
37032a712daSGarrett D'Amore
371*ffb8ebfaSGarrett D'Amore if ( ! man_node_append(man, n))
37232a712daSGarrett D'Amore return(0);
37332a712daSGarrett D'Amore
374*ffb8ebfaSGarrett D'Amore man->next = MAN_NEXT_SIBLING;
375*ffb8ebfaSGarrett D'Amore return(man_descope(man, ep->ln, ep->pos));
37632a712daSGarrett D'Amore }
37732a712daSGarrett D'Amore
37832a712daSGarrett D'Amore int
man_addspan(struct man * man,const struct tbl_span * sp)379*ffb8ebfaSGarrett D'Amore man_addspan(struct man *man, const struct tbl_span *sp)
38032a712daSGarrett D'Amore {
38132a712daSGarrett D'Amore struct man_node *n;
38232a712daSGarrett D'Amore
383*ffb8ebfaSGarrett D'Amore assert( ! (MAN_HALT & man->flags));
38432a712daSGarrett D'Amore
385*ffb8ebfaSGarrett D'Amore n = man_node_alloc(man, sp->line, 0, MAN_TBL, MAN_MAX);
38632a712daSGarrett D'Amore n->span = sp;
38732a712daSGarrett D'Amore
388*ffb8ebfaSGarrett D'Amore if ( ! man_node_append(man, n))
38932a712daSGarrett D'Amore return(0);
39032a712daSGarrett D'Amore
391*ffb8ebfaSGarrett D'Amore man->next = MAN_NEXT_SIBLING;
392*ffb8ebfaSGarrett D'Amore return(man_descope(man, sp->line, 0));
39332a712daSGarrett D'Amore }
39432a712daSGarrett D'Amore
39532a712daSGarrett D'Amore static int
man_descope(struct man * man,int line,int offs)396*ffb8ebfaSGarrett D'Amore man_descope(struct man *man, int line, int offs)
39732a712daSGarrett D'Amore {
39832a712daSGarrett D'Amore /*
39932a712daSGarrett D'Amore * Co-ordinate what happens with having a next-line scope open:
40032a712daSGarrett D'Amore * first close out the element scope (if applicable), then close
40132a712daSGarrett D'Amore * out the block scope (also if applicable).
40232a712daSGarrett D'Amore */
40332a712daSGarrett D'Amore
404*ffb8ebfaSGarrett D'Amore if (MAN_ELINE & man->flags) {
405*ffb8ebfaSGarrett D'Amore man->flags &= ~MAN_ELINE;
406*ffb8ebfaSGarrett D'Amore if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX))
40732a712daSGarrett D'Amore return(0);
40832a712daSGarrett D'Amore }
40932a712daSGarrett D'Amore
410*ffb8ebfaSGarrett D'Amore if ( ! (MAN_BLINE & man->flags))
41132a712daSGarrett D'Amore return(1);
412*ffb8ebfaSGarrett D'Amore man->flags &= ~MAN_BLINE;
41332a712daSGarrett D'Amore
414*ffb8ebfaSGarrett D'Amore if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX))
41532a712daSGarrett D'Amore return(0);
416*ffb8ebfaSGarrett D'Amore return(man_body_alloc(man, line, offs, man->last->tok));
41732a712daSGarrett D'Amore }
41832a712daSGarrett D'Amore
41932a712daSGarrett D'Amore static int
man_ptext(struct man * man,int line,char * buf,int offs)420*ffb8ebfaSGarrett D'Amore man_ptext(struct man *man, int line, char *buf, int offs)
42132a712daSGarrett D'Amore {
42232a712daSGarrett D'Amore int i;
42332a712daSGarrett D'Amore
42432a712daSGarrett D'Amore /* Literal free-form text whitespace is preserved. */
42532a712daSGarrett D'Amore
426*ffb8ebfaSGarrett D'Amore if (MAN_LITERAL & man->flags) {
427*ffb8ebfaSGarrett D'Amore if ( ! man_word_alloc(man, line, offs, buf + offs))
42832a712daSGarrett D'Amore return(0);
429*ffb8ebfaSGarrett D'Amore return(man_descope(man, line, offs));
43032a712daSGarrett D'Amore }
43132a712daSGarrett D'Amore
43232a712daSGarrett D'Amore for (i = offs; ' ' == buf[i]; i++)
43332a712daSGarrett D'Amore /* Skip leading whitespace. */ ;
43432a712daSGarrett D'Amore
435*ffb8ebfaSGarrett D'Amore /*
436*ffb8ebfaSGarrett D'Amore * Blank lines are ignored right after headings
437*ffb8ebfaSGarrett D'Amore * but add a single vertical space elsewhere.
438*ffb8ebfaSGarrett D'Amore */
439*ffb8ebfaSGarrett D'Amore
44032a712daSGarrett D'Amore if ('\0' == buf[i]) {
44132a712daSGarrett D'Amore /* Allocate a blank entry. */
442*ffb8ebfaSGarrett D'Amore if (MAN_SH != man->last->tok &&
443*ffb8ebfaSGarrett D'Amore MAN_SS != man->last->tok) {
444*ffb8ebfaSGarrett D'Amore if ( ! man_elem_alloc(man, line, offs, MAN_sp))
44532a712daSGarrett D'Amore return(0);
446*ffb8ebfaSGarrett D'Amore man->next = MAN_NEXT_SIBLING;
447*ffb8ebfaSGarrett D'Amore }
448*ffb8ebfaSGarrett D'Amore return(1);
44932a712daSGarrett D'Amore }
45032a712daSGarrett D'Amore
45132a712daSGarrett D'Amore /*
45232a712daSGarrett D'Amore * Warn if the last un-escaped character is whitespace. Then
45332a712daSGarrett D'Amore * strip away the remaining spaces (tabs stay!).
45432a712daSGarrett D'Amore */
45532a712daSGarrett D'Amore
45632a712daSGarrett D'Amore i = (int)strlen(buf);
45732a712daSGarrett D'Amore assert(i);
45832a712daSGarrett D'Amore
45932a712daSGarrett D'Amore if (' ' == buf[i - 1] || '\t' == buf[i - 1]) {
46032a712daSGarrett D'Amore if (i > 1 && '\\' != buf[i - 2])
461*ffb8ebfaSGarrett D'Amore man_pmsg(man, line, i - 1, MANDOCERR_EOLNSPACE);
46232a712daSGarrett D'Amore
46332a712daSGarrett D'Amore for (--i; i && ' ' == buf[i]; i--)
46432a712daSGarrett D'Amore /* Spin back to non-space. */ ;
46532a712daSGarrett D'Amore
46632a712daSGarrett D'Amore /* Jump ahead of escaped whitespace. */
46732a712daSGarrett D'Amore i += '\\' == buf[i] ? 2 : 1;
46832a712daSGarrett D'Amore
46932a712daSGarrett D'Amore buf[i] = '\0';
47032a712daSGarrett D'Amore }
47132a712daSGarrett D'Amore
472*ffb8ebfaSGarrett D'Amore if ( ! man_word_alloc(man, line, offs, buf + offs))
47332a712daSGarrett D'Amore return(0);
47432a712daSGarrett D'Amore
47532a712daSGarrett D'Amore /*
47632a712daSGarrett D'Amore * End-of-sentence check. If the last character is an unescaped
47732a712daSGarrett D'Amore * EOS character, then flag the node as being the end of a
47832a712daSGarrett D'Amore * sentence. The front-end will know how to interpret this.
47932a712daSGarrett D'Amore */
48032a712daSGarrett D'Amore
48132a712daSGarrett D'Amore assert(i);
48232a712daSGarrett D'Amore if (mandoc_eos(buf, (size_t)i, 0))
483*ffb8ebfaSGarrett D'Amore man->last->flags |= MAN_EOS;
48432a712daSGarrett D'Amore
485*ffb8ebfaSGarrett D'Amore return(man_descope(man, line, offs));
48632a712daSGarrett D'Amore }
48732a712daSGarrett D'Amore
48832a712daSGarrett D'Amore static int
man_pmacro(struct man * man,int ln,char * buf,int offs)489*ffb8ebfaSGarrett D'Amore man_pmacro(struct man *man, int ln, char *buf, int offs)
49032a712daSGarrett D'Amore {
49132a712daSGarrett D'Amore int i, ppos;
49232a712daSGarrett D'Amore enum mant tok;
49332a712daSGarrett D'Amore char mac[5];
49432a712daSGarrett D'Amore struct man_node *n;
49532a712daSGarrett D'Amore
49632a712daSGarrett D'Amore if ('"' == buf[offs]) {
497*ffb8ebfaSGarrett D'Amore man_pmsg(man, ln, offs, MANDOCERR_BADCOMMENT);
49832a712daSGarrett D'Amore return(1);
49932a712daSGarrett D'Amore } else if ('\0' == buf[offs])
50032a712daSGarrett D'Amore return(1);
50132a712daSGarrett D'Amore
50232a712daSGarrett D'Amore ppos = offs;
50332a712daSGarrett D'Amore
50432a712daSGarrett D'Amore /*
50532a712daSGarrett D'Amore * Copy the first word into a nil-terminated buffer.
50632a712daSGarrett D'Amore * Stop copying when a tab, space, or eoln is encountered.
50732a712daSGarrett D'Amore */
50832a712daSGarrett D'Amore
50932a712daSGarrett D'Amore i = 0;
51032a712daSGarrett D'Amore while (i < 4 && '\0' != buf[offs] &&
51132a712daSGarrett D'Amore ' ' != buf[offs] && '\t' != buf[offs])
51232a712daSGarrett D'Amore mac[i++] = buf[offs++];
51332a712daSGarrett D'Amore
51432a712daSGarrett D'Amore mac[i] = '\0';
51532a712daSGarrett D'Amore
51632a712daSGarrett D'Amore tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX;
51732a712daSGarrett D'Amore
51832a712daSGarrett D'Amore if (MAN_MAX == tok) {
519*ffb8ebfaSGarrett D'Amore mandoc_vmsg(MANDOCERR_MACRO, man->parse, ln,
52032a712daSGarrett D'Amore ppos, "%s", buf + ppos - 1);
52132a712daSGarrett D'Amore return(1);
52232a712daSGarrett D'Amore }
52332a712daSGarrett D'Amore
52432a712daSGarrett D'Amore /* The macro is sane. Jump to the next word. */
52532a712daSGarrett D'Amore
52632a712daSGarrett D'Amore while (buf[offs] && ' ' == buf[offs])
52732a712daSGarrett D'Amore offs++;
52832a712daSGarrett D'Amore
52932a712daSGarrett D'Amore /*
53032a712daSGarrett D'Amore * Trailing whitespace. Note that tabs are allowed to be passed
53132a712daSGarrett D'Amore * into the parser as "text", so we only warn about spaces here.
53232a712daSGarrett D'Amore */
53332a712daSGarrett D'Amore
53432a712daSGarrett D'Amore if ('\0' == buf[offs] && ' ' == buf[offs - 1])
535*ffb8ebfaSGarrett D'Amore man_pmsg(man, ln, offs - 1, MANDOCERR_EOLNSPACE);
53632a712daSGarrett D'Amore
53732a712daSGarrett D'Amore /*
53832a712daSGarrett D'Amore * Remove prior ELINE macro, as it's being clobbered by a new
53932a712daSGarrett D'Amore * macro. Note that NSCOPED macros do not close out ELINE
54032a712daSGarrett D'Amore * macros---they don't print text---so we let those slip by.
54132a712daSGarrett D'Amore */
54232a712daSGarrett D'Amore
54332a712daSGarrett D'Amore if ( ! (MAN_NSCOPED & man_macros[tok].flags) &&
544*ffb8ebfaSGarrett D'Amore man->flags & MAN_ELINE) {
545*ffb8ebfaSGarrett D'Amore n = man->last;
54632a712daSGarrett D'Amore assert(MAN_TEXT != n->type);
54732a712daSGarrett D'Amore
54832a712daSGarrett D'Amore /* Remove repeated NSCOPED macros causing ELINE. */
54932a712daSGarrett D'Amore
55032a712daSGarrett D'Amore if (MAN_NSCOPED & man_macros[n->tok].flags)
55132a712daSGarrett D'Amore n = n->parent;
55232a712daSGarrett D'Amore
553*ffb8ebfaSGarrett D'Amore mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line,
55432a712daSGarrett D'Amore n->pos, "%s breaks %s", man_macronames[tok],
55532a712daSGarrett D'Amore man_macronames[n->tok]);
55632a712daSGarrett D'Amore
557*ffb8ebfaSGarrett D'Amore man_node_delete(man, n);
558*ffb8ebfaSGarrett D'Amore man->flags &= ~MAN_ELINE;
55932a712daSGarrett D'Amore }
56032a712daSGarrett D'Amore
56132a712daSGarrett D'Amore /*
56232a712daSGarrett D'Amore * Remove prior BLINE macro that is being clobbered.
56332a712daSGarrett D'Amore */
564*ffb8ebfaSGarrett D'Amore if ((man->flags & MAN_BLINE) &&
56532a712daSGarrett D'Amore (MAN_BSCOPE & man_macros[tok].flags)) {
566*ffb8ebfaSGarrett D'Amore n = man->last;
56732a712daSGarrett D'Amore
56832a712daSGarrett D'Amore /* Might be a text node like 8 in
56932a712daSGarrett D'Amore * .TP 8
57032a712daSGarrett D'Amore * .SH foo
57132a712daSGarrett D'Amore */
57232a712daSGarrett D'Amore if (MAN_TEXT == n->type)
57332a712daSGarrett D'Amore n = n->parent;
57432a712daSGarrett D'Amore
57532a712daSGarrett D'Amore /* Remove element that didn't end BLINE, if any. */
57632a712daSGarrett D'Amore if ( ! (MAN_BSCOPE & man_macros[n->tok].flags))
57732a712daSGarrett D'Amore n = n->parent;
57832a712daSGarrett D'Amore
57932a712daSGarrett D'Amore assert(MAN_HEAD == n->type);
58032a712daSGarrett D'Amore n = n->parent;
58132a712daSGarrett D'Amore assert(MAN_BLOCK == n->type);
58232a712daSGarrett D'Amore assert(MAN_SCOPED & man_macros[n->tok].flags);
58332a712daSGarrett D'Amore
584*ffb8ebfaSGarrett D'Amore mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line,
58532a712daSGarrett D'Amore n->pos, "%s breaks %s", man_macronames[tok],
58632a712daSGarrett D'Amore man_macronames[n->tok]);
58732a712daSGarrett D'Amore
588*ffb8ebfaSGarrett D'Amore man_node_delete(man, n);
589*ffb8ebfaSGarrett D'Amore man->flags &= ~MAN_BLINE;
59032a712daSGarrett D'Amore }
59132a712daSGarrett D'Amore
59232a712daSGarrett D'Amore /*
59332a712daSGarrett D'Amore * Save the fact that we're in the next-line for a block. In
59432a712daSGarrett D'Amore * this way, embedded roff instructions can "remember" state
59532a712daSGarrett D'Amore * when they exit.
59632a712daSGarrett D'Amore */
59732a712daSGarrett D'Amore
598*ffb8ebfaSGarrett D'Amore if (MAN_BLINE & man->flags)
599*ffb8ebfaSGarrett D'Amore man->flags |= MAN_BPLINE;
60032a712daSGarrett D'Amore
60132a712daSGarrett D'Amore /* Call to handler... */
60232a712daSGarrett D'Amore
60332a712daSGarrett D'Amore assert(man_macros[tok].fp);
604*ffb8ebfaSGarrett D'Amore if ( ! (*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf))
60532a712daSGarrett D'Amore goto err;
60632a712daSGarrett D'Amore
60732a712daSGarrett D'Amore /*
60832a712daSGarrett D'Amore * We weren't in a block-line scope when entering the
60932a712daSGarrett D'Amore * above-parsed macro, so return.
61032a712daSGarrett D'Amore */
61132a712daSGarrett D'Amore
612*ffb8ebfaSGarrett D'Amore if ( ! (MAN_BPLINE & man->flags)) {
613*ffb8ebfaSGarrett D'Amore man->flags &= ~MAN_ILINE;
61432a712daSGarrett D'Amore return(1);
61532a712daSGarrett D'Amore }
616*ffb8ebfaSGarrett D'Amore man->flags &= ~MAN_BPLINE;
61732a712daSGarrett D'Amore
61832a712daSGarrett D'Amore /*
61932a712daSGarrett D'Amore * If we're in a block scope, then allow this macro to slip by
62032a712daSGarrett D'Amore * without closing scope around it.
62132a712daSGarrett D'Amore */
62232a712daSGarrett D'Amore
623*ffb8ebfaSGarrett D'Amore if (MAN_ILINE & man->flags) {
624*ffb8ebfaSGarrett D'Amore man->flags &= ~MAN_ILINE;
62532a712daSGarrett D'Amore return(1);
62632a712daSGarrett D'Amore }
62732a712daSGarrett D'Amore
62832a712daSGarrett D'Amore /*
62932a712daSGarrett D'Amore * If we've opened a new next-line element scope, then return
63032a712daSGarrett D'Amore * now, as the next line will close out the block scope.
63132a712daSGarrett D'Amore */
63232a712daSGarrett D'Amore
633*ffb8ebfaSGarrett D'Amore if (MAN_ELINE & man->flags)
63432a712daSGarrett D'Amore return(1);
63532a712daSGarrett D'Amore
63632a712daSGarrett D'Amore /* Close out the block scope opened in the prior line. */
63732a712daSGarrett D'Amore
638*ffb8ebfaSGarrett D'Amore assert(MAN_BLINE & man->flags);
639*ffb8ebfaSGarrett D'Amore man->flags &= ~MAN_BLINE;
64032a712daSGarrett D'Amore
641*ffb8ebfaSGarrett D'Amore if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX))
64232a712daSGarrett D'Amore return(0);
643*ffb8ebfaSGarrett D'Amore return(man_body_alloc(man, ln, ppos, man->last->tok));
64432a712daSGarrett D'Amore
64532a712daSGarrett D'Amore err: /* Error out. */
64632a712daSGarrett D'Amore
647*ffb8ebfaSGarrett D'Amore man->flags |= MAN_HALT;
64832a712daSGarrett D'Amore return(0);
64932a712daSGarrett D'Amore }
65032a712daSGarrett D'Amore
65132a712daSGarrett D'Amore /*
652*ffb8ebfaSGarrett D'Amore * Unlink a node from its context. If "man" is provided, the last parse
65332a712daSGarrett D'Amore * point will also be adjusted accordingly.
65432a712daSGarrett D'Amore */
65532a712daSGarrett D'Amore static void
man_node_unlink(struct man * man,struct man_node * n)656*ffb8ebfaSGarrett D'Amore man_node_unlink(struct man *man, struct man_node *n)
65732a712daSGarrett D'Amore {
65832a712daSGarrett D'Amore
65932a712daSGarrett D'Amore /* Adjust siblings. */
66032a712daSGarrett D'Amore
66132a712daSGarrett D'Amore if (n->prev)
66232a712daSGarrett D'Amore n->prev->next = n->next;
66332a712daSGarrett D'Amore if (n->next)
66432a712daSGarrett D'Amore n->next->prev = n->prev;
66532a712daSGarrett D'Amore
66632a712daSGarrett D'Amore /* Adjust parent. */
66732a712daSGarrett D'Amore
66832a712daSGarrett D'Amore if (n->parent) {
66932a712daSGarrett D'Amore n->parent->nchild--;
67032a712daSGarrett D'Amore if (n->parent->child == n)
67132a712daSGarrett D'Amore n->parent->child = n->prev ? n->prev : n->next;
67232a712daSGarrett D'Amore }
67332a712daSGarrett D'Amore
67432a712daSGarrett D'Amore /* Adjust parse point, if applicable. */
67532a712daSGarrett D'Amore
676*ffb8ebfaSGarrett D'Amore if (man && man->last == n) {
67732a712daSGarrett D'Amore /*XXX: this can occur when bailing from validation. */
67832a712daSGarrett D'Amore /*assert(NULL == n->next);*/
67932a712daSGarrett D'Amore if (n->prev) {
680*ffb8ebfaSGarrett D'Amore man->last = n->prev;
681*ffb8ebfaSGarrett D'Amore man->next = MAN_NEXT_SIBLING;
68232a712daSGarrett D'Amore } else {
683*ffb8ebfaSGarrett D'Amore man->last = n->parent;
684*ffb8ebfaSGarrett D'Amore man->next = MAN_NEXT_CHILD;
68532a712daSGarrett D'Amore }
68632a712daSGarrett D'Amore }
68732a712daSGarrett D'Amore
688*ffb8ebfaSGarrett D'Amore if (man && man->first == n)
689*ffb8ebfaSGarrett D'Amore man->first = NULL;
69032a712daSGarrett D'Amore }
69132a712daSGarrett D'Amore
69232a712daSGarrett D'Amore const struct mparse *
man_mparse(const struct man * man)693*ffb8ebfaSGarrett D'Amore man_mparse(const struct man *man)
69432a712daSGarrett D'Amore {
69532a712daSGarrett D'Amore
696*ffb8ebfaSGarrett D'Amore assert(man && man->parse);
697*ffb8ebfaSGarrett D'Amore return(man->parse);
69832a712daSGarrett D'Amore }
699