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