xref: /netbsd/external/bsd/mdocml/dist/mdoc_html.c (revision fc3ee6fd)
1*fc3ee6fdSchristos /*	Id: mdoc_html.c,v 1.328 2019/03/01 10:57:18 schwarze Exp  */
24154958bSjoerg /*
30511d63cSchristos  * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
4*fc3ee6fdSchristos  * Copyright (c) 2014-2019 Ingo Schwarze <schwarze@openbsd.org>
54154958bSjoerg  *
64154958bSjoerg  * Permission to use, copy, modify, and distribute this software for any
74154958bSjoerg  * purpose with or without fee is hereby granted, provided that the above
84154958bSjoerg  * copyright notice and this permission notice appear in all copies.
94154958bSjoerg  *
1047a17e0dSchristos  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
114154958bSjoerg  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1247a17e0dSchristos  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
134154958bSjoerg  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
144154958bSjoerg  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
154154958bSjoerg  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
164154958bSjoerg  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
174154958bSjoerg  */
18d5e63c8dSjoerg #include "config.h"
19d5e63c8dSjoerg 
204154958bSjoerg #include <sys/types.h>
214154958bSjoerg 
224154958bSjoerg #include <assert.h>
234154958bSjoerg #include <ctype.h>
244154958bSjoerg #include <stdio.h>
254154958bSjoerg #include <stdlib.h>
264154958bSjoerg #include <string.h>
274154958bSjoerg #include <unistd.h>
284154958bSjoerg 
290511d63cSchristos #include "mandoc_aux.h"
309d9b81f7Schristos #include "mandoc.h"
3147a17e0dSchristos #include "roff.h"
320511d63cSchristos #include "mdoc.h"
334154958bSjoerg #include "out.h"
344154958bSjoerg #include "html.h"
354154958bSjoerg #include "main.h"
364154958bSjoerg 
3747a17e0dSchristos #define	MDOC_ARGS	  const struct roff_meta *meta, \
3847a17e0dSchristos 			  struct roff_node *n, \
394154958bSjoerg 			  struct html *h
404154958bSjoerg 
41d5e63c8dSjoerg #ifndef MIN
42d5e63c8dSjoerg #define	MIN(a,b)	((/*CONSTCOND*/(a)<(b))?(a):(b))
43d5e63c8dSjoerg #endif
44d5e63c8dSjoerg 
45*fc3ee6fdSchristos struct	mdoc_html_act {
464154958bSjoerg 	int		(*pre)(MDOC_ARGS);
474154958bSjoerg 	void		(*post)(MDOC_ARGS);
484154958bSjoerg };
494154958bSjoerg 
509d9b81f7Schristos static	char		 *cond_id(const struct roff_node *);
519d9b81f7Schristos static	void		  print_mdoc_head(const struct roff_meta *,
529d9b81f7Schristos 				struct html *);
534154958bSjoerg static	void		  print_mdoc_node(MDOC_ARGS);
544154958bSjoerg static	void		  print_mdoc_nodelist(MDOC_ARGS);
557574e07eSjoerg static	void		  synopsis_pre(struct html *,
5647a17e0dSchristos 				const struct roff_node *);
574154958bSjoerg 
589d9b81f7Schristos static	void		  mdoc_root_post(const struct roff_meta *,
599d9b81f7Schristos 				struct html *);
609d9b81f7Schristos static	int		  mdoc_root_pre(const struct roff_meta *,
619d9b81f7Schristos 				struct html *);
624154958bSjoerg 
634154958bSjoerg static	void		  mdoc__x_post(MDOC_ARGS);
644154958bSjoerg static	int		  mdoc__x_pre(MDOC_ARGS);
65*fc3ee6fdSchristos static	int		  mdoc_abort_pre(MDOC_ARGS);
664154958bSjoerg static	int		  mdoc_ad_pre(MDOC_ARGS);
674154958bSjoerg static	int		  mdoc_an_pre(MDOC_ARGS);
684154958bSjoerg static	int		  mdoc_ap_pre(MDOC_ARGS);
694154958bSjoerg static	int		  mdoc_ar_pre(MDOC_ARGS);
704154958bSjoerg static	int		  mdoc_bd_pre(MDOC_ARGS);
714154958bSjoerg static	int		  mdoc_bf_pre(MDOC_ARGS);
7282361f10Sjoerg static	void		  mdoc_bk_post(MDOC_ARGS);
7382361f10Sjoerg static	int		  mdoc_bk_pre(MDOC_ARGS);
744154958bSjoerg static	int		  mdoc_bl_pre(MDOC_ARGS);
754154958bSjoerg static	int		  mdoc_cd_pre(MDOC_ARGS);
76b2070ba5Schristos static	int		  mdoc_cm_pre(MDOC_ARGS);
774154958bSjoerg static	int		  mdoc_d1_pre(MDOC_ARGS);
784154958bSjoerg static	int		  mdoc_dv_pre(MDOC_ARGS);
794154958bSjoerg static	int		  mdoc_fa_pre(MDOC_ARGS);
804154958bSjoerg static	int		  mdoc_fd_pre(MDOC_ARGS);
814154958bSjoerg static	int		  mdoc_fl_pre(MDOC_ARGS);
824154958bSjoerg static	int		  mdoc_fn_pre(MDOC_ARGS);
834154958bSjoerg static	int		  mdoc_ft_pre(MDOC_ARGS);
844154958bSjoerg static	int		  mdoc_em_pre(MDOC_ARGS);
850511d63cSchristos static	void		  mdoc_eo_post(MDOC_ARGS);
860511d63cSchristos static	int		  mdoc_eo_pre(MDOC_ARGS);
874154958bSjoerg static	int		  mdoc_er_pre(MDOC_ARGS);
884154958bSjoerg static	int		  mdoc_ev_pre(MDOC_ARGS);
894154958bSjoerg static	int		  mdoc_ex_pre(MDOC_ARGS);
904154958bSjoerg static	void		  mdoc_fo_post(MDOC_ARGS);
914154958bSjoerg static	int		  mdoc_fo_pre(MDOC_ARGS);
924154958bSjoerg static	int		  mdoc_ic_pre(MDOC_ARGS);
93e4fbeb7eSjoerg static	int		  mdoc_igndelim_pre(MDOC_ARGS);
944154958bSjoerg static	int		  mdoc_in_pre(MDOC_ARGS);
954154958bSjoerg static	int		  mdoc_it_pre(MDOC_ARGS);
964154958bSjoerg static	int		  mdoc_lb_pre(MDOC_ARGS);
974154958bSjoerg static	int		  mdoc_li_pre(MDOC_ARGS);
984154958bSjoerg static	int		  mdoc_lk_pre(MDOC_ARGS);
994154958bSjoerg static	int		  mdoc_mt_pre(MDOC_ARGS);
1004154958bSjoerg static	int		  mdoc_ms_pre(MDOC_ARGS);
1014154958bSjoerg static	int		  mdoc_nd_pre(MDOC_ARGS);
1024154958bSjoerg static	int		  mdoc_nm_pre(MDOC_ARGS);
1030511d63cSchristos static	int		  mdoc_no_pre(MDOC_ARGS);
1044154958bSjoerg static	int		  mdoc_ns_pre(MDOC_ARGS);
1054154958bSjoerg static	int		  mdoc_pa_pre(MDOC_ARGS);
1064154958bSjoerg static	void		  mdoc_pf_post(MDOC_ARGS);
107e4fbeb7eSjoerg static	int		  mdoc_pp_pre(MDOC_ARGS);
108e4fbeb7eSjoerg static	void		  mdoc_quote_post(MDOC_ARGS);
109e4fbeb7eSjoerg static	int		  mdoc_quote_pre(MDOC_ARGS);
1104154958bSjoerg static	int		  mdoc_rs_pre(MDOC_ARGS);
1114154958bSjoerg static	int		  mdoc_sh_pre(MDOC_ARGS);
1120511d63cSchristos static	int		  mdoc_skip_pre(MDOC_ARGS);
1137da9b934Sjoerg static	int		  mdoc_sm_pre(MDOC_ARGS);
1144154958bSjoerg static	int		  mdoc_ss_pre(MDOC_ARGS);
115b2070ba5Schristos static	int		  mdoc_st_pre(MDOC_ARGS);
1164154958bSjoerg static	int		  mdoc_sx_pre(MDOC_ARGS);
1174154958bSjoerg static	int		  mdoc_sy_pre(MDOC_ARGS);
1184154958bSjoerg static	int		  mdoc_va_pre(MDOC_ARGS);
1194154958bSjoerg static	int		  mdoc_vt_pre(MDOC_ARGS);
1204154958bSjoerg static	int		  mdoc_xr_pre(MDOC_ARGS);
1214154958bSjoerg static	int		  mdoc_xx_pre(MDOC_ARGS);
1224154958bSjoerg 
123*fc3ee6fdSchristos static const struct mdoc_html_act mdoc_html_acts[MDOC_MAX - MDOC_Dd] = {
1244154958bSjoerg 	{NULL, NULL}, /* Dd */
1254154958bSjoerg 	{NULL, NULL}, /* Dt */
1264154958bSjoerg 	{NULL, NULL}, /* Os */
1274154958bSjoerg 	{mdoc_sh_pre, NULL }, /* Sh */
1284154958bSjoerg 	{mdoc_ss_pre, NULL }, /* Ss */
129e4fbeb7eSjoerg 	{mdoc_pp_pre, NULL}, /* Pp */
1304154958bSjoerg 	{mdoc_d1_pre, NULL}, /* D1 */
1314154958bSjoerg 	{mdoc_d1_pre, NULL}, /* Dl */
1324154958bSjoerg 	{mdoc_bd_pre, NULL}, /* Bd */
1334154958bSjoerg 	{NULL, NULL}, /* Ed */
134e4fbeb7eSjoerg 	{mdoc_bl_pre, NULL}, /* Bl */
1354154958bSjoerg 	{NULL, NULL}, /* El */
1364154958bSjoerg 	{mdoc_it_pre, NULL}, /* It */
1374154958bSjoerg 	{mdoc_ad_pre, NULL}, /* Ad */
1384154958bSjoerg 	{mdoc_an_pre, NULL}, /* An */
1399d9b81f7Schristos 	{mdoc_ap_pre, NULL}, /* Ap */
1404154958bSjoerg 	{mdoc_ar_pre, NULL}, /* Ar */
1414154958bSjoerg 	{mdoc_cd_pre, NULL}, /* Cd */
142b2070ba5Schristos 	{mdoc_cm_pre, NULL}, /* Cm */
1434154958bSjoerg 	{mdoc_dv_pre, NULL}, /* Dv */
1444154958bSjoerg 	{mdoc_er_pre, NULL}, /* Er */
1454154958bSjoerg 	{mdoc_ev_pre, NULL}, /* Ev */
1464154958bSjoerg 	{mdoc_ex_pre, NULL}, /* Ex */
1474154958bSjoerg 	{mdoc_fa_pre, NULL}, /* Fa */
1484154958bSjoerg 	{mdoc_fd_pre, NULL}, /* Fd */
1494154958bSjoerg 	{mdoc_fl_pre, NULL}, /* Fl */
1504154958bSjoerg 	{mdoc_fn_pre, NULL}, /* Fn */
1514154958bSjoerg 	{mdoc_ft_pre, NULL}, /* Ft */
1524154958bSjoerg 	{mdoc_ic_pre, NULL}, /* Ic */
1534154958bSjoerg 	{mdoc_in_pre, NULL}, /* In */
1544154958bSjoerg 	{mdoc_li_pre, NULL}, /* Li */
1554154958bSjoerg 	{mdoc_nd_pre, NULL}, /* Nd */
1564154958bSjoerg 	{mdoc_nm_pre, NULL}, /* Nm */
157e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Op */
158*fc3ee6fdSchristos 	{mdoc_abort_pre, NULL}, /* Ot */
1594154958bSjoerg 	{mdoc_pa_pre, NULL}, /* Pa */
160b2070ba5Schristos 	{mdoc_ex_pre, NULL}, /* Rv */
161b2070ba5Schristos 	{mdoc_st_pre, NULL}, /* St */
1624154958bSjoerg 	{mdoc_va_pre, NULL}, /* Va */
1634154958bSjoerg 	{mdoc_vt_pre, NULL}, /* Vt */
1644154958bSjoerg 	{mdoc_xr_pre, NULL}, /* Xr */
1654154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %A */
1664154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %B */
1674154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %D */
1684154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %I */
1694154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %J */
1704154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %N */
1714154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %O */
1724154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %P */
1734154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %R */
1744154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %T */
1754154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %V */
1764154958bSjoerg 	{NULL, NULL}, /* Ac */
177e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Ao */
178e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Aq */
179b2070ba5Schristos 	{mdoc_xx_pre, NULL}, /* At */
1804154958bSjoerg 	{NULL, NULL}, /* Bc */
1814154958bSjoerg 	{mdoc_bf_pre, NULL}, /* Bf */
182e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Bo */
183e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Bq */
1844154958bSjoerg 	{mdoc_xx_pre, NULL}, /* Bsx */
185b2070ba5Schristos 	{mdoc_xx_pre, NULL}, /* Bx */
1860511d63cSchristos 	{mdoc_skip_pre, NULL}, /* Db */
1874154958bSjoerg 	{NULL, NULL}, /* Dc */
188e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Do */
189e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Dq */
19031e1f4e3Sjoerg 	{NULL, NULL}, /* Ec */ /* FIXME: no space */
1914154958bSjoerg 	{NULL, NULL}, /* Ef */
1924154958bSjoerg 	{mdoc_em_pre, NULL}, /* Em */
1930511d63cSchristos 	{mdoc_eo_pre, mdoc_eo_post}, /* Eo */
1944154958bSjoerg 	{mdoc_xx_pre, NULL}, /* Fx */
1957da9b934Sjoerg 	{mdoc_ms_pre, NULL}, /* Ms */
1960511d63cSchristos 	{mdoc_no_pre, NULL}, /* No */
1974154958bSjoerg 	{mdoc_ns_pre, NULL}, /* Ns */
1984154958bSjoerg 	{mdoc_xx_pre, NULL}, /* Nx */
1994154958bSjoerg 	{mdoc_xx_pre, NULL}, /* Ox */
2004154958bSjoerg 	{NULL, NULL}, /* Pc */
201e4fbeb7eSjoerg 	{mdoc_igndelim_pre, mdoc_pf_post}, /* Pf */
202e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Po */
203e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Pq */
2044154958bSjoerg 	{NULL, NULL}, /* Qc */
205e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Ql */
206e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Qo */
207e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Qq */
2084154958bSjoerg 	{NULL, NULL}, /* Re */
2094154958bSjoerg 	{mdoc_rs_pre, NULL}, /* Rs */
2104154958bSjoerg 	{NULL, NULL}, /* Sc */
211e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* So */
212e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Sq */
2137da9b934Sjoerg 	{mdoc_sm_pre, NULL}, /* Sm */
2144154958bSjoerg 	{mdoc_sx_pre, NULL}, /* Sx */
2154154958bSjoerg 	{mdoc_sy_pre, NULL}, /* Sy */
2164154958bSjoerg 	{NULL, NULL}, /* Tn */
2174154958bSjoerg 	{mdoc_xx_pre, NULL}, /* Ux */
2184154958bSjoerg 	{NULL, NULL}, /* Xc */
2194154958bSjoerg 	{NULL, NULL}, /* Xo */
2204154958bSjoerg 	{mdoc_fo_pre, mdoc_fo_post}, /* Fo */
2214154958bSjoerg 	{NULL, NULL}, /* Fc */
222e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Oo */
2234154958bSjoerg 	{NULL, NULL}, /* Oc */
22482361f10Sjoerg 	{mdoc_bk_pre, mdoc_bk_post}, /* Bk */
2254154958bSjoerg 	{NULL, NULL}, /* Ek */
226b2070ba5Schristos 	{NULL, NULL}, /* Bt */
2274154958bSjoerg 	{NULL, NULL}, /* Hf */
2280511d63cSchristos 	{mdoc_em_pre, NULL}, /* Fr */
229b2070ba5Schristos 	{NULL, NULL}, /* Ud */
2304154958bSjoerg 	{mdoc_lb_pre, NULL}, /* Lb */
231*fc3ee6fdSchristos 	{mdoc_abort_pre, NULL}, /* Lp */
2324154958bSjoerg 	{mdoc_lk_pre, NULL}, /* Lk */
2334154958bSjoerg 	{mdoc_mt_pre, NULL}, /* Mt */
234e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Brq */
235e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Bro */
2364154958bSjoerg 	{NULL, NULL}, /* Brc */
2374154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %C */
2380511d63cSchristos 	{mdoc_skip_pre, NULL}, /* Es */
2390511d63cSchristos 	{mdoc_quote_pre, mdoc_quote_post}, /* En */
2404154958bSjoerg 	{mdoc_xx_pre, NULL}, /* Dx */
2414154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %Q */
24222af4063Sjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %U */
2437574e07eSjoerg 	{NULL, NULL}, /* Ta */
2444154958bSjoerg };
2454154958bSjoerg 
2464154958bSjoerg 
2474154958bSjoerg /*
2487574e07eSjoerg  * See the same function in mdoc_term.c for documentation.
2497574e07eSjoerg  */
2507574e07eSjoerg static void
synopsis_pre(struct html * h,const struct roff_node * n)25147a17e0dSchristos synopsis_pre(struct html *h, const struct roff_node *n)
2527574e07eSjoerg {
2537574e07eSjoerg 
254b2070ba5Schristos 	if (NULL == n->prev || ! (NODE_SYNPRETTY & n->flags))
2557574e07eSjoerg 		return;
2567574e07eSjoerg 
2577574e07eSjoerg 	if (n->prev->tok == n->tok &&
2587574e07eSjoerg 	    MDOC_Fo != n->tok &&
2597574e07eSjoerg 	    MDOC_Ft != n->tok &&
2607574e07eSjoerg 	    MDOC_Fn != n->tok) {
261b2070ba5Schristos 		print_otag(h, TAG_BR, "");
2627574e07eSjoerg 		return;
2637574e07eSjoerg 	}
2647574e07eSjoerg 
2657574e07eSjoerg 	switch (n->prev->tok) {
2660511d63cSchristos 	case MDOC_Fd:
2670511d63cSchristos 	case MDOC_Fn:
2680511d63cSchristos 	case MDOC_Fo:
2690511d63cSchristos 	case MDOC_In:
2700511d63cSchristos 	case MDOC_Vt:
2717574e07eSjoerg 		break;
2720511d63cSchristos 	case MDOC_Ft:
273*fc3ee6fdSchristos 		if (n->tok != MDOC_Fn && n->tok != MDOC_Fo)
2747574e07eSjoerg 			break;
2757574e07eSjoerg 		/* FALLTHROUGH */
2767574e07eSjoerg 	default:
277b2070ba5Schristos 		print_otag(h, TAG_BR, "");
278*fc3ee6fdSchristos 		return;
2797574e07eSjoerg 	}
280*fc3ee6fdSchristos 	html_close_paragraph(h);
281*fc3ee6fdSchristos 	print_otag(h, TAG_P, "c", "Pp");
2827574e07eSjoerg }
2837574e07eSjoerg 
28447a17e0dSchristos void
html_mdoc(void * arg,const struct roff_meta * mdoc)285*fc3ee6fdSchristos html_mdoc(void *arg, const struct roff_meta *mdoc)
2864154958bSjoerg {
28747a17e0dSchristos 	struct html		*h;
2889d9b81f7Schristos 	struct roff_node	*n;
289b2070ba5Schristos 	struct tag		*t;
2904154958bSjoerg 
29147a17e0dSchristos 	h = (struct html *)arg;
2929d9b81f7Schristos 	n = mdoc->first->child;
293f8126693Sjoerg 
294b2070ba5Schristos 	if ((h->oflags & HTML_FRAGMENT) == 0) {
295f8126693Sjoerg 		print_gen_decls(h);
296b2070ba5Schristos 		print_otag(h, TAG_HTML, "");
297*fc3ee6fdSchristos 		if (n != NULL && n->type == ROFFT_COMMENT)
2989d9b81f7Schristos 			print_gen_comment(h, n);
299b2070ba5Schristos 		t = print_otag(h, TAG_HEAD, "");
300*fc3ee6fdSchristos 		print_mdoc_head(mdoc, h);
301b2070ba5Schristos 		print_tagq(h, t);
302b2070ba5Schristos 		print_otag(h, TAG_BODY, "");
303b2070ba5Schristos 	}
3044154958bSjoerg 
305*fc3ee6fdSchristos 	mdoc_root_pre(mdoc, h);
306b2070ba5Schristos 	t = print_otag(h, TAG_DIV, "c", "manual-text");
307*fc3ee6fdSchristos 	print_mdoc_nodelist(mdoc, n, h);
3084154958bSjoerg 	print_tagq(h, t);
309*fc3ee6fdSchristos 	mdoc_root_post(mdoc, h);
310b2070ba5Schristos 	print_tagq(h, NULL);
3114154958bSjoerg }
3124154958bSjoerg 
3134154958bSjoerg static void
print_mdoc_head(const struct roff_meta * meta,struct html * h)3149d9b81f7Schristos print_mdoc_head(const struct roff_meta *meta, struct html *h)
3154154958bSjoerg {
316b2070ba5Schristos 	char	*cp;
3174154958bSjoerg 
3184154958bSjoerg 	print_gen_head(h);
3194154958bSjoerg 
320b2070ba5Schristos 	if (meta->arch != NULL && meta->msec != NULL)
321b2070ba5Schristos 		mandoc_asprintf(&cp, "%s(%s) (%s)", meta->title,
322b2070ba5Schristos 		    meta->msec, meta->arch);
323b2070ba5Schristos 	else if (meta->msec != NULL)
324b2070ba5Schristos 		mandoc_asprintf(&cp, "%s(%s)", meta->title, meta->msec);
325b2070ba5Schristos 	else if (meta->arch != NULL)
326b2070ba5Schristos 		mandoc_asprintf(&cp, "%s (%s)", meta->title, meta->arch);
327b2070ba5Schristos 	else
328b2070ba5Schristos 		cp = mandoc_strdup(meta->title);
329b2070ba5Schristos 
330b2070ba5Schristos 	print_otag(h, TAG_TITLE, "");
331b2070ba5Schristos 	print_text(h, cp);
332b2070ba5Schristos 	free(cp);
3334154958bSjoerg }
3344154958bSjoerg 
3354154958bSjoerg static void
print_mdoc_nodelist(MDOC_ARGS)3364154958bSjoerg print_mdoc_nodelist(MDOC_ARGS)
3374154958bSjoerg {
3384154958bSjoerg 
3390511d63cSchristos 	while (n != NULL) {
340ed7c7912Sjoerg 		print_mdoc_node(meta, n, h);
3410511d63cSchristos 		n = n->next;
3424154958bSjoerg 	}
3430511d63cSchristos }
3444154958bSjoerg 
3454154958bSjoerg static void
print_mdoc_node(MDOC_ARGS)3464154958bSjoerg print_mdoc_node(MDOC_ARGS)
3474154958bSjoerg {
3484154958bSjoerg 	struct tag	*t;
349*fc3ee6fdSchristos 	int		 child;
3504154958bSjoerg 
3519d9b81f7Schristos 	if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
352b2070ba5Schristos 		return;
353b2070ba5Schristos 
354*fc3ee6fdSchristos 	html_fillmode(h, n->flags & NODE_NOFILL ? ROFF_nf : ROFF_fi);
3554154958bSjoerg 
356*fc3ee6fdSchristos 	child = 1;
357*fc3ee6fdSchristos 	n->flags &= ~NODE_ENDED;
3584154958bSjoerg 	switch (n->type) {
35947a17e0dSchristos 	case ROFFT_TEXT:
360*fc3ee6fdSchristos 		t = h->tag;
361*fc3ee6fdSchristos 		t->refcnt++;
362*fc3ee6fdSchristos 
36354a4f7feSjoerg 		/* No tables in this mode... */
36454a4f7feSjoerg 		assert(NULL == h->tblt);
36554a4f7feSjoerg 
36654a4f7feSjoerg 		/*
36754a4f7feSjoerg 		 * Make sure that if we're in a literal mode already
36854a4f7feSjoerg 		 * (i.e., within a <PRE>) don't print the newline.
36954a4f7feSjoerg 		 */
3709d9b81f7Schristos 		if (*n->string == ' ' && n->flags & NODE_LINE &&
371*fc3ee6fdSchristos 		    (h->flags & HTML_NONEWLINE) == 0 &&
372*fc3ee6fdSchristos 		    (n->flags & NODE_NOFILL) == 0)
373b2070ba5Schristos 			print_otag(h, TAG_BR, "");
374b2070ba5Schristos 		if (NODE_DELIMC & n->flags)
37554a4f7feSjoerg 			h->flags |= HTML_NOSPACE;
3764154958bSjoerg 		print_text(h, n->string);
377b2070ba5Schristos 		if (NODE_DELIMO & n->flags)
37854a4f7feSjoerg 			h->flags |= HTML_NOSPACE;
379*fc3ee6fdSchristos 		break;
38047a17e0dSchristos 	case ROFFT_EQN:
381*fc3ee6fdSchristos 		t = h->tag;
382*fc3ee6fdSchristos 		t->refcnt++;
383f8126693Sjoerg 		print_eqn(h, n->eqn);
384e4fbeb7eSjoerg 		break;
38547a17e0dSchristos 	case ROFFT_TBL:
38654a4f7feSjoerg 		/*
38754a4f7feSjoerg 		 * This will take care of initialising all of the table
38854a4f7feSjoerg 		 * state data for the first table, then tearing it down
38954a4f7feSjoerg 		 * for the last one.
39054a4f7feSjoerg 		 */
39154a4f7feSjoerg 		print_tbl(h, n->span);
39254a4f7feSjoerg 		return;
3934154958bSjoerg 	default:
39454a4f7feSjoerg 		/*
39554a4f7feSjoerg 		 * Close out the current table, if it's open, and unset
39654a4f7feSjoerg 		 * the "meta" table state.  This will be reopened on the
39754a4f7feSjoerg 		 * next table element.
39854a4f7feSjoerg 		 */
399*fc3ee6fdSchristos 		if (h->tblt != NULL)
40054a4f7feSjoerg 			print_tblclose(h);
4010511d63cSchristos 		assert(h->tblt == NULL);
402*fc3ee6fdSchristos 		t = h->tag;
403*fc3ee6fdSchristos 		t->refcnt++;
4049d9b81f7Schristos 		if (n->tok < ROFF_MAX) {
4059d9b81f7Schristos 			roff_html_pre(h, n);
406*fc3ee6fdSchristos 			t->refcnt--;
407*fc3ee6fdSchristos 			print_stagq(h, t);
408*fc3ee6fdSchristos 			return;
4099d9b81f7Schristos 		}
4109d9b81f7Schristos 		assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
411*fc3ee6fdSchristos 		if (mdoc_html_acts[n->tok - MDOC_Dd].pre != NULL &&
4129d9b81f7Schristos 		    (n->end == ENDBODY_NOT || n->child != NULL))
413*fc3ee6fdSchristos 			child = (*mdoc_html_acts[n->tok - MDOC_Dd].pre)(meta,
414*fc3ee6fdSchristos 			    n, h);
4154154958bSjoerg 		break;
4164154958bSjoerg 	}
4174154958bSjoerg 
418b2070ba5Schristos 	if (h->flags & HTML_KEEP && n->flags & NODE_LINE) {
41982361f10Sjoerg 		h->flags &= ~HTML_KEEP;
42082361f10Sjoerg 		h->flags |= HTML_PREKEEP;
42182361f10Sjoerg 	}
42282361f10Sjoerg 
423*fc3ee6fdSchristos 	if (child && n->child != NULL)
424ed7c7912Sjoerg 		print_mdoc_nodelist(meta, n->child, h);
4254154958bSjoerg 
426*fc3ee6fdSchristos 	t->refcnt--;
4274154958bSjoerg 	print_stagq(h, t);
4284154958bSjoerg 
4294154958bSjoerg 	switch (n->type) {
430*fc3ee6fdSchristos 	case ROFFT_TEXT:
43147a17e0dSchristos 	case ROFFT_EQN:
432e4fbeb7eSjoerg 		break;
4334154958bSjoerg 	default:
434*fc3ee6fdSchristos 		if (mdoc_html_acts[n->tok - MDOC_Dd].post == NULL ||
4359d9b81f7Schristos 		    n->flags & NODE_ENDED)
4360511d63cSchristos 			break;
437*fc3ee6fdSchristos 		(*mdoc_html_acts[n->tok - MDOC_Dd].post)(meta, n, h);
4380511d63cSchristos 		if (n->end != ENDBODY_NOT)
439b2070ba5Schristos 			n->body->flags |= NODE_ENDED;
4404154958bSjoerg 		break;
4414154958bSjoerg 	}
442*fc3ee6fdSchristos 
443*fc3ee6fdSchristos 	if (n->flags & NODE_NOFILL &&
444*fc3ee6fdSchristos 	    (n->next == NULL || n->next->flags & NODE_LINE)) {
445*fc3ee6fdSchristos 		h->col++;
446*fc3ee6fdSchristos 		print_endline(h);
447*fc3ee6fdSchristos 	}
4484154958bSjoerg }
4494154958bSjoerg 
4504154958bSjoerg static void
mdoc_root_post(const struct roff_meta * meta,struct html * h)4519d9b81f7Schristos mdoc_root_post(const struct roff_meta *meta, struct html *h)
4524154958bSjoerg {
4534154958bSjoerg 	struct tag	*t, *tt;
4544154958bSjoerg 
455b2070ba5Schristos 	t = print_otag(h, TAG_TABLE, "c", "foot");
456b2070ba5Schristos 	tt = print_otag(h, TAG_TR, "");
457e4fbeb7eSjoerg 
458b2070ba5Schristos 	print_otag(h, TAG_TD, "c", "foot-date");
459ed7c7912Sjoerg 	print_text(h, meta->date);
4604154958bSjoerg 	print_stagq(h, tt);
4614154958bSjoerg 
462b2070ba5Schristos 	print_otag(h, TAG_TD, "c", "foot-os");
463ed7c7912Sjoerg 	print_text(h, meta->os);
4644154958bSjoerg 	print_tagq(h, t);
4654154958bSjoerg }
4664154958bSjoerg 
4674154958bSjoerg static int
mdoc_root_pre(const struct roff_meta * meta,struct html * h)4689d9b81f7Schristos mdoc_root_pre(const struct roff_meta *meta, struct html *h)
4694154958bSjoerg {
4704154958bSjoerg 	struct tag	*t, *tt;
4710511d63cSchristos 	char		*volume, *title;
4724154958bSjoerg 
4730511d63cSchristos 	if (NULL == meta->arch)
4740511d63cSchristos 		volume = mandoc_strdup(meta->vol);
4750511d63cSchristos 	else
4760511d63cSchristos 		mandoc_asprintf(&volume, "%s (%s)",
4770511d63cSchristos 		    meta->vol, meta->arch);
4784154958bSjoerg 
4790511d63cSchristos 	if (NULL == meta->msec)
4800511d63cSchristos 		title = mandoc_strdup(meta->title);
4810511d63cSchristos 	else
4820511d63cSchristos 		mandoc_asprintf(&title, "%s(%s)",
4830511d63cSchristos 		    meta->title, meta->msec);
4844154958bSjoerg 
485b2070ba5Schristos 	t = print_otag(h, TAG_TABLE, "c", "head");
486b2070ba5Schristos 	tt = print_otag(h, TAG_TR, "");
487e4fbeb7eSjoerg 
488b2070ba5Schristos 	print_otag(h, TAG_TD, "c", "head-ltitle");
4894154958bSjoerg 	print_text(h, title);
4904154958bSjoerg 	print_stagq(h, tt);
4914154958bSjoerg 
492b2070ba5Schristos 	print_otag(h, TAG_TD, "c", "head-vol");
4930511d63cSchristos 	print_text(h, volume);
4944154958bSjoerg 	print_stagq(h, tt);
4954154958bSjoerg 
496b2070ba5Schristos 	print_otag(h, TAG_TD, "c", "head-rtitle");
4974154958bSjoerg 	print_text(h, title);
4984154958bSjoerg 	print_tagq(h, t);
4990511d63cSchristos 
5000511d63cSchristos 	free(title);
5010511d63cSchristos 	free(volume);
50247a17e0dSchristos 	return 1;
5034154958bSjoerg }
5044154958bSjoerg 
505b2070ba5Schristos static char *
cond_id(const struct roff_node * n)5069d9b81f7Schristos cond_id(const struct roff_node *n)
507b2070ba5Schristos {
5089d9b81f7Schristos 	if (n->child != NULL &&
5099d9b81f7Schristos 	    n->child->type == ROFFT_TEXT &&
5109d9b81f7Schristos 	    (n->prev == NULL ||
5119d9b81f7Schristos 	     (n->prev->type == ROFFT_TEXT &&
5129d9b81f7Schristos 	      strcmp(n->prev->string, "|") == 0)) &&
5139d9b81f7Schristos 	    (n->parent->tok == MDOC_It ||
5149d9b81f7Schristos 	     (n->parent->tok == MDOC_Xo &&
5159d9b81f7Schristos 	      n->parent->parent->prev == NULL &&
5169d9b81f7Schristos 	      n->parent->parent->parent->tok == MDOC_It)))
5179d9b81f7Schristos 		return html_make_id(n, 1);
518b2070ba5Schristos 	return NULL;
519b2070ba5Schristos }
520b2070ba5Schristos 
5214154958bSjoerg static int
mdoc_sh_pre(MDOC_ARGS)5224154958bSjoerg mdoc_sh_pre(MDOC_ARGS)
5234154958bSjoerg {
524*fc3ee6fdSchristos 	struct roff_node	*sn, *subn;
525*fc3ee6fdSchristos 	struct tag		*t, *tsec, *tsub;
526b2070ba5Schristos 	char			*id;
527*fc3ee6fdSchristos 	int			 sc;
5284154958bSjoerg 
5290511d63cSchristos 	switch (n->type) {
530*fc3ee6fdSchristos 	case ROFFT_BLOCK:
531*fc3ee6fdSchristos 		html_close_paragraph(h);
532*fc3ee6fdSchristos 		if ((h->oflags & HTML_TOC) == 0 ||
533*fc3ee6fdSchristos 		    h->flags & HTML_TOCDONE ||
534*fc3ee6fdSchristos 		    n->sec <= SEC_SYNOPSIS) {
535*fc3ee6fdSchristos 			print_otag(h, TAG_SECTION, "c", "Sh");
536*fc3ee6fdSchristos 			break;
537*fc3ee6fdSchristos 		}
538*fc3ee6fdSchristos 		h->flags |= HTML_TOCDONE;
539*fc3ee6fdSchristos 		sc = 0;
540*fc3ee6fdSchristos 		for (sn = n->next; sn != NULL; sn = sn->next)
541*fc3ee6fdSchristos 			if (sn->sec == SEC_CUSTOM)
542*fc3ee6fdSchristos 				if (++sc == 2)
543*fc3ee6fdSchristos 					break;
544*fc3ee6fdSchristos 		if (sc < 2)
545*fc3ee6fdSchristos 			break;
546*fc3ee6fdSchristos 		t = print_otag(h, TAG_H1, "c", "Sh");
547*fc3ee6fdSchristos 		print_text(h, "TABLE OF CONTENTS");
548*fc3ee6fdSchristos 		print_tagq(h, t);
549*fc3ee6fdSchristos 		t = print_otag(h, TAG_UL, "c", "Bl-compact");
550*fc3ee6fdSchristos 		for (sn = n; sn != NULL; sn = sn->next) {
551*fc3ee6fdSchristos 			tsec = print_otag(h, TAG_LI, "");
552*fc3ee6fdSchristos 			id = html_make_id(sn->head, 0);
553*fc3ee6fdSchristos 			tsub = print_otag(h, TAG_A, "hR", id);
554*fc3ee6fdSchristos 			free(id);
555*fc3ee6fdSchristos 			print_mdoc_nodelist(meta, sn->head->child, h);
556*fc3ee6fdSchristos 			print_tagq(h, tsub);
557*fc3ee6fdSchristos 			tsub = NULL;
558*fc3ee6fdSchristos 			for (subn = sn->body->child; subn != NULL;
559*fc3ee6fdSchristos 			    subn = subn->next) {
560*fc3ee6fdSchristos 				if (subn->tok != MDOC_Ss)
561*fc3ee6fdSchristos 					continue;
562*fc3ee6fdSchristos 				id = html_make_id(subn->head, 0);
563*fc3ee6fdSchristos 				if (id == NULL)
564*fc3ee6fdSchristos 					continue;
565*fc3ee6fdSchristos 				if (tsub == NULL)
566*fc3ee6fdSchristos 					print_otag(h, TAG_UL,
567*fc3ee6fdSchristos 					    "c", "Bl-compact");
568*fc3ee6fdSchristos 				tsub = print_otag(h, TAG_LI, "");
569*fc3ee6fdSchristos 				print_otag(h, TAG_A, "hR", id);
570*fc3ee6fdSchristos 				free(id);
571*fc3ee6fdSchristos 				print_mdoc_nodelist(meta,
572*fc3ee6fdSchristos 				    subn->head->child, h);
573*fc3ee6fdSchristos 				print_tagq(h, tsub);
574*fc3ee6fdSchristos 			}
575*fc3ee6fdSchristos 			print_tagq(h, tsec);
576*fc3ee6fdSchristos 		}
577*fc3ee6fdSchristos 		print_tagq(h, t);
578*fc3ee6fdSchristos 		print_otag(h, TAG_SECTION, "c", "Sh");
579*fc3ee6fdSchristos 		break;
580b2070ba5Schristos 	case ROFFT_HEAD:
5819d9b81f7Schristos 		id = html_make_id(n, 1);
582*fc3ee6fdSchristos 		print_otag(h, TAG_H1, "ci", "Sh", id);
5839d9b81f7Schristos 		if (id != NULL)
5849d9b81f7Schristos 			print_otag(h, TAG_A, "chR", "permalink", id);
585b2070ba5Schristos 		break;
58647a17e0dSchristos 	case ROFFT_BODY:
5870511d63cSchristos 		if (n->sec == SEC_AUTHORS)
5880511d63cSchristos 			h->flags &= ~(HTML_SPLIT|HTML_NOSPLIT);
589b2070ba5Schristos 		break;
5900511d63cSchristos 	default:
5910511d63cSchristos 		break;
5920511d63cSchristos 	}
59347a17e0dSchristos 	return 1;
5944154958bSjoerg }
5954154958bSjoerg 
5964154958bSjoerg static int
mdoc_ss_pre(MDOC_ARGS)5974154958bSjoerg mdoc_ss_pre(MDOC_ARGS)
5984154958bSjoerg {
599b2070ba5Schristos 	char	*id;
6004154958bSjoerg 
601*fc3ee6fdSchristos 	switch (n->type) {
602*fc3ee6fdSchristos 	case ROFFT_BLOCK:
603*fc3ee6fdSchristos 		html_close_paragraph(h);
604*fc3ee6fdSchristos 		print_otag(h, TAG_SECTION, "c", "Ss");
60547a17e0dSchristos 		return 1;
606*fc3ee6fdSchristos 	case ROFFT_HEAD:
607*fc3ee6fdSchristos 		break;
608*fc3ee6fdSchristos 	case ROFFT_BODY:
609*fc3ee6fdSchristos 		return 1;
610*fc3ee6fdSchristos 	default:
611*fc3ee6fdSchristos 		abort();
612*fc3ee6fdSchristos 	}
6134154958bSjoerg 
6149d9b81f7Schristos 	id = html_make_id(n, 1);
615*fc3ee6fdSchristos 	print_otag(h, TAG_H2, "ci", "Ss", id);
6169d9b81f7Schristos 	if (id != NULL)
6179d9b81f7Schristos 		print_otag(h, TAG_A, "chR", "permalink", id);
61847a17e0dSchristos 	return 1;
6194154958bSjoerg }
6204154958bSjoerg 
6214154958bSjoerg static int
mdoc_fl_pre(MDOC_ARGS)6224154958bSjoerg mdoc_fl_pre(MDOC_ARGS)
6234154958bSjoerg {
6249d9b81f7Schristos 	char	*id;
625d5e63c8dSjoerg 
6269d9b81f7Schristos 	if ((id = cond_id(n)) != NULL)
6279d9b81f7Schristos 		print_otag(h, TAG_A, "chR", "permalink", id);
628*fc3ee6fdSchristos 	print_otag(h, TAG_CODE, "ci", "Fl", id);
6299d9b81f7Schristos 
6309d9b81f7Schristos 	print_text(h, "\\-");
63147a17e0dSchristos 	if (!(n->child == NULL &&
6320511d63cSchristos 	    (n->next == NULL ||
63347a17e0dSchristos 	     n->next->type == ROFFT_TEXT ||
634b2070ba5Schristos 	     n->next->flags & NODE_LINE)))
6357bcc2a5fSjoerg 		h->flags |= HTML_NOSPACE;
636d5e63c8dSjoerg 
63747a17e0dSchristos 	return 1;
6384154958bSjoerg }
6394154958bSjoerg 
6404154958bSjoerg static int
mdoc_cm_pre(MDOC_ARGS)641b2070ba5Schristos mdoc_cm_pre(MDOC_ARGS)
642b2070ba5Schristos {
6439d9b81f7Schristos 	char	*id;
6449d9b81f7Schristos 
6459d9b81f7Schristos 	if ((id = cond_id(n)) != NULL)
6469d9b81f7Schristos 		print_otag(h, TAG_A, "chR", "permalink", id);
647*fc3ee6fdSchristos 	print_otag(h, TAG_CODE, "ci", "Cm", id);
648b2070ba5Schristos 	return 1;
649b2070ba5Schristos }
650b2070ba5Schristos 
651b2070ba5Schristos static int
mdoc_nd_pre(MDOC_ARGS)6524154958bSjoerg mdoc_nd_pre(MDOC_ARGS)
6534154958bSjoerg {
654*fc3ee6fdSchristos 	switch (n->type) {
655*fc3ee6fdSchristos 	case ROFFT_BLOCK:
656*fc3ee6fdSchristos 		html_close_paragraph(h);
65747a17e0dSchristos 		return 1;
658*fc3ee6fdSchristos 	case ROFFT_HEAD:
659*fc3ee6fdSchristos 		return 0;
660*fc3ee6fdSchristos 	case ROFFT_BODY:
661*fc3ee6fdSchristos 		break;
662*fc3ee6fdSchristos 	default:
663*fc3ee6fdSchristos 		abort();
664*fc3ee6fdSchristos 	}
6654154958bSjoerg 	print_text(h, "\\(em");
6669d9b81f7Schristos 	/* Cannot use TAG_SPAN because it may contain blocks. */
667*fc3ee6fdSchristos 	print_otag(h, TAG_DIV, "c", "Nd");
66847a17e0dSchristos 	return 1;
6694154958bSjoerg }
6704154958bSjoerg 
6714154958bSjoerg static int
mdoc_nm_pre(MDOC_ARGS)6724154958bSjoerg mdoc_nm_pre(MDOC_ARGS)
6734154958bSjoerg {
674e4fbeb7eSjoerg 	switch (n->type) {
675*fc3ee6fdSchristos 	case ROFFT_BLOCK:
676*fc3ee6fdSchristos 		break;
67747a17e0dSchristos 	case ROFFT_HEAD:
678b2070ba5Schristos 		print_otag(h, TAG_TD, "");
67947a17e0dSchristos 		/* FALLTHROUGH */
68047a17e0dSchristos 	case ROFFT_ELEM:
681*fc3ee6fdSchristos 		print_otag(h, TAG_CODE, "c", "Nm");
68247a17e0dSchristos 		return 1;
68347a17e0dSchristos 	case ROFFT_BODY:
684b2070ba5Schristos 		print_otag(h, TAG_TD, "");
68547a17e0dSchristos 		return 1;
686e4fbeb7eSjoerg 	default:
687*fc3ee6fdSchristos 		abort();
68882361f10Sjoerg 	}
689*fc3ee6fdSchristos 	html_close_paragraph(h);
690e4fbeb7eSjoerg 	synopsis_pre(h, n);
691b2070ba5Schristos 	print_otag(h, TAG_TABLE, "c", "Nm");
692b2070ba5Schristos 	print_otag(h, TAG_TR, "");
69347a17e0dSchristos 	return 1;
6944154958bSjoerg }
6954154958bSjoerg 
6964154958bSjoerg static int
mdoc_xr_pre(MDOC_ARGS)6974154958bSjoerg mdoc_xr_pre(MDOC_ARGS)
6984154958bSjoerg {
6997bcc2a5fSjoerg 	if (NULL == n->child)
70047a17e0dSchristos 		return 0;
7017bcc2a5fSjoerg 
702*fc3ee6fdSchristos 	if (h->base_man1)
703*fc3ee6fdSchristos 		print_otag(h, TAG_A, "chM", "Xr",
704b2070ba5Schristos 		    n->child->string, n->child->next == NULL ?
705b2070ba5Schristos 		    NULL : n->child->next->string);
706b2070ba5Schristos 	else
707*fc3ee6fdSchristos 		print_otag(h, TAG_A, "c", "Xr");
7084154958bSjoerg 
70954a4f7feSjoerg 	n = n->child;
71054a4f7feSjoerg 	print_text(h, n->string);
7114154958bSjoerg 
71254a4f7feSjoerg 	if (NULL == (n = n->next))
71347a17e0dSchristos 		return 0;
7144154958bSjoerg 
7154154958bSjoerg 	h->flags |= HTML_NOSPACE;
7164154958bSjoerg 	print_text(h, "(");
7174154958bSjoerg 	h->flags |= HTML_NOSPACE;
71854a4f7feSjoerg 	print_text(h, n->string);
7194154958bSjoerg 	h->flags |= HTML_NOSPACE;
7204154958bSjoerg 	print_text(h, ")");
72147a17e0dSchristos 	return 0;
7224154958bSjoerg }
7234154958bSjoerg 
7244154958bSjoerg static int
mdoc_ns_pre(MDOC_ARGS)7254154958bSjoerg mdoc_ns_pre(MDOC_ARGS)
7264154958bSjoerg {
7274154958bSjoerg 
728b2070ba5Schristos 	if ( ! (NODE_LINE & n->flags))
7294154958bSjoerg 		h->flags |= HTML_NOSPACE;
73047a17e0dSchristos 	return 1;
7314154958bSjoerg }
7324154958bSjoerg 
7334154958bSjoerg static int
mdoc_ar_pre(MDOC_ARGS)7344154958bSjoerg mdoc_ar_pre(MDOC_ARGS)
7354154958bSjoerg {
736*fc3ee6fdSchristos 	print_otag(h, TAG_VAR, "c", "Ar");
73747a17e0dSchristos 	return 1;
7384154958bSjoerg }
7394154958bSjoerg 
7404154958bSjoerg static int
mdoc_xx_pre(MDOC_ARGS)7414154958bSjoerg mdoc_xx_pre(MDOC_ARGS)
7424154958bSjoerg {
743b2070ba5Schristos 	print_otag(h, TAG_SPAN, "c", "Ux");
74447a17e0dSchristos 	return 1;
7454154958bSjoerg }
7464154958bSjoerg 
7474154958bSjoerg static int
mdoc_it_pre(MDOC_ARGS)7484154958bSjoerg mdoc_it_pre(MDOC_ARGS)
7494154958bSjoerg {
75047a17e0dSchristos 	const struct roff_node	*bl;
751b2070ba5Schristos 	enum mdoc_list		 type;
7524154958bSjoerg 
753e4fbeb7eSjoerg 	bl = n->parent;
7549d9b81f7Schristos 	while (bl->tok != MDOC_Bl)
7554154958bSjoerg 		bl = bl->parent;
756e4fbeb7eSjoerg 	type = bl->norm->Bl.type;
7576c26a9aaSjoerg 
758b2070ba5Schristos 	switch (type) {
759b2070ba5Schristos 	case LIST_bullet:
7600511d63cSchristos 	case LIST_dash:
7610511d63cSchristos 	case LIST_hyphen:
762b2070ba5Schristos 	case LIST_item:
7630511d63cSchristos 	case LIST_enum:
764b2070ba5Schristos 		switch (n->type) {
765b2070ba5Schristos 		case ROFFT_HEAD:
76647a17e0dSchristos 			return 0;
767b2070ba5Schristos 		case ROFFT_BODY:
7689d9b81f7Schristos 			print_otag(h, TAG_LI, "");
7694154958bSjoerg 			break;
7704154958bSjoerg 		default:
7714154958bSjoerg 			break;
7724154958bSjoerg 		}
773e4fbeb7eSjoerg 		break;
7740511d63cSchristos 	case LIST_diag:
7750511d63cSchristos 	case LIST_hang:
7760511d63cSchristos 	case LIST_inset:
7770511d63cSchristos 	case LIST_ohang:
778b2070ba5Schristos 		switch (n->type) {
779b2070ba5Schristos 		case ROFFT_HEAD:
7809d9b81f7Schristos 			print_otag(h, TAG_DT, "");
781b2070ba5Schristos 			break;
782b2070ba5Schristos 		case ROFFT_BODY:
7839d9b81f7Schristos 			print_otag(h, TAG_DD, "");
784b2070ba5Schristos 			break;
785b2070ba5Schristos 		default:
786b2070ba5Schristos 			break;
787b2070ba5Schristos 		}
788b2070ba5Schristos 		break;
7890511d63cSchristos 	case LIST_tag:
790b2070ba5Schristos 		switch (n->type) {
791b2070ba5Schristos 		case ROFFT_HEAD:
7929d9b81f7Schristos 			print_otag(h, TAG_DT, "");
793e4fbeb7eSjoerg 			break;
794b2070ba5Schristos 		case ROFFT_BODY:
795b2070ba5Schristos 			if (n->child == NULL) {
7969d9b81f7Schristos 				print_otag(h, TAG_DD, "s", "width", "auto");
797b2070ba5Schristos 				print_text(h, "\\ ");
798b2070ba5Schristos 			} else
7999d9b81f7Schristos 				print_otag(h, TAG_DD, "");
800e4fbeb7eSjoerg 			break;
801e4fbeb7eSjoerg 		default:
802e4fbeb7eSjoerg 			break;
803e4fbeb7eSjoerg 		}
804b2070ba5Schristos 		break;
8050511d63cSchristos 	case LIST_column:
806b2070ba5Schristos 		switch (n->type) {
807b2070ba5Schristos 		case ROFFT_HEAD:
808b2070ba5Schristos 			break;
809b2070ba5Schristos 		case ROFFT_BODY:
8109d9b81f7Schristos 			print_otag(h, TAG_TD, "");
811e4fbeb7eSjoerg 			break;
812e4fbeb7eSjoerg 		default:
8139d9b81f7Schristos 			print_otag(h, TAG_TR, "");
814e4fbeb7eSjoerg 		}
815b2070ba5Schristos 	default:
816b2070ba5Schristos 		break;
8174154958bSjoerg 	}
8184154958bSjoerg 
81947a17e0dSchristos 	return 1;
8204154958bSjoerg }
8214154958bSjoerg 
8224154958bSjoerg static int
mdoc_bl_pre(MDOC_ARGS)8234154958bSjoerg mdoc_bl_pre(MDOC_ARGS)
8244154958bSjoerg {
825*fc3ee6fdSchristos 	char		 cattr[32];
826b2070ba5Schristos 	struct mdoc_bl	*bl;
827b2070ba5Schristos 	enum htmltag	 elemtype;
8284154958bSjoerg 
829b2070ba5Schristos 	switch (n->type) {
830*fc3ee6fdSchristos 	case ROFFT_BLOCK:
831*fc3ee6fdSchristos 		html_close_paragraph(h);
832*fc3ee6fdSchristos 		break;
833b2070ba5Schristos 	case ROFFT_HEAD:
83447a17e0dSchristos 		return 0;
835*fc3ee6fdSchristos 	case ROFFT_BODY:
836*fc3ee6fdSchristos 		return 1;
837b2070ba5Schristos 	default:
838*fc3ee6fdSchristos 		abort();
8394154958bSjoerg 	}
8404154958bSjoerg 
8419d9b81f7Schristos 	bl = &n->norm->Bl;
842b2070ba5Schristos 	switch (bl->type) {
8430511d63cSchristos 	case LIST_bullet:
844b2070ba5Schristos 		elemtype = TAG_UL;
8459d9b81f7Schristos 		(void)strlcpy(cattr, "Bl-bullet", sizeof(cattr));
846b2070ba5Schristos 		break;
8470511d63cSchristos 	case LIST_dash:
8480511d63cSchristos 	case LIST_hyphen:
849b2070ba5Schristos 		elemtype = TAG_UL;
8509d9b81f7Schristos 		(void)strlcpy(cattr, "Bl-dash", sizeof(cattr));
851b2070ba5Schristos 		break;
8520511d63cSchristos 	case LIST_item:
853b2070ba5Schristos 		elemtype = TAG_UL;
8549d9b81f7Schristos 		(void)strlcpy(cattr, "Bl-item", sizeof(cattr));
855e4fbeb7eSjoerg 		break;
8560511d63cSchristos 	case LIST_enum:
857b2070ba5Schristos 		elemtype = TAG_OL;
8589d9b81f7Schristos 		(void)strlcpy(cattr, "Bl-enum", sizeof(cattr));
859e4fbeb7eSjoerg 		break;
8600511d63cSchristos 	case LIST_diag:
861b2070ba5Schristos 		elemtype = TAG_DL;
8629d9b81f7Schristos 		(void)strlcpy(cattr, "Bl-diag", sizeof(cattr));
863e4fbeb7eSjoerg 		break;
864b2070ba5Schristos 	case LIST_hang:
865b2070ba5Schristos 		elemtype = TAG_DL;
8669d9b81f7Schristos 		(void)strlcpy(cattr, "Bl-hang", sizeof(cattr));
867b2070ba5Schristos 		break;
868b2070ba5Schristos 	case LIST_inset:
869b2070ba5Schristos 		elemtype = TAG_DL;
8709d9b81f7Schristos 		(void)strlcpy(cattr, "Bl-inset", sizeof(cattr));
871b2070ba5Schristos 		break;
872b2070ba5Schristos 	case LIST_ohang:
873b2070ba5Schristos 		elemtype = TAG_DL;
8749d9b81f7Schristos 		(void)strlcpy(cattr, "Bl-ohang", sizeof(cattr));
875b2070ba5Schristos 		break;
876b2070ba5Schristos 	case LIST_tag:
877b2070ba5Schristos 		if (bl->offs)
8789d9b81f7Schristos 			print_otag(h, TAG_DIV, "c", "Bd-indent");
8799d9b81f7Schristos 		print_otag(h, TAG_DL, "c", bl->comp ?
8809d9b81f7Schristos 		    "Bl-tag Bl-compact" : "Bl-tag");
881b2070ba5Schristos 		return 1;
8820511d63cSchristos 	case LIST_column:
883b2070ba5Schristos 		elemtype = TAG_TABLE;
8849d9b81f7Schristos 		(void)strlcpy(cattr, "Bl-column", sizeof(cattr));
885e4fbeb7eSjoerg 		break;
886e4fbeb7eSjoerg 	default:
887e4fbeb7eSjoerg 		abort();
888e4fbeb7eSjoerg 	}
8899d9b81f7Schristos 	if (bl->offs != NULL)
8909d9b81f7Schristos 		(void)strlcat(cattr, " Bd-indent", sizeof(cattr));
8919d9b81f7Schristos 	if (bl->comp)
8929d9b81f7Schristos 		(void)strlcat(cattr, " Bl-compact", sizeof(cattr));
8939d9b81f7Schristos 	print_otag(h, elemtype, "c", cattr);
89447a17e0dSchristos 	return 1;
895e4fbeb7eSjoerg }
8964154958bSjoerg 
8974154958bSjoerg static int
mdoc_ex_pre(MDOC_ARGS)8984154958bSjoerg mdoc_ex_pre(MDOC_ARGS)
8994154958bSjoerg {
900e4fbeb7eSjoerg 	if (n->prev)
901b2070ba5Schristos 		print_otag(h, TAG_BR, "");
902b2070ba5Schristos 	return 1;
9034154958bSjoerg }
9044154958bSjoerg 
905b2070ba5Schristos static int
mdoc_st_pre(MDOC_ARGS)906b2070ba5Schristos mdoc_st_pre(MDOC_ARGS)
907b2070ba5Schristos {
908*fc3ee6fdSchristos 	print_otag(h, TAG_SPAN, "c", "St");
909b2070ba5Schristos 	return 1;
9104154958bSjoerg }
9114154958bSjoerg 
9124154958bSjoerg static int
mdoc_em_pre(MDOC_ARGS)9134154958bSjoerg mdoc_em_pre(MDOC_ARGS)
9144154958bSjoerg {
915*fc3ee6fdSchristos 	print_otag(h, TAG_I, "c", "Em");
91647a17e0dSchristos 	return 1;
9174154958bSjoerg }
9184154958bSjoerg 
9194154958bSjoerg static int
mdoc_d1_pre(MDOC_ARGS)9204154958bSjoerg mdoc_d1_pre(MDOC_ARGS)
9214154958bSjoerg {
922*fc3ee6fdSchristos 	switch (n->type) {
923*fc3ee6fdSchristos 	case ROFFT_BLOCK:
924*fc3ee6fdSchristos 		html_close_paragraph(h);
925*fc3ee6fdSchristos 		break;
926*fc3ee6fdSchristos 	case ROFFT_HEAD:
927*fc3ee6fdSchristos 		return 0;
928*fc3ee6fdSchristos 	case ROFFT_BODY:
92947a17e0dSchristos 		return 1;
930*fc3ee6fdSchristos 	default:
931*fc3ee6fdSchristos 		abort();
932*fc3ee6fdSchristos 	}
9339d9b81f7Schristos 	print_otag(h, TAG_DIV, "c", "Bd Bd-indent");
934b2070ba5Schristos 	if (n->tok == MDOC_Dl)
935b2070ba5Schristos 		print_otag(h, TAG_CODE, "c", "Li");
93647a17e0dSchristos 	return 1;
9374154958bSjoerg }
9384154958bSjoerg 
9394154958bSjoerg static int
mdoc_sx_pre(MDOC_ARGS)9404154958bSjoerg mdoc_sx_pre(MDOC_ARGS)
9414154958bSjoerg {
942b2070ba5Schristos 	char	*id;
9434154958bSjoerg 
9449d9b81f7Schristos 	id = html_make_id(n, 0);
945*fc3ee6fdSchristos 	print_otag(h, TAG_A, "chR", "Sx", id);
946b2070ba5Schristos 	free(id);
94747a17e0dSchristos 	return 1;
9484154958bSjoerg }
9494154958bSjoerg 
9504154958bSjoerg static int
mdoc_bd_pre(MDOC_ARGS)9514154958bSjoerg mdoc_bd_pre(MDOC_ARGS)
9524154958bSjoerg {
953*fc3ee6fdSchristos 	char			 buf[16];
95447a17e0dSchristos 	struct roff_node	*nn;
955*fc3ee6fdSchristos 	int			 comp;
9564154958bSjoerg 
957*fc3ee6fdSchristos 	switch (n->type) {
958*fc3ee6fdSchristos 	case ROFFT_BLOCK:
959*fc3ee6fdSchristos 		html_close_paragraph(h);
960*fc3ee6fdSchristos 		return 1;
961*fc3ee6fdSchristos 	case ROFFT_HEAD:
96247a17e0dSchristos 		return 0;
963*fc3ee6fdSchristos 	case ROFFT_BODY:
964*fc3ee6fdSchristos 		break;
965*fc3ee6fdSchristos 	default:
966*fc3ee6fdSchristos 		abort();
967*fc3ee6fdSchristos 	}
9684154958bSjoerg 
969*fc3ee6fdSchristos 	/* Handle preceding whitespace. */
970*fc3ee6fdSchristos 
971e4fbeb7eSjoerg 	comp = n->norm->Bd.comp;
972*fc3ee6fdSchristos 	for (nn = n; nn != NULL && comp == 0; nn = nn->parent) {
97347a17e0dSchristos 		if (nn->type != ROFFT_BLOCK)
9744154958bSjoerg 			continue;
975*fc3ee6fdSchristos 		if (nn->tok == MDOC_Sh || nn->tok == MDOC_Ss)
9764154958bSjoerg 			comp = 1;
977*fc3ee6fdSchristos 		if (nn->prev != NULL)
9784154958bSjoerg 			break;
9794154958bSjoerg 	}
980*fc3ee6fdSchristos 	(void)strlcpy(buf, "Bd", sizeof(buf));
981*fc3ee6fdSchristos 	if (comp == 0)
982*fc3ee6fdSchristos 		(void)strlcat(buf, " Pp", sizeof(buf));
9834154958bSjoerg 
9840511d63cSchristos 	/* Handle the -offset argument. */
9850511d63cSchristos 
986*fc3ee6fdSchristos 	if (n->norm->Bd.offs != NULL &&
987*fc3ee6fdSchristos 	    strcmp(n->norm->Bd.offs, "left") != 0)
988*fc3ee6fdSchristos 		(void)strlcat(buf, " Bd-indent", sizeof(buf));
989e4fbeb7eSjoerg 
990*fc3ee6fdSchristos 	print_otag(h, TAG_DIV, "c", buf);
99147a17e0dSchristos 	return 1;
9924154958bSjoerg }
9934154958bSjoerg 
9944154958bSjoerg static int
mdoc_pa_pre(MDOC_ARGS)9954154958bSjoerg mdoc_pa_pre(MDOC_ARGS)
9964154958bSjoerg {
997*fc3ee6fdSchristos 	print_otag(h, TAG_SPAN, "c", "Pa");
99847a17e0dSchristos 	return 1;
9994154958bSjoerg }
10004154958bSjoerg 
10014154958bSjoerg static int
mdoc_ad_pre(MDOC_ARGS)10024154958bSjoerg mdoc_ad_pre(MDOC_ARGS)
10034154958bSjoerg {
10049d9b81f7Schristos 	print_otag(h, TAG_SPAN, "c", "Ad");
100547a17e0dSchristos 	return 1;
10064154958bSjoerg }
10074154958bSjoerg 
10084154958bSjoerg static int
mdoc_an_pre(MDOC_ARGS)10094154958bSjoerg mdoc_an_pre(MDOC_ARGS)
10104154958bSjoerg {
10110511d63cSchristos 	if (n->norm->An.auth == AUTH_split) {
10120511d63cSchristos 		h->flags &= ~HTML_NOSPLIT;
10130511d63cSchristos 		h->flags |= HTML_SPLIT;
101447a17e0dSchristos 		return 0;
10150511d63cSchristos 	}
10160511d63cSchristos 	if (n->norm->An.auth == AUTH_nosplit) {
10170511d63cSchristos 		h->flags &= ~HTML_SPLIT;
10180511d63cSchristos 		h->flags |= HTML_NOSPLIT;
101947a17e0dSchristos 		return 0;
10200511d63cSchristos 	}
10210511d63cSchristos 
10220511d63cSchristos 	if (h->flags & HTML_SPLIT)
1023b2070ba5Schristos 		print_otag(h, TAG_BR, "");
10240511d63cSchristos 
10250511d63cSchristos 	if (n->sec == SEC_AUTHORS && ! (h->flags & HTML_NOSPLIT))
10260511d63cSchristos 		h->flags |= HTML_SPLIT;
10274154958bSjoerg 
1028*fc3ee6fdSchristos 	print_otag(h, TAG_SPAN, "c", "An");
102947a17e0dSchristos 	return 1;
10304154958bSjoerg }
10314154958bSjoerg 
10324154958bSjoerg static int
mdoc_cd_pre(MDOC_ARGS)10334154958bSjoerg mdoc_cd_pre(MDOC_ARGS)
10344154958bSjoerg {
10357574e07eSjoerg 	synopsis_pre(h, n);
1036*fc3ee6fdSchristos 	print_otag(h, TAG_CODE, "c", "Cd");
103747a17e0dSchristos 	return 1;
10384154958bSjoerg }
10394154958bSjoerg 
10404154958bSjoerg static int
mdoc_dv_pre(MDOC_ARGS)10414154958bSjoerg mdoc_dv_pre(MDOC_ARGS)
10424154958bSjoerg {
10439d9b81f7Schristos 	char	*id;
10449d9b81f7Schristos 
10459d9b81f7Schristos 	if ((id = cond_id(n)) != NULL)
10469d9b81f7Schristos 		print_otag(h, TAG_A, "chR", "permalink", id);
1047*fc3ee6fdSchristos 	print_otag(h, TAG_CODE, "ci", "Dv", id);
104847a17e0dSchristos 	return 1;
10494154958bSjoerg }
10504154958bSjoerg 
10514154958bSjoerg static int
mdoc_ev_pre(MDOC_ARGS)10524154958bSjoerg mdoc_ev_pre(MDOC_ARGS)
10534154958bSjoerg {
10549d9b81f7Schristos 	char	*id;
10559d9b81f7Schristos 
10569d9b81f7Schristos 	if ((id = cond_id(n)) != NULL)
10579d9b81f7Schristos 		print_otag(h, TAG_A, "chR", "permalink", id);
1058*fc3ee6fdSchristos 	print_otag(h, TAG_CODE, "ci", "Ev", id);
105947a17e0dSchristos 	return 1;
10604154958bSjoerg }
10614154958bSjoerg 
10624154958bSjoerg static int
mdoc_er_pre(MDOC_ARGS)10634154958bSjoerg mdoc_er_pre(MDOC_ARGS)
10644154958bSjoerg {
10659d9b81f7Schristos 	char	*id;
10669d9b81f7Schristos 
10679d9b81f7Schristos 	id = n->sec == SEC_ERRORS &&
10689d9b81f7Schristos 	    (n->parent->tok == MDOC_It ||
10699d9b81f7Schristos 	     (n->parent->tok == MDOC_Bq &&
10709d9b81f7Schristos 	      n->parent->parent->parent->tok == MDOC_It)) ?
10719d9b81f7Schristos 	    html_make_id(n, 1) : NULL;
10729d9b81f7Schristos 
10739d9b81f7Schristos 	if (id != NULL)
10749d9b81f7Schristos 		print_otag(h, TAG_A, "chR", "permalink", id);
1075*fc3ee6fdSchristos 	print_otag(h, TAG_CODE, "ci", "Er", id);
107647a17e0dSchristos 	return 1;
10774154958bSjoerg }
10784154958bSjoerg 
10794154958bSjoerg static int
mdoc_fa_pre(MDOC_ARGS)10804154958bSjoerg mdoc_fa_pre(MDOC_ARGS)
10814154958bSjoerg {
108247a17e0dSchristos 	const struct roff_node	*nn;
10834154958bSjoerg 	struct tag		*t;
10844154958bSjoerg 
10854154958bSjoerg 	if (n->parent->tok != MDOC_Fo) {
1086*fc3ee6fdSchristos 		print_otag(h, TAG_VAR, "c", "Fa");
108747a17e0dSchristos 		return 1;
10884154958bSjoerg 	}
10894154958bSjoerg 
10904154958bSjoerg 	for (nn = n->child; nn; nn = nn->next) {
1091*fc3ee6fdSchristos 		t = print_otag(h, TAG_VAR, "c", "Fa");
10924154958bSjoerg 		print_text(h, nn->string);
10934154958bSjoerg 		print_tagq(h, t);
109454a4f7feSjoerg 		if (nn->next) {
109554a4f7feSjoerg 			h->flags |= HTML_NOSPACE;
10964154958bSjoerg 			print_text(h, ",");
10974154958bSjoerg 		}
109854a4f7feSjoerg 	}
10994154958bSjoerg 
110054a4f7feSjoerg 	if (n->child && n->next && n->next->tok == MDOC_Fa) {
110154a4f7feSjoerg 		h->flags |= HTML_NOSPACE;
11024154958bSjoerg 		print_text(h, ",");
110354a4f7feSjoerg 	}
11044154958bSjoerg 
110547a17e0dSchristos 	return 0;
11064154958bSjoerg }
11074154958bSjoerg 
11084154958bSjoerg static int
mdoc_fd_pre(MDOC_ARGS)11094154958bSjoerg mdoc_fd_pre(MDOC_ARGS)
11104154958bSjoerg {
111154a4f7feSjoerg 	struct tag	*t;
1112b2070ba5Schristos 	char		*buf, *cp;
11134154958bSjoerg 
11147574e07eSjoerg 	synopsis_pre(h, n);
11154154958bSjoerg 
111654a4f7feSjoerg 	if (NULL == (n = n->child))
111747a17e0dSchristos 		return 0;
111854a4f7feSjoerg 
111947a17e0dSchristos 	assert(n->type == ROFFT_TEXT);
112054a4f7feSjoerg 
112154a4f7feSjoerg 	if (strcmp(n->string, "#include")) {
1122*fc3ee6fdSchristos 		print_otag(h, TAG_CODE, "c", "Fd");
112347a17e0dSchristos 		return 1;
11244154958bSjoerg 	}
11254154958bSjoerg 
1126*fc3ee6fdSchristos 	print_otag(h, TAG_CODE, "c", "In");
112754a4f7feSjoerg 	print_text(h, n->string);
112854a4f7feSjoerg 
112954a4f7feSjoerg 	if (NULL != (n = n->next)) {
113047a17e0dSchristos 		assert(n->type == ROFFT_TEXT);
11310511d63cSchristos 
113254a4f7feSjoerg 		if (h->base_includes) {
1133b2070ba5Schristos 			cp = n->string;
1134b2070ba5Schristos 			if (*cp == '<' || *cp == '"')
1135b2070ba5Schristos 				cp++;
1136b2070ba5Schristos 			buf = mandoc_strdup(cp);
1137b2070ba5Schristos 			cp = strchr(buf, '\0') - 1;
1138b2070ba5Schristos 			if (cp >= buf && (*cp == '>' || *cp == '"'))
1139b2070ba5Schristos 				*cp = '\0';
1140*fc3ee6fdSchristos 			t = print_otag(h, TAG_A, "chI", "In", buf);
1141b2070ba5Schristos 			free(buf);
1142b2070ba5Schristos 		} else
1143*fc3ee6fdSchristos 			t = print_otag(h, TAG_A, "c", "In");
114454a4f7feSjoerg 
114554a4f7feSjoerg 		print_text(h, n->string);
114654a4f7feSjoerg 		print_tagq(h, t);
114754a4f7feSjoerg 
114854a4f7feSjoerg 		n = n->next;
114954a4f7feSjoerg 	}
115054a4f7feSjoerg 
115154a4f7feSjoerg 	for ( ; n; n = n->next) {
115247a17e0dSchristos 		assert(n->type == ROFFT_TEXT);
115354a4f7feSjoerg 		print_text(h, n->string);
115454a4f7feSjoerg 	}
115554a4f7feSjoerg 
115647a17e0dSchristos 	return 0;
115754a4f7feSjoerg }
115854a4f7feSjoerg 
11594154958bSjoerg static int
mdoc_vt_pre(MDOC_ARGS)11604154958bSjoerg mdoc_vt_pre(MDOC_ARGS)
11614154958bSjoerg {
116247a17e0dSchristos 	if (n->type == ROFFT_BLOCK) {
11637574e07eSjoerg 		synopsis_pre(h, n);
116447a17e0dSchristos 		return 1;
116547a17e0dSchristos 	} else if (n->type == ROFFT_ELEM) {
11667574e07eSjoerg 		synopsis_pre(h, n);
116747a17e0dSchristos 	} else if (n->type == ROFFT_HEAD)
116847a17e0dSchristos 		return 0;
11694154958bSjoerg 
1170*fc3ee6fdSchristos 	print_otag(h, TAG_VAR, "c", "Vt");
117147a17e0dSchristos 	return 1;
11724154958bSjoerg }
11734154958bSjoerg 
11744154958bSjoerg static int
mdoc_ft_pre(MDOC_ARGS)11754154958bSjoerg mdoc_ft_pre(MDOC_ARGS)
11764154958bSjoerg {
11777574e07eSjoerg 	synopsis_pre(h, n);
1178*fc3ee6fdSchristos 	print_otag(h, TAG_VAR, "c", "Ft");
117947a17e0dSchristos 	return 1;
11804154958bSjoerg }
11814154958bSjoerg 
11824154958bSjoerg static int
mdoc_fn_pre(MDOC_ARGS)11834154958bSjoerg mdoc_fn_pre(MDOC_ARGS)
11844154958bSjoerg {
11854154958bSjoerg 	struct tag	*t;
11864154958bSjoerg 	char		 nbuf[BUFSIZ];
11874154958bSjoerg 	const char	*sp, *ep;
1188b2070ba5Schristos 	int		 sz, pretty;
11894154958bSjoerg 
1190b2070ba5Schristos 	pretty = NODE_SYNPRETTY & n->flags;
11917574e07eSjoerg 	synopsis_pre(h, n);
11924154958bSjoerg 
11934154958bSjoerg 	/* Split apart into type and name. */
11944154958bSjoerg 	assert(n->child->string);
11954154958bSjoerg 	sp = n->child->string;
11964154958bSjoerg 
11974154958bSjoerg 	ep = strchr(sp, ' ');
11984154958bSjoerg 	if (NULL != ep) {
1199*fc3ee6fdSchristos 		t = print_otag(h, TAG_VAR, "c", "Ft");
12004154958bSjoerg 
12014154958bSjoerg 		while (ep) {
12024154958bSjoerg 			sz = MIN((int)(ep - sp), BUFSIZ - 1);
12034154958bSjoerg 			(void)memcpy(nbuf, sp, (size_t)sz);
12044154958bSjoerg 			nbuf[sz] = '\0';
12054154958bSjoerg 			print_text(h, nbuf);
12064154958bSjoerg 			sp = ++ep;
12074154958bSjoerg 			ep = strchr(sp, ' ');
12084154958bSjoerg 		}
12094154958bSjoerg 		print_tagq(h, t);
12104154958bSjoerg 	}
12114154958bSjoerg 
1212*fc3ee6fdSchristos 	t = print_otag(h, TAG_CODE, "c", "Fn");
12134154958bSjoerg 
12140511d63cSchristos 	if (sp)
12150511d63cSchristos 		print_text(h, sp);
12164154958bSjoerg 
12174154958bSjoerg 	print_tagq(h, t);
12184154958bSjoerg 
12194154958bSjoerg 	h->flags |= HTML_NOSPACE;
12204154958bSjoerg 	print_text(h, "(");
122154a4f7feSjoerg 	h->flags |= HTML_NOSPACE;
12224154958bSjoerg 
122354a4f7feSjoerg 	for (n = n->child->next; n; n = n->next) {
1224b2070ba5Schristos 		if (NODE_SYNPRETTY & n->flags)
1225*fc3ee6fdSchristos 			t = print_otag(h, TAG_VAR, "cs", "Fa",
1226b2070ba5Schristos 			    "white-space", "nowrap");
1227b2070ba5Schristos 		else
1228*fc3ee6fdSchristos 			t = print_otag(h, TAG_VAR, "c", "Fa");
122954a4f7feSjoerg 		print_text(h, n->string);
12304154958bSjoerg 		print_tagq(h, t);
123154a4f7feSjoerg 		if (n->next) {
123254a4f7feSjoerg 			h->flags |= HTML_NOSPACE;
12334154958bSjoerg 			print_text(h, ",");
12344154958bSjoerg 		}
123554a4f7feSjoerg 	}
12364154958bSjoerg 
123754a4f7feSjoerg 	h->flags |= HTML_NOSPACE;
12384154958bSjoerg 	print_text(h, ")");
123954a4f7feSjoerg 
124054a4f7feSjoerg 	if (pretty) {
124154a4f7feSjoerg 		h->flags |= HTML_NOSPACE;
12424154958bSjoerg 		print_text(h, ";");
124354a4f7feSjoerg 	}
12444154958bSjoerg 
124547a17e0dSchristos 	return 0;
12464154958bSjoerg }
12474154958bSjoerg 
12484154958bSjoerg static int
mdoc_sm_pre(MDOC_ARGS)12497da9b934Sjoerg mdoc_sm_pre(MDOC_ARGS)
12507da9b934Sjoerg {
12517da9b934Sjoerg 
12520511d63cSchristos 	if (NULL == n->child)
12530511d63cSchristos 		h->flags ^= HTML_NONOSPACE;
12540511d63cSchristos 	else if (0 == strcmp("on", n->child->string))
12557da9b934Sjoerg 		h->flags &= ~HTML_NONOSPACE;
12560511d63cSchristos 	else
12577da9b934Sjoerg 		h->flags |= HTML_NONOSPACE;
12587da9b934Sjoerg 
12590511d63cSchristos 	if ( ! (HTML_NONOSPACE & h->flags))
12600511d63cSchristos 		h->flags &= ~HTML_NOSPACE;
12610511d63cSchristos 
126247a17e0dSchristos 	return 0;
12637da9b934Sjoerg }
12647da9b934Sjoerg 
12650511d63cSchristos static int
mdoc_skip_pre(MDOC_ARGS)12660511d63cSchristos mdoc_skip_pre(MDOC_ARGS)
12670511d63cSchristos {
12680511d63cSchristos 
126947a17e0dSchristos 	return 0;
12700511d63cSchristos }
12710511d63cSchristos 
1272e4fbeb7eSjoerg static int
mdoc_pp_pre(MDOC_ARGS)1273e4fbeb7eSjoerg mdoc_pp_pre(MDOC_ARGS)
1274e4fbeb7eSjoerg {
1275*fc3ee6fdSchristos 	if ((n->flags & NODE_NOFILL) == 0) {
1276*fc3ee6fdSchristos 		html_close_paragraph(h);
1277*fc3ee6fdSchristos 		print_otag(h, TAG_P, "c", "Pp");
1278*fc3ee6fdSchristos 	}
127947a17e0dSchristos 	return 0;
1280e4fbeb7eSjoerg }
12817da9b934Sjoerg 
12827da9b934Sjoerg static int
mdoc_lk_pre(MDOC_ARGS)12834154958bSjoerg mdoc_lk_pre(MDOC_ARGS)
12844154958bSjoerg {
12859d9b81f7Schristos 	const struct roff_node *link, *descr, *punct;
12869d9b81f7Schristos 	struct tag	*t;
12879d9b81f7Schristos 
12889d9b81f7Schristos 	if ((link = n->child) == NULL)
128947a17e0dSchristos 		return 0;
129054a4f7feSjoerg 
12919d9b81f7Schristos 	/* Find beginning of trailing punctuation. */
12929d9b81f7Schristos 	punct = n->last;
12939d9b81f7Schristos 	while (punct != link && punct->flags & NODE_DELIMC)
12949d9b81f7Schristos 		punct = punct->prev;
12959d9b81f7Schristos 	punct = punct->next;
12964154958bSjoerg 
12979d9b81f7Schristos 	/* Link target and link text. */
12989d9b81f7Schristos 	descr = link->next;
12999d9b81f7Schristos 	if (descr == punct)
13009d9b81f7Schristos 		descr = link;  /* no text */
1301*fc3ee6fdSchristos 	t = print_otag(h, TAG_A, "ch", "Lk", link->string);
13029d9b81f7Schristos 	do {
13039d9b81f7Schristos 		if (descr->flags & (NODE_DELIMC | NODE_DELIMO))
13049d9b81f7Schristos 			h->flags |= HTML_NOSPACE;
13059d9b81f7Schristos 		print_text(h, descr->string);
13069d9b81f7Schristos 		descr = descr->next;
13079d9b81f7Schristos 	} while (descr != punct);
13089d9b81f7Schristos 	print_tagq(h, t);
13094154958bSjoerg 
13109d9b81f7Schristos 	/* Trailing punctuation. */
13119d9b81f7Schristos 	while (punct != NULL) {
13129d9b81f7Schristos 		h->flags |= HTML_NOSPACE;
13139d9b81f7Schristos 		print_text(h, punct->string);
13149d9b81f7Schristos 		punct = punct->next;
13159d9b81f7Schristos 	}
131647a17e0dSchristos 	return 0;
13174154958bSjoerg }
13184154958bSjoerg 
13194154958bSjoerg static int
mdoc_mt_pre(MDOC_ARGS)13204154958bSjoerg mdoc_mt_pre(MDOC_ARGS)
13214154958bSjoerg {
13224154958bSjoerg 	struct tag	*t;
1323b2070ba5Schristos 	char		*cp;
13244154958bSjoerg 
132554a4f7feSjoerg 	for (n = n->child; n; n = n->next) {
132647a17e0dSchristos 		assert(n->type == ROFFT_TEXT);
132754a4f7feSjoerg 
1328b2070ba5Schristos 		mandoc_asprintf(&cp, "mailto:%s", n->string);
1329*fc3ee6fdSchristos 		t = print_otag(h, TAG_A, "ch", "Mt", cp);
133054a4f7feSjoerg 		print_text(h, n->string);
13314154958bSjoerg 		print_tagq(h, t);
1332b2070ba5Schristos 		free(cp);
13334154958bSjoerg 	}
13344154958bSjoerg 
133547a17e0dSchristos 	return 0;
13364154958bSjoerg }
13374154958bSjoerg 
13384154958bSjoerg static int
mdoc_fo_pre(MDOC_ARGS)13394154958bSjoerg mdoc_fo_pre(MDOC_ARGS)
13404154958bSjoerg {
13417574e07eSjoerg 	struct tag	*t;
13424154958bSjoerg 
134347a17e0dSchristos 	if (n->type == ROFFT_BODY) {
13444154958bSjoerg 		h->flags |= HTML_NOSPACE;
13454154958bSjoerg 		print_text(h, "(");
13464154958bSjoerg 		h->flags |= HTML_NOSPACE;
134747a17e0dSchristos 		return 1;
134847a17e0dSchristos 	} else if (n->type == ROFFT_BLOCK) {
13497574e07eSjoerg 		synopsis_pre(h, n);
135047a17e0dSchristos 		return 1;
13517bcc2a5fSjoerg 	}
13524154958bSjoerg 
135347a17e0dSchristos 	if (n->child == NULL)
135447a17e0dSchristos 		return 0;
13557574e07eSjoerg 
13567574e07eSjoerg 	assert(n->child->string);
1357*fc3ee6fdSchristos 	t = print_otag(h, TAG_CODE, "c", "Fn");
13587574e07eSjoerg 	print_text(h, n->child->string);
13597574e07eSjoerg 	print_tagq(h, t);
136047a17e0dSchristos 	return 0;
13614154958bSjoerg }
13624154958bSjoerg 
13634154958bSjoerg static void
mdoc_fo_post(MDOC_ARGS)13644154958bSjoerg mdoc_fo_post(MDOC_ARGS)
13654154958bSjoerg {
13667574e07eSjoerg 
136747a17e0dSchristos 	if (n->type != ROFFT_BODY)
13684154958bSjoerg 		return;
136954a4f7feSjoerg 	h->flags |= HTML_NOSPACE;
13704154958bSjoerg 	print_text(h, ")");
137154a4f7feSjoerg 	h->flags |= HTML_NOSPACE;
13724154958bSjoerg 	print_text(h, ";");
13734154958bSjoerg }
13744154958bSjoerg 
13754154958bSjoerg static int
mdoc_in_pre(MDOC_ARGS)13764154958bSjoerg mdoc_in_pre(MDOC_ARGS)
13774154958bSjoerg {
13784154958bSjoerg 	struct tag	*t;
13794154958bSjoerg 
13807574e07eSjoerg 	synopsis_pre(h, n);
1381*fc3ee6fdSchristos 	print_otag(h, TAG_CODE, "c", "In");
13824154958bSjoerg 
138354a4f7feSjoerg 	/*
138454a4f7feSjoerg 	 * The first argument of the `In' gets special treatment as
138554a4f7feSjoerg 	 * being a linked value.  Subsequent values are printed
138654a4f7feSjoerg 	 * afterward.  groff does similarly.  This also handles the case
138754a4f7feSjoerg 	 * of no children.
138854a4f7feSjoerg 	 */
138954a4f7feSjoerg 
1390b2070ba5Schristos 	if (NODE_SYNPRETTY & n->flags && NODE_LINE & n->flags)
13914154958bSjoerg 		print_text(h, "#include");
13924154958bSjoerg 
13934154958bSjoerg 	print_text(h, "<");
13944154958bSjoerg 	h->flags |= HTML_NOSPACE;
13954154958bSjoerg 
139654a4f7feSjoerg 	if (NULL != (n = n->child)) {
139747a17e0dSchristos 		assert(n->type == ROFFT_TEXT);
139854a4f7feSjoerg 
1399b2070ba5Schristos 		if (h->base_includes)
1400*fc3ee6fdSchristos 			t = print_otag(h, TAG_A, "chI", "In", n->string);
1401b2070ba5Schristos 		else
1402*fc3ee6fdSchristos 			t = print_otag(h, TAG_A, "c", "In");
140354a4f7feSjoerg 		print_text(h, n->string);
14044154958bSjoerg 		print_tagq(h, t);
140554a4f7feSjoerg 
140654a4f7feSjoerg 		n = n->next;
14074154958bSjoerg 	}
14084154958bSjoerg 
14094154958bSjoerg 	h->flags |= HTML_NOSPACE;
14104154958bSjoerg 	print_text(h, ">");
14114154958bSjoerg 
141254a4f7feSjoerg 	for ( ; n; n = n->next) {
141347a17e0dSchristos 		assert(n->type == ROFFT_TEXT);
141454a4f7feSjoerg 		print_text(h, n->string);
141554a4f7feSjoerg 	}
141654a4f7feSjoerg 
141747a17e0dSchristos 	return 0;
14184154958bSjoerg }
14194154958bSjoerg 
14204154958bSjoerg static int
mdoc_ic_pre(MDOC_ARGS)14214154958bSjoerg mdoc_ic_pre(MDOC_ARGS)
14224154958bSjoerg {
14239d9b81f7Schristos 	char	*id;
14249d9b81f7Schristos 
14259d9b81f7Schristos 	if ((id = cond_id(n)) != NULL)
14269d9b81f7Schristos 		print_otag(h, TAG_A, "chR", "permalink", id);
1427*fc3ee6fdSchristos 	print_otag(h, TAG_CODE, "ci", "Ic", id);
142847a17e0dSchristos 	return 1;
14294154958bSjoerg }
14304154958bSjoerg 
14314154958bSjoerg static int
mdoc_va_pre(MDOC_ARGS)14324154958bSjoerg mdoc_va_pre(MDOC_ARGS)
14334154958bSjoerg {
1434*fc3ee6fdSchristos 	print_otag(h, TAG_VAR, "c", "Va");
143547a17e0dSchristos 	return 1;
14364154958bSjoerg }
14374154958bSjoerg 
14384154958bSjoerg static int
mdoc_ap_pre(MDOC_ARGS)14394154958bSjoerg mdoc_ap_pre(MDOC_ARGS)
14404154958bSjoerg {
14414154958bSjoerg 
14424154958bSjoerg 	h->flags |= HTML_NOSPACE;
14434154958bSjoerg 	print_text(h, "\\(aq");
14444154958bSjoerg 	h->flags |= HTML_NOSPACE;
144547a17e0dSchristos 	return 1;
14464154958bSjoerg }
14474154958bSjoerg 
14484154958bSjoerg static int
mdoc_bf_pre(MDOC_ARGS)14494154958bSjoerg mdoc_bf_pre(MDOC_ARGS)
14504154958bSjoerg {
1451b2070ba5Schristos 	const char	*cattr;
14524154958bSjoerg 
1453*fc3ee6fdSchristos 	switch (n->type) {
1454*fc3ee6fdSchristos 	case ROFFT_BLOCK:
1455*fc3ee6fdSchristos 		html_close_paragraph(h);
145647a17e0dSchristos 		return 1;
1457*fc3ee6fdSchristos 	case ROFFT_HEAD:
1458*fc3ee6fdSchristos 		return 0;
1459*fc3ee6fdSchristos 	case ROFFT_BODY:
1460*fc3ee6fdSchristos 		break;
1461*fc3ee6fdSchristos 	default:
1462*fc3ee6fdSchristos 		abort();
1463*fc3ee6fdSchristos 	}
14644154958bSjoerg 
1465e4fbeb7eSjoerg 	if (FONT_Em == n->norm->Bf.font)
14669d9b81f7Schristos 		cattr = "Bf Em";
1467e4fbeb7eSjoerg 	else if (FONT_Sy == n->norm->Bf.font)
14689d9b81f7Schristos 		cattr = "Bf Sy";
1469e4fbeb7eSjoerg 	else if (FONT_Li == n->norm->Bf.font)
14709d9b81f7Schristos 		cattr = "Bf Li";
147182361f10Sjoerg 	else
14729d9b81f7Schristos 		cattr = "Bf No";
14734154958bSjoerg 
14749d9b81f7Schristos 	/* Cannot use TAG_SPAN because it may contain blocks. */
14759d9b81f7Schristos 	print_otag(h, TAG_DIV, "c", cattr);
147647a17e0dSchristos 	return 1;
14774154958bSjoerg }
14784154958bSjoerg 
14794154958bSjoerg static int
mdoc_ms_pre(MDOC_ARGS)14804154958bSjoerg mdoc_ms_pre(MDOC_ARGS)
14814154958bSjoerg {
14829d9b81f7Schristos 	char *id;
14839d9b81f7Schristos 
14849d9b81f7Schristos 	if ((id = cond_id(n)) != NULL)
14859d9b81f7Schristos 		print_otag(h, TAG_A, "chR", "permalink", id);
1486*fc3ee6fdSchristos 	print_otag(h, TAG_SPAN, "ci", "Ms", id);
148747a17e0dSchristos 	return 1;
14884154958bSjoerg }
14894154958bSjoerg 
14904154958bSjoerg static int
mdoc_igndelim_pre(MDOC_ARGS)1491e4fbeb7eSjoerg mdoc_igndelim_pre(MDOC_ARGS)
14924154958bSjoerg {
14934154958bSjoerg 
14944154958bSjoerg 	h->flags |= HTML_IGNDELIM;
149547a17e0dSchristos 	return 1;
14964154958bSjoerg }
14974154958bSjoerg 
14984154958bSjoerg static void
mdoc_pf_post(MDOC_ARGS)14994154958bSjoerg mdoc_pf_post(MDOC_ARGS)
15004154958bSjoerg {
15014154958bSjoerg 
1502b2070ba5Schristos 	if ( ! (n->next == NULL || n->next->flags & NODE_LINE))
15034154958bSjoerg 		h->flags |= HTML_NOSPACE;
15044154958bSjoerg }
15054154958bSjoerg 
15064154958bSjoerg static int
mdoc_rs_pre(MDOC_ARGS)15074154958bSjoerg mdoc_rs_pre(MDOC_ARGS)
15084154958bSjoerg {
1509*fc3ee6fdSchristos 	switch (n->type) {
1510*fc3ee6fdSchristos 	case ROFFT_BLOCK:
1511*fc3ee6fdSchristos 		if (n->sec == SEC_SEE_ALSO)
1512*fc3ee6fdSchristos 			html_close_paragraph(h);
1513*fc3ee6fdSchristos 		break;
1514*fc3ee6fdSchristos 	case ROFFT_HEAD:
1515*fc3ee6fdSchristos 		return 0;
1516*fc3ee6fdSchristos 	case ROFFT_BODY:
1517*fc3ee6fdSchristos 		if (n->sec == SEC_SEE_ALSO)
1518*fc3ee6fdSchristos 			print_otag(h, TAG_P, "c", "Pp");
1519*fc3ee6fdSchristos 		print_otag(h, TAG_CITE, "c", "Rs");
1520*fc3ee6fdSchristos 		break;
1521*fc3ee6fdSchristos 	default:
1522*fc3ee6fdSchristos 		abort();
1523*fc3ee6fdSchristos 	}
152447a17e0dSchristos 	return 1;
15254154958bSjoerg }
15264154958bSjoerg 
15270511d63cSchristos static int
mdoc_no_pre(MDOC_ARGS)15280511d63cSchristos mdoc_no_pre(MDOC_ARGS)
15290511d63cSchristos {
15309d9b81f7Schristos 	char *id;
15319d9b81f7Schristos 
15329d9b81f7Schristos 	if ((id = cond_id(n)) != NULL)
15339d9b81f7Schristos 		print_otag(h, TAG_A, "chR", "permalink", id);
15349d9b81f7Schristos 	print_otag(h, TAG_SPAN, "ci", "No", id);
153547a17e0dSchristos 	return 1;
15360511d63cSchristos }
15374154958bSjoerg 
15384154958bSjoerg static int
mdoc_li_pre(MDOC_ARGS)15394154958bSjoerg mdoc_li_pre(MDOC_ARGS)
15404154958bSjoerg {
15419d9b81f7Schristos 	char	*id;
15429d9b81f7Schristos 
15439d9b81f7Schristos 	if ((id = cond_id(n)) != NULL)
15449d9b81f7Schristos 		print_otag(h, TAG_A, "chR", "permalink", id);
15459d9b81f7Schristos 	print_otag(h, TAG_CODE, "ci", "Li", id);
154647a17e0dSchristos 	return 1;
15474154958bSjoerg }
15484154958bSjoerg 
15494154958bSjoerg static int
mdoc_sy_pre(MDOC_ARGS)15504154958bSjoerg mdoc_sy_pre(MDOC_ARGS)
15514154958bSjoerg {
1552*fc3ee6fdSchristos 	print_otag(h, TAG_B, "c", "Sy");
155347a17e0dSchristos 	return 1;
15544154958bSjoerg }
15554154958bSjoerg 
15564154958bSjoerg static int
mdoc_lb_pre(MDOC_ARGS)15574154958bSjoerg mdoc_lb_pre(MDOC_ARGS)
15584154958bSjoerg {
1559b2070ba5Schristos 	if (SEC_LIBRARY == n->sec && NODE_LINE & n->flags && n->prev)
1560b2070ba5Schristos 		print_otag(h, TAG_BR, "");
15614154958bSjoerg 
1562*fc3ee6fdSchristos 	print_otag(h, TAG_SPAN, "c", "Lb");
156347a17e0dSchristos 	return 1;
15644154958bSjoerg }
15654154958bSjoerg 
15664154958bSjoerg static int
mdoc__x_pre(MDOC_ARGS)15674154958bSjoerg mdoc__x_pre(MDOC_ARGS)
15684154958bSjoerg {
1569b2070ba5Schristos 	const char	*cattr;
1570e4fbeb7eSjoerg 	enum htmltag	 t;
1571e4fbeb7eSjoerg 
1572e4fbeb7eSjoerg 	t = TAG_SPAN;
15734154958bSjoerg 
15744154958bSjoerg 	switch (n->tok) {
15750511d63cSchristos 	case MDOC__A:
1576b2070ba5Schristos 		cattr = "RsA";
1577e4fbeb7eSjoerg 		if (n->prev && MDOC__A == n->prev->tok)
1578e4fbeb7eSjoerg 			if (NULL == n->next || MDOC__A != n->next->tok)
1579e4fbeb7eSjoerg 				print_text(h, "and");
15804154958bSjoerg 		break;
15810511d63cSchristos 	case MDOC__B:
1582e4fbeb7eSjoerg 		t = TAG_I;
1583b2070ba5Schristos 		cattr = "RsB";
15844154958bSjoerg 		break;
15850511d63cSchristos 	case MDOC__C:
1586b2070ba5Schristos 		cattr = "RsC";
15874154958bSjoerg 		break;
15880511d63cSchristos 	case MDOC__D:
1589b2070ba5Schristos 		cattr = "RsD";
15904154958bSjoerg 		break;
15910511d63cSchristos 	case MDOC__I:
1592e4fbeb7eSjoerg 		t = TAG_I;
1593b2070ba5Schristos 		cattr = "RsI";
15944154958bSjoerg 		break;
15950511d63cSchristos 	case MDOC__J:
1596e4fbeb7eSjoerg 		t = TAG_I;
1597b2070ba5Schristos 		cattr = "RsJ";
15984154958bSjoerg 		break;
15990511d63cSchristos 	case MDOC__N:
1600b2070ba5Schristos 		cattr = "RsN";
16014154958bSjoerg 		break;
16020511d63cSchristos 	case MDOC__O:
1603b2070ba5Schristos 		cattr = "RsO";
16044154958bSjoerg 		break;
16050511d63cSchristos 	case MDOC__P:
1606b2070ba5Schristos 		cattr = "RsP";
16074154958bSjoerg 		break;
16080511d63cSchristos 	case MDOC__Q:
1609b2070ba5Schristos 		cattr = "RsQ";
16104154958bSjoerg 		break;
16110511d63cSchristos 	case MDOC__R:
1612b2070ba5Schristos 		cattr = "RsR";
16134154958bSjoerg 		break;
16140511d63cSchristos 	case MDOC__T:
1615b2070ba5Schristos 		cattr = "RsT";
16164154958bSjoerg 		break;
16170511d63cSchristos 	case MDOC__U:
1618b2070ba5Schristos 		print_otag(h, TAG_A, "ch", "RsU", n->child->string);
1619b2070ba5Schristos 		return 1;
16200511d63cSchristos 	case MDOC__V:
1621b2070ba5Schristos 		cattr = "RsV";
16224154958bSjoerg 		break;
16234154958bSjoerg 	default:
16244154958bSjoerg 		abort();
16254154958bSjoerg 	}
16264154958bSjoerg 
1627b2070ba5Schristos 	print_otag(h, t, "c", cattr);
162847a17e0dSchristos 	return 1;
16294154958bSjoerg }
16304154958bSjoerg 
16314154958bSjoerg static void
mdoc__x_post(MDOC_ARGS)16324154958bSjoerg mdoc__x_post(MDOC_ARGS)
16334154958bSjoerg {
16344154958bSjoerg 
1635e4fbeb7eSjoerg 	if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok)
1636e4fbeb7eSjoerg 		if (NULL == n->next->next || MDOC__A != n->next->next->tok)
1637e4fbeb7eSjoerg 			if (NULL == n->prev || MDOC__A != n->prev->tok)
1638e4fbeb7eSjoerg 				return;
1639e4fbeb7eSjoerg 
16400a84adc5Sjoerg 	/* TODO: %U */
16410a84adc5Sjoerg 
1642e4fbeb7eSjoerg 	if (NULL == n->parent || MDOC_Rs != n->parent->tok)
1643e4fbeb7eSjoerg 		return;
1644e4fbeb7eSjoerg 
164554a4f7feSjoerg 	h->flags |= HTML_NOSPACE;
16464154958bSjoerg 	print_text(h, n->next ? "," : ".");
16474154958bSjoerg }
164882361f10Sjoerg 
164982361f10Sjoerg static int
mdoc_bk_pre(MDOC_ARGS)165082361f10Sjoerg mdoc_bk_pre(MDOC_ARGS)
165182361f10Sjoerg {
165282361f10Sjoerg 
165382361f10Sjoerg 	switch (n->type) {
165447a17e0dSchristos 	case ROFFT_BLOCK:
165582361f10Sjoerg 		break;
165647a17e0dSchristos 	case ROFFT_HEAD:
165747a17e0dSchristos 		return 0;
165847a17e0dSchristos 	case ROFFT_BODY:
165947a17e0dSchristos 		if (n->parent->args != NULL || n->prev->child == NULL)
166082361f10Sjoerg 			h->flags |= HTML_PREKEEP;
166182361f10Sjoerg 		break;
166282361f10Sjoerg 	default:
166382361f10Sjoerg 		abort();
166482361f10Sjoerg 	}
166582361f10Sjoerg 
166647a17e0dSchristos 	return 1;
166782361f10Sjoerg }
166882361f10Sjoerg 
166982361f10Sjoerg static void
mdoc_bk_post(MDOC_ARGS)167082361f10Sjoerg mdoc_bk_post(MDOC_ARGS)
167182361f10Sjoerg {
167282361f10Sjoerg 
167347a17e0dSchristos 	if (n->type == ROFFT_BODY)
167482361f10Sjoerg 		h->flags &= ~(HTML_KEEP | HTML_PREKEEP);
167582361f10Sjoerg }
1676e4fbeb7eSjoerg 
1677e4fbeb7eSjoerg static int
mdoc_quote_pre(MDOC_ARGS)1678e4fbeb7eSjoerg mdoc_quote_pre(MDOC_ARGS)
1679e4fbeb7eSjoerg {
168047a17e0dSchristos 	if (n->type != ROFFT_BODY)
168147a17e0dSchristos 		return 1;
1682e4fbeb7eSjoerg 
1683e4fbeb7eSjoerg 	switch (n->tok) {
16840511d63cSchristos 	case MDOC_Ao:
16850511d63cSchristos 	case MDOC_Aq:
168647a17e0dSchristos 		print_text(h, n->child != NULL && n->child->next == NULL &&
16870511d63cSchristos 		    n->child->tok == MDOC_Mt ?  "<" : "\\(la");
1688e4fbeb7eSjoerg 		break;
16890511d63cSchristos 	case MDOC_Bro:
16900511d63cSchristos 	case MDOC_Brq:
1691e4fbeb7eSjoerg 		print_text(h, "\\(lC");
1692e4fbeb7eSjoerg 		break;
16930511d63cSchristos 	case MDOC_Bo:
16940511d63cSchristos 	case MDOC_Bq:
1695e4fbeb7eSjoerg 		print_text(h, "\\(lB");
1696e4fbeb7eSjoerg 		break;
16970511d63cSchristos 	case MDOC_Oo:
16980511d63cSchristos 	case MDOC_Op:
1699e4fbeb7eSjoerg 		print_text(h, "\\(lB");
1700*fc3ee6fdSchristos 		/*
1701*fc3ee6fdSchristos 		 * Give up on semantic markup for now.
1702*fc3ee6fdSchristos 		 * We cannot use TAG_SPAN because .Oo may contain blocks.
1703*fc3ee6fdSchristos 		 * We cannot use TAG_IDIV because we might be in a
1704*fc3ee6fdSchristos 		 * phrasing context (like .Dl or .Pp); we cannot
1705*fc3ee6fdSchristos 		 * close out a .Pp at this point either because
1706*fc3ee6fdSchristos 		 * that would break the line.
1707*fc3ee6fdSchristos 		 */
1708*fc3ee6fdSchristos 		/* XXX print_otag(h, TAG_???, "c", "Op"); */
1709e4fbeb7eSjoerg 		break;
17100511d63cSchristos 	case MDOC_En:
17110511d63cSchristos 		if (NULL == n->norm->Es ||
17120511d63cSchristos 		    NULL == n->norm->Es->child)
171347a17e0dSchristos 			return 1;
17140511d63cSchristos 		print_text(h, n->norm->Es->child->string);
1715e7fe1698Sjoerg 		break;
17160511d63cSchristos 	case MDOC_Do:
17170511d63cSchristos 	case MDOC_Dq:
17180511d63cSchristos 	case MDOC_Qo:
17190511d63cSchristos 	case MDOC_Qq:
1720e4fbeb7eSjoerg 		print_text(h, "\\(lq");
1721e4fbeb7eSjoerg 		break;
17220511d63cSchristos 	case MDOC_Po:
17230511d63cSchristos 	case MDOC_Pq:
1724e4fbeb7eSjoerg 		print_text(h, "(");
1725e4fbeb7eSjoerg 		break;
17260511d63cSchristos 	case MDOC_Ql:
1727f8126693Sjoerg 		print_text(h, "\\(oq");
1728f8126693Sjoerg 		h->flags |= HTML_NOSPACE;
1729b2070ba5Schristos 		print_otag(h, TAG_CODE, "c", "Li");
1730f8126693Sjoerg 		break;
17310511d63cSchristos 	case MDOC_So:
17320511d63cSchristos 	case MDOC_Sq:
1733e4fbeb7eSjoerg 		print_text(h, "\\(oq");
1734e4fbeb7eSjoerg 		break;
1735e4fbeb7eSjoerg 	default:
1736e4fbeb7eSjoerg 		abort();
1737e4fbeb7eSjoerg 	}
1738e4fbeb7eSjoerg 
1739e4fbeb7eSjoerg 	h->flags |= HTML_NOSPACE;
174047a17e0dSchristos 	return 1;
1741e4fbeb7eSjoerg }
1742e4fbeb7eSjoerg 
1743e4fbeb7eSjoerg static void
mdoc_quote_post(MDOC_ARGS)1744e4fbeb7eSjoerg mdoc_quote_post(MDOC_ARGS)
1745e4fbeb7eSjoerg {
1746e4fbeb7eSjoerg 
174747a17e0dSchristos 	if (n->type != ROFFT_BODY && n->type != ROFFT_ELEM)
1748e4fbeb7eSjoerg 		return;
1749e4fbeb7eSjoerg 
1750e4fbeb7eSjoerg 	h->flags |= HTML_NOSPACE;
1751e4fbeb7eSjoerg 
1752e4fbeb7eSjoerg 	switch (n->tok) {
17530511d63cSchristos 	case MDOC_Ao:
17540511d63cSchristos 	case MDOC_Aq:
175547a17e0dSchristos 		print_text(h, n->child != NULL && n->child->next == NULL &&
17560511d63cSchristos 		    n->child->tok == MDOC_Mt ?  ">" : "\\(ra");
1757e4fbeb7eSjoerg 		break;
17580511d63cSchristos 	case MDOC_Bro:
17590511d63cSchristos 	case MDOC_Brq:
1760e4fbeb7eSjoerg 		print_text(h, "\\(rC");
1761e4fbeb7eSjoerg 		break;
17620511d63cSchristos 	case MDOC_Oo:
17630511d63cSchristos 	case MDOC_Op:
17640511d63cSchristos 	case MDOC_Bo:
17650511d63cSchristos 	case MDOC_Bq:
1766e4fbeb7eSjoerg 		print_text(h, "\\(rB");
1767e4fbeb7eSjoerg 		break;
17680511d63cSchristos 	case MDOC_En:
17690511d63cSchristos 		if (n->norm->Es == NULL ||
17700511d63cSchristos 		    n->norm->Es->child == NULL ||
17710511d63cSchristos 		    n->norm->Es->child->next == NULL)
17720511d63cSchristos 			h->flags &= ~HTML_NOSPACE;
17730511d63cSchristos 		else
17740511d63cSchristos 			print_text(h, n->norm->Es->child->next->string);
1775e7fe1698Sjoerg 		break;
17760511d63cSchristos 	case MDOC_Qo:
17770511d63cSchristos 	case MDOC_Qq:
17780511d63cSchristos 	case MDOC_Do:
17790511d63cSchristos 	case MDOC_Dq:
1780e4fbeb7eSjoerg 		print_text(h, "\\(rq");
1781e4fbeb7eSjoerg 		break;
17820511d63cSchristos 	case MDOC_Po:
17830511d63cSchristos 	case MDOC_Pq:
1784e4fbeb7eSjoerg 		print_text(h, ")");
1785e4fbeb7eSjoerg 		break;
17860511d63cSchristos 	case MDOC_Ql:
17870511d63cSchristos 	case MDOC_So:
17880511d63cSchristos 	case MDOC_Sq:
1789ed7c7912Sjoerg 		print_text(h, "\\(cq");
1790e4fbeb7eSjoerg 		break;
1791e4fbeb7eSjoerg 	default:
1792e4fbeb7eSjoerg 		abort();
1793e4fbeb7eSjoerg 	}
1794e4fbeb7eSjoerg }
1795e4fbeb7eSjoerg 
17960511d63cSchristos static int
mdoc_eo_pre(MDOC_ARGS)17970511d63cSchristos mdoc_eo_pre(MDOC_ARGS)
17980511d63cSchristos {
1799e4fbeb7eSjoerg 
180047a17e0dSchristos 	if (n->type != ROFFT_BODY)
180147a17e0dSchristos 		return 1;
18020511d63cSchristos 
18030511d63cSchristos 	if (n->end == ENDBODY_NOT &&
18040511d63cSchristos 	    n->parent->head->child == NULL &&
18050511d63cSchristos 	    n->child != NULL &&
18060511d63cSchristos 	    n->child->end != ENDBODY_NOT)
18070511d63cSchristos 		print_text(h, "\\&");
18080511d63cSchristos 	else if (n->end != ENDBODY_NOT ? n->child != NULL :
18090511d63cSchristos 	    n->parent->head->child != NULL && (n->child != NULL ||
18100511d63cSchristos 	    (n->parent->tail != NULL && n->parent->tail->child != NULL)))
18110511d63cSchristos 		h->flags |= HTML_NOSPACE;
181247a17e0dSchristos 	return 1;
18130511d63cSchristos }
18140511d63cSchristos 
18150511d63cSchristos static void
mdoc_eo_post(MDOC_ARGS)18160511d63cSchristos mdoc_eo_post(MDOC_ARGS)
18170511d63cSchristos {
18180511d63cSchristos 	int	 body, tail;
18190511d63cSchristos 
182047a17e0dSchristos 	if (n->type != ROFFT_BODY)
18210511d63cSchristos 		return;
18220511d63cSchristos 
18230511d63cSchristos 	if (n->end != ENDBODY_NOT) {
18240511d63cSchristos 		h->flags &= ~HTML_NOSPACE;
18250511d63cSchristos 		return;
18260511d63cSchristos 	}
18270511d63cSchristos 
18280511d63cSchristos 	body = n->child != NULL || n->parent->head->child != NULL;
18290511d63cSchristos 	tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
18300511d63cSchristos 
18310511d63cSchristos 	if (body && tail)
18320511d63cSchristos 		h->flags |= HTML_NOSPACE;
18330511d63cSchristos 	else if ( ! tail)
18340511d63cSchristos 		h->flags &= ~HTML_NOSPACE;
18350511d63cSchristos }
1836*fc3ee6fdSchristos 
1837*fc3ee6fdSchristos static int
mdoc_abort_pre(MDOC_ARGS)1838*fc3ee6fdSchristos mdoc_abort_pre(MDOC_ARGS)
1839*fc3ee6fdSchristos {
1840*fc3ee6fdSchristos 	abort();
1841*fc3ee6fdSchristos }
1842