Print this page
9718 update mandoc to 1.14.4
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/mandoc/mdoc_markdown.c
+++ new/usr/src/cmd/mandoc/mdoc_markdown.c
1 -/* $Id: mdoc_markdown.c,v 1.23 2017/06/14 01:31:26 schwarze Exp $ */
1 +/* $Id: mdoc_markdown.c,v 1.24 2018/04/11 17:11:13 schwarze Exp $ */
2 2 /*
3 3 * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
4 4 *
5 5 * Permission to use, copy, modify, and distribute this software for any
6 6 * purpose with or without fee is hereby granted, provided that the above
7 7 * copyright notice and this permission notice appear in all copies.
8 8 *
9 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
10 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
12 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 16 */
17 17 #include <sys/types.h>
18 18
19 19 #include <assert.h>
20 20 #include <ctype.h>
21 21 #include <stdio.h>
22 22 #include <string.h>
23 23
24 24 #include "mandoc_aux.h"
25 25 #include "mandoc.h"
26 26 #include "roff.h"
27 27 #include "mdoc.h"
28 28 #include "main.h"
29 29
30 30 struct md_act {
31 31 int (*cond)(struct roff_node *n);
32 32 int (*pre)(struct roff_node *n);
33 33 void (*post)(struct roff_node *n);
34 34 const char *prefix; /* pre-node string constant */
35 35 const char *suffix; /* post-node string constant */
36 36 };
37 37
38 38 static void md_nodelist(struct roff_node *);
39 39 static void md_node(struct roff_node *);
40 40 static const char *md_stack(char c);
41 41 static void md_preword(void);
42 42 static void md_rawword(const char *);
43 43 static void md_word(const char *);
44 44 static void md_named(const char *);
45 45 static void md_char(unsigned char);
46 46 static void md_uri(const char *);
47 47
48 48 static int md_cond_head(struct roff_node *);
49 49 static int md_cond_body(struct roff_node *);
50 50
51 51 static int md_pre_raw(struct roff_node *);
52 52 static int md_pre_word(struct roff_node *);
53 53 static int md_pre_skip(struct roff_node *);
54 54 static void md_pre_syn(struct roff_node *);
55 55 static int md_pre_An(struct roff_node *);
56 56 static int md_pre_Ap(struct roff_node *);
57 57 static int md_pre_Bd(struct roff_node *);
58 58 static int md_pre_Bk(struct roff_node *);
59 59 static int md_pre_Bl(struct roff_node *);
60 60 static int md_pre_D1(struct roff_node *);
61 61 static int md_pre_Dl(struct roff_node *);
62 62 static int md_pre_En(struct roff_node *);
63 63 static int md_pre_Eo(struct roff_node *);
64 64 static int md_pre_Fa(struct roff_node *);
65 65 static int md_pre_Fd(struct roff_node *);
66 66 static int md_pre_Fn(struct roff_node *);
67 67 static int md_pre_Fo(struct roff_node *);
68 68 static int md_pre_In(struct roff_node *);
69 69 static int md_pre_It(struct roff_node *);
70 70 static int md_pre_Lk(struct roff_node *);
71 71 static int md_pre_Mt(struct roff_node *);
72 72 static int md_pre_Nd(struct roff_node *);
73 73 static int md_pre_Nm(struct roff_node *);
74 74 static int md_pre_No(struct roff_node *);
75 75 static int md_pre_Ns(struct roff_node *);
76 76 static int md_pre_Pp(struct roff_node *);
77 77 static int md_pre_Rs(struct roff_node *);
78 78 static int md_pre_Sh(struct roff_node *);
79 79 static int md_pre_Sm(struct roff_node *);
80 80 static int md_pre_Vt(struct roff_node *);
81 81 static int md_pre_Xr(struct roff_node *);
82 82 static int md_pre__T(struct roff_node *);
83 83 static int md_pre_br(struct roff_node *);
84 84
85 85 static void md_post_raw(struct roff_node *);
86 86 static void md_post_word(struct roff_node *);
87 87 static void md_post_pc(struct roff_node *);
88 88 static void md_post_Bk(struct roff_node *);
89 89 static void md_post_Bl(struct roff_node *);
90 90 static void md_post_D1(struct roff_node *);
91 91 static void md_post_En(struct roff_node *);
92 92 static void md_post_Eo(struct roff_node *);
93 93 static void md_post_Fa(struct roff_node *);
94 94 static void md_post_Fd(struct roff_node *);
95 95 static void md_post_Fl(struct roff_node *);
96 96 static void md_post_Fn(struct roff_node *);
97 97 static void md_post_Fo(struct roff_node *);
98 98 static void md_post_In(struct roff_node *);
99 99 static void md_post_It(struct roff_node *);
100 100 static void md_post_Lb(struct roff_node *);
101 101 static void md_post_Nm(struct roff_node *);
102 102 static void md_post_Pf(struct roff_node *);
103 103 static void md_post_Vt(struct roff_node *);
104 104 static void md_post__T(struct roff_node *);
105 105
106 106 static const struct md_act __md_acts[MDOC_MAX - MDOC_Dd] = {
107 107 { NULL, NULL, NULL, NULL, NULL }, /* Dd */
108 108 { NULL, NULL, NULL, NULL, NULL }, /* Dt */
109 109 { NULL, NULL, NULL, NULL, NULL }, /* Os */
110 110 { NULL, md_pre_Sh, NULL, NULL, NULL }, /* Sh */
111 111 { NULL, md_pre_Sh, NULL, NULL, NULL }, /* Ss */
112 112 { NULL, md_pre_Pp, NULL, NULL, NULL }, /* Pp */
113 113 { md_cond_body, md_pre_D1, md_post_D1, NULL, NULL }, /* D1 */
114 114 { md_cond_body, md_pre_Dl, md_post_D1, NULL, NULL }, /* Dl */
115 115 { md_cond_body, md_pre_Bd, md_post_D1, NULL, NULL }, /* Bd */
116 116 { NULL, NULL, NULL, NULL, NULL }, /* Ed */
117 117 { md_cond_body, md_pre_Bl, md_post_Bl, NULL, NULL }, /* Bl */
118 118 { NULL, NULL, NULL, NULL, NULL }, /* El */
119 119 { NULL, md_pre_It, md_post_It, NULL, NULL }, /* It */
120 120 { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Ad */
121 121 { NULL, md_pre_An, NULL, NULL, NULL }, /* An */
122 122 { NULL, md_pre_Ap, NULL, NULL, NULL }, /* Ap */
123 123 { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Ar */
124 124 { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Cd */
125 125 { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Cm */
126 126 { NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Dv */
127 127 { NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Er */
128 128 { NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Ev */
129 129 { NULL, NULL, NULL, NULL, NULL }, /* Ex */
130 130 { NULL, md_pre_Fa, md_post_Fa, NULL, NULL }, /* Fa */
131 131 { NULL, md_pre_Fd, md_post_Fd, "**", "**" }, /* Fd */
132 132 { NULL, md_pre_raw, md_post_Fl, "**-", "**" }, /* Fl */
133 133 { NULL, md_pre_Fn, md_post_Fn, NULL, NULL }, /* Fn */
134 134 { NULL, md_pre_Fd, md_post_raw, "*", "*" }, /* Ft */
135 135 { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Ic */
136 136 { NULL, md_pre_In, md_post_In, NULL, NULL }, /* In */
137 137 { NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Li */
138 138 { md_cond_head, md_pre_Nd, NULL, NULL, NULL }, /* Nd */
139 139 { NULL, md_pre_Nm, md_post_Nm, "**", "**" }, /* Nm */
140 140 { md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Op */
141 141 { NULL, md_pre_Fd, md_post_raw, "*", "*" }, /* Ot */
142 142 { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Pa */
143 143 { NULL, NULL, NULL, NULL, NULL }, /* Rv */
144 144 { NULL, NULL, NULL, NULL, NULL }, /* St */
145 145 { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Va */
146 146 { NULL, md_pre_Vt, md_post_Vt, "*", "*" }, /* Vt */
147 147 { NULL, md_pre_Xr, NULL, NULL, NULL }, /* Xr */
148 148 { NULL, NULL, md_post_pc, NULL, NULL }, /* %A */
149 149 { NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %B */
150 150 { NULL, NULL, md_post_pc, NULL, NULL }, /* %D */
151 151 { NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %I */
152 152 { NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %J */
153 153 { NULL, NULL, md_post_pc, NULL, NULL }, /* %N */
154 154 { NULL, NULL, md_post_pc, NULL, NULL }, /* %O */
155 155 { NULL, NULL, md_post_pc, NULL, NULL }, /* %P */
156 156 { NULL, NULL, md_post_pc, NULL, NULL }, /* %R */
157 157 { NULL, md_pre__T, md_post__T, NULL, NULL }, /* %T */
158 158 { NULL, NULL, md_post_pc, NULL, NULL }, /* %V */
159 159 { NULL, NULL, NULL, NULL, NULL }, /* Ac */
160 160 { md_cond_body, md_pre_word, md_post_word, "<", ">" }, /* Ao */
161 161 { md_cond_body, md_pre_word, md_post_word, "<", ">" }, /* Aq */
162 162 { NULL, NULL, NULL, NULL, NULL }, /* At */
163 163 { NULL, NULL, NULL, NULL, NULL }, /* Bc */
164 164 { NULL, NULL, NULL, NULL, NULL }, /* Bf XXX not implemented */
165 165 { md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Bo */
166 166 { md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Bq */
167 167 { NULL, NULL, NULL, NULL, NULL }, /* Bsx */
168 168 { NULL, NULL, NULL, NULL, NULL }, /* Bx */
169 169 { NULL, NULL, NULL, NULL, NULL }, /* Db */
170 170 { NULL, NULL, NULL, NULL, NULL }, /* Dc */
171 171 { md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Do */
172 172 { md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Dq */
173 173 { NULL, NULL, NULL, NULL, NULL }, /* Ec */
174 174 { NULL, NULL, NULL, NULL, NULL }, /* Ef */
175 175 { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Em */
176 176 { md_cond_body, md_pre_Eo, md_post_Eo, NULL, NULL }, /* Eo */
177 177 { NULL, NULL, NULL, NULL, NULL }, /* Fx */
178 178 { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Ms */
179 179 { NULL, md_pre_No, NULL, NULL, NULL }, /* No */
180 180 { NULL, md_pre_Ns, NULL, NULL, NULL }, /* Ns */
181 181 { NULL, NULL, NULL, NULL, NULL }, /* Nx */
182 182 { NULL, NULL, NULL, NULL, NULL }, /* Ox */
183 183 { NULL, NULL, NULL, NULL, NULL }, /* Pc */
184 184 { NULL, NULL, md_post_Pf, NULL, NULL }, /* Pf */
185 185 { md_cond_body, md_pre_word, md_post_word, "(", ")" }, /* Po */
186 186 { md_cond_body, md_pre_word, md_post_word, "(", ")" }, /* Pq */
187 187 { NULL, NULL, NULL, NULL, NULL }, /* Qc */
188 188 { md_cond_body, md_pre_raw, md_post_raw, "'`", "`'" }, /* Ql */
189 189 { md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Qo */
190 190 { md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Qq */
191 191 { NULL, NULL, NULL, NULL, NULL }, /* Re */
192 192 { md_cond_body, md_pre_Rs, NULL, NULL, NULL }, /* Rs */
193 193 { NULL, NULL, NULL, NULL, NULL }, /* Sc */
194 194 { md_cond_body, md_pre_word, md_post_word, "'", "'" }, /* So */
195 195 { md_cond_body, md_pre_word, md_post_word, "'", "'" }, /* Sq */
196 196 { NULL, md_pre_Sm, NULL, NULL, NULL }, /* Sm */
197 197 { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Sx */
198 198 { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Sy */
199 199 { NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Tn */
200 200 { NULL, NULL, NULL, NULL, NULL }, /* Ux */
201 201 { NULL, NULL, NULL, NULL, NULL }, /* Xc */
202 202 { NULL, NULL, NULL, NULL, NULL }, /* Xo */
203 203 { NULL, md_pre_Fo, md_post_Fo, "**", "**" }, /* Fo */
204 204 { NULL, NULL, NULL, NULL, NULL }, /* Fc */
205 205 { md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Oo */
206 206 { NULL, NULL, NULL, NULL, NULL }, /* Oc */
207 207 { NULL, md_pre_Bk, md_post_Bk, NULL, NULL }, /* Bk */
208 208 { NULL, NULL, NULL, NULL, NULL }, /* Ek */
209 209 { NULL, NULL, NULL, NULL, NULL }, /* Bt */
210 210 { NULL, NULL, NULL, NULL, NULL }, /* Hf */
211 211 { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Fr */
212 212 { NULL, NULL, NULL, NULL, NULL }, /* Ud */
213 213 { NULL, NULL, md_post_Lb, NULL, NULL }, /* Lb */
214 214 { NULL, md_pre_Pp, NULL, NULL, NULL }, /* Lp */
215 215 { NULL, md_pre_Lk, NULL, NULL, NULL }, /* Lk */
216 216 { NULL, md_pre_Mt, NULL, NULL, NULL }, /* Mt */
217 217 { md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Brq */
218 218 { md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Bro */
219 219 { NULL, NULL, NULL, NULL, NULL }, /* Brc */
220 220 { NULL, NULL, md_post_pc, NULL, NULL }, /* %C */
221 221 { NULL, md_pre_skip, NULL, NULL, NULL }, /* Es */
222 222 { md_cond_body, md_pre_En, md_post_En, NULL, NULL }, /* En */
223 223 { NULL, NULL, NULL, NULL, NULL }, /* Dx */
224 224 { NULL, NULL, md_post_pc, NULL, NULL }, /* %Q */
225 225 { NULL, md_pre_Lk, md_post_pc, NULL, NULL }, /* %U */
226 226 { NULL, NULL, NULL, NULL, NULL }, /* Ta */
227 227 };
228 228 static const struct md_act *const md_acts = __md_acts - MDOC_Dd;
229 229
230 230 static int outflags;
231 231 #define MD_spc (1 << 0) /* Blank character before next word. */
232 232 #define MD_spc_force (1 << 1) /* Even before trailing punctuation. */
233 233 #define MD_nonl (1 << 2) /* Prevent linebreak in markdown code. */
234 234 #define MD_nl (1 << 3) /* Break markdown code line. */
235 235 #define MD_br (1 << 4) /* Insert an output line break. */
236 236 #define MD_sp (1 << 5) /* Insert a paragraph break. */
237 237 #define MD_Sm (1 << 6) /* Horizontal spacing mode. */
238 238 #define MD_Bk (1 << 7) /* Word keep mode. */
239 239 #define MD_An_split (1 << 8) /* Author mode is "split". */
240 240 #define MD_An_nosplit (1 << 9) /* Author mode is "nosplit". */
241 241
242 242 static int escflags; /* Escape in generated markdown code: */
243 243 #define ESC_BOL (1 << 0) /* "#*+-" near the beginning of a line. */
244 244 #define ESC_NUM (1 << 1) /* "." after a leading number. */
245 245 #define ESC_HYP (1 << 2) /* "(" immediately after "]". */
246 246 #define ESC_SQU (1 << 4) /* "]" when "[" is open. */
247 247 #define ESC_FON (1 << 5) /* "*" immediately after unrelated "*". */
248 248 #define ESC_EOL (1 << 6) /* " " at the and of a line. */
249 249
250 250 static int code_blocks, quote_blocks, list_blocks;
251 251 static int outcount;
252 252
253 253 void
254 254 markdown_mdoc(void *arg, const struct roff_man *mdoc)
255 255 {
256 256 outflags = MD_Sm;
257 257 md_word(mdoc->meta.title);
258 258 if (mdoc->meta.msec != NULL) {
259 259 outflags &= ~MD_spc;
260 260 md_word("(");
261 261 md_word(mdoc->meta.msec);
262 262 md_word(")");
263 263 }
264 264 md_word("-");
265 265 md_word(mdoc->meta.vol);
266 266 if (mdoc->meta.arch != NULL) {
267 267 md_word("(");
268 268 md_word(mdoc->meta.arch);
269 269 md_word(")");
270 270 }
271 271 outflags |= MD_sp;
272 272
273 273 md_nodelist(mdoc->first->child);
274 274
275 275 outflags |= MD_sp;
276 276 md_word(mdoc->meta.os);
277 277 md_word("-");
278 278 md_word(mdoc->meta.date);
279 279 putchar('\n');
280 280 }
281 281
282 282 static void
283 283 md_nodelist(struct roff_node *n)
284 284 {
285 285 while (n != NULL) {
286 286 md_node(n);
↓ open down ↓ |
275 lines elided |
↑ open up ↑ |
287 287 n = n->next;
288 288 }
289 289 }
290 290
291 291 static void
292 292 md_node(struct roff_node *n)
293 293 {
294 294 const struct md_act *act;
295 295 int cond, process_children;
296 296
297 - if (n->flags & NODE_NOPRT)
297 + if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
298 298 return;
299 299
300 300 if (outflags & MD_nonl)
301 301 outflags &= ~(MD_nl | MD_sp);
302 302 else if (outflags & MD_spc && n->flags & NODE_LINE)
303 303 outflags |= MD_nl;
304 304
305 305 act = NULL;
306 306 cond = 0;
307 307 process_children = 1;
308 308 n->flags &= ~NODE_ENDED;
309 309
310 310 if (n->type == ROFFT_TEXT) {
311 311 if (n->flags & NODE_DELIMC)
312 312 outflags &= ~(MD_spc | MD_spc_force);
313 313 else if (outflags & MD_Sm)
314 314 outflags |= MD_spc_force;
315 315 md_word(n->string);
316 316 if (n->flags & NODE_DELIMO)
317 317 outflags &= ~(MD_spc | MD_spc_force);
318 318 else if (outflags & MD_Sm)
319 319 outflags |= MD_spc;
320 320 } else if (n->tok < ROFF_MAX) {
321 321 switch (n->tok) {
322 322 case ROFF_br:
323 323 process_children = md_pre_br(n);
324 324 break;
325 325 case ROFF_sp:
326 326 process_children = md_pre_Pp(n);
327 327 break;
328 328 default:
329 329 process_children = 0;
330 330 break;
331 331 }
332 332 } else {
333 333 assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
334 334 act = md_acts + n->tok;
335 335 cond = act->cond == NULL || (*act->cond)(n);
336 336 if (cond && act->pre != NULL &&
337 337 (n->end == ENDBODY_NOT || n->child != NULL))
338 338 process_children = (*act->pre)(n);
339 339 }
340 340
341 341 if (process_children && n->child != NULL)
342 342 md_nodelist(n->child);
343 343
344 344 if (n->flags & NODE_ENDED)
345 345 return;
346 346
347 347 if (cond && act->post != NULL)
348 348 (*act->post)(n);
349 349
350 350 if (n->end != ENDBODY_NOT)
351 351 n->body->flags |= NODE_ENDED;
352 352 }
353 353
354 354 static const char *
355 355 md_stack(char c)
356 356 {
357 357 static char *stack;
358 358 static size_t sz;
359 359 static size_t cur;
360 360
361 361 switch (c) {
362 362 case '\0':
363 363 break;
364 364 case (char)-1:
365 365 assert(cur);
366 366 stack[--cur] = '\0';
367 367 break;
368 368 default:
369 369 if (cur + 1 >= sz) {
370 370 sz += 8;
371 371 stack = mandoc_realloc(stack, sz);
372 372 }
373 373 stack[cur] = c;
374 374 stack[++cur] = '\0';
375 375 break;
376 376 }
377 377 return stack == NULL ? "" : stack;
378 378 }
379 379
380 380 /*
381 381 * Handle vertical and horizontal spacing.
382 382 */
383 383 static void
384 384 md_preword(void)
385 385 {
386 386 const char *cp;
387 387
388 388 /*
389 389 * If a list block is nested inside a code block or a blockquote,
390 390 * blank lines for paragraph breaks no longer work; instead,
391 391 * they terminate the list. Work around this markdown issue
392 392 * by using mere line breaks instead.
393 393 */
394 394
395 395 if (list_blocks && outflags & MD_sp) {
396 396 outflags &= ~MD_sp;
397 397 outflags |= MD_br;
398 398 }
399 399
400 400 /*
401 401 * End the old line if requested.
402 402 * Escape whitespace at the end of the markdown line
403 403 * such that it won't look like an output line break.
404 404 */
405 405
406 406 if (outflags & MD_sp)
407 407 putchar('\n');
408 408 else if (outflags & MD_br) {
409 409 putchar(' ');
410 410 putchar(' ');
411 411 } else if (outflags & MD_nl && escflags & ESC_EOL)
412 412 md_named("zwnj");
413 413
414 414 /* Start a new line if necessary. */
415 415
416 416 if (outflags & (MD_nl | MD_br | MD_sp)) {
417 417 putchar('\n');
418 418 for (cp = md_stack('\0'); *cp != '\0'; cp++) {
419 419 putchar(*cp);
420 420 if (*cp == '>')
421 421 putchar(' ');
422 422 }
423 423 outflags &= ~(MD_nl | MD_br | MD_sp);
424 424 escflags = ESC_BOL;
425 425 outcount = 0;
426 426
427 427 /* Handle horizontal spacing. */
428 428
429 429 } else if (outflags & MD_spc) {
430 430 if (outflags & MD_Bk)
431 431 fputs(" ", stdout);
432 432 else
433 433 putchar(' ');
434 434 escflags &= ~ESC_FON;
435 435 outcount++;
436 436 }
437 437
438 438 outflags &= ~(MD_spc_force | MD_nonl);
439 439 if (outflags & MD_Sm)
440 440 outflags |= MD_spc;
441 441 else
442 442 outflags &= ~MD_spc;
443 443 }
444 444
445 445 /*
446 446 * Print markdown syntax elements.
447 447 * Can also be used for constant strings when neither escaping
448 448 * nor delimiter handling is required.
449 449 */
450 450 static void
451 451 md_rawword(const char *s)
452 452 {
453 453 md_preword();
454 454
455 455 if (*s == '\0')
456 456 return;
457 457
458 458 if (escflags & ESC_FON) {
459 459 escflags &= ~ESC_FON;
460 460 if (*s == '*' && !code_blocks)
461 461 fputs("‌", stdout);
462 462 }
463 463
464 464 while (*s != '\0') {
465 465 switch(*s) {
466 466 case '*':
467 467 if (s[1] == '\0')
468 468 escflags |= ESC_FON;
469 469 break;
470 470 case '[':
471 471 escflags |= ESC_SQU;
472 472 break;
473 473 case ']':
474 474 escflags |= ESC_HYP;
475 475 escflags &= ~ESC_SQU;
476 476 break;
477 477 default:
478 478 break;
479 479 }
480 480 md_char(*s++);
481 481 }
482 482 if (s[-1] == ' ')
483 483 escflags |= ESC_EOL;
484 484 else
485 485 escflags &= ~ESC_EOL;
486 486 }
487 487
488 488 /*
489 489 * Print text and mdoc(7) syntax elements.
490 490 */
491 491 static void
492 492 md_word(const char *s)
493 493 {
494 494 const char *seq, *prevfont, *currfont, *nextfont;
495 495 char c;
496 496 int bs, sz, uc, breakline;
497 497
498 498 /* No spacing before closing delimiters. */
499 499 if (s[0] != '\0' && s[1] == '\0' &&
500 500 strchr("!),.:;?]", s[0]) != NULL &&
501 501 (outflags & MD_spc_force) == 0)
502 502 outflags &= ~MD_spc;
503 503
504 504 md_preword();
505 505
506 506 if (*s == '\0')
507 507 return;
508 508
509 509 /* No spacing after opening delimiters. */
510 510 if ((s[0] == '(' || s[0] == '[') && s[1] == '\0')
511 511 outflags &= ~MD_spc;
512 512
513 513 breakline = 0;
514 514 prevfont = currfont = "";
515 515 while ((c = *s++) != '\0') {
516 516 bs = 0;
517 517 switch(c) {
518 518 case ASCII_NBRSP:
519 519 if (code_blocks)
520 520 c = ' ';
521 521 else {
522 522 md_named("nbsp");
523 523 c = '\0';
524 524 }
525 525 break;
526 526 case ASCII_HYPH:
527 527 bs = escflags & ESC_BOL && !code_blocks;
528 528 c = '-';
529 529 break;
530 530 case ASCII_BREAK:
531 531 continue;
532 532 case '#':
533 533 case '+':
534 534 case '-':
535 535 bs = escflags & ESC_BOL && !code_blocks;
536 536 break;
537 537 case '(':
538 538 bs = escflags & ESC_HYP && !code_blocks;
539 539 break;
540 540 case ')':
541 541 bs = escflags & ESC_NUM && !code_blocks;
542 542 break;
543 543 case '*':
544 544 case '[':
545 545 case '_':
546 546 case '`':
547 547 bs = !code_blocks;
548 548 break;
549 549 case '.':
550 550 bs = escflags & ESC_NUM && !code_blocks;
551 551 break;
552 552 case '<':
553 553 if (code_blocks == 0) {
554 554 md_named("lt");
555 555 c = '\0';
556 556 }
557 557 break;
558 558 case '=':
559 559 if (escflags & ESC_BOL && !code_blocks) {
560 560 md_named("equals");
561 561 c = '\0';
562 562 }
563 563 break;
564 564 case '>':
565 565 if (code_blocks == 0) {
566 566 md_named("gt");
567 567 c = '\0';
568 568 }
569 569 break;
570 570 case '\\':
571 571 uc = 0;
572 572 nextfont = NULL;
573 573 switch (mandoc_escape(&s, &seq, &sz)) {
574 574 case ESCAPE_UNICODE:
575 575 uc = mchars_num2uc(seq + 1, sz - 1);
576 576 break;
577 577 case ESCAPE_NUMBERED:
578 578 uc = mchars_num2char(seq, sz);
579 579 break;
580 580 case ESCAPE_SPECIAL:
581 581 uc = mchars_spec2cp(seq, sz);
582 582 break;
583 583 case ESCAPE_FONTBOLD:
584 584 nextfont = "**";
585 585 break;
586 586 case ESCAPE_FONTITALIC:
587 587 nextfont = "*";
588 588 break;
589 589 case ESCAPE_FONTBI:
590 590 nextfont = "***";
591 591 break;
592 592 case ESCAPE_FONT:
593 593 case ESCAPE_FONTROMAN:
594 594 nextfont = "";
595 595 break;
596 596 case ESCAPE_FONTPREV:
597 597 nextfont = prevfont;
598 598 break;
599 599 case ESCAPE_BREAK:
600 600 breakline = 1;
601 601 break;
602 602 case ESCAPE_NOSPACE:
603 603 case ESCAPE_SKIPCHAR:
604 604 case ESCAPE_OVERSTRIKE:
605 605 /* XXX not implemented */
606 606 /* FALLTHROUGH */
607 607 case ESCAPE_ERROR:
608 608 default:
609 609 break;
610 610 }
611 611 if (nextfont != NULL && !code_blocks) {
612 612 if (*currfont != '\0') {
613 613 outflags &= ~MD_spc;
614 614 md_rawword(currfont);
615 615 }
616 616 prevfont = currfont;
617 617 currfont = nextfont;
618 618 if (*currfont != '\0') {
619 619 outflags &= ~MD_spc;
620 620 md_rawword(currfont);
621 621 }
622 622 }
623 623 if (uc) {
624 624 if ((uc < 0x20 && uc != 0x09) ||
625 625 (uc > 0x7E && uc < 0xA0))
626 626 uc = 0xFFFD;
627 627 if (code_blocks) {
628 628 seq = mchars_uc2str(uc);
629 629 fputs(seq, stdout);
630 630 outcount += strlen(seq);
631 631 } else {
632 632 printf("&#%d;", uc);
633 633 outcount++;
634 634 }
635 635 escflags &= ~ESC_FON;
636 636 }
637 637 c = '\0';
638 638 break;
639 639 case ']':
640 640 bs = escflags & ESC_SQU && !code_blocks;
641 641 escflags |= ESC_HYP;
642 642 break;
643 643 default:
644 644 break;
645 645 }
646 646 if (bs)
647 647 putchar('\\');
648 648 md_char(c);
649 649 if (breakline &&
650 650 (*s == '\0' || *s == ' ' || *s == ASCII_NBRSP)) {
651 651 printf(" \n");
652 652 breakline = 0;
653 653 while (*s == ' ' || *s == ASCII_NBRSP)
654 654 s++;
655 655 }
656 656 }
657 657 if (*currfont != '\0') {
658 658 outflags &= ~MD_spc;
659 659 md_rawword(currfont);
660 660 } else if (s[-2] == ' ')
661 661 escflags |= ESC_EOL;
662 662 else
663 663 escflags &= ~ESC_EOL;
664 664 }
665 665
666 666 /*
667 667 * Print a single HTML named character reference.
668 668 */
669 669 static void
670 670 md_named(const char *s)
671 671 {
672 672 printf("&%s;", s);
673 673 escflags &= ~(ESC_FON | ESC_EOL);
674 674 outcount++;
675 675 }
676 676
677 677 /*
678 678 * Print a single raw character and maintain certain escape flags.
679 679 */
680 680 static void
681 681 md_char(unsigned char c)
682 682 {
683 683 if (c != '\0') {
684 684 putchar(c);
685 685 if (c == '*')
686 686 escflags |= ESC_FON;
687 687 else
688 688 escflags &= ~ESC_FON;
689 689 outcount++;
690 690 }
691 691 if (c != ']')
692 692 escflags &= ~ESC_HYP;
693 693 if (c == ' ' || c == '\t' || c == '>')
694 694 return;
695 695 if (isdigit(c) == 0)
696 696 escflags &= ~ESC_NUM;
697 697 else if (escflags & ESC_BOL)
698 698 escflags |= ESC_NUM;
699 699 escflags &= ~ESC_BOL;
700 700 }
701 701
702 702 static int
703 703 md_cond_head(struct roff_node *n)
704 704 {
705 705 return n->type == ROFFT_HEAD;
706 706 }
707 707
708 708 static int
709 709 md_cond_body(struct roff_node *n)
710 710 {
711 711 return n->type == ROFFT_BODY;
712 712 }
713 713
714 714 static int
715 715 md_pre_raw(struct roff_node *n)
716 716 {
717 717 const char *prefix;
718 718
719 719 if ((prefix = md_acts[n->tok].prefix) != NULL) {
720 720 md_rawword(prefix);
721 721 outflags &= ~MD_spc;
722 722 if (*prefix == '`')
723 723 code_blocks++;
724 724 }
725 725 return 1;
726 726 }
727 727
728 728 static void
729 729 md_post_raw(struct roff_node *n)
730 730 {
731 731 const char *suffix;
732 732
733 733 if ((suffix = md_acts[n->tok].suffix) != NULL) {
734 734 outflags &= ~(MD_spc | MD_nl);
735 735 md_rawword(suffix);
736 736 if (*suffix == '`')
737 737 code_blocks--;
738 738 }
739 739 }
740 740
741 741 static int
742 742 md_pre_word(struct roff_node *n)
743 743 {
744 744 const char *prefix;
745 745
746 746 if ((prefix = md_acts[n->tok].prefix) != NULL) {
747 747 md_word(prefix);
748 748 outflags &= ~MD_spc;
749 749 }
750 750 return 1;
751 751 }
752 752
753 753 static void
754 754 md_post_word(struct roff_node *n)
755 755 {
756 756 const char *suffix;
757 757
758 758 if ((suffix = md_acts[n->tok].suffix) != NULL) {
759 759 outflags &= ~(MD_spc | MD_nl);
760 760 md_word(suffix);
761 761 }
762 762 }
763 763
764 764 static void
765 765 md_post_pc(struct roff_node *n)
766 766 {
767 767 md_post_raw(n);
768 768 if (n->parent->tok != MDOC_Rs)
769 769 return;
770 770 if (n->next != NULL) {
771 771 md_word(",");
772 772 if (n->prev != NULL &&
773 773 n->prev->tok == n->tok &&
774 774 n->next->tok == n->tok)
775 775 md_word("and");
776 776 } else {
777 777 md_word(".");
778 778 outflags |= MD_nl;
779 779 }
780 780 }
781 781
782 782 static int
783 783 md_pre_skip(struct roff_node *n)
784 784 {
785 785 return 0;
786 786 }
787 787
788 788 static void
789 789 md_pre_syn(struct roff_node *n)
790 790 {
791 791 if (n->prev == NULL || ! (n->flags & NODE_SYNPRETTY))
792 792 return;
793 793
794 794 if (n->prev->tok == n->tok &&
795 795 n->tok != MDOC_Ft &&
796 796 n->tok != MDOC_Fo &&
797 797 n->tok != MDOC_Fn) {
798 798 outflags |= MD_br;
799 799 return;
800 800 }
801 801
802 802 switch (n->prev->tok) {
803 803 case MDOC_Fd:
804 804 case MDOC_Fn:
805 805 case MDOC_Fo:
806 806 case MDOC_In:
807 807 case MDOC_Vt:
808 808 outflags |= MD_sp;
809 809 break;
810 810 case MDOC_Ft:
811 811 if (n->tok != MDOC_Fn && n->tok != MDOC_Fo) {
812 812 outflags |= MD_sp;
813 813 break;
814 814 }
815 815 /* FALLTHROUGH */
816 816 default:
817 817 outflags |= MD_br;
818 818 break;
819 819 }
820 820 }
821 821
822 822 static int
823 823 md_pre_An(struct roff_node *n)
824 824 {
825 825 switch (n->norm->An.auth) {
826 826 case AUTH_split:
827 827 outflags &= ~MD_An_nosplit;
828 828 outflags |= MD_An_split;
829 829 return 0;
830 830 case AUTH_nosplit:
831 831 outflags &= ~MD_An_split;
832 832 outflags |= MD_An_nosplit;
833 833 return 0;
834 834 default:
835 835 if (outflags & MD_An_split)
836 836 outflags |= MD_br;
837 837 else if (n->sec == SEC_AUTHORS &&
838 838 ! (outflags & MD_An_nosplit))
839 839 outflags |= MD_An_split;
840 840 return 1;
841 841 }
842 842 }
843 843
844 844 static int
845 845 md_pre_Ap(struct roff_node *n)
846 846 {
847 847 outflags &= ~MD_spc;
848 848 md_word("'");
849 849 outflags &= ~MD_spc;
850 850 return 0;
851 851 }
852 852
853 853 static int
854 854 md_pre_Bd(struct roff_node *n)
855 855 {
856 856 switch (n->norm->Bd.type) {
857 857 case DISP_unfilled:
858 858 case DISP_literal:
859 859 return md_pre_Dl(n);
860 860 default:
861 861 return md_pre_D1(n);
862 862 }
863 863 }
864 864
865 865 static int
866 866 md_pre_Bk(struct roff_node *n)
867 867 {
868 868 switch (n->type) {
869 869 case ROFFT_BLOCK:
870 870 return 1;
871 871 case ROFFT_BODY:
872 872 outflags |= MD_Bk;
873 873 return 1;
874 874 default:
875 875 return 0;
876 876 }
877 877 }
878 878
879 879 static void
880 880 md_post_Bk(struct roff_node *n)
881 881 {
882 882 if (n->type == ROFFT_BODY)
883 883 outflags &= ~MD_Bk;
884 884 }
885 885
886 886 static int
887 887 md_pre_Bl(struct roff_node *n)
888 888 {
889 889 n->norm->Bl.count = 0;
890 890 if (n->norm->Bl.type == LIST_column)
891 891 md_pre_Dl(n);
892 892 outflags |= MD_sp;
893 893 return 1;
894 894 }
895 895
896 896 static void
897 897 md_post_Bl(struct roff_node *n)
898 898 {
899 899 n->norm->Bl.count = 0;
900 900 if (n->norm->Bl.type == LIST_column)
901 901 md_post_D1(n);
902 902 outflags |= MD_sp;
903 903 }
904 904
905 905 static int
906 906 md_pre_D1(struct roff_node *n)
907 907 {
908 908 /*
909 909 * Markdown blockquote syntax does not work inside code blocks.
910 910 * The best we can do is fall back to another nested code block.
911 911 */
912 912 if (code_blocks) {
913 913 md_stack('\t');
914 914 code_blocks++;
915 915 } else {
916 916 md_stack('>');
917 917 quote_blocks++;
918 918 }
919 919 outflags |= MD_sp;
920 920 return 1;
921 921 }
922 922
923 923 static void
924 924 md_post_D1(struct roff_node *n)
925 925 {
926 926 md_stack((char)-1);
927 927 if (code_blocks)
928 928 code_blocks--;
929 929 else
930 930 quote_blocks--;
931 931 outflags |= MD_sp;
932 932 }
933 933
934 934 static int
935 935 md_pre_Dl(struct roff_node *n)
936 936 {
937 937 /*
938 938 * Markdown code block syntax does not work inside blockquotes.
939 939 * The best we can do is fall back to another nested blockquote.
940 940 */
941 941 if (quote_blocks) {
942 942 md_stack('>');
943 943 quote_blocks++;
944 944 } else {
945 945 md_stack('\t');
946 946 code_blocks++;
947 947 }
948 948 outflags |= MD_sp;
949 949 return 1;
950 950 }
951 951
952 952 static int
953 953 md_pre_En(struct roff_node *n)
954 954 {
955 955 if (n->norm->Es == NULL ||
956 956 n->norm->Es->child == NULL)
957 957 return 1;
958 958
959 959 md_word(n->norm->Es->child->string);
960 960 outflags &= ~MD_spc;
961 961 return 1;
962 962 }
963 963
964 964 static void
965 965 md_post_En(struct roff_node *n)
966 966 {
967 967 if (n->norm->Es == NULL ||
968 968 n->norm->Es->child == NULL ||
969 969 n->norm->Es->child->next == NULL)
970 970 return;
971 971
972 972 outflags &= ~MD_spc;
973 973 md_word(n->norm->Es->child->next->string);
974 974 }
975 975
976 976 static int
977 977 md_pre_Eo(struct roff_node *n)
978 978 {
979 979 if (n->end == ENDBODY_NOT &&
980 980 n->parent->head->child == NULL &&
981 981 n->child != NULL &&
982 982 n->child->end != ENDBODY_NOT)
983 983 md_preword();
984 984 else if (n->end != ENDBODY_NOT ? n->child != NULL :
985 985 n->parent->head->child != NULL && (n->child != NULL ||
986 986 (n->parent->tail != NULL && n->parent->tail->child != NULL)))
987 987 outflags &= ~(MD_spc | MD_nl);
988 988 return 1;
989 989 }
990 990
991 991 static void
992 992 md_post_Eo(struct roff_node *n)
993 993 {
994 994 if (n->end != ENDBODY_NOT) {
995 995 outflags |= MD_spc;
996 996 return;
997 997 }
998 998
999 999 if (n->child == NULL && n->parent->head->child == NULL)
1000 1000 return;
1001 1001
1002 1002 if (n->parent->tail != NULL && n->parent->tail->child != NULL)
1003 1003 outflags &= ~MD_spc;
1004 1004 else
1005 1005 outflags |= MD_spc;
1006 1006 }
1007 1007
1008 1008 static int
1009 1009 md_pre_Fa(struct roff_node *n)
1010 1010 {
1011 1011 int am_Fa;
1012 1012
1013 1013 am_Fa = n->tok == MDOC_Fa;
1014 1014
1015 1015 if (am_Fa)
1016 1016 n = n->child;
1017 1017
1018 1018 while (n != NULL) {
1019 1019 md_rawword("*");
1020 1020 outflags &= ~MD_spc;
1021 1021 md_node(n);
1022 1022 outflags &= ~MD_spc;
1023 1023 md_rawword("*");
1024 1024 if ((n = n->next) != NULL)
1025 1025 md_word(",");
1026 1026 }
1027 1027 return 0;
1028 1028 }
1029 1029
1030 1030 static void
1031 1031 md_post_Fa(struct roff_node *n)
1032 1032 {
1033 1033 if (n->next != NULL && n->next->tok == MDOC_Fa)
1034 1034 md_word(",");
1035 1035 }
1036 1036
1037 1037 static int
1038 1038 md_pre_Fd(struct roff_node *n)
1039 1039 {
1040 1040 md_pre_syn(n);
1041 1041 md_pre_raw(n);
1042 1042 return 1;
1043 1043 }
1044 1044
1045 1045 static void
1046 1046 md_post_Fd(struct roff_node *n)
1047 1047 {
1048 1048 md_post_raw(n);
1049 1049 outflags |= MD_br;
1050 1050 }
1051 1051
1052 1052 static void
1053 1053 md_post_Fl(struct roff_node *n)
1054 1054 {
1055 1055 md_post_raw(n);
1056 1056 if (n->child == NULL && n->next != NULL &&
1057 1057 n->next->type != ROFFT_TEXT && !(n->next->flags & NODE_LINE))
1058 1058 outflags &= ~MD_spc;
1059 1059 }
1060 1060
1061 1061 static int
1062 1062 md_pre_Fn(struct roff_node *n)
1063 1063 {
1064 1064 md_pre_syn(n);
1065 1065
1066 1066 if ((n = n->child) == NULL)
1067 1067 return 0;
1068 1068
1069 1069 md_rawword("**");
1070 1070 outflags &= ~MD_spc;
1071 1071 md_node(n);
1072 1072 outflags &= ~MD_spc;
1073 1073 md_rawword("**");
1074 1074 outflags &= ~MD_spc;
1075 1075 md_word("(");
1076 1076
1077 1077 if ((n = n->next) != NULL)
1078 1078 md_pre_Fa(n);
1079 1079 return 0;
1080 1080 }
1081 1081
1082 1082 static void
1083 1083 md_post_Fn(struct roff_node *n)
1084 1084 {
1085 1085 md_word(")");
1086 1086 if (n->flags & NODE_SYNPRETTY) {
1087 1087 md_word(";");
1088 1088 outflags |= MD_sp;
1089 1089 }
1090 1090 }
1091 1091
1092 1092 static int
1093 1093 md_pre_Fo(struct roff_node *n)
1094 1094 {
1095 1095 switch (n->type) {
1096 1096 case ROFFT_BLOCK:
1097 1097 md_pre_syn(n);
1098 1098 break;
1099 1099 case ROFFT_HEAD:
1100 1100 if (n->child == NULL)
1101 1101 return 0;
1102 1102 md_pre_raw(n);
1103 1103 break;
1104 1104 case ROFFT_BODY:
1105 1105 outflags &= ~(MD_spc | MD_nl);
1106 1106 md_word("(");
1107 1107 break;
1108 1108 default:
1109 1109 break;
1110 1110 }
1111 1111 return 1;
1112 1112 }
1113 1113
1114 1114 static void
1115 1115 md_post_Fo(struct roff_node *n)
1116 1116 {
1117 1117 switch (n->type) {
1118 1118 case ROFFT_HEAD:
1119 1119 if (n->child != NULL)
1120 1120 md_post_raw(n);
1121 1121 break;
1122 1122 case ROFFT_BODY:
1123 1123 md_post_Fn(n);
1124 1124 break;
1125 1125 default:
1126 1126 break;
1127 1127 }
1128 1128 }
1129 1129
1130 1130 static int
1131 1131 md_pre_In(struct roff_node *n)
1132 1132 {
1133 1133 if (n->flags & NODE_SYNPRETTY) {
1134 1134 md_pre_syn(n);
1135 1135 md_rawword("**");
1136 1136 outflags &= ~MD_spc;
1137 1137 md_word("#include <");
1138 1138 } else {
1139 1139 md_word("<");
1140 1140 outflags &= ~MD_spc;
1141 1141 md_rawword("*");
1142 1142 }
1143 1143 outflags &= ~MD_spc;
1144 1144 return 1;
1145 1145 }
1146 1146
1147 1147 static void
1148 1148 md_post_In(struct roff_node *n)
1149 1149 {
1150 1150 if (n->flags & NODE_SYNPRETTY) {
1151 1151 outflags &= ~MD_spc;
1152 1152 md_rawword(">**");
1153 1153 outflags |= MD_nl;
1154 1154 } else {
1155 1155 outflags &= ~MD_spc;
1156 1156 md_rawword("*>");
1157 1157 }
1158 1158 }
1159 1159
1160 1160 static int
1161 1161 md_pre_It(struct roff_node *n)
1162 1162 {
1163 1163 struct roff_node *bln;
1164 1164
1165 1165 switch (n->type) {
1166 1166 case ROFFT_BLOCK:
1167 1167 return 1;
1168 1168
1169 1169 case ROFFT_HEAD:
1170 1170 bln = n->parent->parent;
1171 1171 if (bln->norm->Bl.comp == 0 &&
1172 1172 bln->norm->Bl.type != LIST_column)
1173 1173 outflags |= MD_sp;
1174 1174 outflags |= MD_nl;
1175 1175
1176 1176 switch (bln->norm->Bl.type) {
1177 1177 case LIST_item:
1178 1178 outflags |= MD_br;
1179 1179 return 0;
1180 1180 case LIST_inset:
1181 1181 case LIST_diag:
1182 1182 case LIST_ohang:
1183 1183 outflags |= MD_br;
1184 1184 return 1;
1185 1185 case LIST_tag:
1186 1186 case LIST_hang:
1187 1187 outflags |= MD_sp;
1188 1188 return 1;
1189 1189 case LIST_bullet:
1190 1190 md_rawword("*\t");
1191 1191 break;
1192 1192 case LIST_dash:
1193 1193 case LIST_hyphen:
1194 1194 md_rawword("-\t");
1195 1195 break;
1196 1196 case LIST_enum:
1197 1197 md_preword();
1198 1198 if (bln->norm->Bl.count < 99)
1199 1199 bln->norm->Bl.count++;
1200 1200 printf("%d.\t", bln->norm->Bl.count);
1201 1201 escflags &= ~ESC_FON;
1202 1202 break;
1203 1203 case LIST_column:
1204 1204 outflags |= MD_br;
1205 1205 return 0;
1206 1206 default:
1207 1207 return 0;
1208 1208 }
1209 1209 outflags &= ~MD_spc;
1210 1210 outflags |= MD_nonl;
1211 1211 outcount = 0;
1212 1212 md_stack('\t');
1213 1213 if (code_blocks || quote_blocks)
1214 1214 list_blocks++;
1215 1215 return 0;
1216 1216
1217 1217 case ROFFT_BODY:
1218 1218 bln = n->parent->parent;
1219 1219 switch (bln->norm->Bl.type) {
1220 1220 case LIST_ohang:
1221 1221 outflags |= MD_br;
1222 1222 break;
1223 1223 case LIST_tag:
1224 1224 case LIST_hang:
1225 1225 md_pre_D1(n);
1226 1226 break;
1227 1227 default:
1228 1228 break;
1229 1229 }
1230 1230 return 1;
1231 1231
1232 1232 default:
1233 1233 return 0;
1234 1234 }
1235 1235 }
1236 1236
1237 1237 static void
1238 1238 md_post_It(struct roff_node *n)
1239 1239 {
1240 1240 struct roff_node *bln;
1241 1241 int i, nc;
1242 1242
1243 1243 if (n->type != ROFFT_BODY)
1244 1244 return;
1245 1245
1246 1246 bln = n->parent->parent;
1247 1247 switch (bln->norm->Bl.type) {
1248 1248 case LIST_bullet:
1249 1249 case LIST_dash:
1250 1250 case LIST_hyphen:
1251 1251 case LIST_enum:
1252 1252 md_stack((char)-1);
1253 1253 if (code_blocks || quote_blocks)
1254 1254 list_blocks--;
1255 1255 break;
1256 1256 case LIST_tag:
1257 1257 case LIST_hang:
1258 1258 md_post_D1(n);
1259 1259 break;
1260 1260
1261 1261 case LIST_column:
1262 1262 if (n->next == NULL)
1263 1263 break;
1264 1264
1265 1265 /* Calculate the array index of the current column. */
1266 1266
1267 1267 i = 0;
1268 1268 while ((n = n->prev) != NULL && n->type != ROFFT_HEAD)
1269 1269 i++;
1270 1270
1271 1271 /*
1272 1272 * If a width was specified for this column,
1273 1273 * subtract what printed, and
1274 1274 * add the same spacing as in mdoc_term.c.
1275 1275 */
1276 1276
1277 1277 nc = bln->norm->Bl.ncols;
1278 1278 i = i < nc ? strlen(bln->norm->Bl.cols[i]) - outcount +
1279 1279 (nc < 5 ? 4 : nc == 5 ? 3 : 1) : 1;
1280 1280 if (i < 1)
1281 1281 i = 1;
1282 1282 while (i-- > 0)
1283 1283 putchar(' ');
1284 1284
1285 1285 outflags &= ~MD_spc;
1286 1286 escflags &= ~ESC_FON;
1287 1287 outcount = 0;
1288 1288 break;
1289 1289
1290 1290 default:
1291 1291 break;
1292 1292 }
1293 1293 }
1294 1294
1295 1295 static void
1296 1296 md_post_Lb(struct roff_node *n)
1297 1297 {
1298 1298 if (n->sec == SEC_LIBRARY)
1299 1299 outflags |= MD_br;
1300 1300 }
1301 1301
1302 1302 static void
1303 1303 md_uri(const char *s)
1304 1304 {
1305 1305 while (*s != '\0') {
1306 1306 if (strchr("%()<>", *s) != NULL) {
1307 1307 printf("%%%2.2hhX", *s);
1308 1308 outcount += 3;
1309 1309 } else {
1310 1310 putchar(*s);
1311 1311 outcount++;
1312 1312 }
1313 1313 s++;
1314 1314 }
1315 1315 }
1316 1316
1317 1317 static int
1318 1318 md_pre_Lk(struct roff_node *n)
1319 1319 {
1320 1320 const struct roff_node *link, *descr, *punct;
1321 1321
1322 1322 if ((link = n->child) == NULL)
1323 1323 return 0;
1324 1324
1325 1325 /* Find beginning of trailing punctuation. */
1326 1326 punct = n->last;
1327 1327 while (punct != link && punct->flags & NODE_DELIMC)
1328 1328 punct = punct->prev;
1329 1329 punct = punct->next;
1330 1330
1331 1331 /* Link text. */
1332 1332 descr = link->next;
1333 1333 if (descr == punct)
1334 1334 descr = link; /* no text */
1335 1335 md_rawword("[");
1336 1336 outflags &= ~MD_spc;
1337 1337 do {
1338 1338 md_word(descr->string);
1339 1339 descr = descr->next;
1340 1340 } while (descr != punct);
1341 1341 outflags &= ~MD_spc;
1342 1342
1343 1343 /* Link target. */
1344 1344 md_rawword("](");
1345 1345 md_uri(link->string);
1346 1346 outflags &= ~MD_spc;
1347 1347 md_rawword(")");
1348 1348
1349 1349 /* Trailing punctuation. */
1350 1350 while (punct != NULL) {
1351 1351 md_word(punct->string);
1352 1352 punct = punct->next;
1353 1353 }
1354 1354 return 0;
1355 1355 }
1356 1356
1357 1357 static int
1358 1358 md_pre_Mt(struct roff_node *n)
1359 1359 {
1360 1360 const struct roff_node *nch;
1361 1361
1362 1362 md_rawword("[");
1363 1363 outflags &= ~MD_spc;
1364 1364 for (nch = n->child; nch != NULL; nch = nch->next)
1365 1365 md_word(nch->string);
1366 1366 outflags &= ~MD_spc;
1367 1367 md_rawword("](mailto:");
1368 1368 for (nch = n->child; nch != NULL; nch = nch->next) {
1369 1369 md_uri(nch->string);
1370 1370 if (nch->next != NULL) {
1371 1371 putchar(' ');
1372 1372 outcount++;
1373 1373 }
1374 1374 }
1375 1375 outflags &= ~MD_spc;
1376 1376 md_rawword(")");
1377 1377 return 0;
1378 1378 }
1379 1379
1380 1380 static int
1381 1381 md_pre_Nd(struct roff_node *n)
1382 1382 {
1383 1383 outflags &= ~MD_nl;
1384 1384 outflags |= MD_spc;
1385 1385 md_word("-");
1386 1386 return 1;
1387 1387 }
1388 1388
1389 1389 static int
1390 1390 md_pre_Nm(struct roff_node *n)
1391 1391 {
1392 1392 switch (n->type) {
1393 1393 case ROFFT_BLOCK:
1394 1394 outflags |= MD_Bk;
1395 1395 md_pre_syn(n);
1396 1396 break;
1397 1397 case ROFFT_HEAD:
1398 1398 case ROFFT_ELEM:
1399 1399 md_pre_raw(n);
1400 1400 break;
1401 1401 default:
1402 1402 break;
1403 1403 }
1404 1404 return 1;
1405 1405 }
1406 1406
1407 1407 static void
1408 1408 md_post_Nm(struct roff_node *n)
1409 1409 {
1410 1410 switch (n->type) {
1411 1411 case ROFFT_BLOCK:
1412 1412 outflags &= ~MD_Bk;
1413 1413 break;
1414 1414 case ROFFT_HEAD:
1415 1415 case ROFFT_ELEM:
1416 1416 md_post_raw(n);
1417 1417 break;
1418 1418 default:
1419 1419 break;
1420 1420 }
1421 1421 }
1422 1422
1423 1423 static int
1424 1424 md_pre_No(struct roff_node *n)
1425 1425 {
1426 1426 outflags |= MD_spc_force;
1427 1427 return 1;
1428 1428 }
1429 1429
1430 1430 static int
1431 1431 md_pre_Ns(struct roff_node *n)
1432 1432 {
1433 1433 outflags &= ~MD_spc;
1434 1434 return 0;
1435 1435 }
1436 1436
1437 1437 static void
1438 1438 md_post_Pf(struct roff_node *n)
1439 1439 {
1440 1440 if (n->next != NULL && (n->next->flags & NODE_LINE) == 0)
1441 1441 outflags &= ~MD_spc;
1442 1442 }
1443 1443
1444 1444 static int
1445 1445 md_pre_Pp(struct roff_node *n)
1446 1446 {
1447 1447 outflags |= MD_sp;
1448 1448 return 0;
1449 1449 }
1450 1450
1451 1451 static int
1452 1452 md_pre_Rs(struct roff_node *n)
1453 1453 {
1454 1454 if (n->sec == SEC_SEE_ALSO)
1455 1455 outflags |= MD_sp;
1456 1456 return 1;
1457 1457 }
1458 1458
1459 1459 static int
1460 1460 md_pre_Sh(struct roff_node *n)
1461 1461 {
1462 1462 switch (n->type) {
1463 1463 case ROFFT_BLOCK:
1464 1464 if (n->sec == SEC_AUTHORS)
1465 1465 outflags &= ~(MD_An_split | MD_An_nosplit);
1466 1466 break;
1467 1467 case ROFFT_HEAD:
1468 1468 outflags |= MD_sp;
1469 1469 md_rawword(n->tok == MDOC_Sh ? "#" : "##");
1470 1470 break;
1471 1471 case ROFFT_BODY:
1472 1472 outflags |= MD_sp;
1473 1473 break;
1474 1474 default:
1475 1475 break;
1476 1476 }
1477 1477 return 1;
1478 1478 }
1479 1479
1480 1480 static int
1481 1481 md_pre_Sm(struct roff_node *n)
1482 1482 {
1483 1483 if (n->child == NULL)
1484 1484 outflags ^= MD_Sm;
1485 1485 else if (strcmp("on", n->child->string) == 0)
1486 1486 outflags |= MD_Sm;
1487 1487 else
1488 1488 outflags &= ~MD_Sm;
1489 1489
1490 1490 if (outflags & MD_Sm)
1491 1491 outflags |= MD_spc;
1492 1492
1493 1493 return 0;
1494 1494 }
1495 1495
1496 1496 static int
1497 1497 md_pre_Vt(struct roff_node *n)
1498 1498 {
1499 1499 switch (n->type) {
1500 1500 case ROFFT_BLOCK:
1501 1501 md_pre_syn(n);
1502 1502 return 1;
1503 1503 case ROFFT_BODY:
1504 1504 case ROFFT_ELEM:
1505 1505 md_pre_raw(n);
1506 1506 return 1;
1507 1507 default:
1508 1508 return 0;
1509 1509 }
1510 1510 }
1511 1511
1512 1512 static void
1513 1513 md_post_Vt(struct roff_node *n)
1514 1514 {
1515 1515 switch (n->type) {
1516 1516 case ROFFT_BODY:
1517 1517 case ROFFT_ELEM:
1518 1518 md_post_raw(n);
1519 1519 break;
1520 1520 default:
1521 1521 break;
1522 1522 }
1523 1523 }
1524 1524
1525 1525 static int
1526 1526 md_pre_Xr(struct roff_node *n)
1527 1527 {
1528 1528 n = n->child;
1529 1529 if (n == NULL)
1530 1530 return 0;
1531 1531 md_node(n);
1532 1532 n = n->next;
1533 1533 if (n == NULL)
1534 1534 return 0;
1535 1535 outflags &= ~MD_spc;
1536 1536 md_word("(");
1537 1537 md_node(n);
1538 1538 md_word(")");
1539 1539 return 0;
1540 1540 }
1541 1541
1542 1542 static int
1543 1543 md_pre__T(struct roff_node *n)
1544 1544 {
1545 1545 if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T)
1546 1546 md_word("\"");
1547 1547 else
1548 1548 md_rawword("*");
1549 1549 outflags &= ~MD_spc;
1550 1550 return 1;
1551 1551 }
1552 1552
1553 1553 static void
1554 1554 md_post__T(struct roff_node *n)
1555 1555 {
1556 1556 outflags &= ~MD_spc;
1557 1557 if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T)
1558 1558 md_word("\"");
1559 1559 else
1560 1560 md_rawword("*");
1561 1561 md_post_pc(n);
1562 1562 }
1563 1563
1564 1564 static int
1565 1565 md_pre_br(struct roff_node *n)
1566 1566 {
1567 1567 outflags |= MD_br;
1568 1568 return 0;
1569 1569 }
↓ open down ↓ |
1262 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX