1241675Suqs/*	$Id: mdoc_man.c,v 1.9 2011/10/24 21:47:59 schwarze Exp $ */
2241675Suqs/*
3241675Suqs * Copyright (c) 2011 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#ifdef HAVE_CONFIG_H
18241675Suqs#include "config.h"
19241675Suqs#endif
20241675Suqs
21241675Suqs#include <stdio.h>
22241675Suqs#include <string.h>
23241675Suqs
24241675Suqs#include "mandoc.h"
25241675Suqs#include "man.h"
26241675Suqs#include "mdoc.h"
27241675Suqs#include "main.h"
28241675Suqs
29241675Suqs#define	DECL_ARGS const struct mdoc_meta *m, \
30241675Suqs		  const struct mdoc_node *n, \
31241675Suqs		  struct mman *mm
32241675Suqs
33241675Suqsstruct	mman {
34241675Suqs	int		  need_space; /* next word needs prior ws */
35241675Suqs	int		  need_nl; /* next word needs prior nl */
36241675Suqs};
37241675Suqs
38241675Suqsstruct	manact {
39241675Suqs	int		(*cond)(DECL_ARGS); /* DON'T run actions */
40241675Suqs	int		(*pre)(DECL_ARGS); /* pre-node action */
41241675Suqs	void		(*post)(DECL_ARGS); /* post-node action */
42241675Suqs	const char	 *prefix; /* pre-node string constant */
43241675Suqs	const char	 *suffix; /* post-node string constant */
44241675Suqs};
45241675Suqs
46241675Suqsstatic	int	  cond_body(DECL_ARGS);
47241675Suqsstatic	int	  cond_head(DECL_ARGS);
48241675Suqsstatic	void	  post_bd(DECL_ARGS);
49241675Suqsstatic	void	  post_dl(DECL_ARGS);
50241675Suqsstatic	void	  post_enc(DECL_ARGS);
51241675Suqsstatic	void	  post_nm(DECL_ARGS);
52241675Suqsstatic	void	  post_percent(DECL_ARGS);
53241675Suqsstatic	void	  post_pf(DECL_ARGS);
54241675Suqsstatic	void	  post_sect(DECL_ARGS);
55241675Suqsstatic	void	  post_sp(DECL_ARGS);
56241675Suqsstatic	int	  pre_ap(DECL_ARGS);
57241675Suqsstatic	int	  pre_bd(DECL_ARGS);
58241675Suqsstatic	int	  pre_br(DECL_ARGS);
59241675Suqsstatic	int	  pre_bx(DECL_ARGS);
60241675Suqsstatic	int	  pre_dl(DECL_ARGS);
61241675Suqsstatic	int	  pre_enc(DECL_ARGS);
62241675Suqsstatic	int	  pre_it(DECL_ARGS);
63241675Suqsstatic	int	  pre_nm(DECL_ARGS);
64241675Suqsstatic	int	  pre_ns(DECL_ARGS);
65241675Suqsstatic	int	  pre_pp(DECL_ARGS);
66241675Suqsstatic	int	  pre_sp(DECL_ARGS);
67241675Suqsstatic	int	  pre_sect(DECL_ARGS);
68241675Suqsstatic	int	  pre_ux(DECL_ARGS);
69241675Suqsstatic	int	  pre_xr(DECL_ARGS);
70241675Suqsstatic	void	  print_word(struct mman *, const char *);
71241675Suqsstatic	void	  print_node(DECL_ARGS);
72241675Suqs
73241675Suqsstatic	const struct manact manacts[MDOC_MAX + 1] = {
74241675Suqs	{ NULL, pre_ap, NULL, NULL, NULL }, /* Ap */
75241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Dd */
76241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Dt */
77241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Os */
78241675Suqs	{ NULL, pre_sect, post_sect, ".SH", NULL }, /* Sh */
79241675Suqs	{ NULL, pre_sect, post_sect, ".SS", NULL }, /* Ss */
80241675Suqs	{ NULL, pre_pp, NULL, NULL, NULL }, /* Pp */
81241675Suqs	{ cond_body, pre_dl, post_dl, NULL, NULL }, /* D1 */
82241675Suqs	{ cond_body, pre_dl, post_dl, NULL, NULL }, /* Dl */
83241675Suqs	{ cond_body, pre_bd, post_bd, NULL, NULL }, /* Bd */
84241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Ed */
85241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Bl */
86241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* El */
87241675Suqs	{ NULL, pre_it, NULL, NULL, NULL }, /* _It */
88241675Suqs	{ NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Ad */
89241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _An */
90241675Suqs	{ NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Ar */
91241675Suqs	{ NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Cd */
92241675Suqs	{ NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Cm */
93241675Suqs	{ NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Dv */
94241675Suqs	{ NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Er */
95241675Suqs	{ NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Ev */
96241675Suqs	{ NULL, pre_enc, post_enc, "The \\fB",
97241675Suqs	    "\\fP\nutility exits 0 on success, and >0 if an error occurs."
98241675Suqs	    }, /* Ex */
99241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Fa */
100241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Fd */
101241675Suqs	{ NULL, pre_enc, post_enc, "\\fB-", "\\fP" }, /* Fl */
102241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Fn */
103241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Ft */
104241675Suqs	{ NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Ic */
105241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _In */
106241675Suqs	{ NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Li */
107241675Suqs	{ cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */
108241675Suqs	{ NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */
109241675Suqs	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Op */
110241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Ot */
111241675Suqs	{ NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Pa */
112241675Suqs	{ NULL, pre_enc, post_enc, "The \\fB",
113241675Suqs		"\\fP\nfunction returns the value 0 if successful;\n"
114241675Suqs		"otherwise the value -1 is returned and the global\n"
115241675Suqs		"variable \\fIerrno\\fP is set to indicate the error."
116241675Suqs		}, /* Rv */
117241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* St */
118241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Va */
119241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Vt */
120241675Suqs	{ NULL, pre_xr, NULL, NULL, NULL }, /* Xr */
121241675Suqs	{ NULL, NULL, post_percent, NULL, NULL }, /* _%A */
122241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _%B */
123241675Suqs	{ NULL, NULL, post_percent, NULL, NULL }, /* _%D */
124241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _%I */
125241675Suqs	{ NULL, pre_enc, post_percent, "\\fI", "\\fP" }, /* %J */
126241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _%N */
127241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _%O */
128241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _%P */
129241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _%R */
130241675Suqs	{ NULL, pre_enc, post_percent, "\"", "\"" }, /* %T */
131241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _%V */
132241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Ac */
133241675Suqs	{ cond_body, pre_enc, post_enc, "<", ">" }, /* Ao */
134241675Suqs	{ cond_body, pre_enc, post_enc, "<", ">" }, /* Aq */
135241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* At */
136241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Bc */
137241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Bf */
138241675Suqs	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Bo */
139241675Suqs	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Bq */
140241675Suqs	{ NULL, pre_ux, NULL, "BSD/OS", NULL }, /* Bsx */
141241675Suqs	{ NULL, pre_bx, NULL, NULL, NULL }, /* Bx */
142241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Db */
143241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Dc */
144241675Suqs	{ cond_body, pre_enc, post_enc, "``", "''" }, /* Do */
145241675Suqs	{ cond_body, pre_enc, post_enc, "``", "''" }, /* Dq */
146241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Ec */
147241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Ef */
148241675Suqs	{ NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Em */
149241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Eo */
150241675Suqs	{ NULL, pre_ux, NULL, "FreeBSD", NULL }, /* Fx */
151241675Suqs	{ NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Ms */
152241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* No */
153241675Suqs	{ NULL, pre_ns, NULL, NULL, NULL }, /* Ns */
154241675Suqs	{ NULL, pre_ux, NULL, "NetBSD", NULL }, /* Nx */
155241675Suqs	{ NULL, pre_ux, NULL, "OpenBSD", NULL }, /* Ox */
156241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Pc */
157241675Suqs	{ NULL, NULL, post_pf, NULL, NULL }, /* Pf */
158241675Suqs	{ cond_body, pre_enc, post_enc, "(", ")" }, /* Po */
159241675Suqs	{ cond_body, pre_enc, post_enc, "(", ")" }, /* Pq */
160241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Qc */
161241675Suqs	{ cond_body, pre_enc, post_enc, "`", "'" }, /* Ql */
162241675Suqs	{ cond_body, pre_enc, post_enc, "\"", "\"" }, /* Qo */
163241675Suqs	{ cond_body, pre_enc, post_enc, "\"", "\"" }, /* Qq */
164241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Re */
165241675Suqs	{ cond_body, pre_pp, NULL, NULL, NULL }, /* Rs */
166241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Sc */
167241675Suqs	{ cond_body, pre_enc, post_enc, "`", "'" }, /* So */
168241675Suqs	{ cond_body, pre_enc, post_enc, "`", "'" }, /* Sq */
169241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Sm */
170241675Suqs	{ NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Sx */
171241675Suqs	{ NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Sy */
172241675Suqs	{ NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Tn */
173241675Suqs	{ NULL, pre_ux, NULL, "UNIX", NULL }, /* Ux */
174241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Xc */
175241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Xo */
176241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Fo */
177241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Fc */
178241675Suqs	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Oo */
179241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Oc */
180241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Bk */
181241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Ek */
182241675Suqs	{ NULL, pre_ux, NULL, "is currently in beta test.", NULL }, /* Bt */
183241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Hf */
184241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Fr */
185241675Suqs	{ NULL, pre_ux, NULL, "currently under development.", NULL }, /* Ud */
186241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Lb */
187241675Suqs	{ NULL, pre_pp, NULL, NULL, NULL }, /* Lp */
188241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Lk */
189241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Mt */
190241675Suqs	{ cond_body, pre_enc, post_enc, "{", "}" }, /* Brq */
191241675Suqs	{ cond_body, pre_enc, post_enc, "{", "}" }, /* Bro */
192241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* Brc */
193241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _%C */
194241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Es */
195241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _En */
196241675Suqs	{ NULL, pre_ux, NULL, "DragonFly", NULL }, /* Dx */
197241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _%Q */
198241675Suqs	{ NULL, pre_br, NULL, NULL, NULL }, /* br */
199241675Suqs	{ NULL, pre_sp, post_sp, NULL, NULL }, /* sp */
200241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _%U */
201241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* _Ta */
202241675Suqs	{ NULL, NULL, NULL, NULL, NULL }, /* ROOT */
203241675Suqs};
204241675Suqs
205241675Suqsstatic void
206241675Suqsprint_word(struct mman *mm, const char *s)
207241675Suqs{
208241675Suqs
209241675Suqs	if (mm->need_nl) {
210241675Suqs		/*
211241675Suqs		 * If we need a newline, print it now and start afresh.
212241675Suqs		 */
213241675Suqs		putchar('\n');
214241675Suqs		mm->need_space = 0;
215241675Suqs		mm->need_nl = 0;
216241675Suqs	} else if (mm->need_space && '\0' != s[0])
217241675Suqs		/*
218241675Suqs		 * If we need a space, only print it before
219241675Suqs		 * (1) a nonzero length word;
220241675Suqs		 * (2) a word that is non-punctuation; and
221241675Suqs		 * (3) if punctuation, non-terminating puncutation.
222241675Suqs		 */
223241675Suqs		if (NULL == strchr(".,:;)]?!", s[0]) || '\0' != s[1])
224241675Suqs			putchar(' ');
225241675Suqs
226241675Suqs	/*
227241675Suqs	 * Reassign needing space if we're not following opening
228241675Suqs	 * punctuation.
229241675Suqs	 */
230241675Suqs	mm->need_space =
231241675Suqs		('(' != s[0] && '[' != s[0]) || '\0' != s[1];
232241675Suqs
233241675Suqs	for ( ; *s; s++) {
234241675Suqs		switch (*s) {
235241675Suqs		case (ASCII_NBRSP):
236241675Suqs			printf("\\~");
237241675Suqs			break;
238241675Suqs		case (ASCII_HYPH):
239241675Suqs			putchar('-');
240241675Suqs			break;
241241675Suqs		default:
242241675Suqs			putchar((unsigned char)*s);
243241675Suqs			break;
244241675Suqs		}
245241675Suqs	}
246241675Suqs}
247241675Suqs
248241675Suqsvoid
249241675Suqsman_man(void *arg, const struct man *man)
250241675Suqs{
251241675Suqs
252241675Suqs	/*
253241675Suqs	 * Dump the keep buffer.
254241675Suqs	 * We're guaranteed by now that this exists (is non-NULL).
255241675Suqs	 * Flush stdout afterward, just in case.
256241675Suqs	 */
257241675Suqs	fputs(mparse_getkeep(man_mparse(man)), stdout);
258241675Suqs	fflush(stdout);
259241675Suqs}
260241675Suqs
261241675Suqsvoid
262241675Suqsman_mdoc(void *arg, const struct mdoc *mdoc)
263241675Suqs{
264241675Suqs	const struct mdoc_meta *m;
265241675Suqs	const struct mdoc_node *n;
266241675Suqs	struct mman	        mm;
267241675Suqs
268241675Suqs	m = mdoc_meta(mdoc);
269241675Suqs	n = mdoc_node(mdoc);
270241675Suqs
271241675Suqs	printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"",
272241675Suqs			m->title, m->msec, m->date, m->os, m->vol);
273241675Suqs
274241675Suqs	memset(&mm, 0, sizeof(struct mman));
275241675Suqs
276241675Suqs	mm.need_nl = 1;
277241675Suqs	print_node(m, n, &mm);
278241675Suqs	putchar('\n');
279241675Suqs}
280241675Suqs
281241675Suqsstatic void
282241675Suqsprint_node(DECL_ARGS)
283241675Suqs{
284241675Suqs	const struct mdoc_node	*prev, *sub;
285241675Suqs	const struct manact	*act;
286241675Suqs	int			 cond, do_sub;
287241675Suqs
288241675Suqs	/*
289241675Suqs	 * Break the line if we were parsed subsequent the current node.
290241675Suqs	 * This makes the page structure be more consistent.
291241675Suqs	 */
292241675Suqs	prev = n->prev ? n->prev : n->parent;
293241675Suqs	if (prev && prev->line < n->line)
294241675Suqs		mm->need_nl = 1;
295241675Suqs
296241675Suqs	act = NULL;
297241675Suqs	cond = 0;
298241675Suqs	do_sub = 1;
299241675Suqs
300241675Suqs	if (MDOC_TEXT == n->type) {
301241675Suqs		/*
302241675Suqs		 * Make sure that we don't happen to start with a
303241675Suqs		 * control character at the start of a line.
304241675Suqs		 */
305241675Suqs		if (mm->need_nl && ('.' == *n->string ||
306241675Suqs					'\'' == *n->string)) {
307241675Suqs			print_word(mm, "\\&");
308241675Suqs			mm->need_space = 0;
309241675Suqs		}
310241675Suqs		print_word(mm, n->string);
311241675Suqs	} else {
312241675Suqs		/*
313241675Suqs		 * Conditionally run the pre-node action handler for a
314241675Suqs		 * node.
315241675Suqs		 */
316241675Suqs		act = manacts + n->tok;
317241675Suqs		cond = NULL == act->cond || (*act->cond)(m, n, mm);
318241675Suqs		if (cond && act->pre)
319241675Suqs			do_sub = (*act->pre)(m, n, mm);
320241675Suqs	}
321241675Suqs
322241675Suqs	/*
323241675Suqs	 * Conditionally run all child nodes.
324241675Suqs	 * Note that this iterates over children instead of using
325241675Suqs	 * recursion.  This prevents unnecessary depth in the stack.
326241675Suqs	 */
327241675Suqs	if (do_sub)
328241675Suqs		for (sub = n->child; sub; sub = sub->next)
329241675Suqs			print_node(m, sub, mm);
330241675Suqs
331241675Suqs	/*
332241675Suqs	 * Lastly, conditionally run the post-node handler.
333241675Suqs	 */
334241675Suqs	if (cond && act->post)
335241675Suqs		(*act->post)(m, n, mm);
336241675Suqs}
337241675Suqs
338241675Suqsstatic int
339241675Suqscond_head(DECL_ARGS)
340241675Suqs{
341241675Suqs
342241675Suqs	return(MDOC_HEAD == n->type);
343241675Suqs}
344241675Suqs
345241675Suqsstatic int
346241675Suqscond_body(DECL_ARGS)
347241675Suqs{
348241675Suqs
349241675Suqs	return(MDOC_BODY == n->type);
350241675Suqs}
351241675Suqs
352241675Suqs/*
353241675Suqs * Output a font encoding before a node, e.g., \fR.
354241675Suqs * This obviously has no trailing space.
355241675Suqs */
356241675Suqsstatic int
357241675Suqspre_enc(DECL_ARGS)
358241675Suqs{
359241675Suqs	const char	*prefix;
360241675Suqs
361241675Suqs	prefix = manacts[n->tok].prefix;
362241675Suqs	if (NULL == prefix)
363241675Suqs		return(1);
364241675Suqs	print_word(mm, prefix);
365241675Suqs	mm->need_space = 0;
366241675Suqs	return(1);
367241675Suqs}
368241675Suqs
369241675Suqs/*
370241675Suqs * Output a font encoding subsequent a node, e.g., \fP.
371241675Suqs */
372241675Suqsstatic void
373241675Suqspost_enc(DECL_ARGS)
374241675Suqs{
375241675Suqs	const char *suffix;
376241675Suqs
377241675Suqs	suffix = manacts[n->tok].suffix;
378241675Suqs	if (NULL == suffix)
379241675Suqs		return;
380241675Suqs	mm->need_space = 0;
381241675Suqs	print_word(mm, suffix);
382241675Suqs}
383241675Suqs
384241675Suqs/*
385241675Suqs * Used in listings (percent = %A, e.g.).
386241675Suqs * FIXME: this is incomplete.
387241675Suqs * It doesn't print a nice ", and" for lists.
388241675Suqs */
389241675Suqsstatic void
390241675Suqspost_percent(DECL_ARGS)
391241675Suqs{
392241675Suqs
393241675Suqs	post_enc(m, n, mm);
394241675Suqs	if (n->next)
395241675Suqs		print_word(mm, ",");
396241675Suqs	else {
397241675Suqs		print_word(mm, ".");
398241675Suqs		mm->need_nl = 1;
399241675Suqs	}
400241675Suqs}
401241675Suqs
402241675Suqs/*
403241675Suqs * Print before a section header.
404241675Suqs */
405241675Suqsstatic int
406241675Suqspre_sect(DECL_ARGS)
407241675Suqs{
408241675Suqs
409241675Suqs	if (MDOC_HEAD != n->type)
410241675Suqs		return(1);
411241675Suqs	mm->need_nl = 1;
412241675Suqs	print_word(mm, manacts[n->tok].prefix);
413241675Suqs	print_word(mm, "\"");
414241675Suqs	mm->need_space = 0;
415241675Suqs	return(1);
416241675Suqs}
417241675Suqs
418241675Suqs/*
419241675Suqs * Print subsequent a section header.
420241675Suqs */
421241675Suqsstatic void
422241675Suqspost_sect(DECL_ARGS)
423241675Suqs{
424241675Suqs
425241675Suqs	if (MDOC_HEAD != n->type)
426241675Suqs		return;
427241675Suqs	mm->need_space = 0;
428241675Suqs	print_word(mm, "\"");
429241675Suqs	mm->need_nl = 1;
430241675Suqs}
431241675Suqs
432241675Suqsstatic int
433241675Suqspre_ap(DECL_ARGS)
434241675Suqs{
435241675Suqs
436241675Suqs	mm->need_space = 0;
437241675Suqs	print_word(mm, "'");
438241675Suqs	mm->need_space = 0;
439241675Suqs	return(0);
440241675Suqs}
441241675Suqs
442241675Suqsstatic int
443241675Suqspre_bd(DECL_ARGS)
444241675Suqs{
445241675Suqs
446241675Suqs	if (DISP_unfilled == n->norm->Bd.type ||
447241675Suqs	    DISP_literal  == n->norm->Bd.type) {
448241675Suqs		mm->need_nl = 1;
449241675Suqs		print_word(mm, ".nf");
450241675Suqs	}
451241675Suqs	mm->need_nl = 1;
452241675Suqs	return(1);
453241675Suqs}
454241675Suqs
455241675Suqsstatic void
456241675Suqspost_bd(DECL_ARGS)
457241675Suqs{
458241675Suqs
459241675Suqs	if (DISP_unfilled == n->norm->Bd.type ||
460241675Suqs	    DISP_literal  == n->norm->Bd.type) {
461241675Suqs		mm->need_nl = 1;
462241675Suqs		print_word(mm, ".fi");
463241675Suqs	}
464241675Suqs	mm->need_nl = 1;
465241675Suqs}
466241675Suqs
467241675Suqsstatic int
468241675Suqspre_br(DECL_ARGS)
469241675Suqs{
470241675Suqs
471241675Suqs	mm->need_nl = 1;
472241675Suqs	print_word(mm, ".br");
473241675Suqs	mm->need_nl = 1;
474241675Suqs	return(0);
475241675Suqs}
476241675Suqs
477241675Suqsstatic int
478241675Suqspre_bx(DECL_ARGS)
479241675Suqs{
480241675Suqs
481241675Suqs	n = n->child;
482241675Suqs	if (n) {
483241675Suqs		print_word(mm, n->string);
484241675Suqs		mm->need_space = 0;
485241675Suqs		n = n->next;
486241675Suqs	}
487241675Suqs	print_word(mm, "BSD");
488241675Suqs	if (NULL == n)
489241675Suqs		return(0);
490241675Suqs	mm->need_space = 0;
491241675Suqs	print_word(mm, "-");
492241675Suqs	mm->need_space = 0;
493241675Suqs	print_word(mm, n->string);
494241675Suqs	return(0);
495241675Suqs}
496241675Suqs
497241675Suqsstatic int
498241675Suqspre_dl(DECL_ARGS)
499241675Suqs{
500241675Suqs
501241675Suqs	mm->need_nl = 1;
502241675Suqs	print_word(mm, ".RS 6n");
503241675Suqs	mm->need_nl = 1;
504241675Suqs	return(1);
505241675Suqs}
506241675Suqs
507241675Suqsstatic void
508241675Suqspost_dl(DECL_ARGS)
509241675Suqs{
510241675Suqs
511241675Suqs	mm->need_nl = 1;
512241675Suqs	print_word(mm, ".RE");
513241675Suqs	mm->need_nl = 1;
514241675Suqs}
515241675Suqs
516241675Suqsstatic int
517241675Suqspre_it(DECL_ARGS)
518241675Suqs{
519241675Suqs	const struct mdoc_node *bln;
520241675Suqs
521241675Suqs	if (MDOC_HEAD == n->type) {
522241675Suqs		mm->need_nl = 1;
523241675Suqs		print_word(mm, ".TP");
524241675Suqs		bln = n->parent->parent->prev;
525241675Suqs		switch (bln->norm->Bl.type) {
526241675Suqs		case (LIST_bullet):
527241675Suqs			print_word(mm, "4n");
528241675Suqs			mm->need_nl = 1;
529241675Suqs			print_word(mm, "\\fBo\\fP");
530241675Suqs			break;
531241675Suqs		default:
532241675Suqs			if (bln->norm->Bl.width)
533241675Suqs				print_word(mm, bln->norm->Bl.width);
534241675Suqs			break;
535241675Suqs		}
536241675Suqs		mm->need_nl = 1;
537241675Suqs	}
538241675Suqs	return(1);
539241675Suqs}
540241675Suqs
541241675Suqsstatic int
542241675Suqspre_nm(DECL_ARGS)
543241675Suqs{
544241675Suqs
545241675Suqs	if (MDOC_ELEM != n->type && MDOC_HEAD != n->type)
546241675Suqs		return(1);
547241675Suqs	print_word(mm, "\\fB");
548241675Suqs	mm->need_space = 0;
549241675Suqs	if (NULL == n->child)
550241675Suqs		print_word(mm, m->name);
551241675Suqs	return(1);
552241675Suqs}
553241675Suqs
554241675Suqsstatic void
555241675Suqspost_nm(DECL_ARGS)
556241675Suqs{
557241675Suqs
558241675Suqs	if (MDOC_ELEM != n->type && MDOC_HEAD != n->type)
559241675Suqs		return;
560241675Suqs	mm->need_space = 0;
561241675Suqs	print_word(mm, "\\fP");
562241675Suqs}
563241675Suqs
564241675Suqsstatic int
565241675Suqspre_ns(DECL_ARGS)
566241675Suqs{
567241675Suqs
568241675Suqs	mm->need_space = 0;
569241675Suqs	return(0);
570241675Suqs}
571241675Suqs
572241675Suqsstatic void
573241675Suqspost_pf(DECL_ARGS)
574241675Suqs{
575241675Suqs
576241675Suqs	mm->need_space = 0;
577241675Suqs}
578241675Suqs
579241675Suqsstatic int
580241675Suqspre_pp(DECL_ARGS)
581241675Suqs{
582241675Suqs
583241675Suqs	mm->need_nl = 1;
584241675Suqs	if (MDOC_It == n->parent->tok)
585241675Suqs		print_word(mm, ".sp");
586241675Suqs	else
587241675Suqs		print_word(mm, ".PP");
588241675Suqs	mm->need_nl = 1;
589241675Suqs	return(1);
590241675Suqs}
591241675Suqs
592241675Suqsstatic int
593241675Suqspre_sp(DECL_ARGS)
594241675Suqs{
595241675Suqs
596241675Suqs	mm->need_nl = 1;
597241675Suqs	print_word(mm, ".sp");
598241675Suqs	return(1);
599241675Suqs}
600241675Suqs
601241675Suqsstatic void
602241675Suqspost_sp(DECL_ARGS)
603241675Suqs{
604241675Suqs
605241675Suqs	mm->need_nl = 1;
606241675Suqs}
607241675Suqs
608241675Suqsstatic int
609241675Suqspre_xr(DECL_ARGS)
610241675Suqs{
611241675Suqs
612241675Suqs	n = n->child;
613241675Suqs	if (NULL == n)
614241675Suqs		return(0);
615241675Suqs	print_node(m, n, mm);
616241675Suqs	n = n->next;
617241675Suqs	if (NULL == n)
618241675Suqs		return(0);
619241675Suqs	mm->need_space = 0;
620241675Suqs	print_word(mm, "(");
621241675Suqs	print_node(m, n, mm);
622241675Suqs	print_word(mm, ")");
623241675Suqs	return(0);
624241675Suqs}
625241675Suqs
626241675Suqsstatic int
627241675Suqspre_ux(DECL_ARGS)
628241675Suqs{
629241675Suqs
630241675Suqs	print_word(mm, manacts[n->tok].prefix);
631241675Suqs	if (NULL == n->child)
632241675Suqs		return(0);
633241675Suqs	mm->need_space = 0;
634241675Suqs	print_word(mm, "\\~");
635241675Suqs	mm->need_space = 0;
636241675Suqs	return(1);
637241675Suqs}
638