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

Diff for /docbook2mdoc/docbook2mdoc.c between version 1.5 and 1.12

version 1.5, 2014/03/28 10:03:36 version 1.12, 2014/03/29 22:44:06
Line 24 
Line 24 
 #include <stdio.h>  #include <stdio.h>
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
   #include <unistd.h>
   
 /*  /*
  * All recognised node types.   * All recognised node types.
Line 58  enum nodeid {
Line 59  enum nodeid {
         NODE_REFPURPOSE,          NODE_REFPURPOSE,
         NODE_REFSECT1,          NODE_REFSECT1,
         NODE_REFSYNOPSISDIV,          NODE_REFSYNOPSISDIV,
           NODE_STRUCTNAME,
         NODE_SYNOPSIS,          NODE_SYNOPSIS,
         NODE_TEXT,          NODE_TEXT,
         NODE_TITLE,          NODE_TITLE,
Line 65  enum nodeid {
Line 67  enum nodeid {
 };  };
   
 /*  /*
    * All recognised attribute keys.
    */
   enum    attrkey {
           /* Alpha-order... */
           ATTRKEY_CHOICE = 0,
           ATTRKEY_ID,
           ATTRKEY_REP,
           ATTRKEY__MAX
   };
   
   /*
    * All [explicitly] recognised attribute values.
    * If an attribute has ATTRVAL__MAX, it could be a free-form.
    */
   enum    attrval {
           /* Alpha-order... */
           ATTRVAL_NOREPEAT,
           ATTRVAL_OPT,
           ATTRVAL_PLAIN,
           ATTRVAL_REPEAT,
           ATTRVAL_REQ,
           ATTRVAL__MAX
   };
   
   /*
  * Global parse state.   * Global parse state.
  * Keep this as simple and small as possible.   * Keep this as simple and small as possible.
  */   */
 struct  parse {  struct  parse {
           XML_Parser       xml;
         enum nodeid      node; /* current (NODE_ROOT if pre-tree) */          enum nodeid      node; /* current (NODE_ROOT if pre-tree) */
           const char      *fname; /* filename */
         int              stop; /* should we stop now? */          int              stop; /* should we stop now? */
         struct pnode    *root; /* root of parse tree */          struct pnode    *root; /* root of parse tree */
         struct pnode    *cur; /* current node in tree */          struct pnode    *cur; /* current node in tree */
         char            *b;          char            *b; /* nil-terminated buffer for pre-print */
         size_t           bsz;          size_t           bsz; /* current length of b */
         size_t           mbsz;          size_t           mbsz; /* max bsz allocation */
           int              newln; /* output: are we on a fresh line */
 };  };
   
 struct  node {  struct  node {
         const char      *name;          const char      *name; /* docbook element name */
         unsigned int     flags;          unsigned int     flags;
 #define NODE_IGNTEXT     1 /* ignore all contained text */  #define NODE_IGNTEXT     1 /* ignore all contained text */
 };  };
   
 TAILQ_HEAD(pnodeq, pnode);  TAILQ_HEAD(pnodeq, pnode);
   TAILQ_HEAD(pattrq, pattr);
   
   struct  pattr {
           enum attrkey     key;
           enum attrval     val;
           char            *rawval;
           TAILQ_ENTRY(pattr) child;
   };
   
 struct  pnode {  struct  pnode {
         enum nodeid      node; /* node type */          enum nodeid      node; /* node type */
         char            *b; /* binary data buffer */          char            *b; /* binary data buffer */
         size_t           bsz; /* data buffer size */          size_t           bsz; /* data buffer size */
         struct pnode    *parent; /* parent (or NULL if top) */          struct pnode    *parent; /* parent (or NULL if top) */
         struct pnodeq    childq; /* queue of children */          struct pnodeq    childq; /* queue of children */
           struct pattrq    attrq; /* attributes of node */
         TAILQ_ENTRY(pnode) child;          TAILQ_ENTRY(pnode) child;
 };  };
   
   static  const char *attrkeys[ATTRKEY__MAX] = {
           "choice",
           "id",
           "rep"
   };
   
   static  const char *attrvals[ATTRVAL__MAX] = {
           "norepeat",
           "opt",
           "plain",
           "repeat",
           "req"
   };
   
 static  const struct node nodes[NODE__MAX] = {  static  const struct node nodes[NODE__MAX] = {
         { NULL, 0 },          { NULL, 0 },
         { "arg", 0 },          { "arg", 0 },
Line 124  static const struct node nodes[NODE__MAX] = {
Line 177  static const struct node nodes[NODE__MAX] = {
         { "refpurpose", 0 },          { "refpurpose", 0 },
         { "refsect1", 0 },          { "refsect1", 0 },
         { "refsynopsisdiv", NODE_IGNTEXT },          { "refsynopsisdiv", NODE_IGNTEXT },
           { "structname", 0 },
         { "synopsis", 0 },          { "synopsis", 0 },
         { NULL, 0 },          { NULL, 0 },
         { "title", 0 },          { "title", 0 },
 };  };
   
   static void
   pnode_print(struct parse *p, struct pnode *pn);
   
   static int
   isattrkey(enum nodeid node, enum attrkey key)
   {
   
           switch (key) {
           case (ATTRKEY_CHOICE):
                   return(node == NODE_ARG);
           case (ATTRKEY_ID):
                   /* Common to all. */
                   return(1);
           case (ATTRKEY_REP):
                   return(node == NODE_ARG);
           default:
                   break;
           }
           abort();
           return(0);
   }
   
   static int
   isattrval(enum attrkey key, enum attrval val)
   {
   
           switch (val) {
           case (ATTRVAL_OPT):
           case (ATTRVAL_PLAIN):
           case (ATTRVAL_REQ):
                   return(key == ATTRKEY_CHOICE);
           case (ATTRVAL_REPEAT):
           case (ATTRVAL_NOREPEAT):
                   return(key == ATTRKEY_REP);
           default:
                   break;
           }
           abort();
           return(0);
   }
   
 /*  /*
  * Look up whether "parent" is a valid parent for "node".   * Look up whether "parent" is a valid parent for "node".
    * This is sucked directly from the DocBook specification: look at the
    * "children" and "parent" sections of each node.
  */   */
 static int  static int
 isparent(enum nodeid node, enum nodeid parent)  isparent(enum nodeid node, enum nodeid parent)
Line 334  isparent(enum nodeid node, enum nodeid parent)
Line 431  isparent(enum nodeid node, enum nodeid parent)
                 return(parent == NODE_REFENTRY);                  return(parent == NODE_REFENTRY);
         case (NODE_REFSYNOPSISDIV):          case (NODE_REFSYNOPSISDIV):
                 return(parent == NODE_REFENTRY);                  return(parent == NODE_REFENTRY);
           case (NODE_STRUCTNAME):
                   switch (parent) {
                   case (NODE_CODE):
                   case (NODE_FUNCSYNOPSISINFO):
                   case (NODE_FUNCTION):
                   case (NODE_OPTION):
                   case (NODE_PARA):
                   case (NODE_PARAMETER):
                   case (NODE_PROGRAMLISTING):
                   case (NODE_REFDESCRIPTOR):
                   case (NODE_REFENTRYTITLE):
                   case (NODE_REFNAME):
                   case (NODE_REFPURPOSE):
                   case (NODE_SYNOPSIS):
                   case (NODE_TITLE):
                           return(1);
                   default:
                           break;
                   }
                   return(0);
         case (NODE_SYNOPSIS):          case (NODE_SYNOPSIS):
                 switch (parent) {                  switch (parent) {
                 case (NODE_REFSYNOPSISDIV):                  case (NODE_REFSYNOPSISDIV):
Line 362  isparent(enum nodeid node, enum nodeid parent)
Line 479  isparent(enum nodeid node, enum nodeid parent)
         return(0);          return(0);
 }  }
   
   /*
    * Process a stream of characters.
    * We store text as nodes in and of themselves.
    * If a text node is already open, append to it.
    * If it's not open, open one under the current context.
    */
 static void  static void
 xml_char(void *arg, const XML_Char *p, int sz)  xml_char(void *arg, const XML_Char *p, int sz)
 {  {
Line 383  xml_char(void *arg, const XML_Char *p, int sz)
Line 506  xml_char(void *arg, const XML_Char *p, int sz)
          * If we're not processing text right now, then create a text           * If we're not processing text right now, then create a text
          * node for doing so.           * node for doing so.
          * However, don't do so unless we have some non-whitespace to           * However, don't do so unless we have some non-whitespace to
          * process!           * process: strip out all leading whitespace to be sure.
          */           */
         if (NODE_TEXT != ps->node) {          if (NODE_TEXT != ps->node) {
                 for (i = 0; i < sz; i++)                  for (i = 0; i < sz; i++)
Line 391  xml_char(void *arg, const XML_Char *p, int sz)
Line 514  xml_char(void *arg, const XML_Char *p, int sz)
                                 break;                                  break;
                 if (i == sz)                  if (i == sz)
                         return;                          return;
                   p += i;
                   sz -= i;
                 dat = calloc(1, sizeof(struct pnode));                  dat = calloc(1, sizeof(struct pnode));
                 if (NULL == dat) {                  if (NULL == dat) {
                         perror(NULL);                          perror(NULL);
Line 400  xml_char(void *arg, const XML_Char *p, int sz)
Line 525  xml_char(void *arg, const XML_Char *p, int sz)
                 dat->node = ps->node = NODE_TEXT;                  dat->node = ps->node = NODE_TEXT;
                 dat->parent = ps->cur;                  dat->parent = ps->cur;
                 TAILQ_INIT(&dat->childq);                  TAILQ_INIT(&dat->childq);
                   TAILQ_INIT(&dat->attrq);
                 TAILQ_INSERT_TAIL(&ps->cur->childq, dat, child);                  TAILQ_INSERT_TAIL(&ps->cur->childq, dat, child);
                 ps->cur = dat;                  ps->cur = dat;
                 assert(NULL != ps->root);                  assert(NULL != ps->root);
   
         }          }
   
         /* Append to current buffer. */          /* Append to current buffer. */
Line 418  xml_char(void *arg, const XML_Char *p, int sz)
Line 543  xml_char(void *arg, const XML_Char *p, int sz)
         ps->cur->bsz += (size_t)sz;          ps->cur->bsz += (size_t)sz;
 }  }
   
   static void
   pnode_trim(struct pnode *pn)
   {
   
           assert(NODE_TEXT == pn->node);
           for ( ; pn->bsz > 0; pn->bsz--)
                   if ( ! isspace((int)pn->b[pn->bsz - 1]))
                           break;
   }
   
 /*  /*
  * Begin an element.   * Begin an element.
  * First, look for the element.   * First, look for the element.
  * If we don't find it and we're not parsing, keep going.   * If we don't find it and we're not parsing, keep going.
  * If we don't find it (and we're parsing), puke and exit.   * If we don't find it and we're parsing, puke and exit.
  * If we find it but we're not parsing yet (i.e., it's not a refentry   * If we find it but we're not parsing yet (i.e., it's not a refentry
  * and thus out of context), keep going.   * and thus out of context), keep going.
  * If we're at the root and already have a tree, puke and exit.   * If we find it and we're at the root and already have a tree, puke and
    * exit (FIXME: I don't think this is right?).
    * If we find it but we're parsing a text node, close out the text node,
    * return to its parent, and keep going.
  * Make sure that the element is in the right context.   * Make sure that the element is in the right context.
  * Lastly, put the node onto our parse tree and continue.   * Lastly, put the node onto our parse tree and continue.
  */   */
 static void  static void
 xml_elem_start(void *arg, const XML_Char *name, const XML_Char **atts)  xml_elem_start(void *arg, const XML_Char *name, const XML_Char **atts)
 {  {
         struct parse    *ps = arg;          struct parse     *ps = arg;
         enum nodeid      node;          enum nodeid       node;
         struct pnode    *dat;          enum attrkey      key;
           enum attrval      val;
           struct pnode     *dat;
           struct pattr     *pattr;
           const XML_Char  **att;
   
         if (ps->stop)          if (ps->stop)
                 return;                  return;
Line 442  xml_elem_start(void *arg, const XML_Char *name, const 
Line 584  xml_elem_start(void *arg, const XML_Char *name, const 
         /* Close out text node, if applicable... */          /* Close out text node, if applicable... */
         if (NODE_TEXT == ps->node) {          if (NODE_TEXT == ps->node) {
                 assert(NULL != ps->cur);                  assert(NULL != ps->cur);
                   pnode_trim(ps->cur);
                 ps->cur = ps->cur->parent;                  ps->cur = ps->cur->parent;
                 assert(NULL != ps->cur);                  assert(NULL != ps->cur);
                 ps->node = ps->cur->node;                  ps->node = ps->cur->node;
Line 454  xml_elem_start(void *arg, const XML_Char *name, const 
Line 597  xml_elem_start(void *arg, const XML_Char *name, const 
                         break;                          break;
   
         if (NODE__MAX == node && NODE_ROOT == ps->node) {          if (NODE__MAX == node && NODE_ROOT == ps->node) {
                 fprintf(stderr, "%s: ignoring node\n", name);  
                 return;                  return;
         } else if (NODE__MAX == node) {          } else if (NODE__MAX == node) {
                 fprintf(stderr, "%s: unknown node\n", name);                  fprintf(stderr, "%s:%zu:%zu: unknown node \"%s\"\n",
                           ps->fname, XML_GetCurrentLineNumber(ps->xml),
                           XML_GetCurrentColumnNumber(ps->xml), name);
                 ps->stop = 1;                  ps->stop = 1;
                 return;                  return;
         } else if (NODE_ROOT == ps->node && NULL != ps->root) {          } else if (NODE_ROOT == ps->node && NULL != ps->root) {
                 fprintf(stderr, "%s: reentering?\n", name);                  fprintf(stderr, "%s:%zu:%zu: multiple refentries\n",
                           ps->fname, XML_GetCurrentLineNumber(ps->xml),
                           XML_GetCurrentColumnNumber(ps->xml));
                 ps->stop = 1;                  ps->stop = 1;
                 return;                  return;
         } else if (NODE_ROOT == ps->node && NODE_REFENTRY != node) {          } else if (NODE_ROOT == ps->node && NODE_REFENTRY != node) {
                 fprintf(stderr, "%s: known node w/o context\n", name);  
                 return;                  return;
         } else if ( ! isparent(node, ps->node)) {          } else if ( ! isparent(node, ps->node)) {
                 fprintf(stderr, "%s: bad parent\n", name);                  fprintf(stderr, "%s:%zu:%zu: bad parent \"%s\"\n",
                           ps->fname, XML_GetCurrentLineNumber(ps->xml),
                           XML_GetCurrentColumnNumber(ps->xml),
                           NULL == nodes[ps->node].name ?
                           "(none)" : nodes[ps->node].name);
                 ps->stop = 1;                  ps->stop = 1;
                 return;                  return;
         }          }
Line 481  xml_elem_start(void *arg, const XML_Char *name, const 
Line 630  xml_elem_start(void *arg, const XML_Char *name, const 
         dat->node = ps->node = node;          dat->node = ps->node = node;
         dat->parent = ps->cur;          dat->parent = ps->cur;
         TAILQ_INIT(&dat->childq);          TAILQ_INIT(&dat->childq);
           TAILQ_INIT(&dat->attrq);
   
         if (NULL != ps->cur)          if (NULL != ps->cur)
                 TAILQ_INSERT_TAIL(&ps->cur->childq, dat, child);                  TAILQ_INSERT_TAIL(&ps->cur->childq, dat, child);
Line 488  xml_elem_start(void *arg, const XML_Char *name, const 
Line 638  xml_elem_start(void *arg, const XML_Char *name, const 
         ps->cur = dat;          ps->cur = dat;
         if (NULL == ps->root)          if (NULL == ps->root)
                 ps->root = dat;                  ps->root = dat;
   
           /*
            * Process attributes.
            */
           for (att = atts; NULL != *att; att += 2) {
                   for (key = 0; key < ATTRKEY__MAX; key++)
                           if (0 == strcmp(*att, attrkeys[key]))
                                   break;
                   if (ATTRKEY__MAX == key) {
                           fprintf(stderr, "%s:%zu:%zu: unknown "
                                   "attribute \"%s\"\n", ps->fname,
                                   XML_GetCurrentLineNumber(ps->xml),
                                   XML_GetCurrentColumnNumber(ps->xml),
                                   *att);
                           continue;
                   } else if ( ! isattrkey(node, key)) {
                           fprintf(stderr, "%s:%zu:%zu: bad "
                                   "attribute \"%s\"\n", ps->fname,
                                   XML_GetCurrentLineNumber(ps->xml),
                                   XML_GetCurrentColumnNumber(ps->xml),
                                   *att);
                           continue;
                   }
                   for (val = 0; val < ATTRVAL__MAX; val++)
                           if (0 == strcmp(*(att + 1), attrvals[val]))
                                   break;
                   if (ATTRVAL__MAX != val && ! isattrval(key, val)) {
                           fprintf(stderr, "%s:%zu:%zu: bad "
                                   "value \"%s\"\n", ps->fname,
                                   XML_GetCurrentLineNumber(ps->xml),
                                   XML_GetCurrentColumnNumber(ps->xml),
                                   *(att + 1));
                           continue;
                   }
                   pattr = calloc(1, sizeof(struct pattr));
                   pattr->key = key;
                   pattr->val = val;
                   if (ATTRVAL__MAX == val)
                           pattr->rawval = strdup(*(att + 1));
                   TAILQ_INSERT_TAIL(&dat->attrq, pattr, child);
           }
   
 }  }
   
 /*  /*
  * Roll up the parse tree.   * Roll up the parse tree.
  * Does nothing else special.   * If we're at a text node, roll that one up first.
  * If we hit the root, then assign ourselves as the NODE_ROOT.   * If we hit the root, then assign ourselves as the NODE_ROOT.
  */   */
 static void  static void
Line 506  xml_elem_end(void *arg, const XML_Char *name)
Line 698  xml_elem_end(void *arg, const XML_Char *name)
         /* Close out text node, if applicable... */          /* Close out text node, if applicable... */
         if (NODE_TEXT == ps->node) {          if (NODE_TEXT == ps->node) {
                 assert(NULL != ps->cur);                  assert(NULL != ps->cur);
                   pnode_trim(ps->cur);
                 ps->cur = ps->cur->parent;                  ps->cur = ps->cur->parent;
                 assert(NULL != ps->cur);                  assert(NULL != ps->cur);
                 ps->node = ps->cur->node;                  ps->node = ps->cur->node;
Line 517  xml_elem_end(void *arg, const XML_Char *name)
Line 710  xml_elem_end(void *arg, const XML_Char *name)
                 ps->node = ps->cur->node;                  ps->node = ps->cur->node;
 }  }
   
   /*
    * Recursively free a node (NULL is ok).
    */
 static void  static void
 pnode_free(struct pnode *pn)  pnode_free(struct pnode *pn)
 {  {
         struct pnode    *pp;          struct pnode    *pp;
           struct pattr    *ap;
   
         if (NULL == pn)          if (NULL == pn)
                 return;                  return;
Line 530  pnode_free(struct pnode *pn)
Line 727  pnode_free(struct pnode *pn)
                 pnode_free(pp);                  pnode_free(pp);
         }          }
   
           while (NULL != (ap = TAILQ_FIRST(&pn->attrq))) {
                   TAILQ_REMOVE(&pn->attrq, ap, child);
                   free(ap->rawval);
                   free(ap);
           }
   
         free(pn->b);          free(pn->b);
         free(pn);          free(pn);
 }  }
   
   /*
    * Unlink a node from its parent and pnode_free() it.
    */
 static void  static void
 pnode_unlink(struct pnode *pn)  pnode_unlink(struct pnode *pn)
 {  {
Line 543  pnode_unlink(struct pnode *pn)
Line 749  pnode_unlink(struct pnode *pn)
         pnode_free(pn);          pnode_free(pn);
 }  }
   
   /*
    * Unlink all children of a node and pnode_free() them.
    */
 static void  static void
 pnode_unlinksub(struct pnode *pn)  pnode_unlinksub(struct pnode *pn)
 {  {
Line 551  pnode_unlinksub(struct pnode *pn)
Line 760  pnode_unlinksub(struct pnode *pn)
                 pnode_unlink(TAILQ_FIRST(&pn->childq));                  pnode_unlink(TAILQ_FIRST(&pn->childq));
 }  }
   
   /*
    * Reset the lookaside buffer.
    */
 static void  static void
 bufclear(struct parse *p)  bufclear(struct parse *p)
 {  {
Line 558  bufclear(struct parse *p)
Line 770  bufclear(struct parse *p)
         p->b[p->bsz = 0] = '\0';          p->b[p->bsz = 0] = '\0';
 }  }
   
   /*
    * Append NODE_TEXT contents to the current buffer, reallocating its
    * size if necessary.
    * The buffer is ALWAYS nil-terminated.
    */
 static void  static void
 bufappend(struct parse *p, struct pnode *pn)  bufappend(struct parse *p, struct pnode *pn)
 {  {
Line 575  bufappend(struct parse *p, struct pnode *pn)
Line 792  bufappend(struct parse *p, struct pnode *pn)
         p->b[p->bsz] = '\0';          p->b[p->bsz] = '\0';
 }  }
   
   /*
    * Recursively append all NODE_TEXT nodes to the buffer.
    * This descends into non-text nodes, but doesn't do anything beyond
    * them.
    * In other words, this is a recursive text grok.
    */
 static void  static void
 bufappend_r(struct parse *p, struct pnode *pn)  bufappend_r(struct parse *p, struct pnode *pn)
 {  {
Line 586  bufappend_r(struct parse *p, struct pnode *pn)
Line 809  bufappend_r(struct parse *p, struct pnode *pn)
                 bufappend_r(p, pp);                  bufappend_r(p, pp);
 }  }
   
   #define MACROLINE_NORM  0
   #define MACROLINE_UPPER 1
 /*  /*
  * Print text presumably on a macro line.   * Recursively print text presumably on a macro line.
  * Ignore any child macros.  
  * Convert all whitespace to regular spaces.   * Convert all whitespace to regular spaces.
  */   */
 static void  static void
 pnode_printmacrolinepart(struct parse *p, struct pnode *pn)  pnode_printmacrolinetext(struct parse *p, struct pnode *pn, int fl)
 {  {
         char            *cp;          char            *cp;
   
Line 618  pnode_printmacrolinepart(struct parse *p, struct pnode
Line 842  pnode_printmacrolinepart(struct parse *p, struct pnode
                           ('\0' == *(cp + 3) ||                            ('\0' == *(cp + 3) ||
                            ' ' == *(cp + 3)))))                             ' ' == *(cp + 3)))))
                         fputs("\\&", stdout);                          fputs("\\&", stdout);
                 putchar(*cp);                  if (MACROLINE_UPPER & fl)
                           putchar(toupper((int)*cp));
                   else
                           putchar((int)*cp);
                 /* If we're a character escape, escape us. */                  /* If we're a character escape, escape us. */
                 if ('\\' == *cp)                  if ('\\' == *cp)
                         putchar('e');                          putchar('e');
         }          }
 }  }
   
   static void
   pnode_printmacrolinepart(struct parse *p, struct pnode *pn)
   {
   
           pnode_printmacrolinetext(p, pn, 0);
   }
   
 /*  /*
  * Just pnode_printmacrolinepart() but with a newline.   * Just pnode_printmacrolinepart() but with a newline.
  * If no text, just the newline.   * If no text, just the newline.
Line 633  static void
Line 867  static void
 pnode_printmacroline(struct parse *p, struct pnode *pn)  pnode_printmacroline(struct parse *p, struct pnode *pn)
 {  {
   
         pnode_printmacrolinepart(p, pn);          pnode_printmacrolinetext(p, pn, 0);
         putchar('\n');          putchar('\n');
 }  }
   
 static void  static void
   pnode_printmopen(struct parse *p)
   {
           if (p->newln) {
                   putchar('.');
                   p->newln = 0;
           } else
                   putchar(' ');
   }
   
   static void
   pnode_printmclose(struct parse *p, int sv)
   {
   
           if (sv && ! p->newln) {
                   putchar('\n');
                   p->newln = 1;
           }
   }
   
   /*
    * If the SYNOPSIS macro has a superfluous title, kill it.
    */
   static void
   pnode_printrefsynopsisdiv(struct parse *p, struct pnode *pn)
   {
           struct pnode    *pp;
   
           TAILQ_FOREACH(pp, &pn->childq, child)
                   if (NODE_TITLE == pp->node) {
                           pnode_unlink(pp);
                           return;
                   }
   }
   
   /*
    * Start a hopefully-named `Sh' section.
    */
   static void
 pnode_printrefsect(struct parse *p, struct pnode *pn)  pnode_printrefsect(struct parse *p, struct pnode *pn)
 {  {
         struct pnode    *pp;          struct pnode    *pp;
Line 655  pnode_printrefsect(struct parse *p, struct pnode *pn)
Line 927  pnode_printrefsect(struct parse *p, struct pnode *pn)
                 puts("UNKNOWN");                  puts("UNKNOWN");
 }  }
   
   /*
    * Start a reference, extracting the title and volume.
    */
 static void  static void
 pnode_printciterefentry(struct parse *p, struct pnode *pn)  pnode_printciterefentry(struct parse *p, struct pnode *pn)
 {  {
Line 697  pnode_printrefmeta(struct parse *p, struct pnode *pn)
Line 972  pnode_printrefmeta(struct parse *p, struct pnode *pn)
         fputs(".Dt ", stdout);          fputs(".Dt ", stdout);
   
         if (NULL != title) {          if (NULL != title) {
                 pnode_printmacrolinepart(p, title);                  /* FIXME: uppercase. */
                   pnode_printmacrolinetext(p, title, MACROLINE_UPPER);
                 putchar(' ');                  putchar(' ');
         } else          } else
                 fputs("UNKNOWN ", stdout);                  fputs("UNKNOWN ", stdout);
Line 754  pnode_printparamdef(struct parse *p, struct pnode *pn)
Line 1030  pnode_printparamdef(struct parse *p, struct pnode *pn)
   
         if (NULL != param)          if (NULL != param)
                 pnode_printmacrolinepart(p, param);                  pnode_printmacrolinepart(p, param);
         else  
                 fputs("UNKNOWN", stdout);  
   
         puts("\"");          puts("\"");
 }  }
Line 781  pnode_printfuncprototype(struct parse *p, struct pnode
Line 1055  pnode_printfuncprototype(struct parse *p, struct pnode
         puts(".Fc");          puts(".Fc");
 }  }
   
 /* TODO: handle "optional" values. */  /*
    * The <arg> element is more complicated than it should be because text
    * nodes are treated like ".Ar foo", but non-text nodes need to be
    * re-sent into the printer (i.e., without the preceding ".Ar").
    * This also handles the case of "repetition" (or in other words, the
    * ellipsis following an argument) and optionality.
    */
 static void  static void
 pnode_printarg(struct parse *p, struct pnode *pn, int nested)  pnode_printarg(struct parse *p, struct pnode *pn)
 {  {
         struct pnode    *pp;          struct pnode    *pp;
         int              sv = nested;          struct pattr    *ap;
           int              isop, isrep;
   
         if ( ! nested)          isop = 1;
                 fputs(".", stdout);          isrep = 0;
         nested = 1;          TAILQ_FOREACH(ap, &pn->attrq, child)
         TAILQ_FOREACH(pp, &pn->childq, child)                  if (ATTRKEY_CHOICE == ap->key &&
                 if (NODE_OPTION == pp->node) {                          (ATTRVAL_PLAIN == ap->val ||
                         fputs("Fl ", stdout);                           ATTRVAL_REQ == ap->val))
                         pnode_printmacrolinepart(p, pp);                          isop = 0;
                 } else if (NODE_TEXT == pp->node) {                  else if (ATTRKEY_REP == ap->key &&
                           (ATTRVAL_REPEAT == ap->val))
                           isrep = 1;
   
           if (isop) {
                   pnode_printmopen(p);
                   fputs("Op ", stdout);
           }
   
           TAILQ_FOREACH(pp, &pn->childq, child) {
                   if (NODE_TEXT == pp->node) {
                           pnode_printmopen(p);
                         fputs("Ar ", stdout);                          fputs("Ar ", stdout);
                         pnode_printmacrolinepart(p, pp);                  }
                 } else if (NODE_ARG == pp->node)                  pnode_print(p, pp);
                         pnode_printarg(p, pp, nested);                  if (NODE_TEXT == pp->node && isrep)
                           fputs("...", stdout);
           }
   }
   
         if ( ! sv)  /*
                 puts("");   * Recursively search and return the first instance of "node".
    */
   static struct pnode *
   pnode_findfirst(struct pnode *pn, enum nodeid node)
   {
           struct pnode    *pp, *res;
   
           res = NULL;
           TAILQ_FOREACH(pp, &pn->childq, child) {
                   res = pp->node == node ? pp :
                           pnode_findfirst(pp, node);
                   if (NULL != res)
                           break;
           }
   
           return(res);
 }  }
   
   static void
   pnode_printprologue(struct parse *p, struct pnode *pn)
   {
           struct pnode    *pp;
   
           pp = NULL == p->root ? NULL :
                   pnode_findfirst(p->root, NODE_REFMETA);
   
           if (NULL != pp) {
                   pnode_printrefmeta(p, pp);
                   pnode_unlink(pp);
           } else {
                   puts(".\\\" Supplying bogus prologue...");
                   puts(".Dd $Mdocdate" "$");
                   puts(".Dt UNKNOWN 1");
                   puts(".Os");
           }
   }
   
 /*  /*
  * Print a parsed node (or ignore it--whatever).   * Print a parsed node (or ignore it--whatever).
  * This is a recursive function.   * This is a recursive function.
Line 815  pnode_print(struct parse *p, struct pnode *pn)
Line 1144  pnode_print(struct parse *p, struct pnode *pn)
 {  {
         struct pnode    *pp;          struct pnode    *pp;
         char            *cp;          char            *cp;
         int              last;          int              last, sv;
   
         if (NULL == pn)          if (NULL == pn)
                 return;                  return;
   
         if (NODE_TEXT != pn->node && NODE_ROOT != pn->node)          sv = p->newln;
                 printf(".\\\" %s\n", nodes[pn->node].name);  
   
         switch (pn->node) {          switch (pn->node) {
         case (NODE_ARG):          case (NODE_ARG):
                 pnode_printarg(p, pn, 0);                  pnode_printarg(p, pn);
                 pnode_unlinksub(pn);                  pnode_unlinksub(pn);
                 break;                  break;
         case (NODE_CITEREFENTRY):          case (NODE_CITEREFENTRY):
                   assert(p->newln);
                 pnode_printciterefentry(p, pn);                  pnode_printciterefentry(p, pn);
                 pnode_unlinksub(pn);                  pnode_unlinksub(pn);
                 break;                  break;
         case (NODE_CODE):          case (NODE_CODE):
                 fputs(".Li ", stdout);                  pnode_printmopen(p);
                 pnode_printmacroline(p, pn);                  fputs("Li ", stdout);
                 pnode_unlinksub(pn);  
                 break;                  break;
         case (NODE_COMMAND):          case (NODE_COMMAND):
                 fputs(".Nm ", stdout);                  pnode_printmopen(p);
                 pnode_printmacroline(p, pn);                  fputs("Nm ", stdout);
                 pnode_unlinksub(pn);  
                 break;                  break;
         case (NODE_FUNCTION):          case (NODE_FUNCTION):
                 fputs(".Fn ", stdout);                  pnode_printmopen(p);
                 pnode_printmacroline(p, pn);                  fputs("Fn ", stdout);
                 pnode_unlinksub(pn);  
                 break;                  break;
         case (NODE_FUNCPROTOTYPE):          case (NODE_FUNCPROTOTYPE):
                   assert(p->newln);
                 pnode_printfuncprototype(p, pn);                  pnode_printfuncprototype(p, pn);
                 pnode_unlinksub(pn);                  pnode_unlinksub(pn);
                 break;                  break;
         case (NODE_FUNCSYNOPSISINFO):          case (NODE_FUNCSYNOPSISINFO):
                 fputs(".Fd ", stdout);                  pnode_printmopen(p);
                 pnode_printmacroline(p, pn);                  fputs("Fd ", stdout);
                 pnode_unlinksub(pn);  
                 break;                  break;
           case (NODE_OPTION):
                   pnode_printmopen(p);
                   fputs("Fl ", stdout);
                   break;
         case (NODE_PARA):          case (NODE_PARA):
                 /* FIXME: not always. */                  assert(p->newln);
                 puts(".Pp");                  puts(".Pp");
                 break;                  break;
         case (NODE_PARAMETER):          case (NODE_PARAMETER):
                 fputs(".Fa \"", stdout);                  /* Suppress non-text children... */
                   pnode_printmopen(p);
                   fputs("Fa \"", stdout);
                 pnode_printmacrolinepart(p, pn);                  pnode_printmacrolinepart(p, pn);
                 puts("\"");                  puts("\"");
                 pnode_unlinksub(pn);                  pnode_unlinksub(pn);
                 break;                  break;
         case (NODE_PROGRAMLISTING):          case (NODE_PROGRAMLISTING):
                   assert(p->newln);
                 puts(".Bd -literal");                  puts(".Bd -literal");
                 break;                  break;
         case (NODE_REFMETA):          case (NODE_REFMETA):
                 pnode_printrefmeta(p, pn);                  abort();
                 pnode_unlinksub(pn);  
                 break;                  break;
         case (NODE_REFNAME):          case (NODE_REFNAME):
                 fputs(".Nm ", stdout);                  /* Suppress non-text children... */
                 pnode_printmacroline(p, pn);                  pnode_printmopen(p);
                   fputs("Nm ", stdout);
                   pnode_printmacrolinepart(p, pn);
                 pnode_unlinksub(pn);                  pnode_unlinksub(pn);
                 return;                  break;
         case (NODE_REFNAMEDIV):          case (NODE_REFNAMEDIV):
                   assert(p->newln);
                 puts(".Sh NAME");                  puts(".Sh NAME");
                 break;                  break;
         case (NODE_REFPURPOSE):          case (NODE_REFPURPOSE):
                   assert(p->newln);
                 fputs(".Nd ", stdout);                  fputs(".Nd ", stdout);
                 pnode_printmacroline(p, pn);                  break;
                 pnode_unlinksub(pn);  
                 return;  
         case (NODE_REFSYNOPSISDIV):          case (NODE_REFSYNOPSISDIV):
                   assert(p->newln);
                   pnode_printrefsynopsisdiv(p, pn);
                 puts(".Sh SYNOPSIS");                  puts(".Sh SYNOPSIS");
                 break;                  break;
         case (NODE_REFSECT1):          case (NODE_REFSECT1):
                   assert(p->newln);
                 pnode_printrefsect(p, pn);                  pnode_printrefsect(p, pn);
                 break;                  break;
           case (NODE_STRUCTNAME):
                   pnode_printmopen(p);
                   fputs("Vt ", stdout);
                   break;
         case (NODE_TEXT):          case (NODE_TEXT):
                 bufclear(p);                  bufclear(p);
                 bufappend(p, pn);                  bufappend(p, pn);
Line 901  pnode_print(struct parse *p, struct pnode *pn)
Line 1242  pnode_print(struct parse *p, struct pnode *pn)
                  * XXX: all whitespace, including tabs (?).                   * XXX: all whitespace, including tabs (?).
                  * Remember to escape control characters and escapes.                   * Remember to escape control characters and escapes.
                  */                   */
                   assert(p->bsz);
                 for (last = '\n', cp = p->b; '\0' != *cp; ) {                  for (last = '\n', cp = p->b; '\0' != *cp; ) {
                         if ('\n' == last) {                          if ('\n' == last) {
                                 /* Consume all whitespace. */                                  /* Consume all whitespace. */
Line 916  pnode_print(struct parse *p, struct pnode *pn)
Line 1258  pnode_print(struct parse *p, struct pnode *pn)
                         if ('\\' == last)                          if ('\\' == last)
                                 putchar('e');                                  putchar('e');
                 }                  }
                 if ('\n' != last)                  p->newln = 0;
                         putchar('\n');  
                 break;                  break;
         default:          default:
                 break;                  break;
Line 927  pnode_print(struct parse *p, struct pnode *pn)
Line 1268  pnode_print(struct parse *p, struct pnode *pn)
                 pnode_print(p, pp);                  pnode_print(p, pp);
   
         switch (pn->node) {          switch (pn->node) {
           case (NODE_ARG):
           case (NODE_CODE):
           case (NODE_COMMAND):
           case (NODE_FUNCTION):
           case (NODE_FUNCSYNOPSISINFO):
           case (NODE_OPTION):
           case (NODE_PARAMETER):
           case (NODE_STRUCTNAME):
           case (NODE_TEXT):
                   pnode_printmclose(p, sv);
                   break;
           case (NODE_REFNAME):
                   /*
                    * If we're in the NAME macro and we have multiple
                    * <refname> macros in sequence, then print out a
                    * trailing comma before the newline.
                    */
                   if (NULL != pn->parent &&
                           NODE_REFNAMEDIV == pn->parent->node &&
                           NULL != TAILQ_NEXT(pn, child) &&
                           NODE_REFNAME == TAILQ_NEXT(pn, child)->node)
                           fputs(" ,", stdout);
                   pnode_printmclose(p, sv);
                   break;
         case (NODE_PROGRAMLISTING):          case (NODE_PROGRAMLISTING):
                   assert(p->newln);
                 puts(".Ed");                  puts(".Ed");
                   p->newln = 1;
                 break;                  break;
         default:          default:
                 break;                  break;
Line 950  readfile(XML_Parser xp, int fd, 
Line 1317  readfile(XML_Parser xp, int fd, 
         memset(&p, 0, sizeof(struct parse));          memset(&p, 0, sizeof(struct parse));
   
         p.b = malloc(p.bsz = p.mbsz = 1024);          p.b = malloc(p.bsz = p.mbsz = 1024);
           p.fname = fn;
           p.xml = xp;
   
         XML_SetCharacterDataHandler(xp, xml_char);          XML_SetCharacterDataHandler(xp, xml_char);
         XML_SetElementHandler(xp, xml_elem_start, xml_elem_end);          XML_SetElementHandler(xp, xml_elem_start, xml_elem_end);
Line 966  readfile(XML_Parser xp, int fd, 
Line 1335  readfile(XML_Parser xp, int fd, 
                  * Exit when we've read all or errors have occured                   * Exit when we've read all or errors have occured
                  * during the parse sequence.                   * during the parse sequence.
                  */                   */
                   p.newln = 1;
                   pnode_printprologue(&p, p.root);
                 pnode_print(&p, p.root);                  pnode_print(&p, p.root);
                 pnode_free(p.root);                  pnode_free(p.root);
                 free(p.b);                  free(p.b);

Legend:
Removed from v.1.5  
changed lines
  Added in v.1.12

CVSweb