xref: /netbsd/external/bsd/mdocml/dist/mdoc_html.c (revision 47a17e0d)
1*47a17e0dSchristos /*	Id: mdoc_html.c,v 1.240 2016/01/08 17:48:09 schwarze Exp  */
24154958bSjoerg /*
30511d63cSchristos  * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
4*47a17e0dSchristos  * Copyright (c) 2014, 2015, 2016 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  *
10*47a17e0dSchristos  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
114154958bSjoerg  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*47a17e0dSchristos  * 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"
30*47a17e0dSchristos #include "roff.h"
310511d63cSchristos #include "mdoc.h"
324154958bSjoerg #include "out.h"
334154958bSjoerg #include "html.h"
344154958bSjoerg #include "main.h"
354154958bSjoerg 
364154958bSjoerg #define	INDENT		 5
374154958bSjoerg 
38*47a17e0dSchristos #define	MDOC_ARGS	  const struct roff_meta *meta, \
39*47a17e0dSchristos 			  struct roff_node *n, \
404154958bSjoerg 			  struct html *h
414154958bSjoerg 
42d5e63c8dSjoerg #ifndef MIN
43d5e63c8dSjoerg #define	MIN(a,b)	((/*CONSTCOND*/(a)<(b))?(a):(b))
44d5e63c8dSjoerg #endif
45d5e63c8dSjoerg 
464154958bSjoerg struct	htmlmdoc {
474154958bSjoerg 	int		(*pre)(MDOC_ARGS);
484154958bSjoerg 	void		(*post)(MDOC_ARGS);
494154958bSjoerg };
504154958bSjoerg 
514154958bSjoerg static	void		  print_mdoc_head(MDOC_ARGS);
524154958bSjoerg static	void		  print_mdoc_node(MDOC_ARGS);
534154958bSjoerg static	void		  print_mdoc_nodelist(MDOC_ARGS);
547574e07eSjoerg static	void		  synopsis_pre(struct html *,
55*47a17e0dSchristos 				const struct roff_node *);
564154958bSjoerg 
574154958bSjoerg static	void		  a2width(const char *, struct roffsu *);
584154958bSjoerg 
594154958bSjoerg static	void		  mdoc_root_post(MDOC_ARGS);
604154958bSjoerg static	int		  mdoc_root_pre(MDOC_ARGS);
614154958bSjoerg 
624154958bSjoerg static	void		  mdoc__x_post(MDOC_ARGS);
634154958bSjoerg static	int		  mdoc__x_pre(MDOC_ARGS);
644154958bSjoerg static	int		  mdoc_ad_pre(MDOC_ARGS);
654154958bSjoerg static	int		  mdoc_an_pre(MDOC_ARGS);
664154958bSjoerg static	int		  mdoc_ap_pre(MDOC_ARGS);
674154958bSjoerg static	int		  mdoc_ar_pre(MDOC_ARGS);
684154958bSjoerg static	int		  mdoc_bd_pre(MDOC_ARGS);
694154958bSjoerg static	int		  mdoc_bf_pre(MDOC_ARGS);
7082361f10Sjoerg static	void		  mdoc_bk_post(MDOC_ARGS);
7182361f10Sjoerg static	int		  mdoc_bk_pre(MDOC_ARGS);
724154958bSjoerg static	int		  mdoc_bl_pre(MDOC_ARGS);
734154958bSjoerg static	int		  mdoc_bt_pre(MDOC_ARGS);
744154958bSjoerg static	int		  mdoc_bx_pre(MDOC_ARGS);
754154958bSjoerg static	int		  mdoc_cd_pre(MDOC_ARGS);
764154958bSjoerg static	int		  mdoc_d1_pre(MDOC_ARGS);
774154958bSjoerg static	int		  mdoc_dv_pre(MDOC_ARGS);
784154958bSjoerg static	int		  mdoc_fa_pre(MDOC_ARGS);
794154958bSjoerg static	int		  mdoc_fd_pre(MDOC_ARGS);
804154958bSjoerg static	int		  mdoc_fl_pre(MDOC_ARGS);
814154958bSjoerg static	int		  mdoc_fn_pre(MDOC_ARGS);
824154958bSjoerg static	int		  mdoc_ft_pre(MDOC_ARGS);
834154958bSjoerg static	int		  mdoc_em_pre(MDOC_ARGS);
840511d63cSchristos static	void		  mdoc_eo_post(MDOC_ARGS);
850511d63cSchristos static	int		  mdoc_eo_pre(MDOC_ARGS);
864154958bSjoerg static	int		  mdoc_er_pre(MDOC_ARGS);
874154958bSjoerg static	int		  mdoc_ev_pre(MDOC_ARGS);
884154958bSjoerg static	int		  mdoc_ex_pre(MDOC_ARGS);
894154958bSjoerg static	void		  mdoc_fo_post(MDOC_ARGS);
904154958bSjoerg static	int		  mdoc_fo_pre(MDOC_ARGS);
914154958bSjoerg static	int		  mdoc_ic_pre(MDOC_ARGS);
92e4fbeb7eSjoerg static	int		  mdoc_igndelim_pre(MDOC_ARGS);
934154958bSjoerg static	int		  mdoc_in_pre(MDOC_ARGS);
944154958bSjoerg static	int		  mdoc_it_pre(MDOC_ARGS);
954154958bSjoerg static	int		  mdoc_lb_pre(MDOC_ARGS);
964154958bSjoerg static	int		  mdoc_li_pre(MDOC_ARGS);
974154958bSjoerg static	int		  mdoc_lk_pre(MDOC_ARGS);
984154958bSjoerg static	int		  mdoc_mt_pre(MDOC_ARGS);
994154958bSjoerg static	int		  mdoc_ms_pre(MDOC_ARGS);
1004154958bSjoerg static	int		  mdoc_nd_pre(MDOC_ARGS);
1014154958bSjoerg static	int		  mdoc_nm_pre(MDOC_ARGS);
1020511d63cSchristos static	int		  mdoc_no_pre(MDOC_ARGS);
1034154958bSjoerg static	int		  mdoc_ns_pre(MDOC_ARGS);
1044154958bSjoerg static	int		  mdoc_pa_pre(MDOC_ARGS);
1054154958bSjoerg static	void		  mdoc_pf_post(MDOC_ARGS);
106e4fbeb7eSjoerg static	int		  mdoc_pp_pre(MDOC_ARGS);
107e4fbeb7eSjoerg static	void		  mdoc_quote_post(MDOC_ARGS);
108e4fbeb7eSjoerg static	int		  mdoc_quote_pre(MDOC_ARGS);
1094154958bSjoerg static	int		  mdoc_rs_pre(MDOC_ARGS);
1104154958bSjoerg static	int		  mdoc_rv_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_sp_pre(MDOC_ARGS);
1154154958bSjoerg static	int		  mdoc_ss_pre(MDOC_ARGS);
1164154958bSjoerg static	int		  mdoc_sx_pre(MDOC_ARGS);
1174154958bSjoerg static	int		  mdoc_sy_pre(MDOC_ARGS);
1184154958bSjoerg static	int		  mdoc_ud_pre(MDOC_ARGS);
1194154958bSjoerg static	int		  mdoc_va_pre(MDOC_ARGS);
1204154958bSjoerg static	int		  mdoc_vt_pre(MDOC_ARGS);
1214154958bSjoerg static	int		  mdoc_xr_pre(MDOC_ARGS);
1224154958bSjoerg static	int		  mdoc_xx_pre(MDOC_ARGS);
1234154958bSjoerg 
1244154958bSjoerg static	const struct htmlmdoc mdocs[MDOC_MAX] = {
1254154958bSjoerg 	{mdoc_ap_pre, NULL}, /* Ap */
1264154958bSjoerg 	{NULL, NULL}, /* Dd */
1274154958bSjoerg 	{NULL, NULL}, /* Dt */
1284154958bSjoerg 	{NULL, NULL}, /* Os */
1294154958bSjoerg 	{mdoc_sh_pre, NULL }, /* Sh */
1304154958bSjoerg 	{mdoc_ss_pre, NULL }, /* Ss */
131e4fbeb7eSjoerg 	{mdoc_pp_pre, NULL}, /* Pp */
1324154958bSjoerg 	{mdoc_d1_pre, NULL}, /* D1 */
1334154958bSjoerg 	{mdoc_d1_pre, NULL}, /* Dl */
1344154958bSjoerg 	{mdoc_bd_pre, NULL}, /* Bd */
1354154958bSjoerg 	{NULL, NULL}, /* Ed */
136e4fbeb7eSjoerg 	{mdoc_bl_pre, NULL}, /* Bl */
1374154958bSjoerg 	{NULL, NULL}, /* El */
1384154958bSjoerg 	{mdoc_it_pre, NULL}, /* It */
1394154958bSjoerg 	{mdoc_ad_pre, NULL}, /* Ad */
1404154958bSjoerg 	{mdoc_an_pre, NULL}, /* An */
1414154958bSjoerg 	{mdoc_ar_pre, NULL}, /* Ar */
1424154958bSjoerg 	{mdoc_cd_pre, NULL}, /* Cd */
1434154958bSjoerg 	{mdoc_fl_pre, NULL}, /* Cm */
1444154958bSjoerg 	{mdoc_dv_pre, NULL}, /* Dv */
1454154958bSjoerg 	{mdoc_er_pre, NULL}, /* Er */
1464154958bSjoerg 	{mdoc_ev_pre, NULL}, /* Ev */
1474154958bSjoerg 	{mdoc_ex_pre, NULL}, /* Ex */
1484154958bSjoerg 	{mdoc_fa_pre, NULL}, /* Fa */
1494154958bSjoerg 	{mdoc_fd_pre, NULL}, /* Fd */
1504154958bSjoerg 	{mdoc_fl_pre, NULL}, /* Fl */
1514154958bSjoerg 	{mdoc_fn_pre, NULL}, /* Fn */
1524154958bSjoerg 	{mdoc_ft_pre, NULL}, /* Ft */
1534154958bSjoerg 	{mdoc_ic_pre, NULL}, /* Ic */
1544154958bSjoerg 	{mdoc_in_pre, NULL}, /* In */
1554154958bSjoerg 	{mdoc_li_pre, NULL}, /* Li */
1564154958bSjoerg 	{mdoc_nd_pre, NULL}, /* Nd */
1574154958bSjoerg 	{mdoc_nm_pre, NULL}, /* Nm */
158e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Op */
1590511d63cSchristos 	{mdoc_ft_pre, NULL}, /* Ot */
1604154958bSjoerg 	{mdoc_pa_pre, NULL}, /* Pa */
1614154958bSjoerg 	{mdoc_rv_pre, NULL}, /* Rv */
1624154958bSjoerg 	{NULL, NULL}, /* St */
1634154958bSjoerg 	{mdoc_va_pre, NULL}, /* Va */
1644154958bSjoerg 	{mdoc_vt_pre, NULL}, /* Vt */
1654154958bSjoerg 	{mdoc_xr_pre, NULL}, /* Xr */
1664154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %A */
1674154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %B */
1684154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %D */
1694154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %I */
1704154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %J */
1714154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %N */
1724154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %O */
1734154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %P */
1744154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %R */
1754154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %T */
1764154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %V */
1774154958bSjoerg 	{NULL, NULL}, /* Ac */
178e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Ao */
179e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Aq */
1804154958bSjoerg 	{NULL, NULL}, /* At */
1814154958bSjoerg 	{NULL, NULL}, /* Bc */
1824154958bSjoerg 	{mdoc_bf_pre, NULL}, /* Bf */
183e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Bo */
184e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Bq */
1854154958bSjoerg 	{mdoc_xx_pre, NULL}, /* Bsx */
1864154958bSjoerg 	{mdoc_bx_pre, NULL}, /* Bx */
1870511d63cSchristos 	{mdoc_skip_pre, NULL}, /* Db */
1884154958bSjoerg 	{NULL, NULL}, /* Dc */
189e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Do */
190e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Dq */
19131e1f4e3Sjoerg 	{NULL, NULL}, /* Ec */ /* FIXME: no space */
1924154958bSjoerg 	{NULL, NULL}, /* Ef */
1934154958bSjoerg 	{mdoc_em_pre, NULL}, /* Em */
1940511d63cSchristos 	{mdoc_eo_pre, mdoc_eo_post}, /* Eo */
1954154958bSjoerg 	{mdoc_xx_pre, NULL}, /* Fx */
1967da9b934Sjoerg 	{mdoc_ms_pre, NULL}, /* Ms */
1970511d63cSchristos 	{mdoc_no_pre, NULL}, /* No */
1984154958bSjoerg 	{mdoc_ns_pre, NULL}, /* Ns */
1994154958bSjoerg 	{mdoc_xx_pre, NULL}, /* Nx */
2004154958bSjoerg 	{mdoc_xx_pre, NULL}, /* Ox */
2014154958bSjoerg 	{NULL, NULL}, /* Pc */
202e4fbeb7eSjoerg 	{mdoc_igndelim_pre, mdoc_pf_post}, /* Pf */
203e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Po */
204e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Pq */
2054154958bSjoerg 	{NULL, NULL}, /* Qc */
206e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Ql */
207e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Qo */
208e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Qq */
2094154958bSjoerg 	{NULL, NULL}, /* Re */
2104154958bSjoerg 	{mdoc_rs_pre, NULL}, /* Rs */
2114154958bSjoerg 	{NULL, NULL}, /* Sc */
212e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* So */
213e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Sq */
2147da9b934Sjoerg 	{mdoc_sm_pre, NULL}, /* Sm */
2154154958bSjoerg 	{mdoc_sx_pre, NULL}, /* Sx */
2164154958bSjoerg 	{mdoc_sy_pre, NULL}, /* Sy */
2174154958bSjoerg 	{NULL, NULL}, /* Tn */
2184154958bSjoerg 	{mdoc_xx_pre, NULL}, /* Ux */
2194154958bSjoerg 	{NULL, NULL}, /* Xc */
2204154958bSjoerg 	{NULL, NULL}, /* Xo */
2214154958bSjoerg 	{mdoc_fo_pre, mdoc_fo_post}, /* Fo */
2224154958bSjoerg 	{NULL, NULL}, /* Fc */
223e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Oo */
2244154958bSjoerg 	{NULL, NULL}, /* Oc */
22582361f10Sjoerg 	{mdoc_bk_pre, mdoc_bk_post}, /* Bk */
2264154958bSjoerg 	{NULL, NULL}, /* Ek */
2274154958bSjoerg 	{mdoc_bt_pre, NULL}, /* Bt */
2284154958bSjoerg 	{NULL, NULL}, /* Hf */
2290511d63cSchristos 	{mdoc_em_pre, NULL}, /* Fr */
2304154958bSjoerg 	{mdoc_ud_pre, NULL}, /* Ud */
2314154958bSjoerg 	{mdoc_lb_pre, NULL}, /* Lb */
232e4fbeb7eSjoerg 	{mdoc_pp_pre, NULL}, /* Lp */
2334154958bSjoerg 	{mdoc_lk_pre, NULL}, /* Lk */
2344154958bSjoerg 	{mdoc_mt_pre, NULL}, /* Mt */
235e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Brq */
236e4fbeb7eSjoerg 	{mdoc_quote_pre, mdoc_quote_post}, /* Bro */
2374154958bSjoerg 	{NULL, NULL}, /* Brc */
2384154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %C */
2390511d63cSchristos 	{mdoc_skip_pre, NULL}, /* Es */
2400511d63cSchristos 	{mdoc_quote_pre, mdoc_quote_post}, /* En */
2414154958bSjoerg 	{mdoc_xx_pre, NULL}, /* Dx */
2424154958bSjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %Q */
2434154958bSjoerg 	{mdoc_sp_pre, NULL}, /* br */
2444154958bSjoerg 	{mdoc_sp_pre, NULL}, /* sp */
24522af4063Sjoerg 	{mdoc__x_pre, mdoc__x_post}, /* %U */
2467574e07eSjoerg 	{NULL, NULL}, /* Ta */
2470511d63cSchristos 	{mdoc_skip_pre, NULL}, /* ll */
2484154958bSjoerg };
2494154958bSjoerg 
250e4fbeb7eSjoerg static	const char * const lists[LIST_MAX] = {
251e4fbeb7eSjoerg 	NULL,
252e4fbeb7eSjoerg 	"list-bul",
253e4fbeb7eSjoerg 	"list-col",
254e4fbeb7eSjoerg 	"list-dash",
255e4fbeb7eSjoerg 	"list-diag",
256e4fbeb7eSjoerg 	"list-enum",
257e4fbeb7eSjoerg 	"list-hang",
258e4fbeb7eSjoerg 	"list-hyph",
259e4fbeb7eSjoerg 	"list-inset",
260e4fbeb7eSjoerg 	"list-item",
261e4fbeb7eSjoerg 	"list-ohang",
262e4fbeb7eSjoerg 	"list-tag"
263e4fbeb7eSjoerg };
2644154958bSjoerg 
2650511d63cSchristos 
2664154958bSjoerg /*
2674154958bSjoerg  * Calculate the scaling unit passed in a `-width' argument.  This uses
2684154958bSjoerg  * either a native scaling unit (e.g., 1i, 2m) or the string length of
2694154958bSjoerg  * the value.
2704154958bSjoerg  */
2714154958bSjoerg static void
2724154958bSjoerg a2width(const char *p, struct roffsu *su)
2734154958bSjoerg {
2744154958bSjoerg 
2750511d63cSchristos 	if (a2roffsu(p, su, SCALE_MAX) < 2) {
2760511d63cSchristos 		su->unit = SCALE_EN;
277f8126693Sjoerg 		su->scale = html_strlen(p);
2780511d63cSchristos 	} else if (su->scale < 0.0)
2790511d63cSchristos 		su->scale = 0.0;
2804154958bSjoerg }
2814154958bSjoerg 
2824154958bSjoerg /*
2837574e07eSjoerg  * See the same function in mdoc_term.c for documentation.
2847574e07eSjoerg  */
2857574e07eSjoerg static void
286*47a17e0dSchristos synopsis_pre(struct html *h, const struct roff_node *n)
2877574e07eSjoerg {
2887574e07eSjoerg 
28982361f10Sjoerg 	if (NULL == n->prev || ! (MDOC_SYNPRETTY & n->flags))
2907574e07eSjoerg 		return;
2917574e07eSjoerg 
2927574e07eSjoerg 	if (n->prev->tok == n->tok &&
2937574e07eSjoerg 	    MDOC_Fo != n->tok &&
2947574e07eSjoerg 	    MDOC_Ft != n->tok &&
2957574e07eSjoerg 	    MDOC_Fn != n->tok) {
296e4fbeb7eSjoerg 		print_otag(h, TAG_BR, 0, NULL);
2977574e07eSjoerg 		return;
2987574e07eSjoerg 	}
2997574e07eSjoerg 
3007574e07eSjoerg 	switch (n->prev->tok) {
3010511d63cSchristos 	case MDOC_Fd:
3020511d63cSchristos 	case MDOC_Fn:
3030511d63cSchristos 	case MDOC_Fo:
3040511d63cSchristos 	case MDOC_In:
3050511d63cSchristos 	case MDOC_Vt:
3060511d63cSchristos 		print_paragraph(h);
3077574e07eSjoerg 		break;
3080511d63cSchristos 	case MDOC_Ft:
3097574e07eSjoerg 		if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
3100511d63cSchristos 			print_paragraph(h);
3117574e07eSjoerg 			break;
3127574e07eSjoerg 		}
3137574e07eSjoerg 		/* FALLTHROUGH */
3147574e07eSjoerg 	default:
315e4fbeb7eSjoerg 		print_otag(h, TAG_BR, 0, NULL);
3167574e07eSjoerg 		break;
3177574e07eSjoerg 	}
3187574e07eSjoerg }
3197574e07eSjoerg 
320*47a17e0dSchristos void
321*47a17e0dSchristos html_mdoc(void *arg, const struct roff_man *mdoc)
3224154958bSjoerg {
323f8126693Sjoerg 	struct htmlpair	 tag;
324*47a17e0dSchristos 	struct html	*h;
325*47a17e0dSchristos 	struct tag	*t, *tt;
3264154958bSjoerg 
327f8126693Sjoerg 	PAIR_CLASS_INIT(&tag, "mandoc");
328*47a17e0dSchristos 	h = (struct html *)arg;
329f8126693Sjoerg 
330f8126693Sjoerg 	if ( ! (HTML_FRAGMENT & h->oflags)) {
331f8126693Sjoerg 		print_gen_decls(h);
332f8126693Sjoerg 		t = print_otag(h, TAG_HTML, 0, NULL);
333f8126693Sjoerg 		tt = print_otag(h, TAG_HEAD, 0, NULL);
334*47a17e0dSchristos 		print_mdoc_head(&mdoc->meta, mdoc->first->child, h);
335f8126693Sjoerg 		print_tagq(h, tt);
336f8126693Sjoerg 		print_otag(h, TAG_BODY, 0, NULL);
337f8126693Sjoerg 		print_otag(h, TAG_DIV, 1, &tag);
338f8126693Sjoerg 	} else
339f8126693Sjoerg 		t = print_otag(h, TAG_DIV, 1, &tag);
3404154958bSjoerg 
341*47a17e0dSchristos 	mdoc_root_pre(&mdoc->meta, mdoc->first->child, h);
342*47a17e0dSchristos 	print_mdoc_nodelist(&mdoc->meta, mdoc->first->child, h);
343*47a17e0dSchristos 	mdoc_root_post(&mdoc->meta, mdoc->first->child, h);
3444154958bSjoerg 	print_tagq(h, t);
345*47a17e0dSchristos 	putchar('\n');
3464154958bSjoerg }
3474154958bSjoerg 
3484154958bSjoerg static void
3494154958bSjoerg print_mdoc_head(MDOC_ARGS)
3504154958bSjoerg {
3514154958bSjoerg 
3524154958bSjoerg 	print_gen_head(h);
3534154958bSjoerg 	bufinit(h);
3540511d63cSchristos 	bufcat(h, meta->title);
3550511d63cSchristos 	if (meta->msec)
3560511d63cSchristos 		bufcat_fmt(h, "(%s)", meta->msec);
357ed7c7912Sjoerg 	if (meta->arch)
358ed7c7912Sjoerg 		bufcat_fmt(h, " (%s)", meta->arch);
3594154958bSjoerg 
3604154958bSjoerg 	print_otag(h, TAG_TITLE, 0, NULL);
3614154958bSjoerg 	print_text(h, h->buf);
3624154958bSjoerg }
3634154958bSjoerg 
3644154958bSjoerg static void
3654154958bSjoerg print_mdoc_nodelist(MDOC_ARGS)
3664154958bSjoerg {
3674154958bSjoerg 
3680511d63cSchristos 	while (n != NULL) {
369ed7c7912Sjoerg 		print_mdoc_node(meta, n, h);
3700511d63cSchristos 		n = n->next;
3714154958bSjoerg 	}
3720511d63cSchristos }
3734154958bSjoerg 
3744154958bSjoerg static void
3754154958bSjoerg print_mdoc_node(MDOC_ARGS)
3764154958bSjoerg {
3774154958bSjoerg 	int		 child;
3784154958bSjoerg 	struct tag	*t;
3794154958bSjoerg 
3804154958bSjoerg 	child = 1;
38122af4063Sjoerg 	t = h->tags.head;
3820511d63cSchristos 	n->flags &= ~MDOC_ENDED;
3834154958bSjoerg 
3844154958bSjoerg 	switch (n->type) {
385*47a17e0dSchristos 	case ROFFT_TEXT:
38654a4f7feSjoerg 		/* No tables in this mode... */
38754a4f7feSjoerg 		assert(NULL == h->tblt);
38854a4f7feSjoerg 
38954a4f7feSjoerg 		/*
39054a4f7feSjoerg 		 * Make sure that if we're in a literal mode already
39154a4f7feSjoerg 		 * (i.e., within a <PRE>) don't print the newline.
39254a4f7feSjoerg 		 */
39354a4f7feSjoerg 		if (' ' == *n->string && MDOC_LINE & n->flags)
39454a4f7feSjoerg 			if ( ! (HTML_LITERAL & h->flags))
39554a4f7feSjoerg 				print_otag(h, TAG_BR, 0, NULL);
39654a4f7feSjoerg 		if (MDOC_DELIMC & n->flags)
39754a4f7feSjoerg 			h->flags |= HTML_NOSPACE;
3984154958bSjoerg 		print_text(h, n->string);
39954a4f7feSjoerg 		if (MDOC_DELIMO & n->flags)
40054a4f7feSjoerg 			h->flags |= HTML_NOSPACE;
4017d71a621Sjoerg 		return;
402*47a17e0dSchristos 	case ROFFT_EQN:
4030511d63cSchristos 		if (n->flags & MDOC_LINE)
4040511d63cSchristos 			putchar('\n');
405f8126693Sjoerg 		print_eqn(h, n->eqn);
406e4fbeb7eSjoerg 		break;
407*47a17e0dSchristos 	case ROFFT_TBL:
40854a4f7feSjoerg 		/*
40954a4f7feSjoerg 		 * This will take care of initialising all of the table
41054a4f7feSjoerg 		 * state data for the first table, then tearing it down
41154a4f7feSjoerg 		 * for the last one.
41254a4f7feSjoerg 		 */
41354a4f7feSjoerg 		print_tbl(h, n->span);
41454a4f7feSjoerg 		return;
4154154958bSjoerg 	default:
41654a4f7feSjoerg 		/*
41754a4f7feSjoerg 		 * Close out the current table, if it's open, and unset
41854a4f7feSjoerg 		 * the "meta" table state.  This will be reopened on the
41954a4f7feSjoerg 		 * next table element.
42054a4f7feSjoerg 		 */
4210511d63cSchristos 		if (h->tblt != NULL) {
42254a4f7feSjoerg 			print_tblclose(h);
42354a4f7feSjoerg 			t = h->tags.head;
42454a4f7feSjoerg 		}
4250511d63cSchristos 		assert(h->tblt == NULL);
4260511d63cSchristos 		if (mdocs[n->tok].pre && (n->end == ENDBODY_NOT || n->child))
427ed7c7912Sjoerg 			child = (*mdocs[n->tok].pre)(meta, n, h);
4284154958bSjoerg 		break;
4294154958bSjoerg 	}
4304154958bSjoerg 
4310511d63cSchristos 	if (h->flags & HTML_KEEP && n->flags & MDOC_LINE) {
43282361f10Sjoerg 		h->flags &= ~HTML_KEEP;
43382361f10Sjoerg 		h->flags |= HTML_PREKEEP;
43482361f10Sjoerg 	}
43582361f10Sjoerg 
4364154958bSjoerg 	if (child && n->child)
437ed7c7912Sjoerg 		print_mdoc_nodelist(meta, n->child, h);
4384154958bSjoerg 
4394154958bSjoerg 	print_stagq(h, t);
4404154958bSjoerg 
4414154958bSjoerg 	switch (n->type) {
442*47a17e0dSchristos 	case ROFFT_EQN:
443e4fbeb7eSjoerg 		break;
4444154958bSjoerg 	default:
4450511d63cSchristos 		if ( ! mdocs[n->tok].post || n->flags & MDOC_ENDED)
4460511d63cSchristos 			break;
447ed7c7912Sjoerg 		(*mdocs[n->tok].post)(meta, n, h);
4480511d63cSchristos 		if (n->end != ENDBODY_NOT)
4490511d63cSchristos 			n->body->flags |= MDOC_ENDED;
4500511d63cSchristos 		if (n->end == ENDBODY_NOSPACE)
4510511d63cSchristos 			h->flags |= HTML_NOSPACE;
4524154958bSjoerg 		break;
4534154958bSjoerg 	}
4544154958bSjoerg }
4554154958bSjoerg 
4564154958bSjoerg static void
4574154958bSjoerg mdoc_root_post(MDOC_ARGS)
4584154958bSjoerg {
4590511d63cSchristos 	struct htmlpair	 tag;
4604154958bSjoerg 	struct tag	*t, *tt;
4614154958bSjoerg 
4620511d63cSchristos 	PAIR_CLASS_INIT(&tag, "foot");
4630511d63cSchristos 	t = print_otag(h, TAG_TABLE, 1, &tag);
464e4fbeb7eSjoerg 
465e7fe1698Sjoerg 	print_otag(h, TAG_TBODY, 0, NULL);
466e4fbeb7eSjoerg 
4674154958bSjoerg 	tt = print_otag(h, TAG_TR, 0, NULL);
4684154958bSjoerg 
4690511d63cSchristos 	PAIR_CLASS_INIT(&tag, "foot-date");
4700511d63cSchristos 	print_otag(h, TAG_TD, 1, &tag);
471ed7c7912Sjoerg 	print_text(h, meta->date);
4724154958bSjoerg 	print_stagq(h, tt);
4734154958bSjoerg 
4740511d63cSchristos 	PAIR_CLASS_INIT(&tag, "foot-os");
4750511d63cSchristos 	print_otag(h, TAG_TD, 1, &tag);
476ed7c7912Sjoerg 	print_text(h, meta->os);
4774154958bSjoerg 	print_tagq(h, t);
4784154958bSjoerg }
4794154958bSjoerg 
4804154958bSjoerg static int
4814154958bSjoerg mdoc_root_pre(MDOC_ARGS)
4824154958bSjoerg {
4830511d63cSchristos 	struct htmlpair	 tag;
4844154958bSjoerg 	struct tag	*t, *tt;
4850511d63cSchristos 	char		*volume, *title;
4864154958bSjoerg 
4870511d63cSchristos 	if (NULL == meta->arch)
4880511d63cSchristos 		volume = mandoc_strdup(meta->vol);
4890511d63cSchristos 	else
4900511d63cSchristos 		mandoc_asprintf(&volume, "%s (%s)",
4910511d63cSchristos 		    meta->vol, meta->arch);
4924154958bSjoerg 
4930511d63cSchristos 	if (NULL == meta->msec)
4940511d63cSchristos 		title = mandoc_strdup(meta->title);
4950511d63cSchristos 	else
4960511d63cSchristos 		mandoc_asprintf(&title, "%s(%s)",
4970511d63cSchristos 		    meta->title, meta->msec);
4984154958bSjoerg 
4990511d63cSchristos 	PAIR_CLASS_INIT(&tag, "head");
5000511d63cSchristos 	t = print_otag(h, TAG_TABLE, 1, &tag);
501e4fbeb7eSjoerg 
502e4fbeb7eSjoerg 	print_otag(h, TAG_TBODY, 0, NULL);
5033514411fSjoerg 
5044154958bSjoerg 	tt = print_otag(h, TAG_TR, 0, NULL);
5054154958bSjoerg 
5060511d63cSchristos 	PAIR_CLASS_INIT(&tag, "head-ltitle");
5070511d63cSchristos 	print_otag(h, TAG_TD, 1, &tag);
5084154958bSjoerg 	print_text(h, title);
5094154958bSjoerg 	print_stagq(h, tt);
5104154958bSjoerg 
5110511d63cSchristos 	PAIR_CLASS_INIT(&tag, "head-vol");
5120511d63cSchristos 	print_otag(h, TAG_TD, 1, &tag);
5130511d63cSchristos 	print_text(h, volume);
5144154958bSjoerg 	print_stagq(h, tt);
5154154958bSjoerg 
5160511d63cSchristos 	PAIR_CLASS_INIT(&tag, "head-rtitle");
5170511d63cSchristos 	print_otag(h, TAG_TD, 1, &tag);
5184154958bSjoerg 	print_text(h, title);
5194154958bSjoerg 	print_tagq(h, t);
5200511d63cSchristos 
5210511d63cSchristos 	free(title);
5220511d63cSchristos 	free(volume);
523*47a17e0dSchristos 	return 1;
5244154958bSjoerg }
5254154958bSjoerg 
5264154958bSjoerg static int
5274154958bSjoerg mdoc_sh_pre(MDOC_ARGS)
5284154958bSjoerg {
529e4fbeb7eSjoerg 	struct htmlpair	 tag;
5304154958bSjoerg 
5310511d63cSchristos 	switch (n->type) {
532*47a17e0dSchristos 	case ROFFT_BLOCK:
533e4fbeb7eSjoerg 		PAIR_CLASS_INIT(&tag, "section");
534e4fbeb7eSjoerg 		print_otag(h, TAG_DIV, 1, &tag);
535*47a17e0dSchristos 		return 1;
536*47a17e0dSchristos 	case ROFFT_BODY:
5370511d63cSchristos 		if (n->sec == SEC_AUTHORS)
5380511d63cSchristos 			h->flags &= ~(HTML_SPLIT|HTML_NOSPLIT);
539*47a17e0dSchristos 		return 1;
5400511d63cSchristos 	default:
5410511d63cSchristos 		break;
5420511d63cSchristos 	}
5434154958bSjoerg 
544f8126693Sjoerg 	bufinit(h);
545f8126693Sjoerg 
546*47a17e0dSchristos 	for (n = n->child; n != NULL && n->type == ROFFT_TEXT; ) {
547f8126693Sjoerg 		bufcat_id(h, n->string);
548f8126693Sjoerg 		if (NULL != (n = n->next))
549f8126693Sjoerg 			bufcat_id(h, " ");
5504154958bSjoerg 	}
5514154958bSjoerg 
552f8126693Sjoerg 	if (NULL == n) {
553f8126693Sjoerg 		PAIR_ID_INIT(&tag, h->buf);
554e4fbeb7eSjoerg 		print_otag(h, TAG_H1, 1, &tag);
555f8126693Sjoerg 	} else
556f8126693Sjoerg 		print_otag(h, TAG_H1, 0, NULL);
557f8126693Sjoerg 
558*47a17e0dSchristos 	return 1;
5594154958bSjoerg }
5604154958bSjoerg 
5614154958bSjoerg static int
5624154958bSjoerg mdoc_ss_pre(MDOC_ARGS)
5634154958bSjoerg {
564e4fbeb7eSjoerg 	struct htmlpair	 tag;
5654154958bSjoerg 
566*47a17e0dSchristos 	if (n->type == ROFFT_BLOCK) {
567e4fbeb7eSjoerg 		PAIR_CLASS_INIT(&tag, "subsection");
568e4fbeb7eSjoerg 		print_otag(h, TAG_DIV, 1, &tag);
569*47a17e0dSchristos 		return 1;
570*47a17e0dSchristos 	} else if (n->type == ROFFT_BODY)
571*47a17e0dSchristos 		return 1;
5724154958bSjoerg 
573f8126693Sjoerg 	bufinit(h);
574f8126693Sjoerg 
575*47a17e0dSchristos 	for (n = n->child; n != NULL && n->type == ROFFT_TEXT; ) {
576f8126693Sjoerg 		bufcat_id(h, n->string);
577f8126693Sjoerg 		if (NULL != (n = n->next))
578f8126693Sjoerg 			bufcat_id(h, " ");
5794154958bSjoerg 	}
5804154958bSjoerg 
581f8126693Sjoerg 	if (NULL == n) {
582f8126693Sjoerg 		PAIR_ID_INIT(&tag, h->buf);
583e4fbeb7eSjoerg 		print_otag(h, TAG_H2, 1, &tag);
584f8126693Sjoerg 	} else
585f8126693Sjoerg 		print_otag(h, TAG_H2, 0, NULL);
586f8126693Sjoerg 
587*47a17e0dSchristos 	return 1;
5884154958bSjoerg }
5894154958bSjoerg 
5904154958bSjoerg static int
5914154958bSjoerg mdoc_fl_pre(MDOC_ARGS)
5924154958bSjoerg {
5934154958bSjoerg 	struct htmlpair	 tag;
5944154958bSjoerg 
5954154958bSjoerg 	PAIR_CLASS_INIT(&tag, "flag");
596e4fbeb7eSjoerg 	print_otag(h, TAG_B, 1, &tag);
597d5e63c8dSjoerg 
598d5e63c8dSjoerg 	/* `Cm' has no leading hyphen. */
599d5e63c8dSjoerg 
600d5e63c8dSjoerg 	if (MDOC_Cm == n->tok)
601*47a17e0dSchristos 		return 1;
602d5e63c8dSjoerg 
6034154958bSjoerg 	print_text(h, "\\-");
604d5e63c8dSjoerg 
605*47a17e0dSchristos 	if (!(n->child == NULL &&
6060511d63cSchristos 	    (n->next == NULL ||
607*47a17e0dSchristos 	     n->next->type == ROFFT_TEXT ||
6080511d63cSchristos 	     n->next->flags & MDOC_LINE)))
6097bcc2a5fSjoerg 		h->flags |= HTML_NOSPACE;
610d5e63c8dSjoerg 
611*47a17e0dSchristos 	return 1;
6124154958bSjoerg }
6134154958bSjoerg 
6144154958bSjoerg static int
6154154958bSjoerg mdoc_nd_pre(MDOC_ARGS)
6164154958bSjoerg {
6174154958bSjoerg 	struct htmlpair	 tag;
6184154958bSjoerg 
619*47a17e0dSchristos 	if (n->type != ROFFT_BODY)
620*47a17e0dSchristos 		return 1;
6214154958bSjoerg 
6224154958bSjoerg 	/* XXX: this tag in theory can contain block elements. */
6234154958bSjoerg 
6244154958bSjoerg 	print_text(h, "\\(em");
625e4fbeb7eSjoerg 	PAIR_CLASS_INIT(&tag, "desc");
6264154958bSjoerg 	print_otag(h, TAG_SPAN, 1, &tag);
627*47a17e0dSchristos 	return 1;
6284154958bSjoerg }
6294154958bSjoerg 
6304154958bSjoerg static int
6314154958bSjoerg mdoc_nm_pre(MDOC_ARGS)
6324154958bSjoerg {
6334154958bSjoerg 	struct htmlpair	 tag;
63482361f10Sjoerg 	struct roffsu	 su;
635f8126693Sjoerg 	int		 len;
6364154958bSjoerg 
637e4fbeb7eSjoerg 	switch (n->type) {
638*47a17e0dSchristos 	case ROFFT_HEAD:
639*47a17e0dSchristos 		print_otag(h, TAG_TD, 0, NULL);
640*47a17e0dSchristos 		/* FALLTHROUGH */
641*47a17e0dSchristos 	case ROFFT_ELEM:
6424154958bSjoerg 		PAIR_CLASS_INIT(&tag, "name");
643e4fbeb7eSjoerg 		print_otag(h, TAG_B, 1, &tag);
644*47a17e0dSchristos 		if (n->child == NULL && meta->name != NULL)
645ed7c7912Sjoerg 			print_text(h, meta->name);
646*47a17e0dSchristos 		return 1;
647*47a17e0dSchristos 	case ROFFT_BODY:
648e4fbeb7eSjoerg 		print_otag(h, TAG_TD, 0, NULL);
649*47a17e0dSchristos 		return 1;
650e4fbeb7eSjoerg 	default:
651e4fbeb7eSjoerg 		break;
65282361f10Sjoerg 	}
65382361f10Sjoerg 
654e4fbeb7eSjoerg 	synopsis_pre(h, n);
655e4fbeb7eSjoerg 	PAIR_CLASS_INIT(&tag, "synopsis");
656e4fbeb7eSjoerg 	print_otag(h, TAG_TABLE, 1, &tag);
657e4fbeb7eSjoerg 
658*47a17e0dSchristos 	for (len = 0, n = n->head->child; n; n = n->next)
659*47a17e0dSchristos 		if (n->type == ROFFT_TEXT)
660f8126693Sjoerg 			len += html_strlen(n->string);
661e4fbeb7eSjoerg 
662*47a17e0dSchristos 	if (len == 0 && meta->name != NULL)
663ed7c7912Sjoerg 		len = html_strlen(meta->name);
664e4fbeb7eSjoerg 
6650511d63cSchristos 	SCALE_HS_INIT(&su, len);
666f8126693Sjoerg 	bufinit(h);
667e4fbeb7eSjoerg 	bufcat_su(h, "width", &su);
668e4fbeb7eSjoerg 	PAIR_STYLE_INIT(&tag, h);
669e4fbeb7eSjoerg 	print_otag(h, TAG_COL, 1, &tag);
670e4fbeb7eSjoerg 	print_otag(h, TAG_COL, 0, NULL);
671e4fbeb7eSjoerg 	print_otag(h, TAG_TBODY, 0, NULL);
672e4fbeb7eSjoerg 	print_otag(h, TAG_TR, 0, NULL);
673*47a17e0dSchristos 	return 1;
6744154958bSjoerg }
6754154958bSjoerg 
6764154958bSjoerg static int
6774154958bSjoerg mdoc_xr_pre(MDOC_ARGS)
6784154958bSjoerg {
6794154958bSjoerg 	struct htmlpair	 tag[2];
6804154958bSjoerg 
6817bcc2a5fSjoerg 	if (NULL == n->child)
682*47a17e0dSchristos 		return 0;
6837bcc2a5fSjoerg 
6844154958bSjoerg 	PAIR_CLASS_INIT(&tag[0], "link-man");
6854154958bSjoerg 
6864154958bSjoerg 	if (h->base_man) {
6874154958bSjoerg 		buffmt_man(h, n->child->string,
6884154958bSjoerg 		    n->child->next ?
6894154958bSjoerg 		    n->child->next->string : NULL);
6907bcc2a5fSjoerg 		PAIR_HREF_INIT(&tag[1], h->buf);
6914154958bSjoerg 		print_otag(h, TAG_A, 2, tag);
6924154958bSjoerg 	} else
6934154958bSjoerg 		print_otag(h, TAG_A, 1, tag);
6944154958bSjoerg 
69554a4f7feSjoerg 	n = n->child;
69654a4f7feSjoerg 	print_text(h, n->string);
6974154958bSjoerg 
69854a4f7feSjoerg 	if (NULL == (n = n->next))
699*47a17e0dSchristos 		return 0;
7004154958bSjoerg 
7014154958bSjoerg 	h->flags |= HTML_NOSPACE;
7024154958bSjoerg 	print_text(h, "(");
7034154958bSjoerg 	h->flags |= HTML_NOSPACE;
70454a4f7feSjoerg 	print_text(h, n->string);
7054154958bSjoerg 	h->flags |= HTML_NOSPACE;
7064154958bSjoerg 	print_text(h, ")");
707*47a17e0dSchristos 	return 0;
7084154958bSjoerg }
7094154958bSjoerg 
7104154958bSjoerg static int
7114154958bSjoerg mdoc_ns_pre(MDOC_ARGS)
7124154958bSjoerg {
7134154958bSjoerg 
71454a4f7feSjoerg 	if ( ! (MDOC_LINE & n->flags))
7154154958bSjoerg 		h->flags |= HTML_NOSPACE;
716*47a17e0dSchristos 	return 1;
7174154958bSjoerg }
7184154958bSjoerg 
7194154958bSjoerg static int
7204154958bSjoerg mdoc_ar_pre(MDOC_ARGS)
7214154958bSjoerg {
7224154958bSjoerg 	struct htmlpair tag;
7234154958bSjoerg 
7244154958bSjoerg 	PAIR_CLASS_INIT(&tag, "arg");
725e4fbeb7eSjoerg 	print_otag(h, TAG_I, 1, &tag);
726*47a17e0dSchristos 	return 1;
7274154958bSjoerg }
7284154958bSjoerg 
7294154958bSjoerg static int
7304154958bSjoerg mdoc_xx_pre(MDOC_ARGS)
7314154958bSjoerg {
7324154958bSjoerg 	const char	*pp;
7334154958bSjoerg 	struct htmlpair	 tag;
73454a4f7feSjoerg 	int		 flags;
7354154958bSjoerg 
7364154958bSjoerg 	switch (n->tok) {
7370511d63cSchristos 	case MDOC_Bsx:
738e4fbeb7eSjoerg 		pp = "BSD/OS";
7394154958bSjoerg 		break;
7400511d63cSchristos 	case MDOC_Dx:
7413514411fSjoerg 		pp = "DragonFly";
7424154958bSjoerg 		break;
7430511d63cSchristos 	case MDOC_Fx:
7444154958bSjoerg 		pp = "FreeBSD";
7454154958bSjoerg 		break;
7460511d63cSchristos 	case MDOC_Nx:
7474154958bSjoerg 		pp = "NetBSD";
7484154958bSjoerg 		break;
7490511d63cSchristos 	case MDOC_Ox:
7504154958bSjoerg 		pp = "OpenBSD";
7514154958bSjoerg 		break;
7520511d63cSchristos 	case MDOC_Ux:
7534154958bSjoerg 		pp = "UNIX";
7544154958bSjoerg 		break;
7554154958bSjoerg 	default:
756*47a17e0dSchristos 		return 1;
7574154958bSjoerg 	}
7584154958bSjoerg 
7594154958bSjoerg 	PAIR_CLASS_INIT(&tag, "unix");
7604154958bSjoerg 	print_otag(h, TAG_SPAN, 1, &tag);
76154a4f7feSjoerg 
7624154958bSjoerg 	print_text(h, pp);
76354a4f7feSjoerg 	if (n->child) {
76454a4f7feSjoerg 		flags = h->flags;
76554a4f7feSjoerg 		h->flags |= HTML_KEEP;
76654a4f7feSjoerg 		print_text(h, n->child->string);
76754a4f7feSjoerg 		h->flags = flags;
76854a4f7feSjoerg 	}
769*47a17e0dSchristos 	return 0;
7704154958bSjoerg }
7714154958bSjoerg 
7724154958bSjoerg static int
7734154958bSjoerg mdoc_bx_pre(MDOC_ARGS)
7744154958bSjoerg {
7754154958bSjoerg 	struct htmlpair	 tag;
7764154958bSjoerg 
7774154958bSjoerg 	PAIR_CLASS_INIT(&tag, "unix");
7784154958bSjoerg 	print_otag(h, TAG_SPAN, 1, &tag);
7794154958bSjoerg 
78054a4f7feSjoerg 	if (NULL != (n = n->child)) {
78154a4f7feSjoerg 		print_text(h, n->string);
7824154958bSjoerg 		h->flags |= HTML_NOSPACE;
7834154958bSjoerg 		print_text(h, "BSD");
78454a4f7feSjoerg 	} else {
78554a4f7feSjoerg 		print_text(h, "BSD");
786*47a17e0dSchristos 		return 0;
78754a4f7feSjoerg 	}
78854a4f7feSjoerg 
78954a4f7feSjoerg 	if (NULL != (n = n->next)) {
79054a4f7feSjoerg 		h->flags |= HTML_NOSPACE;
79154a4f7feSjoerg 		print_text(h, "-");
79254a4f7feSjoerg 		h->flags |= HTML_NOSPACE;
79354a4f7feSjoerg 		print_text(h, n->string);
79454a4f7feSjoerg 	}
79554a4f7feSjoerg 
796*47a17e0dSchristos 	return 0;
7974154958bSjoerg }
7984154958bSjoerg 
7994154958bSjoerg static int
8004154958bSjoerg mdoc_it_pre(MDOC_ARGS)
8014154958bSjoerg {
802e4fbeb7eSjoerg 	struct roffsu	 su;
8030a84adc5Sjoerg 	enum mdoc_list	 type;
804e4fbeb7eSjoerg 	struct htmlpair	 tag[2];
805*47a17e0dSchristos 	const struct roff_node *bl;
8064154958bSjoerg 
807e4fbeb7eSjoerg 	bl = n->parent;
808e4fbeb7eSjoerg 	while (bl && MDOC_Bl != bl->tok)
8094154958bSjoerg 		bl = bl->parent;
8104154958bSjoerg 
811e4fbeb7eSjoerg 	assert(bl);
8124154958bSjoerg 
813e4fbeb7eSjoerg 	type = bl->norm->Bl.type;
8146c26a9aaSjoerg 
815e4fbeb7eSjoerg 	assert(lists[type]);
816e4fbeb7eSjoerg 	PAIR_CLASS_INIT(&tag[0], lists[type]);
8176c26a9aaSjoerg 
818f8126693Sjoerg 	bufinit(h);
819f8126693Sjoerg 
820*47a17e0dSchristos 	if (n->type == ROFFT_HEAD) {
8214154958bSjoerg 		switch (type) {
8220511d63cSchristos 		case LIST_bullet:
8230511d63cSchristos 		case LIST_dash:
8240511d63cSchristos 		case LIST_item:
8250511d63cSchristos 		case LIST_hyphen:
8260511d63cSchristos 		case LIST_enum:
827*47a17e0dSchristos 			return 0;
8280511d63cSchristos 		case LIST_diag:
8290511d63cSchristos 		case LIST_hang:
8300511d63cSchristos 		case LIST_inset:
8310511d63cSchristos 		case LIST_ohang:
8320511d63cSchristos 		case LIST_tag:
833e4fbeb7eSjoerg 			SCALE_VS_INIT(&su, ! bl->norm->Bl.comp);
834e4fbeb7eSjoerg 			bufcat_su(h, "margin-top", &su);
835e4fbeb7eSjoerg 			PAIR_STYLE_INIT(&tag[1], h);
836e4fbeb7eSjoerg 			print_otag(h, TAG_DT, 2, tag);
837e4fbeb7eSjoerg 			if (LIST_diag != type)
838e4fbeb7eSjoerg 				break;
839e4fbeb7eSjoerg 			PAIR_CLASS_INIT(&tag[0], "diag");
840e4fbeb7eSjoerg 			print_otag(h, TAG_B, 1, tag);
841e4fbeb7eSjoerg 			break;
8420511d63cSchristos 		case LIST_column:
8434154958bSjoerg 			break;
8444154958bSjoerg 		default:
8454154958bSjoerg 			break;
8464154958bSjoerg 		}
847*47a17e0dSchristos 	} else if (n->type == ROFFT_BODY) {
848e4fbeb7eSjoerg 		switch (type) {
8490511d63cSchristos 		case LIST_bullet:
8500511d63cSchristos 		case LIST_hyphen:
8510511d63cSchristos 		case LIST_dash:
8520511d63cSchristos 		case LIST_enum:
8530511d63cSchristos 		case LIST_item:
854e4fbeb7eSjoerg 			SCALE_VS_INIT(&su, ! bl->norm->Bl.comp);
855e4fbeb7eSjoerg 			bufcat_su(h, "margin-top", &su);
856e4fbeb7eSjoerg 			PAIR_STYLE_INIT(&tag[1], h);
857e4fbeb7eSjoerg 			print_otag(h, TAG_LI, 2, tag);
858e4fbeb7eSjoerg 			break;
8590511d63cSchristos 		case LIST_diag:
8600511d63cSchristos 		case LIST_hang:
8610511d63cSchristos 		case LIST_inset:
8620511d63cSchristos 		case LIST_ohang:
8630511d63cSchristos 		case LIST_tag:
864e4fbeb7eSjoerg 			if (NULL == bl->norm->Bl.width) {
865e4fbeb7eSjoerg 				print_otag(h, TAG_DD, 1, tag);
866e4fbeb7eSjoerg 				break;
867e4fbeb7eSjoerg 			}
868e4fbeb7eSjoerg 			a2width(bl->norm->Bl.width, &su);
869e4fbeb7eSjoerg 			bufcat_su(h, "margin-left", &su);
870e4fbeb7eSjoerg 			PAIR_STYLE_INIT(&tag[1], h);
871e4fbeb7eSjoerg 			print_otag(h, TAG_DD, 2, tag);
872e4fbeb7eSjoerg 			break;
8730511d63cSchristos 		case LIST_column:
874e4fbeb7eSjoerg 			SCALE_VS_INIT(&su, ! bl->norm->Bl.comp);
875e4fbeb7eSjoerg 			bufcat_su(h, "margin-top", &su);
876e4fbeb7eSjoerg 			PAIR_STYLE_INIT(&tag[1], h);
877e4fbeb7eSjoerg 			print_otag(h, TAG_TD, 2, tag);
878e4fbeb7eSjoerg 			break;
879e4fbeb7eSjoerg 		default:
880e4fbeb7eSjoerg 			break;
881e4fbeb7eSjoerg 		}
882e4fbeb7eSjoerg 	} else {
883e4fbeb7eSjoerg 		switch (type) {
8840511d63cSchristos 		case LIST_column:
885e4fbeb7eSjoerg 			print_otag(h, TAG_TR, 1, tag);
886e4fbeb7eSjoerg 			break;
887e4fbeb7eSjoerg 		default:
888e4fbeb7eSjoerg 			break;
889e4fbeb7eSjoerg 		}
8904154958bSjoerg 	}
8914154958bSjoerg 
892*47a17e0dSchristos 	return 1;
8934154958bSjoerg }
8944154958bSjoerg 
8954154958bSjoerg static int
8964154958bSjoerg mdoc_bl_pre(MDOC_ARGS)
8974154958bSjoerg {
898e4fbeb7eSjoerg 	int		 i;
899e4fbeb7eSjoerg 	struct htmlpair	 tag[3];
900e4fbeb7eSjoerg 	struct roffsu	 su;
901e4fbeb7eSjoerg 	char		 buf[BUFSIZ];
9024154958bSjoerg 
903*47a17e0dSchristos 	if (n->type == ROFFT_BODY) {
904e4fbeb7eSjoerg 		if (LIST_column == n->norm->Bl.type)
905e4fbeb7eSjoerg 			print_otag(h, TAG_TBODY, 0, NULL);
906*47a17e0dSchristos 		return 1;
907e4fbeb7eSjoerg 	}
908e4fbeb7eSjoerg 
909*47a17e0dSchristos 	if (n->type == ROFFT_HEAD) {
910e4fbeb7eSjoerg 		if (LIST_column != n->norm->Bl.type)
911*47a17e0dSchristos 			return 0;
9124154958bSjoerg 
913e4fbeb7eSjoerg 		/*
914e4fbeb7eSjoerg 		 * For each column, print out the <COL> tag with our
915e4fbeb7eSjoerg 		 * suggested width.  The last column gets min-width, as
916e4fbeb7eSjoerg 		 * in terminal mode it auto-sizes to the width of the
917e4fbeb7eSjoerg 		 * screen and we want to preserve that behaviour.
918e4fbeb7eSjoerg 		 */
919e4fbeb7eSjoerg 
920e4fbeb7eSjoerg 		for (i = 0; i < (int)n->norm->Bl.ncols; i++) {
921ed7c7912Sjoerg 			bufinit(h);
922e4fbeb7eSjoerg 			a2width(n->norm->Bl.cols[i], &su);
923e4fbeb7eSjoerg 			if (i < (int)n->norm->Bl.ncols - 1)
924e4fbeb7eSjoerg 				bufcat_su(h, "width", &su);
925e4fbeb7eSjoerg 			else
926e4fbeb7eSjoerg 				bufcat_su(h, "min-width", &su);
927e4fbeb7eSjoerg 			PAIR_STYLE_INIT(&tag[0], h);
928e4fbeb7eSjoerg 			print_otag(h, TAG_COL, 1, tag);
9294154958bSjoerg 		}
9304154958bSjoerg 
931*47a17e0dSchristos 		return 0;
9324154958bSjoerg 	}
9334154958bSjoerg 
934e4fbeb7eSjoerg 	SCALE_VS_INIT(&su, 0);
935ed7c7912Sjoerg 	bufinit(h);
936e4fbeb7eSjoerg 	bufcat_su(h, "margin-top", &su);
937e4fbeb7eSjoerg 	bufcat_su(h, "margin-bottom", &su);
938e4fbeb7eSjoerg 	PAIR_STYLE_INIT(&tag[0], h);
939e4fbeb7eSjoerg 
940e4fbeb7eSjoerg 	assert(lists[n->norm->Bl.type]);
9410511d63cSchristos 	(void)strlcpy(buf, "list ", BUFSIZ);
9420511d63cSchristos 	(void)strlcat(buf, lists[n->norm->Bl.type], BUFSIZ);
943e4fbeb7eSjoerg 	PAIR_INIT(&tag[1], ATTR_CLASS, buf);
944e4fbeb7eSjoerg 
945e4fbeb7eSjoerg 	/* Set the block's left-hand margin. */
946e4fbeb7eSjoerg 
947e4fbeb7eSjoerg 	if (n->norm->Bl.offs) {
9480511d63cSchristos 		a2width(n->norm->Bl.offs, &su);
949e4fbeb7eSjoerg 		bufcat_su(h, "margin-left", &su);
950e4fbeb7eSjoerg 	}
951e4fbeb7eSjoerg 
952e4fbeb7eSjoerg 	switch (n->norm->Bl.type) {
9530511d63cSchristos 	case LIST_bullet:
9540511d63cSchristos 	case LIST_dash:
9550511d63cSchristos 	case LIST_hyphen:
9560511d63cSchristos 	case LIST_item:
957e4fbeb7eSjoerg 		print_otag(h, TAG_UL, 2, tag);
958e4fbeb7eSjoerg 		break;
9590511d63cSchristos 	case LIST_enum:
960e4fbeb7eSjoerg 		print_otag(h, TAG_OL, 2, tag);
961e4fbeb7eSjoerg 		break;
9620511d63cSchristos 	case LIST_diag:
9630511d63cSchristos 	case LIST_hang:
9640511d63cSchristos 	case LIST_inset:
9650511d63cSchristos 	case LIST_ohang:
9660511d63cSchristos 	case LIST_tag:
967e4fbeb7eSjoerg 		print_otag(h, TAG_DL, 2, tag);
968e4fbeb7eSjoerg 		break;
9690511d63cSchristos 	case LIST_column:
970e4fbeb7eSjoerg 		print_otag(h, TAG_TABLE, 2, tag);
971e4fbeb7eSjoerg 		break;
972e4fbeb7eSjoerg 	default:
973e4fbeb7eSjoerg 		abort();
974e4fbeb7eSjoerg 	}
975e4fbeb7eSjoerg 
976*47a17e0dSchristos 	return 1;
977e4fbeb7eSjoerg }
9784154958bSjoerg 
9794154958bSjoerg static int
9804154958bSjoerg mdoc_ex_pre(MDOC_ARGS)
9814154958bSjoerg {
9824154958bSjoerg 	struct htmlpair	  tag;
983*47a17e0dSchristos 	struct tag	 *t;
984*47a17e0dSchristos 	struct roff_node *nch;
9854154958bSjoerg 
986e4fbeb7eSjoerg 	if (n->prev)
987e4fbeb7eSjoerg 		print_otag(h, TAG_BR, 0, NULL);
988e4fbeb7eSjoerg 
9894154958bSjoerg 	PAIR_CLASS_INIT(&tag, "utility");
9904154958bSjoerg 
9914154958bSjoerg 	print_text(h, "The");
99254a4f7feSjoerg 
993*47a17e0dSchristos 	for (nch = n->child; nch != NULL; nch = nch->next) {
994*47a17e0dSchristos 		assert(nch->type == ROFFT_TEXT);
99554a4f7feSjoerg 
996e4fbeb7eSjoerg 		t = print_otag(h, TAG_B, 1, &tag);
997*47a17e0dSchristos 		print_text(h, nch->string);
9984154958bSjoerg 		print_tagq(h, t);
9994154958bSjoerg 
1000*47a17e0dSchristos 		if (nch->next == NULL)
1001*47a17e0dSchristos 			continue;
1002*47a17e0dSchristos 
1003*47a17e0dSchristos 		if (nch->prev != NULL || nch->next->next != NULL) {
10044154958bSjoerg 			h->flags |= HTML_NOSPACE;
10054154958bSjoerg 			print_text(h, ",");
10064154958bSjoerg 		}
10074154958bSjoerg 
1008*47a17e0dSchristos 		if (nch->next->next == NULL)
100954a4f7feSjoerg 			print_text(h, "and");
101054a4f7feSjoerg 	}
101154a4f7feSjoerg 
1012*47a17e0dSchristos 	if (n->child != NULL && n->child->next != NULL)
10130511d63cSchristos 		print_text(h, "utilities exit\\~0");
10144154958bSjoerg 	else
10150511d63cSchristos 		print_text(h, "utility exits\\~0");
10164154958bSjoerg 
10170511d63cSchristos 	print_text(h, "on success, and\\~>0 if an error occurs.");
1018*47a17e0dSchristos 	return 0;
10194154958bSjoerg }
10204154958bSjoerg 
10214154958bSjoerg static int
10224154958bSjoerg mdoc_em_pre(MDOC_ARGS)
10234154958bSjoerg {
10244154958bSjoerg 	struct htmlpair	tag;
10254154958bSjoerg 
10264154958bSjoerg 	PAIR_CLASS_INIT(&tag, "emph");
10274154958bSjoerg 	print_otag(h, TAG_SPAN, 1, &tag);
1028*47a17e0dSchristos 	return 1;
10294154958bSjoerg }
10304154958bSjoerg 
10314154958bSjoerg static int
10324154958bSjoerg mdoc_d1_pre(MDOC_ARGS)
10334154958bSjoerg {
10344154958bSjoerg 	struct htmlpair	 tag[2];
10354154958bSjoerg 	struct roffsu	 su;
10364154958bSjoerg 
1037*47a17e0dSchristos 	if (n->type != ROFFT_BLOCK)
1038*47a17e0dSchristos 		return 1;
10394154958bSjoerg 
1040e4fbeb7eSjoerg 	SCALE_VS_INIT(&su, 0);
1041f8126693Sjoerg 	bufinit(h);
1042e4fbeb7eSjoerg 	bufcat_su(h, "margin-top", &su);
1043e4fbeb7eSjoerg 	bufcat_su(h, "margin-bottom", &su);
1044e4fbeb7eSjoerg 	PAIR_STYLE_INIT(&tag[0], h);
1045e4fbeb7eSjoerg 	print_otag(h, TAG_BLOCKQUOTE, 1, tag);
10464154958bSjoerg 
1047e4fbeb7eSjoerg 	/* BLOCKQUOTE needs a block body. */
1048e4fbeb7eSjoerg 
1049e4fbeb7eSjoerg 	PAIR_CLASS_INIT(&tag[0], "display");
1050e4fbeb7eSjoerg 	print_otag(h, TAG_DIV, 1, tag);
1051e4fbeb7eSjoerg 
1052e4fbeb7eSjoerg 	if (MDOC_Dl == n->tok) {
10534154958bSjoerg 		PAIR_CLASS_INIT(&tag[0], "lit");
1054e4fbeb7eSjoerg 		print_otag(h, TAG_CODE, 1, tag);
1055e4fbeb7eSjoerg 	}
1056e4fbeb7eSjoerg 
1057*47a17e0dSchristos 	return 1;
10584154958bSjoerg }
10594154958bSjoerg 
10604154958bSjoerg static int
10614154958bSjoerg mdoc_sx_pre(MDOC_ARGS)
10624154958bSjoerg {
10634154958bSjoerg 	struct htmlpair	 tag[2];
10644154958bSjoerg 
1065f8126693Sjoerg 	bufinit(h);
1066*47a17e0dSchristos 	bufcat(h, "#");
1067f8126693Sjoerg 
1068f8126693Sjoerg 	for (n = n->child; n; ) {
1069f8126693Sjoerg 		bufcat_id(h, n->string);
1070f8126693Sjoerg 		if (NULL != (n = n->next))
1071f8126693Sjoerg 			bufcat_id(h, " ");
10724154958bSjoerg 	}
10734154958bSjoerg 
10744154958bSjoerg 	PAIR_CLASS_INIT(&tag[0], "link-sec");
1075f8126693Sjoerg 	PAIR_HREF_INIT(&tag[1], h->buf);
10764154958bSjoerg 
1077e4fbeb7eSjoerg 	print_otag(h, TAG_I, 1, tag);
10784154958bSjoerg 	print_otag(h, TAG_A, 2, tag);
1079*47a17e0dSchristos 	return 1;
10804154958bSjoerg }
10814154958bSjoerg 
10824154958bSjoerg static int
10834154958bSjoerg mdoc_bd_pre(MDOC_ARGS)
10844154958bSjoerg {
10854154958bSjoerg 	struct htmlpair		 tag[2];
108654a4f7feSjoerg 	int			 comp, sv;
1087*47a17e0dSchristos 	struct roff_node	*nn;
10884154958bSjoerg 	struct roffsu		 su;
10894154958bSjoerg 
1090*47a17e0dSchristos 	if (n->type == ROFFT_HEAD)
1091*47a17e0dSchristos 		return 0;
10924154958bSjoerg 
1093*47a17e0dSchristos 	if (n->type == ROFFT_BLOCK) {
1094e4fbeb7eSjoerg 		comp = n->norm->Bd.comp;
10954154958bSjoerg 		for (nn = n; nn && ! comp; nn = nn->parent) {
1096*47a17e0dSchristos 			if (nn->type != ROFFT_BLOCK)
10974154958bSjoerg 				continue;
10984154958bSjoerg 			if (MDOC_Ss == nn->tok || MDOC_Sh == nn->tok)
10994154958bSjoerg 				comp = 1;
11004154958bSjoerg 			if (nn->prev)
11014154958bSjoerg 				break;
11024154958bSjoerg 		}
1103e4fbeb7eSjoerg 		if ( ! comp)
11040511d63cSchristos 			print_paragraph(h);
1105*47a17e0dSchristos 		return 1;
11064154958bSjoerg 	}
11074154958bSjoerg 
11080511d63cSchristos 	/* Handle the -offset argument. */
11090511d63cSchristos 
11100511d63cSchristos 	if (n->norm->Bd.offs == NULL ||
11110511d63cSchristos 	    ! strcmp(n->norm->Bd.offs, "left"))
1112e4fbeb7eSjoerg 		SCALE_HS_INIT(&su, 0);
11130511d63cSchristos 	else if ( ! strcmp(n->norm->Bd.offs, "indent"))
11140511d63cSchristos 		SCALE_HS_INIT(&su, INDENT);
11150511d63cSchristos 	else if ( ! strcmp(n->norm->Bd.offs, "indent-two"))
11160511d63cSchristos 		SCALE_HS_INIT(&su, INDENT * 2);
11170511d63cSchristos 	else
11180511d63cSchristos 		a2width(n->norm->Bd.offs, &su);
11194154958bSjoerg 
1120f8126693Sjoerg 	bufinit(h);
1121e4fbeb7eSjoerg 	bufcat_su(h, "margin-left", &su);
1122e4fbeb7eSjoerg 	PAIR_STYLE_INIT(&tag[0], h);
1123e4fbeb7eSjoerg 
1124e4fbeb7eSjoerg 	if (DISP_unfilled != n->norm->Bd.type &&
1125e4fbeb7eSjoerg 	    DISP_literal != n->norm->Bd.type) {
1126e4fbeb7eSjoerg 		PAIR_CLASS_INIT(&tag[1], "display");
11274154958bSjoerg 		print_otag(h, TAG_DIV, 2, tag);
1128*47a17e0dSchristos 		return 1;
1129e4fbeb7eSjoerg 	}
1130e4fbeb7eSjoerg 
1131e4fbeb7eSjoerg 	PAIR_CLASS_INIT(&tag[1], "lit display");
1132e4fbeb7eSjoerg 	print_otag(h, TAG_PRE, 2, tag);
11334154958bSjoerg 
113454a4f7feSjoerg 	/* This can be recursive: save & set our literal state. */
113554a4f7feSjoerg 
113654a4f7feSjoerg 	sv = h->flags & HTML_LITERAL;
113754a4f7feSjoerg 	h->flags |= HTML_LITERAL;
113854a4f7feSjoerg 
11394154958bSjoerg 	for (nn = n->child; nn; nn = nn->next) {
1140ed7c7912Sjoerg 		print_mdoc_node(meta, nn, h);
1141e4fbeb7eSjoerg 		/*
1142e4fbeb7eSjoerg 		 * If the printed node flushes its own line, then we
1143e4fbeb7eSjoerg 		 * needn't do it here as well.  This is hacky, but the
1144e4fbeb7eSjoerg 		 * notion of selective eoln whitespace is pretty dumb
1145e4fbeb7eSjoerg 		 * anyway, so don't sweat it.
1146e4fbeb7eSjoerg 		 */
1147e4fbeb7eSjoerg 		switch (nn->tok) {
11480511d63cSchristos 		case MDOC_Sm:
11490511d63cSchristos 		case MDOC_br:
11500511d63cSchristos 		case MDOC_sp:
11510511d63cSchristos 		case MDOC_Bl:
11520511d63cSchristos 		case MDOC_D1:
11530511d63cSchristos 		case MDOC_Dl:
11540511d63cSchristos 		case MDOC_Lp:
11550511d63cSchristos 		case MDOC_Pp:
1156e4fbeb7eSjoerg 			continue;
1157e4fbeb7eSjoerg 		default:
1158e4fbeb7eSjoerg 			break;
1159e4fbeb7eSjoerg 		}
11600511d63cSchristos 		if (h->flags & HTML_NONEWLINE ||
11610511d63cSchristos 		    (nn->next && ! (nn->next->flags & MDOC_LINE)))
1162e4fbeb7eSjoerg 			continue;
1163e4fbeb7eSjoerg 		else if (nn->next)
1164e4fbeb7eSjoerg 			print_text(h, "\n");
1165e4fbeb7eSjoerg 
1166e4fbeb7eSjoerg 		h->flags |= HTML_NOSPACE;
11674154958bSjoerg 	}
11684154958bSjoerg 
116954a4f7feSjoerg 	if (0 == sv)
117054a4f7feSjoerg 		h->flags &= ~HTML_LITERAL;
117154a4f7feSjoerg 
1172*47a17e0dSchristos 	return 0;
11734154958bSjoerg }
11744154958bSjoerg 
11754154958bSjoerg static int
11764154958bSjoerg mdoc_pa_pre(MDOC_ARGS)
11774154958bSjoerg {
11784154958bSjoerg 	struct htmlpair	tag;
11794154958bSjoerg 
11804154958bSjoerg 	PAIR_CLASS_INIT(&tag, "file");
1181e4fbeb7eSjoerg 	print_otag(h, TAG_I, 1, &tag);
1182*47a17e0dSchristos 	return 1;
11834154958bSjoerg }
11844154958bSjoerg 
11854154958bSjoerg static int
11864154958bSjoerg mdoc_ad_pre(MDOC_ARGS)
11874154958bSjoerg {
11884154958bSjoerg 	struct htmlpair	tag;
11894154958bSjoerg 
11904154958bSjoerg 	PAIR_CLASS_INIT(&tag, "addr");
1191e4fbeb7eSjoerg 	print_otag(h, TAG_I, 1, &tag);
1192*47a17e0dSchristos 	return 1;
11934154958bSjoerg }
11944154958bSjoerg 
11954154958bSjoerg static int
11964154958bSjoerg mdoc_an_pre(MDOC_ARGS)
11974154958bSjoerg {
11984154958bSjoerg 	struct htmlpair	tag;
11994154958bSjoerg 
12000511d63cSchristos 	if (n->norm->An.auth == AUTH_split) {
12010511d63cSchristos 		h->flags &= ~HTML_NOSPLIT;
12020511d63cSchristos 		h->flags |= HTML_SPLIT;
1203*47a17e0dSchristos 		return 0;
12040511d63cSchristos 	}
12050511d63cSchristos 	if (n->norm->An.auth == AUTH_nosplit) {
12060511d63cSchristos 		h->flags &= ~HTML_SPLIT;
12070511d63cSchristos 		h->flags |= HTML_NOSPLIT;
1208*47a17e0dSchristos 		return 0;
12090511d63cSchristos 	}
12100511d63cSchristos 
12110511d63cSchristos 	if (h->flags & HTML_SPLIT)
12120511d63cSchristos 		print_otag(h, TAG_BR, 0, NULL);
12130511d63cSchristos 
12140511d63cSchristos 	if (n->sec == SEC_AUTHORS && ! (h->flags & HTML_NOSPLIT))
12150511d63cSchristos 		h->flags |= HTML_SPLIT;
12164154958bSjoerg 
12174154958bSjoerg 	PAIR_CLASS_INIT(&tag, "author");
12184154958bSjoerg 	print_otag(h, TAG_SPAN, 1, &tag);
1219*47a17e0dSchristos 	return 1;
12204154958bSjoerg }
12214154958bSjoerg 
12224154958bSjoerg static int
12234154958bSjoerg mdoc_cd_pre(MDOC_ARGS)
12244154958bSjoerg {
12254154958bSjoerg 	struct htmlpair	tag;
12264154958bSjoerg 
12277574e07eSjoerg 	synopsis_pre(h, n);
12284154958bSjoerg 	PAIR_CLASS_INIT(&tag, "config");
1229e4fbeb7eSjoerg 	print_otag(h, TAG_B, 1, &tag);
1230*47a17e0dSchristos 	return 1;
12314154958bSjoerg }
12324154958bSjoerg 
12334154958bSjoerg static int
12344154958bSjoerg mdoc_dv_pre(MDOC_ARGS)
12354154958bSjoerg {
12364154958bSjoerg 	struct htmlpair	tag;
12374154958bSjoerg 
12384154958bSjoerg 	PAIR_CLASS_INIT(&tag, "define");
12394154958bSjoerg 	print_otag(h, TAG_SPAN, 1, &tag);
1240*47a17e0dSchristos 	return 1;
12414154958bSjoerg }
12424154958bSjoerg 
12434154958bSjoerg static int
12444154958bSjoerg mdoc_ev_pre(MDOC_ARGS)
12454154958bSjoerg {
12464154958bSjoerg 	struct htmlpair	tag;
12474154958bSjoerg 
12484154958bSjoerg 	PAIR_CLASS_INIT(&tag, "env");
12494154958bSjoerg 	print_otag(h, TAG_SPAN, 1, &tag);
1250*47a17e0dSchristos 	return 1;
12514154958bSjoerg }
12524154958bSjoerg 
12534154958bSjoerg static int
12544154958bSjoerg mdoc_er_pre(MDOC_ARGS)
12554154958bSjoerg {
12564154958bSjoerg 	struct htmlpair	tag;
12574154958bSjoerg 
12584154958bSjoerg 	PAIR_CLASS_INIT(&tag, "errno");
12594154958bSjoerg 	print_otag(h, TAG_SPAN, 1, &tag);
1260*47a17e0dSchristos 	return 1;
12614154958bSjoerg }
12624154958bSjoerg 
12634154958bSjoerg static int
12644154958bSjoerg mdoc_fa_pre(MDOC_ARGS)
12654154958bSjoerg {
1266*47a17e0dSchristos 	const struct roff_node	*nn;
12674154958bSjoerg 	struct htmlpair		 tag;
12684154958bSjoerg 	struct tag		*t;
12694154958bSjoerg 
12704154958bSjoerg 	PAIR_CLASS_INIT(&tag, "farg");
12714154958bSjoerg 	if (n->parent->tok != MDOC_Fo) {
1272e4fbeb7eSjoerg 		print_otag(h, TAG_I, 1, &tag);
1273*47a17e0dSchristos 		return 1;
12744154958bSjoerg 	}
12754154958bSjoerg 
12764154958bSjoerg 	for (nn = n->child; nn; nn = nn->next) {
1277e4fbeb7eSjoerg 		t = print_otag(h, TAG_I, 1, &tag);
12784154958bSjoerg 		print_text(h, nn->string);
12794154958bSjoerg 		print_tagq(h, t);
128054a4f7feSjoerg 		if (nn->next) {
128154a4f7feSjoerg 			h->flags |= HTML_NOSPACE;
12824154958bSjoerg 			print_text(h, ",");
12834154958bSjoerg 		}
128454a4f7feSjoerg 	}
12854154958bSjoerg 
128654a4f7feSjoerg 	if (n->child && n->next && n->next->tok == MDOC_Fa) {
128754a4f7feSjoerg 		h->flags |= HTML_NOSPACE;
12884154958bSjoerg 		print_text(h, ",");
128954a4f7feSjoerg 	}
12904154958bSjoerg 
1291*47a17e0dSchristos 	return 0;
12924154958bSjoerg }
12934154958bSjoerg 
12944154958bSjoerg static int
12954154958bSjoerg mdoc_fd_pre(MDOC_ARGS)
12964154958bSjoerg {
129754a4f7feSjoerg 	struct htmlpair	 tag[2];
129854a4f7feSjoerg 	char		 buf[BUFSIZ];
129954a4f7feSjoerg 	size_t		 sz;
130054a4f7feSjoerg 	int		 i;
130154a4f7feSjoerg 	struct tag	*t;
13024154958bSjoerg 
13037574e07eSjoerg 	synopsis_pre(h, n);
13044154958bSjoerg 
130554a4f7feSjoerg 	if (NULL == (n = n->child))
1306*47a17e0dSchristos 		return 0;
130754a4f7feSjoerg 
1308*47a17e0dSchristos 	assert(n->type == ROFFT_TEXT);
130954a4f7feSjoerg 
131054a4f7feSjoerg 	if (strcmp(n->string, "#include")) {
131154a4f7feSjoerg 		PAIR_CLASS_INIT(&tag[0], "macro");
131254a4f7feSjoerg 		print_otag(h, TAG_B, 1, tag);
1313*47a17e0dSchristos 		return 1;
13144154958bSjoerg 	}
13154154958bSjoerg 
131654a4f7feSjoerg 	PAIR_CLASS_INIT(&tag[0], "includes");
131754a4f7feSjoerg 	print_otag(h, TAG_B, 1, tag);
131854a4f7feSjoerg 	print_text(h, n->string);
131954a4f7feSjoerg 
132054a4f7feSjoerg 	if (NULL != (n = n->next)) {
1321*47a17e0dSchristos 		assert(n->type == ROFFT_TEXT);
13220511d63cSchristos 
13230511d63cSchristos 		/*
13240511d63cSchristos 		 * XXX This is broken and not easy to fix.
13250511d63cSchristos 		 * When using -Oincludes, truncation may occur.
13260511d63cSchristos 		 * Dynamic allocation wouldn't help because
13270511d63cSchristos 		 * passing long strings to buffmt_includes()
13280511d63cSchristos 		 * does not work either.
13290511d63cSchristos 		 */
13300511d63cSchristos 
133154a4f7feSjoerg 		strlcpy(buf, '<' == *n->string || '"' == *n->string ?
133254a4f7feSjoerg 		    n->string + 1 : n->string, BUFSIZ);
133354a4f7feSjoerg 
133454a4f7feSjoerg 		sz = strlen(buf);
133554a4f7feSjoerg 		if (sz && ('>' == buf[sz - 1] || '"' == buf[sz - 1]))
133654a4f7feSjoerg 			buf[sz - 1] = '\0';
133754a4f7feSjoerg 
133854a4f7feSjoerg 		PAIR_CLASS_INIT(&tag[0], "link-includes");
133954a4f7feSjoerg 
134054a4f7feSjoerg 		i = 1;
134154a4f7feSjoerg 		if (h->base_includes) {
134254a4f7feSjoerg 			buffmt_includes(h, buf);
134354a4f7feSjoerg 			PAIR_HREF_INIT(&tag[i], h->buf);
134454a4f7feSjoerg 			i++;
134554a4f7feSjoerg 		}
134654a4f7feSjoerg 
134754a4f7feSjoerg 		t = print_otag(h, TAG_A, i, tag);
134854a4f7feSjoerg 		print_text(h, n->string);
134954a4f7feSjoerg 		print_tagq(h, t);
135054a4f7feSjoerg 
135154a4f7feSjoerg 		n = n->next;
135254a4f7feSjoerg 	}
135354a4f7feSjoerg 
135454a4f7feSjoerg 	for ( ; n; n = n->next) {
1355*47a17e0dSchristos 		assert(n->type == ROFFT_TEXT);
135654a4f7feSjoerg 		print_text(h, n->string);
135754a4f7feSjoerg 	}
135854a4f7feSjoerg 
1359*47a17e0dSchristos 	return 0;
136054a4f7feSjoerg }
136154a4f7feSjoerg 
13624154958bSjoerg static int
13634154958bSjoerg mdoc_vt_pre(MDOC_ARGS)
13644154958bSjoerg {
13654154958bSjoerg 	struct htmlpair	 tag;
13664154958bSjoerg 
1367*47a17e0dSchristos 	if (n->type == ROFFT_BLOCK) {
13687574e07eSjoerg 		synopsis_pre(h, n);
1369*47a17e0dSchristos 		return 1;
1370*47a17e0dSchristos 	} else if (n->type == ROFFT_ELEM) {
13717574e07eSjoerg 		synopsis_pre(h, n);
1372*47a17e0dSchristos 	} else if (n->type == ROFFT_HEAD)
1373*47a17e0dSchristos 		return 0;
13744154958bSjoerg 
13754154958bSjoerg 	PAIR_CLASS_INIT(&tag, "type");
13764154958bSjoerg 	print_otag(h, TAG_SPAN, 1, &tag);
1377*47a17e0dSchristos 	return 1;
13784154958bSjoerg }
13794154958bSjoerg 
13804154958bSjoerg static int
13814154958bSjoerg mdoc_ft_pre(MDOC_ARGS)
13824154958bSjoerg {
13834154958bSjoerg 	struct htmlpair	 tag;
13844154958bSjoerg 
13857574e07eSjoerg 	synopsis_pre(h, n);
13864154958bSjoerg 	PAIR_CLASS_INIT(&tag, "ftype");
1387e4fbeb7eSjoerg 	print_otag(h, TAG_I, 1, &tag);
1388*47a17e0dSchristos 	return 1;
13894154958bSjoerg }
13904154958bSjoerg 
13914154958bSjoerg static int
13924154958bSjoerg mdoc_fn_pre(MDOC_ARGS)
13934154958bSjoerg {
13944154958bSjoerg 	struct tag	*t;
13954154958bSjoerg 	struct htmlpair	 tag[2];
13964154958bSjoerg 	char		 nbuf[BUFSIZ];
13974154958bSjoerg 	const char	*sp, *ep;
139854a4f7feSjoerg 	int		 sz, i, pretty;
13994154958bSjoerg 
140054a4f7feSjoerg 	pretty = MDOC_SYNPRETTY & n->flags;
14017574e07eSjoerg 	synopsis_pre(h, n);
14024154958bSjoerg 
14034154958bSjoerg 	/* Split apart into type and name. */
14044154958bSjoerg 	assert(n->child->string);
14054154958bSjoerg 	sp = n->child->string;
14064154958bSjoerg 
14074154958bSjoerg 	ep = strchr(sp, ' ');
14084154958bSjoerg 	if (NULL != ep) {
14094154958bSjoerg 		PAIR_CLASS_INIT(&tag[0], "ftype");
1410e4fbeb7eSjoerg 		t = print_otag(h, TAG_I, 1, tag);
14114154958bSjoerg 
14124154958bSjoerg 		while (ep) {
14134154958bSjoerg 			sz = MIN((int)(ep - sp), BUFSIZ - 1);
14144154958bSjoerg 			(void)memcpy(nbuf, sp, (size_t)sz);
14154154958bSjoerg 			nbuf[sz] = '\0';
14164154958bSjoerg 			print_text(h, nbuf);
14174154958bSjoerg 			sp = ++ep;
14184154958bSjoerg 			ep = strchr(sp, ' ');
14194154958bSjoerg 		}
14204154958bSjoerg 		print_tagq(h, t);
14214154958bSjoerg 	}
14224154958bSjoerg 
14234154958bSjoerg 	PAIR_CLASS_INIT(&tag[0], "fname");
14247bcc2a5fSjoerg 
14257bcc2a5fSjoerg 	/*
14267bcc2a5fSjoerg 	 * FIXME: only refer to IDs that we know exist.
14277bcc2a5fSjoerg 	 */
14287bcc2a5fSjoerg 
14297bcc2a5fSjoerg #if 0
143082361f10Sjoerg 	if (MDOC_SYNPRETTY & n->flags) {
14317bcc2a5fSjoerg 		nbuf[0] = '\0';
14327bcc2a5fSjoerg 		html_idcat(nbuf, sp, BUFSIZ);
14337bcc2a5fSjoerg 		PAIR_ID_INIT(&tag[1], nbuf);
14347bcc2a5fSjoerg 	} else {
14357bcc2a5fSjoerg 		strlcpy(nbuf, "#", BUFSIZ);
14367bcc2a5fSjoerg 		html_idcat(nbuf, sp, BUFSIZ);
14377bcc2a5fSjoerg 		PAIR_HREF_INIT(&tag[1], nbuf);
14387bcc2a5fSjoerg 	}
14397bcc2a5fSjoerg #endif
14407bcc2a5fSjoerg 
1441e4fbeb7eSjoerg 	t = print_otag(h, TAG_B, 1, tag);
14424154958bSjoerg 
14430511d63cSchristos 	if (sp)
14440511d63cSchristos 		print_text(h, sp);
14454154958bSjoerg 
14464154958bSjoerg 	print_tagq(h, t);
14474154958bSjoerg 
14484154958bSjoerg 	h->flags |= HTML_NOSPACE;
14494154958bSjoerg 	print_text(h, "(");
145054a4f7feSjoerg 	h->flags |= HTML_NOSPACE;
14514154958bSjoerg 
14524154958bSjoerg 	PAIR_CLASS_INIT(&tag[0], "farg");
1453f8126693Sjoerg 	bufinit(h);
14544154958bSjoerg 	bufcat_style(h, "white-space", "nowrap");
14554154958bSjoerg 	PAIR_STYLE_INIT(&tag[1], h);
14564154958bSjoerg 
145754a4f7feSjoerg 	for (n = n->child->next; n; n = n->next) {
14584154958bSjoerg 		i = 1;
145982361f10Sjoerg 		if (MDOC_SYNPRETTY & n->flags)
14604154958bSjoerg 			i = 2;
1461e4fbeb7eSjoerg 		t = print_otag(h, TAG_I, i, tag);
146254a4f7feSjoerg 		print_text(h, n->string);
14634154958bSjoerg 		print_tagq(h, t);
146454a4f7feSjoerg 		if (n->next) {
146554a4f7feSjoerg 			h->flags |= HTML_NOSPACE;
14664154958bSjoerg 			print_text(h, ",");
14674154958bSjoerg 		}
146854a4f7feSjoerg 	}
14694154958bSjoerg 
147054a4f7feSjoerg 	h->flags |= HTML_NOSPACE;
14714154958bSjoerg 	print_text(h, ")");
147254a4f7feSjoerg 
147354a4f7feSjoerg 	if (pretty) {
147454a4f7feSjoerg 		h->flags |= HTML_NOSPACE;
14754154958bSjoerg 		print_text(h, ";");
147654a4f7feSjoerg 	}
14774154958bSjoerg 
1478*47a17e0dSchristos 	return 0;
14794154958bSjoerg }
14804154958bSjoerg 
14814154958bSjoerg static int
14827da9b934Sjoerg mdoc_sm_pre(MDOC_ARGS)
14837da9b934Sjoerg {
14847da9b934Sjoerg 
14850511d63cSchristos 	if (NULL == n->child)
14860511d63cSchristos 		h->flags ^= HTML_NONOSPACE;
14870511d63cSchristos 	else if (0 == strcmp("on", n->child->string))
14887da9b934Sjoerg 		h->flags &= ~HTML_NONOSPACE;
14890511d63cSchristos 	else
14907da9b934Sjoerg 		h->flags |= HTML_NONOSPACE;
14917da9b934Sjoerg 
14920511d63cSchristos 	if ( ! (HTML_NONOSPACE & h->flags))
14930511d63cSchristos 		h->flags &= ~HTML_NOSPACE;
14940511d63cSchristos 
1495*47a17e0dSchristos 	return 0;
14967da9b934Sjoerg }
14977da9b934Sjoerg 
14980511d63cSchristos static int
14990511d63cSchristos mdoc_skip_pre(MDOC_ARGS)
15000511d63cSchristos {
15010511d63cSchristos 
1502*47a17e0dSchristos 	return 0;
15030511d63cSchristos }
15040511d63cSchristos 
1505e4fbeb7eSjoerg static int
1506e4fbeb7eSjoerg mdoc_pp_pre(MDOC_ARGS)
1507e4fbeb7eSjoerg {
1508e4fbeb7eSjoerg 
15090511d63cSchristos 	print_paragraph(h);
1510*47a17e0dSchristos 	return 0;
1511e4fbeb7eSjoerg }
15127da9b934Sjoerg 
15137da9b934Sjoerg static int
15144154958bSjoerg mdoc_sp_pre(MDOC_ARGS)
15154154958bSjoerg {
15164154958bSjoerg 	struct roffsu	 su;
1517e4fbeb7eSjoerg 	struct htmlpair	 tag;
15184154958bSjoerg 
1519e4fbeb7eSjoerg 	SCALE_VS_INIT(&su, 1);
15204154958bSjoerg 
1521e4fbeb7eSjoerg 	if (MDOC_sp == n->tok) {
15220511d63cSchristos 		if (NULL != (n = n->child)) {
1523f8126693Sjoerg 			if ( ! a2roffsu(n->string, &su, SCALE_VS))
15240511d63cSchristos 				su.scale = 1.0;
15250511d63cSchristos 			else if (su.scale < 0.0)
15260511d63cSchristos 				su.scale = 0.0;
15270511d63cSchristos 		}
1528e4fbeb7eSjoerg 	} else
15290511d63cSchristos 		su.scale = 0.0;
1530e4fbeb7eSjoerg 
1531f8126693Sjoerg 	bufinit(h);
15324154958bSjoerg 	bufcat_su(h, "height", &su);
15334154958bSjoerg 	PAIR_STYLE_INIT(&tag, h);
15344154958bSjoerg 	print_otag(h, TAG_DIV, 1, &tag);
1535e4fbeb7eSjoerg 
15363514411fSjoerg 	/* So the div isn't empty: */
15373514411fSjoerg 	print_text(h, "\\~");
15383514411fSjoerg 
1539*47a17e0dSchristos 	return 0;
15404154958bSjoerg 
15414154958bSjoerg }
15424154958bSjoerg 
15434154958bSjoerg static int
15444154958bSjoerg mdoc_lk_pre(MDOC_ARGS)
15454154958bSjoerg {
15464154958bSjoerg 	struct htmlpair	 tag[2];
15474154958bSjoerg 
154854a4f7feSjoerg 	if (NULL == (n = n->child))
1549*47a17e0dSchristos 		return 0;
155054a4f7feSjoerg 
1551*47a17e0dSchristos 	assert(n->type == ROFFT_TEXT);
15524154958bSjoerg 
15534154958bSjoerg 	PAIR_CLASS_INIT(&tag[0], "link-ext");
155454a4f7feSjoerg 	PAIR_HREF_INIT(&tag[1], n->string);
155554a4f7feSjoerg 
15564154958bSjoerg 	print_otag(h, TAG_A, 2, tag);
15574154958bSjoerg 
1558f8126693Sjoerg 	if (NULL == n->next)
155954a4f7feSjoerg 		print_text(h, n->string);
1560f8126693Sjoerg 
1561f8126693Sjoerg 	for (n = n->next; n; n = n->next)
1562f8126693Sjoerg 		print_text(h, n->string);
15634154958bSjoerg 
1564*47a17e0dSchristos 	return 0;
15654154958bSjoerg }
15664154958bSjoerg 
15674154958bSjoerg static int
15684154958bSjoerg mdoc_mt_pre(MDOC_ARGS)
15694154958bSjoerg {
15704154958bSjoerg 	struct htmlpair	 tag[2];
15714154958bSjoerg 	struct tag	*t;
15724154958bSjoerg 
15734154958bSjoerg 	PAIR_CLASS_INIT(&tag[0], "link-mail");
15744154958bSjoerg 
157554a4f7feSjoerg 	for (n = n->child; n; n = n->next) {
1576*47a17e0dSchristos 		assert(n->type == ROFFT_TEXT);
157754a4f7feSjoerg 
15784154958bSjoerg 		bufinit(h);
15794154958bSjoerg 		bufcat(h, "mailto:");
158054a4f7feSjoerg 		bufcat(h, n->string);
158154a4f7feSjoerg 
15827bcc2a5fSjoerg 		PAIR_HREF_INIT(&tag[1], h->buf);
15834154958bSjoerg 		t = print_otag(h, TAG_A, 2, tag);
158454a4f7feSjoerg 		print_text(h, n->string);
15854154958bSjoerg 		print_tagq(h, t);
15864154958bSjoerg 	}
15874154958bSjoerg 
1588*47a17e0dSchristos 	return 0;
15894154958bSjoerg }
15904154958bSjoerg 
15914154958bSjoerg static int
15924154958bSjoerg mdoc_fo_pre(MDOC_ARGS)
15934154958bSjoerg {
15944154958bSjoerg 	struct htmlpair	 tag;
15957574e07eSjoerg 	struct tag	*t;
15964154958bSjoerg 
1597*47a17e0dSchristos 	if (n->type == ROFFT_BODY) {
15984154958bSjoerg 		h->flags |= HTML_NOSPACE;
15994154958bSjoerg 		print_text(h, "(");
16004154958bSjoerg 		h->flags |= HTML_NOSPACE;
1601*47a17e0dSchristos 		return 1;
1602*47a17e0dSchristos 	} else if (n->type == ROFFT_BLOCK) {
16037574e07eSjoerg 		synopsis_pre(h, n);
1604*47a17e0dSchristos 		return 1;
16057bcc2a5fSjoerg 	}
16064154958bSjoerg 
1607*47a17e0dSchristos 	if (n->child == NULL)
1608*47a17e0dSchristos 		return 0;
16097574e07eSjoerg 
16107574e07eSjoerg 	assert(n->child->string);
16114154958bSjoerg 	PAIR_CLASS_INIT(&tag, "fname");
1612e4fbeb7eSjoerg 	t = print_otag(h, TAG_B, 1, &tag);
16137574e07eSjoerg 	print_text(h, n->child->string);
16147574e07eSjoerg 	print_tagq(h, t);
1615*47a17e0dSchristos 	return 0;
16164154958bSjoerg }
16174154958bSjoerg 
16184154958bSjoerg static void
16194154958bSjoerg mdoc_fo_post(MDOC_ARGS)
16204154958bSjoerg {
16217574e07eSjoerg 
1622*47a17e0dSchristos 	if (n->type != ROFFT_BODY)
16234154958bSjoerg 		return;
162454a4f7feSjoerg 	h->flags |= HTML_NOSPACE;
16254154958bSjoerg 	print_text(h, ")");
162654a4f7feSjoerg 	h->flags |= HTML_NOSPACE;
16274154958bSjoerg 	print_text(h, ";");
16284154958bSjoerg }
16294154958bSjoerg 
16304154958bSjoerg static int
16314154958bSjoerg mdoc_in_pre(MDOC_ARGS)
16324154958bSjoerg {
16334154958bSjoerg 	struct tag	*t;
16344154958bSjoerg 	struct htmlpair	 tag[2];
16354154958bSjoerg 	int		 i;
16364154958bSjoerg 
16377574e07eSjoerg 	synopsis_pre(h, n);
16384154958bSjoerg 
16394154958bSjoerg 	PAIR_CLASS_INIT(&tag[0], "includes");
1640e4fbeb7eSjoerg 	print_otag(h, TAG_B, 1, tag);
16414154958bSjoerg 
164254a4f7feSjoerg 	/*
164354a4f7feSjoerg 	 * The first argument of the `In' gets special treatment as
164454a4f7feSjoerg 	 * being a linked value.  Subsequent values are printed
164554a4f7feSjoerg 	 * afterward.  groff does similarly.  This also handles the case
164654a4f7feSjoerg 	 * of no children.
164754a4f7feSjoerg 	 */
164854a4f7feSjoerg 
164982361f10Sjoerg 	if (MDOC_SYNPRETTY & n->flags && MDOC_LINE & n->flags)
16504154958bSjoerg 		print_text(h, "#include");
16514154958bSjoerg 
16524154958bSjoerg 	print_text(h, "<");
16534154958bSjoerg 	h->flags |= HTML_NOSPACE;
16544154958bSjoerg 
165554a4f7feSjoerg 	if (NULL != (n = n->child)) {
1656*47a17e0dSchristos 		assert(n->type == ROFFT_TEXT);
165754a4f7feSjoerg 
16584154958bSjoerg 		PAIR_CLASS_INIT(&tag[0], "link-includes");
165954a4f7feSjoerg 
166054a4f7feSjoerg 		i = 1;
16614154958bSjoerg 		if (h->base_includes) {
166254a4f7feSjoerg 			buffmt_includes(h, n->string);
16637bcc2a5fSjoerg 			PAIR_HREF_INIT(&tag[i], h->buf);
16647bcc2a5fSjoerg 			i++;
16654154958bSjoerg 		}
166654a4f7feSjoerg 
16674154958bSjoerg 		t = print_otag(h, TAG_A, i, tag);
166854a4f7feSjoerg 		print_text(h, n->string);
16694154958bSjoerg 		print_tagq(h, t);
167054a4f7feSjoerg 
167154a4f7feSjoerg 		n = n->next;
16724154958bSjoerg 	}
16734154958bSjoerg 
16744154958bSjoerg 	h->flags |= HTML_NOSPACE;
16754154958bSjoerg 	print_text(h, ">");
16764154958bSjoerg 
167754a4f7feSjoerg 	for ( ; n; n = n->next) {
1678*47a17e0dSchristos 		assert(n->type == ROFFT_TEXT);
167954a4f7feSjoerg 		print_text(h, n->string);
168054a4f7feSjoerg 	}
168154a4f7feSjoerg 
1682*47a17e0dSchristos 	return 0;
16834154958bSjoerg }
16844154958bSjoerg 
16854154958bSjoerg static int
16864154958bSjoerg mdoc_ic_pre(MDOC_ARGS)
16874154958bSjoerg {
16884154958bSjoerg 	struct htmlpair	tag;
16894154958bSjoerg 
16904154958bSjoerg 	PAIR_CLASS_INIT(&tag, "cmd");
1691e4fbeb7eSjoerg 	print_otag(h, TAG_B, 1, &tag);
1692*47a17e0dSchristos 	return 1;
16934154958bSjoerg }
16944154958bSjoerg 
16954154958bSjoerg static int
16964154958bSjoerg mdoc_rv_pre(MDOC_ARGS)
16974154958bSjoerg {
16984154958bSjoerg 	struct htmlpair	 tag;
16994154958bSjoerg 	struct tag	*t;
1700*47a17e0dSchristos 	struct roff_node *nch;
17014154958bSjoerg 
1702e4fbeb7eSjoerg 	if (n->prev)
1703e4fbeb7eSjoerg 		print_otag(h, TAG_BR, 0, NULL);
1704e4fbeb7eSjoerg 
170554a4f7feSjoerg 	PAIR_CLASS_INIT(&tag, "fname");
170654a4f7feSjoerg 
1707*47a17e0dSchristos 	if (n->child != NULL) {
17084154958bSjoerg 		print_text(h, "The");
17094154958bSjoerg 
1710*47a17e0dSchristos 		for (nch = n->child; nch != NULL; nch = nch->next) {
1711e4fbeb7eSjoerg 			t = print_otag(h, TAG_B, 1, &tag);
1712*47a17e0dSchristos 			print_text(h, nch->string);
17134154958bSjoerg 			print_tagq(h, t);
17144154958bSjoerg 
17154154958bSjoerg 			h->flags |= HTML_NOSPACE;
17164154958bSjoerg 			print_text(h, "()");
171754a4f7feSjoerg 
1718*47a17e0dSchristos 			if (nch->next == NULL)
17190511d63cSchristos 				continue;
17200511d63cSchristos 
1721*47a17e0dSchristos 			if (nch->prev != NULL || nch->next->next != NULL) {
172254a4f7feSjoerg 				h->flags |= HTML_NOSPACE;
172354a4f7feSjoerg 				print_text(h, ",");
17244154958bSjoerg 			}
1725*47a17e0dSchristos 			if (nch->next->next == NULL)
172654a4f7feSjoerg 				print_text(h, "and");
172754a4f7feSjoerg 		}
172854a4f7feSjoerg 
1729*47a17e0dSchristos 		if (n->child != NULL && n->child->next != NULL)
17304154958bSjoerg 			print_text(h, "functions return");
17314154958bSjoerg 		else
17324154958bSjoerg 			print_text(h, "function returns");
17334154958bSjoerg 
17340511d63cSchristos 		print_text(h, "the value\\~0 if successful;");
17350511d63cSchristos 	} else
17360511d63cSchristos 		print_text(h, "Upon successful completion,"
17370511d63cSchristos                     " the value\\~0 is returned;");
17380511d63cSchristos 
17390511d63cSchristos 	print_text(h, "otherwise the value\\~\\-1 is returned"
17400511d63cSchristos 	   " and the global variable");
17414154958bSjoerg 
17424154958bSjoerg 	PAIR_CLASS_INIT(&tag, "var");
1743e4fbeb7eSjoerg 	t = print_otag(h, TAG_B, 1, &tag);
17444154958bSjoerg 	print_text(h, "errno");
17454154958bSjoerg 	print_tagq(h, t);
17464154958bSjoerg 	print_text(h, "is set to indicate the error.");
1747*47a17e0dSchristos 	return 0;
17484154958bSjoerg }
17494154958bSjoerg 
17504154958bSjoerg static int
17514154958bSjoerg mdoc_va_pre(MDOC_ARGS)
17524154958bSjoerg {
17534154958bSjoerg 	struct htmlpair	tag;
17544154958bSjoerg 
17554154958bSjoerg 	PAIR_CLASS_INIT(&tag, "var");
1756e4fbeb7eSjoerg 	print_otag(h, TAG_B, 1, &tag);
1757*47a17e0dSchristos 	return 1;
17584154958bSjoerg }
17594154958bSjoerg 
17604154958bSjoerg static int
17614154958bSjoerg mdoc_ap_pre(MDOC_ARGS)
17624154958bSjoerg {
17634154958bSjoerg 
17644154958bSjoerg 	h->flags |= HTML_NOSPACE;
17654154958bSjoerg 	print_text(h, "\\(aq");
17664154958bSjoerg 	h->flags |= HTML_NOSPACE;
1767*47a17e0dSchristos 	return 1;
17684154958bSjoerg }
17694154958bSjoerg 
17704154958bSjoerg static int
17714154958bSjoerg mdoc_bf_pre(MDOC_ARGS)
17724154958bSjoerg {
17734154958bSjoerg 	struct htmlpair	 tag[2];
17744154958bSjoerg 	struct roffsu	 su;
17754154958bSjoerg 
1776*47a17e0dSchristos 	if (n->type == ROFFT_HEAD)
1777*47a17e0dSchristos 		return 0;
1778*47a17e0dSchristos 	else if (n->type != ROFFT_BODY)
1779*47a17e0dSchristos 		return 1;
17804154958bSjoerg 
1781e4fbeb7eSjoerg 	if (FONT_Em == n->norm->Bf.font)
17824154958bSjoerg 		PAIR_CLASS_INIT(&tag[0], "emph");
1783e4fbeb7eSjoerg 	else if (FONT_Sy == n->norm->Bf.font)
17844154958bSjoerg 		PAIR_CLASS_INIT(&tag[0], "symb");
1785e4fbeb7eSjoerg 	else if (FONT_Li == n->norm->Bf.font)
17864154958bSjoerg 		PAIR_CLASS_INIT(&tag[0], "lit");
178782361f10Sjoerg 	else
178882361f10Sjoerg 		PAIR_CLASS_INIT(&tag[0], "none");
17894154958bSjoerg 
179082361f10Sjoerg 	/*
179182361f10Sjoerg 	 * We want this to be inline-formatted, but needs to be div to
179282361f10Sjoerg 	 * accept block children.
179382361f10Sjoerg 	 */
1794f8126693Sjoerg 	bufinit(h);
17954154958bSjoerg 	bufcat_style(h, "display", "inline");
17964154958bSjoerg 	SCALE_HS_INIT(&su, 1);
179782361f10Sjoerg 	/* Needs a left-margin for spacing. */
179882361f10Sjoerg 	bufcat_su(h, "margin-left", &su);
17994154958bSjoerg 	PAIR_STYLE_INIT(&tag[1], h);
18004154958bSjoerg 	print_otag(h, TAG_DIV, 2, tag);
1801*47a17e0dSchristos 	return 1;
18024154958bSjoerg }
18034154958bSjoerg 
18044154958bSjoerg static int
18054154958bSjoerg mdoc_ms_pre(MDOC_ARGS)
18064154958bSjoerg {
18074154958bSjoerg 	struct htmlpair	tag;
18084154958bSjoerg 
18094154958bSjoerg 	PAIR_CLASS_INIT(&tag, "symb");
18104154958bSjoerg 	print_otag(h, TAG_SPAN, 1, &tag);
1811*47a17e0dSchristos 	return 1;
18124154958bSjoerg }
18134154958bSjoerg 
18144154958bSjoerg static int
1815e4fbeb7eSjoerg mdoc_igndelim_pre(MDOC_ARGS)
18164154958bSjoerg {
18174154958bSjoerg 
18184154958bSjoerg 	h->flags |= HTML_IGNDELIM;
1819*47a17e0dSchristos 	return 1;
18204154958bSjoerg }
18214154958bSjoerg 
18224154958bSjoerg static void
18234154958bSjoerg mdoc_pf_post(MDOC_ARGS)
18244154958bSjoerg {
18254154958bSjoerg 
18260511d63cSchristos 	if ( ! (n->next == NULL || n->next->flags & MDOC_LINE))
18274154958bSjoerg 		h->flags |= HTML_NOSPACE;
18284154958bSjoerg }
18294154958bSjoerg 
18304154958bSjoerg static int
18314154958bSjoerg mdoc_rs_pre(MDOC_ARGS)
18324154958bSjoerg {
18334154958bSjoerg 	struct htmlpair	 tag;
18344154958bSjoerg 
1835*47a17e0dSchristos 	if (n->type != ROFFT_BLOCK)
1836*47a17e0dSchristos 		return 1;
18374154958bSjoerg 
1838e4fbeb7eSjoerg 	if (n->prev && SEC_SEE_ALSO == n->sec)
18390511d63cSchristos 		print_paragraph(h);
18404154958bSjoerg 
18414154958bSjoerg 	PAIR_CLASS_INIT(&tag, "ref");
18424154958bSjoerg 	print_otag(h, TAG_SPAN, 1, &tag);
1843*47a17e0dSchristos 	return 1;
18444154958bSjoerg }
18454154958bSjoerg 
18460511d63cSchristos static int
18470511d63cSchristos mdoc_no_pre(MDOC_ARGS)
18480511d63cSchristos {
18490511d63cSchristos 	struct htmlpair	tag;
18504154958bSjoerg 
18510511d63cSchristos 	PAIR_CLASS_INIT(&tag, "none");
18520511d63cSchristos 	print_otag(h, TAG_CODE, 1, &tag);
1853*47a17e0dSchristos 	return 1;
18540511d63cSchristos }
18554154958bSjoerg 
18564154958bSjoerg static int
18574154958bSjoerg mdoc_li_pre(MDOC_ARGS)
18584154958bSjoerg {
18594154958bSjoerg 	struct htmlpair	tag;
18604154958bSjoerg 
18614154958bSjoerg 	PAIR_CLASS_INIT(&tag, "lit");
1862f8126693Sjoerg 	print_otag(h, TAG_CODE, 1, &tag);
1863*47a17e0dSchristos 	return 1;
18644154958bSjoerg }
18654154958bSjoerg 
18664154958bSjoerg static int
18674154958bSjoerg mdoc_sy_pre(MDOC_ARGS)
18684154958bSjoerg {
18694154958bSjoerg 	struct htmlpair	tag;
18704154958bSjoerg 
18714154958bSjoerg 	PAIR_CLASS_INIT(&tag, "symb");
18724154958bSjoerg 	print_otag(h, TAG_SPAN, 1, &tag);
1873*47a17e0dSchristos 	return 1;
18744154958bSjoerg }
18754154958bSjoerg 
18764154958bSjoerg static int
18774154958bSjoerg mdoc_bt_pre(MDOC_ARGS)
18784154958bSjoerg {
18794154958bSjoerg 
18804154958bSjoerg 	print_text(h, "is currently in beta test.");
1881*47a17e0dSchristos 	return 0;
18824154958bSjoerg }
18834154958bSjoerg 
18844154958bSjoerg static int
18854154958bSjoerg mdoc_ud_pre(MDOC_ARGS)
18864154958bSjoerg {
18874154958bSjoerg 
18884154958bSjoerg 	print_text(h, "currently under development.");
1889*47a17e0dSchristos 	return 0;
18904154958bSjoerg }
18914154958bSjoerg 
18924154958bSjoerg static int
18934154958bSjoerg mdoc_lb_pre(MDOC_ARGS)
18944154958bSjoerg {
18954154958bSjoerg 	struct htmlpair	tag;
18964154958bSjoerg 
1897e4fbeb7eSjoerg 	if (SEC_LIBRARY == n->sec && MDOC_LINE & n->flags && n->prev)
1898e4fbeb7eSjoerg 		print_otag(h, TAG_BR, 0, NULL);
1899e4fbeb7eSjoerg 
19004154958bSjoerg 	PAIR_CLASS_INIT(&tag, "lib");
19014154958bSjoerg 	print_otag(h, TAG_SPAN, 1, &tag);
1902*47a17e0dSchristos 	return 1;
19034154958bSjoerg }
19044154958bSjoerg 
19054154958bSjoerg static int
19064154958bSjoerg mdoc__x_pre(MDOC_ARGS)
19074154958bSjoerg {
190822af4063Sjoerg 	struct htmlpair	tag[2];
1909e4fbeb7eSjoerg 	enum htmltag	t;
1910e4fbeb7eSjoerg 
1911e4fbeb7eSjoerg 	t = TAG_SPAN;
19124154958bSjoerg 
19134154958bSjoerg 	switch (n->tok) {
19140511d63cSchristos 	case MDOC__A:
191522af4063Sjoerg 		PAIR_CLASS_INIT(&tag[0], "ref-auth");
1916e4fbeb7eSjoerg 		if (n->prev && MDOC__A == n->prev->tok)
1917e4fbeb7eSjoerg 			if (NULL == n->next || MDOC__A != n->next->tok)
1918e4fbeb7eSjoerg 				print_text(h, "and");
19194154958bSjoerg 		break;
19200511d63cSchristos 	case MDOC__B:
192122af4063Sjoerg 		PAIR_CLASS_INIT(&tag[0], "ref-book");
1922e4fbeb7eSjoerg 		t = TAG_I;
19234154958bSjoerg 		break;
19240511d63cSchristos 	case MDOC__C:
192522af4063Sjoerg 		PAIR_CLASS_INIT(&tag[0], "ref-city");
19264154958bSjoerg 		break;
19270511d63cSchristos 	case MDOC__D:
192822af4063Sjoerg 		PAIR_CLASS_INIT(&tag[0], "ref-date");
19294154958bSjoerg 		break;
19300511d63cSchristos 	case MDOC__I:
193122af4063Sjoerg 		PAIR_CLASS_INIT(&tag[0], "ref-issue");
1932e4fbeb7eSjoerg 		t = TAG_I;
19334154958bSjoerg 		break;
19340511d63cSchristos 	case MDOC__J:
193522af4063Sjoerg 		PAIR_CLASS_INIT(&tag[0], "ref-jrnl");
1936e4fbeb7eSjoerg 		t = TAG_I;
19374154958bSjoerg 		break;
19380511d63cSchristos 	case MDOC__N:
193922af4063Sjoerg 		PAIR_CLASS_INIT(&tag[0], "ref-num");
19404154958bSjoerg 		break;
19410511d63cSchristos 	case MDOC__O:
194222af4063Sjoerg 		PAIR_CLASS_INIT(&tag[0], "ref-opt");
19434154958bSjoerg 		break;
19440511d63cSchristos 	case MDOC__P:
194522af4063Sjoerg 		PAIR_CLASS_INIT(&tag[0], "ref-page");
19464154958bSjoerg 		break;
19470511d63cSchristos 	case MDOC__Q:
194822af4063Sjoerg 		PAIR_CLASS_INIT(&tag[0], "ref-corp");
19494154958bSjoerg 		break;
19500511d63cSchristos 	case MDOC__R:
195122af4063Sjoerg 		PAIR_CLASS_INIT(&tag[0], "ref-rep");
19524154958bSjoerg 		break;
19530511d63cSchristos 	case MDOC__T:
195422af4063Sjoerg 		PAIR_CLASS_INIT(&tag[0], "ref-title");
19554154958bSjoerg 		break;
19560511d63cSchristos 	case MDOC__U:
195722af4063Sjoerg 		PAIR_CLASS_INIT(&tag[0], "link-ref");
195822af4063Sjoerg 		break;
19590511d63cSchristos 	case MDOC__V:
196022af4063Sjoerg 		PAIR_CLASS_INIT(&tag[0], "ref-vol");
19614154958bSjoerg 		break;
19624154958bSjoerg 	default:
19634154958bSjoerg 		abort();
19644154958bSjoerg 	}
19654154958bSjoerg 
196622af4063Sjoerg 	if (MDOC__U != n->tok) {
1967e4fbeb7eSjoerg 		print_otag(h, t, 1, tag);
1968*47a17e0dSchristos 		return 1;
196922af4063Sjoerg 	}
197022af4063Sjoerg 
197122af4063Sjoerg 	PAIR_HREF_INIT(&tag[1], n->child->string);
197222af4063Sjoerg 	print_otag(h, TAG_A, 2, tag);
1973e4fbeb7eSjoerg 
1974*47a17e0dSchristos 	return 1;
19754154958bSjoerg }
19764154958bSjoerg 
19774154958bSjoerg static void
19784154958bSjoerg mdoc__x_post(MDOC_ARGS)
19794154958bSjoerg {
19804154958bSjoerg 
1981e4fbeb7eSjoerg 	if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok)
1982e4fbeb7eSjoerg 		if (NULL == n->next->next || MDOC__A != n->next->next->tok)
1983e4fbeb7eSjoerg 			if (NULL == n->prev || MDOC__A != n->prev->tok)
1984e4fbeb7eSjoerg 				return;
1985e4fbeb7eSjoerg 
19860a84adc5Sjoerg 	/* TODO: %U */
19870a84adc5Sjoerg 
1988e4fbeb7eSjoerg 	if (NULL == n->parent || MDOC_Rs != n->parent->tok)
1989e4fbeb7eSjoerg 		return;
1990e4fbeb7eSjoerg 
199154a4f7feSjoerg 	h->flags |= HTML_NOSPACE;
19924154958bSjoerg 	print_text(h, n->next ? "," : ".");
19934154958bSjoerg }
199482361f10Sjoerg 
199582361f10Sjoerg static int
199682361f10Sjoerg mdoc_bk_pre(MDOC_ARGS)
199782361f10Sjoerg {
199882361f10Sjoerg 
199982361f10Sjoerg 	switch (n->type) {
2000*47a17e0dSchristos 	case ROFFT_BLOCK:
200182361f10Sjoerg 		break;
2002*47a17e0dSchristos 	case ROFFT_HEAD:
2003*47a17e0dSchristos 		return 0;
2004*47a17e0dSchristos 	case ROFFT_BODY:
2005*47a17e0dSchristos 		if (n->parent->args != NULL || n->prev->child == NULL)
200682361f10Sjoerg 			h->flags |= HTML_PREKEEP;
200782361f10Sjoerg 		break;
200882361f10Sjoerg 	default:
200982361f10Sjoerg 		abort();
201082361f10Sjoerg 	}
201182361f10Sjoerg 
2012*47a17e0dSchristos 	return 1;
201382361f10Sjoerg }
201482361f10Sjoerg 
201582361f10Sjoerg static void
201682361f10Sjoerg mdoc_bk_post(MDOC_ARGS)
201782361f10Sjoerg {
201882361f10Sjoerg 
2019*47a17e0dSchristos 	if (n->type == ROFFT_BODY)
202082361f10Sjoerg 		h->flags &= ~(HTML_KEEP | HTML_PREKEEP);
202182361f10Sjoerg }
2022e4fbeb7eSjoerg 
2023e4fbeb7eSjoerg static int
2024e4fbeb7eSjoerg mdoc_quote_pre(MDOC_ARGS)
2025e4fbeb7eSjoerg {
2026e4fbeb7eSjoerg 	struct htmlpair	tag;
2027e4fbeb7eSjoerg 
2028*47a17e0dSchristos 	if (n->type != ROFFT_BODY)
2029*47a17e0dSchristos 		return 1;
2030e4fbeb7eSjoerg 
2031e4fbeb7eSjoerg 	switch (n->tok) {
20320511d63cSchristos 	case MDOC_Ao:
20330511d63cSchristos 	case MDOC_Aq:
2034*47a17e0dSchristos 		print_text(h, n->child != NULL && n->child->next == NULL &&
20350511d63cSchristos 		    n->child->tok == MDOC_Mt ?  "<" : "\\(la");
2036e4fbeb7eSjoerg 		break;
20370511d63cSchristos 	case MDOC_Bro:
20380511d63cSchristos 	case MDOC_Brq:
2039e4fbeb7eSjoerg 		print_text(h, "\\(lC");
2040e4fbeb7eSjoerg 		break;
20410511d63cSchristos 	case MDOC_Bo:
20420511d63cSchristos 	case MDOC_Bq:
2043e4fbeb7eSjoerg 		print_text(h, "\\(lB");
2044e4fbeb7eSjoerg 		break;
20450511d63cSchristos 	case MDOC_Oo:
20460511d63cSchristos 	case MDOC_Op:
2047e4fbeb7eSjoerg 		print_text(h, "\\(lB");
2048e4fbeb7eSjoerg 		h->flags |= HTML_NOSPACE;
2049e4fbeb7eSjoerg 		PAIR_CLASS_INIT(&tag, "opt");
2050e4fbeb7eSjoerg 		print_otag(h, TAG_SPAN, 1, &tag);
2051e4fbeb7eSjoerg 		break;
20520511d63cSchristos 	case MDOC_En:
20530511d63cSchristos 		if (NULL == n->norm->Es ||
20540511d63cSchristos 		    NULL == n->norm->Es->child)
2055*47a17e0dSchristos 			return 1;
20560511d63cSchristos 		print_text(h, n->norm->Es->child->string);
2057e7fe1698Sjoerg 		break;
20580511d63cSchristos 	case MDOC_Do:
20590511d63cSchristos 	case MDOC_Dq:
20600511d63cSchristos 	case MDOC_Qo:
20610511d63cSchristos 	case MDOC_Qq:
2062e4fbeb7eSjoerg 		print_text(h, "\\(lq");
2063e4fbeb7eSjoerg 		break;
20640511d63cSchristos 	case MDOC_Po:
20650511d63cSchristos 	case MDOC_Pq:
2066e4fbeb7eSjoerg 		print_text(h, "(");
2067e4fbeb7eSjoerg 		break;
20680511d63cSchristos 	case MDOC_Ql:
2069f8126693Sjoerg 		print_text(h, "\\(oq");
2070f8126693Sjoerg 		h->flags |= HTML_NOSPACE;
2071f8126693Sjoerg 		PAIR_CLASS_INIT(&tag, "lit");
2072f8126693Sjoerg 		print_otag(h, TAG_CODE, 1, &tag);
2073f8126693Sjoerg 		break;
20740511d63cSchristos 	case MDOC_So:
20750511d63cSchristos 	case MDOC_Sq:
2076e4fbeb7eSjoerg 		print_text(h, "\\(oq");
2077e4fbeb7eSjoerg 		break;
2078e4fbeb7eSjoerg 	default:
2079e4fbeb7eSjoerg 		abort();
2080e4fbeb7eSjoerg 	}
2081e4fbeb7eSjoerg 
2082e4fbeb7eSjoerg 	h->flags |= HTML_NOSPACE;
2083*47a17e0dSchristos 	return 1;
2084e4fbeb7eSjoerg }
2085e4fbeb7eSjoerg 
2086e4fbeb7eSjoerg static void
2087e4fbeb7eSjoerg mdoc_quote_post(MDOC_ARGS)
2088e4fbeb7eSjoerg {
2089e4fbeb7eSjoerg 
2090*47a17e0dSchristos 	if (n->type != ROFFT_BODY && n->type != ROFFT_ELEM)
2091e4fbeb7eSjoerg 		return;
2092e4fbeb7eSjoerg 
2093e4fbeb7eSjoerg 	h->flags |= HTML_NOSPACE;
2094e4fbeb7eSjoerg 
2095e4fbeb7eSjoerg 	switch (n->tok) {
20960511d63cSchristos 	case MDOC_Ao:
20970511d63cSchristos 	case MDOC_Aq:
2098*47a17e0dSchristos 		print_text(h, n->child != NULL && n->child->next == NULL &&
20990511d63cSchristos 		    n->child->tok == MDOC_Mt ?  ">" : "\\(ra");
2100e4fbeb7eSjoerg 		break;
21010511d63cSchristos 	case MDOC_Bro:
21020511d63cSchristos 	case MDOC_Brq:
2103e4fbeb7eSjoerg 		print_text(h, "\\(rC");
2104e4fbeb7eSjoerg 		break;
21050511d63cSchristos 	case MDOC_Oo:
21060511d63cSchristos 	case MDOC_Op:
21070511d63cSchristos 	case MDOC_Bo:
21080511d63cSchristos 	case MDOC_Bq:
2109e4fbeb7eSjoerg 		print_text(h, "\\(rB");
2110e4fbeb7eSjoerg 		break;
21110511d63cSchristos 	case MDOC_En:
21120511d63cSchristos 		if (n->norm->Es == NULL ||
21130511d63cSchristos 		    n->norm->Es->child == NULL ||
21140511d63cSchristos 		    n->norm->Es->child->next == NULL)
21150511d63cSchristos 			h->flags &= ~HTML_NOSPACE;
21160511d63cSchristos 		else
21170511d63cSchristos 			print_text(h, n->norm->Es->child->next->string);
2118e7fe1698Sjoerg 		break;
21190511d63cSchristos 	case MDOC_Qo:
21200511d63cSchristos 	case MDOC_Qq:
21210511d63cSchristos 	case MDOC_Do:
21220511d63cSchristos 	case MDOC_Dq:
2123e4fbeb7eSjoerg 		print_text(h, "\\(rq");
2124e4fbeb7eSjoerg 		break;
21250511d63cSchristos 	case MDOC_Po:
21260511d63cSchristos 	case MDOC_Pq:
2127e4fbeb7eSjoerg 		print_text(h, ")");
2128e4fbeb7eSjoerg 		break;
21290511d63cSchristos 	case MDOC_Ql:
21300511d63cSchristos 	case MDOC_So:
21310511d63cSchristos 	case MDOC_Sq:
2132ed7c7912Sjoerg 		print_text(h, "\\(cq");
2133e4fbeb7eSjoerg 		break;
2134e4fbeb7eSjoerg 	default:
2135e4fbeb7eSjoerg 		abort();
2136e4fbeb7eSjoerg 	}
2137e4fbeb7eSjoerg }
2138e4fbeb7eSjoerg 
21390511d63cSchristos static int
21400511d63cSchristos mdoc_eo_pre(MDOC_ARGS)
21410511d63cSchristos {
2142e4fbeb7eSjoerg 
2143*47a17e0dSchristos 	if (n->type != ROFFT_BODY)
2144*47a17e0dSchristos 		return 1;
21450511d63cSchristos 
21460511d63cSchristos 	if (n->end == ENDBODY_NOT &&
21470511d63cSchristos 	    n->parent->head->child == NULL &&
21480511d63cSchristos 	    n->child != NULL &&
21490511d63cSchristos 	    n->child->end != ENDBODY_NOT)
21500511d63cSchristos 		print_text(h, "\\&");
21510511d63cSchristos 	else if (n->end != ENDBODY_NOT ? n->child != NULL :
21520511d63cSchristos 	    n->parent->head->child != NULL && (n->child != NULL ||
21530511d63cSchristos 	    (n->parent->tail != NULL && n->parent->tail->child != NULL)))
21540511d63cSchristos 		h->flags |= HTML_NOSPACE;
2155*47a17e0dSchristos 	return 1;
21560511d63cSchristos }
21570511d63cSchristos 
21580511d63cSchristos static void
21590511d63cSchristos mdoc_eo_post(MDOC_ARGS)
21600511d63cSchristos {
21610511d63cSchristos 	int	 body, tail;
21620511d63cSchristos 
2163*47a17e0dSchristos 	if (n->type != ROFFT_BODY)
21640511d63cSchristos 		return;
21650511d63cSchristos 
21660511d63cSchristos 	if (n->end != ENDBODY_NOT) {
21670511d63cSchristos 		h->flags &= ~HTML_NOSPACE;
21680511d63cSchristos 		return;
21690511d63cSchristos 	}
21700511d63cSchristos 
21710511d63cSchristos 	body = n->child != NULL || n->parent->head->child != NULL;
21720511d63cSchristos 	tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
21730511d63cSchristos 
21740511d63cSchristos 	if (body && tail)
21750511d63cSchristos 		h->flags |= HTML_NOSPACE;
21760511d63cSchristos 	else if ( ! tail)
21770511d63cSchristos 		h->flags &= ~HTML_NOSPACE;
21780511d63cSchristos }
2179