xref: /illumos-gate/usr/src/cmd/mandoc/man_term.c (revision 698f87a48e2e945bfe5493ce168e0d0ae1cedd5c)
1*698f87a4SGarrett D'Amore /*	$Id: man_term.c,v 1.139 2013/12/22 23:34:13 schwarze Exp $ */
295c635efSGarrett D'Amore /*
3*698f87a4SGarrett D'Amore  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
4*698f87a4SGarrett D'Amore  * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
595c635efSGarrett D'Amore  *
695c635efSGarrett D'Amore  * Permission to use, copy, modify, and distribute this software for any
795c635efSGarrett D'Amore  * purpose with or without fee is hereby granted, provided that the above
895c635efSGarrett D'Amore  * copyright notice and this permission notice appear in all copies.
995c635efSGarrett D'Amore  *
1095c635efSGarrett D'Amore  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1195c635efSGarrett D'Amore  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1295c635efSGarrett D'Amore  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1395c635efSGarrett D'Amore  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1495c635efSGarrett D'Amore  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1595c635efSGarrett D'Amore  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1695c635efSGarrett D'Amore  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1795c635efSGarrett D'Amore  */
1895c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H
1995c635efSGarrett D'Amore #include "config.h"
2095c635efSGarrett D'Amore #endif
2195c635efSGarrett D'Amore 
2295c635efSGarrett D'Amore #include <sys/types.h>
2395c635efSGarrett D'Amore 
2495c635efSGarrett D'Amore #include <assert.h>
2595c635efSGarrett D'Amore #include <ctype.h>
2695c635efSGarrett D'Amore #include <stdio.h>
2795c635efSGarrett D'Amore #include <stdlib.h>
2895c635efSGarrett D'Amore #include <string.h>
2995c635efSGarrett D'Amore 
3095c635efSGarrett D'Amore #include "mandoc.h"
3195c635efSGarrett D'Amore #include "out.h"
3295c635efSGarrett D'Amore #include "man.h"
3395c635efSGarrett D'Amore #include "term.h"
3495c635efSGarrett D'Amore #include "main.h"
3595c635efSGarrett D'Amore 
3695c635efSGarrett D'Amore #define	MAXMARGINS	  64 /* maximum number of indented scopes */
3795c635efSGarrett D'Amore 
3895c635efSGarrett D'Amore struct	mtermp {
3995c635efSGarrett D'Amore 	int		  fl;
4095c635efSGarrett D'Amore #define	MANT_LITERAL	 (1 << 0)
4195c635efSGarrett D'Amore 	size_t		  lmargin[MAXMARGINS]; /* margins (incl. visible page) */
4295c635efSGarrett D'Amore 	int		  lmargincur; /* index of current margin */
4395c635efSGarrett D'Amore 	int		  lmarginsz; /* actual number of nested margins */
4495c635efSGarrett D'Amore 	size_t		  offset; /* default offset to visible page */
45*698f87a4SGarrett D'Amore 	int		  pardist; /* vert. space before par., unit: [v] */
4695c635efSGarrett D'Amore };
4795c635efSGarrett D'Amore 
4895c635efSGarrett D'Amore #define	DECL_ARGS 	  struct termp *p, \
4995c635efSGarrett D'Amore 			  struct mtermp *mt, \
5095c635efSGarrett D'Amore 			  const struct man_node *n, \
51*698f87a4SGarrett D'Amore 			  const struct man_meta *meta
5295c635efSGarrett D'Amore 
5395c635efSGarrett D'Amore struct	termact {
5495c635efSGarrett D'Amore 	int		(*pre)(DECL_ARGS);
5595c635efSGarrett D'Amore 	void		(*post)(DECL_ARGS);
5695c635efSGarrett D'Amore 	int		  flags;
5795c635efSGarrett D'Amore #define	MAN_NOTEXT	 (1 << 0) /* Never has text children. */
5895c635efSGarrett D'Amore };
5995c635efSGarrett D'Amore 
6095c635efSGarrett D'Amore static	int		  a2width(const struct termp *, const char *);
6195c635efSGarrett D'Amore static	size_t		  a2height(const struct termp *, const char *);
6295c635efSGarrett D'Amore 
6395c635efSGarrett D'Amore static	void		  print_man_nodelist(DECL_ARGS);
6495c635efSGarrett D'Amore static	void		  print_man_node(DECL_ARGS);
6595c635efSGarrett D'Amore static	void		  print_man_head(struct termp *, const void *);
6695c635efSGarrett D'Amore static	void		  print_man_foot(struct termp *, const void *);
6795c635efSGarrett D'Amore static	void		  print_bvspace(struct termp *,
68*698f87a4SGarrett D'Amore 				const struct man_node *, int);
6995c635efSGarrett D'Amore 
7095c635efSGarrett D'Amore static	int		  pre_B(DECL_ARGS);
7195c635efSGarrett D'Amore static	int		  pre_HP(DECL_ARGS);
7295c635efSGarrett D'Amore static	int		  pre_I(DECL_ARGS);
7395c635efSGarrett D'Amore static	int		  pre_IP(DECL_ARGS);
7495c635efSGarrett D'Amore static	int		  pre_OP(DECL_ARGS);
75*698f87a4SGarrett D'Amore static	int		  pre_PD(DECL_ARGS);
7695c635efSGarrett D'Amore static	int		  pre_PP(DECL_ARGS);
7795c635efSGarrett D'Amore static	int		  pre_RS(DECL_ARGS);
7895c635efSGarrett D'Amore static	int		  pre_SH(DECL_ARGS);
7995c635efSGarrett D'Amore static	int		  pre_SS(DECL_ARGS);
8095c635efSGarrett D'Amore static	int		  pre_TP(DECL_ARGS);
81*698f87a4SGarrett D'Amore static	int		  pre_UR(DECL_ARGS);
8295c635efSGarrett D'Amore static	int		  pre_alternate(DECL_ARGS);
8395c635efSGarrett D'Amore static	int		  pre_ft(DECL_ARGS);
8495c635efSGarrett D'Amore static	int		  pre_ign(DECL_ARGS);
8595c635efSGarrett D'Amore static	int		  pre_in(DECL_ARGS);
8695c635efSGarrett D'Amore static	int		  pre_literal(DECL_ARGS);
8795c635efSGarrett D'Amore static	int		  pre_sp(DECL_ARGS);
8895c635efSGarrett D'Amore 
8995c635efSGarrett D'Amore static	void		  post_IP(DECL_ARGS);
9095c635efSGarrett D'Amore static	void		  post_HP(DECL_ARGS);
9195c635efSGarrett D'Amore static	void		  post_RS(DECL_ARGS);
9295c635efSGarrett D'Amore static	void		  post_SH(DECL_ARGS);
9395c635efSGarrett D'Amore static	void		  post_SS(DECL_ARGS);
9495c635efSGarrett D'Amore static	void		  post_TP(DECL_ARGS);
95*698f87a4SGarrett D'Amore static	void		  post_UR(DECL_ARGS);
9695c635efSGarrett D'Amore 
9795c635efSGarrett D'Amore static	const struct termact termacts[MAN_MAX] = {
9895c635efSGarrett D'Amore 	{ pre_sp, NULL, MAN_NOTEXT }, /* br */
9995c635efSGarrett D'Amore 	{ NULL, NULL, 0 }, /* TH */
10095c635efSGarrett D'Amore 	{ pre_SH, post_SH, 0 }, /* SH */
10195c635efSGarrett D'Amore 	{ pre_SS, post_SS, 0 }, /* SS */
10295c635efSGarrett D'Amore 	{ pre_TP, post_TP, 0 }, /* TP */
10395c635efSGarrett D'Amore 	{ pre_PP, NULL, 0 }, /* LP */
10495c635efSGarrett D'Amore 	{ pre_PP, NULL, 0 }, /* PP */
10595c635efSGarrett D'Amore 	{ pre_PP, NULL, 0 }, /* P */
10695c635efSGarrett D'Amore 	{ pre_IP, post_IP, 0 }, /* IP */
10795c635efSGarrett D'Amore 	{ pre_HP, post_HP, 0 }, /* HP */
10895c635efSGarrett D'Amore 	{ NULL, NULL, 0 }, /* SM */
10995c635efSGarrett D'Amore 	{ pre_B, NULL, 0 }, /* SB */
11095c635efSGarrett D'Amore 	{ pre_alternate, NULL, 0 }, /* BI */
11195c635efSGarrett D'Amore 	{ pre_alternate, NULL, 0 }, /* IB */
11295c635efSGarrett D'Amore 	{ pre_alternate, NULL, 0 }, /* BR */
11395c635efSGarrett D'Amore 	{ pre_alternate, NULL, 0 }, /* RB */
11495c635efSGarrett D'Amore 	{ NULL, NULL, 0 }, /* R */
11595c635efSGarrett D'Amore 	{ pre_B, NULL, 0 }, /* B */
11695c635efSGarrett D'Amore 	{ pre_I, NULL, 0 }, /* I */
11795c635efSGarrett D'Amore 	{ pre_alternate, NULL, 0 }, /* IR */
11895c635efSGarrett D'Amore 	{ pre_alternate, NULL, 0 }, /* RI */
11995c635efSGarrett D'Amore 	{ pre_ign, NULL, MAN_NOTEXT }, /* na */
12095c635efSGarrett D'Amore 	{ pre_sp, NULL, MAN_NOTEXT }, /* sp */
12195c635efSGarrett D'Amore 	{ pre_literal, NULL, 0 }, /* nf */
12295c635efSGarrett D'Amore 	{ pre_literal, NULL, 0 }, /* fi */
12395c635efSGarrett D'Amore 	{ NULL, NULL, 0 }, /* RE */
12495c635efSGarrett D'Amore 	{ pre_RS, post_RS, 0 }, /* RS */
12595c635efSGarrett D'Amore 	{ pre_ign, NULL, 0 }, /* DT */
12695c635efSGarrett D'Amore 	{ pre_ign, NULL, 0 }, /* UC */
127*698f87a4SGarrett D'Amore 	{ pre_PD, NULL, MAN_NOTEXT }, /* PD */
12895c635efSGarrett D'Amore 	{ pre_ign, NULL, 0 }, /* AT */
12995c635efSGarrett D'Amore 	{ pre_in, NULL, MAN_NOTEXT }, /* in */
13095c635efSGarrett D'Amore 	{ pre_ft, NULL, MAN_NOTEXT }, /* ft */
13195c635efSGarrett D'Amore 	{ pre_OP, NULL, 0 }, /* OP */
132*698f87a4SGarrett D'Amore 	{ pre_literal, NULL, 0 }, /* EX */
133*698f87a4SGarrett D'Amore 	{ pre_literal, NULL, 0 }, /* EE */
134*698f87a4SGarrett D'Amore 	{ pre_UR, post_UR, 0 }, /* UR */
135*698f87a4SGarrett D'Amore 	{ NULL, NULL, 0 }, /* UE */
13695c635efSGarrett D'Amore };
13795c635efSGarrett D'Amore 
13895c635efSGarrett D'Amore 
13995c635efSGarrett D'Amore 
14095c635efSGarrett D'Amore void
14195c635efSGarrett D'Amore terminal_man(void *arg, const struct man *man)
14295c635efSGarrett D'Amore {
14395c635efSGarrett D'Amore 	struct termp		*p;
14495c635efSGarrett D'Amore 	const struct man_node	*n;
145*698f87a4SGarrett D'Amore 	const struct man_meta	*meta;
14695c635efSGarrett D'Amore 	struct mtermp		 mt;
14795c635efSGarrett D'Amore 
14895c635efSGarrett D'Amore 	p = (struct termp *)arg;
14995c635efSGarrett D'Amore 
15095c635efSGarrett D'Amore 	if (0 == p->defindent)
15195c635efSGarrett D'Amore 		p->defindent = 7;
15295c635efSGarrett D'Amore 
15395c635efSGarrett D'Amore 	p->overstep = 0;
15495c635efSGarrett D'Amore 	p->maxrmargin = p->defrmargin;
15595c635efSGarrett D'Amore 	p->tabwidth = term_len(p, 5);
15695c635efSGarrett D'Amore 
15795c635efSGarrett D'Amore 	if (NULL == p->symtab)
15895c635efSGarrett D'Amore 		p->symtab = mchars_alloc();
15995c635efSGarrett D'Amore 
16095c635efSGarrett D'Amore 	n = man_node(man);
161*698f87a4SGarrett D'Amore 	meta = man_meta(man);
16295c635efSGarrett D'Amore 
163*698f87a4SGarrett D'Amore 	term_begin(p, print_man_head, print_man_foot, meta);
16495c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
16595c635efSGarrett D'Amore 
16695c635efSGarrett D'Amore 	memset(&mt, 0, sizeof(struct mtermp));
16795c635efSGarrett D'Amore 
16895c635efSGarrett D'Amore 	mt.lmargin[mt.lmargincur] = term_len(p, p->defindent);
16995c635efSGarrett D'Amore 	mt.offset = term_len(p, p->defindent);
170*698f87a4SGarrett D'Amore 	mt.pardist = 1;
17195c635efSGarrett D'Amore 
17295c635efSGarrett D'Amore 	if (n->child)
173*698f87a4SGarrett D'Amore 		print_man_nodelist(p, &mt, n->child, meta);
17495c635efSGarrett D'Amore 
17595c635efSGarrett D'Amore 	term_end(p);
17695c635efSGarrett D'Amore }
17795c635efSGarrett D'Amore 
17895c635efSGarrett D'Amore 
17995c635efSGarrett D'Amore static size_t
18095c635efSGarrett D'Amore a2height(const struct termp *p, const char *cp)
18195c635efSGarrett D'Amore {
18295c635efSGarrett D'Amore 	struct roffsu	 su;
18395c635efSGarrett D'Amore 
18495c635efSGarrett D'Amore 	if ( ! a2roffsu(cp, &su, SCALE_VS))
18595c635efSGarrett D'Amore 		SCALE_VS_INIT(&su, atoi(cp));
18695c635efSGarrett D'Amore 
18795c635efSGarrett D'Amore 	return(term_vspan(p, &su));
18895c635efSGarrett D'Amore }
18995c635efSGarrett D'Amore 
19095c635efSGarrett D'Amore 
19195c635efSGarrett D'Amore static int
19295c635efSGarrett D'Amore a2width(const struct termp *p, const char *cp)
19395c635efSGarrett D'Amore {
19495c635efSGarrett D'Amore 	struct roffsu	 su;
19595c635efSGarrett D'Amore 
19695c635efSGarrett D'Amore 	if ( ! a2roffsu(cp, &su, SCALE_BU))
19795c635efSGarrett D'Amore 		return(-1);
19895c635efSGarrett D'Amore 
19995c635efSGarrett D'Amore 	return((int)term_hspan(p, &su));
20095c635efSGarrett D'Amore }
20195c635efSGarrett D'Amore 
20295c635efSGarrett D'Amore /*
20395c635efSGarrett D'Amore  * Printing leading vertical space before a block.
20495c635efSGarrett D'Amore  * This is used for the paragraph macros.
20595c635efSGarrett D'Amore  * The rules are pretty simple, since there's very little nesting going
20695c635efSGarrett D'Amore  * on here.  Basically, if we're the first within another block (SS/SH),
20795c635efSGarrett D'Amore  * then don't emit vertical space.  If we are (RS), then do.  If not the
20895c635efSGarrett D'Amore  * first, print it.
20995c635efSGarrett D'Amore  */
21095c635efSGarrett D'Amore static void
211*698f87a4SGarrett D'Amore print_bvspace(struct termp *p, const struct man_node *n, int pardist)
21295c635efSGarrett D'Amore {
213*698f87a4SGarrett D'Amore 	int	 i;
21495c635efSGarrett D'Amore 
21595c635efSGarrett D'Amore 	term_newln(p);
21695c635efSGarrett D'Amore 
21795c635efSGarrett D'Amore 	if (n->body && n->body->child)
21895c635efSGarrett D'Amore 		if (MAN_TBL == n->body->child->type)
21995c635efSGarrett D'Amore 			return;
22095c635efSGarrett D'Amore 
22195c635efSGarrett D'Amore 	if (MAN_ROOT == n->parent->type || MAN_RS != n->parent->tok)
22295c635efSGarrett D'Amore 		if (NULL == n->prev)
22395c635efSGarrett D'Amore 			return;
22495c635efSGarrett D'Amore 
225*698f87a4SGarrett D'Amore 	for (i = 0; i < pardist; i++)
22695c635efSGarrett D'Amore 		term_vspace(p);
22795c635efSGarrett D'Amore }
22895c635efSGarrett D'Amore 
22995c635efSGarrett D'Amore /* ARGSUSED */
23095c635efSGarrett D'Amore static int
23195c635efSGarrett D'Amore pre_ign(DECL_ARGS)
23295c635efSGarrett D'Amore {
23395c635efSGarrett D'Amore 
23495c635efSGarrett D'Amore 	return(0);
23595c635efSGarrett D'Amore }
23695c635efSGarrett D'Amore 
23795c635efSGarrett D'Amore 
23895c635efSGarrett D'Amore /* ARGSUSED */
23995c635efSGarrett D'Amore static int
24095c635efSGarrett D'Amore pre_I(DECL_ARGS)
24195c635efSGarrett D'Amore {
24295c635efSGarrett D'Amore 
24395c635efSGarrett D'Amore 	term_fontrepl(p, TERMFONT_UNDER);
24495c635efSGarrett D'Amore 	return(1);
24595c635efSGarrett D'Amore }
24695c635efSGarrett D'Amore 
24795c635efSGarrett D'Amore 
24895c635efSGarrett D'Amore /* ARGSUSED */
24995c635efSGarrett D'Amore static int
25095c635efSGarrett D'Amore pre_literal(DECL_ARGS)
25195c635efSGarrett D'Amore {
25295c635efSGarrett D'Amore 
25395c635efSGarrett D'Amore 	term_newln(p);
25495c635efSGarrett D'Amore 
255*698f87a4SGarrett D'Amore 	if (MAN_nf == n->tok || MAN_EX == n->tok)
25695c635efSGarrett D'Amore 		mt->fl |= MANT_LITERAL;
25795c635efSGarrett D'Amore 	else
25895c635efSGarrett D'Amore 		mt->fl &= ~MANT_LITERAL;
25995c635efSGarrett D'Amore 
26095c635efSGarrett D'Amore 	/*
26195c635efSGarrett D'Amore 	 * Unlike .IP and .TP, .HP does not have a HEAD.
26295c635efSGarrett D'Amore 	 * So in case a second call to term_flushln() is needed,
26395c635efSGarrett D'Amore 	 * indentation has to be set up explicitly.
26495c635efSGarrett D'Amore 	 */
26595c635efSGarrett D'Amore 	if (MAN_HP == n->parent->tok && p->rmargin < p->maxrmargin) {
26695c635efSGarrett D'Amore 		p->offset = p->rmargin;
26795c635efSGarrett D'Amore 		p->rmargin = p->maxrmargin;
268*698f87a4SGarrett D'Amore 		p->trailspace = 0;
269*698f87a4SGarrett D'Amore 		p->flags &= ~TERMP_NOBREAK;
27095c635efSGarrett D'Amore 		p->flags |= TERMP_NOSPACE;
27195c635efSGarrett D'Amore 	}
27295c635efSGarrett D'Amore 
27395c635efSGarrett D'Amore 	return(0);
27495c635efSGarrett D'Amore }
27595c635efSGarrett D'Amore 
27695c635efSGarrett D'Amore /* ARGSUSED */
27795c635efSGarrett D'Amore static int
278*698f87a4SGarrett D'Amore pre_PD(DECL_ARGS)
279*698f87a4SGarrett D'Amore {
280*698f87a4SGarrett D'Amore 
281*698f87a4SGarrett D'Amore 	n = n->child;
282*698f87a4SGarrett D'Amore 	if (0 == n) {
283*698f87a4SGarrett D'Amore 		mt->pardist = 1;
284*698f87a4SGarrett D'Amore 		return(0);
285*698f87a4SGarrett D'Amore 	}
286*698f87a4SGarrett D'Amore 	assert(MAN_TEXT == n->type);
287*698f87a4SGarrett D'Amore 	mt->pardist = atoi(n->string);
288*698f87a4SGarrett D'Amore 	return(0);
289*698f87a4SGarrett D'Amore }
290*698f87a4SGarrett D'Amore 
291*698f87a4SGarrett D'Amore /* ARGSUSED */
292*698f87a4SGarrett D'Amore static int
29395c635efSGarrett D'Amore pre_alternate(DECL_ARGS)
29495c635efSGarrett D'Amore {
29595c635efSGarrett D'Amore 	enum termfont		 font[2];
29695c635efSGarrett D'Amore 	const struct man_node	*nn;
29795c635efSGarrett D'Amore 	int			 savelit, i;
29895c635efSGarrett D'Amore 
29995c635efSGarrett D'Amore 	switch (n->tok) {
30095c635efSGarrett D'Amore 	case (MAN_RB):
30195c635efSGarrett D'Amore 		font[0] = TERMFONT_NONE;
30295c635efSGarrett D'Amore 		font[1] = TERMFONT_BOLD;
30395c635efSGarrett D'Amore 		break;
30495c635efSGarrett D'Amore 	case (MAN_RI):
30595c635efSGarrett D'Amore 		font[0] = TERMFONT_NONE;
30695c635efSGarrett D'Amore 		font[1] = TERMFONT_UNDER;
30795c635efSGarrett D'Amore 		break;
30895c635efSGarrett D'Amore 	case (MAN_BR):
30995c635efSGarrett D'Amore 		font[0] = TERMFONT_BOLD;
31095c635efSGarrett D'Amore 		font[1] = TERMFONT_NONE;
31195c635efSGarrett D'Amore 		break;
31295c635efSGarrett D'Amore 	case (MAN_BI):
31395c635efSGarrett D'Amore 		font[0] = TERMFONT_BOLD;
31495c635efSGarrett D'Amore 		font[1] = TERMFONT_UNDER;
31595c635efSGarrett D'Amore 		break;
31695c635efSGarrett D'Amore 	case (MAN_IR):
31795c635efSGarrett D'Amore 		font[0] = TERMFONT_UNDER;
31895c635efSGarrett D'Amore 		font[1] = TERMFONT_NONE;
31995c635efSGarrett D'Amore 		break;
32095c635efSGarrett D'Amore 	case (MAN_IB):
32195c635efSGarrett D'Amore 		font[0] = TERMFONT_UNDER;
32295c635efSGarrett D'Amore 		font[1] = TERMFONT_BOLD;
32395c635efSGarrett D'Amore 		break;
32495c635efSGarrett D'Amore 	default:
32595c635efSGarrett D'Amore 		abort();
32695c635efSGarrett D'Amore 	}
32795c635efSGarrett D'Amore 
32895c635efSGarrett D'Amore 	savelit = MANT_LITERAL & mt->fl;
32995c635efSGarrett D'Amore 	mt->fl &= ~MANT_LITERAL;
33095c635efSGarrett D'Amore 
33195c635efSGarrett D'Amore 	for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) {
33295c635efSGarrett D'Amore 		term_fontrepl(p, font[i]);
33395c635efSGarrett D'Amore 		if (savelit && NULL == nn->next)
33495c635efSGarrett D'Amore 			mt->fl |= MANT_LITERAL;
335*698f87a4SGarrett D'Amore 		print_man_node(p, mt, nn, meta);
33695c635efSGarrett D'Amore 		if (nn->next)
33795c635efSGarrett D'Amore 			p->flags |= TERMP_NOSPACE;
33895c635efSGarrett D'Amore 	}
33995c635efSGarrett D'Amore 
34095c635efSGarrett D'Amore 	return(0);
34195c635efSGarrett D'Amore }
34295c635efSGarrett D'Amore 
34395c635efSGarrett D'Amore /* ARGSUSED */
34495c635efSGarrett D'Amore static int
34595c635efSGarrett D'Amore pre_B(DECL_ARGS)
34695c635efSGarrett D'Amore {
34795c635efSGarrett D'Amore 
34895c635efSGarrett D'Amore 	term_fontrepl(p, TERMFONT_BOLD);
34995c635efSGarrett D'Amore 	return(1);
35095c635efSGarrett D'Amore }
35195c635efSGarrett D'Amore 
35295c635efSGarrett D'Amore /* ARGSUSED */
35395c635efSGarrett D'Amore static int
35495c635efSGarrett D'Amore pre_OP(DECL_ARGS)
35595c635efSGarrett D'Amore {
35695c635efSGarrett D'Amore 
35795c635efSGarrett D'Amore 	term_word(p, "[");
35895c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
35995c635efSGarrett D'Amore 
36095c635efSGarrett D'Amore 	if (NULL != (n = n->child)) {
36195c635efSGarrett D'Amore 		term_fontrepl(p, TERMFONT_BOLD);
36295c635efSGarrett D'Amore 		term_word(p, n->string);
36395c635efSGarrett D'Amore 	}
36495c635efSGarrett D'Amore 	if (NULL != n && NULL != n->next) {
36595c635efSGarrett D'Amore 		term_fontrepl(p, TERMFONT_UNDER);
36695c635efSGarrett D'Amore 		term_word(p, n->next->string);
36795c635efSGarrett D'Amore 	}
36895c635efSGarrett D'Amore 
36995c635efSGarrett D'Amore 	term_fontrepl(p, TERMFONT_NONE);
37095c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
37195c635efSGarrett D'Amore 	term_word(p, "]");
37295c635efSGarrett D'Amore 	return(0);
37395c635efSGarrett D'Amore }
37495c635efSGarrett D'Amore 
37595c635efSGarrett D'Amore /* ARGSUSED */
37695c635efSGarrett D'Amore static int
37795c635efSGarrett D'Amore pre_ft(DECL_ARGS)
37895c635efSGarrett D'Amore {
37995c635efSGarrett D'Amore 	const char	*cp;
38095c635efSGarrett D'Amore 
38195c635efSGarrett D'Amore 	if (NULL == n->child) {
38295c635efSGarrett D'Amore 		term_fontlast(p);
38395c635efSGarrett D'Amore 		return(0);
38495c635efSGarrett D'Amore 	}
38595c635efSGarrett D'Amore 
38695c635efSGarrett D'Amore 	cp = n->child->string;
38795c635efSGarrett D'Amore 	switch (*cp) {
38895c635efSGarrett D'Amore 	case ('4'):
38995c635efSGarrett D'Amore 		/* FALLTHROUGH */
39095c635efSGarrett D'Amore 	case ('3'):
39195c635efSGarrett D'Amore 		/* FALLTHROUGH */
39295c635efSGarrett D'Amore 	case ('B'):
39395c635efSGarrett D'Amore 		term_fontrepl(p, TERMFONT_BOLD);
39495c635efSGarrett D'Amore 		break;
39595c635efSGarrett D'Amore 	case ('2'):
39695c635efSGarrett D'Amore 		/* FALLTHROUGH */
39795c635efSGarrett D'Amore 	case ('I'):
39895c635efSGarrett D'Amore 		term_fontrepl(p, TERMFONT_UNDER);
39995c635efSGarrett D'Amore 		break;
40095c635efSGarrett D'Amore 	case ('P'):
40195c635efSGarrett D'Amore 		term_fontlast(p);
40295c635efSGarrett D'Amore 		break;
40395c635efSGarrett D'Amore 	case ('1'):
40495c635efSGarrett D'Amore 		/* FALLTHROUGH */
40595c635efSGarrett D'Amore 	case ('C'):
40695c635efSGarrett D'Amore 		/* FALLTHROUGH */
40795c635efSGarrett D'Amore 	case ('R'):
40895c635efSGarrett D'Amore 		term_fontrepl(p, TERMFONT_NONE);
40995c635efSGarrett D'Amore 		break;
41095c635efSGarrett D'Amore 	default:
41195c635efSGarrett D'Amore 		break;
41295c635efSGarrett D'Amore 	}
41395c635efSGarrett D'Amore 	return(0);
41495c635efSGarrett D'Amore }
41595c635efSGarrett D'Amore 
41695c635efSGarrett D'Amore /* ARGSUSED */
41795c635efSGarrett D'Amore static int
41895c635efSGarrett D'Amore pre_in(DECL_ARGS)
41995c635efSGarrett D'Amore {
42095c635efSGarrett D'Amore 	int		 len, less;
42195c635efSGarrett D'Amore 	size_t		 v;
42295c635efSGarrett D'Amore 	const char	*cp;
42395c635efSGarrett D'Amore 
42495c635efSGarrett D'Amore 	term_newln(p);
42595c635efSGarrett D'Amore 
42695c635efSGarrett D'Amore 	if (NULL == n->child) {
42795c635efSGarrett D'Amore 		p->offset = mt->offset;
42895c635efSGarrett D'Amore 		return(0);
42995c635efSGarrett D'Amore 	}
43095c635efSGarrett D'Amore 
43195c635efSGarrett D'Amore 	cp = n->child->string;
43295c635efSGarrett D'Amore 	less = 0;
43395c635efSGarrett D'Amore 
43495c635efSGarrett D'Amore 	if ('-' == *cp)
43595c635efSGarrett D'Amore 		less = -1;
43695c635efSGarrett D'Amore 	else if ('+' == *cp)
43795c635efSGarrett D'Amore 		less = 1;
43895c635efSGarrett D'Amore 	else
43995c635efSGarrett D'Amore 		cp--;
44095c635efSGarrett D'Amore 
44195c635efSGarrett D'Amore 	if ((len = a2width(p, ++cp)) < 0)
44295c635efSGarrett D'Amore 		return(0);
44395c635efSGarrett D'Amore 
44495c635efSGarrett D'Amore 	v = (size_t)len;
44595c635efSGarrett D'Amore 
44695c635efSGarrett D'Amore 	if (less < 0)
44795c635efSGarrett D'Amore 		p->offset -= p->offset > v ? v : p->offset;
44895c635efSGarrett D'Amore 	else if (less > 0)
44995c635efSGarrett D'Amore 		p->offset += v;
45095c635efSGarrett D'Amore 	else
45195c635efSGarrett D'Amore 		p->offset = v;
45295c635efSGarrett D'Amore 
45395c635efSGarrett D'Amore 	/* Don't let this creep beyond the right margin. */
45495c635efSGarrett D'Amore 
45595c635efSGarrett D'Amore 	if (p->offset > p->rmargin)
45695c635efSGarrett D'Amore 		p->offset = p->rmargin;
45795c635efSGarrett D'Amore 
45895c635efSGarrett D'Amore 	return(0);
45995c635efSGarrett D'Amore }
46095c635efSGarrett D'Amore 
46195c635efSGarrett D'Amore 
46295c635efSGarrett D'Amore /* ARGSUSED */
46395c635efSGarrett D'Amore static int
46495c635efSGarrett D'Amore pre_sp(DECL_ARGS)
46595c635efSGarrett D'Amore {
466*698f87a4SGarrett D'Amore 	char		*s;
46795c635efSGarrett D'Amore 	size_t		 i, len;
468*698f87a4SGarrett D'Amore 	int		 neg;
46995c635efSGarrett D'Amore 
47095c635efSGarrett D'Amore 	if ((NULL == n->prev && n->parent)) {
471*698f87a4SGarrett D'Amore 		switch (n->parent->tok) {
472*698f87a4SGarrett D'Amore 		case (MAN_SH):
473*698f87a4SGarrett D'Amore 			/* FALLTHROUGH */
474*698f87a4SGarrett D'Amore 		case (MAN_SS):
475*698f87a4SGarrett D'Amore 			/* FALLTHROUGH */
476*698f87a4SGarrett D'Amore 		case (MAN_PP):
477*698f87a4SGarrett D'Amore 			/* FALLTHROUGH */
478*698f87a4SGarrett D'Amore 		case (MAN_LP):
479*698f87a4SGarrett D'Amore 			/* FALLTHROUGH */
480*698f87a4SGarrett D'Amore 		case (MAN_P):
481*698f87a4SGarrett D'Amore 			/* FALLTHROUGH */
48295c635efSGarrett D'Amore 			return(0);
483*698f87a4SGarrett D'Amore 		default:
484*698f87a4SGarrett D'Amore 			break;
485*698f87a4SGarrett D'Amore 		}
48695c635efSGarrett D'Amore 	}
48795c635efSGarrett D'Amore 
488*698f87a4SGarrett D'Amore 	neg = 0;
48995c635efSGarrett D'Amore 	switch (n->tok) {
49095c635efSGarrett D'Amore 	case (MAN_br):
49195c635efSGarrett D'Amore 		len = 0;
49295c635efSGarrett D'Amore 		break;
49395c635efSGarrett D'Amore 	default:
494*698f87a4SGarrett D'Amore 		if (NULL == n->child) {
495*698f87a4SGarrett D'Amore 			len = 1;
496*698f87a4SGarrett D'Amore 			break;
497*698f87a4SGarrett D'Amore 		}
498*698f87a4SGarrett D'Amore 		s = n->child->string;
499*698f87a4SGarrett D'Amore 		if ('-' == *s) {
500*698f87a4SGarrett D'Amore 			neg = 1;
501*698f87a4SGarrett D'Amore 			s++;
502*698f87a4SGarrett D'Amore 		}
503*698f87a4SGarrett D'Amore 		len = a2height(p, s);
50495c635efSGarrett D'Amore 		break;
50595c635efSGarrett D'Amore 	}
50695c635efSGarrett D'Amore 
50795c635efSGarrett D'Amore 	if (0 == len)
50895c635efSGarrett D'Amore 		term_newln(p);
509*698f87a4SGarrett D'Amore 	else if (neg)
510*698f87a4SGarrett D'Amore 		p->skipvsp += len;
511*698f87a4SGarrett D'Amore 	else
51295c635efSGarrett D'Amore 		for (i = 0; i < len; i++)
51395c635efSGarrett D'Amore 			term_vspace(p);
51495c635efSGarrett D'Amore 
51595c635efSGarrett D'Amore 	return(0);
51695c635efSGarrett D'Amore }
51795c635efSGarrett D'Amore 
51895c635efSGarrett D'Amore 
51995c635efSGarrett D'Amore /* ARGSUSED */
52095c635efSGarrett D'Amore static int
52195c635efSGarrett D'Amore pre_HP(DECL_ARGS)
52295c635efSGarrett D'Amore {
52395c635efSGarrett D'Amore 	size_t			 len, one;
52495c635efSGarrett D'Amore 	int			 ival;
52595c635efSGarrett D'Amore 	const struct man_node	*nn;
52695c635efSGarrett D'Amore 
52795c635efSGarrett D'Amore 	switch (n->type) {
52895c635efSGarrett D'Amore 	case (MAN_BLOCK):
529*698f87a4SGarrett D'Amore 		print_bvspace(p, n, mt->pardist);
53095c635efSGarrett D'Amore 		return(1);
53195c635efSGarrett D'Amore 	case (MAN_BODY):
53295c635efSGarrett D'Amore 		break;
53395c635efSGarrett D'Amore 	default:
53495c635efSGarrett D'Amore 		return(0);
53595c635efSGarrett D'Amore 	}
53695c635efSGarrett D'Amore 
537*698f87a4SGarrett D'Amore 	if ( ! (MANT_LITERAL & mt->fl)) {
538*698f87a4SGarrett D'Amore 		p->flags |= TERMP_NOBREAK;
539*698f87a4SGarrett D'Amore 		p->trailspace = 2;
540*698f87a4SGarrett D'Amore 	}
541*698f87a4SGarrett D'Amore 
54295c635efSGarrett D'Amore 	len = mt->lmargin[mt->lmargincur];
54395c635efSGarrett D'Amore 	ival = -1;
54495c635efSGarrett D'Amore 
54595c635efSGarrett D'Amore 	/* Calculate offset. */
54695c635efSGarrett D'Amore 
54795c635efSGarrett D'Amore 	if (NULL != (nn = n->parent->head->child))
54895c635efSGarrett D'Amore 		if ((ival = a2width(p, nn->string)) >= 0)
54995c635efSGarrett D'Amore 			len = (size_t)ival;
55095c635efSGarrett D'Amore 
55195c635efSGarrett D'Amore 	one = term_len(p, 1);
55295c635efSGarrett D'Amore 	if (len < one)
55395c635efSGarrett D'Amore 		len = one;
55495c635efSGarrett D'Amore 
55595c635efSGarrett D'Amore 	p->offset = mt->offset;
55695c635efSGarrett D'Amore 	p->rmargin = mt->offset + len;
55795c635efSGarrett D'Amore 
55895c635efSGarrett D'Amore 	if (ival >= 0)
55995c635efSGarrett D'Amore 		mt->lmargin[mt->lmargincur] = (size_t)ival;
56095c635efSGarrett D'Amore 
56195c635efSGarrett D'Amore 	return(1);
56295c635efSGarrett D'Amore }
56395c635efSGarrett D'Amore 
56495c635efSGarrett D'Amore 
56595c635efSGarrett D'Amore /* ARGSUSED */
56695c635efSGarrett D'Amore static void
56795c635efSGarrett D'Amore post_HP(DECL_ARGS)
56895c635efSGarrett D'Amore {
56995c635efSGarrett D'Amore 
57095c635efSGarrett D'Amore 	switch (n->type) {
57195c635efSGarrett D'Amore 	case (MAN_BODY):
572*698f87a4SGarrett D'Amore 		term_newln(p);
57395c635efSGarrett D'Amore 		p->flags &= ~TERMP_NOBREAK;
574*698f87a4SGarrett D'Amore 		p->trailspace = 0;
57595c635efSGarrett D'Amore 		p->offset = mt->offset;
57695c635efSGarrett D'Amore 		p->rmargin = p->maxrmargin;
57795c635efSGarrett D'Amore 		break;
57895c635efSGarrett D'Amore 	default:
57995c635efSGarrett D'Amore 		break;
58095c635efSGarrett D'Amore 	}
58195c635efSGarrett D'Amore }
58295c635efSGarrett D'Amore 
58395c635efSGarrett D'Amore 
58495c635efSGarrett D'Amore /* ARGSUSED */
58595c635efSGarrett D'Amore static int
58695c635efSGarrett D'Amore pre_PP(DECL_ARGS)
58795c635efSGarrett D'Amore {
58895c635efSGarrett D'Amore 
58995c635efSGarrett D'Amore 	switch (n->type) {
59095c635efSGarrett D'Amore 	case (MAN_BLOCK):
59195c635efSGarrett D'Amore 		mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
592*698f87a4SGarrett D'Amore 		print_bvspace(p, n, mt->pardist);
59395c635efSGarrett D'Amore 		break;
59495c635efSGarrett D'Amore 	default:
59595c635efSGarrett D'Amore 		p->offset = mt->offset;
59695c635efSGarrett D'Amore 		break;
59795c635efSGarrett D'Amore 	}
59895c635efSGarrett D'Amore 
59995c635efSGarrett D'Amore 	return(MAN_HEAD != n->type);
60095c635efSGarrett D'Amore }
60195c635efSGarrett D'Amore 
60295c635efSGarrett D'Amore 
60395c635efSGarrett D'Amore /* ARGSUSED */
60495c635efSGarrett D'Amore static int
60595c635efSGarrett D'Amore pre_IP(DECL_ARGS)
60695c635efSGarrett D'Amore {
60795c635efSGarrett D'Amore 	const struct man_node	*nn;
60895c635efSGarrett D'Amore 	size_t			 len;
60995c635efSGarrett D'Amore 	int			 savelit, ival;
61095c635efSGarrett D'Amore 
61195c635efSGarrett D'Amore 	switch (n->type) {
61295c635efSGarrett D'Amore 	case (MAN_BODY):
61395c635efSGarrett D'Amore 		p->flags |= TERMP_NOSPACE;
61495c635efSGarrett D'Amore 		break;
61595c635efSGarrett D'Amore 	case (MAN_HEAD):
61695c635efSGarrett D'Amore 		p->flags |= TERMP_NOBREAK;
617*698f87a4SGarrett D'Amore 		p->trailspace = 1;
61895c635efSGarrett D'Amore 		break;
61995c635efSGarrett D'Amore 	case (MAN_BLOCK):
620*698f87a4SGarrett D'Amore 		print_bvspace(p, n, mt->pardist);
62195c635efSGarrett D'Amore 		/* FALLTHROUGH */
62295c635efSGarrett D'Amore 	default:
62395c635efSGarrett D'Amore 		return(1);
62495c635efSGarrett D'Amore 	}
62595c635efSGarrett D'Amore 
62695c635efSGarrett D'Amore 	len = mt->lmargin[mt->lmargincur];
62795c635efSGarrett D'Amore 	ival = -1;
62895c635efSGarrett D'Amore 
62995c635efSGarrett D'Amore 	/* Calculate the offset from the optional second argument. */
63095c635efSGarrett D'Amore 	if (NULL != (nn = n->parent->head->child))
63195c635efSGarrett D'Amore 		if (NULL != (nn = nn->next))
63295c635efSGarrett D'Amore 			if ((ival = a2width(p, nn->string)) >= 0)
63395c635efSGarrett D'Amore 				len = (size_t)ival;
63495c635efSGarrett D'Amore 
63595c635efSGarrett D'Amore 	switch (n->type) {
63695c635efSGarrett D'Amore 	case (MAN_HEAD):
63795c635efSGarrett D'Amore 		/* Handle zero-width lengths. */
63895c635efSGarrett D'Amore 		if (0 == len)
63995c635efSGarrett D'Amore 			len = term_len(p, 1);
64095c635efSGarrett D'Amore 
64195c635efSGarrett D'Amore 		p->offset = mt->offset;
64295c635efSGarrett D'Amore 		p->rmargin = mt->offset + len;
64395c635efSGarrett D'Amore 		if (ival < 0)
64495c635efSGarrett D'Amore 			break;
64595c635efSGarrett D'Amore 
64695c635efSGarrett D'Amore 		/* Set the saved left-margin. */
64795c635efSGarrett D'Amore 		mt->lmargin[mt->lmargincur] = (size_t)ival;
64895c635efSGarrett D'Amore 
64995c635efSGarrett D'Amore 		savelit = MANT_LITERAL & mt->fl;
65095c635efSGarrett D'Amore 		mt->fl &= ~MANT_LITERAL;
65195c635efSGarrett D'Amore 
65295c635efSGarrett D'Amore 		if (n->child)
653*698f87a4SGarrett D'Amore 			print_man_node(p, mt, n->child, meta);
65495c635efSGarrett D'Amore 
65595c635efSGarrett D'Amore 		if (savelit)
65695c635efSGarrett D'Amore 			mt->fl |= MANT_LITERAL;
65795c635efSGarrett D'Amore 
65895c635efSGarrett D'Amore 		return(0);
65995c635efSGarrett D'Amore 	case (MAN_BODY):
66095c635efSGarrett D'Amore 		p->offset = mt->offset + len;
66195c635efSGarrett D'Amore 		p->rmargin = p->maxrmargin;
66295c635efSGarrett D'Amore 		break;
66395c635efSGarrett D'Amore 	default:
66495c635efSGarrett D'Amore 		break;
66595c635efSGarrett D'Amore 	}
66695c635efSGarrett D'Amore 
66795c635efSGarrett D'Amore 	return(1);
66895c635efSGarrett D'Amore }
66995c635efSGarrett D'Amore 
67095c635efSGarrett D'Amore 
67195c635efSGarrett D'Amore /* ARGSUSED */
67295c635efSGarrett D'Amore static void
67395c635efSGarrett D'Amore post_IP(DECL_ARGS)
67495c635efSGarrett D'Amore {
67595c635efSGarrett D'Amore 
67695c635efSGarrett D'Amore 	switch (n->type) {
67795c635efSGarrett D'Amore 	case (MAN_HEAD):
67895c635efSGarrett D'Amore 		term_flushln(p);
67995c635efSGarrett D'Amore 		p->flags &= ~TERMP_NOBREAK;
680*698f87a4SGarrett D'Amore 		p->trailspace = 0;
68195c635efSGarrett D'Amore 		p->rmargin = p->maxrmargin;
68295c635efSGarrett D'Amore 		break;
68395c635efSGarrett D'Amore 	case (MAN_BODY):
68495c635efSGarrett D'Amore 		term_newln(p);
685*698f87a4SGarrett D'Amore 		p->offset = mt->offset;
68695c635efSGarrett D'Amore 		break;
68795c635efSGarrett D'Amore 	default:
68895c635efSGarrett D'Amore 		break;
68995c635efSGarrett D'Amore 	}
69095c635efSGarrett D'Amore }
69195c635efSGarrett D'Amore 
69295c635efSGarrett D'Amore 
69395c635efSGarrett D'Amore /* ARGSUSED */
69495c635efSGarrett D'Amore static int
69595c635efSGarrett D'Amore pre_TP(DECL_ARGS)
69695c635efSGarrett D'Amore {
69795c635efSGarrett D'Amore 	const struct man_node	*nn;
69895c635efSGarrett D'Amore 	size_t			 len;
69995c635efSGarrett D'Amore 	int			 savelit, ival;
70095c635efSGarrett D'Amore 
70195c635efSGarrett D'Amore 	switch (n->type) {
70295c635efSGarrett D'Amore 	case (MAN_HEAD):
70395c635efSGarrett D'Amore 		p->flags |= TERMP_NOBREAK;
704*698f87a4SGarrett D'Amore 		p->trailspace = 1;
70595c635efSGarrett D'Amore 		break;
70695c635efSGarrett D'Amore 	case (MAN_BODY):
70795c635efSGarrett D'Amore 		p->flags |= TERMP_NOSPACE;
70895c635efSGarrett D'Amore 		break;
70995c635efSGarrett D'Amore 	case (MAN_BLOCK):
710*698f87a4SGarrett D'Amore 		print_bvspace(p, n, mt->pardist);
71195c635efSGarrett D'Amore 		/* FALLTHROUGH */
71295c635efSGarrett D'Amore 	default:
71395c635efSGarrett D'Amore 		return(1);
71495c635efSGarrett D'Amore 	}
71595c635efSGarrett D'Amore 
71695c635efSGarrett D'Amore 	len = (size_t)mt->lmargin[mt->lmargincur];
71795c635efSGarrett D'Amore 	ival = -1;
71895c635efSGarrett D'Amore 
71995c635efSGarrett D'Amore 	/* Calculate offset. */
72095c635efSGarrett D'Amore 
72195c635efSGarrett D'Amore 	if (NULL != (nn = n->parent->head->child))
72295c635efSGarrett D'Amore 		if (nn->string && nn->parent->line == nn->line)
72395c635efSGarrett D'Amore 			if ((ival = a2width(p, nn->string)) >= 0)
72495c635efSGarrett D'Amore 				len = (size_t)ival;
72595c635efSGarrett D'Amore 
72695c635efSGarrett D'Amore 	switch (n->type) {
72795c635efSGarrett D'Amore 	case (MAN_HEAD):
72895c635efSGarrett D'Amore 		/* Handle zero-length properly. */
72995c635efSGarrett D'Amore 		if (0 == len)
73095c635efSGarrett D'Amore 			len = term_len(p, 1);
73195c635efSGarrett D'Amore 
73295c635efSGarrett D'Amore 		p->offset = mt->offset;
73395c635efSGarrett D'Amore 		p->rmargin = mt->offset + len;
73495c635efSGarrett D'Amore 
73595c635efSGarrett D'Amore 		savelit = MANT_LITERAL & mt->fl;
73695c635efSGarrett D'Amore 		mt->fl &= ~MANT_LITERAL;
73795c635efSGarrett D'Amore 
73895c635efSGarrett D'Amore 		/* Don't print same-line elements. */
73995c635efSGarrett D'Amore 		for (nn = n->child; nn; nn = nn->next)
74095c635efSGarrett D'Amore 			if (nn->line > n->line)
741*698f87a4SGarrett D'Amore 				print_man_node(p, mt, nn, meta);
74295c635efSGarrett D'Amore 
74395c635efSGarrett D'Amore 		if (savelit)
74495c635efSGarrett D'Amore 			mt->fl |= MANT_LITERAL;
74595c635efSGarrett D'Amore 		if (ival >= 0)
74695c635efSGarrett D'Amore 			mt->lmargin[mt->lmargincur] = (size_t)ival;
74795c635efSGarrett D'Amore 
74895c635efSGarrett D'Amore 		return(0);
74995c635efSGarrett D'Amore 	case (MAN_BODY):
75095c635efSGarrett D'Amore 		p->offset = mt->offset + len;
75195c635efSGarrett D'Amore 		p->rmargin = p->maxrmargin;
752*698f87a4SGarrett D'Amore 		p->trailspace = 0;
753*698f87a4SGarrett D'Amore 		p->flags &= ~TERMP_NOBREAK;
75495c635efSGarrett D'Amore 		break;
75595c635efSGarrett D'Amore 	default:
75695c635efSGarrett D'Amore 		break;
75795c635efSGarrett D'Amore 	}
75895c635efSGarrett D'Amore 
75995c635efSGarrett D'Amore 	return(1);
76095c635efSGarrett D'Amore }
76195c635efSGarrett D'Amore 
76295c635efSGarrett D'Amore 
76395c635efSGarrett D'Amore /* ARGSUSED */
76495c635efSGarrett D'Amore static void
76595c635efSGarrett D'Amore post_TP(DECL_ARGS)
76695c635efSGarrett D'Amore {
76795c635efSGarrett D'Amore 
76895c635efSGarrett D'Amore 	switch (n->type) {
76995c635efSGarrett D'Amore 	case (MAN_HEAD):
77095c635efSGarrett D'Amore 		term_flushln(p);
77195c635efSGarrett D'Amore 		break;
77295c635efSGarrett D'Amore 	case (MAN_BODY):
77395c635efSGarrett D'Amore 		term_newln(p);
774*698f87a4SGarrett D'Amore 		p->offset = mt->offset;
77595c635efSGarrett D'Amore 		break;
77695c635efSGarrett D'Amore 	default:
77795c635efSGarrett D'Amore 		break;
77895c635efSGarrett D'Amore 	}
77995c635efSGarrett D'Amore }
78095c635efSGarrett D'Amore 
78195c635efSGarrett D'Amore 
78295c635efSGarrett D'Amore /* ARGSUSED */
78395c635efSGarrett D'Amore static int
78495c635efSGarrett D'Amore pre_SS(DECL_ARGS)
78595c635efSGarrett D'Amore {
786*698f87a4SGarrett D'Amore 	int	 i;
78795c635efSGarrett D'Amore 
78895c635efSGarrett D'Amore 	switch (n->type) {
78995c635efSGarrett D'Amore 	case (MAN_BLOCK):
79095c635efSGarrett D'Amore 		mt->fl &= ~MANT_LITERAL;
79195c635efSGarrett D'Amore 		mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
79295c635efSGarrett D'Amore 		mt->offset = term_len(p, p->defindent);
79395c635efSGarrett D'Amore 		/* If following a prior empty `SS', no vspace. */
79495c635efSGarrett D'Amore 		if (n->prev && MAN_SS == n->prev->tok)
79595c635efSGarrett D'Amore 			if (NULL == n->prev->body->child)
79695c635efSGarrett D'Amore 				break;
79795c635efSGarrett D'Amore 		if (NULL == n->prev)
79895c635efSGarrett D'Amore 			break;
799*698f87a4SGarrett D'Amore 		for (i = 0; i < mt->pardist; i++)
80095c635efSGarrett D'Amore 			term_vspace(p);
80195c635efSGarrett D'Amore 		break;
80295c635efSGarrett D'Amore 	case (MAN_HEAD):
80395c635efSGarrett D'Amore 		term_fontrepl(p, TERMFONT_BOLD);
804*698f87a4SGarrett D'Amore 		p->offset = term_len(p, 3);
80595c635efSGarrett D'Amore 		break;
80695c635efSGarrett D'Amore 	case (MAN_BODY):
80795c635efSGarrett D'Amore 		p->offset = mt->offset;
80895c635efSGarrett D'Amore 		break;
80995c635efSGarrett D'Amore 	default:
81095c635efSGarrett D'Amore 		break;
81195c635efSGarrett D'Amore 	}
81295c635efSGarrett D'Amore 
81395c635efSGarrett D'Amore 	return(1);
81495c635efSGarrett D'Amore }
81595c635efSGarrett D'Amore 
81695c635efSGarrett D'Amore 
81795c635efSGarrett D'Amore /* ARGSUSED */
81895c635efSGarrett D'Amore static void
81995c635efSGarrett D'Amore post_SS(DECL_ARGS)
82095c635efSGarrett D'Amore {
82195c635efSGarrett D'Amore 
82295c635efSGarrett D'Amore 	switch (n->type) {
82395c635efSGarrett D'Amore 	case (MAN_HEAD):
82495c635efSGarrett D'Amore 		term_newln(p);
82595c635efSGarrett D'Amore 		break;
82695c635efSGarrett D'Amore 	case (MAN_BODY):
82795c635efSGarrett D'Amore 		term_newln(p);
82895c635efSGarrett D'Amore 		break;
82995c635efSGarrett D'Amore 	default:
83095c635efSGarrett D'Amore 		break;
83195c635efSGarrett D'Amore 	}
83295c635efSGarrett D'Amore }
83395c635efSGarrett D'Amore 
83495c635efSGarrett D'Amore 
83595c635efSGarrett D'Amore /* ARGSUSED */
83695c635efSGarrett D'Amore static int
83795c635efSGarrett D'Amore pre_SH(DECL_ARGS)
83895c635efSGarrett D'Amore {
839*698f87a4SGarrett D'Amore 	int	 i;
84095c635efSGarrett D'Amore 
84195c635efSGarrett D'Amore 	switch (n->type) {
84295c635efSGarrett D'Amore 	case (MAN_BLOCK):
84395c635efSGarrett D'Amore 		mt->fl &= ~MANT_LITERAL;
84495c635efSGarrett D'Amore 		mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
84595c635efSGarrett D'Amore 		mt->offset = term_len(p, p->defindent);
84695c635efSGarrett D'Amore 		/* If following a prior empty `SH', no vspace. */
84795c635efSGarrett D'Amore 		if (n->prev && MAN_SH == n->prev->tok)
84895c635efSGarrett D'Amore 			if (NULL == n->prev->body->child)
84995c635efSGarrett D'Amore 				break;
85095c635efSGarrett D'Amore 		/* If the first macro, no vspae. */
85195c635efSGarrett D'Amore 		if (NULL == n->prev)
85295c635efSGarrett D'Amore 			break;
853*698f87a4SGarrett D'Amore 		for (i = 0; i < mt->pardist; i++)
85495c635efSGarrett D'Amore 			term_vspace(p);
85595c635efSGarrett D'Amore 		break;
85695c635efSGarrett D'Amore 	case (MAN_HEAD):
85795c635efSGarrett D'Amore 		term_fontrepl(p, TERMFONT_BOLD);
85895c635efSGarrett D'Amore 		p->offset = 0;
85995c635efSGarrett D'Amore 		break;
86095c635efSGarrett D'Amore 	case (MAN_BODY):
86195c635efSGarrett D'Amore 		p->offset = mt->offset;
86295c635efSGarrett D'Amore 		break;
86395c635efSGarrett D'Amore 	default:
86495c635efSGarrett D'Amore 		break;
86595c635efSGarrett D'Amore 	}
86695c635efSGarrett D'Amore 
86795c635efSGarrett D'Amore 	return(1);
86895c635efSGarrett D'Amore }
86995c635efSGarrett D'Amore 
87095c635efSGarrett D'Amore 
87195c635efSGarrett D'Amore /* ARGSUSED */
87295c635efSGarrett D'Amore static void
87395c635efSGarrett D'Amore post_SH(DECL_ARGS)
87495c635efSGarrett D'Amore {
87595c635efSGarrett D'Amore 
87695c635efSGarrett D'Amore 	switch (n->type) {
87795c635efSGarrett D'Amore 	case (MAN_HEAD):
87895c635efSGarrett D'Amore 		term_newln(p);
87995c635efSGarrett D'Amore 		break;
88095c635efSGarrett D'Amore 	case (MAN_BODY):
88195c635efSGarrett D'Amore 		term_newln(p);
88295c635efSGarrett D'Amore 		break;
88395c635efSGarrett D'Amore 	default:
88495c635efSGarrett D'Amore 		break;
88595c635efSGarrett D'Amore 	}
88695c635efSGarrett D'Amore }
88795c635efSGarrett D'Amore 
88895c635efSGarrett D'Amore /* ARGSUSED */
88995c635efSGarrett D'Amore static int
89095c635efSGarrett D'Amore pre_RS(DECL_ARGS)
89195c635efSGarrett D'Amore {
89295c635efSGarrett D'Amore 	int		 ival;
89395c635efSGarrett D'Amore 	size_t		 sz;
89495c635efSGarrett D'Amore 
89595c635efSGarrett D'Amore 	switch (n->type) {
89695c635efSGarrett D'Amore 	case (MAN_BLOCK):
89795c635efSGarrett D'Amore 		term_newln(p);
89895c635efSGarrett D'Amore 		return(1);
89995c635efSGarrett D'Amore 	case (MAN_HEAD):
90095c635efSGarrett D'Amore 		return(0);
90195c635efSGarrett D'Amore 	default:
90295c635efSGarrett D'Amore 		break;
90395c635efSGarrett D'Amore 	}
90495c635efSGarrett D'Amore 
90595c635efSGarrett D'Amore 	sz = term_len(p, p->defindent);
90695c635efSGarrett D'Amore 
90795c635efSGarrett D'Amore 	if (NULL != (n = n->parent->head->child))
90895c635efSGarrett D'Amore 		if ((ival = a2width(p, n->string)) >= 0)
90995c635efSGarrett D'Amore 			sz = (size_t)ival;
91095c635efSGarrett D'Amore 
91195c635efSGarrett D'Amore 	mt->offset += sz;
91295c635efSGarrett D'Amore 	p->rmargin = p->maxrmargin;
91395c635efSGarrett D'Amore 	p->offset = mt->offset < p->rmargin ? mt->offset : p->rmargin;
91495c635efSGarrett D'Amore 
91595c635efSGarrett D'Amore 	if (++mt->lmarginsz < MAXMARGINS)
91695c635efSGarrett D'Amore 		mt->lmargincur = mt->lmarginsz;
91795c635efSGarrett D'Amore 
91895c635efSGarrett D'Amore 	mt->lmargin[mt->lmargincur] = mt->lmargin[mt->lmargincur - 1];
91995c635efSGarrett D'Amore 	return(1);
92095c635efSGarrett D'Amore }
92195c635efSGarrett D'Amore 
92295c635efSGarrett D'Amore /* ARGSUSED */
92395c635efSGarrett D'Amore static void
92495c635efSGarrett D'Amore post_RS(DECL_ARGS)
92595c635efSGarrett D'Amore {
92695c635efSGarrett D'Amore 	int		 ival;
92795c635efSGarrett D'Amore 	size_t		 sz;
92895c635efSGarrett D'Amore 
92995c635efSGarrett D'Amore 	switch (n->type) {
93095c635efSGarrett D'Amore 	case (MAN_BLOCK):
93195c635efSGarrett D'Amore 		return;
93295c635efSGarrett D'Amore 	case (MAN_HEAD):
93395c635efSGarrett D'Amore 		return;
93495c635efSGarrett D'Amore 	default:
93595c635efSGarrett D'Amore 		term_newln(p);
93695c635efSGarrett D'Amore 		break;
93795c635efSGarrett D'Amore 	}
93895c635efSGarrett D'Amore 
93995c635efSGarrett D'Amore 	sz = term_len(p, p->defindent);
94095c635efSGarrett D'Amore 
94195c635efSGarrett D'Amore 	if (NULL != (n = n->parent->head->child))
94295c635efSGarrett D'Amore 		if ((ival = a2width(p, n->string)) >= 0)
94395c635efSGarrett D'Amore 			sz = (size_t)ival;
94495c635efSGarrett D'Amore 
94595c635efSGarrett D'Amore 	mt->offset = mt->offset < sz ?  0 : mt->offset - sz;
94695c635efSGarrett D'Amore 	p->offset = mt->offset;
94795c635efSGarrett D'Amore 
94895c635efSGarrett D'Amore 	if (--mt->lmarginsz < MAXMARGINS)
94995c635efSGarrett D'Amore 		mt->lmargincur = mt->lmarginsz;
95095c635efSGarrett D'Amore }
95195c635efSGarrett D'Amore 
952*698f87a4SGarrett D'Amore /* ARGSUSED */
953*698f87a4SGarrett D'Amore static int
954*698f87a4SGarrett D'Amore pre_UR(DECL_ARGS)
955*698f87a4SGarrett D'Amore {
956*698f87a4SGarrett D'Amore 
957*698f87a4SGarrett D'Amore 	return (MAN_HEAD != n->type);
958*698f87a4SGarrett D'Amore }
959*698f87a4SGarrett D'Amore 
960*698f87a4SGarrett D'Amore /* ARGSUSED */
961*698f87a4SGarrett D'Amore static void
962*698f87a4SGarrett D'Amore post_UR(DECL_ARGS)
963*698f87a4SGarrett D'Amore {
964*698f87a4SGarrett D'Amore 
965*698f87a4SGarrett D'Amore 	if (MAN_BLOCK != n->type)
966*698f87a4SGarrett D'Amore 		return;
967*698f87a4SGarrett D'Amore 
968*698f87a4SGarrett D'Amore 	term_word(p, "<");
969*698f87a4SGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
970*698f87a4SGarrett D'Amore 
971*698f87a4SGarrett D'Amore 	if (NULL != n->child->child)
972*698f87a4SGarrett D'Amore 		print_man_node(p, mt, n->child->child, meta);
973*698f87a4SGarrett D'Amore 
974*698f87a4SGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
975*698f87a4SGarrett D'Amore 	term_word(p, ">");
976*698f87a4SGarrett D'Amore }
977*698f87a4SGarrett D'Amore 
97895c635efSGarrett D'Amore static void
97995c635efSGarrett D'Amore print_man_node(DECL_ARGS)
98095c635efSGarrett D'Amore {
98195c635efSGarrett D'Amore 	size_t		 rm, rmax;
98295c635efSGarrett D'Amore 	int		 c;
98395c635efSGarrett D'Amore 
98495c635efSGarrett D'Amore 	switch (n->type) {
98595c635efSGarrett D'Amore 	case(MAN_TEXT):
98695c635efSGarrett D'Amore 		/*
98795c635efSGarrett D'Amore 		 * If we have a blank line, output a vertical space.
98895c635efSGarrett D'Amore 		 * If we have a space as the first character, break
98995c635efSGarrett D'Amore 		 * before printing the line's data.
99095c635efSGarrett D'Amore 		 */
99195c635efSGarrett D'Amore 		if ('\0' == *n->string) {
99295c635efSGarrett D'Amore 			term_vspace(p);
99395c635efSGarrett D'Amore 			return;
99495c635efSGarrett D'Amore 		} else if (' ' == *n->string && MAN_LINE & n->flags)
99595c635efSGarrett D'Amore 			term_newln(p);
99695c635efSGarrett D'Amore 
99795c635efSGarrett D'Amore 		term_word(p, n->string);
998*698f87a4SGarrett D'Amore 		goto out;
99995c635efSGarrett D'Amore 
100095c635efSGarrett D'Amore 	case (MAN_EQN):
100195c635efSGarrett D'Amore 		term_eqn(p, n->eqn);
100295c635efSGarrett D'Amore 		return;
100395c635efSGarrett D'Amore 	case (MAN_TBL):
100495c635efSGarrett D'Amore 		/*
100595c635efSGarrett D'Amore 		 * Tables are preceded by a newline.  Then process a
100695c635efSGarrett D'Amore 		 * table line, which will cause line termination,
100795c635efSGarrett D'Amore 		 */
100895c635efSGarrett D'Amore 		if (TBL_SPAN_FIRST & n->span->flags)
100995c635efSGarrett D'Amore 			term_newln(p);
101095c635efSGarrett D'Amore 		term_tbl(p, n->span);
101195c635efSGarrett D'Amore 		return;
101295c635efSGarrett D'Amore 	default:
101395c635efSGarrett D'Amore 		break;
101495c635efSGarrett D'Amore 	}
101595c635efSGarrett D'Amore 
101695c635efSGarrett D'Amore 	if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
101795c635efSGarrett D'Amore 		term_fontrepl(p, TERMFONT_NONE);
101895c635efSGarrett D'Amore 
101995c635efSGarrett D'Amore 	c = 1;
102095c635efSGarrett D'Amore 	if (termacts[n->tok].pre)
1021*698f87a4SGarrett D'Amore 		c = (*termacts[n->tok].pre)(p, mt, n, meta);
102295c635efSGarrett D'Amore 
102395c635efSGarrett D'Amore 	if (c && n->child)
1024*698f87a4SGarrett D'Amore 		print_man_nodelist(p, mt, n->child, meta);
102595c635efSGarrett D'Amore 
102695c635efSGarrett D'Amore 	if (termacts[n->tok].post)
1027*698f87a4SGarrett D'Amore 		(*termacts[n->tok].post)(p, mt, n, meta);
102895c635efSGarrett D'Amore 	if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
102995c635efSGarrett D'Amore 		term_fontrepl(p, TERMFONT_NONE);
103095c635efSGarrett D'Amore 
1031*698f87a4SGarrett D'Amore out:
1032*698f87a4SGarrett D'Amore 	/*
1033*698f87a4SGarrett D'Amore 	 * If we're in a literal context, make sure that words
1034*698f87a4SGarrett D'Amore 	 * together on the same line stay together.  This is a
1035*698f87a4SGarrett D'Amore 	 * POST-printing call, so we check the NEXT word.  Since
1036*698f87a4SGarrett D'Amore 	 * -man doesn't have nested macros, we don't need to be
1037*698f87a4SGarrett D'Amore 	 * more specific than this.
1038*698f87a4SGarrett D'Amore 	 */
1039*698f87a4SGarrett D'Amore 	if (MANT_LITERAL & mt->fl && ! (TERMP_NOBREAK & p->flags) &&
1040*698f87a4SGarrett D'Amore 	    (NULL == n->next || n->next->line > n->line)) {
1041*698f87a4SGarrett D'Amore 		rm = p->rmargin;
1042*698f87a4SGarrett D'Amore 		rmax = p->maxrmargin;
1043*698f87a4SGarrett D'Amore 		p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
1044*698f87a4SGarrett D'Amore 		p->flags |= TERMP_NOSPACE;
1045*698f87a4SGarrett D'Amore 		if (NULL != n->string && '\0' != *n->string)
1046*698f87a4SGarrett D'Amore 			term_flushln(p);
1047*698f87a4SGarrett D'Amore 		else
1048*698f87a4SGarrett D'Amore 			term_newln(p);
1049*698f87a4SGarrett D'Amore 		if (rm < rmax && n->parent->tok == MAN_HP) {
1050*698f87a4SGarrett D'Amore 			p->offset = rm;
1051*698f87a4SGarrett D'Amore 			p->rmargin = rmax;
1052*698f87a4SGarrett D'Amore 		} else
1053*698f87a4SGarrett D'Amore 			p->rmargin = rm;
1054*698f87a4SGarrett D'Amore 		p->maxrmargin = rmax;
1055*698f87a4SGarrett D'Amore 	}
105695c635efSGarrett D'Amore 	if (MAN_EOS & n->flags)
105795c635efSGarrett D'Amore 		p->flags |= TERMP_SENTENCE;
105895c635efSGarrett D'Amore }
105995c635efSGarrett D'Amore 
106095c635efSGarrett D'Amore 
106195c635efSGarrett D'Amore static void
106295c635efSGarrett D'Amore print_man_nodelist(DECL_ARGS)
106395c635efSGarrett D'Amore {
106495c635efSGarrett D'Amore 
1065*698f87a4SGarrett D'Amore 	print_man_node(p, mt, n, meta);
106695c635efSGarrett D'Amore 	if ( ! n->next)
106795c635efSGarrett D'Amore 		return;
1068*698f87a4SGarrett D'Amore 	print_man_nodelist(p, mt, n->next, meta);
106995c635efSGarrett D'Amore }
107095c635efSGarrett D'Amore 
107195c635efSGarrett D'Amore 
107295c635efSGarrett D'Amore static void
107395c635efSGarrett D'Amore print_man_foot(struct termp *p, const void *arg)
107495c635efSGarrett D'Amore {
107595c635efSGarrett D'Amore 	char		title[BUFSIZ];
107695c635efSGarrett D'Amore 	size_t		datelen;
107795c635efSGarrett D'Amore 	const struct man_meta *meta;
107895c635efSGarrett D'Amore 
107995c635efSGarrett D'Amore 	meta = (const struct man_meta *)arg;
108095c635efSGarrett D'Amore 	assert(meta->title);
108195c635efSGarrett D'Amore 	assert(meta->msec);
108295c635efSGarrett D'Amore 	assert(meta->date);
108395c635efSGarrett D'Amore 
108495c635efSGarrett D'Amore 	term_fontrepl(p, TERMFONT_NONE);
108595c635efSGarrett D'Amore 
108695c635efSGarrett D'Amore 	term_vspace(p);
108795c635efSGarrett D'Amore 
108895c635efSGarrett D'Amore 	/*
108995c635efSGarrett D'Amore 	 * Temporary, undocumented option to imitate mdoc(7) output.
109095c635efSGarrett D'Amore 	 * In the bottom right corner, use the source instead of
109195c635efSGarrett D'Amore 	 * the title.
109295c635efSGarrett D'Amore 	 */
109395c635efSGarrett D'Amore 
109495c635efSGarrett D'Amore 	if ( ! p->mdocstyle) {
109595c635efSGarrett D'Amore 		term_vspace(p);
109695c635efSGarrett D'Amore 		term_vspace(p);
109795c635efSGarrett D'Amore 		snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec);
109895c635efSGarrett D'Amore 	} else if (meta->source) {
109995c635efSGarrett D'Amore 		strlcpy(title, meta->source, BUFSIZ);
110095c635efSGarrett D'Amore 	} else {
110195c635efSGarrett D'Amore 		title[0] = '\0';
110295c635efSGarrett D'Amore 	}
110395c635efSGarrett D'Amore 	datelen = term_strlen(p, meta->date);
110495c635efSGarrett D'Amore 
110595c635efSGarrett D'Amore 	/* Bottom left corner: manual source. */
110695c635efSGarrett D'Amore 
110795c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
1108*698f87a4SGarrett D'Amore 	p->trailspace = 1;
110995c635efSGarrett D'Amore 	p->offset = 0;
111095c635efSGarrett D'Amore 	p->rmargin = (p->maxrmargin - datelen + term_len(p, 1)) / 2;
111195c635efSGarrett D'Amore 
111295c635efSGarrett D'Amore 	if (meta->source)
111395c635efSGarrett D'Amore 		term_word(p, meta->source);
111495c635efSGarrett D'Amore 	term_flushln(p);
111595c635efSGarrett D'Amore 
111695c635efSGarrett D'Amore 	/* At the bottom in the middle: manual date. */
111795c635efSGarrett D'Amore 
111895c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
111995c635efSGarrett D'Amore 	p->offset = p->rmargin;
112095c635efSGarrett D'Amore 	p->rmargin = p->maxrmargin - term_strlen(p, title);
112195c635efSGarrett D'Amore 	if (p->offset + datelen >= p->rmargin)
112295c635efSGarrett D'Amore 		p->rmargin = p->offset + datelen;
112395c635efSGarrett D'Amore 
112495c635efSGarrett D'Amore 	term_word(p, meta->date);
112595c635efSGarrett D'Amore 	term_flushln(p);
112695c635efSGarrett D'Amore 
112795c635efSGarrett D'Amore 	/* Bottom right corner: manual title and section. */
112895c635efSGarrett D'Amore 
112995c635efSGarrett D'Amore 	p->flags &= ~TERMP_NOBREAK;
113095c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
1131*698f87a4SGarrett D'Amore 	p->trailspace = 0;
113295c635efSGarrett D'Amore 	p->offset = p->rmargin;
113395c635efSGarrett D'Amore 	p->rmargin = p->maxrmargin;
113495c635efSGarrett D'Amore 
113595c635efSGarrett D'Amore 	term_word(p, title);
113695c635efSGarrett D'Amore 	term_flushln(p);
113795c635efSGarrett D'Amore }
113895c635efSGarrett D'Amore 
113995c635efSGarrett D'Amore 
114095c635efSGarrett D'Amore static void
114195c635efSGarrett D'Amore print_man_head(struct termp *p, const void *arg)
114295c635efSGarrett D'Amore {
114395c635efSGarrett D'Amore 	char		buf[BUFSIZ], title[BUFSIZ];
114495c635efSGarrett D'Amore 	size_t		buflen, titlen;
1145*698f87a4SGarrett D'Amore 	const struct man_meta *meta;
114695c635efSGarrett D'Amore 
1147*698f87a4SGarrett D'Amore 	meta = (const struct man_meta *)arg;
1148*698f87a4SGarrett D'Amore 	assert(meta->title);
1149*698f87a4SGarrett D'Amore 	assert(meta->msec);
115095c635efSGarrett D'Amore 
1151*698f87a4SGarrett D'Amore 	if (meta->vol)
1152*698f87a4SGarrett D'Amore 		strlcpy(buf, meta->vol, BUFSIZ);
115395c635efSGarrett D'Amore 	else
115495c635efSGarrett D'Amore 		buf[0] = '\0';
115595c635efSGarrett D'Amore 	buflen = term_strlen(p, buf);
115695c635efSGarrett D'Amore 
115795c635efSGarrett D'Amore 	/* Top left corner: manual title and section. */
115895c635efSGarrett D'Amore 
1159*698f87a4SGarrett D'Amore 	snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec);
116095c635efSGarrett D'Amore 	titlen = term_strlen(p, title);
116195c635efSGarrett D'Amore 
116295c635efSGarrett D'Amore 	p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
1163*698f87a4SGarrett D'Amore 	p->trailspace = 1;
116495c635efSGarrett D'Amore 	p->offset = 0;
116595c635efSGarrett D'Amore 	p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
116695c635efSGarrett D'Amore 	    (p->maxrmargin -
116795c635efSGarrett D'Amore 	     term_strlen(p, buf) + term_len(p, 1)) / 2 :
116895c635efSGarrett D'Amore 	    p->maxrmargin - buflen;
116995c635efSGarrett D'Amore 
117095c635efSGarrett D'Amore 	term_word(p, title);
117195c635efSGarrett D'Amore 	term_flushln(p);
117295c635efSGarrett D'Amore 
117395c635efSGarrett D'Amore 	/* At the top in the middle: manual volume. */
117495c635efSGarrett D'Amore 
117595c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
117695c635efSGarrett D'Amore 	p->offset = p->rmargin;
117795c635efSGarrett D'Amore 	p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
117895c635efSGarrett D'Amore 	    p->maxrmargin - titlen : p->maxrmargin;
117995c635efSGarrett D'Amore 
118095c635efSGarrett D'Amore 	term_word(p, buf);
118195c635efSGarrett D'Amore 	term_flushln(p);
118295c635efSGarrett D'Amore 
118395c635efSGarrett D'Amore 	/* Top right corner: title and section, again. */
118495c635efSGarrett D'Amore 
118595c635efSGarrett D'Amore 	p->flags &= ~TERMP_NOBREAK;
1186*698f87a4SGarrett D'Amore 	p->trailspace = 0;
118795c635efSGarrett D'Amore 	if (p->rmargin + titlen <= p->maxrmargin) {
118895c635efSGarrett D'Amore 		p->flags |= TERMP_NOSPACE;
118995c635efSGarrett D'Amore 		p->offset = p->rmargin;
119095c635efSGarrett D'Amore 		p->rmargin = p->maxrmargin;
119195c635efSGarrett D'Amore 		term_word(p, title);
119295c635efSGarrett D'Amore 		term_flushln(p);
119395c635efSGarrett D'Amore 	}
119495c635efSGarrett D'Amore 
119595c635efSGarrett D'Amore 	p->flags &= ~TERMP_NOSPACE;
119695c635efSGarrett D'Amore 	p->offset = 0;
119795c635efSGarrett D'Amore 	p->rmargin = p->maxrmargin;
119895c635efSGarrett D'Amore 
119995c635efSGarrett D'Amore 	/*
120095c635efSGarrett D'Amore 	 * Groff prints three blank lines before the content.
120195c635efSGarrett D'Amore 	 * Do the same, except in the temporary, undocumented
120295c635efSGarrett D'Amore 	 * mode imitating mdoc(7) output.
120395c635efSGarrett D'Amore 	 */
120495c635efSGarrett D'Amore 
120595c635efSGarrett D'Amore 	term_vspace(p);
120695c635efSGarrett D'Amore 	if ( ! p->mdocstyle) {
120795c635efSGarrett D'Amore 		term_vspace(p);
120895c635efSGarrett D'Amore 		term_vspace(p);
120995c635efSGarrett D'Amore 	}
121095c635efSGarrett D'Amore }
1211