xref: /openbsd-src/usr.bin/mandoc/mdoc_html.c (revision 645bcdad9ca01652532aace68d73ff04cbd76eef)
1*645bcdadSschwarze /* $OpenBSD: mdoc_html.c,v 1.228 2025/01/25 00:19:23 schwarze Exp $ */
24175bdabSschwarze /*
30aa8d661Sschwarze  * Copyright (c) 2014-2022, 2025 Ingo Schwarze <schwarze@openbsd.org>
40ac7e6ecSschwarze  * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
5b3005203Sschwarze  * Copyright (c) 2022 Anna Vyalkova <cyber@sysrq.in>
64175bdabSschwarze  *
74175bdabSschwarze  * Permission to use, copy, modify, and distribute this software for any
84175bdabSschwarze  * purpose with or without fee is hereby granted, provided that the above
94175bdabSschwarze  * copyright notice and this permission notice appear in all copies.
104175bdabSschwarze  *
11d1982c71Sschwarze  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
124175bdabSschwarze  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13d1982c71Sschwarze  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
144175bdabSschwarze  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
154175bdabSschwarze  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
164175bdabSschwarze  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
174175bdabSschwarze  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
180ac7e6ecSschwarze  *
190ac7e6ecSschwarze  * HTML formatter for mdoc(7) used by mandoc(1).
204175bdabSschwarze  */
214175bdabSschwarze #include <sys/types.h>
224175bdabSschwarze 
234175bdabSschwarze #include <assert.h>
244175bdabSschwarze #include <ctype.h>
254175bdabSschwarze #include <stdio.h>
264175bdabSschwarze #include <stdlib.h>
274175bdabSschwarze #include <string.h>
284175bdabSschwarze #include <unistd.h>
294175bdabSschwarze 
30a92c1cd8Sschwarze #include "mandoc_aux.h"
312e362670Sschwarze #include "mandoc.h"
32d1982c71Sschwarze #include "roff.h"
33dd617d76Sschwarze #include "mdoc.h"
344175bdabSschwarze #include "out.h"
354175bdabSschwarze #include "html.h"
364175bdabSschwarze #include "main.h"
374175bdabSschwarze 
382a238f45Sschwarze #define	MDOC_ARGS	  const struct roff_meta *meta, \
393a0d07afSschwarze 			  struct roff_node *n, \
404175bdabSschwarze 			  struct html *h
414175bdabSschwarze 
425d7d1836Sschwarze #ifndef MIN
435d7d1836Sschwarze #define	MIN(a,b)	((/*CONSTCOND*/(a)<(b))?(a):(b))
445d7d1836Sschwarze #endif
455d7d1836Sschwarze 
4616fe0cfcSschwarze struct	mdoc_html_act {
474175bdabSschwarze 	int		(*pre)(MDOC_ARGS);
484175bdabSschwarze 	void		(*post)(MDOC_ARGS);
494175bdabSschwarze };
504175bdabSschwarze 
51cc202ecaSschwarze static	void		  print_mdoc_head(const struct roff_meta *,
52cc202ecaSschwarze 				struct html *);
534175bdabSschwarze static	void		  print_mdoc_node(MDOC_ARGS);
544175bdabSschwarze static	void		  print_mdoc_nodelist(MDOC_ARGS);
557ebbefbeSschwarze static	void		  synopsis_pre(struct html *, struct roff_node *);
564175bdabSschwarze 
57cc202ecaSschwarze static	void		  mdoc_root_post(const struct roff_meta *,
58cc202ecaSschwarze 				struct html *);
59cc202ecaSschwarze static	int		  mdoc_root_pre(const struct roff_meta *,
60cc202ecaSschwarze 				struct html *);
614175bdabSschwarze 
624175bdabSschwarze static	void		  mdoc__x_post(MDOC_ARGS);
634175bdabSschwarze static	int		  mdoc__x_pre(MDOC_ARGS);
647c539ecbSschwarze static	int		  mdoc_abort_pre(MDOC_ARGS);
654175bdabSschwarze static	int		  mdoc_ad_pre(MDOC_ARGS);
664175bdabSschwarze static	int		  mdoc_an_pre(MDOC_ARGS);
674175bdabSschwarze static	int		  mdoc_ap_pre(MDOC_ARGS);
684175bdabSschwarze static	int		  mdoc_ar_pre(MDOC_ARGS);
694175bdabSschwarze static	int		  mdoc_bd_pre(MDOC_ARGS);
704175bdabSschwarze static	int		  mdoc_bf_pre(MDOC_ARGS);
71769ee804Sschwarze static	void		  mdoc_bk_post(MDOC_ARGS);
72769ee804Sschwarze static	int		  mdoc_bk_pre(MDOC_ARGS);
734175bdabSschwarze static	int		  mdoc_bl_pre(MDOC_ARGS);
744175bdabSschwarze static	int		  mdoc_cd_pre(MDOC_ARGS);
750ac7e6ecSschwarze static	int		  mdoc_code_pre(MDOC_ARGS);
764175bdabSschwarze static	int		  mdoc_d1_pre(MDOC_ARGS);
774175bdabSschwarze static	int		  mdoc_fa_pre(MDOC_ARGS);
784175bdabSschwarze static	int		  mdoc_fd_pre(MDOC_ARGS);
794175bdabSschwarze static	int		  mdoc_fl_pre(MDOC_ARGS);
804175bdabSschwarze static	int		  mdoc_fn_pre(MDOC_ARGS);
814175bdabSschwarze static	int		  mdoc_ft_pre(MDOC_ARGS);
824175bdabSschwarze static	int		  mdoc_em_pre(MDOC_ARGS);
8303ed6ec9Sschwarze static	void		  mdoc_eo_post(MDOC_ARGS);
8403ed6ec9Sschwarze static	int		  mdoc_eo_pre(MDOC_ARGS);
854175bdabSschwarze static	int		  mdoc_ex_pre(MDOC_ARGS);
864175bdabSschwarze static	void		  mdoc_fo_post(MDOC_ARGS);
874175bdabSschwarze static	int		  mdoc_fo_pre(MDOC_ARGS);
8837e2f24fSschwarze static	int		  mdoc_igndelim_pre(MDOC_ARGS);
894175bdabSschwarze static	int		  mdoc_in_pre(MDOC_ARGS);
904175bdabSschwarze static	int		  mdoc_it_pre(MDOC_ARGS);
914175bdabSschwarze static	int		  mdoc_lb_pre(MDOC_ARGS);
924175bdabSschwarze static	int		  mdoc_lk_pre(MDOC_ARGS);
934175bdabSschwarze static	int		  mdoc_mt_pre(MDOC_ARGS);
944175bdabSschwarze static	int		  mdoc_nd_pre(MDOC_ARGS);
954175bdabSschwarze static	int		  mdoc_nm_pre(MDOC_ARGS);
966f9818f6Sschwarze static	int		  mdoc_no_pre(MDOC_ARGS);
974175bdabSschwarze static	int		  mdoc_ns_pre(MDOC_ARGS);
984175bdabSschwarze static	int		  mdoc_pa_pre(MDOC_ARGS);
994175bdabSschwarze static	void		  mdoc_pf_post(MDOC_ARGS);
100467b61c6Sschwarze static	int		  mdoc_pp_pre(MDOC_ARGS);
1012c3450fcSschwarze static	void		  mdoc_quote_post(MDOC_ARGS);
1022c3450fcSschwarze static	int		  mdoc_quote_pre(MDOC_ARGS);
1034175bdabSschwarze static	int		  mdoc_rs_pre(MDOC_ARGS);
1044175bdabSschwarze static	int		  mdoc_sh_pre(MDOC_ARGS);
105551cd4a8Sschwarze static	int		  mdoc_skip_pre(MDOC_ARGS);
106ddce0b0cSschwarze static	int		  mdoc_sm_pre(MDOC_ARGS);
1074175bdabSschwarze static	int		  mdoc_ss_pre(MDOC_ARGS);
108dd15d0f1Sschwarze static	int		  mdoc_st_pre(MDOC_ARGS);
1094175bdabSschwarze static	int		  mdoc_sx_pre(MDOC_ARGS);
1104175bdabSschwarze static	int		  mdoc_sy_pre(MDOC_ARGS);
11192929bf6Sschwarze static	int		  mdoc_tg_pre(MDOC_ARGS);
1124175bdabSschwarze static	int		  mdoc_va_pre(MDOC_ARGS);
1134175bdabSschwarze static	int		  mdoc_vt_pre(MDOC_ARGS);
1144175bdabSschwarze static	int		  mdoc_xr_pre(MDOC_ARGS);
1154175bdabSschwarze static	int		  mdoc_xx_pre(MDOC_ARGS);
1164175bdabSschwarze 
11716fe0cfcSschwarze static const struct mdoc_html_act mdoc_html_acts[MDOC_MAX - MDOC_Dd] = {
1184175bdabSschwarze 	{NULL, NULL}, /* Dd */
1194175bdabSschwarze 	{NULL, NULL}, /* Dt */
1204175bdabSschwarze 	{NULL, NULL}, /* Os */
1214175bdabSschwarze 	{mdoc_sh_pre, NULL }, /* Sh */
1224175bdabSschwarze 	{mdoc_ss_pre, NULL }, /* Ss */
123467b61c6Sschwarze 	{mdoc_pp_pre, NULL}, /* Pp */
1244175bdabSschwarze 	{mdoc_d1_pre, NULL}, /* D1 */
1254175bdabSschwarze 	{mdoc_d1_pre, NULL}, /* Dl */
1264175bdabSschwarze 	{mdoc_bd_pre, NULL}, /* Bd */
1274175bdabSschwarze 	{NULL, NULL}, /* Ed */
128467b61c6Sschwarze 	{mdoc_bl_pre, NULL}, /* Bl */
1294175bdabSschwarze 	{NULL, NULL}, /* El */
1304175bdabSschwarze 	{mdoc_it_pre, NULL}, /* It */
1314175bdabSschwarze 	{mdoc_ad_pre, NULL}, /* Ad */
1324175bdabSschwarze 	{mdoc_an_pre, NULL}, /* An */
13314a309e3Sschwarze 	{mdoc_ap_pre, NULL}, /* Ap */
1344175bdabSschwarze 	{mdoc_ar_pre, NULL}, /* Ar */
1354175bdabSschwarze 	{mdoc_cd_pre, NULL}, /* Cd */
1360ac7e6ecSschwarze 	{mdoc_code_pre, NULL}, /* Cm */
1370ac7e6ecSschwarze 	{mdoc_code_pre, NULL}, /* Dv */
1380ac7e6ecSschwarze 	{mdoc_code_pre, NULL}, /* Er */
1390ac7e6ecSschwarze 	{mdoc_code_pre, NULL}, /* Ev */
1404175bdabSschwarze 	{mdoc_ex_pre, NULL}, /* Ex */
1414175bdabSschwarze 	{mdoc_fa_pre, NULL}, /* Fa */
1429a98b8a1Sschwarze 	{mdoc_fd_pre, NULL}, /* Fd */
1434175bdabSschwarze 	{mdoc_fl_pre, NULL}, /* Fl */
1444175bdabSschwarze 	{mdoc_fn_pre, NULL}, /* Fn */
1454175bdabSschwarze 	{mdoc_ft_pre, NULL}, /* Ft */
1460ac7e6ecSschwarze 	{mdoc_code_pre, NULL}, /* Ic */
1474175bdabSschwarze 	{mdoc_in_pre, NULL}, /* In */
1480ac7e6ecSschwarze 	{mdoc_code_pre, NULL}, /* Li */
1494175bdabSschwarze 	{mdoc_nd_pre, NULL}, /* Nd */
1504175bdabSschwarze 	{mdoc_nm_pre, NULL}, /* Nm */
1512c3450fcSschwarze 	{mdoc_quote_pre, mdoc_quote_post}, /* Op */
1527c539ecbSschwarze 	{mdoc_abort_pre, NULL}, /* Ot */
1534175bdabSschwarze 	{mdoc_pa_pre, NULL}, /* Pa */
1548ccddcd3Sschwarze 	{mdoc_ex_pre, NULL}, /* Rv */
155dd15d0f1Sschwarze 	{mdoc_st_pre, NULL}, /* St */
1564175bdabSschwarze 	{mdoc_va_pre, NULL}, /* Va */
1574175bdabSschwarze 	{mdoc_vt_pre, NULL}, /* Vt */
1584175bdabSschwarze 	{mdoc_xr_pre, NULL}, /* Xr */
1594175bdabSschwarze 	{mdoc__x_pre, mdoc__x_post}, /* %A */
1604175bdabSschwarze 	{mdoc__x_pre, mdoc__x_post}, /* %B */
1614175bdabSschwarze 	{mdoc__x_pre, mdoc__x_post}, /* %D */
1624175bdabSschwarze 	{mdoc__x_pre, mdoc__x_post}, /* %I */
1634175bdabSschwarze 	{mdoc__x_pre, mdoc__x_post}, /* %J */
1644175bdabSschwarze 	{mdoc__x_pre, mdoc__x_post}, /* %N */
1654175bdabSschwarze 	{mdoc__x_pre, mdoc__x_post}, /* %O */
1664175bdabSschwarze 	{mdoc__x_pre, mdoc__x_post}, /* %P */
1674175bdabSschwarze 	{mdoc__x_pre, mdoc__x_post}, /* %R */
1684175bdabSschwarze 	{mdoc__x_pre, mdoc__x_post}, /* %T */
1694175bdabSschwarze 	{mdoc__x_pre, mdoc__x_post}, /* %V */
1704175bdabSschwarze 	{NULL, NULL}, /* Ac */
1712c3450fcSschwarze 	{mdoc_quote_pre, mdoc_quote_post}, /* Ao */
1722c3450fcSschwarze 	{mdoc_quote_pre, mdoc_quote_post}, /* Aq */
173dd15d0f1Sschwarze 	{mdoc_xx_pre, NULL}, /* At */
1744175bdabSschwarze 	{NULL, NULL}, /* Bc */
1754175bdabSschwarze 	{mdoc_bf_pre, NULL}, /* Bf */
1762c3450fcSschwarze 	{mdoc_quote_pre, mdoc_quote_post}, /* Bo */
1772c3450fcSschwarze 	{mdoc_quote_pre, mdoc_quote_post}, /* Bq */
1784175bdabSschwarze 	{mdoc_xx_pre, NULL}, /* Bsx */
1793af8e8d7Sschwarze 	{mdoc_xx_pre, NULL}, /* Bx */
18078bbbab4Sschwarze 	{mdoc_skip_pre, NULL}, /* Db */
1814175bdabSschwarze 	{NULL, NULL}, /* Dc */
1822c3450fcSschwarze 	{mdoc_quote_pre, mdoc_quote_post}, /* Do */
1832c3450fcSschwarze 	{mdoc_quote_pre, mdoc_quote_post}, /* Dq */
184b16e7ddfSschwarze 	{NULL, NULL}, /* Ec */ /* FIXME: no space */
1854175bdabSschwarze 	{NULL, NULL}, /* Ef */
1864175bdabSschwarze 	{mdoc_em_pre, NULL}, /* Em */
18703ed6ec9Sschwarze 	{mdoc_eo_pre, mdoc_eo_post}, /* Eo */
1884175bdabSschwarze 	{mdoc_xx_pre, NULL}, /* Fx */
1890ac7e6ecSschwarze 	{mdoc_no_pre, NULL}, /* Ms */
1906f9818f6Sschwarze 	{mdoc_no_pre, NULL}, /* No */
1914175bdabSschwarze 	{mdoc_ns_pre, NULL}, /* Ns */
1924175bdabSschwarze 	{mdoc_xx_pre, NULL}, /* Nx */
1934175bdabSschwarze 	{mdoc_xx_pre, NULL}, /* Ox */
1944175bdabSschwarze 	{NULL, NULL}, /* Pc */
19537e2f24fSschwarze 	{mdoc_igndelim_pre, mdoc_pf_post}, /* Pf */
1962c3450fcSschwarze 	{mdoc_quote_pre, mdoc_quote_post}, /* Po */
1972c3450fcSschwarze 	{mdoc_quote_pre, mdoc_quote_post}, /* Pq */
1984175bdabSschwarze 	{NULL, NULL}, /* Qc */
1992c3450fcSschwarze 	{mdoc_quote_pre, mdoc_quote_post}, /* Ql */
2002c3450fcSschwarze 	{mdoc_quote_pre, mdoc_quote_post}, /* Qo */
2012c3450fcSschwarze 	{mdoc_quote_pre, mdoc_quote_post}, /* Qq */
2024175bdabSschwarze 	{NULL, NULL}, /* Re */
2034175bdabSschwarze 	{mdoc_rs_pre, NULL}, /* Rs */
2044175bdabSschwarze 	{NULL, NULL}, /* Sc */
2052c3450fcSschwarze 	{mdoc_quote_pre, mdoc_quote_post}, /* So */
2062c3450fcSschwarze 	{mdoc_quote_pre, mdoc_quote_post}, /* Sq */
207ddce0b0cSschwarze 	{mdoc_sm_pre, NULL}, /* Sm */
2084175bdabSschwarze 	{mdoc_sx_pre, NULL}, /* Sx */
2094175bdabSschwarze 	{mdoc_sy_pre, NULL}, /* Sy */
2104175bdabSschwarze 	{NULL, NULL}, /* Tn */
2114175bdabSschwarze 	{mdoc_xx_pre, NULL}, /* Ux */
2124175bdabSschwarze 	{NULL, NULL}, /* Xc */
2134175bdabSschwarze 	{NULL, NULL}, /* Xo */
2144175bdabSschwarze 	{mdoc_fo_pre, mdoc_fo_post}, /* Fo */
2154175bdabSschwarze 	{NULL, NULL}, /* Fc */
2162c3450fcSschwarze 	{mdoc_quote_pre, mdoc_quote_post}, /* Oo */
2174175bdabSschwarze 	{NULL, NULL}, /* Oc */
218769ee804Sschwarze 	{mdoc_bk_pre, mdoc_bk_post}, /* Bk */
2194175bdabSschwarze 	{NULL, NULL}, /* Ek */
2208ccddcd3Sschwarze 	{NULL, NULL}, /* Bt */
2214175bdabSschwarze 	{NULL, NULL}, /* Hf */
222551cd4a8Sschwarze 	{mdoc_em_pre, NULL}, /* Fr */
2238ccddcd3Sschwarze 	{NULL, NULL}, /* Ud */
2244175bdabSschwarze 	{mdoc_lb_pre, NULL}, /* Lb */
2257c539ecbSschwarze 	{mdoc_abort_pre, NULL}, /* Lp */
2264175bdabSschwarze 	{mdoc_lk_pre, NULL}, /* Lk */
2274175bdabSschwarze 	{mdoc_mt_pre, NULL}, /* Mt */
2282c3450fcSschwarze 	{mdoc_quote_pre, mdoc_quote_post}, /* Brq */
2292c3450fcSschwarze 	{mdoc_quote_pre, mdoc_quote_post}, /* Bro */
2304175bdabSschwarze 	{NULL, NULL}, /* Brc */
2314175bdabSschwarze 	{mdoc__x_pre, mdoc__x_post}, /* %C */
232551cd4a8Sschwarze 	{mdoc_skip_pre, NULL}, /* Es */
233551cd4a8Sschwarze 	{mdoc_quote_pre, mdoc_quote_post}, /* En */
2344175bdabSschwarze 	{mdoc_xx_pre, NULL}, /* Dx */
2354175bdabSschwarze 	{mdoc__x_pre, mdoc__x_post}, /* %Q */
236b822ca0dSschwarze 	{mdoc__x_pre, mdoc__x_post}, /* %U */
2376093755cSschwarze 	{NULL, NULL}, /* Ta */
23892929bf6Sschwarze 	{mdoc_tg_pre, NULL}, /* Tg */
2394175bdabSschwarze };
2404175bdabSschwarze 
24149aff9f8Sschwarze 
2424175bdabSschwarze /*
2439a98b8a1Sschwarze  * See the same function in mdoc_term.c for documentation.
2449a98b8a1Sschwarze  */
2459a98b8a1Sschwarze static void
2467ebbefbeSschwarze synopsis_pre(struct html *h, struct roff_node *n)
2479a98b8a1Sschwarze {
2487ebbefbeSschwarze 	struct roff_node *np;
2499a98b8a1Sschwarze 
2507ebbefbeSschwarze 	if ((n->flags & NODE_SYNPRETTY) == 0 ||
2517ebbefbeSschwarze 	    (np = roff_node_prev(n)) == NULL)
2529a98b8a1Sschwarze 		return;
2539a98b8a1Sschwarze 
2547ebbefbeSschwarze 	if (np->tok == n->tok &&
2559a98b8a1Sschwarze 	    MDOC_Fo != n->tok &&
2569a98b8a1Sschwarze 	    MDOC_Ft != n->tok &&
2579a98b8a1Sschwarze 	    MDOC_Fn != n->tok) {
258229cc7fdSschwarze 		print_otag(h, TAG_BR, "");
2599a98b8a1Sschwarze 		return;
2609a98b8a1Sschwarze 	}
2619a98b8a1Sschwarze 
2627ebbefbeSschwarze 	switch (np->tok) {
26349aff9f8Sschwarze 	case MDOC_Fd:
26449aff9f8Sschwarze 	case MDOC_Fn:
26549aff9f8Sschwarze 	case MDOC_Fo:
26649aff9f8Sschwarze 	case MDOC_In:
26749aff9f8Sschwarze 	case MDOC_Vt:
2689a98b8a1Sschwarze 		break;
26949aff9f8Sschwarze 	case MDOC_Ft:
2702dd33770Sschwarze 		if (n->tok != MDOC_Fn && n->tok != MDOC_Fo)
2719a98b8a1Sschwarze 			break;
2729a98b8a1Sschwarze 		/* FALLTHROUGH */
2739a98b8a1Sschwarze 	default:
274229cc7fdSschwarze 		print_otag(h, TAG_BR, "");
2752dd33770Sschwarze 		return;
2769a98b8a1Sschwarze 	}
2772dd33770Sschwarze 	html_close_paragraph(h);
2782dd33770Sschwarze 	print_otag(h, TAG_P, "c", "Pp");
2799a98b8a1Sschwarze }
2809a98b8a1Sschwarze 
2816d0e9b63Sschwarze void
2826b86842eSschwarze html_mdoc(void *arg, const struct roff_meta *mdoc)
2834175bdabSschwarze {
2846d0e9b63Sschwarze 	struct html		*h;
285cc202ecaSschwarze 	struct roff_node	*n;
286ce781f36Sschwarze 	struct tag		*t;
2874175bdabSschwarze 
2886d0e9b63Sschwarze 	h = (struct html *)arg;
289cc202ecaSschwarze 	n = mdoc->first->child;
290ca0ce676Sschwarze 
291ce781f36Sschwarze 	if ((h->oflags & HTML_FRAGMENT) == 0) {
292ca0ce676Sschwarze 		print_gen_decls(h);
293ce781f36Sschwarze 		print_otag(h, TAG_HTML, "");
294ce781f36Sschwarze 		t = print_otag(h, TAG_HEAD, "");
2956b86842eSschwarze 		print_mdoc_head(mdoc, h);
296ce781f36Sschwarze 		print_tagq(h, t);
297501adfefSschwarze 		if (n != NULL && n->type == ROFFT_COMMENT)
298501adfefSschwarze 			print_gen_comment(h, n);
299229cc7fdSschwarze 		print_otag(h, TAG_BODY, "");
300ce781f36Sschwarze 	}
3014175bdabSschwarze 
3026b86842eSschwarze 	mdoc_root_pre(mdoc, h);
3036774f271Sschwarze 	t = print_otag(h, TAG_MAIN, "c", "manual-text");
3046b86842eSschwarze 	print_mdoc_nodelist(mdoc, n, h);
305c7402a19Sschwarze 	print_tagq(h, t);
3066b86842eSschwarze 	mdoc_root_post(mdoc, h);
307ce781f36Sschwarze 	print_tagq(h, NULL);
3084175bdabSschwarze }
3094175bdabSschwarze 
3104175bdabSschwarze static void
311cc202ecaSschwarze print_mdoc_head(const struct roff_meta *meta, struct html *h)
3124175bdabSschwarze {
313fef1eecdSschwarze 	char	*cp;
3144175bdabSschwarze 
3154175bdabSschwarze 	print_gen_head(h);
316fef1eecdSschwarze 
317fef1eecdSschwarze 	if (meta->arch != NULL && meta->msec != NULL)
318fef1eecdSschwarze 		mandoc_asprintf(&cp, "%s(%s) (%s)", meta->title,
319fef1eecdSschwarze 		    meta->msec, meta->arch);
320fef1eecdSschwarze 	else if (meta->msec != NULL)
321fef1eecdSschwarze 		mandoc_asprintf(&cp, "%s(%s)", meta->title, meta->msec);
322fef1eecdSschwarze 	else if (meta->arch != NULL)
323fef1eecdSschwarze 		mandoc_asprintf(&cp, "%s (%s)", meta->title, meta->arch);
324fef1eecdSschwarze 	else
325fef1eecdSschwarze 		cp = mandoc_strdup(meta->title);
3264175bdabSschwarze 
327229cc7fdSschwarze 	print_otag(h, TAG_TITLE, "");
328fef1eecdSschwarze 	print_text(h, cp);
329fef1eecdSschwarze 	free(cp);
3304175bdabSschwarze }
3314175bdabSschwarze 
3324175bdabSschwarze static void
3334175bdabSschwarze print_mdoc_nodelist(MDOC_ARGS)
3344175bdabSschwarze {
3354175bdabSschwarze 
336e4534905Sschwarze 	while (n != NULL) {
3377ead8a4eSschwarze 		print_mdoc_node(meta, n, h);
338e4534905Sschwarze 		n = n->next;
339e4534905Sschwarze 	}
3404175bdabSschwarze }
3414175bdabSschwarze 
3424175bdabSschwarze static void
3434175bdabSschwarze print_mdoc_node(MDOC_ARGS)
3444175bdabSschwarze {
3454175bdabSschwarze 	struct tag	*t;
3462dd33770Sschwarze 	int		 child;
3474175bdabSschwarze 
3484c293873Sschwarze 	if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
34943808411Sschwarze 		return;
35043808411Sschwarze 
35152e71e33Sschwarze 	if ((n->flags & NODE_NOFILL) == 0)
352e2edd184Sschwarze 		html_fillmode(h, ROFF_fi);
35352e71e33Sschwarze 	else if (html_fillmode(h, ROFF_nf) == ROFF_nf &&
35452e71e33Sschwarze 	    n->tok != ROFF_fi && n->flags & NODE_LINE)
35552e71e33Sschwarze 		print_endline(h);
3562dd33770Sschwarze 
3574175bdabSschwarze 	child = 1;
3582dd33770Sschwarze 	n->flags &= ~NODE_ENDED;
3594175bdabSschwarze 	switch (n->type) {
360d1982c71Sschwarze 	case ROFFT_TEXT:
361e2edd184Sschwarze 		if (n->flags & NODE_LINE) {
362e2edd184Sschwarze 			switch (*n->string) {
363e2edd184Sschwarze 			case '\0':
364e2edd184Sschwarze 				h->col = 1;
365e2edd184Sschwarze 				print_endline(h);
366e2edd184Sschwarze 				return;
367e2edd184Sschwarze 			case ' ':
368e2edd184Sschwarze 				if ((h->flags & HTML_NONEWLINE) == 0 &&
36941dbcad6Sschwarze 				    (n->flags & NODE_NOFILL) == 0)
370229cc7fdSschwarze 					print_otag(h, TAG_BR, "");
371e2edd184Sschwarze 				break;
372e2edd184Sschwarze 			default:
373e2edd184Sschwarze 				break;
374e2edd184Sschwarze 			}
375e2edd184Sschwarze 		}
376e2edd184Sschwarze 		t = h->tag;
377e2edd184Sschwarze 		t->refcnt++;
3786e2a0df9Sschwarze 		if (n->flags & NODE_DELIMC)
379a35fc07aSschwarze 			h->flags |= HTML_NOSPACE;
3806e2a0df9Sschwarze 		if (n->flags & NODE_HREF)
3816e2a0df9Sschwarze 			print_tagged_text(h, n->string, n);
3826e2a0df9Sschwarze 		else
3834175bdabSschwarze 			print_text(h, n->string);
3846e2a0df9Sschwarze 		if (n->flags & NODE_DELIMO)
385a35fc07aSschwarze 			h->flags |= HTML_NOSPACE;
3862dd33770Sschwarze 		break;
387d1982c71Sschwarze 	case ROFFT_EQN:
388520a575cSschwarze 		t = h->tag;
389520a575cSschwarze 		t->refcnt++;
390f8618d99Sschwarze 		print_eqn(h, n->eqn);
39119a69263Sschwarze 		break;
392d1982c71Sschwarze 	case ROFFT_TBL:
393366f22eeSschwarze 		/*
394366f22eeSschwarze 		 * This will take care of initialising all of the table
395366f22eeSschwarze 		 * state data for the first table, then tearing it down
396366f22eeSschwarze 		 * for the last one.
397366f22eeSschwarze 		 */
3982791bd1cSschwarze 		print_tbl(h, n->span);
399366f22eeSschwarze 		return;
4004175bdabSschwarze 	default:
401366f22eeSschwarze 		/*
402366f22eeSschwarze 		 * Close out the current table, if it's open, and unset
403366f22eeSschwarze 		 * the "meta" table state.  This will be reopened on the
404366f22eeSschwarze 		 * next table element.
405366f22eeSschwarze 		 */
406520a575cSschwarze 		if (h->tblt != NULL)
407366f22eeSschwarze 			print_tblclose(h);
4087d18a139Sschwarze 		assert(h->tblt == NULL);
409520a575cSschwarze 		t = h->tag;
410520a575cSschwarze 		t->refcnt++;
41129478532Sschwarze 		if (n->tok < ROFF_MAX) {
41296a5de47Sschwarze 			roff_html_pre(h, n);
413520a575cSschwarze 			t->refcnt--;
4142dd33770Sschwarze 			print_stagq(h, t);
4152dd33770Sschwarze 			return;
41629478532Sschwarze 		}
41714a309e3Sschwarze 		assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
41816fe0cfcSschwarze 		if (mdoc_html_acts[n->tok - MDOC_Dd].pre != NULL &&
41914a309e3Sschwarze 		    (n->end == ENDBODY_NOT || n->child != NULL))
42016fe0cfcSschwarze 			child = (*mdoc_html_acts[n->tok - MDOC_Dd].pre)(meta,
42116fe0cfcSschwarze 			    n, h);
4224175bdabSschwarze 		break;
4234175bdabSschwarze 	}
4244175bdabSschwarze 
425c4b0939cSschwarze 	if (h->flags & HTML_KEEP && n->flags & NODE_LINE) {
426769ee804Sschwarze 		h->flags &= ~HTML_KEEP;
427769ee804Sschwarze 		h->flags |= HTML_PREKEEP;
428769ee804Sschwarze 	}
429769ee804Sschwarze 
4302dd33770Sschwarze 	if (child && n->child != NULL)
4317ead8a4eSschwarze 		print_mdoc_nodelist(meta, n->child, h);
4324175bdabSschwarze 
433520a575cSschwarze 	t->refcnt--;
4344175bdabSschwarze 	print_stagq(h, t);
4354175bdabSschwarze 
4364175bdabSschwarze 	switch (n->type) {
4372dd33770Sschwarze 	case ROFFT_TEXT:
438d1982c71Sschwarze 	case ROFFT_EQN:
43919a69263Sschwarze 		break;
4404175bdabSschwarze 	default:
4412dd33770Sschwarze 		if (mdoc_html_acts[n->tok - MDOC_Dd].post == NULL ||
44229478532Sschwarze 		    n->flags & NODE_ENDED)
4437d18a139Sschwarze 			break;
44416fe0cfcSschwarze 		(*mdoc_html_acts[n->tok - MDOC_Dd].post)(meta, n, h);
4457d18a139Sschwarze 		if (n->end != ENDBODY_NOT)
446c4b0939cSschwarze 			n->body->flags |= NODE_ENDED;
4474175bdabSschwarze 		break;
4484175bdabSschwarze 	}
4494175bdabSschwarze }
4504175bdabSschwarze 
4514175bdabSschwarze static void
452cc202ecaSschwarze mdoc_root_post(const struct roff_meta *meta, struct html *h)
4534175bdabSschwarze {
4548f48bc46Sschwarze 	struct tag	*t;
4554175bdabSschwarze 
4568f48bc46Sschwarze 	t = print_otag(h, TAG_DIV, "cr?", "foot", "doc-pagefooter",
457f0f927fcSschwarze 	    "aria-label", "Manual footer line");
458b009ccebSschwarze 
4598f48bc46Sschwarze 	print_otag(h, TAG_SPAN, "c", "foot-left");
4608f48bc46Sschwarze 	print_stagq(h, t);
4618f48bc46Sschwarze 
4628f48bc46Sschwarze 	print_otag(h, TAG_SPAN, "c", "foot-date");
4637ead8a4eSschwarze 	print_text(h, meta->date);
4648f48bc46Sschwarze 	print_stagq(h, t);
4654175bdabSschwarze 
4668f48bc46Sschwarze 	print_otag(h, TAG_SPAN, "c", "foot-os");
4677ead8a4eSschwarze 	print_text(h, meta->os);
4684175bdabSschwarze 	print_tagq(h, t);
4694175bdabSschwarze }
4704175bdabSschwarze 
4714175bdabSschwarze static int
472cc202ecaSschwarze mdoc_root_pre(const struct roff_meta *meta, struct html *h)
4734175bdabSschwarze {
4748f48bc46Sschwarze 	struct tag	*t;
4750b2f1307Sschwarze 	char		*volume, *title;
4764175bdabSschwarze 
4770b2f1307Sschwarze 	if (NULL == meta->arch)
4780b2f1307Sschwarze 		volume = mandoc_strdup(meta->vol);
4790b2f1307Sschwarze 	else
4800b2f1307Sschwarze 		mandoc_asprintf(&volume, "%s (%s)",
4810b2f1307Sschwarze 		    meta->vol, meta->arch);
4824175bdabSschwarze 
4833fdead0cSschwarze 	if (NULL == meta->msec)
4843fdead0cSschwarze 		title = mandoc_strdup(meta->title);
4853fdead0cSschwarze 	else
4863fdead0cSschwarze 		mandoc_asprintf(&title, "%s(%s)",
4873fdead0cSschwarze 		    meta->title, meta->msec);
4884175bdabSschwarze 
4898f48bc46Sschwarze 	t = print_otag(h, TAG_DIV, "cr?", "head", "doc-pageheader",
490f0f927fcSschwarze 	    "aria-label", "Manual header line");
491a66b65d0Sschwarze 
4928f48bc46Sschwarze 	print_otag(h, TAG_SPAN, "c", "head-ltitle");
4934175bdabSschwarze 	print_text(h, title);
4948f48bc46Sschwarze 	print_stagq(h, t);
4954175bdabSschwarze 
4968f48bc46Sschwarze 	print_otag(h, TAG_SPAN, "c", "head-vol");
4970b2f1307Sschwarze 	print_text(h, volume);
4988f48bc46Sschwarze 	print_stagq(h, t);
4994175bdabSschwarze 
5008f48bc46Sschwarze 	print_otag(h, TAG_SPAN, "c", "head-rtitle");
5014175bdabSschwarze 	print_text(h, title);
5024175bdabSschwarze 	print_tagq(h, t);
503a92c1cd8Sschwarze 
504a92c1cd8Sschwarze 	free(title);
5050b2f1307Sschwarze 	free(volume);
506526e306bSschwarze 	return 1;
5074175bdabSschwarze }
5084175bdabSschwarze 
5090ac7e6ecSschwarze static int
5100ac7e6ecSschwarze mdoc_code_pre(MDOC_ARGS)
5116306e64dSschwarze {
5120ac7e6ecSschwarze 	print_otag_id(h, TAG_CODE, roff_name[n->tok], n);
5130ac7e6ecSschwarze 	return 1;
5146306e64dSschwarze }
5156306e64dSschwarze 
5164175bdabSschwarze static int
5174175bdabSschwarze mdoc_sh_pre(MDOC_ARGS)
5184175bdabSschwarze {
5197150bda1Sschwarze 	struct roff_node	*sn, *subn;
52088e033f9Sschwarze 	struct tag		*t, *tnav, *tsec, *tsub;
521fef1eecdSschwarze 	char			*id;
5223327fa00Sschwarze 	int			 sc;
523fef1eecdSschwarze 
524bf997c2cSschwarze 	switch (n->type) {
5253327fa00Sschwarze 	case ROFFT_BLOCK:
5262dd33770Sschwarze 		html_close_paragraph(h);
5273327fa00Sschwarze 		if ((h->oflags & HTML_TOC) == 0 ||
5283327fa00Sschwarze 		    h->flags & HTML_TOCDONE ||
5291a2b7b3cSschwarze 		    n->sec <= SEC_SYNOPSIS) {
5301a2b7b3cSschwarze 			print_otag(h, TAG_SECTION, "c", "Sh");
5313327fa00Sschwarze 			break;
5321a2b7b3cSschwarze 		}
5333327fa00Sschwarze 		h->flags |= HTML_TOCDONE;
5343327fa00Sschwarze 		sc = 0;
5353327fa00Sschwarze 		for (sn = n->next; sn != NULL; sn = sn->next)
5363327fa00Sschwarze 			if (sn->sec == SEC_CUSTOM)
5373327fa00Sschwarze 				if (++sc == 2)
5383327fa00Sschwarze 					break;
5393327fa00Sschwarze 		if (sc < 2)
5403327fa00Sschwarze 			break;
54188e033f9Sschwarze 		tnav = print_otag(h, TAG_NAV, "r", "doc-toc");
54200b92a3fSschwarze 		t = print_otag(h, TAG_H2, "c", "Sh");
5433327fa00Sschwarze 		print_text(h, "TABLE OF CONTENTS");
5443327fa00Sschwarze 		print_tagq(h, t);
5453327fa00Sschwarze 		t = print_otag(h, TAG_UL, "c", "Bl-compact");
5467150bda1Sschwarze 		for (sn = n; sn != NULL; sn = sn->next) {
5477150bda1Sschwarze 			tsec = print_otag(h, TAG_LI, "");
5483327fa00Sschwarze 			id = html_make_id(sn->head, 0);
54972a0eb32Sschwarze 			tsub = print_otag(h, TAG_A, "hR", id);
5503327fa00Sschwarze 			free(id);
5517150bda1Sschwarze 			print_mdoc_nodelist(meta, sn->head->child, h);
55272a0eb32Sschwarze 			print_tagq(h, tsub);
5537150bda1Sschwarze 			tsub = NULL;
5547150bda1Sschwarze 			for (subn = sn->body->child; subn != NULL;
5557150bda1Sschwarze 			    subn = subn->next) {
5567150bda1Sschwarze 				if (subn->tok != MDOC_Ss)
5577150bda1Sschwarze 					continue;
5581d794ce3Sschwarze 				id = html_make_id(subn->head, 0);
5591d794ce3Sschwarze 				if (id == NULL)
5601d794ce3Sschwarze 					continue;
5617150bda1Sschwarze 				if (tsub == NULL)
5627150bda1Sschwarze 					print_otag(h, TAG_UL,
5637150bda1Sschwarze 					    "c", "Bl-compact");
5647150bda1Sschwarze 				tsub = print_otag(h, TAG_LI, "");
5657150bda1Sschwarze 				print_otag(h, TAG_A, "hR", id);
5667150bda1Sschwarze 				free(id);
5677150bda1Sschwarze 				print_mdoc_nodelist(meta,
5687150bda1Sschwarze 				    subn->head->child, h);
5697150bda1Sschwarze 				print_tagq(h, tsub);
5707150bda1Sschwarze 			}
5717150bda1Sschwarze 			print_tagq(h, tsec);
5723327fa00Sschwarze 		}
57388e033f9Sschwarze 		print_tagq(h, tnav);
5741a2b7b3cSschwarze 		print_otag(h, TAG_SECTION, "c", "Sh");
5753327fa00Sschwarze 		break;
5761e98cf61Sschwarze 	case ROFFT_HEAD:
57700b92a3fSschwarze 		print_otag_id(h, TAG_H2, "Sh", n);
5781e98cf61Sschwarze 		break;
579d1982c71Sschwarze 	case ROFFT_BODY:
580bf997c2cSschwarze 		if (n->sec == SEC_AUTHORS)
581bf997c2cSschwarze 			h->flags &= ~(HTML_SPLIT|HTML_NOSPLIT);
5821e98cf61Sschwarze 		break;
583bf997c2cSschwarze 	default:
584bf997c2cSschwarze 		break;
585bf997c2cSschwarze 	}
586526e306bSschwarze 	return 1;
5874175bdabSschwarze }
5884175bdabSschwarze 
5894175bdabSschwarze static int
5904175bdabSschwarze mdoc_ss_pre(MDOC_ARGS)
5914175bdabSschwarze {
5922dd33770Sschwarze 	switch (n->type) {
5932dd33770Sschwarze 	case ROFFT_BLOCK:
5942dd33770Sschwarze 		html_close_paragraph(h);
5951a2b7b3cSschwarze 		print_otag(h, TAG_SECTION, "c", "Ss");
5960ac7e6ecSschwarze 		break;
5972dd33770Sschwarze 	case ROFFT_HEAD:
59800b92a3fSschwarze 		print_otag_id(h, TAG_H3, "Ss", n);
5992dd33770Sschwarze 		break;
6002dd33770Sschwarze 	case ROFFT_BODY:
6010ac7e6ecSschwarze 		break;
6022dd33770Sschwarze 	default:
6032dd33770Sschwarze 		abort();
6042dd33770Sschwarze 	}
605526e306bSschwarze 	return 1;
6064175bdabSschwarze }
6074175bdabSschwarze 
6084175bdabSschwarze static int
6094175bdabSschwarze mdoc_fl_pre(MDOC_ARGS)
6104175bdabSschwarze {
6117ebbefbeSschwarze 	struct roff_node	*nn;
6125d7d1836Sschwarze 
6130ac7e6ecSschwarze 	print_otag_id(h, TAG_CODE, "Fl", n);
6146306e64dSschwarze 	print_text(h, "\\-");
6157ebbefbeSschwarze 	if (n->child != NULL ||
6167ebbefbeSschwarze 	    ((nn = roff_node_next(n)) != NULL &&
6177ebbefbeSschwarze 	     nn->type != ROFFT_TEXT &&
6187ebbefbeSschwarze 	     (nn->flags & NODE_LINE) == 0))
619b16e7ddfSschwarze 		h->flags |= HTML_NOSPACE;
6205d7d1836Sschwarze 
621526e306bSschwarze 	return 1;
6224175bdabSschwarze }
6234175bdabSschwarze 
6244175bdabSschwarze static int
6254175bdabSschwarze mdoc_nd_pre(MDOC_ARGS)
6264175bdabSschwarze {
6272dd33770Sschwarze 	switch (n->type) {
6282dd33770Sschwarze 	case ROFFT_BLOCK:
629526e306bSschwarze 		return 1;
6302dd33770Sschwarze 	case ROFFT_HEAD:
6312dd33770Sschwarze 		return 0;
6322dd33770Sschwarze 	case ROFFT_BODY:
6332dd33770Sschwarze 		break;
6342dd33770Sschwarze 	default:
6352dd33770Sschwarze 		abort();
6362dd33770Sschwarze 	}
6374175bdabSschwarze 	print_text(h, "\\(em");
63893a46bdfSschwarze 	print_otag(h, TAG_SPAN, "cr", "Nd", "doc-subtitle");
639526e306bSschwarze 	return 1;
6404175bdabSschwarze }
6414175bdabSschwarze 
6424175bdabSschwarze static int
6434175bdabSschwarze mdoc_nm_pre(MDOC_ARGS)
6444175bdabSschwarze {
645467b61c6Sschwarze 	switch (n->type) {
6462dd33770Sschwarze 	case ROFFT_BLOCK:
6472dd33770Sschwarze 		break;
648909abc6fSschwarze 	case ROFFT_HEAD:
649229cc7fdSschwarze 		print_otag(h, TAG_TD, "");
650909abc6fSschwarze 		/* FALLTHROUGH */
651d1982c71Sschwarze 	case ROFFT_ELEM:
6520ce603abSschwarze 		print_otag(h, TAG_CODE, "c", "Nm");
653526e306bSschwarze 		return 1;
654d1982c71Sschwarze 	case ROFFT_BODY:
655229cc7fdSschwarze 		print_otag(h, TAG_TD, "");
656526e306bSschwarze 		return 1;
657467b61c6Sschwarze 	default:
6582dd33770Sschwarze 		abort();
659769ee804Sschwarze 	}
6602dd33770Sschwarze 	html_close_paragraph(h);
661467b61c6Sschwarze 	synopsis_pre(h, n);
662774a248cSschwarze 	print_otag(h, TAG_TABLE, "c", "Nm");
663229cc7fdSschwarze 	print_otag(h, TAG_TR, "");
664526e306bSschwarze 	return 1;
6654175bdabSschwarze }
6664175bdabSschwarze 
6674175bdabSschwarze static int
6684175bdabSschwarze mdoc_xr_pre(MDOC_ARGS)
6694175bdabSschwarze {
670b3005203Sschwarze 	char	*name, *section, *label;
671b3005203Sschwarze 
672b3005203Sschwarze 	if (n->child == NULL)
673526e306bSschwarze 		return 0;
674b4dec12aSschwarze 
675b3005203Sschwarze 	name = n->child->string;
676b3005203Sschwarze 	if (n->child->next != NULL) {
677b3005203Sschwarze 		section = n->child->next->string;
678b3005203Sschwarze 		mandoc_asprintf(&label, "%s, section %s", name, section);
679b3005203Sschwarze 	} else
680b3005203Sschwarze 		section = label = NULL;
681b3005203Sschwarze 
6823f160fd1Sschwarze 	if (h->base_man1)
683b3005203Sschwarze 		print_otag(h, TAG_A, "chM?", "Xr",
684b3005203Sschwarze 		    name, section, "aria-label", label);
685fef1eecdSschwarze 	else
686b3005203Sschwarze 		print_otag(h, TAG_A, "c?", "Xr", "aria-label", label);
6874175bdabSschwarze 
688b3005203Sschwarze 	free(label);
689b3005203Sschwarze 	print_text(h, name);
6904175bdabSschwarze 
691b3005203Sschwarze 	if (section == NULL)
692526e306bSschwarze 		return 0;
6934175bdabSschwarze 
6944175bdabSschwarze 	h->flags |= HTML_NOSPACE;
6954175bdabSschwarze 	print_text(h, "(");
6964175bdabSschwarze 	h->flags |= HTML_NOSPACE;
697b3005203Sschwarze 	print_text(h, section);
6984175bdabSschwarze 	h->flags |= HTML_NOSPACE;
6994175bdabSschwarze 	print_text(h, ")");
700526e306bSschwarze 	return 0;
7014175bdabSschwarze }
7024175bdabSschwarze 
7034175bdabSschwarze static int
70492929bf6Sschwarze mdoc_tg_pre(MDOC_ARGS)
70592929bf6Sschwarze {
70692929bf6Sschwarze 	char	*id;
70792929bf6Sschwarze 
7086e69d8cfSschwarze 	if ((id = html_make_id(n, 1)) != NULL) {
70966c5de26Sschwarze 		print_tagq(h, print_otag(h, TAG_MARK, "i", id));
7106e69d8cfSschwarze 		free(id);
7116e69d8cfSschwarze 	}
71292929bf6Sschwarze 	return 0;
71392929bf6Sschwarze }
71492929bf6Sschwarze 
71592929bf6Sschwarze static int
7164175bdabSschwarze mdoc_ns_pre(MDOC_ARGS)
7174175bdabSschwarze {
7184175bdabSschwarze 
719c4b0939cSschwarze 	if ( ! (NODE_LINE & n->flags))
7204175bdabSschwarze 		h->flags |= HTML_NOSPACE;
721526e306bSschwarze 	return 1;
7224175bdabSschwarze }
7234175bdabSschwarze 
7244175bdabSschwarze static int
7254175bdabSschwarze mdoc_ar_pre(MDOC_ARGS)
7264175bdabSschwarze {
7270ce603abSschwarze 	print_otag(h, TAG_VAR, "c", "Ar");
728526e306bSschwarze 	return 1;
7294175bdabSschwarze }
7304175bdabSschwarze 
7314175bdabSschwarze static int
7324175bdabSschwarze mdoc_xx_pre(MDOC_ARGS)
7334175bdabSschwarze {
7340a282dffSschwarze 	print_otag(h, TAG_SPAN, "c", "Ux");
735816c3c54Sschwarze 	return 1;
7364175bdabSschwarze }
7374175bdabSschwarze 
7384175bdabSschwarze static int
7394175bdabSschwarze mdoc_it_pre(MDOC_ARGS)
7404175bdabSschwarze {
7413a0d07afSschwarze 	const struct roff_node	*bl;
742297116b8Sschwarze 	enum mdoc_list		 type;
7434175bdabSschwarze 
744467b61c6Sschwarze 	bl = n->parent;
7459b423113Sschwarze 	while (bl->tok != MDOC_Bl)
7464175bdabSschwarze 		bl = bl->parent;
7478c62fbf5Sschwarze 	type = bl->norm->Bl.type;
74831e23753Sschwarze 
7494175bdabSschwarze 	switch (type) {
75049aff9f8Sschwarze 	case LIST_bullet:
75149aff9f8Sschwarze 	case LIST_dash:
752297116b8Sschwarze 	case LIST_hyphen:
75349aff9f8Sschwarze 	case LIST_item:
754297116b8Sschwarze 	case LIST_enum:
755297116b8Sschwarze 		switch (n->type) {
756297116b8Sschwarze 		case ROFFT_HEAD:
757297116b8Sschwarze 			return 0;
758297116b8Sschwarze 		case ROFFT_BODY:
759e053e0fdSschwarze 			print_otag_id(h, TAG_LI, NULL, n);
760467b61c6Sschwarze 			break;
761297116b8Sschwarze 		default:
762297116b8Sschwarze 			break;
763297116b8Sschwarze 		}
764297116b8Sschwarze 		break;
76549aff9f8Sschwarze 	case LIST_diag:
76649aff9f8Sschwarze 	case LIST_hang:
76749aff9f8Sschwarze 	case LIST_inset:
76849aff9f8Sschwarze 	case LIST_ohang:
769297116b8Sschwarze 		switch (n->type) {
770297116b8Sschwarze 		case ROFFT_HEAD:
771e053e0fdSschwarze 			print_otag_id(h, TAG_DT, NULL, n);
772467b61c6Sschwarze 			break;
773297116b8Sschwarze 		case ROFFT_BODY:
774da5c23dcSschwarze 			print_otag(h, TAG_DD, "");
775467b61c6Sschwarze 			break;
776297116b8Sschwarze 		default:
777297116b8Sschwarze 			break;
778297116b8Sschwarze 		}
779297116b8Sschwarze 		break;
7807c6e1b3aSschwarze 	case LIST_tag:
7817c6e1b3aSschwarze 		switch (n->type) {
7827c6e1b3aSschwarze 		case ROFFT_HEAD:
783e053e0fdSschwarze 			print_otag_id(h, TAG_DT, NULL, n);
7847c6e1b3aSschwarze 			break;
7857c6e1b3aSschwarze 		case ROFFT_BODY:
7867c6e1b3aSschwarze 			if (n->child == NULL) {
7875c9781a4Sschwarze 				print_otag(h, TAG_DD, "s", "width", "auto");
7887c6e1b3aSschwarze 				print_text(h, "\\ ");
7897c6e1b3aSschwarze 			} else
790492a74caSschwarze 				print_otag(h, TAG_DD, "");
7917c6e1b3aSschwarze 			break;
7927c6e1b3aSschwarze 		default:
7937c6e1b3aSschwarze 			break;
7947c6e1b3aSschwarze 		}
7957c6e1b3aSschwarze 		break;
79649aff9f8Sschwarze 	case LIST_column:
797297116b8Sschwarze 		switch (n->type) {
798297116b8Sschwarze 		case ROFFT_HEAD:
799297116b8Sschwarze 			break;
800297116b8Sschwarze 		case ROFFT_BODY:
801492a74caSschwarze 			print_otag(h, TAG_TD, "");
802467b61c6Sschwarze 			break;
803467b61c6Sschwarze 		default:
804e053e0fdSschwarze 			print_otag_id(h, TAG_TR, NULL, n);
805467b61c6Sschwarze 		}
806467b61c6Sschwarze 	default:
807467b61c6Sschwarze 		break;
808467b61c6Sschwarze 	}
8094175bdabSschwarze 
810526e306bSschwarze 	return 1;
8114175bdabSschwarze }
8124175bdabSschwarze 
8134175bdabSschwarze static int
8144175bdabSschwarze mdoc_bl_pre(MDOC_ARGS)
8154175bdabSschwarze {
8168c00a69aSschwarze 	char		 cattr[32];
817b19679ceSschwarze 	struct mdoc_bl	*bl;
818229cc7fdSschwarze 	enum htmltag	 elemtype;
8194175bdabSschwarze 
820408a904eSschwarze 	switch (n->type) {
8212dd33770Sschwarze 	case ROFFT_BLOCK:
8222dd33770Sschwarze 		html_close_paragraph(h);
8232dd33770Sschwarze 		break;
824408a904eSschwarze 	case ROFFT_HEAD:
825526e306bSschwarze 		return 0;
8262dd33770Sschwarze 	case ROFFT_BODY:
8272dd33770Sschwarze 		return 1;
828408a904eSschwarze 	default:
8292dd33770Sschwarze 		abort();
8304175bdabSschwarze 	}
8314175bdabSschwarze 
8327056f56aSschwarze 	bl = &n->norm->Bl;
833b19679ceSschwarze 	switch (bl->type) {
83449aff9f8Sschwarze 	case LIST_bullet:
835297116b8Sschwarze 		elemtype = TAG_UL;
836c67bdbbdSschwarze 		(void)strlcpy(cattr, "Bl-bullet", sizeof(cattr));
837297116b8Sschwarze 		break;
83849aff9f8Sschwarze 	case LIST_dash:
83949aff9f8Sschwarze 	case LIST_hyphen:
840297116b8Sschwarze 		elemtype = TAG_UL;
841c67bdbbdSschwarze 		(void)strlcpy(cattr, "Bl-dash", sizeof(cattr));
842297116b8Sschwarze 		break;
84349aff9f8Sschwarze 	case LIST_item:
844229cc7fdSschwarze 		elemtype = TAG_UL;
845c67bdbbdSschwarze 		(void)strlcpy(cattr, "Bl-item", sizeof(cattr));
846467b61c6Sschwarze 		break;
84749aff9f8Sschwarze 	case LIST_enum:
848229cc7fdSschwarze 		elemtype = TAG_OL;
849c67bdbbdSschwarze 		(void)strlcpy(cattr, "Bl-enum", sizeof(cattr));
850467b61c6Sschwarze 		break;
85149aff9f8Sschwarze 	case LIST_diag:
852297116b8Sschwarze 		elemtype = TAG_DL;
853c67bdbbdSschwarze 		(void)strlcpy(cattr, "Bl-diag", sizeof(cattr));
854297116b8Sschwarze 		break;
85549aff9f8Sschwarze 	case LIST_hang:
856297116b8Sschwarze 		elemtype = TAG_DL;
857c67bdbbdSschwarze 		(void)strlcpy(cattr, "Bl-hang", sizeof(cattr));
858297116b8Sschwarze 		break;
85949aff9f8Sschwarze 	case LIST_inset:
860297116b8Sschwarze 		elemtype = TAG_DL;
861c67bdbbdSschwarze 		(void)strlcpy(cattr, "Bl-inset", sizeof(cattr));
862297116b8Sschwarze 		break;
86349aff9f8Sschwarze 	case LIST_ohang:
864297116b8Sschwarze 		elemtype = TAG_DL;
865c67bdbbdSschwarze 		(void)strlcpy(cattr, "Bl-ohang", sizeof(cattr));
866297116b8Sschwarze 		break;
86749aff9f8Sschwarze 	case LIST_tag:
868b19679ceSschwarze 		if (bl->offs)
8697bdf9c46Sschwarze 			print_otag(h, TAG_DIV, "c", "Bd-indent");
870e053e0fdSschwarze 		print_otag_id(h, TAG_DL,
871e053e0fdSschwarze 		    bl->comp ? "Bl-tag Bl-compact" : "Bl-tag", n->body);
8727c6e1b3aSschwarze 		return 1;
87349aff9f8Sschwarze 	case LIST_column:
874229cc7fdSschwarze 		elemtype = TAG_TABLE;
875c67bdbbdSschwarze 		(void)strlcpy(cattr, "Bl-column", sizeof(cattr));
876467b61c6Sschwarze 		break;
877467b61c6Sschwarze 	default:
878467b61c6Sschwarze 		abort();
879467b61c6Sschwarze 	}
8807bdf9c46Sschwarze 	if (bl->offs != NULL)
8817bdf9c46Sschwarze 		(void)strlcat(cattr, " Bd-indent", sizeof(cattr));
882c67bdbbdSschwarze 	if (bl->comp)
883c67bdbbdSschwarze 		(void)strlcat(cattr, " Bl-compact", sizeof(cattr));
884e053e0fdSschwarze 	print_otag_id(h, elemtype, cattr, n->body);
885526e306bSschwarze 	return 1;
886467b61c6Sschwarze }
8874175bdabSschwarze 
8884175bdabSschwarze static int
8894175bdabSschwarze mdoc_ex_pre(MDOC_ARGS)
8904175bdabSschwarze {
8917ebbefbeSschwarze 	if (roff_node_prev(n) != NULL)
892229cc7fdSschwarze 		print_otag(h, TAG_BR, "");
8938ccddcd3Sschwarze 	return 1;
8944175bdabSschwarze }
8954175bdabSschwarze 
8964175bdabSschwarze static int
897dd15d0f1Sschwarze mdoc_st_pre(MDOC_ARGS)
898dd15d0f1Sschwarze {
8990ce603abSschwarze 	print_otag(h, TAG_SPAN, "c", "St");
900dd15d0f1Sschwarze 	return 1;
901dd15d0f1Sschwarze }
902dd15d0f1Sschwarze 
903dd15d0f1Sschwarze static int
9044175bdabSschwarze mdoc_em_pre(MDOC_ARGS)
9054175bdabSschwarze {
9060ac7e6ecSschwarze 	print_otag_id(h, TAG_I, "Em", n);
907526e306bSschwarze 	return 1;
9084175bdabSschwarze }
9094175bdabSschwarze 
9104175bdabSschwarze static int
9114175bdabSschwarze mdoc_d1_pre(MDOC_ARGS)
9124175bdabSschwarze {
9132dd33770Sschwarze 	switch (n->type) {
9142dd33770Sschwarze 	case ROFFT_BLOCK:
9152dd33770Sschwarze 		html_close_paragraph(h);
916e053e0fdSschwarze 		return 1;
9172dd33770Sschwarze 	case ROFFT_HEAD:
9182dd33770Sschwarze 		return 0;
9192dd33770Sschwarze 	case ROFFT_BODY:
920e053e0fdSschwarze 		break;
9212dd33770Sschwarze 	default:
9222dd33770Sschwarze 		abort();
9232dd33770Sschwarze 	}
924e053e0fdSschwarze 	print_otag_id(h, TAG_DIV, "Bd Bd-indent", n);
925fea50678Sschwarze 	if (n->tok == MDOC_Dl)
926fea50678Sschwarze 		print_otag(h, TAG_CODE, "c", "Li");
927526e306bSschwarze 	return 1;
9284175bdabSschwarze }
9294175bdabSschwarze 
9304175bdabSschwarze static int
9314175bdabSschwarze mdoc_sx_pre(MDOC_ARGS)
9324175bdabSschwarze {
933fef1eecdSschwarze 	char	*id;
9344175bdabSschwarze 
935762c1016Sschwarze 	id = html_make_id(n, 0);
9360ce603abSschwarze 	print_otag(h, TAG_A, "chR", "Sx", id);
937fef1eecdSschwarze 	free(id);
938526e306bSschwarze 	return 1;
9394175bdabSschwarze }
9404175bdabSschwarze 
9414175bdabSschwarze static int
9424175bdabSschwarze mdoc_bd_pre(MDOC_ARGS)
9434175bdabSschwarze {
9444529325aSschwarze 	char			 buf[20];
9453a0d07afSschwarze 	struct roff_node	*nn;
9462dd33770Sschwarze 	int			 comp;
9474175bdabSschwarze 
9482dd33770Sschwarze 	switch (n->type) {
9492dd33770Sschwarze 	case ROFFT_BLOCK:
9502dd33770Sschwarze 		html_close_paragraph(h);
9512dd33770Sschwarze 		return 1;
9522dd33770Sschwarze 	case ROFFT_HEAD:
953526e306bSschwarze 		return 0;
9542dd33770Sschwarze 	case ROFFT_BODY:
9552dd33770Sschwarze 		break;
9562dd33770Sschwarze 	default:
9572dd33770Sschwarze 		abort();
9582dd33770Sschwarze 	}
9594175bdabSschwarze 
9602dd33770Sschwarze 	/* Handle preceding whitespace. */
9612dd33770Sschwarze 
9628c62fbf5Sschwarze 	comp = n->norm->Bd.comp;
9632dd33770Sschwarze 	for (nn = n; nn != NULL && comp == 0; nn = nn->parent) {
964d1982c71Sschwarze 		if (nn->type != ROFFT_BLOCK)
9654175bdabSschwarze 			continue;
9662dd33770Sschwarze 		if (nn->tok == MDOC_Sh || nn->tok == MDOC_Ss)
9674175bdabSschwarze 			comp = 1;
9687ebbefbeSschwarze 		if (roff_node_prev(nn) != NULL)
9694175bdabSschwarze 			break;
9704175bdabSschwarze 	}
9712dd33770Sschwarze 	(void)strlcpy(buf, "Bd", sizeof(buf));
9722dd33770Sschwarze 	if (comp == 0)
9732dd33770Sschwarze 		(void)strlcat(buf, " Pp", sizeof(buf));
974467b61c6Sschwarze 
97590d52a15Sschwarze 	/* Handle the -offset argument. */
97690d52a15Sschwarze 
9772dd33770Sschwarze 	if (n->norm->Bd.offs != NULL &&
9782dd33770Sschwarze 	    strcmp(n->norm->Bd.offs, "left") != 0)
9792dd33770Sschwarze 		(void)strlcat(buf, " Bd-indent", sizeof(buf));
980467b61c6Sschwarze 
9814529325aSschwarze 	if (n->norm->Bd.type == DISP_literal)
9824529325aSschwarze 		(void)strlcat(buf, " Li", sizeof(buf));
9834529325aSschwarze 
984e053e0fdSschwarze 	print_otag_id(h, TAG_DIV, buf, n);
98535030e67Sschwarze 	return 1;
9864175bdabSschwarze }
9874175bdabSschwarze 
9884175bdabSschwarze static int
9894175bdabSschwarze mdoc_pa_pre(MDOC_ARGS)
9904175bdabSschwarze {
9910ce603abSschwarze 	print_otag(h, TAG_SPAN, "c", "Pa");
992526e306bSschwarze 	return 1;
9934175bdabSschwarze }
9944175bdabSschwarze 
9954175bdabSschwarze static int
9964175bdabSschwarze mdoc_ad_pre(MDOC_ARGS)
9974175bdabSschwarze {
998e34b78c5Sschwarze 	print_otag(h, TAG_SPAN, "c", "Ad");
999526e306bSschwarze 	return 1;
10004175bdabSschwarze }
10014175bdabSschwarze 
10024175bdabSschwarze static int
10034175bdabSschwarze mdoc_an_pre(MDOC_ARGS)
10044175bdabSschwarze {
1005bf997c2cSschwarze 	if (n->norm->An.auth == AUTH_split) {
1006bf997c2cSschwarze 		h->flags &= ~HTML_NOSPLIT;
1007bf997c2cSschwarze 		h->flags |= HTML_SPLIT;
1008526e306bSschwarze 		return 0;
1009bf997c2cSschwarze 	}
1010bf997c2cSschwarze 	if (n->norm->An.auth == AUTH_nosplit) {
1011bf997c2cSschwarze 		h->flags &= ~HTML_SPLIT;
1012bf997c2cSschwarze 		h->flags |= HTML_NOSPLIT;
1013526e306bSschwarze 		return 0;
1014bf997c2cSschwarze 	}
1015bf997c2cSschwarze 
1016bf997c2cSschwarze 	if (h->flags & HTML_SPLIT)
1017229cc7fdSschwarze 		print_otag(h, TAG_BR, "");
1018bf997c2cSschwarze 
1019bf997c2cSschwarze 	if (n->sec == SEC_AUTHORS && ! (h->flags & HTML_NOSPLIT))
1020bf997c2cSschwarze 		h->flags |= HTML_SPLIT;
10214175bdabSschwarze 
10220ce603abSschwarze 	print_otag(h, TAG_SPAN, "c", "An");
1023526e306bSschwarze 	return 1;
10244175bdabSschwarze }
10254175bdabSschwarze 
10264175bdabSschwarze static int
10274175bdabSschwarze mdoc_cd_pre(MDOC_ARGS)
10284175bdabSschwarze {
10299a98b8a1Sschwarze 	synopsis_pre(h, n);
10300ce603abSschwarze 	print_otag(h, TAG_CODE, "c", "Cd");
1031526e306bSschwarze 	return 1;
10324175bdabSschwarze }
10334175bdabSschwarze 
10344175bdabSschwarze static int
10354175bdabSschwarze mdoc_fa_pre(MDOC_ARGS)
10364175bdabSschwarze {
10373a0d07afSschwarze 	const struct roff_node	*nn;
10384175bdabSschwarze 	struct tag		*t;
10394175bdabSschwarze 
10404175bdabSschwarze 	if (n->parent->tok != MDOC_Fo) {
10410ce603abSschwarze 		print_otag(h, TAG_VAR, "c", "Fa");
1042526e306bSschwarze 		return 1;
10434175bdabSschwarze 	}
10447ebbefbeSschwarze 	for (nn = n->child; nn != NULL; nn = nn->next) {
10450ce603abSschwarze 		t = print_otag(h, TAG_VAR, "c", "Fa");
10464175bdabSschwarze 		print_text(h, nn->string);
10474175bdabSschwarze 		print_tagq(h, t);
10487ebbefbeSschwarze 		if (nn->next != NULL) {
1049a35fc07aSschwarze 			h->flags |= HTML_NOSPACE;
10504175bdabSschwarze 			print_text(h, ",");
10514175bdabSschwarze 		}
1052a35fc07aSschwarze 	}
10537ebbefbeSschwarze 	if (n->child != NULL &&
10547ebbefbeSschwarze 	    (nn = roff_node_next(n)) != NULL &&
10557ebbefbeSschwarze 	    nn->tok == MDOC_Fa) {
1056a35fc07aSschwarze 		h->flags |= HTML_NOSPACE;
10574175bdabSschwarze 		print_text(h, ",");
1058a35fc07aSschwarze 	}
1059526e306bSschwarze 	return 0;
10604175bdabSschwarze }
10614175bdabSschwarze 
10624175bdabSschwarze static int
10634175bdabSschwarze mdoc_fd_pre(MDOC_ARGS)
10644175bdabSschwarze {
1065a35fc07aSschwarze 	struct tag	*t;
1066fef1eecdSschwarze 	char		*buf, *cp;
10674175bdabSschwarze 
10689a98b8a1Sschwarze 	synopsis_pre(h, n);
10699a98b8a1Sschwarze 
1070a35fc07aSschwarze 	if (NULL == (n = n->child))
1071526e306bSschwarze 		return 0;
1072a35fc07aSschwarze 
1073d1982c71Sschwarze 	assert(n->type == ROFFT_TEXT);
1074a35fc07aSschwarze 
1075a35fc07aSschwarze 	if (strcmp(n->string, "#include")) {
10760ce603abSschwarze 		print_otag(h, TAG_CODE, "c", "Fd");
1077526e306bSschwarze 		return 1;
10784175bdabSschwarze 	}
10794175bdabSschwarze 
10800ce603abSschwarze 	print_otag(h, TAG_CODE, "c", "In");
1081a35fc07aSschwarze 	print_text(h, n->string);
1082a35fc07aSschwarze 
1083a35fc07aSschwarze 	if (NULL != (n = n->next)) {
1084d1982c71Sschwarze 		assert(n->type == ROFFT_TEXT);
10850b2f1307Sschwarze 
1086a35fc07aSschwarze 		if (h->base_includes) {
1087fef1eecdSschwarze 			cp = n->string;
1088fef1eecdSschwarze 			if (*cp == '<' || *cp == '"')
1089fef1eecdSschwarze 				cp++;
1090fef1eecdSschwarze 			buf = mandoc_strdup(cp);
1091fef1eecdSschwarze 			cp = strchr(buf, '\0') - 1;
1092fef1eecdSschwarze 			if (cp >= buf && (*cp == '>' || *cp == '"'))
1093fef1eecdSschwarze 				*cp = '\0';
10940ce603abSschwarze 			t = print_otag(h, TAG_A, "chI", "In", buf);
1095fef1eecdSschwarze 			free(buf);
1096229cc7fdSschwarze 		} else
10970ce603abSschwarze 			t = print_otag(h, TAG_A, "c", "In");
1098a35fc07aSschwarze 
1099a35fc07aSschwarze 		print_text(h, n->string);
1100a35fc07aSschwarze 		print_tagq(h, t);
1101a35fc07aSschwarze 
1102a35fc07aSschwarze 		n = n->next;
1103a35fc07aSschwarze 	}
1104a35fc07aSschwarze 
1105a35fc07aSschwarze 	for ( ; n; n = n->next) {
1106d1982c71Sschwarze 		assert(n->type == ROFFT_TEXT);
1107a35fc07aSschwarze 		print_text(h, n->string);
1108a35fc07aSschwarze 	}
1109a35fc07aSschwarze 
1110526e306bSschwarze 	return 0;
1111a35fc07aSschwarze }
1112a35fc07aSschwarze 
11134175bdabSschwarze static int
11144175bdabSschwarze mdoc_vt_pre(MDOC_ARGS)
11154175bdabSschwarze {
1116d1982c71Sschwarze 	if (n->type == ROFFT_BLOCK) {
11179a98b8a1Sschwarze 		synopsis_pre(h, n);
1118526e306bSschwarze 		return 1;
1119d1982c71Sschwarze 	} else if (n->type == ROFFT_ELEM) {
11209a98b8a1Sschwarze 		synopsis_pre(h, n);
1121d1982c71Sschwarze 	} else if (n->type == ROFFT_HEAD)
1122526e306bSschwarze 		return 0;
11234175bdabSschwarze 
11240ce603abSschwarze 	print_otag(h, TAG_VAR, "c", "Vt");
1125526e306bSschwarze 	return 1;
11264175bdabSschwarze }
11274175bdabSschwarze 
11284175bdabSschwarze static int
11294175bdabSschwarze mdoc_ft_pre(MDOC_ARGS)
11304175bdabSschwarze {
11319a98b8a1Sschwarze 	synopsis_pre(h, n);
11320ce603abSschwarze 	print_otag(h, TAG_VAR, "c", "Ft");
1133526e306bSschwarze 	return 1;
11344175bdabSschwarze }
11354175bdabSschwarze 
11364175bdabSschwarze static int
11374175bdabSschwarze mdoc_fn_pre(MDOC_ARGS)
11384175bdabSschwarze {
11394175bdabSschwarze 	struct tag	*t;
11404175bdabSschwarze 	char		 nbuf[BUFSIZ];
11414175bdabSschwarze 	const char	*sp, *ep;
1142229cc7fdSschwarze 	int		 sz, pretty;
11434175bdabSschwarze 
1144c4b0939cSschwarze 	pretty = NODE_SYNPRETTY & n->flags;
11459a98b8a1Sschwarze 	synopsis_pre(h, n);
11464175bdabSschwarze 
11474175bdabSschwarze 	/* Split apart into type and name. */
11484175bdabSschwarze 	assert(n->child->string);
11494175bdabSschwarze 	sp = n->child->string;
11504175bdabSschwarze 
11514175bdabSschwarze 	ep = strchr(sp, ' ');
11524175bdabSschwarze 	if (NULL != ep) {
11530ce603abSschwarze 		t = print_otag(h, TAG_VAR, "c", "Ft");
11544175bdabSschwarze 
11554175bdabSschwarze 		while (ep) {
11564175bdabSschwarze 			sz = MIN((int)(ep - sp), BUFSIZ - 1);
11574175bdabSschwarze 			(void)memcpy(nbuf, sp, (size_t)sz);
11584175bdabSschwarze 			nbuf[sz] = '\0';
11594175bdabSschwarze 			print_text(h, nbuf);
11604175bdabSschwarze 			sp = ++ep;
11614175bdabSschwarze 			ep = strchr(sp, ' ');
11624175bdabSschwarze 		}
11634175bdabSschwarze 		print_tagq(h, t);
11644175bdabSschwarze 	}
11654175bdabSschwarze 
11660ac7e6ecSschwarze 	t = print_otag_id(h, TAG_CODE, "Fn", n);
11674175bdabSschwarze 
11680b2f1307Sschwarze 	if (sp)
11690b2f1307Sschwarze 		print_text(h, sp);
11704175bdabSschwarze 
11714175bdabSschwarze 	print_tagq(h, t);
11724175bdabSschwarze 
11734175bdabSschwarze 	h->flags |= HTML_NOSPACE;
11744175bdabSschwarze 	print_text(h, "(");
1175a35fc07aSschwarze 	h->flags |= HTML_NOSPACE;
11764175bdabSschwarze 
1177a35fc07aSschwarze 	for (n = n->child->next; n; n = n->next) {
1178c4b0939cSschwarze 		if (NODE_SYNPRETTY & n->flags)
11790ce603abSschwarze 			t = print_otag(h, TAG_VAR, "cs", "Fa",
1180229cc7fdSschwarze 			    "white-space", "nowrap");
1181229cc7fdSschwarze 		else
11820ce603abSschwarze 			t = print_otag(h, TAG_VAR, "c", "Fa");
1183a35fc07aSschwarze 		print_text(h, n->string);
11844175bdabSschwarze 		print_tagq(h, t);
1185a35fc07aSschwarze 		if (n->next) {
1186a35fc07aSschwarze 			h->flags |= HTML_NOSPACE;
11874175bdabSschwarze 			print_text(h, ",");
11884175bdabSschwarze 		}
1189a35fc07aSschwarze 	}
11904175bdabSschwarze 
1191a35fc07aSschwarze 	h->flags |= HTML_NOSPACE;
11924175bdabSschwarze 	print_text(h, ")");
1193a35fc07aSschwarze 
1194a35fc07aSschwarze 	if (pretty) {
1195a35fc07aSschwarze 		h->flags |= HTML_NOSPACE;
11964175bdabSschwarze 		print_text(h, ";");
1197a35fc07aSschwarze 	}
11984175bdabSschwarze 
1199526e306bSschwarze 	return 0;
12004175bdabSschwarze }
12014175bdabSschwarze 
12024175bdabSschwarze static int
1203ddce0b0cSschwarze mdoc_sm_pre(MDOC_ARGS)
1204ddce0b0cSschwarze {
1205ddce0b0cSschwarze 
1206f9e7bf99Sschwarze 	if (NULL == n->child)
1207f9e7bf99Sschwarze 		h->flags ^= HTML_NONOSPACE;
1208f9e7bf99Sschwarze 	else if (0 == strcmp("on", n->child->string))
1209ddce0b0cSschwarze 		h->flags &= ~HTML_NONOSPACE;
1210f9e7bf99Sschwarze 	else
1211ddce0b0cSschwarze 		h->flags |= HTML_NONOSPACE;
1212ddce0b0cSschwarze 
1213f9e7bf99Sschwarze 	if ( ! (HTML_NONOSPACE & h->flags))
1214f9e7bf99Sschwarze 		h->flags &= ~HTML_NOSPACE;
1215f9e7bf99Sschwarze 
1216526e306bSschwarze 	return 0;
1217ddce0b0cSschwarze }
1218ddce0b0cSschwarze 
1219467b61c6Sschwarze static int
1220551cd4a8Sschwarze mdoc_skip_pre(MDOC_ARGS)
12215281506aSschwarze {
12225281506aSschwarze 
1223526e306bSschwarze 	return 0;
12245281506aSschwarze }
12255281506aSschwarze 
12265281506aSschwarze static int
1227467b61c6Sschwarze mdoc_pp_pre(MDOC_ARGS)
1228467b61c6Sschwarze {
12296e69d8cfSschwarze 	char	*id;
12306e69d8cfSschwarze 
1231e2edd184Sschwarze 	if (n->flags & NODE_NOFILL) {
1232e2edd184Sschwarze 		print_endline(h);
1233e053e0fdSschwarze 		if (n->flags & NODE_ID)
1234e053e0fdSschwarze 			mdoc_tg_pre(meta, n, h);
1235e053e0fdSschwarze 		else {
1236e2edd184Sschwarze 			h->col = 1;
1237e2edd184Sschwarze 			print_endline(h);
1238e053e0fdSschwarze 		}
1239e2edd184Sschwarze 	} else {
12402dd33770Sschwarze 		html_close_paragraph(h);
12416e69d8cfSschwarze 		id = n->flags & NODE_ID ? html_make_id(n, 1) : NULL;
12426e69d8cfSschwarze 		print_otag(h, TAG_P, "ci", "Pp", id);
12436e69d8cfSschwarze 		free(id);
12442dd33770Sschwarze 	}
1245526e306bSschwarze 	return 0;
1246467b61c6Sschwarze }
1247ddce0b0cSschwarze 
1248ddce0b0cSschwarze static int
12494175bdabSschwarze mdoc_lk_pre(MDOC_ARGS)
12504175bdabSschwarze {
1251eb4d0f30Sschwarze 	const struct roff_node *link, *descr, *punct;
125296aebfb3Sschwarze 	struct tag	*t;
125396aebfb3Sschwarze 
1254eb4d0f30Sschwarze 	if ((link = n->child) == NULL)
1255526e306bSschwarze 		return 0;
1256a35fc07aSschwarze 
1257eb4d0f30Sschwarze 	/* Find beginning of trailing punctuation. */
1258eb4d0f30Sschwarze 	punct = n->last;
1259eb4d0f30Sschwarze 	while (punct != link && punct->flags & NODE_DELIMC)
1260eb4d0f30Sschwarze 		punct = punct->prev;
1261eb4d0f30Sschwarze 	punct = punct->next;
1262eb4d0f30Sschwarze 
126396aebfb3Sschwarze 	/* Link target and link text. */
1264fd01a48eSschwarze 	descr = link->next;
1265fd01a48eSschwarze 	if (descr == punct)
1266fd01a48eSschwarze 		descr = link;  /* no text */
12670ce603abSschwarze 	t = print_otag(h, TAG_A, "ch", "Lk", link->string);
1268fd01a48eSschwarze 	do {
1269eb4d0f30Sschwarze 		if (descr->flags & (NODE_DELIMC | NODE_DELIMO))
1270eb4d0f30Sschwarze 			h->flags |= HTML_NOSPACE;
1271eb4d0f30Sschwarze 		print_text(h, descr->string);
1272fd01a48eSschwarze 		descr = descr->next;
1273fd01a48eSschwarze 	} while (descr != punct);
127496aebfb3Sschwarze 	print_tagq(h, t);
12754175bdabSschwarze 
127696aebfb3Sschwarze 	/* Trailing punctuation. */
1277eb4d0f30Sschwarze 	while (punct != NULL) {
127896aebfb3Sschwarze 		h->flags |= HTML_NOSPACE;
1279eb4d0f30Sschwarze 		print_text(h, punct->string);
1280eb4d0f30Sschwarze 		punct = punct->next;
128196aebfb3Sschwarze 	}
1282526e306bSschwarze 	return 0;
12834175bdabSschwarze }
12844175bdabSschwarze 
12854175bdabSschwarze static int
12864175bdabSschwarze mdoc_mt_pre(MDOC_ARGS)
12874175bdabSschwarze {
12884175bdabSschwarze 	struct tag	*t;
1289fef1eecdSschwarze 	char		*cp;
12904175bdabSschwarze 
1291a35fc07aSschwarze 	for (n = n->child; n; n = n->next) {
1292d1982c71Sschwarze 		assert(n->type == ROFFT_TEXT);
1293fef1eecdSschwarze 		mandoc_asprintf(&cp, "mailto:%s", n->string);
12940ce603abSschwarze 		t = print_otag(h, TAG_A, "ch", "Mt", cp);
1295a35fc07aSschwarze 		print_text(h, n->string);
12964175bdabSschwarze 		print_tagq(h, t);
1297fef1eecdSschwarze 		free(cp);
12984175bdabSschwarze 	}
1299526e306bSschwarze 	return 0;
13004175bdabSschwarze }
13014175bdabSschwarze 
13024175bdabSschwarze static int
13034175bdabSschwarze mdoc_fo_pre(MDOC_ARGS)
13044175bdabSschwarze {
13056093755cSschwarze 	struct tag	*t;
13064175bdabSschwarze 
13070ac7e6ecSschwarze 	switch (n->type) {
13080ac7e6ecSschwarze 	case ROFFT_BLOCK:
13090ac7e6ecSschwarze 		synopsis_pre(h, n);
13100ac7e6ecSschwarze 		return 1;
13110ac7e6ecSschwarze 	case ROFFT_HEAD:
13120ac7e6ecSschwarze 		if (n->child != NULL) {
13130ac7e6ecSschwarze 			t = print_otag_id(h, TAG_CODE, "Fn", n);
13140ac7e6ecSschwarze 			print_text(h, n->child->string);
13150ac7e6ecSschwarze 			print_tagq(h, t);
13160ac7e6ecSschwarze 		}
13170ac7e6ecSschwarze 		return 0;
13180ac7e6ecSschwarze 	case ROFFT_BODY:
13194175bdabSschwarze 		h->flags |= HTML_NOSPACE;
13204175bdabSschwarze 		print_text(h, "(");
13214175bdabSschwarze 		h->flags |= HTML_NOSPACE;
1322526e306bSschwarze 		return 1;
13230ac7e6ecSschwarze 	default:
13240ac7e6ecSschwarze 		abort();
1325b16e7ddfSschwarze 	}
13264175bdabSschwarze }
13274175bdabSschwarze 
13284175bdabSschwarze static void
13294175bdabSschwarze mdoc_fo_post(MDOC_ARGS)
13304175bdabSschwarze {
1331d1982c71Sschwarze 	if (n->type != ROFFT_BODY)
13324175bdabSschwarze 		return;
1333a35fc07aSschwarze 	h->flags |= HTML_NOSPACE;
13344175bdabSschwarze 	print_text(h, ")");
1335a35fc07aSschwarze 	h->flags |= HTML_NOSPACE;
13364175bdabSschwarze 	print_text(h, ";");
13374175bdabSschwarze }
13384175bdabSschwarze 
13394175bdabSschwarze static int
13404175bdabSschwarze mdoc_in_pre(MDOC_ARGS)
13414175bdabSschwarze {
13424175bdabSschwarze 	struct tag	*t;
13434175bdabSschwarze 
13449a98b8a1Sschwarze 	synopsis_pre(h, n);
13450ce603abSschwarze 	print_otag(h, TAG_CODE, "c", "In");
13464175bdabSschwarze 
1347a35fc07aSschwarze 	/*
1348a35fc07aSschwarze 	 * The first argument of the `In' gets special treatment as
1349a35fc07aSschwarze 	 * being a linked value.  Subsequent values are printed
1350a35fc07aSschwarze 	 * afterward.  groff does similarly.  This also handles the case
1351a35fc07aSschwarze 	 * of no children.
1352a35fc07aSschwarze 	 */
1353a35fc07aSschwarze 
1354c4b0939cSschwarze 	if (NODE_SYNPRETTY & n->flags && NODE_LINE & n->flags)
13554175bdabSschwarze 		print_text(h, "#include");
13564175bdabSschwarze 
13574175bdabSschwarze 	print_text(h, "<");
13584175bdabSschwarze 	h->flags |= HTML_NOSPACE;
13594175bdabSschwarze 
1360a35fc07aSschwarze 	if (NULL != (n = n->child)) {
1361d1982c71Sschwarze 		assert(n->type == ROFFT_TEXT);
1362a35fc07aSschwarze 
1363fef1eecdSschwarze 		if (h->base_includes)
13640ce603abSschwarze 			t = print_otag(h, TAG_A, "chI", "In", n->string);
1365fef1eecdSschwarze 		else
13660ce603abSschwarze 			t = print_otag(h, TAG_A, "c", "In");
1367a35fc07aSschwarze 		print_text(h, n->string);
13684175bdabSschwarze 		print_tagq(h, t);
1369a35fc07aSschwarze 
1370a35fc07aSschwarze 		n = n->next;
13714175bdabSschwarze 	}
13724175bdabSschwarze 
13734175bdabSschwarze 	h->flags |= HTML_NOSPACE;
13744175bdabSschwarze 	print_text(h, ">");
13754175bdabSschwarze 
1376a35fc07aSschwarze 	for ( ; n; n = n->next) {
1377d1982c71Sschwarze 		assert(n->type == ROFFT_TEXT);
1378a35fc07aSschwarze 		print_text(h, n->string);
1379a35fc07aSschwarze 	}
1380526e306bSschwarze 	return 0;
13814175bdabSschwarze }
13824175bdabSschwarze 
13834175bdabSschwarze static int
13844175bdabSschwarze mdoc_va_pre(MDOC_ARGS)
13854175bdabSschwarze {
13860ce603abSschwarze 	print_otag(h, TAG_VAR, "c", "Va");
1387526e306bSschwarze 	return 1;
13884175bdabSschwarze }
13894175bdabSschwarze 
13904175bdabSschwarze static int
13914175bdabSschwarze mdoc_ap_pre(MDOC_ARGS)
13924175bdabSschwarze {
13934175bdabSschwarze 	h->flags |= HTML_NOSPACE;
13944175bdabSschwarze 	print_text(h, "\\(aq");
13954175bdabSschwarze 	h->flags |= HTML_NOSPACE;
1396526e306bSschwarze 	return 1;
13974175bdabSschwarze }
13984175bdabSschwarze 
13994175bdabSschwarze static int
14004175bdabSschwarze mdoc_bf_pre(MDOC_ARGS)
14014175bdabSschwarze {
1402229cc7fdSschwarze 	const char	*cattr;
14034175bdabSschwarze 
14042dd33770Sschwarze 	switch (n->type) {
14052dd33770Sschwarze 	case ROFFT_BLOCK:
14062dd33770Sschwarze 		html_close_paragraph(h);
1407526e306bSschwarze 		return 1;
14082dd33770Sschwarze 	case ROFFT_HEAD:
14092dd33770Sschwarze 		return 0;
14102dd33770Sschwarze 	case ROFFT_BODY:
14112dd33770Sschwarze 		break;
14122dd33770Sschwarze 	default:
14132dd33770Sschwarze 		abort();
14142dd33770Sschwarze 	}
14154175bdabSschwarze 
1416d257d942Sschwarze 	if (FONT_Em == n->norm->Bf.font)
14172e36b507Sschwarze 		cattr = "Bf Em";
1418d257d942Sschwarze 	else if (FONT_Sy == n->norm->Bf.font)
14192e36b507Sschwarze 		cattr = "Bf Sy";
14208c62fbf5Sschwarze 	else if (FONT_Li == n->norm->Bf.font)
14212e36b507Sschwarze 		cattr = "Bf Li";
1422769ee804Sschwarze 	else
14232e36b507Sschwarze 		cattr = "Bf No";
14244175bdabSschwarze 
14252e36b507Sschwarze 	/* Cannot use TAG_SPAN because it may contain blocks. */
142670a5f756Sschwarze 	print_otag(h, TAG_DIV, "c", cattr);
1427526e306bSschwarze 	return 1;
14284175bdabSschwarze }
14294175bdabSschwarze 
14304175bdabSschwarze static int
143137e2f24fSschwarze mdoc_igndelim_pre(MDOC_ARGS)
14324175bdabSschwarze {
14334175bdabSschwarze 	h->flags |= HTML_IGNDELIM;
1434526e306bSschwarze 	return 1;
14354175bdabSschwarze }
14364175bdabSschwarze 
14374175bdabSschwarze static void
14384175bdabSschwarze mdoc_pf_post(MDOC_ARGS)
14394175bdabSschwarze {
1440c4b0939cSschwarze 	if ( ! (n->next == NULL || n->next->flags & NODE_LINE))
14414175bdabSschwarze 		h->flags |= HTML_NOSPACE;
14424175bdabSschwarze }
14434175bdabSschwarze 
14444175bdabSschwarze static int
14454175bdabSschwarze mdoc_rs_pre(MDOC_ARGS)
14464175bdabSschwarze {
14472dd33770Sschwarze 	switch (n->type) {
14482dd33770Sschwarze 	case ROFFT_BLOCK:
14492dd33770Sschwarze 		if (n->sec == SEC_SEE_ALSO)
14502dd33770Sschwarze 			html_close_paragraph(h);
14512dd33770Sschwarze 		break;
14522dd33770Sschwarze 	case ROFFT_HEAD:
14532dd33770Sschwarze 		return 0;
14542dd33770Sschwarze 	case ROFFT_BODY:
14552dd33770Sschwarze 		if (n->sec == SEC_SEE_ALSO)
14562dd33770Sschwarze 			print_otag(h, TAG_P, "c", "Pp");
1457*645bcdadSschwarze 		print_otag(h, TAG_SPAN, "c", "Rs");
14582dd33770Sschwarze 		break;
14592dd33770Sschwarze 	default:
14602dd33770Sschwarze 		abort();
14612dd33770Sschwarze 	}
1462526e306bSschwarze 	return 1;
14634175bdabSschwarze }
14644175bdabSschwarze 
14654175bdabSschwarze static int
14666f9818f6Sschwarze mdoc_no_pre(MDOC_ARGS)
14676f9818f6Sschwarze {
14680ac7e6ecSschwarze 	print_otag_id(h, TAG_SPAN, roff_name[n->tok], n);
1469526e306bSschwarze 	return 1;
14704175bdabSschwarze }
14714175bdabSschwarze 
14724175bdabSschwarze static int
14734175bdabSschwarze mdoc_sy_pre(MDOC_ARGS)
14744175bdabSschwarze {
14750ac7e6ecSschwarze 	print_otag_id(h, TAG_B, "Sy", n);
1476526e306bSschwarze 	return 1;
14774175bdabSschwarze }
14784175bdabSschwarze 
14794175bdabSschwarze static int
14804175bdabSschwarze mdoc_lb_pre(MDOC_ARGS)
14814175bdabSschwarze {
14827ebbefbeSschwarze 	if (n->sec == SEC_LIBRARY &&
14837ebbefbeSschwarze 	    n->flags & NODE_LINE &&
14847ebbefbeSschwarze 	    roff_node_prev(n) != NULL)
1485229cc7fdSschwarze 		print_otag(h, TAG_BR, "");
1486467b61c6Sschwarze 
14870ce603abSschwarze 	print_otag(h, TAG_SPAN, "c", "Lb");
1488526e306bSschwarze 	return 1;
14894175bdabSschwarze }
14904175bdabSschwarze 
14914175bdabSschwarze static int
14924175bdabSschwarze mdoc__x_pre(MDOC_ARGS)
14934175bdabSschwarze {
14947ebbefbeSschwarze 	struct roff_node	*nn;
14950aa8d661Sschwarze 	const unsigned char	*cp;
14960aa8d661Sschwarze 	const char		*cattr, *arg;
14970aa8d661Sschwarze 	char			*url;
1498b009ccebSschwarze 	enum htmltag		 t;
1499b009ccebSschwarze 
1500b009ccebSschwarze 	t = TAG_SPAN;
15010aa8d661Sschwarze 	arg = n->child->string;
15024175bdabSschwarze 
15034175bdabSschwarze 	switch (n->tok) {
150449aff9f8Sschwarze 	case MDOC__A:
1505186d9410Sschwarze 		cattr = "RsA";
15067ebbefbeSschwarze 		if ((nn = roff_node_prev(n)) != NULL && nn->tok == MDOC__A &&
15077ebbefbeSschwarze 		    ((nn = roff_node_next(n)) == NULL || nn->tok != MDOC__A))
1508bf782e42Sschwarze 			print_text(h, "and");
15094175bdabSschwarze 		break;
151049aff9f8Sschwarze 	case MDOC__B:
1511*645bcdadSschwarze 		t = TAG_CITE;
1512186d9410Sschwarze 		cattr = "RsB";
15134175bdabSschwarze 		break;
151449aff9f8Sschwarze 	case MDOC__C:
1515186d9410Sschwarze 		cattr = "RsC";
15164175bdabSschwarze 		break;
151749aff9f8Sschwarze 	case MDOC__D:
1518186d9410Sschwarze 		cattr = "RsD";
15194175bdabSschwarze 		break;
152049aff9f8Sschwarze 	case MDOC__I:
1521b009ccebSschwarze 		t = TAG_I;
1522186d9410Sschwarze 		cattr = "RsI";
15234175bdabSschwarze 		break;
152449aff9f8Sschwarze 	case MDOC__J:
1525b009ccebSschwarze 		t = TAG_I;
1526186d9410Sschwarze 		cattr = "RsJ";
15274175bdabSschwarze 		break;
152849aff9f8Sschwarze 	case MDOC__N:
1529186d9410Sschwarze 		cattr = "RsN";
15304175bdabSschwarze 		break;
153149aff9f8Sschwarze 	case MDOC__O:
1532186d9410Sschwarze 		cattr = "RsO";
15334175bdabSschwarze 		break;
153449aff9f8Sschwarze 	case MDOC__P:
1535186d9410Sschwarze 		cattr = "RsP";
15364175bdabSschwarze 		break;
153749aff9f8Sschwarze 	case MDOC__Q:
1538186d9410Sschwarze 		cattr = "RsQ";
15394175bdabSschwarze 		break;
154049aff9f8Sschwarze 	case MDOC__R:
15410aa8d661Sschwarze 		if (strncmp(arg, "RFC ", 4) == 0) {
15420aa8d661Sschwarze 			cp = arg += 4;
15430aa8d661Sschwarze 			while (isdigit(*cp))
15440aa8d661Sschwarze 				cp++;
15450aa8d661Sschwarze 			if (*cp == '\0') {
15460aa8d661Sschwarze 				mandoc_asprintf(&url, "https://www.rfc-"
15470aa8d661Sschwarze 				    "editor.org/rfc/rfc%s.html", arg);
15480aa8d661Sschwarze 				print_otag(h, TAG_A, "ch", "RsR", url);
15490aa8d661Sschwarze 				free(url);
15500aa8d661Sschwarze 				return 1;
15510aa8d661Sschwarze 			}
15520aa8d661Sschwarze 		}
1553186d9410Sschwarze 		cattr = "RsR";
15544175bdabSschwarze 		break;
155549aff9f8Sschwarze 	case MDOC__T:
1556*645bcdadSschwarze 		t = TAG_CITE;
155761a57034Sschwarze 		if (n->parent != NULL && n->parent->tok == MDOC_Rs &&
155861a57034Sschwarze 		    n->parent->norm->Rs.quote_T) {
155961a57034Sschwarze 			print_text(h, "\\(lq");
156061a57034Sschwarze 			h->flags |= HTML_NOSPACE;
1561186d9410Sschwarze 			cattr = "RsT";
156261a57034Sschwarze 		} else
156361a57034Sschwarze 			cattr = "RsB";
15644175bdabSschwarze 		break;
156549aff9f8Sschwarze 	case MDOC__U:
15660aa8d661Sschwarze 		print_otag(h, TAG_A, "ch", "RsU", arg);
1567186d9410Sschwarze 		return 1;
156849aff9f8Sschwarze 	case MDOC__V:
1569186d9410Sschwarze 		cattr = "RsV";
15704175bdabSschwarze 		break;
15714175bdabSschwarze 	default:
15724175bdabSschwarze 		abort();
15734175bdabSschwarze 	}
15744175bdabSschwarze 
1575229cc7fdSschwarze 	print_otag(h, t, "c", cattr);
1576526e306bSschwarze 	return 1;
1577b822ca0dSschwarze }
1578b822ca0dSschwarze 
15794175bdabSschwarze static void
15804175bdabSschwarze mdoc__x_post(MDOC_ARGS)
15814175bdabSschwarze {
15827ebbefbeSschwarze 	struct roff_node *nn;
15834175bdabSschwarze 
158461a57034Sschwarze 	switch (n->tok) {
158561a57034Sschwarze 	case MDOC__A:
158661a57034Sschwarze 		if ((nn = roff_node_next(n)) != NULL && nn->tok == MDOC__A &&
15877ebbefbeSschwarze 		    ((nn = roff_node_next(nn)) == NULL || nn->tok != MDOC__A) &&
15887ebbefbeSschwarze 		    ((nn = roff_node_prev(n)) == NULL || nn->tok != MDOC__A))
1589bf782e42Sschwarze 			return;
159061a57034Sschwarze 		break;
159161a57034Sschwarze 	case MDOC__T:
159261a57034Sschwarze 		if (n->parent != NULL && n->parent->tok == MDOC_Rs &&
159361a57034Sschwarze 		    n->parent->norm->Rs.quote_T) {
159461a57034Sschwarze 			h->flags |= HTML_NOSPACE;
159561a57034Sschwarze 			print_text(h, "\\(rq");
159661a57034Sschwarze 		}
159761a57034Sschwarze 		break;
159861a57034Sschwarze 	default:
159961a57034Sschwarze 		break;
160061a57034Sschwarze 	}
16017ebbefbeSschwarze 	if (n->parent == NULL || n->parent->tok != MDOC_Rs)
1602d967b250Sschwarze 		return;
1603d967b250Sschwarze 
1604a35fc07aSschwarze 	h->flags |= HTML_NOSPACE;
16057ebbefbeSschwarze 	print_text(h, roff_node_next(n) ? "," : ".");
16064175bdabSschwarze }
1607769ee804Sschwarze 
1608769ee804Sschwarze static int
1609769ee804Sschwarze mdoc_bk_pre(MDOC_ARGS)
1610769ee804Sschwarze {
1611769ee804Sschwarze 
1612769ee804Sschwarze 	switch (n->type) {
1613d1982c71Sschwarze 	case ROFFT_BLOCK:
1614769ee804Sschwarze 		break;
1615d1982c71Sschwarze 	case ROFFT_HEAD:
1616526e306bSschwarze 		return 0;
1617d1982c71Sschwarze 	case ROFFT_BODY:
161830e5ee06Sschwarze 		if (n->parent->args != NULL || n->prev->child == NULL)
1619769ee804Sschwarze 			h->flags |= HTML_PREKEEP;
1620769ee804Sschwarze 		break;
1621769ee804Sschwarze 	default:
1622769ee804Sschwarze 		abort();
1623769ee804Sschwarze 	}
1624769ee804Sschwarze 
1625526e306bSschwarze 	return 1;
1626769ee804Sschwarze }
1627769ee804Sschwarze 
1628769ee804Sschwarze static void
1629769ee804Sschwarze mdoc_bk_post(MDOC_ARGS)
1630769ee804Sschwarze {
1631769ee804Sschwarze 
1632d1982c71Sschwarze 	if (n->type == ROFFT_BODY)
1633769ee804Sschwarze 		h->flags &= ~(HTML_KEEP | HTML_PREKEEP);
1634769ee804Sschwarze }
16352c3450fcSschwarze 
16362c3450fcSschwarze static int
16372c3450fcSschwarze mdoc_quote_pre(MDOC_ARGS)
16382c3450fcSschwarze {
1639d1982c71Sschwarze 	if (n->type != ROFFT_BODY)
1640526e306bSschwarze 		return 1;
16412c3450fcSschwarze 
16422c3450fcSschwarze 	switch (n->tok) {
164349aff9f8Sschwarze 	case MDOC_Ao:
164449aff9f8Sschwarze 	case MDOC_Aq:
164530e5ee06Sschwarze 		print_text(h, n->child != NULL && n->child->next == NULL &&
1646ba61527cSschwarze 		    n->child->tok == MDOC_Mt ?  "<" : "\\(la");
16472c3450fcSschwarze 		break;
164849aff9f8Sschwarze 	case MDOC_Bro:
164949aff9f8Sschwarze 	case MDOC_Brq:
16502c3450fcSschwarze 		print_text(h, "\\(lC");
16512c3450fcSschwarze 		break;
165249aff9f8Sschwarze 	case MDOC_Bo:
165349aff9f8Sschwarze 	case MDOC_Bq:
16542c3450fcSschwarze 		print_text(h, "\\(lB");
16552c3450fcSschwarze 		break;
165649aff9f8Sschwarze 	case MDOC_Oo:
165749aff9f8Sschwarze 	case MDOC_Op:
16582c3450fcSschwarze 		print_text(h, "\\(lB");
16592dd33770Sschwarze 		/*
16602dd33770Sschwarze 		 * Give up on semantic markup for now.
16612dd33770Sschwarze 		 * We cannot use TAG_SPAN because .Oo may contain blocks.
1662c5914f85Sschwarze 		 * We cannot use TAG_DIV because we might be in a
16632dd33770Sschwarze 		 * phrasing context (like .Dl or .Pp); we cannot
16642dd33770Sschwarze 		 * close out a .Pp at this point either because
16652dd33770Sschwarze 		 * that would break the line.
16662dd33770Sschwarze 		 */
16672dd33770Sschwarze 		/* XXX print_otag(h, TAG_???, "c", "Op"); */
16682c3450fcSschwarze 		break;
1669551cd4a8Sschwarze 	case MDOC_En:
1670551cd4a8Sschwarze 		if (NULL == n->norm->Es ||
1671551cd4a8Sschwarze 		    NULL == n->norm->Es->child)
1672526e306bSschwarze 			return 1;
1673551cd4a8Sschwarze 		print_text(h, n->norm->Es->child->string);
1674551cd4a8Sschwarze 		break;
167549aff9f8Sschwarze 	case MDOC_Do:
167649aff9f8Sschwarze 	case MDOC_Dq:
1677ac01d98fSbentley 		print_text(h, "\\(lq");
1678ac01d98fSbentley 		break;
167949aff9f8Sschwarze 	case MDOC_Qo:
168049aff9f8Sschwarze 	case MDOC_Qq:
1681ac01d98fSbentley 		print_text(h, "\"");
16822c3450fcSschwarze 		break;
168349aff9f8Sschwarze 	case MDOC_Po:
168449aff9f8Sschwarze 	case MDOC_Pq:
16852c3450fcSschwarze 		print_text(h, "(");
16862c3450fcSschwarze 		break;
168749aff9f8Sschwarze 	case MDOC_Ql:
168804e980cbSschwarze 		print_text(h, "\\(oq");
168904e980cbSschwarze 		h->flags |= HTML_NOSPACE;
1690fea50678Sschwarze 		print_otag(h, TAG_CODE, "c", "Li");
169104e980cbSschwarze 		break;
169249aff9f8Sschwarze 	case MDOC_So:
169349aff9f8Sschwarze 	case MDOC_Sq:
16942c3450fcSschwarze 		print_text(h, "\\(oq");
16952c3450fcSschwarze 		break;
16962c3450fcSschwarze 	default:
16972c3450fcSschwarze 		abort();
16982c3450fcSschwarze 	}
16992c3450fcSschwarze 
17002c3450fcSschwarze 	h->flags |= HTML_NOSPACE;
1701526e306bSschwarze 	return 1;
17022c3450fcSschwarze }
17032c3450fcSschwarze 
17042c3450fcSschwarze static void
17052c3450fcSschwarze mdoc_quote_post(MDOC_ARGS)
17062c3450fcSschwarze {
17072c3450fcSschwarze 
1708d1982c71Sschwarze 	if (n->type != ROFFT_BODY && n->type != ROFFT_ELEM)
17092c3450fcSschwarze 		return;
17102c3450fcSschwarze 
17112c3450fcSschwarze 	h->flags |= HTML_NOSPACE;
17122c3450fcSschwarze 
17132c3450fcSschwarze 	switch (n->tok) {
171449aff9f8Sschwarze 	case MDOC_Ao:
171549aff9f8Sschwarze 	case MDOC_Aq:
171630e5ee06Sschwarze 		print_text(h, n->child != NULL && n->child->next == NULL &&
1717ba61527cSschwarze 		    n->child->tok == MDOC_Mt ?  ">" : "\\(ra");
17182c3450fcSschwarze 		break;
171949aff9f8Sschwarze 	case MDOC_Bro:
172049aff9f8Sschwarze 	case MDOC_Brq:
17212c3450fcSschwarze 		print_text(h, "\\(rC");
17222c3450fcSschwarze 		break;
172349aff9f8Sschwarze 	case MDOC_Oo:
172449aff9f8Sschwarze 	case MDOC_Op:
172549aff9f8Sschwarze 	case MDOC_Bo:
172649aff9f8Sschwarze 	case MDOC_Bq:
17272c3450fcSschwarze 		print_text(h, "\\(rB");
17282c3450fcSschwarze 		break;
1729551cd4a8Sschwarze 	case MDOC_En:
173003ed6ec9Sschwarze 		if (n->norm->Es == NULL ||
173103ed6ec9Sschwarze 		    n->norm->Es->child == NULL ||
173203ed6ec9Sschwarze 		    n->norm->Es->child->next == NULL)
173303ed6ec9Sschwarze 			h->flags &= ~HTML_NOSPACE;
173403ed6ec9Sschwarze 		else
1735551cd4a8Sschwarze 			print_text(h, n->norm->Es->child->next->string);
1736a1d10d08Sschwarze 		break;
173749aff9f8Sschwarze 	case MDOC_Do:
173849aff9f8Sschwarze 	case MDOC_Dq:
17392c3450fcSschwarze 		print_text(h, "\\(rq");
17402c3450fcSschwarze 		break;
1741ac01d98fSbentley 	case MDOC_Qo:
1742ac01d98fSbentley 	case MDOC_Qq:
1743ac01d98fSbentley 		print_text(h, "\"");
1744ac01d98fSbentley 		break;
174549aff9f8Sschwarze 	case MDOC_Po:
174649aff9f8Sschwarze 	case MDOC_Pq:
17472c3450fcSschwarze 		print_text(h, ")");
17482c3450fcSschwarze 		break;
174949aff9f8Sschwarze 	case MDOC_Ql:
175049aff9f8Sschwarze 	case MDOC_So:
175149aff9f8Sschwarze 	case MDOC_Sq:
1752f5ff5c49Smatthew 		print_text(h, "\\(cq");
17532c3450fcSschwarze 		break;
17542c3450fcSschwarze 	default:
17552c3450fcSschwarze 		abort();
17562c3450fcSschwarze 	}
17572c3450fcSschwarze }
175803ed6ec9Sschwarze 
175903ed6ec9Sschwarze static int
176003ed6ec9Sschwarze mdoc_eo_pre(MDOC_ARGS)
176103ed6ec9Sschwarze {
176203ed6ec9Sschwarze 
1763d1982c71Sschwarze 	if (n->type != ROFFT_BODY)
1764526e306bSschwarze 		return 1;
176503ed6ec9Sschwarze 
176603ed6ec9Sschwarze 	if (n->end == ENDBODY_NOT &&
176703ed6ec9Sschwarze 	    n->parent->head->child == NULL &&
176803ed6ec9Sschwarze 	    n->child != NULL &&
176903ed6ec9Sschwarze 	    n->child->end != ENDBODY_NOT)
177003ed6ec9Sschwarze 		print_text(h, "\\&");
177103ed6ec9Sschwarze 	else if (n->end != ENDBODY_NOT ? n->child != NULL :
1772c69b5c37Sschwarze 	    n->parent->head->child != NULL && (n->child != NULL ||
1773c69b5c37Sschwarze 	    (n->parent->tail != NULL && n->parent->tail->child != NULL)))
177403ed6ec9Sschwarze 		h->flags |= HTML_NOSPACE;
1775526e306bSschwarze 	return 1;
177603ed6ec9Sschwarze }
177703ed6ec9Sschwarze 
177803ed6ec9Sschwarze static void
177903ed6ec9Sschwarze mdoc_eo_post(MDOC_ARGS)
178003ed6ec9Sschwarze {
178103ed6ec9Sschwarze 	int	 body, tail;
178203ed6ec9Sschwarze 
1783d1982c71Sschwarze 	if (n->type != ROFFT_BODY)
178403ed6ec9Sschwarze 		return;
178503ed6ec9Sschwarze 
178603ed6ec9Sschwarze 	if (n->end != ENDBODY_NOT) {
178703ed6ec9Sschwarze 		h->flags &= ~HTML_NOSPACE;
178803ed6ec9Sschwarze 		return;
178903ed6ec9Sschwarze 	}
179003ed6ec9Sschwarze 
179103ed6ec9Sschwarze 	body = n->child != NULL || n->parent->head->child != NULL;
179203ed6ec9Sschwarze 	tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
179303ed6ec9Sschwarze 
179403ed6ec9Sschwarze 	if (body && tail)
179503ed6ec9Sschwarze 		h->flags |= HTML_NOSPACE;
179603ed6ec9Sschwarze 	else if ( ! tail)
179703ed6ec9Sschwarze 		h->flags &= ~HTML_NOSPACE;
179803ed6ec9Sschwarze }
17997c539ecbSschwarze 
18007c539ecbSschwarze static int
18017c539ecbSschwarze mdoc_abort_pre(MDOC_ARGS)
18027c539ecbSschwarze {
18037c539ecbSschwarze 	abort();
18047c539ecbSschwarze }
1805