xref: /dflybsd-src/contrib/mdocml/mdoc_html.c (revision 1e4d43f9c96723e4e55543d240f182e1aac9a4c2)
1*99db7d0eSSascha Wildner /* $Id: mdoc_html.c,v 1.342 2021/03/30 19:26:20 schwarze Exp $ */
280387638SSascha Wildner /*
3*99db7d0eSSascha Wildner  * Copyright (c) 2014-2021 Ingo Schwarze <schwarze@openbsd.org>
454ba9607SSascha Wildner  * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
580387638SSascha Wildner  *
680387638SSascha Wildner  * Permission to use, copy, modify, and distribute this software for any
780387638SSascha Wildner  * purpose with or without fee is hereby granted, provided that the above
880387638SSascha Wildner  * copyright notice and this permission notice appear in all copies.
980387638SSascha Wildner  *
1054ba9607SSascha Wildner  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
1180387638SSascha Wildner  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1254ba9607SSascha Wildner  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
1380387638SSascha Wildner  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1480387638SSascha Wildner  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1580387638SSascha Wildner  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1680387638SSascha Wildner  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*99db7d0eSSascha Wildner  *
18*99db7d0eSSascha Wildner  * HTML formatter for mdoc(7) used by mandoc(1).
1980387638SSascha Wildner  */
2080387638SSascha Wildner #include "config.h"
2180387638SSascha Wildner 
2280387638SSascha Wildner #include <sys/types.h>
2380387638SSascha Wildner 
2480387638SSascha Wildner #include <assert.h>
2580387638SSascha Wildner #include <ctype.h>
2680387638SSascha Wildner #include <stdio.h>
2780387638SSascha Wildner #include <stdlib.h>
2880387638SSascha Wildner #include <string.h>
2980387638SSascha Wildner #include <unistd.h>
3080387638SSascha Wildner 
31070c62a6SFranco Fichtner #include "mandoc_aux.h"
3254ba9607SSascha Wildner #include "mandoc.h"
3354ba9607SSascha Wildner #include "roff.h"
3454ba9607SSascha Wildner #include "mdoc.h"
3580387638SSascha Wildner #include "out.h"
3680387638SSascha Wildner #include "html.h"
3780387638SSascha Wildner #include "main.h"
3880387638SSascha Wildner 
3954ba9607SSascha Wildner #define	MDOC_ARGS	  const struct roff_meta *meta, \
4054ba9607SSascha Wildner 			  struct roff_node *n, \
4180387638SSascha Wildner 			  struct html *h
4280387638SSascha Wildner 
4380387638SSascha Wildner #ifndef MIN
4480387638SSascha Wildner #define	MIN(a,b)	((/*CONSTCOND*/(a)<(b))?(a):(b))
4580387638SSascha Wildner #endif
4680387638SSascha Wildner 
4754ba9607SSascha Wildner struct	mdoc_html_act {
4880387638SSascha Wildner 	int		(*pre)(MDOC_ARGS);
4980387638SSascha Wildner 	void		(*post)(MDOC_ARGS);
5080387638SSascha Wildner };
5180387638SSascha Wildner 
5254ba9607SSascha Wildner static	void		  print_mdoc_head(const struct roff_meta *,
5354ba9607SSascha Wildner 				struct html *);
5480387638SSascha Wildner static	void		  print_mdoc_node(MDOC_ARGS);
5580387638SSascha Wildner static	void		  print_mdoc_nodelist(MDOC_ARGS);
56*99db7d0eSSascha Wildner static	void		  synopsis_pre(struct html *, struct roff_node *);
5780387638SSascha Wildner 
5854ba9607SSascha Wildner static	void		  mdoc_root_post(const struct roff_meta *,
5954ba9607SSascha Wildner 				struct html *);
6054ba9607SSascha Wildner static	int		  mdoc_root_pre(const struct roff_meta *,
6154ba9607SSascha Wildner 				struct html *);
6280387638SSascha Wildner 
6380387638SSascha Wildner static	void		  mdoc__x_post(MDOC_ARGS);
6480387638SSascha Wildner static	int		  mdoc__x_pre(MDOC_ARGS);
6554ba9607SSascha Wildner static	int		  mdoc_abort_pre(MDOC_ARGS);
6680387638SSascha Wildner static	int		  mdoc_ad_pre(MDOC_ARGS);
6780387638SSascha Wildner static	int		  mdoc_an_pre(MDOC_ARGS);
6880387638SSascha Wildner static	int		  mdoc_ap_pre(MDOC_ARGS);
6980387638SSascha Wildner static	int		  mdoc_ar_pre(MDOC_ARGS);
7080387638SSascha Wildner static	int		  mdoc_bd_pre(MDOC_ARGS);
7180387638SSascha Wildner static	int		  mdoc_bf_pre(MDOC_ARGS);
7280387638SSascha Wildner static	void		  mdoc_bk_post(MDOC_ARGS);
7380387638SSascha Wildner static	int		  mdoc_bk_pre(MDOC_ARGS);
7480387638SSascha Wildner static	int		  mdoc_bl_pre(MDOC_ARGS);
7580387638SSascha Wildner static	int		  mdoc_cd_pre(MDOC_ARGS);
76*99db7d0eSSascha Wildner static	int		  mdoc_code_pre(MDOC_ARGS);
7780387638SSascha Wildner static	int		  mdoc_d1_pre(MDOC_ARGS);
7880387638SSascha Wildner static	int		  mdoc_fa_pre(MDOC_ARGS);
7980387638SSascha Wildner static	int		  mdoc_fd_pre(MDOC_ARGS);
8080387638SSascha Wildner static	int		  mdoc_fl_pre(MDOC_ARGS);
8180387638SSascha Wildner static	int		  mdoc_fn_pre(MDOC_ARGS);
8280387638SSascha Wildner static	int		  mdoc_ft_pre(MDOC_ARGS);
8380387638SSascha Wildner static	int		  mdoc_em_pre(MDOC_ARGS);
8454ba9607SSascha Wildner static	void		  mdoc_eo_post(MDOC_ARGS);
8554ba9607SSascha Wildner static	int		  mdoc_eo_pre(MDOC_ARGS);
8680387638SSascha Wildner static	int		  mdoc_ex_pre(MDOC_ARGS);
8780387638SSascha Wildner static	void		  mdoc_fo_post(MDOC_ARGS);
8880387638SSascha Wildner static	int		  mdoc_fo_pre(MDOC_ARGS);
8980387638SSascha Wildner static	int		  mdoc_igndelim_pre(MDOC_ARGS);
9080387638SSascha Wildner static	int		  mdoc_in_pre(MDOC_ARGS);
9180387638SSascha Wildner static	int		  mdoc_it_pre(MDOC_ARGS);
9280387638SSascha Wildner static	int		  mdoc_lb_pre(MDOC_ARGS);
9380387638SSascha Wildner static	int		  mdoc_lk_pre(MDOC_ARGS);
9480387638SSascha Wildner static	int		  mdoc_mt_pre(MDOC_ARGS);
9580387638SSascha Wildner static	int		  mdoc_nd_pre(MDOC_ARGS);
9680387638SSascha Wildner static	int		  mdoc_nm_pre(MDOC_ARGS);
9754ba9607SSascha Wildner static	int		  mdoc_no_pre(MDOC_ARGS);
9880387638SSascha Wildner static	int		  mdoc_ns_pre(MDOC_ARGS);
9980387638SSascha Wildner static	int		  mdoc_pa_pre(MDOC_ARGS);
10080387638SSascha Wildner static	void		  mdoc_pf_post(MDOC_ARGS);
10180387638SSascha Wildner static	int		  mdoc_pp_pre(MDOC_ARGS);
10280387638SSascha Wildner static	void		  mdoc_quote_post(MDOC_ARGS);
10380387638SSascha Wildner static	int		  mdoc_quote_pre(MDOC_ARGS);
10480387638SSascha Wildner static	int		  mdoc_rs_pre(MDOC_ARGS);
10580387638SSascha Wildner static	int		  mdoc_sh_pre(MDOC_ARGS);
106070c62a6SFranco Fichtner static	int		  mdoc_skip_pre(MDOC_ARGS);
10780387638SSascha Wildner static	int		  mdoc_sm_pre(MDOC_ARGS);
10880387638SSascha Wildner static	int		  mdoc_ss_pre(MDOC_ARGS);
10954ba9607SSascha Wildner static	int		  mdoc_st_pre(MDOC_ARGS);
11080387638SSascha Wildner static	int		  mdoc_sx_pre(MDOC_ARGS);
11180387638SSascha Wildner static	int		  mdoc_sy_pre(MDOC_ARGS);
112*99db7d0eSSascha Wildner static	int		  mdoc_tg_pre(MDOC_ARGS);
11380387638SSascha Wildner static	int		  mdoc_va_pre(MDOC_ARGS);
11480387638SSascha Wildner static	int		  mdoc_vt_pre(MDOC_ARGS);
11580387638SSascha Wildner static	int		  mdoc_xr_pre(MDOC_ARGS);
11680387638SSascha Wildner static	int		  mdoc_xx_pre(MDOC_ARGS);
11780387638SSascha Wildner 
11854ba9607SSascha Wildner static const struct mdoc_html_act mdoc_html_acts[MDOC_MAX - MDOC_Dd] = {
11980387638SSascha Wildner 	{NULL, NULL}, /* Dd */
12080387638SSascha Wildner 	{NULL, NULL}, /* Dt */
12180387638SSascha Wildner 	{NULL, NULL}, /* Os */
12280387638SSascha Wildner 	{mdoc_sh_pre, NULL }, /* Sh */
12380387638SSascha Wildner 	{mdoc_ss_pre, NULL }, /* Ss */
12480387638SSascha Wildner 	{mdoc_pp_pre, NULL}, /* Pp */
12580387638SSascha Wildner 	{mdoc_d1_pre, NULL}, /* D1 */
12680387638SSascha Wildner 	{mdoc_d1_pre, NULL}, /* Dl */
12780387638SSascha Wildner 	{mdoc_bd_pre, NULL}, /* Bd */
12880387638SSascha Wildner 	{NULL, NULL}, /* Ed */
12980387638SSascha Wildner 	{mdoc_bl_pre, NULL}, /* Bl */
13080387638SSascha Wildner 	{NULL, NULL}, /* El */
13180387638SSascha Wildner 	{mdoc_it_pre, NULL}, /* It */
13280387638SSascha Wildner 	{mdoc_ad_pre, NULL}, /* Ad */
13380387638SSascha Wildner 	{mdoc_an_pre, NULL}, /* An */
13454ba9607SSascha Wildner 	{mdoc_ap_pre, NULL}, /* Ap */
13580387638SSascha Wildner 	{mdoc_ar_pre, NULL}, /* Ar */
13680387638SSascha Wildner 	{mdoc_cd_pre, NULL}, /* Cd */
137*99db7d0eSSascha Wildner 	{mdoc_code_pre, NULL}, /* Cm */
138*99db7d0eSSascha Wildner 	{mdoc_code_pre, NULL}, /* Dv */
139*99db7d0eSSascha Wildner 	{mdoc_code_pre, NULL}, /* Er */
140*99db7d0eSSascha Wildner 	{mdoc_code_pre, NULL}, /* Ev */
14180387638SSascha Wildner 	{mdoc_ex_pre, NULL}, /* Ex */
14280387638SSascha Wildner 	{mdoc_fa_pre, NULL}, /* Fa */
14380387638SSascha Wildner 	{mdoc_fd_pre, NULL}, /* Fd */
14480387638SSascha Wildner 	{mdoc_fl_pre, NULL}, /* Fl */
14580387638SSascha Wildner 	{mdoc_fn_pre, NULL}, /* Fn */
14680387638SSascha Wildner 	{mdoc_ft_pre, NULL}, /* Ft */
147*99db7d0eSSascha Wildner 	{mdoc_code_pre, NULL}, /* Ic */
14880387638SSascha Wildner 	{mdoc_in_pre, NULL}, /* In */
149*99db7d0eSSascha Wildner 	{mdoc_code_pre, NULL}, /* Li */
15080387638SSascha Wildner 	{mdoc_nd_pre, NULL}, /* Nd */
15180387638SSascha Wildner 	{mdoc_nm_pre, NULL}, /* Nm */
15280387638SSascha Wildner 	{mdoc_quote_pre, mdoc_quote_post}, /* Op */
15354ba9607SSascha Wildner 	{mdoc_abort_pre, NULL}, /* Ot */
15480387638SSascha Wildner 	{mdoc_pa_pre, NULL}, /* Pa */
15554ba9607SSascha Wildner 	{mdoc_ex_pre, NULL}, /* Rv */
15654ba9607SSascha Wildner 	{mdoc_st_pre, NULL}, /* St */
15780387638SSascha Wildner 	{mdoc_va_pre, NULL}, /* Va */
15880387638SSascha Wildner 	{mdoc_vt_pre, NULL}, /* Vt */
15980387638SSascha Wildner 	{mdoc_xr_pre, NULL}, /* Xr */
16080387638SSascha Wildner 	{mdoc__x_pre, mdoc__x_post}, /* %A */
16180387638SSascha Wildner 	{mdoc__x_pre, mdoc__x_post}, /* %B */
16280387638SSascha Wildner 	{mdoc__x_pre, mdoc__x_post}, /* %D */
16380387638SSascha Wildner 	{mdoc__x_pre, mdoc__x_post}, /* %I */
16480387638SSascha Wildner 	{mdoc__x_pre, mdoc__x_post}, /* %J */
16580387638SSascha Wildner 	{mdoc__x_pre, mdoc__x_post}, /* %N */
16680387638SSascha Wildner 	{mdoc__x_pre, mdoc__x_post}, /* %O */
16780387638SSascha Wildner 	{mdoc__x_pre, mdoc__x_post}, /* %P */
16880387638SSascha Wildner 	{mdoc__x_pre, mdoc__x_post}, /* %R */
16980387638SSascha Wildner 	{mdoc__x_pre, mdoc__x_post}, /* %T */
17080387638SSascha Wildner 	{mdoc__x_pre, mdoc__x_post}, /* %V */
17180387638SSascha Wildner 	{NULL, NULL}, /* Ac */
17280387638SSascha Wildner 	{mdoc_quote_pre, mdoc_quote_post}, /* Ao */
17380387638SSascha Wildner 	{mdoc_quote_pre, mdoc_quote_post}, /* Aq */
17454ba9607SSascha Wildner 	{mdoc_xx_pre, NULL}, /* At */
17580387638SSascha Wildner 	{NULL, NULL}, /* Bc */
17680387638SSascha Wildner 	{mdoc_bf_pre, NULL}, /* Bf */
17780387638SSascha Wildner 	{mdoc_quote_pre, mdoc_quote_post}, /* Bo */
17880387638SSascha Wildner 	{mdoc_quote_pre, mdoc_quote_post}, /* Bq */
17980387638SSascha Wildner 	{mdoc_xx_pre, NULL}, /* Bsx */
18054ba9607SSascha Wildner 	{mdoc_xx_pre, NULL}, /* Bx */
18154ba9607SSascha Wildner 	{mdoc_skip_pre, NULL}, /* Db */
18280387638SSascha Wildner 	{NULL, NULL}, /* Dc */
18380387638SSascha Wildner 	{mdoc_quote_pre, mdoc_quote_post}, /* Do */
18480387638SSascha Wildner 	{mdoc_quote_pre, mdoc_quote_post}, /* Dq */
18580387638SSascha Wildner 	{NULL, NULL}, /* Ec */ /* FIXME: no space */
18680387638SSascha Wildner 	{NULL, NULL}, /* Ef */
18780387638SSascha Wildner 	{mdoc_em_pre, NULL}, /* Em */
18854ba9607SSascha Wildner 	{mdoc_eo_pre, mdoc_eo_post}, /* Eo */
18980387638SSascha Wildner 	{mdoc_xx_pre, NULL}, /* Fx */
190*99db7d0eSSascha Wildner 	{mdoc_no_pre, NULL}, /* Ms */
19154ba9607SSascha Wildner 	{mdoc_no_pre, NULL}, /* No */
19280387638SSascha Wildner 	{mdoc_ns_pre, NULL}, /* Ns */
19380387638SSascha Wildner 	{mdoc_xx_pre, NULL}, /* Nx */
19480387638SSascha Wildner 	{mdoc_xx_pre, NULL}, /* Ox */
19580387638SSascha Wildner 	{NULL, NULL}, /* Pc */
19680387638SSascha Wildner 	{mdoc_igndelim_pre, mdoc_pf_post}, /* Pf */
19780387638SSascha Wildner 	{mdoc_quote_pre, mdoc_quote_post}, /* Po */
19880387638SSascha Wildner 	{mdoc_quote_pre, mdoc_quote_post}, /* Pq */
19980387638SSascha Wildner 	{NULL, NULL}, /* Qc */
20080387638SSascha Wildner 	{mdoc_quote_pre, mdoc_quote_post}, /* Ql */
20180387638SSascha Wildner 	{mdoc_quote_pre, mdoc_quote_post}, /* Qo */
20280387638SSascha Wildner 	{mdoc_quote_pre, mdoc_quote_post}, /* Qq */
20380387638SSascha Wildner 	{NULL, NULL}, /* Re */
20480387638SSascha Wildner 	{mdoc_rs_pre, NULL}, /* Rs */
20580387638SSascha Wildner 	{NULL, NULL}, /* Sc */
20680387638SSascha Wildner 	{mdoc_quote_pre, mdoc_quote_post}, /* So */
20780387638SSascha Wildner 	{mdoc_quote_pre, mdoc_quote_post}, /* Sq */
20880387638SSascha Wildner 	{mdoc_sm_pre, NULL}, /* Sm */
20980387638SSascha Wildner 	{mdoc_sx_pre, NULL}, /* Sx */
21080387638SSascha Wildner 	{mdoc_sy_pre, NULL}, /* Sy */
21180387638SSascha Wildner 	{NULL, NULL}, /* Tn */
21280387638SSascha Wildner 	{mdoc_xx_pre, NULL}, /* Ux */
21380387638SSascha Wildner 	{NULL, NULL}, /* Xc */
21480387638SSascha Wildner 	{NULL, NULL}, /* Xo */
21580387638SSascha Wildner 	{mdoc_fo_pre, mdoc_fo_post}, /* Fo */
21680387638SSascha Wildner 	{NULL, NULL}, /* Fc */
21780387638SSascha Wildner 	{mdoc_quote_pre, mdoc_quote_post}, /* Oo */
21880387638SSascha Wildner 	{NULL, NULL}, /* Oc */
21980387638SSascha Wildner 	{mdoc_bk_pre, mdoc_bk_post}, /* Bk */
22080387638SSascha Wildner 	{NULL, NULL}, /* Ek */
22154ba9607SSascha Wildner 	{NULL, NULL}, /* Bt */
22280387638SSascha Wildner 	{NULL, NULL}, /* Hf */
223070c62a6SFranco Fichtner 	{mdoc_em_pre, NULL}, /* Fr */
22454ba9607SSascha Wildner 	{NULL, NULL}, /* Ud */
22580387638SSascha Wildner 	{mdoc_lb_pre, NULL}, /* Lb */
22654ba9607SSascha Wildner 	{mdoc_abort_pre, NULL}, /* Lp */
22780387638SSascha Wildner 	{mdoc_lk_pre, NULL}, /* Lk */
22880387638SSascha Wildner 	{mdoc_mt_pre, NULL}, /* Mt */
22980387638SSascha Wildner 	{mdoc_quote_pre, mdoc_quote_post}, /* Brq */
23080387638SSascha Wildner 	{mdoc_quote_pre, mdoc_quote_post}, /* Bro */
23180387638SSascha Wildner 	{NULL, NULL}, /* Brc */
23280387638SSascha Wildner 	{mdoc__x_pre, mdoc__x_post}, /* %C */
233070c62a6SFranco Fichtner 	{mdoc_skip_pre, NULL}, /* Es */
234070c62a6SFranco Fichtner 	{mdoc_quote_pre, mdoc_quote_post}, /* En */
23580387638SSascha Wildner 	{mdoc_xx_pre, NULL}, /* Dx */
23680387638SSascha Wildner 	{mdoc__x_pre, mdoc__x_post}, /* %Q */
23780387638SSascha Wildner 	{mdoc__x_pre, mdoc__x_post}, /* %U */
23880387638SSascha Wildner 	{NULL, NULL}, /* Ta */
239*99db7d0eSSascha Wildner 	{mdoc_tg_pre, NULL}, /* Tg */
24080387638SSascha Wildner };
24180387638SSascha Wildner 
24280387638SSascha Wildner 
24380387638SSascha Wildner /*
24480387638SSascha Wildner  * See the same function in mdoc_term.c for documentation.
24580387638SSascha Wildner  */
24680387638SSascha Wildner static void
synopsis_pre(struct html * h,struct roff_node * n)247*99db7d0eSSascha Wildner synopsis_pre(struct html *h, struct roff_node *n)
24880387638SSascha Wildner {
249*99db7d0eSSascha Wildner 	struct roff_node *np;
25080387638SSascha Wildner 
251*99db7d0eSSascha Wildner 	if ((n->flags & NODE_SYNPRETTY) == 0 ||
252*99db7d0eSSascha Wildner 	    (np = roff_node_prev(n)) == NULL)
25380387638SSascha Wildner 		return;
25480387638SSascha Wildner 
255*99db7d0eSSascha Wildner 	if (np->tok == n->tok &&
25680387638SSascha Wildner 	    MDOC_Fo != n->tok &&
25780387638SSascha Wildner 	    MDOC_Ft != n->tok &&
25880387638SSascha Wildner 	    MDOC_Fn != n->tok) {
25954ba9607SSascha Wildner 		print_otag(h, TAG_BR, "");
26080387638SSascha Wildner 		return;
26180387638SSascha Wildner 	}
26280387638SSascha Wildner 
263*99db7d0eSSascha Wildner 	switch (np->tok) {
264070c62a6SFranco Fichtner 	case MDOC_Fd:
265070c62a6SFranco Fichtner 	case MDOC_Fn:
266070c62a6SFranco Fichtner 	case MDOC_Fo:
267070c62a6SFranco Fichtner 	case MDOC_In:
268070c62a6SFranco Fichtner 	case MDOC_Vt:
26980387638SSascha Wildner 		break;
270070c62a6SFranco Fichtner 	case MDOC_Ft:
27154ba9607SSascha Wildner 		if (n->tok != MDOC_Fn && n->tok != MDOC_Fo)
27280387638SSascha Wildner 			break;
27380387638SSascha Wildner 		/* FALLTHROUGH */
27480387638SSascha Wildner 	default:
27554ba9607SSascha Wildner 		print_otag(h, TAG_BR, "");
27654ba9607SSascha Wildner 		return;
27780387638SSascha Wildner 	}
27854ba9607SSascha Wildner 	html_close_paragraph(h);
27954ba9607SSascha Wildner 	print_otag(h, TAG_P, "c", "Pp");
28080387638SSascha Wildner }
28180387638SSascha Wildner 
28254ba9607SSascha Wildner void
html_mdoc(void * arg,const struct roff_meta * mdoc)28354ba9607SSascha Wildner html_mdoc(void *arg, const struct roff_meta *mdoc)
28480387638SSascha Wildner {
28554ba9607SSascha Wildner 	struct html		*h;
28654ba9607SSascha Wildner 	struct roff_node	*n;
28754ba9607SSascha Wildner 	struct tag		*t;
28880387638SSascha Wildner 
28954ba9607SSascha Wildner 	h = (struct html *)arg;
29054ba9607SSascha Wildner 	n = mdoc->first->child;
29180387638SSascha Wildner 
29254ba9607SSascha Wildner 	if ((h->oflags & HTML_FRAGMENT) == 0) {
29336342e81SSascha Wildner 		print_gen_decls(h);
29454ba9607SSascha Wildner 		print_otag(h, TAG_HTML, "");
29554ba9607SSascha Wildner 		if (n != NULL && n->type == ROFFT_COMMENT)
29654ba9607SSascha Wildner 			print_gen_comment(h, n);
29754ba9607SSascha Wildner 		t = print_otag(h, TAG_HEAD, "");
29854ba9607SSascha Wildner 		print_mdoc_head(mdoc, h);
29980387638SSascha Wildner 		print_tagq(h, t);
30054ba9607SSascha Wildner 		print_otag(h, TAG_BODY, "");
30154ba9607SSascha Wildner 	}
30254ba9607SSascha Wildner 
30354ba9607SSascha Wildner 	mdoc_root_pre(mdoc, h);
30454ba9607SSascha Wildner 	t = print_otag(h, TAG_DIV, "c", "manual-text");
30554ba9607SSascha Wildner 	print_mdoc_nodelist(mdoc, n, h);
30654ba9607SSascha Wildner 	print_tagq(h, t);
30754ba9607SSascha Wildner 	mdoc_root_post(mdoc, h);
30854ba9607SSascha Wildner 	print_tagq(h, NULL);
30980387638SSascha Wildner }
31080387638SSascha Wildner 
31180387638SSascha Wildner static void
print_mdoc_head(const struct roff_meta * meta,struct html * h)31254ba9607SSascha Wildner print_mdoc_head(const struct roff_meta *meta, struct html *h)
31380387638SSascha Wildner {
31454ba9607SSascha Wildner 	char	*cp;
31580387638SSascha Wildner 
31680387638SSascha Wildner 	print_gen_head(h);
31780387638SSascha Wildner 
31854ba9607SSascha Wildner 	if (meta->arch != NULL && meta->msec != NULL)
31954ba9607SSascha Wildner 		mandoc_asprintf(&cp, "%s(%s) (%s)", meta->title,
32054ba9607SSascha Wildner 		    meta->msec, meta->arch);
32154ba9607SSascha Wildner 	else if (meta->msec != NULL)
32254ba9607SSascha Wildner 		mandoc_asprintf(&cp, "%s(%s)", meta->title, meta->msec);
32354ba9607SSascha Wildner 	else if (meta->arch != NULL)
32454ba9607SSascha Wildner 		mandoc_asprintf(&cp, "%s (%s)", meta->title, meta->arch);
32554ba9607SSascha Wildner 	else
32654ba9607SSascha Wildner 		cp = mandoc_strdup(meta->title);
32754ba9607SSascha Wildner 
32854ba9607SSascha Wildner 	print_otag(h, TAG_TITLE, "");
32954ba9607SSascha Wildner 	print_text(h, cp);
33054ba9607SSascha Wildner 	free(cp);
33180387638SSascha Wildner }
33280387638SSascha Wildner 
33380387638SSascha Wildner static void
print_mdoc_nodelist(MDOC_ARGS)33480387638SSascha Wildner print_mdoc_nodelist(MDOC_ARGS)
33580387638SSascha Wildner {
33680387638SSascha Wildner 
33754ba9607SSascha Wildner 	while (n != NULL) {
338f88b6c16SFranco Fichtner 		print_mdoc_node(meta, n, h);
33954ba9607SSascha Wildner 		n = n->next;
34054ba9607SSascha Wildner 	}
34180387638SSascha Wildner }
34280387638SSascha Wildner 
34380387638SSascha Wildner static void
print_mdoc_node(MDOC_ARGS)34480387638SSascha Wildner print_mdoc_node(MDOC_ARGS)
34580387638SSascha Wildner {
34680387638SSascha Wildner 	struct tag	*t;
34754ba9607SSascha Wildner 	int		 child;
34854ba9607SSascha Wildner 
34954ba9607SSascha Wildner 	if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
35054ba9607SSascha Wildner 		return;
35154ba9607SSascha Wildner 
352*99db7d0eSSascha Wildner 	if ((n->flags & NODE_NOFILL) == 0)
353*99db7d0eSSascha Wildner 		html_fillmode(h, ROFF_fi);
354*99db7d0eSSascha Wildner 	else if (html_fillmode(h, ROFF_nf) == ROFF_nf &&
355*99db7d0eSSascha Wildner 	    n->tok != ROFF_fi && n->flags & NODE_LINE)
356*99db7d0eSSascha Wildner 		print_endline(h);
35780387638SSascha Wildner 
35880387638SSascha Wildner 	child = 1;
35954ba9607SSascha Wildner 	n->flags &= ~NODE_ENDED;
36080387638SSascha Wildner 	switch (n->type) {
36154ba9607SSascha Wildner 	case ROFFT_TEXT:
362*99db7d0eSSascha Wildner 		if (n->flags & NODE_LINE) {
363*99db7d0eSSascha Wildner 			switch (*n->string) {
364*99db7d0eSSascha Wildner 			case '\0':
365*99db7d0eSSascha Wildner 				h->col = 1;
366*99db7d0eSSascha Wildner 				print_endline(h);
367*99db7d0eSSascha Wildner 				return;
368*99db7d0eSSascha Wildner 			case ' ':
369*99db7d0eSSascha Wildner 				if ((h->flags & HTML_NONEWLINE) == 0 &&
37054ba9607SSascha Wildner 				    (n->flags & NODE_NOFILL) == 0)
37154ba9607SSascha Wildner 					print_otag(h, TAG_BR, "");
372*99db7d0eSSascha Wildner 				break;
373*99db7d0eSSascha Wildner 			default:
374*99db7d0eSSascha Wildner 				break;
375*99db7d0eSSascha Wildner 			}
376*99db7d0eSSascha Wildner 		}
377*99db7d0eSSascha Wildner 		t = h->tag;
378*99db7d0eSSascha Wildner 		t->refcnt++;
379*99db7d0eSSascha Wildner 		if (n->flags & NODE_DELIMC)
38060e1e752SSascha Wildner 			h->flags |= HTML_NOSPACE;
381*99db7d0eSSascha Wildner 		if (n->flags & NODE_HREF)
382*99db7d0eSSascha Wildner 			print_tagged_text(h, n->string, n);
383*99db7d0eSSascha Wildner 		else
38480387638SSascha Wildner 			print_text(h, n->string);
385*99db7d0eSSascha Wildner 		if (n->flags & NODE_DELIMO)
38660e1e752SSascha Wildner 			h->flags |= HTML_NOSPACE;
38754ba9607SSascha Wildner 		break;
38854ba9607SSascha Wildner 	case ROFFT_EQN:
38954ba9607SSascha Wildner 		t = h->tag;
39054ba9607SSascha Wildner 		t->refcnt++;
39136342e81SSascha Wildner 		print_eqn(h, n->eqn);
39280387638SSascha Wildner 		break;
39354ba9607SSascha Wildner 	case ROFFT_TBL:
39460e1e752SSascha Wildner 		/*
39560e1e752SSascha Wildner 		 * This will take care of initialising all of the table
39660e1e752SSascha Wildner 		 * state data for the first table, then tearing it down
39760e1e752SSascha Wildner 		 * for the last one.
39860e1e752SSascha Wildner 		 */
39960e1e752SSascha Wildner 		print_tbl(h, n->span);
40060e1e752SSascha Wildner 		return;
40180387638SSascha Wildner 	default:
40260e1e752SSascha Wildner 		/*
40360e1e752SSascha Wildner 		 * Close out the current table, if it's open, and unset
40460e1e752SSascha Wildner 		 * the "meta" table state.  This will be reopened on the
40560e1e752SSascha Wildner 		 * next table element.
40660e1e752SSascha Wildner 		 */
40754ba9607SSascha Wildner 		if (h->tblt != NULL)
40860e1e752SSascha Wildner 			print_tblclose(h);
40954ba9607SSascha Wildner 		assert(h->tblt == NULL);
41054ba9607SSascha Wildner 		t = h->tag;
41154ba9607SSascha Wildner 		t->refcnt++;
41254ba9607SSascha Wildner 		if (n->tok < ROFF_MAX) {
41354ba9607SSascha Wildner 			roff_html_pre(h, n);
41454ba9607SSascha Wildner 			t->refcnt--;
41554ba9607SSascha Wildner 			print_stagq(h, t);
41654ba9607SSascha Wildner 			return;
41760e1e752SSascha Wildner 		}
41854ba9607SSascha Wildner 		assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
41954ba9607SSascha Wildner 		if (mdoc_html_acts[n->tok - MDOC_Dd].pre != NULL &&
42054ba9607SSascha Wildner 		    (n->end == ENDBODY_NOT || n->child != NULL))
42154ba9607SSascha Wildner 			child = (*mdoc_html_acts[n->tok - MDOC_Dd].pre)(meta,
42254ba9607SSascha Wildner 			    n, h);
42380387638SSascha Wildner 		break;
42480387638SSascha Wildner 	}
42580387638SSascha Wildner 
42654ba9607SSascha Wildner 	if (h->flags & HTML_KEEP && n->flags & NODE_LINE) {
42780387638SSascha Wildner 		h->flags &= ~HTML_KEEP;
42880387638SSascha Wildner 		h->flags |= HTML_PREKEEP;
42980387638SSascha Wildner 	}
43080387638SSascha Wildner 
43154ba9607SSascha Wildner 	if (child && n->child != NULL)
432f88b6c16SFranco Fichtner 		print_mdoc_nodelist(meta, n->child, h);
43380387638SSascha Wildner 
43454ba9607SSascha Wildner 	t->refcnt--;
43580387638SSascha Wildner 	print_stagq(h, t);
43680387638SSascha Wildner 
43780387638SSascha Wildner 	switch (n->type) {
43854ba9607SSascha Wildner 	case ROFFT_TEXT:
43954ba9607SSascha Wildner 	case ROFFT_EQN:
44080387638SSascha Wildner 		break;
44180387638SSascha Wildner 	default:
44254ba9607SSascha Wildner 		if (mdoc_html_acts[n->tok - MDOC_Dd].post == NULL ||
44354ba9607SSascha Wildner 		    n->flags & NODE_ENDED)
44480387638SSascha Wildner 			break;
44554ba9607SSascha Wildner 		(*mdoc_html_acts[n->tok - MDOC_Dd].post)(meta, n, h);
44654ba9607SSascha Wildner 		if (n->end != ENDBODY_NOT)
44754ba9607SSascha Wildner 			n->body->flags |= NODE_ENDED;
44854ba9607SSascha Wildner 		break;
44954ba9607SSascha Wildner 	}
45080387638SSascha Wildner }
45180387638SSascha Wildner 
45280387638SSascha Wildner static void
mdoc_root_post(const struct roff_meta * meta,struct html * h)45354ba9607SSascha Wildner mdoc_root_post(const struct roff_meta *meta, struct html *h)
45480387638SSascha Wildner {
45580387638SSascha Wildner 	struct tag	*t, *tt;
45680387638SSascha Wildner 
45754ba9607SSascha Wildner 	t = print_otag(h, TAG_TABLE, "c", "foot");
45854ba9607SSascha Wildner 	tt = print_otag(h, TAG_TR, "");
45980387638SSascha Wildner 
46054ba9607SSascha Wildner 	print_otag(h, TAG_TD, "c", "foot-date");
461f88b6c16SFranco Fichtner 	print_text(h, meta->date);
46280387638SSascha Wildner 	print_stagq(h, tt);
46380387638SSascha Wildner 
46454ba9607SSascha Wildner 	print_otag(h, TAG_TD, "c", "foot-os");
465f88b6c16SFranco Fichtner 	print_text(h, meta->os);
46680387638SSascha Wildner 	print_tagq(h, t);
46780387638SSascha Wildner }
46880387638SSascha Wildner 
46980387638SSascha Wildner static int
mdoc_root_pre(const struct roff_meta * meta,struct html * h)47054ba9607SSascha Wildner mdoc_root_pre(const struct roff_meta *meta, struct html *h)
47180387638SSascha Wildner {
47280387638SSascha Wildner 	struct tag	*t, *tt;
473070c62a6SFranco Fichtner 	char		*volume, *title;
47480387638SSascha Wildner 
475070c62a6SFranco Fichtner 	if (NULL == meta->arch)
476070c62a6SFranco Fichtner 		volume = mandoc_strdup(meta->vol);
477070c62a6SFranco Fichtner 	else
478070c62a6SFranco Fichtner 		mandoc_asprintf(&volume, "%s (%s)",
479070c62a6SFranco Fichtner 		    meta->vol, meta->arch);
48080387638SSascha Wildner 
481070c62a6SFranco Fichtner 	if (NULL == meta->msec)
482070c62a6SFranco Fichtner 		title = mandoc_strdup(meta->title);
483070c62a6SFranco Fichtner 	else
484070c62a6SFranco Fichtner 		mandoc_asprintf(&title, "%s(%s)",
485070c62a6SFranco Fichtner 		    meta->title, meta->msec);
48680387638SSascha Wildner 
48754ba9607SSascha Wildner 	t = print_otag(h, TAG_TABLE, "c", "head");
48854ba9607SSascha Wildner 	tt = print_otag(h, TAG_TR, "");
48980387638SSascha Wildner 
49054ba9607SSascha Wildner 	print_otag(h, TAG_TD, "c", "head-ltitle");
49180387638SSascha Wildner 	print_text(h, title);
49280387638SSascha Wildner 	print_stagq(h, tt);
49380387638SSascha Wildner 
49454ba9607SSascha Wildner 	print_otag(h, TAG_TD, "c", "head-vol");
495070c62a6SFranco Fichtner 	print_text(h, volume);
49680387638SSascha Wildner 	print_stagq(h, tt);
49780387638SSascha Wildner 
49854ba9607SSascha Wildner 	print_otag(h, TAG_TD, "c", "head-rtitle");
49980387638SSascha Wildner 	print_text(h, title);
50080387638SSascha Wildner 	print_tagq(h, t);
501070c62a6SFranco Fichtner 
502070c62a6SFranco Fichtner 	free(title);
503070c62a6SFranco Fichtner 	free(volume);
50454ba9607SSascha Wildner 	return 1;
50554ba9607SSascha Wildner }
50654ba9607SSascha Wildner 
507*99db7d0eSSascha Wildner static int
mdoc_code_pre(MDOC_ARGS)508*99db7d0eSSascha Wildner mdoc_code_pre(MDOC_ARGS)
50954ba9607SSascha Wildner {
510*99db7d0eSSascha Wildner 	print_otag_id(h, TAG_CODE, roff_name[n->tok], n);
511*99db7d0eSSascha Wildner 	return 1;
51280387638SSascha Wildner }
51380387638SSascha Wildner 
51480387638SSascha Wildner static int
mdoc_sh_pre(MDOC_ARGS)51580387638SSascha Wildner mdoc_sh_pre(MDOC_ARGS)
51680387638SSascha Wildner {
51754ba9607SSascha Wildner 	struct roff_node	*sn, *subn;
51854ba9607SSascha Wildner 	struct tag		*t, *tsec, *tsub;
51954ba9607SSascha Wildner 	char			*id;
52054ba9607SSascha Wildner 	int			 sc;
52180387638SSascha Wildner 
52254ba9607SSascha Wildner 	switch (n->type) {
52354ba9607SSascha Wildner 	case ROFFT_BLOCK:
52454ba9607SSascha Wildner 		html_close_paragraph(h);
52554ba9607SSascha Wildner 		if ((h->oflags & HTML_TOC) == 0 ||
52654ba9607SSascha Wildner 		    h->flags & HTML_TOCDONE ||
52754ba9607SSascha Wildner 		    n->sec <= SEC_SYNOPSIS) {
52854ba9607SSascha Wildner 			print_otag(h, TAG_SECTION, "c", "Sh");
52954ba9607SSascha Wildner 			break;
53080387638SSascha Wildner 		}
53154ba9607SSascha Wildner 		h->flags |= HTML_TOCDONE;
53254ba9607SSascha Wildner 		sc = 0;
53354ba9607SSascha Wildner 		for (sn = n->next; sn != NULL; sn = sn->next)
53454ba9607SSascha Wildner 			if (sn->sec == SEC_CUSTOM)
53554ba9607SSascha Wildner 				if (++sc == 2)
53654ba9607SSascha Wildner 					break;
53754ba9607SSascha Wildner 		if (sc < 2)
53854ba9607SSascha Wildner 			break;
53954ba9607SSascha Wildner 		t = print_otag(h, TAG_H1, "c", "Sh");
54054ba9607SSascha Wildner 		print_text(h, "TABLE OF CONTENTS");
54154ba9607SSascha Wildner 		print_tagq(h, t);
54254ba9607SSascha Wildner 		t = print_otag(h, TAG_UL, "c", "Bl-compact");
54354ba9607SSascha Wildner 		for (sn = n; sn != NULL; sn = sn->next) {
54454ba9607SSascha Wildner 			tsec = print_otag(h, TAG_LI, "");
54554ba9607SSascha Wildner 			id = html_make_id(sn->head, 0);
54654ba9607SSascha Wildner 			tsub = print_otag(h, TAG_A, "hR", id);
54754ba9607SSascha Wildner 			free(id);
54854ba9607SSascha Wildner 			print_mdoc_nodelist(meta, sn->head->child, h);
54954ba9607SSascha Wildner 			print_tagq(h, tsub);
55054ba9607SSascha Wildner 			tsub = NULL;
55154ba9607SSascha Wildner 			for (subn = sn->body->child; subn != NULL;
55254ba9607SSascha Wildner 			    subn = subn->next) {
55354ba9607SSascha Wildner 				if (subn->tok != MDOC_Ss)
55454ba9607SSascha Wildner 					continue;
55554ba9607SSascha Wildner 				id = html_make_id(subn->head, 0);
55654ba9607SSascha Wildner 				if (id == NULL)
55754ba9607SSascha Wildner 					continue;
55854ba9607SSascha Wildner 				if (tsub == NULL)
55954ba9607SSascha Wildner 					print_otag(h, TAG_UL,
56054ba9607SSascha Wildner 					    "c", "Bl-compact");
56154ba9607SSascha Wildner 				tsub = print_otag(h, TAG_LI, "");
56254ba9607SSascha Wildner 				print_otag(h, TAG_A, "hR", id);
56354ba9607SSascha Wildner 				free(id);
56454ba9607SSascha Wildner 				print_mdoc_nodelist(meta,
56554ba9607SSascha Wildner 				    subn->head->child, h);
56654ba9607SSascha Wildner 				print_tagq(h, tsub);
56754ba9607SSascha Wildner 			}
56854ba9607SSascha Wildner 			print_tagq(h, tsec);
56954ba9607SSascha Wildner 		}
57054ba9607SSascha Wildner 		print_tagq(h, t);
57154ba9607SSascha Wildner 		print_otag(h, TAG_SECTION, "c", "Sh");
57254ba9607SSascha Wildner 		break;
57354ba9607SSascha Wildner 	case ROFFT_HEAD:
574*99db7d0eSSascha Wildner 		print_otag_id(h, TAG_H1, "Sh", n);
57554ba9607SSascha Wildner 		break;
57654ba9607SSascha Wildner 	case ROFFT_BODY:
57754ba9607SSascha Wildner 		if (n->sec == SEC_AUTHORS)
57854ba9607SSascha Wildner 			h->flags &= ~(HTML_SPLIT|HTML_NOSPLIT);
57954ba9607SSascha Wildner 		break;
58054ba9607SSascha Wildner 	default:
58154ba9607SSascha Wildner 		break;
58254ba9607SSascha Wildner 	}
58354ba9607SSascha Wildner 	return 1;
58480387638SSascha Wildner }
58580387638SSascha Wildner 
58680387638SSascha Wildner static int
mdoc_ss_pre(MDOC_ARGS)58780387638SSascha Wildner mdoc_ss_pre(MDOC_ARGS)
58880387638SSascha Wildner {
58954ba9607SSascha Wildner 	switch (n->type) {
59054ba9607SSascha Wildner 	case ROFFT_BLOCK:
59154ba9607SSascha Wildner 		html_close_paragraph(h);
59254ba9607SSascha Wildner 		print_otag(h, TAG_SECTION, "c", "Ss");
593*99db7d0eSSascha Wildner 		break;
59454ba9607SSascha Wildner 	case ROFFT_HEAD:
595*99db7d0eSSascha Wildner 		print_otag_id(h, TAG_H2, "Ss", n);
59654ba9607SSascha Wildner 		break;
59754ba9607SSascha Wildner 	case ROFFT_BODY:
598*99db7d0eSSascha Wildner 		break;
59954ba9607SSascha Wildner 	default:
60054ba9607SSascha Wildner 		abort();
60180387638SSascha Wildner 	}
60254ba9607SSascha Wildner 	return 1;
60380387638SSascha Wildner }
60480387638SSascha Wildner 
60580387638SSascha Wildner static int
mdoc_fl_pre(MDOC_ARGS)60680387638SSascha Wildner mdoc_fl_pre(MDOC_ARGS)
60780387638SSascha Wildner {
608*99db7d0eSSascha Wildner 	struct roff_node	*nn;
60980387638SSascha Wildner 
610*99db7d0eSSascha Wildner 	print_otag_id(h, TAG_CODE, "Fl", n);
61180387638SSascha Wildner 	print_text(h, "\\-");
612*99db7d0eSSascha Wildner 	if (n->child != NULL ||
613*99db7d0eSSascha Wildner 	    ((nn = roff_node_next(n)) != NULL &&
614*99db7d0eSSascha Wildner 	     nn->type != ROFFT_TEXT &&
615*99db7d0eSSascha Wildner 	     (nn->flags & NODE_LINE) == 0))
61680387638SSascha Wildner 		h->flags |= HTML_NOSPACE;
61780387638SSascha Wildner 
61854ba9607SSascha Wildner 	return 1;
61954ba9607SSascha Wildner }
62054ba9607SSascha Wildner 
62154ba9607SSascha Wildner static int
mdoc_nd_pre(MDOC_ARGS)62280387638SSascha Wildner mdoc_nd_pre(MDOC_ARGS)
62380387638SSascha Wildner {
62454ba9607SSascha Wildner 	switch (n->type) {
62554ba9607SSascha Wildner 	case ROFFT_BLOCK:
62654ba9607SSascha Wildner 		return 1;
62754ba9607SSascha Wildner 	case ROFFT_HEAD:
62854ba9607SSascha Wildner 		return 0;
62954ba9607SSascha Wildner 	case ROFFT_BODY:
63054ba9607SSascha Wildner 		break;
63154ba9607SSascha Wildner 	default:
63254ba9607SSascha Wildner 		abort();
63354ba9607SSascha Wildner 	}
63480387638SSascha Wildner 	print_text(h, "\\(em");
635*99db7d0eSSascha Wildner 	print_otag(h, TAG_SPAN, "c", "Nd");
63654ba9607SSascha Wildner 	return 1;
63780387638SSascha Wildner }
63880387638SSascha Wildner 
63980387638SSascha Wildner static int
mdoc_nm_pre(MDOC_ARGS)64080387638SSascha Wildner mdoc_nm_pre(MDOC_ARGS)
64180387638SSascha Wildner {
64280387638SSascha Wildner 	switch (n->type) {
64354ba9607SSascha Wildner 	case ROFFT_BLOCK:
64480387638SSascha Wildner 		break;
64554ba9607SSascha Wildner 	case ROFFT_HEAD:
64654ba9607SSascha Wildner 		print_otag(h, TAG_TD, "");
64754ba9607SSascha Wildner 		/* FALLTHROUGH */
64854ba9607SSascha Wildner 	case ROFFT_ELEM:
64954ba9607SSascha Wildner 		print_otag(h, TAG_CODE, "c", "Nm");
65054ba9607SSascha Wildner 		return 1;
65154ba9607SSascha Wildner 	case ROFFT_BODY:
65254ba9607SSascha Wildner 		print_otag(h, TAG_TD, "");
65354ba9607SSascha Wildner 		return 1;
65454ba9607SSascha Wildner 	default:
65554ba9607SSascha Wildner 		abort();
65680387638SSascha Wildner 	}
65754ba9607SSascha Wildner 	html_close_paragraph(h);
65880387638SSascha Wildner 	synopsis_pre(h, n);
65954ba9607SSascha Wildner 	print_otag(h, TAG_TABLE, "c", "Nm");
66054ba9607SSascha Wildner 	print_otag(h, TAG_TR, "");
66154ba9607SSascha Wildner 	return 1;
66280387638SSascha Wildner }
66380387638SSascha Wildner 
66480387638SSascha Wildner static int
mdoc_xr_pre(MDOC_ARGS)66580387638SSascha Wildner mdoc_xr_pre(MDOC_ARGS)
66680387638SSascha Wildner {
66780387638SSascha Wildner 	if (NULL == n->child)
66854ba9607SSascha Wildner 		return 0;
66980387638SSascha Wildner 
67054ba9607SSascha Wildner 	if (h->base_man1)
67154ba9607SSascha Wildner 		print_otag(h, TAG_A, "chM", "Xr",
67254ba9607SSascha Wildner 		    n->child->string, n->child->next == NULL ?
67354ba9607SSascha Wildner 		    NULL : n->child->next->string);
67454ba9607SSascha Wildner 	else
67554ba9607SSascha Wildner 		print_otag(h, TAG_A, "c", "Xr");
67680387638SSascha Wildner 
67760e1e752SSascha Wildner 	n = n->child;
67860e1e752SSascha Wildner 	print_text(h, n->string);
67980387638SSascha Wildner 
68060e1e752SSascha Wildner 	if (NULL == (n = n->next))
68154ba9607SSascha Wildner 		return 0;
68280387638SSascha Wildner 
68380387638SSascha Wildner 	h->flags |= HTML_NOSPACE;
68480387638SSascha Wildner 	print_text(h, "(");
68580387638SSascha Wildner 	h->flags |= HTML_NOSPACE;
68660e1e752SSascha Wildner 	print_text(h, n->string);
68780387638SSascha Wildner 	h->flags |= HTML_NOSPACE;
68880387638SSascha Wildner 	print_text(h, ")");
68954ba9607SSascha Wildner 	return 0;
69080387638SSascha Wildner }
69180387638SSascha Wildner 
69280387638SSascha Wildner static int
mdoc_tg_pre(MDOC_ARGS)693*99db7d0eSSascha Wildner mdoc_tg_pre(MDOC_ARGS)
694*99db7d0eSSascha Wildner {
695*99db7d0eSSascha Wildner 	char	*id;
696*99db7d0eSSascha Wildner 
697*99db7d0eSSascha Wildner 	if ((id = html_make_id(n, 1)) != NULL) {
698*99db7d0eSSascha Wildner 		print_tagq(h, print_otag(h, TAG_MARK, "i", id));
699*99db7d0eSSascha Wildner 		free(id);
700*99db7d0eSSascha Wildner 	}
701*99db7d0eSSascha Wildner 	return 0;
702*99db7d0eSSascha Wildner }
703*99db7d0eSSascha Wildner 
704*99db7d0eSSascha Wildner static int
mdoc_ns_pre(MDOC_ARGS)70580387638SSascha Wildner mdoc_ns_pre(MDOC_ARGS)
70680387638SSascha Wildner {
70780387638SSascha Wildner 
70854ba9607SSascha Wildner 	if ( ! (NODE_LINE & n->flags))
70980387638SSascha Wildner 		h->flags |= HTML_NOSPACE;
71054ba9607SSascha Wildner 	return 1;
71180387638SSascha Wildner }
71280387638SSascha Wildner 
71380387638SSascha Wildner static int
mdoc_ar_pre(MDOC_ARGS)71480387638SSascha Wildner mdoc_ar_pre(MDOC_ARGS)
71580387638SSascha Wildner {
71654ba9607SSascha Wildner 	print_otag(h, TAG_VAR, "c", "Ar");
71754ba9607SSascha Wildner 	return 1;
71880387638SSascha Wildner }
71980387638SSascha Wildner 
72080387638SSascha Wildner static int
mdoc_xx_pre(MDOC_ARGS)72180387638SSascha Wildner mdoc_xx_pre(MDOC_ARGS)
72280387638SSascha Wildner {
72354ba9607SSascha Wildner 	print_otag(h, TAG_SPAN, "c", "Ux");
72454ba9607SSascha Wildner 	return 1;
72580387638SSascha Wildner }
72680387638SSascha Wildner 
72780387638SSascha Wildner static int
mdoc_it_pre(MDOC_ARGS)72880387638SSascha Wildner mdoc_it_pre(MDOC_ARGS)
72980387638SSascha Wildner {
73054ba9607SSascha Wildner 	const struct roff_node	*bl;
73180387638SSascha Wildner 	enum mdoc_list		 type;
73280387638SSascha Wildner 
73380387638SSascha Wildner 	bl = n->parent;
73454ba9607SSascha Wildner 	while (bl->tok != MDOC_Bl)
73580387638SSascha Wildner 		bl = bl->parent;
73680387638SSascha Wildner 	type = bl->norm->Bl.type;
73780387638SSascha Wildner 
73880387638SSascha Wildner 	switch (type) {
739070c62a6SFranco Fichtner 	case LIST_bullet:
740070c62a6SFranco Fichtner 	case LIST_dash:
741070c62a6SFranco Fichtner 	case LIST_hyphen:
74254ba9607SSascha Wildner 	case LIST_item:
743070c62a6SFranco Fichtner 	case LIST_enum:
74454ba9607SSascha Wildner 		switch (n->type) {
74554ba9607SSascha Wildner 		case ROFFT_HEAD:
74654ba9607SSascha Wildner 			return 0;
74754ba9607SSascha Wildner 		case ROFFT_BODY:
748*99db7d0eSSascha Wildner 			print_otag_id(h, TAG_LI, NULL, n);
74980387638SSascha Wildner 			break;
75080387638SSascha Wildner 		default:
75180387638SSascha Wildner 			break;
75280387638SSascha Wildner 		}
75380387638SSascha Wildner 		break;
754070c62a6SFranco Fichtner 	case LIST_diag:
755070c62a6SFranco Fichtner 	case LIST_hang:
756070c62a6SFranco Fichtner 	case LIST_inset:
757070c62a6SFranco Fichtner 	case LIST_ohang:
75854ba9607SSascha Wildner 		switch (n->type) {
75954ba9607SSascha Wildner 		case ROFFT_HEAD:
760*99db7d0eSSascha Wildner 			print_otag_id(h, TAG_DT, NULL, n);
76154ba9607SSascha Wildner 			break;
76254ba9607SSascha Wildner 		case ROFFT_BODY:
76354ba9607SSascha Wildner 			print_otag(h, TAG_DD, "");
76454ba9607SSascha Wildner 			break;
76554ba9607SSascha Wildner 		default:
76654ba9607SSascha Wildner 			break;
76754ba9607SSascha Wildner 		}
76854ba9607SSascha Wildner 		break;
769070c62a6SFranco Fichtner 	case LIST_tag:
77054ba9607SSascha Wildner 		switch (n->type) {
77154ba9607SSascha Wildner 		case ROFFT_HEAD:
772*99db7d0eSSascha Wildner 			print_otag_id(h, TAG_DT, NULL, n);
77380387638SSascha Wildner 			break;
77454ba9607SSascha Wildner 		case ROFFT_BODY:
77554ba9607SSascha Wildner 			if (n->child == NULL) {
77654ba9607SSascha Wildner 				print_otag(h, TAG_DD, "s", "width", "auto");
77754ba9607SSascha Wildner 				print_text(h, "\\ ");
77854ba9607SSascha Wildner 			} else
77954ba9607SSascha Wildner 				print_otag(h, TAG_DD, "");
78080387638SSascha Wildner 			break;
78180387638SSascha Wildner 		default:
78280387638SSascha Wildner 			break;
78380387638SSascha Wildner 		}
78454ba9607SSascha Wildner 		break;
785070c62a6SFranco Fichtner 	case LIST_column:
78654ba9607SSascha Wildner 		switch (n->type) {
78754ba9607SSascha Wildner 		case ROFFT_HEAD:
78854ba9607SSascha Wildner 			break;
78954ba9607SSascha Wildner 		case ROFFT_BODY:
79054ba9607SSascha Wildner 			print_otag(h, TAG_TD, "");
79180387638SSascha Wildner 			break;
79280387638SSascha Wildner 		default:
793*99db7d0eSSascha Wildner 			print_otag_id(h, TAG_TR, NULL, n);
79480387638SSascha Wildner 		}
79554ba9607SSascha Wildner 	default:
79654ba9607SSascha Wildner 		break;
79780387638SSascha Wildner 	}
79880387638SSascha Wildner 
79954ba9607SSascha Wildner 	return 1;
80080387638SSascha Wildner }
80180387638SSascha Wildner 
80280387638SSascha Wildner static int
mdoc_bl_pre(MDOC_ARGS)80380387638SSascha Wildner mdoc_bl_pre(MDOC_ARGS)
80480387638SSascha Wildner {
80554ba9607SSascha Wildner 	char		 cattr[32];
80654ba9607SSascha Wildner 	struct mdoc_bl	*bl;
80754ba9607SSascha Wildner 	enum htmltag	 elemtype;
80880387638SSascha Wildner 
80954ba9607SSascha Wildner 	switch (n->type) {
81054ba9607SSascha Wildner 	case ROFFT_BLOCK:
81154ba9607SSascha Wildner 		html_close_paragraph(h);
81254ba9607SSascha Wildner 		break;
81354ba9607SSascha Wildner 	case ROFFT_HEAD:
81454ba9607SSascha Wildner 		return 0;
81554ba9607SSascha Wildner 	case ROFFT_BODY:
81654ba9607SSascha Wildner 		return 1;
81754ba9607SSascha Wildner 	default:
81854ba9607SSascha Wildner 		abort();
81980387638SSascha Wildner 	}
82080387638SSascha Wildner 
82154ba9607SSascha Wildner 	bl = &n->norm->Bl;
82254ba9607SSascha Wildner 	switch (bl->type) {
823070c62a6SFranco Fichtner 	case LIST_bullet:
82454ba9607SSascha Wildner 		elemtype = TAG_UL;
82554ba9607SSascha Wildner 		(void)strlcpy(cattr, "Bl-bullet", sizeof(cattr));
82654ba9607SSascha Wildner 		break;
827070c62a6SFranco Fichtner 	case LIST_dash:
828070c62a6SFranco Fichtner 	case LIST_hyphen:
82954ba9607SSascha Wildner 		elemtype = TAG_UL;
83054ba9607SSascha Wildner 		(void)strlcpy(cattr, "Bl-dash", sizeof(cattr));
83154ba9607SSascha Wildner 		break;
832070c62a6SFranco Fichtner 	case LIST_item:
83354ba9607SSascha Wildner 		elemtype = TAG_UL;
83454ba9607SSascha Wildner 		(void)strlcpy(cattr, "Bl-item", sizeof(cattr));
83580387638SSascha Wildner 		break;
836070c62a6SFranco Fichtner 	case LIST_enum:
83754ba9607SSascha Wildner 		elemtype = TAG_OL;
83854ba9607SSascha Wildner 		(void)strlcpy(cattr, "Bl-enum", sizeof(cattr));
83980387638SSascha Wildner 		break;
840070c62a6SFranco Fichtner 	case LIST_diag:
84154ba9607SSascha Wildner 		elemtype = TAG_DL;
84254ba9607SSascha Wildner 		(void)strlcpy(cattr, "Bl-diag", sizeof(cattr));
84380387638SSascha Wildner 		break;
84454ba9607SSascha Wildner 	case LIST_hang:
84554ba9607SSascha Wildner 		elemtype = TAG_DL;
84654ba9607SSascha Wildner 		(void)strlcpy(cattr, "Bl-hang", sizeof(cattr));
84754ba9607SSascha Wildner 		break;
84854ba9607SSascha Wildner 	case LIST_inset:
84954ba9607SSascha Wildner 		elemtype = TAG_DL;
85054ba9607SSascha Wildner 		(void)strlcpy(cattr, "Bl-inset", sizeof(cattr));
85154ba9607SSascha Wildner 		break;
85254ba9607SSascha Wildner 	case LIST_ohang:
85354ba9607SSascha Wildner 		elemtype = TAG_DL;
85454ba9607SSascha Wildner 		(void)strlcpy(cattr, "Bl-ohang", sizeof(cattr));
85554ba9607SSascha Wildner 		break;
85654ba9607SSascha Wildner 	case LIST_tag:
85754ba9607SSascha Wildner 		if (bl->offs)
85854ba9607SSascha Wildner 			print_otag(h, TAG_DIV, "c", "Bd-indent");
859*99db7d0eSSascha Wildner 		print_otag_id(h, TAG_DL,
860*99db7d0eSSascha Wildner 		    bl->comp ? "Bl-tag Bl-compact" : "Bl-tag", n->body);
86154ba9607SSascha Wildner 		return 1;
862070c62a6SFranco Fichtner 	case LIST_column:
86354ba9607SSascha Wildner 		elemtype = TAG_TABLE;
86454ba9607SSascha Wildner 		(void)strlcpy(cattr, "Bl-column", sizeof(cattr));
86580387638SSascha Wildner 		break;
86680387638SSascha Wildner 	default:
86780387638SSascha Wildner 		abort();
86880387638SSascha Wildner 	}
86954ba9607SSascha Wildner 	if (bl->offs != NULL)
87054ba9607SSascha Wildner 		(void)strlcat(cattr, " Bd-indent", sizeof(cattr));
87154ba9607SSascha Wildner 	if (bl->comp)
87254ba9607SSascha Wildner 		(void)strlcat(cattr, " Bl-compact", sizeof(cattr));
873*99db7d0eSSascha Wildner 	print_otag_id(h, elemtype, cattr, n->body);
87454ba9607SSascha Wildner 	return 1;
87580387638SSascha Wildner }
87680387638SSascha Wildner 
87780387638SSascha Wildner static int
mdoc_ex_pre(MDOC_ARGS)87880387638SSascha Wildner mdoc_ex_pre(MDOC_ARGS)
87980387638SSascha Wildner {
880*99db7d0eSSascha Wildner 	if (roff_node_prev(n) != NULL)
88154ba9607SSascha Wildner 		print_otag(h, TAG_BR, "");
88254ba9607SSascha Wildner 	return 1;
88380387638SSascha Wildner }
88480387638SSascha Wildner 
88554ba9607SSascha Wildner static int
mdoc_st_pre(MDOC_ARGS)88654ba9607SSascha Wildner mdoc_st_pre(MDOC_ARGS)
88754ba9607SSascha Wildner {
88854ba9607SSascha Wildner 	print_otag(h, TAG_SPAN, "c", "St");
88954ba9607SSascha Wildner 	return 1;
89080387638SSascha Wildner }
89180387638SSascha Wildner 
89280387638SSascha Wildner static int
mdoc_em_pre(MDOC_ARGS)89380387638SSascha Wildner mdoc_em_pre(MDOC_ARGS)
89480387638SSascha Wildner {
895*99db7d0eSSascha Wildner 	print_otag_id(h, TAG_I, "Em", n);
89654ba9607SSascha Wildner 	return 1;
89780387638SSascha Wildner }
89880387638SSascha Wildner 
89980387638SSascha Wildner static int
mdoc_d1_pre(MDOC_ARGS)90080387638SSascha Wildner mdoc_d1_pre(MDOC_ARGS)
90180387638SSascha Wildner {
90254ba9607SSascha Wildner 	switch (n->type) {
90354ba9607SSascha Wildner 	case ROFFT_BLOCK:
90454ba9607SSascha Wildner 		html_close_paragraph(h);
905*99db7d0eSSascha Wildner 		return 1;
90654ba9607SSascha Wildner 	case ROFFT_HEAD:
90754ba9607SSascha Wildner 		return 0;
90854ba9607SSascha Wildner 	case ROFFT_BODY:
909*99db7d0eSSascha Wildner 		break;
91054ba9607SSascha Wildner 	default:
91154ba9607SSascha Wildner 		abort();
91280387638SSascha Wildner 	}
913*99db7d0eSSascha Wildner 	print_otag_id(h, TAG_DIV, "Bd Bd-indent", n);
91454ba9607SSascha Wildner 	if (n->tok == MDOC_Dl)
91554ba9607SSascha Wildner 		print_otag(h, TAG_CODE, "c", "Li");
91654ba9607SSascha Wildner 	return 1;
91780387638SSascha Wildner }
91880387638SSascha Wildner 
91980387638SSascha Wildner static int
mdoc_sx_pre(MDOC_ARGS)92080387638SSascha Wildner mdoc_sx_pre(MDOC_ARGS)
92180387638SSascha Wildner {
92254ba9607SSascha Wildner 	char	*id;
92380387638SSascha Wildner 
92454ba9607SSascha Wildner 	id = html_make_id(n, 0);
92554ba9607SSascha Wildner 	print_otag(h, TAG_A, "chR", "Sx", id);
92654ba9607SSascha Wildner 	free(id);
92754ba9607SSascha Wildner 	return 1;
92880387638SSascha Wildner }
92980387638SSascha Wildner 
93080387638SSascha Wildner static int
mdoc_bd_pre(MDOC_ARGS)93180387638SSascha Wildner mdoc_bd_pre(MDOC_ARGS)
93280387638SSascha Wildner {
933*99db7d0eSSascha Wildner 	char			 buf[20];
93454ba9607SSascha Wildner 	struct roff_node	*nn;
93554ba9607SSascha Wildner 	int			 comp;
93680387638SSascha Wildner 
93754ba9607SSascha Wildner 	switch (n->type) {
93854ba9607SSascha Wildner 	case ROFFT_BLOCK:
93954ba9607SSascha Wildner 		html_close_paragraph(h);
94054ba9607SSascha Wildner 		return 1;
94154ba9607SSascha Wildner 	case ROFFT_HEAD:
94254ba9607SSascha Wildner 		return 0;
94354ba9607SSascha Wildner 	case ROFFT_BODY:
94480387638SSascha Wildner 		break;
94580387638SSascha Wildner 	default:
94654ba9607SSascha Wildner 		abort();
94754ba9607SSascha Wildner 	}
94854ba9607SSascha Wildner 
94954ba9607SSascha Wildner 	/* Handle preceding whitespace. */
95054ba9607SSascha Wildner 
95154ba9607SSascha Wildner 	comp = n->norm->Bd.comp;
95254ba9607SSascha Wildner 	for (nn = n; nn != NULL && comp == 0; nn = nn->parent) {
95354ba9607SSascha Wildner 		if (nn->type != ROFFT_BLOCK)
95454ba9607SSascha Wildner 			continue;
95554ba9607SSascha Wildner 		if (nn->tok == MDOC_Sh || nn->tok == MDOC_Ss)
95654ba9607SSascha Wildner 			comp = 1;
957*99db7d0eSSascha Wildner 		if (roff_node_prev(nn) != NULL)
95880387638SSascha Wildner 			break;
95980387638SSascha Wildner 	}
96054ba9607SSascha Wildner 	(void)strlcpy(buf, "Bd", sizeof(buf));
96154ba9607SSascha Wildner 	if (comp == 0)
96254ba9607SSascha Wildner 		(void)strlcat(buf, " Pp", sizeof(buf));
96380387638SSascha Wildner 
96454ba9607SSascha Wildner 	/* Handle the -offset argument. */
96580387638SSascha Wildner 
96654ba9607SSascha Wildner 	if (n->norm->Bd.offs != NULL &&
96754ba9607SSascha Wildner 	    strcmp(n->norm->Bd.offs, "left") != 0)
96854ba9607SSascha Wildner 		(void)strlcat(buf, " Bd-indent", sizeof(buf));
96960e1e752SSascha Wildner 
970*99db7d0eSSascha Wildner 	if (n->norm->Bd.type == DISP_literal)
971*99db7d0eSSascha Wildner 		(void)strlcat(buf, " Li", sizeof(buf));
972*99db7d0eSSascha Wildner 
973*99db7d0eSSascha Wildner 	print_otag_id(h, TAG_DIV, buf, n);
97454ba9607SSascha Wildner 	return 1;
97580387638SSascha Wildner }
97680387638SSascha Wildner 
97780387638SSascha Wildner static int
mdoc_pa_pre(MDOC_ARGS)97880387638SSascha Wildner mdoc_pa_pre(MDOC_ARGS)
97980387638SSascha Wildner {
98054ba9607SSascha Wildner 	print_otag(h, TAG_SPAN, "c", "Pa");
98154ba9607SSascha Wildner 	return 1;
98280387638SSascha Wildner }
98380387638SSascha Wildner 
98480387638SSascha Wildner static int
mdoc_ad_pre(MDOC_ARGS)98580387638SSascha Wildner mdoc_ad_pre(MDOC_ARGS)
98680387638SSascha Wildner {
98754ba9607SSascha Wildner 	print_otag(h, TAG_SPAN, "c", "Ad");
98854ba9607SSascha Wildner 	return 1;
98980387638SSascha Wildner }
99080387638SSascha Wildner 
99180387638SSascha Wildner static int
mdoc_an_pre(MDOC_ARGS)99280387638SSascha Wildner mdoc_an_pre(MDOC_ARGS)
99380387638SSascha Wildner {
99454ba9607SSascha Wildner 	if (n->norm->An.auth == AUTH_split) {
99554ba9607SSascha Wildner 		h->flags &= ~HTML_NOSPLIT;
99654ba9607SSascha Wildner 		h->flags |= HTML_SPLIT;
99754ba9607SSascha Wildner 		return 0;
99854ba9607SSascha Wildner 	}
99954ba9607SSascha Wildner 	if (n->norm->An.auth == AUTH_nosplit) {
100054ba9607SSascha Wildner 		h->flags &= ~HTML_SPLIT;
100154ba9607SSascha Wildner 		h->flags |= HTML_NOSPLIT;
100254ba9607SSascha Wildner 		return 0;
100354ba9607SSascha Wildner 	}
100480387638SSascha Wildner 
100554ba9607SSascha Wildner 	if (h->flags & HTML_SPLIT)
100654ba9607SSascha Wildner 		print_otag(h, TAG_BR, "");
100780387638SSascha Wildner 
100854ba9607SSascha Wildner 	if (n->sec == SEC_AUTHORS && ! (h->flags & HTML_NOSPLIT))
100954ba9607SSascha Wildner 		h->flags |= HTML_SPLIT;
101054ba9607SSascha Wildner 
101154ba9607SSascha Wildner 	print_otag(h, TAG_SPAN, "c", "An");
101254ba9607SSascha Wildner 	return 1;
101380387638SSascha Wildner }
101480387638SSascha Wildner 
101580387638SSascha Wildner static int
mdoc_cd_pre(MDOC_ARGS)101680387638SSascha Wildner mdoc_cd_pre(MDOC_ARGS)
101780387638SSascha Wildner {
101880387638SSascha Wildner 	synopsis_pre(h, n);
101954ba9607SSascha Wildner 	print_otag(h, TAG_CODE, "c", "Cd");
102054ba9607SSascha Wildner 	return 1;
102180387638SSascha Wildner }
102280387638SSascha Wildner 
102380387638SSascha Wildner static int
mdoc_fa_pre(MDOC_ARGS)102480387638SSascha Wildner mdoc_fa_pre(MDOC_ARGS)
102580387638SSascha Wildner {
102654ba9607SSascha Wildner 	const struct roff_node	*nn;
102780387638SSascha Wildner 	struct tag		*t;
102880387638SSascha Wildner 
102980387638SSascha Wildner 	if (n->parent->tok != MDOC_Fo) {
103054ba9607SSascha Wildner 		print_otag(h, TAG_VAR, "c", "Fa");
103154ba9607SSascha Wildner 		return 1;
103280387638SSascha Wildner 	}
1033*99db7d0eSSascha Wildner 	for (nn = n->child; nn != NULL; nn = nn->next) {
103454ba9607SSascha Wildner 		t = print_otag(h, TAG_VAR, "c", "Fa");
103580387638SSascha Wildner 		print_text(h, nn->string);
103680387638SSascha Wildner 		print_tagq(h, t);
1037*99db7d0eSSascha Wildner 		if (nn->next != NULL) {
103860e1e752SSascha Wildner 			h->flags |= HTML_NOSPACE;
103980387638SSascha Wildner 			print_text(h, ",");
104080387638SSascha Wildner 		}
104160e1e752SSascha Wildner 	}
1042*99db7d0eSSascha Wildner 	if (n->child != NULL &&
1043*99db7d0eSSascha Wildner 	    (nn = roff_node_next(n)) != NULL &&
1044*99db7d0eSSascha Wildner 	    nn->tok == MDOC_Fa) {
104560e1e752SSascha Wildner 		h->flags |= HTML_NOSPACE;
104680387638SSascha Wildner 		print_text(h, ",");
104760e1e752SSascha Wildner 	}
104854ba9607SSascha Wildner 	return 0;
104980387638SSascha Wildner }
105080387638SSascha Wildner 
105180387638SSascha Wildner static int
mdoc_fd_pre(MDOC_ARGS)105280387638SSascha Wildner mdoc_fd_pre(MDOC_ARGS)
105380387638SSascha Wildner {
105460e1e752SSascha Wildner 	struct tag	*t;
105554ba9607SSascha Wildner 	char		*buf, *cp;
105680387638SSascha Wildner 
105780387638SSascha Wildner 	synopsis_pre(h, n);
105880387638SSascha Wildner 
105960e1e752SSascha Wildner 	if (NULL == (n = n->child))
106054ba9607SSascha Wildner 		return 0;
106160e1e752SSascha Wildner 
106254ba9607SSascha Wildner 	assert(n->type == ROFFT_TEXT);
106360e1e752SSascha Wildner 
106460e1e752SSascha Wildner 	if (strcmp(n->string, "#include")) {
106554ba9607SSascha Wildner 		print_otag(h, TAG_CODE, "c", "Fd");
106654ba9607SSascha Wildner 		return 1;
106780387638SSascha Wildner 	}
106880387638SSascha Wildner 
106954ba9607SSascha Wildner 	print_otag(h, TAG_CODE, "c", "In");
107060e1e752SSascha Wildner 	print_text(h, n->string);
107160e1e752SSascha Wildner 
107260e1e752SSascha Wildner 	if (NULL != (n = n->next)) {
107354ba9607SSascha Wildner 		assert(n->type == ROFFT_TEXT);
1074070c62a6SFranco Fichtner 
107560e1e752SSascha Wildner 		if (h->base_includes) {
107654ba9607SSascha Wildner 			cp = n->string;
107754ba9607SSascha Wildner 			if (*cp == '<' || *cp == '"')
107854ba9607SSascha Wildner 				cp++;
107954ba9607SSascha Wildner 			buf = mandoc_strdup(cp);
108054ba9607SSascha Wildner 			cp = strchr(buf, '\0') - 1;
108154ba9607SSascha Wildner 			if (cp >= buf && (*cp == '>' || *cp == '"'))
108254ba9607SSascha Wildner 				*cp = '\0';
108354ba9607SSascha Wildner 			t = print_otag(h, TAG_A, "chI", "In", buf);
108454ba9607SSascha Wildner 			free(buf);
108554ba9607SSascha Wildner 		} else
108654ba9607SSascha Wildner 			t = print_otag(h, TAG_A, "c", "In");
108760e1e752SSascha Wildner 
108860e1e752SSascha Wildner 		print_text(h, n->string);
108960e1e752SSascha Wildner 		print_tagq(h, t);
109060e1e752SSascha Wildner 
109160e1e752SSascha Wildner 		n = n->next;
109260e1e752SSascha Wildner 	}
109360e1e752SSascha Wildner 
109460e1e752SSascha Wildner 	for ( ; n; n = n->next) {
109554ba9607SSascha Wildner 		assert(n->type == ROFFT_TEXT);
109660e1e752SSascha Wildner 		print_text(h, n->string);
109760e1e752SSascha Wildner 	}
109860e1e752SSascha Wildner 
109954ba9607SSascha Wildner 	return 0;
110060e1e752SSascha Wildner }
110160e1e752SSascha Wildner 
110280387638SSascha Wildner static int
mdoc_vt_pre(MDOC_ARGS)110380387638SSascha Wildner mdoc_vt_pre(MDOC_ARGS)
110480387638SSascha Wildner {
110554ba9607SSascha Wildner 	if (n->type == ROFFT_BLOCK) {
110680387638SSascha Wildner 		synopsis_pre(h, n);
110754ba9607SSascha Wildner 		return 1;
110854ba9607SSascha Wildner 	} else if (n->type == ROFFT_ELEM) {
110980387638SSascha Wildner 		synopsis_pre(h, n);
111054ba9607SSascha Wildner 	} else if (n->type == ROFFT_HEAD)
111154ba9607SSascha Wildner 		return 0;
111280387638SSascha Wildner 
111354ba9607SSascha Wildner 	print_otag(h, TAG_VAR, "c", "Vt");
111454ba9607SSascha Wildner 	return 1;
111580387638SSascha Wildner }
111680387638SSascha Wildner 
111780387638SSascha Wildner static int
mdoc_ft_pre(MDOC_ARGS)111880387638SSascha Wildner mdoc_ft_pre(MDOC_ARGS)
111980387638SSascha Wildner {
112080387638SSascha Wildner 	synopsis_pre(h, n);
112154ba9607SSascha Wildner 	print_otag(h, TAG_VAR, "c", "Ft");
112254ba9607SSascha Wildner 	return 1;
112380387638SSascha Wildner }
112480387638SSascha Wildner 
112580387638SSascha Wildner static int
mdoc_fn_pre(MDOC_ARGS)112680387638SSascha Wildner mdoc_fn_pre(MDOC_ARGS)
112780387638SSascha Wildner {
112880387638SSascha Wildner 	struct tag	*t;
112980387638SSascha Wildner 	char		 nbuf[BUFSIZ];
113080387638SSascha Wildner 	const char	*sp, *ep;
113154ba9607SSascha Wildner 	int		 sz, pretty;
113280387638SSascha Wildner 
113354ba9607SSascha Wildner 	pretty = NODE_SYNPRETTY & n->flags;
113480387638SSascha Wildner 	synopsis_pre(h, n);
113580387638SSascha Wildner 
113680387638SSascha Wildner 	/* Split apart into type and name. */
113780387638SSascha Wildner 	assert(n->child->string);
113880387638SSascha Wildner 	sp = n->child->string;
113980387638SSascha Wildner 
114080387638SSascha Wildner 	ep = strchr(sp, ' ');
114180387638SSascha Wildner 	if (NULL != ep) {
114254ba9607SSascha Wildner 		t = print_otag(h, TAG_VAR, "c", "Ft");
114380387638SSascha Wildner 
114480387638SSascha Wildner 		while (ep) {
114580387638SSascha Wildner 			sz = MIN((int)(ep - sp), BUFSIZ - 1);
114680387638SSascha Wildner 			(void)memcpy(nbuf, sp, (size_t)sz);
114780387638SSascha Wildner 			nbuf[sz] = '\0';
114880387638SSascha Wildner 			print_text(h, nbuf);
114980387638SSascha Wildner 			sp = ++ep;
115080387638SSascha Wildner 			ep = strchr(sp, ' ');
115180387638SSascha Wildner 		}
115280387638SSascha Wildner 		print_tagq(h, t);
115380387638SSascha Wildner 	}
115480387638SSascha Wildner 
1155*99db7d0eSSascha Wildner 	t = print_otag_id(h, TAG_CODE, "Fn", n);
115680387638SSascha Wildner 
1157070c62a6SFranco Fichtner 	if (sp)
1158070c62a6SFranco Fichtner 		print_text(h, sp);
115980387638SSascha Wildner 
116080387638SSascha Wildner 	print_tagq(h, t);
116180387638SSascha Wildner 
116280387638SSascha Wildner 	h->flags |= HTML_NOSPACE;
116380387638SSascha Wildner 	print_text(h, "(");
1164a4c7eb57SSascha Wildner 	h->flags |= HTML_NOSPACE;
116580387638SSascha Wildner 
116660e1e752SSascha Wildner 	for (n = n->child->next; n; n = n->next) {
116754ba9607SSascha Wildner 		if (NODE_SYNPRETTY & n->flags)
116854ba9607SSascha Wildner 			t = print_otag(h, TAG_VAR, "cs", "Fa",
116954ba9607SSascha Wildner 			    "white-space", "nowrap");
117054ba9607SSascha Wildner 		else
117154ba9607SSascha Wildner 			t = print_otag(h, TAG_VAR, "c", "Fa");
117260e1e752SSascha Wildner 		print_text(h, n->string);
117380387638SSascha Wildner 		print_tagq(h, t);
117460e1e752SSascha Wildner 		if (n->next) {
117560e1e752SSascha Wildner 			h->flags |= HTML_NOSPACE;
117680387638SSascha Wildner 			print_text(h, ",");
117780387638SSascha Wildner 		}
117860e1e752SSascha Wildner 	}
117980387638SSascha Wildner 
118060e1e752SSascha Wildner 	h->flags |= HTML_NOSPACE;
118180387638SSascha Wildner 	print_text(h, ")");
118260e1e752SSascha Wildner 
118360e1e752SSascha Wildner 	if (pretty) {
118460e1e752SSascha Wildner 		h->flags |= HTML_NOSPACE;
118580387638SSascha Wildner 		print_text(h, ";");
118660e1e752SSascha Wildner 	}
118780387638SSascha Wildner 
118854ba9607SSascha Wildner 	return 0;
118980387638SSascha Wildner }
119080387638SSascha Wildner 
119180387638SSascha Wildner static int
mdoc_sm_pre(MDOC_ARGS)119280387638SSascha Wildner mdoc_sm_pre(MDOC_ARGS)
119380387638SSascha Wildner {
119480387638SSascha Wildner 
1195070c62a6SFranco Fichtner 	if (NULL == n->child)
1196070c62a6SFranco Fichtner 		h->flags ^= HTML_NONOSPACE;
1197070c62a6SFranco Fichtner 	else if (0 == strcmp("on", n->child->string))
119880387638SSascha Wildner 		h->flags &= ~HTML_NONOSPACE;
1199070c62a6SFranco Fichtner 	else
120080387638SSascha Wildner 		h->flags |= HTML_NONOSPACE;
120180387638SSascha Wildner 
1202070c62a6SFranco Fichtner 	if ( ! (HTML_NONOSPACE & h->flags))
1203070c62a6SFranco Fichtner 		h->flags &= ~HTML_NOSPACE;
1204070c62a6SFranco Fichtner 
120554ba9607SSascha Wildner 	return 0;
120680387638SSascha Wildner }
120780387638SSascha Wildner 
1208070c62a6SFranco Fichtner static int
mdoc_skip_pre(MDOC_ARGS)1209070c62a6SFranco Fichtner mdoc_skip_pre(MDOC_ARGS)
1210070c62a6SFranco Fichtner {
1211070c62a6SFranco Fichtner 
121254ba9607SSascha Wildner 	return 0;
1213070c62a6SFranco Fichtner }
1214070c62a6SFranco Fichtner 
121580387638SSascha Wildner static int
mdoc_pp_pre(MDOC_ARGS)121680387638SSascha Wildner mdoc_pp_pre(MDOC_ARGS)
121780387638SSascha Wildner {
1218*99db7d0eSSascha Wildner 	char	*id;
1219*99db7d0eSSascha Wildner 
1220*99db7d0eSSascha Wildner 	if (n->flags & NODE_NOFILL) {
1221*99db7d0eSSascha Wildner 		print_endline(h);
1222*99db7d0eSSascha Wildner 		if (n->flags & NODE_ID)
1223*99db7d0eSSascha Wildner 			mdoc_tg_pre(meta, n, h);
1224*99db7d0eSSascha Wildner 		else {
1225*99db7d0eSSascha Wildner 			h->col = 1;
1226*99db7d0eSSascha Wildner 			print_endline(h);
1227*99db7d0eSSascha Wildner 		}
1228*99db7d0eSSascha Wildner 	} else {
122954ba9607SSascha Wildner 		html_close_paragraph(h);
1230*99db7d0eSSascha Wildner 		id = n->flags & NODE_ID ? html_make_id(n, 1) : NULL;
1231*99db7d0eSSascha Wildner 		print_otag(h, TAG_P, "ci", "Pp", id);
1232*99db7d0eSSascha Wildner 		free(id);
123380387638SSascha Wildner 	}
123454ba9607SSascha Wildner 	return 0;
123580387638SSascha Wildner }
123680387638SSascha Wildner 
123780387638SSascha Wildner static int
mdoc_lk_pre(MDOC_ARGS)123880387638SSascha Wildner mdoc_lk_pre(MDOC_ARGS)
123980387638SSascha Wildner {
124054ba9607SSascha Wildner 	const struct roff_node *link, *descr, *punct;
124154ba9607SSascha Wildner 	struct tag	*t;
124280387638SSascha Wildner 
124354ba9607SSascha Wildner 	if ((link = n->child) == NULL)
124454ba9607SSascha Wildner 		return 0;
124560e1e752SSascha Wildner 
124654ba9607SSascha Wildner 	/* Find beginning of trailing punctuation. */
124754ba9607SSascha Wildner 	punct = n->last;
124854ba9607SSascha Wildner 	while (punct != link && punct->flags & NODE_DELIMC)
124954ba9607SSascha Wildner 		punct = punct->prev;
125054ba9607SSascha Wildner 	punct = punct->next;
125180387638SSascha Wildner 
125254ba9607SSascha Wildner 	/* Link target and link text. */
125354ba9607SSascha Wildner 	descr = link->next;
125454ba9607SSascha Wildner 	if (descr == punct)
125554ba9607SSascha Wildner 		descr = link;  /* no text */
125654ba9607SSascha Wildner 	t = print_otag(h, TAG_A, "ch", "Lk", link->string);
125754ba9607SSascha Wildner 	do {
125854ba9607SSascha Wildner 		if (descr->flags & (NODE_DELIMC | NODE_DELIMO))
125954ba9607SSascha Wildner 			h->flags |= HTML_NOSPACE;
126054ba9607SSascha Wildner 		print_text(h, descr->string);
126154ba9607SSascha Wildner 		descr = descr->next;
126254ba9607SSascha Wildner 	} while (descr != punct);
126354ba9607SSascha Wildner 	print_tagq(h, t);
126460e1e752SSascha Wildner 
126554ba9607SSascha Wildner 	/* Trailing punctuation. */
126654ba9607SSascha Wildner 	while (punct != NULL) {
126754ba9607SSascha Wildner 		h->flags |= HTML_NOSPACE;
126854ba9607SSascha Wildner 		print_text(h, punct->string);
126954ba9607SSascha Wildner 		punct = punct->next;
127054ba9607SSascha Wildner 	}
127154ba9607SSascha Wildner 	return 0;
127280387638SSascha Wildner }
127380387638SSascha Wildner 
127480387638SSascha Wildner static int
mdoc_mt_pre(MDOC_ARGS)127580387638SSascha Wildner mdoc_mt_pre(MDOC_ARGS)
127680387638SSascha Wildner {
127780387638SSascha Wildner 	struct tag	*t;
127854ba9607SSascha Wildner 	char		*cp;
127980387638SSascha Wildner 
128060e1e752SSascha Wildner 	for (n = n->child; n; n = n->next) {
128154ba9607SSascha Wildner 		assert(n->type == ROFFT_TEXT);
128254ba9607SSascha Wildner 		mandoc_asprintf(&cp, "mailto:%s", n->string);
128354ba9607SSascha Wildner 		t = print_otag(h, TAG_A, "ch", "Mt", cp);
128460e1e752SSascha Wildner 		print_text(h, n->string);
128580387638SSascha Wildner 		print_tagq(h, t);
128654ba9607SSascha Wildner 		free(cp);
128780387638SSascha Wildner 	}
128854ba9607SSascha Wildner 	return 0;
128980387638SSascha Wildner }
129080387638SSascha Wildner 
129180387638SSascha Wildner static int
mdoc_fo_pre(MDOC_ARGS)129280387638SSascha Wildner mdoc_fo_pre(MDOC_ARGS)
129380387638SSascha Wildner {
129480387638SSascha Wildner 	struct tag	*t;
129580387638SSascha Wildner 
1296*99db7d0eSSascha Wildner 	switch (n->type) {
1297*99db7d0eSSascha Wildner 	case ROFFT_BLOCK:
1298*99db7d0eSSascha Wildner 		synopsis_pre(h, n);
1299*99db7d0eSSascha Wildner 		return 1;
1300*99db7d0eSSascha Wildner 	case ROFFT_HEAD:
1301*99db7d0eSSascha Wildner 		if (n->child != NULL) {
1302*99db7d0eSSascha Wildner 			t = print_otag_id(h, TAG_CODE, "Fn", n);
1303*99db7d0eSSascha Wildner 			print_text(h, n->child->string);
1304*99db7d0eSSascha Wildner 			print_tagq(h, t);
1305*99db7d0eSSascha Wildner 		}
1306*99db7d0eSSascha Wildner 		return 0;
1307*99db7d0eSSascha Wildner 	case ROFFT_BODY:
130880387638SSascha Wildner 		h->flags |= HTML_NOSPACE;
130980387638SSascha Wildner 		print_text(h, "(");
131080387638SSascha Wildner 		h->flags |= HTML_NOSPACE;
131154ba9607SSascha Wildner 		return 1;
1312*99db7d0eSSascha Wildner 	default:
1313*99db7d0eSSascha Wildner 		abort();
131480387638SSascha Wildner 	}
131580387638SSascha Wildner }
131680387638SSascha Wildner 
131780387638SSascha Wildner static void
mdoc_fo_post(MDOC_ARGS)131880387638SSascha Wildner mdoc_fo_post(MDOC_ARGS)
131980387638SSascha Wildner {
132054ba9607SSascha Wildner 	if (n->type != ROFFT_BODY)
132180387638SSascha Wildner 		return;
132260e1e752SSascha Wildner 	h->flags |= HTML_NOSPACE;
132380387638SSascha Wildner 	print_text(h, ")");
132460e1e752SSascha Wildner 	h->flags |= HTML_NOSPACE;
132580387638SSascha Wildner 	print_text(h, ";");
132680387638SSascha Wildner }
132780387638SSascha Wildner 
132880387638SSascha Wildner static int
mdoc_in_pre(MDOC_ARGS)132980387638SSascha Wildner mdoc_in_pre(MDOC_ARGS)
133080387638SSascha Wildner {
133180387638SSascha Wildner 	struct tag	*t;
133280387638SSascha Wildner 
133380387638SSascha Wildner 	synopsis_pre(h, n);
133454ba9607SSascha Wildner 	print_otag(h, TAG_CODE, "c", "In");
133580387638SSascha Wildner 
133660e1e752SSascha Wildner 	/*
133760e1e752SSascha Wildner 	 * The first argument of the `In' gets special treatment as
133860e1e752SSascha Wildner 	 * being a linked value.  Subsequent values are printed
133960e1e752SSascha Wildner 	 * afterward.  groff does similarly.  This also handles the case
134060e1e752SSascha Wildner 	 * of no children.
134160e1e752SSascha Wildner 	 */
134260e1e752SSascha Wildner 
134354ba9607SSascha Wildner 	if (NODE_SYNPRETTY & n->flags && NODE_LINE & n->flags)
134480387638SSascha Wildner 		print_text(h, "#include");
134580387638SSascha Wildner 
134680387638SSascha Wildner 	print_text(h, "<");
134780387638SSascha Wildner 	h->flags |= HTML_NOSPACE;
134880387638SSascha Wildner 
134960e1e752SSascha Wildner 	if (NULL != (n = n->child)) {
135054ba9607SSascha Wildner 		assert(n->type == ROFFT_TEXT);
135160e1e752SSascha Wildner 
135254ba9607SSascha Wildner 		if (h->base_includes)
135354ba9607SSascha Wildner 			t = print_otag(h, TAG_A, "chI", "In", n->string);
135454ba9607SSascha Wildner 		else
135554ba9607SSascha Wildner 			t = print_otag(h, TAG_A, "c", "In");
135660e1e752SSascha Wildner 		print_text(h, n->string);
135780387638SSascha Wildner 		print_tagq(h, t);
135860e1e752SSascha Wildner 
135960e1e752SSascha Wildner 		n = n->next;
136080387638SSascha Wildner 	}
136180387638SSascha Wildner 
136280387638SSascha Wildner 	h->flags |= HTML_NOSPACE;
136380387638SSascha Wildner 	print_text(h, ">");
136480387638SSascha Wildner 
136560e1e752SSascha Wildner 	for ( ; n; n = n->next) {
136654ba9607SSascha Wildner 		assert(n->type == ROFFT_TEXT);
136760e1e752SSascha Wildner 		print_text(h, n->string);
136860e1e752SSascha Wildner 	}
136954ba9607SSascha Wildner 	return 0;
137080387638SSascha Wildner }
137180387638SSascha Wildner 
137280387638SSascha Wildner static int
mdoc_va_pre(MDOC_ARGS)137380387638SSascha Wildner mdoc_va_pre(MDOC_ARGS)
137480387638SSascha Wildner {
137554ba9607SSascha Wildner 	print_otag(h, TAG_VAR, "c", "Va");
137654ba9607SSascha Wildner 	return 1;
137780387638SSascha Wildner }
137880387638SSascha Wildner 
137980387638SSascha Wildner static int
mdoc_ap_pre(MDOC_ARGS)138080387638SSascha Wildner mdoc_ap_pre(MDOC_ARGS)
138180387638SSascha Wildner {
138280387638SSascha Wildner 	h->flags |= HTML_NOSPACE;
138380387638SSascha Wildner 	print_text(h, "\\(aq");
138480387638SSascha Wildner 	h->flags |= HTML_NOSPACE;
138554ba9607SSascha Wildner 	return 1;
138680387638SSascha Wildner }
138780387638SSascha Wildner 
138880387638SSascha Wildner static int
mdoc_bf_pre(MDOC_ARGS)138980387638SSascha Wildner mdoc_bf_pre(MDOC_ARGS)
139080387638SSascha Wildner {
139154ba9607SSascha Wildner 	const char	*cattr;
139280387638SSascha Wildner 
139354ba9607SSascha Wildner 	switch (n->type) {
139454ba9607SSascha Wildner 	case ROFFT_BLOCK:
139554ba9607SSascha Wildner 		html_close_paragraph(h);
139654ba9607SSascha Wildner 		return 1;
139754ba9607SSascha Wildner 	case ROFFT_HEAD:
139854ba9607SSascha Wildner 		return 0;
139954ba9607SSascha Wildner 	case ROFFT_BODY:
140054ba9607SSascha Wildner 		break;
140154ba9607SSascha Wildner 	default:
140254ba9607SSascha Wildner 		abort();
140354ba9607SSascha Wildner 	}
140480387638SSascha Wildner 
140580387638SSascha Wildner 	if (FONT_Em == n->norm->Bf.font)
140654ba9607SSascha Wildner 		cattr = "Bf Em";
140780387638SSascha Wildner 	else if (FONT_Sy == n->norm->Bf.font)
140854ba9607SSascha Wildner 		cattr = "Bf Sy";
140980387638SSascha Wildner 	else if (FONT_Li == n->norm->Bf.font)
141054ba9607SSascha Wildner 		cattr = "Bf Li";
141180387638SSascha Wildner 	else
141254ba9607SSascha Wildner 		cattr = "Bf No";
141380387638SSascha Wildner 
141454ba9607SSascha Wildner 	/* Cannot use TAG_SPAN because it may contain blocks. */
141554ba9607SSascha Wildner 	print_otag(h, TAG_DIV, "c", cattr);
141654ba9607SSascha Wildner 	return 1;
141780387638SSascha Wildner }
141880387638SSascha Wildner 
141980387638SSascha Wildner static int
mdoc_igndelim_pre(MDOC_ARGS)142080387638SSascha Wildner mdoc_igndelim_pre(MDOC_ARGS)
142180387638SSascha Wildner {
142280387638SSascha Wildner 	h->flags |= HTML_IGNDELIM;
142354ba9607SSascha Wildner 	return 1;
142480387638SSascha Wildner }
142580387638SSascha Wildner 
142680387638SSascha Wildner static void
mdoc_pf_post(MDOC_ARGS)142780387638SSascha Wildner mdoc_pf_post(MDOC_ARGS)
142880387638SSascha Wildner {
142954ba9607SSascha Wildner 	if ( ! (n->next == NULL || n->next->flags & NODE_LINE))
143080387638SSascha Wildner 		h->flags |= HTML_NOSPACE;
143180387638SSascha Wildner }
143280387638SSascha Wildner 
143380387638SSascha Wildner static int
mdoc_rs_pre(MDOC_ARGS)143480387638SSascha Wildner mdoc_rs_pre(MDOC_ARGS)
143580387638SSascha Wildner {
143654ba9607SSascha Wildner 	switch (n->type) {
143754ba9607SSascha Wildner 	case ROFFT_BLOCK:
143854ba9607SSascha Wildner 		if (n->sec == SEC_SEE_ALSO)
143954ba9607SSascha Wildner 			html_close_paragraph(h);
144054ba9607SSascha Wildner 		break;
144154ba9607SSascha Wildner 	case ROFFT_HEAD:
144254ba9607SSascha Wildner 		return 0;
144354ba9607SSascha Wildner 	case ROFFT_BODY:
144454ba9607SSascha Wildner 		if (n->sec == SEC_SEE_ALSO)
144554ba9607SSascha Wildner 			print_otag(h, TAG_P, "c", "Pp");
144654ba9607SSascha Wildner 		print_otag(h, TAG_CITE, "c", "Rs");
144754ba9607SSascha Wildner 		break;
144854ba9607SSascha Wildner 	default:
144954ba9607SSascha Wildner 		abort();
145054ba9607SSascha Wildner 	}
145154ba9607SSascha Wildner 	return 1;
145254ba9607SSascha Wildner }
145380387638SSascha Wildner 
145454ba9607SSascha Wildner static int
mdoc_no_pre(MDOC_ARGS)145554ba9607SSascha Wildner mdoc_no_pre(MDOC_ARGS)
145654ba9607SSascha Wildner {
1457*99db7d0eSSascha Wildner 	print_otag_id(h, TAG_SPAN, roff_name[n->tok], n);
145854ba9607SSascha Wildner 	return 1;
145980387638SSascha Wildner }
146080387638SSascha Wildner 
146180387638SSascha Wildner static int
mdoc_sy_pre(MDOC_ARGS)146280387638SSascha Wildner mdoc_sy_pre(MDOC_ARGS)
146380387638SSascha Wildner {
1464*99db7d0eSSascha Wildner 	print_otag_id(h, TAG_B, "Sy", n);
146554ba9607SSascha Wildner 	return 1;
146680387638SSascha Wildner }
146780387638SSascha Wildner 
146880387638SSascha Wildner static int
mdoc_lb_pre(MDOC_ARGS)146980387638SSascha Wildner mdoc_lb_pre(MDOC_ARGS)
147080387638SSascha Wildner {
1471*99db7d0eSSascha Wildner 	if (n->sec == SEC_LIBRARY &&
1472*99db7d0eSSascha Wildner 	    n->flags & NODE_LINE &&
1473*99db7d0eSSascha Wildner 	    roff_node_prev(n) != NULL)
147454ba9607SSascha Wildner 		print_otag(h, TAG_BR, "");
147580387638SSascha Wildner 
147654ba9607SSascha Wildner 	print_otag(h, TAG_SPAN, "c", "Lb");
147754ba9607SSascha Wildner 	return 1;
147880387638SSascha Wildner }
147980387638SSascha Wildner 
148080387638SSascha Wildner static int
mdoc__x_pre(MDOC_ARGS)148180387638SSascha Wildner mdoc__x_pre(MDOC_ARGS)
148280387638SSascha Wildner {
1483*99db7d0eSSascha Wildner 	struct roff_node	*nn;
148454ba9607SSascha Wildner 	const char		*cattr;
148580387638SSascha Wildner 	enum htmltag		 t;
148680387638SSascha Wildner 
148780387638SSascha Wildner 	t = TAG_SPAN;
148880387638SSascha Wildner 
148980387638SSascha Wildner 	switch (n->tok) {
1490070c62a6SFranco Fichtner 	case MDOC__A:
149154ba9607SSascha Wildner 		cattr = "RsA";
1492*99db7d0eSSascha Wildner 		if ((nn = roff_node_prev(n)) != NULL && nn->tok == MDOC__A &&
1493*99db7d0eSSascha Wildner 		    ((nn = roff_node_next(n)) == NULL || nn->tok != MDOC__A))
149480387638SSascha Wildner 			print_text(h, "and");
149580387638SSascha Wildner 		break;
1496070c62a6SFranco Fichtner 	case MDOC__B:
149780387638SSascha Wildner 		t = TAG_I;
149854ba9607SSascha Wildner 		cattr = "RsB";
149980387638SSascha Wildner 		break;
1500070c62a6SFranco Fichtner 	case MDOC__C:
150154ba9607SSascha Wildner 		cattr = "RsC";
150280387638SSascha Wildner 		break;
1503070c62a6SFranco Fichtner 	case MDOC__D:
150454ba9607SSascha Wildner 		cattr = "RsD";
150580387638SSascha Wildner 		break;
1506070c62a6SFranco Fichtner 	case MDOC__I:
150780387638SSascha Wildner 		t = TAG_I;
150854ba9607SSascha Wildner 		cattr = "RsI";
150980387638SSascha Wildner 		break;
1510070c62a6SFranco Fichtner 	case MDOC__J:
151180387638SSascha Wildner 		t = TAG_I;
151254ba9607SSascha Wildner 		cattr = "RsJ";
151380387638SSascha Wildner 		break;
1514070c62a6SFranco Fichtner 	case MDOC__N:
151554ba9607SSascha Wildner 		cattr = "RsN";
151680387638SSascha Wildner 		break;
1517070c62a6SFranco Fichtner 	case MDOC__O:
151854ba9607SSascha Wildner 		cattr = "RsO";
151980387638SSascha Wildner 		break;
1520070c62a6SFranco Fichtner 	case MDOC__P:
152154ba9607SSascha Wildner 		cattr = "RsP";
152280387638SSascha Wildner 		break;
1523070c62a6SFranco Fichtner 	case MDOC__Q:
152454ba9607SSascha Wildner 		cattr = "RsQ";
152580387638SSascha Wildner 		break;
1526070c62a6SFranco Fichtner 	case MDOC__R:
152754ba9607SSascha Wildner 		cattr = "RsR";
152880387638SSascha Wildner 		break;
1529070c62a6SFranco Fichtner 	case MDOC__T:
153054ba9607SSascha Wildner 		cattr = "RsT";
153180387638SSascha Wildner 		break;
1532070c62a6SFranco Fichtner 	case MDOC__U:
153354ba9607SSascha Wildner 		print_otag(h, TAG_A, "ch", "RsU", n->child->string);
153454ba9607SSascha Wildner 		return 1;
1535070c62a6SFranco Fichtner 	case MDOC__V:
153654ba9607SSascha Wildner 		cattr = "RsV";
153780387638SSascha Wildner 		break;
153880387638SSascha Wildner 	default:
153980387638SSascha Wildner 		abort();
154080387638SSascha Wildner 	}
154180387638SSascha Wildner 
154254ba9607SSascha Wildner 	print_otag(h, t, "c", cattr);
154354ba9607SSascha Wildner 	return 1;
154480387638SSascha Wildner }
154580387638SSascha Wildner 
154680387638SSascha Wildner static void
mdoc__x_post(MDOC_ARGS)154780387638SSascha Wildner mdoc__x_post(MDOC_ARGS)
154880387638SSascha Wildner {
1549*99db7d0eSSascha Wildner 	struct roff_node *nn;
155080387638SSascha Wildner 
1551*99db7d0eSSascha Wildner 	if (n->tok == MDOC__A &&
1552*99db7d0eSSascha Wildner 	    (nn = roff_node_next(n)) != NULL && nn->tok == MDOC__A &&
1553*99db7d0eSSascha Wildner 	    ((nn = roff_node_next(nn)) == NULL || nn->tok != MDOC__A) &&
1554*99db7d0eSSascha Wildner 	    ((nn = roff_node_prev(n)) == NULL || nn->tok != MDOC__A))
155580387638SSascha Wildner 		return;
155680387638SSascha Wildner 
155780387638SSascha Wildner 	/* TODO: %U */
155880387638SSascha Wildner 
1559*99db7d0eSSascha Wildner 	if (n->parent == NULL || n->parent->tok != MDOC_Rs)
156080387638SSascha Wildner 		return;
156180387638SSascha Wildner 
156260e1e752SSascha Wildner 	h->flags |= HTML_NOSPACE;
1563*99db7d0eSSascha Wildner 	print_text(h, roff_node_next(n) ? "," : ".");
156480387638SSascha Wildner }
156580387638SSascha Wildner 
156680387638SSascha Wildner static int
mdoc_bk_pre(MDOC_ARGS)156780387638SSascha Wildner mdoc_bk_pre(MDOC_ARGS)
156880387638SSascha Wildner {
156980387638SSascha Wildner 
157080387638SSascha Wildner 	switch (n->type) {
157154ba9607SSascha Wildner 	case ROFFT_BLOCK:
157280387638SSascha Wildner 		break;
157354ba9607SSascha Wildner 	case ROFFT_HEAD:
157454ba9607SSascha Wildner 		return 0;
157554ba9607SSascha Wildner 	case ROFFT_BODY:
157654ba9607SSascha Wildner 		if (n->parent->args != NULL || n->prev->child == NULL)
157780387638SSascha Wildner 			h->flags |= HTML_PREKEEP;
157880387638SSascha Wildner 		break;
157980387638SSascha Wildner 	default:
158080387638SSascha Wildner 		abort();
158180387638SSascha Wildner 	}
158280387638SSascha Wildner 
158354ba9607SSascha Wildner 	return 1;
158480387638SSascha Wildner }
158580387638SSascha Wildner 
158680387638SSascha Wildner static void
mdoc_bk_post(MDOC_ARGS)158780387638SSascha Wildner mdoc_bk_post(MDOC_ARGS)
158880387638SSascha Wildner {
158980387638SSascha Wildner 
159054ba9607SSascha Wildner 	if (n->type == ROFFT_BODY)
159180387638SSascha Wildner 		h->flags &= ~(HTML_KEEP | HTML_PREKEEP);
159280387638SSascha Wildner }
159380387638SSascha Wildner 
159480387638SSascha Wildner static int
mdoc_quote_pre(MDOC_ARGS)159580387638SSascha Wildner mdoc_quote_pre(MDOC_ARGS)
159680387638SSascha Wildner {
159754ba9607SSascha Wildner 	if (n->type != ROFFT_BODY)
159854ba9607SSascha Wildner 		return 1;
159980387638SSascha Wildner 
160080387638SSascha Wildner 	switch (n->tok) {
1601070c62a6SFranco Fichtner 	case MDOC_Ao:
1602070c62a6SFranco Fichtner 	case MDOC_Aq:
160354ba9607SSascha Wildner 		print_text(h, n->child != NULL && n->child->next == NULL &&
160454ba9607SSascha Wildner 		    n->child->tok == MDOC_Mt ?  "<" : "\\(la");
160580387638SSascha Wildner 		break;
1606070c62a6SFranco Fichtner 	case MDOC_Bro:
1607070c62a6SFranco Fichtner 	case MDOC_Brq:
160880387638SSascha Wildner 		print_text(h, "\\(lC");
160980387638SSascha Wildner 		break;
1610070c62a6SFranco Fichtner 	case MDOC_Bo:
1611070c62a6SFranco Fichtner 	case MDOC_Bq:
161280387638SSascha Wildner 		print_text(h, "\\(lB");
161380387638SSascha Wildner 		break;
1614070c62a6SFranco Fichtner 	case MDOC_Oo:
1615070c62a6SFranco Fichtner 	case MDOC_Op:
161680387638SSascha Wildner 		print_text(h, "\\(lB");
161754ba9607SSascha Wildner 		/*
161854ba9607SSascha Wildner 		 * Give up on semantic markup for now.
161954ba9607SSascha Wildner 		 * We cannot use TAG_SPAN because .Oo may contain blocks.
1620*99db7d0eSSascha Wildner 		 * We cannot use TAG_DIV because we might be in a
162154ba9607SSascha Wildner 		 * phrasing context (like .Dl or .Pp); we cannot
162254ba9607SSascha Wildner 		 * close out a .Pp at this point either because
162354ba9607SSascha Wildner 		 * that would break the line.
162454ba9607SSascha Wildner 		 */
162554ba9607SSascha Wildner 		/* XXX print_otag(h, TAG_???, "c", "Op"); */
162680387638SSascha Wildner 		break;
1627070c62a6SFranco Fichtner 	case MDOC_En:
1628070c62a6SFranco Fichtner 		if (NULL == n->norm->Es ||
1629070c62a6SFranco Fichtner 		    NULL == n->norm->Es->child)
163054ba9607SSascha Wildner 			return 1;
1631070c62a6SFranco Fichtner 		print_text(h, n->norm->Es->child->string);
163236342e81SSascha Wildner 		break;
1633070c62a6SFranco Fichtner 	case MDOC_Do:
1634070c62a6SFranco Fichtner 	case MDOC_Dq:
1635*99db7d0eSSascha Wildner 		print_text(h, "\\(lq");
1636*99db7d0eSSascha Wildner 		break;
1637070c62a6SFranco Fichtner 	case MDOC_Qo:
1638070c62a6SFranco Fichtner 	case MDOC_Qq:
1639*99db7d0eSSascha Wildner 		print_text(h, "\"");
164080387638SSascha Wildner 		break;
1641070c62a6SFranco Fichtner 	case MDOC_Po:
1642070c62a6SFranco Fichtner 	case MDOC_Pq:
164380387638SSascha Wildner 		print_text(h, "(");
164480387638SSascha Wildner 		break;
1645070c62a6SFranco Fichtner 	case MDOC_Ql:
164636342e81SSascha Wildner 		print_text(h, "\\(oq");
164736342e81SSascha Wildner 		h->flags |= HTML_NOSPACE;
164854ba9607SSascha Wildner 		print_otag(h, TAG_CODE, "c", "Li");
164936342e81SSascha Wildner 		break;
1650070c62a6SFranco Fichtner 	case MDOC_So:
1651070c62a6SFranco Fichtner 	case MDOC_Sq:
165280387638SSascha Wildner 		print_text(h, "\\(oq");
165380387638SSascha Wildner 		break;
165480387638SSascha Wildner 	default:
165580387638SSascha Wildner 		abort();
165680387638SSascha Wildner 	}
165780387638SSascha Wildner 
165880387638SSascha Wildner 	h->flags |= HTML_NOSPACE;
165954ba9607SSascha Wildner 	return 1;
166080387638SSascha Wildner }
166180387638SSascha Wildner 
166280387638SSascha Wildner static void
mdoc_quote_post(MDOC_ARGS)166380387638SSascha Wildner mdoc_quote_post(MDOC_ARGS)
166480387638SSascha Wildner {
166580387638SSascha Wildner 
166654ba9607SSascha Wildner 	if (n->type != ROFFT_BODY && n->type != ROFFT_ELEM)
166780387638SSascha Wildner 		return;
166880387638SSascha Wildner 
166980387638SSascha Wildner 	h->flags |= HTML_NOSPACE;
167080387638SSascha Wildner 
167180387638SSascha Wildner 	switch (n->tok) {
1672070c62a6SFranco Fichtner 	case MDOC_Ao:
1673070c62a6SFranco Fichtner 	case MDOC_Aq:
167454ba9607SSascha Wildner 		print_text(h, n->child != NULL && n->child->next == NULL &&
167554ba9607SSascha Wildner 		    n->child->tok == MDOC_Mt ?  ">" : "\\(ra");
167680387638SSascha Wildner 		break;
1677070c62a6SFranco Fichtner 	case MDOC_Bro:
1678070c62a6SFranco Fichtner 	case MDOC_Brq:
167980387638SSascha Wildner 		print_text(h, "\\(rC");
168080387638SSascha Wildner 		break;
1681070c62a6SFranco Fichtner 	case MDOC_Oo:
1682070c62a6SFranco Fichtner 	case MDOC_Op:
1683070c62a6SFranco Fichtner 	case MDOC_Bo:
1684070c62a6SFranco Fichtner 	case MDOC_Bq:
168580387638SSascha Wildner 		print_text(h, "\\(rB");
168680387638SSascha Wildner 		break;
1687070c62a6SFranco Fichtner 	case MDOC_En:
168854ba9607SSascha Wildner 		if (n->norm->Es == NULL ||
168954ba9607SSascha Wildner 		    n->norm->Es->child == NULL ||
169054ba9607SSascha Wildner 		    n->norm->Es->child->next == NULL)
169154ba9607SSascha Wildner 			h->flags &= ~HTML_NOSPACE;
169254ba9607SSascha Wildner 		else
1693070c62a6SFranco Fichtner 			print_text(h, n->norm->Es->child->next->string);
1694070c62a6SFranco Fichtner 		break;
1695070c62a6SFranco Fichtner 	case MDOC_Do:
1696070c62a6SFranco Fichtner 	case MDOC_Dq:
169780387638SSascha Wildner 		print_text(h, "\\(rq");
169880387638SSascha Wildner 		break;
1699*99db7d0eSSascha Wildner 	case MDOC_Qo:
1700*99db7d0eSSascha Wildner 	case MDOC_Qq:
1701*99db7d0eSSascha Wildner 		print_text(h, "\"");
1702*99db7d0eSSascha Wildner 		break;
1703070c62a6SFranco Fichtner 	case MDOC_Po:
1704070c62a6SFranco Fichtner 	case MDOC_Pq:
170580387638SSascha Wildner 		print_text(h, ")");
170680387638SSascha Wildner 		break;
1707070c62a6SFranco Fichtner 	case MDOC_Ql:
1708070c62a6SFranco Fichtner 	case MDOC_So:
1709070c62a6SFranco Fichtner 	case MDOC_Sq:
1710f88b6c16SFranco Fichtner 		print_text(h, "\\(cq");
171180387638SSascha Wildner 		break;
171280387638SSascha Wildner 	default:
171380387638SSascha Wildner 		abort();
171480387638SSascha Wildner 	}
171580387638SSascha Wildner }
171654ba9607SSascha Wildner 
171754ba9607SSascha Wildner static int
mdoc_eo_pre(MDOC_ARGS)171854ba9607SSascha Wildner mdoc_eo_pre(MDOC_ARGS)
171954ba9607SSascha Wildner {
172054ba9607SSascha Wildner 
172154ba9607SSascha Wildner 	if (n->type != ROFFT_BODY)
172254ba9607SSascha Wildner 		return 1;
172354ba9607SSascha Wildner 
172454ba9607SSascha Wildner 	if (n->end == ENDBODY_NOT &&
172554ba9607SSascha Wildner 	    n->parent->head->child == NULL &&
172654ba9607SSascha Wildner 	    n->child != NULL &&
172754ba9607SSascha Wildner 	    n->child->end != ENDBODY_NOT)
172854ba9607SSascha Wildner 		print_text(h, "\\&");
172954ba9607SSascha Wildner 	else if (n->end != ENDBODY_NOT ? n->child != NULL :
173054ba9607SSascha Wildner 	    n->parent->head->child != NULL && (n->child != NULL ||
173154ba9607SSascha Wildner 	    (n->parent->tail != NULL && n->parent->tail->child != NULL)))
173254ba9607SSascha Wildner 		h->flags |= HTML_NOSPACE;
173354ba9607SSascha Wildner 	return 1;
173454ba9607SSascha Wildner }
173554ba9607SSascha Wildner 
173654ba9607SSascha Wildner static void
mdoc_eo_post(MDOC_ARGS)173754ba9607SSascha Wildner mdoc_eo_post(MDOC_ARGS)
173854ba9607SSascha Wildner {
173954ba9607SSascha Wildner 	int	 body, tail;
174054ba9607SSascha Wildner 
174154ba9607SSascha Wildner 	if (n->type != ROFFT_BODY)
174254ba9607SSascha Wildner 		return;
174354ba9607SSascha Wildner 
174454ba9607SSascha Wildner 	if (n->end != ENDBODY_NOT) {
174554ba9607SSascha Wildner 		h->flags &= ~HTML_NOSPACE;
174654ba9607SSascha Wildner 		return;
174754ba9607SSascha Wildner 	}
174854ba9607SSascha Wildner 
174954ba9607SSascha Wildner 	body = n->child != NULL || n->parent->head->child != NULL;
175054ba9607SSascha Wildner 	tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
175154ba9607SSascha Wildner 
175254ba9607SSascha Wildner 	if (body && tail)
175354ba9607SSascha Wildner 		h->flags |= HTML_NOSPACE;
175454ba9607SSascha Wildner 	else if ( ! tail)
175554ba9607SSascha Wildner 		h->flags &= ~HTML_NOSPACE;
175654ba9607SSascha Wildner }
175754ba9607SSascha Wildner 
175854ba9607SSascha Wildner static int
mdoc_abort_pre(MDOC_ARGS)175954ba9607SSascha Wildner mdoc_abort_pre(MDOC_ARGS)
176054ba9607SSascha Wildner {
176154ba9607SSascha Wildner 	abort();
176254ba9607SSascha Wildner }
1763