1139749Simp/* $Id: mdoc_markdown.c,v 1.37 2021/08/10 12:55:03 schwarze Exp $ */
2197404Sjoel/*
3197404Sjoel * Copyright (c) 2017, 2018, 2020 Ingo Schwarze <schwarze@openbsd.org>
4197404Sjoel *
550724Scg * Permission to use, copy, modify, and distribute this software for any
6197404Sjoel * purpose with or without fee is hereby granted, provided that the above
7197404Sjoel * copyright notice and this permission notice appear in all copies.
8197404Sjoel *
9197404Sjoel * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
10197404Sjoel * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11197404Sjoel * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
12197404Sjoel * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13197404Sjoel * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14197404Sjoel * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15197404Sjoel * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16197404Sjoel *
17197404Sjoel * Markdown formatter for mdoc(7) used by mandoc(1).
18197404Sjoel */
19197404Sjoel#include "config.h"
20197404Sjoel
21197404Sjoel#include <sys/types.h>
22197404Sjoel
23197404Sjoel#include <assert.h>
24197404Sjoel#include <ctype.h>
25197404Sjoel#include <stdio.h>
26197404Sjoel#include <stdlib.h>
27197404Sjoel#include <string.h>
28197404Sjoel
29119853Scg#include "mandoc_aux.h"
30197404Sjoel#include "mandoc.h"
3150724Scg#include "roff.h"
3250724Scg#include "mdoc.h"
3350724Scg#include "main.h"
3450724Scg
3550724Scgstruct	md_act {
3650724Scg	int		(*cond)(struct roff_node *);
3750724Scg	int		(*pre)(struct roff_node *);
3850724Scg	void		(*post)(struct roff_node *);
3950724Scg	const char	 *prefix; /* pre-node string constant */
4050724Scg	const char	 *suffix; /* post-node string constant */
4150724Scg};
4250724Scg
4350724Scgstatic	void	 md_nodelist(struct roff_node *);
4450724Scgstatic	void	 md_node(struct roff_node *);
4550724Scgstatic	const char *md_stack(char);
4650724Scgstatic	void	 md_preword(void);
4750724Scgstatic	void	 md_rawword(const char *);
4850724Scgstatic	void	 md_word(const char *);
4950724Scgstatic	void	 md_named(const char *);
5050724Scgstatic	void	 md_char(unsigned char);
5150724Scgstatic	void	 md_uri(const char *);
5250724Scg
5350724Scgstatic	int	 md_cond_head(struct roff_node *);
5450724Scgstatic	int	 md_cond_body(struct roff_node *);
5550724Scg
5650724Scgstatic	int	 md_pre_abort(struct roff_node *);
5750724Scgstatic	int	 md_pre_raw(struct roff_node *);
5850724Scgstatic	int	 md_pre_word(struct roff_node *);
5950724Scgstatic	int	 md_pre_skip(struct roff_node *);
6050724Scgstatic	void	 md_pre_syn(struct roff_node *);
6150724Scgstatic	int	 md_pre_An(struct roff_node *);
6250724Scgstatic	int	 md_pre_Ap(struct roff_node *);
6350724Scgstatic	int	 md_pre_Bd(struct roff_node *);
6450724Scgstatic	int	 md_pre_Bk(struct roff_node *);
6553413Srogerstatic	int	 md_pre_Bl(struct roff_node *);
66197404Sjoelstatic	int	 md_pre_D1(struct roff_node *);
67197404Sjoelstatic	int	 md_pre_Dl(struct roff_node *);
68197404Sjoelstatic	int	 md_pre_En(struct roff_node *);
6953413Srogerstatic	int	 md_pre_Eo(struct roff_node *);
7053413Srogerstatic	int	 md_pre_Fa(struct roff_node *);
7154831Scgstatic	int	 md_pre_Fd(struct roff_node *);
7254831Scgstatic	int	 md_pre_Fn(struct roff_node *);
7353413Srogerstatic	int	 md_pre_Fo(struct roff_node *);
7453413Srogerstatic	int	 md_pre_In(struct roff_node *);
7553413Srogerstatic	int	 md_pre_It(struct roff_node *);
76193640Sariffstatic	int	 md_pre_Lk(struct roff_node *);
77193640Sariffstatic	int	 md_pre_Mt(struct roff_node *);
78193640Sariffstatic	int	 md_pre_Nd(struct roff_node *);
79193640Sariffstatic	int	 md_pre_Nm(struct roff_node *);
8053465Scgstatic	int	 md_pre_No(struct roff_node *);
8153465Scgstatic	int	 md_pre_Ns(struct roff_node *);
8253465Scgstatic	int	 md_pre_Pp(struct roff_node *);
8350724Scgstatic	int	 md_pre_Rs(struct roff_node *);
84119287Simpstatic	int	 md_pre_Sh(struct roff_node *);
85119287Simpstatic	int	 md_pre_Sm(struct roff_node *);
8650724Scgstatic	int	 md_pre_Vt(struct roff_node *);
8753413Srogerstatic	int	 md_pre_Xr(struct roff_node *);
8853413Srogerstatic	int	 md_pre__T(struct roff_node *);
8970134Scgstatic	int	 md_pre_br(struct roff_node *);
9070134Scg
9182180Scgstatic	void	 md_post_raw(struct roff_node *);
9282180Scgstatic	void	 md_post_word(struct roff_node *);
9350724Scgstatic	void	 md_post_pc(struct roff_node *);
9450724Scgstatic	void	 md_post_Bk(struct roff_node *);
9550724Scgstatic	void	 md_post_Bl(struct roff_node *);
9650724Scgstatic	void	 md_post_D1(struct roff_node *);
9753413Srogerstatic	void	 md_post_En(struct roff_node *);
9856154Speterstatic	void	 md_post_Eo(struct roff_node *);
9976086Scgstatic	void	 md_post_Fa(struct roff_node *);
100119548Sorionstatic	void	 md_post_Fd(struct roff_node *);
10150724Scgstatic	void	 md_post_Fl(struct roff_node *);
10278033Scgstatic	void	 md_post_Fn(struct roff_node *);
10376086Scgstatic	void	 md_post_Fo(struct roff_node *);
10476086Scgstatic	void	 md_post_In(struct roff_node *);
10576086Scgstatic	void	 md_post_It(struct roff_node *);
10676086Scgstatic	void	 md_post_Lb(struct roff_node *);
10776086Scgstatic	void	 md_post_Nm(struct roff_node *);
10876086Scgstatic	void	 md_post_Pf(struct roff_node *);
10976086Scgstatic	void	 md_post_Vt(struct roff_node *);
11076086Scgstatic	void	 md_post__T(struct roff_node *);
11176086Scg
11276086Scgstatic	const struct md_act md_acts[MDOC_MAX - MDOC_Dd] = {
11395678Scg	{ NULL, NULL, NULL, NULL, NULL }, /* Dd */
11476086Scg	{ NULL, NULL, NULL, NULL, NULL }, /* Dt */
115119548Sorion	{ NULL, NULL, NULL, NULL, NULL }, /* Os */
116119548Sorion	{ NULL, md_pre_Sh, NULL, NULL, NULL }, /* Sh */
11784658Scg	{ NULL, md_pre_Sh, NULL, NULL, NULL }, /* Ss */
11859019Scg	{ NULL, md_pre_Pp, NULL, NULL, NULL }, /* Pp */
119152419Sariff	{ md_cond_body, md_pre_D1, md_post_D1, NULL, NULL }, /* D1 */
120152419Sariff	{ md_cond_body, md_pre_Dl, md_post_D1, NULL, NULL }, /* Dl */
121152419Sariff	{ md_cond_body, md_pre_Bd, md_post_D1, NULL, NULL }, /* Bd */
122152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Ed */
123152419Sariff	{ md_cond_body, md_pre_Bl, md_post_Bl, NULL, NULL }, /* Bl */
124152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* El */
125167648Sariff	{ NULL, md_pre_It, md_post_It, NULL, NULL }, /* It */
126167648Sariff	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Ad */
127167648Sariff	{ NULL, md_pre_An, NULL, NULL, NULL }, /* An */
128167648Sariff	{ NULL, md_pre_Ap, NULL, NULL, NULL }, /* Ap */
129167648Sariff	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Ar */
130152419Sariff	{ NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Cd */
131152419Sariff	{ NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Cm */
132152419Sariff	{ NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Dv */
13350724Scg	{ NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Er */
13450724Scg	{ NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Ev */
13550724Scg	{ NULL, NULL, NULL, NULL, NULL }, /* Ex */
13655209Scg	{ NULL, md_pre_Fa, md_post_Fa, NULL, NULL }, /* Fa */
13750724Scg	{ NULL, md_pre_Fd, md_post_Fd, "**", "**" }, /* Fd */
13874763Scg	{ NULL, md_pre_raw, md_post_Fl, "**-", "**" }, /* Fl */
13974763Scg	{ NULL, md_pre_Fn, md_post_Fn, NULL, NULL }, /* Fn */
140152419Sariff	{ NULL, md_pre_Fd, md_post_raw, "*", "*" }, /* Ft */
141152419Sariff	{ NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Ic */
142164614Sariff	{ NULL, md_pre_In, md_post_In, NULL, NULL }, /* In */
143164614Sariff	{ NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Li */
144164614Sariff	{ md_cond_head, md_pre_Nd, NULL, NULL, NULL }, /* Nd */
14555209Scg	{ NULL, md_pre_Nm, md_post_Nm, "**", "**" }, /* Nm */
14650724Scg	{ md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Op */
147152419Sariff	{ NULL, md_pre_abort, NULL, NULL, NULL }, /* Ot */
148152419Sariff	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Pa */
149152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Rv */
150152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* St */
151152419Sariff	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Va */
152152419Sariff	{ NULL, md_pre_Vt, md_post_Vt, "*", "*" }, /* Vt */
153152419Sariff	{ NULL, md_pre_Xr, NULL, NULL, NULL }, /* Xr */
154152419Sariff	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %A */
155152419Sariff	{ NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %B */
156152419Sariff	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %D */
157152419Sariff	{ NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %I */
158152419Sariff	{ NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %J */
159152419Sariff	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %N */
160152419Sariff	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %O */
161152419Sariff	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %P */
162152419Sariff	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %R */
163152419Sariff	{ NULL, md_pre__T, md_post__T, NULL, NULL }, /* %T */
164152419Sariff	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %V */
165152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Ac */
166152419Sariff	{ md_cond_body, md_pre_word, md_post_word, "<", ">" }, /* Ao */
167152419Sariff	{ md_cond_body, md_pre_word, md_post_word, "<", ">" }, /* Aq */
168152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* At */
169152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Bc */
170152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Bf XXX not implemented */
171152419Sariff	{ md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Bo */
172152419Sariff	{ md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Bq */
173152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Bsx */
174152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Bx */
175152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Db */
176152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Dc */
177152419Sariff	{ md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Do */
178152419Sariff	{ md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Dq */
179152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Ec */
180152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Ef */
181152419Sariff	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Em */
182152419Sariff	{ md_cond_body, md_pre_Eo, md_post_Eo, NULL, NULL }, /* Eo */
183152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Fx */
184152419Sariff	{ NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Ms */
185152419Sariff	{ NULL, md_pre_No, NULL, NULL, NULL }, /* No */
186152419Sariff	{ NULL, md_pre_Ns, NULL, NULL, NULL }, /* Ns */
187152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Nx */
188152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Ox */
189152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Pc */
190152419Sariff	{ NULL, NULL, md_post_Pf, NULL, NULL }, /* Pf */
191152419Sariff	{ md_cond_body, md_pre_word, md_post_word, "(", ")" }, /* Po */
192152419Sariff	{ md_cond_body, md_pre_word, md_post_word, "(", ")" }, /* Pq */
193152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Qc */
194152419Sariff	{ md_cond_body, md_pre_raw, md_post_raw, "'`", "`'" }, /* Ql */
195152419Sariff	{ md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Qo */
196152419Sariff	{ md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Qq */
197152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Re */
198152419Sariff	{ md_cond_body, md_pre_Rs, NULL, NULL, NULL }, /* Rs */
199152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Sc */
200152419Sariff	{ md_cond_body, md_pre_word, md_post_word, "'", "'" }, /* So */
201152419Sariff	{ md_cond_body, md_pre_word, md_post_word, "'", "'" }, /* Sq */
202152419Sariff	{ NULL, md_pre_Sm, NULL, NULL, NULL }, /* Sm */
203152419Sariff	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Sx */
204152419Sariff	{ NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Sy */
205152419Sariff	{ NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Tn */
206152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Ux */
207152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Xc */
208152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Xo */
20955209Scg	{ NULL, md_pre_Fo, md_post_Fo, "**", "**" }, /* Fo */
21050724Scg	{ NULL, NULL, NULL, NULL, NULL }, /* Fc */
21150724Scg	{ md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Oo */
21250724Scg	{ NULL, NULL, NULL, NULL, NULL }, /* Oc */
21350724Scg	{ NULL, md_pre_Bk, md_post_Bk, NULL, NULL }, /* Bk */
21465644Scg	{ NULL, NULL, NULL, NULL, NULL }, /* Ek */
21565644Scg	{ NULL, NULL, NULL, NULL, NULL }, /* Bt */
21665644Scg	{ NULL, NULL, NULL, NULL, NULL }, /* Hf */
21765644Scg	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Fr */
21859019Scg	{ NULL, NULL, NULL, NULL, NULL }, /* Ud */
21954831Scg	{ NULL, NULL, md_post_Lb, NULL, NULL }, /* Lb */
220164614Sariff	{ NULL, md_pre_abort, NULL, NULL, NULL }, /* Lp */
22184658Scg	{ NULL, md_pre_Lk, NULL, NULL, NULL }, /* Lk */
22250724Scg	{ NULL, md_pre_Mt, NULL, NULL, NULL }, /* Mt */
223150832Snetchild	{ md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Brq */
224150832Snetchild	{ md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Bro */
225152419Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Brc */
226152419Sariff	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %C */
227148591Snetchild	{ NULL, md_pre_skip, NULL, NULL, NULL }, /* Es */
228164614Sariff	{ md_cond_body, md_pre_En, md_post_En, NULL, NULL }, /* En */
229164614Sariff	{ NULL, NULL, NULL, NULL, NULL }, /* Dx */
23055209Scg	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %Q */
23150724Scg	{ NULL, md_pre_Lk, md_post_pc, NULL, NULL }, /* %U */
232150832Snetchild	{ NULL, NULL, NULL, NULL, NULL }, /* Ta */
233150832Snetchild	{ NULL, md_pre_skip, NULL, NULL, NULL }, /* Tg */
234150832Snetchild};
23554831Scgstatic const struct md_act *md_act(enum roff_tok);
23653413Sroger
23754831Scgstatic	int	 outflags;
238150832Snetchild#define	MD_spc		 (1 << 0)  /* Blank character before next word. */
239164614Sariff#define	MD_spc_force	 (1 << 1)  /* Even before trailing punctuation. */
240164614Sariff#define	MD_nonl		 (1 << 2)  /* Prevent linebreak in markdown code. */
241164614Sariff#define	MD_nl		 (1 << 3)  /* Break markdown code line. */
242164614Sariff#define	MD_br		 (1 << 4)  /* Insert an output line break. */
243150832Snetchild#define	MD_sp		 (1 << 5)  /* Insert a paragraph break. */
24454831Scg#define	MD_Sm		 (1 << 6)  /* Horizontal spacing mode. */
245164614Sariff#define	MD_Bk		 (1 << 7)  /* Word keep mode. */
24650724Scg#define	MD_An_split	 (1 << 8)  /* Author mode is "split". */
247164614Sariff#define	MD_An_nosplit	 (1 << 9)  /* Author mode is "nosplit". */
248193640Sariff
249193640Sariffstatic	int	 escflags; /* Escape in generated markdown code: */
250193640Sariff#define	ESC_BOL	 (1 << 0)  /* "#*+-" near the beginning of a line. */
251193640Sariff#define	ESC_NUM	 (1 << 1)  /* "." after a leading number. */
25264881Scg#define	ESC_HYP	 (1 << 2)  /* "(" immediately after "]". */
25350724Scg#define	ESC_SQU	 (1 << 4)  /* "]" when "[" is open. */
254150832Snetchild#define	ESC_FON	 (1 << 5)  /* "*" immediately after unrelated "*". */
25550724Scg#define	ESC_EOL	 (1 << 6)  /* " " at the and of a line. */
25650724Scg
25750724Scgstatic	int	 code_blocks, quote_blocks, list_blocks;
25850724Scgstatic	int	 outcount;
25950724Scg
26050724Scg
26150724Scgstatic const struct md_act *
26250724Scgmd_act(enum roff_tok tok)
26350724Scg{
264152419Sariff	assert(tok >= MDOC_Dd && tok <= MDOC_MAX);
26550724Scg	return md_acts + (tok - MDOC_Dd);
26650724Scg}
26750724Scg
26850724Scgvoid
26950724Scgmarkdown_mdoc(void *arg, const struct roff_meta *mdoc)
27050724Scg{
27150724Scg	outflags = MD_Sm;
27250724Scg	md_word(mdoc->title);
27354831Scg	if (mdoc->msec != NULL) {
27454831Scg		outflags &= ~MD_spc;
27550724Scg		md_word("(");
276164614Sariff		md_word(mdoc->msec);
277148591Snetchild		md_word(")");
278148591Snetchild	}
279148591Snetchild	md_word("-");
280148591Snetchild	md_word(mdoc->vol);
281164614Sariff	if (mdoc->arch != NULL) {
282148591Snetchild		md_word("(");
283164614Sariff		md_word(mdoc->arch);
284148591Snetchild		md_word(")");
285164614Sariff	}
286148591Snetchild	outflags |= MD_sp;
287164614Sariff
288148591Snetchild	md_nodelist(mdoc->first->child);
289148591Snetchild
290148591Snetchild	outflags |= MD_sp;
291150832Snetchild	md_word(mdoc->os);
292164614Sariff	md_word("-");
293148591Snetchild	md_word(mdoc->date);
294148591Snetchild	putchar('\n');
295148591Snetchild}
296148591Snetchild
297148591Snetchildstatic void
298148591Snetchildmd_nodelist(struct roff_node *n)
299148591Snetchild{
300148591Snetchild	while (n != NULL) {
301148591Snetchild		md_node(n);
302148591Snetchild		n = n->next;
303148591Snetchild	}
304148591Snetchild}
305148591Snetchild
306148591Snetchildstatic void
307148591Snetchildmd_node(struct roff_node *n)
30870134Scg{
30970134Scg	const struct md_act	*act;
31070134Scg	int			 cond, process_children;
31150724Scg
31274763Scg	if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
31350724Scg		return;
314152419Sariff
31550724Scg	if (outflags & MD_nonl)
316164614Sariff		outflags &= ~(MD_nl | MD_sp);
31750724Scg	else if (outflags & MD_spc &&
318152419Sariff	     n->flags & NODE_LINE &&
31950724Scg	     !roff_node_transparent(n))
320164614Sariff		outflags |= MD_nl;
321164614Sariff
322164614Sariff	act = NULL;
323164614Sariff	cond = 0;
324152419Sariff	process_children = 1;
325152419Sariff	n->flags &= ~NODE_ENDED;
326152419Sariff
327152419Sariff	if (n->type == ROFFT_TEXT) {
328152419Sariff		if (n->flags & NODE_DELIMC)
329152419Sariff			outflags &= ~(MD_spc | MD_spc_force);
330152419Sariff		else if (outflags & MD_Sm)
331152419Sariff			outflags |= MD_spc_force;
332152419Sariff		md_word(n->string);
33350724Scg		if (n->flags & NODE_DELIMO)
33450724Scg			outflags &= ~(MD_spc | MD_spc_force);
335164614Sariff		else if (outflags & MD_Sm)
336164614Sariff			outflags |= MD_spc;
337164614Sariff	} else if (n->tok < ROFF_MAX) {
338164614Sariff		switch (n->tok) {
339152419Sariff		case ROFF_br:
340152419Sariff			process_children = md_pre_br(n);
34150724Scg			break;
342164614Sariff		case ROFF_sp:
34350724Scg			process_children = md_pre_Pp(n);
34450724Scg			break;
34550724Scg		default:
34674763Scg			process_children = 0;
34750724Scg			break;
348150832Snetchild		}
349152419Sariff	} else {
35050724Scg		act = md_act(n->tok);
351164614Sariff		cond = act->cond == NULL || (*act->cond)(n);
352164614Sariff		if (cond && act->pre != NULL &&
35350724Scg		    (n->end == ENDBODY_NOT || n->child != NULL))
354164614Sariff			process_children = (*act->pre)(n);
355164614Sariff	}
356164614Sariff
357164614Sariff	if (process_children && n->child != NULL)
358206033Sjoel		md_nodelist(n->child);
359150832Snetchild
360150832Snetchild	if (n->flags & NODE_ENDED)
361152419Sariff		return;
362164614Sariff
363152419Sariff	if (cond && act->post != NULL)
364164614Sariff		(*act->post)(n);
365152419Sariff
36650724Scg	if (n->end != ENDBODY_NOT)
367206033Sjoel		n->body->flags |= NODE_ENDED;
368150832Snetchild}
369152419Sariff
370164614Sariffstatic const char *
371164614Sariffmd_stack(char c)
37250724Scg{
373150832Snetchild	static char	*stack;
374152419Sariff	static size_t	 sz;
375152419Sariff	static size_t	 cur;
376150832Snetchild
377150832Snetchild	switch (c) {
378164614Sariff	case '\0':
37950724Scg		break;
38050724Scg	case (char)-1:
381193640Sariff		assert(cur);
382164614Sariff		stack[--cur] = '\0';
38350724Scg		break;
384150832Snetchild	default:
38550724Scg		if (cur + 1 >= sz) {
38650724Scg			sz += 8;
387150832Snetchild			stack = mandoc_realloc(stack, sz);
38850724Scg		}
38950724Scg		stack[cur] = c;
39050724Scg		stack[++cur] = '\0';
39150724Scg		break;
39250724Scg	}
393150832Snetchild	return stack == NULL ? "" : stack;
394152419Sariff}
395164614Sariff
396152419Sariff/*
397150832Snetchild * Handle vertical and horizontal spacing.
398150832Snetchild */
399150832Snetchildstatic void
400150832Snetchildmd_preword(void)
401150832Snetchild{
402150832Snetchild	const char	*cp;
403150832Snetchild
404150832Snetchild	/*
405164614Sariff	 * If a list block is nested inside a code block or a blockquote,
40650724Scg	 * blank lines for paragraph breaks no longer work; instead,
40750724Scg	 * they terminate the list.  Work around this markdown issue
40870134Scg	 * by using mere line breaks instead.
409164614Sariff	 */
410164614Sariff
411164614Sariff	if (list_blocks && outflags & MD_sp) {
412193640Sariff		outflags &= ~MD_sp;
41370134Scg		outflags |= MD_br;
41470134Scg	}
41570134Scg
41670134Scg	/*
41770134Scg	 * End the old line if requested.
41850724Scg	 * Escape whitespace at the end of the markdown line
419164614Sariff	 * such that it won't look like an output line break.
42050724Scg	 */
421164614Sariff
42250724Scg	if (outflags & MD_sp)
423150832Snetchild		putchar('\n');
424150832Snetchild	else if (outflags & MD_br) {
425148591Snetchild		putchar(' ');
426148591Snetchild		putchar(' ');
427164614Sariff	} else if (outflags & MD_nl && escflags & ESC_EOL)
428148591Snetchild		md_named("zwnj");
429164614Sariff
430164614Sariff	/* Start a new line if necessary. */
43150724Scg
432148591Snetchild	if (outflags & (MD_nl | MD_br | MD_sp)) {
433148591Snetchild		putchar('\n');
434150832Snetchild		for (cp = md_stack('\0'); *cp != '\0'; cp++) {
435164614Sariff			putchar(*cp);
43650724Scg			if (*cp == '>')
43750724Scg				putchar(' ');
43850724Scg		}
43950724Scg		outflags &= ~(MD_nl | MD_br | MD_sp);
44050724Scg		escflags = ESC_BOL;
44150724Scg		outcount = 0;
442164614Sariff
443164614Sariff	/* Handle horizontal spacing. */
44450724Scg
44550724Scg	} else if (outflags & MD_spc) {
446152419Sariff		if (outflags & MD_Bk)
447152419Sariff			fputs("&nbsp;", stdout);
44850724Scg		else
449152419Sariff			putchar(' ');
450152419Sariff		escflags &= ~ESC_FON;
451152419Sariff		outcount++;
452152419Sariff	}
453152419Sariff
454164614Sariff	outflags &= ~(MD_spc_force | MD_nonl);
455152419Sariff	if (outflags & MD_Sm)
456164614Sariff		outflags |= MD_spc;
457152419Sariff	else
458164614Sariff		outflags &= ~MD_spc;
459164614Sariff}
460164614Sariff
461152419Sariff/*
462164614Sariff * Print markdown syntax elements.
463152419Sariff * Can also be used for constant strings when neither escaping
464152419Sariff * nor delimiter handling is required.
465164614Sariff */
466152419Sariffstatic void
467164614Sariffmd_rawword(const char *s)
468152419Sariff{
469152419Sariff	md_preword();
470152419Sariff
471164614Sariff	if (*s == '\0')
472152419Sariff		return;
473164614Sariff
474152419Sariff	if (escflags & ESC_FON) {
475152419Sariff		escflags &= ~ESC_FON;
476152419Sariff		if (*s == '*' && !code_blocks)
477152419Sariff			fputs("&zwnj;", stdout);
478152419Sariff	}
479152419Sariff
480152419Sariff	while (*s != '\0') {
481152419Sariff		switch(*s) {
482152419Sariff		case '*':
483152419Sariff			if (s[1] == '\0')
484152419Sariff				escflags |= ESC_FON;
485152419Sariff			break;
486152419Sariff		case '[':
487152419Sariff			escflags |= ESC_SQU;
488152419Sariff			break;
489164614Sariff		case ']':
490152419Sariff			escflags |= ESC_HYP;
491152419Sariff			escflags &= ~ESC_SQU;
492152419Sariff			break;
493152419Sariff		default:
494152419Sariff			break;
49550724Scg		}
49650724Scg		md_char(*s++);
49750724Scg	}
49884658Scg	if (s[-1] == ' ')
499164614Sariff		escflags |= ESC_EOL;
500164614Sariff	else
501150832Snetchild		escflags &= ~ESC_EOL;
502152419Sariff}
503168847Sariff
504164614Sariff/*
505150832Snetchild * Print text and mdoc(7) syntax elements.
50650724Scg */
507152419Sariffstatic void
508164614Sariffmd_word(const char *s)
509164614Sariff{
510164614Sariff	const char	*seq, *prevfont, *currfont, *nextfont;
511164614Sariff	char		 c;
512164614Sariff	int		 bs, sz, uc, breakline;
513164614Sariff
514152419Sariff	/* No spacing before closing delimiters. */
515164614Sariff	if (s[0] != '\0' && s[1] == '\0' &&
516164614Sariff	    strchr("!),.:;?]", s[0]) != NULL &&
517164614Sariff	    (outflags & MD_spc_force) == 0)
518164614Sariff		outflags &= ~MD_spc;
519164614Sariff
520164614Sariff	md_preword();
521152419Sariff
52250724Scg	if (*s == '\0')
523148591Snetchild		return;
524164614Sariff
525164614Sariff	/* No spacing after opening delimiters. */
526164614Sariff	if ((s[0] == '(' || s[0] == '[') && s[1] == '\0')
527164614Sariff		outflags &= ~MD_spc;
52850724Scg
529150832Snetchild	breakline = 0;
530164614Sariff	prevfont = currfont = "";
53150724Scg	while ((c = *s++) != '\0') {
53250724Scg		bs = 0;
53350724Scg		switch(c) {
534164614Sariff		case ASCII_NBRSP:
53550724Scg			if (code_blocks)
53650724Scg				c = ' ';
53750724Scg			else {
53850724Scg				md_named("nbsp");
539150832Snetchild				c = '\0';
54050724Scg			}
541152419Sariff			break;
542152419Sariff		case ASCII_HYPH:
543164614Sariff			bs = escflags & ESC_BOL && !code_blocks;
544164614Sariff			c = '-';
545193640Sariff			break;
546164614Sariff		case ASCII_BREAK:
547152419Sariff			continue;
548152419Sariff		case '#':
549164614Sariff		case '+':
550164614Sariff		case '-':
551193640Sariff			bs = escflags & ESC_BOL && !code_blocks;
552164614Sariff			break;
553152419Sariff		case '(':
55450724Scg			bs = escflags & ESC_HYP && !code_blocks;
55550724Scg			break;
556164614Sariff		case ')':
557164614Sariff			bs = escflags & ESC_NUM && !code_blocks;
558193640Sariff			break;
559164614Sariff		case '*':
56050724Scg		case '[':
561148591Snetchild		case '_':
562150832Snetchild		case '`':
56350724Scg			bs = !code_blocks;
564164614Sariff			break;
56550724Scg		case '.':
56650724Scg			bs = escflags & ESC_NUM && !code_blocks;
567193640Sariff			break;
568164614Sariff		case '<':
56950724Scg			if (code_blocks == 0) {
57050724Scg				md_named("lt");
57150724Scg				c = '\0';
57250724Scg			}
573164614Sariff			break;
574152419Sariff		case '=':
575171250Sariff			if (escflags & ESC_BOL && !code_blocks) {
576171250Sariff				md_named("equals");
577164614Sariff				c = '\0';
578171250Sariff			}
579152419Sariff			break;
580152419Sariff		case '>':
581152419Sariff			if (code_blocks == 0) {
582152419Sariff				md_named("gt");
583152419Sariff				c = '\0';
584152419Sariff			}
585152419Sariff			break;
586152419Sariff		case '\\':
587218909Sbrucec			uc = 0;
588152419Sariff			nextfont = NULL;
589152419Sariff			switch (mandoc_escape(&s, &seq, &sz)) {
590152419Sariff			case ESCAPE_UNICODE:
591152419Sariff				uc = mchars_num2uc(seq + 1, sz - 1);
592152419Sariff				break;
593152419Sariff			case ESCAPE_NUMBERED:
594152419Sariff				uc = mchars_num2char(seq, sz);
595152419Sariff				break;
596152419Sariff			case ESCAPE_SPECIAL:
597152419Sariff				uc = mchars_spec2cp(seq, sz);
598152419Sariff				break;
599152419Sariff			case ESCAPE_UNDEF:
600152419Sariff				uc = *seq;
601152419Sariff				break;
602152419Sariff			case ESCAPE_DEVICE:
603152419Sariff				md_rawword("markdown");
604152419Sariff				continue;
605152419Sariff			case ESCAPE_FONTBOLD:
606150832Snetchild			case ESCAPE_FONTCB:
607148591Snetchild				nextfont = "**";
608150832Snetchild				break;
609164614Sariff			case ESCAPE_FONTITALIC:
61050724Scg			case ESCAPE_FONTCI:
61150724Scg				nextfont = "*";
612193640Sariff				break;
613164614Sariff			case ESCAPE_FONTBI:
61454831Scg				nextfont = "***";
61554831Scg				break;
61654831Scg			case ESCAPE_FONT:
617152419Sariff			case ESCAPE_FONTCR:
618152419Sariff			case ESCAPE_FONTROMAN:
61954831Scg				nextfont = "";
620150832Snetchild				break;
621148591Snetchild			case ESCAPE_FONTPREV:
622152419Sariff				nextfont = prevfont;
623148591Snetchild				break;
624152419Sariff			case ESCAPE_BREAK:
625150832Snetchild				breakline = 1;
626164614Sariff				break;
627148591Snetchild			case ESCAPE_NOSPACE:
628164614Sariff			case ESCAPE_SKIPCHAR:
629164614Sariff			case ESCAPE_OVERSTRIKE:
63054831Scg				/* XXX not implemented */
63154831Scg				/* FALLTHROUGH */
63250724Scg			case ESCAPE_ERROR:
633167648Sariff			default:
63450724Scg				break;
63570321Scg			}
636164614Sariff			if (nextfont != NULL && !code_blocks) {
63770321Scg				if (*currfont != '\0') {
638167648Sariff					outflags &= ~MD_spc;
639164614Sariff					md_rawword(currfont);
640167648Sariff				}
641167648Sariff				prevfont = currfont;
642167648Sariff				currfont = nextfont;
643167648Sariff				if (*currfont != '\0') {
644167648Sariff					outflags &= ~MD_spc;
645167648Sariff					md_rawword(currfont);
646167648Sariff				}
647167648Sariff			}
648164614Sariff			if (uc) {
649167648Sariff				if ((uc < 0x20 && uc != 0x09) ||
650167648Sariff				    (uc > 0x7E && uc < 0xA0))
651167648Sariff					uc = 0xFFFD;
652167648Sariff				if (code_blocks) {
653167648Sariff					seq = mchars_uc2str(uc);
654167648Sariff					fputs(seq, stdout);
655167648Sariff					outcount += strlen(seq);
656167648Sariff				} else {
657167648Sariff					printf("&#%d;", uc);
658164614Sariff					outcount++;
659167648Sariff				}
660167648Sariff				escflags &= ~ESC_FON;
661164614Sariff			}
662167648Sariff			c = '\0';
663164614Sariff			break;
664164614Sariff		case ']':
665164614Sariff			bs = escflags & ESC_SQU && !code_blocks;
666167648Sariff			escflags |= ESC_HYP;
667164614Sariff			break;
668193640Sariff		default:
669167648Sariff			break;
670167648Sariff		}
671193640Sariff		if (bs)
672167648Sariff			putchar('\\');
673167648Sariff		md_char(c);
674167648Sariff		if (breakline &&
675167648Sariff		    (*s == '\0' || *s == ' ' || *s == ASCII_NBRSP)) {
676167648Sariff			printf("  \n");
677167648Sariff			breakline = 0;
678167648Sariff			while (*s == ' ' || *s == ASCII_NBRSP)
679164614Sariff				s++;
680164614Sariff		}
681164614Sariff	}
682164614Sariff	if (*currfont != '\0') {
683164614Sariff		outflags &= ~MD_spc;
684164614Sariff		md_rawword(currfont);
685164614Sariff	} else if (s[-2] == ' ')
686164614Sariff		escflags |= ESC_EOL;
687164614Sariff	else
688164614Sariff		escflags &= ~ESC_EOL;
689164614Sariff}
690164614Sariff
691164614Sariff/*
692164614Sariff * Print a single HTML named character reference.
693164614Sariff */
694164614Sariffstatic void
695164614Sariffmd_named(const char *s)
696164614Sariff{
697164614Sariff	printf("&%s;", s);
698164614Sariff	escflags &= ~(ESC_FON | ESC_EOL);
699164614Sariff	outcount++;
700164614Sariff}
701164614Sariff
702164614Sariff/*
703164614Sariff * Print a single raw character and maintain certain escape flags.
704164614Sariff */
705164614Sariffstatic void
706164614Sariffmd_char(unsigned char c)
707164614Sariff{
708164614Sariff	if (c != '\0') {
709164614Sariff		putchar(c);
710164614Sariff		if (c == '*')
711164614Sariff			escflags |= ESC_FON;
712164614Sariff		else
713164614Sariff			escflags &= ~ESC_FON;
714164614Sariff		outcount++;
715164614Sariff	}
716164614Sariff	if (c != ']')
717164614Sariff		escflags &= ~ESC_HYP;
718164614Sariff	if (c == ' ' || c == '\t' || c == '>')
719164614Sariff		return;
720164614Sariff	if (isdigit(c) == 0)
721164614Sariff		escflags &= ~ESC_NUM;
722164614Sariff	else if (escflags & ESC_BOL)
723164614Sariff		escflags |= ESC_NUM;
724164614Sariff	escflags &= ~ESC_BOL;
725164614Sariff}
726164614Sariff
727164614Sariffstatic int
728164614Sariffmd_cond_head(struct roff_node *n)
729164614Sariff{
730164614Sariff	return n->type == ROFFT_HEAD;
731164614Sariff}
732164614Sariff
733164614Sariffstatic int
734164614Sariffmd_cond_body(struct roff_node *n)
735150832Snetchild{
736164614Sariff	return n->type == ROFFT_BODY;
737164614Sariff}
738164614Sariff
739164614Sariffstatic int
740164614Sariffmd_pre_abort(struct roff_node *n)
741164614Sariff{
742164614Sariff	abort();
743164614Sariff}
744164614Sariff
745164614Sariffstatic int
746164614Sariffmd_pre_raw(struct roff_node *n)
747164614Sariff{
748164614Sariff	const char	*prefix;
749164614Sariff
750164614Sariff	if ((prefix = md_act(n->tok)->prefix) != NULL) {
751164614Sariff		md_rawword(prefix);
75250724Scg		outflags &= ~MD_spc;
75350724Scg		if (*prefix == '`')
75450724Scg			code_blocks++;
75570134Scg	}
75650724Scg	return 1;
75750724Scg}
75850724Scg
759152419Sariffstatic void
76050724Scgmd_post_raw(struct roff_node *n)
761170521Sariff{
762170521Sariff	const char	*suffix;
76360958Scg
764164614Sariff	if ((suffix = md_act(n->tok)->suffix) != NULL) {
765193640Sariff		outflags &= ~(MD_spc | MD_nl);
766152419Sariff		md_rawword(suffix);
767152419Sariff		if (*suffix == '`')
768193640Sariff			code_blocks--;
769152419Sariff	}
77050724Scg}
77150724Scg
772152419Sariffstatic int
773152419Sariffmd_pre_word(struct roff_node *n)
774164614Sariff{
775164614Sariff	const char	*prefix;
776164614Sariff
777164614Sariff	if ((prefix = md_act(n->tok)->prefix) != NULL) {
778164614Sariff		md_word(prefix);
779164614Sariff		outflags &= ~MD_spc;
780164614Sariff	}
781152419Sariff	return 1;
782152419Sariff}
783164614Sariff
784164614Sariffstatic void
785164614Sariffmd_post_word(struct roff_node *n)
786164614Sariff{
787152419Sariff	const char	*suffix;
788152419Sariff
789164614Sariff	if ((suffix = md_act(n->tok)->suffix) != NULL) {
790164614Sariff		outflags &= ~(MD_spc | MD_nl);
791164614Sariff		md_word(suffix);
792164614Sariff	}
793164614Sariff}
794164614Sariff
795164614Sariffstatic void
796164614Sariffmd_post_pc(struct roff_node *n)
797164614Sariff{
798152419Sariff	struct roff_node *nn;
799152419Sariff
800164614Sariff	md_post_raw(n);
801164614Sariff	if (n->parent->tok != MDOC_Rs)
802164614Sariff		return;
803164614Sariff
804152419Sariff	if ((nn = roff_node_next(n)) != NULL) {
805164614Sariff		md_word(",");
806164614Sariff		if (nn->tok == n->tok &&
807164614Sariff		    (nn = roff_node_prev(n)) != NULL &&
80850724Scg		    nn->tok == n->tok)
80950724Scg			md_word("and");
81050724Scg	} else {
81150724Scg		md_word(".");
812164614Sariff		outflags |= MD_nl;
813164614Sariff	}
814164614Sariff}
815164614Sariff
816164614Sariffstatic int
817148591Snetchildmd_pre_skip(struct roff_node *n)
81859323Scg{
819164614Sariff	return 0;
820164614Sariff}
821164614Sariff
822164614Sariffstatic void
823164614Sariffmd_pre_syn(struct roff_node *n)
824164614Sariff{
82550724Scg	struct roff_node *np;
826148591Snetchild
827148591Snetchild	if ((n->flags & NODE_SYNPRETTY) == 0 ||
828164614Sariff	    (np = roff_node_prev(n)) == NULL)
829164614Sariff		return;
830164614Sariff
831164614Sariff	if (np->tok == n->tok &&
832164614Sariff	    n->tok != MDOC_Ft &&
833164614Sariff	    n->tok != MDOC_Fo &&
834164614Sariff	    n->tok != MDOC_Fn) {
835164614Sariff		outflags |= MD_br;
836164614Sariff		return;
837164614Sariff	}
838164614Sariff
839164614Sariff	switch (np->tok) {
840164614Sariff	case MDOC_Fd:
841164614Sariff	case MDOC_Fn:
842164614Sariff	case MDOC_Fo:
843164614Sariff	case MDOC_In:
844164614Sariff	case MDOC_Vt:
845164614Sariff		outflags |= MD_sp;
846164614Sariff		break;
847164614Sariff	case MDOC_Ft:
848150832Snetchild		if (n->tok != MDOC_Fn && n->tok != MDOC_Fo) {
849164614Sariff			outflags |= MD_sp;
85050724Scg			break;
85150724Scg		}
852193640Sariff		/* FALLTHROUGH */
85370134Scg	default:
85450724Scg		outflags |= MD_br;
85550724Scg		break;
85650724Scg	}
857164614Sariff}
85859323Scg
859150832Snetchildstatic int
860164614Sariffmd_pre_An(struct roff_node *n)
861164614Sariff{
862164614Sariff	switch (n->norm->An.auth) {
863164614Sariff	case AUTH_split:
864164614Sariff		outflags &= ~MD_An_nosplit;
865164614Sariff		outflags |= MD_An_split;
866164614Sariff		return 0;
867164614Sariff	case AUTH_nosplit:
868164614Sariff		outflags &= ~MD_An_split;
869164614Sariff		outflags |= MD_An_nosplit;
870164614Sariff		return 0;
871164614Sariff	default:
872164614Sariff		if (outflags & MD_An_split)
873164614Sariff			outflags |= MD_br;
874164614Sariff		else if (n->sec == SEC_AUTHORS &&
875150832Snetchild		    ! (outflags & MD_An_nosplit))
876164614Sariff			outflags |= MD_An_split;
877167648Sariff		return 1;
878164614Sariff	}
879164614Sariff}
88050724Scg
88150724Scgstatic int
88274763Scgmd_pre_Ap(struct roff_node *n)
88370134Scg{
88450724Scg	outflags &= ~MD_spc;
88550724Scg	md_word("'");
886150832Snetchild	outflags &= ~MD_spc;
887164614Sariff	return 0;
88850724Scg}
88950724Scg
89070134Scgstatic int
891164614Sariffmd_pre_Bd(struct roff_node *n)
892164614Sariff{
893164614Sariff	switch (n->norm->Bd.type) {
894164614Sariff	case DISP_unfilled:
895167648Sariff	case DISP_literal:
896164614Sariff		return md_pre_Dl(n);
897164614Sariff	default:
898164614Sariff		return md_pre_D1(n);
899193640Sariff	}
90070134Scg}
90170134Scg
90270134Scgstatic int
90370134Scgmd_pre_Bk(struct roff_node *n)
904164614Sariff{
905164614Sariff	switch (n->type) {
906164614Sariff	case ROFFT_BLOCK:
907164614Sariff		return 1;
908167648Sariff	case ROFFT_BODY:
909164614Sariff		outflags |= MD_Bk;
910164614Sariff		return 1;
911164614Sariff	default:
912193640Sariff		return 0;
91370134Scg	}
91470134Scg}
91570134Scg
91670134Scgstatic void
91750724Scgmd_post_Bk(struct roff_node *n)
91850724Scg{
91954831Scg	if (n->type == ROFFT_BODY)
92050724Scg		outflags &= ~MD_Bk;
92150724Scg}
922150832Snetchild
92350724Scgstatic int
924150832Snetchildmd_pre_Bl(struct roff_node *n)
925164614Sariff{
926164614Sariff	n->norm->Bl.count = 0;
927164614Sariff	if (n->norm->Bl.type == LIST_column)
928164614Sariff		md_pre_Dl(n);
929148591Snetchild	outflags |= MD_sp;
930148591Snetchild	return 1;
931150832Snetchild}
932148591Snetchild
933148591Snetchildstatic void
93450724Scgmd_post_Bl(struct roff_node *n)
93550724Scg{
936164614Sariff	n->norm->Bl.count = 0;
937164614Sariff	if (n->norm->Bl.type == LIST_column)
938164614Sariff		md_post_D1(n);
939164614Sariff	outflags |= MD_sp;
940164614Sariff}
941164614Sariff
94250724Scgstatic int
943148591Snetchildmd_pre_D1(struct roff_node *n)
944148591Snetchild{
945150832Snetchild	/*
94650724Scg	 * Markdown blockquote syntax does not work inside code blocks.
947164614Sariff	 * The best we can do is fall back to another nested code block.
948164614Sariff	 */
949164614Sariff	if (code_blocks) {
950164614Sariff		md_stack('\t');
951164614Sariff		code_blocks++;
952164614Sariff	} else {
95350724Scg		md_stack('>');
95450724Scg		quote_blocks++;
95554831Scg	}
95654831Scg	outflags |= MD_sp;
95754831Scg	return 1;
95854831Scg}
959152419Sariff
960152419Sariffstatic void
961150832Snetchildmd_post_D1(struct roff_node *n)
962152419Sariff{
963150832Snetchild	md_stack((char)-1);
964164614Sariff	if (code_blocks)
965152419Sariff		code_blocks--;
966152419Sariff	else
967152419Sariff		quote_blocks--;
968152419Sariff	outflags |= MD_sp;
969152419Sariff}
970152419Sariff
971150832Snetchildstatic int
972150832Snetchildmd_pre_Dl(struct roff_node *n)
973152419Sariff{
974152419Sariff	/*
975152419Sariff	 * Markdown code block syntax does not work inside blockquotes.
976164614Sariff	 * The best we can do is fall back to another nested blockquote.
977164614Sariff	 */
978152419Sariff	if (quote_blocks) {
979152419Sariff		md_stack('>');
980152419Sariff		quote_blocks++;
981150832Snetchild	} else {
982152419Sariff		md_stack('\t');
983152419Sariff		code_blocks++;
984152419Sariff	}
985152419Sariff	outflags |= MD_sp;
986164614Sariff	return 1;
987152419Sariff}
988164614Sariff
989152419Sariffstatic int
990152419Sariffmd_pre_En(struct roff_node *n)
991150832Snetchild{
992164614Sariff	if (n->norm->Es == NULL ||
993152419Sariff	    n->norm->Es->child == NULL)
994164614Sariff		return 1;
995152419Sariff
996152419Sariff	md_word(n->norm->Es->child->string);
997164614Sariff	outflags &= ~MD_spc;
998152419Sariff	return 1;
999148591Snetchild}
100053413Sroger
100154831Scgstatic void
1002148591Snetchildmd_post_En(struct roff_node *n)
100353413Sroger{
1004164614Sariff	if (n->norm->Es == NULL ||
1005164614Sariff	    n->norm->Es->child == NULL ||
1006164614Sariff	    n->norm->Es->child->next == NULL)
1007164614Sariff		return;
1008164614Sariff
1009164614Sariff	outflags &= ~MD_spc;
1010164614Sariff	md_word(n->norm->Es->child->next->string);
1011164614Sariff}
1012164614Sariff
1013164614Sariffstatic int
1014164614Sariffmd_pre_Eo(struct roff_node *n)
1015150832Snetchild{
101653413Sroger	if (n->end == ENDBODY_NOT &&
1017164614Sariff	    n->parent->head->child == NULL &&
101854831Scg	    n->child != NULL &&
101953413Sroger	    n->child->end != ENDBODY_NOT)
102054831Scg		md_preword();
102153413Sroger	else if (n->end != ENDBODY_NOT ? n->child != NULL :
1022150832Snetchild	    n->parent->head->child != NULL && (n->child != NULL ||
102353413Sroger	    (n->parent->tail != NULL && n->parent->tail->child != NULL)))
1024154285Sariff		outflags &= ~(MD_spc | MD_nl);
102553413Sroger	return 1;
102653413Sroger}
1027150832Snetchild
1028152419Sariffstatic void
1029152419Sariffmd_post_Eo(struct roff_node *n)
103054831Scg{
103153413Sroger	if (n->end != ENDBODY_NOT) {
1032148591Snetchild		outflags |= MD_spc;
1033150832Snetchild		return;
1034150832Snetchild	}
1035164614Sariff
1036164614Sariff	if (n->child == NULL && n->parent->head->child == NULL)
1037154285Sariff		return;
1038154285Sariff
1039154285Sariff	if (n->parent->tail != NULL && n->parent->tail->child != NULL)
1040154285Sariff		outflags &= ~MD_spc;
1041154285Sariff        else
1042154285Sariff		outflags |= MD_spc;
1043154285Sariff}
1044154285Sariff
1045154285Sariffstatic int
1046154285Sariffmd_pre_Fa(struct roff_node *n)
1047154285Sariff{
1048154285Sariff	int	 am_Fa;
1049154285Sariff
1050148591Snetchild	am_Fa = n->tok == MDOC_Fa;
1051148591Snetchild
1052148591Snetchild	if (am_Fa)
1053148591Snetchild		n = n->child;
105453413Sroger
1055148591Snetchild	while (n != NULL) {
1056148591Snetchild		md_rawword("*");
1057148591Snetchild		outflags &= ~MD_spc;
105876086Scg		md_node(n);
105976086Scg		outflags &= ~MD_spc;
106076086Scg		md_rawword("*");
106195678Scg		if ((n = n->next) != NULL)
1062148591Snetchild			md_word(",");
1063148591Snetchild	}
1064148591Snetchild	return 0;
106574753Scg}
106655209Scg
106753413Srogerstatic void
1068152419Sariffmd_post_Fa(struct roff_node *n)
1069152419Sariff{
107053413Sroger	struct roff_node *nn;
1071152419Sariff
1072148591Snetchild	if ((nn = roff_node_next(n)) != NULL && nn->tok == MDOC_Fa)
107353413Sroger		md_word(",");
1074148591Snetchild}
107553413Sroger
107654831Scgstatic int
1077164614Sariffmd_pre_Fd(struct roff_node *n)
107853413Sroger{
1079164614Sariff	md_pre_syn(n);
108053413Sroger	md_pre_raw(n);
1081164614Sariff	return 1;
1082164614Sariff}
1083164614Sariff
1084164614Sariffstatic void
1085164614Sariffmd_post_Fd(struct roff_node *n)
1086164614Sariff{
1087164614Sariff	md_post_raw(n);
1088164614Sariff	outflags |= MD_br;
1089164614Sariff}
1090164614Sariff
1091164614Sariffstatic void
109253413Srogermd_post_Fl(struct roff_node *n)
109353413Sroger{
109453413Sroger	struct roff_node *nn;
109553413Sroger
109653413Sroger	md_post_raw(n);
1097148591Snetchild	if (n->child == NULL && (nn = roff_node_next(n)) != NULL &&
1098148591Snetchild	    nn->type != ROFFT_TEXT && (nn->flags & NODE_LINE) == 0)
1099148591Snetchild		outflags &= ~MD_spc;
1100148591Snetchild}
1101148591Snetchild
1102150832Snetchildstatic int
110353413Srogermd_pre_Fn(struct roff_node *n)
110453413Sroger{
110553413Sroger	md_pre_syn(n);
110653413Sroger
110770134Scg	if ((n = n->child) == NULL)
110870134Scg		return 0;
110970134Scg
1110164614Sariff	md_rawword("**");
111153413Sroger	outflags &= ~MD_spc;
1112150832Snetchild	md_node(n);
111353413Sroger	outflags &= ~MD_spc;
111453413Sroger	md_rawword("**");
1115167648Sariff	outflags &= ~MD_spc;
1116148591Snetchild	md_word("(");
111753413Sroger
1118167648Sariff	if ((n = n->next) != NULL)
111953413Sroger		md_pre_Fa(n);
1120148591Snetchild	return 0;
112153413Sroger}
1122164614Sariff
1123164614Sariffstatic void
1124148591Snetchildmd_post_Fn(struct roff_node *n)
1125164614Sariff{
1126164614Sariff	md_word(")");
1127164614Sariff	if (n->flags & NODE_SYNPRETTY) {
1128148591Snetchild		md_word(";");
1129164614Sariff		outflags |= MD_sp;
113053413Sroger	}
1131164614Sariff}
1132164614Sariff
1133164614Sariffstatic int
113454831Scgmd_pre_Fo(struct roff_node *n)
1135164614Sariff{
113654831Scg	switch (n->type) {
1137164614Sariff	case ROFFT_BLOCK:
1138164614Sariff		md_pre_syn(n);
1139164614Sariff		break;
114053413Sroger	case ROFFT_HEAD:
114153413Sroger		if (n->child == NULL)
1142148591Snetchild			return 0;
114370134Scg		md_pre_raw(n);
1144164614Sariff		break;
114553413Sroger	case ROFFT_BODY:
114653413Sroger		outflags &= ~(MD_spc | MD_nl);
114770134Scg		md_word("(");
114870134Scg		break;
114953413Sroger	default:
1150150832Snetchild		break;
115154831Scg	}
115253413Sroger	return 1;
1153164614Sariff}
1154148591Snetchild
115554831Scgstatic void
1156164614Sariffmd_post_Fo(struct roff_node *n)
115753413Sroger{
115854831Scg	switch (n->type) {
1159148591Snetchild	case ROFFT_HEAD:
116054831Scg		if (n->child != NULL)
1161164614Sariff			md_post_raw(n);
1162164614Sariff		break;
1163148591Snetchild	case ROFFT_BODY:
1164164614Sariff		md_post_Fn(n);
1165164614Sariff		break;
1166164614Sariff	default:
1167148591Snetchild		break;
1168164614Sariff	}
116954831Scg}
1170164614Sariff
1171164614Sariffstatic int
1172164614Sariffmd_pre_In(struct roff_node *n)
117354831Scg{
1174164614Sariff	if (n->flags & NODE_SYNPRETTY) {
117553413Sroger		md_pre_syn(n);
1176164614Sariff		md_rawword("**");
1177164614Sariff		outflags &= ~MD_spc;
1178148591Snetchild		md_word("#include <");
117954831Scg	} else {
118054831Scg		md_word("<");
1181148591Snetchild		outflags &= ~MD_spc;
118253413Sroger		md_rawword("*");
118354831Scg	}
1184164614Sariff	outflags &= ~MD_spc;
1185148591Snetchild	return 1;
118654831Scg}
1187164614Sariff
1188148591Snetchildstatic void
118954831Scgmd_post_In(struct roff_node *n)
119053413Sroger{
119153413Sroger	if (n->flags & NODE_SYNPRETTY) {
119270134Scg		outflags &= ~MD_spc;
1193164614Sariff		md_rawword(">**");
1194164614Sariff		outflags |= MD_nl;
1195193640Sariff	} else {
119670134Scg		outflags &= ~MD_spc;
119770134Scg		md_rawword("*>");
119870134Scg	}
119970134Scg}
120070134Scg
1201164614Sariffstatic int
1202164614Sariffmd_pre_It(struct roff_node *n)
120354831Scg{
1204150832Snetchild	struct roff_node	*bln;
120553413Sroger
1206164614Sariff	switch (n->type) {
1207164614Sariff	case ROFFT_BLOCK:
120854831Scg		return 1;
1209148591Snetchild
1210164614Sariff	case ROFFT_HEAD:
121153413Sroger		bln = n->parent->parent;
121253413Sroger		if (bln->norm->Bl.comp == 0 &&
121353413Sroger		    bln->norm->Bl.type != LIST_column)
1214164614Sariff			outflags |= MD_sp;
1215148591Snetchild		outflags |= MD_nl;
1216150832Snetchild
121753413Sroger		switch (bln->norm->Bl.type) {
1218164614Sariff		case LIST_item:
1219164614Sariff			outflags |= MD_br;
122053413Sroger			return 0;
1221148591Snetchild		case LIST_inset:
122253413Sroger		case LIST_diag:
122353413Sroger		case LIST_ohang:
1224164614Sariff			outflags |= MD_br;
1225164614Sariff			return 1;
122654831Scg		case LIST_tag:
1227164614Sariff		case LIST_hang:
122854831Scg			outflags |= MD_sp;
1229150832Snetchild			return 1;
1230150832Snetchild		case LIST_bullet:
1231164614Sariff			md_rawword("*\t");
1232164614Sariff			break;
1233164614Sariff		case LIST_dash:
1234164614Sariff		case LIST_hyphen:
123554831Scg			md_rawword("-\t");
123654831Scg			break;
123754831Scg		case LIST_enum:
123854831Scg			md_preword();
123954831Scg			if (bln->norm->Bl.count < 99)
124054831Scg				bln->norm->Bl.count++;
124154831Scg			printf("%d.\t", bln->norm->Bl.count);
124254831Scg			escflags &= ~ESC_FON;
1243164614Sariff			break;
1244164614Sariff		case LIST_column:
124554831Scg			outflags |= MD_br;
1246164614Sariff			return 0;
124754831Scg		default:
1248164614Sariff			return 0;
1249164614Sariff		}
125054831Scg		outflags &= ~MD_spc;
1251164614Sariff		outflags |= MD_nonl;
125254831Scg		outcount = 0;
125354831Scg		md_stack('\t');
1254164614Sariff		if (code_blocks || quote_blocks)
1255164614Sariff			list_blocks++;
1256164614Sariff		return 0;
1257164614Sariff
125854831Scg	case ROFFT_BODY:
125954831Scg		bln = n->parent->parent;
126053413Sroger		switch (bln->norm->Bl.type) {
1261164614Sariff		case LIST_ohang:
126253413Sroger			outflags |= MD_br;
126353413Sroger			break;
1264164614Sariff		case LIST_tag:
1265164614Sariff		case LIST_hang:
126654831Scg			md_pre_D1(n);
1267164614Sariff			break;
126853413Sroger		default:
1269150832Snetchild			break;
1270150832Snetchild		}
1271164614Sariff		return 1;
1272164614Sariff
1273164614Sariff	default:
1274164614Sariff		return 0;
1275152419Sariff	}
127654831Scg}
1277164614Sariff
1278152419Sariffstatic void
1279152419Sariffmd_post_It(struct roff_node *n)
1280164614Sariff{
1281164614Sariff	struct roff_node	*bln;
1282152419Sariff	int			 i, nc;
1283152419Sariff
1284164614Sariff	if (n->type != ROFFT_BODY)
1285164614Sariff		return;
1286152419Sariff
1287164614Sariff	bln = n->parent->parent;
1288164614Sariff	switch (bln->norm->Bl.type) {
1289152419Sariff	case LIST_bullet:
1290164614Sariff	case LIST_dash:
129153413Sroger	case LIST_hyphen:
129253413Sroger	case LIST_enum:
1293150832Snetchild		md_stack((char)-1);
129455209Scg		if (code_blocks || quote_blocks)
129554831Scg			list_blocks--;
1296150832Snetchild		break;
129753413Sroger	case LIST_tag:
1298148591Snetchild	case LIST_hang:
1299164614Sariff		md_post_D1(n);
1300164614Sariff		break;
1301164614Sariff
1302148591Snetchild	case LIST_column:
130354831Scg		if (n->next == NULL)
1304150832Snetchild			break;
1305150832Snetchild
1306164614Sariff		/* Calculate the array index of the current column. */
130753413Sroger
130853413Sroger		i = 0;
130950724Scg		while ((n = n->prev) != NULL && n->type != ROFFT_HEAD)
131050724Scg			i++;
131150724Scg
131250724Scg		/*
131350724Scg		 * If a width was specified for this column,
131450724Scg		 * subtract what printed, and
131550724Scg		 * add the same spacing as in mdoc_term.c.
131650724Scg		 */
131750724Scg
131876086Scg		nc = bln->norm->Bl.ncols;
131976086Scg		i = i < nc ? strlen(bln->norm->Bl.cols[i]) - outcount +
132050724Scg		    (nc < 5 ? 4 : nc == 5 ? 3 : 1) : 1;
1321164614Sariff		if (i < 1)
132276086Scg			i = 1;
132376086Scg		while (i-- > 0)
132478033Scg			putchar(' ');
132578033Scg
1326164614Sariff		outflags &= ~MD_spc;
132776086Scg		escflags &= ~ESC_FON;
132876086Scg		outcount = 0;
1329164614Sariff		break;
133076086Scg
133176086Scg	default:
1332164614Sariff		break;
133376086Scg	}
133476086Scg}
1335164614Sariff
133676086Scgstatic void
133776086Scgmd_post_Lb(struct roff_node *n)
1338164614Sariff{
133976086Scg	if (n->sec == SEC_LIBRARY)
134076086Scg		outflags |= MD_br;
1341164614Sariff}
134276086Scg
134376086Scgstatic void
1344164614Sariffmd_uri(const char *s)
1345164614Sariff{
1346164614Sariff	while (*s != '\0') {
1347164614Sariff		if (strchr("%()<>", *s) != NULL) {
1348164614Sariff			printf("%%%2.2hhX", *s);
134976086Scg			outcount += 3;
135076086Scg		} else {
135178033Scg			putchar(*s);
1352164614Sariff			outcount++;
1353164614Sariff		}
1354164614Sariff		s++;
1355164614Sariff	}
1356119548Sorion}
1357119548Sorion
1358119548Sorionstatic int
1359164614Sariffmd_pre_Lk(struct roff_node *n)
1360164614Sariff{
1361164614Sariff	const struct roff_node *link, *descr, *punct;
1362119548Sorion
1363119548Sorion	if ((link = n->child) == NULL)
1364164614Sariff		return 0;
1365164614Sariff
1366164614Sariff	/* Find beginning of trailing punctuation. */
1367164614Sariff	punct = n->last;
1368164614Sariff	while (punct != link && punct->flags & NODE_DELIMC)
1369119548Sorion		punct = punct->prev;
137076086Scg	punct = punct->next;
137176086Scg
137276086Scg	/* Link text. */
137376086Scg	descr = link->next;
1374164614Sariff	if (descr == punct)
137576086Scg		descr = link;  /* no text */
137676086Scg	md_rawword("[");
1377164614Sariff	outflags &= ~MD_spc;
137895678Scg	do {
137995678Scg		md_word(descr->string);
1380164614Sariff		descr = descr->next;
138176086Scg	} while (descr != punct);
138276086Scg	outflags &= ~MD_spc;
1383164614Sariff
1384164614Sariff	/* Link target. */
1385164614Sariff	md_rawword("](");
1386164614Sariff	md_uri(link->string);
1387164614Sariff	outflags &= ~MD_spc;
138876086Scg	md_rawword(")");
138976086Scg
1390164614Sariff	/* Trailing punctuation. */
139150724Scg	while (punct != NULL) {
139250724Scg		md_word(punct->string);
139350724Scg		punct = punct->next;
139450724Scg	}
1395150832Snetchild	return 0;
1396148591Snetchild}
1397148591Snetchild
1398148591Snetchildstatic int
1399150832Snetchildmd_pre_Mt(struct roff_node *n)
1400150832Snetchild{
1401148591Snetchild	const struct roff_node *nch;
1402148591Snetchild
1403148591Snetchild	md_rawword("[");
1404150832Snetchild	outflags &= ~MD_spc;
1405150832Snetchild	for (nch = n->child; nch != NULL; nch = nch->next)
1406150832Snetchild		md_word(nch->string);
1407150832Snetchild	outflags &= ~MD_spc;
1408170289Sdwmalone	md_rawword("](mailto:");
1409148591Snetchild	for (nch = n->child; nch != NULL; nch = nch->next) {
1410148591Snetchild		md_uri(nch->string);
1411150832Snetchild		if (nch->next != NULL) {
1412148591Snetchild			putchar(' ');
1413150832Snetchild			outcount++;
1414148591Snetchild		}
1415150832Snetchild	}
1416148591Snetchild	outflags &= ~MD_spc;
1417148591Snetchild	md_rawword(")");
1418148591Snetchild	return 0;
1419148591Snetchild}
1420148591Snetchild
1421148591Snetchildstatic int
1422148591Snetchildmd_pre_Nd(struct roff_node *n)
1423148591Snetchild{
1424148591Snetchild	outflags &= ~MD_nl;
1425148591Snetchild	outflags |= MD_spc;
1426148591Snetchild	md_word("-");
1427150832Snetchild	return 1;
1428150832Snetchild}
1429150832Snetchild
1430148591Snetchildstatic int
1431148591Snetchildmd_pre_Nm(struct roff_node *n)
1432148591Snetchild{
1433150832Snetchild	switch (n->type) {
1434148591Snetchild	case ROFFT_BLOCK:
1435148591Snetchild		outflags |= MD_Bk;
1436148591Snetchild		md_pre_syn(n);
1437150832Snetchild		break;
1438150832Snetchild	case ROFFT_HEAD:
1439148591Snetchild	case ROFFT_ELEM:
1440148591Snetchild		md_pre_raw(n);
1441148591Snetchild		break;
1442150832Snetchild	default:
1443148591Snetchild		break;
1444150832Snetchild	}
1445170289Sdwmalone	return 1;
1446164614Sariff}
1447148591Snetchild
1448150832Snetchildstatic void
1449150832Snetchildmd_post_Nm(struct roff_node *n)
1450150832Snetchild{
1451148591Snetchild	switch (n->type) {
1452150832Snetchild	case ROFFT_BLOCK:
1453148591Snetchild		outflags &= ~MD_Bk;
1454150832Snetchild		break;
1455150832Snetchild	case ROFFT_HEAD:
1456150832Snetchild	case ROFFT_ELEM:
1457148591Snetchild		md_post_raw(n);
1458150832Snetchild		break;
1459150832Snetchild	default:
1460150832Snetchild		break;
1461150832Snetchild	}
1462150832Snetchild}
1463150832Snetchild
1464150832Snetchildstatic int
1465150832Snetchildmd_pre_No(struct roff_node *n)
1466150832Snetchild{
1467150832Snetchild	outflags |= MD_spc_force;
1468150832Snetchild	return 1;
1469150832Snetchild}
1470152419Sariff
1471152419Sariffstatic int
1472150832Snetchildmd_pre_Ns(struct roff_node *n)
1473150832Snetchild{
1474170289Sdwmalone	outflags &= ~MD_spc;
1475164614Sariff	return 0;
1476150832Snetchild}
1477150832Snetchild
1478150832Snetchildstatic void
1479150832Snetchildmd_post_Pf(struct roff_node *n)
1480150832Snetchild{
1481150832Snetchild	if (n->next != NULL && (n->next->flags & NODE_LINE) == 0)
1482152419Sariff		outflags &= ~MD_spc;
1483152419Sariff}
1484152419Sariff
1485152419Sariffstatic int
1486150832Snetchildmd_pre_Pp(struct roff_node *n)
1487152419Sariff{
1488152419Sariff	outflags |= MD_sp;
1489152419Sariff	return 0;
1490152419Sariff}
1491152419Sariff
1492152419Sariffstatic int
1493152419Sariffmd_pre_Rs(struct roff_node *n)
1494152419Sariff{
1495152419Sariff	if (n->sec == SEC_SEE_ALSO)
1496152419Sariff		outflags |= MD_sp;
1497150832Snetchild	return 1;
1498152419Sariff}
1499152419Sariff
1500152419Sariffstatic int
1501150832Snetchildmd_pre_Sh(struct roff_node *n)
1502150832Snetchild{
1503150832Snetchild	switch (n->type) {
1504150832Snetchild	case ROFFT_BLOCK:
1505150832Snetchild		if (n->sec == SEC_AUTHORS)
1506152419Sariff			outflags &= ~(MD_An_split | MD_An_nosplit);
1507152419Sariff		break;
1508152419Sariff	case ROFFT_HEAD:
1509152419Sariff		outflags |= MD_sp;
1510152419Sariff		md_rawword(n->tok == MDOC_Sh ? "#" : "##");
1511152419Sariff		break;
1512152419Sariff	case ROFFT_BODY:
1513152419Sariff		outflags |= MD_sp;
1514152419Sariff		break;
1515152419Sariff	default:
1516152419Sariff		break;
1517152419Sariff	}
1518152419Sariff	return 1;
1519170815Sariff}
1520170815Sariff
1521152419Sariffstatic int
1522152419Sariffmd_pre_Sm(struct roff_node *n)
1523152419Sariff{
1524152419Sariff	if (n->child == NULL)
1525152419Sariff		outflags ^= MD_Sm;
1526152419Sariff	else if (strcmp("on", n->child->string) == 0)
1527152419Sariff		outflags |= MD_Sm;
1528152419Sariff	else
1529170289Sdwmalone		outflags &= ~MD_Sm;
1530164614Sariff
1531152419Sariff	if (outflags & MD_Sm)
1532152419Sariff		outflags |= MD_spc;
1533152419Sariff
1534152419Sariff	return 0;
1535152419Sariff}
1536152419Sariff
1537170815Sariffstatic int
1538170815Sariffmd_pre_Vt(struct roff_node *n)
1539170815Sariff{
1540170815Sariff	switch (n->type) {
1541170815Sariff	case ROFFT_BLOCK:
1542170815Sariff		md_pre_syn(n);
1543170815Sariff		return 1;
1544170815Sariff	case ROFFT_BODY:
1545152419Sariff	case ROFFT_ELEM:
1546170815Sariff		md_pre_raw(n);
1547170815Sariff		return 1;
1548170815Sariff	default:
1549170815Sariff		return 0;
1550170815Sariff	}
1551170815Sariff}
1552170815Sariff
1553152419Sariffstatic void
1554152419Sariffmd_post_Vt(struct roff_node *n)
1555152419Sariff{
1556152419Sariff	switch (n->type) {
1557170815Sariff	case ROFFT_BODY:
1558152419Sariff	case ROFFT_ELEM:
1559152419Sariff		md_post_raw(n);
1560164614Sariff		break;
1561152419Sariff	default:
1562164614Sariff		break;
1563152419Sariff	}
1564152419Sariff}
1565152419Sariff
1566170815Sariffstatic int
1567170815Sariffmd_pre_Xr(struct roff_node *n)
1568170815Sariff{
1569170815Sariff	n = n->child;
1570152419Sariff	if (n == NULL)
1571170815Sariff		return 0;
1572170815Sariff	md_node(n);
1573170815Sariff	n = n->next;
1574170815Sariff	if (n == NULL)
1575164614Sariff		return 0;
1576152419Sariff	outflags &= ~MD_spc;
1577152419Sariff	md_word("(");
1578152419Sariff	md_node(n);
1579152419Sariff	md_word(")");
1580152419Sariff	return 0;
1581152419Sariff}
1582152419Sariff
1583152419Sariffstatic int
1584170815Sariffmd_pre__T(struct roff_node *n)
1585152419Sariff{
1586170815Sariff	if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T)
1587170815Sariff		md_word("\"");
1588170815Sariff	else
1589152419Sariff		md_rawword("*");
1590152419Sariff	outflags &= ~MD_spc;
1591164614Sariff	return 1;
1592164614Sariff}
1593164614Sariff
1594164614Sariffstatic void
1595164614Sariffmd_post__T(struct roff_node *n)
1596164614Sariff{
1597164614Sariff	outflags &= ~MD_spc;
1598164614Sariff	if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T)
1599164614Sariff		md_word("\"");
1600164614Sariff	else
1601164614Sariff		md_rawword("*");
1602164614Sariff	md_post_pc(n);
1603164614Sariff}
1604164614Sariff
1605164614Sariffstatic int
1606170289Sdwmalonemd_pre_br(struct roff_node *n)
1607164614Sariff{
1608164614Sariff	outflags |= MD_br;
1609164614Sariff	return 0;
1610164614Sariff}
1611164614Sariff