xref: /titanic_41/usr/src/cmd/mandoc/man.c (revision ffb8ebfab4941f959e7caea93ecfb348cfa3515e)
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