[BACK]Return to mdoc_markdown.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

Diff for /mandoc/mdoc_markdown.c between version 1.19 and 1.37

version 1.19, 2017/05/05 02:06:19 version 1.37, 2021/08/10 12:55:03
Line 1 
Line 1 
 /*      $Id$ */  /* $Id$ */
 /*  /*
  * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>   * Copyright (c) 2017, 2018, 2020 Ingo Schwarze <schwarze@openbsd.org>
  *   *
  * Permission to use, copy, modify, and distribute this software for any   * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above   * purpose with or without fee is hereby granted, provided that the above
Line 13 
Line 13 
  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN   * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF   * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    *
    * Markdown formatter for mdoc(7) used by mandoc(1).
  */   */
   #include "config.h"
   
 #include <sys/types.h>  #include <sys/types.h>
   
 #include <assert.h>  #include <assert.h>
Line 29 
Line 33 
 #include "main.h"  #include "main.h"
   
 struct  md_act {  struct  md_act {
         int             (*cond)(struct roff_node *n);          int             (*cond)(struct roff_node *);
         int             (*pre)(struct roff_node *n);          int             (*pre)(struct roff_node *);
         void            (*post)(struct roff_node *n);          void            (*post)(struct roff_node *);
         const char       *prefix; /* pre-node string constant */          const char       *prefix; /* pre-node string constant */
         const char       *suffix; /* post-node string constant */          const char       *suffix; /* post-node string constant */
 };  };
   
 static  void     md_nodelist(struct roff_node *);  static  void     md_nodelist(struct roff_node *);
 static  void     md_node(struct roff_node *);  static  void     md_node(struct roff_node *);
 static  const char *md_stack(char c);  static  const char *md_stack(char);
 static  void     md_preword(void);  static  void     md_preword(void);
 static  void     md_rawword(const char *);  static  void     md_rawword(const char *);
 static  void     md_word(const char *);  static  void     md_word(const char *);
Line 49  static void  md_uri(const char *);
Line 53  static void  md_uri(const char *);
 static  int      md_cond_head(struct roff_node *);  static  int      md_cond_head(struct roff_node *);
 static  int      md_cond_body(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_raw(struct roff_node *);
 static  int      md_pre_word(struct roff_node *);  static  int      md_pre_word(struct roff_node *);
 static  int      md_pre_skip(struct roff_node *);  static  int      md_pre_skip(struct roff_node *);
Line 104  static void  md_post_Pf(struct roff_node *);
Line 109  static void  md_post_Pf(struct roff_node *);
 static  void     md_post_Vt(struct roff_node *);  static  void     md_post_Vt(struct roff_node *);
 static  void     md_post__T(struct roff_node *);  static  void     md_post__T(struct roff_node *);
   
 static  const struct md_act __md_acts[MDOC_MAX - MDOC_Dd] = {  static  const struct md_act md_acts[MDOC_MAX - MDOC_Dd] = {
         { NULL, NULL, NULL, NULL, NULL }, /* Dd */          { NULL, NULL, NULL, NULL, NULL }, /* Dd */
         { NULL, NULL, NULL, NULL, NULL }, /* Dt */          { NULL, NULL, NULL, NULL, NULL }, /* Dt */
         { NULL, NULL, NULL, NULL, NULL }, /* Os */          { NULL, NULL, NULL, NULL, NULL }, /* Os */
Line 139  static const struct md_act __md_acts[MDOC_MAX - MDOC_D
Line 144  static const struct md_act __md_acts[MDOC_MAX - MDOC_D
         { md_cond_head, md_pre_Nd, NULL, NULL, NULL }, /* Nd */          { md_cond_head, md_pre_Nd, NULL, NULL, NULL }, /* Nd */
         { NULL, md_pre_Nm, md_post_Nm, "**", "**" }, /* Nm */          { NULL, md_pre_Nm, md_post_Nm, "**", "**" }, /* Nm */
         { md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Op */          { 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, md_pre_raw, md_post_raw, "*", "*" }, /* Pa */
         { NULL, NULL, NULL, NULL, NULL }, /* Rv */          { NULL, NULL, NULL, NULL, NULL }, /* Rv */
         { NULL, NULL, NULL, NULL, NULL }, /* St */          { NULL, NULL, NULL, NULL, NULL }, /* St */
Line 212  static const struct md_act __md_acts[MDOC_MAX - MDOC_D
Line 217  static const struct md_act __md_acts[MDOC_MAX - MDOC_D
         { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Fr */          { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Fr */
         { NULL, NULL, NULL, NULL, NULL }, /* Ud */          { NULL, NULL, NULL, NULL, NULL }, /* Ud */
         { NULL, NULL, md_post_Lb, NULL, NULL }, /* Lb */          { 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_Lk, NULL, NULL, NULL }, /* Lk */
         { NULL, md_pre_Mt, NULL, NULL, NULL }, /* 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, "{", "}" }, /* Brq */
Line 223  static const struct md_act __md_acts[MDOC_MAX - MDOC_D
Line 228  static const struct md_act __md_acts[MDOC_MAX - MDOC_D
         { md_cond_body, md_pre_En, md_post_En, NULL, NULL }, /* En */          { md_cond_body, md_pre_En, md_post_En, NULL, NULL }, /* En */
         { NULL, NULL, NULL, NULL, NULL }, /* Dx */          { NULL, NULL, NULL, NULL, NULL }, /* Dx */
         { NULL, NULL, md_post_pc, NULL, NULL }, /* %Q */          { NULL, NULL, md_post_pc, NULL, NULL }, /* %Q */
         { NULL, md_pre_Pp, NULL, NULL, NULL }, /* sp */  
         { NULL, md_pre_Lk, md_post_pc, NULL, NULL }, /* %U */          { NULL, md_pre_Lk, md_post_pc, NULL, NULL }, /* %U */
         { NULL, NULL, NULL, NULL, NULL }, /* Ta */          { NULL, NULL, NULL, NULL, NULL }, /* Ta */
         { NULL, NULL, NULL, NULL, NULL }, /* ll */          { NULL, md_pre_skip, NULL, NULL, NULL }, /* Tg */
 };  };
 static  const struct md_act *const md_acts = __md_acts - MDOC_Dd;  static const struct md_act *md_act(enum roff_tok);
   
 static  int      outflags;  static  int      outflags;
 #define MD_spc           (1 << 0)  /* Blank character before next word. */  #define MD_spc           (1 << 0)  /* Blank character before next word. */
Line 253  static int  escflags; /* Escape in generated markdown 
Line 257  static int  escflags; /* Escape in generated markdown 
 static  int      code_blocks, quote_blocks, list_blocks;  static  int      code_blocks, quote_blocks, list_blocks;
 static  int      outcount;  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  void
 markdown_mdoc(void *arg, const struct roff_man *mdoc)  markdown_mdoc(void *arg, const struct roff_meta *mdoc)
 {  {
         outflags = MD_Sm;          outflags = MD_Sm;
         md_word(mdoc->meta.title);          md_word(mdoc->title);
         if (mdoc->meta.msec != NULL) {          if (mdoc->msec != NULL) {
                 outflags &= ~MD_spc;                  outflags &= ~MD_spc;
                 md_word("(");                  md_word("(");
                 md_word(mdoc->meta.msec);                  md_word(mdoc->msec);
                 md_word(")");                  md_word(")");
         }          }
         md_word("-");          md_word("-");
         md_word(mdoc->meta.vol);          md_word(mdoc->vol);
         if (mdoc->meta.arch != NULL) {          if (mdoc->arch != NULL) {
                 md_word("(");                  md_word("(");
                 md_word(mdoc->meta.arch);                  md_word(mdoc->arch);
                 md_word(")");                  md_word(")");
         }          }
         outflags |= MD_sp;          outflags |= MD_sp;
Line 276  markdown_mdoc(void *arg, const struct roff_man *mdoc)
Line 288  markdown_mdoc(void *arg, const struct roff_man *mdoc)
         md_nodelist(mdoc->first->child);          md_nodelist(mdoc->first->child);
   
         outflags |= MD_sp;          outflags |= MD_sp;
         md_word(mdoc->meta.os);          md_word(mdoc->os);
         md_word("-");          md_word("-");
         md_word(mdoc->meta.date);          md_word(mdoc->date);
         putchar('\n');          putchar('\n');
 }  }
   
Line 297  md_node(struct roff_node *n)
Line 309  md_node(struct roff_node *n)
         const struct md_act     *act;          const struct md_act     *act;
         int                      cond, process_children;          int                      cond, process_children;
   
         if (n->flags & NODE_NOPRT)          if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
                 return;                  return;
   
         if (outflags & MD_nonl)          if (outflags & MD_nonl)
                 outflags &= ~(MD_nl | MD_sp);                  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;                  outflags |= MD_nl;
   
         act = NULL;          act = NULL;
Line 325  md_node(struct roff_node *n)
Line 339  md_node(struct roff_node *n)
                 case ROFF_br:                  case ROFF_br:
                         process_children = md_pre_br(n);                          process_children = md_pre_br(n);
                         break;                          break;
                 case ROFF_ft:                  case ROFF_sp:
                         process_children = 0;                          process_children = md_pre_Pp(n);
                         break;                          break;
                 default:                  default:
                         abort();                          process_children = 0;
                           break;
                 }                  }
         } else {          } else {
                 assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);                  act = md_act(n->tok);
                 act = md_acts + n->tok;  
                 cond = act->cond == NULL || (*act->cond)(n);                  cond = act->cond == NULL || (*act->cond)(n);
                 if (cond && act->pre != NULL &&                  if (cond && act->pre != NULL &&
                     (n->end == ENDBODY_NOT || n->child != NULL))                      (n->end == ENDBODY_NOT || n->child != NULL))
Line 495  md_word(const char *s)
Line 509  md_word(const char *s)
 {  {
         const char      *seq, *prevfont, *currfont, *nextfont;          const char      *seq, *prevfont, *currfont, *nextfont;
         char             c;          char             c;
         int              bs, sz, uc;          int              bs, sz, uc, breakline;
   
         /* No spacing before closing delimiters. */          /* No spacing before closing delimiters. */
         if (s[0] != '\0' && s[1] == '\0' &&          if (s[0] != '\0' && s[1] == '\0' &&
Line 512  md_word(const char *s)
Line 526  md_word(const char *s)
         if ((s[0] == '(' || s[0] == '[') && s[1] == '\0')          if ((s[0] == '(' || s[0] == '[') && s[1] == '\0')
                 outflags &= ~MD_spc;                  outflags &= ~MD_spc;
   
           breakline = 0;
         prevfont = currfont = "";          prevfont = currfont = "";
         while ((c = *s++) != '\0') {          while ((c = *s++) != '\0') {
                 bs = 0;                  bs = 0;
Line 581  md_word(const char *s)
Line 596  md_word(const char *s)
                         case ESCAPE_SPECIAL:                          case ESCAPE_SPECIAL:
                                 uc = mchars_spec2cp(seq, sz);                                  uc = mchars_spec2cp(seq, sz);
                                 break;                                  break;
                           case ESCAPE_UNDEF:
                                   uc = *seq;
                                   break;
                           case ESCAPE_DEVICE:
                                   md_rawword("markdown");
                                   continue;
                         case ESCAPE_FONTBOLD:                          case ESCAPE_FONTBOLD:
                           case ESCAPE_FONTCB:
                                 nextfont = "**";                                  nextfont = "**";
                                 break;                                  break;
                         case ESCAPE_FONTITALIC:                          case ESCAPE_FONTITALIC:
                           case ESCAPE_FONTCI:
                                 nextfont = "*";                                  nextfont = "*";
                                 break;                                  break;
                         case ESCAPE_FONTBI:                          case ESCAPE_FONTBI:
                                 nextfont = "***";                                  nextfont = "***";
                                 break;                                  break;
                         case ESCAPE_FONT:                          case ESCAPE_FONT:
                           case ESCAPE_FONTCR:
                         case ESCAPE_FONTROMAN:                          case ESCAPE_FONTROMAN:
                                 nextfont = "";                                  nextfont = "";
                                 break;                                  break;
                         case ESCAPE_FONTPREV:                          case ESCAPE_FONTPREV:
                                 nextfont = prevfont;                                  nextfont = prevfont;
                                 break;                                  break;
                           case ESCAPE_BREAK:
                                   breakline = 1;
                                   break;
                         case ESCAPE_NOSPACE:                          case ESCAPE_NOSPACE:
                         case ESCAPE_SKIPCHAR:                          case ESCAPE_SKIPCHAR:
                         case ESCAPE_OVERSTRIKE:                          case ESCAPE_OVERSTRIKE:
Line 644  md_word(const char *s)
Line 671  md_word(const char *s)
                 if (bs)                  if (bs)
                         putchar('\\');                          putchar('\\');
                 md_char(c);                  md_char(c);
                   if (breakline &&
                       (*s == '\0' || *s == ' ' || *s == ASCII_NBRSP)) {
                           printf("  \n");
                           breakline = 0;
                           while (*s == ' ' || *s == ASCII_NBRSP)
                                   s++;
                   }
         }          }
         if (*currfont != '\0') {          if (*currfont != '\0') {
                 outflags &= ~MD_spc;                  outflags &= ~MD_spc;
Line 703  md_cond_body(struct roff_node *n)
Line 737  md_cond_body(struct roff_node *n)
 }  }
   
 static int  static int
   md_pre_abort(struct roff_node *n)
   {
           abort();
   }
   
   static int
 md_pre_raw(struct roff_node *n)  md_pre_raw(struct roff_node *n)
 {  {
         const char      *prefix;          const char      *prefix;
   
         if ((prefix = md_acts[n->tok].prefix) != NULL) {          if ((prefix = md_act(n->tok)->prefix) != NULL) {
                 md_rawword(prefix);                  md_rawword(prefix);
                 outflags &= ~MD_spc;                  outflags &= ~MD_spc;
                 if (*prefix == '`')                  if (*prefix == '`')
Line 721  md_post_raw(struct roff_node *n)
Line 761  md_post_raw(struct roff_node *n)
 {  {
         const char      *suffix;          const char      *suffix;
   
         if ((suffix = md_acts[n->tok].suffix) != NULL) {          if ((suffix = md_act(n->tok)->suffix) != NULL) {
                 outflags &= ~(MD_spc | MD_nl);                  outflags &= ~(MD_spc | MD_nl);
                 md_rawword(suffix);                  md_rawword(suffix);
                 if (*suffix == '`')                  if (*suffix == '`')
Line 734  md_pre_word(struct roff_node *n)
Line 774  md_pre_word(struct roff_node *n)
 {  {
         const char      *prefix;          const char      *prefix;
   
         if ((prefix = md_acts[n->tok].prefix) != NULL) {          if ((prefix = md_act(n->tok)->prefix) != NULL) {
                 md_word(prefix);                  md_word(prefix);
                 outflags &= ~MD_spc;                  outflags &= ~MD_spc;
         }          }
Line 746  md_post_word(struct roff_node *n)
Line 786  md_post_word(struct roff_node *n)
 {  {
         const char      *suffix;          const char      *suffix;
   
         if ((suffix = md_acts[n->tok].suffix) != NULL) {          if ((suffix = md_act(n->tok)->suffix) != NULL) {
                 outflags &= ~(MD_spc | MD_nl);                  outflags &= ~(MD_spc | MD_nl);
                 md_word(suffix);                  md_word(suffix);
         }          }
Line 755  md_post_word(struct roff_node *n)
Line 795  md_post_word(struct roff_node *n)
 static void  static void
 md_post_pc(struct roff_node *n)  md_post_pc(struct roff_node *n)
 {  {
           struct roff_node *nn;
   
         md_post_raw(n);          md_post_raw(n);
         if (n->parent->tok != MDOC_Rs)          if (n->parent->tok != MDOC_Rs)
                 return;                  return;
         if (n->next != NULL) {  
           if ((nn = roff_node_next(n)) != NULL) {
                 md_word(",");                  md_word(",");
                 if (n->prev != NULL &&                  if (nn->tok == n->tok &&
                     n->prev->tok == n->tok &&                      (nn = roff_node_prev(n)) != NULL &&
                     n->next->tok == n->tok)                      nn->tok == n->tok)
                         md_word("and");                          md_word("and");
         } else {          } else {
                 md_word(".");                  md_word(".");
Line 779  md_pre_skip(struct roff_node *n)
Line 822  md_pre_skip(struct roff_node *n)
 static void  static void
 md_pre_syn(struct roff_node *n)  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;                  return;
   
         if (n->prev->tok == n->tok &&          if (np->tok == n->tok &&
             n->tok != MDOC_Ft &&              n->tok != MDOC_Ft &&
             n->tok != MDOC_Fo &&              n->tok != MDOC_Fo &&
             n->tok != MDOC_Fn) {              n->tok != MDOC_Fn) {
Line 790  md_pre_syn(struct roff_node *n)
Line 836  md_pre_syn(struct roff_node *n)
                 return;                  return;
         }          }
   
         switch (n->prev->tok) {          switch (np->tok) {
         case MDOC_Fd:          case MDOC_Fd:
         case MDOC_Fn:          case MDOC_Fn:
         case MDOC_Fo:          case MDOC_Fo:
Line 1021  md_pre_Fa(struct roff_node *n)
Line 1067  md_pre_Fa(struct roff_node *n)
 static void  static void
 md_post_Fa(struct roff_node *n)  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(",");                  md_word(",");
 }  }
   
Line 1043  md_post_Fd(struct roff_node *n)
Line 1091  md_post_Fd(struct roff_node *n)
 static void  static void
 md_post_Fl(struct roff_node *n)  md_post_Fl(struct roff_node *n)
 {  {
           struct roff_node *nn;
   
         md_post_raw(n);          md_post_raw(n);
         if (n->child == NULL && n->next != NULL &&          if (n->child == NULL && (nn = roff_node_next(n)) != NULL &&
             n->next->type != ROFFT_TEXT && !(n->next->flags & NODE_LINE))              nn->type != ROFFT_TEXT && (nn->flags & NODE_LINE) == 0)
                 outflags &= ~MD_spc;                  outflags &= ~MD_spc;
 }  }
   
Line 1259  md_post_It(struct roff_node *n)
Line 1309  md_post_It(struct roff_node *n)
                 while ((n = n->prev) != NULL && n->type != ROFFT_HEAD)                  while ((n = n->prev) != NULL && n->type != ROFFT_HEAD)
                         i++;                          i++;
   
                 /*                  /*
                  * If a width was specified for this column,                   * If a width was specified for this column,
                  * subtract what printed, and                   * subtract what printed, and
                  * add the same spacing as in mdoc_term.c.                   * add the same spacing as in mdoc_term.c.
Line 1308  md_uri(const char *s)
Line 1358  md_uri(const char *s)
 static int  static int
 md_pre_Lk(struct roff_node *n)  md_pre_Lk(struct roff_node *n)
 {  {
         const struct roff_node *link, *descr;          const struct roff_node *link, *descr, *punct;
   
         if ((link = n->child) == NULL)          if ((link = n->child) == NULL)
                 return 0;                  return 0;
   
           /* Find beginning of trailing punctuation. */
           punct = n->last;
           while (punct != link && punct->flags & NODE_DELIMC)
                   punct = punct->prev;
           punct = punct->next;
   
         /* Link text. */          /* Link text. */
         descr = link->next;          descr = link->next;
         if (descr == NULL || descr->flags & NODE_DELIMC)          if (descr == punct)
                 descr = link;  /* no text */                  descr = link;  /* no text */
         md_rawword("[");          md_rawword("[");
         outflags &= ~MD_spc;          outflags &= ~MD_spc;
         do {          do {
                 md_word(descr->string);                  md_word(descr->string);
                 descr = descr->next;                  descr = descr->next;
         } while (descr != NULL && !(descr->flags & NODE_DELIMC));          } while (descr != punct);
         outflags &= ~MD_spc;          outflags &= ~MD_spc;
   
         /* Link target. */          /* Link target. */
Line 1332  md_pre_Lk(struct roff_node *n)
Line 1388  md_pre_Lk(struct roff_node *n)
         md_rawword(")");          md_rawword(")");
   
         /* Trailing punctuation. */          /* Trailing punctuation. */
         while (descr != NULL) {          while (punct != NULL) {
                 md_word(descr->string);                  md_word(punct->string);
                 descr = descr->next;                  punct = punct->next;
         }          }
         return 0;          return 0;
 }  }

Legend:
Removed from v.1.19  
changed lines
  Added in v.1.37

CVSweb