1294113Sbapt/*	$Id: mdoc_man.c,v 1.96 2016/01/08 17:48:09 schwarze Exp $ */
2241675Suqs/*
3294113Sbapt * Copyright (c) 2011-2016 Ingo Schwarze <schwarze@openbsd.org>
4241675Suqs *
5241675Suqs * Permission to use, copy, modify, and distribute this software for any
6241675Suqs * purpose with or without fee is hereby granted, provided that the above
7241675Suqs * copyright notice and this permission notice appear in all copies.
8241675Suqs *
9241675Suqs * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10241675Suqs * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11241675Suqs * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12241675Suqs * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13241675Suqs * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14241675Suqs * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15241675Suqs * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16241675Suqs */
17241675Suqs#include "config.h"
18241675Suqs
19275432Sbapt#include <sys/types.h>
20275432Sbapt
21261344Suqs#include <assert.h>
22241675Suqs#include <stdio.h>
23241675Suqs#include <string.h>
24241675Suqs
25294113Sbapt#include "mandoc_aux.h"
26241675Suqs#include "mandoc.h"
27294113Sbapt#include "roff.h"
28294113Sbapt#include "mdoc.h"
29294113Sbapt#include "man.h"
30261344Suqs#include "out.h"
31241675Suqs#include "main.h"
32241675Suqs
33294113Sbapt#define	DECL_ARGS const struct roff_meta *meta, struct roff_node *n
34241675Suqs
35241675Suqsstruct	manact {
36241675Suqs	int		(*cond)(DECL_ARGS); /* DON'T run actions */
37241675Suqs	int		(*pre)(DECL_ARGS); /* pre-node action */
38241675Suqs	void		(*post)(DECL_ARGS); /* post-node action */
39241675Suqs	const char	 *prefix; /* pre-node string constant */
40241675Suqs	const char	 *suffix; /* post-node string constant */
41241675Suqs};
42241675Suqs
43241675Suqsstatic	int	  cond_body(DECL_ARGS);
44241675Suqsstatic	int	  cond_head(DECL_ARGS);
45261344Suqsstatic  void	  font_push(char);
46261344Suqsstatic	void	  font_pop(void);
47261344Suqsstatic	void	  mid_it(void);
48261344Suqsstatic	void	  post__t(DECL_ARGS);
49275432Sbaptstatic	void	  post_aq(DECL_ARGS);
50241675Suqsstatic	void	  post_bd(DECL_ARGS);
51261344Suqsstatic	void	  post_bf(DECL_ARGS);
52261344Suqsstatic	void	  post_bk(DECL_ARGS);
53261344Suqsstatic	void	  post_bl(DECL_ARGS);
54241675Suqsstatic	void	  post_dl(DECL_ARGS);
55274880Sbaptstatic	void	  post_en(DECL_ARGS);
56241675Suqsstatic	void	  post_enc(DECL_ARGS);
57261344Suqsstatic	void	  post_eo(DECL_ARGS);
58261344Suqsstatic	void	  post_fa(DECL_ARGS);
59261344Suqsstatic	void	  post_fd(DECL_ARGS);
60261344Suqsstatic	void	  post_fl(DECL_ARGS);
61261344Suqsstatic	void	  post_fn(DECL_ARGS);
62261344Suqsstatic	void	  post_fo(DECL_ARGS);
63261344Suqsstatic	void	  post_font(DECL_ARGS);
64261344Suqsstatic	void	  post_in(DECL_ARGS);
65261344Suqsstatic	void	  post_it(DECL_ARGS);
66261344Suqsstatic	void	  post_lb(DECL_ARGS);
67241675Suqsstatic	void	  post_nm(DECL_ARGS);
68241675Suqsstatic	void	  post_percent(DECL_ARGS);
69241675Suqsstatic	void	  post_pf(DECL_ARGS);
70241675Suqsstatic	void	  post_sect(DECL_ARGS);
71241675Suqsstatic	void	  post_sp(DECL_ARGS);
72261344Suqsstatic	void	  post_vt(DECL_ARGS);
73261344Suqsstatic	int	  pre__t(DECL_ARGS);
74261344Suqsstatic	int	  pre_an(DECL_ARGS);
75241675Suqsstatic	int	  pre_ap(DECL_ARGS);
76275432Sbaptstatic	int	  pre_aq(DECL_ARGS);
77241675Suqsstatic	int	  pre_bd(DECL_ARGS);
78261344Suqsstatic	int	  pre_bf(DECL_ARGS);
79261344Suqsstatic	int	  pre_bk(DECL_ARGS);
80261344Suqsstatic	int	  pre_bl(DECL_ARGS);
81241675Suqsstatic	int	  pre_br(DECL_ARGS);
82241675Suqsstatic	int	  pre_bx(DECL_ARGS);
83241675Suqsstatic	int	  pre_dl(DECL_ARGS);
84274880Sbaptstatic	int	  pre_en(DECL_ARGS);
85241675Suqsstatic	int	  pre_enc(DECL_ARGS);
86261344Suqsstatic	int	  pre_em(DECL_ARGS);
87275432Sbaptstatic	int	  pre_skip(DECL_ARGS);
88275432Sbaptstatic	int	  pre_eo(DECL_ARGS);
89274880Sbaptstatic	int	  pre_ex(DECL_ARGS);
90261344Suqsstatic	int	  pre_fa(DECL_ARGS);
91261344Suqsstatic	int	  pre_fd(DECL_ARGS);
92261344Suqsstatic	int	  pre_fl(DECL_ARGS);
93261344Suqsstatic	int	  pre_fn(DECL_ARGS);
94261344Suqsstatic	int	  pre_fo(DECL_ARGS);
95261344Suqsstatic	int	  pre_ft(DECL_ARGS);
96261344Suqsstatic	int	  pre_in(DECL_ARGS);
97241675Suqsstatic	int	  pre_it(DECL_ARGS);
98261344Suqsstatic	int	  pre_lk(DECL_ARGS);
99261344Suqsstatic	int	  pre_li(DECL_ARGS);
100274880Sbaptstatic	int	  pre_ll(DECL_ARGS);
101241675Suqsstatic	int	  pre_nm(DECL_ARGS);
102261344Suqsstatic	int	  pre_no(DECL_ARGS);
103241675Suqsstatic	int	  pre_ns(DECL_ARGS);
104241675Suqsstatic	int	  pre_pp(DECL_ARGS);
105261344Suqsstatic	int	  pre_rs(DECL_ARGS);
106274880Sbaptstatic	int	  pre_rv(DECL_ARGS);
107261344Suqsstatic	int	  pre_sm(DECL_ARGS);
108241675Suqsstatic	int	  pre_sp(DECL_ARGS);
109241675Suqsstatic	int	  pre_sect(DECL_ARGS);
110261344Suqsstatic	int	  pre_sy(DECL_ARGS);
111294113Sbaptstatic	void	  pre_syn(const struct roff_node *);
112261344Suqsstatic	int	  pre_vt(DECL_ARGS);
113241675Suqsstatic	int	  pre_ux(DECL_ARGS);
114241675Suqsstatic	int	  pre_xr(DECL_ARGS);
115261344Suqsstatic	void	  print_word(const char *);
116261344Suqsstatic	void	  print_line(const char *, int);
117261344Suqsstatic	void	  print_block(const char *, int);
118275432Sbaptstatic	void	  print_offs(const char *, int);
119279527Sbaptstatic	void	  print_width(const struct mdoc_bl *,
120294113Sbapt			const struct roff_node *);
121261344Suqsstatic	void	  print_count(int *);
122241675Suqsstatic	void	  print_node(DECL_ARGS);
123241675Suqs
124241675Suqsstatic	const struct manact manacts[MDOC_MAX + 1] = {
125241675Suqs	{ NULL, pre_ap, NULL, NULL, NULL }, /* Ap */
126241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Dd */
127241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Dt */
128241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Os */
129241675Suqs	{ NULL, pre_sect, post_sect, ".SH", NULL }, /* Sh */
130241675Suqs	{ NULL, pre_sect, post_sect, ".SS", NULL }, /* Ss */
131241675Suqs	{ NULL, pre_pp, NULL, NULL, NULL }, /* Pp */
132241675Suqs	{ cond_body, pre_dl, post_dl, NULL, NULL }, /* D1 */
133241675Suqs	{ cond_body, pre_dl, post_dl, NULL, NULL }, /* Dl */
134241675Suqs	{ cond_body, pre_bd, post_bd, NULL, NULL }, /* Bd */
135241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Ed */
136261344Suqs	{ cond_body, pre_bl, post_bl, NULL, NULL }, /* Bl */
137241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* El */
138261344Suqs	{ NULL, pre_it, post_it, NULL, NULL }, /* It */
139261344Suqs	{ NULL, pre_em, post_font, NULL, NULL }, /* Ad */
140261344Suqs	{ NULL, pre_an, NULL, NULL, NULL }, /* An */
141261344Suqs	{ NULL, pre_em, post_font, NULL, NULL }, /* Ar */
142261344Suqs	{ NULL, pre_sy, post_font, NULL, NULL }, /* Cd */
143261344Suqs	{ NULL, pre_sy, post_font, NULL, NULL }, /* Cm */
144261344Suqs	{ NULL, pre_li, post_font, NULL, NULL }, /* Dv */
145261344Suqs	{ NULL, pre_li, post_font, NULL, NULL }, /* Er */
146261344Suqs	{ NULL, pre_li, post_font, NULL, NULL }, /* Ev */
147274880Sbapt	{ NULL, pre_ex, NULL, NULL, NULL }, /* Ex */
148261344Suqs	{ NULL, pre_fa, post_fa, NULL, NULL }, /* Fa */
149261344Suqs	{ NULL, pre_fd, post_fd, NULL, NULL }, /* Fd */
150261344Suqs	{ NULL, pre_fl, post_fl, NULL, NULL }, /* Fl */
151261344Suqs	{ NULL, pre_fn, post_fn, NULL, NULL }, /* Fn */
152261344Suqs	{ NULL, pre_ft, post_font, NULL, NULL }, /* Ft */
153261344Suqs	{ NULL, pre_sy, post_font, NULL, NULL }, /* Ic */
154261344Suqs	{ NULL, pre_in, post_in, NULL, NULL }, /* In */
155261344Suqs	{ NULL, pre_li, post_font, NULL, NULL }, /* Li */
156241675Suqs	{ cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */
157241675Suqs	{ NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */
158241675Suqs	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Op */
159274880Sbapt	{ NULL, pre_ft, post_font, NULL, NULL }, /* Ot */
160261344Suqs	{ NULL, pre_em, post_font, NULL, NULL }, /* Pa */
161274880Sbapt	{ NULL, pre_rv, NULL, NULL, NULL }, /* Rv */
162241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* St */
163261344Suqs	{ NULL, pre_em, post_font, NULL, NULL }, /* Va */
164261344Suqs	{ NULL, pre_vt, post_vt, NULL, NULL }, /* Vt */
165241675Suqs	{ NULL, pre_xr, NULL, NULL, NULL }, /* Xr */
166261344Suqs	{ NULL, NULL, post_percent, NULL, NULL }, /* %A */
167261344Suqs	{ NULL, pre_em, post_percent, NULL, NULL }, /* %B */
168261344Suqs	{ NULL, NULL, post_percent, NULL, NULL }, /* %D */
169261344Suqs	{ NULL, pre_em, post_percent, NULL, NULL }, /* %I */
170261344Suqs	{ NULL, pre_em, post_percent, NULL, NULL }, /* %J */
171261344Suqs	{ NULL, NULL, post_percent, NULL, NULL }, /* %N */
172261344Suqs	{ NULL, NULL, post_percent, NULL, NULL }, /* %O */
173261344Suqs	{ NULL, NULL, post_percent, NULL, NULL }, /* %P */
174261344Suqs	{ NULL, NULL, post_percent, NULL, NULL }, /* %R */
175261344Suqs	{ NULL, pre__t, post__t, NULL, NULL }, /* %T */
176261344Suqs	{ NULL, NULL, post_percent, NULL, NULL }, /* %V */
177241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Ac */
178275432Sbapt	{ cond_body, pre_aq, post_aq, NULL, NULL }, /* Ao */
179275432Sbapt	{ cond_body, pre_aq, post_aq, NULL, NULL }, /* Aq */
180241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* At */
181241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Bc */
182261344Suqs	{ NULL, pre_bf, post_bf, NULL, NULL }, /* Bf */
183241675Suqs	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Bo */
184241675Suqs	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Bq */
185241675Suqs	{ NULL, pre_ux, NULL, "BSD/OS", NULL }, /* Bsx */
186241675Suqs	{ NULL, pre_bx, NULL, NULL, NULL }, /* Bx */
187275432Sbapt	{ NULL, pre_skip, NULL, NULL, NULL }, /* Db */
188241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Dc */
189279527Sbapt	{ cond_body, pre_enc, post_enc, "\\(Lq", "\\(Rq" }, /* Do */
190279527Sbapt	{ cond_body, pre_enc, post_enc, "\\(Lq", "\\(Rq" }, /* Dq */
191261344Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Ec */
192261344Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Ef */
193261344Suqs	{ NULL, pre_em, post_font, NULL, NULL }, /* Em */
194275432Sbapt	{ cond_body, pre_eo, post_eo, NULL, NULL }, /* Eo */
195241675Suqs	{ NULL, pre_ux, NULL, "FreeBSD", NULL }, /* Fx */
196261344Suqs	{ NULL, pre_sy, post_font, NULL, NULL }, /* Ms */
197261344Suqs	{ NULL, pre_no, NULL, NULL, NULL }, /* No */
198241675Suqs	{ NULL, pre_ns, NULL, NULL, NULL }, /* Ns */
199241675Suqs	{ NULL, pre_ux, NULL, "NetBSD", NULL }, /* Nx */
200241675Suqs	{ NULL, pre_ux, NULL, "OpenBSD", NULL }, /* Ox */
201241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Pc */
202241675Suqs	{ NULL, NULL, post_pf, NULL, NULL }, /* Pf */
203241675Suqs	{ cond_body, pre_enc, post_enc, "(", ")" }, /* Po */
204241675Suqs	{ cond_body, pre_enc, post_enc, "(", ")" }, /* Pq */
205241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Qc */
206261344Suqs	{ cond_body, pre_enc, post_enc, "\\(oq", "\\(cq" }, /* Ql */
207241675Suqs	{ cond_body, pre_enc, post_enc, "\"", "\"" }, /* Qo */
208241675Suqs	{ cond_body, pre_enc, post_enc, "\"", "\"" }, /* Qq */
209241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Re */
210261344Suqs	{ cond_body, pre_rs, NULL, NULL, NULL }, /* Rs */
211241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Sc */
212261344Suqs	{ cond_body, pre_enc, post_enc, "\\(oq", "\\(cq" }, /* So */
213261344Suqs	{ cond_body, pre_enc, post_enc, "\\(oq", "\\(cq" }, /* Sq */
214261344Suqs	{ NULL, pre_sm, NULL, NULL, NULL }, /* Sm */
215261344Suqs	{ NULL, pre_em, post_font, NULL, NULL }, /* Sx */
216261344Suqs	{ NULL, pre_sy, post_font, NULL, NULL }, /* Sy */
217261344Suqs	{ NULL, pre_li, post_font, NULL, NULL }, /* Tn */
218241675Suqs	{ NULL, pre_ux, NULL, "UNIX", NULL }, /* Ux */
219261344Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Xc */
220261344Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Xo */
221261344Suqs	{ NULL, pre_fo, post_fo, NULL, NULL }, /* Fo */
222261344Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Fc */
223241675Suqs	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Oo */
224241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Oc */
225261344Suqs	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Bk */
226261344Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Ek */
227241675Suqs	{ NULL, pre_ux, NULL, "is currently in beta test.", NULL }, /* Bt */
228241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Hf */
229274880Sbapt	{ NULL, pre_em, post_font, NULL, NULL }, /* Fr */
230241675Suqs	{ NULL, pre_ux, NULL, "currently under development.", NULL }, /* Ud */
231261344Suqs	{ NULL, NULL, post_lb, NULL, NULL }, /* Lb */
232241675Suqs	{ NULL, pre_pp, NULL, NULL, NULL }, /* Lp */
233261344Suqs	{ NULL, pre_lk, NULL, NULL, NULL }, /* Lk */
234261344Suqs	{ NULL, pre_em, post_font, NULL, NULL }, /* Mt */
235241675Suqs	{ cond_body, pre_enc, post_enc, "{", "}" }, /* Brq */
236241675Suqs	{ cond_body, pre_enc, post_enc, "{", "}" }, /* Bro */
237241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Brc */
238261344Suqs	{ NULL, NULL, post_percent, NULL, NULL }, /* %C */
239275432Sbapt	{ NULL, pre_skip, NULL, NULL, NULL }, /* Es */
240274880Sbapt	{ cond_body, pre_en, post_en, NULL, NULL }, /* En */
241241675Suqs	{ NULL, pre_ux, NULL, "DragonFly", NULL }, /* Dx */
242261344Suqs	{ NULL, NULL, post_percent, NULL, NULL }, /* %Q */
243241675Suqs	{ NULL, pre_br, NULL, NULL, NULL }, /* br */
244241675Suqs	{ NULL, pre_sp, post_sp, NULL, NULL }, /* sp */
245261344Suqs	{ NULL, NULL, post_percent, NULL, NULL }, /* %U */
246261344Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Ta */
247274880Sbapt	{ NULL, pre_ll, post_sp, NULL, NULL }, /* ll */
248241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* ROOT */
249241675Suqs};
250241675Suqs
251261344Suqsstatic	int		outflags;
252261344Suqs#define	MMAN_spc	(1 << 0)  /* blank character before next word */
253261344Suqs#define	MMAN_spc_force	(1 << 1)  /* even before trailing punctuation */
254261344Suqs#define	MMAN_nl		(1 << 2)  /* break man(7) code line */
255261344Suqs#define	MMAN_br		(1 << 3)  /* break output line */
256261344Suqs#define	MMAN_sp		(1 << 4)  /* insert a blank output line */
257261344Suqs#define	MMAN_PP		(1 << 5)  /* reset indentation etc. */
258261344Suqs#define	MMAN_Sm		(1 << 6)  /* horizontal spacing mode */
259261344Suqs#define	MMAN_Bk		(1 << 7)  /* word keep mode */
260261344Suqs#define	MMAN_Bk_susp	(1 << 8)  /* suspend this (after a macro) */
261261344Suqs#define	MMAN_An_split	(1 << 9)  /* author mode is "split" */
262261344Suqs#define	MMAN_An_nosplit	(1 << 10) /* author mode is "nosplit" */
263261344Suqs#define	MMAN_PD		(1 << 11) /* inter-paragraph spacing disabled */
264261344Suqs#define	MMAN_nbrword	(1 << 12) /* do not break the next word */
265261344Suqs
266261344Suqs#define	BL_STACK_MAX	32
267261344Suqs
268279527Sbaptstatic	int		Bl_stack[BL_STACK_MAX];  /* offsets [chars] */
269261344Suqsstatic	int		Bl_stack_post[BL_STACK_MAX];  /* add final .RE */
270261344Suqsstatic	int		Bl_stack_len;  /* number of nested Bl blocks */
271261344Suqsstatic	int		TPremain;  /* characters before tag is full */
272261344Suqs
273261344Suqsstatic	struct {
274261344Suqs	char	*head;
275261344Suqs	char	*tail;
276261344Suqs	size_t	 size;
277261344Suqs}	fontqueue;
278261344Suqs
279274880Sbapt
280241675Suqsstatic void
281261344Suqsfont_push(char newfont)
282241675Suqs{
283241675Suqs
284261344Suqs	if (fontqueue.head + fontqueue.size <= ++fontqueue.tail) {
285261344Suqs		fontqueue.size += 8;
286261344Suqs		fontqueue.head = mandoc_realloc(fontqueue.head,
287274880Sbapt		    fontqueue.size);
288261344Suqs	}
289261344Suqs	*fontqueue.tail = newfont;
290261344Suqs	print_word("");
291261344Suqs	printf("\\f");
292261344Suqs	putchar(newfont);
293261344Suqs	outflags &= ~MMAN_spc;
294261344Suqs}
295261344Suqs
296261344Suqsstatic void
297261344Suqsfont_pop(void)
298261344Suqs{
299261344Suqs
300261344Suqs	if (fontqueue.tail > fontqueue.head)
301261344Suqs		fontqueue.tail--;
302261344Suqs	outflags &= ~MMAN_spc;
303261344Suqs	print_word("");
304261344Suqs	printf("\\f");
305261344Suqs	putchar(*fontqueue.tail);
306261344Suqs}
307261344Suqs
308261344Suqsstatic void
309261344Suqsprint_word(const char *s)
310261344Suqs{
311261344Suqs
312261344Suqs	if ((MMAN_PP | MMAN_sp | MMAN_br | MMAN_nl) & outflags) {
313274880Sbapt		/*
314241675Suqs		 * If we need a newline, print it now and start afresh.
315241675Suqs		 */
316261344Suqs		if (MMAN_PP & outflags) {
317261344Suqs			if (MMAN_sp & outflags) {
318261344Suqs				if (MMAN_PD & outflags) {
319261344Suqs					printf("\n.PD");
320261344Suqs					outflags &= ~MMAN_PD;
321261344Suqs				}
322261344Suqs			} else if ( ! (MMAN_PD & outflags)) {
323261344Suqs				printf("\n.PD 0");
324261344Suqs				outflags |= MMAN_PD;
325261344Suqs			}
326261344Suqs			printf("\n.PP\n");
327261344Suqs		} else if (MMAN_sp & outflags)
328261344Suqs			printf("\n.sp\n");
329261344Suqs		else if (MMAN_br & outflags)
330261344Suqs			printf("\n.br\n");
331261344Suqs		else if (MMAN_nl & outflags)
332261344Suqs			putchar('\n');
333261344Suqs		outflags &= ~(MMAN_PP|MMAN_sp|MMAN_br|MMAN_nl|MMAN_spc);
334261344Suqs		if (1 == TPremain)
335261344Suqs			printf(".br\n");
336261344Suqs		TPremain = 0;
337261344Suqs	} else if (MMAN_spc & outflags) {
338241675Suqs		/*
339261344Suqs		 * If we need a space, only print it if
340261344Suqs		 * (1) it is forced by `No' or
341261344Suqs		 * (2) what follows is not terminating punctuation or
342261344Suqs		 * (3) what follows is longer than one character.
343241675Suqs		 */
344261344Suqs		if (MMAN_spc_force & outflags || '\0' == s[0] ||
345261344Suqs		    NULL == strchr(".,:;)]?!", s[0]) || '\0' != s[1]) {
346261344Suqs			if (MMAN_Bk & outflags &&
347261344Suqs			    ! (MMAN_Bk_susp & outflags))
348261344Suqs				putchar('\\');
349241675Suqs			putchar(' ');
350261344Suqs			if (TPremain)
351261344Suqs				TPremain--;
352261344Suqs		}
353261344Suqs	}
354241675Suqs
355241675Suqs	/*
356241675Suqs	 * Reassign needing space if we're not following opening
357241675Suqs	 * punctuation.
358241675Suqs	 */
359261344Suqs	if (MMAN_Sm & outflags && ('\0' == s[0] ||
360261344Suqs	    (('(' != s[0] && '[' != s[0]) || '\0' != s[1])))
361261344Suqs		outflags |= MMAN_spc;
362261344Suqs	else
363261344Suqs		outflags &= ~MMAN_spc;
364261344Suqs	outflags &= ~(MMAN_spc_force | MMAN_Bk_susp);
365241675Suqs
366241675Suqs	for ( ; *s; s++) {
367241675Suqs		switch (*s) {
368274880Sbapt		case ASCII_NBRSP:
369261344Suqs			printf("\\ ");
370241675Suqs			break;
371274880Sbapt		case ASCII_HYPH:
372241675Suqs			putchar('-');
373241675Suqs			break;
374274880Sbapt		case ASCII_BREAK:
375274880Sbapt			printf("\\:");
376274880Sbapt			break;
377274880Sbapt		case ' ':
378261344Suqs			if (MMAN_nbrword & outflags) {
379261344Suqs				printf("\\ ");
380261344Suqs				break;
381261344Suqs			}
382261344Suqs			/* FALLTHROUGH */
383241675Suqs		default:
384241675Suqs			putchar((unsigned char)*s);
385241675Suqs			break;
386241675Suqs		}
387261344Suqs		if (TPremain)
388261344Suqs			TPremain--;
389241675Suqs	}
390261344Suqs	outflags &= ~MMAN_nbrword;
391241675Suqs}
392241675Suqs
393261344Suqsstatic void
394261344Suqsprint_line(const char *s, int newflags)
395261344Suqs{
396261344Suqs
397261344Suqs	outflags &= ~MMAN_br;
398261344Suqs	outflags |= MMAN_nl;
399261344Suqs	print_word(s);
400261344Suqs	outflags |= newflags;
401261344Suqs}
402261344Suqs
403261344Suqsstatic void
404261344Suqsprint_block(const char *s, int newflags)
405261344Suqs{
406261344Suqs
407261344Suqs	outflags &= ~MMAN_PP;
408261344Suqs	if (MMAN_sp & outflags) {
409261344Suqs		outflags &= ~(MMAN_sp | MMAN_br);
410261344Suqs		if (MMAN_PD & outflags) {
411261344Suqs			print_line(".PD", 0);
412261344Suqs			outflags &= ~MMAN_PD;
413261344Suqs		}
414261344Suqs	} else if (! (MMAN_PD & outflags))
415261344Suqs		print_line(".PD 0", MMAN_PD);
416261344Suqs	outflags |= MMAN_nl;
417261344Suqs	print_word(s);
418261344Suqs	outflags |= MMAN_Bk_susp | newflags;
419261344Suqs}
420261344Suqs
421261344Suqsstatic void
422275432Sbaptprint_offs(const char *v, int keywords)
423261344Suqs{
424261344Suqs	char		  buf[24];
425261344Suqs	struct roffsu	  su;
426279527Sbapt	int		  sz;
427261344Suqs
428261344Suqs	print_line(".RS", MMAN_Bk_susp);
429261344Suqs
430261344Suqs	/* Convert v into a number (of characters). */
431275432Sbapt	if (NULL == v || '\0' == *v || (keywords && !strcmp(v, "left")))
432261344Suqs		sz = 0;
433275432Sbapt	else if (keywords && !strcmp(v, "indent"))
434261344Suqs		sz = 6;
435275432Sbapt	else if (keywords && !strcmp(v, "indent-two"))
436261344Suqs		sz = 12;
437279527Sbapt	else if (a2roffsu(v, &su, SCALE_EN) > 1) {
438261344Suqs		if (SCALE_EN == su.unit)
439261344Suqs			sz = su.scale;
440261344Suqs		else {
441261344Suqs			/*
442261344Suqs			 * XXX
443261344Suqs			 * If we are inside an enclosing list,
444261344Suqs			 * there is no easy way to add the two
445261344Suqs			 * indentations because they are provided
446261344Suqs			 * in terms of different units.
447261344Suqs			 */
448261344Suqs			print_word(v);
449261344Suqs			outflags |= MMAN_nl;
450261344Suqs			return;
451261344Suqs		}
452261344Suqs	} else
453261344Suqs		sz = strlen(v);
454261344Suqs
455261344Suqs	/*
456261344Suqs	 * We are inside an enclosing list.
457261344Suqs	 * Add the two indentations.
458261344Suqs	 */
459261344Suqs	if (Bl_stack_len)
460261344Suqs		sz += Bl_stack[Bl_stack_len - 1];
461261344Suqs
462279527Sbapt	(void)snprintf(buf, sizeof(buf), "%dn", sz);
463261344Suqs	print_word(buf);
464261344Suqs	outflags |= MMAN_nl;
465261344Suqs}
466261344Suqs
467261344Suqs/*
468261344Suqs * Set up the indentation for a list item; used from pre_it().
469261344Suqs */
470274880Sbaptstatic void
471294113Sbaptprint_width(const struct mdoc_bl *bl, const struct roff_node *child)
472261344Suqs{
473261344Suqs	char		  buf[24];
474261344Suqs	struct roffsu	  su;
475279527Sbapt	int		  numeric, remain, sz, chsz;
476261344Suqs
477261344Suqs	numeric = 1;
478261344Suqs	remain = 0;
479261344Suqs
480279527Sbapt	/* Convert the width into a number (of characters). */
481279527Sbapt	if (bl->width == NULL)
482279527Sbapt		sz = (bl->type == LIST_hang) ? 6 : 0;
483279527Sbapt	else if (a2roffsu(bl->width, &su, SCALE_MAX) > 1) {
484261344Suqs		if (SCALE_EN == su.unit)
485261344Suqs			sz = su.scale;
486261344Suqs		else {
487261344Suqs			sz = 0;
488261344Suqs			numeric = 0;
489261344Suqs		}
490261344Suqs	} else
491279527Sbapt		sz = strlen(bl->width);
492261344Suqs
493261344Suqs	/* XXX Rough estimation, might have multiple parts. */
494279527Sbapt	if (bl->type == LIST_enum)
495279527Sbapt		chsz = (bl->count > 8) + 1;
496294113Sbapt	else if (child != NULL && child->type == ROFFT_TEXT)
497279527Sbapt		chsz = strlen(child->string);
498279527Sbapt	else
499279527Sbapt		chsz = 0;
500261344Suqs
501261344Suqs	/* Maybe we are inside an enclosing list? */
502261344Suqs	mid_it();
503261344Suqs
504261344Suqs	/*
505261344Suqs	 * Save our own indentation,
506261344Suqs	 * such that child lists can use it.
507261344Suqs	 */
508261344Suqs	Bl_stack[Bl_stack_len++] = sz + 2;
509261344Suqs
510261344Suqs	/* Set up the current list. */
511279527Sbapt	if (chsz > sz && bl->type != LIST_tag)
512261344Suqs		print_block(".HP", 0);
513261344Suqs	else {
514261344Suqs		print_block(".TP", 0);
515261344Suqs		remain = sz + 2;
516261344Suqs	}
517261344Suqs	if (numeric) {
518279527Sbapt		(void)snprintf(buf, sizeof(buf), "%dn", sz + 2);
519261344Suqs		print_word(buf);
520261344Suqs	} else
521279527Sbapt		print_word(bl->width);
522261344Suqs	TPremain = remain;
523261344Suqs}
524261344Suqs
525274880Sbaptstatic void
526261344Suqsprint_count(int *count)
527261344Suqs{
528274880Sbapt	char		  buf[24];
529261344Suqs
530279527Sbapt	(void)snprintf(buf, sizeof(buf), "%d.\\&", ++*count);
531261344Suqs	print_word(buf);
532261344Suqs}
533261344Suqs
534261344Suqsvoid
535294113Sbaptman_man(void *arg, const struct roff_man *man)
536241675Suqs{
537241675Suqs
538241675Suqs	/*
539241675Suqs	 * Dump the keep buffer.
540241675Suqs	 * We're guaranteed by now that this exists (is non-NULL).
541241675Suqs	 * Flush stdout afterward, just in case.
542241675Suqs	 */
543241675Suqs	fputs(mparse_getkeep(man_mparse(man)), stdout);
544241675Suqs	fflush(stdout);
545241675Suqs}
546241675Suqs
547241675Suqsvoid
548294113Sbaptman_mdoc(void *arg, const struct roff_man *mdoc)
549241675Suqs{
550294113Sbapt	struct roff_node *n;
551241675Suqs
552261344Suqs	printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",
553294113Sbapt	    mdoc->meta.title,
554294113Sbapt	    (mdoc->meta.msec == NULL ? "" : mdoc->meta.msec),
555294113Sbapt	    mdoc->meta.date, mdoc->meta.os, mdoc->meta.vol);
556241675Suqs
557261344Suqs	/* Disable hyphenation and if nroff, disable justification. */
558261344Suqs	printf(".nh\n.if n .ad l");
559241675Suqs
560261344Suqs	outflags = MMAN_nl | MMAN_Sm;
561261344Suqs	if (0 == fontqueue.size) {
562261344Suqs		fontqueue.size = 8;
563261344Suqs		fontqueue.head = fontqueue.tail = mandoc_malloc(8);
564261344Suqs		*fontqueue.tail = 'R';
565261344Suqs	}
566294113Sbapt	for (n = mdoc->first->child; n != NULL; n = n->next)
567294113Sbapt		print_node(&mdoc->meta, n);
568241675Suqs	putchar('\n');
569241675Suqs}
570241675Suqs
571241675Suqsstatic void
572241675Suqsprint_node(DECL_ARGS)
573241675Suqs{
574241675Suqs	const struct manact	*act;
575294113Sbapt	struct roff_node	*sub;
576241675Suqs	int			 cond, do_sub;
577261344Suqs
578241675Suqs	/*
579241675Suqs	 * Break the line if we were parsed subsequent the current node.
580241675Suqs	 * This makes the page structure be more consistent.
581241675Suqs	 */
582261344Suqs	if (MMAN_spc & outflags && MDOC_LINE & n->flags)
583261344Suqs		outflags |= MMAN_nl;
584241675Suqs
585241675Suqs	act = NULL;
586241675Suqs	cond = 0;
587241675Suqs	do_sub = 1;
588279527Sbapt	n->flags &= ~MDOC_ENDED;
589241675Suqs
590294113Sbapt	if (n->type == ROFFT_TEXT) {
591241675Suqs		/*
592241675Suqs		 * Make sure that we don't happen to start with a
593241675Suqs		 * control character at the start of a line.
594241675Suqs		 */
595274880Sbapt		if (MMAN_nl & outflags &&
596274880Sbapt		    ('.' == *n->string || '\'' == *n->string)) {
597261344Suqs			print_word("");
598261344Suqs			printf("\\&");
599261344Suqs			outflags &= ~MMAN_spc;
600241675Suqs		}
601275432Sbapt		if (outflags & MMAN_Sm && ! (n->flags & MDOC_DELIMC))
602275432Sbapt			outflags |= MMAN_spc_force;
603261344Suqs		print_word(n->string);
604275432Sbapt		if (outflags & MMAN_Sm && ! (n->flags & MDOC_DELIMO))
605275432Sbapt			outflags |= MMAN_spc;
606241675Suqs	} else {
607241675Suqs		/*
608241675Suqs		 * Conditionally run the pre-node action handler for a
609241675Suqs		 * node.
610241675Suqs		 */
611241675Suqs		act = manacts + n->tok;
612275432Sbapt		cond = act->cond == NULL || (*act->cond)(meta, n);
613294113Sbapt		if (cond && act->pre != NULL &&
614294113Sbapt		    (n->end == ENDBODY_NOT || n->child != NULL))
615261344Suqs			do_sub = (*act->pre)(meta, n);
616241675Suqs	}
617241675Suqs
618274880Sbapt	/*
619241675Suqs	 * Conditionally run all child nodes.
620241675Suqs	 * Note that this iterates over children instead of using
621241675Suqs	 * recursion.  This prevents unnecessary depth in the stack.
622241675Suqs	 */
623241675Suqs	if (do_sub)
624241675Suqs		for (sub = n->child; sub; sub = sub->next)
625261344Suqs			print_node(meta, sub);
626241675Suqs
627241675Suqs	/*
628241675Suqs	 * Lastly, conditionally run the post-node handler.
629241675Suqs	 */
630274880Sbapt	if (MDOC_ENDED & n->flags)
631274880Sbapt		return;
632274880Sbapt
633241675Suqs	if (cond && act->post)
634261344Suqs		(*act->post)(meta, n);
635274880Sbapt
636274880Sbapt	if (ENDBODY_NOT != n->end)
637279527Sbapt		n->body->flags |= MDOC_ENDED;
638274880Sbapt
639274880Sbapt	if (ENDBODY_NOSPACE == n->end)
640274880Sbapt		outflags &= ~(MMAN_spc | MMAN_nl);
641241675Suqs}
642241675Suqs
643241675Suqsstatic int
644241675Suqscond_head(DECL_ARGS)
645241675Suqs{
646241675Suqs
647294113Sbapt	return n->type == ROFFT_HEAD;
648241675Suqs}
649241675Suqs
650241675Suqsstatic int
651241675Suqscond_body(DECL_ARGS)
652241675Suqs{
653241675Suqs
654294113Sbapt	return n->type == ROFFT_BODY;
655241675Suqs}
656241675Suqs
657241675Suqsstatic int
658241675Suqspre_enc(DECL_ARGS)
659241675Suqs{
660241675Suqs	const char	*prefix;
661241675Suqs
662241675Suqs	prefix = manacts[n->tok].prefix;
663241675Suqs	if (NULL == prefix)
664294113Sbapt		return 1;
665261344Suqs	print_word(prefix);
666261344Suqs	outflags &= ~MMAN_spc;
667294113Sbapt	return 1;
668241675Suqs}
669241675Suqs
670241675Suqsstatic void
671241675Suqspost_enc(DECL_ARGS)
672241675Suqs{
673241675Suqs	const char *suffix;
674241675Suqs
675241675Suqs	suffix = manacts[n->tok].suffix;
676241675Suqs	if (NULL == suffix)
677241675Suqs		return;
678274880Sbapt	outflags &= ~(MMAN_spc | MMAN_nl);
679261344Suqs	print_word(suffix);
680241675Suqs}
681241675Suqs
682274880Sbaptstatic int
683274880Sbaptpre_ex(DECL_ARGS)
684274880Sbapt{
685294113Sbapt	struct roff_node *nch;
686274880Sbapt
687274880Sbapt	outflags |= MMAN_br | MMAN_nl;
688274880Sbapt
689274880Sbapt	print_word("The");
690274880Sbapt
691294113Sbapt	for (nch = n->child; nch != NULL; nch = nch->next) {
692274880Sbapt		font_push('B');
693294113Sbapt		print_word(nch->string);
694274880Sbapt		font_pop();
695274880Sbapt
696294113Sbapt		if (nch->next == NULL)
697274880Sbapt			continue;
698274880Sbapt
699294113Sbapt		if (nch->prev != NULL || nch->next->next != NULL) {
700274880Sbapt			outflags &= ~MMAN_spc;
701274880Sbapt			print_word(",");
702274880Sbapt		}
703294113Sbapt		if (nch->next->next == NULL)
704274880Sbapt			print_word("and");
705274880Sbapt	}
706274880Sbapt
707294113Sbapt	if (n->child != NULL && n->child->next != NULL)
708274880Sbapt		print_word("utilities exit\\~0");
709274880Sbapt	else
710274880Sbapt		print_word("utility exits\\~0");
711274880Sbapt
712274880Sbapt	print_word("on success, and\\~>0 if an error occurs.");
713274880Sbapt	outflags |= MMAN_nl;
714294113Sbapt	return 0;
715274880Sbapt}
716274880Sbapt
717241675Suqsstatic void
718261344Suqspost_font(DECL_ARGS)
719261344Suqs{
720261344Suqs
721261344Suqs	font_pop();
722261344Suqs}
723261344Suqs
724261344Suqsstatic void
725241675Suqspost_percent(DECL_ARGS)
726241675Suqs{
727241675Suqs
728261344Suqs	if (pre_em == manacts[n->tok].pre)
729261344Suqs		font_pop();
730261344Suqs	if (n->next) {
731261344Suqs		print_word(",");
732261344Suqs		if (n->prev &&	n->prev->tok == n->tok &&
733261344Suqs				n->next->tok == n->tok)
734261344Suqs			print_word("and");
735261344Suqs	} else {
736261344Suqs		print_word(".");
737261344Suqs		outflags |= MMAN_nl;
738241675Suqs	}
739241675Suqs}
740241675Suqs
741261344Suqsstatic int
742261344Suqspre__t(DECL_ARGS)
743261344Suqs{
744261344Suqs
745274880Sbapt	if (n->parent && MDOC_Rs == n->parent->tok &&
746274880Sbapt	    n->parent->norm->Rs.quote_T) {
747261344Suqs		print_word("");
748261344Suqs		putchar('\"');
749261344Suqs		outflags &= ~MMAN_spc;
750261344Suqs	} else
751261344Suqs		font_push('I');
752294113Sbapt	return 1;
753261344Suqs}
754261344Suqs
755261344Suqsstatic void
756261344Suqspost__t(DECL_ARGS)
757261344Suqs{
758261344Suqs
759274880Sbapt	if (n->parent && MDOC_Rs == n->parent->tok &&
760274880Sbapt	    n->parent->norm->Rs.quote_T) {
761261344Suqs		outflags &= ~MMAN_spc;
762261344Suqs		print_word("");
763261344Suqs		putchar('\"');
764261344Suqs	} else
765261344Suqs		font_pop();
766261344Suqs	post_percent(meta, n);
767261344Suqs}
768261344Suqs
769241675Suqs/*
770241675Suqs * Print before a section header.
771241675Suqs */
772241675Suqsstatic int
773241675Suqspre_sect(DECL_ARGS)
774241675Suqs{
775241675Suqs
776294113Sbapt	if (n->type == ROFFT_HEAD) {
777261344Suqs		outflags |= MMAN_sp;
778261344Suqs		print_block(manacts[n->tok].prefix, 0);
779261344Suqs		print_word("");
780261344Suqs		putchar('\"');
781261344Suqs		outflags &= ~MMAN_spc;
782261344Suqs	}
783294113Sbapt	return 1;
784241675Suqs}
785241675Suqs
786241675Suqs/*
787241675Suqs * Print subsequent a section header.
788241675Suqs */
789241675Suqsstatic void
790241675Suqspost_sect(DECL_ARGS)
791241675Suqs{
792241675Suqs
793294113Sbapt	if (n->type != ROFFT_HEAD)
794241675Suqs		return;
795261344Suqs	outflags &= ~MMAN_spc;
796261344Suqs	print_word("");
797261344Suqs	putchar('\"');
798261344Suqs	outflags |= MMAN_nl;
799261344Suqs	if (MDOC_Sh == n->tok && SEC_AUTHORS == n->sec)
800261344Suqs		outflags &= ~(MMAN_An_split | MMAN_An_nosplit);
801241675Suqs}
802241675Suqs
803261344Suqs/* See mdoc_term.c, synopsis_pre() for comments. */
804261344Suqsstatic void
805294113Sbaptpre_syn(const struct roff_node *n)
806261344Suqs{
807261344Suqs
808261344Suqs	if (NULL == n->prev || ! (MDOC_SYNPRETTY & n->flags))
809261344Suqs		return;
810261344Suqs
811261344Suqs	if (n->prev->tok == n->tok &&
812274880Sbapt	    MDOC_Ft != n->tok &&
813274880Sbapt	    MDOC_Fo != n->tok &&
814274880Sbapt	    MDOC_Fn != n->tok) {
815261344Suqs		outflags |= MMAN_br;
816261344Suqs		return;
817261344Suqs	}
818261344Suqs
819261344Suqs	switch (n->prev->tok) {
820274880Sbapt	case MDOC_Fd:
821274880Sbapt	case MDOC_Fn:
822274880Sbapt	case MDOC_Fo:
823274880Sbapt	case MDOC_In:
824274880Sbapt	case MDOC_Vt:
825261344Suqs		outflags |= MMAN_sp;
826261344Suqs		break;
827274880Sbapt	case MDOC_Ft:
828261344Suqs		if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
829261344Suqs			outflags |= MMAN_sp;
830261344Suqs			break;
831261344Suqs		}
832261344Suqs		/* FALLTHROUGH */
833261344Suqs	default:
834261344Suqs		outflags |= MMAN_br;
835261344Suqs		break;
836261344Suqs	}
837261344Suqs}
838261344Suqs
839241675Suqsstatic int
840261344Suqspre_an(DECL_ARGS)
841261344Suqs{
842261344Suqs
843261344Suqs	switch (n->norm->An.auth) {
844274880Sbapt	case AUTH_split:
845261344Suqs		outflags &= ~MMAN_An_nosplit;
846261344Suqs		outflags |= MMAN_An_split;
847294113Sbapt		return 0;
848274880Sbapt	case AUTH_nosplit:
849261344Suqs		outflags &= ~MMAN_An_split;
850261344Suqs		outflags |= MMAN_An_nosplit;
851294113Sbapt		return 0;
852261344Suqs	default:
853261344Suqs		if (MMAN_An_split & outflags)
854261344Suqs			outflags |= MMAN_br;
855261344Suqs		else if (SEC_AUTHORS == n->sec &&
856261344Suqs		    ! (MMAN_An_nosplit & outflags))
857261344Suqs			outflags |= MMAN_An_split;
858294113Sbapt		return 1;
859261344Suqs	}
860261344Suqs}
861261344Suqs
862261344Suqsstatic int
863241675Suqspre_ap(DECL_ARGS)
864241675Suqs{
865241675Suqs
866261344Suqs	outflags &= ~MMAN_spc;
867261344Suqs	print_word("'");
868261344Suqs	outflags &= ~MMAN_spc;
869294113Sbapt	return 0;
870241675Suqs}
871241675Suqs
872241675Suqsstatic int
873275432Sbaptpre_aq(DECL_ARGS)
874275432Sbapt{
875275432Sbapt
876294113Sbapt	print_word(n->child != NULL && n->child->next == NULL &&
877279527Sbapt	    n->child->tok == MDOC_Mt ?  "<" : "\\(la");
878275432Sbapt	outflags &= ~MMAN_spc;
879294113Sbapt	return 1;
880275432Sbapt}
881275432Sbapt
882275432Sbaptstatic void
883275432Sbaptpost_aq(DECL_ARGS)
884275432Sbapt{
885275432Sbapt
886275432Sbapt	outflags &= ~(MMAN_spc | MMAN_nl);
887294113Sbapt	print_word(n->child != NULL && n->child->next == NULL &&
888279527Sbapt	    n->child->tok == MDOC_Mt ?  ">" : "\\(ra");
889275432Sbapt}
890275432Sbapt
891275432Sbaptstatic int
892241675Suqspre_bd(DECL_ARGS)
893241675Suqs{
894241675Suqs
895261344Suqs	outflags &= ~(MMAN_PP | MMAN_sp | MMAN_br);
896261344Suqs
897241675Suqs	if (DISP_unfilled == n->norm->Bd.type ||
898261344Suqs	    DISP_literal  == n->norm->Bd.type)
899261344Suqs		print_line(".nf", 0);
900261344Suqs	if (0 == n->norm->Bd.comp && NULL != n->parent->prev)
901261344Suqs		outflags |= MMAN_sp;
902275432Sbapt	print_offs(n->norm->Bd.offs, 1);
903294113Sbapt	return 1;
904241675Suqs}
905241675Suqs
906241675Suqsstatic void
907241675Suqspost_bd(DECL_ARGS)
908241675Suqs{
909241675Suqs
910261344Suqs	/* Close out this display. */
911261344Suqs	print_line(".RE", MMAN_nl);
912241675Suqs	if (DISP_unfilled == n->norm->Bd.type ||
913261344Suqs	    DISP_literal  == n->norm->Bd.type)
914261344Suqs		print_line(".fi", MMAN_nl);
915261344Suqs
916261344Suqs	/* Maybe we are inside an enclosing list? */
917261344Suqs	if (NULL != n->parent->next)
918261344Suqs		mid_it();
919261344Suqs}
920261344Suqs
921261344Suqsstatic int
922261344Suqspre_bf(DECL_ARGS)
923261344Suqs{
924261344Suqs
925261344Suqs	switch (n->type) {
926294113Sbapt	case ROFFT_BLOCK:
927294113Sbapt		return 1;
928294113Sbapt	case ROFFT_BODY:
929261344Suqs		break;
930261344Suqs	default:
931294113Sbapt		return 0;
932241675Suqs	}
933261344Suqs	switch (n->norm->Bf.font) {
934274880Sbapt	case FONT_Em:
935261344Suqs		font_push('I');
936261344Suqs		break;
937274880Sbapt	case FONT_Sy:
938261344Suqs		font_push('B');
939261344Suqs		break;
940261344Suqs	default:
941261344Suqs		font_push('R');
942261344Suqs		break;
943261344Suqs	}
944294113Sbapt	return 1;
945241675Suqs}
946241675Suqs
947261344Suqsstatic void
948261344Suqspost_bf(DECL_ARGS)
949261344Suqs{
950261344Suqs
951294113Sbapt	if (n->type == ROFFT_BODY)
952261344Suqs		font_pop();
953261344Suqs}
954261344Suqs
955241675Suqsstatic int
956261344Suqspre_bk(DECL_ARGS)
957261344Suqs{
958261344Suqs
959261344Suqs	switch (n->type) {
960294113Sbapt	case ROFFT_BLOCK:
961294113Sbapt		return 1;
962294113Sbapt	case ROFFT_BODY:
963261344Suqs		outflags |= MMAN_Bk;
964294113Sbapt		return 1;
965261344Suqs	default:
966294113Sbapt		return 0;
967261344Suqs	}
968261344Suqs}
969261344Suqs
970261344Suqsstatic void
971261344Suqspost_bk(DECL_ARGS)
972261344Suqs{
973261344Suqs
974294113Sbapt	if (n->type == ROFFT_BODY)
975261344Suqs		outflags &= ~MMAN_Bk;
976261344Suqs}
977261344Suqs
978261344Suqsstatic int
979261344Suqspre_bl(DECL_ARGS)
980261344Suqs{
981261344Suqs	size_t		 icol;
982261344Suqs
983261344Suqs	/*
984261344Suqs	 * print_offs() will increase the -offset to account for
985261344Suqs	 * a possible enclosing .It, but any enclosed .It blocks
986261344Suqs	 * just nest and do not add up their indentation.
987261344Suqs	 */
988261344Suqs	if (n->norm->Bl.offs) {
989275432Sbapt		print_offs(n->norm->Bl.offs, 0);
990261344Suqs		Bl_stack[Bl_stack_len++] = 0;
991261344Suqs	}
992261344Suqs
993261344Suqs	switch (n->norm->Bl.type) {
994274880Sbapt	case LIST_enum:
995261344Suqs		n->norm->Bl.count = 0;
996294113Sbapt		return 1;
997274880Sbapt	case LIST_column:
998261344Suqs		break;
999261344Suqs	default:
1000294113Sbapt		return 1;
1001261344Suqs	}
1002261344Suqs
1003294113Sbapt	if (n->child != NULL) {
1004279527Sbapt		print_line(".TS", MMAN_nl);
1005279527Sbapt		for (icol = 0; icol < n->norm->Bl.ncols; icol++)
1006279527Sbapt			print_word("l");
1007279527Sbapt		print_word(".");
1008279527Sbapt	}
1009261344Suqs	outflags |= MMAN_nl;
1010294113Sbapt	return 1;
1011261344Suqs}
1012261344Suqs
1013261344Suqsstatic void
1014261344Suqspost_bl(DECL_ARGS)
1015261344Suqs{
1016261344Suqs
1017261344Suqs	switch (n->norm->Bl.type) {
1018274880Sbapt	case LIST_column:
1019294113Sbapt		if (n->child != NULL)
1020279527Sbapt			print_line(".TE", 0);
1021261344Suqs		break;
1022274880Sbapt	case LIST_enum:
1023261344Suqs		n->norm->Bl.count = 0;
1024261344Suqs		break;
1025261344Suqs	default:
1026261344Suqs		break;
1027261344Suqs	}
1028261344Suqs
1029261344Suqs	if (n->norm->Bl.offs) {
1030261344Suqs		print_line(".RE", MMAN_nl);
1031261344Suqs		assert(Bl_stack_len);
1032261344Suqs		Bl_stack_len--;
1033261344Suqs		assert(0 == Bl_stack[Bl_stack_len]);
1034261344Suqs	} else {
1035261344Suqs		outflags |= MMAN_PP | MMAN_nl;
1036261344Suqs		outflags &= ~(MMAN_sp | MMAN_br);
1037261344Suqs	}
1038261344Suqs
1039261344Suqs	/* Maybe we are inside an enclosing list? */
1040261344Suqs	if (NULL != n->parent->next)
1041261344Suqs		mid_it();
1042261344Suqs
1043261344Suqs}
1044261344Suqs
1045261344Suqsstatic int
1046241675Suqspre_br(DECL_ARGS)
1047241675Suqs{
1048241675Suqs
1049261344Suqs	outflags |= MMAN_br;
1050294113Sbapt	return 0;
1051241675Suqs}
1052241675Suqs
1053241675Suqsstatic int
1054241675Suqspre_bx(DECL_ARGS)
1055241675Suqs{
1056241675Suqs
1057241675Suqs	n = n->child;
1058241675Suqs	if (n) {
1059261344Suqs		print_word(n->string);
1060261344Suqs		outflags &= ~MMAN_spc;
1061241675Suqs		n = n->next;
1062241675Suqs	}
1063261344Suqs	print_word("BSD");
1064241675Suqs	if (NULL == n)
1065294113Sbapt		return 0;
1066261344Suqs	outflags &= ~MMAN_spc;
1067261344Suqs	print_word("-");
1068261344Suqs	outflags &= ~MMAN_spc;
1069261344Suqs	print_word(n->string);
1070294113Sbapt	return 0;
1071241675Suqs}
1072241675Suqs
1073241675Suqsstatic int
1074241675Suqspre_dl(DECL_ARGS)
1075241675Suqs{
1076241675Suqs
1077275432Sbapt	print_offs("6n", 0);
1078294113Sbapt	return 1;
1079241675Suqs}
1080241675Suqs
1081241675Suqsstatic void
1082241675Suqspost_dl(DECL_ARGS)
1083241675Suqs{
1084241675Suqs
1085261344Suqs	print_line(".RE", MMAN_nl);
1086261344Suqs
1087261344Suqs	/* Maybe we are inside an enclosing list? */
1088261344Suqs	if (NULL != n->parent->next)
1089261344Suqs		mid_it();
1090241675Suqs}
1091241675Suqs
1092241675Suqsstatic int
1093261344Suqspre_em(DECL_ARGS)
1094261344Suqs{
1095261344Suqs
1096261344Suqs	font_push('I');
1097294113Sbapt	return 1;
1098261344Suqs}
1099261344Suqs
1100274880Sbaptstatic int
1101274880Sbaptpre_en(DECL_ARGS)
1102274880Sbapt{
1103274880Sbapt
1104274880Sbapt	if (NULL == n->norm->Es ||
1105274880Sbapt	    NULL == n->norm->Es->child)
1106294113Sbapt		return 1;
1107274880Sbapt
1108274880Sbapt	print_word(n->norm->Es->child->string);
1109274880Sbapt	outflags &= ~MMAN_spc;
1110294113Sbapt	return 1;
1111274880Sbapt}
1112274880Sbapt
1113261344Suqsstatic void
1114274880Sbaptpost_en(DECL_ARGS)
1115274880Sbapt{
1116274880Sbapt
1117274880Sbapt	if (NULL == n->norm->Es ||
1118274880Sbapt	    NULL == n->norm->Es->child ||
1119274880Sbapt	    NULL == n->norm->Es->child->next)
1120274880Sbapt		return;
1121274880Sbapt
1122274880Sbapt	outflags &= ~MMAN_spc;
1123274880Sbapt	print_word(n->norm->Es->child->next->string);
1124274880Sbapt	return;
1125274880Sbapt}
1126274880Sbapt
1127275432Sbaptstatic int
1128275432Sbaptpre_eo(DECL_ARGS)
1129261344Suqs{
1130261344Suqs
1131279527Sbapt	if (n->end == ENDBODY_NOT &&
1132279527Sbapt	    n->parent->head->child == NULL &&
1133279527Sbapt	    n->child != NULL &&
1134279527Sbapt	    n->child->end != ENDBODY_NOT)
1135279527Sbapt		print_word("\\&");
1136279527Sbapt	else if (n->end != ENDBODY_NOT ? n->child != NULL :
1137279527Sbapt	    n->parent->head->child != NULL && (n->child != NULL ||
1138279527Sbapt	    (n->parent->tail != NULL && n->parent->tail->child != NULL)))
1139279527Sbapt		outflags &= ~(MMAN_spc | MMAN_nl);
1140294113Sbapt	return 1;
1141261344Suqs}
1142261344Suqs
1143275432Sbaptstatic void
1144275432Sbaptpost_eo(DECL_ARGS)
1145274880Sbapt{
1146279527Sbapt	int	 body, tail;
1147274880Sbapt
1148279527Sbapt	if (n->end != ENDBODY_NOT) {
1149279527Sbapt		outflags |= MMAN_spc;
1150279527Sbapt		return;
1151279527Sbapt	}
1152279527Sbapt
1153279527Sbapt	body = n->child != NULL || n->parent->head->child != NULL;
1154279527Sbapt	tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
1155279527Sbapt
1156279527Sbapt	if (body && tail)
1157275432Sbapt		outflags &= ~MMAN_spc;
1158279527Sbapt	else if ( ! (body || tail))
1159279527Sbapt		print_word("\\&");
1160279527Sbapt	else if ( ! tail)
1161279527Sbapt		outflags |= MMAN_spc;
1162274880Sbapt}
1163274880Sbapt
1164274880Sbaptstatic int
1165261344Suqspre_fa(DECL_ARGS)
1166261344Suqs{
1167261344Suqs	int	 am_Fa;
1168261344Suqs
1169261344Suqs	am_Fa = MDOC_Fa == n->tok;
1170261344Suqs
1171261344Suqs	if (am_Fa)
1172261344Suqs		n = n->child;
1173261344Suqs
1174261344Suqs	while (NULL != n) {
1175261344Suqs		font_push('I');
1176261344Suqs		if (am_Fa || MDOC_SYNPRETTY & n->flags)
1177261344Suqs			outflags |= MMAN_nbrword;
1178261344Suqs		print_node(meta, n);
1179261344Suqs		font_pop();
1180261344Suqs		if (NULL != (n = n->next))
1181261344Suqs			print_word(",");
1182261344Suqs	}
1183294113Sbapt	return 0;
1184261344Suqs}
1185261344Suqs
1186261344Suqsstatic void
1187261344Suqspost_fa(DECL_ARGS)
1188261344Suqs{
1189261344Suqs
1190261344Suqs	if (NULL != n->next && MDOC_Fa == n->next->tok)
1191261344Suqs		print_word(",");
1192261344Suqs}
1193261344Suqs
1194261344Suqsstatic int
1195261344Suqspre_fd(DECL_ARGS)
1196261344Suqs{
1197261344Suqs
1198261344Suqs	pre_syn(n);
1199261344Suqs	font_push('B');
1200294113Sbapt	return 1;
1201261344Suqs}
1202261344Suqs
1203261344Suqsstatic void
1204261344Suqspost_fd(DECL_ARGS)
1205261344Suqs{
1206261344Suqs
1207261344Suqs	font_pop();
1208261344Suqs	outflags |= MMAN_br;
1209261344Suqs}
1210261344Suqs
1211261344Suqsstatic int
1212261344Suqspre_fl(DECL_ARGS)
1213261344Suqs{
1214261344Suqs
1215261344Suqs	font_push('B');
1216261344Suqs	print_word("\\-");
1217294113Sbapt	if (n->child != NULL)
1218275432Sbapt		outflags &= ~MMAN_spc;
1219294113Sbapt	return 1;
1220261344Suqs}
1221261344Suqs
1222261344Suqsstatic void
1223261344Suqspost_fl(DECL_ARGS)
1224261344Suqs{
1225261344Suqs
1226261344Suqs	font_pop();
1227294113Sbapt	if (!(n->child != NULL ||
1228275432Sbapt	    n->next == NULL ||
1229294113Sbapt	    n->next->type == ROFFT_TEXT ||
1230275432Sbapt	    n->next->flags & MDOC_LINE))
1231261344Suqs		outflags &= ~MMAN_spc;
1232261344Suqs}
1233261344Suqs
1234261344Suqsstatic int
1235261344Suqspre_fn(DECL_ARGS)
1236261344Suqs{
1237261344Suqs
1238261344Suqs	pre_syn(n);
1239261344Suqs
1240261344Suqs	n = n->child;
1241261344Suqs	if (NULL == n)
1242294113Sbapt		return 0;
1243261344Suqs
1244261344Suqs	if (MDOC_SYNPRETTY & n->flags)
1245261344Suqs		print_block(".HP 4n", MMAN_nl);
1246261344Suqs
1247261344Suqs	font_push('B');
1248261344Suqs	print_node(meta, n);
1249261344Suqs	font_pop();
1250261344Suqs	outflags &= ~MMAN_spc;
1251261344Suqs	print_word("(");
1252261344Suqs	outflags &= ~MMAN_spc;
1253261344Suqs
1254261344Suqs	n = n->next;
1255261344Suqs	if (NULL != n)
1256261344Suqs		pre_fa(meta, n);
1257294113Sbapt	return 0;
1258261344Suqs}
1259261344Suqs
1260261344Suqsstatic void
1261261344Suqspost_fn(DECL_ARGS)
1262261344Suqs{
1263261344Suqs
1264261344Suqs	print_word(")");
1265261344Suqs	if (MDOC_SYNPRETTY & n->flags) {
1266261344Suqs		print_word(";");
1267261344Suqs		outflags |= MMAN_PP;
1268261344Suqs	}
1269261344Suqs}
1270261344Suqs
1271261344Suqsstatic int
1272261344Suqspre_fo(DECL_ARGS)
1273261344Suqs{
1274261344Suqs
1275261344Suqs	switch (n->type) {
1276294113Sbapt	case ROFFT_BLOCK:
1277261344Suqs		pre_syn(n);
1278261344Suqs		break;
1279294113Sbapt	case ROFFT_HEAD:
1280279527Sbapt		if (n->child == NULL)
1281294113Sbapt			return 0;
1282261344Suqs		if (MDOC_SYNPRETTY & n->flags)
1283261344Suqs			print_block(".HP 4n", MMAN_nl);
1284261344Suqs		font_push('B');
1285261344Suqs		break;
1286294113Sbapt	case ROFFT_BODY:
1287279527Sbapt		outflags &= ~(MMAN_spc | MMAN_nl);
1288261344Suqs		print_word("(");
1289261344Suqs		outflags &= ~MMAN_spc;
1290261344Suqs		break;
1291261344Suqs	default:
1292261344Suqs		break;
1293261344Suqs	}
1294294113Sbapt	return 1;
1295261344Suqs}
1296261344Suqs
1297261344Suqsstatic void
1298261344Suqspost_fo(DECL_ARGS)
1299261344Suqs{
1300261344Suqs
1301261344Suqs	switch (n->type) {
1302294113Sbapt	case ROFFT_HEAD:
1303279527Sbapt		if (n->child != NULL)
1304279527Sbapt			font_pop();
1305261344Suqs		break;
1306294113Sbapt	case ROFFT_BODY:
1307261344Suqs		post_fn(meta, n);
1308261344Suqs		break;
1309261344Suqs	default:
1310261344Suqs		break;
1311261344Suqs	}
1312261344Suqs}
1313261344Suqs
1314261344Suqsstatic int
1315261344Suqspre_ft(DECL_ARGS)
1316261344Suqs{
1317261344Suqs
1318261344Suqs	pre_syn(n);
1319261344Suqs	font_push('I');
1320294113Sbapt	return 1;
1321261344Suqs}
1322261344Suqs
1323261344Suqsstatic int
1324261344Suqspre_in(DECL_ARGS)
1325261344Suqs{
1326261344Suqs
1327261344Suqs	if (MDOC_SYNPRETTY & n->flags) {
1328261344Suqs		pre_syn(n);
1329261344Suqs		font_push('B');
1330261344Suqs		print_word("#include <");
1331261344Suqs		outflags &= ~MMAN_spc;
1332261344Suqs	} else {
1333261344Suqs		print_word("<");
1334261344Suqs		outflags &= ~MMAN_spc;
1335261344Suqs		font_push('I');
1336261344Suqs	}
1337294113Sbapt	return 1;
1338261344Suqs}
1339261344Suqs
1340261344Suqsstatic void
1341261344Suqspost_in(DECL_ARGS)
1342261344Suqs{
1343261344Suqs
1344261344Suqs	if (MDOC_SYNPRETTY & n->flags) {
1345261344Suqs		outflags &= ~MMAN_spc;
1346261344Suqs		print_word(">");
1347261344Suqs		font_pop();
1348261344Suqs		outflags |= MMAN_br;
1349261344Suqs	} else {
1350261344Suqs		font_pop();
1351261344Suqs		outflags &= ~MMAN_spc;
1352261344Suqs		print_word(">");
1353261344Suqs	}
1354261344Suqs}
1355261344Suqs
1356261344Suqsstatic int
1357241675Suqspre_it(DECL_ARGS)
1358241675Suqs{
1359294113Sbapt	const struct roff_node *bln;
1360241675Suqs
1361261344Suqs	switch (n->type) {
1362294113Sbapt	case ROFFT_HEAD:
1363261344Suqs		outflags |= MMAN_PP | MMAN_nl;
1364261344Suqs		bln = n->parent->parent;
1365261344Suqs		if (0 == bln->norm->Bl.comp ||
1366261344Suqs		    (NULL == n->parent->prev &&
1367261344Suqs		     NULL == bln->parent->prev))
1368261344Suqs			outflags |= MMAN_sp;
1369261344Suqs		outflags &= ~MMAN_br;
1370241675Suqs		switch (bln->norm->Bl.type) {
1371274880Sbapt		case LIST_item:
1372294113Sbapt			return 0;
1373274880Sbapt		case LIST_inset:
1374274880Sbapt		case LIST_diag:
1375274880Sbapt		case LIST_ohang:
1376261344Suqs			if (bln->norm->Bl.type == LIST_diag)
1377261344Suqs				print_line(".B \"", 0);
1378261344Suqs			else
1379261344Suqs				print_line(".R \"", 0);
1380261344Suqs			outflags &= ~MMAN_spc;
1381294113Sbapt			return 1;
1382274880Sbapt		case LIST_bullet:
1383274880Sbapt		case LIST_dash:
1384274880Sbapt		case LIST_hyphen:
1385279527Sbapt			print_width(&bln->norm->Bl, NULL);
1386261344Suqs			TPremain = 0;
1387261344Suqs			outflags |= MMAN_nl;
1388261344Suqs			font_push('B');
1389261344Suqs			if (LIST_bullet == bln->norm->Bl.type)
1390275432Sbapt				print_word("\\(bu");
1391261344Suqs			else
1392261344Suqs				print_word("-");
1393261344Suqs			font_pop();
1394274880Sbapt			outflags |= MMAN_nl;
1395294113Sbapt			return 0;
1396274880Sbapt		case LIST_enum:
1397279527Sbapt			print_width(&bln->norm->Bl, NULL);
1398261344Suqs			TPremain = 0;
1399261344Suqs			outflags |= MMAN_nl;
1400261344Suqs			print_count(&bln->norm->Bl.count);
1401274880Sbapt			outflags |= MMAN_nl;
1402294113Sbapt			return 0;
1403274880Sbapt		case LIST_hang:
1404279527Sbapt			print_width(&bln->norm->Bl, n->child);
1405261344Suqs			TPremain = 0;
1406274880Sbapt			outflags |= MMAN_nl;
1407294113Sbapt			return 1;
1408274880Sbapt		case LIST_tag:
1409279527Sbapt			print_width(&bln->norm->Bl, n->child);
1410261344Suqs			putchar('\n');
1411261344Suqs			outflags &= ~MMAN_spc;
1412294113Sbapt			return 1;
1413241675Suqs		default:
1414294113Sbapt			return 1;
1415261344Suqs		}
1416261344Suqs	default:
1417261344Suqs		break;
1418261344Suqs	}
1419294113Sbapt	return 1;
1420261344Suqs}
1421261344Suqs
1422261344Suqs/*
1423261344Suqs * This function is called after closing out an indented block.
1424261344Suqs * If we are inside an enclosing list, restore its indentation.
1425261344Suqs */
1426261344Suqsstatic void
1427261344Suqsmid_it(void)
1428261344Suqs{
1429261344Suqs	char		 buf[24];
1430261344Suqs
1431261344Suqs	/* Nothing to do outside a list. */
1432261344Suqs	if (0 == Bl_stack_len || 0 == Bl_stack[Bl_stack_len - 1])
1433261344Suqs		return;
1434261344Suqs
1435261344Suqs	/* The indentation has already been set up. */
1436261344Suqs	if (Bl_stack_post[Bl_stack_len - 1])
1437261344Suqs		return;
1438261344Suqs
1439261344Suqs	/* Restore the indentation of the enclosing list. */
1440261344Suqs	print_line(".RS", MMAN_Bk_susp);
1441279527Sbapt	(void)snprintf(buf, sizeof(buf), "%dn",
1442274880Sbapt	    Bl_stack[Bl_stack_len - 1]);
1443261344Suqs	print_word(buf);
1444261344Suqs
1445261344Suqs	/* Remeber to close out this .RS block later. */
1446261344Suqs	Bl_stack_post[Bl_stack_len - 1] = 1;
1447261344Suqs}
1448261344Suqs
1449261344Suqsstatic void
1450261344Suqspost_it(DECL_ARGS)
1451261344Suqs{
1452294113Sbapt	const struct roff_node *bln;
1453261344Suqs
1454261344Suqs	bln = n->parent->parent;
1455261344Suqs
1456261344Suqs	switch (n->type) {
1457294113Sbapt	case ROFFT_HEAD:
1458261344Suqs		switch (bln->norm->Bl.type) {
1459274880Sbapt		case LIST_diag:
1460261344Suqs			outflags &= ~MMAN_spc;
1461261344Suqs			print_word("\\ ");
1462241675Suqs			break;
1463274880Sbapt		case LIST_ohang:
1464261344Suqs			outflags |= MMAN_br;
1465261344Suqs			break;
1466261344Suqs		default:
1467261344Suqs			break;
1468241675Suqs		}
1469261344Suqs		break;
1470294113Sbapt	case ROFFT_BODY:
1471261344Suqs		switch (bln->norm->Bl.type) {
1472274880Sbapt		case LIST_bullet:
1473274880Sbapt		case LIST_dash:
1474274880Sbapt		case LIST_hyphen:
1475274880Sbapt		case LIST_enum:
1476274880Sbapt		case LIST_hang:
1477274880Sbapt		case LIST_tag:
1478261344Suqs			assert(Bl_stack_len);
1479261344Suqs			Bl_stack[--Bl_stack_len] = 0;
1480261344Suqs
1481261344Suqs			/*
1482261344Suqs			 * Our indentation had to be restored
1483261344Suqs			 * after a child display or child list.
1484261344Suqs			 * Close out that indentation block now.
1485261344Suqs			 */
1486261344Suqs			if (Bl_stack_post[Bl_stack_len]) {
1487261344Suqs				print_line(".RE", MMAN_nl);
1488261344Suqs				Bl_stack_post[Bl_stack_len] = 0;
1489261344Suqs			}
1490261344Suqs			break;
1491274880Sbapt		case LIST_column:
1492261344Suqs			if (NULL != n->next) {
1493261344Suqs				putchar('\t');
1494261344Suqs				outflags &= ~MMAN_spc;
1495261344Suqs			}
1496261344Suqs			break;
1497261344Suqs		default:
1498261344Suqs			break;
1499261344Suqs		}
1500261344Suqs		break;
1501261344Suqs	default:
1502261344Suqs		break;
1503241675Suqs	}
1504261344Suqs}
1505261344Suqs
1506261344Suqsstatic void
1507261344Suqspost_lb(DECL_ARGS)
1508261344Suqs{
1509261344Suqs
1510261344Suqs	if (SEC_LIBRARY == n->sec)
1511261344Suqs		outflags |= MMAN_br;
1512261344Suqs}
1513261344Suqs
1514261344Suqsstatic int
1515261344Suqspre_lk(DECL_ARGS)
1516261344Suqs{
1517294113Sbapt	const struct roff_node *link, *descr;
1518261344Suqs
1519261344Suqs	if (NULL == (link = n->child))
1520294113Sbapt		return 0;
1521261344Suqs
1522261344Suqs	if (NULL != (descr = link->next)) {
1523261344Suqs		font_push('I');
1524261344Suqs		while (NULL != descr) {
1525261344Suqs			print_word(descr->string);
1526261344Suqs			descr = descr->next;
1527261344Suqs		}
1528261344Suqs		print_word(":");
1529261344Suqs		font_pop();
1530261344Suqs	}
1531261344Suqs
1532261344Suqs	font_push('B');
1533261344Suqs	print_word(link->string);
1534261344Suqs	font_pop();
1535294113Sbapt	return 0;
1536261344Suqs}
1537261344Suqs
1538261344Suqsstatic int
1539274880Sbaptpre_ll(DECL_ARGS)
1540274880Sbapt{
1541274880Sbapt
1542274880Sbapt	print_line(".ll", 0);
1543294113Sbapt	return 1;
1544274880Sbapt}
1545274880Sbapt
1546274880Sbaptstatic int
1547261344Suqspre_li(DECL_ARGS)
1548261344Suqs{
1549261344Suqs
1550261344Suqs	font_push('R');
1551294113Sbapt	return 1;
1552241675Suqs}
1553241675Suqs
1554241675Suqsstatic int
1555241675Suqspre_nm(DECL_ARGS)
1556241675Suqs{
1557261344Suqs	char	*name;
1558241675Suqs
1559294113Sbapt	if (n->type == ROFFT_BLOCK) {
1560261344Suqs		outflags |= MMAN_Bk;
1561261344Suqs		pre_syn(n);
1562261344Suqs	}
1563294113Sbapt	if (n->type != ROFFT_ELEM && n->type != ROFFT_HEAD)
1564294113Sbapt		return 1;
1565261344Suqs	name = n->child ? n->child->string : meta->name;
1566261344Suqs	if (NULL == name)
1567294113Sbapt		return 0;
1568294113Sbapt	if (n->type == ROFFT_HEAD) {
1569261344Suqs		if (NULL == n->parent->prev)
1570261344Suqs			outflags |= MMAN_sp;
1571261344Suqs		print_block(".HP", 0);
1572261344Suqs		printf(" %zun", strlen(name) + 1);
1573261344Suqs		outflags |= MMAN_nl;
1574261344Suqs	}
1575261344Suqs	font_push('B');
1576241675Suqs	if (NULL == n->child)
1577261344Suqs		print_word(meta->name);
1578294113Sbapt	return 1;
1579241675Suqs}
1580241675Suqs
1581241675Suqsstatic void
1582241675Suqspost_nm(DECL_ARGS)
1583241675Suqs{
1584241675Suqs
1585261344Suqs	switch (n->type) {
1586294113Sbapt	case ROFFT_BLOCK:
1587261344Suqs		outflags &= ~MMAN_Bk;
1588261344Suqs		break;
1589294113Sbapt	case ROFFT_HEAD:
1590294113Sbapt	case ROFFT_ELEM:
1591274880Sbapt		if (n->child != NULL || meta->name != NULL)
1592274880Sbapt			font_pop();
1593261344Suqs		break;
1594261344Suqs	default:
1595261344Suqs		break;
1596261344Suqs	}
1597241675Suqs}
1598241675Suqs
1599241675Suqsstatic int
1600261344Suqspre_no(DECL_ARGS)
1601261344Suqs{
1602261344Suqs
1603261344Suqs	outflags |= MMAN_spc_force;
1604294113Sbapt	return 1;
1605261344Suqs}
1606261344Suqs
1607261344Suqsstatic int
1608241675Suqspre_ns(DECL_ARGS)
1609241675Suqs{
1610241675Suqs
1611261344Suqs	outflags &= ~MMAN_spc;
1612294113Sbapt	return 0;
1613241675Suqs}
1614241675Suqs
1615241675Suqsstatic void
1616241675Suqspost_pf(DECL_ARGS)
1617241675Suqs{
1618241675Suqs
1619276219Sbapt	if ( ! (n->next == NULL || n->next->flags & MDOC_LINE))
1620276219Sbapt		outflags &= ~MMAN_spc;
1621241675Suqs}
1622241675Suqs
1623241675Suqsstatic int
1624241675Suqspre_pp(DECL_ARGS)
1625241675Suqs{
1626241675Suqs
1627261344Suqs	if (MDOC_It != n->parent->tok)
1628261344Suqs		outflags |= MMAN_PP;
1629261344Suqs	outflags |= MMAN_sp | MMAN_nl;
1630261344Suqs	outflags &= ~MMAN_br;
1631294113Sbapt	return 0;
1632261344Suqs}
1633261344Suqs
1634261344Suqsstatic int
1635261344Suqspre_rs(DECL_ARGS)
1636261344Suqs{
1637261344Suqs
1638261344Suqs	if (SEC_SEE_ALSO == n->sec) {
1639261344Suqs		outflags |= MMAN_PP | MMAN_sp | MMAN_nl;
1640261344Suqs		outflags &= ~MMAN_br;
1641261344Suqs	}
1642294113Sbapt	return 1;
1643241675Suqs}
1644241675Suqs
1645241675Suqsstatic int
1646274880Sbaptpre_rv(DECL_ARGS)
1647274880Sbapt{
1648294113Sbapt	struct roff_node *nch;
1649274880Sbapt
1650274880Sbapt	outflags |= MMAN_br | MMAN_nl;
1651274880Sbapt
1652294113Sbapt	if (n->child != NULL) {
1653274880Sbapt		print_word("The");
1654274880Sbapt
1655294113Sbapt		for (nch = n->child; nch != NULL; nch = nch->next) {
1656274880Sbapt			font_push('B');
1657294113Sbapt			print_word(nch->string);
1658274880Sbapt			font_pop();
1659274880Sbapt
1660274880Sbapt			outflags &= ~MMAN_spc;
1661274880Sbapt			print_word("()");
1662274880Sbapt
1663294113Sbapt			if (nch->next == NULL)
1664274880Sbapt				continue;
1665274880Sbapt
1666294113Sbapt			if (nch->prev != NULL || nch->next->next != NULL) {
1667274880Sbapt				outflags &= ~MMAN_spc;
1668274880Sbapt				print_word(",");
1669274880Sbapt			}
1670294113Sbapt			if (nch->next->next == NULL)
1671274880Sbapt				print_word("and");
1672274880Sbapt		}
1673274880Sbapt
1674294113Sbapt		if (n->child != NULL && n->child->next != NULL)
1675274880Sbapt			print_word("functions return");
1676274880Sbapt		else
1677274880Sbapt			print_word("function returns");
1678274880Sbapt
1679274880Sbapt		print_word("the value\\~0 if successful;");
1680274880Sbapt	} else
1681274880Sbapt		print_word("Upon successful completion, "
1682274880Sbapt		    "the value\\~0 is returned;");
1683274880Sbapt
1684274880Sbapt	print_word("otherwise the value\\~\\-1 is returned"
1685274880Sbapt	    " and the global variable");
1686274880Sbapt
1687274880Sbapt	font_push('I');
1688274880Sbapt	print_word("errno");
1689274880Sbapt	font_pop();
1690274880Sbapt
1691274880Sbapt	print_word("is set to indicate the error.");
1692274880Sbapt	outflags |= MMAN_nl;
1693294113Sbapt	return 0;
1694274880Sbapt}
1695274880Sbapt
1696274880Sbaptstatic int
1697275432Sbaptpre_skip(DECL_ARGS)
1698275432Sbapt{
1699275432Sbapt
1700294113Sbapt	return 0;
1701275432Sbapt}
1702275432Sbapt
1703275432Sbaptstatic int
1704261344Suqspre_sm(DECL_ARGS)
1705261344Suqs{
1706261344Suqs
1707274880Sbapt	if (NULL == n->child)
1708274880Sbapt		outflags ^= MMAN_Sm;
1709274880Sbapt	else if (0 == strcmp("on", n->child->string))
1710274880Sbapt		outflags |= MMAN_Sm;
1711261344Suqs	else
1712261344Suqs		outflags &= ~MMAN_Sm;
1713274880Sbapt
1714274880Sbapt	if (MMAN_Sm & outflags)
1715274880Sbapt		outflags |= MMAN_spc;
1716274880Sbapt
1717294113Sbapt	return 0;
1718261344Suqs}
1719261344Suqs
1720261344Suqsstatic int
1721241675Suqspre_sp(DECL_ARGS)
1722241675Suqs{
1723241675Suqs
1724261344Suqs	if (MMAN_PP & outflags) {
1725261344Suqs		outflags &= ~MMAN_PP;
1726261344Suqs		print_line(".PP", 0);
1727261344Suqs	} else
1728261344Suqs		print_line(".sp", 0);
1729294113Sbapt	return 1;
1730241675Suqs}
1731241675Suqs
1732241675Suqsstatic void
1733241675Suqspost_sp(DECL_ARGS)
1734241675Suqs{
1735241675Suqs
1736261344Suqs	outflags |= MMAN_nl;
1737241675Suqs}
1738241675Suqs
1739241675Suqsstatic int
1740261344Suqspre_sy(DECL_ARGS)
1741261344Suqs{
1742261344Suqs
1743261344Suqs	font_push('B');
1744294113Sbapt	return 1;
1745261344Suqs}
1746261344Suqs
1747261344Suqsstatic int
1748261344Suqspre_vt(DECL_ARGS)
1749261344Suqs{
1750261344Suqs
1751261344Suqs	if (MDOC_SYNPRETTY & n->flags) {
1752261344Suqs		switch (n->type) {
1753294113Sbapt		case ROFFT_BLOCK:
1754261344Suqs			pre_syn(n);
1755294113Sbapt			return 1;
1756294113Sbapt		case ROFFT_BODY:
1757261344Suqs			break;
1758261344Suqs		default:
1759294113Sbapt			return 0;
1760261344Suqs		}
1761261344Suqs	}
1762261344Suqs	font_push('I');
1763294113Sbapt	return 1;
1764261344Suqs}
1765261344Suqs
1766261344Suqsstatic void
1767261344Suqspost_vt(DECL_ARGS)
1768261344Suqs{
1769261344Suqs
1770294113Sbapt	if (n->flags & MDOC_SYNPRETTY && n->type != ROFFT_BODY)
1771261344Suqs		return;
1772261344Suqs	font_pop();
1773261344Suqs}
1774261344Suqs
1775261344Suqsstatic int
1776241675Suqspre_xr(DECL_ARGS)
1777241675Suqs{
1778241675Suqs
1779241675Suqs	n = n->child;
1780241675Suqs	if (NULL == n)
1781294113Sbapt		return 0;
1782261344Suqs	print_node(meta, n);
1783241675Suqs	n = n->next;
1784241675Suqs	if (NULL == n)
1785294113Sbapt		return 0;
1786261344Suqs	outflags &= ~MMAN_spc;
1787261344Suqs	print_word("(");
1788261344Suqs	print_node(meta, n);
1789261344Suqs	print_word(")");
1790294113Sbapt	return 0;
1791241675Suqs}
1792241675Suqs
1793241675Suqsstatic int
1794241675Suqspre_ux(DECL_ARGS)
1795241675Suqs{
1796241675Suqs
1797261344Suqs	print_word(manacts[n->tok].prefix);
1798241675Suqs	if (NULL == n->child)
1799294113Sbapt		return 0;
1800261344Suqs	outflags &= ~MMAN_spc;
1801261344Suqs	print_word("\\ ");
1802261344Suqs	outflags &= ~MMAN_spc;
1803294113Sbapt	return 1;
1804241675Suqs}
1805