xref: /freebsd/contrib/mandoc/mdoc_markdown.c (revision 80c12959679ab203459dc20eb9ece3a7328b7de5)
1*80c12959SAlexander Ziaee /* $Id: mdoc_markdown.c,v 1.39 2025/01/20 07:01:17 schwarze Exp $ */
261d06d6bSBaptiste Daroussin /*
3*80c12959SAlexander Ziaee  * Copyright (c) 2017, 2018, 2020, 2025 Ingo Schwarze <schwarze@openbsd.org>
461d06d6bSBaptiste Daroussin  *
561d06d6bSBaptiste Daroussin  * Permission to use, copy, modify, and distribute this software for any
661d06d6bSBaptiste Daroussin  * purpose with or without fee is hereby granted, provided that the above
761d06d6bSBaptiste Daroussin  * copyright notice and this permission notice appear in all copies.
861d06d6bSBaptiste Daroussin  *
961d06d6bSBaptiste Daroussin  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
1061d06d6bSBaptiste Daroussin  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1161d06d6bSBaptiste Daroussin  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
1261d06d6bSBaptiste Daroussin  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1361d06d6bSBaptiste Daroussin  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1461d06d6bSBaptiste Daroussin  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1561d06d6bSBaptiste Daroussin  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
166d38604fSBaptiste Daroussin  *
176d38604fSBaptiste Daroussin  * Markdown formatter for mdoc(7) used by mandoc(1).
1861d06d6bSBaptiste Daroussin  */
196d38604fSBaptiste Daroussin #include "config.h"
206d38604fSBaptiste Daroussin 
2161d06d6bSBaptiste Daroussin #include <sys/types.h>
2261d06d6bSBaptiste Daroussin 
2361d06d6bSBaptiste Daroussin #include <assert.h>
2461d06d6bSBaptiste Daroussin #include <ctype.h>
2561d06d6bSBaptiste Daroussin #include <stdio.h>
267295610fSBaptiste Daroussin #include <stdlib.h>
2761d06d6bSBaptiste Daroussin #include <string.h>
2861d06d6bSBaptiste Daroussin 
2961d06d6bSBaptiste Daroussin #include "mandoc_aux.h"
3061d06d6bSBaptiste Daroussin #include "mandoc.h"
3161d06d6bSBaptiste Daroussin #include "roff.h"
3261d06d6bSBaptiste Daroussin #include "mdoc.h"
3361d06d6bSBaptiste Daroussin #include "main.h"
3461d06d6bSBaptiste Daroussin 
3561d06d6bSBaptiste Daroussin struct	md_act {
366d38604fSBaptiste Daroussin 	int		(*cond)(struct roff_node *);
376d38604fSBaptiste Daroussin 	int		(*pre)(struct roff_node *);
386d38604fSBaptiste Daroussin 	void		(*post)(struct roff_node *);
3961d06d6bSBaptiste Daroussin 	const char	 *prefix; /* pre-node string constant */
4061d06d6bSBaptiste Daroussin 	const char	 *suffix; /* post-node string constant */
4161d06d6bSBaptiste Daroussin };
4261d06d6bSBaptiste Daroussin 
4361d06d6bSBaptiste Daroussin static	void	 md_nodelist(struct roff_node *);
4461d06d6bSBaptiste Daroussin static	void	 md_node(struct roff_node *);
456d38604fSBaptiste Daroussin static	const char *md_stack(char);
4661d06d6bSBaptiste Daroussin static	void	 md_preword(void);
4761d06d6bSBaptiste Daroussin static	void	 md_rawword(const char *);
4861d06d6bSBaptiste Daroussin static	void	 md_word(const char *);
4961d06d6bSBaptiste Daroussin static	void	 md_named(const char *);
5061d06d6bSBaptiste Daroussin static	void	 md_char(unsigned char);
5161d06d6bSBaptiste Daroussin static	void	 md_uri(const char *);
5261d06d6bSBaptiste Daroussin 
5361d06d6bSBaptiste Daroussin static	int	 md_cond_head(struct roff_node *);
5461d06d6bSBaptiste Daroussin static	int	 md_cond_body(struct roff_node *);
5561d06d6bSBaptiste Daroussin 
567295610fSBaptiste Daroussin static	int	 md_pre_abort(struct roff_node *);
5761d06d6bSBaptiste Daroussin static	int	 md_pre_raw(struct roff_node *);
5861d06d6bSBaptiste Daroussin static	int	 md_pre_word(struct roff_node *);
5961d06d6bSBaptiste Daroussin static	int	 md_pre_skip(struct roff_node *);
6061d06d6bSBaptiste Daroussin static	void	 md_pre_syn(struct roff_node *);
6161d06d6bSBaptiste Daroussin static	int	 md_pre_An(struct roff_node *);
6261d06d6bSBaptiste Daroussin static	int	 md_pre_Ap(struct roff_node *);
6361d06d6bSBaptiste Daroussin static	int	 md_pre_Bd(struct roff_node *);
6461d06d6bSBaptiste Daroussin static	int	 md_pre_Bk(struct roff_node *);
6561d06d6bSBaptiste Daroussin static	int	 md_pre_Bl(struct roff_node *);
6661d06d6bSBaptiste Daroussin static	int	 md_pre_D1(struct roff_node *);
6761d06d6bSBaptiste Daroussin static	int	 md_pre_Dl(struct roff_node *);
6861d06d6bSBaptiste Daroussin static	int	 md_pre_En(struct roff_node *);
6961d06d6bSBaptiste Daroussin static	int	 md_pre_Eo(struct roff_node *);
7061d06d6bSBaptiste Daroussin static	int	 md_pre_Fa(struct roff_node *);
7161d06d6bSBaptiste Daroussin static	int	 md_pre_Fd(struct roff_node *);
7261d06d6bSBaptiste Daroussin static	int	 md_pre_Fn(struct roff_node *);
7361d06d6bSBaptiste Daroussin static	int	 md_pre_Fo(struct roff_node *);
7461d06d6bSBaptiste Daroussin static	int	 md_pre_In(struct roff_node *);
7561d06d6bSBaptiste Daroussin static	int	 md_pre_It(struct roff_node *);
7661d06d6bSBaptiste Daroussin static	int	 md_pre_Lk(struct roff_node *);
7761d06d6bSBaptiste Daroussin static	int	 md_pre_Mt(struct roff_node *);
7861d06d6bSBaptiste Daroussin static	int	 md_pre_Nd(struct roff_node *);
7961d06d6bSBaptiste Daroussin static	int	 md_pre_Nm(struct roff_node *);
8061d06d6bSBaptiste Daroussin static	int	 md_pre_No(struct roff_node *);
8161d06d6bSBaptiste Daroussin static	int	 md_pre_Ns(struct roff_node *);
8261d06d6bSBaptiste Daroussin static	int	 md_pre_Pp(struct roff_node *);
8361d06d6bSBaptiste Daroussin static	int	 md_pre_Rs(struct roff_node *);
8461d06d6bSBaptiste Daroussin static	int	 md_pre_Sh(struct roff_node *);
8561d06d6bSBaptiste Daroussin static	int	 md_pre_Sm(struct roff_node *);
8661d06d6bSBaptiste Daroussin static	int	 md_pre_Vt(struct roff_node *);
8761d06d6bSBaptiste Daroussin static	int	 md_pre_Xr(struct roff_node *);
88*80c12959SAlexander Ziaee static	int	 md_pre__R(struct roff_node *);
8961d06d6bSBaptiste Daroussin static	int	 md_pre__T(struct roff_node *);
9061d06d6bSBaptiste Daroussin static	int	 md_pre_br(struct roff_node *);
9161d06d6bSBaptiste Daroussin 
9261d06d6bSBaptiste Daroussin static	void	 md_post_raw(struct roff_node *);
9361d06d6bSBaptiste Daroussin static	void	 md_post_word(struct roff_node *);
9461d06d6bSBaptiste Daroussin static	void	 md_post_pc(struct roff_node *);
9561d06d6bSBaptiste Daroussin static	void	 md_post_Bk(struct roff_node *);
9661d06d6bSBaptiste Daroussin static	void	 md_post_Bl(struct roff_node *);
9761d06d6bSBaptiste Daroussin static	void	 md_post_D1(struct roff_node *);
9861d06d6bSBaptiste Daroussin static	void	 md_post_En(struct roff_node *);
9961d06d6bSBaptiste Daroussin static	void	 md_post_Eo(struct roff_node *);
10061d06d6bSBaptiste Daroussin static	void	 md_post_Fa(struct roff_node *);
10161d06d6bSBaptiste Daroussin static	void	 md_post_Fd(struct roff_node *);
10261d06d6bSBaptiste Daroussin static	void	 md_post_Fl(struct roff_node *);
10361d06d6bSBaptiste Daroussin static	void	 md_post_Fn(struct roff_node *);
10461d06d6bSBaptiste Daroussin static	void	 md_post_Fo(struct roff_node *);
10561d06d6bSBaptiste Daroussin static	void	 md_post_In(struct roff_node *);
10661d06d6bSBaptiste Daroussin static	void	 md_post_It(struct roff_node *);
10761d06d6bSBaptiste Daroussin static	void	 md_post_Lb(struct roff_node *);
10861d06d6bSBaptiste Daroussin static	void	 md_post_Nm(struct roff_node *);
10961d06d6bSBaptiste Daroussin static	void	 md_post_Pf(struct roff_node *);
11061d06d6bSBaptiste Daroussin static	void	 md_post_Vt(struct roff_node *);
11161d06d6bSBaptiste Daroussin static	void	 md_post__T(struct roff_node *);
11261d06d6bSBaptiste Daroussin 
1137295610fSBaptiste Daroussin static	const struct md_act md_acts[MDOC_MAX - MDOC_Dd] = {
11461d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Dd */
11561d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Dt */
11661d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Os */
11761d06d6bSBaptiste Daroussin 	{ NULL, md_pre_Sh, NULL, NULL, NULL }, /* Sh */
11861d06d6bSBaptiste Daroussin 	{ NULL, md_pre_Sh, NULL, NULL, NULL }, /* Ss */
11961d06d6bSBaptiste Daroussin 	{ NULL, md_pre_Pp, NULL, NULL, NULL }, /* Pp */
12061d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_D1, md_post_D1, NULL, NULL }, /* D1 */
12161d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_Dl, md_post_D1, NULL, NULL }, /* Dl */
12261d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_Bd, md_post_D1, NULL, NULL }, /* Bd */
12361d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Ed */
12461d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_Bl, md_post_Bl, NULL, NULL }, /* Bl */
12561d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* El */
12661d06d6bSBaptiste Daroussin 	{ NULL, md_pre_It, md_post_It, NULL, NULL }, /* It */
12761d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Ad */
12861d06d6bSBaptiste Daroussin 	{ NULL, md_pre_An, NULL, NULL, NULL }, /* An */
12961d06d6bSBaptiste Daroussin 	{ NULL, md_pre_Ap, NULL, NULL, NULL }, /* Ap */
13061d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Ar */
13161d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Cd */
13261d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Cm */
13361d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Dv */
13461d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Er */
13561d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Ev */
13661d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Ex */
13761d06d6bSBaptiste Daroussin 	{ NULL, md_pre_Fa, md_post_Fa, NULL, NULL }, /* Fa */
13861d06d6bSBaptiste Daroussin 	{ NULL, md_pre_Fd, md_post_Fd, "**", "**" }, /* Fd */
13961d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_Fl, "**-", "**" }, /* Fl */
14061d06d6bSBaptiste Daroussin 	{ NULL, md_pre_Fn, md_post_Fn, NULL, NULL }, /* Fn */
14161d06d6bSBaptiste Daroussin 	{ NULL, md_pre_Fd, md_post_raw, "*", "*" }, /* Ft */
14261d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Ic */
14361d06d6bSBaptiste Daroussin 	{ NULL, md_pre_In, md_post_In, NULL, NULL }, /* In */
14461d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Li */
14561d06d6bSBaptiste Daroussin 	{ md_cond_head, md_pre_Nd, NULL, NULL, NULL }, /* Nd */
14661d06d6bSBaptiste Daroussin 	{ NULL, md_pre_Nm, md_post_Nm, "**", "**" }, /* Nm */
14761d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Op */
1487295610fSBaptiste Daroussin 	{ NULL, md_pre_abort, NULL, NULL, NULL }, /* Ot */
14961d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Pa */
15061d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Rv */
15161d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* St */
15261d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Va */
15361d06d6bSBaptiste Daroussin 	{ NULL, md_pre_Vt, md_post_Vt, "*", "*" }, /* Vt */
15461d06d6bSBaptiste Daroussin 	{ NULL, md_pre_Xr, NULL, NULL, NULL }, /* Xr */
15561d06d6bSBaptiste Daroussin 	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %A */
15661d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %B */
15761d06d6bSBaptiste Daroussin 	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %D */
15861d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %I */
15961d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %J */
16061d06d6bSBaptiste Daroussin 	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %N */
16161d06d6bSBaptiste Daroussin 	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %O */
16261d06d6bSBaptiste Daroussin 	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %P */
163*80c12959SAlexander Ziaee 	{ NULL, md_pre__R, md_post_pc, NULL, NULL }, /* %R */
16461d06d6bSBaptiste Daroussin 	{ NULL, md_pre__T, md_post__T, NULL, NULL }, /* %T */
16561d06d6bSBaptiste Daroussin 	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %V */
16661d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Ac */
16761d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_word, md_post_word, "<", ">" }, /* Ao */
16861d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_word, md_post_word, "<", ">" }, /* Aq */
16961d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* At */
17061d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Bc */
17161d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Bf XXX not implemented */
17261d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Bo */
17361d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Bq */
17461d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Bsx */
17561d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Bx */
17661d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Db */
17761d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Dc */
17861d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Do */
17961d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Dq */
18061d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Ec */
18161d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Ef */
18261d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Em */
18361d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_Eo, md_post_Eo, NULL, NULL }, /* Eo */
18461d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Fx */
18561d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Ms */
18661d06d6bSBaptiste Daroussin 	{ NULL, md_pre_No, NULL, NULL, NULL }, /* No */
18761d06d6bSBaptiste Daroussin 	{ NULL, md_pre_Ns, NULL, NULL, NULL }, /* Ns */
18861d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Nx */
18961d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Ox */
19061d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Pc */
19161d06d6bSBaptiste Daroussin 	{ NULL, NULL, md_post_Pf, NULL, NULL }, /* Pf */
19261d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_word, md_post_word, "(", ")" }, /* Po */
19361d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_word, md_post_word, "(", ")" }, /* Pq */
19461d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Qc */
19561d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_raw, md_post_raw, "'`", "`'" }, /* Ql */
19661d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Qo */
19761d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Qq */
19861d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Re */
19961d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_Rs, NULL, NULL, NULL }, /* Rs */
20061d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Sc */
20161d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_word, md_post_word, "'", "'" }, /* So */
20261d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_word, md_post_word, "'", "'" }, /* Sq */
20361d06d6bSBaptiste Daroussin 	{ NULL, md_pre_Sm, NULL, NULL, NULL }, /* Sm */
20461d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Sx */
20561d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Sy */
20661d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Tn */
20761d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Ux */
20861d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Xc */
20961d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Xo */
21061d06d6bSBaptiste Daroussin 	{ NULL, md_pre_Fo, md_post_Fo, "**", "**" }, /* Fo */
21161d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Fc */
21261d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Oo */
21361d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Oc */
21461d06d6bSBaptiste Daroussin 	{ NULL, md_pre_Bk, md_post_Bk, NULL, NULL }, /* Bk */
21561d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Ek */
21661d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Bt */
21761d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Hf */
21861d06d6bSBaptiste Daroussin 	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Fr */
21961d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Ud */
22061d06d6bSBaptiste Daroussin 	{ NULL, NULL, md_post_Lb, NULL, NULL }, /* Lb */
2217295610fSBaptiste Daroussin 	{ NULL, md_pre_abort, NULL, NULL, NULL }, /* Lp */
22261d06d6bSBaptiste Daroussin 	{ NULL, md_pre_Lk, NULL, NULL, NULL }, /* Lk */
22361d06d6bSBaptiste Daroussin 	{ NULL, md_pre_Mt, NULL, NULL, NULL }, /* Mt */
22461d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Brq */
22561d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Bro */
22661d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Brc */
22761d06d6bSBaptiste Daroussin 	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %C */
22861d06d6bSBaptiste Daroussin 	{ NULL, md_pre_skip, NULL, NULL, NULL }, /* Es */
22961d06d6bSBaptiste Daroussin 	{ md_cond_body, md_pre_En, md_post_En, NULL, NULL }, /* En */
23061d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Dx */
23161d06d6bSBaptiste Daroussin 	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %Q */
23261d06d6bSBaptiste Daroussin 	{ NULL, md_pre_Lk, md_post_pc, NULL, NULL }, /* %U */
23361d06d6bSBaptiste Daroussin 	{ NULL, NULL, NULL, NULL, NULL }, /* Ta */
2346d38604fSBaptiste Daroussin 	{ NULL, md_pre_skip, NULL, NULL, NULL }, /* Tg */
23561d06d6bSBaptiste Daroussin };
2367295610fSBaptiste Daroussin static const struct md_act *md_act(enum roff_tok);
23761d06d6bSBaptiste Daroussin 
23861d06d6bSBaptiste Daroussin static	int	 outflags;
23961d06d6bSBaptiste Daroussin #define	MD_spc		 (1 << 0)  /* Blank character before next word. */
24061d06d6bSBaptiste Daroussin #define	MD_spc_force	 (1 << 1)  /* Even before trailing punctuation. */
24161d06d6bSBaptiste Daroussin #define	MD_nonl		 (1 << 2)  /* Prevent linebreak in markdown code. */
24261d06d6bSBaptiste Daroussin #define	MD_nl		 (1 << 3)  /* Break markdown code line. */
24361d06d6bSBaptiste Daroussin #define	MD_br		 (1 << 4)  /* Insert an output line break. */
24461d06d6bSBaptiste Daroussin #define	MD_sp		 (1 << 5)  /* Insert a paragraph break. */
24561d06d6bSBaptiste Daroussin #define	MD_Sm		 (1 << 6)  /* Horizontal spacing mode. */
24661d06d6bSBaptiste Daroussin #define	MD_Bk		 (1 << 7)  /* Word keep mode. */
24761d06d6bSBaptiste Daroussin #define	MD_An_split	 (1 << 8)  /* Author mode is "split". */
24861d06d6bSBaptiste Daroussin #define	MD_An_nosplit	 (1 << 9)  /* Author mode is "nosplit". */
24961d06d6bSBaptiste Daroussin 
25061d06d6bSBaptiste Daroussin static	int	 escflags; /* Escape in generated markdown code: */
25161d06d6bSBaptiste Daroussin #define	ESC_BOL	 (1 << 0)  /* "#*+-" near the beginning of a line. */
25261d06d6bSBaptiste Daroussin #define	ESC_NUM	 (1 << 1)  /* "." after a leading number. */
25361d06d6bSBaptiste Daroussin #define	ESC_HYP	 (1 << 2)  /* "(" immediately after "]". */
25461d06d6bSBaptiste Daroussin #define	ESC_SQU	 (1 << 4)  /* "]" when "[" is open. */
25561d06d6bSBaptiste Daroussin #define	ESC_FON	 (1 << 5)  /* "*" immediately after unrelated "*". */
25661d06d6bSBaptiste Daroussin #define	ESC_EOL	 (1 << 6)  /* " " at the and of a line. */
25761d06d6bSBaptiste Daroussin 
25861d06d6bSBaptiste Daroussin static	int	 code_blocks, quote_blocks, list_blocks;
25961d06d6bSBaptiste Daroussin static	int	 outcount;
26061d06d6bSBaptiste Daroussin 
2617295610fSBaptiste Daroussin 
2627295610fSBaptiste Daroussin static const struct md_act *
md_act(enum roff_tok tok)2637295610fSBaptiste Daroussin md_act(enum roff_tok tok)
2647295610fSBaptiste Daroussin {
2657295610fSBaptiste Daroussin 	assert(tok >= MDOC_Dd && tok <= MDOC_MAX);
2667295610fSBaptiste Daroussin 	return md_acts + (tok - MDOC_Dd);
2677295610fSBaptiste Daroussin }
2687295610fSBaptiste Daroussin 
26961d06d6bSBaptiste Daroussin void
markdown_mdoc(void * arg,const struct roff_meta * mdoc)2707295610fSBaptiste Daroussin markdown_mdoc(void *arg, const struct roff_meta *mdoc)
27161d06d6bSBaptiste Daroussin {
27261d06d6bSBaptiste Daroussin 	outflags = MD_Sm;
2737295610fSBaptiste Daroussin 	md_word(mdoc->title);
2747295610fSBaptiste Daroussin 	if (mdoc->msec != NULL) {
27561d06d6bSBaptiste Daroussin 		outflags &= ~MD_spc;
27661d06d6bSBaptiste Daroussin 		md_word("(");
2777295610fSBaptiste Daroussin 		md_word(mdoc->msec);
27861d06d6bSBaptiste Daroussin 		md_word(")");
27961d06d6bSBaptiste Daroussin 	}
28061d06d6bSBaptiste Daroussin 	md_word("-");
2817295610fSBaptiste Daroussin 	md_word(mdoc->vol);
2827295610fSBaptiste Daroussin 	if (mdoc->arch != NULL) {
28361d06d6bSBaptiste Daroussin 		md_word("(");
2847295610fSBaptiste Daroussin 		md_word(mdoc->arch);
28561d06d6bSBaptiste Daroussin 		md_word(")");
28661d06d6bSBaptiste Daroussin 	}
28761d06d6bSBaptiste Daroussin 	outflags |= MD_sp;
28861d06d6bSBaptiste Daroussin 
28961d06d6bSBaptiste Daroussin 	md_nodelist(mdoc->first->child);
29061d06d6bSBaptiste Daroussin 
29161d06d6bSBaptiste Daroussin 	outflags |= MD_sp;
2927295610fSBaptiste Daroussin 	md_word(mdoc->os);
29361d06d6bSBaptiste Daroussin 	md_word("-");
2947295610fSBaptiste Daroussin 	md_word(mdoc->date);
29561d06d6bSBaptiste Daroussin 	putchar('\n');
29661d06d6bSBaptiste Daroussin }
29761d06d6bSBaptiste Daroussin 
29861d06d6bSBaptiste Daroussin static void
md_nodelist(struct roff_node * n)29961d06d6bSBaptiste Daroussin md_nodelist(struct roff_node *n)
30061d06d6bSBaptiste Daroussin {
30161d06d6bSBaptiste Daroussin 	while (n != NULL) {
30261d06d6bSBaptiste Daroussin 		md_node(n);
30361d06d6bSBaptiste Daroussin 		n = n->next;
30461d06d6bSBaptiste Daroussin 	}
30561d06d6bSBaptiste Daroussin }
30661d06d6bSBaptiste Daroussin 
30761d06d6bSBaptiste Daroussin static void
md_node(struct roff_node * n)30861d06d6bSBaptiste Daroussin md_node(struct roff_node *n)
30961d06d6bSBaptiste Daroussin {
31061d06d6bSBaptiste Daroussin 	const struct md_act	*act;
31161d06d6bSBaptiste Daroussin 	int			 cond, process_children;
31261d06d6bSBaptiste Daroussin 
31361d06d6bSBaptiste Daroussin 	if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
31461d06d6bSBaptiste Daroussin 		return;
31561d06d6bSBaptiste Daroussin 
31661d06d6bSBaptiste Daroussin 	if (outflags & MD_nonl)
31761d06d6bSBaptiste Daroussin 		outflags &= ~(MD_nl | MD_sp);
3186d38604fSBaptiste Daroussin 	else if (outflags & MD_spc &&
3196d38604fSBaptiste Daroussin 	     n->flags & NODE_LINE &&
3206d38604fSBaptiste Daroussin 	     !roff_node_transparent(n))
32161d06d6bSBaptiste Daroussin 		outflags |= MD_nl;
32261d06d6bSBaptiste Daroussin 
32361d06d6bSBaptiste Daroussin 	act = NULL;
32461d06d6bSBaptiste Daroussin 	cond = 0;
32561d06d6bSBaptiste Daroussin 	process_children = 1;
32661d06d6bSBaptiste Daroussin 	n->flags &= ~NODE_ENDED;
32761d06d6bSBaptiste Daroussin 
32861d06d6bSBaptiste Daroussin 	if (n->type == ROFFT_TEXT) {
32961d06d6bSBaptiste Daroussin 		if (n->flags & NODE_DELIMC)
33061d06d6bSBaptiste Daroussin 			outflags &= ~(MD_spc | MD_spc_force);
33161d06d6bSBaptiste Daroussin 		else if (outflags & MD_Sm)
33261d06d6bSBaptiste Daroussin 			outflags |= MD_spc_force;
33361d06d6bSBaptiste Daroussin 		md_word(n->string);
33461d06d6bSBaptiste Daroussin 		if (n->flags & NODE_DELIMO)
33561d06d6bSBaptiste Daroussin 			outflags &= ~(MD_spc | MD_spc_force);
33661d06d6bSBaptiste Daroussin 		else if (outflags & MD_Sm)
33761d06d6bSBaptiste Daroussin 			outflags |= MD_spc;
33861d06d6bSBaptiste Daroussin 	} else if (n->tok < ROFF_MAX) {
33961d06d6bSBaptiste Daroussin 		switch (n->tok) {
34061d06d6bSBaptiste Daroussin 		case ROFF_br:
34161d06d6bSBaptiste Daroussin 			process_children = md_pre_br(n);
34261d06d6bSBaptiste Daroussin 			break;
34361d06d6bSBaptiste Daroussin 		case ROFF_sp:
34461d06d6bSBaptiste Daroussin 			process_children = md_pre_Pp(n);
34561d06d6bSBaptiste Daroussin 			break;
34661d06d6bSBaptiste Daroussin 		default:
34761d06d6bSBaptiste Daroussin 			process_children = 0;
34861d06d6bSBaptiste Daroussin 			break;
34961d06d6bSBaptiste Daroussin 		}
35061d06d6bSBaptiste Daroussin 	} else {
3517295610fSBaptiste Daroussin 		act = md_act(n->tok);
35261d06d6bSBaptiste Daroussin 		cond = act->cond == NULL || (*act->cond)(n);
35361d06d6bSBaptiste Daroussin 		if (cond && act->pre != NULL &&
35461d06d6bSBaptiste Daroussin 		    (n->end == ENDBODY_NOT || n->child != NULL))
35561d06d6bSBaptiste Daroussin 			process_children = (*act->pre)(n);
35661d06d6bSBaptiste Daroussin 	}
35761d06d6bSBaptiste Daroussin 
35861d06d6bSBaptiste Daroussin 	if (process_children && n->child != NULL)
35961d06d6bSBaptiste Daroussin 		md_nodelist(n->child);
36061d06d6bSBaptiste Daroussin 
36161d06d6bSBaptiste Daroussin 	if (n->flags & NODE_ENDED)
36261d06d6bSBaptiste Daroussin 		return;
36361d06d6bSBaptiste Daroussin 
36461d06d6bSBaptiste Daroussin 	if (cond && act->post != NULL)
36561d06d6bSBaptiste Daroussin 		(*act->post)(n);
36661d06d6bSBaptiste Daroussin 
36761d06d6bSBaptiste Daroussin 	if (n->end != ENDBODY_NOT)
36861d06d6bSBaptiste Daroussin 		n->body->flags |= NODE_ENDED;
36961d06d6bSBaptiste Daroussin }
37061d06d6bSBaptiste Daroussin 
37161d06d6bSBaptiste Daroussin static const char *
md_stack(char c)37261d06d6bSBaptiste Daroussin md_stack(char c)
37361d06d6bSBaptiste Daroussin {
37461d06d6bSBaptiste Daroussin 	static char	*stack;
37561d06d6bSBaptiste Daroussin 	static size_t	 sz;
37661d06d6bSBaptiste Daroussin 	static size_t	 cur;
37761d06d6bSBaptiste Daroussin 
37861d06d6bSBaptiste Daroussin 	switch (c) {
37961d06d6bSBaptiste Daroussin 	case '\0':
38061d06d6bSBaptiste Daroussin 		break;
38161d06d6bSBaptiste Daroussin 	case (char)-1:
38261d06d6bSBaptiste Daroussin 		assert(cur);
38361d06d6bSBaptiste Daroussin 		stack[--cur] = '\0';
38461d06d6bSBaptiste Daroussin 		break;
38561d06d6bSBaptiste Daroussin 	default:
38661d06d6bSBaptiste Daroussin 		if (cur + 1 >= sz) {
38761d06d6bSBaptiste Daroussin 			sz += 8;
38861d06d6bSBaptiste Daroussin 			stack = mandoc_realloc(stack, sz);
38961d06d6bSBaptiste Daroussin 		}
39061d06d6bSBaptiste Daroussin 		stack[cur] = c;
39161d06d6bSBaptiste Daroussin 		stack[++cur] = '\0';
39261d06d6bSBaptiste Daroussin 		break;
39361d06d6bSBaptiste Daroussin 	}
39461d06d6bSBaptiste Daroussin 	return stack == NULL ? "" : stack;
39561d06d6bSBaptiste Daroussin }
39661d06d6bSBaptiste Daroussin 
39761d06d6bSBaptiste Daroussin /*
39861d06d6bSBaptiste Daroussin  * Handle vertical and horizontal spacing.
39961d06d6bSBaptiste Daroussin  */
40061d06d6bSBaptiste Daroussin static void
md_preword(void)40161d06d6bSBaptiste Daroussin md_preword(void)
40261d06d6bSBaptiste Daroussin {
40361d06d6bSBaptiste Daroussin 	const char	*cp;
40461d06d6bSBaptiste Daroussin 
40561d06d6bSBaptiste Daroussin 	/*
40661d06d6bSBaptiste Daroussin 	 * If a list block is nested inside a code block or a blockquote,
40761d06d6bSBaptiste Daroussin 	 * blank lines for paragraph breaks no longer work; instead,
40861d06d6bSBaptiste Daroussin 	 * they terminate the list.  Work around this markdown issue
40961d06d6bSBaptiste Daroussin 	 * by using mere line breaks instead.
41061d06d6bSBaptiste Daroussin 	 */
41161d06d6bSBaptiste Daroussin 
41261d06d6bSBaptiste Daroussin 	if (list_blocks && outflags & MD_sp) {
41361d06d6bSBaptiste Daroussin 		outflags &= ~MD_sp;
41461d06d6bSBaptiste Daroussin 		outflags |= MD_br;
41561d06d6bSBaptiste Daroussin 	}
41661d06d6bSBaptiste Daroussin 
41761d06d6bSBaptiste Daroussin 	/*
41861d06d6bSBaptiste Daroussin 	 * End the old line if requested.
41961d06d6bSBaptiste Daroussin 	 * Escape whitespace at the end of the markdown line
42061d06d6bSBaptiste Daroussin 	 * such that it won't look like an output line break.
42161d06d6bSBaptiste Daroussin 	 */
42261d06d6bSBaptiste Daroussin 
42361d06d6bSBaptiste Daroussin 	if (outflags & MD_sp)
42461d06d6bSBaptiste Daroussin 		putchar('\n');
42561d06d6bSBaptiste Daroussin 	else if (outflags & MD_br) {
42661d06d6bSBaptiste Daroussin 		putchar(' ');
42761d06d6bSBaptiste Daroussin 		putchar(' ');
42861d06d6bSBaptiste Daroussin 	} else if (outflags & MD_nl && escflags & ESC_EOL)
42961d06d6bSBaptiste Daroussin 		md_named("zwnj");
43061d06d6bSBaptiste Daroussin 
43161d06d6bSBaptiste Daroussin 	/* Start a new line if necessary. */
43261d06d6bSBaptiste Daroussin 
43361d06d6bSBaptiste Daroussin 	if (outflags & (MD_nl | MD_br | MD_sp)) {
43461d06d6bSBaptiste Daroussin 		putchar('\n');
43561d06d6bSBaptiste Daroussin 		for (cp = md_stack('\0'); *cp != '\0'; cp++) {
43661d06d6bSBaptiste Daroussin 			putchar(*cp);
43761d06d6bSBaptiste Daroussin 			if (*cp == '>')
43861d06d6bSBaptiste Daroussin 				putchar(' ');
43961d06d6bSBaptiste Daroussin 		}
44061d06d6bSBaptiste Daroussin 		outflags &= ~(MD_nl | MD_br | MD_sp);
44161d06d6bSBaptiste Daroussin 		escflags = ESC_BOL;
44261d06d6bSBaptiste Daroussin 		outcount = 0;
44361d06d6bSBaptiste Daroussin 
44461d06d6bSBaptiste Daroussin 	/* Handle horizontal spacing. */
44561d06d6bSBaptiste Daroussin 
44661d06d6bSBaptiste Daroussin 	} else if (outflags & MD_spc) {
44761d06d6bSBaptiste Daroussin 		if (outflags & MD_Bk)
44861d06d6bSBaptiste Daroussin 			fputs("&nbsp;", stdout);
44961d06d6bSBaptiste Daroussin 		else
45061d06d6bSBaptiste Daroussin 			putchar(' ');
45161d06d6bSBaptiste Daroussin 		escflags &= ~ESC_FON;
45261d06d6bSBaptiste Daroussin 		outcount++;
45361d06d6bSBaptiste Daroussin 	}
45461d06d6bSBaptiste Daroussin 
45561d06d6bSBaptiste Daroussin 	outflags &= ~(MD_spc_force | MD_nonl);
45661d06d6bSBaptiste Daroussin 	if (outflags & MD_Sm)
45761d06d6bSBaptiste Daroussin 		outflags |= MD_spc;
45861d06d6bSBaptiste Daroussin 	else
45961d06d6bSBaptiste Daroussin 		outflags &= ~MD_spc;
46061d06d6bSBaptiste Daroussin }
46161d06d6bSBaptiste Daroussin 
46261d06d6bSBaptiste Daroussin /*
46361d06d6bSBaptiste Daroussin  * Print markdown syntax elements.
46461d06d6bSBaptiste Daroussin  * Can also be used for constant strings when neither escaping
46561d06d6bSBaptiste Daroussin  * nor delimiter handling is required.
46661d06d6bSBaptiste Daroussin  */
46761d06d6bSBaptiste Daroussin static void
md_rawword(const char * s)46861d06d6bSBaptiste Daroussin md_rawword(const char *s)
46961d06d6bSBaptiste Daroussin {
47061d06d6bSBaptiste Daroussin 	md_preword();
47161d06d6bSBaptiste Daroussin 
47261d06d6bSBaptiste Daroussin 	if (*s == '\0')
47361d06d6bSBaptiste Daroussin 		return;
47461d06d6bSBaptiste Daroussin 
47561d06d6bSBaptiste Daroussin 	if (escflags & ESC_FON) {
47661d06d6bSBaptiste Daroussin 		escflags &= ~ESC_FON;
47761d06d6bSBaptiste Daroussin 		if (*s == '*' && !code_blocks)
47861d06d6bSBaptiste Daroussin 			fputs("&zwnj;", stdout);
47961d06d6bSBaptiste Daroussin 	}
48061d06d6bSBaptiste Daroussin 
48161d06d6bSBaptiste Daroussin 	while (*s != '\0') {
48261d06d6bSBaptiste Daroussin 		switch(*s) {
48361d06d6bSBaptiste Daroussin 		case '*':
48461d06d6bSBaptiste Daroussin 			if (s[1] == '\0')
48561d06d6bSBaptiste Daroussin 				escflags |= ESC_FON;
48661d06d6bSBaptiste Daroussin 			break;
48761d06d6bSBaptiste Daroussin 		case '[':
48861d06d6bSBaptiste Daroussin 			escflags |= ESC_SQU;
48961d06d6bSBaptiste Daroussin 			break;
49061d06d6bSBaptiste Daroussin 		case ']':
49161d06d6bSBaptiste Daroussin 			escflags |= ESC_HYP;
49261d06d6bSBaptiste Daroussin 			escflags &= ~ESC_SQU;
49361d06d6bSBaptiste Daroussin 			break;
49461d06d6bSBaptiste Daroussin 		default:
49561d06d6bSBaptiste Daroussin 			break;
49661d06d6bSBaptiste Daroussin 		}
49761d06d6bSBaptiste Daroussin 		md_char(*s++);
49861d06d6bSBaptiste Daroussin 	}
49961d06d6bSBaptiste Daroussin 	if (s[-1] == ' ')
50061d06d6bSBaptiste Daroussin 		escflags |= ESC_EOL;
50161d06d6bSBaptiste Daroussin 	else
50261d06d6bSBaptiste Daroussin 		escflags &= ~ESC_EOL;
50361d06d6bSBaptiste Daroussin }
50461d06d6bSBaptiste Daroussin 
50561d06d6bSBaptiste Daroussin /*
50661d06d6bSBaptiste Daroussin  * Print text and mdoc(7) syntax elements.
50761d06d6bSBaptiste Daroussin  */
50861d06d6bSBaptiste Daroussin static void
md_word(const char * s)50961d06d6bSBaptiste Daroussin md_word(const char *s)
51061d06d6bSBaptiste Daroussin {
51161d06d6bSBaptiste Daroussin 	const char	*seq, *prevfont, *currfont, *nextfont;
51261d06d6bSBaptiste Daroussin 	char		 c;
51361d06d6bSBaptiste Daroussin 	int		 bs, sz, uc, breakline;
51461d06d6bSBaptiste Daroussin 
51561d06d6bSBaptiste Daroussin 	/* No spacing before closing delimiters. */
51661d06d6bSBaptiste Daroussin 	if (s[0] != '\0' && s[1] == '\0' &&
51761d06d6bSBaptiste Daroussin 	    strchr("!),.:;?]", s[0]) != NULL &&
51861d06d6bSBaptiste Daroussin 	    (outflags & MD_spc_force) == 0)
51961d06d6bSBaptiste Daroussin 		outflags &= ~MD_spc;
52061d06d6bSBaptiste Daroussin 
52161d06d6bSBaptiste Daroussin 	md_preword();
52261d06d6bSBaptiste Daroussin 
52361d06d6bSBaptiste Daroussin 	if (*s == '\0')
52461d06d6bSBaptiste Daroussin 		return;
52561d06d6bSBaptiste Daroussin 
52661d06d6bSBaptiste Daroussin 	/* No spacing after opening delimiters. */
52761d06d6bSBaptiste Daroussin 	if ((s[0] == '(' || s[0] == '[') && s[1] == '\0')
52861d06d6bSBaptiste Daroussin 		outflags &= ~MD_spc;
52961d06d6bSBaptiste Daroussin 
53061d06d6bSBaptiste Daroussin 	breakline = 0;
53161d06d6bSBaptiste Daroussin 	prevfont = currfont = "";
53261d06d6bSBaptiste Daroussin 	while ((c = *s++) != '\0') {
53361d06d6bSBaptiste Daroussin 		bs = 0;
53461d06d6bSBaptiste Daroussin 		switch(c) {
53561d06d6bSBaptiste Daroussin 		case ASCII_NBRSP:
53661d06d6bSBaptiste Daroussin 			if (code_blocks)
53761d06d6bSBaptiste Daroussin 				c = ' ';
53861d06d6bSBaptiste Daroussin 			else {
53961d06d6bSBaptiste Daroussin 				md_named("nbsp");
54061d06d6bSBaptiste Daroussin 				c = '\0';
54161d06d6bSBaptiste Daroussin 			}
54261d06d6bSBaptiste Daroussin 			break;
54361d06d6bSBaptiste Daroussin 		case ASCII_HYPH:
54461d06d6bSBaptiste Daroussin 			bs = escflags & ESC_BOL && !code_blocks;
54561d06d6bSBaptiste Daroussin 			c = '-';
54661d06d6bSBaptiste Daroussin 			break;
54761d06d6bSBaptiste Daroussin 		case ASCII_BREAK:
54861d06d6bSBaptiste Daroussin 			continue;
54961d06d6bSBaptiste Daroussin 		case '#':
55061d06d6bSBaptiste Daroussin 		case '+':
55161d06d6bSBaptiste Daroussin 		case '-':
55261d06d6bSBaptiste Daroussin 			bs = escflags & ESC_BOL && !code_blocks;
55361d06d6bSBaptiste Daroussin 			break;
55461d06d6bSBaptiste Daroussin 		case '(':
55561d06d6bSBaptiste Daroussin 			bs = escflags & ESC_HYP && !code_blocks;
55661d06d6bSBaptiste Daroussin 			break;
55761d06d6bSBaptiste Daroussin 		case ')':
55861d06d6bSBaptiste Daroussin 			bs = escflags & ESC_NUM && !code_blocks;
55961d06d6bSBaptiste Daroussin 			break;
56061d06d6bSBaptiste Daroussin 		case '*':
56161d06d6bSBaptiste Daroussin 		case '[':
56261d06d6bSBaptiste Daroussin 		case '_':
56361d06d6bSBaptiste Daroussin 		case '`':
56461d06d6bSBaptiste Daroussin 			bs = !code_blocks;
56561d06d6bSBaptiste Daroussin 			break;
56661d06d6bSBaptiste Daroussin 		case '.':
56761d06d6bSBaptiste Daroussin 			bs = escflags & ESC_NUM && !code_blocks;
56861d06d6bSBaptiste Daroussin 			break;
56961d06d6bSBaptiste Daroussin 		case '<':
57061d06d6bSBaptiste Daroussin 			if (code_blocks == 0) {
57161d06d6bSBaptiste Daroussin 				md_named("lt");
57261d06d6bSBaptiste Daroussin 				c = '\0';
57361d06d6bSBaptiste Daroussin 			}
57461d06d6bSBaptiste Daroussin 			break;
57561d06d6bSBaptiste Daroussin 		case '=':
57661d06d6bSBaptiste Daroussin 			if (escflags & ESC_BOL && !code_blocks) {
57761d06d6bSBaptiste Daroussin 				md_named("equals");
57861d06d6bSBaptiste Daroussin 				c = '\0';
57961d06d6bSBaptiste Daroussin 			}
58061d06d6bSBaptiste Daroussin 			break;
58161d06d6bSBaptiste Daroussin 		case '>':
58261d06d6bSBaptiste Daroussin 			if (code_blocks == 0) {
58361d06d6bSBaptiste Daroussin 				md_named("gt");
58461d06d6bSBaptiste Daroussin 				c = '\0';
58561d06d6bSBaptiste Daroussin 			}
58661d06d6bSBaptiste Daroussin 			break;
58761d06d6bSBaptiste Daroussin 		case '\\':
58861d06d6bSBaptiste Daroussin 			uc = 0;
58961d06d6bSBaptiste Daroussin 			nextfont = NULL;
59061d06d6bSBaptiste Daroussin 			switch (mandoc_escape(&s, &seq, &sz)) {
59161d06d6bSBaptiste Daroussin 			case ESCAPE_UNICODE:
59261d06d6bSBaptiste Daroussin 				uc = mchars_num2uc(seq + 1, sz - 1);
59361d06d6bSBaptiste Daroussin 				break;
59461d06d6bSBaptiste Daroussin 			case ESCAPE_NUMBERED:
59561d06d6bSBaptiste Daroussin 				uc = mchars_num2char(seq, sz);
59661d06d6bSBaptiste Daroussin 				break;
59761d06d6bSBaptiste Daroussin 			case ESCAPE_SPECIAL:
59861d06d6bSBaptiste Daroussin 				uc = mchars_spec2cp(seq, sz);
59961d06d6bSBaptiste Daroussin 				break;
6007295610fSBaptiste Daroussin 			case ESCAPE_UNDEF:
6017295610fSBaptiste Daroussin 				uc = *seq;
6027295610fSBaptiste Daroussin 				break;
6037295610fSBaptiste Daroussin 			case ESCAPE_DEVICE:
6047295610fSBaptiste Daroussin 				md_rawword("markdown");
6057295610fSBaptiste Daroussin 				continue;
60661d06d6bSBaptiste Daroussin 			case ESCAPE_FONTBOLD:
6076d38604fSBaptiste Daroussin 			case ESCAPE_FONTCB:
60861d06d6bSBaptiste Daroussin 				nextfont = "**";
60961d06d6bSBaptiste Daroussin 				break;
61061d06d6bSBaptiste Daroussin 			case ESCAPE_FONTITALIC:
6116d38604fSBaptiste Daroussin 			case ESCAPE_FONTCI:
61261d06d6bSBaptiste Daroussin 				nextfont = "*";
61361d06d6bSBaptiste Daroussin 				break;
61461d06d6bSBaptiste Daroussin 			case ESCAPE_FONTBI:
61561d06d6bSBaptiste Daroussin 				nextfont = "***";
61661d06d6bSBaptiste Daroussin 				break;
61761d06d6bSBaptiste Daroussin 			case ESCAPE_FONT:
6186d38604fSBaptiste Daroussin 			case ESCAPE_FONTCR:
61961d06d6bSBaptiste Daroussin 			case ESCAPE_FONTROMAN:
62061d06d6bSBaptiste Daroussin 				nextfont = "";
62161d06d6bSBaptiste Daroussin 				break;
62261d06d6bSBaptiste Daroussin 			case ESCAPE_FONTPREV:
62361d06d6bSBaptiste Daroussin 				nextfont = prevfont;
62461d06d6bSBaptiste Daroussin 				break;
62561d06d6bSBaptiste Daroussin 			case ESCAPE_BREAK:
62661d06d6bSBaptiste Daroussin 				breakline = 1;
62761d06d6bSBaptiste Daroussin 				break;
62861d06d6bSBaptiste Daroussin 			case ESCAPE_NOSPACE:
62961d06d6bSBaptiste Daroussin 			case ESCAPE_SKIPCHAR:
63061d06d6bSBaptiste Daroussin 			case ESCAPE_OVERSTRIKE:
63161d06d6bSBaptiste Daroussin 				/* XXX not implemented */
63261d06d6bSBaptiste Daroussin 				/* FALLTHROUGH */
63361d06d6bSBaptiste Daroussin 			case ESCAPE_ERROR:
63461d06d6bSBaptiste Daroussin 			default:
63561d06d6bSBaptiste Daroussin 				break;
63661d06d6bSBaptiste Daroussin 			}
63761d06d6bSBaptiste Daroussin 			if (nextfont != NULL && !code_blocks) {
63861d06d6bSBaptiste Daroussin 				if (*currfont != '\0') {
63961d06d6bSBaptiste Daroussin 					outflags &= ~MD_spc;
64061d06d6bSBaptiste Daroussin 					md_rawword(currfont);
64161d06d6bSBaptiste Daroussin 				}
64261d06d6bSBaptiste Daroussin 				prevfont = currfont;
64361d06d6bSBaptiste Daroussin 				currfont = nextfont;
64461d06d6bSBaptiste Daroussin 				if (*currfont != '\0') {
64561d06d6bSBaptiste Daroussin 					outflags &= ~MD_spc;
64661d06d6bSBaptiste Daroussin 					md_rawword(currfont);
64761d06d6bSBaptiste Daroussin 				}
64861d06d6bSBaptiste Daroussin 			}
64961d06d6bSBaptiste Daroussin 			if (uc) {
65061d06d6bSBaptiste Daroussin 				if ((uc < 0x20 && uc != 0x09) ||
65161d06d6bSBaptiste Daroussin 				    (uc > 0x7E && uc < 0xA0))
65261d06d6bSBaptiste Daroussin 					uc = 0xFFFD;
65361d06d6bSBaptiste Daroussin 				if (code_blocks) {
65461d06d6bSBaptiste Daroussin 					seq = mchars_uc2str(uc);
65561d06d6bSBaptiste Daroussin 					fputs(seq, stdout);
65661d06d6bSBaptiste Daroussin 					outcount += strlen(seq);
65761d06d6bSBaptiste Daroussin 				} else {
65861d06d6bSBaptiste Daroussin 					printf("&#%d;", uc);
65961d06d6bSBaptiste Daroussin 					outcount++;
66061d06d6bSBaptiste Daroussin 				}
66161d06d6bSBaptiste Daroussin 				escflags &= ~ESC_FON;
66261d06d6bSBaptiste Daroussin 			}
66361d06d6bSBaptiste Daroussin 			c = '\0';
66461d06d6bSBaptiste Daroussin 			break;
66561d06d6bSBaptiste Daroussin 		case ']':
66661d06d6bSBaptiste Daroussin 			bs = escflags & ESC_SQU && !code_blocks;
66761d06d6bSBaptiste Daroussin 			escflags |= ESC_HYP;
66861d06d6bSBaptiste Daroussin 			break;
66961d06d6bSBaptiste Daroussin 		default:
67061d06d6bSBaptiste Daroussin 			break;
67161d06d6bSBaptiste Daroussin 		}
67261d06d6bSBaptiste Daroussin 		if (bs)
67361d06d6bSBaptiste Daroussin 			putchar('\\');
67461d06d6bSBaptiste Daroussin 		md_char(c);
67561d06d6bSBaptiste Daroussin 		if (breakline &&
67661d06d6bSBaptiste Daroussin 		    (*s == '\0' || *s == ' ' || *s == ASCII_NBRSP)) {
67761d06d6bSBaptiste Daroussin 			printf("  \n");
67861d06d6bSBaptiste Daroussin 			breakline = 0;
67961d06d6bSBaptiste Daroussin 			while (*s == ' ' || *s == ASCII_NBRSP)
68061d06d6bSBaptiste Daroussin 				s++;
68161d06d6bSBaptiste Daroussin 		}
68261d06d6bSBaptiste Daroussin 	}
68361d06d6bSBaptiste Daroussin 	if (*currfont != '\0') {
68461d06d6bSBaptiste Daroussin 		outflags &= ~MD_spc;
68561d06d6bSBaptiste Daroussin 		md_rawword(currfont);
68661d06d6bSBaptiste Daroussin 	} else if (s[-2] == ' ')
68761d06d6bSBaptiste Daroussin 		escflags |= ESC_EOL;
68861d06d6bSBaptiste Daroussin 	else
68961d06d6bSBaptiste Daroussin 		escflags &= ~ESC_EOL;
69061d06d6bSBaptiste Daroussin }
69161d06d6bSBaptiste Daroussin 
69261d06d6bSBaptiste Daroussin /*
69361d06d6bSBaptiste Daroussin  * Print a single HTML named character reference.
69461d06d6bSBaptiste Daroussin  */
69561d06d6bSBaptiste Daroussin static void
md_named(const char * s)69661d06d6bSBaptiste Daroussin md_named(const char *s)
69761d06d6bSBaptiste Daroussin {
69861d06d6bSBaptiste Daroussin 	printf("&%s;", s);
69961d06d6bSBaptiste Daroussin 	escflags &= ~(ESC_FON | ESC_EOL);
70061d06d6bSBaptiste Daroussin 	outcount++;
70161d06d6bSBaptiste Daroussin }
70261d06d6bSBaptiste Daroussin 
70361d06d6bSBaptiste Daroussin /*
70461d06d6bSBaptiste Daroussin  * Print a single raw character and maintain certain escape flags.
70561d06d6bSBaptiste Daroussin  */
70661d06d6bSBaptiste Daroussin static void
md_char(unsigned char c)70761d06d6bSBaptiste Daroussin md_char(unsigned char c)
70861d06d6bSBaptiste Daroussin {
70961d06d6bSBaptiste Daroussin 	if (c != '\0') {
71061d06d6bSBaptiste Daroussin 		putchar(c);
71161d06d6bSBaptiste Daroussin 		if (c == '*')
71261d06d6bSBaptiste Daroussin 			escflags |= ESC_FON;
71361d06d6bSBaptiste Daroussin 		else
71461d06d6bSBaptiste Daroussin 			escflags &= ~ESC_FON;
71561d06d6bSBaptiste Daroussin 		outcount++;
71661d06d6bSBaptiste Daroussin 	}
71761d06d6bSBaptiste Daroussin 	if (c != ']')
71861d06d6bSBaptiste Daroussin 		escflags &= ~ESC_HYP;
71961d06d6bSBaptiste Daroussin 	if (c == ' ' || c == '\t' || c == '>')
72061d06d6bSBaptiste Daroussin 		return;
72161d06d6bSBaptiste Daroussin 	if (isdigit(c) == 0)
72261d06d6bSBaptiste Daroussin 		escflags &= ~ESC_NUM;
72361d06d6bSBaptiste Daroussin 	else if (escflags & ESC_BOL)
72461d06d6bSBaptiste Daroussin 		escflags |= ESC_NUM;
72561d06d6bSBaptiste Daroussin 	escflags &= ~ESC_BOL;
72661d06d6bSBaptiste Daroussin }
72761d06d6bSBaptiste Daroussin 
72861d06d6bSBaptiste Daroussin static int
md_cond_head(struct roff_node * n)72961d06d6bSBaptiste Daroussin md_cond_head(struct roff_node *n)
73061d06d6bSBaptiste Daroussin {
73161d06d6bSBaptiste Daroussin 	return n->type == ROFFT_HEAD;
73261d06d6bSBaptiste Daroussin }
73361d06d6bSBaptiste Daroussin 
73461d06d6bSBaptiste Daroussin static int
md_cond_body(struct roff_node * n)73561d06d6bSBaptiste Daroussin md_cond_body(struct roff_node *n)
73661d06d6bSBaptiste Daroussin {
73761d06d6bSBaptiste Daroussin 	return n->type == ROFFT_BODY;
73861d06d6bSBaptiste Daroussin }
73961d06d6bSBaptiste Daroussin 
74061d06d6bSBaptiste Daroussin static int
md_pre_abort(struct roff_node * n)7417295610fSBaptiste Daroussin md_pre_abort(struct roff_node *n)
7427295610fSBaptiste Daroussin {
7437295610fSBaptiste Daroussin 	abort();
7447295610fSBaptiste Daroussin }
7457295610fSBaptiste Daroussin 
7467295610fSBaptiste Daroussin static int
md_pre_raw(struct roff_node * n)74761d06d6bSBaptiste Daroussin md_pre_raw(struct roff_node *n)
74861d06d6bSBaptiste Daroussin {
74961d06d6bSBaptiste Daroussin 	const char	*prefix;
75061d06d6bSBaptiste Daroussin 
7517295610fSBaptiste Daroussin 	if ((prefix = md_act(n->tok)->prefix) != NULL) {
75261d06d6bSBaptiste Daroussin 		md_rawword(prefix);
75361d06d6bSBaptiste Daroussin 		outflags &= ~MD_spc;
754c1c95addSBrooks Davis 		if (strchr(prefix, '`') != NULL)
75561d06d6bSBaptiste Daroussin 			code_blocks++;
75661d06d6bSBaptiste Daroussin 	}
75761d06d6bSBaptiste Daroussin 	return 1;
75861d06d6bSBaptiste Daroussin }
75961d06d6bSBaptiste Daroussin 
76061d06d6bSBaptiste Daroussin static void
md_post_raw(struct roff_node * n)76161d06d6bSBaptiste Daroussin md_post_raw(struct roff_node *n)
76261d06d6bSBaptiste Daroussin {
76361d06d6bSBaptiste Daroussin 	const char	*suffix;
76461d06d6bSBaptiste Daroussin 
7657295610fSBaptiste Daroussin 	if ((suffix = md_act(n->tok)->suffix) != NULL) {
76661d06d6bSBaptiste Daroussin 		outflags &= ~(MD_spc | MD_nl);
76761d06d6bSBaptiste Daroussin 		md_rawword(suffix);
768c1c95addSBrooks Davis 		if (strchr(suffix, '`') != NULL)
76961d06d6bSBaptiste Daroussin 			code_blocks--;
77061d06d6bSBaptiste Daroussin 	}
77161d06d6bSBaptiste Daroussin }
77261d06d6bSBaptiste Daroussin 
77361d06d6bSBaptiste Daroussin static int
md_pre_word(struct roff_node * n)77461d06d6bSBaptiste Daroussin md_pre_word(struct roff_node *n)
77561d06d6bSBaptiste Daroussin {
77661d06d6bSBaptiste Daroussin 	const char	*prefix;
77761d06d6bSBaptiste Daroussin 
7787295610fSBaptiste Daroussin 	if ((prefix = md_act(n->tok)->prefix) != NULL) {
77961d06d6bSBaptiste Daroussin 		md_word(prefix);
78061d06d6bSBaptiste Daroussin 		outflags &= ~MD_spc;
78161d06d6bSBaptiste Daroussin 	}
78261d06d6bSBaptiste Daroussin 	return 1;
78361d06d6bSBaptiste Daroussin }
78461d06d6bSBaptiste Daroussin 
78561d06d6bSBaptiste Daroussin static void
md_post_word(struct roff_node * n)78661d06d6bSBaptiste Daroussin md_post_word(struct roff_node *n)
78761d06d6bSBaptiste Daroussin {
78861d06d6bSBaptiste Daroussin 	const char	*suffix;
78961d06d6bSBaptiste Daroussin 
7907295610fSBaptiste Daroussin 	if ((suffix = md_act(n->tok)->suffix) != NULL) {
79161d06d6bSBaptiste Daroussin 		outflags &= ~(MD_spc | MD_nl);
79261d06d6bSBaptiste Daroussin 		md_word(suffix);
79361d06d6bSBaptiste Daroussin 	}
79461d06d6bSBaptiste Daroussin }
79561d06d6bSBaptiste Daroussin 
79661d06d6bSBaptiste Daroussin static void
md_post_pc(struct roff_node * n)79761d06d6bSBaptiste Daroussin md_post_pc(struct roff_node *n)
79861d06d6bSBaptiste Daroussin {
7996d38604fSBaptiste Daroussin 	struct roff_node *nn;
8006d38604fSBaptiste Daroussin 
80161d06d6bSBaptiste Daroussin 	md_post_raw(n);
80261d06d6bSBaptiste Daroussin 	if (n->parent->tok != MDOC_Rs)
80361d06d6bSBaptiste Daroussin 		return;
8046d38604fSBaptiste Daroussin 
8056d38604fSBaptiste Daroussin 	if ((nn = roff_node_next(n)) != NULL) {
80661d06d6bSBaptiste Daroussin 		md_word(",");
8076d38604fSBaptiste Daroussin 		if (nn->tok == n->tok &&
8086d38604fSBaptiste Daroussin 		    (nn = roff_node_prev(n)) != NULL &&
8096d38604fSBaptiste Daroussin 		    nn->tok == n->tok)
81061d06d6bSBaptiste Daroussin 			md_word("and");
81161d06d6bSBaptiste Daroussin 	} else {
81261d06d6bSBaptiste Daroussin 		md_word(".");
81361d06d6bSBaptiste Daroussin 		outflags |= MD_nl;
81461d06d6bSBaptiste Daroussin 	}
81561d06d6bSBaptiste Daroussin }
81661d06d6bSBaptiste Daroussin 
81761d06d6bSBaptiste Daroussin static int
md_pre_skip(struct roff_node * n)81861d06d6bSBaptiste Daroussin md_pre_skip(struct roff_node *n)
81961d06d6bSBaptiste Daroussin {
82061d06d6bSBaptiste Daroussin 	return 0;
82161d06d6bSBaptiste Daroussin }
82261d06d6bSBaptiste Daroussin 
82361d06d6bSBaptiste Daroussin static void
md_pre_syn(struct roff_node * n)82461d06d6bSBaptiste Daroussin md_pre_syn(struct roff_node *n)
82561d06d6bSBaptiste Daroussin {
8266d38604fSBaptiste Daroussin 	struct roff_node *np;
8276d38604fSBaptiste Daroussin 
8286d38604fSBaptiste Daroussin 	if ((n->flags & NODE_SYNPRETTY) == 0 ||
8296d38604fSBaptiste Daroussin 	    (np = roff_node_prev(n)) == NULL)
83061d06d6bSBaptiste Daroussin 		return;
83161d06d6bSBaptiste Daroussin 
8326d38604fSBaptiste Daroussin 	if (np->tok == n->tok &&
83361d06d6bSBaptiste Daroussin 	    n->tok != MDOC_Ft &&
83461d06d6bSBaptiste Daroussin 	    n->tok != MDOC_Fo &&
83561d06d6bSBaptiste Daroussin 	    n->tok != MDOC_Fn) {
83661d06d6bSBaptiste Daroussin 		outflags |= MD_br;
83761d06d6bSBaptiste Daroussin 		return;
83861d06d6bSBaptiste Daroussin 	}
83961d06d6bSBaptiste Daroussin 
8406d38604fSBaptiste Daroussin 	switch (np->tok) {
84161d06d6bSBaptiste Daroussin 	case MDOC_Fd:
84261d06d6bSBaptiste Daroussin 	case MDOC_Fn:
84361d06d6bSBaptiste Daroussin 	case MDOC_Fo:
84461d06d6bSBaptiste Daroussin 	case MDOC_In:
84561d06d6bSBaptiste Daroussin 	case MDOC_Vt:
84661d06d6bSBaptiste Daroussin 		outflags |= MD_sp;
84761d06d6bSBaptiste Daroussin 		break;
84861d06d6bSBaptiste Daroussin 	case MDOC_Ft:
84961d06d6bSBaptiste Daroussin 		if (n->tok != MDOC_Fn && n->tok != MDOC_Fo) {
85061d06d6bSBaptiste Daroussin 			outflags |= MD_sp;
85161d06d6bSBaptiste Daroussin 			break;
85261d06d6bSBaptiste Daroussin 		}
85361d06d6bSBaptiste Daroussin 		/* FALLTHROUGH */
85461d06d6bSBaptiste Daroussin 	default:
85561d06d6bSBaptiste Daroussin 		outflags |= MD_br;
85661d06d6bSBaptiste Daroussin 		break;
85761d06d6bSBaptiste Daroussin 	}
85861d06d6bSBaptiste Daroussin }
85961d06d6bSBaptiste Daroussin 
86061d06d6bSBaptiste Daroussin static int
md_pre_An(struct roff_node * n)86161d06d6bSBaptiste Daroussin md_pre_An(struct roff_node *n)
86261d06d6bSBaptiste Daroussin {
86361d06d6bSBaptiste Daroussin 	switch (n->norm->An.auth) {
86461d06d6bSBaptiste Daroussin 	case AUTH_split:
86561d06d6bSBaptiste Daroussin 		outflags &= ~MD_An_nosplit;
86661d06d6bSBaptiste Daroussin 		outflags |= MD_An_split;
86761d06d6bSBaptiste Daroussin 		return 0;
86861d06d6bSBaptiste Daroussin 	case AUTH_nosplit:
86961d06d6bSBaptiste Daroussin 		outflags &= ~MD_An_split;
87061d06d6bSBaptiste Daroussin 		outflags |= MD_An_nosplit;
87161d06d6bSBaptiste Daroussin 		return 0;
87261d06d6bSBaptiste Daroussin 	default:
87361d06d6bSBaptiste Daroussin 		if (outflags & MD_An_split)
87461d06d6bSBaptiste Daroussin 			outflags |= MD_br;
87561d06d6bSBaptiste Daroussin 		else if (n->sec == SEC_AUTHORS &&
87661d06d6bSBaptiste Daroussin 		    ! (outflags & MD_An_nosplit))
87761d06d6bSBaptiste Daroussin 			outflags |= MD_An_split;
87861d06d6bSBaptiste Daroussin 		return 1;
87961d06d6bSBaptiste Daroussin 	}
88061d06d6bSBaptiste Daroussin }
88161d06d6bSBaptiste Daroussin 
88261d06d6bSBaptiste Daroussin static int
md_pre_Ap(struct roff_node * n)88361d06d6bSBaptiste Daroussin md_pre_Ap(struct roff_node *n)
88461d06d6bSBaptiste Daroussin {
88561d06d6bSBaptiste Daroussin 	outflags &= ~MD_spc;
88661d06d6bSBaptiste Daroussin 	md_word("'");
88761d06d6bSBaptiste Daroussin 	outflags &= ~MD_spc;
88861d06d6bSBaptiste Daroussin 	return 0;
88961d06d6bSBaptiste Daroussin }
89061d06d6bSBaptiste Daroussin 
89161d06d6bSBaptiste Daroussin static int
md_pre_Bd(struct roff_node * n)89261d06d6bSBaptiste Daroussin md_pre_Bd(struct roff_node *n)
89361d06d6bSBaptiste Daroussin {
89461d06d6bSBaptiste Daroussin 	switch (n->norm->Bd.type) {
89561d06d6bSBaptiste Daroussin 	case DISP_unfilled:
89661d06d6bSBaptiste Daroussin 	case DISP_literal:
89761d06d6bSBaptiste Daroussin 		return md_pre_Dl(n);
89861d06d6bSBaptiste Daroussin 	default:
89961d06d6bSBaptiste Daroussin 		return md_pre_D1(n);
90061d06d6bSBaptiste Daroussin 	}
90161d06d6bSBaptiste Daroussin }
90261d06d6bSBaptiste Daroussin 
90361d06d6bSBaptiste Daroussin static int
md_pre_Bk(struct roff_node * n)90461d06d6bSBaptiste Daroussin md_pre_Bk(struct roff_node *n)
90561d06d6bSBaptiste Daroussin {
90661d06d6bSBaptiste Daroussin 	switch (n->type) {
90761d06d6bSBaptiste Daroussin 	case ROFFT_BLOCK:
90861d06d6bSBaptiste Daroussin 		return 1;
90961d06d6bSBaptiste Daroussin 	case ROFFT_BODY:
91061d06d6bSBaptiste Daroussin 		outflags |= MD_Bk;
91161d06d6bSBaptiste Daroussin 		return 1;
91261d06d6bSBaptiste Daroussin 	default:
91361d06d6bSBaptiste Daroussin 		return 0;
91461d06d6bSBaptiste Daroussin 	}
91561d06d6bSBaptiste Daroussin }
91661d06d6bSBaptiste Daroussin 
91761d06d6bSBaptiste Daroussin static void
md_post_Bk(struct roff_node * n)91861d06d6bSBaptiste Daroussin md_post_Bk(struct roff_node *n)
91961d06d6bSBaptiste Daroussin {
92061d06d6bSBaptiste Daroussin 	if (n->type == ROFFT_BODY)
92161d06d6bSBaptiste Daroussin 		outflags &= ~MD_Bk;
92261d06d6bSBaptiste Daroussin }
92361d06d6bSBaptiste Daroussin 
92461d06d6bSBaptiste Daroussin static int
md_pre_Bl(struct roff_node * n)92561d06d6bSBaptiste Daroussin md_pre_Bl(struct roff_node *n)
92661d06d6bSBaptiste Daroussin {
92761d06d6bSBaptiste Daroussin 	n->norm->Bl.count = 0;
92861d06d6bSBaptiste Daroussin 	if (n->norm->Bl.type == LIST_column)
92961d06d6bSBaptiste Daroussin 		md_pre_Dl(n);
93061d06d6bSBaptiste Daroussin 	outflags |= MD_sp;
93161d06d6bSBaptiste Daroussin 	return 1;
93261d06d6bSBaptiste Daroussin }
93361d06d6bSBaptiste Daroussin 
93461d06d6bSBaptiste Daroussin static void
md_post_Bl(struct roff_node * n)93561d06d6bSBaptiste Daroussin md_post_Bl(struct roff_node *n)
93661d06d6bSBaptiste Daroussin {
93761d06d6bSBaptiste Daroussin 	n->norm->Bl.count = 0;
93861d06d6bSBaptiste Daroussin 	if (n->norm->Bl.type == LIST_column)
93961d06d6bSBaptiste Daroussin 		md_post_D1(n);
94061d06d6bSBaptiste Daroussin 	outflags |= MD_sp;
94161d06d6bSBaptiste Daroussin }
94261d06d6bSBaptiste Daroussin 
94361d06d6bSBaptiste Daroussin static int
md_pre_D1(struct roff_node * n)94461d06d6bSBaptiste Daroussin md_pre_D1(struct roff_node *n)
94561d06d6bSBaptiste Daroussin {
94661d06d6bSBaptiste Daroussin 	/*
94761d06d6bSBaptiste Daroussin 	 * Markdown blockquote syntax does not work inside code blocks.
94861d06d6bSBaptiste Daroussin 	 * The best we can do is fall back to another nested code block.
94961d06d6bSBaptiste Daroussin 	 */
95061d06d6bSBaptiste Daroussin 	if (code_blocks) {
95161d06d6bSBaptiste Daroussin 		md_stack('\t');
95261d06d6bSBaptiste Daroussin 		code_blocks++;
95361d06d6bSBaptiste Daroussin 	} else {
95461d06d6bSBaptiste Daroussin 		md_stack('>');
95561d06d6bSBaptiste Daroussin 		quote_blocks++;
95661d06d6bSBaptiste Daroussin 	}
95761d06d6bSBaptiste Daroussin 	outflags |= MD_sp;
95861d06d6bSBaptiste Daroussin 	return 1;
95961d06d6bSBaptiste Daroussin }
96061d06d6bSBaptiste Daroussin 
96161d06d6bSBaptiste Daroussin static void
md_post_D1(struct roff_node * n)96261d06d6bSBaptiste Daroussin md_post_D1(struct roff_node *n)
96361d06d6bSBaptiste Daroussin {
96461d06d6bSBaptiste Daroussin 	md_stack((char)-1);
96561d06d6bSBaptiste Daroussin 	if (code_blocks)
96661d06d6bSBaptiste Daroussin 		code_blocks--;
96761d06d6bSBaptiste Daroussin 	else
96861d06d6bSBaptiste Daroussin 		quote_blocks--;
96961d06d6bSBaptiste Daroussin 	outflags |= MD_sp;
97061d06d6bSBaptiste Daroussin }
97161d06d6bSBaptiste Daroussin 
97261d06d6bSBaptiste Daroussin static int
md_pre_Dl(struct roff_node * n)97361d06d6bSBaptiste Daroussin md_pre_Dl(struct roff_node *n)
97461d06d6bSBaptiste Daroussin {
97561d06d6bSBaptiste Daroussin 	/*
97661d06d6bSBaptiste Daroussin 	 * Markdown code block syntax does not work inside blockquotes.
97761d06d6bSBaptiste Daroussin 	 * The best we can do is fall back to another nested blockquote.
97861d06d6bSBaptiste Daroussin 	 */
97961d06d6bSBaptiste Daroussin 	if (quote_blocks) {
98061d06d6bSBaptiste Daroussin 		md_stack('>');
98161d06d6bSBaptiste Daroussin 		quote_blocks++;
98261d06d6bSBaptiste Daroussin 	} else {
98361d06d6bSBaptiste Daroussin 		md_stack('\t');
98461d06d6bSBaptiste Daroussin 		code_blocks++;
98561d06d6bSBaptiste Daroussin 	}
98661d06d6bSBaptiste Daroussin 	outflags |= MD_sp;
98761d06d6bSBaptiste Daroussin 	return 1;
98861d06d6bSBaptiste Daroussin }
98961d06d6bSBaptiste Daroussin 
99061d06d6bSBaptiste Daroussin static int
md_pre_En(struct roff_node * n)99161d06d6bSBaptiste Daroussin md_pre_En(struct roff_node *n)
99261d06d6bSBaptiste Daroussin {
99361d06d6bSBaptiste Daroussin 	if (n->norm->Es == NULL ||
99461d06d6bSBaptiste Daroussin 	    n->norm->Es->child == NULL)
99561d06d6bSBaptiste Daroussin 		return 1;
99661d06d6bSBaptiste Daroussin 
99761d06d6bSBaptiste Daroussin 	md_word(n->norm->Es->child->string);
99861d06d6bSBaptiste Daroussin 	outflags &= ~MD_spc;
99961d06d6bSBaptiste Daroussin 	return 1;
100061d06d6bSBaptiste Daroussin }
100161d06d6bSBaptiste Daroussin 
100261d06d6bSBaptiste Daroussin static void
md_post_En(struct roff_node * n)100361d06d6bSBaptiste Daroussin md_post_En(struct roff_node *n)
100461d06d6bSBaptiste Daroussin {
100561d06d6bSBaptiste Daroussin 	if (n->norm->Es == NULL ||
100661d06d6bSBaptiste Daroussin 	    n->norm->Es->child == NULL ||
100761d06d6bSBaptiste Daroussin 	    n->norm->Es->child->next == NULL)
100861d06d6bSBaptiste Daroussin 		return;
100961d06d6bSBaptiste Daroussin 
101061d06d6bSBaptiste Daroussin 	outflags &= ~MD_spc;
101161d06d6bSBaptiste Daroussin 	md_word(n->norm->Es->child->next->string);
101261d06d6bSBaptiste Daroussin }
101361d06d6bSBaptiste Daroussin 
101461d06d6bSBaptiste Daroussin static int
md_pre_Eo(struct roff_node * n)101561d06d6bSBaptiste Daroussin md_pre_Eo(struct roff_node *n)
101661d06d6bSBaptiste Daroussin {
101761d06d6bSBaptiste Daroussin 	if (n->end == ENDBODY_NOT &&
101861d06d6bSBaptiste Daroussin 	    n->parent->head->child == NULL &&
101961d06d6bSBaptiste Daroussin 	    n->child != NULL &&
102061d06d6bSBaptiste Daroussin 	    n->child->end != ENDBODY_NOT)
102161d06d6bSBaptiste Daroussin 		md_preword();
102261d06d6bSBaptiste Daroussin 	else if (n->end != ENDBODY_NOT ? n->child != NULL :
102361d06d6bSBaptiste Daroussin 	    n->parent->head->child != NULL && (n->child != NULL ||
102461d06d6bSBaptiste Daroussin 	    (n->parent->tail != NULL && n->parent->tail->child != NULL)))
102561d06d6bSBaptiste Daroussin 		outflags &= ~(MD_spc | MD_nl);
102661d06d6bSBaptiste Daroussin 	return 1;
102761d06d6bSBaptiste Daroussin }
102861d06d6bSBaptiste Daroussin 
102961d06d6bSBaptiste Daroussin static void
md_post_Eo(struct roff_node * n)103061d06d6bSBaptiste Daroussin md_post_Eo(struct roff_node *n)
103161d06d6bSBaptiste Daroussin {
103261d06d6bSBaptiste Daroussin 	if (n->end != ENDBODY_NOT) {
103361d06d6bSBaptiste Daroussin 		outflags |= MD_spc;
103461d06d6bSBaptiste Daroussin 		return;
103561d06d6bSBaptiste Daroussin 	}
103661d06d6bSBaptiste Daroussin 
103761d06d6bSBaptiste Daroussin 	if (n->child == NULL && n->parent->head->child == NULL)
103861d06d6bSBaptiste Daroussin 		return;
103961d06d6bSBaptiste Daroussin 
104061d06d6bSBaptiste Daroussin 	if (n->parent->tail != NULL && n->parent->tail->child != NULL)
104161d06d6bSBaptiste Daroussin 		outflags &= ~MD_spc;
104261d06d6bSBaptiste Daroussin         else
104361d06d6bSBaptiste Daroussin 		outflags |= MD_spc;
104461d06d6bSBaptiste Daroussin }
104561d06d6bSBaptiste Daroussin 
104661d06d6bSBaptiste Daroussin static int
md_pre_Fa(struct roff_node * n)104761d06d6bSBaptiste Daroussin md_pre_Fa(struct roff_node *n)
104861d06d6bSBaptiste Daroussin {
104961d06d6bSBaptiste Daroussin 	int	 am_Fa;
105061d06d6bSBaptiste Daroussin 
105161d06d6bSBaptiste Daroussin 	am_Fa = n->tok == MDOC_Fa;
105261d06d6bSBaptiste Daroussin 
105361d06d6bSBaptiste Daroussin 	if (am_Fa)
105461d06d6bSBaptiste Daroussin 		n = n->child;
105561d06d6bSBaptiste Daroussin 
105661d06d6bSBaptiste Daroussin 	while (n != NULL) {
105761d06d6bSBaptiste Daroussin 		md_rawword("*");
105861d06d6bSBaptiste Daroussin 		outflags &= ~MD_spc;
105961d06d6bSBaptiste Daroussin 		md_node(n);
106061d06d6bSBaptiste Daroussin 		outflags &= ~MD_spc;
106161d06d6bSBaptiste Daroussin 		md_rawword("*");
106261d06d6bSBaptiste Daroussin 		if ((n = n->next) != NULL)
106361d06d6bSBaptiste Daroussin 			md_word(",");
106461d06d6bSBaptiste Daroussin 	}
106561d06d6bSBaptiste Daroussin 	return 0;
106661d06d6bSBaptiste Daroussin }
106761d06d6bSBaptiste Daroussin 
106861d06d6bSBaptiste Daroussin static void
md_post_Fa(struct roff_node * n)106961d06d6bSBaptiste Daroussin md_post_Fa(struct roff_node *n)
107061d06d6bSBaptiste Daroussin {
10716d38604fSBaptiste Daroussin 	struct roff_node *nn;
10726d38604fSBaptiste Daroussin 
10736d38604fSBaptiste Daroussin 	if ((nn = roff_node_next(n)) != NULL && nn->tok == MDOC_Fa)
107461d06d6bSBaptiste Daroussin 		md_word(",");
107561d06d6bSBaptiste Daroussin }
107661d06d6bSBaptiste Daroussin 
107761d06d6bSBaptiste Daroussin static int
md_pre_Fd(struct roff_node * n)107861d06d6bSBaptiste Daroussin md_pre_Fd(struct roff_node *n)
107961d06d6bSBaptiste Daroussin {
108061d06d6bSBaptiste Daroussin 	md_pre_syn(n);
108161d06d6bSBaptiste Daroussin 	md_pre_raw(n);
108261d06d6bSBaptiste Daroussin 	return 1;
108361d06d6bSBaptiste Daroussin }
108461d06d6bSBaptiste Daroussin 
108561d06d6bSBaptiste Daroussin static void
md_post_Fd(struct roff_node * n)108661d06d6bSBaptiste Daroussin md_post_Fd(struct roff_node *n)
108761d06d6bSBaptiste Daroussin {
108861d06d6bSBaptiste Daroussin 	md_post_raw(n);
108961d06d6bSBaptiste Daroussin 	outflags |= MD_br;
109061d06d6bSBaptiste Daroussin }
109161d06d6bSBaptiste Daroussin 
109261d06d6bSBaptiste Daroussin static void
md_post_Fl(struct roff_node * n)109361d06d6bSBaptiste Daroussin md_post_Fl(struct roff_node *n)
109461d06d6bSBaptiste Daroussin {
10956d38604fSBaptiste Daroussin 	struct roff_node *nn;
10966d38604fSBaptiste Daroussin 
109761d06d6bSBaptiste Daroussin 	md_post_raw(n);
10986d38604fSBaptiste Daroussin 	if (n->child == NULL && (nn = roff_node_next(n)) != NULL &&
10996d38604fSBaptiste Daroussin 	    nn->type != ROFFT_TEXT && (nn->flags & NODE_LINE) == 0)
110061d06d6bSBaptiste Daroussin 		outflags &= ~MD_spc;
110161d06d6bSBaptiste Daroussin }
110261d06d6bSBaptiste Daroussin 
110361d06d6bSBaptiste Daroussin static int
md_pre_Fn(struct roff_node * n)110461d06d6bSBaptiste Daroussin md_pre_Fn(struct roff_node *n)
110561d06d6bSBaptiste Daroussin {
110661d06d6bSBaptiste Daroussin 	md_pre_syn(n);
110761d06d6bSBaptiste Daroussin 
110861d06d6bSBaptiste Daroussin 	if ((n = n->child) == NULL)
110961d06d6bSBaptiste Daroussin 		return 0;
111061d06d6bSBaptiste Daroussin 
111161d06d6bSBaptiste Daroussin 	md_rawword("**");
111261d06d6bSBaptiste Daroussin 	outflags &= ~MD_spc;
111361d06d6bSBaptiste Daroussin 	md_node(n);
111461d06d6bSBaptiste Daroussin 	outflags &= ~MD_spc;
111561d06d6bSBaptiste Daroussin 	md_rawword("**");
111661d06d6bSBaptiste Daroussin 	outflags &= ~MD_spc;
111761d06d6bSBaptiste Daroussin 	md_word("(");
111861d06d6bSBaptiste Daroussin 
111961d06d6bSBaptiste Daroussin 	if ((n = n->next) != NULL)
112061d06d6bSBaptiste Daroussin 		md_pre_Fa(n);
112161d06d6bSBaptiste Daroussin 	return 0;
112261d06d6bSBaptiste Daroussin }
112361d06d6bSBaptiste Daroussin 
112461d06d6bSBaptiste Daroussin static void
md_post_Fn(struct roff_node * n)112561d06d6bSBaptiste Daroussin md_post_Fn(struct roff_node *n)
112661d06d6bSBaptiste Daroussin {
112761d06d6bSBaptiste Daroussin 	md_word(")");
112861d06d6bSBaptiste Daroussin 	if (n->flags & NODE_SYNPRETTY) {
112961d06d6bSBaptiste Daroussin 		md_word(";");
113061d06d6bSBaptiste Daroussin 		outflags |= MD_sp;
113161d06d6bSBaptiste Daroussin 	}
113261d06d6bSBaptiste Daroussin }
113361d06d6bSBaptiste Daroussin 
113461d06d6bSBaptiste Daroussin static int
md_pre_Fo(struct roff_node * n)113561d06d6bSBaptiste Daroussin md_pre_Fo(struct roff_node *n)
113661d06d6bSBaptiste Daroussin {
113761d06d6bSBaptiste Daroussin 	switch (n->type) {
113861d06d6bSBaptiste Daroussin 	case ROFFT_BLOCK:
113961d06d6bSBaptiste Daroussin 		md_pre_syn(n);
114061d06d6bSBaptiste Daroussin 		break;
114161d06d6bSBaptiste Daroussin 	case ROFFT_HEAD:
114261d06d6bSBaptiste Daroussin 		if (n->child == NULL)
114361d06d6bSBaptiste Daroussin 			return 0;
114461d06d6bSBaptiste Daroussin 		md_pre_raw(n);
114561d06d6bSBaptiste Daroussin 		break;
114661d06d6bSBaptiste Daroussin 	case ROFFT_BODY:
114761d06d6bSBaptiste Daroussin 		outflags &= ~(MD_spc | MD_nl);
114861d06d6bSBaptiste Daroussin 		md_word("(");
114961d06d6bSBaptiste Daroussin 		break;
115061d06d6bSBaptiste Daroussin 	default:
115161d06d6bSBaptiste Daroussin 		break;
115261d06d6bSBaptiste Daroussin 	}
115361d06d6bSBaptiste Daroussin 	return 1;
115461d06d6bSBaptiste Daroussin }
115561d06d6bSBaptiste Daroussin 
115661d06d6bSBaptiste Daroussin static void
md_post_Fo(struct roff_node * n)115761d06d6bSBaptiste Daroussin md_post_Fo(struct roff_node *n)
115861d06d6bSBaptiste Daroussin {
115961d06d6bSBaptiste Daroussin 	switch (n->type) {
116061d06d6bSBaptiste Daroussin 	case ROFFT_HEAD:
116161d06d6bSBaptiste Daroussin 		if (n->child != NULL)
116261d06d6bSBaptiste Daroussin 			md_post_raw(n);
116361d06d6bSBaptiste Daroussin 		break;
116461d06d6bSBaptiste Daroussin 	case ROFFT_BODY:
116561d06d6bSBaptiste Daroussin 		md_post_Fn(n);
116661d06d6bSBaptiste Daroussin 		break;
116761d06d6bSBaptiste Daroussin 	default:
116861d06d6bSBaptiste Daroussin 		break;
116961d06d6bSBaptiste Daroussin 	}
117061d06d6bSBaptiste Daroussin }
117161d06d6bSBaptiste Daroussin 
117261d06d6bSBaptiste Daroussin static int
md_pre_In(struct roff_node * n)117361d06d6bSBaptiste Daroussin md_pre_In(struct roff_node *n)
117461d06d6bSBaptiste Daroussin {
117561d06d6bSBaptiste Daroussin 	if (n->flags & NODE_SYNPRETTY) {
117661d06d6bSBaptiste Daroussin 		md_pre_syn(n);
117761d06d6bSBaptiste Daroussin 		md_rawword("**");
117861d06d6bSBaptiste Daroussin 		outflags &= ~MD_spc;
117961d06d6bSBaptiste Daroussin 		md_word("#include <");
118061d06d6bSBaptiste Daroussin 	} else {
118161d06d6bSBaptiste Daroussin 		md_word("<");
118261d06d6bSBaptiste Daroussin 		outflags &= ~MD_spc;
118361d06d6bSBaptiste Daroussin 		md_rawword("*");
118461d06d6bSBaptiste Daroussin 	}
118561d06d6bSBaptiste Daroussin 	outflags &= ~MD_spc;
118661d06d6bSBaptiste Daroussin 	return 1;
118761d06d6bSBaptiste Daroussin }
118861d06d6bSBaptiste Daroussin 
118961d06d6bSBaptiste Daroussin static void
md_post_In(struct roff_node * n)119061d06d6bSBaptiste Daroussin md_post_In(struct roff_node *n)
119161d06d6bSBaptiste Daroussin {
119261d06d6bSBaptiste Daroussin 	if (n->flags & NODE_SYNPRETTY) {
119361d06d6bSBaptiste Daroussin 		outflags &= ~MD_spc;
119461d06d6bSBaptiste Daroussin 		md_rawword(">**");
119561d06d6bSBaptiste Daroussin 		outflags |= MD_nl;
119661d06d6bSBaptiste Daroussin 	} else {
119761d06d6bSBaptiste Daroussin 		outflags &= ~MD_spc;
119861d06d6bSBaptiste Daroussin 		md_rawword("*>");
119961d06d6bSBaptiste Daroussin 	}
120061d06d6bSBaptiste Daroussin }
120161d06d6bSBaptiste Daroussin 
120261d06d6bSBaptiste Daroussin static int
md_pre_It(struct roff_node * n)120361d06d6bSBaptiste Daroussin md_pre_It(struct roff_node *n)
120461d06d6bSBaptiste Daroussin {
120561d06d6bSBaptiste Daroussin 	struct roff_node	*bln;
120661d06d6bSBaptiste Daroussin 
120761d06d6bSBaptiste Daroussin 	switch (n->type) {
120861d06d6bSBaptiste Daroussin 	case ROFFT_BLOCK:
120961d06d6bSBaptiste Daroussin 		return 1;
121061d06d6bSBaptiste Daroussin 
121161d06d6bSBaptiste Daroussin 	case ROFFT_HEAD:
121261d06d6bSBaptiste Daroussin 		bln = n->parent->parent;
121361d06d6bSBaptiste Daroussin 		if (bln->norm->Bl.comp == 0 &&
121461d06d6bSBaptiste Daroussin 		    bln->norm->Bl.type != LIST_column)
121561d06d6bSBaptiste Daroussin 			outflags |= MD_sp;
121661d06d6bSBaptiste Daroussin 		outflags |= MD_nl;
121761d06d6bSBaptiste Daroussin 
121861d06d6bSBaptiste Daroussin 		switch (bln->norm->Bl.type) {
121961d06d6bSBaptiste Daroussin 		case LIST_item:
122061d06d6bSBaptiste Daroussin 			outflags |= MD_br;
122161d06d6bSBaptiste Daroussin 			return 0;
122261d06d6bSBaptiste Daroussin 		case LIST_inset:
122361d06d6bSBaptiste Daroussin 		case LIST_diag:
122461d06d6bSBaptiste Daroussin 		case LIST_ohang:
122561d06d6bSBaptiste Daroussin 			outflags |= MD_br;
122661d06d6bSBaptiste Daroussin 			return 1;
122761d06d6bSBaptiste Daroussin 		case LIST_tag:
122861d06d6bSBaptiste Daroussin 		case LIST_hang:
122961d06d6bSBaptiste Daroussin 			outflags |= MD_sp;
123061d06d6bSBaptiste Daroussin 			return 1;
123161d06d6bSBaptiste Daroussin 		case LIST_bullet:
123261d06d6bSBaptiste Daroussin 			md_rawword("*\t");
123361d06d6bSBaptiste Daroussin 			break;
123461d06d6bSBaptiste Daroussin 		case LIST_dash:
123561d06d6bSBaptiste Daroussin 		case LIST_hyphen:
123661d06d6bSBaptiste Daroussin 			md_rawword("-\t");
123761d06d6bSBaptiste Daroussin 			break;
123861d06d6bSBaptiste Daroussin 		case LIST_enum:
123961d06d6bSBaptiste Daroussin 			md_preword();
124061d06d6bSBaptiste Daroussin 			if (bln->norm->Bl.count < 99)
124161d06d6bSBaptiste Daroussin 				bln->norm->Bl.count++;
124261d06d6bSBaptiste Daroussin 			printf("%d.\t", bln->norm->Bl.count);
124361d06d6bSBaptiste Daroussin 			escflags &= ~ESC_FON;
124461d06d6bSBaptiste Daroussin 			break;
124561d06d6bSBaptiste Daroussin 		case LIST_column:
124661d06d6bSBaptiste Daroussin 			outflags |= MD_br;
124761d06d6bSBaptiste Daroussin 			return 0;
124861d06d6bSBaptiste Daroussin 		default:
124961d06d6bSBaptiste Daroussin 			return 0;
125061d06d6bSBaptiste Daroussin 		}
125161d06d6bSBaptiste Daroussin 		outflags &= ~MD_spc;
125261d06d6bSBaptiste Daroussin 		outflags |= MD_nonl;
125361d06d6bSBaptiste Daroussin 		outcount = 0;
125461d06d6bSBaptiste Daroussin 		md_stack('\t');
125561d06d6bSBaptiste Daroussin 		if (code_blocks || quote_blocks)
125661d06d6bSBaptiste Daroussin 			list_blocks++;
125761d06d6bSBaptiste Daroussin 		return 0;
125861d06d6bSBaptiste Daroussin 
125961d06d6bSBaptiste Daroussin 	case ROFFT_BODY:
126061d06d6bSBaptiste Daroussin 		bln = n->parent->parent;
126161d06d6bSBaptiste Daroussin 		switch (bln->norm->Bl.type) {
126261d06d6bSBaptiste Daroussin 		case LIST_ohang:
126361d06d6bSBaptiste Daroussin 			outflags |= MD_br;
126461d06d6bSBaptiste Daroussin 			break;
126561d06d6bSBaptiste Daroussin 		case LIST_tag:
126661d06d6bSBaptiste Daroussin 		case LIST_hang:
126761d06d6bSBaptiste Daroussin 			md_pre_D1(n);
126861d06d6bSBaptiste Daroussin 			break;
126961d06d6bSBaptiste Daroussin 		default:
127061d06d6bSBaptiste Daroussin 			break;
127161d06d6bSBaptiste Daroussin 		}
127261d06d6bSBaptiste Daroussin 		return 1;
127361d06d6bSBaptiste Daroussin 
127461d06d6bSBaptiste Daroussin 	default:
127561d06d6bSBaptiste Daroussin 		return 0;
127661d06d6bSBaptiste Daroussin 	}
127761d06d6bSBaptiste Daroussin }
127861d06d6bSBaptiste Daroussin 
127961d06d6bSBaptiste Daroussin static void
md_post_It(struct roff_node * n)128061d06d6bSBaptiste Daroussin md_post_It(struct roff_node *n)
128161d06d6bSBaptiste Daroussin {
128261d06d6bSBaptiste Daroussin 	struct roff_node	*bln;
128361d06d6bSBaptiste Daroussin 	int			 i, nc;
128461d06d6bSBaptiste Daroussin 
128561d06d6bSBaptiste Daroussin 	if (n->type != ROFFT_BODY)
128661d06d6bSBaptiste Daroussin 		return;
128761d06d6bSBaptiste Daroussin 
128861d06d6bSBaptiste Daroussin 	bln = n->parent->parent;
128961d06d6bSBaptiste Daroussin 	switch (bln->norm->Bl.type) {
129061d06d6bSBaptiste Daroussin 	case LIST_bullet:
129161d06d6bSBaptiste Daroussin 	case LIST_dash:
129261d06d6bSBaptiste Daroussin 	case LIST_hyphen:
129361d06d6bSBaptiste Daroussin 	case LIST_enum:
129461d06d6bSBaptiste Daroussin 		md_stack((char)-1);
129561d06d6bSBaptiste Daroussin 		if (code_blocks || quote_blocks)
129661d06d6bSBaptiste Daroussin 			list_blocks--;
129761d06d6bSBaptiste Daroussin 		break;
129861d06d6bSBaptiste Daroussin 	case LIST_tag:
129961d06d6bSBaptiste Daroussin 	case LIST_hang:
130061d06d6bSBaptiste Daroussin 		md_post_D1(n);
130161d06d6bSBaptiste Daroussin 		break;
130261d06d6bSBaptiste Daroussin 
130361d06d6bSBaptiste Daroussin 	case LIST_column:
130461d06d6bSBaptiste Daroussin 		if (n->next == NULL)
130561d06d6bSBaptiste Daroussin 			break;
130661d06d6bSBaptiste Daroussin 
130761d06d6bSBaptiste Daroussin 		/* Calculate the array index of the current column. */
130861d06d6bSBaptiste Daroussin 
130961d06d6bSBaptiste Daroussin 		i = 0;
131061d06d6bSBaptiste Daroussin 		while ((n = n->prev) != NULL && n->type != ROFFT_HEAD)
131161d06d6bSBaptiste Daroussin 			i++;
131261d06d6bSBaptiste Daroussin 
131361d06d6bSBaptiste Daroussin 		/*
131461d06d6bSBaptiste Daroussin 		 * If a width was specified for this column,
131561d06d6bSBaptiste Daroussin 		 * subtract what printed, and
131661d06d6bSBaptiste Daroussin 		 * add the same spacing as in mdoc_term.c.
131761d06d6bSBaptiste Daroussin 		 */
131861d06d6bSBaptiste Daroussin 
131961d06d6bSBaptiste Daroussin 		nc = bln->norm->Bl.ncols;
132061d06d6bSBaptiste Daroussin 		i = i < nc ? strlen(bln->norm->Bl.cols[i]) - outcount +
132161d06d6bSBaptiste Daroussin 		    (nc < 5 ? 4 : nc == 5 ? 3 : 1) : 1;
132261d06d6bSBaptiste Daroussin 		if (i < 1)
132361d06d6bSBaptiste Daroussin 			i = 1;
132461d06d6bSBaptiste Daroussin 		while (i-- > 0)
132561d06d6bSBaptiste Daroussin 			putchar(' ');
132661d06d6bSBaptiste Daroussin 
132761d06d6bSBaptiste Daroussin 		outflags &= ~MD_spc;
132861d06d6bSBaptiste Daroussin 		escflags &= ~ESC_FON;
132961d06d6bSBaptiste Daroussin 		outcount = 0;
133061d06d6bSBaptiste Daroussin 		break;
133161d06d6bSBaptiste Daroussin 
133261d06d6bSBaptiste Daroussin 	default:
133361d06d6bSBaptiste Daroussin 		break;
133461d06d6bSBaptiste Daroussin 	}
133561d06d6bSBaptiste Daroussin }
133661d06d6bSBaptiste Daroussin 
133761d06d6bSBaptiste Daroussin static void
md_post_Lb(struct roff_node * n)133861d06d6bSBaptiste Daroussin md_post_Lb(struct roff_node *n)
133961d06d6bSBaptiste Daroussin {
134061d06d6bSBaptiste Daroussin 	if (n->sec == SEC_LIBRARY)
134161d06d6bSBaptiste Daroussin 		outflags |= MD_br;
134261d06d6bSBaptiste Daroussin }
134361d06d6bSBaptiste Daroussin 
134461d06d6bSBaptiste Daroussin static void
md_uri(const char * s)134561d06d6bSBaptiste Daroussin md_uri(const char *s)
134661d06d6bSBaptiste Daroussin {
134761d06d6bSBaptiste Daroussin 	while (*s != '\0') {
134861d06d6bSBaptiste Daroussin 		if (strchr("%()<>", *s) != NULL) {
134961d06d6bSBaptiste Daroussin 			printf("%%%2.2hhX", *s);
135061d06d6bSBaptiste Daroussin 			outcount += 3;
135161d06d6bSBaptiste Daroussin 		} else {
135261d06d6bSBaptiste Daroussin 			putchar(*s);
135361d06d6bSBaptiste Daroussin 			outcount++;
135461d06d6bSBaptiste Daroussin 		}
135561d06d6bSBaptiste Daroussin 		s++;
135661d06d6bSBaptiste Daroussin 	}
135761d06d6bSBaptiste Daroussin }
135861d06d6bSBaptiste Daroussin 
135961d06d6bSBaptiste Daroussin static int
md_pre_Lk(struct roff_node * n)136061d06d6bSBaptiste Daroussin md_pre_Lk(struct roff_node *n)
136161d06d6bSBaptiste Daroussin {
136261d06d6bSBaptiste Daroussin 	const struct roff_node *link, *descr, *punct;
136361d06d6bSBaptiste Daroussin 
136461d06d6bSBaptiste Daroussin 	if ((link = n->child) == NULL)
136561d06d6bSBaptiste Daroussin 		return 0;
136661d06d6bSBaptiste Daroussin 
136761d06d6bSBaptiste Daroussin 	/* Find beginning of trailing punctuation. */
136861d06d6bSBaptiste Daroussin 	punct = n->last;
136961d06d6bSBaptiste Daroussin 	while (punct != link && punct->flags & NODE_DELIMC)
137061d06d6bSBaptiste Daroussin 		punct = punct->prev;
137161d06d6bSBaptiste Daroussin 	punct = punct->next;
137261d06d6bSBaptiste Daroussin 
137361d06d6bSBaptiste Daroussin 	/* Link text. */
137461d06d6bSBaptiste Daroussin 	descr = link->next;
137561d06d6bSBaptiste Daroussin 	if (descr == punct)
137661d06d6bSBaptiste Daroussin 		descr = link;  /* no text */
137761d06d6bSBaptiste Daroussin 	md_rawword("[");
137861d06d6bSBaptiste Daroussin 	outflags &= ~MD_spc;
137961d06d6bSBaptiste Daroussin 	do {
138061d06d6bSBaptiste Daroussin 		md_word(descr->string);
138161d06d6bSBaptiste Daroussin 		descr = descr->next;
138261d06d6bSBaptiste Daroussin 	} while (descr != punct);
138361d06d6bSBaptiste Daroussin 	outflags &= ~MD_spc;
138461d06d6bSBaptiste Daroussin 
138561d06d6bSBaptiste Daroussin 	/* Link target. */
138661d06d6bSBaptiste Daroussin 	md_rawword("](");
138761d06d6bSBaptiste Daroussin 	md_uri(link->string);
138861d06d6bSBaptiste Daroussin 	outflags &= ~MD_spc;
138961d06d6bSBaptiste Daroussin 	md_rawword(")");
139061d06d6bSBaptiste Daroussin 
139161d06d6bSBaptiste Daroussin 	/* Trailing punctuation. */
139261d06d6bSBaptiste Daroussin 	while (punct != NULL) {
139361d06d6bSBaptiste Daroussin 		md_word(punct->string);
139461d06d6bSBaptiste Daroussin 		punct = punct->next;
139561d06d6bSBaptiste Daroussin 	}
139661d06d6bSBaptiste Daroussin 	return 0;
139761d06d6bSBaptiste Daroussin }
139861d06d6bSBaptiste Daroussin 
139961d06d6bSBaptiste Daroussin static int
md_pre_Mt(struct roff_node * n)140061d06d6bSBaptiste Daroussin md_pre_Mt(struct roff_node *n)
140161d06d6bSBaptiste Daroussin {
140261d06d6bSBaptiste Daroussin 	const struct roff_node *nch;
140361d06d6bSBaptiste Daroussin 
140461d06d6bSBaptiste Daroussin 	md_rawword("[");
140561d06d6bSBaptiste Daroussin 	outflags &= ~MD_spc;
140661d06d6bSBaptiste Daroussin 	for (nch = n->child; nch != NULL; nch = nch->next)
140761d06d6bSBaptiste Daroussin 		md_word(nch->string);
140861d06d6bSBaptiste Daroussin 	outflags &= ~MD_spc;
140961d06d6bSBaptiste Daroussin 	md_rawword("](mailto:");
141061d06d6bSBaptiste Daroussin 	for (nch = n->child; nch != NULL; nch = nch->next) {
141161d06d6bSBaptiste Daroussin 		md_uri(nch->string);
141261d06d6bSBaptiste Daroussin 		if (nch->next != NULL) {
141361d06d6bSBaptiste Daroussin 			putchar(' ');
141461d06d6bSBaptiste Daroussin 			outcount++;
141561d06d6bSBaptiste Daroussin 		}
141661d06d6bSBaptiste Daroussin 	}
141761d06d6bSBaptiste Daroussin 	outflags &= ~MD_spc;
141861d06d6bSBaptiste Daroussin 	md_rawword(")");
141961d06d6bSBaptiste Daroussin 	return 0;
142061d06d6bSBaptiste Daroussin }
142161d06d6bSBaptiste Daroussin 
142261d06d6bSBaptiste Daroussin static int
md_pre_Nd(struct roff_node * n)142361d06d6bSBaptiste Daroussin md_pre_Nd(struct roff_node *n)
142461d06d6bSBaptiste Daroussin {
142561d06d6bSBaptiste Daroussin 	outflags &= ~MD_nl;
142661d06d6bSBaptiste Daroussin 	outflags |= MD_spc;
142761d06d6bSBaptiste Daroussin 	md_word("-");
142861d06d6bSBaptiste Daroussin 	return 1;
142961d06d6bSBaptiste Daroussin }
143061d06d6bSBaptiste Daroussin 
143161d06d6bSBaptiste Daroussin static int
md_pre_Nm(struct roff_node * n)143261d06d6bSBaptiste Daroussin md_pre_Nm(struct roff_node *n)
143361d06d6bSBaptiste Daroussin {
143461d06d6bSBaptiste Daroussin 	switch (n->type) {
143561d06d6bSBaptiste Daroussin 	case ROFFT_BLOCK:
143661d06d6bSBaptiste Daroussin 		outflags |= MD_Bk;
143761d06d6bSBaptiste Daroussin 		md_pre_syn(n);
143861d06d6bSBaptiste Daroussin 		break;
143961d06d6bSBaptiste Daroussin 	case ROFFT_HEAD:
144061d06d6bSBaptiste Daroussin 	case ROFFT_ELEM:
144161d06d6bSBaptiste Daroussin 		md_pre_raw(n);
144261d06d6bSBaptiste Daroussin 		break;
144361d06d6bSBaptiste Daroussin 	default:
144461d06d6bSBaptiste Daroussin 		break;
144561d06d6bSBaptiste Daroussin 	}
144661d06d6bSBaptiste Daroussin 	return 1;
144761d06d6bSBaptiste Daroussin }
144861d06d6bSBaptiste Daroussin 
144961d06d6bSBaptiste Daroussin static void
md_post_Nm(struct roff_node * n)145061d06d6bSBaptiste Daroussin md_post_Nm(struct roff_node *n)
145161d06d6bSBaptiste Daroussin {
145261d06d6bSBaptiste Daroussin 	switch (n->type) {
145361d06d6bSBaptiste Daroussin 	case ROFFT_BLOCK:
145461d06d6bSBaptiste Daroussin 		outflags &= ~MD_Bk;
145561d06d6bSBaptiste Daroussin 		break;
145661d06d6bSBaptiste Daroussin 	case ROFFT_HEAD:
145761d06d6bSBaptiste Daroussin 	case ROFFT_ELEM:
145861d06d6bSBaptiste Daroussin 		md_post_raw(n);
145961d06d6bSBaptiste Daroussin 		break;
146061d06d6bSBaptiste Daroussin 	default:
146161d06d6bSBaptiste Daroussin 		break;
146261d06d6bSBaptiste Daroussin 	}
146361d06d6bSBaptiste Daroussin }
146461d06d6bSBaptiste Daroussin 
146561d06d6bSBaptiste Daroussin static int
md_pre_No(struct roff_node * n)146661d06d6bSBaptiste Daroussin md_pre_No(struct roff_node *n)
146761d06d6bSBaptiste Daroussin {
146861d06d6bSBaptiste Daroussin 	outflags |= MD_spc_force;
146961d06d6bSBaptiste Daroussin 	return 1;
147061d06d6bSBaptiste Daroussin }
147161d06d6bSBaptiste Daroussin 
147261d06d6bSBaptiste Daroussin static int
md_pre_Ns(struct roff_node * n)147361d06d6bSBaptiste Daroussin md_pre_Ns(struct roff_node *n)
147461d06d6bSBaptiste Daroussin {
147561d06d6bSBaptiste Daroussin 	outflags &= ~MD_spc;
147661d06d6bSBaptiste Daroussin 	return 0;
147761d06d6bSBaptiste Daroussin }
147861d06d6bSBaptiste Daroussin 
147961d06d6bSBaptiste Daroussin static void
md_post_Pf(struct roff_node * n)148061d06d6bSBaptiste Daroussin md_post_Pf(struct roff_node *n)
148161d06d6bSBaptiste Daroussin {
148261d06d6bSBaptiste Daroussin 	if (n->next != NULL && (n->next->flags & NODE_LINE) == 0)
148361d06d6bSBaptiste Daroussin 		outflags &= ~MD_spc;
148461d06d6bSBaptiste Daroussin }
148561d06d6bSBaptiste Daroussin 
148661d06d6bSBaptiste Daroussin static int
md_pre_Pp(struct roff_node * n)148761d06d6bSBaptiste Daroussin md_pre_Pp(struct roff_node *n)
148861d06d6bSBaptiste Daroussin {
148961d06d6bSBaptiste Daroussin 	outflags |= MD_sp;
149061d06d6bSBaptiste Daroussin 	return 0;
149161d06d6bSBaptiste Daroussin }
149261d06d6bSBaptiste Daroussin 
149361d06d6bSBaptiste Daroussin static int
md_pre_Rs(struct roff_node * n)149461d06d6bSBaptiste Daroussin md_pre_Rs(struct roff_node *n)
149561d06d6bSBaptiste Daroussin {
149661d06d6bSBaptiste Daroussin 	if (n->sec == SEC_SEE_ALSO)
149761d06d6bSBaptiste Daroussin 		outflags |= MD_sp;
149861d06d6bSBaptiste Daroussin 	return 1;
149961d06d6bSBaptiste Daroussin }
150061d06d6bSBaptiste Daroussin 
150161d06d6bSBaptiste Daroussin static int
md_pre_Sh(struct roff_node * n)150261d06d6bSBaptiste Daroussin md_pre_Sh(struct roff_node *n)
150361d06d6bSBaptiste Daroussin {
150461d06d6bSBaptiste Daroussin 	switch (n->type) {
150561d06d6bSBaptiste Daroussin 	case ROFFT_BLOCK:
150661d06d6bSBaptiste Daroussin 		if (n->sec == SEC_AUTHORS)
150761d06d6bSBaptiste Daroussin 			outflags &= ~(MD_An_split | MD_An_nosplit);
150861d06d6bSBaptiste Daroussin 		break;
150961d06d6bSBaptiste Daroussin 	case ROFFT_HEAD:
151061d06d6bSBaptiste Daroussin 		outflags |= MD_sp;
151161d06d6bSBaptiste Daroussin 		md_rawword(n->tok == MDOC_Sh ? "#" : "##");
151261d06d6bSBaptiste Daroussin 		break;
151361d06d6bSBaptiste Daroussin 	case ROFFT_BODY:
151461d06d6bSBaptiste Daroussin 		outflags |= MD_sp;
151561d06d6bSBaptiste Daroussin 		break;
151661d06d6bSBaptiste Daroussin 	default:
151761d06d6bSBaptiste Daroussin 		break;
151861d06d6bSBaptiste Daroussin 	}
151961d06d6bSBaptiste Daroussin 	return 1;
152061d06d6bSBaptiste Daroussin }
152161d06d6bSBaptiste Daroussin 
152261d06d6bSBaptiste Daroussin static int
md_pre_Sm(struct roff_node * n)152361d06d6bSBaptiste Daroussin md_pre_Sm(struct roff_node *n)
152461d06d6bSBaptiste Daroussin {
152561d06d6bSBaptiste Daroussin 	if (n->child == NULL)
152661d06d6bSBaptiste Daroussin 		outflags ^= MD_Sm;
152761d06d6bSBaptiste Daroussin 	else if (strcmp("on", n->child->string) == 0)
152861d06d6bSBaptiste Daroussin 		outflags |= MD_Sm;
152961d06d6bSBaptiste Daroussin 	else
153061d06d6bSBaptiste Daroussin 		outflags &= ~MD_Sm;
153161d06d6bSBaptiste Daroussin 
153261d06d6bSBaptiste Daroussin 	if (outflags & MD_Sm)
153361d06d6bSBaptiste Daroussin 		outflags |= MD_spc;
153461d06d6bSBaptiste Daroussin 
153561d06d6bSBaptiste Daroussin 	return 0;
153661d06d6bSBaptiste Daroussin }
153761d06d6bSBaptiste Daroussin 
153861d06d6bSBaptiste Daroussin static int
md_pre_Vt(struct roff_node * n)153961d06d6bSBaptiste Daroussin md_pre_Vt(struct roff_node *n)
154061d06d6bSBaptiste Daroussin {
154161d06d6bSBaptiste Daroussin 	switch (n->type) {
154261d06d6bSBaptiste Daroussin 	case ROFFT_BLOCK:
154361d06d6bSBaptiste Daroussin 		md_pre_syn(n);
154461d06d6bSBaptiste Daroussin 		return 1;
154561d06d6bSBaptiste Daroussin 	case ROFFT_BODY:
154661d06d6bSBaptiste Daroussin 	case ROFFT_ELEM:
154761d06d6bSBaptiste Daroussin 		md_pre_raw(n);
154861d06d6bSBaptiste Daroussin 		return 1;
154961d06d6bSBaptiste Daroussin 	default:
155061d06d6bSBaptiste Daroussin 		return 0;
155161d06d6bSBaptiste Daroussin 	}
155261d06d6bSBaptiste Daroussin }
155361d06d6bSBaptiste Daroussin 
155461d06d6bSBaptiste Daroussin static void
md_post_Vt(struct roff_node * n)155561d06d6bSBaptiste Daroussin md_post_Vt(struct roff_node *n)
155661d06d6bSBaptiste Daroussin {
155761d06d6bSBaptiste Daroussin 	switch (n->type) {
155861d06d6bSBaptiste Daroussin 	case ROFFT_BODY:
155961d06d6bSBaptiste Daroussin 	case ROFFT_ELEM:
156061d06d6bSBaptiste Daroussin 		md_post_raw(n);
156161d06d6bSBaptiste Daroussin 		break;
156261d06d6bSBaptiste Daroussin 	default:
156361d06d6bSBaptiste Daroussin 		break;
156461d06d6bSBaptiste Daroussin 	}
156561d06d6bSBaptiste Daroussin }
156661d06d6bSBaptiste Daroussin 
156761d06d6bSBaptiste Daroussin static int
md_pre_Xr(struct roff_node * n)156861d06d6bSBaptiste Daroussin md_pre_Xr(struct roff_node *n)
156961d06d6bSBaptiste Daroussin {
157061d06d6bSBaptiste Daroussin 	n = n->child;
157161d06d6bSBaptiste Daroussin 	if (n == NULL)
157261d06d6bSBaptiste Daroussin 		return 0;
157361d06d6bSBaptiste Daroussin 	md_node(n);
157461d06d6bSBaptiste Daroussin 	n = n->next;
157561d06d6bSBaptiste Daroussin 	if (n == NULL)
157661d06d6bSBaptiste Daroussin 		return 0;
157761d06d6bSBaptiste Daroussin 	outflags &= ~MD_spc;
157861d06d6bSBaptiste Daroussin 	md_word("(");
157961d06d6bSBaptiste Daroussin 	md_node(n);
158061d06d6bSBaptiste Daroussin 	md_word(")");
158161d06d6bSBaptiste Daroussin 	return 0;
158261d06d6bSBaptiste Daroussin }
158361d06d6bSBaptiste Daroussin 
158461d06d6bSBaptiste Daroussin static int
md_pre__R(struct roff_node * n)1585*80c12959SAlexander Ziaee md_pre__R(struct roff_node *n)
1586*80c12959SAlexander Ziaee {
1587*80c12959SAlexander Ziaee 	const unsigned char	*cp;
1588*80c12959SAlexander Ziaee 	const char		*arg;
1589*80c12959SAlexander Ziaee 
1590*80c12959SAlexander Ziaee 	arg = n->child->string;
1591*80c12959SAlexander Ziaee 
1592*80c12959SAlexander Ziaee 	if (strncmp(arg, "RFC ", 4) != 0)
1593*80c12959SAlexander Ziaee 		return 1;
1594*80c12959SAlexander Ziaee 	cp = arg += 4;
1595*80c12959SAlexander Ziaee 	while (isdigit(*cp))
1596*80c12959SAlexander Ziaee 		cp++;
1597*80c12959SAlexander Ziaee 	if (*cp != '\0')
1598*80c12959SAlexander Ziaee 		return 1;
1599*80c12959SAlexander Ziaee 
1600*80c12959SAlexander Ziaee 	md_rawword("[RFC ");
1601*80c12959SAlexander Ziaee 	outflags &= ~MD_spc;
1602*80c12959SAlexander Ziaee 	md_rawword(arg);
1603*80c12959SAlexander Ziaee 	outflags &= ~MD_spc;
1604*80c12959SAlexander Ziaee 	md_rawword("](http://www.rfc-editor.org/rfc/rfc");
1605*80c12959SAlexander Ziaee 	outflags &= ~MD_spc;
1606*80c12959SAlexander Ziaee 	md_rawword(arg);
1607*80c12959SAlexander Ziaee 	outflags &= ~MD_spc;
1608*80c12959SAlexander Ziaee 	md_rawword(".html)");
1609*80c12959SAlexander Ziaee 	return 0;
1610*80c12959SAlexander Ziaee }
1611*80c12959SAlexander Ziaee 
1612*80c12959SAlexander Ziaee static int
md_pre__T(struct roff_node * n)161361d06d6bSBaptiste Daroussin md_pre__T(struct roff_node *n)
161461d06d6bSBaptiste Daroussin {
161561d06d6bSBaptiste Daroussin 	if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T)
161661d06d6bSBaptiste Daroussin 		md_word("\"");
161761d06d6bSBaptiste Daroussin 	else
161861d06d6bSBaptiste Daroussin 		md_rawword("*");
161961d06d6bSBaptiste Daroussin 	outflags &= ~MD_spc;
162061d06d6bSBaptiste Daroussin 	return 1;
162161d06d6bSBaptiste Daroussin }
162261d06d6bSBaptiste Daroussin 
162361d06d6bSBaptiste Daroussin static void
md_post__T(struct roff_node * n)162461d06d6bSBaptiste Daroussin md_post__T(struct roff_node *n)
162561d06d6bSBaptiste Daroussin {
162661d06d6bSBaptiste Daroussin 	outflags &= ~MD_spc;
162761d06d6bSBaptiste Daroussin 	if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T)
162861d06d6bSBaptiste Daroussin 		md_word("\"");
162961d06d6bSBaptiste Daroussin 	else
163061d06d6bSBaptiste Daroussin 		md_rawword("*");
163161d06d6bSBaptiste Daroussin 	md_post_pc(n);
163261d06d6bSBaptiste Daroussin }
163361d06d6bSBaptiste Daroussin 
163461d06d6bSBaptiste Daroussin static int
md_pre_br(struct roff_node * n)163561d06d6bSBaptiste Daroussin md_pre_br(struct roff_node *n)
163661d06d6bSBaptiste Daroussin {
163761d06d6bSBaptiste Daroussin 	outflags |= MD_br;
163861d06d6bSBaptiste Daroussin 	return 0;
163961d06d6bSBaptiste Daroussin }
1640