xref: /titanic_50/usr/src/cmd/mandoc/man.c (revision 260e9a87725c090ba5835b1f9f0b62fa2f96036f)
1*260e9a87SYuri Pankov /*	$Id: man.c,v 1.149 2015/01/30 21:28:46 schwarze Exp $ */
295c635efSGarrett D'Amore /*
395c635efSGarrett D'Amore  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*260e9a87SYuri Pankov  * Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
5*260e9a87SYuri Pankov  * Copyright (c) 2011 Joerg Sonnenberger <joerg@netbsd.org>
695c635efSGarrett D'Amore  *
795c635efSGarrett D'Amore  * Permission to use, copy, modify, and distribute this software for any
895c635efSGarrett D'Amore  * purpose with or without fee is hereby granted, provided that the above
995c635efSGarrett D'Amore  * copyright notice and this permission notice appear in all copies.
1095c635efSGarrett D'Amore  *
1195c635efSGarrett D'Amore  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1295c635efSGarrett D'Amore  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1395c635efSGarrett D'Amore  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1495c635efSGarrett D'Amore  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1595c635efSGarrett D'Amore  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1695c635efSGarrett D'Amore  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1795c635efSGarrett D'Amore  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1895c635efSGarrett D'Amore  */
1995c635efSGarrett D'Amore #include "config.h"
2095c635efSGarrett D'Amore 
2195c635efSGarrett D'Amore #include <sys/types.h>
2295c635efSGarrett D'Amore 
2395c635efSGarrett D'Amore #include <assert.h>
24*260e9a87SYuri Pankov #include <ctype.h>
2595c635efSGarrett D'Amore #include <stdarg.h>
2695c635efSGarrett D'Amore #include <stdlib.h>
2795c635efSGarrett D'Amore #include <stdio.h>
2895c635efSGarrett D'Amore #include <string.h>
2995c635efSGarrett D'Amore 
3095c635efSGarrett D'Amore #include "man.h"
3195c635efSGarrett D'Amore #include "mandoc.h"
32*260e9a87SYuri Pankov #include "mandoc_aux.h"
3395c635efSGarrett D'Amore #include "libman.h"
3495c635efSGarrett D'Amore #include "libmandoc.h"
3595c635efSGarrett D'Amore 
3695c635efSGarrett D'Amore const	char *const __man_macronames[MAN_MAX] = {
3795c635efSGarrett D'Amore 	"br",		"TH",		"SH",		"SS",
3895c635efSGarrett D'Amore 	"TP",		"LP",		"PP",		"P",
3995c635efSGarrett D'Amore 	"IP",		"HP",		"SM",		"SB",
4095c635efSGarrett D'Amore 	"BI",		"IB",		"BR",		"RB",
4195c635efSGarrett D'Amore 	"R",		"B",		"I",		"IR",
42*260e9a87SYuri Pankov 	"RI",		"sp",		"nf",
4395c635efSGarrett D'Amore 	"fi",		"RE",		"RS",		"DT",
4495c635efSGarrett D'Amore 	"UC",		"PD",		"AT",		"in",
45698f87a4SGarrett D'Amore 	"ft",		"OP",		"EX",		"EE",
46*260e9a87SYuri Pankov 	"UR",		"UE",		"ll"
4795c635efSGarrett D'Amore 	};
4895c635efSGarrett D'Amore 
4995c635efSGarrett D'Amore const	char * const *man_macronames = __man_macronames;
5095c635efSGarrett D'Amore 
51*260e9a87SYuri Pankov static	void		 man_alloc1(struct man *);
52*260e9a87SYuri Pankov static	void		 man_breakscope(struct man *, enum mant);
53*260e9a87SYuri Pankov static	void		 man_descope(struct man *, int, int);
54*260e9a87SYuri Pankov static	void		 man_free1(struct man *);
5595c635efSGarrett D'Amore static	struct man_node	*man_node_alloc(struct man *, int, int,
5695c635efSGarrett D'Amore 				enum man_type, enum mant);
57*260e9a87SYuri Pankov static	void		 man_node_append(struct man *, struct man_node *);
5895c635efSGarrett D'Amore static	void		 man_node_free(struct man_node *);
5995c635efSGarrett D'Amore static	void		 man_node_unlink(struct man *,
6095c635efSGarrett D'Amore 				struct man_node *);
6195c635efSGarrett D'Amore static	int		 man_ptext(struct man *, int, char *, int);
6295c635efSGarrett D'Amore static	int		 man_pmacro(struct man *, int, char *, int);
6395c635efSGarrett D'Amore 
6495c635efSGarrett D'Amore 
6595c635efSGarrett D'Amore const struct man_node *
man_node(const struct man * man)66698f87a4SGarrett D'Amore man_node(const struct man *man)
6795c635efSGarrett D'Amore {
6895c635efSGarrett D'Amore 
69698f87a4SGarrett D'Amore 	return(man->first);
7095c635efSGarrett D'Amore }
7195c635efSGarrett D'Amore 
7295c635efSGarrett D'Amore const struct man_meta *
man_meta(const struct man * man)73698f87a4SGarrett D'Amore man_meta(const struct man *man)
7495c635efSGarrett D'Amore {
7595c635efSGarrett D'Amore 
76698f87a4SGarrett D'Amore 	return(&man->meta);
7795c635efSGarrett D'Amore }
7895c635efSGarrett D'Amore 
7995c635efSGarrett D'Amore void
man_reset(struct man * man)8095c635efSGarrett D'Amore man_reset(struct man *man)
8195c635efSGarrett D'Amore {
8295c635efSGarrett D'Amore 
8395c635efSGarrett D'Amore 	man_free1(man);
8495c635efSGarrett D'Amore 	man_alloc1(man);
8595c635efSGarrett D'Amore }
8695c635efSGarrett D'Amore 
8795c635efSGarrett D'Amore void
man_free(struct man * man)8895c635efSGarrett D'Amore man_free(struct man *man)
8995c635efSGarrett D'Amore {
9095c635efSGarrett D'Amore 
9195c635efSGarrett D'Amore 	man_free1(man);
9295c635efSGarrett D'Amore 	free(man);
9395c635efSGarrett D'Amore }
9495c635efSGarrett D'Amore 
9595c635efSGarrett D'Amore struct man *
man_alloc(struct roff * roff,struct mparse * parse,const char * defos,int quick)96*260e9a87SYuri Pankov man_alloc(struct roff *roff, struct mparse *parse,
97*260e9a87SYuri Pankov 	const char *defos, int quick)
9895c635efSGarrett D'Amore {
9995c635efSGarrett D'Amore 	struct man	*p;
10095c635efSGarrett D'Amore 
10195c635efSGarrett D'Amore 	p = mandoc_calloc(1, sizeof(struct man));
10295c635efSGarrett D'Amore 
10395c635efSGarrett D'Amore 	man_hash_init();
10495c635efSGarrett D'Amore 	p->parse = parse;
105*260e9a87SYuri Pankov 	p->defos = defos;
106*260e9a87SYuri Pankov 	p->quick = quick;
10795c635efSGarrett D'Amore 	p->roff = roff;
10895c635efSGarrett D'Amore 
10995c635efSGarrett D'Amore 	man_alloc1(p);
11095c635efSGarrett D'Amore 	return(p);
11195c635efSGarrett D'Amore }
11295c635efSGarrett D'Amore 
113*260e9a87SYuri Pankov void
man_endparse(struct man * man)114698f87a4SGarrett D'Amore man_endparse(struct man *man)
11595c635efSGarrett D'Amore {
11695c635efSGarrett D'Amore 
117*260e9a87SYuri Pankov 	man_macroend(man);
11895c635efSGarrett D'Amore }
11995c635efSGarrett D'Amore 
12095c635efSGarrett D'Amore int
man_parseln(struct man * man,int ln,char * buf,int offs)121698f87a4SGarrett D'Amore man_parseln(struct man *man, int ln, char *buf, int offs)
12295c635efSGarrett D'Amore {
12395c635efSGarrett D'Amore 
124*260e9a87SYuri Pankov 	if (man->last->type != MAN_EQN || ln > man->last->line)
125698f87a4SGarrett D'Amore 		man->flags |= MAN_NEWLINE;
12695c635efSGarrett D'Amore 
127698f87a4SGarrett D'Amore 	return (roff_getcontrol(man->roff, buf, &offs) ?
128698f87a4SGarrett D'Amore 	    man_pmacro(man, ln, buf, offs) :
129698f87a4SGarrett D'Amore 	    man_ptext(man, ln, buf, offs));
13095c635efSGarrett D'Amore }
13195c635efSGarrett D'Amore 
13295c635efSGarrett D'Amore static void
man_free1(struct man * man)13395c635efSGarrett D'Amore man_free1(struct man *man)
13495c635efSGarrett D'Amore {
13595c635efSGarrett D'Amore 
13695c635efSGarrett D'Amore 	if (man->first)
13795c635efSGarrett D'Amore 		man_node_delete(man, man->first);
13895c635efSGarrett D'Amore 	free(man->meta.title);
13995c635efSGarrett D'Amore 	free(man->meta.source);
14095c635efSGarrett D'Amore 	free(man->meta.date);
14195c635efSGarrett D'Amore 	free(man->meta.vol);
14295c635efSGarrett D'Amore 	free(man->meta.msec);
14395c635efSGarrett D'Amore }
14495c635efSGarrett D'Amore 
14595c635efSGarrett D'Amore static void
man_alloc1(struct man * man)146698f87a4SGarrett D'Amore man_alloc1(struct man *man)
14795c635efSGarrett D'Amore {
14895c635efSGarrett D'Amore 
149698f87a4SGarrett D'Amore 	memset(&man->meta, 0, sizeof(struct man_meta));
150698f87a4SGarrett D'Amore 	man->flags = 0;
151698f87a4SGarrett D'Amore 	man->last = mandoc_calloc(1, sizeof(struct man_node));
152698f87a4SGarrett D'Amore 	man->first = man->last;
153698f87a4SGarrett D'Amore 	man->last->type = MAN_ROOT;
154698f87a4SGarrett D'Amore 	man->last->tok = MAN_MAX;
155698f87a4SGarrett D'Amore 	man->next = MAN_NEXT_CHILD;
15695c635efSGarrett D'Amore }
15795c635efSGarrett D'Amore 
15895c635efSGarrett D'Amore 
159*260e9a87SYuri Pankov static void
man_node_append(struct man * man,struct man_node * p)16095c635efSGarrett D'Amore man_node_append(struct man *man, struct man_node *p)
16195c635efSGarrett D'Amore {
16295c635efSGarrett D'Amore 
16395c635efSGarrett D'Amore 	assert(man->last);
16495c635efSGarrett D'Amore 	assert(man->first);
165*260e9a87SYuri Pankov 	assert(p->type != MAN_ROOT);
16695c635efSGarrett D'Amore 
16795c635efSGarrett D'Amore 	switch (man->next) {
168*260e9a87SYuri Pankov 	case MAN_NEXT_SIBLING:
16995c635efSGarrett D'Amore 		man->last->next = p;
17095c635efSGarrett D'Amore 		p->prev = man->last;
17195c635efSGarrett D'Amore 		p->parent = man->last->parent;
17295c635efSGarrett D'Amore 		break;
173*260e9a87SYuri Pankov 	case MAN_NEXT_CHILD:
17495c635efSGarrett D'Amore 		man->last->child = p;
17595c635efSGarrett D'Amore 		p->parent = man->last;
17695c635efSGarrett D'Amore 		break;
17795c635efSGarrett D'Amore 	default:
17895c635efSGarrett D'Amore 		abort();
17995c635efSGarrett D'Amore 		/* NOTREACHED */
18095c635efSGarrett D'Amore 	}
18195c635efSGarrett D'Amore 
18295c635efSGarrett D'Amore 	assert(p->parent);
18395c635efSGarrett D'Amore 	p->parent->nchild++;
18495c635efSGarrett D'Amore 
18595c635efSGarrett D'Amore 	switch (p->type) {
186*260e9a87SYuri Pankov 	case MAN_BLOCK:
187*260e9a87SYuri Pankov 		if (p->tok == MAN_SH || p->tok == MAN_SS)
188*260e9a87SYuri Pankov 			man->flags &= ~MAN_LITERAL;
189*260e9a87SYuri Pankov 		break;
190*260e9a87SYuri Pankov 	case MAN_HEAD:
191*260e9a87SYuri Pankov 		assert(p->parent->type == MAN_BLOCK);
19295c635efSGarrett D'Amore 		p->parent->head = p;
19395c635efSGarrett D'Amore 		break;
194*260e9a87SYuri Pankov 	case MAN_BODY:
195*260e9a87SYuri Pankov 		assert(p->parent->type == MAN_BLOCK);
19695c635efSGarrett D'Amore 		p->parent->body = p;
19795c635efSGarrett D'Amore 		break;
19895c635efSGarrett D'Amore 	default:
19995c635efSGarrett D'Amore 		break;
20095c635efSGarrett D'Amore 	}
20195c635efSGarrett D'Amore 
20295c635efSGarrett D'Amore 	man->last = p;
20395c635efSGarrett D'Amore 
20495c635efSGarrett D'Amore 	switch (p->type) {
205*260e9a87SYuri Pankov 	case MAN_TBL:
20695c635efSGarrett D'Amore 		/* FALLTHROUGH */
207*260e9a87SYuri Pankov 	case MAN_TEXT:
208*260e9a87SYuri Pankov 		man_valid_post(man);
20995c635efSGarrett D'Amore 		break;
21095c635efSGarrett D'Amore 	default:
21195c635efSGarrett D'Amore 		break;
21295c635efSGarrett D'Amore 	}
21395c635efSGarrett D'Amore }
21495c635efSGarrett D'Amore 
21595c635efSGarrett D'Amore static struct man_node *
man_node_alloc(struct man * man,int line,int pos,enum man_type type,enum mant tok)216698f87a4SGarrett D'Amore man_node_alloc(struct man *man, int line, int pos,
21795c635efSGarrett D'Amore 		enum man_type type, enum mant tok)
21895c635efSGarrett D'Amore {
21995c635efSGarrett D'Amore 	struct man_node *p;
22095c635efSGarrett D'Amore 
22195c635efSGarrett D'Amore 	p = mandoc_calloc(1, sizeof(struct man_node));
22295c635efSGarrett D'Amore 	p->line = line;
22395c635efSGarrett D'Amore 	p->pos = pos;
22495c635efSGarrett D'Amore 	p->type = type;
22595c635efSGarrett D'Amore 	p->tok = tok;
22695c635efSGarrett D'Amore 
227*260e9a87SYuri Pankov 	if (man->flags & MAN_NEWLINE)
22895c635efSGarrett D'Amore 		p->flags |= MAN_LINE;
229698f87a4SGarrett D'Amore 	man->flags &= ~MAN_NEWLINE;
23095c635efSGarrett D'Amore 	return(p);
23195c635efSGarrett D'Amore }
23295c635efSGarrett D'Amore 
233*260e9a87SYuri Pankov void
man_elem_alloc(struct man * man,int line,int pos,enum mant tok)234698f87a4SGarrett D'Amore man_elem_alloc(struct man *man, int line, int pos, enum mant tok)
23595c635efSGarrett D'Amore {
23695c635efSGarrett D'Amore 	struct man_node *p;
23795c635efSGarrett D'Amore 
238698f87a4SGarrett D'Amore 	p = man_node_alloc(man, line, pos, MAN_ELEM, tok);
239*260e9a87SYuri Pankov 	man_node_append(man, p);
240698f87a4SGarrett D'Amore 	man->next = MAN_NEXT_CHILD;
24195c635efSGarrett D'Amore }
24295c635efSGarrett D'Amore 
243*260e9a87SYuri Pankov void
man_head_alloc(struct man * man,int line,int pos,enum mant tok)244698f87a4SGarrett D'Amore man_head_alloc(struct man *man, int line, int pos, enum mant tok)
24595c635efSGarrett D'Amore {
24695c635efSGarrett D'Amore 	struct man_node *p;
24795c635efSGarrett D'Amore 
248698f87a4SGarrett D'Amore 	p = man_node_alloc(man, line, pos, MAN_HEAD, tok);
249*260e9a87SYuri Pankov 	man_node_append(man, p);
250698f87a4SGarrett D'Amore 	man->next = MAN_NEXT_CHILD;
25195c635efSGarrett D'Amore }
25295c635efSGarrett D'Amore 
253*260e9a87SYuri Pankov void
man_body_alloc(struct man * man,int line,int pos,enum mant tok)254698f87a4SGarrett D'Amore man_body_alloc(struct man *man, int line, int pos, enum mant tok)
25595c635efSGarrett D'Amore {
25695c635efSGarrett D'Amore 	struct man_node *p;
25795c635efSGarrett D'Amore 
258698f87a4SGarrett D'Amore 	p = man_node_alloc(man, line, pos, MAN_BODY, tok);
259*260e9a87SYuri Pankov 	man_node_append(man, p);
260698f87a4SGarrett D'Amore 	man->next = MAN_NEXT_CHILD;
26195c635efSGarrett D'Amore }
26295c635efSGarrett D'Amore 
263*260e9a87SYuri Pankov void
man_block_alloc(struct man * man,int line,int pos,enum mant tok)264698f87a4SGarrett D'Amore man_block_alloc(struct man *man, int line, int pos, enum mant tok)
26595c635efSGarrett D'Amore {
26695c635efSGarrett D'Amore 	struct man_node *p;
26795c635efSGarrett D'Amore 
268698f87a4SGarrett D'Amore 	p = man_node_alloc(man, line, pos, MAN_BLOCK, tok);
269*260e9a87SYuri Pankov 	man_node_append(man, p);
270698f87a4SGarrett D'Amore 	man->next = MAN_NEXT_CHILD;
27195c635efSGarrett D'Amore }
27295c635efSGarrett D'Amore 
273*260e9a87SYuri Pankov void
man_word_alloc(struct man * man,int line,int pos,const char * word)274698f87a4SGarrett D'Amore man_word_alloc(struct man *man, int line, int pos, const char *word)
27595c635efSGarrett D'Amore {
27695c635efSGarrett D'Amore 	struct man_node	*n;
27795c635efSGarrett D'Amore 
278698f87a4SGarrett D'Amore 	n = man_node_alloc(man, line, pos, MAN_TEXT, MAN_MAX);
279698f87a4SGarrett D'Amore 	n->string = roff_strdup(man->roff, word);
280*260e9a87SYuri Pankov 	man_node_append(man, n);
281698f87a4SGarrett D'Amore 	man->next = MAN_NEXT_SIBLING;
28295c635efSGarrett D'Amore }
28395c635efSGarrett D'Amore 
284*260e9a87SYuri Pankov void
man_word_append(struct man * man,const char * word)285*260e9a87SYuri Pankov man_word_append(struct man *man, const char *word)
286*260e9a87SYuri Pankov {
287*260e9a87SYuri Pankov 	struct man_node	*n;
288*260e9a87SYuri Pankov 	char		*addstr, *newstr;
289*260e9a87SYuri Pankov 
290*260e9a87SYuri Pankov 	n = man->last;
291*260e9a87SYuri Pankov 	addstr = roff_strdup(man->roff, word);
292*260e9a87SYuri Pankov 	mandoc_asprintf(&newstr, "%s %s", n->string, addstr);
293*260e9a87SYuri Pankov 	free(addstr);
294*260e9a87SYuri Pankov 	free(n->string);
295*260e9a87SYuri Pankov 	n->string = newstr;
296*260e9a87SYuri Pankov 	man->next = MAN_NEXT_SIBLING;
297*260e9a87SYuri Pankov }
29895c635efSGarrett D'Amore 
29995c635efSGarrett D'Amore /*
30095c635efSGarrett D'Amore  * Free all of the resources held by a node.  This does NOT unlink a
30195c635efSGarrett D'Amore  * node from its context; for that, see man_node_unlink().
30295c635efSGarrett D'Amore  */
30395c635efSGarrett D'Amore static void
man_node_free(struct man_node * p)30495c635efSGarrett D'Amore man_node_free(struct man_node *p)
30595c635efSGarrett D'Amore {
30695c635efSGarrett D'Amore 
30795c635efSGarrett D'Amore 	free(p->string);
30895c635efSGarrett D'Amore 	free(p);
30995c635efSGarrett D'Amore }
31095c635efSGarrett D'Amore 
31195c635efSGarrett D'Amore void
man_node_delete(struct man * man,struct man_node * p)312698f87a4SGarrett D'Amore man_node_delete(struct man *man, struct man_node *p)
31395c635efSGarrett D'Amore {
31495c635efSGarrett D'Amore 
31595c635efSGarrett D'Amore 	while (p->child)
316698f87a4SGarrett D'Amore 		man_node_delete(man, p->child);
31795c635efSGarrett D'Amore 
318698f87a4SGarrett D'Amore 	man_node_unlink(man, p);
31995c635efSGarrett D'Amore 	man_node_free(p);
32095c635efSGarrett D'Amore }
32195c635efSGarrett D'Amore 
322*260e9a87SYuri Pankov void
man_addeqn(struct man * man,const struct eqn * ep)323698f87a4SGarrett D'Amore man_addeqn(struct man *man, const struct eqn *ep)
32495c635efSGarrett D'Amore {
32595c635efSGarrett D'Amore 	struct man_node	*n;
32695c635efSGarrett D'Amore 
327698f87a4SGarrett D'Amore 	n = man_node_alloc(man, ep->ln, ep->pos, MAN_EQN, MAN_MAX);
32895c635efSGarrett D'Amore 	n->eqn = ep;
329*260e9a87SYuri Pankov 	if (ep->ln > man->last->line)
330*260e9a87SYuri Pankov 		n->flags |= MAN_LINE;
331*260e9a87SYuri Pankov 	man_node_append(man, n);
332698f87a4SGarrett D'Amore 	man->next = MAN_NEXT_SIBLING;
333*260e9a87SYuri Pankov 	man_descope(man, ep->ln, ep->pos);
33495c635efSGarrett D'Amore }
33595c635efSGarrett D'Amore 
336*260e9a87SYuri Pankov void
man_addspan(struct man * man,const struct tbl_span * sp)337698f87a4SGarrett D'Amore man_addspan(struct man *man, const struct tbl_span *sp)
33895c635efSGarrett D'Amore {
33995c635efSGarrett D'Amore 	struct man_node	*n;
34095c635efSGarrett D'Amore 
341*260e9a87SYuri Pankov 	man_breakscope(man, MAN_MAX);
342698f87a4SGarrett D'Amore 	n = man_node_alloc(man, sp->line, 0, MAN_TBL, MAN_MAX);
34395c635efSGarrett D'Amore 	n->span = sp;
344*260e9a87SYuri Pankov 	man_node_append(man, n);
345698f87a4SGarrett D'Amore 	man->next = MAN_NEXT_SIBLING;
346*260e9a87SYuri Pankov 	man_descope(man, sp->line, 0);
34795c635efSGarrett D'Amore }
34895c635efSGarrett D'Amore 
349*260e9a87SYuri Pankov static void
man_descope(struct man * man,int line,int offs)350698f87a4SGarrett D'Amore man_descope(struct man *man, int line, int offs)
35195c635efSGarrett D'Amore {
35295c635efSGarrett D'Amore 	/*
35395c635efSGarrett D'Amore 	 * Co-ordinate what happens with having a next-line scope open:
35495c635efSGarrett D'Amore 	 * first close out the element scope (if applicable), then close
35595c635efSGarrett D'Amore 	 * out the block scope (also if applicable).
35695c635efSGarrett D'Amore 	 */
35795c635efSGarrett D'Amore 
358*260e9a87SYuri Pankov 	if (man->flags & MAN_ELINE) {
359698f87a4SGarrett D'Amore 		man->flags &= ~MAN_ELINE;
360*260e9a87SYuri Pankov 		man_unscope(man, man->last->parent);
36195c635efSGarrett D'Amore 	}
362*260e9a87SYuri Pankov 	if ( ! (man->flags & MAN_BLINE))
363*260e9a87SYuri Pankov 		return;
364698f87a4SGarrett D'Amore 	man->flags &= ~MAN_BLINE;
365*260e9a87SYuri Pankov 	man_unscope(man, man->last->parent);
366*260e9a87SYuri Pankov 	man_body_alloc(man, line, offs, man->last->tok);
36795c635efSGarrett D'Amore }
36895c635efSGarrett D'Amore 
36995c635efSGarrett D'Amore static int
man_ptext(struct man * man,int line,char * buf,int offs)370698f87a4SGarrett D'Amore man_ptext(struct man *man, int line, char *buf, int offs)
37195c635efSGarrett D'Amore {
37295c635efSGarrett D'Amore 	int		 i;
37395c635efSGarrett D'Amore 
37495c635efSGarrett D'Amore 	/* Literal free-form text whitespace is preserved. */
37595c635efSGarrett D'Amore 
376*260e9a87SYuri Pankov 	if (man->flags & MAN_LITERAL) {
377*260e9a87SYuri Pankov 		man_word_alloc(man, line, offs, buf + offs);
378*260e9a87SYuri Pankov 		man_descope(man, line, offs);
379*260e9a87SYuri Pankov 		return(1);
38095c635efSGarrett D'Amore 	}
38195c635efSGarrett D'Amore 
382*260e9a87SYuri Pankov 	for (i = offs; buf[i] == ' '; i++)
38395c635efSGarrett D'Amore 		/* Skip leading whitespace. */ ;
38495c635efSGarrett D'Amore 
385698f87a4SGarrett D'Amore 	/*
386698f87a4SGarrett D'Amore 	 * Blank lines are ignored right after headings
387698f87a4SGarrett D'Amore 	 * but add a single vertical space elsewhere.
388698f87a4SGarrett D'Amore 	 */
389698f87a4SGarrett D'Amore 
390*260e9a87SYuri Pankov 	if (buf[i] == '\0') {
39195c635efSGarrett D'Amore 		/* Allocate a blank entry. */
392*260e9a87SYuri Pankov 		if (man->last->tok != MAN_SH &&
393*260e9a87SYuri Pankov 		    man->last->tok != MAN_SS) {
394*260e9a87SYuri Pankov 			man_elem_alloc(man, line, offs, MAN_sp);
395698f87a4SGarrett D'Amore 			man->next = MAN_NEXT_SIBLING;
396698f87a4SGarrett D'Amore 		}
397698f87a4SGarrett D'Amore 		return(1);
39895c635efSGarrett D'Amore 	}
39995c635efSGarrett D'Amore 
40095c635efSGarrett D'Amore 	/*
40195c635efSGarrett D'Amore 	 * Warn if the last un-escaped character is whitespace. Then
40295c635efSGarrett D'Amore 	 * strip away the remaining spaces (tabs stay!).
40395c635efSGarrett D'Amore 	 */
40495c635efSGarrett D'Amore 
40595c635efSGarrett D'Amore 	i = (int)strlen(buf);
40695c635efSGarrett D'Amore 	assert(i);
40795c635efSGarrett D'Amore 
40895c635efSGarrett D'Amore 	if (' ' == buf[i - 1] || '\t' == buf[i - 1]) {
40995c635efSGarrett D'Amore 		if (i > 1 && '\\' != buf[i - 2])
410*260e9a87SYuri Pankov 			mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
411*260e9a87SYuri Pankov 			    line, i - 1, NULL);
41295c635efSGarrett D'Amore 
41395c635efSGarrett D'Amore 		for (--i; i && ' ' == buf[i]; i--)
41495c635efSGarrett D'Amore 			/* Spin back to non-space. */ ;
41595c635efSGarrett D'Amore 
41695c635efSGarrett D'Amore 		/* Jump ahead of escaped whitespace. */
41795c635efSGarrett D'Amore 		i += '\\' == buf[i] ? 2 : 1;
41895c635efSGarrett D'Amore 
41995c635efSGarrett D'Amore 		buf[i] = '\0';
42095c635efSGarrett D'Amore 	}
421*260e9a87SYuri Pankov 	man_word_alloc(man, line, offs, buf + offs);
42295c635efSGarrett D'Amore 
42395c635efSGarrett D'Amore 	/*
42495c635efSGarrett D'Amore 	 * End-of-sentence check.  If the last character is an unescaped
42595c635efSGarrett D'Amore 	 * EOS character, then flag the node as being the end of a
42695c635efSGarrett D'Amore 	 * sentence.  The front-end will know how to interpret this.
42795c635efSGarrett D'Amore 	 */
42895c635efSGarrett D'Amore 
42995c635efSGarrett D'Amore 	assert(i);
430*260e9a87SYuri Pankov 	if (mandoc_eos(buf, (size_t)i))
431698f87a4SGarrett D'Amore 		man->last->flags |= MAN_EOS;
43295c635efSGarrett D'Amore 
433*260e9a87SYuri Pankov 	man_descope(man, line, offs);
434*260e9a87SYuri Pankov 	return(1);
43595c635efSGarrett D'Amore }
43695c635efSGarrett D'Amore 
43795c635efSGarrett D'Amore static int
man_pmacro(struct man * man,int ln,char * buf,int offs)438698f87a4SGarrett D'Amore man_pmacro(struct man *man, int ln, char *buf, int offs)
43995c635efSGarrett D'Amore {
44095c635efSGarrett D'Amore 	struct man_node	*n;
441*260e9a87SYuri Pankov 	const char	*cp;
442*260e9a87SYuri Pankov 	enum mant	 tok;
443*260e9a87SYuri Pankov 	int		 i, ppos;
444*260e9a87SYuri Pankov 	int		 bline;
445*260e9a87SYuri Pankov 	char		 mac[5];
44695c635efSGarrett D'Amore 
44795c635efSGarrett D'Amore 	ppos = offs;
44895c635efSGarrett D'Amore 
44995c635efSGarrett D'Amore 	/*
45095c635efSGarrett D'Amore 	 * Copy the first word into a nil-terminated buffer.
451*260e9a87SYuri Pankov 	 * Stop when a space, tab, escape, or eoln is encountered.
45295c635efSGarrett D'Amore 	 */
45395c635efSGarrett D'Amore 
45495c635efSGarrett D'Amore 	i = 0;
455*260e9a87SYuri Pankov 	while (i < 4 && strchr(" \t\\", buf[offs]) == NULL)
45695c635efSGarrett D'Amore 		mac[i++] = buf[offs++];
45795c635efSGarrett D'Amore 
45895c635efSGarrett D'Amore 	mac[i] = '\0';
45995c635efSGarrett D'Amore 
46095c635efSGarrett D'Amore 	tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX;
46195c635efSGarrett D'Amore 
462*260e9a87SYuri Pankov 	if (tok == MAN_MAX) {
463*260e9a87SYuri Pankov 		mandoc_msg(MANDOCERR_MACRO, man->parse,
464*260e9a87SYuri Pankov 		    ln, ppos, buf + ppos - 1);
46595c635efSGarrett D'Amore 		return(1);
46695c635efSGarrett D'Amore 	}
46795c635efSGarrett D'Amore 
468*260e9a87SYuri Pankov 	/* Skip a leading escape sequence or tab. */
46995c635efSGarrett D'Amore 
470*260e9a87SYuri Pankov 	switch (buf[offs]) {
471*260e9a87SYuri Pankov 	case '\\':
472*260e9a87SYuri Pankov 		cp = buf + offs + 1;
473*260e9a87SYuri Pankov 		mandoc_escape(&cp, NULL, NULL);
474*260e9a87SYuri Pankov 		offs = cp - buf;
475*260e9a87SYuri Pankov 		break;
476*260e9a87SYuri Pankov 	case '\t':
477*260e9a87SYuri Pankov 		offs++;
478*260e9a87SYuri Pankov 		break;
479*260e9a87SYuri Pankov 	default:
480*260e9a87SYuri Pankov 		break;
481*260e9a87SYuri Pankov 	}
482*260e9a87SYuri Pankov 
483*260e9a87SYuri Pankov 	/* Jump to the next non-whitespace word. */
484*260e9a87SYuri Pankov 
485*260e9a87SYuri Pankov 	while (buf[offs] && buf[offs] == ' ')
48695c635efSGarrett D'Amore 		offs++;
48795c635efSGarrett D'Amore 
48895c635efSGarrett D'Amore 	/*
48995c635efSGarrett D'Amore 	 * Trailing whitespace.  Note that tabs are allowed to be passed
49095c635efSGarrett D'Amore 	 * into the parser as "text", so we only warn about spaces here.
49195c635efSGarrett D'Amore 	 */
49295c635efSGarrett D'Amore 
493*260e9a87SYuri Pankov 	if (buf[offs] == '\0' && buf[offs - 1] == ' ')
494*260e9a87SYuri Pankov 		mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
495*260e9a87SYuri Pankov 		    ln, offs - 1, NULL);
49695c635efSGarrett D'Amore 
49795c635efSGarrett D'Amore 	/*
498*260e9a87SYuri Pankov 	 * Some macros break next-line scopes; otherwise, remember
499*260e9a87SYuri Pankov 	 * whether we are in next-line scope for a block head.
50095c635efSGarrett D'Amore 	 */
50195c635efSGarrett D'Amore 
502*260e9a87SYuri Pankov 	man_breakscope(man, tok);
503*260e9a87SYuri Pankov 	bline = man->flags & MAN_BLINE;
504*260e9a87SYuri Pankov 
505*260e9a87SYuri Pankov 	/* Call to handler... */
506*260e9a87SYuri Pankov 
507*260e9a87SYuri Pankov 	assert(man_macros[tok].fp);
508*260e9a87SYuri Pankov 	(*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf);
509*260e9a87SYuri Pankov 
510*260e9a87SYuri Pankov 	/* In quick mode (for mandocdb), abort after the NAME section. */
511*260e9a87SYuri Pankov 
512*260e9a87SYuri Pankov 	if (man->quick && tok == MAN_SH) {
513698f87a4SGarrett D'Amore 		n = man->last;
514*260e9a87SYuri Pankov 		if (n->type == MAN_BODY &&
515*260e9a87SYuri Pankov 		    strcmp(n->prev->child->string, "NAME"))
516*260e9a87SYuri Pankov 			return(2);
517*260e9a87SYuri Pankov 	}
51895c635efSGarrett D'Amore 
519*260e9a87SYuri Pankov 	/*
520*260e9a87SYuri Pankov 	 * If we are in a next-line scope for a block head,
521*260e9a87SYuri Pankov 	 * close it out now and switch to the body,
522*260e9a87SYuri Pankov 	 * unless the next-line scope is allowed to continue.
523*260e9a87SYuri Pankov 	 */
52495c635efSGarrett D'Amore 
525*260e9a87SYuri Pankov 	if ( ! bline || man->flags & MAN_ELINE ||
526*260e9a87SYuri Pankov 	    man_macros[tok].flags & MAN_NSCOPED)
527*260e9a87SYuri Pankov 		return(1);
528*260e9a87SYuri Pankov 
529*260e9a87SYuri Pankov 	assert(man->flags & MAN_BLINE);
530*260e9a87SYuri Pankov 	man->flags &= ~MAN_BLINE;
531*260e9a87SYuri Pankov 
532*260e9a87SYuri Pankov 	man_unscope(man, man->last->parent);
533*260e9a87SYuri Pankov 	man_body_alloc(man, ln, ppos, man->last->tok);
534*260e9a87SYuri Pankov 	return(1);
535*260e9a87SYuri Pankov }
536*260e9a87SYuri Pankov 
537*260e9a87SYuri Pankov void
man_breakscope(struct man * man,enum mant tok)538*260e9a87SYuri Pankov man_breakscope(struct man *man, enum mant tok)
539*260e9a87SYuri Pankov {
540*260e9a87SYuri Pankov 	struct man_node	*n;
541*260e9a87SYuri Pankov 
542*260e9a87SYuri Pankov 	/*
543*260e9a87SYuri Pankov 	 * An element next line scope is open,
544*260e9a87SYuri Pankov 	 * and the new macro is not allowed inside elements.
545*260e9a87SYuri Pankov 	 * Delete the element that is being broken.
546*260e9a87SYuri Pankov 	 */
547*260e9a87SYuri Pankov 
548*260e9a87SYuri Pankov 	if (man->flags & MAN_ELINE && (tok == MAN_MAX ||
549*260e9a87SYuri Pankov 	    ! (man_macros[tok].flags & MAN_NSCOPED))) {
550*260e9a87SYuri Pankov 		n = man->last;
551*260e9a87SYuri Pankov 		assert(n->type != MAN_TEXT);
552*260e9a87SYuri Pankov 		if (man_macros[n->tok].flags & MAN_NSCOPED)
55395c635efSGarrett D'Amore 			n = n->parent;
55495c635efSGarrett D'Amore 
555*260e9a87SYuri Pankov 		mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
556*260e9a87SYuri Pankov 		    n->line, n->pos, "%s breaks %s",
557*260e9a87SYuri Pankov 		    tok == MAN_MAX ? "TS" : man_macronames[tok],
55895c635efSGarrett D'Amore 		    man_macronames[n->tok]);
55995c635efSGarrett D'Amore 
560698f87a4SGarrett D'Amore 		man_node_delete(man, n);
561698f87a4SGarrett D'Amore 		man->flags &= ~MAN_ELINE;
56295c635efSGarrett D'Amore 	}
56395c635efSGarrett D'Amore 
56495c635efSGarrett D'Amore 	/*
565*260e9a87SYuri Pankov 	 * A block header next line scope is open,
566*260e9a87SYuri Pankov 	 * and the new macro is not allowed inside block headers.
567*260e9a87SYuri Pankov 	 * Delete the block that is being broken.
56895c635efSGarrett D'Amore 	 */
569*260e9a87SYuri Pankov 
570*260e9a87SYuri Pankov 	if (man->flags & MAN_BLINE && (tok == MAN_MAX ||
571*260e9a87SYuri Pankov 	    man_macros[tok].flags & MAN_BSCOPE)) {
572698f87a4SGarrett D'Amore 		n = man->last;
573*260e9a87SYuri Pankov 		if (n->type == MAN_TEXT)
574*260e9a87SYuri Pankov 			n = n->parent;
575*260e9a87SYuri Pankov 		if ( ! (man_macros[n->tok].flags & MAN_BSCOPE))
57695c635efSGarrett D'Amore 			n = n->parent;
57795c635efSGarrett D'Amore 
578*260e9a87SYuri Pankov 		assert(n->type == MAN_HEAD);
57995c635efSGarrett D'Amore 		n = n->parent;
580*260e9a87SYuri Pankov 		assert(n->type == MAN_BLOCK);
581*260e9a87SYuri Pankov 		assert(man_macros[n->tok].flags & MAN_SCOPED);
58295c635efSGarrett D'Amore 
583*260e9a87SYuri Pankov 		mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
584*260e9a87SYuri Pankov 		    n->line, n->pos, "%s breaks %s",
585*260e9a87SYuri Pankov 		    tok == MAN_MAX ? "TS" : man_macronames[tok],
58695c635efSGarrett D'Amore 		    man_macronames[n->tok]);
58795c635efSGarrett D'Amore 
588698f87a4SGarrett D'Amore 		man_node_delete(man, n);
589698f87a4SGarrett D'Amore 		man->flags &= ~MAN_BLINE;
59095c635efSGarrett D'Amore 	}
59195c635efSGarrett D'Amore }
59295c635efSGarrett D'Amore 
59395c635efSGarrett D'Amore /*
594698f87a4SGarrett D'Amore  * Unlink a node from its context.  If "man" is provided, the last parse
59595c635efSGarrett D'Amore  * point will also be adjusted accordingly.
59695c635efSGarrett D'Amore  */
59795c635efSGarrett D'Amore static void
man_node_unlink(struct man * man,struct man_node * n)598698f87a4SGarrett D'Amore man_node_unlink(struct man *man, struct man_node *n)
59995c635efSGarrett D'Amore {
60095c635efSGarrett D'Amore 
60195c635efSGarrett D'Amore 	/* Adjust siblings. */
60295c635efSGarrett D'Amore 
60395c635efSGarrett D'Amore 	if (n->prev)
60495c635efSGarrett D'Amore 		n->prev->next = n->next;
60595c635efSGarrett D'Amore 	if (n->next)
60695c635efSGarrett D'Amore 		n->next->prev = n->prev;
60795c635efSGarrett D'Amore 
60895c635efSGarrett D'Amore 	/* Adjust parent. */
60995c635efSGarrett D'Amore 
61095c635efSGarrett D'Amore 	if (n->parent) {
61195c635efSGarrett D'Amore 		n->parent->nchild--;
61295c635efSGarrett D'Amore 		if (n->parent->child == n)
61395c635efSGarrett D'Amore 			n->parent->child = n->prev ? n->prev : n->next;
61495c635efSGarrett D'Amore 	}
61595c635efSGarrett D'Amore 
61695c635efSGarrett D'Amore 	/* Adjust parse point, if applicable. */
61795c635efSGarrett D'Amore 
618698f87a4SGarrett D'Amore 	if (man && man->last == n) {
61995c635efSGarrett D'Amore 		/*XXX: this can occur when bailing from validation. */
62095c635efSGarrett D'Amore 		/*assert(NULL == n->next);*/
62195c635efSGarrett D'Amore 		if (n->prev) {
622698f87a4SGarrett D'Amore 			man->last = n->prev;
623698f87a4SGarrett D'Amore 			man->next = MAN_NEXT_SIBLING;
62495c635efSGarrett D'Amore 		} else {
625698f87a4SGarrett D'Amore 			man->last = n->parent;
626698f87a4SGarrett D'Amore 			man->next = MAN_NEXT_CHILD;
62795c635efSGarrett D'Amore 		}
62895c635efSGarrett D'Amore 	}
62995c635efSGarrett D'Amore 
630698f87a4SGarrett D'Amore 	if (man && man->first == n)
631698f87a4SGarrett D'Amore 		man->first = NULL;
63295c635efSGarrett D'Amore }
63395c635efSGarrett D'Amore 
63495c635efSGarrett D'Amore const struct mparse *
man_mparse(const struct man * man)635698f87a4SGarrett D'Amore man_mparse(const struct man *man)
63695c635efSGarrett D'Amore {
63795c635efSGarrett D'Amore 
638698f87a4SGarrett D'Amore 	assert(man && man->parse);
639698f87a4SGarrett D'Amore 	return(man->parse);
64095c635efSGarrett D'Amore }
641*260e9a87SYuri Pankov 
642*260e9a87SYuri Pankov void
man_deroff(char ** dest,const struct man_node * n)643*260e9a87SYuri Pankov man_deroff(char **dest, const struct man_node *n)
644*260e9a87SYuri Pankov {
645*260e9a87SYuri Pankov 	char	*cp;
646*260e9a87SYuri Pankov 	size_t	 sz;
647*260e9a87SYuri Pankov 
648*260e9a87SYuri Pankov 	if (n->type != MAN_TEXT) {
649*260e9a87SYuri Pankov 		for (n = n->child; n; n = n->next)
650*260e9a87SYuri Pankov 			man_deroff(dest, n);
651*260e9a87SYuri Pankov 		return;
652*260e9a87SYuri Pankov 	}
653*260e9a87SYuri Pankov 
654*260e9a87SYuri Pankov 	/* Skip leading whitespace and escape sequences. */
655*260e9a87SYuri Pankov 
656*260e9a87SYuri Pankov 	cp = n->string;
657*260e9a87SYuri Pankov 	while ('\0' != *cp) {
658*260e9a87SYuri Pankov 		if ('\\' == *cp) {
659*260e9a87SYuri Pankov 			cp++;
660*260e9a87SYuri Pankov 			mandoc_escape((const char **)&cp, NULL, NULL);
661*260e9a87SYuri Pankov 		} else if (isspace((unsigned char)*cp))
662*260e9a87SYuri Pankov 			cp++;
663*260e9a87SYuri Pankov 		else
664*260e9a87SYuri Pankov 			break;
665*260e9a87SYuri Pankov 	}
666*260e9a87SYuri Pankov 
667*260e9a87SYuri Pankov 	/* Skip trailing whitespace. */
668*260e9a87SYuri Pankov 
669*260e9a87SYuri Pankov 	for (sz = strlen(cp); sz; sz--)
670*260e9a87SYuri Pankov 		if (0 == isspace((unsigned char)cp[sz-1]))
671*260e9a87SYuri Pankov 			break;
672*260e9a87SYuri Pankov 
673*260e9a87SYuri Pankov 	/* Skip empty strings. */
674*260e9a87SYuri Pankov 
675*260e9a87SYuri Pankov 	if (0 == sz)
676*260e9a87SYuri Pankov 		return;
677*260e9a87SYuri Pankov 
678*260e9a87SYuri Pankov 	if (NULL == *dest) {
679*260e9a87SYuri Pankov 		*dest = mandoc_strndup(cp, sz);
680*260e9a87SYuri Pankov 		return;
681*260e9a87SYuri Pankov 	}
682*260e9a87SYuri Pankov 
683*260e9a87SYuri Pankov 	mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp);
684*260e9a87SYuri Pankov 	free(*dest);
685*260e9a87SYuri Pankov 	*dest = cp;
686*260e9a87SYuri Pankov }
687