xref: /titanic_51/usr/src/cmd/mandoc/mdoc_term.c (revision 260e9a87725c090ba5835b1f9f0b62fa2f96036f)
1*260e9a87SYuri Pankov /*	$Id: mdoc_term.c,v 1.313 2015/03/06 15:48:52 schwarze Exp $ */
295c635efSGarrett D'Amore /*
395c635efSGarrett D'Amore  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*260e9a87SYuri Pankov  * Copyright (c) 2010, 2012-2015 Ingo Schwarze <schwarze@openbsd.org>
5698f87a4SGarrett D'Amore  * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
695c635efSGarrett D'Amore  *
795c635efSGarrett D'Amore  * Permission to use, copy, modify, and distribute this software for any
895c635efSGarrett D'Amore  * purpose with or without fee is hereby granted, provided that the above
995c635efSGarrett D'Amore  * copyright notice and this permission notice appear in all copies.
1095c635efSGarrett D'Amore  *
1195c635efSGarrett D'Amore  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1295c635efSGarrett D'Amore  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1395c635efSGarrett D'Amore  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1495c635efSGarrett D'Amore  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1595c635efSGarrett D'Amore  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1695c635efSGarrett D'Amore  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1795c635efSGarrett D'Amore  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1895c635efSGarrett D'Amore  */
1995c635efSGarrett D'Amore #include "config.h"
2095c635efSGarrett D'Amore 
2195c635efSGarrett D'Amore #include <sys/types.h>
2295c635efSGarrett D'Amore 
2395c635efSGarrett D'Amore #include <assert.h>
2495c635efSGarrett D'Amore #include <ctype.h>
25*260e9a87SYuri Pankov #include <limits.h>
2695c635efSGarrett D'Amore #include <stdint.h>
2795c635efSGarrett D'Amore #include <stdio.h>
2895c635efSGarrett D'Amore #include <stdlib.h>
2995c635efSGarrett D'Amore #include <string.h>
3095c635efSGarrett D'Amore 
3195c635efSGarrett D'Amore #include "mandoc.h"
32*260e9a87SYuri Pankov #include "mandoc_aux.h"
3395c635efSGarrett D'Amore #include "out.h"
3495c635efSGarrett D'Amore #include "term.h"
3595c635efSGarrett D'Amore #include "mdoc.h"
3695c635efSGarrett D'Amore #include "main.h"
3795c635efSGarrett D'Amore 
3895c635efSGarrett D'Amore struct	termpair {
3995c635efSGarrett D'Amore 	struct termpair	 *ppair;
4095c635efSGarrett D'Amore 	int		  count;
4195c635efSGarrett D'Amore };
4295c635efSGarrett D'Amore 
4395c635efSGarrett D'Amore #define	DECL_ARGS struct termp *p, \
4495c635efSGarrett D'Amore 		  struct termpair *pair, \
45698f87a4SGarrett D'Amore 		  const struct mdoc_meta *meta, \
46698f87a4SGarrett D'Amore 		  struct mdoc_node *n
4795c635efSGarrett D'Amore 
4895c635efSGarrett D'Amore struct	termact {
4995c635efSGarrett D'Amore 	int	(*pre)(DECL_ARGS);
5095c635efSGarrett D'Amore 	void	(*post)(DECL_ARGS);
5195c635efSGarrett D'Amore };
5295c635efSGarrett D'Amore 
53*260e9a87SYuri Pankov static	int	  a2width(const struct termp *, const char *);
5495c635efSGarrett D'Amore 
5595c635efSGarrett D'Amore static	void	  print_bvspace(struct termp *,
5695c635efSGarrett D'Amore 			const struct mdoc_node *,
5795c635efSGarrett D'Amore 			const struct mdoc_node *);
5895c635efSGarrett D'Amore static	void	  print_mdoc_node(DECL_ARGS);
5995c635efSGarrett D'Amore static	void	  print_mdoc_nodelist(DECL_ARGS);
6095c635efSGarrett D'Amore static	void	  print_mdoc_head(struct termp *, const void *);
6195c635efSGarrett D'Amore static	void	  print_mdoc_foot(struct termp *, const void *);
6295c635efSGarrett D'Amore static	void	  synopsis_pre(struct termp *,
6395c635efSGarrett D'Amore 			const struct mdoc_node *);
6495c635efSGarrett D'Amore 
6595c635efSGarrett D'Amore static	void	  termp____post(DECL_ARGS);
6695c635efSGarrett D'Amore static	void	  termp__t_post(DECL_ARGS);
6795c635efSGarrett D'Amore static	void	  termp_bd_post(DECL_ARGS);
6895c635efSGarrett D'Amore static	void	  termp_bk_post(DECL_ARGS);
6995c635efSGarrett D'Amore static	void	  termp_bl_post(DECL_ARGS);
70*260e9a87SYuri Pankov static	void	  termp_eo_post(DECL_ARGS);
71698f87a4SGarrett D'Amore static	void	  termp_fd_post(DECL_ARGS);
7295c635efSGarrett D'Amore static	void	  termp_fo_post(DECL_ARGS);
7395c635efSGarrett D'Amore static	void	  termp_in_post(DECL_ARGS);
7495c635efSGarrett D'Amore static	void	  termp_it_post(DECL_ARGS);
7595c635efSGarrett D'Amore static	void	  termp_lb_post(DECL_ARGS);
7695c635efSGarrett D'Amore static	void	  termp_nm_post(DECL_ARGS);
7795c635efSGarrett D'Amore static	void	  termp_pf_post(DECL_ARGS);
7895c635efSGarrett D'Amore static	void	  termp_quote_post(DECL_ARGS);
7995c635efSGarrett D'Amore static	void	  termp_sh_post(DECL_ARGS);
8095c635efSGarrett D'Amore static	void	  termp_ss_post(DECL_ARGS);
8195c635efSGarrett D'Amore 
8295c635efSGarrett D'Amore static	int	  termp__a_pre(DECL_ARGS);
8395c635efSGarrett D'Amore static	int	  termp__t_pre(DECL_ARGS);
8495c635efSGarrett D'Amore static	int	  termp_an_pre(DECL_ARGS);
8595c635efSGarrett D'Amore static	int	  termp_ap_pre(DECL_ARGS);
8695c635efSGarrett D'Amore static	int	  termp_bd_pre(DECL_ARGS);
8795c635efSGarrett D'Amore static	int	  termp_bf_pre(DECL_ARGS);
8895c635efSGarrett D'Amore static	int	  termp_bk_pre(DECL_ARGS);
8995c635efSGarrett D'Amore static	int	  termp_bl_pre(DECL_ARGS);
9095c635efSGarrett D'Amore static	int	  termp_bold_pre(DECL_ARGS);
9195c635efSGarrett D'Amore static	int	  termp_bt_pre(DECL_ARGS);
9295c635efSGarrett D'Amore static	int	  termp_bx_pre(DECL_ARGS);
9395c635efSGarrett D'Amore static	int	  termp_cd_pre(DECL_ARGS);
9495c635efSGarrett D'Amore static	int	  termp_d1_pre(DECL_ARGS);
95*260e9a87SYuri Pankov static	int	  termp_eo_pre(DECL_ARGS);
9695c635efSGarrett D'Amore static	int	  termp_ex_pre(DECL_ARGS);
9795c635efSGarrett D'Amore static	int	  termp_fa_pre(DECL_ARGS);
9895c635efSGarrett D'Amore static	int	  termp_fd_pre(DECL_ARGS);
9995c635efSGarrett D'Amore static	int	  termp_fl_pre(DECL_ARGS);
10095c635efSGarrett D'Amore static	int	  termp_fn_pre(DECL_ARGS);
10195c635efSGarrett D'Amore static	int	  termp_fo_pre(DECL_ARGS);
10295c635efSGarrett D'Amore static	int	  termp_ft_pre(DECL_ARGS);
10395c635efSGarrett D'Amore static	int	  termp_in_pre(DECL_ARGS);
10495c635efSGarrett D'Amore static	int	  termp_it_pre(DECL_ARGS);
10595c635efSGarrett D'Amore static	int	  termp_li_pre(DECL_ARGS);
106*260e9a87SYuri Pankov static	int	  termp_ll_pre(DECL_ARGS);
10795c635efSGarrett D'Amore static	int	  termp_lk_pre(DECL_ARGS);
10895c635efSGarrett D'Amore static	int	  termp_nd_pre(DECL_ARGS);
10995c635efSGarrett D'Amore static	int	  termp_nm_pre(DECL_ARGS);
11095c635efSGarrett D'Amore static	int	  termp_ns_pre(DECL_ARGS);
11195c635efSGarrett D'Amore static	int	  termp_quote_pre(DECL_ARGS);
11295c635efSGarrett D'Amore static	int	  termp_rs_pre(DECL_ARGS);
11395c635efSGarrett D'Amore static	int	  termp_rv_pre(DECL_ARGS);
11495c635efSGarrett D'Amore static	int	  termp_sh_pre(DECL_ARGS);
115*260e9a87SYuri Pankov static	int	  termp_skip_pre(DECL_ARGS);
11695c635efSGarrett D'Amore static	int	  termp_sm_pre(DECL_ARGS);
11795c635efSGarrett D'Amore static	int	  termp_sp_pre(DECL_ARGS);
11895c635efSGarrett D'Amore static	int	  termp_ss_pre(DECL_ARGS);
11995c635efSGarrett D'Amore static	int	  termp_under_pre(DECL_ARGS);
12095c635efSGarrett D'Amore static	int	  termp_ud_pre(DECL_ARGS);
12195c635efSGarrett D'Amore static	int	  termp_vt_pre(DECL_ARGS);
12295c635efSGarrett D'Amore static	int	  termp_xr_pre(DECL_ARGS);
12395c635efSGarrett D'Amore static	int	  termp_xx_pre(DECL_ARGS);
12495c635efSGarrett D'Amore 
12595c635efSGarrett D'Amore static	const struct termact termacts[MDOC_MAX] = {
12695c635efSGarrett D'Amore 	{ termp_ap_pre, NULL }, /* Ap */
12795c635efSGarrett D'Amore 	{ NULL, NULL }, /* Dd */
12895c635efSGarrett D'Amore 	{ NULL, NULL }, /* Dt */
12995c635efSGarrett D'Amore 	{ NULL, NULL }, /* Os */
13095c635efSGarrett D'Amore 	{ termp_sh_pre, termp_sh_post }, /* Sh */
13195c635efSGarrett D'Amore 	{ termp_ss_pre, termp_ss_post }, /* Ss */
13295c635efSGarrett D'Amore 	{ termp_sp_pre, NULL }, /* Pp */
133698f87a4SGarrett D'Amore 	{ termp_d1_pre, termp_bl_post }, /* D1 */
134698f87a4SGarrett D'Amore 	{ termp_d1_pre, termp_bl_post }, /* Dl */
13595c635efSGarrett D'Amore 	{ termp_bd_pre, termp_bd_post }, /* Bd */
13695c635efSGarrett D'Amore 	{ NULL, NULL }, /* Ed */
13795c635efSGarrett D'Amore 	{ termp_bl_pre, termp_bl_post }, /* Bl */
13895c635efSGarrett D'Amore 	{ NULL, NULL }, /* El */
13995c635efSGarrett D'Amore 	{ termp_it_pre, termp_it_post }, /* It */
14095c635efSGarrett D'Amore 	{ termp_under_pre, NULL }, /* Ad */
141*260e9a87SYuri Pankov 	{ termp_an_pre, NULL }, /* An */
14295c635efSGarrett D'Amore 	{ termp_under_pre, NULL }, /* Ar */
14395c635efSGarrett D'Amore 	{ termp_cd_pre, NULL }, /* Cd */
14495c635efSGarrett D'Amore 	{ termp_bold_pre, NULL }, /* Cm */
14595c635efSGarrett D'Amore 	{ NULL, NULL }, /* Dv */
14695c635efSGarrett D'Amore 	{ NULL, NULL }, /* Er */
14795c635efSGarrett D'Amore 	{ NULL, NULL }, /* Ev */
14895c635efSGarrett D'Amore 	{ termp_ex_pre, NULL }, /* Ex */
14995c635efSGarrett D'Amore 	{ termp_fa_pre, NULL }, /* Fa */
150698f87a4SGarrett D'Amore 	{ termp_fd_pre, termp_fd_post }, /* Fd */
15195c635efSGarrett D'Amore 	{ termp_fl_pre, NULL }, /* Fl */
15295c635efSGarrett D'Amore 	{ termp_fn_pre, NULL }, /* Fn */
15395c635efSGarrett D'Amore 	{ termp_ft_pre, NULL }, /* Ft */
15495c635efSGarrett D'Amore 	{ termp_bold_pre, NULL }, /* Ic */
15595c635efSGarrett D'Amore 	{ termp_in_pre, termp_in_post }, /* In */
15695c635efSGarrett D'Amore 	{ termp_li_pre, NULL }, /* Li */
15795c635efSGarrett D'Amore 	{ termp_nd_pre, NULL }, /* Nd */
15895c635efSGarrett D'Amore 	{ termp_nm_pre, termp_nm_post }, /* Nm */
15995c635efSGarrett D'Amore 	{ termp_quote_pre, termp_quote_post }, /* Op */
160*260e9a87SYuri Pankov 	{ termp_ft_pre, NULL }, /* Ot */
16195c635efSGarrett D'Amore 	{ termp_under_pre, NULL }, /* Pa */
16295c635efSGarrett D'Amore 	{ termp_rv_pre, NULL }, /* Rv */
16395c635efSGarrett D'Amore 	{ NULL, NULL }, /* St */
16495c635efSGarrett D'Amore 	{ termp_under_pre, NULL }, /* Va */
16595c635efSGarrett D'Amore 	{ termp_vt_pre, NULL }, /* Vt */
16695c635efSGarrett D'Amore 	{ termp_xr_pre, NULL }, /* Xr */
16795c635efSGarrett D'Amore 	{ termp__a_pre, termp____post }, /* %A */
16895c635efSGarrett D'Amore 	{ termp_under_pre, termp____post }, /* %B */
16995c635efSGarrett D'Amore 	{ NULL, termp____post }, /* %D */
17095c635efSGarrett D'Amore 	{ termp_under_pre, termp____post }, /* %I */
17195c635efSGarrett D'Amore 	{ termp_under_pre, termp____post }, /* %J */
17295c635efSGarrett D'Amore 	{ NULL, termp____post }, /* %N */
17395c635efSGarrett D'Amore 	{ NULL, termp____post }, /* %O */
17495c635efSGarrett D'Amore 	{ NULL, termp____post }, /* %P */
17595c635efSGarrett D'Amore 	{ NULL, termp____post }, /* %R */
17695c635efSGarrett D'Amore 	{ termp__t_pre, termp__t_post }, /* %T */
17795c635efSGarrett D'Amore 	{ NULL, termp____post }, /* %V */
17895c635efSGarrett D'Amore 	{ NULL, NULL }, /* Ac */
17995c635efSGarrett D'Amore 	{ termp_quote_pre, termp_quote_post }, /* Ao */
18095c635efSGarrett D'Amore 	{ termp_quote_pre, termp_quote_post }, /* Aq */
18195c635efSGarrett D'Amore 	{ NULL, NULL }, /* At */
18295c635efSGarrett D'Amore 	{ NULL, NULL }, /* Bc */
18395c635efSGarrett D'Amore 	{ termp_bf_pre, NULL }, /* Bf */
18495c635efSGarrett D'Amore 	{ termp_quote_pre, termp_quote_post }, /* Bo */
18595c635efSGarrett D'Amore 	{ termp_quote_pre, termp_quote_post }, /* Bq */
18695c635efSGarrett D'Amore 	{ termp_xx_pre, NULL }, /* Bsx */
18795c635efSGarrett D'Amore 	{ termp_bx_pre, NULL }, /* Bx */
188*260e9a87SYuri Pankov 	{ termp_skip_pre, NULL }, /* Db */
18995c635efSGarrett D'Amore 	{ NULL, NULL }, /* Dc */
19095c635efSGarrett D'Amore 	{ termp_quote_pre, termp_quote_post }, /* Do */
19195c635efSGarrett D'Amore 	{ termp_quote_pre, termp_quote_post }, /* Dq */
19295c635efSGarrett D'Amore 	{ NULL, NULL }, /* Ec */ /* FIXME: no space */
19395c635efSGarrett D'Amore 	{ NULL, NULL }, /* Ef */
19495c635efSGarrett D'Amore 	{ termp_under_pre, NULL }, /* Em */
195*260e9a87SYuri Pankov 	{ termp_eo_pre, termp_eo_post }, /* Eo */
19695c635efSGarrett D'Amore 	{ termp_xx_pre, NULL }, /* Fx */
19795c635efSGarrett D'Amore 	{ termp_bold_pre, NULL }, /* Ms */
198*260e9a87SYuri Pankov 	{ termp_li_pre, NULL }, /* No */
19995c635efSGarrett D'Amore 	{ termp_ns_pre, NULL }, /* Ns */
20095c635efSGarrett D'Amore 	{ termp_xx_pre, NULL }, /* Nx */
20195c635efSGarrett D'Amore 	{ termp_xx_pre, NULL }, /* Ox */
20295c635efSGarrett D'Amore 	{ NULL, NULL }, /* Pc */
203698f87a4SGarrett D'Amore 	{ NULL, termp_pf_post }, /* Pf */
20495c635efSGarrett D'Amore 	{ termp_quote_pre, termp_quote_post }, /* Po */
20595c635efSGarrett D'Amore 	{ termp_quote_pre, termp_quote_post }, /* Pq */
20695c635efSGarrett D'Amore 	{ NULL, NULL }, /* Qc */
20795c635efSGarrett D'Amore 	{ termp_quote_pre, termp_quote_post }, /* Ql */
20895c635efSGarrett D'Amore 	{ termp_quote_pre, termp_quote_post }, /* Qo */
20995c635efSGarrett D'Amore 	{ termp_quote_pre, termp_quote_post }, /* Qq */
21095c635efSGarrett D'Amore 	{ NULL, NULL }, /* Re */
21195c635efSGarrett D'Amore 	{ termp_rs_pre, NULL }, /* Rs */
21295c635efSGarrett D'Amore 	{ NULL, NULL }, /* Sc */
21395c635efSGarrett D'Amore 	{ termp_quote_pre, termp_quote_post }, /* So */
21495c635efSGarrett D'Amore 	{ termp_quote_pre, termp_quote_post }, /* Sq */
21595c635efSGarrett D'Amore 	{ termp_sm_pre, NULL }, /* Sm */
21695c635efSGarrett D'Amore 	{ termp_under_pre, NULL }, /* Sx */
21795c635efSGarrett D'Amore 	{ termp_bold_pre, NULL }, /* Sy */
21895c635efSGarrett D'Amore 	{ NULL, NULL }, /* Tn */
21995c635efSGarrett D'Amore 	{ termp_xx_pre, NULL }, /* Ux */
22095c635efSGarrett D'Amore 	{ NULL, NULL }, /* Xc */
22195c635efSGarrett D'Amore 	{ NULL, NULL }, /* Xo */
22295c635efSGarrett D'Amore 	{ termp_fo_pre, termp_fo_post }, /* Fo */
22395c635efSGarrett D'Amore 	{ NULL, NULL }, /* Fc */
22495c635efSGarrett D'Amore 	{ termp_quote_pre, termp_quote_post }, /* Oo */
22595c635efSGarrett D'Amore 	{ NULL, NULL }, /* Oc */
22695c635efSGarrett D'Amore 	{ termp_bk_pre, termp_bk_post }, /* Bk */
22795c635efSGarrett D'Amore 	{ NULL, NULL }, /* Ek */
22895c635efSGarrett D'Amore 	{ termp_bt_pre, NULL }, /* Bt */
22995c635efSGarrett D'Amore 	{ NULL, NULL }, /* Hf */
230*260e9a87SYuri Pankov 	{ termp_under_pre, NULL }, /* Fr */
23195c635efSGarrett D'Amore 	{ termp_ud_pre, NULL }, /* Ud */
23295c635efSGarrett D'Amore 	{ NULL, termp_lb_post }, /* Lb */
23395c635efSGarrett D'Amore 	{ termp_sp_pre, NULL }, /* Lp */
23495c635efSGarrett D'Amore 	{ termp_lk_pre, NULL }, /* Lk */
23595c635efSGarrett D'Amore 	{ termp_under_pre, NULL }, /* Mt */
23695c635efSGarrett D'Amore 	{ termp_quote_pre, termp_quote_post }, /* Brq */
23795c635efSGarrett D'Amore 	{ termp_quote_pre, termp_quote_post }, /* Bro */
23895c635efSGarrett D'Amore 	{ NULL, NULL }, /* Brc */
23995c635efSGarrett D'Amore 	{ NULL, termp____post }, /* %C */
240*260e9a87SYuri Pankov 	{ termp_skip_pre, NULL }, /* Es */
241*260e9a87SYuri Pankov 	{ termp_quote_pre, termp_quote_post }, /* En */
24295c635efSGarrett D'Amore 	{ termp_xx_pre, NULL }, /* Dx */
24395c635efSGarrett D'Amore 	{ NULL, termp____post }, /* %Q */
24495c635efSGarrett D'Amore 	{ termp_sp_pre, NULL }, /* br */
24595c635efSGarrett D'Amore 	{ termp_sp_pre, NULL }, /* sp */
246698f87a4SGarrett D'Amore 	{ NULL, termp____post }, /* %U */
24795c635efSGarrett D'Amore 	{ NULL, NULL }, /* Ta */
248*260e9a87SYuri Pankov 	{ termp_ll_pre, NULL }, /* ll */
24995c635efSGarrett D'Amore };
25095c635efSGarrett D'Amore 
25195c635efSGarrett D'Amore 
25295c635efSGarrett D'Amore void
25395c635efSGarrett D'Amore terminal_mdoc(void *arg, const struct mdoc *mdoc)
25495c635efSGarrett D'Amore {
255698f87a4SGarrett D'Amore 	const struct mdoc_meta	*meta;
256*260e9a87SYuri Pankov 	struct mdoc_node	*n;
25795c635efSGarrett D'Amore 	struct termp		*p;
25895c635efSGarrett D'Amore 
25995c635efSGarrett D'Amore 	p = (struct termp *)arg;
26095c635efSGarrett D'Amore 
26195c635efSGarrett D'Amore 	p->overstep = 0;
262*260e9a87SYuri Pankov 	p->rmargin = p->maxrmargin = p->defrmargin;
26395c635efSGarrett D'Amore 	p->tabwidth = term_len(p, 5);
26495c635efSGarrett D'Amore 
265*260e9a87SYuri Pankov 	n = mdoc_node(mdoc)->child;
266698f87a4SGarrett D'Amore 	meta = mdoc_meta(mdoc);
26795c635efSGarrett D'Amore 
268*260e9a87SYuri Pankov 	if (p->synopsisonly) {
269*260e9a87SYuri Pankov 		while (n != NULL) {
270*260e9a87SYuri Pankov 			if (n->tok == MDOC_Sh && n->sec == SEC_SYNOPSIS) {
271*260e9a87SYuri Pankov 				if (n->child->next->child != NULL)
272*260e9a87SYuri Pankov 					print_mdoc_nodelist(p, NULL,
273*260e9a87SYuri Pankov 					    meta, n->child->next->child);
274*260e9a87SYuri Pankov 				term_newln(p);
275*260e9a87SYuri Pankov 				break;
276*260e9a87SYuri Pankov 			}
277*260e9a87SYuri Pankov 			n = n->next;
278*260e9a87SYuri Pankov 		}
279*260e9a87SYuri Pankov 	} else {
280*260e9a87SYuri Pankov 		if (p->defindent == 0)
281*260e9a87SYuri Pankov 			p->defindent = 5;
282698f87a4SGarrett D'Amore 		term_begin(p, print_mdoc_head, print_mdoc_foot, meta);
283*260e9a87SYuri Pankov 		if (n != NULL) {
284*260e9a87SYuri Pankov 			if (n->tok != MDOC_Sh)
285*260e9a87SYuri Pankov 				term_vspace(p);
286*260e9a87SYuri Pankov 			print_mdoc_nodelist(p, NULL, meta, n);
287*260e9a87SYuri Pankov 		}
28895c635efSGarrett D'Amore 		term_end(p);
28995c635efSGarrett D'Amore 	}
290*260e9a87SYuri Pankov }
29195c635efSGarrett D'Amore 
29295c635efSGarrett D'Amore static void
29395c635efSGarrett D'Amore print_mdoc_nodelist(DECL_ARGS)
29495c635efSGarrett D'Amore {
29595c635efSGarrett D'Amore 
296*260e9a87SYuri Pankov 	while (n != NULL) {
297698f87a4SGarrett D'Amore 		print_mdoc_node(p, pair, meta, n);
298*260e9a87SYuri Pankov 		n = n->next;
299*260e9a87SYuri Pankov 	}
30095c635efSGarrett D'Amore }
30195c635efSGarrett D'Amore 
30295c635efSGarrett D'Amore static void
30395c635efSGarrett D'Amore print_mdoc_node(DECL_ARGS)
30495c635efSGarrett D'Amore {
30595c635efSGarrett D'Amore 	int		 chld;
30695c635efSGarrett D'Amore 	struct termpair	 npair;
30795c635efSGarrett D'Amore 	size_t		 offset, rmargin;
30895c635efSGarrett D'Amore 
30995c635efSGarrett D'Amore 	chld = 1;
31095c635efSGarrett D'Amore 	offset = p->offset;
31195c635efSGarrett D'Amore 	rmargin = p->rmargin;
312*260e9a87SYuri Pankov 	n->flags &= ~MDOC_ENDED;
313*260e9a87SYuri Pankov 	n->prev_font = p->fonti;
31495c635efSGarrett D'Amore 
31595c635efSGarrett D'Amore 	memset(&npair, 0, sizeof(struct termpair));
31695c635efSGarrett D'Amore 	npair.ppair = pair;
31795c635efSGarrett D'Amore 
31895c635efSGarrett D'Amore 	/*
31995c635efSGarrett D'Amore 	 * Keeps only work until the end of a line.  If a keep was
32095c635efSGarrett D'Amore 	 * invoked in a prior line, revert it to PREKEEP.
32195c635efSGarrett D'Amore 	 */
32295c635efSGarrett D'Amore 
323*260e9a87SYuri Pankov 	if (p->flags & TERMP_KEEP && n->flags & MDOC_LINE) {
32495c635efSGarrett D'Amore 		p->flags &= ~TERMP_KEEP;
32595c635efSGarrett D'Amore 		p->flags |= TERMP_PREKEEP;
32695c635efSGarrett D'Amore 	}
32795c635efSGarrett D'Amore 
32895c635efSGarrett D'Amore 	/*
32995c635efSGarrett D'Amore 	 * After the keep flags have been set up, we may now
33095c635efSGarrett D'Amore 	 * produce output.  Note that some pre-handlers do so.
33195c635efSGarrett D'Amore 	 */
33295c635efSGarrett D'Amore 
33395c635efSGarrett D'Amore 	switch (n->type) {
334*260e9a87SYuri Pankov 	case MDOC_TEXT:
33595c635efSGarrett D'Amore 		if (' ' == *n->string && MDOC_LINE & n->flags)
33695c635efSGarrett D'Amore 			term_newln(p);
33795c635efSGarrett D'Amore 		if (MDOC_DELIMC & n->flags)
33895c635efSGarrett D'Amore 			p->flags |= TERMP_NOSPACE;
33995c635efSGarrett D'Amore 		term_word(p, n->string);
34095c635efSGarrett D'Amore 		if (MDOC_DELIMO & n->flags)
34195c635efSGarrett D'Amore 			p->flags |= TERMP_NOSPACE;
34295c635efSGarrett D'Amore 		break;
343*260e9a87SYuri Pankov 	case MDOC_EQN:
344*260e9a87SYuri Pankov 		if ( ! (n->flags & MDOC_LINE))
345*260e9a87SYuri Pankov 			p->flags |= TERMP_NOSPACE;
34695c635efSGarrett D'Amore 		term_eqn(p, n->eqn);
347*260e9a87SYuri Pankov 		if (n->next != NULL && ! (n->next->flags & MDOC_LINE))
348*260e9a87SYuri Pankov 			p->flags |= TERMP_NOSPACE;
34995c635efSGarrett D'Amore 		break;
350*260e9a87SYuri Pankov 	case MDOC_TBL:
351*260e9a87SYuri Pankov 		if (p->tbl.cols == NULL)
352*260e9a87SYuri Pankov 			term_newln(p);
35395c635efSGarrett D'Amore 		term_tbl(p, n->span);
35495c635efSGarrett D'Amore 		break;
35595c635efSGarrett D'Amore 	default:
356*260e9a87SYuri Pankov 		if (termacts[n->tok].pre &&
357*260e9a87SYuri Pankov 		    (n->end == ENDBODY_NOT || n->nchild))
35895c635efSGarrett D'Amore 			chld = (*termacts[n->tok].pre)
359698f87a4SGarrett D'Amore 				(p, &npair, meta, n);
36095c635efSGarrett D'Amore 		break;
36195c635efSGarrett D'Amore 	}
36295c635efSGarrett D'Amore 
36395c635efSGarrett D'Amore 	if (chld && n->child)
364698f87a4SGarrett D'Amore 		print_mdoc_nodelist(p, &npair, meta, n->child);
36595c635efSGarrett D'Amore 
366698f87a4SGarrett D'Amore 	term_fontpopq(p,
367*260e9a87SYuri Pankov 	    (ENDBODY_NOT == n->end ? n : n->body)->prev_font);
36895c635efSGarrett D'Amore 
36995c635efSGarrett D'Amore 	switch (n->type) {
370*260e9a87SYuri Pankov 	case MDOC_TEXT:
37195c635efSGarrett D'Amore 		break;
372*260e9a87SYuri Pankov 	case MDOC_TBL:
37395c635efSGarrett D'Amore 		break;
374*260e9a87SYuri Pankov 	case MDOC_EQN:
37595c635efSGarrett D'Amore 		break;
37695c635efSGarrett D'Amore 	default:
37795c635efSGarrett D'Amore 		if ( ! termacts[n->tok].post || MDOC_ENDED & n->flags)
37895c635efSGarrett D'Amore 			break;
379698f87a4SGarrett D'Amore 		(void)(*termacts[n->tok].post)(p, &npair, meta, n);
38095c635efSGarrett D'Amore 
38195c635efSGarrett D'Amore 		/*
38295c635efSGarrett D'Amore 		 * Explicit end tokens not only call the post
38395c635efSGarrett D'Amore 		 * handler, but also tell the respective block
38495c635efSGarrett D'Amore 		 * that it must not call the post handler again.
38595c635efSGarrett D'Amore 		 */
38695c635efSGarrett D'Amore 		if (ENDBODY_NOT != n->end)
387*260e9a87SYuri Pankov 			n->body->flags |= MDOC_ENDED;
38895c635efSGarrett D'Amore 
38995c635efSGarrett D'Amore 		/*
39095c635efSGarrett D'Amore 		 * End of line terminating an implicit block
39195c635efSGarrett D'Amore 		 * while an explicit block is still open.
39295c635efSGarrett D'Amore 		 * Continue the explicit block without spacing.
39395c635efSGarrett D'Amore 		 */
39495c635efSGarrett D'Amore 		if (ENDBODY_NOSPACE == n->end)
39595c635efSGarrett D'Amore 			p->flags |= TERMP_NOSPACE;
39695c635efSGarrett D'Amore 		break;
39795c635efSGarrett D'Amore 	}
39895c635efSGarrett D'Amore 
39995c635efSGarrett D'Amore 	if (MDOC_EOS & n->flags)
40095c635efSGarrett D'Amore 		p->flags |= TERMP_SENTENCE;
40195c635efSGarrett D'Amore 
402*260e9a87SYuri Pankov 	if (MDOC_ll != n->tok) {
40395c635efSGarrett D'Amore 		p->offset = offset;
40495c635efSGarrett D'Amore 		p->rmargin = rmargin;
40595c635efSGarrett D'Amore 	}
406*260e9a87SYuri Pankov }
40795c635efSGarrett D'Amore 
40895c635efSGarrett D'Amore static void
40995c635efSGarrett D'Amore print_mdoc_foot(struct termp *p, const void *arg)
41095c635efSGarrett D'Amore {
411698f87a4SGarrett D'Amore 	const struct mdoc_meta *meta;
412*260e9a87SYuri Pankov 	size_t sz;
41395c635efSGarrett D'Amore 
414698f87a4SGarrett D'Amore 	meta = (const struct mdoc_meta *)arg;
41595c635efSGarrett D'Amore 
41695c635efSGarrett D'Amore 	term_fontrepl(p, TERMFONT_NONE);
41795c635efSGarrett D'Amore 
41895c635efSGarrett D'Amore 	/*
41995c635efSGarrett D'Amore 	 * Output the footer in new-groff style, that is, three columns
42095c635efSGarrett D'Amore 	 * with the middle being the manual date and flanking columns
42195c635efSGarrett D'Amore 	 * being the operating system:
42295c635efSGarrett D'Amore 	 *
42395c635efSGarrett D'Amore 	 * SYSTEM                  DATE                    SYSTEM
42495c635efSGarrett D'Amore 	 */
42595c635efSGarrett D'Amore 
42695c635efSGarrett D'Amore 	term_vspace(p);
42795c635efSGarrett D'Amore 
42895c635efSGarrett D'Amore 	p->offset = 0;
429*260e9a87SYuri Pankov 	sz = term_strlen(p, meta->date);
430*260e9a87SYuri Pankov 	p->rmargin = p->maxrmargin > sz ?
431*260e9a87SYuri Pankov 	    (p->maxrmargin + term_len(p, 1) - sz) / 2 : 0;
432698f87a4SGarrett D'Amore 	p->trailspace = 1;
43395c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
43495c635efSGarrett D'Amore 
435698f87a4SGarrett D'Amore 	term_word(p, meta->os);
43695c635efSGarrett D'Amore 	term_flushln(p);
43795c635efSGarrett D'Amore 
43895c635efSGarrett D'Amore 	p->offset = p->rmargin;
439*260e9a87SYuri Pankov 	sz = term_strlen(p, meta->os);
440*260e9a87SYuri Pankov 	p->rmargin = p->maxrmargin > sz ? p->maxrmargin - sz : 0;
44195c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
44295c635efSGarrett D'Amore 
443698f87a4SGarrett D'Amore 	term_word(p, meta->date);
44495c635efSGarrett D'Amore 	term_flushln(p);
44595c635efSGarrett D'Amore 
44695c635efSGarrett D'Amore 	p->offset = p->rmargin;
44795c635efSGarrett D'Amore 	p->rmargin = p->maxrmargin;
448698f87a4SGarrett D'Amore 	p->trailspace = 0;
44995c635efSGarrett D'Amore 	p->flags &= ~TERMP_NOBREAK;
45095c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
45195c635efSGarrett D'Amore 
452698f87a4SGarrett D'Amore 	term_word(p, meta->os);
45395c635efSGarrett D'Amore 	term_flushln(p);
45495c635efSGarrett D'Amore 
45595c635efSGarrett D'Amore 	p->offset = 0;
45695c635efSGarrett D'Amore 	p->rmargin = p->maxrmargin;
45795c635efSGarrett D'Amore 	p->flags = 0;
45895c635efSGarrett D'Amore }
45995c635efSGarrett D'Amore 
46095c635efSGarrett D'Amore static void
46195c635efSGarrett D'Amore print_mdoc_head(struct termp *p, const void *arg)
46295c635efSGarrett D'Amore {
463698f87a4SGarrett D'Amore 	const struct mdoc_meta	*meta;
464*260e9a87SYuri Pankov 	char			*volume, *title;
465*260e9a87SYuri Pankov 	size_t			 vollen, titlen;
46695c635efSGarrett D'Amore 
467698f87a4SGarrett D'Amore 	meta = (const struct mdoc_meta *)arg;
46895c635efSGarrett D'Amore 
46995c635efSGarrett D'Amore 	/*
47095c635efSGarrett D'Amore 	 * The header is strange.  It has three components, which are
47195c635efSGarrett D'Amore 	 * really two with the first duplicated.  It goes like this:
47295c635efSGarrett D'Amore 	 *
47395c635efSGarrett D'Amore 	 * IDENTIFIER              TITLE                   IDENTIFIER
47495c635efSGarrett D'Amore 	 *
47595c635efSGarrett D'Amore 	 * The IDENTIFIER is NAME(SECTION), which is the command-name
47695c635efSGarrett D'Amore 	 * (if given, or "unknown" if not) followed by the manual page
47795c635efSGarrett D'Amore 	 * section.  These are given in `Dt'.  The TITLE is a free-form
47895c635efSGarrett D'Amore 	 * string depending on the manual volume.  If not specified, it
47995c635efSGarrett D'Amore 	 * switches on the manual section.
48095c635efSGarrett D'Amore 	 */
48195c635efSGarrett D'Amore 
482698f87a4SGarrett D'Amore 	assert(meta->vol);
483*260e9a87SYuri Pankov 	if (NULL == meta->arch)
484*260e9a87SYuri Pankov 		volume = mandoc_strdup(meta->vol);
485*260e9a87SYuri Pankov 	else
486*260e9a87SYuri Pankov 		mandoc_asprintf(&volume, "%s (%s)",
487*260e9a87SYuri Pankov 		    meta->vol, meta->arch);
488*260e9a87SYuri Pankov 	vollen = term_strlen(p, volume);
48995c635efSGarrett D'Amore 
490*260e9a87SYuri Pankov 	if (NULL == meta->msec)
491*260e9a87SYuri Pankov 		title = mandoc_strdup(meta->title);
492*260e9a87SYuri Pankov 	else
493*260e9a87SYuri Pankov 		mandoc_asprintf(&title, "%s(%s)",
494*260e9a87SYuri Pankov 		    meta->title, meta->msec);
49595c635efSGarrett D'Amore 	titlen = term_strlen(p, title);
49695c635efSGarrett D'Amore 
49795c635efSGarrett D'Amore 	p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
498698f87a4SGarrett D'Amore 	p->trailspace = 1;
49995c635efSGarrett D'Amore 	p->offset = 0;
500*260e9a87SYuri Pankov 	p->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
501*260e9a87SYuri Pankov 	    (p->maxrmargin - vollen + term_len(p, 1)) / 2 :
502*260e9a87SYuri Pankov 	    vollen < p->maxrmargin ?  p->maxrmargin - vollen : 0;
50395c635efSGarrett D'Amore 
50495c635efSGarrett D'Amore 	term_word(p, title);
50595c635efSGarrett D'Amore 	term_flushln(p);
50695c635efSGarrett D'Amore 
50795c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
50895c635efSGarrett D'Amore 	p->offset = p->rmargin;
509*260e9a87SYuri Pankov 	p->rmargin = p->offset + vollen + titlen < p->maxrmargin ?
51095c635efSGarrett D'Amore 	    p->maxrmargin - titlen : p->maxrmargin;
51195c635efSGarrett D'Amore 
512*260e9a87SYuri Pankov 	term_word(p, volume);
51395c635efSGarrett D'Amore 	term_flushln(p);
51495c635efSGarrett D'Amore 
51595c635efSGarrett D'Amore 	p->flags &= ~TERMP_NOBREAK;
516698f87a4SGarrett D'Amore 	p->trailspace = 0;
51795c635efSGarrett D'Amore 	if (p->rmargin + titlen <= p->maxrmargin) {
51895c635efSGarrett D'Amore 		p->flags |= TERMP_NOSPACE;
51995c635efSGarrett D'Amore 		p->offset = p->rmargin;
52095c635efSGarrett D'Amore 		p->rmargin = p->maxrmargin;
52195c635efSGarrett D'Amore 		term_word(p, title);
52295c635efSGarrett D'Amore 		term_flushln(p);
52395c635efSGarrett D'Amore 	}
52495c635efSGarrett D'Amore 
52595c635efSGarrett D'Amore 	p->flags &= ~TERMP_NOSPACE;
52695c635efSGarrett D'Amore 	p->offset = 0;
52795c635efSGarrett D'Amore 	p->rmargin = p->maxrmargin;
528*260e9a87SYuri Pankov 	free(title);
529*260e9a87SYuri Pankov 	free(volume);
53095c635efSGarrett D'Amore }
53195c635efSGarrett D'Amore 
532*260e9a87SYuri Pankov static int
53395c635efSGarrett D'Amore a2width(const struct termp *p, const char *v)
53495c635efSGarrett D'Amore {
53595c635efSGarrett D'Amore 	struct roffsu	 su;
53695c635efSGarrett D'Amore 
537*260e9a87SYuri Pankov 	if (a2roffsu(v, &su, SCALE_MAX) < 2) {
53895c635efSGarrett D'Amore 		SCALE_HS_INIT(&su, term_strlen(p, v));
539*260e9a87SYuri Pankov 		su.scale /= term_strlen(p, "0");
540*260e9a87SYuri Pankov 	}
54195c635efSGarrett D'Amore 	return(term_hspan(p, &su));
54295c635efSGarrett D'Amore }
54395c635efSGarrett D'Amore 
54495c635efSGarrett D'Amore /*
54595c635efSGarrett D'Amore  * Determine how much space to print out before block elements of `It'
54695c635efSGarrett D'Amore  * (and thus `Bl') and `Bd'.  And then go ahead and print that space,
54795c635efSGarrett D'Amore  * too.
54895c635efSGarrett D'Amore  */
54995c635efSGarrett D'Amore static void
55095c635efSGarrett D'Amore print_bvspace(struct termp *p,
55195c635efSGarrett D'Amore 	const struct mdoc_node *bl,
55295c635efSGarrett D'Amore 	const struct mdoc_node *n)
55395c635efSGarrett D'Amore {
55495c635efSGarrett D'Amore 	const struct mdoc_node	*nn;
55595c635efSGarrett D'Amore 
55695c635efSGarrett D'Amore 	assert(n);
55795c635efSGarrett D'Amore 
55895c635efSGarrett D'Amore 	term_newln(p);
55995c635efSGarrett D'Amore 
56095c635efSGarrett D'Amore 	if (MDOC_Bd == bl->tok && bl->norm->Bd.comp)
56195c635efSGarrett D'Amore 		return;
56295c635efSGarrett D'Amore 	if (MDOC_Bl == bl->tok && bl->norm->Bl.comp)
56395c635efSGarrett D'Amore 		return;
56495c635efSGarrett D'Amore 
56595c635efSGarrett D'Amore 	/* Do not vspace directly after Ss/Sh. */
56695c635efSGarrett D'Amore 
567*260e9a87SYuri Pankov 	nn = n;
568*260e9a87SYuri Pankov 	while (nn->prev == NULL) {
569*260e9a87SYuri Pankov 		do {
570*260e9a87SYuri Pankov 			nn = nn->parent;
571*260e9a87SYuri Pankov 			if (nn->type == MDOC_ROOT)
57295c635efSGarrett D'Amore 				return;
573*260e9a87SYuri Pankov 		} while (nn->type != MDOC_BLOCK);
574*260e9a87SYuri Pankov 		if (nn->tok == MDOC_Sh || nn->tok == MDOC_Ss)
57595c635efSGarrett D'Amore 			return;
576*260e9a87SYuri Pankov 		if (nn->tok == MDOC_It &&
577*260e9a87SYuri Pankov 		    nn->parent->parent->norm->Bl.type != LIST_item)
57895c635efSGarrett D'Amore 			break;
57995c635efSGarrett D'Amore 	}
58095c635efSGarrett D'Amore 
58195c635efSGarrett D'Amore 	/* A `-column' does not assert vspace within the list. */
58295c635efSGarrett D'Amore 
58395c635efSGarrett D'Amore 	if (MDOC_Bl == bl->tok && LIST_column == bl->norm->Bl.type)
58495c635efSGarrett D'Amore 		if (n->prev && MDOC_It == n->prev->tok)
58595c635efSGarrett D'Amore 			return;
58695c635efSGarrett D'Amore 
58795c635efSGarrett D'Amore 	/* A `-diag' without body does not vspace. */
58895c635efSGarrett D'Amore 
58995c635efSGarrett D'Amore 	if (MDOC_Bl == bl->tok && LIST_diag == bl->norm->Bl.type)
59095c635efSGarrett D'Amore 		if (n->prev && MDOC_It == n->prev->tok) {
59195c635efSGarrett D'Amore 			assert(n->prev->body);
59295c635efSGarrett D'Amore 			if (NULL == n->prev->body->child)
59395c635efSGarrett D'Amore 				return;
59495c635efSGarrett D'Amore 		}
59595c635efSGarrett D'Amore 
59695c635efSGarrett D'Amore 	term_vspace(p);
59795c635efSGarrett D'Amore }
59895c635efSGarrett D'Amore 
59995c635efSGarrett D'Amore 
600*260e9a87SYuri Pankov static int
601*260e9a87SYuri Pankov termp_ll_pre(DECL_ARGS)
602*260e9a87SYuri Pankov {
603*260e9a87SYuri Pankov 
604*260e9a87SYuri Pankov 	term_setwidth(p, n->nchild ? n->child->string : NULL);
605*260e9a87SYuri Pankov 	return(0);
606*260e9a87SYuri Pankov }
607*260e9a87SYuri Pankov 
60895c635efSGarrett D'Amore static int
60995c635efSGarrett D'Amore termp_it_pre(DECL_ARGS)
61095c635efSGarrett D'Amore {
611*260e9a87SYuri Pankov 	char			buf[24];
61295c635efSGarrett D'Amore 	const struct mdoc_node *bl, *nn;
613*260e9a87SYuri Pankov 	size_t			ncols, dcol;
614*260e9a87SYuri Pankov 	int			i, offset, width;
61595c635efSGarrett D'Amore 	enum mdoc_list		type;
61695c635efSGarrett D'Amore 
61795c635efSGarrett D'Amore 	if (MDOC_BLOCK == n->type) {
61895c635efSGarrett D'Amore 		print_bvspace(p, n->parent->parent, n);
61995c635efSGarrett D'Amore 		return(1);
62095c635efSGarrett D'Amore 	}
62195c635efSGarrett D'Amore 
62295c635efSGarrett D'Amore 	bl = n->parent->parent->parent;
62395c635efSGarrett D'Amore 	type = bl->norm->Bl.type;
62495c635efSGarrett D'Amore 
62595c635efSGarrett D'Amore 	/*
626*260e9a87SYuri Pankov 	 * Defaults for specific list types.
627*260e9a87SYuri Pankov 	 */
628*260e9a87SYuri Pankov 
629*260e9a87SYuri Pankov 	switch (type) {
630*260e9a87SYuri Pankov 	case LIST_bullet:
631*260e9a87SYuri Pankov 		/* FALLTHROUGH */
632*260e9a87SYuri Pankov 	case LIST_dash:
633*260e9a87SYuri Pankov 		/* FALLTHROUGH */
634*260e9a87SYuri Pankov 	case LIST_hyphen:
635*260e9a87SYuri Pankov 		/* FALLTHROUGH */
636*260e9a87SYuri Pankov 	case LIST_enum:
637*260e9a87SYuri Pankov 		width = term_len(p, 2);
638*260e9a87SYuri Pankov 		break;
639*260e9a87SYuri Pankov 	case LIST_hang:
640*260e9a87SYuri Pankov 		width = term_len(p, 8);
641*260e9a87SYuri Pankov 		break;
642*260e9a87SYuri Pankov 	case LIST_column:
643*260e9a87SYuri Pankov 		/* FALLTHROUGH */
644*260e9a87SYuri Pankov 	case LIST_tag:
645*260e9a87SYuri Pankov 		width = term_len(p, 10);
646*260e9a87SYuri Pankov 		break;
647*260e9a87SYuri Pankov 	default:
648*260e9a87SYuri Pankov 		width = 0;
649*260e9a87SYuri Pankov 		break;
650*260e9a87SYuri Pankov 	}
651*260e9a87SYuri Pankov 	offset = 0;
652*260e9a87SYuri Pankov 
653*260e9a87SYuri Pankov 	/*
65495c635efSGarrett D'Amore 	 * First calculate width and offset.  This is pretty easy unless
65595c635efSGarrett D'Amore 	 * we're a -column list, in which case all prior columns must
65695c635efSGarrett D'Amore 	 * be accounted for.
65795c635efSGarrett D'Amore 	 */
65895c635efSGarrett D'Amore 
659*260e9a87SYuri Pankov 	if (bl->norm->Bl.offs != NULL) {
660*260e9a87SYuri Pankov 		offset = a2width(p, bl->norm->Bl.offs);
661*260e9a87SYuri Pankov 		if (offset < 0 && (size_t)(-offset) > p->offset)
662*260e9a87SYuri Pankov 			offset = -p->offset;
663*260e9a87SYuri Pankov 		else if (offset > SHRT_MAX)
664*260e9a87SYuri Pankov 			offset = 0;
665*260e9a87SYuri Pankov 	}
66695c635efSGarrett D'Amore 
66795c635efSGarrett D'Amore 	switch (type) {
668*260e9a87SYuri Pankov 	case LIST_column:
66995c635efSGarrett D'Amore 		if (MDOC_HEAD == n->type)
67095c635efSGarrett D'Amore 			break;
67195c635efSGarrett D'Amore 
67295c635efSGarrett D'Amore 		/*
67395c635efSGarrett D'Amore 		 * Imitate groff's column handling:
67495c635efSGarrett D'Amore 		 * - For each earlier column, add its width.
67595c635efSGarrett D'Amore 		 * - For less than 5 columns, add four more blanks per
67695c635efSGarrett D'Amore 		 *   column.
67795c635efSGarrett D'Amore 		 * - For exactly 5 columns, add three more blank per
67895c635efSGarrett D'Amore 		 *   column.
67995c635efSGarrett D'Amore 		 * - For more than 5 columns, add only one column.
68095c635efSGarrett D'Amore 		 */
68195c635efSGarrett D'Amore 		ncols = bl->norm->Bl.ncols;
68295c635efSGarrett D'Amore 		dcol = ncols < 5 ? term_len(p, 4) :
68395c635efSGarrett D'Amore 		    ncols == 5 ? term_len(p, 3) : term_len(p, 1);
68495c635efSGarrett D'Amore 
68595c635efSGarrett D'Amore 		/*
68695c635efSGarrett D'Amore 		 * Calculate the offset by applying all prior MDOC_BODY,
68795c635efSGarrett D'Amore 		 * so we stop at the MDOC_HEAD (NULL == nn->prev).
68895c635efSGarrett D'Amore 		 */
68995c635efSGarrett D'Amore 
69095c635efSGarrett D'Amore 		for (i = 0, nn = n->prev;
69195c635efSGarrett D'Amore 		    nn->prev && i < (int)ncols;
69295c635efSGarrett D'Amore 		    nn = nn->prev, i++)
693*260e9a87SYuri Pankov 			offset += dcol + a2width(p,
694*260e9a87SYuri Pankov 			    bl->norm->Bl.cols[i]);
69595c635efSGarrett D'Amore 
69695c635efSGarrett D'Amore 		/*
69795c635efSGarrett D'Amore 		 * When exceeding the declared number of columns, leave
69895c635efSGarrett D'Amore 		 * the remaining widths at 0.  This will later be
69995c635efSGarrett D'Amore 		 * adjusted to the default width of 10, or, for the last
70095c635efSGarrett D'Amore 		 * column, stretched to the right margin.
70195c635efSGarrett D'Amore 		 */
70295c635efSGarrett D'Amore 		if (i >= (int)ncols)
70395c635efSGarrett D'Amore 			break;
70495c635efSGarrett D'Amore 
70595c635efSGarrett D'Amore 		/*
70695c635efSGarrett D'Amore 		 * Use the declared column widths, extended as explained
70795c635efSGarrett D'Amore 		 * in the preceding paragraph.
70895c635efSGarrett D'Amore 		 */
70995c635efSGarrett D'Amore 		width = a2width(p, bl->norm->Bl.cols[i]) + dcol;
71095c635efSGarrett D'Amore 		break;
71195c635efSGarrett D'Amore 	default:
71295c635efSGarrett D'Amore 		if (NULL == bl->norm->Bl.width)
71395c635efSGarrett D'Amore 			break;
71495c635efSGarrett D'Amore 
71595c635efSGarrett D'Amore 		/*
71695c635efSGarrett D'Amore 		 * Note: buffer the width by 2, which is groff's magic
71795c635efSGarrett D'Amore 		 * number for buffering single arguments.  See the above
71895c635efSGarrett D'Amore 		 * handling for column for how this changes.
71995c635efSGarrett D'Amore 		 */
72095c635efSGarrett D'Amore 		width = a2width(p, bl->norm->Bl.width) + term_len(p, 2);
721*260e9a87SYuri Pankov 		if (width < 0 && (size_t)(-width) > p->offset)
722*260e9a87SYuri Pankov 			width = -p->offset;
723*260e9a87SYuri Pankov 		else if (width > SHRT_MAX)
724*260e9a87SYuri Pankov 			width = 0;
72595c635efSGarrett D'Amore 		break;
72695c635efSGarrett D'Amore 	}
72795c635efSGarrett D'Amore 
72895c635efSGarrett D'Amore 	/*
72995c635efSGarrett D'Amore 	 * Whitespace control.  Inset bodies need an initial space,
73095c635efSGarrett D'Amore 	 * while diagonal bodies need two.
73195c635efSGarrett D'Amore 	 */
73295c635efSGarrett D'Amore 
73395c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
73495c635efSGarrett D'Amore 
73595c635efSGarrett D'Amore 	switch (type) {
736*260e9a87SYuri Pankov 	case LIST_diag:
73795c635efSGarrett D'Amore 		if (MDOC_BODY == n->type)
73895c635efSGarrett D'Amore 			term_word(p, "\\ \\ ");
73995c635efSGarrett D'Amore 		break;
740*260e9a87SYuri Pankov 	case LIST_inset:
741*260e9a87SYuri Pankov 		if (MDOC_BODY == n->type && n->parent->head->nchild)
74295c635efSGarrett D'Amore 			term_word(p, "\\ ");
74395c635efSGarrett D'Amore 		break;
74495c635efSGarrett D'Amore 	default:
74595c635efSGarrett D'Amore 		break;
74695c635efSGarrett D'Amore 	}
74795c635efSGarrett D'Amore 
74895c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
74995c635efSGarrett D'Amore 
75095c635efSGarrett D'Amore 	switch (type) {
751*260e9a87SYuri Pankov 	case LIST_diag:
75295c635efSGarrett D'Amore 		if (MDOC_HEAD == n->type)
75395c635efSGarrett D'Amore 			term_fontpush(p, TERMFONT_BOLD);
75495c635efSGarrett D'Amore 		break;
75595c635efSGarrett D'Amore 	default:
75695c635efSGarrett D'Amore 		break;
75795c635efSGarrett D'Amore 	}
75895c635efSGarrett D'Amore 
75995c635efSGarrett D'Amore 	/*
76095c635efSGarrett D'Amore 	 * Pad and break control.  This is the tricky part.  These flags
76195c635efSGarrett D'Amore 	 * are documented in term_flushln() in term.c.  Note that we're
76295c635efSGarrett D'Amore 	 * going to unset all of these flags in termp_it_post() when we
76395c635efSGarrett D'Amore 	 * exit.
76495c635efSGarrett D'Amore 	 */
76595c635efSGarrett D'Amore 
76695c635efSGarrett D'Amore 	switch (type) {
767*260e9a87SYuri Pankov 	case LIST_enum:
768698f87a4SGarrett D'Amore 		/*
769698f87a4SGarrett D'Amore 		 * Weird special case.
770*260e9a87SYuri Pankov 		 * Some very narrow lists actually hang.
771698f87a4SGarrett D'Amore 		 */
772*260e9a87SYuri Pankov 		/* FALLTHROUGH */
773*260e9a87SYuri Pankov 	case LIST_bullet:
774*260e9a87SYuri Pankov 		/* FALLTHROUGH */
775*260e9a87SYuri Pankov 	case LIST_dash:
776*260e9a87SYuri Pankov 		/* FALLTHROUGH */
777*260e9a87SYuri Pankov 	case LIST_hyphen:
778*260e9a87SYuri Pankov 		if (width <= (int)term_len(p, 2))
779698f87a4SGarrett D'Amore 			p->flags |= TERMP_HANG;
780698f87a4SGarrett D'Amore 		if (MDOC_HEAD != n->type)
781698f87a4SGarrett D'Amore 			break;
78295c635efSGarrett D'Amore 		p->flags |= TERMP_NOBREAK;
783698f87a4SGarrett D'Amore 		p->trailspace = 1;
78495c635efSGarrett D'Amore 		break;
785*260e9a87SYuri Pankov 	case LIST_hang:
786698f87a4SGarrett D'Amore 		if (MDOC_HEAD != n->type)
78795c635efSGarrett D'Amore 			break;
78895c635efSGarrett D'Amore 
78995c635efSGarrett D'Amore 		/*
79095c635efSGarrett D'Amore 		 * This is ugly.  If `-hang' is specified and the body
79195c635efSGarrett D'Amore 		 * is a `Bl' or `Bd', then we want basically to nullify
79295c635efSGarrett D'Amore 		 * the "overstep" effect in term_flushln() and treat
79395c635efSGarrett D'Amore 		 * this as a `-ohang' list instead.
79495c635efSGarrett D'Amore 		 */
795*260e9a87SYuri Pankov 		if (NULL != n->next &&
796*260e9a87SYuri Pankov 		    NULL != n->next->child &&
79795c635efSGarrett D'Amore 		    (MDOC_Bl == n->next->child->tok ||
79895c635efSGarrett D'Amore 		     MDOC_Bd == n->next->child->tok))
799698f87a4SGarrett D'Amore 			break;
800698f87a4SGarrett D'Amore 
801*260e9a87SYuri Pankov 		p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
802698f87a4SGarrett D'Amore 		p->trailspace = 1;
80395c635efSGarrett D'Amore 		break;
804*260e9a87SYuri Pankov 	case LIST_tag:
80595c635efSGarrett D'Amore 		if (MDOC_HEAD != n->type)
80695c635efSGarrett D'Amore 			break;
807698f87a4SGarrett D'Amore 
808*260e9a87SYuri Pankov 		p->flags |= TERMP_NOBREAK | TERMP_BRIND;
809698f87a4SGarrett D'Amore 		p->trailspace = 2;
810698f87a4SGarrett D'Amore 
81195c635efSGarrett D'Amore 		if (NULL == n->next || NULL == n->next->child)
81295c635efSGarrett D'Amore 			p->flags |= TERMP_DANGLE;
81395c635efSGarrett D'Amore 		break;
814*260e9a87SYuri Pankov 	case LIST_column:
81595c635efSGarrett D'Amore 		if (MDOC_HEAD == n->type)
81695c635efSGarrett D'Amore 			break;
81795c635efSGarrett D'Amore 
818698f87a4SGarrett D'Amore 		if (NULL == n->next) {
81995c635efSGarrett D'Amore 			p->flags &= ~TERMP_NOBREAK;
820698f87a4SGarrett D'Amore 			p->trailspace = 0;
821698f87a4SGarrett D'Amore 		} else {
82295c635efSGarrett D'Amore 			p->flags |= TERMP_NOBREAK;
823698f87a4SGarrett D'Amore 			p->trailspace = 1;
824698f87a4SGarrett D'Amore 		}
82595c635efSGarrett D'Amore 
82695c635efSGarrett D'Amore 		break;
827*260e9a87SYuri Pankov 	case LIST_diag:
828698f87a4SGarrett D'Amore 		if (MDOC_HEAD != n->type)
829698f87a4SGarrett D'Amore 			break;
830*260e9a87SYuri Pankov 		p->flags |= TERMP_NOBREAK | TERMP_BRIND;
831698f87a4SGarrett D'Amore 		p->trailspace = 1;
83295c635efSGarrett D'Amore 		break;
83395c635efSGarrett D'Amore 	default:
83495c635efSGarrett D'Amore 		break;
83595c635efSGarrett D'Amore 	}
83695c635efSGarrett D'Amore 
83795c635efSGarrett D'Amore 	/*
83895c635efSGarrett D'Amore 	 * Margin control.  Set-head-width lists have their right
83995c635efSGarrett D'Amore 	 * margins shortened.  The body for these lists has the offset
84095c635efSGarrett D'Amore 	 * necessarily lengthened.  Everybody gets the offset.
84195c635efSGarrett D'Amore 	 */
84295c635efSGarrett D'Amore 
84395c635efSGarrett D'Amore 	p->offset += offset;
84495c635efSGarrett D'Amore 
84595c635efSGarrett D'Amore 	switch (type) {
846*260e9a87SYuri Pankov 	case LIST_hang:
84795c635efSGarrett D'Amore 		/*
84895c635efSGarrett D'Amore 		 * Same stipulation as above, regarding `-hang'.  We
84995c635efSGarrett D'Amore 		 * don't want to recalculate rmargin and offsets when
85095c635efSGarrett D'Amore 		 * using `Bd' or `Bl' within `-hang' overstep lists.
85195c635efSGarrett D'Amore 		 */
852*260e9a87SYuri Pankov 		if (MDOC_HEAD == n->type &&
853*260e9a87SYuri Pankov 		    NULL != n->next &&
854*260e9a87SYuri Pankov 		    NULL != n->next->child &&
85595c635efSGarrett D'Amore 		    (MDOC_Bl == n->next->child->tok ||
85695c635efSGarrett D'Amore 		     MDOC_Bd == n->next->child->tok))
85795c635efSGarrett D'Amore 			break;
85895c635efSGarrett D'Amore 		/* FALLTHROUGH */
859*260e9a87SYuri Pankov 	case LIST_bullet:
86095c635efSGarrett D'Amore 		/* FALLTHROUGH */
861*260e9a87SYuri Pankov 	case LIST_dash:
86295c635efSGarrett D'Amore 		/* FALLTHROUGH */
863*260e9a87SYuri Pankov 	case LIST_enum:
86495c635efSGarrett D'Amore 		/* FALLTHROUGH */
865*260e9a87SYuri Pankov 	case LIST_hyphen:
86695c635efSGarrett D'Amore 		/* FALLTHROUGH */
867*260e9a87SYuri Pankov 	case LIST_tag:
86895c635efSGarrett D'Amore 		if (MDOC_HEAD == n->type)
86995c635efSGarrett D'Amore 			p->rmargin = p->offset + width;
87095c635efSGarrett D'Amore 		else
87195c635efSGarrett D'Amore 			p->offset += width;
87295c635efSGarrett D'Amore 		break;
873*260e9a87SYuri Pankov 	case LIST_column:
87495c635efSGarrett D'Amore 		assert(width);
87595c635efSGarrett D'Amore 		p->rmargin = p->offset + width;
87695c635efSGarrett D'Amore 		/*
87795c635efSGarrett D'Amore 		 * XXX - this behaviour is not documented: the
87895c635efSGarrett D'Amore 		 * right-most column is filled to the right margin.
87995c635efSGarrett D'Amore 		 */
88095c635efSGarrett D'Amore 		if (MDOC_HEAD == n->type)
88195c635efSGarrett D'Amore 			break;
88295c635efSGarrett D'Amore 		if (NULL == n->next && p->rmargin < p->maxrmargin)
88395c635efSGarrett D'Amore 			p->rmargin = p->maxrmargin;
88495c635efSGarrett D'Amore 		break;
88595c635efSGarrett D'Amore 	default:
88695c635efSGarrett D'Amore 		break;
88795c635efSGarrett D'Amore 	}
88895c635efSGarrett D'Amore 
88995c635efSGarrett D'Amore 	/*
89095c635efSGarrett D'Amore 	 * The dash, hyphen, bullet and enum lists all have a special
89195c635efSGarrett D'Amore 	 * HEAD character (temporarily bold, in some cases).
89295c635efSGarrett D'Amore 	 */
89395c635efSGarrett D'Amore 
89495c635efSGarrett D'Amore 	if (MDOC_HEAD == n->type)
89595c635efSGarrett D'Amore 		switch (type) {
896*260e9a87SYuri Pankov 		case LIST_bullet:
89795c635efSGarrett D'Amore 			term_fontpush(p, TERMFONT_BOLD);
89895c635efSGarrett D'Amore 			term_word(p, "\\[bu]");
89995c635efSGarrett D'Amore 			term_fontpop(p);
90095c635efSGarrett D'Amore 			break;
901*260e9a87SYuri Pankov 		case LIST_dash:
90295c635efSGarrett D'Amore 			/* FALLTHROUGH */
903*260e9a87SYuri Pankov 		case LIST_hyphen:
90495c635efSGarrett D'Amore 			term_fontpush(p, TERMFONT_BOLD);
90595c635efSGarrett D'Amore 			term_word(p, "\\(hy");
90695c635efSGarrett D'Amore 			term_fontpop(p);
90795c635efSGarrett D'Amore 			break;
908*260e9a87SYuri Pankov 		case LIST_enum:
90995c635efSGarrett D'Amore 			(pair->ppair->ppair->count)++;
910*260e9a87SYuri Pankov 			(void)snprintf(buf, sizeof(buf), "%d.",
91195c635efSGarrett D'Amore 			    pair->ppair->ppair->count);
91295c635efSGarrett D'Amore 			term_word(p, buf);
91395c635efSGarrett D'Amore 			break;
91495c635efSGarrett D'Amore 		default:
91595c635efSGarrett D'Amore 			break;
91695c635efSGarrett D'Amore 		}
91795c635efSGarrett D'Amore 
91895c635efSGarrett D'Amore 	/*
91995c635efSGarrett D'Amore 	 * If we're not going to process our children, indicate so here.
92095c635efSGarrett D'Amore 	 */
92195c635efSGarrett D'Amore 
92295c635efSGarrett D'Amore 	switch (type) {
923*260e9a87SYuri Pankov 	case LIST_bullet:
92495c635efSGarrett D'Amore 		/* FALLTHROUGH */
925*260e9a87SYuri Pankov 	case LIST_item:
92695c635efSGarrett D'Amore 		/* FALLTHROUGH */
927*260e9a87SYuri Pankov 	case LIST_dash:
92895c635efSGarrett D'Amore 		/* FALLTHROUGH */
929*260e9a87SYuri Pankov 	case LIST_hyphen:
93095c635efSGarrett D'Amore 		/* FALLTHROUGH */
931*260e9a87SYuri Pankov 	case LIST_enum:
93295c635efSGarrett D'Amore 		if (MDOC_HEAD == n->type)
93395c635efSGarrett D'Amore 			return(0);
93495c635efSGarrett D'Amore 		break;
935*260e9a87SYuri Pankov 	case LIST_column:
93695c635efSGarrett D'Amore 		if (MDOC_HEAD == n->type)
93795c635efSGarrett D'Amore 			return(0);
93895c635efSGarrett D'Amore 		break;
93995c635efSGarrett D'Amore 	default:
94095c635efSGarrett D'Amore 		break;
94195c635efSGarrett D'Amore 	}
94295c635efSGarrett D'Amore 
94395c635efSGarrett D'Amore 	return(1);
94495c635efSGarrett D'Amore }
94595c635efSGarrett D'Amore 
94695c635efSGarrett D'Amore static void
94795c635efSGarrett D'Amore termp_it_post(DECL_ARGS)
94895c635efSGarrett D'Amore {
94995c635efSGarrett D'Amore 	enum mdoc_list	   type;
95095c635efSGarrett D'Amore 
95195c635efSGarrett D'Amore 	if (MDOC_BLOCK == n->type)
95295c635efSGarrett D'Amore 		return;
95395c635efSGarrett D'Amore 
95495c635efSGarrett D'Amore 	type = n->parent->parent->parent->norm->Bl.type;
95595c635efSGarrett D'Amore 
95695c635efSGarrett D'Amore 	switch (type) {
957*260e9a87SYuri Pankov 	case LIST_item:
95895c635efSGarrett D'Amore 		/* FALLTHROUGH */
959*260e9a87SYuri Pankov 	case LIST_diag:
96095c635efSGarrett D'Amore 		/* FALLTHROUGH */
961*260e9a87SYuri Pankov 	case LIST_inset:
96295c635efSGarrett D'Amore 		if (MDOC_BODY == n->type)
96395c635efSGarrett D'Amore 			term_newln(p);
96495c635efSGarrett D'Amore 		break;
965*260e9a87SYuri Pankov 	case LIST_column:
96695c635efSGarrett D'Amore 		if (MDOC_BODY == n->type)
96795c635efSGarrett D'Amore 			term_flushln(p);
96895c635efSGarrett D'Amore 		break;
96995c635efSGarrett D'Amore 	default:
97095c635efSGarrett D'Amore 		term_newln(p);
97195c635efSGarrett D'Amore 		break;
97295c635efSGarrett D'Amore 	}
97395c635efSGarrett D'Amore 
97495c635efSGarrett D'Amore 	/*
97595c635efSGarrett D'Amore 	 * Now that our output is flushed, we can reset our tags.  Since
97695c635efSGarrett D'Amore 	 * only `It' sets these flags, we're free to assume that nobody
97795c635efSGarrett D'Amore 	 * has munged them in the meanwhile.
97895c635efSGarrett D'Amore 	 */
97995c635efSGarrett D'Amore 
980*260e9a87SYuri Pankov 	p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND |
981*260e9a87SYuri Pankov 			TERMP_DANGLE | TERMP_HANG);
982698f87a4SGarrett D'Amore 	p->trailspace = 0;
98395c635efSGarrett D'Amore }
98495c635efSGarrett D'Amore 
98595c635efSGarrett D'Amore static int
98695c635efSGarrett D'Amore termp_nm_pre(DECL_ARGS)
98795c635efSGarrett D'Amore {
988*260e9a87SYuri Pankov 	const char	*cp;
98995c635efSGarrett D'Amore 
990698f87a4SGarrett D'Amore 	if (MDOC_BLOCK == n->type) {
991698f87a4SGarrett D'Amore 		p->flags |= TERMP_PREKEEP;
99295c635efSGarrett D'Amore 		return(1);
993698f87a4SGarrett D'Amore 	}
99495c635efSGarrett D'Amore 
99595c635efSGarrett D'Amore 	if (MDOC_BODY == n->type) {
99695c635efSGarrett D'Amore 		if (NULL == n->child)
99795c635efSGarrett D'Amore 			return(0);
99895c635efSGarrett D'Amore 		p->flags |= TERMP_NOSPACE;
999*260e9a87SYuri Pankov 		cp = NULL;
1000*260e9a87SYuri Pankov 		if (n->prev->child != NULL)
1001*260e9a87SYuri Pankov 		    cp = n->prev->child->string;
1002*260e9a87SYuri Pankov 		if (cp == NULL)
1003*260e9a87SYuri Pankov 			cp = meta->name;
1004*260e9a87SYuri Pankov 		if (cp == NULL)
1005*260e9a87SYuri Pankov 			p->offset += term_len(p, 6);
1006*260e9a87SYuri Pankov 		else
1007*260e9a87SYuri Pankov 			p->offset += term_len(p, 1) + term_strlen(p, cp);
100895c635efSGarrett D'Amore 		return(1);
100995c635efSGarrett D'Amore 	}
101095c635efSGarrett D'Amore 
1011698f87a4SGarrett D'Amore 	if (NULL == n->child && NULL == meta->name)
101295c635efSGarrett D'Amore 		return(0);
101395c635efSGarrett D'Amore 
101495c635efSGarrett D'Amore 	if (MDOC_HEAD == n->type)
101595c635efSGarrett D'Amore 		synopsis_pre(p, n->parent);
101695c635efSGarrett D'Amore 
1017*260e9a87SYuri Pankov 	if (MDOC_HEAD == n->type &&
1018*260e9a87SYuri Pankov 	    NULL != n->next && NULL != n->next->child) {
1019*260e9a87SYuri Pankov 		p->flags |= TERMP_NOSPACE | TERMP_NOBREAK | TERMP_BRIND;
1020698f87a4SGarrett D'Amore 		p->trailspace = 1;
102195c635efSGarrett D'Amore 		p->rmargin = p->offset + term_len(p, 1);
102295c635efSGarrett D'Amore 		if (NULL == n->child) {
1023698f87a4SGarrett D'Amore 			p->rmargin += term_strlen(p, meta->name);
102495c635efSGarrett D'Amore 		} else if (MDOC_TEXT == n->child->type) {
102595c635efSGarrett D'Amore 			p->rmargin += term_strlen(p, n->child->string);
102695c635efSGarrett D'Amore 			if (n->child->next)
102795c635efSGarrett D'Amore 				p->flags |= TERMP_HANG;
102895c635efSGarrett D'Amore 		} else {
102995c635efSGarrett D'Amore 			p->rmargin += term_len(p, 5);
103095c635efSGarrett D'Amore 			p->flags |= TERMP_HANG;
103195c635efSGarrett D'Amore 		}
103295c635efSGarrett D'Amore 	}
103395c635efSGarrett D'Amore 
103495c635efSGarrett D'Amore 	term_fontpush(p, TERMFONT_BOLD);
103595c635efSGarrett D'Amore 	if (NULL == n->child)
1036698f87a4SGarrett D'Amore 		term_word(p, meta->name);
103795c635efSGarrett D'Amore 	return(1);
103895c635efSGarrett D'Amore }
103995c635efSGarrett D'Amore 
104095c635efSGarrett D'Amore static void
104195c635efSGarrett D'Amore termp_nm_post(DECL_ARGS)
104295c635efSGarrett D'Amore {
104395c635efSGarrett D'Amore 
1044698f87a4SGarrett D'Amore 	if (MDOC_BLOCK == n->type) {
1045698f87a4SGarrett D'Amore 		p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
1046*260e9a87SYuri Pankov 	} else if (MDOC_HEAD == n->type &&
1047*260e9a87SYuri Pankov 	    NULL != n->next && NULL != n->next->child) {
104895c635efSGarrett D'Amore 		term_flushln(p);
1049*260e9a87SYuri Pankov 		p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
1050698f87a4SGarrett D'Amore 		p->trailspace = 0;
105195c635efSGarrett D'Amore 	} else if (MDOC_BODY == n->type && n->child)
105295c635efSGarrett D'Amore 		term_flushln(p);
105395c635efSGarrett D'Amore }
105495c635efSGarrett D'Amore 
105595c635efSGarrett D'Amore static int
105695c635efSGarrett D'Amore termp_fl_pre(DECL_ARGS)
105795c635efSGarrett D'Amore {
105895c635efSGarrett D'Amore 
105995c635efSGarrett D'Amore 	term_fontpush(p, TERMFONT_BOLD);
106095c635efSGarrett D'Amore 	term_word(p, "\\-");
106195c635efSGarrett D'Amore 
1062*260e9a87SYuri Pankov 	if ( ! (n->nchild == 0 &&
1063*260e9a87SYuri Pankov 	    (n->next == NULL ||
1064*260e9a87SYuri Pankov 	     n->next->type == MDOC_TEXT ||
1065*260e9a87SYuri Pankov 	     n->next->flags & MDOC_LINE)))
106695c635efSGarrett D'Amore 		p->flags |= TERMP_NOSPACE;
106795c635efSGarrett D'Amore 
106895c635efSGarrett D'Amore 	return(1);
106995c635efSGarrett D'Amore }
107095c635efSGarrett D'Amore 
107195c635efSGarrett D'Amore static int
107295c635efSGarrett D'Amore termp__a_pre(DECL_ARGS)
107395c635efSGarrett D'Amore {
107495c635efSGarrett D'Amore 
107595c635efSGarrett D'Amore 	if (n->prev && MDOC__A == n->prev->tok)
107695c635efSGarrett D'Amore 		if (NULL == n->next || MDOC__A != n->next->tok)
107795c635efSGarrett D'Amore 			term_word(p, "and");
107895c635efSGarrett D'Amore 
107995c635efSGarrett D'Amore 	return(1);
108095c635efSGarrett D'Amore }
108195c635efSGarrett D'Amore 
108295c635efSGarrett D'Amore static int
108395c635efSGarrett D'Amore termp_an_pre(DECL_ARGS)
108495c635efSGarrett D'Amore {
108595c635efSGarrett D'Amore 
1086*260e9a87SYuri Pankov 	if (n->norm->An.auth == AUTH_split) {
108795c635efSGarrett D'Amore 		p->flags &= ~TERMP_NOSPLIT;
108895c635efSGarrett D'Amore 		p->flags |= TERMP_SPLIT;
1089*260e9a87SYuri Pankov 		return(0);
1090*260e9a87SYuri Pankov 	}
1091*260e9a87SYuri Pankov 	if (n->norm->An.auth == AUTH_nosplit) {
109295c635efSGarrett D'Amore 		p->flags &= ~TERMP_SPLIT;
109395c635efSGarrett D'Amore 		p->flags |= TERMP_NOSPLIT;
1094*260e9a87SYuri Pankov 		return(0);
109595c635efSGarrett D'Amore 	}
109695c635efSGarrett D'Amore 
1097*260e9a87SYuri Pankov 	if (p->flags & TERMP_SPLIT)
1098*260e9a87SYuri Pankov 		term_newln(p);
1099*260e9a87SYuri Pankov 
1100*260e9a87SYuri Pankov 	if (n->sec == SEC_AUTHORS && ! (p->flags & TERMP_NOSPLIT))
1101*260e9a87SYuri Pankov 		p->flags |= TERMP_SPLIT;
1102*260e9a87SYuri Pankov 
1103*260e9a87SYuri Pankov 	return(1);
110495c635efSGarrett D'Amore }
110595c635efSGarrett D'Amore 
110695c635efSGarrett D'Amore static int
110795c635efSGarrett D'Amore termp_ns_pre(DECL_ARGS)
110895c635efSGarrett D'Amore {
110995c635efSGarrett D'Amore 
111095c635efSGarrett D'Amore 	if ( ! (MDOC_LINE & n->flags))
111195c635efSGarrett D'Amore 		p->flags |= TERMP_NOSPACE;
111295c635efSGarrett D'Amore 	return(1);
111395c635efSGarrett D'Amore }
111495c635efSGarrett D'Amore 
111595c635efSGarrett D'Amore static int
111695c635efSGarrett D'Amore termp_rs_pre(DECL_ARGS)
111795c635efSGarrett D'Amore {
111895c635efSGarrett D'Amore 
111995c635efSGarrett D'Amore 	if (SEC_SEE_ALSO != n->sec)
112095c635efSGarrett D'Amore 		return(1);
112195c635efSGarrett D'Amore 	if (MDOC_BLOCK == n->type && n->prev)
112295c635efSGarrett D'Amore 		term_vspace(p);
112395c635efSGarrett D'Amore 	return(1);
112495c635efSGarrett D'Amore }
112595c635efSGarrett D'Amore 
112695c635efSGarrett D'Amore static int
112795c635efSGarrett D'Amore termp_rv_pre(DECL_ARGS)
112895c635efSGarrett D'Amore {
112995c635efSGarrett D'Amore 	int		 nchild;
113095c635efSGarrett D'Amore 
113195c635efSGarrett D'Amore 	term_newln(p);
113295c635efSGarrett D'Amore 
113395c635efSGarrett D'Amore 	nchild = n->nchild;
1134*260e9a87SYuri Pankov 	if (nchild > 0) {
1135*260e9a87SYuri Pankov 		term_word(p, "The");
1136*260e9a87SYuri Pankov 
113795c635efSGarrett D'Amore 		for (n = n->child; n; n = n->next) {
113895c635efSGarrett D'Amore 			term_fontpush(p, TERMFONT_BOLD);
113995c635efSGarrett D'Amore 			term_word(p, n->string);
114095c635efSGarrett D'Amore 			term_fontpop(p);
114195c635efSGarrett D'Amore 
114295c635efSGarrett D'Amore 			p->flags |= TERMP_NOSPACE;
114395c635efSGarrett D'Amore 			term_word(p, "()");
114495c635efSGarrett D'Amore 
1145*260e9a87SYuri Pankov 			if (n->next == NULL)
1146*260e9a87SYuri Pankov 				continue;
1147*260e9a87SYuri Pankov 
1148*260e9a87SYuri Pankov 			if (nchild > 2) {
114995c635efSGarrett D'Amore 				p->flags |= TERMP_NOSPACE;
115095c635efSGarrett D'Amore 				term_word(p, ",");
115195c635efSGarrett D'Amore 			}
1152*260e9a87SYuri Pankov 			if (n->next->next == NULL)
115395c635efSGarrett D'Amore 				term_word(p, "and");
115495c635efSGarrett D'Amore 		}
115595c635efSGarrett D'Amore 
115695c635efSGarrett D'Amore 		if (nchild > 1)
115795c635efSGarrett D'Amore 			term_word(p, "functions return");
115895c635efSGarrett D'Amore 		else
115995c635efSGarrett D'Amore 			term_word(p, "function returns");
116095c635efSGarrett D'Amore 
1161*260e9a87SYuri Pankov 		term_word(p, "the value\\~0 if successful;");
1162*260e9a87SYuri Pankov 	} else
1163*260e9a87SYuri Pankov 		term_word(p, "Upon successful completion,"
1164*260e9a87SYuri Pankov 		    " the value\\~0 is returned;");
1165*260e9a87SYuri Pankov 
1166*260e9a87SYuri Pankov 	term_word(p, "otherwise the value\\~\\-1 is returned"
1167*260e9a87SYuri Pankov 	    " and the global variable");
116895c635efSGarrett D'Amore 
116995c635efSGarrett D'Amore 	term_fontpush(p, TERMFONT_UNDER);
117095c635efSGarrett D'Amore 	term_word(p, "errno");
117195c635efSGarrett D'Amore 	term_fontpop(p);
117295c635efSGarrett D'Amore 
117395c635efSGarrett D'Amore 	term_word(p, "is set to indicate the error.");
117495c635efSGarrett D'Amore 	p->flags |= TERMP_SENTENCE;
117595c635efSGarrett D'Amore 
117695c635efSGarrett D'Amore 	return(0);
117795c635efSGarrett D'Amore }
117895c635efSGarrett D'Amore 
117995c635efSGarrett D'Amore static int
118095c635efSGarrett D'Amore termp_ex_pre(DECL_ARGS)
118195c635efSGarrett D'Amore {
118295c635efSGarrett D'Amore 	int		 nchild;
118395c635efSGarrett D'Amore 
118495c635efSGarrett D'Amore 	term_newln(p);
118595c635efSGarrett D'Amore 	term_word(p, "The");
118695c635efSGarrett D'Amore 
118795c635efSGarrett D'Amore 	nchild = n->nchild;
118895c635efSGarrett D'Amore 	for (n = n->child; n; n = n->next) {
118995c635efSGarrett D'Amore 		term_fontpush(p, TERMFONT_BOLD);
119095c635efSGarrett D'Amore 		term_word(p, n->string);
119195c635efSGarrett D'Amore 		term_fontpop(p);
119295c635efSGarrett D'Amore 
119395c635efSGarrett D'Amore 		if (nchild > 2 && n->next) {
119495c635efSGarrett D'Amore 			p->flags |= TERMP_NOSPACE;
119595c635efSGarrett D'Amore 			term_word(p, ",");
119695c635efSGarrett D'Amore 		}
119795c635efSGarrett D'Amore 
119895c635efSGarrett D'Amore 		if (n->next && NULL == n->next->next)
119995c635efSGarrett D'Amore 			term_word(p, "and");
120095c635efSGarrett D'Amore 	}
120195c635efSGarrett D'Amore 
120295c635efSGarrett D'Amore 	if (nchild > 1)
1203*260e9a87SYuri Pankov 		term_word(p, "utilities exit\\~0");
120495c635efSGarrett D'Amore 	else
1205*260e9a87SYuri Pankov 		term_word(p, "utility exits\\~0");
120695c635efSGarrett D'Amore 
1207*260e9a87SYuri Pankov 	term_word(p, "on success, and\\~>0 if an error occurs.");
120895c635efSGarrett D'Amore 
120995c635efSGarrett D'Amore 	p->flags |= TERMP_SENTENCE;
121095c635efSGarrett D'Amore 	return(0);
121195c635efSGarrett D'Amore }
121295c635efSGarrett D'Amore 
121395c635efSGarrett D'Amore static int
121495c635efSGarrett D'Amore termp_nd_pre(DECL_ARGS)
121595c635efSGarrett D'Amore {
121695c635efSGarrett D'Amore 
1217*260e9a87SYuri Pankov 	if (n->type == MDOC_BODY)
121895c635efSGarrett D'Amore 		term_word(p, "\\(en");
121995c635efSGarrett D'Amore 	return(1);
122095c635efSGarrett D'Amore }
122195c635efSGarrett D'Amore 
122295c635efSGarrett D'Amore static int
122395c635efSGarrett D'Amore termp_bl_pre(DECL_ARGS)
122495c635efSGarrett D'Amore {
122595c635efSGarrett D'Amore 
122695c635efSGarrett D'Amore 	return(MDOC_HEAD != n->type);
122795c635efSGarrett D'Amore }
122895c635efSGarrett D'Amore 
122995c635efSGarrett D'Amore static void
123095c635efSGarrett D'Amore termp_bl_post(DECL_ARGS)
123195c635efSGarrett D'Amore {
123295c635efSGarrett D'Amore 
123395c635efSGarrett D'Amore 	if (MDOC_BLOCK == n->type)
123495c635efSGarrett D'Amore 		term_newln(p);
123595c635efSGarrett D'Amore }
123695c635efSGarrett D'Amore 
123795c635efSGarrett D'Amore static int
123895c635efSGarrett D'Amore termp_xr_pre(DECL_ARGS)
123995c635efSGarrett D'Amore {
124095c635efSGarrett D'Amore 
124195c635efSGarrett D'Amore 	if (NULL == (n = n->child))
124295c635efSGarrett D'Amore 		return(0);
124395c635efSGarrett D'Amore 
124495c635efSGarrett D'Amore 	assert(MDOC_TEXT == n->type);
124595c635efSGarrett D'Amore 	term_word(p, n->string);
124695c635efSGarrett D'Amore 
124795c635efSGarrett D'Amore 	if (NULL == (n = n->next))
124895c635efSGarrett D'Amore 		return(0);
124995c635efSGarrett D'Amore 
125095c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
125195c635efSGarrett D'Amore 	term_word(p, "(");
125295c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
125395c635efSGarrett D'Amore 
125495c635efSGarrett D'Amore 	assert(MDOC_TEXT == n->type);
125595c635efSGarrett D'Amore 	term_word(p, n->string);
125695c635efSGarrett D'Amore 
125795c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
125895c635efSGarrett D'Amore 	term_word(p, ")");
125995c635efSGarrett D'Amore 
126095c635efSGarrett D'Amore 	return(0);
126195c635efSGarrett D'Amore }
126295c635efSGarrett D'Amore 
126395c635efSGarrett D'Amore /*
126495c635efSGarrett D'Amore  * This decides how to assert whitespace before any of the SYNOPSIS set
126595c635efSGarrett D'Amore  * of macros (which, as in the case of Ft/Fo and Ft/Fn, may contain
126695c635efSGarrett D'Amore  * macro combos).
126795c635efSGarrett D'Amore  */
126895c635efSGarrett D'Amore static void
126995c635efSGarrett D'Amore synopsis_pre(struct termp *p, const struct mdoc_node *n)
127095c635efSGarrett D'Amore {
127195c635efSGarrett D'Amore 	/*
127295c635efSGarrett D'Amore 	 * Obviously, if we're not in a SYNOPSIS or no prior macros
127395c635efSGarrett D'Amore 	 * exist, do nothing.
127495c635efSGarrett D'Amore 	 */
127595c635efSGarrett D'Amore 	if (NULL == n->prev || ! (MDOC_SYNPRETTY & n->flags))
127695c635efSGarrett D'Amore 		return;
127795c635efSGarrett D'Amore 
127895c635efSGarrett D'Amore 	/*
127995c635efSGarrett D'Amore 	 * If we're the second in a pair of like elements, emit our
128095c635efSGarrett D'Amore 	 * newline and return.  UNLESS we're `Fo', `Fn', `Fn', in which
128195c635efSGarrett D'Amore 	 * case we soldier on.
128295c635efSGarrett D'Amore 	 */
128395c635efSGarrett D'Amore 	if (n->prev->tok == n->tok &&
128495c635efSGarrett D'Amore 	    MDOC_Ft != n->tok &&
128595c635efSGarrett D'Amore 	    MDOC_Fo != n->tok &&
128695c635efSGarrett D'Amore 	    MDOC_Fn != n->tok) {
128795c635efSGarrett D'Amore 		term_newln(p);
128895c635efSGarrett D'Amore 		return;
128995c635efSGarrett D'Amore 	}
129095c635efSGarrett D'Amore 
129195c635efSGarrett D'Amore 	/*
129295c635efSGarrett D'Amore 	 * If we're one of the SYNOPSIS set and non-like pair-wise after
129395c635efSGarrett D'Amore 	 * another (or Fn/Fo, which we've let slip through) then assert
129495c635efSGarrett D'Amore 	 * vertical space, else only newline and move on.
129595c635efSGarrett D'Amore 	 */
129695c635efSGarrett D'Amore 	switch (n->prev->tok) {
1297*260e9a87SYuri Pankov 	case MDOC_Fd:
129895c635efSGarrett D'Amore 		/* FALLTHROUGH */
1299*260e9a87SYuri Pankov 	case MDOC_Fn:
130095c635efSGarrett D'Amore 		/* FALLTHROUGH */
1301*260e9a87SYuri Pankov 	case MDOC_Fo:
130295c635efSGarrett D'Amore 		/* FALLTHROUGH */
1303*260e9a87SYuri Pankov 	case MDOC_In:
130495c635efSGarrett D'Amore 		/* FALLTHROUGH */
1305*260e9a87SYuri Pankov 	case MDOC_Vt:
130695c635efSGarrett D'Amore 		term_vspace(p);
130795c635efSGarrett D'Amore 		break;
1308*260e9a87SYuri Pankov 	case MDOC_Ft:
130995c635efSGarrett D'Amore 		if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
131095c635efSGarrett D'Amore 			term_vspace(p);
131195c635efSGarrett D'Amore 			break;
131295c635efSGarrett D'Amore 		}
131395c635efSGarrett D'Amore 		/* FALLTHROUGH */
131495c635efSGarrett D'Amore 	default:
131595c635efSGarrett D'Amore 		term_newln(p);
131695c635efSGarrett D'Amore 		break;
131795c635efSGarrett D'Amore 	}
131895c635efSGarrett D'Amore }
131995c635efSGarrett D'Amore 
132095c635efSGarrett D'Amore static int
132195c635efSGarrett D'Amore termp_vt_pre(DECL_ARGS)
132295c635efSGarrett D'Amore {
132395c635efSGarrett D'Amore 
132495c635efSGarrett D'Amore 	if (MDOC_ELEM == n->type) {
132595c635efSGarrett D'Amore 		synopsis_pre(p, n);
1326698f87a4SGarrett D'Amore 		return(termp_under_pre(p, pair, meta, n));
132795c635efSGarrett D'Amore 	} else if (MDOC_BLOCK == n->type) {
132895c635efSGarrett D'Amore 		synopsis_pre(p, n);
132995c635efSGarrett D'Amore 		return(1);
133095c635efSGarrett D'Amore 	} else if (MDOC_HEAD == n->type)
133195c635efSGarrett D'Amore 		return(0);
133295c635efSGarrett D'Amore 
1333698f87a4SGarrett D'Amore 	return(termp_under_pre(p, pair, meta, n));
133495c635efSGarrett D'Amore }
133595c635efSGarrett D'Amore 
133695c635efSGarrett D'Amore static int
133795c635efSGarrett D'Amore termp_bold_pre(DECL_ARGS)
133895c635efSGarrett D'Amore {
133995c635efSGarrett D'Amore 
134095c635efSGarrett D'Amore 	term_fontpush(p, TERMFONT_BOLD);
134195c635efSGarrett D'Amore 	return(1);
134295c635efSGarrett D'Amore }
134395c635efSGarrett D'Amore 
134495c635efSGarrett D'Amore static int
134595c635efSGarrett D'Amore termp_fd_pre(DECL_ARGS)
134695c635efSGarrett D'Amore {
134795c635efSGarrett D'Amore 
134895c635efSGarrett D'Amore 	synopsis_pre(p, n);
1349698f87a4SGarrett D'Amore 	return(termp_bold_pre(p, pair, meta, n));
1350698f87a4SGarrett D'Amore }
1351698f87a4SGarrett D'Amore 
1352698f87a4SGarrett D'Amore static void
1353698f87a4SGarrett D'Amore termp_fd_post(DECL_ARGS)
1354698f87a4SGarrett D'Amore {
1355698f87a4SGarrett D'Amore 
1356698f87a4SGarrett D'Amore 	term_newln(p);
135795c635efSGarrett D'Amore }
135895c635efSGarrett D'Amore 
135995c635efSGarrett D'Amore static int
136095c635efSGarrett D'Amore termp_sh_pre(DECL_ARGS)
136195c635efSGarrett D'Amore {
136295c635efSGarrett D'Amore 
136395c635efSGarrett D'Amore 	switch (n->type) {
1364*260e9a87SYuri Pankov 	case MDOC_BLOCK:
1365*260e9a87SYuri Pankov 		/*
1366*260e9a87SYuri Pankov 		 * Vertical space before sections, except
1367*260e9a87SYuri Pankov 		 * when the previous section was empty.
1368*260e9a87SYuri Pankov 		 */
1369*260e9a87SYuri Pankov 		if (n->prev == NULL ||
1370*260e9a87SYuri Pankov 		    MDOC_Sh != n->prev->tok ||
1371*260e9a87SYuri Pankov 		    (n->prev->body != NULL &&
1372*260e9a87SYuri Pankov 		     n->prev->body->child != NULL))
137395c635efSGarrett D'Amore 			term_vspace(p);
137495c635efSGarrett D'Amore 		break;
1375*260e9a87SYuri Pankov 	case MDOC_HEAD:
137695c635efSGarrett D'Amore 		term_fontpush(p, TERMFONT_BOLD);
137795c635efSGarrett D'Amore 		break;
1378*260e9a87SYuri Pankov 	case MDOC_BODY:
137995c635efSGarrett D'Amore 		p->offset = term_len(p, p->defindent);
1380698f87a4SGarrett D'Amore 		if (SEC_AUTHORS == n->sec)
1381698f87a4SGarrett D'Amore 			p->flags &= ~(TERMP_SPLIT|TERMP_NOSPLIT);
138295c635efSGarrett D'Amore 		break;
138395c635efSGarrett D'Amore 	default:
138495c635efSGarrett D'Amore 		break;
138595c635efSGarrett D'Amore 	}
138695c635efSGarrett D'Amore 	return(1);
138795c635efSGarrett D'Amore }
138895c635efSGarrett D'Amore 
138995c635efSGarrett D'Amore static void
139095c635efSGarrett D'Amore termp_sh_post(DECL_ARGS)
139195c635efSGarrett D'Amore {
139295c635efSGarrett D'Amore 
139395c635efSGarrett D'Amore 	switch (n->type) {
1394*260e9a87SYuri Pankov 	case MDOC_HEAD:
139595c635efSGarrett D'Amore 		term_newln(p);
139695c635efSGarrett D'Amore 		break;
1397*260e9a87SYuri Pankov 	case MDOC_BODY:
139895c635efSGarrett D'Amore 		term_newln(p);
139995c635efSGarrett D'Amore 		p->offset = 0;
140095c635efSGarrett D'Amore 		break;
140195c635efSGarrett D'Amore 	default:
140295c635efSGarrett D'Amore 		break;
140395c635efSGarrett D'Amore 	}
140495c635efSGarrett D'Amore }
140595c635efSGarrett D'Amore 
140695c635efSGarrett D'Amore static int
140795c635efSGarrett D'Amore termp_bt_pre(DECL_ARGS)
140895c635efSGarrett D'Amore {
140995c635efSGarrett D'Amore 
141095c635efSGarrett D'Amore 	term_word(p, "is currently in beta test.");
141195c635efSGarrett D'Amore 	p->flags |= TERMP_SENTENCE;
141295c635efSGarrett D'Amore 	return(0);
141395c635efSGarrett D'Amore }
141495c635efSGarrett D'Amore 
141595c635efSGarrett D'Amore static void
141695c635efSGarrett D'Amore termp_lb_post(DECL_ARGS)
141795c635efSGarrett D'Amore {
141895c635efSGarrett D'Amore 
141995c635efSGarrett D'Amore 	if (SEC_LIBRARY == n->sec && MDOC_LINE & n->flags)
142095c635efSGarrett D'Amore 		term_newln(p);
142195c635efSGarrett D'Amore }
142295c635efSGarrett D'Amore 
142395c635efSGarrett D'Amore static int
142495c635efSGarrett D'Amore termp_ud_pre(DECL_ARGS)
142595c635efSGarrett D'Amore {
142695c635efSGarrett D'Amore 
142795c635efSGarrett D'Amore 	term_word(p, "currently under development.");
142895c635efSGarrett D'Amore 	p->flags |= TERMP_SENTENCE;
142995c635efSGarrett D'Amore 	return(0);
143095c635efSGarrett D'Amore }
143195c635efSGarrett D'Amore 
143295c635efSGarrett D'Amore static int
143395c635efSGarrett D'Amore termp_d1_pre(DECL_ARGS)
143495c635efSGarrett D'Amore {
143595c635efSGarrett D'Amore 
143695c635efSGarrett D'Amore 	if (MDOC_BLOCK != n->type)
143795c635efSGarrett D'Amore 		return(1);
143895c635efSGarrett D'Amore 	term_newln(p);
143995c635efSGarrett D'Amore 	p->offset += term_len(p, p->defindent + 1);
144095c635efSGarrett D'Amore 	return(1);
144195c635efSGarrett D'Amore }
144295c635efSGarrett D'Amore 
144395c635efSGarrett D'Amore static int
144495c635efSGarrett D'Amore termp_ft_pre(DECL_ARGS)
144595c635efSGarrett D'Amore {
144695c635efSGarrett D'Amore 
144795c635efSGarrett D'Amore 	/* NB: MDOC_LINE does not effect this! */
144895c635efSGarrett D'Amore 	synopsis_pre(p, n);
144995c635efSGarrett D'Amore 	term_fontpush(p, TERMFONT_UNDER);
145095c635efSGarrett D'Amore 	return(1);
145195c635efSGarrett D'Amore }
145295c635efSGarrett D'Amore 
145395c635efSGarrett D'Amore static int
145495c635efSGarrett D'Amore termp_fn_pre(DECL_ARGS)
145595c635efSGarrett D'Amore {
1456698f87a4SGarrett D'Amore 	size_t		 rmargin = 0;
145795c635efSGarrett D'Amore 	int		 pretty;
145895c635efSGarrett D'Amore 
145995c635efSGarrett D'Amore 	pretty = MDOC_SYNPRETTY & n->flags;
146095c635efSGarrett D'Amore 
146195c635efSGarrett D'Amore 	synopsis_pre(p, n);
146295c635efSGarrett D'Amore 
146395c635efSGarrett D'Amore 	if (NULL == (n = n->child))
146495c635efSGarrett D'Amore 		return(0);
146595c635efSGarrett D'Amore 
1466698f87a4SGarrett D'Amore 	if (pretty) {
1467698f87a4SGarrett D'Amore 		rmargin = p->rmargin;
1468698f87a4SGarrett D'Amore 		p->rmargin = p->offset + term_len(p, 4);
1469*260e9a87SYuri Pankov 		p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
1470698f87a4SGarrett D'Amore 	}
1471698f87a4SGarrett D'Amore 
147295c635efSGarrett D'Amore 	assert(MDOC_TEXT == n->type);
147395c635efSGarrett D'Amore 	term_fontpush(p, TERMFONT_BOLD);
147495c635efSGarrett D'Amore 	term_word(p, n->string);
147595c635efSGarrett D'Amore 	term_fontpop(p);
147695c635efSGarrett D'Amore 
1477698f87a4SGarrett D'Amore 	if (pretty) {
1478698f87a4SGarrett D'Amore 		term_flushln(p);
1479*260e9a87SYuri Pankov 		p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
1480698f87a4SGarrett D'Amore 		p->offset = p->rmargin;
1481698f87a4SGarrett D'Amore 		p->rmargin = rmargin;
1482698f87a4SGarrett D'Amore 	}
1483698f87a4SGarrett D'Amore 
148495c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
148595c635efSGarrett D'Amore 	term_word(p, "(");
148695c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
148795c635efSGarrett D'Amore 
148895c635efSGarrett D'Amore 	for (n = n->next; n; n = n->next) {
148995c635efSGarrett D'Amore 		assert(MDOC_TEXT == n->type);
149095c635efSGarrett D'Amore 		term_fontpush(p, TERMFONT_UNDER);
1491698f87a4SGarrett D'Amore 		if (pretty)
1492698f87a4SGarrett D'Amore 			p->flags |= TERMP_NBRWORD;
149395c635efSGarrett D'Amore 		term_word(p, n->string);
149495c635efSGarrett D'Amore 		term_fontpop(p);
149595c635efSGarrett D'Amore 
149695c635efSGarrett D'Amore 		if (n->next) {
149795c635efSGarrett D'Amore 			p->flags |= TERMP_NOSPACE;
149895c635efSGarrett D'Amore 			term_word(p, ",");
149995c635efSGarrett D'Amore 		}
150095c635efSGarrett D'Amore 	}
150195c635efSGarrett D'Amore 
150295c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
150395c635efSGarrett D'Amore 	term_word(p, ")");
150495c635efSGarrett D'Amore 
150595c635efSGarrett D'Amore 	if (pretty) {
150695c635efSGarrett D'Amore 		p->flags |= TERMP_NOSPACE;
150795c635efSGarrett D'Amore 		term_word(p, ";");
1508698f87a4SGarrett D'Amore 		term_flushln(p);
150995c635efSGarrett D'Amore 	}
151095c635efSGarrett D'Amore 
151195c635efSGarrett D'Amore 	return(0);
151295c635efSGarrett D'Amore }
151395c635efSGarrett D'Amore 
151495c635efSGarrett D'Amore static int
151595c635efSGarrett D'Amore termp_fa_pre(DECL_ARGS)
151695c635efSGarrett D'Amore {
151795c635efSGarrett D'Amore 	const struct mdoc_node	*nn;
151895c635efSGarrett D'Amore 
151995c635efSGarrett D'Amore 	if (n->parent->tok != MDOC_Fo) {
152095c635efSGarrett D'Amore 		term_fontpush(p, TERMFONT_UNDER);
152195c635efSGarrett D'Amore 		return(1);
152295c635efSGarrett D'Amore 	}
152395c635efSGarrett D'Amore 
152495c635efSGarrett D'Amore 	for (nn = n->child; nn; nn = nn->next) {
152595c635efSGarrett D'Amore 		term_fontpush(p, TERMFONT_UNDER);
1526698f87a4SGarrett D'Amore 		p->flags |= TERMP_NBRWORD;
152795c635efSGarrett D'Amore 		term_word(p, nn->string);
152895c635efSGarrett D'Amore 		term_fontpop(p);
152995c635efSGarrett D'Amore 
1530698f87a4SGarrett D'Amore 		if (nn->next || (n->next && n->next->tok == MDOC_Fa)) {
153195c635efSGarrett D'Amore 			p->flags |= TERMP_NOSPACE;
153295c635efSGarrett D'Amore 			term_word(p, ",");
153395c635efSGarrett D'Amore 		}
153495c635efSGarrett D'Amore 	}
153595c635efSGarrett D'Amore 
153695c635efSGarrett D'Amore 	return(0);
153795c635efSGarrett D'Amore }
153895c635efSGarrett D'Amore 
153995c635efSGarrett D'Amore static int
154095c635efSGarrett D'Amore termp_bd_pre(DECL_ARGS)
154195c635efSGarrett D'Amore {
1542*260e9a87SYuri Pankov 	size_t			 tabwidth, lm, len, rm, rmax;
1543698f87a4SGarrett D'Amore 	struct mdoc_node	*nn;
1544*260e9a87SYuri Pankov 	int			 offset;
154595c635efSGarrett D'Amore 
154695c635efSGarrett D'Amore 	if (MDOC_BLOCK == n->type) {
154795c635efSGarrett D'Amore 		print_bvspace(p, n, n);
154895c635efSGarrett D'Amore 		return(1);
154995c635efSGarrett D'Amore 	} else if (MDOC_HEAD == n->type)
155095c635efSGarrett D'Amore 		return(0);
155195c635efSGarrett D'Amore 
1552*260e9a87SYuri Pankov 	/* Handle the -offset argument. */
1553*260e9a87SYuri Pankov 
1554*260e9a87SYuri Pankov 	if (n->norm->Bd.offs == NULL ||
1555*260e9a87SYuri Pankov 	    ! strcmp(n->norm->Bd.offs, "left"))
1556*260e9a87SYuri Pankov 		/* nothing */;
1557*260e9a87SYuri Pankov 	else if ( ! strcmp(n->norm->Bd.offs, "indent"))
1558*260e9a87SYuri Pankov 		p->offset += term_len(p, p->defindent + 1);
1559*260e9a87SYuri Pankov 	else if ( ! strcmp(n->norm->Bd.offs, "indent-two"))
1560*260e9a87SYuri Pankov 		p->offset += term_len(p, (p->defindent + 1) * 2);
1561*260e9a87SYuri Pankov 	else {
1562*260e9a87SYuri Pankov 		offset = a2width(p, n->norm->Bd.offs);
1563*260e9a87SYuri Pankov 		if (offset < 0 && (size_t)(-offset) > p->offset)
1564*260e9a87SYuri Pankov 			p->offset = 0;
1565*260e9a87SYuri Pankov 		else if (offset < SHRT_MAX)
1566*260e9a87SYuri Pankov 			p->offset += offset;
1567*260e9a87SYuri Pankov 	}
156895c635efSGarrett D'Amore 
156995c635efSGarrett D'Amore 	/*
157095c635efSGarrett D'Amore 	 * If -ragged or -filled are specified, the block does nothing
157195c635efSGarrett D'Amore 	 * but change the indentation.  If -unfilled or -literal are
157295c635efSGarrett D'Amore 	 * specified, text is printed exactly as entered in the display:
157395c635efSGarrett D'Amore 	 * for macro lines, a newline is appended to the line.  Blank
157495c635efSGarrett D'Amore 	 * lines are allowed.
157595c635efSGarrett D'Amore 	 */
157695c635efSGarrett D'Amore 
157795c635efSGarrett D'Amore 	if (DISP_literal != n->norm->Bd.type &&
1578*260e9a87SYuri Pankov 	    DISP_unfilled != n->norm->Bd.type &&
1579*260e9a87SYuri Pankov 	    DISP_centered != n->norm->Bd.type)
158095c635efSGarrett D'Amore 		return(1);
158195c635efSGarrett D'Amore 
158295c635efSGarrett D'Amore 	tabwidth = p->tabwidth;
158395c635efSGarrett D'Amore 	if (DISP_literal == n->norm->Bd.type)
158495c635efSGarrett D'Amore 		p->tabwidth = term_len(p, 8);
158595c635efSGarrett D'Amore 
1586*260e9a87SYuri Pankov 	lm = p->offset;
158795c635efSGarrett D'Amore 	rm = p->rmargin;
158895c635efSGarrett D'Amore 	rmax = p->maxrmargin;
158995c635efSGarrett D'Amore 	p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
159095c635efSGarrett D'Amore 
159195c635efSGarrett D'Amore 	for (nn = n->child; nn; nn = nn->next) {
1592*260e9a87SYuri Pankov 		if (DISP_centered == n->norm->Bd.type) {
1593*260e9a87SYuri Pankov 			if (MDOC_TEXT == nn->type) {
1594*260e9a87SYuri Pankov 				len = term_strlen(p, nn->string);
1595*260e9a87SYuri Pankov 				p->offset = len >= rm ? 0 :
1596*260e9a87SYuri Pankov 				    lm + len >= rm ? rm - len :
1597*260e9a87SYuri Pankov 				    (lm + rm - len) / 2;
1598*260e9a87SYuri Pankov 			} else
1599*260e9a87SYuri Pankov 				p->offset = lm;
1600*260e9a87SYuri Pankov 		}
1601698f87a4SGarrett D'Amore 		print_mdoc_node(p, pair, meta, nn);
160295c635efSGarrett D'Amore 		/*
160395c635efSGarrett D'Amore 		 * If the printed node flushes its own line, then we
160495c635efSGarrett D'Amore 		 * needn't do it here as well.  This is hacky, but the
160595c635efSGarrett D'Amore 		 * notion of selective eoln whitespace is pretty dumb
160695c635efSGarrett D'Amore 		 * anyway, so don't sweat it.
160795c635efSGarrett D'Amore 		 */
160895c635efSGarrett D'Amore 		switch (nn->tok) {
1609*260e9a87SYuri Pankov 		case MDOC_Sm:
161095c635efSGarrett D'Amore 			/* FALLTHROUGH */
1611*260e9a87SYuri Pankov 		case MDOC_br:
161295c635efSGarrett D'Amore 			/* FALLTHROUGH */
1613*260e9a87SYuri Pankov 		case MDOC_sp:
161495c635efSGarrett D'Amore 			/* FALLTHROUGH */
1615*260e9a87SYuri Pankov 		case MDOC_Bl:
161695c635efSGarrett D'Amore 			/* FALLTHROUGH */
1617*260e9a87SYuri Pankov 		case MDOC_D1:
161895c635efSGarrett D'Amore 			/* FALLTHROUGH */
1619*260e9a87SYuri Pankov 		case MDOC_Dl:
162095c635efSGarrett D'Amore 			/* FALLTHROUGH */
1621*260e9a87SYuri Pankov 		case MDOC_Lp:
162295c635efSGarrett D'Amore 			/* FALLTHROUGH */
1623*260e9a87SYuri Pankov 		case MDOC_Pp:
162495c635efSGarrett D'Amore 			continue;
162595c635efSGarrett D'Amore 		default:
162695c635efSGarrett D'Amore 			break;
162795c635efSGarrett D'Amore 		}
1628*260e9a87SYuri Pankov 		if (p->flags & TERMP_NONEWLINE ||
1629*260e9a87SYuri Pankov 		    (nn->next && ! (nn->next->flags & MDOC_LINE)))
163095c635efSGarrett D'Amore 			continue;
163195c635efSGarrett D'Amore 		term_flushln(p);
163295c635efSGarrett D'Amore 		p->flags |= TERMP_NOSPACE;
163395c635efSGarrett D'Amore 	}
163495c635efSGarrett D'Amore 
163595c635efSGarrett D'Amore 	p->tabwidth = tabwidth;
163695c635efSGarrett D'Amore 	p->rmargin = rm;
163795c635efSGarrett D'Amore 	p->maxrmargin = rmax;
163895c635efSGarrett D'Amore 	return(0);
163995c635efSGarrett D'Amore }
164095c635efSGarrett D'Amore 
164195c635efSGarrett D'Amore static void
164295c635efSGarrett D'Amore termp_bd_post(DECL_ARGS)
164395c635efSGarrett D'Amore {
164495c635efSGarrett D'Amore 	size_t		 rm, rmax;
164595c635efSGarrett D'Amore 
164695c635efSGarrett D'Amore 	if (MDOC_BODY != n->type)
164795c635efSGarrett D'Amore 		return;
164895c635efSGarrett D'Amore 
164995c635efSGarrett D'Amore 	rm = p->rmargin;
165095c635efSGarrett D'Amore 	rmax = p->maxrmargin;
165195c635efSGarrett D'Amore 
165295c635efSGarrett D'Amore 	if (DISP_literal == n->norm->Bd.type ||
165395c635efSGarrett D'Amore 	    DISP_unfilled == n->norm->Bd.type)
165495c635efSGarrett D'Amore 		p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
165595c635efSGarrett D'Amore 
165695c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
165795c635efSGarrett D'Amore 	term_newln(p);
165895c635efSGarrett D'Amore 
165995c635efSGarrett D'Amore 	p->rmargin = rm;
166095c635efSGarrett D'Amore 	p->maxrmargin = rmax;
166195c635efSGarrett D'Amore }
166295c635efSGarrett D'Amore 
166395c635efSGarrett D'Amore static int
166495c635efSGarrett D'Amore termp_bx_pre(DECL_ARGS)
166595c635efSGarrett D'Amore {
166695c635efSGarrett D'Amore 
166795c635efSGarrett D'Amore 	if (NULL != (n = n->child)) {
166895c635efSGarrett D'Amore 		term_word(p, n->string);
166995c635efSGarrett D'Amore 		p->flags |= TERMP_NOSPACE;
167095c635efSGarrett D'Amore 		term_word(p, "BSD");
167195c635efSGarrett D'Amore 	} else {
167295c635efSGarrett D'Amore 		term_word(p, "BSD");
167395c635efSGarrett D'Amore 		return(0);
167495c635efSGarrett D'Amore 	}
167595c635efSGarrett D'Amore 
167695c635efSGarrett D'Amore 	if (NULL != (n = n->next)) {
167795c635efSGarrett D'Amore 		p->flags |= TERMP_NOSPACE;
167895c635efSGarrett D'Amore 		term_word(p, "-");
167995c635efSGarrett D'Amore 		p->flags |= TERMP_NOSPACE;
168095c635efSGarrett D'Amore 		term_word(p, n->string);
168195c635efSGarrett D'Amore 	}
168295c635efSGarrett D'Amore 
168395c635efSGarrett D'Amore 	return(0);
168495c635efSGarrett D'Amore }
168595c635efSGarrett D'Amore 
168695c635efSGarrett D'Amore static int
168795c635efSGarrett D'Amore termp_xx_pre(DECL_ARGS)
168895c635efSGarrett D'Amore {
168995c635efSGarrett D'Amore 	const char	*pp;
169095c635efSGarrett D'Amore 	int		 flags;
169195c635efSGarrett D'Amore 
169295c635efSGarrett D'Amore 	pp = NULL;
169395c635efSGarrett D'Amore 	switch (n->tok) {
1694*260e9a87SYuri Pankov 	case MDOC_Bsx:
169595c635efSGarrett D'Amore 		pp = "BSD/OS";
169695c635efSGarrett D'Amore 		break;
1697*260e9a87SYuri Pankov 	case MDOC_Dx:
169895c635efSGarrett D'Amore 		pp = "DragonFly";
169995c635efSGarrett D'Amore 		break;
1700*260e9a87SYuri Pankov 	case MDOC_Fx:
170195c635efSGarrett D'Amore 		pp = "FreeBSD";
170295c635efSGarrett D'Amore 		break;
1703*260e9a87SYuri Pankov 	case MDOC_Nx:
170495c635efSGarrett D'Amore 		pp = "NetBSD";
170595c635efSGarrett D'Amore 		break;
1706*260e9a87SYuri Pankov 	case MDOC_Ox:
170795c635efSGarrett D'Amore 		pp = "OpenBSD";
170895c635efSGarrett D'Amore 		break;
1709*260e9a87SYuri Pankov 	case MDOC_Ux:
171095c635efSGarrett D'Amore 		pp = "UNIX";
171195c635efSGarrett D'Amore 		break;
171295c635efSGarrett D'Amore 	default:
1713698f87a4SGarrett D'Amore 		abort();
1714698f87a4SGarrett D'Amore 		/* NOTREACHED */
171595c635efSGarrett D'Amore 	}
171695c635efSGarrett D'Amore 
171795c635efSGarrett D'Amore 	term_word(p, pp);
171895c635efSGarrett D'Amore 	if (n->child) {
171995c635efSGarrett D'Amore 		flags = p->flags;
172095c635efSGarrett D'Amore 		p->flags |= TERMP_KEEP;
172195c635efSGarrett D'Amore 		term_word(p, n->child->string);
172295c635efSGarrett D'Amore 		p->flags = flags;
172395c635efSGarrett D'Amore 	}
172495c635efSGarrett D'Amore 	return(0);
172595c635efSGarrett D'Amore }
172695c635efSGarrett D'Amore 
172795c635efSGarrett D'Amore static void
172895c635efSGarrett D'Amore termp_pf_post(DECL_ARGS)
172995c635efSGarrett D'Amore {
173095c635efSGarrett D'Amore 
1731*260e9a87SYuri Pankov 	if ( ! (n->next == NULL || n->next->flags & MDOC_LINE))
173295c635efSGarrett D'Amore 		p->flags |= TERMP_NOSPACE;
173395c635efSGarrett D'Amore }
173495c635efSGarrett D'Amore 
173595c635efSGarrett D'Amore static int
173695c635efSGarrett D'Amore termp_ss_pre(DECL_ARGS)
173795c635efSGarrett D'Amore {
173895c635efSGarrett D'Amore 
173995c635efSGarrett D'Amore 	switch (n->type) {
1740*260e9a87SYuri Pankov 	case MDOC_BLOCK:
174195c635efSGarrett D'Amore 		term_newln(p);
174295c635efSGarrett D'Amore 		if (n->prev)
174395c635efSGarrett D'Amore 			term_vspace(p);
174495c635efSGarrett D'Amore 		break;
1745*260e9a87SYuri Pankov 	case MDOC_HEAD:
174695c635efSGarrett D'Amore 		term_fontpush(p, TERMFONT_BOLD);
174795c635efSGarrett D'Amore 		p->offset = term_len(p, (p->defindent+1)/2);
174895c635efSGarrett D'Amore 		break;
1749*260e9a87SYuri Pankov 	case MDOC_BODY:
1750*260e9a87SYuri Pankov 		p->offset = term_len(p, p->defindent);
1751*260e9a87SYuri Pankov 		break;
175295c635efSGarrett D'Amore 	default:
175395c635efSGarrett D'Amore 		break;
175495c635efSGarrett D'Amore 	}
175595c635efSGarrett D'Amore 
175695c635efSGarrett D'Amore 	return(1);
175795c635efSGarrett D'Amore }
175895c635efSGarrett D'Amore 
175995c635efSGarrett D'Amore static void
176095c635efSGarrett D'Amore termp_ss_post(DECL_ARGS)
176195c635efSGarrett D'Amore {
176295c635efSGarrett D'Amore 
1763*260e9a87SYuri Pankov 	if (n->type == MDOC_HEAD || n->type == MDOC_BODY)
176495c635efSGarrett D'Amore 		term_newln(p);
176595c635efSGarrett D'Amore }
176695c635efSGarrett D'Amore 
176795c635efSGarrett D'Amore static int
176895c635efSGarrett D'Amore termp_cd_pre(DECL_ARGS)
176995c635efSGarrett D'Amore {
177095c635efSGarrett D'Amore 
177195c635efSGarrett D'Amore 	synopsis_pre(p, n);
177295c635efSGarrett D'Amore 	term_fontpush(p, TERMFONT_BOLD);
177395c635efSGarrett D'Amore 	return(1);
177495c635efSGarrett D'Amore }
177595c635efSGarrett D'Amore 
177695c635efSGarrett D'Amore static int
177795c635efSGarrett D'Amore termp_in_pre(DECL_ARGS)
177895c635efSGarrett D'Amore {
177995c635efSGarrett D'Amore 
178095c635efSGarrett D'Amore 	synopsis_pre(p, n);
178195c635efSGarrett D'Amore 
178295c635efSGarrett D'Amore 	if (MDOC_SYNPRETTY & n->flags && MDOC_LINE & n->flags) {
178395c635efSGarrett D'Amore 		term_fontpush(p, TERMFONT_BOLD);
178495c635efSGarrett D'Amore 		term_word(p, "#include");
178595c635efSGarrett D'Amore 		term_word(p, "<");
178695c635efSGarrett D'Amore 	} else {
178795c635efSGarrett D'Amore 		term_word(p, "<");
178895c635efSGarrett D'Amore 		term_fontpush(p, TERMFONT_UNDER);
178995c635efSGarrett D'Amore 	}
179095c635efSGarrett D'Amore 
179195c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
179295c635efSGarrett D'Amore 	return(1);
179395c635efSGarrett D'Amore }
179495c635efSGarrett D'Amore 
179595c635efSGarrett D'Amore static void
179695c635efSGarrett D'Amore termp_in_post(DECL_ARGS)
179795c635efSGarrett D'Amore {
179895c635efSGarrett D'Amore 
179995c635efSGarrett D'Amore 	if (MDOC_SYNPRETTY & n->flags)
180095c635efSGarrett D'Amore 		term_fontpush(p, TERMFONT_BOLD);
180195c635efSGarrett D'Amore 
180295c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
180395c635efSGarrett D'Amore 	term_word(p, ">");
180495c635efSGarrett D'Amore 
180595c635efSGarrett D'Amore 	if (MDOC_SYNPRETTY & n->flags)
180695c635efSGarrett D'Amore 		term_fontpop(p);
180795c635efSGarrett D'Amore }
180895c635efSGarrett D'Amore 
180995c635efSGarrett D'Amore static int
181095c635efSGarrett D'Amore termp_sp_pre(DECL_ARGS)
181195c635efSGarrett D'Amore {
1812*260e9a87SYuri Pankov 	struct roffsu	 su;
1813*260e9a87SYuri Pankov 	int		 i, len;
181495c635efSGarrett D'Amore 
181595c635efSGarrett D'Amore 	switch (n->tok) {
1816*260e9a87SYuri Pankov 	case MDOC_sp:
1817*260e9a87SYuri Pankov 		if (n->child) {
1818*260e9a87SYuri Pankov 			if ( ! a2roffsu(n->child->string, &su, SCALE_VS))
1819*260e9a87SYuri Pankov 				su.scale = 1.0;
1820*260e9a87SYuri Pankov 			len = term_vspan(p, &su);
1821*260e9a87SYuri Pankov 		} else
1822*260e9a87SYuri Pankov 			len = 1;
182395c635efSGarrett D'Amore 		break;
1824*260e9a87SYuri Pankov 	case MDOC_br:
182595c635efSGarrett D'Amore 		len = 0;
182695c635efSGarrett D'Amore 		break;
182795c635efSGarrett D'Amore 	default:
182895c635efSGarrett D'Amore 		len = 1;
182995c635efSGarrett D'Amore 		break;
183095c635efSGarrett D'Amore 	}
183195c635efSGarrett D'Amore 
183295c635efSGarrett D'Amore 	if (0 == len)
183395c635efSGarrett D'Amore 		term_newln(p);
1834*260e9a87SYuri Pankov 	else if (len < 0)
1835*260e9a87SYuri Pankov 		p->skipvsp -= len;
1836*260e9a87SYuri Pankov 	else
183795c635efSGarrett D'Amore 		for (i = 0; i < len; i++)
183895c635efSGarrett D'Amore 			term_vspace(p);
183995c635efSGarrett D'Amore 
184095c635efSGarrett D'Amore 	return(0);
184195c635efSGarrett D'Amore }
184295c635efSGarrett D'Amore 
1843*260e9a87SYuri Pankov static int
1844*260e9a87SYuri Pankov termp_skip_pre(DECL_ARGS)
1845*260e9a87SYuri Pankov {
184695c635efSGarrett D'Amore 
1847*260e9a87SYuri Pankov 	return(0);
1848*260e9a87SYuri Pankov }
1849*260e9a87SYuri Pankov 
185095c635efSGarrett D'Amore static int
185195c635efSGarrett D'Amore termp_quote_pre(DECL_ARGS)
185295c635efSGarrett D'Amore {
185395c635efSGarrett D'Amore 
185495c635efSGarrett D'Amore 	if (MDOC_BODY != n->type && MDOC_ELEM != n->type)
185595c635efSGarrett D'Amore 		return(1);
185695c635efSGarrett D'Amore 
185795c635efSGarrett D'Amore 	switch (n->tok) {
1858*260e9a87SYuri Pankov 	case MDOC_Ao:
185995c635efSGarrett D'Amore 		/* FALLTHROUGH */
1860*260e9a87SYuri Pankov 	case MDOC_Aq:
1861*260e9a87SYuri Pankov 		term_word(p, n->nchild == 1 &&
1862*260e9a87SYuri Pankov 		    n->child->tok == MDOC_Mt ? "<" : "\\(la");
186395c635efSGarrett D'Amore 		break;
1864*260e9a87SYuri Pankov 	case MDOC_Bro:
186595c635efSGarrett D'Amore 		/* FALLTHROUGH */
1866*260e9a87SYuri Pankov 	case MDOC_Brq:
186795c635efSGarrett D'Amore 		term_word(p, "{");
186895c635efSGarrett D'Amore 		break;
1869*260e9a87SYuri Pankov 	case MDOC_Oo:
187095c635efSGarrett D'Amore 		/* FALLTHROUGH */
1871*260e9a87SYuri Pankov 	case MDOC_Op:
187295c635efSGarrett D'Amore 		/* FALLTHROUGH */
1873*260e9a87SYuri Pankov 	case MDOC_Bo:
187495c635efSGarrett D'Amore 		/* FALLTHROUGH */
1875*260e9a87SYuri Pankov 	case MDOC_Bq:
187695c635efSGarrett D'Amore 		term_word(p, "[");
187795c635efSGarrett D'Amore 		break;
1878*260e9a87SYuri Pankov 	case MDOC_Do:
187995c635efSGarrett D'Amore 		/* FALLTHROUGH */
1880*260e9a87SYuri Pankov 	case MDOC_Dq:
1881*260e9a87SYuri Pankov 		term_word(p, "\\(Lq");
188295c635efSGarrett D'Amore 		break;
1883*260e9a87SYuri Pankov 	case MDOC_En:
1884*260e9a87SYuri Pankov 		if (NULL == n->norm->Es ||
1885*260e9a87SYuri Pankov 		    NULL == n->norm->Es->child)
1886*260e9a87SYuri Pankov 			return(1);
1887*260e9a87SYuri Pankov 		term_word(p, n->norm->Es->child->string);
188895c635efSGarrett D'Amore 		break;
1889*260e9a87SYuri Pankov 	case MDOC_Po:
189095c635efSGarrett D'Amore 		/* FALLTHROUGH */
1891*260e9a87SYuri Pankov 	case MDOC_Pq:
189295c635efSGarrett D'Amore 		term_word(p, "(");
189395c635efSGarrett D'Amore 		break;
1894*260e9a87SYuri Pankov 	case MDOC__T:
189595c635efSGarrett D'Amore 		/* FALLTHROUGH */
1896*260e9a87SYuri Pankov 	case MDOC_Qo:
189795c635efSGarrett D'Amore 		/* FALLTHROUGH */
1898*260e9a87SYuri Pankov 	case MDOC_Qq:
189995c635efSGarrett D'Amore 		term_word(p, "\"");
190095c635efSGarrett D'Amore 		break;
1901*260e9a87SYuri Pankov 	case MDOC_Ql:
190295c635efSGarrett D'Amore 		/* FALLTHROUGH */
1903*260e9a87SYuri Pankov 	case MDOC_So:
190495c635efSGarrett D'Amore 		/* FALLTHROUGH */
1905*260e9a87SYuri Pankov 	case MDOC_Sq:
1906698f87a4SGarrett D'Amore 		term_word(p, "\\(oq");
190795c635efSGarrett D'Amore 		break;
190895c635efSGarrett D'Amore 	default:
190995c635efSGarrett D'Amore 		abort();
191095c635efSGarrett D'Amore 		/* NOTREACHED */
191195c635efSGarrett D'Amore 	}
191295c635efSGarrett D'Amore 
191395c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
191495c635efSGarrett D'Amore 	return(1);
191595c635efSGarrett D'Amore }
191695c635efSGarrett D'Amore 
191795c635efSGarrett D'Amore static void
191895c635efSGarrett D'Amore termp_quote_post(DECL_ARGS)
191995c635efSGarrett D'Amore {
192095c635efSGarrett D'Amore 
1921*260e9a87SYuri Pankov 	if (n->type != MDOC_BODY && n->type != MDOC_ELEM)
192295c635efSGarrett D'Amore 		return;
192395c635efSGarrett D'Amore 
192495c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
192595c635efSGarrett D'Amore 
192695c635efSGarrett D'Amore 	switch (n->tok) {
1927*260e9a87SYuri Pankov 	case MDOC_Ao:
192895c635efSGarrett D'Amore 		/* FALLTHROUGH */
1929*260e9a87SYuri Pankov 	case MDOC_Aq:
1930*260e9a87SYuri Pankov 		term_word(p, n->nchild == 1 &&
1931*260e9a87SYuri Pankov 		    n->child->tok == MDOC_Mt ? ">" : "\\(ra");
193295c635efSGarrett D'Amore 		break;
1933*260e9a87SYuri Pankov 	case MDOC_Bro:
193495c635efSGarrett D'Amore 		/* FALLTHROUGH */
1935*260e9a87SYuri Pankov 	case MDOC_Brq:
193695c635efSGarrett D'Amore 		term_word(p, "}");
193795c635efSGarrett D'Amore 		break;
1938*260e9a87SYuri Pankov 	case MDOC_Oo:
193995c635efSGarrett D'Amore 		/* FALLTHROUGH */
1940*260e9a87SYuri Pankov 	case MDOC_Op:
194195c635efSGarrett D'Amore 		/* FALLTHROUGH */
1942*260e9a87SYuri Pankov 	case MDOC_Bo:
194395c635efSGarrett D'Amore 		/* FALLTHROUGH */
1944*260e9a87SYuri Pankov 	case MDOC_Bq:
194595c635efSGarrett D'Amore 		term_word(p, "]");
194695c635efSGarrett D'Amore 		break;
1947*260e9a87SYuri Pankov 	case MDOC_Do:
194895c635efSGarrett D'Amore 		/* FALLTHROUGH */
1949*260e9a87SYuri Pankov 	case MDOC_Dq:
1950*260e9a87SYuri Pankov 		term_word(p, "\\(Rq");
195195c635efSGarrett D'Amore 		break;
1952*260e9a87SYuri Pankov 	case MDOC_En:
1953*260e9a87SYuri Pankov 		if (n->norm->Es == NULL ||
1954*260e9a87SYuri Pankov 		    n->norm->Es->child == NULL ||
1955*260e9a87SYuri Pankov 		    n->norm->Es->child->next == NULL)
1956*260e9a87SYuri Pankov 			p->flags &= ~TERMP_NOSPACE;
1957*260e9a87SYuri Pankov 		else
1958*260e9a87SYuri Pankov 			term_word(p, n->norm->Es->child->next->string);
195995c635efSGarrett D'Amore 		break;
1960*260e9a87SYuri Pankov 	case MDOC_Po:
196195c635efSGarrett D'Amore 		/* FALLTHROUGH */
1962*260e9a87SYuri Pankov 	case MDOC_Pq:
196395c635efSGarrett D'Amore 		term_word(p, ")");
196495c635efSGarrett D'Amore 		break;
1965*260e9a87SYuri Pankov 	case MDOC__T:
196695c635efSGarrett D'Amore 		/* FALLTHROUGH */
1967*260e9a87SYuri Pankov 	case MDOC_Qo:
196895c635efSGarrett D'Amore 		/* FALLTHROUGH */
1969*260e9a87SYuri Pankov 	case MDOC_Qq:
197095c635efSGarrett D'Amore 		term_word(p, "\"");
197195c635efSGarrett D'Amore 		break;
1972*260e9a87SYuri Pankov 	case MDOC_Ql:
197395c635efSGarrett D'Amore 		/* FALLTHROUGH */
1974*260e9a87SYuri Pankov 	case MDOC_So:
197595c635efSGarrett D'Amore 		/* FALLTHROUGH */
1976*260e9a87SYuri Pankov 	case MDOC_Sq:
1977698f87a4SGarrett D'Amore 		term_word(p, "\\(cq");
197895c635efSGarrett D'Amore 		break;
197995c635efSGarrett D'Amore 	default:
198095c635efSGarrett D'Amore 		abort();
198195c635efSGarrett D'Amore 		/* NOTREACHED */
198295c635efSGarrett D'Amore 	}
198395c635efSGarrett D'Amore }
198495c635efSGarrett D'Amore 
1985*260e9a87SYuri Pankov static int
1986*260e9a87SYuri Pankov termp_eo_pre(DECL_ARGS)
1987*260e9a87SYuri Pankov {
198895c635efSGarrett D'Amore 
1989*260e9a87SYuri Pankov 	if (n->type != MDOC_BODY)
1990*260e9a87SYuri Pankov 		return(1);
1991*260e9a87SYuri Pankov 
1992*260e9a87SYuri Pankov 	if (n->end == ENDBODY_NOT &&
1993*260e9a87SYuri Pankov 	    n->parent->head->child == NULL &&
1994*260e9a87SYuri Pankov 	    n->child != NULL &&
1995*260e9a87SYuri Pankov 	    n->child->end != ENDBODY_NOT)
1996*260e9a87SYuri Pankov 		term_word(p, "\\&");
1997*260e9a87SYuri Pankov 	else if (n->end != ENDBODY_NOT ? n->child != NULL :
1998*260e9a87SYuri Pankov 	     n->parent->head->child != NULL && (n->child != NULL ||
1999*260e9a87SYuri Pankov 	     (n->parent->tail != NULL && n->parent->tail->child != NULL)))
2000*260e9a87SYuri Pankov 		p->flags |= TERMP_NOSPACE;
2001*260e9a87SYuri Pankov 
2002*260e9a87SYuri Pankov 	return(1);
2003*260e9a87SYuri Pankov }
2004*260e9a87SYuri Pankov 
2005*260e9a87SYuri Pankov static void
2006*260e9a87SYuri Pankov termp_eo_post(DECL_ARGS)
2007*260e9a87SYuri Pankov {
2008*260e9a87SYuri Pankov 	int	 body, tail;
2009*260e9a87SYuri Pankov 
2010*260e9a87SYuri Pankov 	if (n->type != MDOC_BODY)
2011*260e9a87SYuri Pankov 		return;
2012*260e9a87SYuri Pankov 
2013*260e9a87SYuri Pankov 	if (n->end != ENDBODY_NOT) {
2014*260e9a87SYuri Pankov 		p->flags &= ~TERMP_NOSPACE;
2015*260e9a87SYuri Pankov 		return;
2016*260e9a87SYuri Pankov 	}
2017*260e9a87SYuri Pankov 
2018*260e9a87SYuri Pankov 	body = n->child != NULL || n->parent->head->child != NULL;
2019*260e9a87SYuri Pankov 	tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
2020*260e9a87SYuri Pankov 
2021*260e9a87SYuri Pankov 	if (body && tail)
2022*260e9a87SYuri Pankov 		p->flags |= TERMP_NOSPACE;
2023*260e9a87SYuri Pankov 	else if ( ! (body || tail))
2024*260e9a87SYuri Pankov 		term_word(p, "\\&");
2025*260e9a87SYuri Pankov 	else if ( ! tail)
2026*260e9a87SYuri Pankov 		p->flags &= ~TERMP_NOSPACE;
2027*260e9a87SYuri Pankov }
2028*260e9a87SYuri Pankov 
202995c635efSGarrett D'Amore static int
203095c635efSGarrett D'Amore termp_fo_pre(DECL_ARGS)
203195c635efSGarrett D'Amore {
2032698f87a4SGarrett D'Amore 	size_t		 rmargin = 0;
2033698f87a4SGarrett D'Amore 	int		 pretty;
2034698f87a4SGarrett D'Amore 
2035698f87a4SGarrett D'Amore 	pretty = MDOC_SYNPRETTY & n->flags;
203695c635efSGarrett D'Amore 
203795c635efSGarrett D'Amore 	if (MDOC_BLOCK == n->type) {
203895c635efSGarrett D'Amore 		synopsis_pre(p, n);
203995c635efSGarrett D'Amore 		return(1);
204095c635efSGarrett D'Amore 	} else if (MDOC_BODY == n->type) {
2041698f87a4SGarrett D'Amore 		if (pretty) {
2042698f87a4SGarrett D'Amore 			rmargin = p->rmargin;
2043698f87a4SGarrett D'Amore 			p->rmargin = p->offset + term_len(p, 4);
2044*260e9a87SYuri Pankov 			p->flags |= TERMP_NOBREAK | TERMP_BRIND |
2045*260e9a87SYuri Pankov 					TERMP_HANG;
2046698f87a4SGarrett D'Amore 		}
204795c635efSGarrett D'Amore 		p->flags |= TERMP_NOSPACE;
204895c635efSGarrett D'Amore 		term_word(p, "(");
204995c635efSGarrett D'Amore 		p->flags |= TERMP_NOSPACE;
2050698f87a4SGarrett D'Amore 		if (pretty) {
2051698f87a4SGarrett D'Amore 			term_flushln(p);
2052*260e9a87SYuri Pankov 			p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND |
2053*260e9a87SYuri Pankov 					TERMP_HANG);
2054698f87a4SGarrett D'Amore 			p->offset = p->rmargin;
2055698f87a4SGarrett D'Amore 			p->rmargin = rmargin;
2056698f87a4SGarrett D'Amore 		}
205795c635efSGarrett D'Amore 		return(1);
205895c635efSGarrett D'Amore 	}
205995c635efSGarrett D'Amore 
206095c635efSGarrett D'Amore 	if (NULL == n->child)
206195c635efSGarrett D'Amore 		return(0);
206295c635efSGarrett D'Amore 
206395c635efSGarrett D'Amore 	/* XXX: we drop non-initial arguments as per groff. */
206495c635efSGarrett D'Amore 
206595c635efSGarrett D'Amore 	assert(n->child->string);
206695c635efSGarrett D'Amore 	term_fontpush(p, TERMFONT_BOLD);
206795c635efSGarrett D'Amore 	term_word(p, n->child->string);
206895c635efSGarrett D'Amore 	return(0);
206995c635efSGarrett D'Amore }
207095c635efSGarrett D'Amore 
207195c635efSGarrett D'Amore static void
207295c635efSGarrett D'Amore termp_fo_post(DECL_ARGS)
207395c635efSGarrett D'Amore {
207495c635efSGarrett D'Amore 
207595c635efSGarrett D'Amore 	if (MDOC_BODY != n->type)
207695c635efSGarrett D'Amore 		return;
207795c635efSGarrett D'Amore 
207895c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
207995c635efSGarrett D'Amore 	term_word(p, ")");
208095c635efSGarrett D'Amore 
208195c635efSGarrett D'Amore 	if (MDOC_SYNPRETTY & n->flags) {
208295c635efSGarrett D'Amore 		p->flags |= TERMP_NOSPACE;
208395c635efSGarrett D'Amore 		term_word(p, ";");
2084698f87a4SGarrett D'Amore 		term_flushln(p);
208595c635efSGarrett D'Amore 	}
208695c635efSGarrett D'Amore }
208795c635efSGarrett D'Amore 
208895c635efSGarrett D'Amore static int
208995c635efSGarrett D'Amore termp_bf_pre(DECL_ARGS)
209095c635efSGarrett D'Amore {
209195c635efSGarrett D'Amore 
209295c635efSGarrett D'Amore 	if (MDOC_HEAD == n->type)
209395c635efSGarrett D'Amore 		return(0);
2094698f87a4SGarrett D'Amore 	else if (MDOC_BODY != n->type)
209595c635efSGarrett D'Amore 		return(1);
209695c635efSGarrett D'Amore 
209795c635efSGarrett D'Amore 	if (FONT_Em == n->norm->Bf.font)
209895c635efSGarrett D'Amore 		term_fontpush(p, TERMFONT_UNDER);
209995c635efSGarrett D'Amore 	else if (FONT_Sy == n->norm->Bf.font)
210095c635efSGarrett D'Amore 		term_fontpush(p, TERMFONT_BOLD);
210195c635efSGarrett D'Amore 	else
210295c635efSGarrett D'Amore 		term_fontpush(p, TERMFONT_NONE);
210395c635efSGarrett D'Amore 
210495c635efSGarrett D'Amore 	return(1);
210595c635efSGarrett D'Amore }
210695c635efSGarrett D'Amore 
210795c635efSGarrett D'Amore static int
210895c635efSGarrett D'Amore termp_sm_pre(DECL_ARGS)
210995c635efSGarrett D'Amore {
211095c635efSGarrett D'Amore 
2111*260e9a87SYuri Pankov 	if (NULL == n->child)
2112*260e9a87SYuri Pankov 		p->flags ^= TERMP_NONOSPACE;
2113*260e9a87SYuri Pankov 	else if (0 == strcmp("on", n->child->string))
211495c635efSGarrett D'Amore 		p->flags &= ~TERMP_NONOSPACE;
2115*260e9a87SYuri Pankov 	else
211695c635efSGarrett D'Amore 		p->flags |= TERMP_NONOSPACE;
211795c635efSGarrett D'Amore 
2118*260e9a87SYuri Pankov 	if (p->col && ! (TERMP_NONOSPACE & p->flags))
2119*260e9a87SYuri Pankov 		p->flags &= ~TERMP_NOSPACE;
2120*260e9a87SYuri Pankov 
212195c635efSGarrett D'Amore 	return(0);
212295c635efSGarrett D'Amore }
212395c635efSGarrett D'Amore 
212495c635efSGarrett D'Amore static int
212595c635efSGarrett D'Amore termp_ap_pre(DECL_ARGS)
212695c635efSGarrett D'Amore {
212795c635efSGarrett D'Amore 
212895c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
212995c635efSGarrett D'Amore 	term_word(p, "'");
213095c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
213195c635efSGarrett D'Amore 	return(1);
213295c635efSGarrett D'Amore }
213395c635efSGarrett D'Amore 
213495c635efSGarrett D'Amore static void
213595c635efSGarrett D'Amore termp____post(DECL_ARGS)
213695c635efSGarrett D'Amore {
213795c635efSGarrett D'Amore 
213895c635efSGarrett D'Amore 	/*
213995c635efSGarrett D'Amore 	 * Handle lists of authors.  In general, print each followed by
214095c635efSGarrett D'Amore 	 * a comma.  Don't print the comma if there are only two
214195c635efSGarrett D'Amore 	 * authors.
214295c635efSGarrett D'Amore 	 */
214395c635efSGarrett D'Amore 	if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok)
214495c635efSGarrett D'Amore 		if (NULL == n->next->next || MDOC__A != n->next->next->tok)
214595c635efSGarrett D'Amore 			if (NULL == n->prev || MDOC__A != n->prev->tok)
214695c635efSGarrett D'Amore 				return;
214795c635efSGarrett D'Amore 
214895c635efSGarrett D'Amore 	/* TODO: %U. */
214995c635efSGarrett D'Amore 
215095c635efSGarrett D'Amore 	if (NULL == n->parent || MDOC_Rs != n->parent->tok)
215195c635efSGarrett D'Amore 		return;
215295c635efSGarrett D'Amore 
215395c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
215495c635efSGarrett D'Amore 	if (NULL == n->next) {
215595c635efSGarrett D'Amore 		term_word(p, ".");
215695c635efSGarrett D'Amore 		p->flags |= TERMP_SENTENCE;
215795c635efSGarrett D'Amore 	} else
215895c635efSGarrett D'Amore 		term_word(p, ",");
215995c635efSGarrett D'Amore }
216095c635efSGarrett D'Amore 
216195c635efSGarrett D'Amore static int
216295c635efSGarrett D'Amore termp_li_pre(DECL_ARGS)
216395c635efSGarrett D'Amore {
216495c635efSGarrett D'Amore 
216595c635efSGarrett D'Amore 	term_fontpush(p, TERMFONT_NONE);
216695c635efSGarrett D'Amore 	return(1);
216795c635efSGarrett D'Amore }
216895c635efSGarrett D'Amore 
216995c635efSGarrett D'Amore static int
217095c635efSGarrett D'Amore termp_lk_pre(DECL_ARGS)
217195c635efSGarrett D'Amore {
2172698f87a4SGarrett D'Amore 	const struct mdoc_node *link, *descr;
217395c635efSGarrett D'Amore 
2174698f87a4SGarrett D'Amore 	if (NULL == (link = n->child))
2175698f87a4SGarrett D'Amore 		return(0);
2176698f87a4SGarrett D'Amore 
2177698f87a4SGarrett D'Amore 	if (NULL != (descr = link->next)) {
217895c635efSGarrett D'Amore 		term_fontpush(p, TERMFONT_UNDER);
2179698f87a4SGarrett D'Amore 		while (NULL != descr) {
2180698f87a4SGarrett D'Amore 			term_word(p, descr->string);
2181698f87a4SGarrett D'Amore 			descr = descr->next;
2182698f87a4SGarrett D'Amore 		}
218395c635efSGarrett D'Amore 		p->flags |= TERMP_NOSPACE;
218495c635efSGarrett D'Amore 		term_word(p, ":");
2185698f87a4SGarrett D'Amore 		term_fontpop(p);
2186698f87a4SGarrett D'Amore 	}
218795c635efSGarrett D'Amore 
218895c635efSGarrett D'Amore 	term_fontpush(p, TERMFONT_BOLD);
2189698f87a4SGarrett D'Amore 	term_word(p, link->string);
219095c635efSGarrett D'Amore 	term_fontpop(p);
219195c635efSGarrett D'Amore 
219295c635efSGarrett D'Amore 	return(0);
219395c635efSGarrett D'Amore }
219495c635efSGarrett D'Amore 
219595c635efSGarrett D'Amore static int
219695c635efSGarrett D'Amore termp_bk_pre(DECL_ARGS)
219795c635efSGarrett D'Amore {
219895c635efSGarrett D'Amore 
219995c635efSGarrett D'Amore 	switch (n->type) {
2200*260e9a87SYuri Pankov 	case MDOC_BLOCK:
220195c635efSGarrett D'Amore 		break;
2202*260e9a87SYuri Pankov 	case MDOC_HEAD:
220395c635efSGarrett D'Amore 		return(0);
2204*260e9a87SYuri Pankov 	case MDOC_BODY:
220595c635efSGarrett D'Amore 		if (n->parent->args || 0 == n->prev->nchild)
220695c635efSGarrett D'Amore 			p->flags |= TERMP_PREKEEP;
220795c635efSGarrett D'Amore 		break;
220895c635efSGarrett D'Amore 	default:
220995c635efSGarrett D'Amore 		abort();
221095c635efSGarrett D'Amore 		/* NOTREACHED */
221195c635efSGarrett D'Amore 	}
221295c635efSGarrett D'Amore 
221395c635efSGarrett D'Amore 	return(1);
221495c635efSGarrett D'Amore }
221595c635efSGarrett D'Amore 
221695c635efSGarrett D'Amore static void
221795c635efSGarrett D'Amore termp_bk_post(DECL_ARGS)
221895c635efSGarrett D'Amore {
221995c635efSGarrett D'Amore 
222095c635efSGarrett D'Amore 	if (MDOC_BODY == n->type)
222195c635efSGarrett D'Amore 		p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
222295c635efSGarrett D'Amore }
222395c635efSGarrett D'Amore 
222495c635efSGarrett D'Amore static void
222595c635efSGarrett D'Amore termp__t_post(DECL_ARGS)
222695c635efSGarrett D'Amore {
222795c635efSGarrett D'Amore 
222895c635efSGarrett D'Amore 	/*
222995c635efSGarrett D'Amore 	 * If we're in an `Rs' and there's a journal present, then quote
223095c635efSGarrett D'Amore 	 * us instead of underlining us (for disambiguation).
223195c635efSGarrett D'Amore 	 */
223295c635efSGarrett D'Amore 	if (n->parent && MDOC_Rs == n->parent->tok &&
223395c635efSGarrett D'Amore 	    n->parent->norm->Rs.quote_T)
2234698f87a4SGarrett D'Amore 		termp_quote_post(p, pair, meta, n);
223595c635efSGarrett D'Amore 
2236698f87a4SGarrett D'Amore 	termp____post(p, pair, meta, n);
223795c635efSGarrett D'Amore }
223895c635efSGarrett D'Amore 
223995c635efSGarrett D'Amore static int
224095c635efSGarrett D'Amore termp__t_pre(DECL_ARGS)
224195c635efSGarrett D'Amore {
224295c635efSGarrett D'Amore 
224395c635efSGarrett D'Amore 	/*
224495c635efSGarrett D'Amore 	 * If we're in an `Rs' and there's a journal present, then quote
224595c635efSGarrett D'Amore 	 * us instead of underlining us (for disambiguation).
224695c635efSGarrett D'Amore 	 */
224795c635efSGarrett D'Amore 	if (n->parent && MDOC_Rs == n->parent->tok &&
224895c635efSGarrett D'Amore 	    n->parent->norm->Rs.quote_T)
2249698f87a4SGarrett D'Amore 		return(termp_quote_pre(p, pair, meta, n));
225095c635efSGarrett D'Amore 
225195c635efSGarrett D'Amore 	term_fontpush(p, TERMFONT_UNDER);
225295c635efSGarrett D'Amore 	return(1);
225395c635efSGarrett D'Amore }
225495c635efSGarrett D'Amore 
225595c635efSGarrett D'Amore static int
225695c635efSGarrett D'Amore termp_under_pre(DECL_ARGS)
225795c635efSGarrett D'Amore {
225895c635efSGarrett D'Amore 
225995c635efSGarrett D'Amore 	term_fontpush(p, TERMFONT_UNDER);
226095c635efSGarrett D'Amore 	return(1);
226195c635efSGarrett D'Amore }
2262