xref: /titanic_50/usr/src/cmd/mandoc/man.c (revision 698f87a48e2e945bfe5493ce168e0d0ae1cedd5c)
1*698f87a4SGarrett D'Amore /*	$Id: man.c,v 1.121 2013/11/10 22:54:40 schwarze Exp $ */
295c635efSGarrett D'Amore /*
395c635efSGarrett D'Amore  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
495c635efSGarrett D'Amore  *
595c635efSGarrett D'Amore  * Permission to use, copy, modify, and distribute this software for any
695c635efSGarrett D'Amore  * purpose with or without fee is hereby granted, provided that the above
795c635efSGarrett D'Amore  * copyright notice and this permission notice appear in all copies.
895c635efSGarrett D'Amore  *
995c635efSGarrett D'Amore  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1095c635efSGarrett D'Amore  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1195c635efSGarrett D'Amore  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1295c635efSGarrett D'Amore  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1395c635efSGarrett D'Amore  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1495c635efSGarrett D'Amore  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1595c635efSGarrett D'Amore  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1695c635efSGarrett D'Amore  */
1795c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H
1895c635efSGarrett D'Amore #include "config.h"
1995c635efSGarrett D'Amore #endif
2095c635efSGarrett D'Amore 
2195c635efSGarrett D'Amore #include <sys/types.h>
2295c635efSGarrett D'Amore 
2395c635efSGarrett D'Amore #include <assert.h>
2495c635efSGarrett D'Amore #include <stdarg.h>
2595c635efSGarrett D'Amore #include <stdlib.h>
2695c635efSGarrett D'Amore #include <stdio.h>
2795c635efSGarrett D'Amore #include <string.h>
2895c635efSGarrett D'Amore 
2995c635efSGarrett D'Amore #include "man.h"
3095c635efSGarrett D'Amore #include "mandoc.h"
3195c635efSGarrett D'Amore #include "libman.h"
3295c635efSGarrett D'Amore #include "libmandoc.h"
3395c635efSGarrett D'Amore 
3495c635efSGarrett D'Amore const	char *const __man_macronames[MAN_MAX] = {
3595c635efSGarrett D'Amore 	"br",		"TH",		"SH",		"SS",
3695c635efSGarrett D'Amore 	"TP", 		"LP",		"PP",		"P",
3795c635efSGarrett D'Amore 	"IP",		"HP",		"SM",		"SB",
3895c635efSGarrett D'Amore 	"BI",		"IB",		"BR",		"RB",
3995c635efSGarrett D'Amore 	"R",		"B",		"I",		"IR",
4095c635efSGarrett D'Amore 	"RI",		"na",		"sp",		"nf",
4195c635efSGarrett D'Amore 	"fi",		"RE",		"RS",		"DT",
4295c635efSGarrett D'Amore 	"UC",		"PD",		"AT",		"in",
43*698f87a4SGarrett D'Amore 	"ft",		"OP",		"EX",		"EE",
44*698f87a4SGarrett D'Amore 	"UR",		"UE"
4595c635efSGarrett D'Amore 	};
4695c635efSGarrett D'Amore 
4795c635efSGarrett D'Amore const	char * const *man_macronames = __man_macronames;
4895c635efSGarrett D'Amore 
4995c635efSGarrett D'Amore static	struct man_node	*man_node_alloc(struct man *, int, int,
5095c635efSGarrett D'Amore 				enum man_type, enum mant);
5195c635efSGarrett D'Amore static	int		 man_node_append(struct man *,
5295c635efSGarrett D'Amore 				struct man_node *);
5395c635efSGarrett D'Amore static	void		 man_node_free(struct man_node *);
5495c635efSGarrett D'Amore static	void		 man_node_unlink(struct man *,
5595c635efSGarrett D'Amore 				struct man_node *);
5695c635efSGarrett D'Amore static	int		 man_ptext(struct man *, int, char *, int);
5795c635efSGarrett D'Amore static	int		 man_pmacro(struct man *, int, char *, int);
5895c635efSGarrett D'Amore static	void		 man_free1(struct man *);
5995c635efSGarrett D'Amore static	void		 man_alloc1(struct man *);
6095c635efSGarrett D'Amore static	int		 man_descope(struct man *, int, int);
6195c635efSGarrett D'Amore 
6295c635efSGarrett D'Amore 
6395c635efSGarrett D'Amore const struct man_node *
64*698f87a4SGarrett D'Amore man_node(const struct man *man)
6595c635efSGarrett D'Amore {
6695c635efSGarrett D'Amore 
67*698f87a4SGarrett D'Amore 	assert( ! (MAN_HALT & man->flags));
68*698f87a4SGarrett D'Amore 	return(man->first);
6995c635efSGarrett D'Amore }
7095c635efSGarrett D'Amore 
7195c635efSGarrett D'Amore 
7295c635efSGarrett D'Amore const struct man_meta *
73*698f87a4SGarrett D'Amore man_meta(const struct man *man)
7495c635efSGarrett D'Amore {
7595c635efSGarrett D'Amore 
76*698f87a4SGarrett D'Amore 	assert( ! (MAN_HALT & man->flags));
77*698f87a4SGarrett D'Amore 	return(&man->meta);
7895c635efSGarrett D'Amore }
7995c635efSGarrett D'Amore 
8095c635efSGarrett D'Amore 
8195c635efSGarrett D'Amore void
8295c635efSGarrett D'Amore man_reset(struct man *man)
8395c635efSGarrett D'Amore {
8495c635efSGarrett D'Amore 
8595c635efSGarrett D'Amore 	man_free1(man);
8695c635efSGarrett D'Amore 	man_alloc1(man);
8795c635efSGarrett D'Amore }
8895c635efSGarrett D'Amore 
8995c635efSGarrett D'Amore 
9095c635efSGarrett D'Amore void
9195c635efSGarrett D'Amore man_free(struct man *man)
9295c635efSGarrett D'Amore {
9395c635efSGarrett D'Amore 
9495c635efSGarrett D'Amore 	man_free1(man);
9595c635efSGarrett D'Amore 	free(man);
9695c635efSGarrett D'Amore }
9795c635efSGarrett D'Amore 
9895c635efSGarrett D'Amore 
9995c635efSGarrett D'Amore struct man *
10095c635efSGarrett D'Amore man_alloc(struct roff *roff, struct mparse *parse)
10195c635efSGarrett D'Amore {
10295c635efSGarrett D'Amore 	struct man	*p;
10395c635efSGarrett D'Amore 
10495c635efSGarrett D'Amore 	p = mandoc_calloc(1, sizeof(struct man));
10595c635efSGarrett D'Amore 
10695c635efSGarrett D'Amore 	man_hash_init();
10795c635efSGarrett D'Amore 	p->parse = parse;
10895c635efSGarrett D'Amore 	p->roff = roff;
10995c635efSGarrett D'Amore 
11095c635efSGarrett D'Amore 	man_alloc1(p);
11195c635efSGarrett D'Amore 	return(p);
11295c635efSGarrett D'Amore }
11395c635efSGarrett D'Amore 
11495c635efSGarrett D'Amore 
11595c635efSGarrett D'Amore int
116*698f87a4SGarrett D'Amore man_endparse(struct man *man)
11795c635efSGarrett D'Amore {
11895c635efSGarrett D'Amore 
119*698f87a4SGarrett D'Amore 	assert( ! (MAN_HALT & man->flags));
120*698f87a4SGarrett D'Amore 	if (man_macroend(man))
12195c635efSGarrett D'Amore 		return(1);
122*698f87a4SGarrett D'Amore 	man->flags |= MAN_HALT;
12395c635efSGarrett D'Amore 	return(0);
12495c635efSGarrett D'Amore }
12595c635efSGarrett D'Amore 
12695c635efSGarrett D'Amore 
12795c635efSGarrett D'Amore int
128*698f87a4SGarrett D'Amore man_parseln(struct man *man, int ln, char *buf, int offs)
12995c635efSGarrett D'Amore {
13095c635efSGarrett D'Amore 
131*698f87a4SGarrett D'Amore 	man->flags |= MAN_NEWLINE;
13295c635efSGarrett D'Amore 
133*698f87a4SGarrett D'Amore 	assert( ! (MAN_HALT & man->flags));
13495c635efSGarrett D'Amore 
135*698f87a4SGarrett D'Amore 	return (roff_getcontrol(man->roff, buf, &offs) ?
136*698f87a4SGarrett D'Amore 			man_pmacro(man, ln, buf, offs) :
137*698f87a4SGarrett D'Amore 			man_ptext(man, ln, buf, offs));
13895c635efSGarrett D'Amore }
13995c635efSGarrett D'Amore 
14095c635efSGarrett D'Amore 
14195c635efSGarrett D'Amore static void
14295c635efSGarrett D'Amore man_free1(struct man *man)
14395c635efSGarrett D'Amore {
14495c635efSGarrett D'Amore 
14595c635efSGarrett D'Amore 	if (man->first)
14695c635efSGarrett D'Amore 		man_node_delete(man, man->first);
14795c635efSGarrett D'Amore 	if (man->meta.title)
14895c635efSGarrett D'Amore 		free(man->meta.title);
14995c635efSGarrett D'Amore 	if (man->meta.source)
15095c635efSGarrett D'Amore 		free(man->meta.source);
15195c635efSGarrett D'Amore 	if (man->meta.date)
15295c635efSGarrett D'Amore 		free(man->meta.date);
15395c635efSGarrett D'Amore 	if (man->meta.vol)
15495c635efSGarrett D'Amore 		free(man->meta.vol);
15595c635efSGarrett D'Amore 	if (man->meta.msec)
15695c635efSGarrett D'Amore 		free(man->meta.msec);
15795c635efSGarrett D'Amore }
15895c635efSGarrett D'Amore 
15995c635efSGarrett D'Amore 
16095c635efSGarrett D'Amore static void
161*698f87a4SGarrett D'Amore man_alloc1(struct man *man)
16295c635efSGarrett D'Amore {
16395c635efSGarrett D'Amore 
164*698f87a4SGarrett D'Amore 	memset(&man->meta, 0, sizeof(struct man_meta));
165*698f87a4SGarrett D'Amore 	man->flags = 0;
166*698f87a4SGarrett D'Amore 	man->last = mandoc_calloc(1, sizeof(struct man_node));
167*698f87a4SGarrett D'Amore 	man->first = man->last;
168*698f87a4SGarrett D'Amore 	man->last->type = MAN_ROOT;
169*698f87a4SGarrett D'Amore 	man->last->tok = MAN_MAX;
170*698f87a4SGarrett D'Amore 	man->next = MAN_NEXT_CHILD;
17195c635efSGarrett D'Amore }
17295c635efSGarrett D'Amore 
17395c635efSGarrett D'Amore 
17495c635efSGarrett D'Amore static int
17595c635efSGarrett D'Amore man_node_append(struct man *man, struct man_node *p)
17695c635efSGarrett D'Amore {
17795c635efSGarrett D'Amore 
17895c635efSGarrett D'Amore 	assert(man->last);
17995c635efSGarrett D'Amore 	assert(man->first);
18095c635efSGarrett D'Amore 	assert(MAN_ROOT != p->type);
18195c635efSGarrett D'Amore 
18295c635efSGarrett D'Amore 	switch (man->next) {
18395c635efSGarrett D'Amore 	case (MAN_NEXT_SIBLING):
18495c635efSGarrett D'Amore 		man->last->next = p;
18595c635efSGarrett D'Amore 		p->prev = man->last;
18695c635efSGarrett D'Amore 		p->parent = man->last->parent;
18795c635efSGarrett D'Amore 		break;
18895c635efSGarrett D'Amore 	case (MAN_NEXT_CHILD):
18995c635efSGarrett D'Amore 		man->last->child = p;
19095c635efSGarrett D'Amore 		p->parent = man->last;
19195c635efSGarrett D'Amore 		break;
19295c635efSGarrett D'Amore 	default:
19395c635efSGarrett D'Amore 		abort();
19495c635efSGarrett D'Amore 		/* NOTREACHED */
19595c635efSGarrett D'Amore 	}
19695c635efSGarrett D'Amore 
19795c635efSGarrett D'Amore 	assert(p->parent);
19895c635efSGarrett D'Amore 	p->parent->nchild++;
19995c635efSGarrett D'Amore 
20095c635efSGarrett D'Amore 	if ( ! man_valid_pre(man, p))
20195c635efSGarrett D'Amore 		return(0);
20295c635efSGarrett D'Amore 
20395c635efSGarrett D'Amore 	switch (p->type) {
20495c635efSGarrett D'Amore 	case (MAN_HEAD):
20595c635efSGarrett D'Amore 		assert(MAN_BLOCK == p->parent->type);
20695c635efSGarrett D'Amore 		p->parent->head = p;
20795c635efSGarrett D'Amore 		break;
20895c635efSGarrett D'Amore 	case (MAN_TAIL):
20995c635efSGarrett D'Amore 		assert(MAN_BLOCK == p->parent->type);
21095c635efSGarrett D'Amore 		p->parent->tail = p;
21195c635efSGarrett D'Amore 		break;
21295c635efSGarrett D'Amore 	case (MAN_BODY):
21395c635efSGarrett D'Amore 		assert(MAN_BLOCK == p->parent->type);
21495c635efSGarrett D'Amore 		p->parent->body = p;
21595c635efSGarrett D'Amore 		break;
21695c635efSGarrett D'Amore 	default:
21795c635efSGarrett D'Amore 		break;
21895c635efSGarrett D'Amore 	}
21995c635efSGarrett D'Amore 
22095c635efSGarrett D'Amore 	man->last = p;
22195c635efSGarrett D'Amore 
22295c635efSGarrett D'Amore 	switch (p->type) {
22395c635efSGarrett D'Amore 	case (MAN_TBL):
22495c635efSGarrett D'Amore 		/* FALLTHROUGH */
22595c635efSGarrett D'Amore 	case (MAN_TEXT):
22695c635efSGarrett D'Amore 		if ( ! man_valid_post(man))
22795c635efSGarrett D'Amore 			return(0);
22895c635efSGarrett D'Amore 		break;
22995c635efSGarrett D'Amore 	default:
23095c635efSGarrett D'Amore 		break;
23195c635efSGarrett D'Amore 	}
23295c635efSGarrett D'Amore 
23395c635efSGarrett D'Amore 	return(1);
23495c635efSGarrett D'Amore }
23595c635efSGarrett D'Amore 
23695c635efSGarrett D'Amore 
23795c635efSGarrett D'Amore static struct man_node *
238*698f87a4SGarrett D'Amore man_node_alloc(struct man *man, int line, int pos,
23995c635efSGarrett D'Amore 		enum man_type type, enum mant tok)
24095c635efSGarrett D'Amore {
24195c635efSGarrett D'Amore 	struct man_node *p;
24295c635efSGarrett D'Amore 
24395c635efSGarrett D'Amore 	p = mandoc_calloc(1, sizeof(struct man_node));
24495c635efSGarrett D'Amore 	p->line = line;
24595c635efSGarrett D'Amore 	p->pos = pos;
24695c635efSGarrett D'Amore 	p->type = type;
24795c635efSGarrett D'Amore 	p->tok = tok;
24895c635efSGarrett D'Amore 
249*698f87a4SGarrett D'Amore 	if (MAN_NEWLINE & man->flags)
25095c635efSGarrett D'Amore 		p->flags |= MAN_LINE;
251*698f87a4SGarrett D'Amore 	man->flags &= ~MAN_NEWLINE;
25295c635efSGarrett D'Amore 	return(p);
25395c635efSGarrett D'Amore }
25495c635efSGarrett D'Amore 
25595c635efSGarrett D'Amore 
25695c635efSGarrett D'Amore int
257*698f87a4SGarrett D'Amore man_elem_alloc(struct man *man, int line, int pos, enum mant tok)
25895c635efSGarrett D'Amore {
25995c635efSGarrett D'Amore 	struct man_node *p;
26095c635efSGarrett D'Amore 
261*698f87a4SGarrett D'Amore 	p = man_node_alloc(man, line, pos, MAN_ELEM, tok);
262*698f87a4SGarrett D'Amore 	if ( ! man_node_append(man, p))
26395c635efSGarrett D'Amore 		return(0);
264*698f87a4SGarrett D'Amore 	man->next = MAN_NEXT_CHILD;
26595c635efSGarrett D'Amore 	return(1);
26695c635efSGarrett D'Amore }
26795c635efSGarrett D'Amore 
26895c635efSGarrett D'Amore 
26995c635efSGarrett D'Amore int
270*698f87a4SGarrett D'Amore man_tail_alloc(struct man *man, int line, int pos, enum mant tok)
27195c635efSGarrett D'Amore {
27295c635efSGarrett D'Amore 	struct man_node *p;
27395c635efSGarrett D'Amore 
274*698f87a4SGarrett D'Amore 	p = man_node_alloc(man, line, pos, MAN_TAIL, tok);
275*698f87a4SGarrett D'Amore 	if ( ! man_node_append(man, p))
27695c635efSGarrett D'Amore 		return(0);
277*698f87a4SGarrett D'Amore 	man->next = MAN_NEXT_CHILD;
27895c635efSGarrett D'Amore 	return(1);
27995c635efSGarrett D'Amore }
28095c635efSGarrett D'Amore 
28195c635efSGarrett D'Amore 
28295c635efSGarrett D'Amore int
283*698f87a4SGarrett D'Amore man_head_alloc(struct man *man, int line, int pos, enum mant tok)
28495c635efSGarrett D'Amore {
28595c635efSGarrett D'Amore 	struct man_node *p;
28695c635efSGarrett D'Amore 
287*698f87a4SGarrett D'Amore 	p = man_node_alloc(man, line, pos, MAN_HEAD, tok);
288*698f87a4SGarrett D'Amore 	if ( ! man_node_append(man, p))
28995c635efSGarrett D'Amore 		return(0);
290*698f87a4SGarrett D'Amore 	man->next = MAN_NEXT_CHILD;
29195c635efSGarrett D'Amore 	return(1);
29295c635efSGarrett D'Amore }
29395c635efSGarrett D'Amore 
29495c635efSGarrett D'Amore 
29595c635efSGarrett D'Amore int
296*698f87a4SGarrett D'Amore man_body_alloc(struct man *man, int line, int pos, enum mant tok)
29795c635efSGarrett D'Amore {
29895c635efSGarrett D'Amore 	struct man_node *p;
29995c635efSGarrett D'Amore 
300*698f87a4SGarrett D'Amore 	p = man_node_alloc(man, line, pos, MAN_BODY, tok);
301*698f87a4SGarrett D'Amore 	if ( ! man_node_append(man, p))
30295c635efSGarrett D'Amore 		return(0);
303*698f87a4SGarrett D'Amore 	man->next = MAN_NEXT_CHILD;
30495c635efSGarrett D'Amore 	return(1);
30595c635efSGarrett D'Amore }
30695c635efSGarrett D'Amore 
30795c635efSGarrett D'Amore 
30895c635efSGarrett D'Amore int
309*698f87a4SGarrett D'Amore man_block_alloc(struct man *man, int line, int pos, enum mant tok)
31095c635efSGarrett D'Amore {
31195c635efSGarrett D'Amore 	struct man_node *p;
31295c635efSGarrett D'Amore 
313*698f87a4SGarrett D'Amore 	p = man_node_alloc(man, line, pos, MAN_BLOCK, tok);
314*698f87a4SGarrett D'Amore 	if ( ! man_node_append(man, p))
31595c635efSGarrett D'Amore 		return(0);
316*698f87a4SGarrett D'Amore 	man->next = MAN_NEXT_CHILD;
31795c635efSGarrett D'Amore 	return(1);
31895c635efSGarrett D'Amore }
31995c635efSGarrett D'Amore 
32095c635efSGarrett D'Amore int
321*698f87a4SGarrett D'Amore man_word_alloc(struct man *man, int line, int pos, const char *word)
32295c635efSGarrett D'Amore {
32395c635efSGarrett D'Amore 	struct man_node	*n;
32495c635efSGarrett D'Amore 
325*698f87a4SGarrett D'Amore 	n = man_node_alloc(man, line, pos, MAN_TEXT, MAN_MAX);
326*698f87a4SGarrett D'Amore 	n->string = roff_strdup(man->roff, word);
32795c635efSGarrett D'Amore 
328*698f87a4SGarrett D'Amore 	if ( ! man_node_append(man, n))
32995c635efSGarrett D'Amore 		return(0);
33095c635efSGarrett D'Amore 
331*698f87a4SGarrett D'Amore 	man->next = MAN_NEXT_SIBLING;
33295c635efSGarrett D'Amore 	return(1);
33395c635efSGarrett D'Amore }
33495c635efSGarrett D'Amore 
33595c635efSGarrett D'Amore 
33695c635efSGarrett D'Amore /*
33795c635efSGarrett D'Amore  * Free all of the resources held by a node.  This does NOT unlink a
33895c635efSGarrett D'Amore  * node from its context; for that, see man_node_unlink().
33995c635efSGarrett D'Amore  */
34095c635efSGarrett D'Amore static void
34195c635efSGarrett D'Amore man_node_free(struct man_node *p)
34295c635efSGarrett D'Amore {
34395c635efSGarrett D'Amore 
34495c635efSGarrett D'Amore 	if (p->string)
34595c635efSGarrett D'Amore 		free(p->string);
34695c635efSGarrett D'Amore 	free(p);
34795c635efSGarrett D'Amore }
34895c635efSGarrett D'Amore 
34995c635efSGarrett D'Amore 
35095c635efSGarrett D'Amore void
351*698f87a4SGarrett D'Amore man_node_delete(struct man *man, struct man_node *p)
35295c635efSGarrett D'Amore {
35395c635efSGarrett D'Amore 
35495c635efSGarrett D'Amore 	while (p->child)
355*698f87a4SGarrett D'Amore 		man_node_delete(man, p->child);
35695c635efSGarrett D'Amore 
357*698f87a4SGarrett D'Amore 	man_node_unlink(man, p);
35895c635efSGarrett D'Amore 	man_node_free(p);
35995c635efSGarrett D'Amore }
36095c635efSGarrett D'Amore 
36195c635efSGarrett D'Amore int
362*698f87a4SGarrett D'Amore man_addeqn(struct man *man, const struct eqn *ep)
36395c635efSGarrett D'Amore {
36495c635efSGarrett D'Amore 	struct man_node	*n;
36595c635efSGarrett D'Amore 
366*698f87a4SGarrett D'Amore 	assert( ! (MAN_HALT & man->flags));
36795c635efSGarrett D'Amore 
368*698f87a4SGarrett D'Amore 	n = man_node_alloc(man, ep->ln, ep->pos, MAN_EQN, MAN_MAX);
36995c635efSGarrett D'Amore 	n->eqn = ep;
37095c635efSGarrett D'Amore 
371*698f87a4SGarrett D'Amore 	if ( ! man_node_append(man, n))
37295c635efSGarrett D'Amore 		return(0);
37395c635efSGarrett D'Amore 
374*698f87a4SGarrett D'Amore 	man->next = MAN_NEXT_SIBLING;
375*698f87a4SGarrett D'Amore 	return(man_descope(man, ep->ln, ep->pos));
37695c635efSGarrett D'Amore }
37795c635efSGarrett D'Amore 
37895c635efSGarrett D'Amore int
379*698f87a4SGarrett D'Amore man_addspan(struct man *man, const struct tbl_span *sp)
38095c635efSGarrett D'Amore {
38195c635efSGarrett D'Amore 	struct man_node	*n;
38295c635efSGarrett D'Amore 
383*698f87a4SGarrett D'Amore 	assert( ! (MAN_HALT & man->flags));
38495c635efSGarrett D'Amore 
385*698f87a4SGarrett D'Amore 	n = man_node_alloc(man, sp->line, 0, MAN_TBL, MAN_MAX);
38695c635efSGarrett D'Amore 	n->span = sp;
38795c635efSGarrett D'Amore 
388*698f87a4SGarrett D'Amore 	if ( ! man_node_append(man, n))
38995c635efSGarrett D'Amore 		return(0);
39095c635efSGarrett D'Amore 
391*698f87a4SGarrett D'Amore 	man->next = MAN_NEXT_SIBLING;
392*698f87a4SGarrett D'Amore 	return(man_descope(man, sp->line, 0));
39395c635efSGarrett D'Amore }
39495c635efSGarrett D'Amore 
39595c635efSGarrett D'Amore static int
396*698f87a4SGarrett D'Amore man_descope(struct man *man, int line, int offs)
39795c635efSGarrett D'Amore {
39895c635efSGarrett D'Amore 	/*
39995c635efSGarrett D'Amore 	 * Co-ordinate what happens with having a next-line scope open:
40095c635efSGarrett D'Amore 	 * first close out the element scope (if applicable), then close
40195c635efSGarrett D'Amore 	 * out the block scope (also if applicable).
40295c635efSGarrett D'Amore 	 */
40395c635efSGarrett D'Amore 
404*698f87a4SGarrett D'Amore 	if (MAN_ELINE & man->flags) {
405*698f87a4SGarrett D'Amore 		man->flags &= ~MAN_ELINE;
406*698f87a4SGarrett D'Amore 		if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX))
40795c635efSGarrett D'Amore 			return(0);
40895c635efSGarrett D'Amore 	}
40995c635efSGarrett D'Amore 
410*698f87a4SGarrett D'Amore 	if ( ! (MAN_BLINE & man->flags))
41195c635efSGarrett D'Amore 		return(1);
412*698f87a4SGarrett D'Amore 	man->flags &= ~MAN_BLINE;
41395c635efSGarrett D'Amore 
414*698f87a4SGarrett D'Amore 	if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX))
41595c635efSGarrett D'Amore 		return(0);
416*698f87a4SGarrett D'Amore 	return(man_body_alloc(man, line, offs, man->last->tok));
41795c635efSGarrett D'Amore }
41895c635efSGarrett D'Amore 
41995c635efSGarrett D'Amore static int
420*698f87a4SGarrett D'Amore man_ptext(struct man *man, int line, char *buf, int offs)
42195c635efSGarrett D'Amore {
42295c635efSGarrett D'Amore 	int		 i;
42395c635efSGarrett D'Amore 
42495c635efSGarrett D'Amore 	/* Literal free-form text whitespace is preserved. */
42595c635efSGarrett D'Amore 
426*698f87a4SGarrett D'Amore 	if (MAN_LITERAL & man->flags) {
427*698f87a4SGarrett D'Amore 		if ( ! man_word_alloc(man, line, offs, buf + offs))
42895c635efSGarrett D'Amore 			return(0);
429*698f87a4SGarrett D'Amore 		return(man_descope(man, line, offs));
43095c635efSGarrett D'Amore 	}
43195c635efSGarrett D'Amore 
43295c635efSGarrett D'Amore 	for (i = offs; ' ' == buf[i]; i++)
43395c635efSGarrett D'Amore 		/* Skip leading whitespace. */ ;
43495c635efSGarrett D'Amore 
435*698f87a4SGarrett D'Amore 	/*
436*698f87a4SGarrett D'Amore 	 * Blank lines are ignored right after headings
437*698f87a4SGarrett D'Amore 	 * but add a single vertical space elsewhere.
438*698f87a4SGarrett D'Amore 	 */
439*698f87a4SGarrett D'Amore 
44095c635efSGarrett D'Amore 	if ('\0' == buf[i]) {
44195c635efSGarrett D'Amore 		/* Allocate a blank entry. */
442*698f87a4SGarrett D'Amore 		if (MAN_SH != man->last->tok &&
443*698f87a4SGarrett D'Amore 		    MAN_SS != man->last->tok) {
444*698f87a4SGarrett D'Amore 			if ( ! man_elem_alloc(man, line, offs, MAN_sp))
44595c635efSGarrett D'Amore 				return(0);
446*698f87a4SGarrett D'Amore 			man->next = MAN_NEXT_SIBLING;
447*698f87a4SGarrett D'Amore 		}
448*698f87a4SGarrett D'Amore 		return(1);
44995c635efSGarrett D'Amore 	}
45095c635efSGarrett D'Amore 
45195c635efSGarrett D'Amore 	/*
45295c635efSGarrett D'Amore 	 * Warn if the last un-escaped character is whitespace. Then
45395c635efSGarrett D'Amore 	 * strip away the remaining spaces (tabs stay!).
45495c635efSGarrett D'Amore 	 */
45595c635efSGarrett D'Amore 
45695c635efSGarrett D'Amore 	i = (int)strlen(buf);
45795c635efSGarrett D'Amore 	assert(i);
45895c635efSGarrett D'Amore 
45995c635efSGarrett D'Amore 	if (' ' == buf[i - 1] || '\t' == buf[i - 1]) {
46095c635efSGarrett D'Amore 		if (i > 1 && '\\' != buf[i - 2])
461*698f87a4SGarrett D'Amore 			man_pmsg(man, line, i - 1, MANDOCERR_EOLNSPACE);
46295c635efSGarrett D'Amore 
46395c635efSGarrett D'Amore 		for (--i; i && ' ' == buf[i]; i--)
46495c635efSGarrett D'Amore 			/* Spin back to non-space. */ ;
46595c635efSGarrett D'Amore 
46695c635efSGarrett D'Amore 		/* Jump ahead of escaped whitespace. */
46795c635efSGarrett D'Amore 		i += '\\' == buf[i] ? 2 : 1;
46895c635efSGarrett D'Amore 
46995c635efSGarrett D'Amore 		buf[i] = '\0';
47095c635efSGarrett D'Amore 	}
47195c635efSGarrett D'Amore 
472*698f87a4SGarrett D'Amore 	if ( ! man_word_alloc(man, line, offs, buf + offs))
47395c635efSGarrett D'Amore 		return(0);
47495c635efSGarrett D'Amore 
47595c635efSGarrett D'Amore 	/*
47695c635efSGarrett D'Amore 	 * End-of-sentence check.  If the last character is an unescaped
47795c635efSGarrett D'Amore 	 * EOS character, then flag the node as being the end of a
47895c635efSGarrett D'Amore 	 * sentence.  The front-end will know how to interpret this.
47995c635efSGarrett D'Amore 	 */
48095c635efSGarrett D'Amore 
48195c635efSGarrett D'Amore 	assert(i);
48295c635efSGarrett D'Amore 	if (mandoc_eos(buf, (size_t)i, 0))
483*698f87a4SGarrett D'Amore 		man->last->flags |= MAN_EOS;
48495c635efSGarrett D'Amore 
485*698f87a4SGarrett D'Amore 	return(man_descope(man, line, offs));
48695c635efSGarrett D'Amore }
48795c635efSGarrett D'Amore 
48895c635efSGarrett D'Amore static int
489*698f87a4SGarrett D'Amore man_pmacro(struct man *man, int ln, char *buf, int offs)
49095c635efSGarrett D'Amore {
49195c635efSGarrett D'Amore 	int		 i, ppos;
49295c635efSGarrett D'Amore 	enum mant	 tok;
49395c635efSGarrett D'Amore 	char		 mac[5];
49495c635efSGarrett D'Amore 	struct man_node	*n;
49595c635efSGarrett D'Amore 
49695c635efSGarrett D'Amore 	if ('"' == buf[offs]) {
497*698f87a4SGarrett D'Amore 		man_pmsg(man, ln, offs, MANDOCERR_BADCOMMENT);
49895c635efSGarrett D'Amore 		return(1);
49995c635efSGarrett D'Amore 	} else if ('\0' == buf[offs])
50095c635efSGarrett D'Amore 		return(1);
50195c635efSGarrett D'Amore 
50295c635efSGarrett D'Amore 	ppos = offs;
50395c635efSGarrett D'Amore 
50495c635efSGarrett D'Amore 	/*
50595c635efSGarrett D'Amore 	 * Copy the first word into a nil-terminated buffer.
50695c635efSGarrett D'Amore 	 * Stop copying when a tab, space, or eoln is encountered.
50795c635efSGarrett D'Amore 	 */
50895c635efSGarrett D'Amore 
50995c635efSGarrett D'Amore 	i = 0;
51095c635efSGarrett D'Amore 	while (i < 4 && '\0' != buf[offs] &&
51195c635efSGarrett D'Amore 			' ' != buf[offs] && '\t' != buf[offs])
51295c635efSGarrett D'Amore 		mac[i++] = buf[offs++];
51395c635efSGarrett D'Amore 
51495c635efSGarrett D'Amore 	mac[i] = '\0';
51595c635efSGarrett D'Amore 
51695c635efSGarrett D'Amore 	tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX;
51795c635efSGarrett D'Amore 
51895c635efSGarrett D'Amore 	if (MAN_MAX == tok) {
519*698f87a4SGarrett D'Amore 		mandoc_vmsg(MANDOCERR_MACRO, man->parse, ln,
52095c635efSGarrett D'Amore 				ppos, "%s", buf + ppos - 1);
52195c635efSGarrett D'Amore 		return(1);
52295c635efSGarrett D'Amore 	}
52395c635efSGarrett D'Amore 
52495c635efSGarrett D'Amore 	/* The macro is sane.  Jump to the next word. */
52595c635efSGarrett D'Amore 
52695c635efSGarrett D'Amore 	while (buf[offs] && ' ' == buf[offs])
52795c635efSGarrett D'Amore 		offs++;
52895c635efSGarrett D'Amore 
52995c635efSGarrett D'Amore 	/*
53095c635efSGarrett D'Amore 	 * Trailing whitespace.  Note that tabs are allowed to be passed
53195c635efSGarrett D'Amore 	 * into the parser as "text", so we only warn about spaces here.
53295c635efSGarrett D'Amore 	 */
53395c635efSGarrett D'Amore 
53495c635efSGarrett D'Amore 	if ('\0' == buf[offs] && ' ' == buf[offs - 1])
535*698f87a4SGarrett D'Amore 		man_pmsg(man, ln, offs - 1, MANDOCERR_EOLNSPACE);
53695c635efSGarrett D'Amore 
53795c635efSGarrett D'Amore 	/*
53895c635efSGarrett D'Amore 	 * Remove prior ELINE macro, as it's being clobbered by a new
53995c635efSGarrett D'Amore 	 * macro.  Note that NSCOPED macros do not close out ELINE
54095c635efSGarrett D'Amore 	 * macros---they don't print text---so we let those slip by.
54195c635efSGarrett D'Amore 	 */
54295c635efSGarrett D'Amore 
54395c635efSGarrett D'Amore 	if ( ! (MAN_NSCOPED & man_macros[tok].flags) &&
544*698f87a4SGarrett D'Amore 			man->flags & MAN_ELINE) {
545*698f87a4SGarrett D'Amore 		n = man->last;
54695c635efSGarrett D'Amore 		assert(MAN_TEXT != n->type);
54795c635efSGarrett D'Amore 
54895c635efSGarrett D'Amore 		/* Remove repeated NSCOPED macros causing ELINE. */
54995c635efSGarrett D'Amore 
55095c635efSGarrett D'Amore 		if (MAN_NSCOPED & man_macros[n->tok].flags)
55195c635efSGarrett D'Amore 			n = n->parent;
55295c635efSGarrett D'Amore 
553*698f87a4SGarrett D'Amore 		mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line,
55495c635efSGarrett D'Amore 		    n->pos, "%s breaks %s", man_macronames[tok],
55595c635efSGarrett D'Amore 		    man_macronames[n->tok]);
55695c635efSGarrett D'Amore 
557*698f87a4SGarrett D'Amore 		man_node_delete(man, n);
558*698f87a4SGarrett D'Amore 		man->flags &= ~MAN_ELINE;
55995c635efSGarrett D'Amore 	}
56095c635efSGarrett D'Amore 
56195c635efSGarrett D'Amore 	/*
56295c635efSGarrett D'Amore 	 * Remove prior BLINE macro that is being clobbered.
56395c635efSGarrett D'Amore 	 */
564*698f87a4SGarrett D'Amore 	if ((man->flags & MAN_BLINE) &&
56595c635efSGarrett D'Amore 	    (MAN_BSCOPE & man_macros[tok].flags)) {
566*698f87a4SGarrett D'Amore 		n = man->last;
56795c635efSGarrett D'Amore 
56895c635efSGarrett D'Amore 		/* Might be a text node like 8 in
56995c635efSGarrett D'Amore 		 * .TP 8
57095c635efSGarrett D'Amore 		 * .SH foo
57195c635efSGarrett D'Amore 		 */
57295c635efSGarrett D'Amore 		if (MAN_TEXT == n->type)
57395c635efSGarrett D'Amore 			n = n->parent;
57495c635efSGarrett D'Amore 
57595c635efSGarrett D'Amore 		/* Remove element that didn't end BLINE, if any. */
57695c635efSGarrett D'Amore 		if ( ! (MAN_BSCOPE & man_macros[n->tok].flags))
57795c635efSGarrett D'Amore 			n = n->parent;
57895c635efSGarrett D'Amore 
57995c635efSGarrett D'Amore 		assert(MAN_HEAD == n->type);
58095c635efSGarrett D'Amore 		n = n->parent;
58195c635efSGarrett D'Amore 		assert(MAN_BLOCK == n->type);
58295c635efSGarrett D'Amore 		assert(MAN_SCOPED & man_macros[n->tok].flags);
58395c635efSGarrett D'Amore 
584*698f87a4SGarrett D'Amore 		mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line,
58595c635efSGarrett D'Amore 		    n->pos, "%s breaks %s", man_macronames[tok],
58695c635efSGarrett D'Amore 		    man_macronames[n->tok]);
58795c635efSGarrett D'Amore 
588*698f87a4SGarrett D'Amore 		man_node_delete(man, n);
589*698f87a4SGarrett D'Amore 		man->flags &= ~MAN_BLINE;
59095c635efSGarrett D'Amore 	}
59195c635efSGarrett D'Amore 
59295c635efSGarrett D'Amore 	/*
59395c635efSGarrett D'Amore 	 * Save the fact that we're in the next-line for a block.  In
59495c635efSGarrett D'Amore 	 * this way, embedded roff instructions can "remember" state
59595c635efSGarrett D'Amore 	 * when they exit.
59695c635efSGarrett D'Amore 	 */
59795c635efSGarrett D'Amore 
598*698f87a4SGarrett D'Amore 	if (MAN_BLINE & man->flags)
599*698f87a4SGarrett D'Amore 		man->flags |= MAN_BPLINE;
60095c635efSGarrett D'Amore 
60195c635efSGarrett D'Amore 	/* Call to handler... */
60295c635efSGarrett D'Amore 
60395c635efSGarrett D'Amore 	assert(man_macros[tok].fp);
604*698f87a4SGarrett D'Amore 	if ( ! (*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf))
60595c635efSGarrett D'Amore 		goto err;
60695c635efSGarrett D'Amore 
60795c635efSGarrett D'Amore 	/*
60895c635efSGarrett D'Amore 	 * We weren't in a block-line scope when entering the
60995c635efSGarrett D'Amore 	 * above-parsed macro, so return.
61095c635efSGarrett D'Amore 	 */
61195c635efSGarrett D'Amore 
612*698f87a4SGarrett D'Amore 	if ( ! (MAN_BPLINE & man->flags)) {
613*698f87a4SGarrett D'Amore 		man->flags &= ~MAN_ILINE;
61495c635efSGarrett D'Amore 		return(1);
61595c635efSGarrett D'Amore 	}
616*698f87a4SGarrett D'Amore 	man->flags &= ~MAN_BPLINE;
61795c635efSGarrett D'Amore 
61895c635efSGarrett D'Amore 	/*
61995c635efSGarrett D'Amore 	 * If we're in a block scope, then allow this macro to slip by
62095c635efSGarrett D'Amore 	 * without closing scope around it.
62195c635efSGarrett D'Amore 	 */
62295c635efSGarrett D'Amore 
623*698f87a4SGarrett D'Amore 	if (MAN_ILINE & man->flags) {
624*698f87a4SGarrett D'Amore 		man->flags &= ~MAN_ILINE;
62595c635efSGarrett D'Amore 		return(1);
62695c635efSGarrett D'Amore 	}
62795c635efSGarrett D'Amore 
62895c635efSGarrett D'Amore 	/*
62995c635efSGarrett D'Amore 	 * If we've opened a new next-line element scope, then return
63095c635efSGarrett D'Amore 	 * now, as the next line will close out the block scope.
63195c635efSGarrett D'Amore 	 */
63295c635efSGarrett D'Amore 
633*698f87a4SGarrett D'Amore 	if (MAN_ELINE & man->flags)
63495c635efSGarrett D'Amore 		return(1);
63595c635efSGarrett D'Amore 
63695c635efSGarrett D'Amore 	/* Close out the block scope opened in the prior line.  */
63795c635efSGarrett D'Amore 
638*698f87a4SGarrett D'Amore 	assert(MAN_BLINE & man->flags);
639*698f87a4SGarrett D'Amore 	man->flags &= ~MAN_BLINE;
64095c635efSGarrett D'Amore 
641*698f87a4SGarrett D'Amore 	if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX))
64295c635efSGarrett D'Amore 		return(0);
643*698f87a4SGarrett D'Amore 	return(man_body_alloc(man, ln, ppos, man->last->tok));
64495c635efSGarrett D'Amore 
64595c635efSGarrett D'Amore err:	/* Error out. */
64695c635efSGarrett D'Amore 
647*698f87a4SGarrett D'Amore 	man->flags |= MAN_HALT;
64895c635efSGarrett D'Amore 	return(0);
64995c635efSGarrett D'Amore }
65095c635efSGarrett D'Amore 
65195c635efSGarrett D'Amore /*
652*698f87a4SGarrett D'Amore  * Unlink a node from its context.  If "man" is provided, the last parse
65395c635efSGarrett D'Amore  * point will also be adjusted accordingly.
65495c635efSGarrett D'Amore  */
65595c635efSGarrett D'Amore static void
656*698f87a4SGarrett D'Amore man_node_unlink(struct man *man, struct man_node *n)
65795c635efSGarrett D'Amore {
65895c635efSGarrett D'Amore 
65995c635efSGarrett D'Amore 	/* Adjust siblings. */
66095c635efSGarrett D'Amore 
66195c635efSGarrett D'Amore 	if (n->prev)
66295c635efSGarrett D'Amore 		n->prev->next = n->next;
66395c635efSGarrett D'Amore 	if (n->next)
66495c635efSGarrett D'Amore 		n->next->prev = n->prev;
66595c635efSGarrett D'Amore 
66695c635efSGarrett D'Amore 	/* Adjust parent. */
66795c635efSGarrett D'Amore 
66895c635efSGarrett D'Amore 	if (n->parent) {
66995c635efSGarrett D'Amore 		n->parent->nchild--;
67095c635efSGarrett D'Amore 		if (n->parent->child == n)
67195c635efSGarrett D'Amore 			n->parent->child = n->prev ? n->prev : n->next;
67295c635efSGarrett D'Amore 	}
67395c635efSGarrett D'Amore 
67495c635efSGarrett D'Amore 	/* Adjust parse point, if applicable. */
67595c635efSGarrett D'Amore 
676*698f87a4SGarrett D'Amore 	if (man && man->last == n) {
67795c635efSGarrett D'Amore 		/*XXX: this can occur when bailing from validation. */
67895c635efSGarrett D'Amore 		/*assert(NULL == n->next);*/
67995c635efSGarrett D'Amore 		if (n->prev) {
680*698f87a4SGarrett D'Amore 			man->last = n->prev;
681*698f87a4SGarrett D'Amore 			man->next = MAN_NEXT_SIBLING;
68295c635efSGarrett D'Amore 		} else {
683*698f87a4SGarrett D'Amore 			man->last = n->parent;
684*698f87a4SGarrett D'Amore 			man->next = MAN_NEXT_CHILD;
68595c635efSGarrett D'Amore 		}
68695c635efSGarrett D'Amore 	}
68795c635efSGarrett D'Amore 
688*698f87a4SGarrett D'Amore 	if (man && man->first == n)
689*698f87a4SGarrett D'Amore 		man->first = NULL;
69095c635efSGarrett D'Amore }
69195c635efSGarrett D'Amore 
69295c635efSGarrett D'Amore const struct mparse *
693*698f87a4SGarrett D'Amore man_mparse(const struct man *man)
69495c635efSGarrett D'Amore {
69595c635efSGarrett D'Amore 
696*698f87a4SGarrett D'Amore 	assert(man && man->parse);
697*698f87a4SGarrett D'Amore 	return(man->parse);
69895c635efSGarrett D'Amore }
699