=================================================================== RCS file: /cvs/mandoc/mdoc_markdown.c,v retrieving revision 1.14 retrieving revision 1.34 diff -u -p -r1.14 -r1.34 --- mandoc/mdoc_markdown.c 2017/03/08 19:23:43 1.14 +++ mandoc/mdoc_markdown.c 2020/02/27 01:43:52 1.34 @@ -1,6 +1,6 @@ -/* $Id: mdoc_markdown.c,v 1.14 2017/03/08 19:23:43 schwarze Exp $ */ +/* $Id: mdoc_markdown.c,v 1.34 2020/02/27 01:43:52 schwarze Exp $ */ /* - * Copyright (c) 2017 Ingo Schwarze + * Copyright (c) 2017, 2018, 2020 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "mandoc_aux.h" @@ -43,10 +44,12 @@ static void md_rawword(const char *); static void md_word(const char *); static void md_named(const char *); static void md_char(unsigned char); +static void md_uri(const char *); static int md_cond_head(struct roff_node *); static int md_cond_body(struct roff_node *); +static int md_pre_abort(struct roff_node *); static int md_pre_raw(struct roff_node *); static int md_pre_word(struct roff_node *); static int md_pre_skip(struct roff_node *); @@ -67,6 +70,7 @@ static int md_pre_Fo(struct roff_node *); static int md_pre_In(struct roff_node *); static int md_pre_It(struct roff_node *); static int md_pre_Lk(struct roff_node *); +static int md_pre_Mt(struct roff_node *); static int md_pre_Nd(struct roff_node *); static int md_pre_Nm(struct roff_node *); static int md_pre_No(struct roff_node *); @@ -101,8 +105,7 @@ static void md_post_Pf(struct roff_node *); static void md_post_Vt(struct roff_node *); static void md_post__T(struct roff_node *); -static const struct md_act md_acts[MDOC_MAX + 1] = { - { NULL, md_pre_Ap, NULL, NULL, NULL }, /* Ap */ +static const struct md_act md_acts[MDOC_MAX - MDOC_Dd] = { { NULL, NULL, NULL, NULL, NULL }, /* Dd */ { NULL, NULL, NULL, NULL, NULL }, /* Dt */ { NULL, NULL, NULL, NULL, NULL }, /* Os */ @@ -118,6 +121,7 @@ static const struct md_act md_acts[MDOC_MAX + 1] = { { NULL, md_pre_It, md_post_It, NULL, NULL }, /* It */ { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Ad */ { NULL, md_pre_An, NULL, NULL, NULL }, /* An */ + { NULL, md_pre_Ap, NULL, NULL, NULL }, /* Ap */ { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Ar */ { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Cd */ { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Cm */ @@ -136,7 +140,7 @@ static const struct md_act md_acts[MDOC_MAX + 1] = { { md_cond_head, md_pre_Nd, NULL, NULL, NULL }, /* Nd */ { NULL, md_pre_Nm, md_post_Nm, "**", "**" }, /* Nm */ { md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Op */ - { NULL, md_pre_Fd, md_post_raw, "*", "*" }, /* Ot */ + { NULL, md_pre_abort, NULL, NULL, NULL }, /* Ot */ { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Pa */ { NULL, NULL, NULL, NULL, NULL }, /* Rv */ { NULL, NULL, NULL, NULL, NULL }, /* St */ @@ -209,9 +213,9 @@ static const struct md_act md_acts[MDOC_MAX + 1] = { { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Fr */ { NULL, NULL, NULL, NULL, NULL }, /* Ud */ { NULL, NULL, md_post_Lb, NULL, NULL }, /* Lb */ - { NULL, md_pre_Pp, NULL, NULL, NULL }, /* Lp */ + { NULL, md_pre_abort, NULL, NULL, NULL }, /* Lp */ { NULL, md_pre_Lk, NULL, NULL, NULL }, /* Lk */ - { NULL, md_pre_raw, md_post_raw, "<", ">" }, /* Mt */ + { NULL, md_pre_Mt, NULL, NULL, NULL }, /* Mt */ { md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Brq */ { md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Bro */ { NULL, NULL, NULL, NULL, NULL }, /* Brc */ @@ -220,13 +224,11 @@ static const struct md_act md_acts[MDOC_MAX + 1] = { { md_cond_body, md_pre_En, md_post_En, NULL, NULL }, /* En */ { NULL, NULL, NULL, NULL, NULL }, /* Dx */ { NULL, NULL, md_post_pc, NULL, NULL }, /* %Q */ - { NULL, md_pre_br, NULL, NULL, NULL }, /* br */ - { NULL, md_pre_Pp, NULL, NULL, NULL }, /* sp */ { NULL, md_pre_Lk, md_post_pc, NULL, NULL }, /* %U */ { NULL, NULL, NULL, NULL, NULL }, /* Ta */ - { NULL, NULL, NULL, NULL, NULL }, /* ll */ - { NULL, NULL, NULL, NULL, NULL }, /* ROOT */ + { NULL, md_pre_skip, NULL, NULL, NULL }, /* Tg */ }; +static const struct md_act *md_act(enum roff_tok); static int outflags; #define MD_spc (1 << 0) /* Blank character before next word. */ @@ -251,22 +253,30 @@ static int escflags; /* Escape in generated markdown static int code_blocks, quote_blocks, list_blocks; static int outcount; + +static const struct md_act * +md_act(enum roff_tok tok) +{ + assert(tok >= MDOC_Dd && tok <= MDOC_MAX); + return md_acts + (tok - MDOC_Dd); +} + void -markdown_mdoc(void *arg, const struct roff_man *mdoc) +markdown_mdoc(void *arg, const struct roff_meta *mdoc) { outflags = MD_Sm; - md_word(mdoc->meta.title); - if (mdoc->meta.msec != NULL) { + md_word(mdoc->title); + if (mdoc->msec != NULL) { outflags &= ~MD_spc; md_word("("); - md_word(mdoc->meta.msec); + md_word(mdoc->msec); md_word(")"); } md_word("-"); - md_word(mdoc->meta.vol); - if (mdoc->meta.arch != NULL) { + md_word(mdoc->vol); + if (mdoc->arch != NULL) { md_word("("); - md_word(mdoc->meta.arch); + md_word(mdoc->arch); md_word(")"); } outflags |= MD_sp; @@ -274,9 +284,9 @@ markdown_mdoc(void *arg, const struct roff_man *mdoc) md_nodelist(mdoc->first->child); outflags |= MD_sp; - md_word(mdoc->meta.os); + md_word(mdoc->os); md_word("-"); - md_word(mdoc->meta.date); + md_word(mdoc->date); putchar('\n'); } @@ -295,12 +305,14 @@ md_node(struct roff_node *n) const struct md_act *act; int cond, process_children; - if (n->flags & NODE_NOPRT) + if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT) return; if (outflags & MD_nonl) outflags &= ~(MD_nl | MD_sp); - else if (outflags & MD_spc && n->flags & NODE_LINE) + else if (outflags & MD_spc && + n->flags & NODE_LINE && + !roff_node_transparent(n)) outflags |= MD_nl; act = NULL; @@ -308,8 +320,7 @@ md_node(struct roff_node *n) process_children = 1; n->flags &= ~NODE_ENDED; - switch (n->type) { - case ROFFT_TEXT: + if (n->type == ROFFT_TEXT) { if (n->flags & NODE_DELIMC) outflags &= ~(MD_spc | MD_spc_force); else if (outflags & MD_Sm) @@ -319,14 +330,24 @@ md_node(struct roff_node *n) outflags &= ~(MD_spc | MD_spc_force); else if (outflags & MD_Sm) outflags |= MD_spc; - break; - default: - act = md_acts + n->tok; + } else if (n->tok < ROFF_MAX) { + switch (n->tok) { + case ROFF_br: + process_children = md_pre_br(n); + break; + case ROFF_sp: + process_children = md_pre_Pp(n); + break; + default: + process_children = 0; + break; + } + } else { + act = md_act(n->tok); cond = act->cond == NULL || (*act->cond)(n); if (cond && act->pre != NULL && (n->end == ENDBODY_NOT || n->child != NULL)) process_children = (*act->pre)(n); - break; } if (process_children && n->child != NULL) @@ -484,7 +505,7 @@ md_word(const char *s) { const char *seq, *prevfont, *currfont, *nextfont; char c; - int bs, sz, uc; + int bs, sz, uc, breakline; /* No spacing before closing delimiters. */ if (s[0] != '\0' && s[1] == '\0' && @@ -501,6 +522,7 @@ md_word(const char *s) if ((s[0] == '(' || s[0] == '[') && s[1] == '\0') outflags &= ~MD_spc; + breakline = 0; prevfont = currfont = ""; while ((c = *s++) != '\0') { bs = 0; @@ -570,6 +592,12 @@ md_word(const char *s) case ESCAPE_SPECIAL: uc = mchars_spec2cp(seq, sz); break; + case ESCAPE_UNDEF: + uc = *seq; + break; + case ESCAPE_DEVICE: + md_rawword("markdown"); + continue; case ESCAPE_FONTBOLD: nextfont = "**"; break; @@ -580,12 +608,16 @@ md_word(const char *s) nextfont = "***"; break; case ESCAPE_FONT: + case ESCAPE_FONTCW: case ESCAPE_FONTROMAN: nextfont = ""; break; case ESCAPE_FONTPREV: nextfont = prevfont; break; + case ESCAPE_BREAK: + breakline = 1; + break; case ESCAPE_NOSPACE: case ESCAPE_SKIPCHAR: case ESCAPE_OVERSTRIKE: @@ -633,6 +665,13 @@ md_word(const char *s) if (bs) putchar('\\'); md_char(c); + if (breakline && + (*s == '\0' || *s == ' ' || *s == ASCII_NBRSP)) { + printf(" \n"); + breakline = 0; + while (*s == ' ' || *s == ASCII_NBRSP) + s++; + } } if (*currfont != '\0') { outflags &= ~MD_spc; @@ -692,11 +731,17 @@ md_cond_body(struct roff_node *n) } static int +md_pre_abort(struct roff_node *n) +{ + abort(); +} + +static int md_pre_raw(struct roff_node *n) { const char *prefix; - if ((prefix = md_acts[n->tok].prefix) != NULL) { + if ((prefix = md_act(n->tok)->prefix) != NULL) { md_rawword(prefix); outflags &= ~MD_spc; if (*prefix == '`') @@ -710,7 +755,7 @@ md_post_raw(struct roff_node *n) { const char *suffix; - if ((suffix = md_acts[n->tok].suffix) != NULL) { + if ((suffix = md_act(n->tok)->suffix) != NULL) { outflags &= ~(MD_spc | MD_nl); md_rawword(suffix); if (*suffix == '`') @@ -723,7 +768,7 @@ md_pre_word(struct roff_node *n) { const char *prefix; - if ((prefix = md_acts[n->tok].prefix) != NULL) { + if ((prefix = md_act(n->tok)->prefix) != NULL) { md_word(prefix); outflags &= ~MD_spc; } @@ -735,7 +780,7 @@ md_post_word(struct roff_node *n) { const char *suffix; - if ((suffix = md_acts[n->tok].suffix) != NULL) { + if ((suffix = md_act(n->tok)->suffix) != NULL) { outflags &= ~(MD_spc | MD_nl); md_word(suffix); } @@ -744,14 +789,17 @@ md_post_word(struct roff_node *n) static void md_post_pc(struct roff_node *n) { + struct roff_node *nn; + md_post_raw(n); if (n->parent->tok != MDOC_Rs) return; - if (n->next != NULL) { + + if ((nn = roff_node_next(n)) != NULL) { md_word(","); - if (n->prev != NULL && - n->prev->tok == n->tok && - n->next->tok == n->tok) + if (nn->tok == n->tok && + (nn = roff_node_prev(n)) != NULL && + nn->tok == n->tok) md_word("and"); } else { md_word("."); @@ -768,10 +816,13 @@ md_pre_skip(struct roff_node *n) static void md_pre_syn(struct roff_node *n) { - if (n->prev == NULL || ! (n->flags & NODE_SYNPRETTY)) + struct roff_node *np; + + if ((n->flags & NODE_SYNPRETTY) == 0 || + (np = roff_node_prev(n)) == NULL) return; - if (n->prev->tok == n->tok && + if (np->tok == n->tok && n->tok != MDOC_Ft && n->tok != MDOC_Fo && n->tok != MDOC_Fn) { @@ -779,7 +830,7 @@ md_pre_syn(struct roff_node *n) return; } - switch (n->prev->tok) { + switch (np->tok) { case MDOC_Fd: case MDOC_Fn: case MDOC_Fo: @@ -1010,7 +1061,9 @@ md_pre_Fa(struct roff_node *n) static void md_post_Fa(struct roff_node *n) { - if (n->next != NULL && n->next->tok == MDOC_Fa) + struct roff_node *nn; + + if ((nn = roff_node_next(n)) != NULL && nn->tok == MDOC_Fa) md_word(","); } @@ -1032,9 +1085,11 @@ md_post_Fd(struct roff_node *n) static void md_post_Fl(struct roff_node *n) { + struct roff_node *nn; + md_post_raw(n); - if (n->child == NULL && n->next != NULL && - n->next->type != ROFFT_TEXT && !(n->next->flags & NODE_LINE)) + if (n->child == NULL && (nn = roff_node_next(n)) != NULL && + nn->type != ROFFT_TEXT && (nn->flags & NODE_LINE) == 0) outflags &= ~MD_spc; } @@ -1248,7 +1303,7 @@ md_post_It(struct roff_node *n) while ((n = n->prev) != NULL && n->type != ROFFT_HEAD) i++; - /* + /* * If a width was specified for this column, * subtract what printed, and * add the same spacing as in mdoc_term.c. @@ -1279,39 +1334,81 @@ md_post_Lb(struct roff_node *n) outflags |= MD_br; } +static void +md_uri(const char *s) +{ + while (*s != '\0') { + if (strchr("%()<>", *s) != NULL) { + printf("%%%2.2hhX", *s); + outcount += 3; + } else { + putchar(*s); + outcount++; + } + s++; + } +} + static int md_pre_Lk(struct roff_node *n) { - const struct roff_node *link, *descr; - const unsigned char *s; + const struct roff_node *link, *descr, *punct; if ((link = n->child) == NULL) return 0; - if ((descr = link->next) != NULL) { - md_rawword("["); - outflags &= ~MD_spc; - while (descr != NULL) { - md_word(descr->string); - descr = descr->next; - } - outflags &= ~MD_spc; - md_rawword("]("); - } else - md_rawword("<"); + /* Find beginning of trailing punctuation. */ + punct = n->last; + while (punct != link && punct->flags & NODE_DELIMC) + punct = punct->prev; + punct = punct->next; - for (s = link->string; *s != '\0'; s++) { - if (strchr("%()<>", *s) != NULL) { - printf("%%%2.2hhX", *s); - outcount += 3; - } else { - putchar(*s); + /* Link text. */ + descr = link->next; + if (descr == punct) + descr = link; /* no text */ + md_rawword("["); + outflags &= ~MD_spc; + do { + md_word(descr->string); + descr = descr->next; + } while (descr != punct); + outflags &= ~MD_spc; + + /* Link target. */ + md_rawword("]("); + md_uri(link->string); + outflags &= ~MD_spc; + md_rawword(")"); + + /* Trailing punctuation. */ + while (punct != NULL) { + md_word(punct->string); + punct = punct->next; + } + return 0; +} + +static int +md_pre_Mt(struct roff_node *n) +{ + const struct roff_node *nch; + + md_rawword("["); + outflags &= ~MD_spc; + for (nch = n->child; nch != NULL; nch = nch->next) + md_word(nch->string); + outflags &= ~MD_spc; + md_rawword("](mailto:"); + for (nch = n->child; nch != NULL; nch = nch->next) { + md_uri(nch->string); + if (nch->next != NULL) { + putchar(' '); outcount++; } } - outflags &= ~MD_spc; - md_rawword(link->next == NULL ? ">" : ")"); + md_rawword(")"); return 0; }