/home/dko/projects/mobilec/tags/MobileC-v1.10.2/MobileC-v1.10.2/src/mxml-2.2.2/mxmldoc.c

Go to the documentation of this file.
00001 /* SVN FILE INFO
00002  * $Revision: 207 $ : Last Committed Revision
00003  * $Date: 2008-07-11 17:55:19 -0700 (Fri, 11 Jul 2008) $ : Last Committed Date */
00004 /*
00005  * "$Id: mxmldoc.c,v 1.1 2007/05/23 20:43:28 david_ko Exp $"
00006  *
00007  * Documentation generator using Mini-XML, a small XML-like file parsing
00008  * library.
00009  *
00010  * Copyright 2003-2005 by Michael Sweet.
00011  *
00012  * This program is free software; you can redistribute it and/or
00013  * modify it under the terms of the GNU Library General Public
00014  * License as published by the Free Software Foundation; either
00015  * version 2, or (at your option) any later version.
00016  *
00017  * This program is distributed in the hope that it will be useful,
00018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  * GNU General Public License for more details.
00021  *
00022  * Contents:
00023  *
00024  *   main()                - Main entry for test program.
00025  *   add_variable()        - Add a variable or argument.
00026  *   safe_strcpy()         - Copy a string allowing for overlapping strings.
00027  *   scan_file()           - Scan a source file.
00028  *   sort_node()           - Insert a node sorted into a tree.
00029  *   update_comment()      - Update a comment node.
00030  *   write_documentation() - Write HTML documentation.
00031  *   write_element()       - Write an elements text nodes.
00032  *   write_string()        - Write a string, quoting XHTML special chars
00033  *                           as needed...
00034  *   ws_cb()               - Whitespace callback for saving.
00035  */
00036 
00037 /*
00038  * Include necessary headers...
00039  */
00040 
00041 #include "config.h"
00042 #include "mxml.h"
00043 
00044 
00045 /*
00046  * This program scans source and header files and produces public API
00047  * documentation for code that conforms to the CUPS Configuration
00048  * Management Plan (CMP) coding standards.  Please see the following web
00049  * page for details:
00050  *
00051  *     http://www.cups.org/cmp.html
00052  *
00053  * Using Mini-XML, this program creates and maintains an XML representation
00054  * of the public API code documentation which can then be converted to HTML
00055  * as desired.  The following is a poor-man's schema:
00056  *
00057  * <?xml version="1.0"?>
00058  * <mxmldoc xmlns="http://www.easysw.com"
00059  *  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
00060  *  xsi:schemaLocation="http://www.easysw.com/~mike/mxml/mxmldoc.xsd">
00061  *
00062  *   <namespace name="">                        [optional...]
00063  *     <constant name="">
00064  *       <description>descriptive text</description>
00065  *     </constant>
00066  *  
00067  *     <enumeration name="">
00068  *       <description>descriptive text</description>
00069  *       <constant name="">...</constant>
00070  *     </enumeration>
00071  *  
00072  *     <typedef name="">
00073  *       <description>descriptive text</description>
00074  *       <type>type string</type>
00075  *     </typedef>
00076  *  
00077  *     <function name="" scope="">
00078  *       <description>descriptive text</description>
00079  *       <argument name="" direction="I|O|IO" default="">
00080  *         <description>descriptive text</description>
00081  *         <type>type string</type>
00082  *       </argument>
00083  *       <returnvalue>
00084  *         <description>descriptive text</description>
00085  *         <type>type string</type>
00086  *       </returnvalue>
00087  *       <seealso>function names separated by spaces</seealso>
00088  *     </function>
00089  *  
00090  *     <variable name="" scope="">
00091  *       <description>descriptive text</description>
00092  *       <type>type string</type>
00093  *     </variable>
00094  *  
00095  *     <struct name="">
00096  *       <description>descriptive text</description>
00097  *       <variable name="">...</variable>
00098  *       <function name="">...</function>
00099  *     </struct>
00100  *  
00101  *     <union name="">
00102  *       <description>descriptive text</description>
00103  *       <variable name="">...</variable>
00104  *     </union>
00105  *  
00106  *     <class name="" parent="">
00107  *       <description>descriptive text</description>
00108  *       <class name="">...</class>
00109  *       <enumeration name="">...</enumeration>
00110  *       <function name="">...</function>
00111  *       <struct name="">...</struct>
00112  *       <variable name="">...</variable>
00113  *     </class>
00114  *   </namespace>
00115  * </mxmldoc>
00116  */
00117  
00118 
00119 /*
00120  * Basic states for file parser...
00121  */
00122 
00123 #define STATE_NONE              0       /* No state - whitespace, etc. */
00124 #define STATE_PREPROCESSOR      1       /* Preprocessor directive */
00125 #define STATE_C_COMMENT         2       /* Inside a C comment */
00126 #define STATE_CXX_COMMENT       3       /* Inside a C++ comment */
00127 #define STATE_STRING            4       /* Inside a string constant */
00128 #define STATE_CHARACTER         5       /* Inside a character constant */
00129 #define STATE_IDENTIFIER        6       /* Inside a keyword/identifier */
00130 
00131 
00132 /*
00133  * Local functions...
00134  */
00135 
00136 static mxml_node_t      *add_variable(mxml_node_t *parent, const char *name,
00137                                       mxml_node_t *type);
00138 static void             safe_strcpy(char *dst, const char *src);
00139 static int              scan_file(const char *filename, FILE *fp,
00140                                   mxml_node_t *doc);
00141 static void             sort_node(mxml_node_t *tree, mxml_node_t *func);
00142 static void             update_comment(mxml_node_t *parent,
00143                                        mxml_node_t *comment);
00144 static void             write_documentation(mxml_node_t *doc);
00145 static void             write_element(mxml_node_t *doc, mxml_node_t *element);
00146 static void             write_string(const char *s);
00147 static const char       *ws_cb(mxml_node_t *node, int where);
00148 
00149 
00150 /*
00151  * 'main()' - Main entry for test program.
00152  */
00153 
00154 int                                     /* O - Exit status */
00155 main(int  argc,                         /* I - Number of command-line args */
00156      char *argv[])                      /* I - Command-line args */
00157 {
00158   int           i;                      /* Looping var */
00159   FILE          *fp;                    /* File to read */
00160   mxml_node_t   *doc;                   /* XML documentation tree */
00161   mxml_node_t   *mxmldoc;               /* mxmldoc node */
00162 
00163 
00164  /*
00165   * Check arguments...
00166   */
00167 
00168   if (argc < 2)
00169   {
00170     fputs("Usage: mxmldoc filename.xml [source files] >filename.html\n", stderr);
00171     return (1);
00172   }
00173 
00174  /*
00175   * Read the XML documentation file, if it exists...
00176   */
00177 
00178   if ((fp = fopen(argv[1], "r")) != NULL)
00179   {
00180    /*
00181     * Read the existing XML file...
00182     */
00183 
00184     doc = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
00185 
00186     fclose(fp);
00187 
00188     if (!doc)
00189     {
00190       mxmldoc = NULL;
00191 
00192       fprintf(stderr, "mxmldoc: Unable to read the XML documentation file \"%s\"!\n",
00193               argv[1]);
00194     }
00195     else if ((mxmldoc = mxmlFindElement(doc, doc, "mxmldoc", NULL,
00196                                         NULL, MXML_DESCEND)) == NULL)
00197     {
00198       fprintf(stderr, "mxmldoc: XML documentation file \"%s\" is missing <mxmldoc> node!!\n",
00199               argv[1]);
00200 
00201       mxmlDelete(doc);
00202       doc = NULL;
00203     }
00204   }
00205   else
00206   {
00207     doc     = NULL;
00208     mxmldoc = NULL;
00209   }
00210 
00211   if (!doc)
00212   {
00213    /*
00214     * Create an empty XML documentation file...
00215     */
00216 
00217     doc = mxmlNewElement(NULL, "?xml version=\"1.0\"?");
00218 
00219     mxmldoc = mxmlNewElement(doc, "mxmldoc");
00220 
00221 #ifdef MXML_INCLUDE_SCHEMA
00222    /*
00223     * Currently we don't include the schema/namespace stuff with the
00224     * XML output since some validators don't seem to like it...
00225     */
00226 
00227     mxmlElementSetAttr(mxmldoc, "xmlns", "http://www.easysw.com");
00228     mxmlElementSetAttr(mxmldoc, "xmlns:xsi",
00229                        "http://www.w3.org/2001/XMLSchema-instance");
00230     mxmlElementSetAttr(mxmldoc, "xsi:schemaLocation",
00231                        "http://www.easysw.com/~mike/mxml/mxmldoc.xsd");
00232 #endif /* MXML_INCLUDE_SCHEMA */
00233   }
00234 
00235  /*
00236   * Loop through all of the source files...
00237   */
00238 
00239   for (i = 2; i < argc; i ++)
00240     if ((fp = fopen(argv[i], "r")) == NULL)
00241     {
00242       fprintf(stderr, "Unable to open source file \"%s\": %s\n", argv[i],
00243               strerror(errno));
00244       mxmlDelete(doc);
00245       return (1);
00246     }
00247     else if (scan_file(argv[i], fp, mxmldoc))
00248     {
00249       fclose(fp);
00250       mxmlDelete(doc);
00251       return (1);
00252     }
00253     else
00254       fclose(fp);
00255 
00256   if (argc > 2)
00257   {
00258    /*
00259     * Save the updated XML documentation file...
00260     */
00261 
00262     if ((fp = fopen(argv[1], "w")) != NULL)
00263     {
00264      /*
00265       * Write over the existing XML file...
00266       */
00267 
00268       if (mxmlSaveFile(doc, fp, ws_cb))
00269       {
00270         fprintf(stderr, "Unable to write the XML documentation file \"%s\": %s!\n",
00271                 argv[1], strerror(errno));
00272         fclose(fp);
00273         mxmlDelete(doc);
00274         return (1);
00275       }
00276 
00277       fclose(fp);
00278     }
00279     else
00280     {
00281       fprintf(stderr, "Unable to create the XML documentation file \"%s\": %s!\n",
00282               argv[1], strerror(errno));
00283       mxmlDelete(doc);
00284       return (1);
00285     }
00286   }
00287 
00288  /*
00289   * Write HTML documentation...
00290   */
00291 
00292   write_documentation(mxmldoc);
00293 
00294  /*
00295   * Delete the tree and return...
00296   */
00297 
00298   mxmlDelete(doc);
00299 
00300   return (0);
00301 }
00302 
00303 
00304 /*
00305  * 'add_variable()' - Add a variable or argument.
00306  */
00307 
00308 static mxml_node_t *                    /* O - New variable/argument */
00309 add_variable(mxml_node_t *parent,       /* I - Parent node */
00310              const char  *name,         /* I - "argument" or "variable" */
00311              mxml_node_t *type)         /* I - Type nodes */
00312 {
00313   mxml_node_t   *variable,              /* New variable */
00314                 *node,                  /* Current node */
00315                 *next;                  /* Next node */
00316   char          buffer[16384],          /* String buffer */
00317                 *bufptr;                /* Pointer into buffer */
00318 
00319 
00320  /*
00321   * Range check input...
00322   */
00323 
00324   if (!type || !type->child)
00325     return (NULL);
00326 
00327  /*
00328   * Create the variable/argument node...
00329   */
00330 
00331   variable = mxmlNewElement(parent, name);
00332 
00333  /*
00334   * Check for a default value...
00335   */
00336 
00337   for (node = type->child; node; node = node->next)
00338     if (!strcmp(node->value.text.string, "="))
00339       break;
00340 
00341   if (node)
00342   {
00343    /*
00344     * Default value found, copy it and add as a "default" attribute...
00345     */
00346 
00347     for (bufptr = buffer; node; bufptr += strlen(bufptr))
00348     {
00349       if (node->value.text.whitespace && bufptr > buffer)
00350         *bufptr++ = ' ';
00351 
00352       strcpy(bufptr, node->value.text.string);
00353 
00354       next = node->next;
00355       mxmlDelete(node);
00356       node = next;
00357     }
00358 
00359     mxmlElementSetAttr(variable, "default", buffer);
00360   }
00361 
00362  /*
00363   * Extract the argument/variable name...
00364   */
00365 
00366   if (type->last_child->value.text.string[0] == ')')
00367   {
00368    /*
00369     * Handle "type (*name)(args)"...
00370     */
00371 
00372     for (node = type->child; node; node = node->next)
00373       if (node->value.text.string[0] == '(')
00374         break;
00375 
00376     for (bufptr = buffer; node; bufptr += strlen(bufptr))
00377     {
00378       if (node->value.text.whitespace && bufptr > buffer)
00379         *bufptr++ = ' ';
00380 
00381       strcpy(bufptr, node->value.text.string);
00382 
00383       next = node->next;
00384       mxmlDelete(node);
00385       node = next;
00386     }
00387   }
00388   else
00389   {
00390    /*
00391     * Handle "type name"...
00392     */
00393 
00394     strcpy(buffer, type->last_child->value.text.string);
00395     mxmlDelete(type->last_child);
00396   }
00397 
00398  /*
00399   * Set the name...
00400   */
00401 
00402   mxmlElementSetAttr(variable, "name", buffer);
00403 
00404  /*
00405   * Add the remaining type information to the variable node...
00406   */
00407 
00408   mxmlAdd(variable, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, type);
00409 
00410  /*
00411   * Add new new variable node...
00412   */
00413 
00414   return (variable);
00415 }
00416 
00417 
00418 /*
00419  * 'safe_strcpy()' - Copy a string allowing for overlapping strings.
00420  */
00421 
00422 static void
00423 safe_strcpy(char       *dst,            /* I - Destination string */
00424             const char *src)            /* I - Source string */
00425 {
00426   while (*src)
00427     *dst++ = *src++;
00428 
00429   *dst = '\0';
00430 }
00431 
00432 
00433 /*
00434  * 'scan_file()' - Scan a source file.
00435  */
00436 
00437 static int                              /* O - 0 on success, -1 on error */
00438 scan_file(const char  *filename,        /* I - Filename */
00439           FILE        *fp,              /* I - File to scan */
00440           mxml_node_t *tree)            /* I - Function tree */
00441 {
00442   int           state,                  /* Current parser state */
00443                 braces,                 /* Number of braces active */
00444                 parens;                 /* Number of active parenthesis */
00445   int           ch;                     /* Current character */
00446   char          buffer[65536],          /* String buffer */
00447                 *bufptr;                /* Pointer into buffer */
00448   const char    *scope;                 /* Current variable/function scope */
00449   mxml_node_t   *comment,               /* <comment> node */
00450                 *constant,              /* <constant> node */
00451                 *enumeration,           /* <enumeration> node */
00452                 *function,              /* <function> node */
00453                 *fstructclass,          /* function struct/class node */
00454                 *structclass,           /* <struct> or <class> node */
00455                 *typedefnode,           /* <typedef> node */
00456                 *variable,              /* <variable> or <argument> node */
00457                 *returnvalue,           /* <returnvalue> node */
00458                 *type,                  /* <type> node */
00459                 *description,           /* <description> node */
00460                 *node,                  /* Current node */
00461                 *next;                  /* Next node */
00462 #if DEBUG > 1
00463   mxml_node_t   *temp;                  /* Temporary node */
00464   int           oldstate,               /* Previous state */
00465                 oldch;                  /* Old character */
00466   static const char *states[] =         /* State strings */
00467                 {
00468                   "STATE_NONE",
00469                   "STATE_PREPROCESSOR",
00470                   "STATE_C_COMMENT",
00471                   "STATE_CXX_COMMENT",
00472                   "STATE_STRING",
00473                   "STATE_CHARACTER",
00474                   "STATE_IDENTIFIER"
00475                 };
00476 #endif /* DEBUG > 1 */
00477 
00478 
00479 #ifdef DEBUG
00480   fprintf(stderr, "scan_file(filename=\"%s\", fp=%p, tree=%p)\n", filename,
00481           fp, tree);
00482 #endif // DEBUG
00483 
00484  /*
00485   * Initialize the finite state machine...
00486   */
00487 
00488   state        = STATE_NONE;
00489   braces       = 0;
00490   parens       = 0;
00491   bufptr       = buffer;
00492 
00493   comment      = mxmlNewElement(MXML_NO_PARENT, "temp");
00494   constant     = NULL;
00495   enumeration  = NULL;
00496   function     = NULL;
00497   variable     = NULL;
00498   returnvalue  = NULL;
00499   type         = NULL;
00500   description  = NULL;
00501   typedefnode  = NULL;
00502   structclass  = NULL;
00503   fstructclass = NULL;
00504 
00505   if (!strcmp(tree->value.element.name, "class"))
00506     scope = "private";
00507   else
00508     scope = NULL;
00509 
00510  /*
00511   * Read until end-of-file...
00512   */
00513 
00514   while ((ch = getc(fp)) != EOF)
00515   {
00516 #if DEBUG > 1
00517     oldstate = state;
00518     oldch    = ch;
00519 #endif /* DEBUG > 1 */
00520 
00521     switch (state)
00522     {
00523       case STATE_NONE :                 /* No state - whitespace, etc. */
00524           switch (ch)
00525           {
00526             case '/' :                  /* Possible C/C++ comment */
00527                 ch     = getc(fp);
00528                 bufptr = buffer;
00529 
00530                 if (ch == '*')
00531                   state = STATE_C_COMMENT;
00532                 else if (ch == '/')
00533                   state = STATE_CXX_COMMENT;
00534                 else
00535                 {
00536                   ungetc(ch, fp);
00537 
00538                   if (type)
00539                   {
00540 #ifdef DEBUG
00541                     fputs("Identifier: <<<< / >>>\n", stderr);
00542 #endif /* DEBUG */
00543                     ch = type->last_child->value.text.string[0];
00544                     mxmlNewText(type, isalnum(ch) || ch == '_', "/");
00545                   }
00546                 }
00547                 break;
00548 
00549             case '#' :                  /* Preprocessor */
00550 #ifdef DEBUG
00551                 fputs("    #preprocessor...\n", stderr);
00552 #endif /* DEBUG */
00553                 state = STATE_PREPROCESSOR;
00554                 break;
00555 
00556             case '\'' :                 /* Character constant */
00557                 state = STATE_CHARACTER;
00558                 bufptr = buffer;
00559                 *bufptr++ = ch;
00560                 break;
00561 
00562             case '\"' :                 /* String constant */
00563                 state = STATE_STRING;
00564                 bufptr = buffer;
00565                 *bufptr++ = ch;
00566                 break;
00567 
00568             case '{' :
00569 #ifdef DEBUG
00570                 fprintf(stderr, "    open brace, function=%p, type=%p...\n",
00571                         function, type);
00572                 if (type)
00573                   fprintf(stderr, "    type->child=\"%s\"...\n",
00574                           type->child->value.text.string);
00575 #endif /* DEBUG */
00576 
00577                 if (function)
00578                 {
00579                   if (fstructclass)
00580                   {
00581                     sort_node(fstructclass, function);
00582                     fstructclass = NULL;
00583                   }
00584                   else
00585                     sort_node(tree, function);
00586 
00587                   function = NULL;
00588                 }
00589                 else if (type && type->child &&
00590                          ((!strcmp(type->child->value.text.string, "typedef") &&
00591                            type->child->next &&
00592                            (!strcmp(type->child->next->value.text.string, "struct") ||
00593                             !strcmp(type->child->next->value.text.string, "union") ||
00594                             !strcmp(type->child->next->value.text.string, "class"))) ||
00595                           !strcmp(type->child->value.text.string, "union") ||
00596                           !strcmp(type->child->value.text.string, "struct") ||
00597                           !strcmp(type->child->value.text.string, "class")))
00598                 {
00599                  /*
00600                   * Start of a class or structure...
00601                   */
00602 
00603                   if (!strcmp(type->child->value.text.string, "typedef"))
00604                   {
00605 #ifdef DEBUG
00606                     fputs("    starting typedef...\n", stderr);
00607 #endif /* DEBUG */
00608 
00609                     typedefnode = mxmlNewElement(MXML_NO_PARENT, "typedef");
00610                     mxmlDelete(type->child);
00611                   }
00612                   else
00613                     typedefnode = NULL;
00614         
00615                   structclass = mxmlNewElement(MXML_NO_PARENT,
00616                                                type->child->value.text.string);
00617 
00618 #ifdef DEBUG
00619                   fprintf(stderr, "%c%s: <<<< %s >>>\n",
00620                           toupper(type->child->value.text.string[0]),
00621                           type->child->value.text.string + 1,
00622                           type->child->next ?
00623                               type->child->next->value.text.string : "(noname)");
00624 
00625                   fputs("    type =", stderr);
00626                   for (node = type->child; node; node = node->next)
00627                     fprintf(stderr, " \"%s\"", node->value.text.string);
00628                   putc('\n', stderr);
00629 
00630                   fprintf(stderr, "    scope = %s\n", scope ? scope : "(null)");
00631 #endif /* DEBUG */
00632 
00633                   if (comment->last_child &&
00634                       strstr(comment->last_child->value.text.string, "@private"))
00635                   {
00636                     mxmlDelete(type);
00637                     type = NULL;
00638 
00639                     if (typedefnode)
00640                     {
00641                       mxmlDelete(typedefnode);
00642                       typedefnode = NULL;
00643                     }
00644 
00645                     mxmlDelete(structclass);
00646                     structclass = NULL;
00647 
00648                     braces ++;
00649                     function = NULL;
00650                     variable = NULL;
00651                     break;
00652                   }
00653 
00654                   if (type->child->next)
00655                   {
00656                     mxmlElementSetAttr(structclass, "name",
00657                                        type->child->next->value.text.string);
00658                     sort_node(tree, structclass);
00659                   }
00660 
00661                   if (typedefnode && type->child)
00662                     type->child->value.text.whitespace = 0;
00663                   else if (structclass && type->child &&
00664                            type->child->next && type->child->next->next)
00665                   {
00666                     for (bufptr = buffer, node = type->child->next->next;
00667                          node;
00668                          bufptr += strlen(bufptr))
00669                     {
00670                       if (node->value.text.whitespace && bufptr > buffer)
00671                         *bufptr++ = ' ';
00672 
00673                       strcpy(bufptr, node->value.text.string);
00674 
00675                       next = node->next;
00676                       mxmlDelete(node);
00677                       node = next;
00678                     }
00679 
00680                     mxmlElementSetAttr(structclass, "parent", buffer);
00681 
00682                     mxmlDelete(type);
00683                     type = NULL;
00684                   }
00685                   else
00686                   {
00687                     mxmlDelete(type);
00688                     type = NULL;
00689                   }
00690 
00691                   if (typedefnode && comment->last_child)
00692                   {
00693                    /*
00694                     * Copy comment for typedef as well as class/struct/union...
00695                     */
00696 
00697                     mxmlNewText(comment, 0,
00698                                 comment->last_child->value.text.string);
00699                     description = mxmlNewElement(typedefnode, "description");
00700 #ifdef DEBUG
00701                     fputs("    duplicating comment for typedef...\n", stderr);
00702 #endif /* DEBUG */
00703                     update_comment(typedefnode, comment->last_child);
00704                     mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT,
00705                             comment->last_child);
00706                   }
00707 
00708                   description = mxmlNewElement(structclass, "description");
00709 #ifdef DEBUG
00710                   fprintf(stderr, "    adding comment to %s...\n",
00711                           structclass->value.element.name);
00712 #endif /* DEBUG */
00713                   update_comment(structclass, comment->last_child);
00714                   mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT,
00715                           comment->last_child);
00716 
00717                   if (scan_file(filename, fp, structclass))
00718                   {
00719                     mxmlDelete(comment);
00720                     return (-1);
00721                   }
00722 
00723 #ifdef DEBUG
00724                   fputs("    ended typedef...\n", stderr);
00725 #endif /* DEBUG */
00726                   structclass = NULL;
00727                   break;
00728                 }
00729                 else if (type && type->child && type->child->next &&
00730                          (!strcmp(type->child->value.text.string, "enum") ||
00731                           (!strcmp(type->child->value.text.string, "typedef") &&
00732                            !strcmp(type->child->next->value.text.string, "enum"))))
00733                 {
00734                  /*
00735                   * Enumeration type...
00736                   */
00737 
00738                   if (!strcmp(type->child->value.text.string, "typedef"))
00739                   {
00740 #ifdef DEBUG
00741                     fputs("    starting typedef...\n", stderr);
00742 #endif /* DEBUG */
00743 
00744                     typedefnode = mxmlNewElement(MXML_NO_PARENT, "typedef");
00745                     mxmlDelete(type->child);
00746                   }
00747                   else
00748                     typedefnode = NULL;
00749         
00750                   enumeration = mxmlNewElement(MXML_NO_PARENT, "enumeration");
00751 
00752 #ifdef DEBUG
00753                   fprintf(stderr, "Enumeration: <<<< %s >>>\n",
00754                           type->child->next ?
00755                               type->child->next->value.text.string : "(noname)");
00756 #endif /* DEBUG */
00757 
00758                   if (type->child->next)
00759                   {
00760                     mxmlElementSetAttr(enumeration, "name",
00761                                        type->child->next->value.text.string);
00762                     sort_node(tree, enumeration);
00763                   }
00764 
00765                   if (typedefnode && type->child)
00766                     type->child->value.text.whitespace = 0;
00767                   else
00768                   {
00769                     mxmlDelete(type);
00770                     type = NULL;
00771                   }
00772 
00773                   if (typedefnode && comment->last_child)
00774                   {
00775                    /*
00776                     * Copy comment for typedef as well as class/struct/union...
00777                     */
00778 
00779                     mxmlNewText(comment, 0,
00780                                 comment->last_child->value.text.string);
00781                     description = mxmlNewElement(typedefnode, "description");
00782 #ifdef DEBUG
00783                     fputs("    duplicating comment for typedef...\n", stderr);
00784 #endif /* DEBUG */
00785                     update_comment(typedefnode, comment->last_child);
00786                     mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT,
00787                             comment->last_child);
00788                   }
00789 
00790                   description = mxmlNewElement(enumeration, "description");
00791 #ifdef DEBUG
00792                   fputs("    adding comment to enumeration...\n", stderr);
00793 #endif /* DEBUG */
00794                   update_comment(enumeration, comment->last_child);
00795                   mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT,
00796                           comment->last_child);
00797                 }
00798                 else if (type && type->child &&
00799                          !strcmp(type->child->value.text.string, "extern"))
00800                 {
00801                   if (scan_file(filename, fp, tree))
00802                   {
00803                     mxmlDelete(comment);
00804                     return (-1);
00805                   }
00806                 }
00807                 else if (type)
00808                 {
00809                   mxmlDelete(type);
00810                   type = NULL;
00811                 }
00812 
00813                 braces ++;
00814                 function = NULL;
00815                 variable = NULL;
00816                 break;
00817 
00818             case '}' :
00819 #ifdef DEBUG
00820                 fputs("    close brace...\n", stderr);
00821 #endif /* DEBUG */
00822 
00823                 if (structclass)
00824                   scope = NULL;
00825 
00826                 enumeration = NULL;
00827                 constant    = NULL;
00828                 structclass = NULL;
00829 
00830                 if (braces > 0)
00831                   braces --;
00832                 else
00833                 {
00834                   mxmlDelete(comment);
00835                   return (0);
00836                 }
00837                 break;
00838 
00839             case '(' :
00840                 if (type)
00841                 {
00842 #ifdef DEBUG
00843                   fputs("Identifier: <<<< ( >>>\n", stderr);
00844 #endif /* DEBUG */
00845                   mxmlNewText(type, 0, "(");
00846                 }
00847 
00848                 parens ++;
00849                 break;
00850 
00851             case ')' :
00852                 if (parens > 0)
00853                   parens --;
00854 
00855                 if (type && parens)
00856                 {
00857 #ifdef DEBUG
00858                   fputs("Identifier: <<<< ) >>>\n", stderr);
00859 #endif /* DEBUG */
00860                   mxmlNewText(type, 0, ")");
00861                 }
00862 
00863                 if (function && type && !parens)
00864                 {
00865                   variable = add_variable(function, "argument", type);
00866                   type     = NULL;
00867                 }
00868                 break;
00869 
00870             case ';' :
00871 #ifdef DEBUG
00872                 fputs("Identifier: <<<< ; >>>\n", stderr);
00873                 fprintf(stderr, "    function=%p, type=%p\n", function, type);
00874 #endif /* DEBUG */
00875 
00876                 if (function)
00877                 {
00878                   if (!strcmp(tree->value.element.name, "class"))
00879                   {
00880 #ifdef DEBUG
00881                     fputs("    ADDING FUNCTION TO CLASS\n", stderr);
00882 #endif /* DEBUG */
00883                     sort_node(tree, function);
00884                   }
00885                   else
00886                     mxmlDelete(function);
00887 
00888                   function = NULL;
00889                   variable = NULL;
00890                 }
00891 
00892                 if (type)
00893                 {
00894                   mxmlDelete(type);
00895                   type = NULL;
00896                 }
00897                 break;
00898 
00899             case ':' :
00900                 if (type)
00901                 {
00902 #ifdef DEBUG
00903                   fputs("Identifier: <<<< : >>>\n", stderr);
00904 #endif /* DEBUG */
00905                   mxmlNewText(type, 1, ":");
00906                 }
00907                 break;
00908 
00909             case '*' :
00910                 if (type)
00911                 {
00912 #ifdef DEBUG
00913                   fputs("Identifier: <<<< * >>>\n", stderr);
00914 #endif /* DEBUG */
00915                   ch = type->last_child->value.text.string[0];
00916                   mxmlNewText(type, isalnum(ch) || ch == '_', "*");
00917                 }
00918                 break;
00919 
00920             case '&' :
00921                 if (type)
00922                 {
00923 #ifdef DEBUG
00924                   fputs("Identifier: <<<< & >>>\n", stderr);
00925 #endif /* DEBUG */
00926                   mxmlNewText(type, 1, "&");
00927                 }
00928                 break;
00929 
00930             case '+' :
00931                 if (type)
00932                 {
00933 #ifdef DEBUG
00934                   fputs("Identifier: <<<< + >>>\n", stderr);
00935 #endif /* DEBUG */
00936                   ch = type->last_child->value.text.string[0];
00937                   mxmlNewText(type, isalnum(ch) || ch == '_', "+");
00938                 }
00939                 break;
00940 
00941             case '-' :
00942                 if (type)
00943                 {
00944 #ifdef DEBUG
00945                   fputs("Identifier: <<<< - >>>\n", stderr);
00946 #endif /* DEBUG */
00947                   ch = type->last_child->value.text.string[0];
00948                   mxmlNewText(type, isalnum(ch) || ch == '_', "-");
00949                 }
00950                 break;
00951 
00952             case '=' :
00953                 if (type)
00954                 {
00955 #ifdef DEBUG
00956                   fputs("Identifier: <<<< = >>>\n", stderr);
00957 #endif /* DEBUG */
00958                   ch = type->last_child->value.text.string[0];
00959                   mxmlNewText(type, isalnum(ch) || ch == '_', "=");
00960                 }
00961                 break;
00962 
00963             default :                   /* Other */
00964                 if (isalnum(ch) || ch == '_' || ch == '.' || ch == ':' || ch == '~')
00965                 {
00966                   state     = STATE_IDENTIFIER;
00967                   bufptr    = buffer;
00968                   *bufptr++ = ch;
00969                 }
00970                 break;
00971           }
00972           break;
00973 
00974       case STATE_PREPROCESSOR :         /* Preprocessor directive */
00975           if (ch == '\n')
00976             state = STATE_NONE;
00977           else if (ch == '\\')
00978             getc(fp);
00979           break;
00980 
00981       case STATE_C_COMMENT :            /* Inside a C comment */
00982           switch (ch)
00983           {
00984             case '\n' :
00985                 while ((ch = getc(fp)) != EOF)
00986                   if (ch == '*')
00987                   {
00988                     ch = getc(fp);
00989 
00990                     if (ch == '/')
00991                     {
00992                       *bufptr = '\0';
00993 
00994                       if (comment->child != comment->last_child)
00995                       {
00996 #ifdef DEBUG
00997                         fprintf(stderr, "    removing comment %p, last comment %p...\n",
00998                                 comment->child, comment->last_child);
00999 #endif /* DEBUG */
01000                         mxmlDelete(comment->child);
01001 #ifdef DEBUG
01002                         fprintf(stderr, "    new comment %p, last comment %p...\n",
01003                                 comment->child, comment->last_child);
01004 #endif /* DEBUG */
01005                       }
01006 
01007 #ifdef DEBUG
01008                       fprintf(stderr, "    processing comment, variable=%p, constant=%p, tree=\"%s\"\n",
01009                               variable, constant, tree->value.element.name);
01010 #endif /* DEBUG */
01011 
01012                       if (variable)
01013                       {
01014                         description = mxmlNewElement(variable, "description");
01015 #ifdef DEBUG
01016                         fputs("    adding comment to variable...\n", stderr);
01017 #endif /* DEBUG */
01018                         update_comment(variable,
01019                                        mxmlNewText(description, 0, buffer));
01020                         variable = NULL;
01021                       }
01022                       else if (constant)
01023                       {
01024                         description = mxmlNewElement(constant, "description");
01025 #ifdef DEBUG
01026                         fputs("    adding comment to constant...\n", stderr);
01027 #endif /* DEBUG */
01028                         update_comment(constant,
01029                                        mxmlNewText(description, 0, buffer));
01030                         constant = NULL;
01031                       }
01032                       else if (typedefnode)
01033                       {
01034                         description = mxmlNewElement(typedefnode, "description");
01035 #ifdef DEBUG
01036                         fprintf(stderr, "    adding comment to typedef %s...\n",
01037                                 mxmlElementGetAttr(typedefnode, "name"));
01038 #endif /* DEBUG */
01039                         update_comment(typedefnode,
01040                                        mxmlNewText(description, 0, buffer));
01041                       }
01042                       else if (strcmp(tree->value.element.name, "mxmldoc") &&
01043                                !mxmlFindElement(tree, tree, "description",
01044                                                 NULL, NULL, MXML_DESCEND_FIRST))
01045                       {
01046                         description = mxmlNewElement(tree, "description");
01047 #ifdef DEBUG
01048                         fputs("    adding comment to parent...\n", stderr);
01049 #endif /* DEBUG */
01050                         update_comment(tree,
01051                                        mxmlNewText(description, 0, buffer));
01052                       }
01053                       else
01054                       {
01055 #ifdef DEBUG
01056                         fprintf(stderr, "    before adding comment, child=%p, last_child=%p\n",
01057                                 comment->child, comment->last_child);
01058 #endif /* DEBUG */
01059                         mxmlNewText(comment, 0, buffer);
01060 #ifdef DEBUG
01061                         fprintf(stderr, "    after adding comment, child=%p, last_child=%p\n",
01062                                 comment->child, comment->last_child);
01063 #endif /* DEBUG */
01064                       }
01065 #ifdef DEBUG
01066                       fprintf(stderr, "C comment: <<<< %s >>>\n", buffer);
01067 #endif /* DEBUG */
01068 
01069                       state = STATE_NONE;
01070                       break;
01071                     }
01072                     else
01073                       ungetc(ch, fp);
01074                   }
01075                   else if (ch == '\n' && bufptr > buffer &&
01076                            bufptr < (buffer + sizeof(buffer) - 1))
01077                     *bufptr++ = ch;
01078                   else if (!isspace(ch))
01079                     break;
01080 
01081                 if (ch != EOF)
01082                   ungetc(ch, fp);
01083 
01084                 if (bufptr > buffer && bufptr < (buffer + sizeof(buffer) - 1))
01085                   *bufptr++ = '\n';
01086                 break;
01087 
01088             case '/' :
01089                 if (ch == '/' && bufptr > buffer && bufptr[-1] == '*')
01090                 {
01091                   while (bufptr > buffer &&
01092                          (bufptr[-1] == '*' || isspace(bufptr[-1] & 255)))
01093                     bufptr --;
01094                   *bufptr = '\0';
01095 
01096                   if (comment->child != comment->last_child)
01097                   {
01098 #ifdef DEBUG
01099                     fprintf(stderr, "    removing comment %p, last comment %p...\n",
01100                             comment->child, comment->last_child);
01101 #endif /* DEBUG */
01102                     mxmlDelete(comment->child);
01103 #ifdef DEBUG
01104                     fprintf(stderr, "    new comment %p, last comment %p...\n",
01105                             comment->child, comment->last_child);
01106 #endif /* DEBUG */
01107                   }
01108 
01109                   if (variable)
01110                   {
01111                     description = mxmlNewElement(variable, "description");
01112 #ifdef DEBUG
01113                     fputs("    adding comment to variable...\n", stderr);
01114 #endif /* DEBUG */
01115                     update_comment(variable,
01116                                    mxmlNewText(description, 0, buffer));
01117                     variable = NULL;
01118                   }
01119                   else if (constant)
01120                   {
01121                     description = mxmlNewElement(constant, "description");
01122 #ifdef DEBUG
01123                     fputs("    adding comment to constant...\n", stderr);
01124 #endif /* DEBUG */
01125                     update_comment(constant,
01126                                    mxmlNewText(description, 0, buffer));
01127                     constant = NULL;
01128                   }
01129                   else if (typedefnode)
01130                   {
01131                     description = mxmlNewElement(typedefnode, "description");
01132 #ifdef DEBUG
01133                     fprintf(stderr, "    adding comment to typedef %s...\n",
01134                             mxmlElementGetAttr(typedefnode, "name"));
01135 #endif /* DEBUG */
01136                     update_comment(typedefnode,
01137                                    mxmlNewText(description, 0, buffer));
01138                   }
01139                   else if (strcmp(tree->value.element.name, "mxmldoc") &&
01140                            !mxmlFindElement(tree, tree, "description",
01141                                             NULL, NULL, MXML_DESCEND_FIRST))
01142                   {
01143                     description = mxmlNewElement(tree, "description");
01144 #ifdef DEBUG
01145                     fputs("    adding comment to parent...\n", stderr);
01146 #endif /* DEBUG */
01147                     update_comment(tree,
01148                                    mxmlNewText(description, 0, buffer));
01149                   }
01150                   else
01151                     mxmlNewText(comment, 0, buffer);
01152 
01153 #ifdef DEBUG
01154                   fprintf(stderr, "C comment: <<<< %s >>>\n", buffer);
01155 #endif /* DEBUG */
01156 
01157                   state = STATE_NONE;
01158                   break;
01159                 }
01160 
01161             default :
01162                 if (ch == ' ' && bufptr == buffer)
01163                   break;
01164 
01165                 if (bufptr < (buffer + sizeof(buffer) - 1))
01166                   *bufptr++ = ch;
01167                 break;
01168           }
01169           break;
01170 
01171       case STATE_CXX_COMMENT :          /* Inside a C++ comment */
01172           if (ch == '\n')
01173           {
01174             state = STATE_NONE;
01175             *bufptr = '\0';
01176 
01177             if (comment->child != comment->last_child)
01178             {
01179 #ifdef DEBUG
01180               fprintf(stderr, "    removing comment %p, last comment %p...\n",
01181                       comment->child, comment->last_child);
01182 #endif /* DEBUG */
01183               mxmlDelete(comment->child);
01184 #ifdef DEBUG
01185               fprintf(stderr, "    new comment %p, last comment %p...\n",
01186                       comment->child, comment->last_child);
01187 #endif /* DEBUG */
01188             }
01189 
01190             if (variable)
01191             {
01192               description = mxmlNewElement(variable, "description");
01193 #ifdef DEBUG
01194               fputs("    adding comment to variable...\n", stderr);
01195 #endif /* DEBUG */
01196               update_comment(variable,
01197                              mxmlNewText(description, 0, buffer));
01198               variable = NULL;
01199             }
01200             else if (constant)
01201             {
01202               description = mxmlNewElement(constant, "description");
01203 #ifdef DEBUG
01204               fputs("    adding comment to constant...\n", stderr);
01205 #endif /* DEBUG */
01206               update_comment(constant,
01207                              mxmlNewText(description, 0, buffer));
01208               constant = NULL;
01209             }
01210             else if (typedefnode)
01211             {
01212               description = mxmlNewElement(typedefnode, "description");
01213 #ifdef DEBUG
01214               fprintf(stderr, "    adding comment to typedef %s...\n",
01215                       mxmlElementGetAttr(typedefnode, "name"));
01216 #endif /* DEBUG */
01217               update_comment(typedefnode,
01218                              mxmlNewText(description, 0, buffer));
01219             }
01220             else if (strcmp(tree->value.element.name, "mxmldoc") &&
01221                      !mxmlFindElement(tree, tree, "description",
01222                                       NULL, NULL, MXML_DESCEND_FIRST))
01223             {
01224               description = mxmlNewElement(tree, "description");
01225 #ifdef DEBUG
01226               fputs("    adding comment to parent...\n", stderr);
01227 #endif /* DEBUG */
01228               update_comment(tree,
01229                              mxmlNewText(description, 0, buffer));
01230             }
01231             else
01232               mxmlNewText(comment, 0, buffer);
01233 
01234 #ifdef DEBUG
01235             fprintf(stderr, "C++ comment: <<<< %s >>>\n", buffer);
01236 #endif /* DEBUG */
01237           }
01238           else if (ch == ' ' && bufptr == buffer)
01239             break;
01240           else if (bufptr < (buffer + sizeof(buffer) - 1))
01241             *bufptr++ = ch;
01242           break;
01243 
01244       case STATE_STRING :               /* Inside a string constant */
01245           *bufptr++ = ch;
01246 
01247           if (ch == '\\')
01248             *bufptr++ = getc(fp);
01249           else if (ch == '\"')
01250           {
01251             *bufptr = '\0';
01252 
01253             if (type)
01254               mxmlNewText(type, type->child != NULL, buffer);
01255 
01256             state = STATE_NONE;
01257           }
01258           break;
01259 
01260       case STATE_CHARACTER :            /* Inside a character constant */
01261           *bufptr++ = ch;
01262 
01263           if (ch == '\\')
01264             *bufptr++ = getc(fp);
01265           else if (ch == '\'')
01266           {
01267             *bufptr = '\0';
01268 
01269             if (type)
01270               mxmlNewText(type, type->child != NULL, buffer);
01271 
01272             state = STATE_NONE;
01273           }
01274           break;
01275 
01276       case STATE_IDENTIFIER :           /* Inside a keyword or identifier */
01277           if (isalnum(ch) || ch == '_' || ch == '[' || ch == ']' ||
01278               (ch == ',' && parens > 1) || ch == ':' || ch == '.' || ch == '~')
01279           {
01280             if (bufptr < (buffer + sizeof(buffer) - 1))
01281               *bufptr++ = ch;
01282           }
01283           else
01284           {
01285             ungetc(ch, fp);
01286             *bufptr = '\0';
01287             state   = STATE_NONE;
01288 
01289 #ifdef DEBUG
01290             fprintf(stderr, "    braces=%d, type=%p, type->child=%p, buffer=\"%s\"\n",
01291                     braces, type, type ? type->child : NULL, buffer);
01292 #endif /* DEBUG */
01293 
01294             if (!braces)
01295             {
01296               if (!type || !type->child)
01297               {
01298                 if (!strcmp(tree->value.element.name, "class"))
01299                 {
01300                   if (!strcmp(buffer, "public") ||
01301                       !strcmp(buffer, "public:"))
01302                   {
01303                     scope = "public";
01304 #ifdef DEBUG
01305                     fputs("    scope = public\n", stderr);
01306 #endif /* DEBUG */
01307                     break;
01308                   }
01309                   else if (!strcmp(buffer, "private") ||
01310                            !strcmp(buffer, "private:"))
01311                   {
01312                     scope = "private";
01313 #ifdef DEBUG
01314                     fputs("    scope = private\n", stderr);
01315 #endif /* DEBUG */
01316                     break;
01317                   }
01318                   else if (!strcmp(buffer, "protected") ||
01319                            !strcmp(buffer, "protected:"))
01320                   {
01321                     scope = "protected";
01322 #ifdef DEBUG
01323                     fputs("    scope = protected\n", stderr);
01324 #endif /* DEBUG */
01325                     break;
01326                   }
01327                 }
01328               }
01329 
01330               if (!type)
01331                 type = mxmlNewElement(MXML_NO_PARENT, "type");
01332 
01333 #ifdef DEBUG
01334               fprintf(stderr, "    function=%p (%s), type->child=%p, ch='%c', parens=%d\n",
01335                       function,
01336                       function ? mxmlElementGetAttr(function, "name") : "null",
01337                       type->child, ch, parens);
01338 #endif /* DEBUG */
01339 
01340               if (!function && ch == '(')
01341               {
01342                 if (type->child &&
01343                     !strcmp(type->child->value.text.string, "extern"))
01344                 {
01345                  /*
01346                   * Remove external declarations...
01347                   */
01348 
01349                   mxmlDelete(type);
01350                   type = NULL;
01351                   break;
01352                 }
01353 
01354                 if (type->child &&
01355                     !strcmp(type->child->value.text.string, "static") &&
01356                     !strcmp(tree->value.element.name, "mxmldoc"))
01357                 {
01358                  /*
01359                   * Remove static functions...
01360                   */
01361 
01362                   mxmlDelete(type);
01363                   type = NULL;
01364                   break;
01365                 }
01366 
01367                 function = mxmlNewElement(MXML_NO_PARENT, "function");
01368                 if ((bufptr = strchr(buffer, ':')) != NULL && bufptr[1] == ':')
01369                 {
01370                   *bufptr = '\0';
01371                   bufptr += 2;
01372 
01373                   if ((fstructclass =
01374                            mxmlFindElement(tree, tree, "class", "name", buffer,
01375                                            MXML_DESCEND_FIRST)) == NULL)
01376                     fstructclass =
01377                         mxmlFindElement(tree, tree, "struct", "name", buffer,
01378                                         MXML_DESCEND_FIRST);
01379                 }
01380                 else
01381                   bufptr = buffer;
01382 
01383                 mxmlElementSetAttr(function, "name", bufptr);
01384 
01385                 if (scope)
01386                   mxmlElementSetAttr(function, "scope", scope);
01387 
01388 #ifdef DEBUG
01389                 fprintf(stderr, "function: %s\n", buffer);
01390                 fprintf(stderr, "    scope = %s\n", scope ? scope : "(null)");
01391                 fprintf(stderr, "    comment = %p\n", comment);
01392                 fprintf(stderr, "    child = (%p) %s\n",
01393                         comment->child,
01394                         comment->child ?
01395                             comment->child->value.text.string : "(null)");
01396                 fprintf(stderr, "    last_child = (%p) %s\n",
01397                         comment->last_child,
01398                         comment->last_child ?
01399                             comment->last_child->value.text.string : "(null)");
01400 #endif /* DEBUG */
01401 
01402                 if (type->last_child &&
01403                     strcmp(type->last_child->value.text.string, "void"))
01404                 {
01405                   returnvalue = mxmlNewElement(function, "returnvalue");
01406 
01407                   mxmlAdd(returnvalue, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, type);
01408 
01409                   description = mxmlNewElement(returnvalue, "description");
01410 #ifdef DEBUG
01411                   fputs("    adding comment to returnvalue...\n", stderr);
01412 #endif /* DEBUG */
01413                   update_comment(returnvalue, comment->last_child);
01414                   mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT,
01415                           comment->last_child);
01416                 }
01417                 else
01418                   mxmlDelete(type);
01419 
01420                 description = mxmlNewElement(function, "description");
01421 #ifdef DEBUG
01422                   fputs("    adding comment to function...\n", stderr);
01423 #endif /* DEBUG */
01424                 update_comment(function, comment->last_child);
01425                 mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT,
01426                         comment->last_child);
01427 
01428                 type = NULL;
01429               }
01430               else if (function && ((ch == ')' && parens == 1) || ch == ','))
01431               {
01432                /*
01433                 * Argument definition...
01434                 */
01435 
01436                 mxmlNewText(type, type->child != NULL &&
01437                                   type->last_child->value.text.string[0] != '(' &&
01438                                   type->last_child->value.text.string[0] != '*',
01439                             buffer);
01440 
01441 #ifdef DEBUG
01442                 fprintf(stderr, "Argument: <<<< %s >>>\n", buffer);
01443 #endif /* DEBUG */
01444 
01445                 variable = add_variable(function, "argument", type);
01446                 type     = NULL;
01447               }
01448               else if (type->child && !function && (ch == ';' || ch == ','))
01449               {
01450 #ifdef DEBUG
01451                 fprintf(stderr, "    got semicolon, typedefnode=%p, structclass=%p\n",
01452                         typedefnode, structclass);
01453 #endif /* DEBUG */
01454 
01455                 if (typedefnode || structclass)
01456                 {
01457 #ifdef DEBUG
01458                   fprintf(stderr, "Typedef/struct/class: <<<< %s >>>>\n", buffer);
01459 #endif /* DEBUG */
01460 
01461                   if (typedefnode)
01462                   {
01463                     mxmlElementSetAttr(typedefnode, "name", buffer);
01464 
01465                     sort_node(tree, typedefnode);
01466                   }
01467 
01468                   if (structclass && !mxmlElementGetAttr(structclass, "name"))
01469                   {
01470 #ifdef DEBUG
01471                     fprintf(stderr, "setting struct/class name to %s!\n",
01472                             type->last_child->value.text.string);
01473 #endif /* DEBUG */
01474                     mxmlElementSetAttr(structclass, "name", buffer);
01475 
01476                     sort_node(tree, structclass);
01477                     structclass = NULL;
01478                   }
01479 
01480                   if (typedefnode)
01481                     mxmlAdd(typedefnode, MXML_ADD_BEFORE, MXML_ADD_TO_PARENT,
01482                             type);
01483                   else
01484                     mxmlDelete(type);
01485 
01486                   type        = NULL;
01487                   typedefnode = NULL;
01488                 }
01489                 else if (type->child &&
01490                          !strcmp(type->child->value.text.string, "typedef"))
01491                 {
01492                  /*
01493                   * Simple typedef...
01494                   */
01495 
01496 #ifdef DEBUG
01497                   fprintf(stderr, "Typedef: <<<< %s >>>\n", buffer);
01498 #endif /* DEBUG */
01499 
01500                   typedefnode = mxmlNewElement(MXML_NO_PARENT, "typedef");
01501                   mxmlElementSetAttr(typedefnode, "name", buffer);
01502                   mxmlDelete(type->child);
01503 
01504                   sort_node(tree, typedefnode);
01505 
01506                   if (type->child)
01507                     type->child->value.text.whitespace = 0;
01508 
01509                   mxmlAdd(typedefnode, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, type);
01510                   type = NULL;
01511                 }
01512                 else if (!parens)
01513                 {
01514                  /*
01515                   * Variable definition...
01516                   */
01517 
01518                   if (type->child &&
01519                       !strcmp(type->child->value.text.string, "static") &&
01520                       !strcmp(tree->value.element.name, "mxmldoc"))
01521                   {
01522                    /*
01523                     * Remove static functions...
01524                     */
01525 
01526                     mxmlDelete(type);
01527                     type = NULL;
01528                     break;
01529                   }
01530 
01531                   mxmlNewText(type, type->child != NULL &&
01532                                     type->last_child->value.text.string[0] != '(' &&
01533                                     type->last_child->value.text.string[0] != '*',
01534                               buffer);
01535 
01536 #ifdef DEBUG
01537                   fprintf(stderr, "Variable: <<<< %s >>>>\n", buffer);
01538                   fprintf(stderr, "    scope = %s\n", scope ? scope : "(null)");
01539 #endif /* DEBUG */
01540 
01541                   variable = add_variable(MXML_NO_PARENT, "variable", type);
01542                   type     = NULL;
01543 
01544                   sort_node(tree, variable);
01545 
01546                   if (scope)
01547                     mxmlElementSetAttr(variable, "scope", scope);
01548                 }
01549               }
01550               else
01551               {
01552 #ifdef DEBUG
01553                 fprintf(stderr, "Identifier: <<<< %s >>>>\n", buffer);
01554 #endif /* DEBUG */
01555 
01556                 mxmlNewText(type, type->child != NULL &&
01557                                   type->last_child->value.text.string[0] != '(' &&
01558                                   type->last_child->value.text.string[0] != '*',
01559                             buffer);
01560               }
01561             }
01562             else if (enumeration && !isdigit(buffer[0] & 255))
01563             {
01564 #ifdef DEBUG
01565               fprintf(stderr, "Constant: <<<< %s >>>\n", buffer);
01566 #endif /* DEBUG */
01567 
01568               constant = mxmlNewElement(MXML_NO_PARENT, "constant");
01569               mxmlElementSetAttr(constant, "name", buffer);
01570               sort_node(enumeration, constant);
01571             }
01572             else if (type)
01573             {
01574               mxmlDelete(type);
01575               type = NULL;
01576             }
01577           }
01578           break;
01579     }
01580 
01581 #if DEBUG > 1
01582     if (state != oldstate)
01583     {
01584       fprintf(stderr, "    changed states from %s to %s on receipt of character '%c'...\n",
01585               states[oldstate], states[state], oldch);
01586       fprintf(stderr, "    variable = %p\n", variable);
01587       if (type)
01588       {
01589         fputs("    type =", stderr);
01590         for (temp = type->child; temp; temp = temp->next)
01591           fprintf(stderr, " \"%s\"", temp->value.text.string);
01592         fputs("\n", stderr);
01593       }
01594     }
01595 #endif /* DEBUG > 1 */
01596   }
01597 
01598   mxmlDelete(comment);
01599 
01600  /*
01601   * All done, return with no errors...
01602   */
01603 
01604   return (0);
01605 }
01606 
01607 
01608 /*
01609  * 'sort_node()' - Insert a node sorted into a tree.
01610  */
01611 
01612 static void
01613 sort_node(mxml_node_t *tree,            /* I - Tree to sort into */
01614           mxml_node_t *node)            /* I - Node to add */
01615 {
01616   mxml_node_t   *temp;                  /* Current node */
01617   const char    *tempname,              /* Name of current node */
01618                 *nodename,              /* Name of node */
01619                 *scope;                 /* Scope */
01620 
01621 
01622 #if DEBUG > 1
01623   fprintf(stderr, "    sort_node(tree=%p, node=%p)\n", tree, node);
01624 #endif /* DEBUG > 1 */
01625 
01626  /*
01627   * Range check input...
01628   */
01629 
01630   if (!tree || !node || node->parent == tree)
01631     return;
01632 
01633  /*
01634   * Get the node name...
01635   */
01636 
01637   if ((nodename = mxmlElementGetAttr(node, "name")) == NULL)
01638     return;
01639 
01640 #if DEBUG > 1
01641   fprintf(stderr, "        nodename=%p (\"%s\")\n", nodename, nodename);
01642 #endif /* DEBUG > 1 */
01643 
01644  /*
01645   * Delete any existing definition at this level, if one exists...
01646   */
01647 
01648   if ((temp = mxmlFindElement(tree, tree, node->value.element.name,
01649                               "name", nodename, MXML_DESCEND_FIRST)) != NULL)
01650   {
01651    /*
01652     * Copy the scope if needed...
01653     */
01654 
01655     if ((scope = mxmlElementGetAttr(temp, "scope")) != NULL &&
01656         mxmlElementGetAttr(node, "scope") == NULL)
01657     {
01658 #ifdef DEBUG
01659       fprintf(stderr, "    copying scope %s for %s\n", scope, nodename);
01660 #endif /* DEBUG */
01661 
01662       mxmlElementSetAttr(node, "scope", scope);
01663     }
01664 
01665     mxmlDelete(temp);
01666   }
01667 
01668  /*
01669   * Add the node into the tree at the proper place...
01670   */
01671 
01672   for (temp = tree->child; temp; temp = temp->next)
01673   {
01674 #if DEBUG > 1
01675     fprintf(stderr, "        temp=%p\n", temp);
01676 #endif /* DEBUG > 1 */
01677 
01678     if ((tempname = mxmlElementGetAttr(temp, "name")) == NULL)
01679       continue;
01680 
01681 #if DEBUG > 1
01682     fprintf(stderr, "        tempname=%p (\"%s\")\n", tempname, tempname);
01683 #endif /* DEBUG > 1 */
01684 
01685     if (strcmp(nodename, tempname) < 0)
01686       break;
01687   }
01688 
01689   if (temp)
01690     mxmlAdd(tree, MXML_ADD_BEFORE, temp, node);
01691   else
01692     mxmlAdd(tree, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, node);
01693 }
01694 
01695 
01696 /*
01697  * 'update_comment()' - Update a comment node.
01698  */
01699 
01700 static void
01701 update_comment(mxml_node_t *parent,     /* I - Parent node */
01702                mxml_node_t *comment)    /* I - Comment node */
01703 {
01704   char  *ptr;                           /* Pointer into comment */
01705 
01706 
01707 #ifdef DEBUG
01708   fprintf(stderr, "update_comment(parent=%p, comment=%p)\n",
01709           parent, comment);
01710 #endif /* DEBUG */
01711 
01712  /*
01713   * Range check the input...
01714   */
01715 
01716   if (!parent || !comment)
01717     return;
01718  
01719  /*
01720   * Update the comment...
01721   */
01722 
01723   ptr = comment->value.text.string;
01724 
01725   if (*ptr == '\'')
01726   {
01727    /*
01728     * Convert "'name()' - description" to "description".
01729     */
01730 
01731     for (ptr ++; *ptr && *ptr != '\''; ptr ++);
01732 
01733     if (*ptr == '\'')
01734     {
01735       ptr ++;
01736       while (isspace(*ptr & 255))
01737         ptr ++;
01738 
01739       if (*ptr == '-')
01740         ptr ++;
01741 
01742       while (isspace(*ptr & 255))
01743         ptr ++;
01744 
01745       safe_strcpy(comment->value.text.string, ptr);
01746     }
01747   }
01748   else if (!strncmp(ptr, "I ", 2) || !strncmp(ptr, "O ", 2) ||
01749            !strncmp(ptr, "IO ", 3))
01750   {
01751    /*
01752     * 'Convert "I - description", "IO - description", or "O - description"
01753     * to description + directory attribute.
01754     */
01755 
01756     ptr = strchr(ptr, ' ');
01757     *ptr++ = '\0';
01758 
01759     if (!strcmp(parent->value.element.name, "argument"))
01760       mxmlElementSetAttr(parent, "direction", comment->value.text.string);
01761 
01762     while (isspace(*ptr & 255))
01763       ptr ++;
01764 
01765     if (*ptr == '-')
01766       ptr ++;
01767 
01768     while (isspace(*ptr & 255))
01769       ptr ++;
01770 
01771     safe_strcpy(comment->value.text.string, ptr);
01772   }
01773 
01774  /*
01775   * Eliminate leading and trailing *'s...
01776   */
01777 
01778   for (ptr = comment->value.text.string; *ptr == '*'; ptr ++);
01779   for (; isspace(*ptr & 255); ptr ++);
01780   if (ptr > comment->value.text.string)
01781     safe_strcpy(comment->value.text.string, ptr);
01782 
01783   for (ptr = comment->value.text.string + strlen(comment->value.text.string) - 1;
01784        ptr > comment->value.text.string && *ptr == '*';
01785        ptr --)
01786     *ptr = '\0';
01787   for (; ptr > comment->value.text.string && isspace(*ptr & 255); ptr --)
01788     *ptr = '\0';
01789 
01790 #ifdef DEBUG
01791   fprintf(stderr, "    updated comment = %s\n", comment->value.text.string);
01792 #endif /* DEBUG */
01793 }
01794 
01795 
01796 /*
01797  * 'write_documentation()' - Write HTML documentation.
01798  */
01799 
01800 static void
01801 write_documentation(mxml_node_t *doc)   /* I - XML documentation */
01802 {
01803   int           i;                      /* Looping var */
01804   mxml_node_t   *function,              /* Current function */
01805                 *scut,                  /* Struct/class/union/typedef */
01806                 *arg,                   /* Current argument */
01807                 *description,           /* Description of function/var */
01808                 *type;                  /* Type for argument */
01809   const char    *name,                  /* Name of function/type */
01810                 *cname,                 /* Class name */
01811                 *defval,                /* Default value */
01812                 *parent;                /* Parent class */
01813   int           inscope;                /* Variable/method scope */
01814   char          prefix;                 /* Prefix character */
01815   static const char * const scopes[] =  /* Scope strings */
01816                 {
01817                   "private",
01818                   "protected",
01819                   "public"
01820                 };
01821 
01822 
01823  /*
01824   * Standard header...
01825   */
01826 
01827   puts("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
01828        "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
01829        "<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n"
01830        "<head>\n"
01831        "\t<title>Documentation</title>\n"
01832        "\t<meta name='creator' content='" MXML_VERSION "'/>\n"
01833        "\t<style><!--\n"
01834        "\th1, h2, h3, p { font-family: sans-serif; text-align: justify; }\n"
01835        "\ttt, pre a:link, pre a:visited, tt a:link, tt a:visited { font-weight: bold; color: #7f0000; }\n"
01836        "\tpre { font-weight: bold; color: #7f0000; margin-left: 2em; }\n"
01837        "\t--></style>\n"
01838        "</head>\n"
01839        "<body>");
01840 
01841  /*
01842   * Table of contents...
01843   */
01844 
01845   puts("<h2>Contents</h2>");
01846   puts("<ul>");
01847   if (mxmlFindElement(doc, doc, "class", NULL, NULL, MXML_DESCEND_FIRST))
01848     puts("\t<li><a href='#_classes'>Classes</a></li>");
01849   if (mxmlFindElement(doc, doc, "enumeration", NULL, NULL, MXML_DESCEND_FIRST))
01850     puts("\t<li><a href='#_enumerations'>Enumerations</a></li>");
01851   if (mxmlFindElement(doc, doc, "function", NULL, NULL, MXML_DESCEND_FIRST))
01852     puts("\t<li><a href='#_functions'>Functions</a></li>");
01853   if (mxmlFindElement(doc, doc, "struct", NULL, NULL, MXML_DESCEND_FIRST))
01854     puts("\t<li><a href='#_structures'>Structures</a></li>");
01855   if (mxmlFindElement(doc, doc, "typedef", NULL, NULL, MXML_DESCEND_FIRST))
01856     puts("\t<li><a href='#_types'>Types</a></li>");
01857   if (mxmlFindElement(doc, doc, "union", NULL, NULL, MXML_DESCEND_FIRST))
01858     puts("\t<li><a href='#_unions'>Unions</a></li>");
01859   if (mxmlFindElement(doc, doc, "variable", NULL, NULL, MXML_DESCEND_FIRST))
01860     puts("\t<li><a href='#_variables'>Variables</a></li>");
01861   puts("</ul>");
01862 
01863  /*
01864   * List of classes...
01865   */
01866 
01867   if (mxmlFindElement(doc, doc, "class", NULL, NULL, MXML_DESCEND_FIRST))
01868   {
01869     puts("<!-- NEW PAGE -->\n"
01870          "<h2><a name='_classes'>Classes</a></h2>\n"
01871          "<ul>");
01872 
01873     for (scut = mxmlFindElement(doc, doc, "class", NULL, NULL,
01874                                 MXML_DESCEND_FIRST);
01875          scut;
01876          scut = mxmlFindElement(scut, doc, "class", NULL, NULL,
01877                                 MXML_NO_DESCEND))
01878     {
01879       name = mxmlElementGetAttr(scut, "name");
01880       printf("\t<li><a href='#%s'><tt>%s</tt></a></li>\n", name, name);
01881     }
01882 
01883     puts("</ul>");
01884 
01885     for (scut = mxmlFindElement(doc, doc, "class", NULL, NULL,
01886                                 MXML_DESCEND_FIRST);
01887          scut;
01888          scut = mxmlFindElement(scut, doc, "class", NULL, NULL,
01889                                 MXML_NO_DESCEND))
01890     {
01891       cname = mxmlElementGetAttr(scut, "name");
01892       printf("<!-- NEW PAGE -->\n"
01893              "<h3><a name='%s'>%s</a></h3>\n"
01894              "<hr noshade/>\n", cname, cname);
01895 
01896       description = mxmlFindElement(scut, scut, "description", NULL,
01897                                     NULL, MXML_DESCEND_FIRST);
01898       if (description)
01899       {
01900         fputs("<h4>Description</h4>\n"
01901               "<p>", stdout);
01902         write_element(NULL, description);
01903         puts("</p>");
01904       }
01905 
01906       printf("<h4>Definition</h4>\n"
01907              "<pre>\n"
01908              "class %s", cname);
01909       if ((parent = mxmlElementGetAttr(scut, "parent")) != NULL)
01910         printf(" %s", parent);
01911       puts("\n{");
01912 
01913       for (i = 0; i < 3; i ++)
01914       {
01915         inscope = 0;
01916 
01917         for (arg = mxmlFindElement(scut, scut, "variable", "scope", scopes[i],
01918                                    MXML_DESCEND_FIRST);
01919              arg;
01920              arg = mxmlFindElement(arg, scut, "variable", "scope", scopes[i],
01921                                    MXML_NO_DESCEND))
01922         {
01923           if (!inscope)
01924           {
01925             inscope = 1;
01926             printf("  %s:\n", scopes[i]);
01927           }
01928 
01929           printf("    ");
01930           write_element(doc, mxmlFindElement(arg, arg, "type", NULL,
01931                                              NULL, MXML_DESCEND_FIRST));
01932           printf(" %s;\n", mxmlElementGetAttr(arg, "name"));
01933         }
01934 
01935         for (function = mxmlFindElement(scut, scut, "function", "scope", scopes[i],
01936                                         MXML_DESCEND_FIRST);
01937              function;
01938              function = mxmlFindElement(function, scut, "function", "scope", scopes[i],
01939                                         MXML_NO_DESCEND))
01940         {
01941           if (!inscope)
01942           {
01943             inscope = 1;
01944             printf("  %s:\n", scopes[i]);
01945           }
01946 
01947           name = mxmlElementGetAttr(function, "name");
01948 
01949           printf("    ");
01950 
01951           arg = mxmlFindElement(function, function, "returnvalue", NULL,
01952                                 NULL, MXML_DESCEND_FIRST);
01953 
01954           if (arg)
01955           {
01956             write_element(doc, mxmlFindElement(arg, arg, "type", NULL,
01957                                                NULL, MXML_DESCEND_FIRST));
01958             putchar(' ');
01959           }
01960           else if (strcmp(cname, name) && strcmp(cname, name + 1))
01961             fputs("void ", stdout);
01962 
01963           printf("<a href='#%s.%s'>%s</a>", cname, name, name);
01964 
01965           for (arg = mxmlFindElement(function, function, "argument", NULL, NULL,
01966                                      MXML_DESCEND_FIRST), prefix = '(';
01967                arg;
01968                arg = mxmlFindElement(arg, function, "argument", NULL, NULL,
01969                                      MXML_NO_DESCEND), prefix = ',')
01970           {
01971             type = mxmlFindElement(arg, arg, "type", NULL, NULL,
01972                                    MXML_DESCEND_FIRST);
01973 
01974             putchar(prefix);
01975             if (prefix == ',')
01976               putchar(' ');
01977 
01978             if (type->child)
01979             {
01980               write_element(doc, type);
01981               putchar(' ');
01982             }
01983             fputs(mxmlElementGetAttr(arg, "name"), stdout);
01984             if ((defval = mxmlElementGetAttr(arg, "default")) != NULL)
01985               printf(" %s", defval);
01986           }
01987 
01988           if (prefix == '(')
01989             puts("(void);");
01990           else
01991             puts(");");
01992         }
01993       }
01994 
01995       puts("};\n</pre>\n"
01996            "<h4>Members</h4>\n"
01997            "<p class='table'><table align='center' border='1' "
01998            "cellpadding='5' cellspacing='0' width='80%'>\n"
01999            "<thead><tr bgcolor='#cccccc'><th>Name</th><th>Description</th></tr></thead>\n"
02000            "<tbody>");
02001 
02002       for (arg = mxmlFindElement(scut, scut, "variable", NULL, NULL,
02003                                  MXML_DESCEND_FIRST);
02004            arg;
02005            arg = mxmlFindElement(arg, scut, "variable", NULL, NULL,
02006                                  MXML_NO_DESCEND))
02007       {
02008         printf("<tr><td><tt>%s</tt></td><td>", mxmlElementGetAttr(arg, "name"));
02009 
02010         write_element(NULL, mxmlFindElement(arg, arg, "description", NULL,
02011                                             NULL, MXML_DESCEND_FIRST));
02012 
02013         puts("</td></tr>");
02014       }
02015 
02016       for (function = mxmlFindElement(scut, scut, "function", NULL, NULL,
02017                                       MXML_DESCEND_FIRST);
02018            function;
02019            function = mxmlFindElement(function, scut, "function", NULL, NULL,
02020                                       MXML_NO_DESCEND))
02021       {
02022         name = mxmlElementGetAttr(function, "name");
02023 
02024         printf("<tr><td><tt><a name='%s.%s'>%s()</a></tt></td><td>",
02025                cname, name, name);
02026 
02027         description = mxmlFindElement(function, function, "description", NULL,
02028                                       NULL, MXML_DESCEND_FIRST);
02029         if (description)
02030           write_element(NULL, description);
02031 
02032         arg = mxmlFindElement(function, function, "returnvalue", NULL,
02033                               NULL, MXML_DESCEND_FIRST);
02034 
02035         if (arg)
02036         {
02037           fputs("\n<i>Returns:</i> ", stdout);
02038           write_element(NULL, mxmlFindElement(arg, arg, "description", NULL,
02039                                               NULL, MXML_DESCEND_FIRST));
02040         }
02041 
02042         puts("</td></tr>");
02043       }
02044 
02045       puts("</tbody></table></p>");
02046     }
02047   }
02048 
02049  /*
02050   * List of enumerations...
02051   */
02052 
02053   if (mxmlFindElement(doc, doc, "enumeration", NULL, NULL, MXML_DESCEND_FIRST))
02054   {
02055     puts("<!-- NEW PAGE -->\n"
02056          "<h2><a name='_enumerations'>Enumerations</a></h2>\n"
02057          "<ul>");
02058 
02059     for (scut = mxmlFindElement(doc, doc, "enumeration", NULL, NULL,
02060                                 MXML_DESCEND_FIRST);
02061          scut;
02062          scut = mxmlFindElement(scut, doc, "enumeration", NULL, NULL,
02063                                 MXML_NO_DESCEND))
02064     {
02065       name = mxmlElementGetAttr(scut, "name");
02066       printf("\t<li><a href='#%s'><tt>%s</tt></a></li>\n", name, name);
02067     }
02068 
02069     puts("</ul>");
02070 
02071     for (scut = mxmlFindElement(doc, doc, "enumeration", NULL, NULL,
02072                                 MXML_DESCEND_FIRST);
02073          scut;
02074          scut = mxmlFindElement(scut, doc, "enumeration", NULL, NULL,
02075                                 MXML_NO_DESCEND))
02076     {
02077       name = mxmlElementGetAttr(scut, "name");
02078       printf("<!-- NEW PAGE -->\n"
02079              "<h3><a name='%s'>%s</a></h3>\n"
02080              "<hr noshade/>\n", name, name);
02081 
02082       description = mxmlFindElement(scut, scut, "description", NULL,
02083                                     NULL, MXML_DESCEND_FIRST);
02084       if (description)
02085       {
02086         fputs("<h4>Description</h4>\n"
02087               "<p>", stdout);
02088         write_element(NULL, description);
02089         puts("</p>");
02090       }
02091 
02092       puts("<h4>Values</h4>\n"
02093            "<p class='table'><table align='center' border='1' width='80%' "
02094            "cellpadding='5' cellspacing='0' width='80%'>\n"
02095            "<thead><tr bgcolor='#cccccc'><th>Name</th><th>Description</th></tr></thead>\n"
02096            "<tbody>");
02097 
02098       for (arg = mxmlFindElement(scut, scut, "constant", NULL, NULL,
02099                                  MXML_DESCEND_FIRST);
02100            arg;
02101            arg = mxmlFindElement(arg, scut, "constant", NULL, NULL,
02102                                  MXML_NO_DESCEND))
02103       {
02104         printf("<tr><td><tt>%s</tt></td><td>", mxmlElementGetAttr(arg, "name"));
02105 
02106         write_element(doc, mxmlFindElement(arg, arg, "description", NULL,
02107                                            NULL, MXML_DESCEND_FIRST));
02108 
02109         puts("</td></tr>");
02110       }
02111 
02112       puts("</tbody></table></p>");
02113     }
02114   }
02115 
02116  /*
02117   * List of functions...
02118   */
02119 
02120   if (mxmlFindElement(doc, doc, "function", NULL, NULL, MXML_DESCEND_FIRST))
02121   {
02122     puts("<!-- NEW PAGE -->\n"
02123          "<h2><a name='_functions'>Functions</a></h2>\n"
02124          "<ul>");
02125 
02126     for (function = mxmlFindElement(doc, doc, "function", NULL, NULL,
02127                                     MXML_DESCEND_FIRST);
02128          function;
02129          function = mxmlFindElement(function, doc, "function", NULL, NULL,
02130                                     MXML_NO_DESCEND))
02131     {
02132       name = mxmlElementGetAttr(function, "name");
02133       printf("\t<li><a href='#%s'><tt>%s()</tt></a></li>\n", name, name);
02134     }
02135 
02136     puts("</ul>");
02137 
02138     for (function = mxmlFindElement(doc, doc, "function", NULL, NULL,
02139                                     MXML_DESCEND_FIRST);
02140          function;
02141          function = mxmlFindElement(function, doc, "function", NULL, NULL,
02142                                     MXML_NO_DESCEND))
02143     {
02144       name = mxmlElementGetAttr(function, "name");
02145       printf("<!-- NEW PAGE -->\n"
02146              "<h3><a name='%s'>%s()</a></h3>\n"
02147              "<hr noshade/>\n", name, name);
02148 
02149       description = mxmlFindElement(function, function, "description", NULL,
02150                                     NULL, MXML_DESCEND_FIRST);
02151       if (description)
02152       {
02153         fputs("<h4>Description</h4>\n"
02154               "<p>", stdout);
02155         write_element(NULL, description);
02156         puts("</p>");
02157       }
02158 
02159       puts("<h4>Syntax</h4>\n"
02160            "<pre>");
02161 
02162       arg = mxmlFindElement(function, function, "returnvalue", NULL,
02163                             NULL, MXML_DESCEND_FIRST);
02164 
02165       if (arg)
02166         write_element(doc, mxmlFindElement(arg, arg, "type", NULL,
02167                                            NULL, MXML_DESCEND_FIRST));
02168       else
02169         fputs("void", stdout);
02170 
02171       printf("\n%s", name);
02172       for (arg = mxmlFindElement(function, function, "argument", NULL, NULL,
02173                                  MXML_DESCEND_FIRST), prefix = '(';
02174            arg;
02175            arg = mxmlFindElement(arg, function, "argument", NULL, NULL,
02176                                  MXML_NO_DESCEND), prefix = ',')
02177       {
02178         type = mxmlFindElement(arg, arg, "type", NULL, NULL,
02179                                MXML_DESCEND_FIRST);
02180 
02181         printf("%c\n    ", prefix);
02182         if (type->child)
02183         {
02184           write_element(doc, type);
02185           putchar(' ');
02186         }
02187         fputs(mxmlElementGetAttr(arg, "name"), stdout);
02188         if ((defval = mxmlElementGetAttr(arg, "default")) != NULL)
02189           printf(" %s", defval);
02190       }
02191 
02192       if (prefix == '(')
02193         puts("(void);\n</pre>");
02194       else
02195         puts(");\n</pre>");
02196 
02197       puts("<h4>Arguments</h4>");
02198 
02199       if (prefix == '(')
02200         puts("<p>None.</p>");
02201       else
02202       {
02203         puts("<p class='table'><table align='center' border='1' width='80%' "
02204              "cellpadding='5' cellspacing='0' width='80%'>\n"
02205              "<thead><tr bgcolor='#cccccc'><th>Name</th><th>Description</th></tr></thead>\n"
02206              "<tbody>");
02207 
02208         for (arg = mxmlFindElement(function, function, "argument", NULL, NULL,
02209                                    MXML_DESCEND_FIRST);
02210              arg;
02211              arg = mxmlFindElement(arg, function, "argument", NULL, NULL,
02212                                    MXML_NO_DESCEND))
02213         {
02214           printf("<tr><td><tt>%s</tt></td><td>", mxmlElementGetAttr(arg, "name"));
02215 
02216           write_element(NULL, mxmlFindElement(arg, arg, "description", NULL,
02217                                               NULL, MXML_DESCEND_FIRST));
02218 
02219           puts("</td></tr>");
02220         }
02221 
02222         puts("</tbody></table></p>");
02223       }
02224 
02225       puts("<h4>Returns</h4>");
02226 
02227       arg = mxmlFindElement(function, function, "returnvalue", NULL,
02228                             NULL, MXML_DESCEND_FIRST);
02229 
02230       if (!arg)
02231         puts("<p>Nothing.</p>");
02232       else
02233       {
02234         fputs("<p>", stdout);
02235         write_element(NULL, mxmlFindElement(arg, arg, "description", NULL,
02236                                             NULL, MXML_DESCEND_FIRST));
02237         puts("</p>");
02238       }
02239     }
02240   }
02241 
02242  /*
02243   * List of structures...
02244   */
02245 
02246   if (mxmlFindElement(doc, doc, "struct", NULL, NULL, MXML_DESCEND_FIRST))
02247   {
02248     puts("<!-- NEW PAGE -->\n"
02249          "<h2><a name='_structures'>Structures</a></h2>\n"
02250          "<ul>");
02251 
02252     for (scut = mxmlFindElement(doc, doc, "struct", NULL, NULL,
02253                                 MXML_DESCEND_FIRST);
02254          scut;
02255          scut = mxmlFindElement(scut, doc, "struct", NULL, NULL,
02256                                 MXML_NO_DESCEND))
02257     {
02258       name = mxmlElementGetAttr(scut, "name");
02259       printf("\t<li><a href='#%s'><tt>%s</tt></a></li>\n", name, name);
02260     }
02261 
02262     puts("</ul>");
02263 
02264     for (scut = mxmlFindElement(doc, doc, "struct", NULL, NULL,
02265                                 MXML_DESCEND_FIRST);
02266          scut;
02267          scut = mxmlFindElement(scut, doc, "struct", NULL, NULL,
02268                                 MXML_NO_DESCEND))
02269     {
02270       cname = mxmlElementGetAttr(scut, "name");
02271       printf("<!-- NEW PAGE -->\n"
02272              "<h3><a name='%s'>%s</a></h3>\n"
02273              "<hr noshade/>\n", cname, cname);
02274 
02275       description = mxmlFindElement(scut, scut, "description", NULL,
02276                                     NULL, MXML_DESCEND_FIRST);
02277       if (description)
02278       {
02279         fputs("<h4>Description</h4>\n"
02280               "<p>", stdout);
02281         write_element(NULL, description);
02282         puts("</p>");
02283       }
02284 
02285       printf("<h4>Definition</h4>\n"
02286              "<pre>\n"
02287              "struct %s\n{\n", cname);
02288       for (arg = mxmlFindElement(scut, scut, "variable", NULL, NULL,
02289                                  MXML_DESCEND_FIRST);
02290            arg;
02291            arg = mxmlFindElement(arg, scut, "variable", NULL, NULL,
02292                                  MXML_NO_DESCEND))
02293       {
02294         printf("  ");
02295         write_element(doc, mxmlFindElement(arg, arg, "type", NULL,
02296                                            NULL, MXML_DESCEND_FIRST));
02297         printf(" %s;\n", mxmlElementGetAttr(arg, "name"));
02298       }
02299 
02300       for (function = mxmlFindElement(scut, scut, "function", NULL, NULL,
02301                                       MXML_DESCEND_FIRST);
02302            function;
02303            function = mxmlFindElement(function, scut, "function", NULL, NULL,
02304                                       MXML_NO_DESCEND))
02305       {
02306         name = mxmlElementGetAttr(function, "name");
02307 
02308         printf("  ");
02309 
02310         arg = mxmlFindElement(function, function, "returnvalue", NULL,
02311                               NULL, MXML_DESCEND_FIRST);
02312 
02313         if (arg)
02314         {
02315           write_element(doc, mxmlFindElement(arg, arg, "type", NULL,
02316                                              NULL, MXML_DESCEND_FIRST));
02317           putchar(' ');
02318         }
02319         else if (strcmp(cname, name) && strcmp(cname, name + 1))
02320           fputs("void ", stdout);
02321 
02322         printf("<a href='#%s.%s'>%s</a>", cname, name, name);
02323 
02324         for (arg = mxmlFindElement(function, function, "argument", NULL, NULL,
02325                                    MXML_DESCEND_FIRST), prefix = '(';
02326              arg;
02327              arg = mxmlFindElement(arg, function, "argument", NULL, NULL,
02328                                    MXML_NO_DESCEND), prefix = ',')
02329         {
02330           type = mxmlFindElement(arg, arg, "type", NULL, NULL,
02331                                  MXML_DESCEND_FIRST);
02332 
02333           putchar(prefix);
02334           if (prefix == ',')
02335             putchar(' ');
02336 
02337           if (type->child)
02338           {
02339             write_element(doc, type);
02340             putchar(' ');
02341           }
02342           fputs(mxmlElementGetAttr(arg, "name"), stdout);
02343           if ((defval = mxmlElementGetAttr(arg, "default")) != NULL)
02344             printf(" %s", defval);
02345         }
02346 
02347         if (prefix == '(')
02348           puts("(void);");
02349         else
02350           puts(");");
02351       }
02352 
02353       puts("};\n</pre>\n"
02354            "<h4>Members</h4>\n"
02355            "<p class='table'><table align='center' border='1' width='80%' "
02356            "cellpadding='5' cellspacing='0' width='80%'>\n"
02357            "<thead><tr bgcolor='#cccccc'><th>Name</th><th>Description</th></tr></thead>\n"
02358            "<tbody>");
02359 
02360       for (arg = mxmlFindElement(scut, scut, "variable", NULL, NULL,
02361                                  MXML_DESCEND_FIRST);
02362            arg;
02363            arg = mxmlFindElement(arg, scut, "variable", NULL, NULL,
02364                                  MXML_NO_DESCEND))
02365       {
02366         printf("<tr><td><tt>%s</tt></td><td>", mxmlElementGetAttr(arg, "name"));
02367 
02368         write_element(NULL, mxmlFindElement(arg, arg, "description", NULL,
02369                                             NULL, MXML_DESCEND_FIRST));
02370 
02371         puts("</td></tr>");
02372       }
02373 
02374       for (function = mxmlFindElement(scut, scut, "function", NULL, NULL,
02375                                       MXML_DESCEND_FIRST);
02376            function;
02377            function = mxmlFindElement(function, scut, "function", NULL, NULL,
02378                                       MXML_NO_DESCEND))
02379       {
02380         name = mxmlElementGetAttr(function, "name");
02381 
02382         printf("<tr><td><tt><a name='%s.%s'>%s()</a></tt></td><td>",
02383                cname, name, name);
02384 
02385         description = mxmlFindElement(function, function, "description", NULL,
02386                                       NULL, MXML_DESCEND_FIRST);
02387         if (description)
02388           write_element(NULL, description);
02389 
02390         arg = mxmlFindElement(function, function, "returnvalue", NULL,
02391                               NULL, MXML_DESCEND_FIRST);
02392 
02393         if (arg)
02394         {
02395           fputs("\n<i>Returns:</i> ", stdout);
02396           write_element(NULL, mxmlFindElement(arg, arg, "description", NULL,
02397                                               NULL, MXML_DESCEND_FIRST));
02398         }
02399 
02400         puts("</td></tr>");
02401       }
02402 
02403       puts("</tbody></table></p>");
02404     }
02405   }
02406 
02407  /*
02408   * List of types...
02409   */
02410 
02411   if (mxmlFindElement(doc, doc, "typedef", NULL, NULL, MXML_DESCEND_FIRST))
02412   {
02413     puts("<!-- NEW PAGE -->\n"
02414          "<h2><a name='_types'>Types</a></h2>\n"
02415          "<ul>");
02416 
02417     for (scut = mxmlFindElement(doc, doc, "typedef", NULL, NULL,
02418                                 MXML_DESCEND_FIRST);
02419          scut;
02420          scut = mxmlFindElement(scut, doc, "typedef", NULL, NULL,
02421                                 MXML_NO_DESCEND))
02422     {
02423       name = mxmlElementGetAttr(scut, "name");
02424       printf("\t<li><a href='#%s'><tt>%s</tt></a></li>\n", name, name);
02425     }
02426 
02427     puts("</ul>");
02428 
02429     for (scut = mxmlFindElement(doc, doc, "typedef", NULL, NULL,
02430                                 MXML_DESCEND_FIRST);
02431          scut;
02432          scut = mxmlFindElement(scut, doc, "typedef", NULL, NULL,
02433                                 MXML_NO_DESCEND))
02434     {
02435       name = mxmlElementGetAttr(scut, "name");
02436       printf("<!-- NEW PAGE -->\n"
02437              "<h3><a name='%s'>%s</a></h3>\n"
02438              "<hr noshade/>\n", name, name);
02439 
02440       description = mxmlFindElement(scut, scut, "description", NULL,
02441                                     NULL, MXML_DESCEND_FIRST);
02442       if (description)
02443       {
02444         fputs("<h4>Description</h4>\n"
02445               "<p>", stdout);
02446         write_element(NULL, description);
02447         puts("</p>");
02448       }
02449 
02450       fputs("<h4>Definition</h4>\n"
02451             "<pre>\n"
02452             "typedef ", stdout);
02453       write_element(doc, mxmlFindElement(scut, scut, "type", NULL,
02454                                          NULL, MXML_DESCEND_FIRST));
02455       printf(" %s;\n</pre>\n", name);
02456     }
02457   }
02458 
02459  /*
02460   * List of unions...
02461   */
02462 
02463   if (mxmlFindElement(doc, doc, "union", NULL, NULL, MXML_DESCEND_FIRST))
02464   {
02465     puts("<!-- NEW PAGE -->\n"
02466          "<h2><a name='_unions'>Unions</a></h2>\n"
02467          "<ul>");
02468 
02469     for (scut = mxmlFindElement(doc, doc, "union", NULL, NULL,
02470                                 MXML_DESCEND_FIRST);
02471          scut;
02472          scut = mxmlFindElement(scut, doc, "union", NULL, NULL,
02473                                 MXML_NO_DESCEND))
02474     {
02475       name = mxmlElementGetAttr(scut, "name");
02476       printf("\t<li><a href='#%s'><tt>%s</tt></a></li>\n", name, name);
02477     }
02478 
02479     puts("</ul>");
02480 
02481     for (scut = mxmlFindElement(doc, doc, "union", NULL, NULL,
02482                                 MXML_DESCEND_FIRST);
02483          scut;
02484          scut = mxmlFindElement(scut, doc, "union", NULL, NULL,
02485                                 MXML_NO_DESCEND))
02486     {
02487       name = mxmlElementGetAttr(scut, "name");
02488       printf("<!-- NEW PAGE -->\n"
02489              "<h3><a name='%s'>%s</a></h3>\n"
02490              "<hr noshade/>\n", name, name);
02491 
02492       description = mxmlFindElement(scut, scut, "description", NULL,
02493                                     NULL, MXML_DESCEND_FIRST);
02494       if (description)
02495       {
02496         fputs("<h4>Description</h4>\n"
02497               "<p>", stdout);
02498         write_element(NULL, description);
02499         puts("</p>");
02500       }
02501 
02502       printf("<h4>Definition</h4>\n"
02503              "<pre>\n"
02504              "union %s\n{\n", name);
02505       for (arg = mxmlFindElement(scut, scut, "variable", NULL, NULL,
02506                                  MXML_DESCEND_FIRST);
02507            arg;
02508            arg = mxmlFindElement(arg, scut, "variable", NULL, NULL,
02509                                  MXML_NO_DESCEND))
02510       {
02511         printf("  ");
02512         write_element(doc, mxmlFindElement(arg, arg, "type", NULL,
02513                                            NULL, MXML_DESCEND_FIRST));
02514         printf(" %s;\n", mxmlElementGetAttr(arg, "name"));
02515       }
02516 
02517       puts("};\n</pre>\n"
02518            "<h4>Members</h4>\n"
02519            "<p class='table'><table align='center' border='1' width='80%' "
02520            "cellpadding='5' cellspacing='0' width='80%'>\n"
02521            "<thead><tr bgcolor='#cccccc'><th>Name</th><th>Description</th></tr></thead>\n"
02522            "<tbody>");
02523 
02524       for (arg = mxmlFindElement(scut, scut, "variable", NULL, NULL,
02525                                  MXML_DESCEND_FIRST);
02526            arg;
02527            arg = mxmlFindElement(arg, scut, "variable", NULL, NULL,
02528                                  MXML_NO_DESCEND))
02529       {
02530         printf("<tr><td><tt>%s</tt></td><td>", mxmlElementGetAttr(arg, "name"));
02531 
02532         write_element(NULL, mxmlFindElement(arg, arg, "description", NULL,
02533                                             NULL, MXML_DESCEND_FIRST));
02534 
02535         puts("</td></tr>");
02536       }
02537 
02538       puts("</tbody></table></p>");
02539     }
02540   }
02541 
02542  /*
02543   * Variables...
02544   */
02545 
02546   if (mxmlFindElement(doc, doc, "variable", NULL, NULL, MXML_DESCEND_FIRST))
02547   {
02548     puts("<!-- NEW PAGE -->\n"
02549          "<h2><a name='_variables'>Variables</a></h2>\n"
02550          "<ul>");
02551 
02552     for (arg = mxmlFindElement(doc, doc, "variable", NULL, NULL,
02553                                MXML_DESCEND_FIRST);
02554          arg;
02555          arg = mxmlFindElement(arg, doc, "variable", NULL, NULL,
02556                                MXML_NO_DESCEND))
02557     {
02558       name = mxmlElementGetAttr(arg, "name");
02559       printf("\t<li><a href='#%s'><tt>%s</tt></a></li>\n", name, name);
02560     }
02561 
02562     puts("</ul>");
02563 
02564     for (arg = mxmlFindElement(doc, doc, "variable", NULL, NULL,
02565                                MXML_DESCEND_FIRST);
02566          arg;
02567          arg = mxmlFindElement(arg, doc, "variable", NULL, NULL,
02568                                MXML_NO_DESCEND))
02569     {
02570       name = mxmlElementGetAttr(arg, "name");
02571       printf("<!-- NEW PAGE -->\n"
02572              "<h3><a name='%s'>%s</a></h3>\n"
02573              "<hr noshade/>", name, name);
02574 
02575       description = mxmlFindElement(arg, arg, "description", NULL,
02576                                     NULL, MXML_DESCEND_FIRST);
02577       if (description)
02578       {
02579         fputs("<h4>Description</h4>\n"
02580               "<p>", stdout);
02581         write_element(NULL, description);
02582         puts("</p>");
02583       }
02584 
02585       puts("<h4>Definition</h4>\n"
02586            "<pre>");
02587 
02588       write_element(doc, mxmlFindElement(arg, arg, "type", NULL,
02589                                          NULL, MXML_DESCEND_FIRST));
02590       printf(" %s", mxmlElementGetAttr(arg, "name"));
02591       if ((defval = mxmlElementGetAttr(arg, "default")) != NULL)
02592         printf(" %s", defval);
02593       puts(";\n</pre>");
02594     }
02595   }
02596 
02597  /*
02598   * Standard footer...
02599   */
02600 
02601   puts("</body>\n"
02602        "</html>");
02603 }
02604 
02605 
02606 /*
02607  * 'write_element()' - Write an element's text nodes.
02608  */
02609 
02610 static void
02611 write_element(mxml_node_t *doc,         /* I - Document tree */
02612               mxml_node_t *element)     /* I - Element to write */
02613 {
02614   mxml_node_t   *node;                  /* Current node */
02615 
02616 
02617   if (!element)
02618     return;
02619 
02620   for (node = element->child;
02621        node;
02622        node = mxmlWalkNext(node, element, MXML_NO_DESCEND))
02623     if (node->type == MXML_TEXT)
02624     {
02625       if (node->value.text.whitespace)
02626         putchar(' ');
02627 
02628       if (mxmlFindElement(doc, doc, "class", "name", node->value.text.string,
02629                           MXML_DESCEND) ||
02630           mxmlFindElement(doc, doc, "enumeration", "name",
02631                           node->value.text.string, MXML_DESCEND) ||
02632           mxmlFindElement(doc, doc, "struct", "name", node->value.text.string,
02633                           MXML_DESCEND) ||
02634           mxmlFindElement(doc, doc, "typedef", "name", node->value.text.string,
02635                           MXML_DESCEND) ||
02636           mxmlFindElement(doc, doc, "union", "name", node->value.text.string,
02637                           MXML_DESCEND))
02638       {
02639         printf("<a href='#");
02640         write_string(node->value.text.string);
02641         printf("'>");
02642         write_string(node->value.text.string);
02643         printf("</a>");
02644       }
02645       else
02646         write_string(node->value.text.string);
02647     }
02648 }
02649 
02650 
02651 /*
02652  * 'write_string()' - Write a string, quoting XHTML special chars as needed...
02653  */
02654 
02655 static void
02656 write_string(const char *s)             /* I - String to write */
02657 {
02658   while (*s)
02659   {
02660     if (*s == '&')
02661       fputs("&amp;", stdout);
02662     else if (*s == '<')
02663       fputs("&lt;", stdout);
02664     else if (*s == '>')
02665       fputs("&gt;", stdout);
02666     else if (*s == '\"')
02667       fputs("&quot;", stdout);
02668     else if (*s & 128)
02669     {
02670      /*
02671       * Convert UTF-8 to Unicode constant...
02672       */
02673 
02674       int       ch;                     /* Unicode character */
02675 
02676 
02677       ch = *s & 255;
02678 
02679       if ((ch & 0xe0) == 0xc0)
02680       {
02681         ch = ((ch & 0x1f) << 6) | (s[1] & 0x3f);
02682         s ++;
02683       }
02684       else if ((ch & 0xf0) == 0xe0)
02685       {
02686         ch = ((((ch * 0x0f) << 6) | (s[1] & 0x3f)) << 6) | (s[2] & 0x3f);
02687         s += 2;
02688       }
02689 
02690       if (ch == 0xa0)
02691       {
02692        /*
02693         * Handle non-breaking space as-is...
02694         */
02695 
02696         fputs("&nbsp;", stdout);
02697       }
02698       else
02699         printf("&#x%x;", ch);
02700     }
02701     else
02702       putchar(*s);
02703 
02704     s ++;
02705   }
02706 }
02707 
02708 
02709 /*
02710  * 'ws_cb()' - Whitespace callback for saving.
02711  */
02712 
02713 static const char *                     /* O - Whitespace string or NULL for none */
02714 ws_cb(mxml_node_t *node,                /* I - Element node */
02715       int         where)                /* I - Where value */
02716 {
02717   const char *name;                     /* Name of element */
02718   int   depth;                          /* Depth of node */
02719   static const char *spaces = "                                        ";
02720                                         /* Whitespace (40 spaces) for indent */
02721 
02722 
02723   name = node->value.element.name;
02724 
02725   switch (where)
02726   {
02727     case MXML_WS_BEFORE_CLOSE :
02728         if (strcmp(name, "argument") &&
02729             strcmp(name, "class") &&
02730             strcmp(name, "constant") &&
02731             strcmp(name, "enumeration") &&
02732             strcmp(name, "function") &&
02733             strcmp(name, "mxmldoc") &&
02734             strcmp(name, "namespace") &&
02735             strcmp(name, "returnvalue") &&
02736             strcmp(name, "struct") &&
02737             strcmp(name, "typedef") &&
02738             strcmp(name, "union") &&
02739             strcmp(name, "variable"))
02740           return (NULL);
02741 
02742         for (depth = -4; node; node = node->parent, depth += 2);
02743         if (depth > 40)
02744           return (spaces);
02745         else if (depth < 2)
02746           return (NULL);
02747         else
02748           return (spaces + 40 - depth);
02749 
02750     case MXML_WS_AFTER_CLOSE :
02751         return ("\n");
02752 
02753     case MXML_WS_BEFORE_OPEN :
02754         for (depth = -4; node; node = node->parent, depth += 2);
02755         if (depth > 40)
02756           return (spaces);
02757         else if (depth < 2)
02758           return (NULL);
02759         else
02760           return (spaces + 40 - depth);
02761 
02762     default :
02763     case MXML_WS_AFTER_OPEN :
02764         if (strcmp(name, "argument") &&
02765             strcmp(name, "class") &&
02766             strcmp(name, "constant") &&
02767             strcmp(name, "enumeration") &&
02768             strcmp(name, "function") &&
02769             strcmp(name, "mxmldoc") &&
02770             strcmp(name, "namespace") &&
02771             strcmp(name, "returnvalue") &&
02772             strcmp(name, "struct") &&
02773             strcmp(name, "typedef") &&
02774             strcmp(name, "union") &&
02775             strcmp(name, "variable"))
02776           return (NULL);
02777         else
02778           return ("\n");
02779   }
02780 }
02781 
02782 
02783 /*
02784  * End of "$Id: mxmldoc.c,v 1.1 2007/05/23 20:43:28 david_ko Exp $".
02785  */

Generated on Fri Jul 11 17:59:45 2008 for Mobile-C by  doxygen 1.5.4