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

Diff for /docbook2mdoc/macro.c between version 1.1 and 1.20

version 1.1, 2019/03/26 19:17:29 version 1.20, 2019/05/02 12:40:42
Line 17 
Line 17 
 #include <assert.h>  #include <assert.h>
 #include <ctype.h>  #include <ctype.h>
 #include <stdio.h>  #include <stdio.h>
   #include <string.h>
   
 #include "node.h"  #include "node.h"
 #include "macro.h"  #include "macro.h"
Line 27 
Line 28 
  */   */
   
 void  void
   para_check(struct format *f)
   {
           if (f->parastate != PARA_WANT)
                   return;
           if (f->linestate != LINE_NEW) {
                   putchar('\n');
                   f->linestate = LINE_NEW;
           }
           puts(".Pp");
           f->parastate = PARA_HAVE;
   }
   
   void
 macro_open(struct format *f, const char *name)  macro_open(struct format *f, const char *name)
 {  {
           para_check(f);
         switch (f->linestate) {          switch (f->linestate) {
           case LINE_MACRO:
                   if (f->flags & FMT_NOSPC) {
                           fputs(" Ns ", stdout);
                           break;
                   }
                   if (f->nofill || f->flags & (FMT_CHILD | FMT_IMPL)) {
                           putchar(' ');
                           break;
                   }
                   /* FALLTHROUGH */
         case LINE_TEXT:          case LINE_TEXT:
                   if (f->nofill && f->linestate == LINE_TEXT)
                           fputs(" \\c", stdout);
                 putchar('\n');                  putchar('\n');
                 /* FALLTHROUGH */                  /* FALLTHROUGH */
         case LINE_NEW:          case LINE_NEW:
                 putchar('.');                  putchar('.');
                 f->linestate = LINE_MACRO;                  f->linestate = LINE_MACRO;
                   f->flags = 0;
                 break;                  break;
         case LINE_MACRO:  
                 putchar(' ');  
                 break;  
         }          }
         fputs(name, stdout);          fputs(name, stdout);
           f->flags &= FMT_IMPL;
           f->flags |= FMT_ARG;
           f->parastate = PARA_MID;
 }  }
   
 void  void
 macro_close(struct format *f)  macro_close(struct format *f)
 {  {
         assert(f->linestate == LINE_MACRO);          if (f->linestate != LINE_NEW)
         putchar('\n');                  putchar('\n');
         f->linestate = LINE_NEW;          f->linestate = LINE_NEW;
           f->flags = 0;
 }  }
   
 void  void
 macro_line(struct format *f, const char *name)  macro_line(struct format *f, const char *name)
 {  {
           macro_close(f);
         macro_open(f, name);          macro_open(f, name);
         macro_close(f);          macro_close(f);
 }  }
   
 /*  /*
  * If the next node is a text node starting with closing punctuation,  
  * emit the closing punctuation as a trailing macro argument.  
  */  
 void  
 macro_closepunct(struct format *f, struct pnode *pn)  
 {  
         if ((pn = TAILQ_NEXT(pn, child)) != NULL &&  
             pn->node == NODE_TEXT && pn->bsz > 0 &&  
             (pn->b[0] == ',' || pn->b[0] == '.') &&  
             (pn->bsz == 1 || isspace((unsigned char)pn->b[1]))) {  
                 putchar(' ');  
                 putchar(pn->b[0]);  
                 pn->b++;  
                 pn->bsz--;  
         }  
         macro_close(f);  
 }  
   
 /*  
  * Print an argument string on a macro line, collapsing whitespace.   * Print an argument string on a macro line, collapsing whitespace.
  */   */
 void  void
 macro_addarg(struct format *f, const char *arg, int flags)  macro_addarg(struct format *f, const char *arg, int flags)
 {  {
         const char      *cp;          const char      *cp;
           int              quote_now;
   
         assert(f->linestate == LINE_MACRO);          assert(f->linestate == LINE_MACRO);
   
         /* Quote if requested and necessary. */          /* Quote if requested and necessary. */
   
           quote_now = 0;
         if ((flags & (ARG_SINGLE | ARG_QUOTED)) == ARG_SINGLE) {          if ((flags & (ARG_SINGLE | ARG_QUOTED)) == ARG_SINGLE) {
                 for (cp = arg; *cp != '\0'; cp++)                  for (cp = arg; *cp != '\0'; cp++)
                         if (isspace((unsigned char)*cp))                          if (isspace((unsigned char)*cp))
Line 101  macro_addarg(struct format *f, const char *arg, int fl
Line 114  macro_addarg(struct format *f, const char *arg, int fl
                         }                          }
                         putchar('"');                          putchar('"');
                         flags = ARG_QUOTED;                          flags = ARG_QUOTED;
                           quote_now = 1;
                 }                  }
         }          }
   
Line 118  macro_addarg(struct format *f, const char *arg, int fl
Line 132  macro_addarg(struct format *f, const char *arg, int fl
   
                 /* Escape us if we look like a macro. */                  /* Escape us if we look like a macro. */
   
                 if ((flags & ARG_QUOTED) == 0 &&                  if ((flags & (ARG_QUOTED | ARG_UPPER)) == 0 &&
                     (cp == arg || isspace((unsigned char)cp[-1])) &&                      (cp == arg || isspace((unsigned char)cp[-1])) &&
                     isupper((unsigned char)cp[0]) &&                      isupper((unsigned char)cp[0]) &&
                     islower((unsigned char)cp[1]) &&                      islower((unsigned char)cp[1]) &&
                     (cp[2] == '\0' || cp[2] == ' ' ||                      (cp[2] == '\0' || cp[2] == ' ' ||
                      (islower((unsigned char)cp[2]) &&                       ((cp[3] == '\0' || cp[3] == ' ') &&
                       (cp[3] == '\0' || cp[3] == ' '))))                        (strncmp(cp, "Brq", 3) == 0 ||
                          strncmp(cp, "Bro", 3) == 0 ||
                          strncmp(cp, "Brc", 3) == 0 ||
                          strncmp(cp, "Bsx", 3) == 0))))
                         fputs("\\&", stdout);                          fputs("\\&", stdout);
   
                 if (*cp == '"')                  if (*cp == '"')
Line 136  macro_addarg(struct format *f, const char *arg, int fl
Line 153  macro_addarg(struct format *f, const char *arg, int fl
                 if (*cp == '\\')                  if (*cp == '\\')
                         putchar('e');                          putchar('e');
         }          }
           if (quote_now)
                   putchar('"');
           f->parastate = PARA_MID;
 }  }
   
 void  void
Line 150  macro_argline(struct format *f, const char *name, cons
Line 170  macro_argline(struct format *f, const char *name, cons
  * Recursively append text from the children of a node to a macro line.   * Recursively append text from the children of a node to a macro line.
  */   */
 void  void
 macro_addnode(struct format *f, struct pnode *pn, int flags)  macro_addnode(struct format *f, struct pnode *n, int flags)
 {  {
         int              quote_now;          struct pnode    *nc;
           int              is_text, quote_now;
   
         assert(f->linestate == LINE_MACRO);          assert(f->linestate == LINE_MACRO);
   
         /*          /*
          * If the only child is a text node, just add that text,           * If this node or its only child is a text node, just add
          * letting macro_addarg() decide about quoting.           * that text, letting macro_addarg() decide about quoting.
          */           */
   
         pn = TAILQ_FIRST(&pn->childq);          while ((nc = TAILQ_FIRST(&n->childq)) != NULL &&
         if (pn != NULL && pn->node == NODE_TEXT &&              TAILQ_NEXT(nc, child) == NULL)
             TAILQ_NEXT(pn, child) == NULL) {                  n = nc;
                 macro_addarg(f, pn->b, flags);  
           if (n->node == NODE_TEXT || n->node == NODE_ESCAPE) {
                   macro_addarg(f, n->b, flags);
                   f->parastate = PARA_MID;
                 return;                  return;
         }          }
   
Line 192  macro_addnode(struct format *f, struct pnode *pn, int 
Line 216  macro_addnode(struct format *f, struct pnode *pn, int 
          * inserting whitespace between nodes.           * inserting whitespace between nodes.
          */           */
   
         while (pn != NULL) {          while (nc != NULL) {
                 if (pn->node == NODE_TEXT)                  macro_addnode(f, nc, flags);
                         macro_addarg(f, pn->b, flags);                  is_text = pnode_class(nc->node) == CLASS_TEXT;
                   nc = TAILQ_NEXT(nc, child);
                   if (nc == NULL || pnode_class(nc->node) != CLASS_TEXT)
                           is_text = 0;
                   if (is_text && (nc->flags & NFLAG_SPC) == 0)
                           flags &= ~ARG_SPACE;
                 else                  else
                         macro_addnode(f, pn, flags);                          flags |= ARG_SPACE;
                 pn = TAILQ_NEXT(pn, child);  
                 flags |= ARG_SPACE;  
         }          }
         if (quote_now)          if (quote_now)
                 putchar('"');                  putchar('"');
           f->parastate = PARA_MID;
 }  }
   
 void  void
 macro_nodeline(struct format *f, const char *name, struct pnode *pn, int flags)  macro_nodeline(struct format *f, const char *name, struct pnode *n, int flags)
 {  {
         macro_open(f, name);          macro_open(f, name);
         macro_addnode(f, pn, ARG_SPACE | flags);          macro_addnode(f, n, ARG_SPACE | flags);
         macro_close(f);          macro_close(f);
   }
   
   
   /*
    * Print a word on the current text line if one is open, or on a new text
    * line otherwise.  The flag ARG_SPACE inserts spaces between words.
    */
   void
   print_text(struct format *f, const char *word, int flags)
   {
           int      ateos, inword;
   
           para_check(f);
           switch (f->linestate) {
           case LINE_NEW:
                   break;
           case LINE_TEXT:
                   if (flags & ARG_SPACE)
                           putchar(' ');
                   break;
           case LINE_MACRO:
                   macro_close(f);
                   break;
           }
           if (f->linestate == LINE_NEW && (*word == '.' || *word == '\''))
                   fputs("\\&", stdout);
           ateos = inword = 0;
           while (*word != '\0') {
                   if (f->nofill == 0) {
                           switch (*word) {
                           case ' ':
                                   if (ateos == 0) {
                                           inword = 0;
                                           break;
                                   }
                                   ateos = inword = 0;
                                   /* Handle the end of a sentence. */
                                   while (*word == ' ')
                                           word++;
                                   switch (*word) {
                                   case '\0':
                                           break;
                                   case '\'':
                                   case '.':
                                           fputs("\n\\&", stdout);
                                           break;
                                   default:
                                           putchar('\n');
                                           break;
                                   }
                                   continue;
                           /* Detect the end of a sentence. */
                           case '!':
                           case '.':
                           case '?':
                                   if (inword > 1 &&
                                       (word[-2] != 'n' || word[-1] != 'c') &&
                                       (word[-2] != 'v' || word[-1] != 's'))
                                           ateos = 1;
                                   /* FALLTHROUGH */
                           case '"':
                           case '\'':
                           case ')':
                           case ']':
                                   inword = 0;
                                   break;
                           default:
                                   if (isalnum((unsigned char)*word))
                                           inword++;
                                   ateos = 0;
                                   break;
                           }
                   }
                   putchar(*word);
                   if (*word++ == '\\')
                           putchar('e');
           }
           f->linestate = LINE_TEXT;
           f->parastate = PARA_MID;
           f->flags = 0;
   }
   
   /*
    * Recursively print the content of a node on a text line.
    */
   void
   print_textnode(struct format *f, struct pnode *n)
   {
           struct pnode    *nc;
   
           if (n->node == NODE_TEXT || n->node == NODE_ESCAPE)
                   print_text(f, n->b, ARG_SPACE);
           else
                   TAILQ_FOREACH(nc, &n->childq, child)
                           print_textnode(f, nc);
 }  }

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.20

CVSweb