1241675Suqs/*	$Id: mdoc_term.c,v 1.238 2011/11/13 13:15:14 schwarze Exp $ */
2241675Suqs/*
3241675Suqs * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4241675Suqs * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org>
5241675Suqs *
6241675Suqs * Permission to use, copy, modify, and distribute this software for any
7241675Suqs * purpose with or without fee is hereby granted, provided that the above
8241675Suqs * copyright notice and this permission notice appear in all copies.
9241675Suqs *
10241675Suqs * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11241675Suqs * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12241675Suqs * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13241675Suqs * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14241675Suqs * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15241675Suqs * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16241675Suqs * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17241675Suqs */
18241675Suqs#ifdef HAVE_CONFIG_H
19241675Suqs#include "config.h"
20241675Suqs#endif
21241675Suqs
22241675Suqs#include <sys/types.h>
23241675Suqs
24241675Suqs#include <assert.h>
25241675Suqs#include <ctype.h>
26241675Suqs#include <stdint.h>
27241675Suqs#include <stdio.h>
28241675Suqs#include <stdlib.h>
29241675Suqs#include <string.h>
30241675Suqs
31241675Suqs#include "mandoc.h"
32241675Suqs#include "out.h"
33241675Suqs#include "term.h"
34241675Suqs#include "mdoc.h"
35241675Suqs#include "main.h"
36241675Suqs
37241675Suqsstruct	termpair {
38241675Suqs	struct termpair	 *ppair;
39241675Suqs	int		  count;
40241675Suqs};
41241675Suqs
42241675Suqs#define	DECL_ARGS struct termp *p, \
43241675Suqs		  struct termpair *pair, \
44241675Suqs	  	  const struct mdoc_meta *m, \
45241675Suqs		  const struct mdoc_node *n
46241675Suqs
47241675Suqsstruct	termact {
48241675Suqs	int	(*pre)(DECL_ARGS);
49241675Suqs	void	(*post)(DECL_ARGS);
50241675Suqs};
51241675Suqs
52241675Suqsstatic	size_t	  a2width(const struct termp *, const char *);
53241675Suqsstatic	size_t	  a2height(const struct termp *, const char *);
54241675Suqsstatic	size_t	  a2offs(const struct termp *, const char *);
55241675Suqs
56241675Suqsstatic	void	  print_bvspace(struct termp *,
57241675Suqs			const struct mdoc_node *,
58241675Suqs			const struct mdoc_node *);
59241675Suqsstatic	void  	  print_mdoc_node(DECL_ARGS);
60241675Suqsstatic	void	  print_mdoc_nodelist(DECL_ARGS);
61241675Suqsstatic	void	  print_mdoc_head(struct termp *, const void *);
62241675Suqsstatic	void	  print_mdoc_foot(struct termp *, const void *);
63241675Suqsstatic	void	  synopsis_pre(struct termp *,
64241675Suqs			const struct mdoc_node *);
65241675Suqs
66241675Suqsstatic	void	  termp____post(DECL_ARGS);
67241675Suqsstatic	void	  termp__t_post(DECL_ARGS);
68241675Suqsstatic	void	  termp_an_post(DECL_ARGS);
69241675Suqsstatic	void	  termp_bd_post(DECL_ARGS);
70241675Suqsstatic	void	  termp_bk_post(DECL_ARGS);
71241675Suqsstatic	void	  termp_bl_post(DECL_ARGS);
72241675Suqsstatic	void	  termp_d1_post(DECL_ARGS);
73241675Suqsstatic	void	  termp_fo_post(DECL_ARGS);
74241675Suqsstatic	void	  termp_in_post(DECL_ARGS);
75241675Suqsstatic	void	  termp_it_post(DECL_ARGS);
76241675Suqsstatic	void	  termp_lb_post(DECL_ARGS);
77241675Suqsstatic	void	  termp_nm_post(DECL_ARGS);
78241675Suqsstatic	void	  termp_pf_post(DECL_ARGS);
79241675Suqsstatic	void	  termp_quote_post(DECL_ARGS);
80241675Suqsstatic	void	  termp_sh_post(DECL_ARGS);
81241675Suqsstatic	void	  termp_ss_post(DECL_ARGS);
82241675Suqs
83241675Suqsstatic	int	  termp__a_pre(DECL_ARGS);
84241675Suqsstatic	int	  termp__t_pre(DECL_ARGS);
85241675Suqsstatic	int	  termp_an_pre(DECL_ARGS);
86241675Suqsstatic	int	  termp_ap_pre(DECL_ARGS);
87241675Suqsstatic	int	  termp_bd_pre(DECL_ARGS);
88241675Suqsstatic	int	  termp_bf_pre(DECL_ARGS);
89241675Suqsstatic	int	  termp_bk_pre(DECL_ARGS);
90241675Suqsstatic	int	  termp_bl_pre(DECL_ARGS);
91241675Suqsstatic	int	  termp_bold_pre(DECL_ARGS);
92241675Suqsstatic	int	  termp_bt_pre(DECL_ARGS);
93241675Suqsstatic	int	  termp_bx_pre(DECL_ARGS);
94241675Suqsstatic	int	  termp_cd_pre(DECL_ARGS);
95241675Suqsstatic	int	  termp_d1_pre(DECL_ARGS);
96241675Suqsstatic	int	  termp_ex_pre(DECL_ARGS);
97241675Suqsstatic	int	  termp_fa_pre(DECL_ARGS);
98241675Suqsstatic	int	  termp_fd_pre(DECL_ARGS);
99241675Suqsstatic	int	  termp_fl_pre(DECL_ARGS);
100241675Suqsstatic	int	  termp_fn_pre(DECL_ARGS);
101241675Suqsstatic	int	  termp_fo_pre(DECL_ARGS);
102241675Suqsstatic	int	  termp_ft_pre(DECL_ARGS);
103241675Suqsstatic	int	  termp_igndelim_pre(DECL_ARGS);
104241675Suqsstatic	int	  termp_in_pre(DECL_ARGS);
105241675Suqsstatic	int	  termp_it_pre(DECL_ARGS);
106241675Suqsstatic	int	  termp_li_pre(DECL_ARGS);
107241675Suqsstatic	int	  termp_lk_pre(DECL_ARGS);
108241675Suqsstatic	int	  termp_nd_pre(DECL_ARGS);
109241675Suqsstatic	int	  termp_nm_pre(DECL_ARGS);
110241675Suqsstatic	int	  termp_ns_pre(DECL_ARGS);
111241675Suqsstatic	int	  termp_quote_pre(DECL_ARGS);
112241675Suqsstatic	int	  termp_rs_pre(DECL_ARGS);
113241675Suqsstatic	int	  termp_rv_pre(DECL_ARGS);
114241675Suqsstatic	int	  termp_sh_pre(DECL_ARGS);
115241675Suqsstatic	int	  termp_sm_pre(DECL_ARGS);
116241675Suqsstatic	int	  termp_sp_pre(DECL_ARGS);
117241675Suqsstatic	int	  termp_ss_pre(DECL_ARGS);
118241675Suqsstatic	int	  termp_under_pre(DECL_ARGS);
119241675Suqsstatic	int	  termp_ud_pre(DECL_ARGS);
120241675Suqsstatic	int	  termp_vt_pre(DECL_ARGS);
121241675Suqsstatic	int	  termp_xr_pre(DECL_ARGS);
122241675Suqsstatic	int	  termp_xx_pre(DECL_ARGS);
123241675Suqs
124241675Suqsstatic	const struct termact termacts[MDOC_MAX] = {
125241675Suqs	{ termp_ap_pre, NULL }, /* Ap */
126241675Suqs	{ NULL, NULL }, /* Dd */
127241675Suqs	{ NULL, NULL }, /* Dt */
128241675Suqs	{ NULL, NULL }, /* Os */
129241675Suqs	{ termp_sh_pre, termp_sh_post }, /* Sh */
130241675Suqs	{ termp_ss_pre, termp_ss_post }, /* Ss */
131241675Suqs	{ termp_sp_pre, NULL }, /* Pp */
132241675Suqs	{ termp_d1_pre, termp_d1_post }, /* D1 */
133241675Suqs	{ termp_d1_pre, termp_d1_post }, /* Dl */
134241675Suqs	{ termp_bd_pre, termp_bd_post }, /* Bd */
135241675Suqs	{ NULL, NULL }, /* Ed */
136241675Suqs	{ termp_bl_pre, termp_bl_post }, /* Bl */
137241675Suqs	{ NULL, NULL }, /* El */
138241675Suqs	{ termp_it_pre, termp_it_post }, /* It */
139241675Suqs	{ termp_under_pre, NULL }, /* Ad */
140241675Suqs	{ termp_an_pre, termp_an_post }, /* An */
141241675Suqs	{ termp_under_pre, NULL }, /* Ar */
142241675Suqs	{ termp_cd_pre, NULL }, /* Cd */
143241675Suqs	{ termp_bold_pre, NULL }, /* Cm */
144241675Suqs	{ NULL, NULL }, /* Dv */
145241675Suqs	{ NULL, NULL }, /* Er */
146241675Suqs	{ NULL, NULL }, /* Ev */
147241675Suqs	{ termp_ex_pre, NULL }, /* Ex */
148241675Suqs	{ termp_fa_pre, NULL }, /* Fa */
149241675Suqs	{ termp_fd_pre, NULL }, /* Fd */
150241675Suqs	{ termp_fl_pre, NULL }, /* Fl */
151241675Suqs	{ termp_fn_pre, NULL }, /* Fn */
152241675Suqs	{ termp_ft_pre, NULL }, /* Ft */
153241675Suqs	{ termp_bold_pre, NULL }, /* Ic */
154241675Suqs	{ termp_in_pre, termp_in_post }, /* In */
155241675Suqs	{ termp_li_pre, NULL }, /* Li */
156241675Suqs	{ termp_nd_pre, NULL }, /* Nd */
157241675Suqs	{ termp_nm_pre, termp_nm_post }, /* Nm */
158241675Suqs	{ termp_quote_pre, termp_quote_post }, /* Op */
159241675Suqs	{ NULL, NULL }, /* Ot */
160241675Suqs	{ termp_under_pre, NULL }, /* Pa */
161241675Suqs	{ termp_rv_pre, NULL }, /* Rv */
162241675Suqs	{ NULL, NULL }, /* St */
163241675Suqs	{ termp_under_pre, NULL }, /* Va */
164241675Suqs	{ termp_vt_pre, NULL }, /* Vt */
165241675Suqs	{ termp_xr_pre, NULL }, /* Xr */
166241675Suqs	{ termp__a_pre, termp____post }, /* %A */
167241675Suqs	{ termp_under_pre, termp____post }, /* %B */
168241675Suqs	{ NULL, termp____post }, /* %D */
169241675Suqs	{ termp_under_pre, termp____post }, /* %I */
170241675Suqs	{ termp_under_pre, termp____post }, /* %J */
171241675Suqs	{ NULL, termp____post }, /* %N */
172241675Suqs	{ NULL, termp____post }, /* %O */
173241675Suqs	{ NULL, termp____post }, /* %P */
174241675Suqs	{ NULL, termp____post }, /* %R */
175241675Suqs	{ termp__t_pre, termp__t_post }, /* %T */
176241675Suqs	{ NULL, termp____post }, /* %V */
177241675Suqs	{ NULL, NULL }, /* Ac */
178241675Suqs	{ termp_quote_pre, termp_quote_post }, /* Ao */
179241675Suqs	{ termp_quote_pre, termp_quote_post }, /* Aq */
180241675Suqs	{ NULL, NULL }, /* At */
181241675Suqs	{ NULL, NULL }, /* Bc */
182241675Suqs	{ termp_bf_pre, NULL }, /* Bf */
183241675Suqs	{ termp_quote_pre, termp_quote_post }, /* Bo */
184241675Suqs	{ termp_quote_pre, termp_quote_post }, /* Bq */
185241675Suqs	{ termp_xx_pre, NULL }, /* Bsx */
186241675Suqs	{ termp_bx_pre, NULL }, /* Bx */
187241675Suqs	{ NULL, NULL }, /* Db */
188241675Suqs	{ NULL, NULL }, /* Dc */
189241675Suqs	{ termp_quote_pre, termp_quote_post }, /* Do */
190241675Suqs	{ termp_quote_pre, termp_quote_post }, /* Dq */
191241675Suqs	{ NULL, NULL }, /* Ec */ /* FIXME: no space */
192241675Suqs	{ NULL, NULL }, /* Ef */
193241675Suqs	{ termp_under_pre, NULL }, /* Em */
194241675Suqs	{ termp_quote_pre, termp_quote_post }, /* Eo */
195241675Suqs	{ termp_xx_pre, NULL }, /* Fx */
196241675Suqs	{ termp_bold_pre, NULL }, /* Ms */
197241675Suqs	{ termp_igndelim_pre, NULL }, /* No */
198241675Suqs	{ termp_ns_pre, NULL }, /* Ns */
199241675Suqs	{ termp_xx_pre, NULL }, /* Nx */
200241675Suqs	{ termp_xx_pre, NULL }, /* Ox */
201241675Suqs	{ NULL, NULL }, /* Pc */
202241675Suqs	{ termp_igndelim_pre, termp_pf_post }, /* Pf */
203241675Suqs	{ termp_quote_pre, termp_quote_post }, /* Po */
204241675Suqs	{ termp_quote_pre, termp_quote_post }, /* Pq */
205241675Suqs	{ NULL, NULL }, /* Qc */
206241675Suqs	{ termp_quote_pre, termp_quote_post }, /* Ql */
207241675Suqs	{ termp_quote_pre, termp_quote_post }, /* Qo */
208241675Suqs	{ termp_quote_pre, termp_quote_post }, /* Qq */
209241675Suqs	{ NULL, NULL }, /* Re */
210241675Suqs	{ termp_rs_pre, NULL }, /* Rs */
211241675Suqs	{ NULL, NULL }, /* Sc */
212241675Suqs	{ termp_quote_pre, termp_quote_post }, /* So */
213241675Suqs	{ termp_quote_pre, termp_quote_post }, /* Sq */
214241675Suqs	{ termp_sm_pre, NULL }, /* Sm */
215241675Suqs	{ termp_under_pre, NULL }, /* Sx */
216241675Suqs	{ termp_bold_pre, NULL }, /* Sy */
217241675Suqs	{ NULL, NULL }, /* Tn */
218241675Suqs	{ termp_xx_pre, NULL }, /* Ux */
219241675Suqs	{ NULL, NULL }, /* Xc */
220241675Suqs	{ NULL, NULL }, /* Xo */
221241675Suqs	{ termp_fo_pre, termp_fo_post }, /* Fo */
222241675Suqs	{ NULL, NULL }, /* Fc */
223241675Suqs	{ termp_quote_pre, termp_quote_post }, /* Oo */
224241675Suqs	{ NULL, NULL }, /* Oc */
225241675Suqs	{ termp_bk_pre, termp_bk_post }, /* Bk */
226241675Suqs	{ NULL, NULL }, /* Ek */
227241675Suqs	{ termp_bt_pre, NULL }, /* Bt */
228241675Suqs	{ NULL, NULL }, /* Hf */
229241675Suqs	{ NULL, NULL }, /* Fr */
230241675Suqs	{ termp_ud_pre, NULL }, /* Ud */
231241675Suqs	{ NULL, termp_lb_post }, /* Lb */
232241675Suqs	{ termp_sp_pre, NULL }, /* Lp */
233241675Suqs	{ termp_lk_pre, NULL }, /* Lk */
234241675Suqs	{ termp_under_pre, NULL }, /* Mt */
235241675Suqs	{ termp_quote_pre, termp_quote_post }, /* Brq */
236241675Suqs	{ termp_quote_pre, termp_quote_post }, /* Bro */
237241675Suqs	{ NULL, NULL }, /* Brc */
238241675Suqs	{ NULL, termp____post }, /* %C */
239241675Suqs	{ NULL, NULL }, /* Es */ /* TODO */
240241675Suqs	{ NULL, NULL }, /* En */ /* TODO */
241241675Suqs	{ termp_xx_pre, NULL }, /* Dx */
242241675Suqs	{ NULL, termp____post }, /* %Q */
243241675Suqs	{ termp_sp_pre, NULL }, /* br */
244241675Suqs	{ termp_sp_pre, NULL }, /* sp */
245241675Suqs	{ termp_under_pre, termp____post }, /* %U */
246241675Suqs	{ NULL, NULL }, /* Ta */
247241675Suqs};
248241675Suqs
249241675Suqs
250241675Suqsvoid
251241675Suqsterminal_mdoc(void *arg, const struct mdoc *mdoc)
252241675Suqs{
253241675Suqs	const struct mdoc_node	*n;
254241675Suqs	const struct mdoc_meta	*m;
255241675Suqs	struct termp		*p;
256241675Suqs
257241675Suqs	p = (struct termp *)arg;
258241675Suqs
259241675Suqs	if (0 == p->defindent)
260241675Suqs		p->defindent = 5;
261241675Suqs
262241675Suqs	p->overstep = 0;
263241675Suqs	p->maxrmargin = p->defrmargin;
264241675Suqs	p->tabwidth = term_len(p, 5);
265241675Suqs
266241675Suqs	if (NULL == p->symtab)
267241675Suqs		p->symtab = mchars_alloc();
268241675Suqs
269241675Suqs	n = mdoc_node(mdoc);
270241675Suqs	m = mdoc_meta(mdoc);
271241675Suqs
272241675Suqs	term_begin(p, print_mdoc_head, print_mdoc_foot, m);
273241675Suqs
274241675Suqs	if (n->child)
275241675Suqs		print_mdoc_nodelist(p, NULL, m, n->child);
276241675Suqs
277241675Suqs	term_end(p);
278241675Suqs}
279241675Suqs
280241675Suqs
281241675Suqsstatic void
282241675Suqsprint_mdoc_nodelist(DECL_ARGS)
283241675Suqs{
284241675Suqs
285241675Suqs	print_mdoc_node(p, pair, m, n);
286241675Suqs	if (n->next)
287241675Suqs		print_mdoc_nodelist(p, pair, m, n->next);
288241675Suqs}
289241675Suqs
290241675Suqs
291241675Suqs/* ARGSUSED */
292241675Suqsstatic void
293241675Suqsprint_mdoc_node(DECL_ARGS)
294241675Suqs{
295241675Suqs	int		 chld;
296241675Suqs	const void	*font;
297241675Suqs	struct termpair	 npair;
298241675Suqs	size_t		 offset, rmargin;
299241675Suqs
300241675Suqs	chld = 1;
301241675Suqs	offset = p->offset;
302241675Suqs	rmargin = p->rmargin;
303241675Suqs	font = term_fontq(p);
304241675Suqs
305241675Suqs	memset(&npair, 0, sizeof(struct termpair));
306241675Suqs	npair.ppair = pair;
307241675Suqs
308241675Suqs	/*
309241675Suqs	 * Keeps only work until the end of a line.  If a keep was
310241675Suqs	 * invoked in a prior line, revert it to PREKEEP.
311241675Suqs	 *
312241675Suqs	 * Also let SYNPRETTY sections behave as if they were wrapped
313241675Suqs	 * in a `Bk' block.
314241675Suqs	 */
315241675Suqs
316241675Suqs	if (TERMP_KEEP & p->flags || MDOC_SYNPRETTY & n->flags) {
317241675Suqs		if (n->prev && n->prev->line != n->line) {
318241675Suqs			p->flags &= ~TERMP_KEEP;
319241675Suqs			p->flags |= TERMP_PREKEEP;
320241675Suqs		} else if (NULL == n->prev) {
321241675Suqs			if (n->parent && n->parent->line != n->line) {
322241675Suqs				p->flags &= ~TERMP_KEEP;
323241675Suqs				p->flags |= TERMP_PREKEEP;
324241675Suqs			}
325241675Suqs		}
326241675Suqs	}
327241675Suqs
328241675Suqs	/*
329241675Suqs	 * Since SYNPRETTY sections aren't "turned off" with `Ek',
330241675Suqs	 * we have to intuit whether we should disable formatting.
331241675Suqs	 */
332241675Suqs
333241675Suqs	if ( ! (MDOC_SYNPRETTY & n->flags) &&
334241675Suqs	    ((n->prev   && MDOC_SYNPRETTY & n->prev->flags) ||
335241675Suqs	     (n->parent && MDOC_SYNPRETTY & n->parent->flags)))
336241675Suqs		p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
337241675Suqs
338241675Suqs	/*
339241675Suqs	 * After the keep flags have been set up, we may now
340241675Suqs	 * produce output.  Note that some pre-handlers do so.
341241675Suqs	 */
342241675Suqs
343241675Suqs	switch (n->type) {
344241675Suqs	case (MDOC_TEXT):
345241675Suqs		if (' ' == *n->string && MDOC_LINE & n->flags)
346241675Suqs			term_newln(p);
347241675Suqs		if (MDOC_DELIMC & n->flags)
348241675Suqs			p->flags |= TERMP_NOSPACE;
349241675Suqs		term_word(p, n->string);
350241675Suqs		if (MDOC_DELIMO & n->flags)
351241675Suqs			p->flags |= TERMP_NOSPACE;
352241675Suqs		break;
353241675Suqs	case (MDOC_EQN):
354241675Suqs		term_eqn(p, n->eqn);
355241675Suqs		break;
356241675Suqs	case (MDOC_TBL):
357241675Suqs		term_tbl(p, n->span);
358241675Suqs		break;
359241675Suqs	default:
360241675Suqs		if (termacts[n->tok].pre && ENDBODY_NOT == n->end)
361241675Suqs			chld = (*termacts[n->tok].pre)
362241675Suqs				(p, &npair, m, n);
363241675Suqs		break;
364241675Suqs	}
365241675Suqs
366241675Suqs	if (chld && n->child)
367241675Suqs		print_mdoc_nodelist(p, &npair, m, n->child);
368241675Suqs
369241675Suqs	term_fontpopq(p, font);
370241675Suqs
371241675Suqs	switch (n->type) {
372241675Suqs	case (MDOC_TEXT):
373241675Suqs		break;
374241675Suqs	case (MDOC_TBL):
375241675Suqs		break;
376241675Suqs	case (MDOC_EQN):
377241675Suqs		break;
378241675Suqs	default:
379241675Suqs		if ( ! termacts[n->tok].post || MDOC_ENDED & n->flags)
380241675Suqs			break;
381241675Suqs		(void)(*termacts[n->tok].post)(p, &npair, m, n);
382241675Suqs
383241675Suqs		/*
384241675Suqs		 * Explicit end tokens not only call the post
385241675Suqs		 * handler, but also tell the respective block
386241675Suqs		 * that it must not call the post handler again.
387241675Suqs		 */
388241675Suqs		if (ENDBODY_NOT != n->end)
389241675Suqs			n->pending->flags |= MDOC_ENDED;
390241675Suqs
391241675Suqs		/*
392241675Suqs		 * End of line terminating an implicit block
393241675Suqs		 * while an explicit block is still open.
394241675Suqs		 * Continue the explicit block without spacing.
395241675Suqs		 */
396241675Suqs		if (ENDBODY_NOSPACE == n->end)
397241675Suqs			p->flags |= TERMP_NOSPACE;
398241675Suqs		break;
399241675Suqs	}
400241675Suqs
401241675Suqs	if (MDOC_EOS & n->flags)
402241675Suqs		p->flags |= TERMP_SENTENCE;
403241675Suqs
404241675Suqs	p->offset = offset;
405241675Suqs	p->rmargin = rmargin;
406241675Suqs}
407241675Suqs
408241675Suqs
409241675Suqsstatic void
410241675Suqsprint_mdoc_foot(struct termp *p, const void *arg)
411241675Suqs{
412241675Suqs	const struct mdoc_meta *m;
413241675Suqs
414241675Suqs	m = (const struct mdoc_meta *)arg;
415241675Suqs
416241675Suqs	term_fontrepl(p, TERMFONT_NONE);
417241675Suqs
418241675Suqs	/*
419241675Suqs	 * Output the footer in new-groff style, that is, three columns
420241675Suqs	 * with the middle being the manual date and flanking columns
421241675Suqs	 * being the operating system:
422241675Suqs	 *
423241675Suqs	 * SYSTEM                  DATE                    SYSTEM
424241675Suqs	 */
425241675Suqs
426241675Suqs	term_vspace(p);
427241675Suqs
428241675Suqs	p->offset = 0;
429241675Suqs	p->rmargin = (p->maxrmargin -
430241675Suqs			term_strlen(p, m->date) + term_len(p, 1)) / 2;
431241675Suqs	p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
432241675Suqs
433241675Suqs	term_word(p, m->os);
434241675Suqs	term_flushln(p);
435241675Suqs
436241675Suqs	p->offset = p->rmargin;
437241675Suqs	p->rmargin = p->maxrmargin - term_strlen(p, m->os);
438241675Suqs	p->flags |= TERMP_NOSPACE;
439241675Suqs
440241675Suqs	term_word(p, m->date);
441241675Suqs	term_flushln(p);
442241675Suqs
443241675Suqs	p->offset = p->rmargin;
444241675Suqs	p->rmargin = p->maxrmargin;
445241675Suqs	p->flags &= ~TERMP_NOBREAK;
446241675Suqs	p->flags |= TERMP_NOSPACE;
447241675Suqs
448241675Suqs	term_word(p, m->os);
449241675Suqs	term_flushln(p);
450241675Suqs
451241675Suqs	p->offset = 0;
452241675Suqs	p->rmargin = p->maxrmargin;
453241675Suqs	p->flags = 0;
454241675Suqs}
455241675Suqs
456241675Suqs
457241675Suqsstatic void
458241675Suqsprint_mdoc_head(struct termp *p, const void *arg)
459241675Suqs{
460241675Suqs	char		buf[BUFSIZ], title[BUFSIZ];
461241675Suqs	size_t		buflen, titlen;
462241675Suqs	const struct mdoc_meta *m;
463241675Suqs
464241675Suqs	m = (const struct mdoc_meta *)arg;
465241675Suqs
466241675Suqs	/*
467241675Suqs	 * The header is strange.  It has three components, which are
468241675Suqs	 * really two with the first duplicated.  It goes like this:
469241675Suqs	 *
470241675Suqs	 * IDENTIFIER              TITLE                   IDENTIFIER
471241675Suqs	 *
472241675Suqs	 * The IDENTIFIER is NAME(SECTION), which is the command-name
473241675Suqs	 * (if given, or "unknown" if not) followed by the manual page
474241675Suqs	 * section.  These are given in `Dt'.  The TITLE is a free-form
475241675Suqs	 * string depending on the manual volume.  If not specified, it
476241675Suqs	 * switches on the manual section.
477241675Suqs	 */
478241675Suqs
479241675Suqs	p->offset = 0;
480241675Suqs	p->rmargin = p->maxrmargin;
481241675Suqs
482241675Suqs	assert(m->vol);
483241675Suqs	strlcpy(buf, m->vol, BUFSIZ);
484241675Suqs	buflen = term_strlen(p, buf);
485241675Suqs
486241675Suqs	if (m->arch) {
487241675Suqs		strlcat(buf, " (", BUFSIZ);
488241675Suqs		strlcat(buf, m->arch, BUFSIZ);
489241675Suqs		strlcat(buf, ")", BUFSIZ);
490241675Suqs	}
491241675Suqs
492241675Suqs	snprintf(title, BUFSIZ, "%s(%s)", m->title, m->msec);
493241675Suqs	titlen = term_strlen(p, title);
494241675Suqs
495241675Suqs	p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
496241675Suqs	p->offset = 0;
497241675Suqs	p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
498241675Suqs	    (p->maxrmargin -
499241675Suqs	     term_strlen(p, buf) + term_len(p, 1)) / 2 :
500241675Suqs	    p->maxrmargin - buflen;
501241675Suqs
502241675Suqs	term_word(p, title);
503241675Suqs	term_flushln(p);
504241675Suqs
505241675Suqs	p->flags |= TERMP_NOSPACE;
506241675Suqs	p->offset = p->rmargin;
507241675Suqs	p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
508241675Suqs	    p->maxrmargin - titlen : p->maxrmargin;
509241675Suqs
510241675Suqs	term_word(p, buf);
511241675Suqs	term_flushln(p);
512241675Suqs
513241675Suqs	p->flags &= ~TERMP_NOBREAK;
514241675Suqs	if (p->rmargin + titlen <= p->maxrmargin) {
515241675Suqs		p->flags |= TERMP_NOSPACE;
516241675Suqs		p->offset = p->rmargin;
517241675Suqs		p->rmargin = p->maxrmargin;
518241675Suqs		term_word(p, title);
519241675Suqs		term_flushln(p);
520241675Suqs	}
521241675Suqs
522241675Suqs	p->flags &= ~TERMP_NOSPACE;
523241675Suqs	p->offset = 0;
524241675Suqs	p->rmargin = p->maxrmargin;
525241675Suqs}
526241675Suqs
527241675Suqs
528241675Suqsstatic size_t
529241675Suqsa2height(const struct termp *p, const char *v)
530241675Suqs{
531241675Suqs	struct roffsu	 su;
532241675Suqs
533241675Suqs
534241675Suqs	assert(v);
535241675Suqs	if ( ! a2roffsu(v, &su, SCALE_VS))
536241675Suqs		SCALE_VS_INIT(&su, atoi(v));
537241675Suqs
538241675Suqs	return(term_vspan(p, &su));
539241675Suqs}
540241675Suqs
541241675Suqs
542241675Suqsstatic size_t
543241675Suqsa2width(const struct termp *p, const char *v)
544241675Suqs{
545241675Suqs	struct roffsu	 su;
546241675Suqs
547241675Suqs	assert(v);
548241675Suqs	if ( ! a2roffsu(v, &su, SCALE_MAX))
549241675Suqs		SCALE_HS_INIT(&su, term_strlen(p, v));
550241675Suqs
551241675Suqs	return(term_hspan(p, &su));
552241675Suqs}
553241675Suqs
554241675Suqs
555241675Suqsstatic size_t
556241675Suqsa2offs(const struct termp *p, const char *v)
557241675Suqs{
558241675Suqs	struct roffsu	 su;
559241675Suqs
560241675Suqs	if ('\0' == *v)
561241675Suqs		return(0);
562241675Suqs	else if (0 == strcmp(v, "left"))
563241675Suqs		return(0);
564241675Suqs	else if (0 == strcmp(v, "indent"))
565241675Suqs		return(term_len(p, p->defindent + 1));
566241675Suqs	else if (0 == strcmp(v, "indent-two"))
567241675Suqs		return(term_len(p, (p->defindent + 1) * 2));
568241675Suqs	else if ( ! a2roffsu(v, &su, SCALE_MAX))
569241675Suqs		SCALE_HS_INIT(&su, term_strlen(p, v));
570241675Suqs
571241675Suqs	return(term_hspan(p, &su));
572241675Suqs}
573241675Suqs
574241675Suqs
575241675Suqs/*
576241675Suqs * Determine how much space to print out before block elements of `It'
577241675Suqs * (and thus `Bl') and `Bd'.  And then go ahead and print that space,
578241675Suqs * too.
579241675Suqs */
580241675Suqsstatic void
581241675Suqsprint_bvspace(struct termp *p,
582241675Suqs		const struct mdoc_node *bl,
583241675Suqs		const struct mdoc_node *n)
584241675Suqs{
585241675Suqs	const struct mdoc_node	*nn;
586241675Suqs
587241675Suqs	assert(n);
588241675Suqs
589241675Suqs	term_newln(p);
590241675Suqs
591241675Suqs	if (MDOC_Bd == bl->tok && bl->norm->Bd.comp)
592241675Suqs		return;
593241675Suqs	if (MDOC_Bl == bl->tok && bl->norm->Bl.comp)
594241675Suqs		return;
595241675Suqs
596241675Suqs	/* Do not vspace directly after Ss/Sh. */
597241675Suqs
598241675Suqs	for (nn = n; nn; nn = nn->parent) {
599241675Suqs		if (MDOC_BLOCK != nn->type)
600241675Suqs			continue;
601241675Suqs		if (MDOC_Ss == nn->tok)
602241675Suqs			return;
603241675Suqs		if (MDOC_Sh == nn->tok)
604241675Suqs			return;
605241675Suqs		if (NULL == nn->prev)
606241675Suqs			continue;
607241675Suqs		break;
608241675Suqs	}
609241675Suqs
610241675Suqs	/* A `-column' does not assert vspace within the list. */
611241675Suqs
612241675Suqs	if (MDOC_Bl == bl->tok && LIST_column == bl->norm->Bl.type)
613241675Suqs		if (n->prev && MDOC_It == n->prev->tok)
614241675Suqs			return;
615241675Suqs
616241675Suqs	/* A `-diag' without body does not vspace. */
617241675Suqs
618241675Suqs	if (MDOC_Bl == bl->tok && LIST_diag == bl->norm->Bl.type)
619241675Suqs		if (n->prev && MDOC_It == n->prev->tok) {
620241675Suqs			assert(n->prev->body);
621241675Suqs			if (NULL == n->prev->body->child)
622241675Suqs				return;
623241675Suqs		}
624241675Suqs
625241675Suqs	term_vspace(p);
626241675Suqs}
627241675Suqs
628241675Suqs
629241675Suqs/* ARGSUSED */
630241675Suqsstatic int
631241675Suqstermp_it_pre(DECL_ARGS)
632241675Suqs{
633241675Suqs	const struct mdoc_node *bl, *nn;
634241675Suqs	char		        buf[7];
635241675Suqs	int		        i;
636241675Suqs	size_t		        width, offset, ncols, dcol;
637241675Suqs	enum mdoc_list		type;
638241675Suqs
639241675Suqs	if (MDOC_BLOCK == n->type) {
640241675Suqs		print_bvspace(p, n->parent->parent, n);
641241675Suqs		return(1);
642241675Suqs	}
643241675Suqs
644241675Suqs	bl = n->parent->parent->parent;
645241675Suqs	type = bl->norm->Bl.type;
646241675Suqs
647241675Suqs	/*
648241675Suqs	 * First calculate width and offset.  This is pretty easy unless
649241675Suqs	 * we're a -column list, in which case all prior columns must
650241675Suqs	 * be accounted for.
651241675Suqs	 */
652241675Suqs
653241675Suqs	width = offset = 0;
654241675Suqs
655241675Suqs	if (bl->norm->Bl.offs)
656241675Suqs		offset = a2offs(p, bl->norm->Bl.offs);
657241675Suqs
658241675Suqs	switch (type) {
659241675Suqs	case (LIST_column):
660241675Suqs		if (MDOC_HEAD == n->type)
661241675Suqs			break;
662241675Suqs
663241675Suqs		/*
664241675Suqs		 * Imitate groff's column handling:
665241675Suqs		 * - For each earlier column, add its width.
666241675Suqs		 * - For less than 5 columns, add four more blanks per
667241675Suqs		 *   column.
668241675Suqs		 * - For exactly 5 columns, add three more blank per
669241675Suqs		 *   column.
670241675Suqs		 * - For more than 5 columns, add only one column.
671241675Suqs		 */
672241675Suqs		ncols = bl->norm->Bl.ncols;
673241675Suqs
674241675Suqs		/* LINTED */
675241675Suqs		dcol = ncols < 5 ? term_len(p, 4) :
676241675Suqs			ncols == 5 ? term_len(p, 3) : term_len(p, 1);
677241675Suqs
678241675Suqs		/*
679241675Suqs		 * Calculate the offset by applying all prior MDOC_BODY,
680241675Suqs		 * so we stop at the MDOC_HEAD (NULL == nn->prev).
681241675Suqs		 */
682241675Suqs
683241675Suqs		for (i = 0, nn = n->prev;
684241675Suqs				nn->prev && i < (int)ncols;
685241675Suqs				nn = nn->prev, i++)
686241675Suqs			offset += dcol + a2width
687241675Suqs				(p, bl->norm->Bl.cols[i]);
688241675Suqs
689241675Suqs		/*
690241675Suqs		 * When exceeding the declared number of columns, leave
691241675Suqs		 * the remaining widths at 0.  This will later be
692241675Suqs		 * adjusted to the default width of 10, or, for the last
693241675Suqs		 * column, stretched to the right margin.
694241675Suqs		 */
695241675Suqs		if (i >= (int)ncols)
696241675Suqs			break;
697241675Suqs
698241675Suqs		/*
699241675Suqs		 * Use the declared column widths, extended as explained
700241675Suqs		 * in the preceding paragraph.
701241675Suqs		 */
702241675Suqs		width = a2width(p, bl->norm->Bl.cols[i]) + dcol;
703241675Suqs		break;
704241675Suqs	default:
705241675Suqs		if (NULL == bl->norm->Bl.width)
706241675Suqs			break;
707241675Suqs
708241675Suqs		/*
709241675Suqs		 * Note: buffer the width by 2, which is groff's magic
710241675Suqs		 * number for buffering single arguments.  See the above
711241675Suqs		 * handling for column for how this changes.
712241675Suqs		 */
713241675Suqs		assert(bl->norm->Bl.width);
714241675Suqs		width = a2width(p, bl->norm->Bl.width) + term_len(p, 2);
715241675Suqs		break;
716241675Suqs	}
717241675Suqs
718241675Suqs	/*
719241675Suqs	 * List-type can override the width in the case of fixed-head
720241675Suqs	 * values (bullet, dash/hyphen, enum).  Tags need a non-zero
721241675Suqs	 * offset.
722241675Suqs	 */
723241675Suqs
724241675Suqs	switch (type) {
725241675Suqs	case (LIST_bullet):
726241675Suqs		/* FALLTHROUGH */
727241675Suqs	case (LIST_dash):
728241675Suqs		/* FALLTHROUGH */
729241675Suqs	case (LIST_hyphen):
730241675Suqs		if (width < term_len(p, 4))
731241675Suqs			width = term_len(p, 4);
732241675Suqs		break;
733241675Suqs	case (LIST_enum):
734241675Suqs		if (width < term_len(p, 5))
735241675Suqs			width = term_len(p, 5);
736241675Suqs		break;
737241675Suqs	case (LIST_hang):
738241675Suqs		if (0 == width)
739241675Suqs			width = term_len(p, 8);
740241675Suqs		break;
741241675Suqs	case (LIST_column):
742241675Suqs		/* FALLTHROUGH */
743241675Suqs	case (LIST_tag):
744241675Suqs		if (0 == width)
745241675Suqs			width = term_len(p, 10);
746241675Suqs		break;
747241675Suqs	default:
748241675Suqs		break;
749241675Suqs	}
750241675Suqs
751241675Suqs	/*
752241675Suqs	 * Whitespace control.  Inset bodies need an initial space,
753241675Suqs	 * while diagonal bodies need two.
754241675Suqs	 */
755241675Suqs
756241675Suqs	p->flags |= TERMP_NOSPACE;
757241675Suqs
758241675Suqs	switch (type) {
759241675Suqs	case (LIST_diag):
760241675Suqs		if (MDOC_BODY == n->type)
761241675Suqs			term_word(p, "\\ \\ ");
762241675Suqs		break;
763241675Suqs	case (LIST_inset):
764241675Suqs		if (MDOC_BODY == n->type)
765241675Suqs			term_word(p, "\\ ");
766241675Suqs		break;
767241675Suqs	default:
768241675Suqs		break;
769241675Suqs	}
770241675Suqs
771241675Suqs	p->flags |= TERMP_NOSPACE;
772241675Suqs
773241675Suqs	switch (type) {
774241675Suqs	case (LIST_diag):
775241675Suqs		if (MDOC_HEAD == n->type)
776241675Suqs			term_fontpush(p, TERMFONT_BOLD);
777241675Suqs		break;
778241675Suqs	default:
779241675Suqs		break;
780241675Suqs	}
781241675Suqs
782241675Suqs	/*
783241675Suqs	 * Pad and break control.  This is the tricky part.  These flags
784241675Suqs	 * are documented in term_flushln() in term.c.  Note that we're
785241675Suqs	 * going to unset all of these flags in termp_it_post() when we
786241675Suqs	 * exit.
787241675Suqs	 */
788241675Suqs
789241675Suqs	switch (type) {
790241675Suqs	case (LIST_bullet):
791241675Suqs		/* FALLTHROUGH */
792241675Suqs	case (LIST_dash):
793241675Suqs		/* FALLTHROUGH */
794241675Suqs	case (LIST_enum):
795241675Suqs		/* FALLTHROUGH */
796241675Suqs	case (LIST_hyphen):
797241675Suqs		if (MDOC_HEAD == n->type)
798241675Suqs			p->flags |= TERMP_NOBREAK;
799241675Suqs		break;
800241675Suqs	case (LIST_hang):
801241675Suqs		if (MDOC_HEAD == n->type)
802241675Suqs			p->flags |= TERMP_NOBREAK;
803241675Suqs		else
804241675Suqs			break;
805241675Suqs
806241675Suqs		/*
807241675Suqs		 * This is ugly.  If `-hang' is specified and the body
808241675Suqs		 * is a `Bl' or `Bd', then we want basically to nullify
809241675Suqs		 * the "overstep" effect in term_flushln() and treat
810241675Suqs		 * this as a `-ohang' list instead.
811241675Suqs		 */
812241675Suqs		if (n->next->child &&
813241675Suqs				(MDOC_Bl == n->next->child->tok ||
814241675Suqs				 MDOC_Bd == n->next->child->tok))
815241675Suqs			p->flags &= ~TERMP_NOBREAK;
816241675Suqs		else
817241675Suqs			p->flags |= TERMP_HANG;
818241675Suqs		break;
819241675Suqs	case (LIST_tag):
820241675Suqs		if (MDOC_HEAD == n->type)
821241675Suqs			p->flags |= TERMP_NOBREAK | TERMP_TWOSPACE;
822241675Suqs
823241675Suqs		if (MDOC_HEAD != n->type)
824241675Suqs			break;
825241675Suqs		if (NULL == n->next || NULL == n->next->child)
826241675Suqs			p->flags |= TERMP_DANGLE;
827241675Suqs		break;
828241675Suqs	case (LIST_column):
829241675Suqs		if (MDOC_HEAD == n->type)
830241675Suqs			break;
831241675Suqs
832241675Suqs		if (NULL == n->next)
833241675Suqs			p->flags &= ~TERMP_NOBREAK;
834241675Suqs		else
835241675Suqs			p->flags |= TERMP_NOBREAK;
836241675Suqs
837241675Suqs		break;
838241675Suqs	case (LIST_diag):
839241675Suqs		if (MDOC_HEAD == n->type)
840241675Suqs			p->flags |= TERMP_NOBREAK;
841241675Suqs		break;
842241675Suqs	default:
843241675Suqs		break;
844241675Suqs	}
845241675Suqs
846241675Suqs	/*
847241675Suqs	 * Margin control.  Set-head-width lists have their right
848241675Suqs	 * margins shortened.  The body for these lists has the offset
849241675Suqs	 * necessarily lengthened.  Everybody gets the offset.
850241675Suqs	 */
851241675Suqs
852241675Suqs	p->offset += offset;
853241675Suqs
854241675Suqs	switch (type) {
855241675Suqs	case (LIST_hang):
856241675Suqs		/*
857241675Suqs		 * Same stipulation as above, regarding `-hang'.  We
858241675Suqs		 * don't want to recalculate rmargin and offsets when
859241675Suqs		 * using `Bd' or `Bl' within `-hang' overstep lists.
860241675Suqs		 */
861241675Suqs		if (MDOC_HEAD == n->type && n->next->child &&
862241675Suqs				(MDOC_Bl == n->next->child->tok ||
863241675Suqs				 MDOC_Bd == n->next->child->tok))
864241675Suqs			break;
865241675Suqs		/* FALLTHROUGH */
866241675Suqs	case (LIST_bullet):
867241675Suqs		/* FALLTHROUGH */
868241675Suqs	case (LIST_dash):
869241675Suqs		/* FALLTHROUGH */
870241675Suqs	case (LIST_enum):
871241675Suqs		/* FALLTHROUGH */
872241675Suqs	case (LIST_hyphen):
873241675Suqs		/* FALLTHROUGH */
874241675Suqs	case (LIST_tag):
875241675Suqs		assert(width);
876241675Suqs		if (MDOC_HEAD == n->type)
877241675Suqs			p->rmargin = p->offset + width;
878241675Suqs		else
879241675Suqs			p->offset += width;
880241675Suqs		break;
881241675Suqs	case (LIST_column):
882241675Suqs		assert(width);
883241675Suqs		p->rmargin = p->offset + width;
884241675Suqs		/*
885241675Suqs		 * XXX - this behaviour is not documented: the
886241675Suqs		 * right-most column is filled to the right margin.
887241675Suqs		 */
888241675Suqs		if (MDOC_HEAD == n->type)
889241675Suqs			break;
890241675Suqs		if (NULL == n->next && p->rmargin < p->maxrmargin)
891241675Suqs			p->rmargin = p->maxrmargin;
892241675Suqs		break;
893241675Suqs	default:
894241675Suqs		break;
895241675Suqs	}
896241675Suqs
897241675Suqs	/*
898241675Suqs	 * The dash, hyphen, bullet and enum lists all have a special
899241675Suqs	 * HEAD character (temporarily bold, in some cases).
900241675Suqs	 */
901241675Suqs
902241675Suqs	if (MDOC_HEAD == n->type)
903241675Suqs		switch (type) {
904241675Suqs		case (LIST_bullet):
905241675Suqs			term_fontpush(p, TERMFONT_BOLD);
906241675Suqs			term_word(p, "\\[bu]");
907241675Suqs			term_fontpop(p);
908241675Suqs			break;
909241675Suqs		case (LIST_dash):
910241675Suqs			/* FALLTHROUGH */
911241675Suqs		case (LIST_hyphen):
912241675Suqs			term_fontpush(p, TERMFONT_BOLD);
913241675Suqs			term_word(p, "\\(hy");
914241675Suqs			term_fontpop(p);
915241675Suqs			break;
916241675Suqs		case (LIST_enum):
917241675Suqs			(pair->ppair->ppair->count)++;
918241675Suqs			snprintf(buf, sizeof(buf), "%d.",
919241675Suqs					pair->ppair->ppair->count);
920241675Suqs			term_word(p, buf);
921241675Suqs			break;
922241675Suqs		default:
923241675Suqs			break;
924241675Suqs		}
925241675Suqs
926241675Suqs	/*
927241675Suqs	 * If we're not going to process our children, indicate so here.
928241675Suqs	 */
929241675Suqs
930241675Suqs	switch (type) {
931241675Suqs	case (LIST_bullet):
932241675Suqs		/* FALLTHROUGH */
933241675Suqs	case (LIST_item):
934241675Suqs		/* FALLTHROUGH */
935241675Suqs	case (LIST_dash):
936241675Suqs		/* FALLTHROUGH */
937241675Suqs	case (LIST_hyphen):
938241675Suqs		/* FALLTHROUGH */
939241675Suqs	case (LIST_enum):
940241675Suqs		if (MDOC_HEAD == n->type)
941241675Suqs			return(0);
942241675Suqs		break;
943241675Suqs	case (LIST_column):
944241675Suqs		if (MDOC_HEAD == n->type)
945241675Suqs			return(0);
946241675Suqs		break;
947241675Suqs	default:
948241675Suqs		break;
949241675Suqs	}
950241675Suqs
951241675Suqs	return(1);
952241675Suqs}
953241675Suqs
954241675Suqs
955241675Suqs/* ARGSUSED */
956241675Suqsstatic void
957241675Suqstermp_it_post(DECL_ARGS)
958241675Suqs{
959241675Suqs	enum mdoc_list	   type;
960241675Suqs
961241675Suqs	if (MDOC_BLOCK == n->type)
962241675Suqs		return;
963241675Suqs
964241675Suqs	type = n->parent->parent->parent->norm->Bl.type;
965241675Suqs
966241675Suqs	switch (type) {
967241675Suqs	case (LIST_item):
968241675Suqs		/* FALLTHROUGH */
969241675Suqs	case (LIST_diag):
970241675Suqs		/* FALLTHROUGH */
971241675Suqs	case (LIST_inset):
972241675Suqs		if (MDOC_BODY == n->type)
973241675Suqs			term_newln(p);
974241675Suqs		break;
975241675Suqs	case (LIST_column):
976241675Suqs		if (MDOC_BODY == n->type)
977241675Suqs			term_flushln(p);
978241675Suqs		break;
979241675Suqs	default:
980241675Suqs		term_newln(p);
981241675Suqs		break;
982241675Suqs	}
983241675Suqs
984241675Suqs	/*
985241675Suqs	 * Now that our output is flushed, we can reset our tags.  Since
986241675Suqs	 * only `It' sets these flags, we're free to assume that nobody
987241675Suqs	 * has munged them in the meanwhile.
988241675Suqs	 */
989241675Suqs
990241675Suqs	p->flags &= ~TERMP_DANGLE;
991241675Suqs	p->flags &= ~TERMP_NOBREAK;
992241675Suqs	p->flags &= ~TERMP_TWOSPACE;
993241675Suqs	p->flags &= ~TERMP_HANG;
994241675Suqs}
995241675Suqs
996241675Suqs
997241675Suqs/* ARGSUSED */
998241675Suqsstatic int
999241675Suqstermp_nm_pre(DECL_ARGS)
1000241675Suqs{
1001241675Suqs
1002241675Suqs	if (MDOC_BLOCK == n->type)
1003241675Suqs		return(1);
1004241675Suqs
1005241675Suqs	if (MDOC_BODY == n->type) {
1006241675Suqs		if (NULL == n->child)
1007241675Suqs			return(0);
1008241675Suqs		p->flags |= TERMP_NOSPACE;
1009241675Suqs		p->offset += term_len(p, 1) +
1010241675Suqs		    (NULL == n->prev->child ? term_strlen(p, m->name) :
1011241675Suqs		     MDOC_TEXT == n->prev->child->type ?
1012241675Suqs			term_strlen(p, n->prev->child->string) :
1013241675Suqs		     term_len(p, 5));
1014241675Suqs		return(1);
1015241675Suqs	}
1016241675Suqs
1017241675Suqs	if (NULL == n->child && NULL == m->name)
1018241675Suqs		return(0);
1019241675Suqs
1020241675Suqs	if (MDOC_HEAD == n->type)
1021241675Suqs		synopsis_pre(p, n->parent);
1022241675Suqs
1023241675Suqs	if (MDOC_HEAD == n->type && n->next->child) {
1024241675Suqs		p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
1025241675Suqs		p->rmargin = p->offset + term_len(p, 1);
1026241675Suqs		if (NULL == n->child) {
1027241675Suqs			p->rmargin += term_strlen(p, m->name);
1028241675Suqs		} else if (MDOC_TEXT == n->child->type) {
1029241675Suqs			p->rmargin += term_strlen(p, n->child->string);
1030241675Suqs			if (n->child->next)
1031241675Suqs				p->flags |= TERMP_HANG;
1032241675Suqs		} else {
1033241675Suqs			p->rmargin += term_len(p, 5);
1034241675Suqs			p->flags |= TERMP_HANG;
1035241675Suqs		}
1036241675Suqs	}
1037241675Suqs
1038241675Suqs	term_fontpush(p, TERMFONT_BOLD);
1039241675Suqs	if (NULL == n->child)
1040241675Suqs		term_word(p, m->name);
1041241675Suqs	return(1);
1042241675Suqs}
1043241675Suqs
1044241675Suqs
1045241675Suqs/* ARGSUSED */
1046241675Suqsstatic void
1047241675Suqstermp_nm_post(DECL_ARGS)
1048241675Suqs{
1049241675Suqs
1050241675Suqs	if (MDOC_HEAD == n->type && n->next->child) {
1051241675Suqs		term_flushln(p);
1052241675Suqs		p->flags &= ~(TERMP_NOBREAK | TERMP_HANG);
1053241675Suqs	} else if (MDOC_BODY == n->type && n->child)
1054241675Suqs		term_flushln(p);
1055241675Suqs}
1056241675Suqs
1057241675Suqs
1058241675Suqs/* ARGSUSED */
1059241675Suqsstatic int
1060241675Suqstermp_fl_pre(DECL_ARGS)
1061241675Suqs{
1062241675Suqs
1063241675Suqs	term_fontpush(p, TERMFONT_BOLD);
1064241675Suqs	term_word(p, "\\-");
1065241675Suqs
1066241675Suqs	if (n->child)
1067241675Suqs		p->flags |= TERMP_NOSPACE;
1068241675Suqs	else if (n->next && n->next->line == n->line)
1069241675Suqs		p->flags |= TERMP_NOSPACE;
1070241675Suqs
1071241675Suqs	return(1);
1072241675Suqs}
1073241675Suqs
1074241675Suqs
1075241675Suqs/* ARGSUSED */
1076241675Suqsstatic int
1077241675Suqstermp__a_pre(DECL_ARGS)
1078241675Suqs{
1079241675Suqs
1080241675Suqs	if (n->prev && MDOC__A == n->prev->tok)
1081241675Suqs		if (NULL == n->next || MDOC__A != n->next->tok)
1082241675Suqs			term_word(p, "and");
1083241675Suqs
1084241675Suqs	return(1);
1085241675Suqs}
1086241675Suqs
1087241675Suqs
1088241675Suqs/* ARGSUSED */
1089241675Suqsstatic int
1090241675Suqstermp_an_pre(DECL_ARGS)
1091241675Suqs{
1092241675Suqs
1093241675Suqs	if (NULL == n->child)
1094241675Suqs		return(1);
1095241675Suqs
1096241675Suqs	/*
1097241675Suqs	 * If not in the AUTHORS section, `An -split' will cause
1098241675Suqs	 * newlines to occur before the author name.  If in the AUTHORS
1099241675Suqs	 * section, by default, the first `An' invocation is nosplit,
1100241675Suqs	 * then all subsequent ones, regardless of whether interspersed
1101241675Suqs	 * with other macros/text, are split.  -split, in this case,
1102241675Suqs	 * will override the condition of the implied first -nosplit.
1103241675Suqs	 */
1104241675Suqs
1105241675Suqs	if (n->sec == SEC_AUTHORS) {
1106241675Suqs		if ( ! (TERMP_ANPREC & p->flags)) {
1107241675Suqs			if (TERMP_SPLIT & p->flags)
1108241675Suqs				term_newln(p);
1109241675Suqs			return(1);
1110241675Suqs		}
1111241675Suqs		if (TERMP_NOSPLIT & p->flags)
1112241675Suqs			return(1);
1113241675Suqs		term_newln(p);
1114241675Suqs		return(1);
1115241675Suqs	}
1116241675Suqs
1117241675Suqs	if (TERMP_SPLIT & p->flags)
1118241675Suqs		term_newln(p);
1119241675Suqs
1120241675Suqs	return(1);
1121241675Suqs}
1122241675Suqs
1123241675Suqs
1124241675Suqs/* ARGSUSED */
1125241675Suqsstatic void
1126241675Suqstermp_an_post(DECL_ARGS)
1127241675Suqs{
1128241675Suqs
1129241675Suqs	if (n->child) {
1130241675Suqs		if (SEC_AUTHORS == n->sec)
1131241675Suqs			p->flags |= TERMP_ANPREC;
1132241675Suqs		return;
1133241675Suqs	}
1134241675Suqs
1135241675Suqs	if (AUTH_split == n->norm->An.auth) {
1136241675Suqs		p->flags &= ~TERMP_NOSPLIT;
1137241675Suqs		p->flags |= TERMP_SPLIT;
1138241675Suqs	} else if (AUTH_nosplit == n->norm->An.auth) {
1139241675Suqs		p->flags &= ~TERMP_SPLIT;
1140241675Suqs		p->flags |= TERMP_NOSPLIT;
1141241675Suqs	}
1142241675Suqs
1143241675Suqs}
1144241675Suqs
1145241675Suqs
1146241675Suqs/* ARGSUSED */
1147241675Suqsstatic int
1148241675Suqstermp_ns_pre(DECL_ARGS)
1149241675Suqs{
1150241675Suqs
1151241675Suqs	if ( ! (MDOC_LINE & n->flags))
1152241675Suqs		p->flags |= TERMP_NOSPACE;
1153241675Suqs	return(1);
1154241675Suqs}
1155241675Suqs
1156241675Suqs
1157241675Suqs/* ARGSUSED */
1158241675Suqsstatic int
1159241675Suqstermp_rs_pre(DECL_ARGS)
1160241675Suqs{
1161241675Suqs
1162241675Suqs	if (SEC_SEE_ALSO != n->sec)
1163241675Suqs		return(1);
1164241675Suqs	if (MDOC_BLOCK == n->type && n->prev)
1165241675Suqs		term_vspace(p);
1166241675Suqs	return(1);
1167241675Suqs}
1168241675Suqs
1169241675Suqs
1170241675Suqs/* ARGSUSED */
1171241675Suqsstatic int
1172241675Suqstermp_rv_pre(DECL_ARGS)
1173241675Suqs{
1174241675Suqs	int		 nchild;
1175241675Suqs
1176241675Suqs	term_newln(p);
1177241675Suqs	term_word(p, "The");
1178241675Suqs
1179241675Suqs	nchild = n->nchild;
1180241675Suqs	for (n = n->child; n; n = n->next) {
1181241675Suqs		term_fontpush(p, TERMFONT_BOLD);
1182241675Suqs		term_word(p, n->string);
1183241675Suqs		term_fontpop(p);
1184241675Suqs
1185241675Suqs		p->flags |= TERMP_NOSPACE;
1186241675Suqs		term_word(p, "()");
1187241675Suqs
1188241675Suqs		if (nchild > 2 && n->next) {
1189241675Suqs			p->flags |= TERMP_NOSPACE;
1190241675Suqs			term_word(p, ",");
1191241675Suqs		}
1192241675Suqs
1193241675Suqs		if (n->next && NULL == n->next->next)
1194241675Suqs			term_word(p, "and");
1195241675Suqs	}
1196241675Suqs
1197241675Suqs	if (nchild > 1)
1198241675Suqs		term_word(p, "functions return");
1199241675Suqs	else
1200241675Suqs		term_word(p, "function returns");
1201241675Suqs
1202241675Suqs       	term_word(p, "the value 0 if successful; otherwise the value "
1203241675Suqs			"-1 is returned and the global variable");
1204241675Suqs
1205241675Suqs	term_fontpush(p, TERMFONT_UNDER);
1206241675Suqs	term_word(p, "errno");
1207241675Suqs	term_fontpop(p);
1208241675Suqs
1209241675Suqs       	term_word(p, "is set to indicate the error.");
1210241675Suqs	p->flags |= TERMP_SENTENCE;
1211241675Suqs
1212241675Suqs	return(0);
1213241675Suqs}
1214241675Suqs
1215241675Suqs
1216241675Suqs/* ARGSUSED */
1217241675Suqsstatic int
1218241675Suqstermp_ex_pre(DECL_ARGS)
1219241675Suqs{
1220241675Suqs	int		 nchild;
1221241675Suqs
1222241675Suqs	term_newln(p);
1223241675Suqs	term_word(p, "The");
1224241675Suqs
1225241675Suqs	nchild = n->nchild;
1226241675Suqs	for (n = n->child; n; n = n->next) {
1227241675Suqs		term_fontpush(p, TERMFONT_BOLD);
1228241675Suqs		term_word(p, n->string);
1229241675Suqs		term_fontpop(p);
1230241675Suqs
1231241675Suqs		if (nchild > 2 && n->next) {
1232241675Suqs			p->flags |= TERMP_NOSPACE;
1233241675Suqs			term_word(p, ",");
1234241675Suqs		}
1235241675Suqs
1236241675Suqs		if (n->next && NULL == n->next->next)
1237241675Suqs			term_word(p, "and");
1238241675Suqs	}
1239241675Suqs
1240241675Suqs	if (nchild > 1)
1241241675Suqs		term_word(p, "utilities exit");
1242241675Suqs	else
1243241675Suqs		term_word(p, "utility exits");
1244241675Suqs
1245241675Suqs       	term_word(p, "0 on success, and >0 if an error occurs.");
1246241675Suqs
1247241675Suqs	p->flags |= TERMP_SENTENCE;
1248241675Suqs	return(0);
1249241675Suqs}
1250241675Suqs
1251241675Suqs
1252241675Suqs/* ARGSUSED */
1253241675Suqsstatic int
1254241675Suqstermp_nd_pre(DECL_ARGS)
1255241675Suqs{
1256241675Suqs
1257241675Suqs	if (MDOC_BODY != n->type)
1258241675Suqs		return(1);
1259241675Suqs
1260241675Suqs#if defined(__OpenBSD__) || defined(__linux__)
1261241675Suqs	term_word(p, "\\(en");
1262241675Suqs#else
1263241675Suqs	term_word(p, "\\(em");
1264241675Suqs#endif
1265241675Suqs	return(1);
1266241675Suqs}
1267241675Suqs
1268241675Suqs
1269241675Suqs/* ARGSUSED */
1270241675Suqsstatic int
1271241675Suqstermp_bl_pre(DECL_ARGS)
1272241675Suqs{
1273241675Suqs
1274241675Suqs	return(MDOC_HEAD != n->type);
1275241675Suqs}
1276241675Suqs
1277241675Suqs
1278241675Suqs/* ARGSUSED */
1279241675Suqsstatic void
1280241675Suqstermp_bl_post(DECL_ARGS)
1281241675Suqs{
1282241675Suqs
1283241675Suqs	if (MDOC_BLOCK == n->type)
1284241675Suqs		term_newln(p);
1285241675Suqs}
1286241675Suqs
1287241675Suqs/* ARGSUSED */
1288241675Suqsstatic int
1289241675Suqstermp_xr_pre(DECL_ARGS)
1290241675Suqs{
1291241675Suqs
1292241675Suqs	if (NULL == (n = n->child))
1293241675Suqs		return(0);
1294241675Suqs
1295241675Suqs	assert(MDOC_TEXT == n->type);
1296241675Suqs	term_word(p, n->string);
1297241675Suqs
1298241675Suqs	if (NULL == (n = n->next))
1299241675Suqs		return(0);
1300241675Suqs
1301241675Suqs	p->flags |= TERMP_NOSPACE;
1302241675Suqs	term_word(p, "(");
1303241675Suqs	p->flags |= TERMP_NOSPACE;
1304241675Suqs
1305241675Suqs	assert(MDOC_TEXT == n->type);
1306241675Suqs	term_word(p, n->string);
1307241675Suqs
1308241675Suqs	p->flags |= TERMP_NOSPACE;
1309241675Suqs	term_word(p, ")");
1310241675Suqs
1311241675Suqs	return(0);
1312241675Suqs}
1313241675Suqs
1314241675Suqs/*
1315241675Suqs * This decides how to assert whitespace before any of the SYNOPSIS set
1316241675Suqs * of macros (which, as in the case of Ft/Fo and Ft/Fn, may contain
1317241675Suqs * macro combos).
1318241675Suqs */
1319241675Suqsstatic void
1320241675Suqssynopsis_pre(struct termp *p, const struct mdoc_node *n)
1321241675Suqs{
1322241675Suqs	/*
1323241675Suqs	 * Obviously, if we're not in a SYNOPSIS or no prior macros
1324241675Suqs	 * exist, do nothing.
1325241675Suqs	 */
1326241675Suqs	if (NULL == n->prev || ! (MDOC_SYNPRETTY & n->flags))
1327241675Suqs		return;
1328241675Suqs
1329241675Suqs	/*
1330241675Suqs	 * If we're the second in a pair of like elements, emit our
1331241675Suqs	 * newline and return.  UNLESS we're `Fo', `Fn', `Fn', in which
1332241675Suqs	 * case we soldier on.
1333241675Suqs	 */
1334241675Suqs	if (n->prev->tok == n->tok &&
1335241675Suqs			MDOC_Ft != n->tok &&
1336241675Suqs			MDOC_Fo != n->tok &&
1337241675Suqs			MDOC_Fn != n->tok) {
1338241675Suqs		term_newln(p);
1339241675Suqs		return;
1340241675Suqs	}
1341241675Suqs
1342241675Suqs	/*
1343241675Suqs	 * If we're one of the SYNOPSIS set and non-like pair-wise after
1344241675Suqs	 * another (or Fn/Fo, which we've let slip through) then assert
1345241675Suqs	 * vertical space, else only newline and move on.
1346241675Suqs	 */
1347241675Suqs	switch (n->prev->tok) {
1348241675Suqs	case (MDOC_Fd):
1349241675Suqs		/* FALLTHROUGH */
1350241675Suqs	case (MDOC_Fn):
1351241675Suqs		/* FALLTHROUGH */
1352241675Suqs	case (MDOC_Fo):
1353241675Suqs		/* FALLTHROUGH */
1354241675Suqs	case (MDOC_In):
1355241675Suqs		/* FALLTHROUGH */
1356241675Suqs	case (MDOC_Vt):
1357241675Suqs		term_vspace(p);
1358241675Suqs		break;
1359241675Suqs	case (MDOC_Ft):
1360241675Suqs		if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
1361241675Suqs			term_vspace(p);
1362241675Suqs			break;
1363241675Suqs		}
1364241675Suqs		/* FALLTHROUGH */
1365241675Suqs	default:
1366241675Suqs		term_newln(p);
1367241675Suqs		break;
1368241675Suqs	}
1369241675Suqs}
1370241675Suqs
1371241675Suqs
1372241675Suqsstatic int
1373241675Suqstermp_vt_pre(DECL_ARGS)
1374241675Suqs{
1375241675Suqs
1376241675Suqs	if (MDOC_ELEM == n->type) {
1377241675Suqs		synopsis_pre(p, n);
1378241675Suqs		return(termp_under_pre(p, pair, m, n));
1379241675Suqs	} else if (MDOC_BLOCK == n->type) {
1380241675Suqs		synopsis_pre(p, n);
1381241675Suqs		return(1);
1382241675Suqs	} else if (MDOC_HEAD == n->type)
1383241675Suqs		return(0);
1384241675Suqs
1385241675Suqs	return(termp_under_pre(p, pair, m, n));
1386241675Suqs}
1387241675Suqs
1388241675Suqs
1389241675Suqs/* ARGSUSED */
1390241675Suqsstatic int
1391241675Suqstermp_bold_pre(DECL_ARGS)
1392241675Suqs{
1393241675Suqs
1394241675Suqs	term_fontpush(p, TERMFONT_BOLD);
1395241675Suqs	return(1);
1396241675Suqs}
1397241675Suqs
1398241675Suqs
1399241675Suqs/* ARGSUSED */
1400241675Suqsstatic int
1401241675Suqstermp_fd_pre(DECL_ARGS)
1402241675Suqs{
1403241675Suqs
1404241675Suqs	synopsis_pre(p, n);
1405241675Suqs	return(termp_bold_pre(p, pair, m, n));
1406241675Suqs}
1407241675Suqs
1408241675Suqs
1409241675Suqs/* ARGSUSED */
1410241675Suqsstatic int
1411241675Suqstermp_sh_pre(DECL_ARGS)
1412241675Suqs{
1413241675Suqs
1414241675Suqs	/* No vspace between consecutive `Sh' calls. */
1415241675Suqs
1416241675Suqs	switch (n->type) {
1417241675Suqs	case (MDOC_BLOCK):
1418241675Suqs		if (n->prev && MDOC_Sh == n->prev->tok)
1419241675Suqs			if (NULL == n->prev->body->child)
1420241675Suqs				break;
1421241675Suqs		term_vspace(p);
1422241675Suqs		break;
1423241675Suqs	case (MDOC_HEAD):
1424241675Suqs		term_fontpush(p, TERMFONT_BOLD);
1425241675Suqs		break;
1426241675Suqs	case (MDOC_BODY):
1427241675Suqs		p->offset = term_len(p, p->defindent);
1428241675Suqs		break;
1429241675Suqs	default:
1430241675Suqs		break;
1431241675Suqs	}
1432241675Suqs	return(1);
1433241675Suqs}
1434241675Suqs
1435241675Suqs
1436241675Suqs/* ARGSUSED */
1437241675Suqsstatic void
1438241675Suqstermp_sh_post(DECL_ARGS)
1439241675Suqs{
1440241675Suqs
1441241675Suqs	switch (n->type) {
1442241675Suqs	case (MDOC_HEAD):
1443241675Suqs		term_newln(p);
1444241675Suqs		break;
1445241675Suqs	case (MDOC_BODY):
1446241675Suqs		term_newln(p);
1447241675Suqs		p->offset = 0;
1448241675Suqs		break;
1449241675Suqs	default:
1450241675Suqs		break;
1451241675Suqs	}
1452241675Suqs}
1453241675Suqs
1454241675Suqs
1455241675Suqs/* ARGSUSED */
1456241675Suqsstatic int
1457241675Suqstermp_bt_pre(DECL_ARGS)
1458241675Suqs{
1459241675Suqs
1460241675Suqs	term_word(p, "is currently in beta test.");
1461241675Suqs	p->flags |= TERMP_SENTENCE;
1462241675Suqs	return(0);
1463241675Suqs}
1464241675Suqs
1465241675Suqs
1466241675Suqs/* ARGSUSED */
1467241675Suqsstatic void
1468241675Suqstermp_lb_post(DECL_ARGS)
1469241675Suqs{
1470241675Suqs
1471241675Suqs	if (SEC_LIBRARY == n->sec && MDOC_LINE & n->flags)
1472241675Suqs		term_newln(p);
1473241675Suqs}
1474241675Suqs
1475241675Suqs
1476241675Suqs/* ARGSUSED */
1477241675Suqsstatic int
1478241675Suqstermp_ud_pre(DECL_ARGS)
1479241675Suqs{
1480241675Suqs
1481241675Suqs	term_word(p, "currently under development.");
1482241675Suqs	p->flags |= TERMP_SENTENCE;
1483241675Suqs	return(0);
1484241675Suqs}
1485241675Suqs
1486241675Suqs
1487241675Suqs/* ARGSUSED */
1488241675Suqsstatic int
1489241675Suqstermp_d1_pre(DECL_ARGS)
1490241675Suqs{
1491241675Suqs
1492241675Suqs	if (MDOC_BLOCK != n->type)
1493241675Suqs		return(1);
1494241675Suqs	term_newln(p);
1495241675Suqs	p->offset += term_len(p, p->defindent + 1);
1496241675Suqs	return(1);
1497241675Suqs}
1498241675Suqs
1499241675Suqs
1500241675Suqs/* ARGSUSED */
1501241675Suqsstatic void
1502241675Suqstermp_d1_post(DECL_ARGS)
1503241675Suqs{
1504241675Suqs
1505241675Suqs	if (MDOC_BLOCK != n->type)
1506241675Suqs		return;
1507241675Suqs	term_newln(p);
1508241675Suqs}
1509241675Suqs
1510241675Suqs
1511241675Suqs/* ARGSUSED */
1512241675Suqsstatic int
1513241675Suqstermp_ft_pre(DECL_ARGS)
1514241675Suqs{
1515241675Suqs
1516241675Suqs	/* NB: MDOC_LINE does not effect this! */
1517241675Suqs	synopsis_pre(p, n);
1518241675Suqs	term_fontpush(p, TERMFONT_UNDER);
1519241675Suqs	return(1);
1520241675Suqs}
1521241675Suqs
1522241675Suqs
1523241675Suqs/* ARGSUSED */
1524241675Suqsstatic int
1525241675Suqstermp_fn_pre(DECL_ARGS)
1526241675Suqs{
1527241675Suqs	int		 pretty;
1528241675Suqs
1529241675Suqs	pretty = MDOC_SYNPRETTY & n->flags;
1530241675Suqs
1531241675Suqs	synopsis_pre(p, n);
1532241675Suqs
1533241675Suqs	if (NULL == (n = n->child))
1534241675Suqs		return(0);
1535241675Suqs
1536241675Suqs	assert(MDOC_TEXT == n->type);
1537241675Suqs	term_fontpush(p, TERMFONT_BOLD);
1538241675Suqs	term_word(p, n->string);
1539241675Suqs	term_fontpop(p);
1540241675Suqs
1541241675Suqs	p->flags |= TERMP_NOSPACE;
1542241675Suqs	term_word(p, "(");
1543241675Suqs	p->flags |= TERMP_NOSPACE;
1544241675Suqs
1545241675Suqs	for (n = n->next; n; n = n->next) {
1546241675Suqs		assert(MDOC_TEXT == n->type);
1547241675Suqs		term_fontpush(p, TERMFONT_UNDER);
1548241675Suqs		term_word(p, n->string);
1549241675Suqs		term_fontpop(p);
1550241675Suqs
1551241675Suqs		if (n->next) {
1552241675Suqs			p->flags |= TERMP_NOSPACE;
1553241675Suqs			term_word(p, ",");
1554241675Suqs		}
1555241675Suqs	}
1556241675Suqs
1557241675Suqs	p->flags |= TERMP_NOSPACE;
1558241675Suqs	term_word(p, ")");
1559241675Suqs
1560241675Suqs	if (pretty) {
1561241675Suqs		p->flags |= TERMP_NOSPACE;
1562241675Suqs		term_word(p, ";");
1563241675Suqs	}
1564241675Suqs
1565241675Suqs	return(0);
1566241675Suqs}
1567241675Suqs
1568241675Suqs
1569241675Suqs/* ARGSUSED */
1570241675Suqsstatic int
1571241675Suqstermp_fa_pre(DECL_ARGS)
1572241675Suqs{
1573241675Suqs	const struct mdoc_node	*nn;
1574241675Suqs
1575241675Suqs	if (n->parent->tok != MDOC_Fo) {
1576241675Suqs		term_fontpush(p, TERMFONT_UNDER);
1577241675Suqs		return(1);
1578241675Suqs	}
1579241675Suqs
1580241675Suqs	for (nn = n->child; nn; nn = nn->next) {
1581241675Suqs		term_fontpush(p, TERMFONT_UNDER);
1582241675Suqs		term_word(p, nn->string);
1583241675Suqs		term_fontpop(p);
1584241675Suqs
1585241675Suqs		if (nn->next) {
1586241675Suqs			p->flags |= TERMP_NOSPACE;
1587241675Suqs			term_word(p, ",");
1588241675Suqs		}
1589241675Suqs	}
1590241675Suqs
1591241675Suqs	if (n->child && n->next && n->next->tok == MDOC_Fa) {
1592241675Suqs		p->flags |= TERMP_NOSPACE;
1593241675Suqs		term_word(p, ",");
1594241675Suqs	}
1595241675Suqs
1596241675Suqs	return(0);
1597241675Suqs}
1598241675Suqs
1599241675Suqs
1600241675Suqs/* ARGSUSED */
1601241675Suqsstatic int
1602241675Suqstermp_bd_pre(DECL_ARGS)
1603241675Suqs{
1604241675Suqs	size_t			 tabwidth, rm, rmax;
1605241675Suqs	const struct mdoc_node	*nn;
1606241675Suqs
1607241675Suqs	if (MDOC_BLOCK == n->type) {
1608241675Suqs		print_bvspace(p, n, n);
1609241675Suqs		return(1);
1610241675Suqs	} else if (MDOC_HEAD == n->type)
1611241675Suqs		return(0);
1612241675Suqs
1613241675Suqs	if (n->norm->Bd.offs)
1614241675Suqs		p->offset += a2offs(p, n->norm->Bd.offs);
1615241675Suqs
1616241675Suqs	/*
1617241675Suqs	 * If -ragged or -filled are specified, the block does nothing
1618241675Suqs	 * but change the indentation.  If -unfilled or -literal are
1619241675Suqs	 * specified, text is printed exactly as entered in the display:
1620241675Suqs	 * for macro lines, a newline is appended to the line.  Blank
1621241675Suqs	 * lines are allowed.
1622241675Suqs	 */
1623241675Suqs
1624241675Suqs	if (DISP_literal != n->norm->Bd.type &&
1625241675Suqs			DISP_unfilled != n->norm->Bd.type)
1626241675Suqs		return(1);
1627241675Suqs
1628241675Suqs	tabwidth = p->tabwidth;
1629241675Suqs	if (DISP_literal == n->norm->Bd.type)
1630241675Suqs		p->tabwidth = term_len(p, 8);
1631241675Suqs
1632241675Suqs	rm = p->rmargin;
1633241675Suqs	rmax = p->maxrmargin;
1634241675Suqs	p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
1635241675Suqs
1636241675Suqs	for (nn = n->child; nn; nn = nn->next) {
1637241675Suqs		print_mdoc_node(p, pair, m, nn);
1638241675Suqs		/*
1639241675Suqs		 * If the printed node flushes its own line, then we
1640241675Suqs		 * needn't do it here as well.  This is hacky, but the
1641241675Suqs		 * notion of selective eoln whitespace is pretty dumb
1642241675Suqs		 * anyway, so don't sweat it.
1643241675Suqs		 */
1644241675Suqs		switch (nn->tok) {
1645241675Suqs		case (MDOC_Sm):
1646241675Suqs			/* FALLTHROUGH */
1647241675Suqs		case (MDOC_br):
1648241675Suqs			/* FALLTHROUGH */
1649241675Suqs		case (MDOC_sp):
1650241675Suqs			/* FALLTHROUGH */
1651241675Suqs		case (MDOC_Bl):
1652241675Suqs			/* FALLTHROUGH */
1653241675Suqs		case (MDOC_D1):
1654241675Suqs			/* FALLTHROUGH */
1655241675Suqs		case (MDOC_Dl):
1656241675Suqs			/* FALLTHROUGH */
1657241675Suqs		case (MDOC_Lp):
1658241675Suqs			/* FALLTHROUGH */
1659241675Suqs		case (MDOC_Pp):
1660241675Suqs			continue;
1661241675Suqs		default:
1662241675Suqs			break;
1663241675Suqs		}
1664241675Suqs		if (nn->next && nn->next->line == nn->line)
1665241675Suqs			continue;
1666241675Suqs		term_flushln(p);
1667241675Suqs		p->flags |= TERMP_NOSPACE;
1668241675Suqs	}
1669241675Suqs
1670241675Suqs	p->tabwidth = tabwidth;
1671241675Suqs	p->rmargin = rm;
1672241675Suqs	p->maxrmargin = rmax;
1673241675Suqs	return(0);
1674241675Suqs}
1675241675Suqs
1676241675Suqs
1677241675Suqs/* ARGSUSED */
1678241675Suqsstatic void
1679241675Suqstermp_bd_post(DECL_ARGS)
1680241675Suqs{
1681241675Suqs	size_t		 rm, rmax;
1682241675Suqs
1683241675Suqs	if (MDOC_BODY != n->type)
1684241675Suqs		return;
1685241675Suqs
1686241675Suqs	rm = p->rmargin;
1687241675Suqs	rmax = p->maxrmargin;
1688241675Suqs
1689241675Suqs	if (DISP_literal == n->norm->Bd.type ||
1690241675Suqs			DISP_unfilled == n->norm->Bd.type)
1691241675Suqs		p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
1692241675Suqs
1693241675Suqs	p->flags |= TERMP_NOSPACE;
1694241675Suqs	term_newln(p);
1695241675Suqs
1696241675Suqs	p->rmargin = rm;
1697241675Suqs	p->maxrmargin = rmax;
1698241675Suqs}
1699241675Suqs
1700241675Suqs
1701241675Suqs/* ARGSUSED */
1702241675Suqsstatic int
1703241675Suqstermp_bx_pre(DECL_ARGS)
1704241675Suqs{
1705241675Suqs
1706241675Suqs	if (NULL != (n = n->child)) {
1707241675Suqs		term_word(p, n->string);
1708241675Suqs		p->flags |= TERMP_NOSPACE;
1709241675Suqs		term_word(p, "BSD");
1710241675Suqs	} else {
1711241675Suqs		term_word(p, "BSD");
1712241675Suqs		return(0);
1713241675Suqs	}
1714241675Suqs
1715241675Suqs	if (NULL != (n = n->next)) {
1716241675Suqs		p->flags |= TERMP_NOSPACE;
1717241675Suqs		term_word(p, "-");
1718241675Suqs		p->flags |= TERMP_NOSPACE;
1719241675Suqs		term_word(p, n->string);
1720241675Suqs	}
1721241675Suqs
1722241675Suqs	return(0);
1723241675Suqs}
1724241675Suqs
1725241675Suqs
1726241675Suqs/* ARGSUSED */
1727241675Suqsstatic int
1728241675Suqstermp_xx_pre(DECL_ARGS)
1729241675Suqs{
1730241675Suqs	const char	*pp;
1731241675Suqs	int		 flags;
1732241675Suqs
1733241675Suqs	pp = NULL;
1734241675Suqs	switch (n->tok) {
1735241675Suqs	case (MDOC_Bsx):
1736241675Suqs		pp = "BSD/OS";
1737241675Suqs		break;
1738241675Suqs	case (MDOC_Dx):
1739241675Suqs		pp = "DragonFly";
1740241675Suqs		break;
1741241675Suqs	case (MDOC_Fx):
1742241675Suqs		pp = "FreeBSD";
1743241675Suqs		break;
1744241675Suqs	case (MDOC_Nx):
1745241675Suqs		pp = "NetBSD";
1746241675Suqs		break;
1747241675Suqs	case (MDOC_Ox):
1748241675Suqs		pp = "OpenBSD";
1749241675Suqs		break;
1750241675Suqs	case (MDOC_Ux):
1751241675Suqs		pp = "UNIX";
1752241675Suqs		break;
1753241675Suqs	default:
1754241675Suqs		break;
1755241675Suqs	}
1756241675Suqs
1757241675Suqs	term_word(p, pp);
1758241675Suqs	if (n->child) {
1759241675Suqs		flags = p->flags;
1760241675Suqs		p->flags |= TERMP_KEEP;
1761241675Suqs		term_word(p, n->child->string);
1762241675Suqs		p->flags = flags;
1763241675Suqs	}
1764241675Suqs	return(0);
1765241675Suqs}
1766241675Suqs
1767241675Suqs
1768241675Suqs/* ARGSUSED */
1769241675Suqsstatic int
1770241675Suqstermp_igndelim_pre(DECL_ARGS)
1771241675Suqs{
1772241675Suqs
1773241675Suqs	p->flags |= TERMP_IGNDELIM;
1774241675Suqs	return(1);
1775241675Suqs}
1776241675Suqs
1777241675Suqs
1778241675Suqs/* ARGSUSED */
1779241675Suqsstatic void
1780241675Suqstermp_pf_post(DECL_ARGS)
1781241675Suqs{
1782241675Suqs
1783241675Suqs	p->flags |= TERMP_NOSPACE;
1784241675Suqs}
1785241675Suqs
1786241675Suqs
1787241675Suqs/* ARGSUSED */
1788241675Suqsstatic int
1789241675Suqstermp_ss_pre(DECL_ARGS)
1790241675Suqs{
1791241675Suqs
1792241675Suqs	switch (n->type) {
1793241675Suqs	case (MDOC_BLOCK):
1794241675Suqs		term_newln(p);
1795241675Suqs		if (n->prev)
1796241675Suqs			term_vspace(p);
1797241675Suqs		break;
1798241675Suqs	case (MDOC_HEAD):
1799241675Suqs		term_fontpush(p, TERMFONT_BOLD);
1800241675Suqs		p->offset = term_len(p, (p->defindent+1)/2);
1801241675Suqs		break;
1802241675Suqs	default:
1803241675Suqs		break;
1804241675Suqs	}
1805241675Suqs
1806241675Suqs	return(1);
1807241675Suqs}
1808241675Suqs
1809241675Suqs
1810241675Suqs/* ARGSUSED */
1811241675Suqsstatic void
1812241675Suqstermp_ss_post(DECL_ARGS)
1813241675Suqs{
1814241675Suqs
1815241675Suqs	if (MDOC_HEAD == n->type)
1816241675Suqs		term_newln(p);
1817241675Suqs}
1818241675Suqs
1819241675Suqs
1820241675Suqs/* ARGSUSED */
1821241675Suqsstatic int
1822241675Suqstermp_cd_pre(DECL_ARGS)
1823241675Suqs{
1824241675Suqs
1825241675Suqs	synopsis_pre(p, n);
1826241675Suqs	term_fontpush(p, TERMFONT_BOLD);
1827241675Suqs	return(1);
1828241675Suqs}
1829241675Suqs
1830241675Suqs
1831241675Suqs/* ARGSUSED */
1832241675Suqsstatic int
1833241675Suqstermp_in_pre(DECL_ARGS)
1834241675Suqs{
1835241675Suqs
1836241675Suqs	synopsis_pre(p, n);
1837241675Suqs
1838241675Suqs	if (MDOC_SYNPRETTY & n->flags && MDOC_LINE & n->flags) {
1839241675Suqs		term_fontpush(p, TERMFONT_BOLD);
1840241675Suqs		term_word(p, "#include");
1841241675Suqs		term_word(p, "<");
1842241675Suqs	} else {
1843241675Suqs		term_word(p, "<");
1844241675Suqs		term_fontpush(p, TERMFONT_UNDER);
1845241675Suqs	}
1846241675Suqs
1847241675Suqs	p->flags |= TERMP_NOSPACE;
1848241675Suqs	return(1);
1849241675Suqs}
1850241675Suqs
1851241675Suqs
1852241675Suqs/* ARGSUSED */
1853241675Suqsstatic void
1854241675Suqstermp_in_post(DECL_ARGS)
1855241675Suqs{
1856241675Suqs
1857241675Suqs	if (MDOC_SYNPRETTY & n->flags)
1858241675Suqs		term_fontpush(p, TERMFONT_BOLD);
1859241675Suqs
1860241675Suqs	p->flags |= TERMP_NOSPACE;
1861241675Suqs	term_word(p, ">");
1862241675Suqs
1863241675Suqs	if (MDOC_SYNPRETTY & n->flags)
1864241675Suqs		term_fontpop(p);
1865241675Suqs}
1866241675Suqs
1867241675Suqs
1868241675Suqs/* ARGSUSED */
1869241675Suqsstatic int
1870241675Suqstermp_sp_pre(DECL_ARGS)
1871241675Suqs{
1872241675Suqs	size_t		 i, len;
1873241675Suqs
1874241675Suqs	switch (n->tok) {
1875241675Suqs	case (MDOC_sp):
1876241675Suqs		len = n->child ? a2height(p, n->child->string) : 1;
1877241675Suqs		break;
1878241675Suqs	case (MDOC_br):
1879241675Suqs		len = 0;
1880241675Suqs		break;
1881241675Suqs	default:
1882241675Suqs		len = 1;
1883241675Suqs		break;
1884241675Suqs	}
1885241675Suqs
1886241675Suqs	if (0 == len)
1887241675Suqs		term_newln(p);
1888241675Suqs	for (i = 0; i < len; i++)
1889241675Suqs		term_vspace(p);
1890241675Suqs
1891241675Suqs	return(0);
1892241675Suqs}
1893241675Suqs
1894241675Suqs
1895241675Suqs/* ARGSUSED */
1896241675Suqsstatic int
1897241675Suqstermp_quote_pre(DECL_ARGS)
1898241675Suqs{
1899241675Suqs
1900241675Suqs	if (MDOC_BODY != n->type && MDOC_ELEM != n->type)
1901241675Suqs		return(1);
1902241675Suqs
1903241675Suqs	switch (n->tok) {
1904241675Suqs	case (MDOC_Ao):
1905241675Suqs		/* FALLTHROUGH */
1906241675Suqs	case (MDOC_Aq):
1907241675Suqs		term_word(p, "<");
1908241675Suqs		break;
1909241675Suqs	case (MDOC_Bro):
1910241675Suqs		/* FALLTHROUGH */
1911241675Suqs	case (MDOC_Brq):
1912241675Suqs		term_word(p, "{");
1913241675Suqs		break;
1914241675Suqs	case (MDOC_Oo):
1915241675Suqs		/* FALLTHROUGH */
1916241675Suqs	case (MDOC_Op):
1917241675Suqs		/* FALLTHROUGH */
1918241675Suqs	case (MDOC_Bo):
1919241675Suqs		/* FALLTHROUGH */
1920241675Suqs	case (MDOC_Bq):
1921241675Suqs		term_word(p, "[");
1922241675Suqs		break;
1923241675Suqs	case (MDOC_Do):
1924241675Suqs		/* FALLTHROUGH */
1925241675Suqs	case (MDOC_Dq):
1926241675Suqs		term_word(p, "``");
1927241675Suqs		break;
1928241675Suqs	case (MDOC_Eo):
1929241675Suqs		break;
1930241675Suqs	case (MDOC_Po):
1931241675Suqs		/* FALLTHROUGH */
1932241675Suqs	case (MDOC_Pq):
1933241675Suqs		term_word(p, "(");
1934241675Suqs		break;
1935241675Suqs	case (MDOC__T):
1936241675Suqs		/* FALLTHROUGH */
1937241675Suqs	case (MDOC_Qo):
1938241675Suqs		/* FALLTHROUGH */
1939241675Suqs	case (MDOC_Qq):
1940241675Suqs		term_word(p, "\"");
1941241675Suqs		break;
1942241675Suqs	case (MDOC_Ql):
1943241675Suqs		/* FALLTHROUGH */
1944241675Suqs	case (MDOC_So):
1945241675Suqs		/* FALLTHROUGH */
1946241675Suqs	case (MDOC_Sq):
1947241675Suqs		term_word(p, "`");
1948241675Suqs		break;
1949241675Suqs	default:
1950241675Suqs		abort();
1951241675Suqs		/* NOTREACHED */
1952241675Suqs	}
1953241675Suqs
1954241675Suqs	p->flags |= TERMP_NOSPACE;
1955241675Suqs	return(1);
1956241675Suqs}
1957241675Suqs
1958241675Suqs
1959241675Suqs/* ARGSUSED */
1960241675Suqsstatic void
1961241675Suqstermp_quote_post(DECL_ARGS)
1962241675Suqs{
1963241675Suqs
1964241675Suqs	if (MDOC_BODY != n->type && MDOC_ELEM != n->type)
1965241675Suqs		return;
1966241675Suqs
1967241675Suqs	p->flags |= TERMP_NOSPACE;
1968241675Suqs
1969241675Suqs	switch (n->tok) {
1970241675Suqs	case (MDOC_Ao):
1971241675Suqs		/* FALLTHROUGH */
1972241675Suqs	case (MDOC_Aq):
1973241675Suqs		term_word(p, ">");
1974241675Suqs		break;
1975241675Suqs	case (MDOC_Bro):
1976241675Suqs		/* FALLTHROUGH */
1977241675Suqs	case (MDOC_Brq):
1978241675Suqs		term_word(p, "}");
1979241675Suqs		break;
1980241675Suqs	case (MDOC_Oo):
1981241675Suqs		/* FALLTHROUGH */
1982241675Suqs	case (MDOC_Op):
1983241675Suqs		/* FALLTHROUGH */
1984241675Suqs	case (MDOC_Bo):
1985241675Suqs		/* FALLTHROUGH */
1986241675Suqs	case (MDOC_Bq):
1987241675Suqs		term_word(p, "]");
1988241675Suqs		break;
1989241675Suqs	case (MDOC_Do):
1990241675Suqs		/* FALLTHROUGH */
1991241675Suqs	case (MDOC_Dq):
1992241675Suqs		term_word(p, "''");
1993241675Suqs		break;
1994241675Suqs	case (MDOC_Eo):
1995241675Suqs		break;
1996241675Suqs	case (MDOC_Po):
1997241675Suqs		/* FALLTHROUGH */
1998241675Suqs	case (MDOC_Pq):
1999241675Suqs		term_word(p, ")");
2000241675Suqs		break;
2001241675Suqs	case (MDOC__T):
2002241675Suqs		/* FALLTHROUGH */
2003241675Suqs	case (MDOC_Qo):
2004241675Suqs		/* FALLTHROUGH */
2005241675Suqs	case (MDOC_Qq):
2006241675Suqs		term_word(p, "\"");
2007241675Suqs		break;
2008241675Suqs	case (MDOC_Ql):
2009241675Suqs		/* FALLTHROUGH */
2010241675Suqs	case (MDOC_So):
2011241675Suqs		/* FALLTHROUGH */
2012241675Suqs	case (MDOC_Sq):
2013241675Suqs		term_word(p, "'");
2014241675Suqs		break;
2015241675Suqs	default:
2016241675Suqs		abort();
2017241675Suqs		/* NOTREACHED */
2018241675Suqs	}
2019241675Suqs}
2020241675Suqs
2021241675Suqs
2022241675Suqs/* ARGSUSED */
2023241675Suqsstatic int
2024241675Suqstermp_fo_pre(DECL_ARGS)
2025241675Suqs{
2026241675Suqs
2027241675Suqs	if (MDOC_BLOCK == n->type) {
2028241675Suqs		synopsis_pre(p, n);
2029241675Suqs		return(1);
2030241675Suqs	} else if (MDOC_BODY == n->type) {
2031241675Suqs		p->flags |= TERMP_NOSPACE;
2032241675Suqs		term_word(p, "(");
2033241675Suqs		p->flags |= TERMP_NOSPACE;
2034241675Suqs		return(1);
2035241675Suqs	}
2036241675Suqs
2037241675Suqs	if (NULL == n->child)
2038241675Suqs		return(0);
2039241675Suqs
2040241675Suqs	/* XXX: we drop non-initial arguments as per groff. */
2041241675Suqs
2042241675Suqs	assert(n->child->string);
2043241675Suqs	term_fontpush(p, TERMFONT_BOLD);
2044241675Suqs	term_word(p, n->child->string);
2045241675Suqs	return(0);
2046241675Suqs}
2047241675Suqs
2048241675Suqs
2049241675Suqs/* ARGSUSED */
2050241675Suqsstatic void
2051241675Suqstermp_fo_post(DECL_ARGS)
2052241675Suqs{
2053241675Suqs
2054241675Suqs	if (MDOC_BODY != n->type)
2055241675Suqs		return;
2056241675Suqs
2057241675Suqs	p->flags |= TERMP_NOSPACE;
2058241675Suqs	term_word(p, ")");
2059241675Suqs
2060241675Suqs	if (MDOC_SYNPRETTY & n->flags) {
2061241675Suqs		p->flags |= TERMP_NOSPACE;
2062241675Suqs		term_word(p, ";");
2063241675Suqs	}
2064241675Suqs}
2065241675Suqs
2066241675Suqs
2067241675Suqs/* ARGSUSED */
2068241675Suqsstatic int
2069241675Suqstermp_bf_pre(DECL_ARGS)
2070241675Suqs{
2071241675Suqs
2072241675Suqs	if (MDOC_HEAD == n->type)
2073241675Suqs		return(0);
2074241675Suqs	else if (MDOC_BLOCK != n->type)
2075241675Suqs		return(1);
2076241675Suqs
2077241675Suqs	if (FONT_Em == n->norm->Bf.font)
2078241675Suqs		term_fontpush(p, TERMFONT_UNDER);
2079241675Suqs	else if (FONT_Sy == n->norm->Bf.font)
2080241675Suqs		term_fontpush(p, TERMFONT_BOLD);
2081241675Suqs	else
2082241675Suqs		term_fontpush(p, TERMFONT_NONE);
2083241675Suqs
2084241675Suqs	return(1);
2085241675Suqs}
2086241675Suqs
2087241675Suqs
2088241675Suqs/* ARGSUSED */
2089241675Suqsstatic int
2090241675Suqstermp_sm_pre(DECL_ARGS)
2091241675Suqs{
2092241675Suqs
2093241675Suqs	assert(n->child && MDOC_TEXT == n->child->type);
2094241675Suqs	if (0 == strcmp("on", n->child->string)) {
2095241675Suqs		if (p->col)
2096241675Suqs			p->flags &= ~TERMP_NOSPACE;
2097241675Suqs		p->flags &= ~TERMP_NONOSPACE;
2098241675Suqs	} else
2099241675Suqs		p->flags |= TERMP_NONOSPACE;
2100241675Suqs
2101241675Suqs	return(0);
2102241675Suqs}
2103241675Suqs
2104241675Suqs
2105241675Suqs/* ARGSUSED */
2106241675Suqsstatic int
2107241675Suqstermp_ap_pre(DECL_ARGS)
2108241675Suqs{
2109241675Suqs
2110241675Suqs	p->flags |= TERMP_NOSPACE;
2111241675Suqs	term_word(p, "'");
2112241675Suqs	p->flags |= TERMP_NOSPACE;
2113241675Suqs	return(1);
2114241675Suqs}
2115241675Suqs
2116241675Suqs
2117241675Suqs/* ARGSUSED */
2118241675Suqsstatic void
2119241675Suqstermp____post(DECL_ARGS)
2120241675Suqs{
2121241675Suqs
2122241675Suqs	/*
2123241675Suqs	 * Handle lists of authors.  In general, print each followed by
2124241675Suqs	 * a comma.  Don't print the comma if there are only two
2125241675Suqs	 * authors.
2126241675Suqs	 */
2127241675Suqs	if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok)
2128241675Suqs		if (NULL == n->next->next || MDOC__A != n->next->next->tok)
2129241675Suqs			if (NULL == n->prev || MDOC__A != n->prev->tok)
2130241675Suqs				return;
2131241675Suqs
2132241675Suqs	/* TODO: %U. */
2133241675Suqs
2134241675Suqs	if (NULL == n->parent || MDOC_Rs != n->parent->tok)
2135241675Suqs		return;
2136241675Suqs
2137241675Suqs	p->flags |= TERMP_NOSPACE;
2138241675Suqs	if (NULL == n->next) {
2139241675Suqs		term_word(p, ".");
2140241675Suqs		p->flags |= TERMP_SENTENCE;
2141241675Suqs	} else
2142241675Suqs		term_word(p, ",");
2143241675Suqs}
2144241675Suqs
2145241675Suqs
2146241675Suqs/* ARGSUSED */
2147241675Suqsstatic int
2148241675Suqstermp_li_pre(DECL_ARGS)
2149241675Suqs{
2150241675Suqs
2151241675Suqs	term_fontpush(p, TERMFONT_NONE);
2152241675Suqs	return(1);
2153241675Suqs}
2154241675Suqs
2155241675Suqs
2156241675Suqs/* ARGSUSED */
2157241675Suqsstatic int
2158241675Suqstermp_lk_pre(DECL_ARGS)
2159241675Suqs{
2160241675Suqs	const struct mdoc_node *nn, *sv;
2161241675Suqs
2162241675Suqs	term_fontpush(p, TERMFONT_UNDER);
2163241675Suqs
2164241675Suqs	nn = sv = n->child;
2165241675Suqs
2166241675Suqs	if (NULL == nn || NULL == nn->next)
2167241675Suqs		return(1);
2168241675Suqs
2169241675Suqs	for (nn = nn->next; nn; nn = nn->next)
2170241675Suqs		term_word(p, nn->string);
2171241675Suqs
2172241675Suqs	term_fontpop(p);
2173241675Suqs
2174241675Suqs	p->flags |= TERMP_NOSPACE;
2175241675Suqs	term_word(p, ":");
2176241675Suqs
2177241675Suqs	term_fontpush(p, TERMFONT_BOLD);
2178241675Suqs	term_word(p, sv->string);
2179241675Suqs	term_fontpop(p);
2180241675Suqs
2181241675Suqs	return(0);
2182241675Suqs}
2183241675Suqs
2184241675Suqs
2185241675Suqs/* ARGSUSED */
2186241675Suqsstatic int
2187241675Suqstermp_bk_pre(DECL_ARGS)
2188241675Suqs{
2189241675Suqs
2190241675Suqs	switch (n->type) {
2191241675Suqs	case (MDOC_BLOCK):
2192241675Suqs		break;
2193241675Suqs	case (MDOC_HEAD):
2194241675Suqs		return(0);
2195241675Suqs	case (MDOC_BODY):
2196241675Suqs		if (n->parent->args || 0 == n->prev->nchild)
2197241675Suqs			p->flags |= TERMP_PREKEEP;
2198241675Suqs		break;
2199241675Suqs	default:
2200241675Suqs		abort();
2201241675Suqs		/* NOTREACHED */
2202241675Suqs	}
2203241675Suqs
2204241675Suqs	return(1);
2205241675Suqs}
2206241675Suqs
2207241675Suqs
2208241675Suqs/* ARGSUSED */
2209241675Suqsstatic void
2210241675Suqstermp_bk_post(DECL_ARGS)
2211241675Suqs{
2212241675Suqs
2213241675Suqs	if (MDOC_BODY == n->type)
2214241675Suqs		p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
2215241675Suqs}
2216241675Suqs
2217241675Suqs/* ARGSUSED */
2218241675Suqsstatic void
2219241675Suqstermp__t_post(DECL_ARGS)
2220241675Suqs{
2221241675Suqs
2222241675Suqs	/*
2223241675Suqs	 * If we're in an `Rs' and there's a journal present, then quote
2224241675Suqs	 * us instead of underlining us (for disambiguation).
2225241675Suqs	 */
2226241675Suqs	if (n->parent && MDOC_Rs == n->parent->tok &&
2227241675Suqs			n->parent->norm->Rs.quote_T)
2228241675Suqs		termp_quote_post(p, pair, m, n);
2229241675Suqs
2230241675Suqs	termp____post(p, pair, m, n);
2231241675Suqs}
2232241675Suqs
2233241675Suqs/* ARGSUSED */
2234241675Suqsstatic int
2235241675Suqstermp__t_pre(DECL_ARGS)
2236241675Suqs{
2237241675Suqs
2238241675Suqs	/*
2239241675Suqs	 * If we're in an `Rs' and there's a journal present, then quote
2240241675Suqs	 * us instead of underlining us (for disambiguation).
2241241675Suqs	 */
2242241675Suqs	if (n->parent && MDOC_Rs == n->parent->tok &&
2243241675Suqs			n->parent->norm->Rs.quote_T)
2244241675Suqs		return(termp_quote_pre(p, pair, m, n));
2245241675Suqs
2246241675Suqs	term_fontpush(p, TERMFONT_UNDER);
2247241675Suqs	return(1);
2248241675Suqs}
2249241675Suqs
2250241675Suqs/* ARGSUSED */
2251241675Suqsstatic int
2252241675Suqstermp_under_pre(DECL_ARGS)
2253241675Suqs{
2254241675Suqs
2255241675Suqs	term_fontpush(p, TERMFONT_UNDER);
2256241675Suqs	return(1);
2257241675Suqs}
2258