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

Diff for /docbook2mdoc/docbook2mdoc.c between version 1.1 and 1.10

version 1.1, 2014/03/28 02:04:47 version 1.10, 2014/03/29 10:56:21
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 31 
Line 32 
 enum    nodeid {  enum    nodeid {
         NODE_ROOT = 0, /* Must comes first. */          NODE_ROOT = 0, /* Must comes first. */
         /* Alpha-ordered hereafter. */          /* Alpha-ordered hereafter. */
           NODE_ARG,
         NODE_CITEREFENTRY,          NODE_CITEREFENTRY,
           NODE_CMDSYNOPSIS,
         NODE_CODE,          NODE_CODE,
           NODE_COMMAND,
           NODE_FUNCDEF,
           NODE_FUNCPROTOTYPE,
         NODE_FUNCSYNOPSIS,          NODE_FUNCSYNOPSIS,
         NODE_FUNCSYNOPSISINFO,          NODE_FUNCSYNOPSISINFO,
           NODE_FUNCTION,
         NODE_MANVOLNUM,          NODE_MANVOLNUM,
           NODE_OPTION,
         NODE_PARA,          NODE_PARA,
           NODE_PARAMDEF,
           NODE_PARAMETER,
         NODE_PROGRAMLISTING,          NODE_PROGRAMLISTING,
         NODE_REFCLASS,          NODE_REFCLASS,
         NODE_REFDESCRIPTOR,          NODE_REFDESCRIPTOR,
Line 49  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 64  struct parse {
Line 75  struct parse {
         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 */
 };  };
Line 88  struct pnode {
Line 100  struct pnode {
   
 static  const struct node nodes[NODE__MAX] = {  static  const struct node nodes[NODE__MAX] = {
         { NULL, 0 },          { NULL, 0 },
           { "arg", 0 },
         { "citerefentry", NODE_IGNTEXT },          { "citerefentry", NODE_IGNTEXT },
           { "cmdsynopsis", NODE_IGNTEXT },
         { "code", 0 },          { "code", 0 },
           { "command", 0 },
           { "funcdef", 0 },
           { "funcprototype", NODE_IGNTEXT },
         { "funcsynopsis", NODE_IGNTEXT },          { "funcsynopsis", NODE_IGNTEXT },
         { "funcsynopsisinfo", 0 },          { "funcsynopsisinfo", 0 },
           { "function", 0 },
         { "manvolnum", 0 },          { "manvolnum", 0 },
           { "option", 0 },
         { "para", 0 },          { "para", 0 },
           { "paramdef", 0 },
           { "parameter", 0 },
         { "programlisting", 0 },          { "programlisting", 0 },
         { "refclass", NODE_IGNTEXT },          { "refclass", NODE_IGNTEXT },
         { "refdescriptor", NODE_IGNTEXT },          { "refdescriptor", NODE_IGNTEXT },
Line 106  static const struct node nodes[NODE__MAX] = {
Line 127  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);
   
 /*  /*
  * 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 121  isparent(enum nodeid node, enum nodeid parent)
Line 148  isparent(enum nodeid node, enum nodeid parent)
         switch (node) {          switch (node) {
         case (NODE_ROOT):          case (NODE_ROOT):
                 return(0);                  return(0);
           case (NODE_ARG):
                   switch (parent) {
                   case (NODE_ARG):
                   case (NODE_CMDSYNOPSIS):
                           return(1);
                   default:
                           break;
                   }
                   return(0);
         case (NODE_CITEREFENTRY):          case (NODE_CITEREFENTRY):
                 switch (parent) {                  switch (parent) {
                 case (NODE_FUNCSYNOPSISINFO):                  case (NODE_FUNCSYNOPSISINFO):
Line 137  isparent(enum nodeid node, enum nodeid parent)
Line 173  isparent(enum nodeid node, enum nodeid parent)
                         break;                          break;
                 }                  }
                 return(0);                  return(0);
           case (NODE_CMDSYNOPSIS):
                   switch (parent) {
                   case (NODE_PARA):
                   case (NODE_REFSECT1):
                   case (NODE_REFSYNOPSISDIV):
                           return(1);
                   default:
                           break;
                   }
                   return(0);
         case (NODE_CODE):          case (NODE_CODE):
                 switch (parent) {                  switch (parent) {
                 case (NODE_FUNCSYNOPSISINFO):                  case (NODE_FUNCSYNOPSISINFO):
Line 153  isparent(enum nodeid node, enum nodeid parent)
Line 199  isparent(enum nodeid node, enum nodeid parent)
                         break;                          break;
                 }                  }
                 return(0);                  return(0);
         case (NODE_MANVOLNUM):          case (NODE_COMMAND):
                 switch (parent) {                  switch (parent) {
                 case (NODE_CITEREFENTRY):                  case (NODE_CMDSYNOPSIS):
                 case (NODE_REFMETA):                  case (NODE_FUNCSYNOPSISINFO):
                   case (NODE_PARA):
                   case (NODE_PROGRAMLISTING):
                   case (NODE_REFDESCRIPTOR):
                   case (NODE_REFENTRYTITLE):
                   case (NODE_REFNAME):
                   case (NODE_REFPURPOSE):
                   case (NODE_SYNOPSIS):
                   case (NODE_TITLE):
                         return(1);                          return(1);
                 default:                  default:
                         break;                          break;
                 }                  }
                 return(0);                  return(0);
           case (NODE_FUNCDEF):
                   return(NODE_FUNCPROTOTYPE == parent);
           case (NODE_FUNCPROTOTYPE):
                   return(NODE_FUNCSYNOPSIS == parent);
         case (NODE_FUNCSYNOPSIS):          case (NODE_FUNCSYNOPSIS):
                 switch (parent) {                  switch (parent) {
                 case (NODE_PARA):                  case (NODE_PARA):
Line 174  isparent(enum nodeid node, enum nodeid parent)
Line 232  isparent(enum nodeid node, enum nodeid parent)
                 return(0);                  return(0);
         case (NODE_FUNCSYNOPSISINFO):          case (NODE_FUNCSYNOPSISINFO):
                 return(NODE_FUNCSYNOPSIS == parent);                  return(NODE_FUNCSYNOPSIS == parent);
           case (NODE_FUNCTION):
                   switch (parent) {
                   case (NODE_CODE):
                   case (NODE_FUNCDEF):
                   case (NODE_FUNCSYNOPSISINFO):
                   case (NODE_PARA):
                   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_MANVOLNUM):
                   switch (parent) {
                   case (NODE_CITEREFENTRY):
                   case (NODE_REFMETA):
                           return(1);
                   default:
                           break;
                   }
                   return(0);
           case (NODE_OPTION):
                   switch (parent) {
                   case (NODE_ARG):
                   case (NODE_FUNCSYNOPSISINFO):
                   case (NODE_PARA):
                   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_PARA):          case (NODE_PARA):
                 switch (parent) {                  switch (parent) {
                 case (NODE_REFSECT1):                  case (NODE_REFSECT1):
Line 183  isparent(enum nodeid node, enum nodeid parent)
Line 285  isparent(enum nodeid node, enum nodeid parent)
                         break;                          break;
                 }                  }
                 return(0);                  return(0);
           case (NODE_PARAMDEF):
                   return(NODE_FUNCPROTOTYPE == parent);
           case (NODE_PARAMETER):
                   switch (parent) {
                   case (NODE_CODE):
                   case (NODE_FUNCSYNOPSISINFO):
                   case (NODE_PARA):
                   case (NODE_PARAMDEF):
                   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_PROGRAMLISTING):          case (NODE_PROGRAMLISTING):
                 switch (parent) {                  switch (parent) {
                 case (NODE_PARA):                  case (NODE_PARA):
Line 221  isparent(enum nodeid node, enum nodeid parent)
Line 343  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 249  isparent(enum nodeid node, enum nodeid parent)
Line 391  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)
 {  {
         struct parse    *ps = arg;          struct parse    *ps = arg;
         struct pnode    *dat;          struct pnode    *dat;
           int              i;
   
         /* Stopped or no tree yet. */          /* Stopped or no tree yet. */
         if (ps->stop || NODE_ROOT == ps->node)          if (ps->stop || NODE_ROOT == ps->node)
Line 268  xml_char(void *arg, const XML_Char *p, int sz)
Line 417  xml_char(void *arg, const XML_Char *p, int sz)
          * Are we in the midst of processing text?           * Are we in the midst of processing text?
          * 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
            * 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++)
                           if ( ! isspace((int)p[i]))
                                   break;
                   if (i == sz)
                           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 282  xml_char(void *arg, const XML_Char *p, int sz)
Line 440  xml_char(void *arg, const XML_Char *p, int sz)
                 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 297  xml_char(void *arg, const XML_Char *p, int sz)
Line 454  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.
  */   */
Line 321  xml_elem_start(void *arg, const XML_Char *name, const 
Line 491  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 332  xml_elem_start(void *arg, const XML_Char *name, const 
Line 503  xml_elem_start(void *arg, const XML_Char *name, const 
                 else if (0 == strcmp(nodes[node].name, name))                  else if (0 == strcmp(nodes[node].name, name))
                         break;                          break;
   
           /* FIXME: do more with these error messages... */
         if (NODE__MAX == node && NODE_ROOT == ps->node) {          if (NODE__MAX == node && NODE_ROOT == ps->node) {
                 fprintf(stderr, "%s: ignoring node\n", name);                  fprintf(stderr, "%s: ignoring node\n", name);
                 return;                  return;
Line 371  xml_elem_start(void *arg, const XML_Char *name, const 
Line 543  xml_elem_start(void *arg, const XML_Char *name, const 
   
 /*  /*
  * 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 385  xml_elem_end(void *arg, const XML_Char *name)
Line 557  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 396  xml_elem_end(void *arg, const XML_Char *name)
Line 569  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)
 {  {
Line 413  pnode_free(struct pnode *pn)
Line 589  pnode_free(struct pnode *pn)
         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 422  pnode_unlink(struct pnode *pn)
Line 601  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)
   {
   
           while ( ! TAILQ_EMPTY(&pn->childq))
                   pnode_unlink(TAILQ_FIRST(&pn->childq));
   }
   
   /*
    * Reset the lookaside buffer.
    */
   static void
 bufclear(struct parse *p)  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 447  bufappend(struct parse *p, struct pnode *pn)
Line 645  bufappend(struct parse *p, struct pnode *pn)
 }  }
   
 /*  /*
  * Print text presumably on a macro line.   * Recursively append all NODE_TEXT nodes to the buffer.
  * Ignore any child macros.   * This descends into non-text nodes, but doesn't do anything beyond
    * them.
    * In other words, this is a recursive text grok.
    */
   static void
   bufappend_r(struct parse *p, struct pnode *pn)
   {
           struct pnode    *pp;
   
           if (NODE_TEXT == pn->node)
                   bufappend(p, pn);
           TAILQ_FOREACH(pp, &pn->childq, child)
                   bufappend_r(p, pp);
   }
   
   /*
    * Recursively print text presumably on a macro line.
  * 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_printmacrolinepart(struct parse *p, struct pnode *pn)
 {  {
         struct pnode    *pp;  
         char            *cp;          char            *cp;
   
         bufclear(p);          bufclear(p);
         while (NULL != (pp = TAILQ_FIRST(&pn->childq))) {          bufappend_r(p, pn);
                 if (NODE_TEXT == pp->node)  
                         bufappend(p, pp);  
                 pnode_unlink(pp);  
         }  
   
         /* Convert all space to spaces. */          /* Convert all space to spaces. */
         for (cp = p->b; '\0' != *cp; cp++)          for (cp = p->b; '\0' != *cp; cp++)
Line 470  pnode_printmacrolinepart(struct parse *p, struct pnode
Line 679  pnode_printmacrolinepart(struct parse *p, struct pnode
                         *cp = ' ';                          *cp = ' ';
   
         for (cp = p->b; isspace((int)*cp); cp++)          for (cp = p->b; isspace((int)*cp); cp++)
                 /* Spin. */ ;                  /* Spin past whitespace (XXX: necessary?) */ ;
   
         for ( ; '\0' != *cp; cp++) {          for ( ; '\0' != *cp; cp++) {
                 /* Escape us if we look like a macro. */                  /* Escape us if we look like a macro. */
                 if ((cp == p->b || ' ' == *(cp - 1)) &&                  if ((cp == p->b || ' ' == *(cp - 1)) &&
Line 504  pnode_printmacroline(struct parse *p, struct pnode *pn
Line 712  pnode_printmacroline(struct parse *p, struct pnode *pn
 }  }
   
 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 512  pnode_printrefsect(struct parse *p, struct pnode *pn)
Line 758  pnode_printrefsect(struct parse *p, struct pnode *pn)
                 if (NODE_TITLE == pp->node)                  if (NODE_TITLE == pp->node)
                         break;                          break;
   
           fputs(".Sh ", stdout);
   
         if (NULL != pp) {          if (NULL != pp) {
                 fputs(".Sh ", stdout);  
                 pnode_printmacroline(p, pp);                  pnode_printmacroline(p, pp);
                 pnode_unlink(pp);                  pnode_unlink(pp);
         } else          } else
                 puts(".Sh 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 533  pnode_printciterefentry(struct parse *p, struct pnode 
Line 783  pnode_printciterefentry(struct parse *p, struct pnode 
                         title = pp;                          title = pp;
   
         fputs(".Xr ", stdout);          fputs(".Xr ", stdout);
   
         if (NULL != title) {          if (NULL != title) {
                 pnode_printmacrolinepart(p, title);                  pnode_printmacrolinepart(p, title);
                 pnode_unlink(title);                  putchar(' ');
         } else          } else
                 fputs("unknown", stdout);                  fputs("unknown ", stdout);
         putchar(' ');  
         if (NULL != manvol) {          if (NULL != manvol)
                 pnode_printmacroline(p, manvol);                  pnode_printmacroline(p, manvol);
                 pnode_unlink(manvol);          else
         } else  
                 puts("1");                  puts("1");
 }  }
   
Line 558  pnode_printrefmeta(struct parse *p, struct pnode *pn)
Line 808  pnode_printrefmeta(struct parse *p, struct pnode *pn)
                 else if (NODE_REFENTRYTITLE == pp->node)                  else if (NODE_REFENTRYTITLE == pp->node)
                         title = pp;                          title = pp;
   
         puts(".Dd $Mdocdate$");          puts(".Dd $Mdocdate" "$");
         fputs(".Dt ", stdout);          fputs(".Dt ", stdout);
   
         if (NULL != title) {          if (NULL != title) {
                   /* FIXME: uppercase. */
                 pnode_printmacrolinepart(p, title);                  pnode_printmacrolinepart(p, title);
                 pnode_unlink(title);                  putchar(' ');
         } else          } else
                 fputs("UNKNOWN", stdout);                  fputs("UNKNOWN ", stdout);
         putchar(' ');  
         if (NULL != manvol) {          if (NULL != manvol)
                 pnode_printmacroline(p, manvol);                  pnode_printmacroline(p, manvol);
                 pnode_unlink(manvol);          else
         } else  
                 puts("1");                  puts("1");
   
         puts(".Os");          puts(".Os");
 }  }
   
   static void
   pnode_printfuncdef(struct parse *p, struct pnode *pn)
   {
           struct pnode    *pp, *ftype, *func;
   
           ftype = func = NULL;
           TAILQ_FOREACH(pp, &pn->childq, child)
                   if (NODE_TEXT == pp->node)
                           ftype = pp;
                   else if (NODE_FUNCTION == pp->node)
                           func = pp;
   
           if (NULL != ftype) {
                   fputs(".Ft ", stdout);
                   pnode_printmacroline(p, ftype);
           }
   
           if (NULL != func) {
                   fputs(".Fo ", stdout);
                   pnode_printmacroline(p, func);
           } else
                   puts(".Fo UNKNOWN");
   }
   
   static void
   pnode_printparamdef(struct parse *p, struct pnode *pn)
   {
           struct pnode    *pp, *ptype, *param;
   
           ptype = param = NULL;
           TAILQ_FOREACH(pp, &pn->childq, child)
                   if (NODE_TEXT == pp->node)
                           ptype = pp;
                   else if (NODE_PARAMETER == pp->node)
                           param = pp;
   
           fputs(".Fa \"", stdout);
           if (NULL != ptype) {
                   pnode_printmacrolinepart(p, ptype);
                   putchar(' ');
           }
   
           if (NULL != param)
                   pnode_printmacrolinepart(p, param);
           else
                   fputs("UNKNOWN", stdout);
   
           puts("\"");
   }
   
   static void
   pnode_printfuncprototype(struct parse *p, struct pnode *pn)
   {
           struct pnode    *pp, *fdef;
   
           TAILQ_FOREACH(fdef, &pn->childq, child)
                   if (NODE_FUNCDEF == fdef->node)
                           break;
   
           if (NULL != fdef)
                   pnode_printfuncdef(p, fdef);
           else
                   puts(".Fo UNKNOWN");
   
           TAILQ_FOREACH(pp, &pn->childq, child)
                   if (NODE_PARAMDEF == pp->node)
                           pnode_printparamdef(p, pp);
   
           puts(".Fc");
   }
   
   /*
    * 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").
    * TODO: handle "optional" attribute.
    */
   static void
   pnode_printarg(struct parse *p, struct pnode *pn)
   {
           struct pnode    *pp;
   
           TAILQ_FOREACH(pp, &pn->childq, child) {
                   if (NODE_TEXT == pp->node) {
                           pnode_printmopen(p);
                           fputs("Ar ", stdout);
                   }
                   pnode_print(p, pp);
           }
   }
   
   /*
    * 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 586  pnode_print(struct parse *p, struct pnode *pn)
Line 965  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):
                   pnode_printarg(p, pn);
                   pnode_unlinksub(pn);
                   break;
         case (NODE_CITEREFENTRY):          case (NODE_CITEREFENTRY):
                   assert(p->newln);
                 pnode_printciterefentry(p, pn);                  pnode_printciterefentry(p, 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);
                 break;                  break;
           case (NODE_COMMAND):
                   pnode_printmopen(p);
                   fputs("Nm ", stdout);
                   break;
           case (NODE_FUNCTION):
                   pnode_printmopen(p);
                   fputs("Fn ", stdout);
                   break;
           case (NODE_FUNCPROTOTYPE):
                   assert(p->newln);
                   pnode_printfuncprototype(p, pn);
                   pnode_unlinksub(pn);
                   break;
         case (NODE_FUNCSYNOPSISINFO):          case (NODE_FUNCSYNOPSISINFO):
                 fputs(".Fd ", stdout);                  pnode_printmopen(p);
                 pnode_printmacroline(p, pn);                  fputs("Fd ", stdout);
                 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):
                   /* Suppress non-text children... */
                   pnode_printmopen(p);
                   fputs("Fa \"", stdout);
                   pnode_printmacrolinepart(p, pn);
                   puts("\"");
                   pnode_unlinksub(pn);
                   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();
                 break;                  break;
         case (NODE_REFNAME):          case (NODE_REFNAME):
                 fputs(".Nm ", stdout);                  /* Suppress non-text children... */
                 pnode_printmacroline(p, pn);                  pnode_printmopen(p);
                 return;                  fputs("Nm ", stdout);
                   pnode_printmacrolinepart(p, pn);
                   pnode_unlinksub(pn);
                   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;
                 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 642  pnode_print(struct parse *p, struct pnode *pn)
Line 1063  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 657  pnode_print(struct parse *p, struct pnode *pn)
Line 1079  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 668  pnode_print(struct parse *p, struct pnode *pn)
Line 1089  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_REFNAME):
           case (NODE_STRUCTNAME):
           case (NODE_TEXT):
                   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 707  readfile(XML_Parser xp, int fd, 
Line 1142  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.1  
changed lines
  Added in v.1.10

CVSweb