[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.2 and 1.31

version 1.2, 2017/03/04 21:41:29 version 1.31, 2019/07/01 22:56:24
Line 1 
Line 1 
 /*      $Id$ */  /*      $Id$ */
 /*  /*
  * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>   * Copyright (c) 2017, 2018 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 19 
Line 19 
 #include <assert.h>  #include <assert.h>
 #include <ctype.h>  #include <ctype.h>
 #include <stdio.h>  #include <stdio.h>
   #include <stdlib.h>
 #include <string.h>  #include <string.h>
   
 #include "mandoc_aux.h"  #include "mandoc_aux.h"
Line 43  static void  md_rawword(const char *);
Line 44  static void  md_rawword(const char *);
 static  void     md_word(const char *);  static  void     md_word(const char *);
 static  void     md_named(const char *);  static  void     md_named(const char *);
 static  void     md_char(unsigned 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_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 *);
 static  void     md_pre_syn(struct roff_node *);  static  void     md_pre_syn(struct roff_node *);
   static  int      md_pre_An(struct roff_node *);
 static  int      md_pre_Ap(struct roff_node *);  static  int      md_pre_Ap(struct roff_node *);
 static  int      md_pre_Bd(struct roff_node *);  static  int      md_pre_Bd(struct roff_node *);
 static  int      md_pre_Bk(struct roff_node *);  static  int      md_pre_Bk(struct roff_node *);
Line 66  static int  md_pre_Fo(struct roff_node *);
Line 70  static int  md_pre_Fo(struct roff_node *);
 static  int      md_pre_In(struct roff_node *);  static  int      md_pre_In(struct roff_node *);
 static  int      md_pre_It(struct roff_node *);  static  int      md_pre_It(struct roff_node *);
 static  int      md_pre_Lk(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_Nd(struct roff_node *);
 static  int      md_pre_Nm(struct roff_node *);  static  int      md_pre_Nm(struct roff_node *);
 static  int      md_pre_No(struct roff_node *);  static  int      md_pre_No(struct roff_node *);
Line 89  static void  md_post_En(struct roff_node *);
Line 94  static void  md_post_En(struct roff_node *);
 static  void     md_post_Eo(struct roff_node *);  static  void     md_post_Eo(struct roff_node *);
 static  void     md_post_Fa(struct roff_node *);  static  void     md_post_Fa(struct roff_node *);
 static  void     md_post_Fd(struct roff_node *);  static  void     md_post_Fd(struct roff_node *);
   static  void     md_post_Fl(struct roff_node *);
 static  void     md_post_Fn(struct roff_node *);  static  void     md_post_Fn(struct roff_node *);
 static  void     md_post_Fo(struct roff_node *);  static  void     md_post_Fo(struct roff_node *);
 static  void     md_post_In(struct roff_node *);  static  void     md_post_In(struct roff_node *);
Line 99  static void  md_post_Pf(struct roff_node *);
Line 105  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 + 1] = {  static  const struct md_act md_acts[MDOC_MAX - MDOC_Dd] = {
         { NULL, md_pre_Ap, NULL, NULL, NULL }, /* Ap */  
         { 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 115  static const struct md_act md_acts[MDOC_MAX + 1] = {
Line 120  static const struct md_act md_acts[MDOC_MAX + 1] = {
         { NULL, NULL, NULL, NULL, NULL }, /* El */          { NULL, NULL, NULL, NULL, NULL }, /* El */
         { NULL, md_pre_It, md_post_It, NULL, NULL }, /* It */          { NULL, md_pre_It, md_post_It, NULL, NULL }, /* It */
         { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Ad */          { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Ad */
         { NULL, NULL, NULL, NULL, NULL }, /* An */          { 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, "*", "*" }, /* Ar */
         { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Cd */          { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Cd */
         { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Cm */          { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Cm */
Line 125  static const struct md_act md_acts[MDOC_MAX + 1] = {
Line 131  static const struct md_act md_acts[MDOC_MAX + 1] = {
         { NULL, NULL, NULL, NULL, NULL }, /* Ex */          { NULL, NULL, NULL, NULL, NULL }, /* Ex */
         { NULL, md_pre_Fa, md_post_Fa, NULL, NULL }, /* Fa */          { NULL, md_pre_Fa, md_post_Fa, NULL, NULL }, /* Fa */
         { NULL, md_pre_Fd, md_post_Fd, "**", "**" }, /* Fd */          { NULL, md_pre_Fd, md_post_Fd, "**", "**" }, /* Fd */
         { NULL, md_pre_raw, md_post_raw, "**-", "**" }, /* Fl */          { NULL, md_pre_raw, md_post_Fl, "**-", "**" }, /* Fl */
         { NULL, md_pre_Fn, md_post_Fn, NULL, NULL }, /* Fn */          { NULL, md_pre_Fn, md_post_Fn, NULL, NULL }, /* Fn */
         { NULL, md_pre_Fd, md_post_raw, "*", "*" }, /* Ft */          { NULL, md_pre_Fd, md_post_raw, "*", "*" }, /* Ft */
         { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Ic */          { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Ic */
         { NULL, md_pre_In, md_post_In, "*", "*" }, /* In */          { NULL, md_pre_In, md_post_In, NULL, NULL }, /* In */
         { NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Li */          { NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Li */
         { 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 207  static const struct md_act md_acts[MDOC_MAX + 1] = {
Line 213  static const struct md_act md_acts[MDOC_MAX + 1] = {
         { 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_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, "{", "}" }, /* Brq */
         { md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Bro */          { md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Bro */
         { NULL, NULL, NULL, NULL, NULL }, /* Brc */          { NULL, NULL, NULL, NULL, NULL }, /* Brc */
Line 218  static const struct md_act md_acts[MDOC_MAX + 1] = {
Line 224  static const struct md_act md_acts[MDOC_MAX + 1] = {
         { 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_br, NULL, NULL, NULL }, /* br */          { NULL, md_pre_Lk, md_post_pc, NULL, NULL }, /* %U */
         { NULL, md_pre_Pp, NULL, NULL, NULL }, /* sp */  
         { NULL, NULL, 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, NULL, NULL, NULL, NULL }, /* ROOT */  
 };  };
   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 235  static int  outflags;
Line 238  static int  outflags;
 #define MD_sp            (1 << 5)  /* Insert a paragraph break. */  #define MD_sp            (1 << 5)  /* Insert a paragraph break. */
 #define MD_Sm            (1 << 6)  /* Horizontal spacing mode. */  #define MD_Sm            (1 << 6)  /* Horizontal spacing mode. */
 #define MD_Bk            (1 << 7)  /* Word keep mode. */  #define MD_Bk            (1 << 7)  /* Word keep mode. */
   #define MD_An_split      (1 << 8)  /* Author mode is "split". */
   #define MD_An_nosplit    (1 << 9)  /* Author mode is "nosplit". */
   
 static  int      escflags; /* Escape in generated markdown code: */  static  int      escflags; /* Escape in generated markdown code: */
 #define ESC_BOL  (1 << 0)  /* "#*+-" near the beginning of a line. */  #define ESC_BOL  (1 << 0)  /* "#*+-" near the beginning of a line. */
 #define ESC_NUM  (1 << 1)  /* "." after a leading number. */  #define ESC_NUM  (1 << 1)  /* "." after a leading number. */
 #define ESC_HYP  (1 << 2)  /* "(" immediately after "]". */  #define ESC_HYP  (1 << 2)  /* "(" immediately after "]". */
 #define ESC_PAR  (1 << 3)  /* ")" when "(" is open. */  
 #define ESC_SQU  (1 << 4)  /* "]" when "[" is open. */  #define ESC_SQU  (1 << 4)  /* "]" when "[" is open. */
 #define ESC_FON  (1 << 5)  /* "*" immediately after unrelated "*". */  #define ESC_FON  (1 << 5)  /* "*" immediately after unrelated "*". */
   #define ESC_EOL  (1 << 6)  /* " " at the and of a line. */
   
 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 270  markdown_mdoc(void *arg, const struct roff_man *mdoc)
Line 283  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 291  md_node(struct roff_node *n)
Line 304  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)
Line 304  md_node(struct roff_node *n)
Line 317  md_node(struct roff_node *n)
         process_children = 1;          process_children = 1;
         n->flags &= ~NODE_ENDED;          n->flags &= ~NODE_ENDED;
   
         switch (n->type) {          if (n->type == ROFFT_TEXT) {
         case ROFFT_TEXT:  
                 if (n->flags & NODE_DELIMC)                  if (n->flags & NODE_DELIMC)
                         outflags &= ~(MD_spc | MD_spc_force);                          outflags &= ~(MD_spc | MD_spc_force);
                 else if (outflags & MD_Sm)                  else if (outflags & MD_Sm)
Line 315  md_node(struct roff_node *n)
Line 327  md_node(struct roff_node *n)
                         outflags &= ~(MD_spc | MD_spc_force);                          outflags &= ~(MD_spc | MD_spc_force);
                 else if (outflags & MD_Sm)                  else if (outflags & MD_Sm)
                         outflags |= MD_spc;                          outflags |= MD_spc;
                 break;          } else if (n->tok < ROFF_MAX) {
         default:                  switch (n->tok) {
                 act = md_acts + 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);                  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))
                         process_children = (*act->pre)(n);                          process_children = (*act->pre)(n);
                 break;  
         }          }
   
         if (process_children && n->child != NULL)          if (process_children && n->child != NULL)
Line 370  md_stack(char c)
Line 392  md_stack(char c)
 static void  static void
 md_preword(void)  md_preword(void)
 {  {
           const char      *cp;
   
         /*          /*
          * If a list block is nested inside a code block or a blockquote,           * If a list block is nested inside a code block or a blockquote,
          * blank lines for paragraph breaks no longer work; instead,           * blank lines for paragraph breaks no longer work; instead,
          * they terminate the list.  Work around this markdown issue           * they terminate the list.  Work around this markdown issue
          * by using mere line breaks instead.           * by using mere line breaks instead.
          */           */
   
         if (list_blocks && outflags & MD_sp) {          if (list_blocks && outflags & MD_sp) {
                 outflags &= ~MD_sp;                  outflags &= ~MD_sp;
                 outflags |= MD_br;                  outflags |= MD_br;
         }          }
   
         /* End the old line if requested. */          /*
            * End the old line if requested.
            * Escape whitespace at the end of the markdown line
            * such that it won't look like an output line break.
            */
   
         if (outflags & MD_sp)          if (outflags & MD_sp)
                 putchar('\n');                  putchar('\n');
         else if (outflags & MD_br) {          else if (outflags & MD_br) {
                 putchar(' ');                  putchar(' ');
                 putchar(' ');                  putchar(' ');
 #ifdef DEBUG          } else if (outflags & MD_nl && escflags & ESC_EOL)
                 putchar(':');                  md_named("zwnj");
                 putchar(':');  
                 putchar(' ');  
                 putchar(' ');  
 #endif  
         }  
   
         /* Start a new line if necessary. */          /* Start a new line if necessary. */
   
         if (outflags & (MD_nl | MD_br | MD_sp)) {          if (outflags & (MD_nl | MD_br | MD_sp)) {
                 putchar('\n');                  putchar('\n');
                 fputs(md_stack('\0'), stdout);                  for (cp = md_stack('\0'); *cp != '\0'; cp++) {
                           putchar(*cp);
                           if (*cp == '>')
                                   putchar(' ');
                   }
                 outflags &= ~(MD_nl | MD_br | MD_sp);                  outflags &= ~(MD_nl | MD_br | MD_sp);
                 escflags = ESC_BOL;                  escflags = ESC_BOL;
                 outcount = 0;                  outcount = 0;
Line 433  md_rawword(const char *s)
Line 461  md_rawword(const char *s)
 {  {
         md_preword();          md_preword();
   
         if (*s == 0)          if (*s == '\0')
                 return;                  return;
   
         if (escflags & ESC_FON) {          if (escflags & ESC_FON) {
Line 444  md_rawword(const char *s)
Line 472  md_rawword(const char *s)
   
         while (*s != '\0') {          while (*s != '\0') {
                 switch(*s) {                  switch(*s) {
                 case '(':  
                         escflags |= ESC_PAR;  
                         break;  
                 case ')':  
                         escflags |= ~ESC_PAR;  
                         break;  
                 case '*':                  case '*':
                         if (s[1] == '\0')                          if (s[1] == '\0')
                                 escflags |= ESC_FON;                                  escflags |= ESC_FON;
Line 466  md_rawword(const char *s)
Line 488  md_rawword(const char *s)
                 }                  }
                 md_char(*s++);                  md_char(*s++);
         }          }
           if (s[-1] == ' ')
                   escflags |= ESC_EOL;
           else
                   escflags &= ~ESC_EOL;
 }  }
   
 /*  /*
Line 476  md_word(const char *s)
Line 502  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 486  md_word(const char *s)
Line 512  md_word(const char *s)
   
         md_preword();          md_preword();
   
           if (*s == '\0')
                   return;
   
         /* No spacing after opening delimiters. */          /* No spacing after opening delimiters. */
         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 517  md_word(const char *s)
Line 547  md_word(const char *s)
                         bs = escflags & ESC_HYP && !code_blocks;                          bs = escflags & ESC_HYP && !code_blocks;
                         break;                          break;
                 case ')':                  case ')':
                         bs = escflags & ESC_PAR && !code_blocks;                          bs = escflags & ESC_NUM && !code_blocks;
                         break;                          break;
                 case '*':                  case '*':
                 case '[':                  case '[':
Line 559  md_word(const char *s)
Line 589  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:
                                 nextfont = "**";                                  nextfont = "**";
                                 break;                                  break;
Line 569  md_word(const char *s)
Line 605  md_word(const char *s)
                                 nextfont = "***";                                  nextfont = "***";
                                 break;                                  break;
                         case ESCAPE_FONT:                          case ESCAPE_FONT:
                           case ESCAPE_FONTCW:
                         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 622  md_word(const char *s)
Line 662  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;
                 md_rawword(currfont);                  md_rawword(currfont);
         }          } else if (s[-2] == ' ')
                   escflags |= ESC_EOL;
           else
                   escflags &= ~ESC_EOL;
 }  }
   
 /*  /*
Line 636  static void
Line 686  static void
 md_named(const char *s)  md_named(const char *s)
 {  {
         printf("&%s;", s);          printf("&%s;", s);
         escflags &= ~ESC_FON;          escflags &= ~(ESC_FON | ESC_EOL);
         outcount++;          outcount++;
 }  }
   
Line 678  md_cond_body(struct roff_node *n)
Line 728  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 == '`')
                           code_blocks++;
         }          }
         return 1;          return 1;
 }  }
Line 694  md_post_raw(struct roff_node *n)
Line 752  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 == '`')
                           code_blocks--;
         }          }
 }  }
   
Line 705  md_pre_word(struct roff_node *n)
Line 765  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 717  md_post_word(struct roff_node *n)
Line 777  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 782  md_pre_syn(struct roff_node *n)
Line 842  md_pre_syn(struct roff_node *n)
 }  }
   
 static int  static int
   md_pre_An(struct roff_node *n)
   {
           switch (n->norm->An.auth) {
           case AUTH_split:
                   outflags &= ~MD_An_nosplit;
                   outflags |= MD_An_split;
                   return 0;
           case AUTH_nosplit:
                   outflags &= ~MD_An_split;
                   outflags |= MD_An_nosplit;
                   return 0;
           default:
                   if (outflags & MD_An_split)
                           outflags |= MD_br;
                   else if (n->sec == SEC_AUTHORS &&
                       ! (outflags & MD_An_nosplit))
                           outflags |= MD_An_split;
                   return 1;
           }
   }
   
   static int
 md_pre_Ap(struct roff_node *n)  md_pre_Ap(struct roff_node *n)
 {  {
         outflags &= ~MD_spc;          outflags &= ~MD_spc;
Line 931  md_pre_Eo(struct roff_node *n)
Line 1013  md_pre_Eo(struct roff_node *n)
 static void  static void
 md_post_Eo(struct roff_node *n)  md_post_Eo(struct roff_node *n)
 {  {
         int      body, tail;  
   
         if (n->end != ENDBODY_NOT) {          if (n->end != ENDBODY_NOT) {
                 outflags |= MD_spc;                  outflags |= MD_spc;
                 return;                  return;
         }          }
   
         body = n->child != NULL || n->parent->head->child != NULL;          if (n->child == NULL && n->parent->head->child == NULL)
         tail = n->parent->tail != NULL && n->parent->tail->child != NULL;                  return;
   
         if (body && tail)          if (n->parent->tail != NULL && n->parent->tail->child != NULL)
                 outflags &= ~MD_spc;                  outflags &= ~MD_spc;
         else if ( ! (body || tail))          else
                 md_preword();  
         else if ( ! tail)  
                 outflags |= MD_spc;                  outflags |= MD_spc;
 }  }
   
Line 993  md_post_Fd(struct roff_node *n)
Line 1071  md_post_Fd(struct roff_node *n)
         outflags |= MD_br;          outflags |= MD_br;
 }  }
   
   static void
   md_post_Fl(struct roff_node *n)
   {
           md_post_raw(n);
           if (n->child == NULL && n->next != NULL &&
               n->next->type != ROFFT_TEXT && !(n->next->flags & NODE_LINE))
                   outflags &= ~MD_spc;
   }
   
 static int  static int
 md_pre_Fn(struct roff_node *n)  md_pre_Fn(struct roff_node *n)
 {  {
Line 1067  md_pre_In(struct roff_node *n)
Line 1154  md_pre_In(struct roff_node *n)
 {  {
         if (n->flags & NODE_SYNPRETTY) {          if (n->flags & NODE_SYNPRETTY) {
                 md_pre_syn(n);                  md_pre_syn(n);
                 md_pre_raw(n);                  md_rawword("**");
                 md_rawword("*");  
                 outflags &= ~MD_spc;                  outflags &= ~MD_spc;
                 md_word("#include <");                  md_word("#include <");
                 outflags &= ~MD_spc;  
         } else {          } else {
                 md_word("<");                  md_word("<");
                 outflags &= ~MD_spc;                  outflags &= ~MD_spc;
                 md_pre_raw(n);                  md_rawword("*");
         }          }
           outflags &= ~MD_spc;
         return 1;          return 1;
 }  }
   
Line 1085  md_post_In(struct roff_node *n)
Line 1171  md_post_In(struct roff_node *n)
 {  {
         if (n->flags & NODE_SYNPRETTY) {          if (n->flags & NODE_SYNPRETTY) {
                 outflags &= ~MD_spc;                  outflags &= ~MD_spc;
                 md_rawword(">*");                  md_rawword(">**");
                 md_post_raw(n);  
                 outflags |= MD_nl;                  outflags |= MD_nl;
         } else {          } else {
                 md_post_raw(n);  
                 outflags &= ~MD_spc;                  outflags &= ~MD_spc;
                 md_rawword(">");                  md_rawword("*>");
         }          }
 }  }
   
Line 1106  md_pre_It(struct roff_node *n)
Line 1190  md_pre_It(struct roff_node *n)
   
         case ROFFT_HEAD:          case ROFFT_HEAD:
                 bln = n->parent->parent;                  bln = n->parent->parent;
                 if (bln->norm->Bl.comp == 0)                  if (bln->norm->Bl.comp == 0 &&
                       bln->norm->Bl.type != LIST_column)
                         outflags |= MD_sp;                          outflags |= MD_sp;
                 outflags |= MD_nl;                  outflags |= MD_nl;
   
Line 1132  md_pre_It(struct roff_node *n)
Line 1217  md_pre_It(struct roff_node *n)
                         break;                          break;
                 case LIST_enum:                  case LIST_enum:
                         md_preword();                          md_preword();
                         printf("%d.\t", ++bln->norm->Bl.count);                          if (bln->norm->Bl.count < 99)
                                   bln->norm->Bl.count++;
                           printf("%d.\t", bln->norm->Bl.count);
                         escflags &= ~ESC_FON;                          escflags &= ~ESC_FON;
                         break;                          break;
                   case LIST_column:
                           outflags |= MD_br;
                           return 0;
                 default:                  default:
                         return 0;                          return 0;
                 }                  }
Line 1200  md_post_It(struct roff_node *n)
Line 1290  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 1231  md_post_Lb(struct roff_node *n)
Line 1321  md_post_Lb(struct roff_node *n)
                 outflags |= MD_br;                  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  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;
   
         if ((descr = link->next) != NULL) {          /* Find beginning of trailing punctuation. */
                 md_rawword("[");          punct = n->last;
                 outflags &= ~MD_spc;          while (punct != link && punct->flags & NODE_DELIMC)
                 while (descr != NULL) {                  punct = punct->prev;
                         md_word(descr->string);          punct = punct->next;
                         descr = descr->next;  
                 }  
                 outflags &= ~MD_spc;  
                 md_rawword("](");  
         } else  
                 md_rawword("<");  
   
           /* Link text. */
           descr = link->next;
           if (descr == punct)
                   descr = link;  /* no text */
           md_rawword("[");
         outflags &= ~MD_spc;          outflags &= ~MD_spc;
         md_word(link->string);          do {
                   md_word(descr->string);
                   descr = descr->next;
           } while (descr != punct);
         outflags &= ~MD_spc;          outflags &= ~MD_spc;
         md_rawword(link->next == NULL ? ">" : ")");  
           /* 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;          return 0;
 }  }
   
 static int  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(")");
           return 0;
   }
   
   static int
 md_pre_Nd(struct roff_node *n)  md_pre_Nd(struct roff_node *n)
 {  {
         outflags &= ~MD_nl;          outflags &= ~MD_nl;
Line 1341  static int
Line 1482  static int
 md_pre_Sh(struct roff_node *n)  md_pre_Sh(struct roff_node *n)
 {  {
         switch (n->type) {          switch (n->type) {
           case ROFFT_BLOCK:
                   if (n->sec == SEC_AUTHORS)
                           outflags &= ~(MD_An_split | MD_An_nosplit);
                   break;
         case ROFFT_HEAD:          case ROFFT_HEAD:
                 outflags |= MD_sp;                  outflags |= MD_sp;
                 md_rawword(n->tok == MDOC_Sh ? "#" : "##");                  md_rawword(n->tok == MDOC_Sh ? "#" : "##");

Legend:
Removed from v.1.2  
changed lines
  Added in v.1.31

CVSweb