/home/dko/projects/mobilec/trunk/src/mxml-2.2.2/mxmldoc.c

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

Generated on Fri May 16 14:49:55 2008 for Mobile-C by  doxygen 1.5.4