xref: /freebsd/contrib/mandoc/man_term.c (revision 61d06d6bd19dafe8ea971dd43e8328fa1b473456)
1*61d06d6bSBaptiste Daroussin /*	$Id: man_term.c,v 1.211 2018/06/10 15:12:35 schwarze Exp $ */
2*61d06d6bSBaptiste Daroussin /*
3*61d06d6bSBaptiste Daroussin  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
4*61d06d6bSBaptiste Daroussin  * Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
5*61d06d6bSBaptiste Daroussin  *
6*61d06d6bSBaptiste Daroussin  * Permission to use, copy, modify, and distribute this software for any
7*61d06d6bSBaptiste Daroussin  * purpose with or without fee is hereby granted, provided that the above
8*61d06d6bSBaptiste Daroussin  * copyright notice and this permission notice appear in all copies.
9*61d06d6bSBaptiste Daroussin  *
10*61d06d6bSBaptiste Daroussin  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
11*61d06d6bSBaptiste Daroussin  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*61d06d6bSBaptiste Daroussin  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
13*61d06d6bSBaptiste Daroussin  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*61d06d6bSBaptiste Daroussin  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*61d06d6bSBaptiste Daroussin  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*61d06d6bSBaptiste Daroussin  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*61d06d6bSBaptiste Daroussin  */
18*61d06d6bSBaptiste Daroussin #include "config.h"
19*61d06d6bSBaptiste Daroussin 
20*61d06d6bSBaptiste Daroussin #include <sys/types.h>
21*61d06d6bSBaptiste Daroussin 
22*61d06d6bSBaptiste Daroussin #include <assert.h>
23*61d06d6bSBaptiste Daroussin #include <ctype.h>
24*61d06d6bSBaptiste Daroussin #include <limits.h>
25*61d06d6bSBaptiste Daroussin #include <stdio.h>
26*61d06d6bSBaptiste Daroussin #include <stdlib.h>
27*61d06d6bSBaptiste Daroussin #include <string.h>
28*61d06d6bSBaptiste Daroussin 
29*61d06d6bSBaptiste Daroussin #include "mandoc_aux.h"
30*61d06d6bSBaptiste Daroussin #include "mandoc.h"
31*61d06d6bSBaptiste Daroussin #include "roff.h"
32*61d06d6bSBaptiste Daroussin #include "man.h"
33*61d06d6bSBaptiste Daroussin #include "out.h"
34*61d06d6bSBaptiste Daroussin #include "term.h"
35*61d06d6bSBaptiste Daroussin #include "main.h"
36*61d06d6bSBaptiste Daroussin 
37*61d06d6bSBaptiste Daroussin #define	MAXMARGINS	  64 /* maximum number of indented scopes */
38*61d06d6bSBaptiste Daroussin 
39*61d06d6bSBaptiste Daroussin struct	mtermp {
40*61d06d6bSBaptiste Daroussin 	int		  fl;
41*61d06d6bSBaptiste Daroussin #define	MANT_LITERAL	 (1 << 0)
42*61d06d6bSBaptiste Daroussin 	int		  lmargin[MAXMARGINS]; /* margins (incl. vis. page) */
43*61d06d6bSBaptiste Daroussin 	int		  lmargincur; /* index of current margin */
44*61d06d6bSBaptiste Daroussin 	int		  lmarginsz; /* actual number of nested margins */
45*61d06d6bSBaptiste Daroussin 	size_t		  offset; /* default offset to visible page */
46*61d06d6bSBaptiste Daroussin 	int		  pardist; /* vert. space before par., unit: [v] */
47*61d06d6bSBaptiste Daroussin };
48*61d06d6bSBaptiste Daroussin 
49*61d06d6bSBaptiste Daroussin #define	DECL_ARGS	  struct termp *p, \
50*61d06d6bSBaptiste Daroussin 			  struct mtermp *mt, \
51*61d06d6bSBaptiste Daroussin 			  struct roff_node *n, \
52*61d06d6bSBaptiste Daroussin 			  const struct roff_meta *meta
53*61d06d6bSBaptiste Daroussin 
54*61d06d6bSBaptiste Daroussin struct	termact {
55*61d06d6bSBaptiste Daroussin 	int		(*pre)(DECL_ARGS);
56*61d06d6bSBaptiste Daroussin 	void		(*post)(DECL_ARGS);
57*61d06d6bSBaptiste Daroussin 	int		  flags;
58*61d06d6bSBaptiste Daroussin #define	MAN_NOTEXT	 (1 << 0) /* Never has text children. */
59*61d06d6bSBaptiste Daroussin };
60*61d06d6bSBaptiste Daroussin 
61*61d06d6bSBaptiste Daroussin static	void		  print_man_nodelist(DECL_ARGS);
62*61d06d6bSBaptiste Daroussin static	void		  print_man_node(DECL_ARGS);
63*61d06d6bSBaptiste Daroussin static	void		  print_man_head(struct termp *,
64*61d06d6bSBaptiste Daroussin 				const struct roff_meta *);
65*61d06d6bSBaptiste Daroussin static	void		  print_man_foot(struct termp *,
66*61d06d6bSBaptiste Daroussin 				const struct roff_meta *);
67*61d06d6bSBaptiste Daroussin static	void		  print_bvspace(struct termp *,
68*61d06d6bSBaptiste Daroussin 				const struct roff_node *, int);
69*61d06d6bSBaptiste Daroussin 
70*61d06d6bSBaptiste Daroussin static	int		  pre_B(DECL_ARGS);
71*61d06d6bSBaptiste Daroussin static	int		  pre_DT(DECL_ARGS);
72*61d06d6bSBaptiste Daroussin static	int		  pre_HP(DECL_ARGS);
73*61d06d6bSBaptiste Daroussin static	int		  pre_I(DECL_ARGS);
74*61d06d6bSBaptiste Daroussin static	int		  pre_IP(DECL_ARGS);
75*61d06d6bSBaptiste Daroussin static	int		  pre_OP(DECL_ARGS);
76*61d06d6bSBaptiste Daroussin static	int		  pre_PD(DECL_ARGS);
77*61d06d6bSBaptiste Daroussin static	int		  pre_PP(DECL_ARGS);
78*61d06d6bSBaptiste Daroussin static	int		  pre_RS(DECL_ARGS);
79*61d06d6bSBaptiste Daroussin static	int		  pre_SH(DECL_ARGS);
80*61d06d6bSBaptiste Daroussin static	int		  pre_SS(DECL_ARGS);
81*61d06d6bSBaptiste Daroussin static	int		  pre_TP(DECL_ARGS);
82*61d06d6bSBaptiste Daroussin static	int		  pre_UR(DECL_ARGS);
83*61d06d6bSBaptiste Daroussin static	int		  pre_alternate(DECL_ARGS);
84*61d06d6bSBaptiste Daroussin static	int		  pre_ign(DECL_ARGS);
85*61d06d6bSBaptiste Daroussin static	int		  pre_in(DECL_ARGS);
86*61d06d6bSBaptiste Daroussin static	int		  pre_literal(DECL_ARGS);
87*61d06d6bSBaptiste Daroussin 
88*61d06d6bSBaptiste Daroussin static	void		  post_IP(DECL_ARGS);
89*61d06d6bSBaptiste Daroussin static	void		  post_HP(DECL_ARGS);
90*61d06d6bSBaptiste Daroussin static	void		  post_RS(DECL_ARGS);
91*61d06d6bSBaptiste Daroussin static	void		  post_SH(DECL_ARGS);
92*61d06d6bSBaptiste Daroussin static	void		  post_SS(DECL_ARGS);
93*61d06d6bSBaptiste Daroussin static	void		  post_TP(DECL_ARGS);
94*61d06d6bSBaptiste Daroussin static	void		  post_UR(DECL_ARGS);
95*61d06d6bSBaptiste Daroussin 
96*61d06d6bSBaptiste Daroussin static	const struct termact __termacts[MAN_MAX - MAN_TH] = {
97*61d06d6bSBaptiste Daroussin 	{ NULL, NULL, 0 }, /* TH */
98*61d06d6bSBaptiste Daroussin 	{ pre_SH, post_SH, 0 }, /* SH */
99*61d06d6bSBaptiste Daroussin 	{ pre_SS, post_SS, 0 }, /* SS */
100*61d06d6bSBaptiste Daroussin 	{ pre_TP, post_TP, 0 }, /* TP */
101*61d06d6bSBaptiste Daroussin 	{ pre_PP, NULL, 0 }, /* LP */
102*61d06d6bSBaptiste Daroussin 	{ pre_PP, NULL, 0 }, /* PP */
103*61d06d6bSBaptiste Daroussin 	{ pre_PP, NULL, 0 }, /* P */
104*61d06d6bSBaptiste Daroussin 	{ pre_IP, post_IP, 0 }, /* IP */
105*61d06d6bSBaptiste Daroussin 	{ pre_HP, post_HP, 0 }, /* HP */
106*61d06d6bSBaptiste Daroussin 	{ NULL, NULL, 0 }, /* SM */
107*61d06d6bSBaptiste Daroussin 	{ pre_B, NULL, 0 }, /* SB */
108*61d06d6bSBaptiste Daroussin 	{ pre_alternate, NULL, 0 }, /* BI */
109*61d06d6bSBaptiste Daroussin 	{ pre_alternate, NULL, 0 }, /* IB */
110*61d06d6bSBaptiste Daroussin 	{ pre_alternate, NULL, 0 }, /* BR */
111*61d06d6bSBaptiste Daroussin 	{ pre_alternate, NULL, 0 }, /* RB */
112*61d06d6bSBaptiste Daroussin 	{ NULL, NULL, 0 }, /* R */
113*61d06d6bSBaptiste Daroussin 	{ pre_B, NULL, 0 }, /* B */
114*61d06d6bSBaptiste Daroussin 	{ pre_I, NULL, 0 }, /* I */
115*61d06d6bSBaptiste Daroussin 	{ pre_alternate, NULL, 0 }, /* IR */
116*61d06d6bSBaptiste Daroussin 	{ pre_alternate, NULL, 0 }, /* RI */
117*61d06d6bSBaptiste Daroussin 	{ pre_literal, NULL, 0 }, /* nf */
118*61d06d6bSBaptiste Daroussin 	{ pre_literal, NULL, 0 }, /* fi */
119*61d06d6bSBaptiste Daroussin 	{ NULL, NULL, 0 }, /* RE */
120*61d06d6bSBaptiste Daroussin 	{ pre_RS, post_RS, 0 }, /* RS */
121*61d06d6bSBaptiste Daroussin 	{ pre_DT, NULL, 0 }, /* DT */
122*61d06d6bSBaptiste Daroussin 	{ pre_ign, NULL, MAN_NOTEXT }, /* UC */
123*61d06d6bSBaptiste Daroussin 	{ pre_PD, NULL, MAN_NOTEXT }, /* PD */
124*61d06d6bSBaptiste Daroussin 	{ pre_ign, NULL, 0 }, /* AT */
125*61d06d6bSBaptiste Daroussin 	{ pre_in, NULL, MAN_NOTEXT }, /* in */
126*61d06d6bSBaptiste Daroussin 	{ pre_OP, NULL, 0 }, /* OP */
127*61d06d6bSBaptiste Daroussin 	{ pre_literal, NULL, 0 }, /* EX */
128*61d06d6bSBaptiste Daroussin 	{ pre_literal, NULL, 0 }, /* EE */
129*61d06d6bSBaptiste Daroussin 	{ pre_UR, post_UR, 0 }, /* UR */
130*61d06d6bSBaptiste Daroussin 	{ NULL, NULL, 0 }, /* UE */
131*61d06d6bSBaptiste Daroussin 	{ pre_UR, post_UR, 0 }, /* MT */
132*61d06d6bSBaptiste Daroussin 	{ NULL, NULL, 0 }, /* ME */
133*61d06d6bSBaptiste Daroussin };
134*61d06d6bSBaptiste Daroussin static	const struct termact *termacts = __termacts - MAN_TH;
135*61d06d6bSBaptiste Daroussin 
136*61d06d6bSBaptiste Daroussin 
137*61d06d6bSBaptiste Daroussin void
138*61d06d6bSBaptiste Daroussin terminal_man(void *arg, const struct roff_man *man)
139*61d06d6bSBaptiste Daroussin {
140*61d06d6bSBaptiste Daroussin 	struct termp		*p;
141*61d06d6bSBaptiste Daroussin 	struct roff_node	*n;
142*61d06d6bSBaptiste Daroussin 	struct mtermp		 mt;
143*61d06d6bSBaptiste Daroussin 	size_t			 save_defindent;
144*61d06d6bSBaptiste Daroussin 
145*61d06d6bSBaptiste Daroussin 	p = (struct termp *)arg;
146*61d06d6bSBaptiste Daroussin 	save_defindent = p->defindent;
147*61d06d6bSBaptiste Daroussin 	if (p->synopsisonly == 0 && p->defindent == 0)
148*61d06d6bSBaptiste Daroussin 		p->defindent = 7;
149*61d06d6bSBaptiste Daroussin 	p->tcol->rmargin = p->maxrmargin = p->defrmargin;
150*61d06d6bSBaptiste Daroussin 	term_tab_set(p, NULL);
151*61d06d6bSBaptiste Daroussin 	term_tab_set(p, "T");
152*61d06d6bSBaptiste Daroussin 	term_tab_set(p, ".5i");
153*61d06d6bSBaptiste Daroussin 
154*61d06d6bSBaptiste Daroussin 	memset(&mt, 0, sizeof(struct mtermp));
155*61d06d6bSBaptiste Daroussin 	mt.lmargin[mt.lmargincur] = term_len(p, p->defindent);
156*61d06d6bSBaptiste Daroussin 	mt.offset = term_len(p, p->defindent);
157*61d06d6bSBaptiste Daroussin 	mt.pardist = 1;
158*61d06d6bSBaptiste Daroussin 
159*61d06d6bSBaptiste Daroussin 	n = man->first->child;
160*61d06d6bSBaptiste Daroussin 	if (p->synopsisonly) {
161*61d06d6bSBaptiste Daroussin 		while (n != NULL) {
162*61d06d6bSBaptiste Daroussin 			if (n->tok == MAN_SH &&
163*61d06d6bSBaptiste Daroussin 			    n->child->child->type == ROFFT_TEXT &&
164*61d06d6bSBaptiste Daroussin 			    !strcmp(n->child->child->string, "SYNOPSIS")) {
165*61d06d6bSBaptiste Daroussin 				if (n->child->next->child != NULL)
166*61d06d6bSBaptiste Daroussin 					print_man_nodelist(p, &mt,
167*61d06d6bSBaptiste Daroussin 					    n->child->next->child,
168*61d06d6bSBaptiste Daroussin 					    &man->meta);
169*61d06d6bSBaptiste Daroussin 				term_newln(p);
170*61d06d6bSBaptiste Daroussin 				break;
171*61d06d6bSBaptiste Daroussin 			}
172*61d06d6bSBaptiste Daroussin 			n = n->next;
173*61d06d6bSBaptiste Daroussin 		}
174*61d06d6bSBaptiste Daroussin 	} else {
175*61d06d6bSBaptiste Daroussin 		term_begin(p, print_man_head, print_man_foot, &man->meta);
176*61d06d6bSBaptiste Daroussin 		p->flags |= TERMP_NOSPACE;
177*61d06d6bSBaptiste Daroussin 		if (n != NULL)
178*61d06d6bSBaptiste Daroussin 			print_man_nodelist(p, &mt, n, &man->meta);
179*61d06d6bSBaptiste Daroussin 		term_end(p);
180*61d06d6bSBaptiste Daroussin 	}
181*61d06d6bSBaptiste Daroussin 	p->defindent = save_defindent;
182*61d06d6bSBaptiste Daroussin }
183*61d06d6bSBaptiste Daroussin 
184*61d06d6bSBaptiste Daroussin /*
185*61d06d6bSBaptiste Daroussin  * Printing leading vertical space before a block.
186*61d06d6bSBaptiste Daroussin  * This is used for the paragraph macros.
187*61d06d6bSBaptiste Daroussin  * The rules are pretty simple, since there's very little nesting going
188*61d06d6bSBaptiste Daroussin  * on here.  Basically, if we're the first within another block (SS/SH),
189*61d06d6bSBaptiste Daroussin  * then don't emit vertical space.  If we are (RS), then do.  If not the
190*61d06d6bSBaptiste Daroussin  * first, print it.
191*61d06d6bSBaptiste Daroussin  */
192*61d06d6bSBaptiste Daroussin static void
193*61d06d6bSBaptiste Daroussin print_bvspace(struct termp *p, const struct roff_node *n, int pardist)
194*61d06d6bSBaptiste Daroussin {
195*61d06d6bSBaptiste Daroussin 	int	 i;
196*61d06d6bSBaptiste Daroussin 
197*61d06d6bSBaptiste Daroussin 	term_newln(p);
198*61d06d6bSBaptiste Daroussin 
199*61d06d6bSBaptiste Daroussin 	if (n->body && n->body->child)
200*61d06d6bSBaptiste Daroussin 		if (n->body->child->type == ROFFT_TBL)
201*61d06d6bSBaptiste Daroussin 			return;
202*61d06d6bSBaptiste Daroussin 
203*61d06d6bSBaptiste Daroussin 	if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS)
204*61d06d6bSBaptiste Daroussin 		if (NULL == n->prev)
205*61d06d6bSBaptiste Daroussin 			return;
206*61d06d6bSBaptiste Daroussin 
207*61d06d6bSBaptiste Daroussin 	for (i = 0; i < pardist; i++)
208*61d06d6bSBaptiste Daroussin 		term_vspace(p);
209*61d06d6bSBaptiste Daroussin }
210*61d06d6bSBaptiste Daroussin 
211*61d06d6bSBaptiste Daroussin 
212*61d06d6bSBaptiste Daroussin static int
213*61d06d6bSBaptiste Daroussin pre_ign(DECL_ARGS)
214*61d06d6bSBaptiste Daroussin {
215*61d06d6bSBaptiste Daroussin 
216*61d06d6bSBaptiste Daroussin 	return 0;
217*61d06d6bSBaptiste Daroussin }
218*61d06d6bSBaptiste Daroussin 
219*61d06d6bSBaptiste Daroussin static int
220*61d06d6bSBaptiste Daroussin pre_I(DECL_ARGS)
221*61d06d6bSBaptiste Daroussin {
222*61d06d6bSBaptiste Daroussin 
223*61d06d6bSBaptiste Daroussin 	term_fontrepl(p, TERMFONT_UNDER);
224*61d06d6bSBaptiste Daroussin 	return 1;
225*61d06d6bSBaptiste Daroussin }
226*61d06d6bSBaptiste Daroussin 
227*61d06d6bSBaptiste Daroussin static int
228*61d06d6bSBaptiste Daroussin pre_literal(DECL_ARGS)
229*61d06d6bSBaptiste Daroussin {
230*61d06d6bSBaptiste Daroussin 
231*61d06d6bSBaptiste Daroussin 	term_newln(p);
232*61d06d6bSBaptiste Daroussin 
233*61d06d6bSBaptiste Daroussin 	if (n->tok == MAN_nf || n->tok == MAN_EX)
234*61d06d6bSBaptiste Daroussin 		mt->fl |= MANT_LITERAL;
235*61d06d6bSBaptiste Daroussin 	else
236*61d06d6bSBaptiste Daroussin 		mt->fl &= ~MANT_LITERAL;
237*61d06d6bSBaptiste Daroussin 
238*61d06d6bSBaptiste Daroussin 	/*
239*61d06d6bSBaptiste Daroussin 	 * Unlike .IP and .TP, .HP does not have a HEAD.
240*61d06d6bSBaptiste Daroussin 	 * So in case a second call to term_flushln() is needed,
241*61d06d6bSBaptiste Daroussin 	 * indentation has to be set up explicitly.
242*61d06d6bSBaptiste Daroussin 	 */
243*61d06d6bSBaptiste Daroussin 	if (n->parent->tok == MAN_HP && p->tcol->rmargin < p->maxrmargin) {
244*61d06d6bSBaptiste Daroussin 		p->tcol->offset = p->tcol->rmargin;
245*61d06d6bSBaptiste Daroussin 		p->tcol->rmargin = p->maxrmargin;
246*61d06d6bSBaptiste Daroussin 		p->trailspace = 0;
247*61d06d6bSBaptiste Daroussin 		p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
248*61d06d6bSBaptiste Daroussin 		p->flags |= TERMP_NOSPACE;
249*61d06d6bSBaptiste Daroussin 	}
250*61d06d6bSBaptiste Daroussin 
251*61d06d6bSBaptiste Daroussin 	return 0;
252*61d06d6bSBaptiste Daroussin }
253*61d06d6bSBaptiste Daroussin 
254*61d06d6bSBaptiste Daroussin static int
255*61d06d6bSBaptiste Daroussin pre_PD(DECL_ARGS)
256*61d06d6bSBaptiste Daroussin {
257*61d06d6bSBaptiste Daroussin 	struct roffsu	 su;
258*61d06d6bSBaptiste Daroussin 
259*61d06d6bSBaptiste Daroussin 	n = n->child;
260*61d06d6bSBaptiste Daroussin 	if (n == NULL) {
261*61d06d6bSBaptiste Daroussin 		mt->pardist = 1;
262*61d06d6bSBaptiste Daroussin 		return 0;
263*61d06d6bSBaptiste Daroussin 	}
264*61d06d6bSBaptiste Daroussin 	assert(n->type == ROFFT_TEXT);
265*61d06d6bSBaptiste Daroussin 	if (a2roffsu(n->string, &su, SCALE_VS) != NULL)
266*61d06d6bSBaptiste Daroussin 		mt->pardist = term_vspan(p, &su);
267*61d06d6bSBaptiste Daroussin 	return 0;
268*61d06d6bSBaptiste Daroussin }
269*61d06d6bSBaptiste Daroussin 
270*61d06d6bSBaptiste Daroussin static int
271*61d06d6bSBaptiste Daroussin pre_alternate(DECL_ARGS)
272*61d06d6bSBaptiste Daroussin {
273*61d06d6bSBaptiste Daroussin 	enum termfont		 font[2];
274*61d06d6bSBaptiste Daroussin 	struct roff_node	*nn;
275*61d06d6bSBaptiste Daroussin 	int			 savelit, i;
276*61d06d6bSBaptiste Daroussin 
277*61d06d6bSBaptiste Daroussin 	switch (n->tok) {
278*61d06d6bSBaptiste Daroussin 	case MAN_RB:
279*61d06d6bSBaptiste Daroussin 		font[0] = TERMFONT_NONE;
280*61d06d6bSBaptiste Daroussin 		font[1] = TERMFONT_BOLD;
281*61d06d6bSBaptiste Daroussin 		break;
282*61d06d6bSBaptiste Daroussin 	case MAN_RI:
283*61d06d6bSBaptiste Daroussin 		font[0] = TERMFONT_NONE;
284*61d06d6bSBaptiste Daroussin 		font[1] = TERMFONT_UNDER;
285*61d06d6bSBaptiste Daroussin 		break;
286*61d06d6bSBaptiste Daroussin 	case MAN_BR:
287*61d06d6bSBaptiste Daroussin 		font[0] = TERMFONT_BOLD;
288*61d06d6bSBaptiste Daroussin 		font[1] = TERMFONT_NONE;
289*61d06d6bSBaptiste Daroussin 		break;
290*61d06d6bSBaptiste Daroussin 	case MAN_BI:
291*61d06d6bSBaptiste Daroussin 		font[0] = TERMFONT_BOLD;
292*61d06d6bSBaptiste Daroussin 		font[1] = TERMFONT_UNDER;
293*61d06d6bSBaptiste Daroussin 		break;
294*61d06d6bSBaptiste Daroussin 	case MAN_IR:
295*61d06d6bSBaptiste Daroussin 		font[0] = TERMFONT_UNDER;
296*61d06d6bSBaptiste Daroussin 		font[1] = TERMFONT_NONE;
297*61d06d6bSBaptiste Daroussin 		break;
298*61d06d6bSBaptiste Daroussin 	case MAN_IB:
299*61d06d6bSBaptiste Daroussin 		font[0] = TERMFONT_UNDER;
300*61d06d6bSBaptiste Daroussin 		font[1] = TERMFONT_BOLD;
301*61d06d6bSBaptiste Daroussin 		break;
302*61d06d6bSBaptiste Daroussin 	default:
303*61d06d6bSBaptiste Daroussin 		abort();
304*61d06d6bSBaptiste Daroussin 	}
305*61d06d6bSBaptiste Daroussin 
306*61d06d6bSBaptiste Daroussin 	savelit = MANT_LITERAL & mt->fl;
307*61d06d6bSBaptiste Daroussin 	mt->fl &= ~MANT_LITERAL;
308*61d06d6bSBaptiste Daroussin 
309*61d06d6bSBaptiste Daroussin 	for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) {
310*61d06d6bSBaptiste Daroussin 		term_fontrepl(p, font[i]);
311*61d06d6bSBaptiste Daroussin 		if (savelit && NULL == nn->next)
312*61d06d6bSBaptiste Daroussin 			mt->fl |= MANT_LITERAL;
313*61d06d6bSBaptiste Daroussin 		assert(nn->type == ROFFT_TEXT);
314*61d06d6bSBaptiste Daroussin 		term_word(p, nn->string);
315*61d06d6bSBaptiste Daroussin 		if (nn->flags & NODE_EOS)
316*61d06d6bSBaptiste Daroussin                 	p->flags |= TERMP_SENTENCE;
317*61d06d6bSBaptiste Daroussin 		if (nn->next)
318*61d06d6bSBaptiste Daroussin 			p->flags |= TERMP_NOSPACE;
319*61d06d6bSBaptiste Daroussin 	}
320*61d06d6bSBaptiste Daroussin 
321*61d06d6bSBaptiste Daroussin 	return 0;
322*61d06d6bSBaptiste Daroussin }
323*61d06d6bSBaptiste Daroussin 
324*61d06d6bSBaptiste Daroussin static int
325*61d06d6bSBaptiste Daroussin pre_B(DECL_ARGS)
326*61d06d6bSBaptiste Daroussin {
327*61d06d6bSBaptiste Daroussin 
328*61d06d6bSBaptiste Daroussin 	term_fontrepl(p, TERMFONT_BOLD);
329*61d06d6bSBaptiste Daroussin 	return 1;
330*61d06d6bSBaptiste Daroussin }
331*61d06d6bSBaptiste Daroussin 
332*61d06d6bSBaptiste Daroussin static int
333*61d06d6bSBaptiste Daroussin pre_OP(DECL_ARGS)
334*61d06d6bSBaptiste Daroussin {
335*61d06d6bSBaptiste Daroussin 
336*61d06d6bSBaptiste Daroussin 	term_word(p, "[");
337*61d06d6bSBaptiste Daroussin 	p->flags |= TERMP_NOSPACE;
338*61d06d6bSBaptiste Daroussin 
339*61d06d6bSBaptiste Daroussin 	if (NULL != (n = n->child)) {
340*61d06d6bSBaptiste Daroussin 		term_fontrepl(p, TERMFONT_BOLD);
341*61d06d6bSBaptiste Daroussin 		term_word(p, n->string);
342*61d06d6bSBaptiste Daroussin 	}
343*61d06d6bSBaptiste Daroussin 	if (NULL != n && NULL != n->next) {
344*61d06d6bSBaptiste Daroussin 		term_fontrepl(p, TERMFONT_UNDER);
345*61d06d6bSBaptiste Daroussin 		term_word(p, n->next->string);
346*61d06d6bSBaptiste Daroussin 	}
347*61d06d6bSBaptiste Daroussin 
348*61d06d6bSBaptiste Daroussin 	term_fontrepl(p, TERMFONT_NONE);
349*61d06d6bSBaptiste Daroussin 	p->flags |= TERMP_NOSPACE;
350*61d06d6bSBaptiste Daroussin 	term_word(p, "]");
351*61d06d6bSBaptiste Daroussin 	return 0;
352*61d06d6bSBaptiste Daroussin }
353*61d06d6bSBaptiste Daroussin 
354*61d06d6bSBaptiste Daroussin static int
355*61d06d6bSBaptiste Daroussin pre_in(DECL_ARGS)
356*61d06d6bSBaptiste Daroussin {
357*61d06d6bSBaptiste Daroussin 	struct roffsu	 su;
358*61d06d6bSBaptiste Daroussin 	const char	*cp;
359*61d06d6bSBaptiste Daroussin 	size_t		 v;
360*61d06d6bSBaptiste Daroussin 	int		 less;
361*61d06d6bSBaptiste Daroussin 
362*61d06d6bSBaptiste Daroussin 	term_newln(p);
363*61d06d6bSBaptiste Daroussin 
364*61d06d6bSBaptiste Daroussin 	if (n->child == NULL) {
365*61d06d6bSBaptiste Daroussin 		p->tcol->offset = mt->offset;
366*61d06d6bSBaptiste Daroussin 		return 0;
367*61d06d6bSBaptiste Daroussin 	}
368*61d06d6bSBaptiste Daroussin 
369*61d06d6bSBaptiste Daroussin 	cp = n->child->string;
370*61d06d6bSBaptiste Daroussin 	less = 0;
371*61d06d6bSBaptiste Daroussin 
372*61d06d6bSBaptiste Daroussin 	if ('-' == *cp)
373*61d06d6bSBaptiste Daroussin 		less = -1;
374*61d06d6bSBaptiste Daroussin 	else if ('+' == *cp)
375*61d06d6bSBaptiste Daroussin 		less = 1;
376*61d06d6bSBaptiste Daroussin 	else
377*61d06d6bSBaptiste Daroussin 		cp--;
378*61d06d6bSBaptiste Daroussin 
379*61d06d6bSBaptiste Daroussin 	if (a2roffsu(++cp, &su, SCALE_EN) == NULL)
380*61d06d6bSBaptiste Daroussin 		return 0;
381*61d06d6bSBaptiste Daroussin 
382*61d06d6bSBaptiste Daroussin 	v = term_hen(p, &su);
383*61d06d6bSBaptiste Daroussin 
384*61d06d6bSBaptiste Daroussin 	if (less < 0)
385*61d06d6bSBaptiste Daroussin 		p->tcol->offset -= p->tcol->offset > v ? v : p->tcol->offset;
386*61d06d6bSBaptiste Daroussin 	else if (less > 0)
387*61d06d6bSBaptiste Daroussin 		p->tcol->offset += v;
388*61d06d6bSBaptiste Daroussin 	else
389*61d06d6bSBaptiste Daroussin 		p->tcol->offset = v;
390*61d06d6bSBaptiste Daroussin 	if (p->tcol->offset > SHRT_MAX)
391*61d06d6bSBaptiste Daroussin 		p->tcol->offset = term_len(p, p->defindent);
392*61d06d6bSBaptiste Daroussin 
393*61d06d6bSBaptiste Daroussin 	return 0;
394*61d06d6bSBaptiste Daroussin }
395*61d06d6bSBaptiste Daroussin 
396*61d06d6bSBaptiste Daroussin static int
397*61d06d6bSBaptiste Daroussin pre_DT(DECL_ARGS)
398*61d06d6bSBaptiste Daroussin {
399*61d06d6bSBaptiste Daroussin 	term_tab_set(p, NULL);
400*61d06d6bSBaptiste Daroussin 	term_tab_set(p, "T");
401*61d06d6bSBaptiste Daroussin 	term_tab_set(p, ".5i");
402*61d06d6bSBaptiste Daroussin 	return 0;
403*61d06d6bSBaptiste Daroussin }
404*61d06d6bSBaptiste Daroussin 
405*61d06d6bSBaptiste Daroussin static int
406*61d06d6bSBaptiste Daroussin pre_HP(DECL_ARGS)
407*61d06d6bSBaptiste Daroussin {
408*61d06d6bSBaptiste Daroussin 	struct roffsu		 su;
409*61d06d6bSBaptiste Daroussin 	const struct roff_node	*nn;
410*61d06d6bSBaptiste Daroussin 	int			 len;
411*61d06d6bSBaptiste Daroussin 
412*61d06d6bSBaptiste Daroussin 	switch (n->type) {
413*61d06d6bSBaptiste Daroussin 	case ROFFT_BLOCK:
414*61d06d6bSBaptiste Daroussin 		print_bvspace(p, n, mt->pardist);
415*61d06d6bSBaptiste Daroussin 		return 1;
416*61d06d6bSBaptiste Daroussin 	case ROFFT_BODY:
417*61d06d6bSBaptiste Daroussin 		break;
418*61d06d6bSBaptiste Daroussin 	default:
419*61d06d6bSBaptiste Daroussin 		return 0;
420*61d06d6bSBaptiste Daroussin 	}
421*61d06d6bSBaptiste Daroussin 
422*61d06d6bSBaptiste Daroussin 	if ( ! (MANT_LITERAL & mt->fl)) {
423*61d06d6bSBaptiste Daroussin 		p->flags |= TERMP_NOBREAK | TERMP_BRIND;
424*61d06d6bSBaptiste Daroussin 		p->trailspace = 2;
425*61d06d6bSBaptiste Daroussin 	}
426*61d06d6bSBaptiste Daroussin 
427*61d06d6bSBaptiste Daroussin 	/* Calculate offset. */
428*61d06d6bSBaptiste Daroussin 
429*61d06d6bSBaptiste Daroussin 	if ((nn = n->parent->head->child) != NULL &&
430*61d06d6bSBaptiste Daroussin 	    a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
431*61d06d6bSBaptiste Daroussin 		len = term_hen(p, &su);
432*61d06d6bSBaptiste Daroussin 		if (len < 0 && (size_t)(-len) > mt->offset)
433*61d06d6bSBaptiste Daroussin 			len = -mt->offset;
434*61d06d6bSBaptiste Daroussin 		else if (len > SHRT_MAX)
435*61d06d6bSBaptiste Daroussin 			len = term_len(p, p->defindent);
436*61d06d6bSBaptiste Daroussin 		mt->lmargin[mt->lmargincur] = len;
437*61d06d6bSBaptiste Daroussin 	} else
438*61d06d6bSBaptiste Daroussin 		len = mt->lmargin[mt->lmargincur];
439*61d06d6bSBaptiste Daroussin 
440*61d06d6bSBaptiste Daroussin 	p->tcol->offset = mt->offset;
441*61d06d6bSBaptiste Daroussin 	p->tcol->rmargin = mt->offset + len;
442*61d06d6bSBaptiste Daroussin 	return 1;
443*61d06d6bSBaptiste Daroussin }
444*61d06d6bSBaptiste Daroussin 
445*61d06d6bSBaptiste Daroussin static void
446*61d06d6bSBaptiste Daroussin post_HP(DECL_ARGS)
447*61d06d6bSBaptiste Daroussin {
448*61d06d6bSBaptiste Daroussin 
449*61d06d6bSBaptiste Daroussin 	switch (n->type) {
450*61d06d6bSBaptiste Daroussin 	case ROFFT_BODY:
451*61d06d6bSBaptiste Daroussin 		term_newln(p);
452*61d06d6bSBaptiste Daroussin 
453*61d06d6bSBaptiste Daroussin 		/*
454*61d06d6bSBaptiste Daroussin 		 * Compatibility with a groff bug.
455*61d06d6bSBaptiste Daroussin 		 * The .HP macro uses the undocumented .tag request
456*61d06d6bSBaptiste Daroussin 		 * which causes a line break and cancels no-space
457*61d06d6bSBaptiste Daroussin 		 * mode even if there isn't any output.
458*61d06d6bSBaptiste Daroussin 		 */
459*61d06d6bSBaptiste Daroussin 
460*61d06d6bSBaptiste Daroussin 		if (n->child == NULL)
461*61d06d6bSBaptiste Daroussin 			term_vspace(p);
462*61d06d6bSBaptiste Daroussin 
463*61d06d6bSBaptiste Daroussin 		p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
464*61d06d6bSBaptiste Daroussin 		p->trailspace = 0;
465*61d06d6bSBaptiste Daroussin 		p->tcol->offset = mt->offset;
466*61d06d6bSBaptiste Daroussin 		p->tcol->rmargin = p->maxrmargin;
467*61d06d6bSBaptiste Daroussin 		break;
468*61d06d6bSBaptiste Daroussin 	default:
469*61d06d6bSBaptiste Daroussin 		break;
470*61d06d6bSBaptiste Daroussin 	}
471*61d06d6bSBaptiste Daroussin }
472*61d06d6bSBaptiste Daroussin 
473*61d06d6bSBaptiste Daroussin static int
474*61d06d6bSBaptiste Daroussin pre_PP(DECL_ARGS)
475*61d06d6bSBaptiste Daroussin {
476*61d06d6bSBaptiste Daroussin 
477*61d06d6bSBaptiste Daroussin 	switch (n->type) {
478*61d06d6bSBaptiste Daroussin 	case ROFFT_BLOCK:
479*61d06d6bSBaptiste Daroussin 		mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
480*61d06d6bSBaptiste Daroussin 		print_bvspace(p, n, mt->pardist);
481*61d06d6bSBaptiste Daroussin 		break;
482*61d06d6bSBaptiste Daroussin 	default:
483*61d06d6bSBaptiste Daroussin 		p->tcol->offset = mt->offset;
484*61d06d6bSBaptiste Daroussin 		break;
485*61d06d6bSBaptiste Daroussin 	}
486*61d06d6bSBaptiste Daroussin 
487*61d06d6bSBaptiste Daroussin 	return n->type != ROFFT_HEAD;
488*61d06d6bSBaptiste Daroussin }
489*61d06d6bSBaptiste Daroussin 
490*61d06d6bSBaptiste Daroussin static int
491*61d06d6bSBaptiste Daroussin pre_IP(DECL_ARGS)
492*61d06d6bSBaptiste Daroussin {
493*61d06d6bSBaptiste Daroussin 	struct roffsu		 su;
494*61d06d6bSBaptiste Daroussin 	const struct roff_node	*nn;
495*61d06d6bSBaptiste Daroussin 	int			 len, savelit;
496*61d06d6bSBaptiste Daroussin 
497*61d06d6bSBaptiste Daroussin 	switch (n->type) {
498*61d06d6bSBaptiste Daroussin 	case ROFFT_BODY:
499*61d06d6bSBaptiste Daroussin 		p->flags |= TERMP_NOSPACE;
500*61d06d6bSBaptiste Daroussin 		break;
501*61d06d6bSBaptiste Daroussin 	case ROFFT_HEAD:
502*61d06d6bSBaptiste Daroussin 		p->flags |= TERMP_NOBREAK;
503*61d06d6bSBaptiste Daroussin 		p->trailspace = 1;
504*61d06d6bSBaptiste Daroussin 		break;
505*61d06d6bSBaptiste Daroussin 	case ROFFT_BLOCK:
506*61d06d6bSBaptiste Daroussin 		print_bvspace(p, n, mt->pardist);
507*61d06d6bSBaptiste Daroussin 		/* FALLTHROUGH */
508*61d06d6bSBaptiste Daroussin 	default:
509*61d06d6bSBaptiste Daroussin 		return 1;
510*61d06d6bSBaptiste Daroussin 	}
511*61d06d6bSBaptiste Daroussin 
512*61d06d6bSBaptiste Daroussin 	/* Calculate the offset from the optional second argument. */
513*61d06d6bSBaptiste Daroussin 	if ((nn = n->parent->head->child) != NULL &&
514*61d06d6bSBaptiste Daroussin 	    (nn = nn->next) != NULL &&
515*61d06d6bSBaptiste Daroussin 	    a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
516*61d06d6bSBaptiste Daroussin 		len = term_hen(p, &su);
517*61d06d6bSBaptiste Daroussin 		if (len < 0 && (size_t)(-len) > mt->offset)
518*61d06d6bSBaptiste Daroussin 			len = -mt->offset;
519*61d06d6bSBaptiste Daroussin 		else if (len > SHRT_MAX)
520*61d06d6bSBaptiste Daroussin 			len = term_len(p, p->defindent);
521*61d06d6bSBaptiste Daroussin 		mt->lmargin[mt->lmargincur] = len;
522*61d06d6bSBaptiste Daroussin 	} else
523*61d06d6bSBaptiste Daroussin 		len = mt->lmargin[mt->lmargincur];
524*61d06d6bSBaptiste Daroussin 
525*61d06d6bSBaptiste Daroussin 	switch (n->type) {
526*61d06d6bSBaptiste Daroussin 	case ROFFT_HEAD:
527*61d06d6bSBaptiste Daroussin 		p->tcol->offset = mt->offset;
528*61d06d6bSBaptiste Daroussin 		p->tcol->rmargin = mt->offset + len;
529*61d06d6bSBaptiste Daroussin 
530*61d06d6bSBaptiste Daroussin 		savelit = MANT_LITERAL & mt->fl;
531*61d06d6bSBaptiste Daroussin 		mt->fl &= ~MANT_LITERAL;
532*61d06d6bSBaptiste Daroussin 
533*61d06d6bSBaptiste Daroussin 		if (n->child)
534*61d06d6bSBaptiste Daroussin 			print_man_node(p, mt, n->child, meta);
535*61d06d6bSBaptiste Daroussin 
536*61d06d6bSBaptiste Daroussin 		if (savelit)
537*61d06d6bSBaptiste Daroussin 			mt->fl |= MANT_LITERAL;
538*61d06d6bSBaptiste Daroussin 
539*61d06d6bSBaptiste Daroussin 		return 0;
540*61d06d6bSBaptiste Daroussin 	case ROFFT_BODY:
541*61d06d6bSBaptiste Daroussin 		p->tcol->offset = mt->offset + len;
542*61d06d6bSBaptiste Daroussin 		p->tcol->rmargin = p->maxrmargin;
543*61d06d6bSBaptiste Daroussin 		break;
544*61d06d6bSBaptiste Daroussin 	default:
545*61d06d6bSBaptiste Daroussin 		break;
546*61d06d6bSBaptiste Daroussin 	}
547*61d06d6bSBaptiste Daroussin 
548*61d06d6bSBaptiste Daroussin 	return 1;
549*61d06d6bSBaptiste Daroussin }
550*61d06d6bSBaptiste Daroussin 
551*61d06d6bSBaptiste Daroussin static void
552*61d06d6bSBaptiste Daroussin post_IP(DECL_ARGS)
553*61d06d6bSBaptiste Daroussin {
554*61d06d6bSBaptiste Daroussin 
555*61d06d6bSBaptiste Daroussin 	switch (n->type) {
556*61d06d6bSBaptiste Daroussin 	case ROFFT_HEAD:
557*61d06d6bSBaptiste Daroussin 		term_flushln(p);
558*61d06d6bSBaptiste Daroussin 		p->flags &= ~TERMP_NOBREAK;
559*61d06d6bSBaptiste Daroussin 		p->trailspace = 0;
560*61d06d6bSBaptiste Daroussin 		p->tcol->rmargin = p->maxrmargin;
561*61d06d6bSBaptiste Daroussin 		break;
562*61d06d6bSBaptiste Daroussin 	case ROFFT_BODY:
563*61d06d6bSBaptiste Daroussin 		term_newln(p);
564*61d06d6bSBaptiste Daroussin 		p->tcol->offset = mt->offset;
565*61d06d6bSBaptiste Daroussin 		break;
566*61d06d6bSBaptiste Daroussin 	default:
567*61d06d6bSBaptiste Daroussin 		break;
568*61d06d6bSBaptiste Daroussin 	}
569*61d06d6bSBaptiste Daroussin }
570*61d06d6bSBaptiste Daroussin 
571*61d06d6bSBaptiste Daroussin static int
572*61d06d6bSBaptiste Daroussin pre_TP(DECL_ARGS)
573*61d06d6bSBaptiste Daroussin {
574*61d06d6bSBaptiste Daroussin 	struct roffsu		 su;
575*61d06d6bSBaptiste Daroussin 	struct roff_node	*nn;
576*61d06d6bSBaptiste Daroussin 	int			 len, savelit;
577*61d06d6bSBaptiste Daroussin 
578*61d06d6bSBaptiste Daroussin 	switch (n->type) {
579*61d06d6bSBaptiste Daroussin 	case ROFFT_HEAD:
580*61d06d6bSBaptiste Daroussin 		p->flags |= TERMP_NOBREAK | TERMP_BRTRSP;
581*61d06d6bSBaptiste Daroussin 		p->trailspace = 1;
582*61d06d6bSBaptiste Daroussin 		break;
583*61d06d6bSBaptiste Daroussin 	case ROFFT_BODY:
584*61d06d6bSBaptiste Daroussin 		p->flags |= TERMP_NOSPACE;
585*61d06d6bSBaptiste Daroussin 		break;
586*61d06d6bSBaptiste Daroussin 	case ROFFT_BLOCK:
587*61d06d6bSBaptiste Daroussin 		print_bvspace(p, n, mt->pardist);
588*61d06d6bSBaptiste Daroussin 		/* FALLTHROUGH */
589*61d06d6bSBaptiste Daroussin 	default:
590*61d06d6bSBaptiste Daroussin 		return 1;
591*61d06d6bSBaptiste Daroussin 	}
592*61d06d6bSBaptiste Daroussin 
593*61d06d6bSBaptiste Daroussin 	/* Calculate offset. */
594*61d06d6bSBaptiste Daroussin 
595*61d06d6bSBaptiste Daroussin 	if ((nn = n->parent->head->child) != NULL &&
596*61d06d6bSBaptiste Daroussin 	    nn->string != NULL && ! (NODE_LINE & nn->flags) &&
597*61d06d6bSBaptiste Daroussin 	    a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
598*61d06d6bSBaptiste Daroussin 		len = term_hen(p, &su);
599*61d06d6bSBaptiste Daroussin 		if (len < 0 && (size_t)(-len) > mt->offset)
600*61d06d6bSBaptiste Daroussin 			len = -mt->offset;
601*61d06d6bSBaptiste Daroussin 		else if (len > SHRT_MAX)
602*61d06d6bSBaptiste Daroussin 			len = term_len(p, p->defindent);
603*61d06d6bSBaptiste Daroussin 		mt->lmargin[mt->lmargincur] = len;
604*61d06d6bSBaptiste Daroussin 	} else
605*61d06d6bSBaptiste Daroussin 		len = mt->lmargin[mt->lmargincur];
606*61d06d6bSBaptiste Daroussin 
607*61d06d6bSBaptiste Daroussin 	switch (n->type) {
608*61d06d6bSBaptiste Daroussin 	case ROFFT_HEAD:
609*61d06d6bSBaptiste Daroussin 		p->tcol->offset = mt->offset;
610*61d06d6bSBaptiste Daroussin 		p->tcol->rmargin = mt->offset + len;
611*61d06d6bSBaptiste Daroussin 
612*61d06d6bSBaptiste Daroussin 		savelit = MANT_LITERAL & mt->fl;
613*61d06d6bSBaptiste Daroussin 		mt->fl &= ~MANT_LITERAL;
614*61d06d6bSBaptiste Daroussin 
615*61d06d6bSBaptiste Daroussin 		/* Don't print same-line elements. */
616*61d06d6bSBaptiste Daroussin 		nn = n->child;
617*61d06d6bSBaptiste Daroussin 		while (NULL != nn && 0 == (NODE_LINE & nn->flags))
618*61d06d6bSBaptiste Daroussin 			nn = nn->next;
619*61d06d6bSBaptiste Daroussin 
620*61d06d6bSBaptiste Daroussin 		while (NULL != nn) {
621*61d06d6bSBaptiste Daroussin 			print_man_node(p, mt, nn, meta);
622*61d06d6bSBaptiste Daroussin 			nn = nn->next;
623*61d06d6bSBaptiste Daroussin 		}
624*61d06d6bSBaptiste Daroussin 
625*61d06d6bSBaptiste Daroussin 		if (savelit)
626*61d06d6bSBaptiste Daroussin 			mt->fl |= MANT_LITERAL;
627*61d06d6bSBaptiste Daroussin 		return 0;
628*61d06d6bSBaptiste Daroussin 	case ROFFT_BODY:
629*61d06d6bSBaptiste Daroussin 		p->tcol->offset = mt->offset + len;
630*61d06d6bSBaptiste Daroussin 		p->tcol->rmargin = p->maxrmargin;
631*61d06d6bSBaptiste Daroussin 		p->trailspace = 0;
632*61d06d6bSBaptiste Daroussin 		p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP);
633*61d06d6bSBaptiste Daroussin 		break;
634*61d06d6bSBaptiste Daroussin 	default:
635*61d06d6bSBaptiste Daroussin 		break;
636*61d06d6bSBaptiste Daroussin 	}
637*61d06d6bSBaptiste Daroussin 
638*61d06d6bSBaptiste Daroussin 	return 1;
639*61d06d6bSBaptiste Daroussin }
640*61d06d6bSBaptiste Daroussin 
641*61d06d6bSBaptiste Daroussin static void
642*61d06d6bSBaptiste Daroussin post_TP(DECL_ARGS)
643*61d06d6bSBaptiste Daroussin {
644*61d06d6bSBaptiste Daroussin 
645*61d06d6bSBaptiste Daroussin 	switch (n->type) {
646*61d06d6bSBaptiste Daroussin 	case ROFFT_HEAD:
647*61d06d6bSBaptiste Daroussin 		term_flushln(p);
648*61d06d6bSBaptiste Daroussin 		break;
649*61d06d6bSBaptiste Daroussin 	case ROFFT_BODY:
650*61d06d6bSBaptiste Daroussin 		term_newln(p);
651*61d06d6bSBaptiste Daroussin 		p->tcol->offset = mt->offset;
652*61d06d6bSBaptiste Daroussin 		break;
653*61d06d6bSBaptiste Daroussin 	default:
654*61d06d6bSBaptiste Daroussin 		break;
655*61d06d6bSBaptiste Daroussin 	}
656*61d06d6bSBaptiste Daroussin }
657*61d06d6bSBaptiste Daroussin 
658*61d06d6bSBaptiste Daroussin static int
659*61d06d6bSBaptiste Daroussin pre_SS(DECL_ARGS)
660*61d06d6bSBaptiste Daroussin {
661*61d06d6bSBaptiste Daroussin 	int	 i;
662*61d06d6bSBaptiste Daroussin 
663*61d06d6bSBaptiste Daroussin 	switch (n->type) {
664*61d06d6bSBaptiste Daroussin 	case ROFFT_BLOCK:
665*61d06d6bSBaptiste Daroussin 		mt->fl &= ~MANT_LITERAL;
666*61d06d6bSBaptiste Daroussin 		mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
667*61d06d6bSBaptiste Daroussin 		mt->offset = term_len(p, p->defindent);
668*61d06d6bSBaptiste Daroussin 
669*61d06d6bSBaptiste Daroussin 		/*
670*61d06d6bSBaptiste Daroussin 		 * No vertical space before the first subsection
671*61d06d6bSBaptiste Daroussin 		 * and after an empty subsection.
672*61d06d6bSBaptiste Daroussin 		 */
673*61d06d6bSBaptiste Daroussin 
674*61d06d6bSBaptiste Daroussin 		do {
675*61d06d6bSBaptiste Daroussin 			n = n->prev;
676*61d06d6bSBaptiste Daroussin 		} while (n != NULL && n->tok >= MAN_TH &&
677*61d06d6bSBaptiste Daroussin 		    termacts[n->tok].flags & MAN_NOTEXT);
678*61d06d6bSBaptiste Daroussin 		if (n == NULL || n->type == ROFFT_COMMENT ||
679*61d06d6bSBaptiste Daroussin 		    (n->tok == MAN_SS && n->body->child == NULL))
680*61d06d6bSBaptiste Daroussin 			break;
681*61d06d6bSBaptiste Daroussin 
682*61d06d6bSBaptiste Daroussin 		for (i = 0; i < mt->pardist; i++)
683*61d06d6bSBaptiste Daroussin 			term_vspace(p);
684*61d06d6bSBaptiste Daroussin 		break;
685*61d06d6bSBaptiste Daroussin 	case ROFFT_HEAD:
686*61d06d6bSBaptiste Daroussin 		term_fontrepl(p, TERMFONT_BOLD);
687*61d06d6bSBaptiste Daroussin 		p->tcol->offset = term_len(p, 3);
688*61d06d6bSBaptiste Daroussin 		p->tcol->rmargin = mt->offset;
689*61d06d6bSBaptiste Daroussin 		p->trailspace = mt->offset;
690*61d06d6bSBaptiste Daroussin 		p->flags |= TERMP_NOBREAK | TERMP_BRIND;
691*61d06d6bSBaptiste Daroussin 		break;
692*61d06d6bSBaptiste Daroussin 	case ROFFT_BODY:
693*61d06d6bSBaptiste Daroussin 		p->tcol->offset = mt->offset;
694*61d06d6bSBaptiste Daroussin 		p->tcol->rmargin = p->maxrmargin;
695*61d06d6bSBaptiste Daroussin 		p->trailspace = 0;
696*61d06d6bSBaptiste Daroussin 		p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
697*61d06d6bSBaptiste Daroussin 		break;
698*61d06d6bSBaptiste Daroussin 	default:
699*61d06d6bSBaptiste Daroussin 		break;
700*61d06d6bSBaptiste Daroussin 	}
701*61d06d6bSBaptiste Daroussin 
702*61d06d6bSBaptiste Daroussin 	return 1;
703*61d06d6bSBaptiste Daroussin }
704*61d06d6bSBaptiste Daroussin 
705*61d06d6bSBaptiste Daroussin static void
706*61d06d6bSBaptiste Daroussin post_SS(DECL_ARGS)
707*61d06d6bSBaptiste Daroussin {
708*61d06d6bSBaptiste Daroussin 
709*61d06d6bSBaptiste Daroussin 	switch (n->type) {
710*61d06d6bSBaptiste Daroussin 	case ROFFT_HEAD:
711*61d06d6bSBaptiste Daroussin 		term_newln(p);
712*61d06d6bSBaptiste Daroussin 		break;
713*61d06d6bSBaptiste Daroussin 	case ROFFT_BODY:
714*61d06d6bSBaptiste Daroussin 		term_newln(p);
715*61d06d6bSBaptiste Daroussin 		break;
716*61d06d6bSBaptiste Daroussin 	default:
717*61d06d6bSBaptiste Daroussin 		break;
718*61d06d6bSBaptiste Daroussin 	}
719*61d06d6bSBaptiste Daroussin }
720*61d06d6bSBaptiste Daroussin 
721*61d06d6bSBaptiste Daroussin static int
722*61d06d6bSBaptiste Daroussin pre_SH(DECL_ARGS)
723*61d06d6bSBaptiste Daroussin {
724*61d06d6bSBaptiste Daroussin 	int	 i;
725*61d06d6bSBaptiste Daroussin 
726*61d06d6bSBaptiste Daroussin 	switch (n->type) {
727*61d06d6bSBaptiste Daroussin 	case ROFFT_BLOCK:
728*61d06d6bSBaptiste Daroussin 		mt->fl &= ~MANT_LITERAL;
729*61d06d6bSBaptiste Daroussin 		mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
730*61d06d6bSBaptiste Daroussin 		mt->offset = term_len(p, p->defindent);
731*61d06d6bSBaptiste Daroussin 
732*61d06d6bSBaptiste Daroussin 		/*
733*61d06d6bSBaptiste Daroussin 		 * No vertical space before the first section
734*61d06d6bSBaptiste Daroussin 		 * and after an empty section.
735*61d06d6bSBaptiste Daroussin 		 */
736*61d06d6bSBaptiste Daroussin 
737*61d06d6bSBaptiste Daroussin 		do {
738*61d06d6bSBaptiste Daroussin 			n = n->prev;
739*61d06d6bSBaptiste Daroussin 		} while (n != NULL && n->tok >= MAN_TH &&
740*61d06d6bSBaptiste Daroussin 		    termacts[n->tok].flags & MAN_NOTEXT);
741*61d06d6bSBaptiste Daroussin 		if (n == NULL || n->type == ROFFT_COMMENT ||
742*61d06d6bSBaptiste Daroussin 		    (n->tok == MAN_SH && n->body->child == NULL))
743*61d06d6bSBaptiste Daroussin 			break;
744*61d06d6bSBaptiste Daroussin 
745*61d06d6bSBaptiste Daroussin 		for (i = 0; i < mt->pardist; i++)
746*61d06d6bSBaptiste Daroussin 			term_vspace(p);
747*61d06d6bSBaptiste Daroussin 		break;
748*61d06d6bSBaptiste Daroussin 	case ROFFT_HEAD:
749*61d06d6bSBaptiste Daroussin 		term_fontrepl(p, TERMFONT_BOLD);
750*61d06d6bSBaptiste Daroussin 		p->tcol->offset = 0;
751*61d06d6bSBaptiste Daroussin 		p->tcol->rmargin = mt->offset;
752*61d06d6bSBaptiste Daroussin 		p->trailspace = mt->offset;
753*61d06d6bSBaptiste Daroussin 		p->flags |= TERMP_NOBREAK | TERMP_BRIND;
754*61d06d6bSBaptiste Daroussin 		break;
755*61d06d6bSBaptiste Daroussin 	case ROFFT_BODY:
756*61d06d6bSBaptiste Daroussin 		p->tcol->offset = mt->offset;
757*61d06d6bSBaptiste Daroussin 		p->tcol->rmargin = p->maxrmargin;
758*61d06d6bSBaptiste Daroussin 		p->trailspace = 0;
759*61d06d6bSBaptiste Daroussin 		p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
760*61d06d6bSBaptiste Daroussin 		break;
761*61d06d6bSBaptiste Daroussin 	default:
762*61d06d6bSBaptiste Daroussin 		break;
763*61d06d6bSBaptiste Daroussin 	}
764*61d06d6bSBaptiste Daroussin 
765*61d06d6bSBaptiste Daroussin 	return 1;
766*61d06d6bSBaptiste Daroussin }
767*61d06d6bSBaptiste Daroussin 
768*61d06d6bSBaptiste Daroussin static void
769*61d06d6bSBaptiste Daroussin post_SH(DECL_ARGS)
770*61d06d6bSBaptiste Daroussin {
771*61d06d6bSBaptiste Daroussin 
772*61d06d6bSBaptiste Daroussin 	switch (n->type) {
773*61d06d6bSBaptiste Daroussin 	case ROFFT_HEAD:
774*61d06d6bSBaptiste Daroussin 		term_newln(p);
775*61d06d6bSBaptiste Daroussin 		break;
776*61d06d6bSBaptiste Daroussin 	case ROFFT_BODY:
777*61d06d6bSBaptiste Daroussin 		term_newln(p);
778*61d06d6bSBaptiste Daroussin 		break;
779*61d06d6bSBaptiste Daroussin 	default:
780*61d06d6bSBaptiste Daroussin 		break;
781*61d06d6bSBaptiste Daroussin 	}
782*61d06d6bSBaptiste Daroussin }
783*61d06d6bSBaptiste Daroussin 
784*61d06d6bSBaptiste Daroussin static int
785*61d06d6bSBaptiste Daroussin pre_RS(DECL_ARGS)
786*61d06d6bSBaptiste Daroussin {
787*61d06d6bSBaptiste Daroussin 	struct roffsu	 su;
788*61d06d6bSBaptiste Daroussin 
789*61d06d6bSBaptiste Daroussin 	switch (n->type) {
790*61d06d6bSBaptiste Daroussin 	case ROFFT_BLOCK:
791*61d06d6bSBaptiste Daroussin 		term_newln(p);
792*61d06d6bSBaptiste Daroussin 		return 1;
793*61d06d6bSBaptiste Daroussin 	case ROFFT_HEAD:
794*61d06d6bSBaptiste Daroussin 		return 0;
795*61d06d6bSBaptiste Daroussin 	default:
796*61d06d6bSBaptiste Daroussin 		break;
797*61d06d6bSBaptiste Daroussin 	}
798*61d06d6bSBaptiste Daroussin 
799*61d06d6bSBaptiste Daroussin 	n = n->parent->head;
800*61d06d6bSBaptiste Daroussin 	n->aux = SHRT_MAX + 1;
801*61d06d6bSBaptiste Daroussin 	if (n->child == NULL)
802*61d06d6bSBaptiste Daroussin 		n->aux = mt->lmargin[mt->lmargincur];
803*61d06d6bSBaptiste Daroussin 	else if (a2roffsu(n->child->string, &su, SCALE_EN) != NULL)
804*61d06d6bSBaptiste Daroussin 		n->aux = term_hen(p, &su);
805*61d06d6bSBaptiste Daroussin 	if (n->aux < 0 && (size_t)(-n->aux) > mt->offset)
806*61d06d6bSBaptiste Daroussin 		n->aux = -mt->offset;
807*61d06d6bSBaptiste Daroussin 	else if (n->aux > SHRT_MAX)
808*61d06d6bSBaptiste Daroussin 		n->aux = term_len(p, p->defindent);
809*61d06d6bSBaptiste Daroussin 
810*61d06d6bSBaptiste Daroussin 	mt->offset += n->aux;
811*61d06d6bSBaptiste Daroussin 	p->tcol->offset = mt->offset;
812*61d06d6bSBaptiste Daroussin 	p->tcol->rmargin = p->maxrmargin;
813*61d06d6bSBaptiste Daroussin 
814*61d06d6bSBaptiste Daroussin 	if (++mt->lmarginsz < MAXMARGINS)
815*61d06d6bSBaptiste Daroussin 		mt->lmargincur = mt->lmarginsz;
816*61d06d6bSBaptiste Daroussin 
817*61d06d6bSBaptiste Daroussin 	mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
818*61d06d6bSBaptiste Daroussin 	return 1;
819*61d06d6bSBaptiste Daroussin }
820*61d06d6bSBaptiste Daroussin 
821*61d06d6bSBaptiste Daroussin static void
822*61d06d6bSBaptiste Daroussin post_RS(DECL_ARGS)
823*61d06d6bSBaptiste Daroussin {
824*61d06d6bSBaptiste Daroussin 
825*61d06d6bSBaptiste Daroussin 	switch (n->type) {
826*61d06d6bSBaptiste Daroussin 	case ROFFT_BLOCK:
827*61d06d6bSBaptiste Daroussin 		return;
828*61d06d6bSBaptiste Daroussin 	case ROFFT_HEAD:
829*61d06d6bSBaptiste Daroussin 		return;
830*61d06d6bSBaptiste Daroussin 	default:
831*61d06d6bSBaptiste Daroussin 		term_newln(p);
832*61d06d6bSBaptiste Daroussin 		break;
833*61d06d6bSBaptiste Daroussin 	}
834*61d06d6bSBaptiste Daroussin 
835*61d06d6bSBaptiste Daroussin 	mt->offset -= n->parent->head->aux;
836*61d06d6bSBaptiste Daroussin 	p->tcol->offset = mt->offset;
837*61d06d6bSBaptiste Daroussin 
838*61d06d6bSBaptiste Daroussin 	if (--mt->lmarginsz < MAXMARGINS)
839*61d06d6bSBaptiste Daroussin 		mt->lmargincur = mt->lmarginsz;
840*61d06d6bSBaptiste Daroussin }
841*61d06d6bSBaptiste Daroussin 
842*61d06d6bSBaptiste Daroussin static int
843*61d06d6bSBaptiste Daroussin pre_UR(DECL_ARGS)
844*61d06d6bSBaptiste Daroussin {
845*61d06d6bSBaptiste Daroussin 
846*61d06d6bSBaptiste Daroussin 	return n->type != ROFFT_HEAD;
847*61d06d6bSBaptiste Daroussin }
848*61d06d6bSBaptiste Daroussin 
849*61d06d6bSBaptiste Daroussin static void
850*61d06d6bSBaptiste Daroussin post_UR(DECL_ARGS)
851*61d06d6bSBaptiste Daroussin {
852*61d06d6bSBaptiste Daroussin 
853*61d06d6bSBaptiste Daroussin 	if (n->type != ROFFT_BLOCK)
854*61d06d6bSBaptiste Daroussin 		return;
855*61d06d6bSBaptiste Daroussin 
856*61d06d6bSBaptiste Daroussin 	term_word(p, "<");
857*61d06d6bSBaptiste Daroussin 	p->flags |= TERMP_NOSPACE;
858*61d06d6bSBaptiste Daroussin 
859*61d06d6bSBaptiste Daroussin 	if (NULL != n->child->child)
860*61d06d6bSBaptiste Daroussin 		print_man_node(p, mt, n->child->child, meta);
861*61d06d6bSBaptiste Daroussin 
862*61d06d6bSBaptiste Daroussin 	p->flags |= TERMP_NOSPACE;
863*61d06d6bSBaptiste Daroussin 	term_word(p, ">");
864*61d06d6bSBaptiste Daroussin }
865*61d06d6bSBaptiste Daroussin 
866*61d06d6bSBaptiste Daroussin static void
867*61d06d6bSBaptiste Daroussin print_man_node(DECL_ARGS)
868*61d06d6bSBaptiste Daroussin {
869*61d06d6bSBaptiste Daroussin 	int		 c;
870*61d06d6bSBaptiste Daroussin 
871*61d06d6bSBaptiste Daroussin 	switch (n->type) {
872*61d06d6bSBaptiste Daroussin 	case ROFFT_TEXT:
873*61d06d6bSBaptiste Daroussin 		/*
874*61d06d6bSBaptiste Daroussin 		 * If we have a blank line, output a vertical space.
875*61d06d6bSBaptiste Daroussin 		 * If we have a space as the first character, break
876*61d06d6bSBaptiste Daroussin 		 * before printing the line's data.
877*61d06d6bSBaptiste Daroussin 		 */
878*61d06d6bSBaptiste Daroussin 		if (*n->string == '\0') {
879*61d06d6bSBaptiste Daroussin 			if (p->flags & TERMP_NONEWLINE)
880*61d06d6bSBaptiste Daroussin 				term_newln(p);
881*61d06d6bSBaptiste Daroussin 			else
882*61d06d6bSBaptiste Daroussin 				term_vspace(p);
883*61d06d6bSBaptiste Daroussin 			return;
884*61d06d6bSBaptiste Daroussin 		} else if (*n->string == ' ' && n->flags & NODE_LINE &&
885*61d06d6bSBaptiste Daroussin 		    (p->flags & TERMP_NONEWLINE) == 0)
886*61d06d6bSBaptiste Daroussin 			term_newln(p);
887*61d06d6bSBaptiste Daroussin 
888*61d06d6bSBaptiste Daroussin 		term_word(p, n->string);
889*61d06d6bSBaptiste Daroussin 		goto out;
890*61d06d6bSBaptiste Daroussin 	case ROFFT_COMMENT:
891*61d06d6bSBaptiste Daroussin 		return;
892*61d06d6bSBaptiste Daroussin 	case ROFFT_EQN:
893*61d06d6bSBaptiste Daroussin 		if ( ! (n->flags & NODE_LINE))
894*61d06d6bSBaptiste Daroussin 			p->flags |= TERMP_NOSPACE;
895*61d06d6bSBaptiste Daroussin 		term_eqn(p, n->eqn);
896*61d06d6bSBaptiste Daroussin 		if (n->next != NULL && ! (n->next->flags & NODE_LINE))
897*61d06d6bSBaptiste Daroussin 			p->flags |= TERMP_NOSPACE;
898*61d06d6bSBaptiste Daroussin 		return;
899*61d06d6bSBaptiste Daroussin 	case ROFFT_TBL:
900*61d06d6bSBaptiste Daroussin 		if (p->tbl.cols == NULL)
901*61d06d6bSBaptiste Daroussin 			term_vspace(p);
902*61d06d6bSBaptiste Daroussin 		term_tbl(p, n->span);
903*61d06d6bSBaptiste Daroussin 		return;
904*61d06d6bSBaptiste Daroussin 	default:
905*61d06d6bSBaptiste Daroussin 		break;
906*61d06d6bSBaptiste Daroussin 	}
907*61d06d6bSBaptiste Daroussin 
908*61d06d6bSBaptiste Daroussin 	if (n->tok < ROFF_MAX) {
909*61d06d6bSBaptiste Daroussin 		roff_term_pre(p, n);
910*61d06d6bSBaptiste Daroussin 		return;
911*61d06d6bSBaptiste Daroussin 	}
912*61d06d6bSBaptiste Daroussin 
913*61d06d6bSBaptiste Daroussin 	assert(n->tok >= MAN_TH && n->tok <= MAN_MAX);
914*61d06d6bSBaptiste Daroussin 	if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
915*61d06d6bSBaptiste Daroussin 		term_fontrepl(p, TERMFONT_NONE);
916*61d06d6bSBaptiste Daroussin 
917*61d06d6bSBaptiste Daroussin 	c = 1;
918*61d06d6bSBaptiste Daroussin 	if (termacts[n->tok].pre)
919*61d06d6bSBaptiste Daroussin 		c = (*termacts[n->tok].pre)(p, mt, n, meta);
920*61d06d6bSBaptiste Daroussin 
921*61d06d6bSBaptiste Daroussin 	if (c && n->child)
922*61d06d6bSBaptiste Daroussin 		print_man_nodelist(p, mt, n->child, meta);
923*61d06d6bSBaptiste Daroussin 
924*61d06d6bSBaptiste Daroussin 	if (termacts[n->tok].post)
925*61d06d6bSBaptiste Daroussin 		(*termacts[n->tok].post)(p, mt, n, meta);
926*61d06d6bSBaptiste Daroussin 	if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
927*61d06d6bSBaptiste Daroussin 		term_fontrepl(p, TERMFONT_NONE);
928*61d06d6bSBaptiste Daroussin 
929*61d06d6bSBaptiste Daroussin out:
930*61d06d6bSBaptiste Daroussin 	/*
931*61d06d6bSBaptiste Daroussin 	 * If we're in a literal context, make sure that words
932*61d06d6bSBaptiste Daroussin 	 * together on the same line stay together.  This is a
933*61d06d6bSBaptiste Daroussin 	 * POST-printing call, so we check the NEXT word.  Since
934*61d06d6bSBaptiste Daroussin 	 * -man doesn't have nested macros, we don't need to be
935*61d06d6bSBaptiste Daroussin 	 * more specific than this.
936*61d06d6bSBaptiste Daroussin 	 */
937*61d06d6bSBaptiste Daroussin 	if (mt->fl & MANT_LITERAL &&
938*61d06d6bSBaptiste Daroussin 	    ! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) &&
939*61d06d6bSBaptiste Daroussin 	    (n->next == NULL || n->next->flags & NODE_LINE)) {
940*61d06d6bSBaptiste Daroussin 		p->flags |= TERMP_BRNEVER | TERMP_NOSPACE;
941*61d06d6bSBaptiste Daroussin 		if (n->string != NULL && *n->string != '\0')
942*61d06d6bSBaptiste Daroussin 			term_flushln(p);
943*61d06d6bSBaptiste Daroussin 		else
944*61d06d6bSBaptiste Daroussin 			term_newln(p);
945*61d06d6bSBaptiste Daroussin 		p->flags &= ~TERMP_BRNEVER;
946*61d06d6bSBaptiste Daroussin 		if (p->tcol->rmargin < p->maxrmargin &&
947*61d06d6bSBaptiste Daroussin 		    n->parent->tok == MAN_HP) {
948*61d06d6bSBaptiste Daroussin 			p->tcol->offset = p->tcol->rmargin;
949*61d06d6bSBaptiste Daroussin 			p->tcol->rmargin = p->maxrmargin;
950*61d06d6bSBaptiste Daroussin 		}
951*61d06d6bSBaptiste Daroussin 	}
952*61d06d6bSBaptiste Daroussin 	if (NODE_EOS & n->flags)
953*61d06d6bSBaptiste Daroussin 		p->flags |= TERMP_SENTENCE;
954*61d06d6bSBaptiste Daroussin }
955*61d06d6bSBaptiste Daroussin 
956*61d06d6bSBaptiste Daroussin 
957*61d06d6bSBaptiste Daroussin static void
958*61d06d6bSBaptiste Daroussin print_man_nodelist(DECL_ARGS)
959*61d06d6bSBaptiste Daroussin {
960*61d06d6bSBaptiste Daroussin 
961*61d06d6bSBaptiste Daroussin 	while (n != NULL) {
962*61d06d6bSBaptiste Daroussin 		print_man_node(p, mt, n, meta);
963*61d06d6bSBaptiste Daroussin 		n = n->next;
964*61d06d6bSBaptiste Daroussin 	}
965*61d06d6bSBaptiste Daroussin }
966*61d06d6bSBaptiste Daroussin 
967*61d06d6bSBaptiste Daroussin static void
968*61d06d6bSBaptiste Daroussin print_man_foot(struct termp *p, const struct roff_meta *meta)
969*61d06d6bSBaptiste Daroussin {
970*61d06d6bSBaptiste Daroussin 	char			*title;
971*61d06d6bSBaptiste Daroussin 	size_t			 datelen, titlen;
972*61d06d6bSBaptiste Daroussin 
973*61d06d6bSBaptiste Daroussin 	assert(meta->title);
974*61d06d6bSBaptiste Daroussin 	assert(meta->msec);
975*61d06d6bSBaptiste Daroussin 	assert(meta->date);
976*61d06d6bSBaptiste Daroussin 
977*61d06d6bSBaptiste Daroussin 	term_fontrepl(p, TERMFONT_NONE);
978*61d06d6bSBaptiste Daroussin 
979*61d06d6bSBaptiste Daroussin 	if (meta->hasbody)
980*61d06d6bSBaptiste Daroussin 		term_vspace(p);
981*61d06d6bSBaptiste Daroussin 
982*61d06d6bSBaptiste Daroussin 	/*
983*61d06d6bSBaptiste Daroussin 	 * Temporary, undocumented option to imitate mdoc(7) output.
984*61d06d6bSBaptiste Daroussin 	 * In the bottom right corner, use the operating system
985*61d06d6bSBaptiste Daroussin 	 * instead of the title.
986*61d06d6bSBaptiste Daroussin 	 */
987*61d06d6bSBaptiste Daroussin 
988*61d06d6bSBaptiste Daroussin 	if ( ! p->mdocstyle) {
989*61d06d6bSBaptiste Daroussin 		if (meta->hasbody) {
990*61d06d6bSBaptiste Daroussin 			term_vspace(p);
991*61d06d6bSBaptiste Daroussin 			term_vspace(p);
992*61d06d6bSBaptiste Daroussin 		}
993*61d06d6bSBaptiste Daroussin 		mandoc_asprintf(&title, "%s(%s)",
994*61d06d6bSBaptiste Daroussin 		    meta->title, meta->msec);
995*61d06d6bSBaptiste Daroussin 	} else if (meta->os) {
996*61d06d6bSBaptiste Daroussin 		title = mandoc_strdup(meta->os);
997*61d06d6bSBaptiste Daroussin 	} else {
998*61d06d6bSBaptiste Daroussin 		title = mandoc_strdup("");
999*61d06d6bSBaptiste Daroussin 	}
1000*61d06d6bSBaptiste Daroussin 	datelen = term_strlen(p, meta->date);
1001*61d06d6bSBaptiste Daroussin 
1002*61d06d6bSBaptiste Daroussin 	/* Bottom left corner: operating system. */
1003*61d06d6bSBaptiste Daroussin 
1004*61d06d6bSBaptiste Daroussin 	p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
1005*61d06d6bSBaptiste Daroussin 	p->trailspace = 1;
1006*61d06d6bSBaptiste Daroussin 	p->tcol->offset = 0;
1007*61d06d6bSBaptiste Daroussin 	p->tcol->rmargin = p->maxrmargin > datelen ?
1008*61d06d6bSBaptiste Daroussin 	    (p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0;
1009*61d06d6bSBaptiste Daroussin 
1010*61d06d6bSBaptiste Daroussin 	if (meta->os)
1011*61d06d6bSBaptiste Daroussin 		term_word(p, meta->os);
1012*61d06d6bSBaptiste Daroussin 	term_flushln(p);
1013*61d06d6bSBaptiste Daroussin 
1014*61d06d6bSBaptiste Daroussin 	/* At the bottom in the middle: manual date. */
1015*61d06d6bSBaptiste Daroussin 
1016*61d06d6bSBaptiste Daroussin 	p->tcol->offset = p->tcol->rmargin;
1017*61d06d6bSBaptiste Daroussin 	titlen = term_strlen(p, title);
1018*61d06d6bSBaptiste Daroussin 	p->tcol->rmargin = p->maxrmargin > titlen ?
1019*61d06d6bSBaptiste Daroussin 	    p->maxrmargin - titlen : 0;
1020*61d06d6bSBaptiste Daroussin 	p->flags |= TERMP_NOSPACE;
1021*61d06d6bSBaptiste Daroussin 
1022*61d06d6bSBaptiste Daroussin 	term_word(p, meta->date);
1023*61d06d6bSBaptiste Daroussin 	term_flushln(p);
1024*61d06d6bSBaptiste Daroussin 
1025*61d06d6bSBaptiste Daroussin 	/* Bottom right corner: manual title and section. */
1026*61d06d6bSBaptiste Daroussin 
1027*61d06d6bSBaptiste Daroussin 	p->flags &= ~TERMP_NOBREAK;
1028*61d06d6bSBaptiste Daroussin 	p->flags |= TERMP_NOSPACE;
1029*61d06d6bSBaptiste Daroussin 	p->trailspace = 0;
1030*61d06d6bSBaptiste Daroussin 	p->tcol->offset = p->tcol->rmargin;
1031*61d06d6bSBaptiste Daroussin 	p->tcol->rmargin = p->maxrmargin;
1032*61d06d6bSBaptiste Daroussin 
1033*61d06d6bSBaptiste Daroussin 	term_word(p, title);
1034*61d06d6bSBaptiste Daroussin 	term_flushln(p);
1035*61d06d6bSBaptiste Daroussin 
1036*61d06d6bSBaptiste Daroussin 	/*
1037*61d06d6bSBaptiste Daroussin 	 * Reset the terminal state for more output after the footer:
1038*61d06d6bSBaptiste Daroussin 	 * Some output modes, in particular PostScript and PDF, print
1039*61d06d6bSBaptiste Daroussin 	 * the header and the footer into a buffer such that it can be
1040*61d06d6bSBaptiste Daroussin 	 * reused for multiple output pages, then go on to format the
1041*61d06d6bSBaptiste Daroussin 	 * main text.
1042*61d06d6bSBaptiste Daroussin 	 */
1043*61d06d6bSBaptiste Daroussin 
1044*61d06d6bSBaptiste Daroussin         p->tcol->offset = 0;
1045*61d06d6bSBaptiste Daroussin         p->flags = 0;
1046*61d06d6bSBaptiste Daroussin 
1047*61d06d6bSBaptiste Daroussin 	free(title);
1048*61d06d6bSBaptiste Daroussin }
1049*61d06d6bSBaptiste Daroussin 
1050*61d06d6bSBaptiste Daroussin static void
1051*61d06d6bSBaptiste Daroussin print_man_head(struct termp *p, const struct roff_meta *meta)
1052*61d06d6bSBaptiste Daroussin {
1053*61d06d6bSBaptiste Daroussin 	const char		*volume;
1054*61d06d6bSBaptiste Daroussin 	char			*title;
1055*61d06d6bSBaptiste Daroussin 	size_t			 vollen, titlen;
1056*61d06d6bSBaptiste Daroussin 
1057*61d06d6bSBaptiste Daroussin 	assert(meta->title);
1058*61d06d6bSBaptiste Daroussin 	assert(meta->msec);
1059*61d06d6bSBaptiste Daroussin 
1060*61d06d6bSBaptiste Daroussin 	volume = NULL == meta->vol ? "" : meta->vol;
1061*61d06d6bSBaptiste Daroussin 	vollen = term_strlen(p, volume);
1062*61d06d6bSBaptiste Daroussin 
1063*61d06d6bSBaptiste Daroussin 	/* Top left corner: manual title and section. */
1064*61d06d6bSBaptiste Daroussin 
1065*61d06d6bSBaptiste Daroussin 	mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec);
1066*61d06d6bSBaptiste Daroussin 	titlen = term_strlen(p, title);
1067*61d06d6bSBaptiste Daroussin 
1068*61d06d6bSBaptiste Daroussin 	p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
1069*61d06d6bSBaptiste Daroussin 	p->trailspace = 1;
1070*61d06d6bSBaptiste Daroussin 	p->tcol->offset = 0;
1071*61d06d6bSBaptiste Daroussin 	p->tcol->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
1072*61d06d6bSBaptiste Daroussin 	    (p->maxrmargin - vollen + term_len(p, 1)) / 2 :
1073*61d06d6bSBaptiste Daroussin 	    vollen < p->maxrmargin ? p->maxrmargin - vollen : 0;
1074*61d06d6bSBaptiste Daroussin 
1075*61d06d6bSBaptiste Daroussin 	term_word(p, title);
1076*61d06d6bSBaptiste Daroussin 	term_flushln(p);
1077*61d06d6bSBaptiste Daroussin 
1078*61d06d6bSBaptiste Daroussin 	/* At the top in the middle: manual volume. */
1079*61d06d6bSBaptiste Daroussin 
1080*61d06d6bSBaptiste Daroussin 	p->flags |= TERMP_NOSPACE;
1081*61d06d6bSBaptiste Daroussin 	p->tcol->offset = p->tcol->rmargin;
1082*61d06d6bSBaptiste Daroussin 	p->tcol->rmargin = p->tcol->offset + vollen + titlen <
1083*61d06d6bSBaptiste Daroussin 	    p->maxrmargin ?  p->maxrmargin - titlen : p->maxrmargin;
1084*61d06d6bSBaptiste Daroussin 
1085*61d06d6bSBaptiste Daroussin 	term_word(p, volume);
1086*61d06d6bSBaptiste Daroussin 	term_flushln(p);
1087*61d06d6bSBaptiste Daroussin 
1088*61d06d6bSBaptiste Daroussin 	/* Top right corner: title and section, again. */
1089*61d06d6bSBaptiste Daroussin 
1090*61d06d6bSBaptiste Daroussin 	p->flags &= ~TERMP_NOBREAK;
1091*61d06d6bSBaptiste Daroussin 	p->trailspace = 0;
1092*61d06d6bSBaptiste Daroussin 	if (p->tcol->rmargin + titlen <= p->maxrmargin) {
1093*61d06d6bSBaptiste Daroussin 		p->flags |= TERMP_NOSPACE;
1094*61d06d6bSBaptiste Daroussin 		p->tcol->offset = p->tcol->rmargin;
1095*61d06d6bSBaptiste Daroussin 		p->tcol->rmargin = p->maxrmargin;
1096*61d06d6bSBaptiste Daroussin 		term_word(p, title);
1097*61d06d6bSBaptiste Daroussin 		term_flushln(p);
1098*61d06d6bSBaptiste Daroussin 	}
1099*61d06d6bSBaptiste Daroussin 
1100*61d06d6bSBaptiste Daroussin 	p->flags &= ~TERMP_NOSPACE;
1101*61d06d6bSBaptiste Daroussin 	p->tcol->offset = 0;
1102*61d06d6bSBaptiste Daroussin 	p->tcol->rmargin = p->maxrmargin;
1103*61d06d6bSBaptiste Daroussin 
1104*61d06d6bSBaptiste Daroussin 	/*
1105*61d06d6bSBaptiste Daroussin 	 * Groff prints three blank lines before the content.
1106*61d06d6bSBaptiste Daroussin 	 * Do the same, except in the temporary, undocumented
1107*61d06d6bSBaptiste Daroussin 	 * mode imitating mdoc(7) output.
1108*61d06d6bSBaptiste Daroussin 	 */
1109*61d06d6bSBaptiste Daroussin 
1110*61d06d6bSBaptiste Daroussin 	term_vspace(p);
1111*61d06d6bSBaptiste Daroussin 	if ( ! p->mdocstyle) {
1112*61d06d6bSBaptiste Daroussin 		term_vspace(p);
1113*61d06d6bSBaptiste Daroussin 		term_vspace(p);
1114*61d06d6bSBaptiste Daroussin 	}
1115*61d06d6bSBaptiste Daroussin 	free(title);
1116*61d06d6bSBaptiste Daroussin }
1117