xref: /freebsd/contrib/mandoc/man_html.c (revision c1c95add8c80843ba15d784f95c361d795b1f593)
1*c1c95addSBrooks Davis /* $Id: man_html.c,v 1.187 2023/10/24 20:53:12 schwarze Exp $ */
261d06d6bSBaptiste Daroussin /*
3*c1c95addSBrooks Davis  * Copyright (c) 2013-15,2017-20,2022-23 Ingo Schwarze <schwarze@openbsd.org>
461d06d6bSBaptiste Daroussin  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
561d06d6bSBaptiste Daroussin  *
661d06d6bSBaptiste Daroussin  * Permission to use, copy, modify, and distribute this software for any
761d06d6bSBaptiste Daroussin  * purpose with or without fee is hereby granted, provided that the above
861d06d6bSBaptiste Daroussin  * copyright notice and this permission notice appear in all copies.
961d06d6bSBaptiste Daroussin  *
1061d06d6bSBaptiste Daroussin  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
1161d06d6bSBaptiste Daroussin  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1261d06d6bSBaptiste Daroussin  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
1361d06d6bSBaptiste Daroussin  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1461d06d6bSBaptiste Daroussin  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1561d06d6bSBaptiste Daroussin  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1661d06d6bSBaptiste Daroussin  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176d38604fSBaptiste Daroussin  *
186d38604fSBaptiste Daroussin  * HTML formatter for man(7) used by mandoc(1).
1961d06d6bSBaptiste Daroussin  */
2061d06d6bSBaptiste Daroussin #include "config.h"
2161d06d6bSBaptiste Daroussin 
2261d06d6bSBaptiste Daroussin #include <sys/types.h>
2361d06d6bSBaptiste Daroussin 
2461d06d6bSBaptiste Daroussin #include <assert.h>
2561d06d6bSBaptiste Daroussin #include <ctype.h>
2661d06d6bSBaptiste Daroussin #include <stdio.h>
2761d06d6bSBaptiste Daroussin #include <stdlib.h>
2861d06d6bSBaptiste Daroussin #include <string.h>
2961d06d6bSBaptiste Daroussin 
3061d06d6bSBaptiste Daroussin #include "mandoc_aux.h"
3161d06d6bSBaptiste Daroussin #include "mandoc.h"
3261d06d6bSBaptiste Daroussin #include "roff.h"
3361d06d6bSBaptiste Daroussin #include "man.h"
3461d06d6bSBaptiste Daroussin #include "out.h"
3561d06d6bSBaptiste Daroussin #include "html.h"
3661d06d6bSBaptiste Daroussin #include "main.h"
3761d06d6bSBaptiste Daroussin 
3861d06d6bSBaptiste Daroussin #define	MAN_ARGS	  const struct roff_meta *man, \
396d38604fSBaptiste Daroussin 			  struct roff_node *n, \
4061d06d6bSBaptiste Daroussin 			  struct html *h
4161d06d6bSBaptiste Daroussin 
427295610fSBaptiste Daroussin struct	man_html_act {
4361d06d6bSBaptiste Daroussin 	int		(*pre)(MAN_ARGS);
4461d06d6bSBaptiste Daroussin 	int		(*post)(MAN_ARGS);
4561d06d6bSBaptiste Daroussin };
4661d06d6bSBaptiste Daroussin 
4761d06d6bSBaptiste Daroussin static	void		  print_man_head(const struct roff_meta *,
4861d06d6bSBaptiste Daroussin 				struct html *);
4961d06d6bSBaptiste Daroussin static	void		  print_man_nodelist(MAN_ARGS);
5061d06d6bSBaptiste Daroussin static	void		  print_man_node(MAN_ARGS);
517295610fSBaptiste Daroussin static	char		  list_continues(const struct roff_node *,
527295610fSBaptiste Daroussin 				const struct roff_node *);
5361d06d6bSBaptiste Daroussin static	int		  man_B_pre(MAN_ARGS);
5461d06d6bSBaptiste Daroussin static	int		  man_IP_pre(MAN_ARGS);
5561d06d6bSBaptiste Daroussin static	int		  man_I_pre(MAN_ARGS);
56*c1c95addSBrooks Davis static	int		  man_MR_pre(MAN_ARGS);
5761d06d6bSBaptiste Daroussin static	int		  man_OP_pre(MAN_ARGS);
5861d06d6bSBaptiste Daroussin static	int		  man_PP_pre(MAN_ARGS);
5961d06d6bSBaptiste Daroussin static	int		  man_RS_pre(MAN_ARGS);
6061d06d6bSBaptiste Daroussin static	int		  man_SH_pre(MAN_ARGS);
6161d06d6bSBaptiste Daroussin static	int		  man_SM_pre(MAN_ARGS);
627295610fSBaptiste Daroussin static	int		  man_SY_pre(MAN_ARGS);
6361d06d6bSBaptiste Daroussin static	int		  man_UR_pre(MAN_ARGS);
6461d06d6bSBaptiste Daroussin static	int		  man_alt_pre(MAN_ARGS);
6561d06d6bSBaptiste Daroussin static	int		  man_ign_pre(MAN_ARGS);
6661d06d6bSBaptiste Daroussin static	int		  man_in_pre(MAN_ARGS);
6761d06d6bSBaptiste Daroussin static	void		  man_root_post(const struct roff_meta *,
6861d06d6bSBaptiste Daroussin 				struct html *);
6961d06d6bSBaptiste Daroussin static	void		  man_root_pre(const struct roff_meta *,
7061d06d6bSBaptiste Daroussin 				struct html *);
7161d06d6bSBaptiste Daroussin 
727295610fSBaptiste Daroussin static	const struct man_html_act man_html_acts[MAN_MAX - MAN_TH] = {
7361d06d6bSBaptiste Daroussin 	{ NULL, NULL }, /* TH */
7461d06d6bSBaptiste Daroussin 	{ man_SH_pre, NULL }, /* SH */
757295610fSBaptiste Daroussin 	{ man_SH_pre, NULL }, /* SS */
7661d06d6bSBaptiste Daroussin 	{ man_IP_pre, NULL }, /* TP */
777295610fSBaptiste Daroussin 	{ man_IP_pre, NULL }, /* TQ */
78*c1c95addSBrooks Davis 	{ man_PP_pre, NULL }, /* LP */
7961d06d6bSBaptiste Daroussin 	{ man_PP_pre, NULL }, /* PP */
80*c1c95addSBrooks Davis 	{ man_PP_pre, NULL }, /* P */
8161d06d6bSBaptiste Daroussin 	{ man_IP_pre, NULL }, /* IP */
827295610fSBaptiste Daroussin 	{ man_PP_pre, NULL }, /* HP */
8361d06d6bSBaptiste Daroussin 	{ man_SM_pre, NULL }, /* SM */
8461d06d6bSBaptiste Daroussin 	{ man_SM_pre, NULL }, /* SB */
8561d06d6bSBaptiste Daroussin 	{ man_alt_pre, NULL }, /* BI */
8661d06d6bSBaptiste Daroussin 	{ man_alt_pre, NULL }, /* IB */
8761d06d6bSBaptiste Daroussin 	{ man_alt_pre, NULL }, /* BR */
8861d06d6bSBaptiste Daroussin 	{ man_alt_pre, NULL }, /* RB */
8961d06d6bSBaptiste Daroussin 	{ NULL, NULL }, /* R */
9061d06d6bSBaptiste Daroussin 	{ man_B_pre, NULL }, /* B */
9161d06d6bSBaptiste Daroussin 	{ man_I_pre, NULL }, /* I */
9261d06d6bSBaptiste Daroussin 	{ man_alt_pre, NULL }, /* IR */
9361d06d6bSBaptiste Daroussin 	{ man_alt_pre, NULL }, /* RI */
9461d06d6bSBaptiste Daroussin 	{ NULL, NULL }, /* RE */
9561d06d6bSBaptiste Daroussin 	{ man_RS_pre, NULL }, /* RS */
9661d06d6bSBaptiste Daroussin 	{ man_ign_pre, NULL }, /* DT */
9761d06d6bSBaptiste Daroussin 	{ man_ign_pre, NULL }, /* UC */
9861d06d6bSBaptiste Daroussin 	{ man_ign_pre, NULL }, /* PD */
9961d06d6bSBaptiste Daroussin 	{ man_ign_pre, NULL }, /* AT */
10061d06d6bSBaptiste Daroussin 	{ man_in_pre, NULL }, /* in */
1017295610fSBaptiste Daroussin 	{ man_SY_pre, NULL }, /* SY */
1027295610fSBaptiste Daroussin 	{ NULL, NULL }, /* YS */
10361d06d6bSBaptiste Daroussin 	{ man_OP_pre, NULL }, /* OP */
10461d06d6bSBaptiste Daroussin 	{ NULL, NULL }, /* EX */
10561d06d6bSBaptiste Daroussin 	{ NULL, NULL }, /* EE */
10661d06d6bSBaptiste Daroussin 	{ man_UR_pre, NULL }, /* UR */
10761d06d6bSBaptiste Daroussin 	{ NULL, NULL }, /* UE */
10861d06d6bSBaptiste Daroussin 	{ man_UR_pre, NULL }, /* MT */
10961d06d6bSBaptiste Daroussin 	{ NULL, NULL }, /* ME */
110*c1c95addSBrooks Davis 	{ man_MR_pre, NULL }, /* MR */
11161d06d6bSBaptiste Daroussin };
11261d06d6bSBaptiste Daroussin 
11361d06d6bSBaptiste Daroussin 
11461d06d6bSBaptiste Daroussin void
html_man(void * arg,const struct roff_meta * man)1157295610fSBaptiste Daroussin html_man(void *arg, const struct roff_meta *man)
11661d06d6bSBaptiste Daroussin {
11761d06d6bSBaptiste Daroussin 	struct html		*h;
11861d06d6bSBaptiste Daroussin 	struct roff_node	*n;
11961d06d6bSBaptiste Daroussin 	struct tag		*t;
12061d06d6bSBaptiste Daroussin 
12161d06d6bSBaptiste Daroussin 	h = (struct html *)arg;
12261d06d6bSBaptiste Daroussin 	n = man->first->child;
12361d06d6bSBaptiste Daroussin 
12461d06d6bSBaptiste Daroussin 	if ((h->oflags & HTML_FRAGMENT) == 0) {
12561d06d6bSBaptiste Daroussin 		print_gen_decls(h);
12661d06d6bSBaptiste Daroussin 		print_otag(h, TAG_HTML, "");
12761d06d6bSBaptiste Daroussin 		t = print_otag(h, TAG_HEAD, "");
1287295610fSBaptiste Daroussin 		print_man_head(man, h);
12961d06d6bSBaptiste Daroussin 		print_tagq(h, t);
130*c1c95addSBrooks Davis 		if (n != NULL && n->type == ROFFT_COMMENT)
131*c1c95addSBrooks Davis 			print_gen_comment(h, n);
13261d06d6bSBaptiste Daroussin 		print_otag(h, TAG_BODY, "");
13361d06d6bSBaptiste Daroussin 	}
13461d06d6bSBaptiste Daroussin 
1357295610fSBaptiste Daroussin 	man_root_pre(man, h);
136*c1c95addSBrooks Davis 	t = print_otag(h, TAG_MAIN, "c", "manual-text");
1377295610fSBaptiste Daroussin 	print_man_nodelist(man, n, h);
13861d06d6bSBaptiste Daroussin 	print_tagq(h, t);
1397295610fSBaptiste Daroussin 	man_root_post(man, h);
14061d06d6bSBaptiste Daroussin 	print_tagq(h, NULL);
14161d06d6bSBaptiste Daroussin }
14261d06d6bSBaptiste Daroussin 
14361d06d6bSBaptiste Daroussin static void
print_man_head(const struct roff_meta * man,struct html * h)14461d06d6bSBaptiste Daroussin print_man_head(const struct roff_meta *man, struct html *h)
14561d06d6bSBaptiste Daroussin {
14661d06d6bSBaptiste Daroussin 	char	*cp;
14761d06d6bSBaptiste Daroussin 
14861d06d6bSBaptiste Daroussin 	print_gen_head(h);
14961d06d6bSBaptiste Daroussin 	mandoc_asprintf(&cp, "%s(%s)", man->title, man->msec);
15061d06d6bSBaptiste Daroussin 	print_otag(h, TAG_TITLE, "");
15161d06d6bSBaptiste Daroussin 	print_text(h, cp);
15261d06d6bSBaptiste Daroussin 	free(cp);
15361d06d6bSBaptiste Daroussin }
15461d06d6bSBaptiste Daroussin 
15561d06d6bSBaptiste Daroussin static void
print_man_nodelist(MAN_ARGS)15661d06d6bSBaptiste Daroussin print_man_nodelist(MAN_ARGS)
15761d06d6bSBaptiste Daroussin {
15861d06d6bSBaptiste Daroussin 	while (n != NULL) {
15961d06d6bSBaptiste Daroussin 		print_man_node(man, n, h);
16061d06d6bSBaptiste Daroussin 		n = n->next;
16161d06d6bSBaptiste Daroussin 	}
16261d06d6bSBaptiste Daroussin }
16361d06d6bSBaptiste Daroussin 
16461d06d6bSBaptiste Daroussin static void
print_man_node(MAN_ARGS)16561d06d6bSBaptiste Daroussin print_man_node(MAN_ARGS)
16661d06d6bSBaptiste Daroussin {
16761d06d6bSBaptiste Daroussin 	struct tag	*t;
16861d06d6bSBaptiste Daroussin 	int		 child;
16961d06d6bSBaptiste Daroussin 
1707295610fSBaptiste Daroussin 	if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
17161d06d6bSBaptiste Daroussin 		return;
17261d06d6bSBaptiste Daroussin 
1736d38604fSBaptiste Daroussin 	if ((n->flags & NODE_NOFILL) == 0)
1746d38604fSBaptiste Daroussin 		html_fillmode(h, ROFF_fi);
1756d38604fSBaptiste Daroussin 	else if (html_fillmode(h, ROFF_nf) == ROFF_nf &&
1766d38604fSBaptiste Daroussin 	    n->tok != ROFF_fi && n->flags & NODE_LINE &&
1776d38604fSBaptiste Daroussin 	    (n->prev == NULL || n->prev->tok != MAN_YS))
1786d38604fSBaptiste Daroussin 		print_endline(h);
17961d06d6bSBaptiste Daroussin 
18061d06d6bSBaptiste Daroussin 	child = 1;
18161d06d6bSBaptiste Daroussin 	switch (n->type) {
18261d06d6bSBaptiste Daroussin 	case ROFFT_TEXT:
1837295610fSBaptiste Daroussin 		if (*n->string == '\0') {
1847295610fSBaptiste Daroussin 			print_endline(h);
1857295610fSBaptiste Daroussin 			return;
1867295610fSBaptiste Daroussin 		}
1877295610fSBaptiste Daroussin 		if (*n->string == ' ' && n->flags & NODE_LINE &&
1887295610fSBaptiste Daroussin 		    (h->flags & HTML_NONEWLINE) == 0)
1896d38604fSBaptiste Daroussin 			print_otag(h, TAG_BR, "");
1907295610fSBaptiste Daroussin 		else if (n->flags & NODE_DELIMC)
1917295610fSBaptiste Daroussin 			h->flags |= HTML_NOSPACE;
19261d06d6bSBaptiste Daroussin 		t = h->tag;
1937295610fSBaptiste Daroussin 		t->refcnt++;
19461d06d6bSBaptiste Daroussin 		print_text(h, n->string);
19561d06d6bSBaptiste Daroussin 		break;
19661d06d6bSBaptiste Daroussin 	case ROFFT_EQN:
19761d06d6bSBaptiste Daroussin 		t = h->tag;
1987295610fSBaptiste Daroussin 		t->refcnt++;
19961d06d6bSBaptiste Daroussin 		print_eqn(h, n->eqn);
20061d06d6bSBaptiste Daroussin 		break;
20161d06d6bSBaptiste Daroussin 	case ROFFT_TBL:
20261d06d6bSBaptiste Daroussin 		/*
20361d06d6bSBaptiste Daroussin 		 * This will take care of initialising all of the table
20461d06d6bSBaptiste Daroussin 		 * state data for the first table, then tearing it down
20561d06d6bSBaptiste Daroussin 		 * for the last one.
20661d06d6bSBaptiste Daroussin 		 */
20761d06d6bSBaptiste Daroussin 		print_tbl(h, n->span);
20861d06d6bSBaptiste Daroussin 		return;
20961d06d6bSBaptiste Daroussin 	default:
21061d06d6bSBaptiste Daroussin 		/*
21161d06d6bSBaptiste Daroussin 		 * Close out scope of font prior to opening a macro
21261d06d6bSBaptiste Daroussin 		 * scope.
21361d06d6bSBaptiste Daroussin 		 */
21445a5aec3SBaptiste Daroussin 		if (h->metac != ESCAPE_FONTROMAN) {
21561d06d6bSBaptiste Daroussin 			h->metal = h->metac;
21645a5aec3SBaptiste Daroussin 			h->metac = ESCAPE_FONTROMAN;
21761d06d6bSBaptiste Daroussin 		}
21861d06d6bSBaptiste Daroussin 
21961d06d6bSBaptiste Daroussin 		/*
22061d06d6bSBaptiste Daroussin 		 * Close out the current table, if it's open, and unset
22161d06d6bSBaptiste Daroussin 		 * the "meta" table state.  This will be reopened on the
22261d06d6bSBaptiste Daroussin 		 * next table element.
22361d06d6bSBaptiste Daroussin 		 */
2247295610fSBaptiste Daroussin 		if (h->tblt != NULL)
22561d06d6bSBaptiste Daroussin 			print_tblclose(h);
22661d06d6bSBaptiste Daroussin 		t = h->tag;
2277295610fSBaptiste Daroussin 		t->refcnt++;
22861d06d6bSBaptiste Daroussin 		if (n->tok < ROFF_MAX) {
22961d06d6bSBaptiste Daroussin 			roff_html_pre(h, n);
2307295610fSBaptiste Daroussin 			t->refcnt--;
2317295610fSBaptiste Daroussin 			print_stagq(h, t);
2327295610fSBaptiste Daroussin 			return;
23361d06d6bSBaptiste Daroussin 		}
23461d06d6bSBaptiste Daroussin 		assert(n->tok >= MAN_TH && n->tok < MAN_MAX);
2357295610fSBaptiste Daroussin 		if (man_html_acts[n->tok - MAN_TH].pre != NULL)
2367295610fSBaptiste Daroussin 			child = (*man_html_acts[n->tok - MAN_TH].pre)(man,
2377295610fSBaptiste Daroussin 			    n, h);
23861d06d6bSBaptiste Daroussin 		break;
23961d06d6bSBaptiste Daroussin 	}
24061d06d6bSBaptiste Daroussin 
2417295610fSBaptiste Daroussin 	if (child && n->child != NULL)
24261d06d6bSBaptiste Daroussin 		print_man_nodelist(man, n->child, h);
24361d06d6bSBaptiste Daroussin 
24461d06d6bSBaptiste Daroussin 	/* This will automatically close out any font scope. */
2457295610fSBaptiste Daroussin 	t->refcnt--;
2467295610fSBaptiste Daroussin 	if (n->type == ROFFT_BLOCK &&
2477295610fSBaptiste Daroussin 	    (n->tok == MAN_IP || n->tok == MAN_TP || n->tok == MAN_TQ)) {
2487295610fSBaptiste Daroussin 		t = h->tag;
2497295610fSBaptiste Daroussin 		while (t->tag != TAG_DL && t->tag != TAG_UL)
2507295610fSBaptiste Daroussin 			t = t->next;
2517295610fSBaptiste Daroussin 		/*
2527295610fSBaptiste Daroussin 		 * Close the list if no further item of the same type
2537295610fSBaptiste Daroussin 		 * follows; otherwise, close the item only.
2547295610fSBaptiste Daroussin 		 */
2556d38604fSBaptiste Daroussin 		if (list_continues(n, roff_node_next(n)) == '\0') {
2567295610fSBaptiste Daroussin 			print_tagq(h, t);
2577295610fSBaptiste Daroussin 			t = NULL;
2587295610fSBaptiste Daroussin 		}
2597295610fSBaptiste Daroussin 	}
2607295610fSBaptiste Daroussin 	if (t != NULL)
26161d06d6bSBaptiste Daroussin 		print_stagq(h, t);
26261d06d6bSBaptiste Daroussin }
26361d06d6bSBaptiste Daroussin 
26461d06d6bSBaptiste Daroussin static void
man_root_pre(const struct roff_meta * man,struct html * h)26561d06d6bSBaptiste Daroussin man_root_pre(const struct roff_meta *man, struct html *h)
26661d06d6bSBaptiste Daroussin {
267*c1c95addSBrooks Davis 	struct tag	*t;
26861d06d6bSBaptiste Daroussin 	char		*title;
26961d06d6bSBaptiste Daroussin 
27061d06d6bSBaptiste Daroussin 	assert(man->title);
27161d06d6bSBaptiste Daroussin 	assert(man->msec);
27261d06d6bSBaptiste Daroussin 	mandoc_asprintf(&title, "%s(%s)", man->title, man->msec);
27361d06d6bSBaptiste Daroussin 
274*c1c95addSBrooks Davis 	t = print_otag(h, TAG_DIV, "cr?", "head", "doc-pageheader",
275*c1c95addSBrooks Davis 	    "aria-label", "Manual header line");
27661d06d6bSBaptiste Daroussin 
277*c1c95addSBrooks Davis 	print_otag(h, TAG_SPAN, "c", "head-ltitle");
27861d06d6bSBaptiste Daroussin 	print_text(h, title);
279*c1c95addSBrooks Davis 	print_stagq(h, t);
28061d06d6bSBaptiste Daroussin 
281*c1c95addSBrooks Davis 	print_otag(h, TAG_SPAN, "c", "head-vol");
2827295610fSBaptiste Daroussin 	if (man->vol != NULL)
28361d06d6bSBaptiste Daroussin 		print_text(h, man->vol);
284*c1c95addSBrooks Davis 	print_stagq(h, t);
28561d06d6bSBaptiste Daroussin 
286*c1c95addSBrooks Davis 	print_otag(h, TAG_SPAN, "c", "head-rtitle");
28761d06d6bSBaptiste Daroussin 	print_text(h, title);
28861d06d6bSBaptiste Daroussin 	print_tagq(h, t);
28961d06d6bSBaptiste Daroussin 	free(title);
29061d06d6bSBaptiste Daroussin }
29161d06d6bSBaptiste Daroussin 
29261d06d6bSBaptiste Daroussin static void
man_root_post(const struct roff_meta * man,struct html * h)29361d06d6bSBaptiste Daroussin man_root_post(const struct roff_meta *man, struct html *h)
29461d06d6bSBaptiste Daroussin {
295*c1c95addSBrooks Davis 	struct tag	*t;
29661d06d6bSBaptiste Daroussin 
297*c1c95addSBrooks Davis 	t = print_otag(h, TAG_DIV, "cr?", "foot", "doc-pagefooter",
298*c1c95addSBrooks Davis 	    "aria-label", "Manual footer line");
29961d06d6bSBaptiste Daroussin 
300*c1c95addSBrooks Davis 	print_otag(h, TAG_SPAN, "c", "foot-left");
301*c1c95addSBrooks Davis 	print_stagq(h, t);
302*c1c95addSBrooks Davis 
303*c1c95addSBrooks Davis 	print_otag(h, TAG_SPAN, "c", "foot-date");
30461d06d6bSBaptiste Daroussin 	print_text(h, man->date);
305*c1c95addSBrooks Davis 	print_stagq(h, t);
30661d06d6bSBaptiste Daroussin 
307*c1c95addSBrooks Davis 	print_otag(h, TAG_SPAN, "c", "foot-os");
3087295610fSBaptiste Daroussin 	if (man->os != NULL)
30961d06d6bSBaptiste Daroussin 		print_text(h, man->os);
31061d06d6bSBaptiste Daroussin 	print_tagq(h, t);
31161d06d6bSBaptiste Daroussin }
31261d06d6bSBaptiste Daroussin 
31361d06d6bSBaptiste Daroussin static int
man_SH_pre(MAN_ARGS)31461d06d6bSBaptiste Daroussin man_SH_pre(MAN_ARGS)
31561d06d6bSBaptiste Daroussin {
3167295610fSBaptiste Daroussin 	const char	*class;
3177295610fSBaptiste Daroussin 	enum htmltag	 tag;
31861d06d6bSBaptiste Daroussin 
3197295610fSBaptiste Daroussin 	if (n->tok == MAN_SH) {
320*c1c95addSBrooks Davis 		tag = TAG_H2;
3217295610fSBaptiste Daroussin 		class = "Sh";
3227295610fSBaptiste Daroussin 	} else {
323*c1c95addSBrooks Davis 		tag = TAG_H3;
3247295610fSBaptiste Daroussin 		class = "Ss";
3257295610fSBaptiste Daroussin 	}
3267295610fSBaptiste Daroussin 	switch (n->type) {
3277295610fSBaptiste Daroussin 	case ROFFT_BLOCK:
3287295610fSBaptiste Daroussin 		html_close_paragraph(h);
3297295610fSBaptiste Daroussin 		print_otag(h, TAG_SECTION, "c", class);
3307295610fSBaptiste Daroussin 		break;
3317295610fSBaptiste Daroussin 	case ROFFT_HEAD:
3326d38604fSBaptiste Daroussin 		print_otag_id(h, tag, class, n);
3337295610fSBaptiste Daroussin 		break;
3347295610fSBaptiste Daroussin 	case ROFFT_BODY:
3357295610fSBaptiste Daroussin 		break;
3367295610fSBaptiste Daroussin 	default:
3377295610fSBaptiste Daroussin 		abort();
33861d06d6bSBaptiste Daroussin 	}
33961d06d6bSBaptiste Daroussin 	return 1;
34061d06d6bSBaptiste Daroussin }
34161d06d6bSBaptiste Daroussin 
34261d06d6bSBaptiste Daroussin static int
man_alt_pre(MAN_ARGS)34361d06d6bSBaptiste Daroussin man_alt_pre(MAN_ARGS)
34461d06d6bSBaptiste Daroussin {
34561d06d6bSBaptiste Daroussin 	const struct roff_node	*nn;
3467295610fSBaptiste Daroussin 	struct tag	*t;
34761d06d6bSBaptiste Daroussin 	int		 i;
34861d06d6bSBaptiste Daroussin 	enum htmltag	 fp;
34961d06d6bSBaptiste Daroussin 
3507295610fSBaptiste Daroussin 	for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i++) {
35161d06d6bSBaptiste Daroussin 		switch (n->tok) {
35261d06d6bSBaptiste Daroussin 		case MAN_BI:
35361d06d6bSBaptiste Daroussin 			fp = i % 2 ? TAG_I : TAG_B;
35461d06d6bSBaptiste Daroussin 			break;
35561d06d6bSBaptiste Daroussin 		case MAN_IB:
35661d06d6bSBaptiste Daroussin 			fp = i % 2 ? TAG_B : TAG_I;
35761d06d6bSBaptiste Daroussin 			break;
35861d06d6bSBaptiste Daroussin 		case MAN_RI:
35961d06d6bSBaptiste Daroussin 			fp = i % 2 ? TAG_I : TAG_MAX;
36061d06d6bSBaptiste Daroussin 			break;
36161d06d6bSBaptiste Daroussin 		case MAN_IR:
36261d06d6bSBaptiste Daroussin 			fp = i % 2 ? TAG_MAX : TAG_I;
36361d06d6bSBaptiste Daroussin 			break;
36461d06d6bSBaptiste Daroussin 		case MAN_BR:
36561d06d6bSBaptiste Daroussin 			fp = i % 2 ? TAG_MAX : TAG_B;
36661d06d6bSBaptiste Daroussin 			break;
36761d06d6bSBaptiste Daroussin 		case MAN_RB:
36861d06d6bSBaptiste Daroussin 			fp = i % 2 ? TAG_B : TAG_MAX;
36961d06d6bSBaptiste Daroussin 			break;
37061d06d6bSBaptiste Daroussin 		default:
37161d06d6bSBaptiste Daroussin 			abort();
37261d06d6bSBaptiste Daroussin 		}
37361d06d6bSBaptiste Daroussin 
37461d06d6bSBaptiste Daroussin 		if (i)
37561d06d6bSBaptiste Daroussin 			h->flags |= HTML_NOSPACE;
37661d06d6bSBaptiste Daroussin 
37761d06d6bSBaptiste Daroussin 		if (fp != TAG_MAX)
37861d06d6bSBaptiste Daroussin 			t = print_otag(h, fp, "");
37961d06d6bSBaptiste Daroussin 
38061d06d6bSBaptiste Daroussin 		print_text(h, nn->string);
38161d06d6bSBaptiste Daroussin 
38261d06d6bSBaptiste Daroussin 		if (fp != TAG_MAX)
38361d06d6bSBaptiste Daroussin 			print_tagq(h, t);
38461d06d6bSBaptiste Daroussin 	}
38561d06d6bSBaptiste Daroussin 	return 0;
38661d06d6bSBaptiste Daroussin }
38761d06d6bSBaptiste Daroussin 
38861d06d6bSBaptiste Daroussin static int
man_SM_pre(MAN_ARGS)38961d06d6bSBaptiste Daroussin man_SM_pre(MAN_ARGS)
39061d06d6bSBaptiste Daroussin {
39161d06d6bSBaptiste Daroussin 	print_otag(h, TAG_SMALL, "");
3927295610fSBaptiste Daroussin 	if (n->tok == MAN_SB)
39361d06d6bSBaptiste Daroussin 		print_otag(h, TAG_B, "");
39461d06d6bSBaptiste Daroussin 	return 1;
39561d06d6bSBaptiste Daroussin }
39661d06d6bSBaptiste Daroussin 
39761d06d6bSBaptiste Daroussin static int
man_PP_pre(MAN_ARGS)39861d06d6bSBaptiste Daroussin man_PP_pre(MAN_ARGS)
39961d06d6bSBaptiste Daroussin {
4007295610fSBaptiste Daroussin 	switch (n->type) {
4017295610fSBaptiste Daroussin 	case ROFFT_BLOCK:
4027295610fSBaptiste Daroussin 		html_close_paragraph(h);
4037295610fSBaptiste Daroussin 		break;
4047295610fSBaptiste Daroussin 	case ROFFT_HEAD:
40561d06d6bSBaptiste Daroussin 		return 0;
4067295610fSBaptiste Daroussin 	case ROFFT_BODY:
4077295610fSBaptiste Daroussin 		if (n->child != NULL &&
4087295610fSBaptiste Daroussin 		    (n->child->flags & NODE_NOFILL) == 0)
4097295610fSBaptiste Daroussin 			print_otag(h, TAG_P, "c",
410*c1c95addSBrooks Davis 			    n->tok == MAN_HP ? "Pp HP" : "Pp");
4117295610fSBaptiste Daroussin 		break;
4127295610fSBaptiste Daroussin 	default:
4137295610fSBaptiste Daroussin 		abort();
4147295610fSBaptiste Daroussin 	}
41561d06d6bSBaptiste Daroussin 	return 1;
41661d06d6bSBaptiste Daroussin }
41761d06d6bSBaptiste Daroussin 
4187295610fSBaptiste Daroussin static char
list_continues(const struct roff_node * n1,const struct roff_node * n2)4197295610fSBaptiste Daroussin list_continues(const struct roff_node *n1, const struct roff_node *n2)
4207295610fSBaptiste Daroussin {
4217295610fSBaptiste Daroussin 	const char *s1, *s2;
4227295610fSBaptiste Daroussin 	char c1, c2;
4237295610fSBaptiste Daroussin 
4247295610fSBaptiste Daroussin 	if (n1 == NULL || n1->type != ROFFT_BLOCK ||
4257295610fSBaptiste Daroussin 	    n2 == NULL || n2->type != ROFFT_BLOCK)
4267295610fSBaptiste Daroussin 		return '\0';
4277295610fSBaptiste Daroussin 	if ((n1->tok == MAN_TP || n1->tok == MAN_TQ) &&
4287295610fSBaptiste Daroussin 	    (n2->tok == MAN_TP || n2->tok == MAN_TQ))
4297295610fSBaptiste Daroussin 		return ' ';
4307295610fSBaptiste Daroussin 	if (n1->tok != MAN_IP || n2->tok != MAN_IP)
4317295610fSBaptiste Daroussin 		return '\0';
4327295610fSBaptiste Daroussin 	n1 = n1->head->child;
4337295610fSBaptiste Daroussin 	n2 = n2->head->child;
4347295610fSBaptiste Daroussin 	s1 = n1 == NULL ? "" : n1->string;
4357295610fSBaptiste Daroussin 	s2 = n2 == NULL ? "" : n2->string;
4367295610fSBaptiste Daroussin 	c1 = strcmp(s1, "*") == 0 ? '*' :
4377295610fSBaptiste Daroussin 	     strcmp(s1, "\\-") == 0 ? '-' :
438*c1c95addSBrooks Davis 	     strcmp(s1, "\\(bu") == 0 ? 'b' :
439*c1c95addSBrooks Davis 	     strcmp(s1, "\\[bu]") == 0 ? 'b' : ' ';
4407295610fSBaptiste Daroussin 	c2 = strcmp(s2, "*") == 0 ? '*' :
4417295610fSBaptiste Daroussin 	     strcmp(s2, "\\-") == 0 ? '-' :
442*c1c95addSBrooks Davis 	     strcmp(s2, "\\(bu") == 0 ? 'b' :
443*c1c95addSBrooks Davis 	     strcmp(s2, "\\[bu]") == 0 ? 'b' : ' ';
4447295610fSBaptiste Daroussin 	return c1 != c2 ? '\0' : c1 == 'b' ? '*' : c1;
4457295610fSBaptiste Daroussin }
4467295610fSBaptiste Daroussin 
44761d06d6bSBaptiste Daroussin static int
man_IP_pre(MAN_ARGS)44861d06d6bSBaptiste Daroussin man_IP_pre(MAN_ARGS)
44961d06d6bSBaptiste Daroussin {
4506d38604fSBaptiste Daroussin 	struct roff_node	*nn;
4517295610fSBaptiste Daroussin 	const char		*list_class;
4527295610fSBaptiste Daroussin 	enum htmltag		 list_elem, body_elem;
4537295610fSBaptiste Daroussin 	char			 list_type;
45461d06d6bSBaptiste Daroussin 
4557295610fSBaptiste Daroussin 	nn = n->type == ROFFT_BLOCK ? n : n->parent;
4566d38604fSBaptiste Daroussin 	list_type = list_continues(roff_node_prev(nn), nn);
4576d38604fSBaptiste Daroussin 	if (list_type == '\0') {
4587295610fSBaptiste Daroussin 		/* Start a new list. */
4596d38604fSBaptiste Daroussin 		list_type = list_continues(nn, roff_node_next(nn));
4606d38604fSBaptiste Daroussin 		if (list_type == '\0')
4617295610fSBaptiste Daroussin 			list_type = ' ';
4627295610fSBaptiste Daroussin 		switch (list_type) {
4637295610fSBaptiste Daroussin 		case ' ':
4647295610fSBaptiste Daroussin 			list_class = "Bl-tag";
4657295610fSBaptiste Daroussin 			list_elem = TAG_DL;
4667295610fSBaptiste Daroussin 			break;
4677295610fSBaptiste Daroussin 		case '*':
4687295610fSBaptiste Daroussin 			list_class = "Bl-bullet";
4697295610fSBaptiste Daroussin 			list_elem = TAG_UL;
4707295610fSBaptiste Daroussin 			break;
4717295610fSBaptiste Daroussin 		case '-':
4727295610fSBaptiste Daroussin 			list_class = "Bl-dash";
4737295610fSBaptiste Daroussin 			list_elem = TAG_UL;
4747295610fSBaptiste Daroussin 			break;
4757295610fSBaptiste Daroussin 		default:
4767295610fSBaptiste Daroussin 			abort();
4777295610fSBaptiste Daroussin 		}
4787295610fSBaptiste Daroussin 	} else {
4797295610fSBaptiste Daroussin 		/* Continue a list that was started earlier. */
4807295610fSBaptiste Daroussin 		list_class = NULL;
4817295610fSBaptiste Daroussin 		list_elem = TAG_MAX;
4827295610fSBaptiste Daroussin 	}
4837295610fSBaptiste Daroussin 	body_elem = list_type == ' ' ? TAG_DD : TAG_LI;
4847295610fSBaptiste Daroussin 
4857295610fSBaptiste Daroussin 	switch (n->type) {
4867295610fSBaptiste Daroussin 	case ROFFT_BLOCK:
4877295610fSBaptiste Daroussin 		html_close_paragraph(h);
4887295610fSBaptiste Daroussin 		if (list_elem != TAG_MAX)
4897295610fSBaptiste Daroussin 			print_otag(h, list_elem, "c", list_class);
49061d06d6bSBaptiste Daroussin 		return 1;
4917295610fSBaptiste Daroussin 	case ROFFT_HEAD:
4927295610fSBaptiste Daroussin 		if (body_elem == TAG_LI)
4937295610fSBaptiste Daroussin 			return 0;
4946d38604fSBaptiste Daroussin 		print_otag_id(h, TAG_DT, NULL, n);
4957295610fSBaptiste Daroussin 		break;
4967295610fSBaptiste Daroussin 	case ROFFT_BODY:
4977295610fSBaptiste Daroussin 		print_otag(h, body_elem, "");
49861d06d6bSBaptiste Daroussin 		return 1;
4997295610fSBaptiste Daroussin 	default:
5007295610fSBaptiste Daroussin 		abort();
50161d06d6bSBaptiste Daroussin 	}
5027295610fSBaptiste Daroussin 	switch(n->tok) {
5037295610fSBaptiste Daroussin 	case MAN_IP:  /* Only print the first header element. */
5047295610fSBaptiste Daroussin 		if (n->child != NULL)
50561d06d6bSBaptiste Daroussin 			print_man_node(man, n->child, h);
5067295610fSBaptiste Daroussin 		break;
5077295610fSBaptiste Daroussin 	case MAN_TP:  /* Only print next-line header elements. */
5087295610fSBaptiste Daroussin 	case MAN_TQ:
50961d06d6bSBaptiste Daroussin 		nn = n->child;
5107295610fSBaptiste Daroussin 		while (nn != NULL && (NODE_LINE & nn->flags) == 0)
51161d06d6bSBaptiste Daroussin 			nn = nn->next;
5127295610fSBaptiste Daroussin 		while (nn != NULL) {
51361d06d6bSBaptiste Daroussin 			print_man_node(man, nn, h);
51461d06d6bSBaptiste Daroussin 			nn = nn->next;
51561d06d6bSBaptiste Daroussin 		}
5167295610fSBaptiste Daroussin 		break;
5177295610fSBaptiste Daroussin 	default:
5187295610fSBaptiste Daroussin 		abort();
51961d06d6bSBaptiste Daroussin 	}
52061d06d6bSBaptiste Daroussin 	return 0;
52161d06d6bSBaptiste Daroussin }
52261d06d6bSBaptiste Daroussin 
52361d06d6bSBaptiste Daroussin static int
man_MR_pre(MAN_ARGS)524*c1c95addSBrooks Davis man_MR_pre(MAN_ARGS)
525*c1c95addSBrooks Davis {
526*c1c95addSBrooks Davis 	struct tag	*t;
527*c1c95addSBrooks Davis 	const char	*name, *section, *suffix;
528*c1c95addSBrooks Davis 	char		*label;
529*c1c95addSBrooks Davis 
530*c1c95addSBrooks Davis 	html_setfont(h, ESCAPE_FONTROMAN);
531*c1c95addSBrooks Davis 	name = section = suffix = label = NULL;
532*c1c95addSBrooks Davis 	if (n->child != NULL) {
533*c1c95addSBrooks Davis 		name = n->child->string;
534*c1c95addSBrooks Davis 		if (n->child->next != NULL) {
535*c1c95addSBrooks Davis 			section = n->child->next->string;
536*c1c95addSBrooks Davis 			mandoc_asprintf(&label,
537*c1c95addSBrooks Davis 			    "%s, section %s", name, section);
538*c1c95addSBrooks Davis 			if (n->child->next->next != NULL)
539*c1c95addSBrooks Davis 				suffix = n->child->next->next->string;
540*c1c95addSBrooks Davis 		}
541*c1c95addSBrooks Davis 	}
542*c1c95addSBrooks Davis 
543*c1c95addSBrooks Davis 	if (name != NULL && section != NULL && h->base_man1 != NULL)
544*c1c95addSBrooks Davis 		t = print_otag(h, TAG_A, "chM?", "Xr",
545*c1c95addSBrooks Davis 		    name, section, "aria-label", label);
546*c1c95addSBrooks Davis 	else
547*c1c95addSBrooks Davis 		t = print_otag(h, TAG_A, "c?", "Xr", "aria-label", label);
548*c1c95addSBrooks Davis 
549*c1c95addSBrooks Davis 	free(label);
550*c1c95addSBrooks Davis 	if (name != NULL) {
551*c1c95addSBrooks Davis 		print_text(h, name);
552*c1c95addSBrooks Davis 		h->flags |= HTML_NOSPACE;
553*c1c95addSBrooks Davis 	}
554*c1c95addSBrooks Davis 	print_text(h, "(");
555*c1c95addSBrooks Davis 	h->flags |= HTML_NOSPACE;
556*c1c95addSBrooks Davis 	if (section != NULL) {
557*c1c95addSBrooks Davis 		print_text(h, section);
558*c1c95addSBrooks Davis 		h->flags |= HTML_NOSPACE;
559*c1c95addSBrooks Davis 	}
560*c1c95addSBrooks Davis 	print_text(h, ")");
561*c1c95addSBrooks Davis 	print_tagq(h, t);
562*c1c95addSBrooks Davis 	if (suffix != NULL) {
563*c1c95addSBrooks Davis 		h->flags |= HTML_NOSPACE;
564*c1c95addSBrooks Davis 		print_text(h, suffix);
565*c1c95addSBrooks Davis 	}
566*c1c95addSBrooks Davis 	return 0;
567*c1c95addSBrooks Davis }
568*c1c95addSBrooks Davis 
569*c1c95addSBrooks Davis static int
man_OP_pre(MAN_ARGS)57061d06d6bSBaptiste Daroussin man_OP_pre(MAN_ARGS)
57161d06d6bSBaptiste Daroussin {
57261d06d6bSBaptiste Daroussin 	struct tag	*tt;
57361d06d6bSBaptiste Daroussin 
57461d06d6bSBaptiste Daroussin 	print_text(h, "[");
57561d06d6bSBaptiste Daroussin 	h->flags |= HTML_NOSPACE;
57661d06d6bSBaptiste Daroussin 	tt = print_otag(h, TAG_SPAN, "c", "Op");
57761d06d6bSBaptiste Daroussin 
5787295610fSBaptiste Daroussin 	if ((n = n->child) != NULL) {
57961d06d6bSBaptiste Daroussin 		print_otag(h, TAG_B, "");
58061d06d6bSBaptiste Daroussin 		print_text(h, n->string);
58161d06d6bSBaptiste Daroussin 	}
58261d06d6bSBaptiste Daroussin 
58361d06d6bSBaptiste Daroussin 	print_stagq(h, tt);
58461d06d6bSBaptiste Daroussin 
5857295610fSBaptiste Daroussin 	if (n != NULL && n->next != NULL) {
58661d06d6bSBaptiste Daroussin 		print_otag(h, TAG_I, "");
58761d06d6bSBaptiste Daroussin 		print_text(h, n->next->string);
58861d06d6bSBaptiste Daroussin 	}
58961d06d6bSBaptiste Daroussin 
59061d06d6bSBaptiste Daroussin 	print_stagq(h, tt);
59161d06d6bSBaptiste Daroussin 	h->flags |= HTML_NOSPACE;
59261d06d6bSBaptiste Daroussin 	print_text(h, "]");
59361d06d6bSBaptiste Daroussin 	return 0;
59461d06d6bSBaptiste Daroussin }
59561d06d6bSBaptiste Daroussin 
59661d06d6bSBaptiste Daroussin static int
man_B_pre(MAN_ARGS)59761d06d6bSBaptiste Daroussin man_B_pre(MAN_ARGS)
59861d06d6bSBaptiste Daroussin {
59961d06d6bSBaptiste Daroussin 	print_otag(h, TAG_B, "");
60061d06d6bSBaptiste Daroussin 	return 1;
60161d06d6bSBaptiste Daroussin }
60261d06d6bSBaptiste Daroussin 
60361d06d6bSBaptiste Daroussin static int
man_I_pre(MAN_ARGS)60461d06d6bSBaptiste Daroussin man_I_pre(MAN_ARGS)
60561d06d6bSBaptiste Daroussin {
60661d06d6bSBaptiste Daroussin 	print_otag(h, TAG_I, "");
60761d06d6bSBaptiste Daroussin 	return 1;
60861d06d6bSBaptiste Daroussin }
60961d06d6bSBaptiste Daroussin 
61061d06d6bSBaptiste Daroussin static int
man_in_pre(MAN_ARGS)61161d06d6bSBaptiste Daroussin man_in_pre(MAN_ARGS)
61261d06d6bSBaptiste Daroussin {
61361d06d6bSBaptiste Daroussin 	print_otag(h, TAG_BR, "");
61461d06d6bSBaptiste Daroussin 	return 0;
61561d06d6bSBaptiste Daroussin }
61661d06d6bSBaptiste Daroussin 
61761d06d6bSBaptiste Daroussin static int
man_ign_pre(MAN_ARGS)61861d06d6bSBaptiste Daroussin man_ign_pre(MAN_ARGS)
61961d06d6bSBaptiste Daroussin {
62061d06d6bSBaptiste Daroussin 	return 0;
62161d06d6bSBaptiste Daroussin }
62261d06d6bSBaptiste Daroussin 
62361d06d6bSBaptiste Daroussin static int
man_RS_pre(MAN_ARGS)62461d06d6bSBaptiste Daroussin man_RS_pre(MAN_ARGS)
62561d06d6bSBaptiste Daroussin {
6267295610fSBaptiste Daroussin 	switch (n->type) {
6277295610fSBaptiste Daroussin 	case ROFFT_BLOCK:
6287295610fSBaptiste Daroussin 		html_close_paragraph(h);
6297295610fSBaptiste Daroussin 		break;
6307295610fSBaptiste Daroussin 	case ROFFT_HEAD:
63161d06d6bSBaptiste Daroussin 		return 0;
6327295610fSBaptiste Daroussin 	case ROFFT_BODY:
63361d06d6bSBaptiste Daroussin 		print_otag(h, TAG_DIV, "c", "Bd-indent");
6347295610fSBaptiste Daroussin 		break;
6357295610fSBaptiste Daroussin 	default:
6367295610fSBaptiste Daroussin 		abort();
6377295610fSBaptiste Daroussin 	}
6387295610fSBaptiste Daroussin 	return 1;
6397295610fSBaptiste Daroussin }
6407295610fSBaptiste Daroussin 
6417295610fSBaptiste Daroussin static int
man_SY_pre(MAN_ARGS)6427295610fSBaptiste Daroussin man_SY_pre(MAN_ARGS)
6437295610fSBaptiste Daroussin {
6447295610fSBaptiste Daroussin 	switch (n->type) {
6457295610fSBaptiste Daroussin 	case ROFFT_BLOCK:
6467295610fSBaptiste Daroussin 		html_close_paragraph(h);
6477295610fSBaptiste Daroussin 		print_otag(h, TAG_TABLE, "c", "Nm");
6487295610fSBaptiste Daroussin 		print_otag(h, TAG_TR, "");
6497295610fSBaptiste Daroussin 		break;
6507295610fSBaptiste Daroussin 	case ROFFT_HEAD:
6517295610fSBaptiste Daroussin 		print_otag(h, TAG_TD, "");
6527295610fSBaptiste Daroussin 		print_otag(h, TAG_CODE, "c", "Nm");
6537295610fSBaptiste Daroussin 		break;
6547295610fSBaptiste Daroussin 	case ROFFT_BODY:
6557295610fSBaptiste Daroussin 		print_otag(h, TAG_TD, "");
6567295610fSBaptiste Daroussin 		break;
6577295610fSBaptiste Daroussin 	default:
6587295610fSBaptiste Daroussin 		abort();
6597295610fSBaptiste Daroussin 	}
66061d06d6bSBaptiste Daroussin 	return 1;
66161d06d6bSBaptiste Daroussin }
66261d06d6bSBaptiste Daroussin 
66361d06d6bSBaptiste Daroussin static int
man_UR_pre(MAN_ARGS)66461d06d6bSBaptiste Daroussin man_UR_pre(MAN_ARGS)
66561d06d6bSBaptiste Daroussin {
66661d06d6bSBaptiste Daroussin 	char *cp;
6677295610fSBaptiste Daroussin 
66861d06d6bSBaptiste Daroussin 	n = n->child;
66961d06d6bSBaptiste Daroussin 	assert(n->type == ROFFT_HEAD);
67061d06d6bSBaptiste Daroussin 	if (n->child != NULL) {
67161d06d6bSBaptiste Daroussin 		assert(n->child->type == ROFFT_TEXT);
67261d06d6bSBaptiste Daroussin 		if (n->tok == MAN_MT) {
67361d06d6bSBaptiste Daroussin 			mandoc_asprintf(&cp, "mailto:%s", n->child->string);
6747295610fSBaptiste Daroussin 			print_otag(h, TAG_A, "ch", "Mt", cp);
67561d06d6bSBaptiste Daroussin 			free(cp);
67661d06d6bSBaptiste Daroussin 		} else
6777295610fSBaptiste Daroussin 			print_otag(h, TAG_A, "ch", "Lk", n->child->string);
67861d06d6bSBaptiste Daroussin 	}
67961d06d6bSBaptiste Daroussin 
68061d06d6bSBaptiste Daroussin 	assert(n->next->type == ROFFT_BODY);
68161d06d6bSBaptiste Daroussin 	if (n->next->child != NULL)
68261d06d6bSBaptiste Daroussin 		n = n->next;
68361d06d6bSBaptiste Daroussin 
68461d06d6bSBaptiste Daroussin 	print_man_nodelist(man, n->child, h);
68561d06d6bSBaptiste Daroussin 	return 0;
68661d06d6bSBaptiste Daroussin }
687