| /*#define DEBUG 1*/ |
| /* |
| * "$Id: mxmldoc.c 451 2014-01-04 21:50:06Z msweet $" |
| * |
| * Documentation generator using Mini-XML, a small XML-like file parsing |
| * library. |
| * |
| * Copyright 2003-2014 by Michael R Sweet. |
| * |
| * These coded instructions, statements, and computer programs are the |
| * property of Michael R Sweet and are protected by Federal copyright |
| * law. Distribution and use rights are outlined in the file "COPYING" |
| * which should have been included with this file. If this file is |
| * missing or damaged, see the license at: |
| * |
| * http://www.minixml.org/ |
| */ |
| |
| /* |
| * Include necessary headers... |
| */ |
| |
| #include "config.h" |
| #include "mxml.h" |
| #include <time.h> |
| #include <sys/stat.h> |
| #ifndef WIN32 |
| # include <dirent.h> |
| # include <unistd.h> |
| #endif /* !WIN32 */ |
| #ifdef __APPLE__ |
| # include <spawn.h> |
| # include <sys/wait.h> |
| extern char **environ; |
| #endif /* __APPLE__ */ |
| |
| |
| /* |
| * This program scans source and header files and produces public API |
| * documentation for code that conforms to the CUPS Configuration |
| * Management Plan (CMP) coding standards. Please see the following web |
| * page for details: |
| * |
| * http://www.cups.org/cmp.html |
| * |
| * Using Mini-XML, this program creates and maintains an XML representation |
| * of the public API code documentation which can then be converted to HTML |
| * as desired. The following is a poor-man's schema: |
| * |
| * <?xml version="1.0"?> |
| * <mxmldoc xmlns="http://www.easysw.com" |
| * xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| * xsi:schemaLocation="http://www.minixml.org/mxmldoc.xsd"> |
| * |
| * <namespace name=""> [optional...] |
| * <constant name=""> |
| * <description>descriptive text</description> |
| * </constant> |
| * |
| * <enumeration name=""> |
| * <description>descriptive text</description> |
| * <constant name="">...</constant> |
| * </enumeration> |
| * |
| * <typedef name=""> |
| * <description>descriptive text</description> |
| * <type>type string</type> |
| * </typedef> |
| * |
| * <function name="" scope=""> |
| * <description>descriptive text</description> |
| * <argument name="" direction="I|O|IO" default=""> |
| * <description>descriptive text</description> |
| * <type>type string</type> |
| * </argument> |
| * <returnvalue> |
| * <description>descriptive text</description> |
| * <type>type string</type> |
| * </returnvalue> |
| * <seealso>function names separated by spaces</seealso> |
| * </function> |
| * |
| * <variable name="" scope=""> |
| * <description>descriptive text</description> |
| * <type>type string</type> |
| * </variable> |
| * |
| * <struct name=""> |
| * <description>descriptive text</description> |
| * <variable name="">...</variable> |
| * <function name="">...</function> |
| * </struct> |
| * |
| * <union name=""> |
| * <description>descriptive text</description> |
| * <variable name="">...</variable> |
| * </union> |
| * |
| * <class name="" parent=""> |
| * <description>descriptive text</description> |
| * <class name="">...</class> |
| * <enumeration name="">...</enumeration> |
| * <function name="">...</function> |
| * <struct name="">...</struct> |
| * <variable name="">...</variable> |
| * </class> |
| * </namespace> |
| * </mxmldoc> |
| */ |
| |
| |
| /* |
| * Basic states for file parser... |
| */ |
| |
| #define STATE_NONE 0 /* No state - whitespace, etc. */ |
| #define STATE_PREPROCESSOR 1 /* Preprocessor directive */ |
| #define STATE_C_COMMENT 2 /* Inside a C comment */ |
| #define STATE_CXX_COMMENT 3 /* Inside a C++ comment */ |
| #define STATE_STRING 4 /* Inside a string constant */ |
| #define STATE_CHARACTER 5 /* Inside a character constant */ |
| #define STATE_IDENTIFIER 6 /* Inside a keyword/identifier */ |
| |
| |
| /* |
| * Output modes... |
| */ |
| |
| #define OUTPUT_NONE 0 /* No output */ |
| #define OUTPUT_HTML 1 /* Output HTML */ |
| #define OUTPUT_XML 2 /* Output XML */ |
| #define OUTPUT_MAN 3 /* Output nroff/man */ |
| #define OUTPUT_TOKENS 4 /* Output docset Tokens.xml file */ |
| |
| |
| /* |
| * Local functions... |
| */ |
| |
| static mxml_node_t *add_variable(mxml_node_t *parent, const char *name, |
| mxml_node_t *type); |
| static mxml_node_t *find_public(mxml_node_t *node, mxml_node_t *top, |
| const char *name); |
| static char *get_comment_info(mxml_node_t *description); |
| static char *get_text(mxml_node_t *node, char *buffer, int buflen); |
| static mxml_type_t load_cb(mxml_node_t *node); |
| static mxml_node_t *new_documentation(mxml_node_t **mxmldoc); |
| static int remove_directory(const char *path); |
| static void safe_strcpy(char *dst, const char *src); |
| static int scan_file(const char *filename, FILE *fp, |
| mxml_node_t *doc); |
| static void sort_node(mxml_node_t *tree, mxml_node_t *func); |
| static void update_comment(mxml_node_t *parent, |
| mxml_node_t *comment); |
| static void usage(const char *option); |
| static void write_description(FILE *out, mxml_node_t *description, |
| const char *element, int summary); |
| static void write_element(FILE *out, mxml_node_t *doc, |
| mxml_node_t *element, int mode); |
| static void write_file(FILE *out, const char *file); |
| static void write_function(FILE *out, mxml_node_t *doc, |
| mxml_node_t *function, int level); |
| static void write_html(const char *section, const char *title, |
| const char *footerfile, |
| const char *headerfile, |
| const char *introfile, const char *cssfile, |
| const char *framefile, |
| const char *docset, const char *docversion, |
| const char *feedname, const char *feedurl, |
| mxml_node_t *doc); |
| static void write_html_head(FILE *out, const char *section, |
| const char *title, const char *cssfile); |
| static void write_man(const char *man_name, const char *section, |
| const char *title, const char *headerfile, |
| const char *footerfile, const char *introfile, |
| mxml_node_t *doc); |
| static void write_scu(FILE *out, mxml_node_t *doc, |
| mxml_node_t *scut); |
| static void write_string(FILE *out, const char *s, int mode); |
| static void write_toc(FILE *out, mxml_node_t *doc, |
| const char *introfile, const char *target, |
| int xml); |
| static void write_tokens(FILE *out, mxml_node_t *doc, |
| const char *path); |
| static const char *ws_cb(mxml_node_t *node, int where); |
| |
| |
| /* |
| * 'main()' - Main entry for test program. |
| */ |
| |
| int /* O - Exit status */ |
| main(int argc, /* I - Number of command-line args */ |
| char *argv[]) /* I - Command-line args */ |
| { |
| int i; /* Looping var */ |
| int len; /* Length of argument */ |
| FILE *fp; /* File to read */ |
| mxml_node_t *doc; /* XML documentation tree */ |
| mxml_node_t *mxmldoc; /* mxmldoc node */ |
| const char *cssfile, /* CSS stylesheet file */ |
| *docset, /* Documentation set directory */ |
| *docversion, /* Documentation set version */ |
| *feedname, /* Feed name for documentation set */ |
| *feedurl, /* Feed URL for documentation set */ |
| *footerfile, /* Footer file */ |
| *framefile, /* Framed HTML basename */ |
| *headerfile, /* Header file */ |
| *introfile, /* Introduction file */ |
| *name, /* Name of manpage */ |
| *path, /* Path to help file for tokens */ |
| *section, /* Section/keywords of documentation */ |
| *title, /* Title of documentation */ |
| *xmlfile; /* XML file */ |
| int mode, /* Output mode */ |
| update; /* Updated XML file */ |
| |
| |
| /* |
| * Check arguments... |
| */ |
| |
| cssfile = NULL; |
| doc = NULL; |
| docset = NULL; |
| docversion = NULL; |
| feedname = NULL; |
| feedurl = NULL; |
| footerfile = NULL; |
| framefile = NULL; |
| headerfile = NULL; |
| introfile = NULL; |
| mode = OUTPUT_HTML; |
| mxmldoc = NULL; |
| name = NULL; |
| path = NULL; |
| section = NULL; |
| title = NULL; |
| update = 0; |
| xmlfile = NULL; |
| |
| for (i = 1; i < argc; i ++) |
| if (!strcmp(argv[i], "--help")) |
| { |
| /* |
| * Show help... |
| */ |
| |
| usage(NULL); |
| } |
| else if (!strcmp(argv[i], "--version")) |
| { |
| /* |
| * Show version... |
| */ |
| |
| puts(MXML_VERSION + 10); |
| return (0); |
| } |
| else if (!strcmp(argv[i], "--css") && !cssfile) |
| { |
| /* |
| * Set CSS stylesheet file... |
| */ |
| |
| i ++; |
| if (i < argc) |
| cssfile = argv[i]; |
| else |
| usage(NULL); |
| } |
| else if (!strcmp(argv[i], "--docset") && !docset) |
| { |
| /* |
| * Set documentation set directory... |
| */ |
| |
| i ++; |
| if (i < argc) |
| docset = argv[i]; |
| else |
| usage(NULL); |
| } |
| else if (!strcmp(argv[i], "--docversion") && !docversion) |
| { |
| /* |
| * Set documentation set directory... |
| */ |
| |
| i ++; |
| if (i < argc) |
| docversion = argv[i]; |
| else |
| usage(NULL); |
| } |
| else if (!strcmp(argv[i], "--footer") && !footerfile) |
| { |
| /* |
| * Set footer file... |
| */ |
| |
| i ++; |
| if (i < argc) |
| footerfile = argv[i]; |
| else |
| usage(NULL); |
| } |
| else if (!strcmp(argv[i], "--feedname") && !feedname) |
| { |
| /* |
| * Set documentation set feed name... |
| */ |
| |
| i ++; |
| if (i < argc) |
| feedname = argv[i]; |
| else |
| usage(NULL); |
| } |
| else if (!strcmp(argv[i], "--feedurl") && !feedurl) |
| { |
| /* |
| * Set documentation set feed name... |
| */ |
| |
| i ++; |
| if (i < argc) |
| feedurl = argv[i]; |
| else |
| usage(NULL); |
| } |
| else if (!strcmp(argv[i], "--framed") && !framefile) |
| { |
| /* |
| * Set base filename for framed HTML output... |
| */ |
| |
| i ++; |
| if (i < argc) |
| framefile = argv[i]; |
| else |
| usage(NULL); |
| } |
| else if (!strcmp(argv[i], "--header") && !headerfile) |
| { |
| /* |
| * Set header file... |
| */ |
| |
| i ++; |
| if (i < argc) |
| headerfile = argv[i]; |
| else |
| usage(NULL); |
| } |
| else if (!strcmp(argv[i], "--intro") && !introfile) |
| { |
| /* |
| * Set intro file... |
| */ |
| |
| i ++; |
| if (i < argc) |
| introfile = argv[i]; |
| else |
| usage(NULL); |
| } |
| else if (!strcmp(argv[i], "--man") && !name) |
| { |
| /* |
| * Output manpage... |
| */ |
| |
| i ++; |
| if (i < argc) |
| { |
| mode = OUTPUT_MAN; |
| name = argv[i]; |
| } |
| else |
| usage(NULL); |
| } |
| else if (!strcmp(argv[i], "--no-output")) |
| mode = OUTPUT_NONE; |
| else if (!strcmp(argv[i], "--section") && !section) |
| { |
| /* |
| * Set section/keywords... |
| */ |
| |
| i ++; |
| if (i < argc) |
| section = argv[i]; |
| else |
| usage(NULL); |
| } |
| else if (!strcmp(argv[i], "--title") && !title) |
| { |
| /* |
| * Set title... |
| */ |
| |
| i ++; |
| if (i < argc) |
| title = argv[i]; |
| else |
| usage(NULL); |
| } |
| else if (!strcmp(argv[i], "--tokens")) |
| { |
| /* |
| * Output Tokens.xml file... |
| */ |
| |
| mode = OUTPUT_TOKENS; |
| |
| i ++; |
| if (i < argc) |
| path = argv[i]; |
| else |
| usage(NULL); |
| } |
| else if (argv[i][0] == '-') |
| { |
| /* |
| * Unknown/bad option... |
| */ |
| |
| usage(argv[i]); |
| } |
| else |
| { |
| /* |
| * Process XML or source file... |
| */ |
| |
| len = (int)strlen(argv[i]); |
| if (len > 4 && !strcmp(argv[i] + len - 4, ".xml")) |
| { |
| /* |
| * Set XML file... |
| */ |
| |
| if (xmlfile) |
| usage(NULL); |
| |
| xmlfile = argv[i]; |
| |
| if (!doc) |
| { |
| if ((fp = fopen(argv[i], "r")) != NULL) |
| { |
| /* |
| * Read the existing XML file... |
| */ |
| |
| doc = mxmlLoadFile(NULL, fp, load_cb); |
| |
| fclose(fp); |
| |
| if (!doc) |
| { |
| mxmldoc = NULL; |
| |
| fprintf(stderr, |
| "mxmldoc: Unable to read the XML documentation file " |
| "\"%s\"!\n", argv[i]); |
| } |
| else if ((mxmldoc = mxmlFindElement(doc, doc, "mxmldoc", NULL, |
| NULL, MXML_DESCEND)) == NULL) |
| { |
| fprintf(stderr, |
| "mxmldoc: XML documentation file \"%s\" is missing " |
| "<mxmldoc> node!!\n", argv[i]); |
| |
| mxmlDelete(doc); |
| doc = NULL; |
| } |
| } |
| else |
| { |
| doc = NULL; |
| mxmldoc = NULL; |
| } |
| |
| if (!doc) |
| doc = new_documentation(&mxmldoc); |
| } |
| } |
| else |
| { |
| /* |
| * Load source file... |
| */ |
| |
| update = 1; |
| |
| if (!doc) |
| doc = new_documentation(&mxmldoc); |
| |
| if ((fp = fopen(argv[i], "r")) == NULL) |
| { |
| fprintf(stderr, "mxmldoc: Unable to open source file \"%s\": %s\n", |
| argv[i], strerror(errno)); |
| mxmlDelete(doc); |
| return (1); |
| } |
| else if (scan_file(argv[i], fp, mxmldoc)) |
| { |
| fclose(fp); |
| mxmlDelete(doc); |
| return (1); |
| } |
| else |
| fclose(fp); |
| } |
| } |
| |
| if (update && xmlfile) |
| { |
| /* |
| * Save the updated XML documentation file... |
| */ |
| |
| if ((fp = fopen(xmlfile, "w")) != NULL) |
| { |
| /* |
| * Write over the existing XML file... |
| */ |
| |
| mxmlSetWrapMargin(0); |
| |
| if (mxmlSaveFile(doc, fp, ws_cb)) |
| { |
| fprintf(stderr, |
| "mxmldoc: Unable to write the XML documentation file \"%s\": " |
| "%s!\n", xmlfile, strerror(errno)); |
| fclose(fp); |
| mxmlDelete(doc); |
| return (1); |
| } |
| |
| fclose(fp); |
| } |
| else |
| { |
| fprintf(stderr, |
| "mxmldoc: Unable to create the XML documentation file \"%s\": " |
| "%s!\n", xmlfile, strerror(errno)); |
| mxmlDelete(doc); |
| return (1); |
| } |
| } |
| |
| switch (mode) |
| { |
| case OUTPUT_HTML : |
| /* |
| * Write HTML documentation... |
| */ |
| |
| write_html(section, title ? title : "Documentation", footerfile, |
| headerfile, introfile, cssfile, framefile, docset, |
| docversion, feedname, feedurl, mxmldoc); |
| break; |
| |
| case OUTPUT_MAN : |
| /* |
| * Write manpage documentation... |
| */ |
| |
| write_man(name, section, title, footerfile, headerfile, introfile, |
| mxmldoc); |
| break; |
| |
| case OUTPUT_TOKENS : |
| fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" |
| "<Tokens version=\"1.0\">\n", stdout); |
| |
| write_tokens(stdout, mxmldoc, path); |
| |
| fputs("</Tokens>\n", stdout); |
| break; |
| } |
| |
| /* |
| * Delete the tree and return... |
| */ |
| |
| mxmlDelete(doc); |
| |
| return (0); |
| } |
| |
| |
| /* |
| * 'add_variable()' - Add a variable or argument. |
| */ |
| |
| static mxml_node_t * /* O - New variable/argument */ |
| add_variable(mxml_node_t *parent, /* I - Parent node */ |
| const char *name, /* I - "argument" or "variable" */ |
| mxml_node_t *type) /* I - Type nodes */ |
| { |
| mxml_node_t *variable, /* New variable */ |
| *node, /* Current node */ |
| *next; /* Next node */ |
| char buffer[16384], /* String buffer */ |
| *bufptr; /* Pointer into buffer */ |
| |
| |
| #ifdef DEBUG |
| fprintf(stderr, "add_variable(parent=%p, name=\"%s\", type=%p)\n", |
| parent, name, type); |
| #endif /* DEBUG */ |
| |
| /* |
| * Range check input... |
| */ |
| |
| if (!type || !type->child) |
| return (NULL); |
| |
| /* |
| * Create the variable/argument node... |
| */ |
| |
| variable = mxmlNewElement(parent, name); |
| |
| /* |
| * Check for a default value... |
| */ |
| |
| for (node = type->child; node; node = node->next) |
| if (!strcmp(node->value.text.string, "=")) |
| break; |
| |
| if (node) |
| { |
| /* |
| * Default value found, copy it and add as a "default" attribute... |
| */ |
| |
| for (bufptr = buffer; node; bufptr += strlen(bufptr)) |
| { |
| if (node->value.text.whitespace && bufptr > buffer) |
| *bufptr++ = ' '; |
| |
| strcpy(bufptr, node->value.text.string); |
| |
| next = node->next; |
| mxmlDelete(node); |
| node = next; |
| } |
| |
| mxmlElementSetAttr(variable, "default", buffer); |
| } |
| |
| /* |
| * Extract the argument/variable name... |
| */ |
| |
| if (type->last_child->value.text.string[0] == ')') |
| { |
| /* |
| * Handle "type (*name)(args)"... |
| */ |
| |
| for (node = type->child; node; node = node->next) |
| if (node->value.text.string[0] == '(') |
| break; |
| |
| for (bufptr = buffer; node; bufptr += strlen(bufptr)) |
| { |
| if (node->value.text.whitespace && bufptr > buffer) |
| *bufptr++ = ' '; |
| |
| strcpy(bufptr, node->value.text.string); |
| |
| next = node->next; |
| mxmlDelete(node); |
| node = next; |
| } |
| } |
| else |
| { |
| /* |
| * Handle "type name"... |
| */ |
| |
| strcpy(buffer, type->last_child->value.text.string); |
| mxmlDelete(type->last_child); |
| } |
| |
| /* |
| * Set the name... |
| */ |
| |
| mxmlElementSetAttr(variable, "name", buffer); |
| |
| /* |
| * Add the remaining type information to the variable node... |
| */ |
| |
| mxmlAdd(variable, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, type); |
| |
| /* |
| * Add new new variable node... |
| */ |
| |
| return (variable); |
| } |
| |
| |
| /* |
| * 'find_public()' - Find a public function, type, etc. |
| */ |
| |
| static mxml_node_t * /* I - Found node or NULL */ |
| find_public(mxml_node_t *node, /* I - Current node */ |
| mxml_node_t *top, /* I - Top node */ |
| const char *name) /* I - Name of element */ |
| { |
| mxml_node_t *description, /* Description node */ |
| *comment; /* Comment node */ |
| |
| |
| for (node = mxmlFindElement(node, top, name, NULL, NULL, |
| node == top ? MXML_DESCEND_FIRST : |
| MXML_NO_DESCEND); |
| node; |
| node = mxmlFindElement(node, top, name, NULL, NULL, MXML_NO_DESCEND)) |
| { |
| /* |
| * Get the description for this node... |
| */ |
| |
| description = mxmlFindElement(node, node, "description", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| |
| /* |
| * A missing or empty description signals a private node... |
| */ |
| |
| if (!description) |
| continue; |
| |
| /* |
| * Look for @private@ in the comment text... |
| */ |
| |
| for (comment = description->child; comment; comment = comment->next) |
| if ((comment->type == MXML_TEXT && |
| strstr(comment->value.text.string, "@private@")) || |
| (comment->type == MXML_OPAQUE && |
| strstr(comment->value.opaque, "@private@"))) |
| break; |
| |
| if (!comment) |
| { |
| /* |
| * No @private@, so return this node... |
| */ |
| |
| return (node); |
| } |
| } |
| |
| /* |
| * If we get here, there are no (more) public nodes... |
| */ |
| |
| return (NULL); |
| } |
| |
| |
| /* |
| * 'get_comment_info()' - Get info from comment. |
| */ |
| |
| static char * /* O - Info from comment */ |
| get_comment_info( |
| mxml_node_t *description) /* I - Description node */ |
| { |
| char text[10240], /* Description text */ |
| since[255], /* @since value */ |
| *ptr; /* Pointer into text */ |
| static char info[1024]; /* Info string */ |
| |
| |
| if (!description) |
| return (""); |
| |
| get_text(description, text, sizeof(text)); |
| |
| for (ptr = strchr(text, '@'); ptr; ptr = strchr(ptr + 1, '@')) |
| { |
| if (!strncmp(ptr, "@deprecated@", 12)) |
| return ("<span class=\"info\"> DEPRECATED </span>"); |
| else if (!strncmp(ptr, "@since ", 7)) |
| { |
| strncpy(since, ptr + 7, sizeof(since) - 1); |
| since[sizeof(since) - 1] = '\0'; |
| |
| if ((ptr = strchr(since, '@')) != NULL) |
| *ptr = '\0'; |
| |
| snprintf(info, sizeof(info), "<span class=\"info\"> %s </span>", since); |
| return (info); |
| } |
| } |
| |
| return (""); |
| } |
| |
| |
| /* |
| * 'get_text()' - Get the text for a node. |
| */ |
| |
| static char * /* O - Text in node */ |
| get_text(mxml_node_t *node, /* I - Node to get */ |
| char *buffer, /* I - Buffer */ |
| int buflen) /* I - Size of buffer */ |
| { |
| char *ptr, /* Pointer into buffer */ |
| *end; /* End of buffer */ |
| int len; /* Length of node */ |
| mxml_node_t *current; /* Current node */ |
| |
| |
| ptr = buffer; |
| end = buffer + buflen - 1; |
| |
| for (current = node->child; current && ptr < end; current = current->next) |
| { |
| if (current->type == MXML_TEXT) |
| { |
| if (current->value.text.whitespace) |
| *ptr++ = ' '; |
| |
| len = (int)strlen(current->value.text.string); |
| if (len > (int)(end - ptr)) |
| len = (int)(end - ptr); |
| |
| memcpy(ptr, current->value.text.string, len); |
| ptr += len; |
| } |
| else if (current->type == MXML_OPAQUE) |
| { |
| len = (int)strlen(current->value.opaque); |
| if (len > (int)(end - ptr)) |
| len = (int)(end - ptr); |
| |
| memcpy(ptr, current->value.opaque, len); |
| ptr += len; |
| } |
| } |
| |
| *ptr = '\0'; |
| |
| return (buffer); |
| } |
| |
| |
| /* |
| * 'load_cb()' - Set the type of child nodes. |
| */ |
| |
| static mxml_type_t /* O - Node type */ |
| load_cb(mxml_node_t *node) /* I - Node */ |
| { |
| if (!strcmp(node->value.element.name, "description")) |
| return (MXML_OPAQUE); |
| else |
| return (MXML_TEXT); |
| } |
| |
| |
| /* |
| * 'new_documentation()' - Create a new documentation tree. |
| */ |
| |
| static mxml_node_t * /* O - New documentation */ |
| new_documentation(mxml_node_t **mxmldoc)/* O - mxmldoc node */ |
| { |
| mxml_node_t *doc; /* New documentation */ |
| |
| |
| /* |
| * Create an empty XML documentation file... |
| */ |
| |
| doc = mxmlNewXML(NULL); |
| |
| *mxmldoc = mxmlNewElement(doc, "mxmldoc"); |
| |
| mxmlElementSetAttr(*mxmldoc, "xmlns", "http://www.easysw.com"); |
| mxmlElementSetAttr(*mxmldoc, "xmlns:xsi", |
| "http://www.w3.org/2001/XMLSchema-instance"); |
| mxmlElementSetAttr(*mxmldoc, "xsi:schemaLocation", |
| "http://www.minixml.org/mxmldoc.xsd"); |
| |
| return (doc); |
| } |
| |
| |
| /* |
| * 'remove_directory()' - Remove a directory. |
| */ |
| |
| static int /* O - 1 on success, 0 on failure */ |
| remove_directory(const char *path) /* I - Directory to remove */ |
| { |
| #ifdef WIN32 |
| /* TODO: Add Windows directory removal code */ |
| |
| #else |
| DIR *dir; /* Directory */ |
| struct dirent *dent; /* Current directory entry */ |
| char filename[1024]; /* Current filename */ |
| struct stat fileinfo; /* File information */ |
| |
| |
| if ((dir = opendir(path)) == NULL) |
| { |
| fprintf(stderr, "mxmldoc: Unable to open directory \"%s\": %s\n", path, |
| strerror(errno)); |
| return (0); |
| } |
| |
| while ((dent = readdir(dir)) != NULL) |
| { |
| /* |
| * Skip "." and ".."... |
| */ |
| |
| if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) |
| continue; |
| |
| /* |
| * See if we have a file or directory... |
| */ |
| |
| snprintf(filename, sizeof(filename), "%s/%s", path, dent->d_name); |
| |
| if (stat(filename, &fileinfo)) |
| { |
| fprintf(stderr, "mxmldoc: Unable to stat \"%s\": %s\n", filename, |
| strerror(errno)); |
| closedir(dir); |
| return (0); |
| } |
| |
| if (S_ISDIR(fileinfo.st_mode)) |
| { |
| if (!remove_directory(filename)) |
| { |
| closedir(dir); |
| return (0); |
| } |
| } |
| else if (unlink(filename)) |
| { |
| fprintf(stderr, "mxmldoc: Unable to remove \"%s\": %s\n", filename, |
| strerror(errno)); |
| closedir(dir); |
| return (0); |
| } |
| } |
| |
| closedir(dir); |
| |
| if (rmdir(path)) |
| { |
| fprintf(stderr, "mxmldoc: Unable to remove directory \"%s\": %s\n", path, |
| strerror(errno)); |
| return (0); |
| } |
| #endif /* WIN32 */ |
| |
| return (1); |
| } |
| |
| |
| /* |
| * 'safe_strcpy()' - Copy a string allowing for overlapping strings. |
| */ |
| |
| static void |
| safe_strcpy(char *dst, /* I - Destination string */ |
| const char *src) /* I - Source string */ |
| { |
| while (*src) |
| *dst++ = *src++; |
| |
| *dst = '\0'; |
| } |
| |
| |
| /* |
| * 'scan_file()' - Scan a source file. |
| */ |
| |
| static int /* O - 0 on success, -1 on error */ |
| scan_file(const char *filename, /* I - Filename */ |
| FILE *fp, /* I - File to scan */ |
| mxml_node_t *tree) /* I - Function tree */ |
| { |
| int state, /* Current parser state */ |
| braces, /* Number of braces active */ |
| parens; /* Number of active parenthesis */ |
| int ch; /* Current character */ |
| char buffer[65536], /* String buffer */ |
| *bufptr; /* Pointer into buffer */ |
| const char *scope; /* Current variable/function scope */ |
| mxml_node_t *comment, /* <comment> node */ |
| *constant, /* <constant> node */ |
| *enumeration, /* <enumeration> node */ |
| *function, /* <function> node */ |
| *fstructclass, /* function struct/class node */ |
| *structclass, /* <struct> or <class> node */ |
| *typedefnode, /* <typedef> node */ |
| *variable, /* <variable> or <argument> node */ |
| *returnvalue, /* <returnvalue> node */ |
| *type, /* <type> node */ |
| *description, /* <description> node */ |
| *node, /* Current node */ |
| *next; /* Next node */ |
| #if DEBUG > 1 |
| mxml_node_t *temp; /* Temporary node */ |
| int oldstate, /* Previous state */ |
| oldch; /* Old character */ |
| static const char *states[] = /* State strings */ |
| { |
| "STATE_NONE", |
| "STATE_PREPROCESSOR", |
| "STATE_C_COMMENT", |
| "STATE_CXX_COMMENT", |
| "STATE_STRING", |
| "STATE_CHARACTER", |
| "STATE_IDENTIFIER" |
| }; |
| #endif /* DEBUG > 1 */ |
| |
| |
| #ifdef DEBUG |
| fprintf(stderr, "scan_file(filename=\"%s\", fp=%p, tree=%p)\n", filename, |
| fp, tree); |
| #endif /* DEBUG */ |
| |
| /* |
| * Initialize the finite state machine... |
| */ |
| |
| state = STATE_NONE; |
| braces = 0; |
| parens = 0; |
| bufptr = buffer; |
| |
| comment = mxmlNewElement(MXML_NO_PARENT, "temp"); |
| constant = NULL; |
| enumeration = NULL; |
| function = NULL; |
| variable = NULL; |
| returnvalue = NULL; |
| type = NULL; |
| description = NULL; |
| typedefnode = NULL; |
| structclass = NULL; |
| fstructclass = NULL; |
| |
| if (!strcmp(tree->value.element.name, "class")) |
| scope = "private"; |
| else |
| scope = NULL; |
| |
| /* |
| * Read until end-of-file... |
| */ |
| |
| while ((ch = getc(fp)) != EOF) |
| { |
| #if DEBUG > 1 |
| oldstate = state; |
| oldch = ch; |
| #endif /* DEBUG > 1 */ |
| |
| switch (state) |
| { |
| case STATE_NONE : /* No state - whitespace, etc. */ |
| switch (ch) |
| { |
| case '/' : /* Possible C/C++ comment */ |
| ch = getc(fp); |
| bufptr = buffer; |
| |
| if (ch == '*') |
| state = STATE_C_COMMENT; |
| else if (ch == '/') |
| state = STATE_CXX_COMMENT; |
| else |
| { |
| ungetc(ch, fp); |
| |
| if (type) |
| { |
| #ifdef DEBUG |
| fputs("Identifier: <<<< / >>>\n", stderr); |
| #endif /* DEBUG */ |
| ch = type->last_child->value.text.string[0]; |
| mxmlNewText(type, isalnum(ch) || ch == '_', "/"); |
| } |
| } |
| break; |
| |
| case '#' : /* Preprocessor */ |
| #ifdef DEBUG |
| fputs(" #preprocessor...\n", stderr); |
| #endif /* DEBUG */ |
| state = STATE_PREPROCESSOR; |
| break; |
| |
| case '\'' : /* Character constant */ |
| state = STATE_CHARACTER; |
| bufptr = buffer; |
| *bufptr++ = ch; |
| break; |
| |
| case '\"' : /* String constant */ |
| state = STATE_STRING; |
| bufptr = buffer; |
| *bufptr++ = ch; |
| break; |
| |
| case '{' : |
| #ifdef DEBUG |
| fprintf(stderr, " open brace, function=%p, type=%p...\n", |
| function, type); |
| if (type) |
| fprintf(stderr, " type->child=\"%s\"...\n", |
| type->child->value.text.string); |
| #endif /* DEBUG */ |
| |
| if (function) |
| { |
| if (fstructclass) |
| { |
| sort_node(fstructclass, function); |
| fstructclass = NULL; |
| } |
| else |
| sort_node(tree, function); |
| |
| function = NULL; |
| } |
| else if (type && type->child && |
| ((!strcmp(type->child->value.text.string, "typedef") && |
| type->child->next && |
| (!strcmp(type->child->next->value.text.string, "struct") || |
| !strcmp(type->child->next->value.text.string, "union") || |
| !strcmp(type->child->next->value.text.string, "class"))) || |
| !strcmp(type->child->value.text.string, "union") || |
| !strcmp(type->child->value.text.string, "struct") || |
| !strcmp(type->child->value.text.string, "class"))) |
| { |
| /* |
| * Start of a class or structure... |
| */ |
| |
| if (!strcmp(type->child->value.text.string, "typedef")) |
| { |
| #ifdef DEBUG |
| fputs(" starting typedef...\n", stderr); |
| #endif /* DEBUG */ |
| |
| typedefnode = mxmlNewElement(MXML_NO_PARENT, "typedef"); |
| mxmlDelete(type->child); |
| } |
| else |
| typedefnode = NULL; |
| |
| structclass = mxmlNewElement(MXML_NO_PARENT, |
| type->child->value.text.string); |
| |
| #ifdef DEBUG |
| fprintf(stderr, "%c%s: <<<< %s >>>\n", |
| toupper(type->child->value.text.string[0]), |
| type->child->value.text.string + 1, |
| type->child->next ? |
| type->child->next->value.text.string : "(noname)"); |
| |
| fputs(" type =", stderr); |
| for (node = type->child; node; node = node->next) |
| fprintf(stderr, " \"%s\"", node->value.text.string); |
| putc('\n', stderr); |
| |
| fprintf(stderr, " scope = %s\n", scope ? scope : "(null)"); |
| #endif /* DEBUG */ |
| |
| if (type->child->next) |
| { |
| mxmlElementSetAttr(structclass, "name", |
| type->child->next->value.text.string); |
| sort_node(tree, structclass); |
| } |
| |
| if (typedefnode && type->child) |
| type->child->value.text.whitespace = 0; |
| else if (structclass && type->child && |
| type->child->next && type->child->next->next) |
| { |
| for (bufptr = buffer, node = type->child->next->next; |
| node; |
| bufptr += strlen(bufptr)) |
| { |
| if (node->value.text.whitespace && bufptr > buffer) |
| *bufptr++ = ' '; |
| |
| strcpy(bufptr, node->value.text.string); |
| |
| next = node->next; |
| mxmlDelete(node); |
| node = next; |
| } |
| |
| mxmlElementSetAttr(structclass, "parent", buffer); |
| |
| mxmlDelete(type); |
| type = NULL; |
| } |
| else |
| { |
| mxmlDelete(type); |
| type = NULL; |
| } |
| |
| if (typedefnode && comment->last_child) |
| { |
| /* |
| * Copy comment for typedef as well as class/struct/union... |
| */ |
| |
| mxmlNewText(comment, 0, |
| comment->last_child->value.text.string); |
| description = mxmlNewElement(typedefnode, "description"); |
| #ifdef DEBUG |
| fprintf(stderr, |
| " duplicating comment %p/%p for typedef...\n", |
| comment->last_child, comment->child); |
| #endif /* DEBUG */ |
| update_comment(typedefnode, comment->last_child); |
| mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, |
| comment->last_child); |
| } |
| |
| description = mxmlNewElement(structclass, "description"); |
| #ifdef DEBUG |
| fprintf(stderr, " adding comment %p/%p to %s...\n", |
| comment->last_child, comment->child, |
| structclass->value.element.name); |
| #endif /* DEBUG */ |
| update_comment(structclass, comment->last_child); |
| mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, |
| comment->last_child); |
| |
| if (scan_file(filename, fp, structclass)) |
| { |
| mxmlDelete(comment); |
| return (-1); |
| } |
| |
| #ifdef DEBUG |
| fputs(" ended typedef...\n", stderr); |
| #endif /* DEBUG */ |
| structclass = NULL; |
| break; |
| } |
| else if (type && type->child && type->child->next && |
| (!strcmp(type->child->value.text.string, "enum") || |
| (!strcmp(type->child->value.text.string, "typedef") && |
| !strcmp(type->child->next->value.text.string, "enum")))) |
| { |
| /* |
| * Enumeration type... |
| */ |
| |
| if (!strcmp(type->child->value.text.string, "typedef")) |
| { |
| #ifdef DEBUG |
| fputs(" starting typedef...\n", stderr); |
| #endif /* DEBUG */ |
| |
| typedefnode = mxmlNewElement(MXML_NO_PARENT, "typedef"); |
| mxmlDelete(type->child); |
| } |
| else |
| typedefnode = NULL; |
| |
| enumeration = mxmlNewElement(MXML_NO_PARENT, "enumeration"); |
| |
| #ifdef DEBUG |
| fprintf(stderr, "Enumeration: <<<< %s >>>\n", |
| type->child->next ? |
| type->child->next->value.text.string : "(noname)"); |
| #endif /* DEBUG */ |
| |
| if (type->child->next) |
| { |
| mxmlElementSetAttr(enumeration, "name", |
| type->child->next->value.text.string); |
| sort_node(tree, enumeration); |
| } |
| |
| if (typedefnode && type->child) |
| type->child->value.text.whitespace = 0; |
| else |
| { |
| mxmlDelete(type); |
| type = NULL; |
| } |
| |
| if (typedefnode && comment->last_child) |
| { |
| /* |
| * Copy comment for typedef as well as class/struct/union... |
| */ |
| |
| mxmlNewText(comment, 0, |
| comment->last_child->value.text.string); |
| description = mxmlNewElement(typedefnode, "description"); |
| #ifdef DEBUG |
| fprintf(stderr, |
| " duplicating comment %p/%p for typedef...\n", |
| comment->last_child, comment->child); |
| #endif /* DEBUG */ |
| update_comment(typedefnode, comment->last_child); |
| mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, |
| comment->last_child); |
| } |
| |
| description = mxmlNewElement(enumeration, "description"); |
| #ifdef DEBUG |
| fprintf(stderr, " adding comment %p/%p to enumeration...\n", |
| comment->last_child, comment->child); |
| #endif /* DEBUG */ |
| update_comment(enumeration, comment->last_child); |
| mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, |
| comment->last_child); |
| } |
| else if (type && type->child && |
| !strcmp(type->child->value.text.string, "extern")) |
| { |
| if (scan_file(filename, fp, tree)) |
| { |
| mxmlDelete(comment); |
| return (-1); |
| } |
| } |
| else if (type) |
| { |
| mxmlDelete(type); |
| type = NULL; |
| } |
| |
| braces ++; |
| function = NULL; |
| variable = NULL; |
| break; |
| |
| case '}' : |
| #ifdef DEBUG |
| fputs(" close brace...\n", stderr); |
| #endif /* DEBUG */ |
| |
| if (structclass) |
| scope = NULL; |
| |
| if (!typedefnode) |
| enumeration = NULL; |
| |
| constant = NULL; |
| structclass = NULL; |
| |
| if (braces > 0) |
| braces --; |
| else |
| { |
| mxmlDelete(comment); |
| return (0); |
| } |
| break; |
| |
| case '(' : |
| if (type) |
| { |
| #ifdef DEBUG |
| fputs("Identifier: <<<< ( >>>\n", stderr); |
| #endif /* DEBUG */ |
| mxmlNewText(type, 0, "("); |
| } |
| |
| parens ++; |
| break; |
| |
| case ')' : |
| if (type && parens) |
| { |
| #ifdef DEBUG |
| fputs("Identifier: <<<< ) >>>\n", stderr); |
| #endif /* DEBUG */ |
| mxmlNewText(type, 0, ")"); |
| } |
| |
| if (function && type && !parens) |
| { |
| /* |
| * Check for "void" argument... |
| */ |
| |
| if (type->child && type->child->next) |
| variable = add_variable(function, "argument", type); |
| else |
| mxmlDelete(type); |
| |
| type = NULL; |
| } |
| |
| if (parens > 0) |
| parens --; |
| break; |
| |
| case ';' : |
| #ifdef DEBUG |
| fputs("Identifier: <<<< ; >>>\n", stderr); |
| fprintf(stderr, " enumeration=%p, function=%p, type=%p, type->child=%p, typedefnode=%p\n", |
| enumeration, function, type, type ? type->child : NULL, typedefnode); |
| #endif /* DEBUG */ |
| |
| if (function) |
| { |
| if (!strcmp(tree->value.element.name, "class")) |
| { |
| #ifdef DEBUG |
| fputs(" ADDING FUNCTION TO CLASS\n", stderr); |
| #endif /* DEBUG */ |
| sort_node(tree, function); |
| } |
| else |
| mxmlDelete(function); |
| |
| function = NULL; |
| variable = NULL; |
| } |
| |
| if (type) |
| { |
| /* |
| * See if we have a typedef... |
| */ |
| |
| if (type->child && |
| !strcmp(type->child->value.text.string, "typedef")) |
| { |
| /* |
| * Yes, add it! |
| */ |
| |
| typedefnode = mxmlNewElement(MXML_NO_PARENT, "typedef"); |
| |
| for (node = type->child->next; node; node = node->next) |
| if (!strcmp(node->value.text.string, "(")) |
| break; |
| |
| if (node) |
| { |
| for (node = node->next; node; node = node->next) |
| if (strcmp(node->value.text.string, "*")) |
| break; |
| } |
| |
| if (!node) |
| node = type->last_child; |
| |
| #ifdef DEBUG |
| fprintf(stderr, " ADDING TYPEDEF FOR %p(%s)...\n", |
| node, node->value.text.string); |
| #endif /* DEBUG */ |
| |
| mxmlElementSetAttr(typedefnode, "name", |
| node->value.text.string); |
| sort_node(tree, typedefnode); |
| |
| if (type->child != node) |
| mxmlDelete(type->child); |
| |
| mxmlDelete(node); |
| |
| if (type->child) |
| type->child->value.text.whitespace = 0; |
| |
| mxmlAdd(typedefnode, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, |
| type); |
| type = NULL; |
| break; |
| } |
| else if (typedefnode && enumeration) |
| { |
| /* |
| * Add enum typedef... |
| */ |
| |
| node = type->child; |
| |
| #ifdef DEBUG |
| fprintf(stderr, " ADDING TYPEDEF FOR %p(%s)...\n", |
| node, node->value.text.string); |
| #endif /* DEBUG */ |
| |
| mxmlElementSetAttr(typedefnode, "name", |
| node->value.text.string); |
| sort_node(tree, typedefnode); |
| mxmlDelete(type); |
| |
| type = mxmlNewElement(typedefnode, "type"); |
| mxmlNewText(type, 0, "enum"); |
| mxmlNewText(type, 1, |
| mxmlElementGetAttr(enumeration, "name")); |
| enumeration = NULL; |
| type = NULL; |
| break; |
| } |
| |
| mxmlDelete(type); |
| type = NULL; |
| } |
| break; |
| |
| case ':' : |
| if (type) |
| { |
| #ifdef DEBUG |
| fputs("Identifier: <<<< : >>>\n", stderr); |
| #endif /* DEBUG */ |
| mxmlNewText(type, 1, ":"); |
| } |
| break; |
| |
| case '*' : |
| if (type) |
| { |
| #ifdef DEBUG |
| fputs("Identifier: <<<< * >>>\n", stderr); |
| #endif /* DEBUG */ |
| ch = type->last_child->value.text.string[0]; |
| mxmlNewText(type, isalnum(ch) || ch == '_', "*"); |
| } |
| break; |
| |
| case ',' : |
| if (type && !enumeration) |
| { |
| #ifdef DEBUG |
| fputs("Identifier: <<<< , >>>\n", stderr); |
| #endif /* DEBUG */ |
| mxmlNewText(type, 0, ","); |
| } |
| break; |
| |
| case '&' : |
| if (type) |
| { |
| #ifdef DEBUG |
| fputs("Identifier: <<<< & >>>\n", stderr); |
| #endif /* DEBUG */ |
| mxmlNewText(type, 1, "&"); |
| } |
| break; |
| |
| case '+' : |
| if (type) |
| { |
| #ifdef DEBUG |
| fputs("Identifier: <<<< + >>>\n", stderr); |
| #endif /* DEBUG */ |
| ch = type->last_child->value.text.string[0]; |
| mxmlNewText(type, isalnum(ch) || ch == '_', "+"); |
| } |
| break; |
| |
| case '-' : |
| if (type) |
| { |
| #ifdef DEBUG |
| fputs("Identifier: <<<< - >>>\n", stderr); |
| #endif /* DEBUG */ |
| ch = type->last_child->value.text.string[0]; |
| mxmlNewText(type, isalnum(ch) || ch == '_', "-"); |
| } |
| break; |
| |
| case '=' : |
| if (type) |
| { |
| #ifdef DEBUG |
| fputs("Identifier: <<<< = >>>\n", stderr); |
| #endif /* DEBUG */ |
| ch = type->last_child->value.text.string[0]; |
| mxmlNewText(type, isalnum(ch) || ch == '_', "="); |
| } |
| break; |
| |
| default : /* Other */ |
| if (isalnum(ch) || ch == '_' || ch == '.' || ch == ':' || ch == '~') |
| { |
| state = STATE_IDENTIFIER; |
| bufptr = buffer; |
| *bufptr++ = ch; |
| } |
| break; |
| } |
| break; |
| |
| case STATE_PREPROCESSOR : /* Preprocessor directive */ |
| if (ch == '\n') |
| state = STATE_NONE; |
| else if (ch == '\\') |
| getc(fp); |
| break; |
| |
| case STATE_C_COMMENT : /* Inside a C comment */ |
| switch (ch) |
| { |
| case '\n' : |
| while ((ch = getc(fp)) != EOF) |
| if (ch == '*') |
| { |
| ch = getc(fp); |
| |
| if (ch == '/') |
| { |
| *bufptr = '\0'; |
| |
| if (comment->child != comment->last_child) |
| { |
| #ifdef DEBUG |
| fprintf(stderr, " removing comment %p(%20.20s), last comment %p(%20.20s)...\n", |
| comment->child, |
| comment->child ? comment->child->value.text.string : "", |
| comment->last_child, |
| comment->last_child ? comment->last_child->value.text.string : ""); |
| #endif /* DEBUG */ |
| mxmlDelete(comment->child); |
| #ifdef DEBUG |
| fprintf(stderr, " new comment %p, last comment %p...\n", |
| comment->child, comment->last_child); |
| #endif /* DEBUG */ |
| } |
| |
| #ifdef DEBUG |
| fprintf(stderr, |
| " processing comment, variable=%p, " |
| "constant=%p, typedefnode=%p, tree=\"%s\"\n", |
| variable, constant, typedefnode, |
| tree->value.element.name); |
| #endif /* DEBUG */ |
| |
| if (variable) |
| { |
| if (strstr(buffer, "@private@")) |
| { |
| /* |
| * Delete private variables... |
| */ |
| |
| mxmlDelete(variable); |
| } |
| else |
| { |
| description = mxmlNewElement(variable, "description"); |
| #ifdef DEBUG |
| fprintf(stderr, |
| " adding comment %p/%p to variable...\n", |
| comment->last_child, comment->child); |
| #endif /* DEBUG */ |
| mxmlNewText(comment, 0, buffer); |
| update_comment(variable, |
| mxmlNewText(description, 0, buffer)); |
| } |
| |
| variable = NULL; |
| } |
| else if (constant) |
| { |
| if (strstr(buffer, "@private@")) |
| { |
| /* |
| * Delete private constants... |
| */ |
| |
| mxmlDelete(constant); |
| } |
| else |
| { |
| description = mxmlNewElement(constant, "description"); |
| #ifdef DEBUG |
| fprintf(stderr, |
| " adding comment %p/%p to constant...\n", |
| comment->last_child, comment->child); |
| #endif /* DEBUG */ |
| mxmlNewText(comment, 0, buffer); |
| update_comment(constant, |
| mxmlNewText(description, 0, buffer)); |
| } |
| |
| constant = NULL; |
| } |
| else if (typedefnode) |
| { |
| if (strstr(buffer, "@private@")) |
| { |
| /* |
| * Delete private typedefs... |
| */ |
| |
| mxmlDelete(typedefnode); |
| |
| if (structclass) |
| { |
| mxmlDelete(structclass); |
| structclass = NULL; |
| } |
| |
| if (enumeration) |
| { |
| mxmlDelete(enumeration); |
| enumeration = NULL; |
| } |
| } |
| else |
| { |
| description = mxmlNewElement(typedefnode, "description"); |
| #ifdef DEBUG |
| fprintf(stderr, |
| " adding comment %p/%p to typedef %s...\n", |
| comment->last_child, comment->child, |
| mxmlElementGetAttr(typedefnode, "name")); |
| #endif /* DEBUG */ |
| mxmlNewText(comment, 0, buffer); |
| update_comment(typedefnode, |
| mxmlNewText(description, 0, buffer)); |
| |
| if (structclass) |
| { |
| description = mxmlNewElement(structclass, "description"); |
| update_comment(structclass, |
| mxmlNewText(description, 0, buffer)); |
| } |
| else if (enumeration) |
| { |
| description = mxmlNewElement(enumeration, "description"); |
| update_comment(enumeration, |
| mxmlNewText(description, 0, buffer)); |
| } |
| } |
| |
| typedefnode = NULL; |
| } |
| else if (strcmp(tree->value.element.name, "mxmldoc") && |
| !mxmlFindElement(tree, tree, "description", |
| NULL, NULL, MXML_DESCEND_FIRST)) |
| { |
| description = mxmlNewElement(tree, "description"); |
| #ifdef DEBUG |
| fprintf(stderr, " adding comment %p/%p to parent...\n", |
| comment->last_child, comment->child); |
| #endif /* DEBUG */ |
| mxmlNewText(comment, 0, buffer); |
| update_comment(tree, |
| mxmlNewText(description, 0, buffer)); |
| } |
| else |
| { |
| #ifdef DEBUG |
| fprintf(stderr, " before adding comment, child=%p, last_child=%p\n", |
| comment->child, comment->last_child); |
| #endif /* DEBUG */ |
| mxmlNewText(comment, 0, buffer); |
| #ifdef DEBUG |
| fprintf(stderr, " after adding comment, child=%p, last_child=%p\n", |
| comment->child, comment->last_child); |
| #endif /* DEBUG */ |
| } |
| #ifdef DEBUG |
| fprintf(stderr, "C comment: <<<< %s >>>\n", buffer); |
| #endif /* DEBUG */ |
| |
| state = STATE_NONE; |
| break; |
| } |
| else |
| ungetc(ch, fp); |
| } |
| else if (ch == '\n' && bufptr > buffer && |
| bufptr < (buffer + sizeof(buffer) - 1)) |
| *bufptr++ = ch; |
| else if (!isspace(ch)) |
| break; |
| |
| if (ch != EOF) |
| ungetc(ch, fp); |
| |
| if (bufptr > buffer && bufptr < (buffer + sizeof(buffer) - 1)) |
| *bufptr++ = '\n'; |
| break; |
| |
| case '/' : |
| if (ch == '/' && bufptr > buffer && bufptr[-1] == '*') |
| { |
| while (bufptr > buffer && |
| (bufptr[-1] == '*' || isspace(bufptr[-1] & 255))) |
| bufptr --; |
| *bufptr = '\0'; |
| |
| if (comment->child != comment->last_child) |
| { |
| #ifdef DEBUG |
| fprintf(stderr, " removing comment %p(%20.20s), last comment %p(%20.20s)...\n", |
| comment->child, |
| comment->child ? comment->child->value.text.string : "", |
| comment->last_child, |
| comment->last_child ? comment->last_child->value.text.string : ""); |
| #endif /* DEBUG */ |
| mxmlDelete(comment->child); |
| #ifdef DEBUG |
| fprintf(stderr, " new comment %p, last comment %p...\n", |
| comment->child, comment->last_child); |
| #endif /* DEBUG */ |
| } |
| |
| #ifdef DEBUG |
| fprintf(stderr, |
| " processing comment, variable=%p, " |
| "constant=%p, typedefnode=%p, tree=\"%s\"\n", |
| variable, constant, typedefnode, |
| tree->value.element.name); |
| #endif /* DEBUG */ |
| |
| if (variable) |
| { |
| if (strstr(buffer, "@private@")) |
| { |
| /* |
| * Delete private variables... |
| */ |
| |
| mxmlDelete(variable); |
| } |
| else |
| { |
| description = mxmlNewElement(variable, "description"); |
| #ifdef DEBUG |
| fprintf(stderr, " adding comment %p/%p to variable...\n", |
| comment->last_child, comment->child); |
| #endif /* DEBUG */ |
| mxmlNewText(comment, 0, buffer); |
| update_comment(variable, |
| mxmlNewText(description, 0, buffer)); |
| } |
| |
| variable = NULL; |
| } |
| else if (constant) |
| { |
| if (strstr(buffer, "@private@")) |
| { |
| /* |
| * Delete private constants... |
| */ |
| |
| mxmlDelete(constant); |
| } |
| else |
| { |
| description = mxmlNewElement(constant, "description"); |
| #ifdef DEBUG |
| fprintf(stderr, " adding comment %p/%p to constant...\n", |
| comment->last_child, comment->child); |
| #endif /* DEBUG */ |
| mxmlNewText(comment, 0, buffer); |
| update_comment(constant, |
| mxmlNewText(description, 0, buffer)); |
| } |
| |
| constant = NULL; |
| } |
| else if (typedefnode) |
| { |
| if (strstr(buffer, "@private@")) |
| { |
| /* |
| * Delete private typedefs... |
| */ |
| |
| mxmlDelete(typedefnode); |
| |
| if (structclass) |
| { |
| mxmlDelete(structclass); |
| structclass = NULL; |
| } |
| |
| if (enumeration) |
| { |
| mxmlDelete(enumeration); |
| enumeration = NULL; |
| } |
| } |
| else |
| { |
| description = mxmlNewElement(typedefnode, "description"); |
| #ifdef DEBUG |
| fprintf(stderr, |
| " adding comment %p/%p to typedef %s...\n", |
| comment->last_child, comment->child, |
| mxmlElementGetAttr(typedefnode, "name")); |
| #endif /* DEBUG */ |
| mxmlNewText(comment, 0, buffer); |
| update_comment(typedefnode, |
| mxmlNewText(description, 0, buffer)); |
| |
| if (structclass) |
| { |
| description = mxmlNewElement(structclass, "description"); |
| update_comment(structclass, |
| mxmlNewText(description, 0, buffer)); |
| } |
| else if (enumeration) |
| { |
| description = mxmlNewElement(enumeration, "description"); |
| update_comment(enumeration, |
| mxmlNewText(description, 0, buffer)); |
| } |
| } |
| |
| typedefnode = NULL; |
| } |
| else if (strcmp(tree->value.element.name, "mxmldoc") && |
| !mxmlFindElement(tree, tree, "description", |
| NULL, NULL, MXML_DESCEND_FIRST)) |
| { |
| description = mxmlNewElement(tree, "description"); |
| #ifdef DEBUG |
| fprintf(stderr, " adding comment %p/%p to parent...\n", |
| comment->last_child, comment->child); |
| #endif /* DEBUG */ |
| mxmlNewText(comment, 0, buffer); |
| update_comment(tree, |
| mxmlNewText(description, 0, buffer)); |
| } |
| else |
| mxmlNewText(comment, 0, buffer); |
| |
| #ifdef DEBUG |
| fprintf(stderr, "C comment: <<<< %s >>>\n", buffer); |
| #endif /* DEBUG */ |
| |
| state = STATE_NONE; |
| break; |
| } |
| |
| default : |
| if (ch == ' ' && bufptr == buffer) |
| break; |
| |
| if (bufptr < (buffer + sizeof(buffer) - 1)) |
| *bufptr++ = ch; |
| break; |
| } |
| break; |
| |
| case STATE_CXX_COMMENT : /* Inside a C++ comment */ |
| if (ch == '\n') |
| { |
| state = STATE_NONE; |
| *bufptr = '\0'; |
| |
| if (comment->child != comment->last_child) |
| { |
| #ifdef DEBUG |
| fprintf(stderr, " removing comment %p(%20.20s), last comment %p(%20.20s)...\n", |
| comment->child, |
| comment->child ? comment->child->value.text.string : "", |
| comment->last_child, |
| comment->last_child ? comment->last_child->value.text.string : ""); |
| #endif /* DEBUG */ |
| mxmlDelete(comment->child); |
| #ifdef DEBUG |
| fprintf(stderr, " new comment %p, last comment %p...\n", |
| comment->child, comment->last_child); |
| #endif /* DEBUG */ |
| } |
| |
| if (variable) |
| { |
| if (strstr(buffer, "@private@")) |
| { |
| /* |
| * Delete private variables... |
| */ |
| |
| mxmlDelete(variable); |
| } |
| else |
| { |
| description = mxmlNewElement(variable, "description"); |
| #ifdef DEBUG |
| fprintf(stderr, " adding comment %p/%p to variable...\n", |
| comment->last_child, comment->child); |
| #endif /* DEBUG */ |
| mxmlNewText(comment, 0, buffer); |
| update_comment(variable, |
| mxmlNewText(description, 0, buffer)); |
| } |
| |
| variable = NULL; |
| } |
| else if (constant) |
| { |
| if (strstr(buffer, "@private@")) |
| { |
| /* |
| * Delete private constants... |
| */ |
| |
| mxmlDelete(constant); |
| } |
| else |
| { |
| description = mxmlNewElement(constant, "description"); |
| #ifdef DEBUG |
| fprintf(stderr, " adding comment %p/%p to constant...\n", |
| comment->last_child, comment->child); |
| #endif /* DEBUG */ |
| mxmlNewText(comment, 0, buffer); |
| update_comment(constant, |
| mxmlNewText(description, 0, buffer)); |
| } |
| |
| constant = NULL; |
| } |
| else if (typedefnode) |
| { |
| if (strstr(buffer, "@private@")) |
| { |
| /* |
| * Delete private typedefs... |
| */ |
| |
| mxmlDelete(typedefnode); |
| typedefnode = NULL; |
| |
| if (structclass) |
| { |
| mxmlDelete(structclass); |
| structclass = NULL; |
| } |
| |
| if (enumeration) |
| { |
| mxmlDelete(enumeration); |
| enumeration = NULL; |
| } |
| } |
| else |
| { |
| description = mxmlNewElement(typedefnode, "description"); |
| #ifdef DEBUG |
| fprintf(stderr, " adding comment %p/%p to typedef %s...\n", |
| comment->last_child, comment->child, |
| mxmlElementGetAttr(typedefnode, "name")); |
| #endif /* DEBUG */ |
| mxmlNewText(comment, 0, buffer); |
| update_comment(typedefnode, |
| mxmlNewText(description, 0, buffer)); |
| |
| if (structclass) |
| { |
| description = mxmlNewElement(structclass, "description"); |
| update_comment(structclass, |
| mxmlNewText(description, 0, buffer)); |
| } |
| else if (enumeration) |
| { |
| description = mxmlNewElement(enumeration, "description"); |
| update_comment(enumeration, |
| mxmlNewText(description, 0, buffer)); |
| } |
| } |
| } |
| else if (strcmp(tree->value.element.name, "mxmldoc") && |
| !mxmlFindElement(tree, tree, "description", |
| NULL, NULL, MXML_DESCEND_FIRST)) |
| { |
| description = mxmlNewElement(tree, "description"); |
| #ifdef DEBUG |
| fprintf(stderr, " adding comment %p/%p to parent...\n", |
| comment->last_child, comment->child); |
| #endif /* DEBUG */ |
| mxmlNewText(comment, 0, buffer); |
| update_comment(tree, |
| mxmlNewText(description, 0, buffer)); |
| } |
| else |
| mxmlNewText(comment, 0, buffer); |
| |
| #ifdef DEBUG |
| fprintf(stderr, "C++ comment: <<<< %s >>>\n", buffer); |
| #endif /* DEBUG */ |
| } |
| else if (ch == ' ' && bufptr == buffer) |
| break; |
| else if (bufptr < (buffer + sizeof(buffer) - 1)) |
| *bufptr++ = ch; |
| break; |
| |
| case STATE_STRING : /* Inside a string constant */ |
| *bufptr++ = ch; |
| |
| if (ch == '\\') |
| *bufptr++ = getc(fp); |
| else if (ch == '\"') |
| { |
| *bufptr = '\0'; |
| |
| if (type) |
| mxmlNewText(type, type->child != NULL, buffer); |
| |
| state = STATE_NONE; |
| } |
| break; |
| |
| case STATE_CHARACTER : /* Inside a character constant */ |
| *bufptr++ = ch; |
| |
| if (ch == '\\') |
| *bufptr++ = getc(fp); |
| else if (ch == '\'') |
| { |
| *bufptr = '\0'; |
| |
| if (type) |
| mxmlNewText(type, type->child != NULL, buffer); |
| |
| state = STATE_NONE; |
| } |
| break; |
| |
| case STATE_IDENTIFIER : /* Inside a keyword or identifier */ |
| if (isalnum(ch) || ch == '_' || ch == '[' || ch == ']' || |
| (ch == ',' && (parens > 1 || (type && !enumeration && !function))) || |
| ch == ':' || ch == '.' || ch == '~') |
| { |
| if (bufptr < (buffer + sizeof(buffer) - 1)) |
| *bufptr++ = ch; |
| } |
| else |
| { |
| ungetc(ch, fp); |
| *bufptr = '\0'; |
| state = STATE_NONE; |
| |
| #ifdef DEBUG |
| fprintf(stderr, " braces=%d, type=%p, type->child=%p, buffer=\"%s\"\n", |
| braces, type, type ? type->child : NULL, buffer); |
| #endif /* DEBUG */ |
| |
| if (!braces) |
| { |
| if (!type || !type->child) |
| { |
| if (!strcmp(tree->value.element.name, "class")) |
| { |
| if (!strcmp(buffer, "public") || |
| !strcmp(buffer, "public:")) |
| { |
| scope = "public"; |
| #ifdef DEBUG |
| fputs(" scope = public\n", stderr); |
| #endif /* DEBUG */ |
| break; |
| } |
| else if (!strcmp(buffer, "private") || |
| !strcmp(buffer, "private:")) |
| { |
| scope = "private"; |
| #ifdef DEBUG |
| fputs(" scope = private\n", stderr); |
| #endif /* DEBUG */ |
| break; |
| } |
| else if (!strcmp(buffer, "protected") || |
| !strcmp(buffer, "protected:")) |
| { |
| scope = "protected"; |
| #ifdef DEBUG |
| fputs(" scope = protected\n", stderr); |
| #endif /* DEBUG */ |
| break; |
| } |
| } |
| } |
| |
| if (!type) |
| type = mxmlNewElement(MXML_NO_PARENT, "type"); |
| |
| #ifdef DEBUG |
| fprintf(stderr, " function=%p (%s), type->child=%p, ch='%c', parens=%d\n", |
| function, |
| function ? mxmlElementGetAttr(function, "name") : "null", |
| type->child, ch, parens); |
| #endif /* DEBUG */ |
| |
| if (!function && ch == '(') |
| { |
| if (type->child && |
| !strcmp(type->child->value.text.string, "extern")) |
| { |
| /* |
| * Remove external declarations... |
| */ |
| |
| mxmlDelete(type); |
| type = NULL; |
| break; |
| } |
| |
| if (type->child && |
| !strcmp(type->child->value.text.string, "static") && |
| !strcmp(tree->value.element.name, "mxmldoc")) |
| { |
| /* |
| * Remove static functions... |
| */ |
| |
| mxmlDelete(type); |
| type = NULL; |
| break; |
| } |
| |
| function = mxmlNewElement(MXML_NO_PARENT, "function"); |
| if ((bufptr = strchr(buffer, ':')) != NULL && bufptr[1] == ':') |
| { |
| *bufptr = '\0'; |
| bufptr += 2; |
| |
| if ((fstructclass = |
| mxmlFindElement(tree, tree, "class", "name", buffer, |
| MXML_DESCEND_FIRST)) == NULL) |
| fstructclass = |
| mxmlFindElement(tree, tree, "struct", "name", buffer, |
| MXML_DESCEND_FIRST); |
| } |
| else |
| bufptr = buffer; |
| |
| mxmlElementSetAttr(function, "name", bufptr); |
| |
| if (scope) |
| mxmlElementSetAttr(function, "scope", scope); |
| |
| #ifdef DEBUG |
| fprintf(stderr, "function: %s\n", buffer); |
| fprintf(stderr, " scope = %s\n", scope ? scope : "(null)"); |
| fprintf(stderr, " comment = %p\n", comment); |
| fprintf(stderr, " child = (%p) %s\n", |
| comment->child, |
| comment->child ? |
| comment->child->value.text.string : "(null)"); |
| fprintf(stderr, " last_child = (%p) %s\n", |
| comment->last_child, |
| comment->last_child ? |
| comment->last_child->value.text.string : "(null)"); |
| #endif /* DEBUG */ |
| |
| if (type->last_child && |
| strcmp(type->last_child->value.text.string, "void")) |
| { |
| returnvalue = mxmlNewElement(function, "returnvalue"); |
| |
| mxmlAdd(returnvalue, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, type); |
| |
| description = mxmlNewElement(returnvalue, "description"); |
| #ifdef DEBUG |
| fprintf(stderr, " adding comment %p/%p to returnvalue...\n", |
| comment->last_child, comment->child); |
| #endif /* DEBUG */ |
| update_comment(returnvalue, comment->last_child); |
| mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, |
| comment->last_child); |
| } |
| else |
| mxmlDelete(type); |
| |
| description = mxmlNewElement(function, "description"); |
| #ifdef DEBUG |
| fprintf(stderr, " adding comment %p/%p to function...\n", |
| comment->last_child, comment->child); |
| #endif /* DEBUG */ |
| update_comment(function, comment->last_child); |
| mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, |
| comment->last_child); |
| |
| type = NULL; |
| } |
| else if (function && ((ch == ')' && parens == 1) || ch == ',')) |
| { |
| /* |
| * Argument definition... |
| */ |
| |
| if (strcmp(buffer, "void")) |
| { |
| mxmlNewText(type, type->child != NULL && |
| type->last_child->value.text.string[0] != '(' && |
| type->last_child->value.text.string[0] != '*', |
| buffer); |
| |
| #ifdef DEBUG |
| fprintf(stderr, "Argument: <<<< %s >>>\n", buffer); |
| #endif /* DEBUG */ |
| |
| variable = add_variable(function, "argument", type); |
| } |
| else |
| mxmlDelete(type); |
| |
| type = NULL; |
| } |
| else if (type->child && !function && (ch == ';' || ch == ',')) |
| { |
| #ifdef DEBUG |
| fprintf(stderr, " got semicolon, typedefnode=%p, structclass=%p\n", |
| typedefnode, structclass); |
| #endif /* DEBUG */ |
| |
| if (typedefnode || structclass) |
| { |
| #ifdef DEBUG |
| fprintf(stderr, "Typedef/struct/class: <<<< %s >>>>\n", buffer); |
| #endif /* DEBUG */ |
| |
| if (typedefnode) |
| { |
| mxmlElementSetAttr(typedefnode, "name", buffer); |
| |
| sort_node(tree, typedefnode); |
| } |
| |
| if (structclass && !mxmlElementGetAttr(structclass, "name")) |
| { |
| #ifdef DEBUG |
| fprintf(stderr, "setting struct/class name to %s!\n", |
| type->last_child->value.text.string); |
| #endif /* DEBUG */ |
| mxmlElementSetAttr(structclass, "name", buffer); |
| |
| sort_node(tree, structclass); |
| structclass = NULL; |
| } |
| |
| if (typedefnode) |
| mxmlAdd(typedefnode, MXML_ADD_BEFORE, MXML_ADD_TO_PARENT, |
| type); |
| else |
| mxmlDelete(type); |
| |
| type = NULL; |
| typedefnode = NULL; |
| } |
| else if (type->child && |
| !strcmp(type->child->value.text.string, "typedef")) |
| { |
| /* |
| * Simple typedef... |
| */ |
| |
| #ifdef DEBUG |
| fprintf(stderr, "Typedef: <<<< %s >>>\n", buffer); |
| #endif /* DEBUG */ |
| |
| typedefnode = mxmlNewElement(MXML_NO_PARENT, "typedef"); |
| mxmlElementSetAttr(typedefnode, "name", buffer); |
| mxmlDelete(type->child); |
| |
| sort_node(tree, typedefnode); |
| |
| if (type->child) |
| type->child->value.text.whitespace = 0; |
| |
| mxmlAdd(typedefnode, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, type); |
| type = NULL; |
| } |
| else if (!parens) |
| { |
| /* |
| * Variable definition... |
| */ |
| |
| if (type->child && |
| !strcmp(type->child->value.text.string, "static") && |
| !strcmp(tree->value.element.name, "mxmldoc")) |
| { |
| /* |
| * Remove static functions... |
| */ |
| |
| mxmlDelete(type); |
| type = NULL; |
| break; |
| } |
| |
| mxmlNewText(type, type->child != NULL && |
| type->last_child->value.text.string[0] != '(' && |
| type->last_child->value.text.string[0] != '*', |
| buffer); |
| |
| #ifdef DEBUG |
| fprintf(stderr, "Variable: <<<< %s >>>>\n", buffer); |
| fprintf(stderr, " scope = %s\n", scope ? scope : "(null)"); |
| #endif /* DEBUG */ |
| |
| variable = add_variable(MXML_NO_PARENT, "variable", type); |
| type = NULL; |
| |
| sort_node(tree, variable); |
| |
| if (scope) |
| mxmlElementSetAttr(variable, "scope", scope); |
| } |
| } |
| else |
| { |
| #ifdef DEBUG |
| fprintf(stderr, "Identifier: <<<< %s >>>>\n", buffer); |
| #endif /* DEBUG */ |
| |
| mxmlNewText(type, type->child != NULL && |
| type->last_child->value.text.string[0] != '(' && |
| type->last_child->value.text.string[0] != '*', |
| buffer); |
| } |
| } |
| else if (enumeration && !isdigit(buffer[0] & 255)) |
| { |
| #ifdef DEBUG |
| fprintf(stderr, "Constant: <<<< %s >>>\n", buffer); |
| #endif /* DEBUG */ |
| |
| constant = mxmlNewElement(MXML_NO_PARENT, "constant"); |
| mxmlElementSetAttr(constant, "name", buffer); |
| sort_node(enumeration, constant); |
| } |
| else if (type) |
| { |
| mxmlDelete(type); |
| type = NULL; |
| } |
| } |
| break; |
| } |
| |
| #if DEBUG > 1 |
| if (state != oldstate) |
| { |
| fprintf(stderr, " changed states from %s to %s on receipt of character '%c'...\n", |
| states[oldstate], states[state], oldch); |
| fprintf(stderr, " variable = %p\n", variable); |
| if (type) |
| { |
| fputs(" type =", stderr); |
| for (temp = type->child; temp; temp = temp->next) |
| fprintf(stderr, " \"%s\"", temp->value.text.string); |
| fputs("\n", stderr); |
| } |
| } |
| #endif /* DEBUG > 1 */ |
| } |
| |
| mxmlDelete(comment); |
| |
| /* |
| * All done, return with no errors... |
| */ |
| |
| return (0); |
| } |
| |
| |
| /* |
| * 'sort_node()' - Insert a node sorted into a tree. |
| */ |
| |
| static void |
| sort_node(mxml_node_t *tree, /* I - Tree to sort into */ |
| mxml_node_t *node) /* I - Node to add */ |
| { |
| mxml_node_t *temp; /* Current node */ |
| const char *tempname, /* Name of current node */ |
| *nodename, /* Name of node */ |
| *scope; /* Scope */ |
| |
| |
| #if DEBUG > 1 |
| fprintf(stderr, " sort_node(tree=%p, node=%p)\n", tree, node); |
| #endif /* DEBUG > 1 */ |
| |
| /* |
| * Range check input... |
| */ |
| |
| if (!tree || !node || node->parent == tree) |
| return; |
| |
| /* |
| * Get the node name... |
| */ |
| |
| if ((nodename = mxmlElementGetAttr(node, "name")) == NULL) |
| return; |
| |
| if (nodename[0] == '_') |
| return; /* Hide private names */ |
| |
| #if DEBUG > 1 |
| fprintf(stderr, " nodename=%p (\"%s\")\n", nodename, nodename); |
| #endif /* DEBUG > 1 */ |
| |
| /* |
| * Delete any existing definition at this level, if one exists... |
| */ |
| |
| if ((temp = mxmlFindElement(tree, tree, node->value.element.name, |
| "name", nodename, MXML_DESCEND_FIRST)) != NULL) |
| { |
| /* |
| * Copy the scope if needed... |
| */ |
| |
| if ((scope = mxmlElementGetAttr(temp, "scope")) != NULL && |
| mxmlElementGetAttr(node, "scope") == NULL) |
| { |
| #ifdef DEBUG |
| fprintf(stderr, " copying scope %s for %s\n", scope, nodename); |
| #endif /* DEBUG */ |
| |
| mxmlElementSetAttr(node, "scope", scope); |
| } |
| |
| mxmlDelete(temp); |
| } |
| |
| /* |
| * Add the node into the tree at the proper place... |
| */ |
| |
| for (temp = tree->child; temp; temp = temp->next) |
| { |
| #if DEBUG > 1 |
| fprintf(stderr, " temp=%p\n", temp); |
| #endif /* DEBUG > 1 */ |
| |
| if ((tempname = mxmlElementGetAttr(temp, "name")) == NULL) |
| continue; |
| |
| #if DEBUG > 1 |
| fprintf(stderr, " tempname=%p (\"%s\")\n", tempname, tempname); |
| #endif /* DEBUG > 1 */ |
| |
| if (strcmp(nodename, tempname) < 0) |
| break; |
| } |
| |
| if (temp) |
| mxmlAdd(tree, MXML_ADD_BEFORE, temp, node); |
| else |
| mxmlAdd(tree, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, node); |
| } |
| |
| |
| /* |
| * 'update_comment()' - Update a comment node. |
| */ |
| |
| static void |
| update_comment(mxml_node_t *parent, /* I - Parent node */ |
| mxml_node_t *comment) /* I - Comment node */ |
| { |
| char *ptr; /* Pointer into comment */ |
| |
| |
| #ifdef DEBUG |
| fprintf(stderr, "update_comment(parent=%p, comment=%p)\n", |
| parent, comment); |
| #endif /* DEBUG */ |
| |
| /* |
| * Range check the input... |
| */ |
| |
| if (!parent || !comment) |
| return; |
| |
| /* |
| * Convert "\/" to "/"... |
| */ |
| |
| for (ptr = strstr(comment->value.text.string, "\\/"); |
| ptr; |
| ptr = strstr(ptr, "\\/")) |
| safe_strcpy(ptr, ptr + 1); |
| |
| /* |
| * Update the comment... |
| */ |
| |
| ptr = comment->value.text.string; |
| |
| if (*ptr == '\'') |
| { |
| /* |
| * Convert "'name()' - description" to "description". |
| */ |
| |
| for (ptr ++; *ptr && *ptr != '\''; ptr ++); |
| |
| if (*ptr == '\'') |
| { |
| ptr ++; |
| while (isspace(*ptr & 255)) |
| ptr ++; |
| |
| if (*ptr == '-') |
| ptr ++; |
| |
| while (isspace(*ptr & 255)) |
| ptr ++; |
| |
| safe_strcpy(comment->value.text.string, ptr); |
| } |
| } |
| else if (!strncmp(ptr, "I ", 2) || !strncmp(ptr, "O ", 2) || |
| !strncmp(ptr, "IO ", 3)) |
| { |
| /* |
| * 'Convert "I - description", "IO - description", or "O - description" |
| * to description + direction attribute. |
| */ |
| |
| ptr = strchr(ptr, ' '); |
| *ptr++ = '\0'; |
| |
| if (!strcmp(parent->value.element.name, "argument")) |
| mxmlElementSetAttr(parent, "direction", comment->value.text.string); |
| |
| while (isspace(*ptr & 255)) |
| ptr ++; |
| |
| if (*ptr == '-') |
| ptr ++; |
| |
| while (isspace(*ptr & 255)) |
| ptr ++; |
| |
| safe_strcpy(comment->value.text.string, ptr); |
| } |
| |
| /* |
| * Eliminate leading and trailing *'s... |
| */ |
| |
| for (ptr = comment->value.text.string; *ptr == '*'; ptr ++); |
| for (; isspace(*ptr & 255); ptr ++); |
| if (ptr > comment->value.text.string) |
| safe_strcpy(comment->value.text.string, ptr); |
| |
| for (ptr = comment->value.text.string + strlen(comment->value.text.string) - 1; |
| ptr > comment->value.text.string && *ptr == '*'; |
| ptr --) |
| *ptr = '\0'; |
| for (; ptr > comment->value.text.string && isspace(*ptr & 255); ptr --) |
| *ptr = '\0'; |
| |
| #ifdef DEBUG |
| fprintf(stderr, " updated comment = %s\n", comment->value.text.string); |
| #endif /* DEBUG */ |
| } |
| |
| |
| /* |
| * 'usage()' - Show program usage... |
| */ |
| |
| static void |
| usage(const char *option) /* I - Unknown option */ |
| { |
| if (option) |
| printf("mxmldoc: Bad option \"%s\"!\n\n", option); |
| |
| puts("Usage: mxmldoc [options] [filename.xml] [source files] >filename.html"); |
| puts("Options:"); |
| puts(" --css filename.css Set CSS stylesheet file"); |
| puts(" --docset bundleid.docset Generate documentation set"); |
| puts(" --docversion version Set documentation version"); |
| puts(" --feedname name Set documentation set feed name"); |
| puts(" --feedurl url Set documentation set feed URL"); |
| puts(" --footer footerfile Set footer file"); |
| puts(" --framed basename Generate framed HTML to basename*.html"); |
| puts(" --header headerfile Set header file"); |
| puts(" --intro introfile Set introduction file"); |
| puts(" --man name Generate man page"); |
| puts(" --no-output Do no generate documentation file"); |
| puts(" --section section Set section name"); |
| puts(" --title title Set documentation title"); |
| puts(" --tokens path Generate Xcode docset Tokens.xml file"); |
| puts(" --version Show mxmldoc/Mini-XML version"); |
| |
| exit(1); |
| } |
| |
| |
| /* |
| * 'write_description()' - Write the description text. |
| */ |
| |
| static void |
| write_description( |
| FILE *out, /* I - Output file */ |
| mxml_node_t *description, /* I - Description node */ |
| const char *element, /* I - HTML element, if any */ |
| int summary) /* I - Show summary */ |
| { |
| char text[10240], /* Text for description */ |
| *start, /* Start of code/link */ |
| *ptr; /* Pointer into text */ |
| int col; /* Current column */ |
| |
| |
| if (!description) |
| return; |
| |
| get_text(description, text, sizeof(text)); |
| |
| ptr = strstr(text, "\n\n"); |
| |
| if (summary) |
| { |
| if (ptr) |
| *ptr = '\0'; |
| |
| ptr = text; |
| } |
| else if (!ptr || !ptr[2]) |
| return; |
| else |
| ptr += 2; |
| |
| if (element && *element) |
| fprintf(out, "<%s class=\"%s\">", element, |
| summary ? "description" : "discussion"); |
| else if (!summary) |
| fputs(".PP\n", out); |
| |
| for (col = 0; *ptr; ptr ++) |
| { |
| if (*ptr == '@' && |
| (!strncmp(ptr + 1, "deprecated@", 11) || |
| !strncmp(ptr + 1, "since ", 6))) |
| { |
| ptr ++; |
| while (*ptr && *ptr != '@') |
| ptr ++; |
| |
| if (!*ptr) |
| return; |
| } |
| else if (!strncmp(ptr, "@code ", 6)) |
| { |
| for (ptr += 6; isspace(*ptr & 255); ptr ++); |
| |
| for (start = ptr, ptr ++; *ptr && *ptr != '@'; ptr ++); |
| |
| if (*ptr) |
| *ptr = '\0'; |
| else |
| ptr --; |
| |
| if (element && *element) |
| { |
| fputs("<code>", out); |
| for (; *start; start ++) |
| { |
| if (*start == '<') |
| fputs("<", out); |
| else if (*start == '>') |
| fputs(">", out); |
| else if (*start == '&') |
| fputs("&", out); |
| else |
| putc(*start, out); |
| } |
| fputs("</code>", out); |
| } |
| else if (element) |
| fputs(start, out); |
| else |
| fprintf(out, "\\fB%s\\fR", start); |
| } |
| else if (!strncmp(ptr, "@link ", 6)) |
| { |
| for (ptr += 6; isspace(*ptr & 255); ptr ++); |
| |
| for (start = ptr, ptr ++; *ptr && *ptr != '@'; ptr ++); |
| |
| if (*ptr) |
| *ptr = '\0'; |
| else |
| ptr --; |
| |
| if (element && *element) |
| fprintf(out, "<a href=\"#%s\"><code>%s</code></a>", start, start); |
| else if (element) |
| fputs(start, out); |
| else |
| fprintf(out, "\\fI%s\\fR", start); |
| } |
| else if (element) |
| { |
| if (*ptr == '&') |
| fputs("&", out); |
| else if (*ptr == '<') |
| fputs("<", out); |
| else if (*ptr == '>') |
| fputs(">", out); |
| else if (*ptr == '\"') |
| fputs(""", out); |
| else if (*ptr & 128) |
| { |
| /* |
| * Convert UTF-8 to Unicode constant... |
| */ |
| |
| int ch; /* Unicode character */ |
| |
| |
| ch = *ptr & 255; |
| |
| if ((ch & 0xe0) == 0xc0) |
| { |
| ch = ((ch & 0x1f) << 6) | (ptr[1] & 0x3f); |
| ptr ++; |
| } |
| else if ((ch & 0xf0) == 0xe0) |
| { |
| ch = ((((ch * 0x0f) << 6) | (ptr[1] & 0x3f)) << 6) | (ptr[2] & 0x3f); |
| ptr += 2; |
| } |
| |
| if (ch == 0xa0) |
| { |
| /* |
| * Handle non-breaking space as-is... |
| */ |
| |
| fputs(" ", out); |
| } |
| else |
| fprintf(out, "&#x%x;", ch); |
| } |
| else if (*ptr == '\n' && ptr[1] == '\n' && ptr[2] && ptr[2] != '@') |
| { |
| fputs("<br>\n<br>\n", out); |
| ptr ++; |
| } |
| else |
| putc(*ptr, out); |
| } |
| else if (*ptr == '\n' && ptr[1] == '\n' && ptr[2] && ptr[2] != '@') |
| { |
| fputs("\n.PP\n", out); |
| ptr ++; |
| } |
| else |
| { |
| if (*ptr == '\\' || (*ptr == '.' && col == 0)) |
| putc('\\', out); |
| |
| putc(*ptr, out); |
| |
| if (*ptr == '\n') |
| col = 0; |
| else |
| col ++; |
| } |
| } |
| |
| if (element && *element) |
| fprintf(out, "</%s>\n", element); |
| else if (!element) |
| putc('\n', out); |
| } |
| |
| |
| /* |
| * 'write_element()' - Write an element's text nodes. |
| */ |
| |
| static void |
| write_element(FILE *out, /* I - Output file */ |
| mxml_node_t *doc, /* I - Document tree */ |
| mxml_node_t *element, /* I - Element to write */ |
| int mode) /* I - Output mode */ |
| { |
| mxml_node_t *node; /* Current node */ |
| |
| |
| if (!element) |
| return; |
| |
| for (node = element->child; |
| node; |
| node = mxmlWalkNext(node, element, MXML_NO_DESCEND)) |
| if (node->type == MXML_TEXT) |
| { |
| if (node->value.text.whitespace) |
| putc(' ', out); |
| |
| if (mode == OUTPUT_HTML && |
| (mxmlFindElement(doc, doc, "class", "name", node->value.text.string, |
| MXML_DESCEND) || |
| mxmlFindElement(doc, doc, "enumeration", "name", |
| node->value.text.string, MXML_DESCEND) || |
| mxmlFindElement(doc, doc, "struct", "name", node->value.text.string, |
| MXML_DESCEND) || |
| mxmlFindElement(doc, doc, "typedef", "name", node->value.text.string, |
| MXML_DESCEND) || |
| mxmlFindElement(doc, doc, "union", "name", node->value.text.string, |
| MXML_DESCEND))) |
| { |
| fputs("<a href=\"#", out); |
| write_string(out, node->value.text.string, mode); |
| fputs("\">", out); |
| write_string(out, node->value.text.string, mode); |
| fputs("</a>", out); |
| } |
| else |
| write_string(out, node->value.text.string, mode); |
| } |
| |
| if (!strcmp(element->value.element.name, "type") && |
| element->last_child->value.text.string[0] != '*') |
| putc(' ', out); |
| } |
| |
| |
| /* |
| * 'write_file()' - Copy a file to the output. |
| */ |
| |
| static void |
| write_file(FILE *out, /* I - Output file */ |
| const char *file) /* I - File to copy */ |
| { |
| FILE *fp; /* Copy file */ |
| char line[8192]; /* Line from file */ |
| |
| |
| if ((fp = fopen(file, "r")) == NULL) |
| { |
| fprintf(stderr, "mxmldoc: Unable to open \"%s\": %s\n", file, |
| strerror(errno)); |
| return; |
| } |
| |
| while (fgets(line, sizeof(line), fp)) |
| fputs(line, out); |
| |
| fclose(fp); |
| } |
| |
| |
| /* |
| * 'write_function()' - Write documentation for a function. |
| */ |
| |
| static void |
| write_function(FILE *out, /* I - Output file */ |
| mxml_node_t *doc, /* I - Document */ |
| mxml_node_t *function, /* I - Function */ |
| int level) /* I - Base heading level */ |
| { |
| mxml_node_t *arg, /* Current argument */ |
| *adesc, /* Description of argument */ |
| *description, /* Description of function */ |
| *type, /* Type for argument */ |
| *node; /* Node in description */ |
| const char *name, /* Name of function/type */ |
| *defval; /* Default value */ |
| char prefix; /* Prefix character */ |
| char *sep; /* Newline separator */ |
| |
| |
| name = mxmlElementGetAttr(function, "name"); |
| description = mxmlFindElement(function, function, "description", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| |
| fprintf(out, "<h%d class=\"%s\">%s<a name=\"%s\">%s</a></h%d>\n", |
| level, level == 3 ? "function" : "method", |
| get_comment_info(description), name, name, level); |
| |
| if (description) |
| write_description(out, description, "p", 1); |
| |
| fputs("<p class=\"code\">\n", out); |
| |
| arg = mxmlFindElement(function, function, "returnvalue", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| |
| if (arg) |
| write_element(out, doc, mxmlFindElement(arg, arg, "type", NULL, |
| NULL, MXML_DESCEND_FIRST), |
| OUTPUT_HTML); |
| else |
| fputs("void ", out); |
| |
| fprintf(out, "%s ", name); |
| for (arg = mxmlFindElement(function, function, "argument", NULL, NULL, |
| MXML_DESCEND_FIRST), prefix = '('; |
| arg; |
| arg = mxmlFindElement(arg, function, "argument", NULL, NULL, |
| MXML_NO_DESCEND), prefix = ',') |
| { |
| type = mxmlFindElement(arg, arg, "type", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| |
| fprintf(out, "%c<br>\n ", prefix); |
| if (type->child) |
| write_element(out, doc, type, OUTPUT_HTML); |
| |
| fputs(mxmlElementGetAttr(arg, "name"), out); |
| if ((defval = mxmlElementGetAttr(arg, "default")) != NULL) |
| fprintf(out, " %s", defval); |
| } |
| |
| if (prefix == '(') |
| fputs("(void);</p>\n", out); |
| else |
| { |
| fprintf(out, |
| "<br>\n);</p>\n" |
| "<h%d class=\"parameters\">Parameters</h%d>\n" |
| "<dl>\n", level + 1, level + 1); |
| |
| for (arg = mxmlFindElement(function, function, "argument", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| arg; |
| arg = mxmlFindElement(arg, function, "argument", NULL, NULL, |
| MXML_NO_DESCEND)) |
| { |
| fprintf(out, "<dt>%s</dt>\n", mxmlElementGetAttr(arg, "name")); |
| |
| adesc = mxmlFindElement(arg, arg, "description", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| |
| write_description(out, adesc, "dd", 1); |
| write_description(out, adesc, "dd", 0); |
| } |
| |
| fputs("</dl>\n", out); |
| } |
| |
| arg = mxmlFindElement(function, function, "returnvalue", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| |
| if (arg) |
| { |
| fprintf(out, "<h%d class=\"returnvalue\">Return Value</h%d>\n", level + 1, |
| level + 1); |
| |
| adesc = mxmlFindElement(arg, arg, "description", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| |
| write_description(out, adesc, "p", 1); |
| write_description(out, adesc, "p", 0); |
| } |
| |
| if (description) |
| { |
| for (node = description->child; node; node = node->next) |
| if (node->value.text.string && |
| (sep = strstr(node->value.text.string, "\n\n")) != NULL) |
| { |
| sep += 2; |
| if (*sep && strncmp(sep, "@since ", 7) && |
| strncmp(sep, "@deprecated@", 12)) |
| break; |
| } |
| |
| if (node) |
| { |
| fprintf(out, "<h%d class=\"discussion\">Discussion</h%d>\n", level + 1, |
| level + 1); |
| write_description(out, description, "p", 0); |
| } |
| } |
| } |
| |
| |
| /* |
| * 'write_html()' - Write HTML documentation. |
| */ |
| |
| static void |
| write_html(const char *section, /* I - Section */ |
| const char *title, /* I - Title */ |
| const char *footerfile, /* I - Footer file */ |
| const char *headerfile, /* I - Header file */ |
| const char *introfile, /* I - Intro file */ |
| const char *cssfile, /* I - Stylesheet file */ |
| const char *framefile, /* I - Framed HTML basename */ |
| const char *docset, /* I - Documentation set directory */ |
| const char *docversion, /* I - Documentation set version */ |
| const char *feedname, /* I - Feed name for doc set */ |
| const char *feedurl, /* I - Feed URL for doc set */ |
| mxml_node_t *doc) /* I - XML documentation */ |
| { |
| FILE *out; /* Output file */ |
| mxml_node_t *function, /* Current function */ |
| *scut, /* Struct/class/union/typedef */ |
| *arg, /* Current argument */ |
| *description, /* Description of function/var */ |
| *type; /* Type for argument */ |
| const char *name, /* Name of function/type */ |
| *defval, /* Default value */ |
| *basename; /* Base filename for framed output */ |
| char filename[1024]; /* Current output filename */ |
| |
| |
| if (framefile) |
| { |
| /* |
| * Get the basename of the frame file... |
| */ |
| |
| if ((basename = strrchr(framefile, '/')) != NULL) |
| basename ++; |
| else |
| basename = framefile; |
| |
| if (strstr(basename, ".html")) |
| fputs("mxmldoc: Frame base name should not contain .html extension!\n", |
| stderr); |
| |
| /* |
| * Create the container HTML file for the frames... |
| */ |
| |
| snprintf(filename, sizeof(filename), "%s.html", framefile); |
| |
| if ((out = fopen(filename, "w")) == NULL) |
| { |
| fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", filename, |
| strerror(errno)); |
| return; |
| } |
| |
| fputs("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Frameset//EN\" " |
| "\"http://www.w3.org/TR/html4/frameset.dtd\">\n" |
| "<html>\n" |
| "<head>\n" |
| "\t<title>", out); |
| write_string(out, title, OUTPUT_HTML); |
| fputs("</title>\n", out); |
| |
| if (section) |
| fprintf(out, "\t<meta name=\"keywords\" content=\"%s\">\n", section); |
| |
| fputs("\t<meta http-equiv=\"Content-Type\" " |
| "content=\"text/html;charset=utf-8\">\n" |
| "\t<meta name=\"creator\" content=\"" MXML_VERSION "\">\n" |
| "</head>\n", out); |
| |
| fputs("<frameset cols=\"250,*\">\n", out); |
| fprintf(out, "<frame src=\"%s-toc.html\">\n", basename); |
| fprintf(out, "<frame name=\"body\" src=\"%s-body.html\">\n", basename); |
| fputs("</frameset>\n" |
| "<noframes>\n" |
| "<h1>", out); |
| write_string(out, title, OUTPUT_HTML); |
| fprintf(out, |
| "</h1>\n" |
| "<ul>\n" |
| "\t<li><a href=\"%s-toc.html\">Table of Contents</a></li>\n" |
| "\t<li><a href=\"%s-body.html\">Body</a></li>\n" |
| "</ul>\n", basename, basename); |
| fputs("</noframes>\n" |
| "</html>\n", out); |
| fclose(out); |
| |
| /* |
| * Write the table-of-contents file... |
| */ |
| |
| snprintf(filename, sizeof(filename), "%s-toc.html", framefile); |
| |
| if ((out = fopen(filename, "w")) == NULL) |
| { |
| fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", filename, |
| strerror(errno)); |
| return; |
| } |
| |
| write_html_head(out, section, title, cssfile); |
| |
| snprintf(filename, sizeof(filename), "%s-body.html", basename); |
| |
| fputs("<div class=\"contents\">\n", out); |
| fprintf(out, "<h1 class=\"title\"><a href=\"%s\" target=\"body\">", |
| filename); |
| write_string(out, title, OUTPUT_HTML); |
| fputs("</a></h1>\n", out); |
| |
| write_toc(out, doc, introfile, filename, 0); |
| |
| fputs("</div>\n" |
| "</body>\n" |
| "</html>\n", out); |
| fclose(out); |
| |
| /* |
| * Finally, open the body file... |
| */ |
| |
| snprintf(filename, sizeof(filename), "%s-body.html", framefile); |
| |
| if ((out = fopen(filename, "w")) == NULL) |
| { |
| fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", filename, |
| strerror(errno)); |
| return; |
| } |
| } |
| else if (docset) |
| { |
| /* |
| * Create an Xcode documentation set - start by removing any existing |
| * output directory... |
| */ |
| |
| #ifdef __APPLE__ |
| const char *id; /* Identifier */ |
| |
| |
| if (!access(docset, 0) && !remove_directory(docset)) |
| return; |
| |
| /* |
| * Then make the Apple standard bundle directory structure... |
| */ |
| |
| if (mkdir(docset, 0755)) |
| { |
| fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", docset, |
| strerror(errno)); |
| return; |
| } |
| |
| snprintf(filename, sizeof(filename), "%s/Contents", docset); |
| if (mkdir(filename, 0755)) |
| { |
| fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", filename, |
| strerror(errno)); |
| return; |
| } |
| |
| snprintf(filename, sizeof(filename), "%s/Contents/Resources", docset); |
| if (mkdir(filename, 0755)) |
| { |
| fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", filename, |
| strerror(errno)); |
| return; |
| } |
| |
| snprintf(filename, sizeof(filename), "%s/Contents/Resources/Documentation", |
| docset); |
| if (mkdir(filename, 0755)) |
| { |
| fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", filename, |
| strerror(errno)); |
| return; |
| } |
| |
| /* |
| * The Info.plist file, which describes the documentation set... |
| */ |
| |
| if ((id = strrchr(docset, '/')) != NULL) |
| id ++; |
| else |
| id = docset; |
| |
| snprintf(filename, sizeof(filename), "%s/Contents/Info.plist", docset); |
| if ((out = fopen(filename, "w")) == NULL) |
| { |
| fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", filename, |
| strerror(errno)); |
| return; |
| } |
| |
| fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" |
| "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" |
| "<plist version=\"1.0\">\n" |
| "<dict>\n" |
| "\t<key>CFBundleIdentifier</key>\n" |
| "\t<string>", out); |
| write_string(out, id, OUTPUT_HTML); |
| fputs("</string>\n" |
| "\t<key>CFBundleName</key>\n" |
| "\t<string>", out); |
| write_string(out, title, OUTPUT_HTML); |
| fputs("</string>\n" |
| "\t<key>CFBundleVersion</key>\n" |
| "\t<string>", out); |
| write_string(out, docversion ? docversion : "0.0", OUTPUT_HTML); |
| fputs("</string>\n" |
| "\t<key>CFBundleShortVersionString</key>\n" |
| "\t<string>", out); |
| write_string(out, docversion ? docversion : "0.0", OUTPUT_HTML); |
| fputs("</string>\n", out); |
| |
| if (feedname) |
| { |
| fputs("\t<key>DocSetFeedName</key>\n" |
| "\t<string>", out); |
| write_string(out, feedname ? feedname : title, OUTPUT_HTML); |
| fputs("</string>\n", out); |
| } |
| |
| if (feedurl) |
| { |
| fputs("\t<key>DocSetFeedURL</key>\n" |
| "\t<string>", out); |
| write_string(out, feedurl, OUTPUT_HTML); |
| fputs("</string>\n", out); |
| } |
| |
| fputs("</dict>\n" |
| "</plist>\n", out); |
| |
| fclose(out); |
| |
| /* |
| * Next the Nodes.xml file... |
| */ |
| |
| snprintf(filename, sizeof(filename), "%s/Contents/Resources/Nodes.xml", |
| docset); |
| if ((out = fopen(filename, "w")) == NULL) |
| { |
| fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", filename, |
| strerror(errno)); |
| return; |
| } |
| |
| fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" |
| "<DocSetNodes version=\"1.0\">\n" |
| "<TOC>\n" |
| "<Node id=\"0\">\n" |
| "<Name>", out); |
| write_string(out, title, OUTPUT_HTML); |
| fputs("</Name>\n" |
| "<Path>Documentation/index.html</Path>\n" |
| "<Subnodes>\n", out); |
| |
| write_toc(out, doc, introfile, NULL, 1); |
| |
| fputs("</Subnodes>\n" |
| "</Node>\n" |
| "</TOC>\n" |
| "</DocSetNodes>\n", out); |
| |
| fclose(out); |
| |
| /* |
| * Then the Tokens.xml file... |
| */ |
| |
| snprintf(filename, sizeof(filename), "%s/Contents/Resources/Tokens.xml", |
| docset); |
| if ((out = fopen(filename, "w")) == NULL) |
| { |
| fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", filename, |
| strerror(errno)); |
| return; |
| } |
| |
| fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" |
| "<Tokens version=\"1.0\">\n", out); |
| |
| write_tokens(out, doc, "index.html"); |
| |
| fputs("</Tokens>\n", out); |
| |
| fclose(out); |
| |
| /* |
| * Finally the HTML file... |
| */ |
| |
| snprintf(filename, sizeof(filename), |
| "%s/Contents/Resources/Documentation/index.html", |
| docset); |
| if ((out = fopen(filename, "w")) == NULL) |
| { |
| fprintf(stderr, "mxmldoc: Unable to create \"%s\": %s\n", filename, |
| strerror(errno)); |
| return; |
| } |
| |
| #else |
| fputs("mxmldoc: Xcode documentation sets can only be created on " |
| "Mac OS X.\n", stderr); |
| return; |
| #endif /* __APPLE__ */ |
| } |
| else |
| out = stdout; |
| |
| /* |
| * Standard header... |
| */ |
| |
| write_html_head(out, section, title, cssfile); |
| |
| fputs("<div class='body'>\n", out); |
| |
| /* |
| * Header... |
| */ |
| |
| if (headerfile) |
| { |
| /* |
| * Use custom header... |
| */ |
| |
| write_file(out, headerfile); |
| } |
| else |
| { |
| /* |
| * Use standard header... |
| */ |
| |
| fputs("<h1 class=\"title\">", out); |
| write_string(out, title, OUTPUT_HTML); |
| fputs("</h1>\n", out); |
| } |
| |
| /* |
| * Table of contents... |
| */ |
| |
| if (!framefile) |
| write_toc(out, doc, introfile, NULL, 0); |
| |
| /* |
| * Intro... |
| */ |
| |
| if (introfile) |
| write_file(out, introfile); |
| |
| /* |
| * List of classes... |
| */ |
| |
| if ((scut = find_public(doc, doc, "class")) != NULL) |
| { |
| fputs("<h2 class=\"title\"><a name=\"CLASSES\">Classes</a></h2>\n", out); |
| |
| while (scut) |
| { |
| write_scu(out, doc, scut); |
| |
| scut = find_public(scut, doc, "class"); |
| } |
| } |
| |
| /* |
| * List of functions... |
| */ |
| |
| if ((function = find_public(doc, doc, "function")) != NULL) |
| { |
| fputs("<h2 class=\"title\"><a name=\"FUNCTIONS\">Functions</a></h2>\n", out); |
| |
| while (function) |
| { |
| write_function(out, doc, function, 3); |
| |
| function = find_public(function, doc, "function"); |
| } |
| } |
| |
| /* |
| * List of types... |
| */ |
| |
| if ((scut = find_public(doc, doc, "typedef")) != NULL) |
| { |
| fputs("<h2 class=\"title\"><a name=\"TYPES\">Data Types</a></h2>\n", out); |
| |
| while (scut) |
| { |
| name = mxmlElementGetAttr(scut, "name"); |
| description = mxmlFindElement(scut, scut, "description", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| fprintf(out, "<h3 class=\"typedef\">%s<a name=\"%s\">%s</a></h3>\n", |
| get_comment_info(description), name, name); |
| |
| if (description) |
| write_description(out, description, "p", 1); |
| |
| fputs("<p class=\"code\">\n" |
| "typedef ", out); |
| |
| type = mxmlFindElement(scut, scut, "type", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| |
| for (type = type->child; type; type = type->next) |
| if (!strcmp(type->value.text.string, "(")) |
| break; |
| else |
| { |
| if (type->value.text.whitespace) |
| putc(' ', out); |
| |
| if (mxmlFindElement(doc, doc, "class", "name", |
| type->value.text.string, MXML_DESCEND) || |
| mxmlFindElement(doc, doc, "enumeration", "name", |
| type->value.text.string, MXML_DESCEND) || |
| mxmlFindElement(doc, doc, "struct", "name", |
| type->value.text.string, MXML_DESCEND) || |
| mxmlFindElement(doc, doc, "typedef", "name", |
| type->value.text.string, MXML_DESCEND) || |
| mxmlFindElement(doc, doc, "union", "name", |
| type->value.text.string, MXML_DESCEND)) |
| { |
| fputs("<a href=\"#", out); |
| write_string(out, type->value.text.string, OUTPUT_HTML); |
| fputs("\">", out); |
| write_string(out, type->value.text.string, OUTPUT_HTML); |
| fputs("</a>", out); |
| } |
| else |
| write_string(out, type->value.text.string, OUTPUT_HTML); |
| } |
| |
| if (type) |
| { |
| /* |
| * Output function type... |
| */ |
| |
| if (type->prev && type->prev->value.text.string[0] != '*') |
| putc(' ', out); |
| |
| fprintf(out, "(*%s", name); |
| |
| for (type = type->next->next; type; type = type->next) |
| { |
| if (type->value.text.whitespace) |
| putc(' ', out); |
| |
| if (mxmlFindElement(doc, doc, "class", "name", |
| type->value.text.string, MXML_DESCEND) || |
| mxmlFindElement(doc, doc, "enumeration", "name", |
| type->value.text.string, MXML_DESCEND) || |
| mxmlFindElement(doc, doc, "struct", "name", |
| type->value.text.string, MXML_DESCEND) || |
| mxmlFindElement(doc, doc, "typedef", "name", |
| type->value.text.string, MXML_DESCEND) || |
| mxmlFindElement(doc, doc, "union", "name", |
| type->value.text.string, MXML_DESCEND)) |
| { |
| fputs("<a href=\"#", out); |
| write_string(out, type->value.text.string, OUTPUT_HTML); |
| fputs("\">", out); |
| write_string(out, type->value.text.string, OUTPUT_HTML); |
| fputs("</a>", out); |
| } |
| else |
| write_string(out, type->value.text.string, OUTPUT_HTML); |
| } |
| |
| fputs(";\n", out); |
| } |
| else |
| { |
| type = mxmlFindElement(scut, scut, "type", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| if (type->last_child->value.text.string[0] != '*') |
| putc(' ', out); |
| |
| fprintf(out, "%s;\n", name); |
| } |
| |
| fputs("</p>\n", out); |
| |
| scut = find_public(scut, doc, "typedef"); |
| } |
| } |
| |
| /* |
| * List of structures... |
| */ |
| |
| if ((scut = find_public(doc, doc, "struct")) != NULL) |
| { |
| fputs("<h2 class=\"title\"><a name=\"STRUCTURES\">Structures</a></h2>\n", |
| out); |
| |
| while (scut) |
| { |
| write_scu(out, doc, scut); |
| |
| scut = find_public(scut, doc, "struct"); |
| } |
| } |
| |
| /* |
| * List of unions... |
| */ |
| |
| if ((scut = find_public(doc, doc, "union")) != NULL) |
| { |
| fputs("<h2 class=\"title\"><a name=\"UNIONS\">Unions</a></h2>\n", out); |
| |
| while (scut) |
| { |
| write_scu(out, doc, scut); |
| |
| scut = find_public(scut, doc, "union"); |
| } |
| } |
| |
| /* |
| * Variables... |
| */ |
| |
| if ((arg = find_public(doc, doc, "variable")) != NULL) |
| { |
| fputs("<h2 class=\"title\"><a name=\"VARIABLES\">Variables</a></h2>\n", |
| out); |
| |
| while (arg) |
| { |
| name = mxmlElementGetAttr(arg, "name"); |
| description = mxmlFindElement(arg, arg, "description", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| fprintf(out, "<h3 class=\"variable\">%s<a name=\"%s\">%s</a></h3>\n", |
| get_comment_info(description), name, name); |
| |
| if (description) |
| write_description(out, description, "p", 1); |
| |
| fputs("<p class=\"code\">", out); |
| |
| write_element(out, doc, mxmlFindElement(arg, arg, "type", NULL, |
| NULL, MXML_DESCEND_FIRST), |
| OUTPUT_HTML); |
| fputs(mxmlElementGetAttr(arg, "name"), out); |
| if ((defval = mxmlElementGetAttr(arg, "default")) != NULL) |
| fprintf(out, " %s", defval); |
| fputs(";</p>\n", out); |
| |
| arg = find_public(arg, doc, "variable"); |
| } |
| } |
| |
| /* |
| * List of enumerations... |
| */ |
| |
| if ((scut = find_public(doc, doc, "enumeration")) != NULL) |
| { |
| fputs("<h2 class=\"title\"><a name=\"ENUMERATIONS\">Constants</a></h2>\n", |
| out); |
| |
| while (scut) |
| { |
| name = mxmlElementGetAttr(scut, "name"); |
| description = mxmlFindElement(scut, scut, "description", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| fprintf(out, "<h3 class=\"enumeration\">%s<a name=\"%s\">%s</a></h3>\n", |
| get_comment_info(description), name, name); |
| |
| if (description) |
| write_description(out, description, "p", 1); |
| |
| fputs("<h4 class=\"constants\">Constants</h4>\n" |
| "<dl>\n", out); |
| |
| for (arg = mxmlFindElement(scut, scut, "constant", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| arg; |
| arg = mxmlFindElement(arg, scut, "constant", NULL, NULL, |
| MXML_NO_DESCEND)) |
| { |
| description = mxmlFindElement(arg, arg, "description", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| fprintf(out, "<dt>%s %s</dt>\n", |
| mxmlElementGetAttr(arg, "name"), get_comment_info(description)); |
| |
| write_description(out, description, "dd", 1); |
| write_description(out, description, "dd", 0); |
| } |
| |
| fputs("</dl>\n", out); |
| |
| scut = find_public(scut, doc, "enumeration"); |
| } |
| } |
| |
| /* |
| * Footer... |
| */ |
| |
| if (footerfile) |
| { |
| /* |
| * Use custom footer... |
| */ |
| |
| write_file(out, footerfile); |
| } |
| |
| fputs("</div>\n" |
| "</body>\n" |
| "</html>\n", out); |
| |
| /* |
| * Close output file as needed... |
| */ |
| |
| if (out != stdout) |
| fclose(out); |
| |
| #ifdef __APPLE__ |
| /* |
| * When generating document sets, run the docsetutil program to index it... |
| */ |
| |
| if (docset) |
| { |
| int argc = 0; /* Argument count */ |
| const char *args[5]; /* Argument array */ |
| pid_t pid; /* Process ID */ |
| int status; /* Exit status */ |
| |
| |
| args[argc++] = "/usr/bin/xcrun"; |
| args[argc++] = "docsetutil"; |
| args[argc++] = "index"; |
| args[argc++] = docset; |
| args[argc ] = NULL; |
| |
| if (posix_spawn(&pid, args[0], NULL, NULL, (char **)args, environ)) |
| { |
| fprintf(stderr, "mxmldoc: Unable to index documentation set \"%s\": %s\n", |
| docset, strerror(errno)); |
| } |
| else |
| { |
| while (wait(&status) != pid); |
| |
| if (status) |
| { |
| if (WIFEXITED(status)) |
| fprintf(stderr, "mxmldoc: docsetutil exited with status %d\n", |
| WEXITSTATUS(status)); |
| else |
| fprintf(stderr, "mxmldoc: docsetutil crashed with signal %d\n", |
| WTERMSIG(status)); |
| } |
| else |
| { |
| /* |
| * Remove unneeded temporary XML files... |
| */ |
| |
| snprintf(filename, sizeof(filename), "%s/Contents/Resources/Nodes.xml", |
| docset); |
| unlink(filename); |
| |
| snprintf(filename, sizeof(filename), "%s/Contents/Resources/Tokens.xml", |
| docset); |
| unlink(filename); |
| } |
| } |
| } |
| #endif /* __APPLE__ */ |
| } |
| |
| |
| /* |
| * 'write_html_head()' - Write the standard HTML header. |
| */ |
| |
| static void |
| write_html_head(FILE *out, /* I - Output file */ |
| const char *section, /* I - Section */ |
| const char *title, /* I - Title */ |
| const char *cssfile) /* I - Stylesheet */ |
| { |
| fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" " |
| "\"http://www.w3.org/TR/html4/loose.dtd\">\n" |
| "<html>\n", out); |
| |
| if (section) |
| fprintf(out, "<!-- SECTION: %s -->\n", section); |
| |
| fputs("<head>\n" |
| "\t<title>", out); |
| write_string(out, title, OUTPUT_HTML); |
| fputs("\t</title>\n", out); |
| |
| if (section) |
| fprintf(out, "\t<meta name=\"keywords\" content=\"%s\">\n", section); |
| |
| fputs("\t<meta http-equiv=\"Content-Type\" " |
| "content=\"text/html;charset=utf-8\">\n" |
| "\t<meta name=\"creator\" content=\"" MXML_VERSION "\">\n" |
| "<style type=\"text/css\"><!--\n", out); |
| |
| if (cssfile) |
| { |
| /* |
| * Use custom stylesheet file... |
| */ |
| |
| write_file(out, cssfile); |
| } |
| else |
| { |
| /* |
| * Use standard stylesheet... |
| */ |
| |
| fputs("body, p, h1, h2, h3, h4 {\n" |
| " font-family: \"lucida grande\", geneva, helvetica, arial, " |
| "sans-serif;\n" |
| "}\n" |
| "div.body h1 {\n" |
| " font-size: 250%;\n" |
| " font-weight: bold;\n" |
| " margin: 0;\n" |
| "}\n" |
| "div.body h2 {\n" |
| " font-size: 250%;\n" |
| " margin-top: 1.5em;\n" |
| "}\n" |
| "div.body h3 {\n" |
| " font-size: 150%;\n" |
| " margin-bottom: 0.5em;\n" |
| " margin-top: 1.5em;\n" |
| "}\n" |
| "div.body h4 {\n" |
| " font-size: 110%;\n" |
| " margin-bottom: 0.5em;\n" |
| " margin-top: 1.5em;\n" |
| "}\n" |
| "div.body h5 {\n" |
| " font-size: 100%;\n" |
| " margin-bottom: 0.5em;\n" |
| " margin-top: 1.5em;\n" |
| "}\n" |
| "div.contents {\n" |
| " background: #e8e8e8;\n" |
| " border: solid thin black;\n" |
| " padding: 10px;\n" |
| "}\n" |
| "div.contents h1 {\n" |
| " font-size: 110%;\n" |
| "}\n" |
| "div.contents h2 {\n" |
| " font-size: 100%;\n" |
| "}\n" |
| "div.contents ul.contents {\n" |
| " font-size: 80%;\n" |
| "}\n" |
| ".class {\n" |
| " border-bottom: solid 2px gray;\n" |
| "}\n" |
| ".constants {\n" |
| "}\n" |
| ".description {\n" |
| " margin-top: 0.5em;\n" |
| "}\n" |
| ".discussion {\n" |
| "}\n" |
| ".enumeration {\n" |
| " border-bottom: solid 2px gray;\n" |
| "}\n" |
| ".function {\n" |
| " border-bottom: solid 2px gray;\n" |
| " margin-bottom: 0;\n" |
| "}\n" |
| ".members {\n" |
| "}\n" |
| ".method {\n" |
| "}\n" |
| ".parameters {\n" |
| "}\n" |
| ".returnvalue {\n" |
| "}\n" |
| ".struct {\n" |
| " border-bottom: solid 2px gray;\n" |
| "}\n" |
| ".typedef {\n" |
| " border-bottom: solid 2px gray;\n" |
| "}\n" |
| ".union {\n" |
| " border-bottom: solid 2px gray;\n" |
| "}\n" |
| ".variable {\n" |
| "}\n" |
| "code, p.code, pre, ul.code li {\n" |
| " font-family: monaco, courier, monospace;\n" |
| " font-size: 90%;\n" |
| "}\n" |
| "a:link, a:visited {\n" |
| " text-decoration: none;\n" |
| "}\n" |
| "span.info {\n" |
| " background: black;\n" |
| " border: solid thin black;\n" |
| " color: white;\n" |
| " font-size: 80%;\n" |
| " font-style: italic;\n" |
| " font-weight: bold;\n" |
| " white-space: nowrap;\n" |
| "}\n" |
| "h3 span.info, h4 span.info {\n" |
| " float: right;\n" |
| " font-size: 100%;\n" |
| "}\n" |
| "ul.code, ul.contents, ul.subcontents {\n" |
| " list-style-type: none;\n" |
| " margin: 0;\n" |
| " padding-left: 0;\n" |
| "}\n" |
| "ul.code li {\n" |
| " margin: 0;\n" |
| "}\n" |
| "ul.contents > li {\n" |
| " margin-top: 1em;\n" |
| "}\n" |
| "ul.contents li ul.code, ul.contents li ul.subcontents {\n" |
| " padding-left: 2em;\n" |
| "}\n" |
| "div.body dl {\n" |
| " margin-top: 0;\n" |
| "}\n" |
| "div.body dt {\n" |
| " font-style: italic;\n" |
| " margin-top: 0;\n" |
| "}\n" |
| "div.body dd {\n" |
| " margin-bottom: 0.5em;\n" |
| "}\n" |
| "h1.title {\n" |
| "}\n" |
| "h2.title {\n" |
| " border-bottom: solid 2px black;\n" |
| "}\n" |
| "h3.title {\n" |
| " border-bottom: solid 2px black;\n" |
| "}\n", out); |
| } |
| |
| fputs("--></style>\n" |
| "</head>\n" |
| "<body>\n", out); |
| } |
| |
| |
| /* |
| * 'write_man()' - Write manpage documentation. |
| */ |
| |
| static void |
| write_man(const char *man_name, /* I - Name of manpage */ |
| const char *section, /* I - Section */ |
| const char *title, /* I - Title */ |
| const char *footerfile, /* I - Footer file */ |
| const char *headerfile, /* I - Header file */ |
| const char *introfile, /* I - Intro file */ |
| mxml_node_t *doc) /* I - XML documentation */ |
| { |
| int i; /* Looping var */ |
| mxml_node_t *function, /* Current function */ |
| *scut, /* Struct/class/union/typedef */ |
| *arg, /* Current argument */ |
| *description, /* Description of function/var */ |
| *type; /* Type for argument */ |
| const char *name, /* Name of function/type */ |
| *cname, /* Class name */ |
| *defval, /* Default value */ |
| *parent; /* Parent class */ |
| int inscope; /* Variable/method scope */ |
| char prefix; /* Prefix character */ |
| time_t curtime; /* Current time */ |
| struct tm *curdate; /* Current date */ |
| char buffer[1024]; /* String buffer */ |
| static const char * const scopes[] = /* Scope strings */ |
| { |
| "private", |
| "protected", |
| "public" |
| }; |
| |
| |
| /* |
| * Standard man page... |
| */ |
| |
| curtime = time(NULL); |
| curdate = localtime(&curtime); |
| strftime(buffer, sizeof(buffer), "%x", curdate); |
| |
| printf(".TH %s %s \"%s\" \"%s\" \"%s\"\n", man_name, section ? section : "3", |
| title ? title : "", buffer, title ? title : ""); |
| |
| /* |
| * Header... |
| */ |
| |
| if (headerfile) |
| { |
| /* |
| * Use custom header... |
| */ |
| |
| write_file(stdout, headerfile); |
| } |
| else |
| { |
| /* |
| * Use standard header... |
| */ |
| |
| puts(".SH NAME"); |
| printf("%s \\- %s\n", man_name, title ? title : man_name); |
| } |
| |
| /* |
| * Intro... |
| */ |
| |
| if (introfile) |
| write_file(stdout, introfile); |
| |
| /* |
| * List of classes... |
| */ |
| |
| if (find_public(doc, doc, "class")) |
| { |
| puts(".SH CLASSES"); |
| |
| for (scut = find_public(doc, doc, "class"); |
| scut; |
| scut = find_public(scut, doc, "class")) |
| { |
| cname = mxmlElementGetAttr(scut, "name"); |
| description = mxmlFindElement(scut, scut, "description", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| printf(".SS %s\n", cname); |
| |
| write_description(stdout, description, NULL, 1); |
| |
| printf(".PP\n" |
| ".nf\n" |
| "class %s", cname); |
| if ((parent = mxmlElementGetAttr(scut, "parent")) != NULL) |
| printf(" %s", parent); |
| puts("\n{"); |
| |
| for (i = 0; i < 3; i ++) |
| { |
| inscope = 0; |
| |
| for (arg = mxmlFindElement(scut, scut, "variable", "scope", scopes[i], |
| MXML_DESCEND_FIRST); |
| arg; |
| arg = mxmlFindElement(arg, scut, "variable", "scope", scopes[i], |
| MXML_NO_DESCEND)) |
| { |
| if (!inscope) |
| { |
| inscope = 1; |
| printf(" %s:\n", scopes[i]); |
| } |
| |
| printf(" "); |
| write_element(stdout, doc, mxmlFindElement(arg, arg, "type", NULL, |
| NULL, MXML_DESCEND_FIRST), |
| OUTPUT_MAN); |
| printf("%s;\n", mxmlElementGetAttr(arg, "name")); |
| } |
| |
| for (function = mxmlFindElement(scut, scut, "function", "scope", |
| scopes[i], MXML_DESCEND_FIRST); |
| function; |
| function = mxmlFindElement(function, scut, "function", "scope", |
| scopes[i], MXML_NO_DESCEND)) |
| { |
| if (!inscope) |
| { |
| inscope = 1; |
| printf(" %s:\n", scopes[i]); |
| } |
| |
| name = mxmlElementGetAttr(function, "name"); |
| |
| printf(" "); |
| |
| arg = mxmlFindElement(function, function, "returnvalue", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| |
| if (arg) |
| write_element(stdout, doc, mxmlFindElement(arg, arg, "type", NULL, |
| NULL, MXML_DESCEND_FIRST), |
| OUTPUT_MAN); |
| else if (strcmp(cname, name) && strcmp(cname, name + 1)) |
| fputs("void ", stdout); |
| |
| printf("%s", name); |
| |
| for (arg = mxmlFindElement(function, function, "argument", NULL, NULL, |
| MXML_DESCEND_FIRST), prefix = '('; |
| arg; |
| arg = mxmlFindElement(arg, function, "argument", NULL, NULL, |
| MXML_NO_DESCEND), prefix = ',') |
| { |
| type = mxmlFindElement(arg, arg, "type", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| |
| putchar(prefix); |
| if (prefix == ',') |
| putchar(' '); |
| |
| if (type->child) |
| write_element(stdout, doc, type, OUTPUT_MAN); |
| fputs(mxmlElementGetAttr(arg, "name"), stdout); |
| if ((defval = mxmlElementGetAttr(arg, "default")) != NULL) |
| printf(" %s", defval); |
| } |
| |
| if (prefix == '(') |
| puts("(void);"); |
| else |
| puts(");"); |
| } |
| } |
| |
| puts("};\n" |
| ".fi"); |
| |
| write_description(stdout, description, NULL, 0); |
| } |
| } |
| |
| /* |
| * List of enumerations... |
| */ |
| |
| if (find_public(doc, doc, "enumeration")) |
| { |
| puts(".SH ENUMERATIONS"); |
| |
| for (scut = find_public(doc, doc, "enumeration"); |
| scut; |
| scut = find_public(scut, doc, "enumeration")) |
| { |
| name = mxmlElementGetAttr(scut, "name"); |
| description = mxmlFindElement(scut, scut, "description", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| printf(".SS %s\n", name); |
| |
| write_description(stdout, description, NULL, 1); |
| write_description(stdout, description, NULL, 0); |
| |
| for (arg = mxmlFindElement(scut, scut, "constant", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| arg; |
| arg = mxmlFindElement(arg, scut, "constant", NULL, NULL, |
| MXML_NO_DESCEND)) |
| { |
| description = mxmlFindElement(arg, arg, "description", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| printf(".TP 5\n%s\n.br\n", mxmlElementGetAttr(arg, "name")); |
| write_description(stdout, description, NULL, 1); |
| } |
| } |
| } |
| |
| /* |
| * List of functions... |
| */ |
| |
| if (find_public(doc, doc, "function")) |
| { |
| puts(".SH FUNCTIONS"); |
| |
| for (function = find_public(doc, doc, "function"); |
| function; |
| function = find_public(function, doc, "function")) |
| { |
| name = mxmlElementGetAttr(function, "name"); |
| description = mxmlFindElement(function, function, "description", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| printf(".SS %s\n", name); |
| |
| write_description(stdout, description, NULL, 1); |
| |
| puts(".PP\n" |
| ".nf"); |
| |
| arg = mxmlFindElement(function, function, "returnvalue", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| |
| if (arg) |
| write_element(stdout, doc, mxmlFindElement(arg, arg, "type", NULL, |
| NULL, MXML_DESCEND_FIRST), |
| OUTPUT_MAN); |
| else |
| fputs("void", stdout); |
| |
| printf(" %s ", name); |
| for (arg = mxmlFindElement(function, function, "argument", NULL, NULL, |
| MXML_DESCEND_FIRST), prefix = '('; |
| arg; |
| arg = mxmlFindElement(arg, function, "argument", NULL, NULL, |
| MXML_NO_DESCEND), prefix = ',') |
| { |
| type = mxmlFindElement(arg, arg, "type", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| |
| printf("%c\n ", prefix); |
| if (type->child) |
| write_element(stdout, doc, type, OUTPUT_MAN); |
| fputs(mxmlElementGetAttr(arg, "name"), stdout); |
| if ((defval = mxmlElementGetAttr(arg, "default")) != NULL) |
| printf(" %s", defval); |
| } |
| |
| if (prefix == '(') |
| puts("(void);"); |
| else |
| puts("\n);"); |
| |
| puts(".fi"); |
| |
| write_description(stdout, description, NULL, 0); |
| } |
| } |
| |
| /* |
| * List of structures... |
| */ |
| |
| if (find_public(doc, doc, "struct")) |
| { |
| puts(".SH STRUCTURES"); |
| |
| for (scut = find_public(doc, doc, "struct"); |
| scut; |
| scut = find_public(scut, doc, "struct")) |
| { |
| cname = mxmlElementGetAttr(scut, "name"); |
| description = mxmlFindElement(scut, scut, "description", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| printf(".SS %s\n", cname); |
| |
| write_description(stdout, description, NULL, 1); |
| |
| printf(".PP\n" |
| ".nf\n" |
| "struct %s\n{\n", cname); |
| for (arg = mxmlFindElement(scut, scut, "variable", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| arg; |
| arg = mxmlFindElement(arg, scut, "variable", NULL, NULL, |
| MXML_NO_DESCEND)) |
| { |
| printf(" "); |
| write_element(stdout, doc, mxmlFindElement(arg, arg, "type", NULL, |
| NULL, MXML_DESCEND_FIRST), |
| OUTPUT_MAN); |
| printf("%s;\n", mxmlElementGetAttr(arg, "name")); |
| } |
| |
| for (function = mxmlFindElement(scut, scut, "function", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| function; |
| function = mxmlFindElement(function, scut, "function", NULL, NULL, |
| MXML_NO_DESCEND)) |
| { |
| name = mxmlElementGetAttr(function, "name"); |
| |
| printf(" "); |
| |
| arg = mxmlFindElement(function, function, "returnvalue", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| |
| if (arg) |
| write_element(stdout, doc, mxmlFindElement(arg, arg, "type", NULL, |
| NULL, MXML_DESCEND_FIRST), |
| OUTPUT_MAN); |
| else if (strcmp(cname, name) && strcmp(cname, name + 1)) |
| fputs("void ", stdout); |
| |
| fputs(name, stdout); |
| |
| for (arg = mxmlFindElement(function, function, "argument", NULL, NULL, |
| MXML_DESCEND_FIRST), prefix = '('; |
| arg; |
| arg = mxmlFindElement(arg, function, "argument", NULL, NULL, |
| MXML_NO_DESCEND), prefix = ',') |
| { |
| type = mxmlFindElement(arg, arg, "type", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| |
| putchar(prefix); |
| if (prefix == ',') |
| putchar(' '); |
| |
| if (type->child) |
| write_element(stdout, doc, type, OUTPUT_MAN); |
| fputs(mxmlElementGetAttr(arg, "name"), stdout); |
| if ((defval = mxmlElementGetAttr(arg, "default")) != NULL) |
| printf(" %s", defval); |
| } |
| |
| if (prefix == '(') |
| puts("(void);"); |
| else |
| puts(");"); |
| } |
| |
| puts("};\n" |
| ".fi"); |
| |
| write_description(stdout, description, NULL, 0); |
| } |
| } |
| |
| /* |
| * List of types... |
| */ |
| |
| if (find_public(doc, doc, "typedef")) |
| { |
| puts(".SH TYPES"); |
| |
| for (scut = find_public(doc, doc, "typedef"); |
| scut; |
| scut = find_public(scut, doc, "typedef")) |
| { |
| name = mxmlElementGetAttr(scut, "name"); |
| description = mxmlFindElement(scut, scut, "description", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| printf(".SS %s\n", name); |
| |
| write_description(stdout, description, NULL, 1); |
| |
| fputs(".PP\n" |
| ".nf\n" |
| "typedef ", stdout); |
| |
| type = mxmlFindElement(scut, scut, "type", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| |
| for (type = type->child; type; type = type->next) |
| if (!strcmp(type->value.text.string, "(")) |
| break; |
| else |
| { |
| if (type->value.text.whitespace) |
| putchar(' '); |
| |
| write_string(stdout, type->value.text.string, OUTPUT_MAN); |
| } |
| |
| if (type) |
| { |
| /* |
| * Output function type... |
| */ |
| |
| printf(" (*%s", name); |
| |
| for (type = type->next->next; type; type = type->next) |
| { |
| if (type->value.text.whitespace) |
| putchar(' '); |
| |
| write_string(stdout, type->value.text.string, OUTPUT_MAN); |
| } |
| |
| puts(";"); |
| } |
| else |
| printf(" %s;\n", name); |
| |
| puts(".fi"); |
| |
| write_description(stdout, description, NULL, 0); |
| } |
| } |
| |
| /* |
| * List of unions... |
| */ |
| |
| if (find_public(doc, doc, "union")) |
| { |
| puts(".SH UNIONS"); |
| |
| for (scut = find_public(doc, doc, "union"); |
| scut; |
| scut = find_public(scut, doc, "union")) |
| { |
| name = mxmlElementGetAttr(scut, "name"); |
| description = mxmlFindElement(scut, scut, "description", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| printf(".SS %s\n", name); |
| |
| write_description(stdout, description, NULL, 1); |
| |
| printf(".PP\n" |
| ".nf\n" |
| "union %s\n{\n", name); |
| for (arg = mxmlFindElement(scut, scut, "variable", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| arg; |
| arg = mxmlFindElement(arg, scut, "variable", NULL, NULL, |
| MXML_NO_DESCEND)) |
| { |
| printf(" "); |
| write_element(stdout, doc, mxmlFindElement(arg, arg, "type", NULL, |
| NULL, MXML_DESCEND_FIRST), |
| OUTPUT_MAN); |
| printf("%s;\n", mxmlElementGetAttr(arg, "name")); |
| } |
| |
| puts("};\n" |
| ".fi"); |
| |
| write_description(stdout, description, NULL, 0); |
| } |
| } |
| |
| /* |
| * Variables... |
| */ |
| |
| if (find_public(doc, doc, "variable")) |
| { |
| puts(".SH VARIABLES"); |
| |
| for (arg = find_public(doc, doc, "variable"); |
| arg; |
| arg = find_public(arg, doc, "variable")) |
| { |
| name = mxmlElementGetAttr(arg, "name"); |
| description = mxmlFindElement(arg, arg, "description", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| printf(".SS %s\n", name); |
| |
| write_description(stdout, description, NULL, 1); |
| |
| puts(".PP\n" |
| ".nf"); |
| |
| write_element(stdout, doc, mxmlFindElement(arg, arg, "type", NULL, |
| NULL, MXML_DESCEND_FIRST), |
| OUTPUT_MAN); |
| fputs(mxmlElementGetAttr(arg, "name"), stdout); |
| if ((defval = mxmlElementGetAttr(arg, "default")) != NULL) |
| printf(" %s", defval); |
| puts(";\n" |
| ".fi"); |
| |
| write_description(stdout, description, NULL, 0); |
| } |
| } |
| |
| if (footerfile) |
| { |
| /* |
| * Use custom footer... |
| */ |
| |
| write_file(stdout, footerfile); |
| } |
| } |
| |
| |
| /* |
| * 'write_scu()' - Write a structure, class, or union. |
| */ |
| |
| static void |
| write_scu(FILE *out, /* I - Output file */ |
| mxml_node_t *doc, /* I - Document */ |
| mxml_node_t *scut) /* I - Structure, class, or union */ |
| { |
| int i; /* Looping var */ |
| mxml_node_t *function, /* Current function */ |
| *arg, /* Current argument */ |
| *description, /* Description of function/var */ |
| *type; /* Type for argument */ |
| const char *name, /* Name of function/type */ |
| *cname, /* Class name */ |
| *defval, /* Default value */ |
| *parent, /* Parent class */ |
| *scope; /* Scope for variable/function */ |
| int inscope, /* Variable/method scope */ |
| maxscope; /* Maximum scope */ |
| char prefix; /* Prefix character */ |
| static const char * const scopes[] = /* Scope strings */ |
| { |
| "private", |
| "protected", |
| "public" |
| }; |
| |
| |
| cname = mxmlElementGetAttr(scut, "name"); |
| description = mxmlFindElement(scut, scut, "description", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| |
| fprintf(out, "<h3 class=\"%s\">%s<a name=\"%s\">%s</a></h3>\n", |
| scut->value.element.name, get_comment_info(description), cname, |
| cname); |
| |
| if (description) |
| write_description(out, description, "p", 1); |
| |
| fprintf(out, "<p class=\"code\">%s %s", scut->value.element.name, cname); |
| if ((parent = mxmlElementGetAttr(scut, "parent")) != NULL) |
| fprintf(out, " %s", parent); |
| fputs(" {<br>\n", out); |
| |
| maxscope = !strcmp(scut->value.element.name, "class") ? 3 : 1; |
| |
| for (i = 0; i < maxscope; i ++) |
| { |
| inscope = maxscope == 1; |
| |
| for (arg = mxmlFindElement(scut, scut, "variable", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| arg; |
| arg = mxmlFindElement(arg, scut, "variable", NULL, NULL, |
| MXML_NO_DESCEND)) |
| { |
| if (maxscope > 1 && |
| ((scope = mxmlElementGetAttr(arg, "scope")) == NULL || |
| strcmp(scope, scopes[i]))) |
| continue; |
| |
| if (!inscope) |
| { |
| inscope = 1; |
| fprintf(out, " %s:<br>\n", scopes[i]); |
| } |
| |
| fputs(" ", out); |
| write_element(out, doc, mxmlFindElement(arg, arg, "type", NULL, |
| NULL, MXML_DESCEND_FIRST), |
| OUTPUT_HTML); |
| fprintf(out, "%s;<br>\n", mxmlElementGetAttr(arg, "name")); |
| } |
| |
| for (function = mxmlFindElement(scut, scut, "function", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| function; |
| function = mxmlFindElement(function, scut, "function", NULL, NULL, |
| MXML_NO_DESCEND)) |
| { |
| if (maxscope > 1 && |
| ((scope = mxmlElementGetAttr(arg, "scope")) == NULL || |
| strcmp(scope, scopes[i]))) |
| continue; |
| |
| if (!inscope) |
| { |
| inscope = 1; |
| fprintf(out, " %s:<br>\n", scopes[i]); |
| } |
| |
| name = mxmlElementGetAttr(function, "name"); |
| |
| fputs(" ", out); |
| |
| arg = mxmlFindElement(function, function, "returnvalue", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| |
| if (arg) |
| write_element(out, doc, mxmlFindElement(arg, arg, "type", NULL, |
| NULL, MXML_DESCEND_FIRST), |
| OUTPUT_HTML); |
| else if (strcmp(cname, name) && strcmp(cname, name + 1)) |
| fputs("void ", out); |
| |
| fprintf(out, "<a href=\"#%s.%s\">%s</a>", cname, name, name); |
| |
| for (arg = mxmlFindElement(function, function, "argument", NULL, NULL, |
| MXML_DESCEND_FIRST), prefix = '('; |
| arg; |
| arg = mxmlFindElement(arg, function, "argument", NULL, NULL, |
| MXML_NO_DESCEND), prefix = ',') |
| { |
| type = mxmlFindElement(arg, arg, "type", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| |
| putc(prefix, out); |
| if (prefix == ',') |
| putc(' ', out); |
| |
| if (type->child) |
| write_element(out, doc, type, OUTPUT_HTML); |
| |
| fputs(mxmlElementGetAttr(arg, "name"), out); |
| if ((defval = mxmlElementGetAttr(arg, "default")) != NULL) |
| fprintf(out, " %s", defval); |
| } |
| |
| if (prefix == '(') |
| fputs("(void);<br>\n", out); |
| else |
| fputs(");<br>\n", out); |
| } |
| } |
| |
| fputs("};</p>\n" |
| "<h4 class=\"members\">Members</h4>\n" |
| "<dl>\n", out); |
| |
| for (arg = mxmlFindElement(scut, scut, "variable", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| arg; |
| arg = mxmlFindElement(arg, scut, "variable", NULL, NULL, |
| MXML_NO_DESCEND)) |
| { |
| description = mxmlFindElement(arg, arg, "description", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| |
| fprintf(out, "<dt>%s %s</dt>\n", |
| mxmlElementGetAttr(arg, "name"), get_comment_info(description)); |
| |
| write_description(out, description, "dd", 1); |
| write_description(out, description, "dd", 0); |
| } |
| |
| fputs("</dl>\n", out); |
| |
| for (function = mxmlFindElement(scut, scut, "function", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| function; |
| function = mxmlFindElement(function, scut, "function", NULL, NULL, |
| MXML_NO_DESCEND)) |
| { |
| write_function(out, doc, function, 4); |
| } |
| } |
| |
| |
| /* |
| * 'write_string()' - Write a string, quoting HTML special chars as needed. |
| */ |
| |
| static void |
| write_string(FILE *out, /* I - Output file */ |
| const char *s, /* I - String to write */ |
| int mode) /* I - Output mode */ |
| { |
| switch (mode) |
| { |
| case OUTPUT_HTML : |
| case OUTPUT_XML : |
| while (*s) |
| { |
| if (*s == '&') |
| fputs("&", out); |
| else if (*s == '<') |
| fputs("<", out); |
| else if (*s == '>') |
| fputs(">", out); |
| else if (*s == '\"') |
| fputs(""", out); |
| else if (*s & 128) |
| { |
| /* |
| * Convert UTF-8 to Unicode constant... |
| */ |
| |
| int ch; /* Unicode character */ |
| |
| |
| ch = *s & 255; |
| |
| if ((ch & 0xe0) == 0xc0) |
| { |
| ch = ((ch & 0x1f) << 6) | (s[1] & 0x3f); |
| s ++; |
| } |
| else if ((ch & 0xf0) == 0xe0) |
| { |
| ch = ((((ch * 0x0f) << 6) | (s[1] & 0x3f)) << 6) | (s[2] & 0x3f); |
| s += 2; |
| } |
| |
| if (ch == 0xa0) |
| { |
| /* |
| * Handle non-breaking space as-is... |
| */ |
| |
| fputs(" ", out); |
| } |
| else |
| fprintf(out, "&#x%x;", ch); |
| } |
| else |
| putc(*s, out); |
| |
| s ++; |
| } |
| break; |
| |
| case OUTPUT_MAN : |
| while (*s) |
| { |
| if (*s == '\\' || *s == '-') |
| putc('\\', out); |
| |
| putc(*s++, out); |
| } |
| break; |
| } |
| } |
| |
| |
| /* |
| * 'write_toc()' - Write a table-of-contents. |
| */ |
| |
| static void |
| write_toc(FILE *out, /* I - Output file */ |
| mxml_node_t *doc, /* I - Document */ |
| const char *introfile, /* I - Introduction file */ |
| const char *target, /* I - Target name */ |
| int xml) /* I - Write XML nodes? */ |
| { |
| FILE *fp; /* Intro file */ |
| mxml_node_t *function, /* Current function */ |
| *scut, /* Struct/class/union/typedef */ |
| *arg, /* Current argument */ |
| *description; /* Description of function/var */ |
| const char *name, /* Name of function/type */ |
| *targetattr; /* Target attribute, if any */ |
| int xmlid = 1; /* Current XML node ID */ |
| |
| |
| /* |
| * If target is set, it is the frame file that contains the body. |
| * Otherwise, we are creating a single-file... |
| */ |
| |
| if (target) |
| targetattr = " target=\"body\""; |
| else |
| targetattr = ""; |
| |
| /* |
| * The table-of-contents is a nested unordered list. Start by |
| * reading any intro file to see if there are any headings there. |
| */ |
| |
| if (!xml) |
| fputs("<h2 class=\"title\">Contents</h2>\n" |
| "<ul class=\"contents\">\n", out); |
| |
| if (introfile && (fp = fopen(introfile, "r")) != NULL) |
| { |
| char line[8192], /* Line from file */ |
| *ptr, /* Pointer in line */ |
| *end, /* End of line */ |
| *anchor, /* Anchor name */ |
| quote, /* Quote character for value */ |
| level = '2', /* Current heading level */ |
| newlevel; /* New heading level */ |
| int inelement; /* In an element? */ |
| |
| |
| while (fgets(line, sizeof(line), fp)) |
| { |
| /* |
| * See if this line has a heading... |
| */ |
| |
| if ((ptr = strstr(line, "<h")) == NULL && |
| (ptr = strstr(line, "<H")) == NULL) |
| continue; |
| |
| if (ptr[2] != '2' && ptr[2] != '3') |
| continue; |
| |
| newlevel = ptr[2]; |
| |
| /* |
| * Make sure we have the whole heading... |
| */ |
| |
| while (!strstr(line, "</h") && !strstr(line, "</H")) |
| { |
| end = line + strlen(line); |
| |
| if (end == (line + sizeof(line) - 1) || |
| !fgets(end, (int)(sizeof(line) - (end - line)), fp)) |
| break; |
| } |
| |
| /* |
| * Convert newlines and tabs to spaces... |
| */ |
| |
| for (ptr = line; *ptr; ptr ++) |
| if (isspace(*ptr & 255)) |
| *ptr = ' '; |
| |
| /* |
| * Find the anchor and text... |
| */ |
| |
| for (ptr = strchr(line, '<'); ptr; ptr = strchr(ptr + 1, '<')) |
| if (!strncmp(ptr, "<A NAME=", 8) || !strncmp(ptr, "<a name=", 8)) |
| break; |
| |
| if (!ptr) |
| continue; |
| |
| ptr += 8; |
| inelement = 1; |
| |
| if (*ptr == '\'' || *ptr == '\"') |
| { |
| /* |
| * Quoted anchor... |
| */ |
| |
| quote = *ptr++; |
| anchor = ptr; |
| |
| while (*ptr && *ptr != quote) |
| ptr ++; |
| |
| if (!*ptr) |
| continue; |
| |
| *ptr++ = '\0'; |
| } |
| else |
| { |
| /* |
| * Non-quoted anchor... |
| */ |
| |
| anchor = ptr; |
| |
| while (*ptr && *ptr != '>' && !isspace(*ptr & 255)) |
| ptr ++; |
| |
| if (!*ptr) |
| continue; |
| |
| if (*ptr == '>') |
| inelement = 0; |
| |
| *ptr++ = '\0'; |
| } |
| |
| /* |
| * Write text until we see "</A>"... |
| */ |
| |
| if (xml) |
| { |
| if (newlevel < level) |
| fputs("</Node>\n" |
| "</Subnodes></Node>\n", out); |
| else if (newlevel > level && newlevel == '3') |
| fputs("<Subnodes>\n", out); |
| else if (xmlid > 1) |
| fputs("</Node>\n", out); |
| |
| level = newlevel; |
| |
| fprintf(out, "<Node id=\"%d\">\n" |
| "<Path>Documentation/index.html</Path>\n" |
| "<Anchor>%s</Anchor>\n" |
| "<Name>", xmlid ++, anchor); |
| |
| quote = 0; |
| |
| while (*ptr) |
| { |
| if (inelement) |
| { |
| if (*ptr == quote) |
| quote = 0; |
| else if (*ptr == '>') |
| inelement = 0; |
| else if (*ptr == '\'' || *ptr == '\"') |
| quote = *ptr; |
| } |
| else if (*ptr == '<') |
| { |
| if (!strncmp(ptr, "</A>", 4) || !strncmp(ptr, "</a>", 4)) |
| break; |
| |
| inelement = 1; |
| } |
| else |
| putc(*ptr, out); |
| |
| ptr ++; |
| } |
| |
| fputs("</Name>\n", out); |
| } |
| else |
| { |
| if (newlevel < level) |
| fputs("</li>\n" |
| "</ul></li>\n", out); |
| else if (newlevel > level) |
| fputs("<ul class=\"subcontents\">\n", out); |
| else if (xmlid > 1) |
| fputs("</li>\n", out); |
| |
| level = newlevel; |
| xmlid ++; |
| |
| fprintf(out, "%s<li><a href=\"%s#%s\"%s>", level > '2' ? "\t" : "", |
| target ? target : "", anchor, targetattr); |
| |
| quote = 0; |
| |
| while (*ptr) |
| { |
| if (inelement) |
| { |
| if (*ptr == quote) |
| quote = 0; |
| else if (*ptr == '>') |
| inelement = 0; |
| else if (*ptr == '\'' || *ptr == '\"') |
| quote = *ptr; |
| } |
| else if (*ptr == '<') |
| { |
| if (!strncmp(ptr, "</A>", 4) || !strncmp(ptr, "</a>", 4)) |
| break; |
| |
| inelement = 1; |
| } |
| else |
| putc(*ptr, out); |
| |
| ptr ++; |
| } |
| |
| fputs("</a>", out); |
| } |
| } |
| |
| if (level > '1') |
| { |
| if (xml) |
| { |
| fputs("</Node>\n", out); |
| |
| if (level == '3') |
| fputs("</Subnodes></Node>\n", out); |
| } |
| else |
| { |
| fputs("</li>\n", out); |
| |
| if (level == '3') |
| fputs("</ul></li>\n", out); |
| } |
| } |
| |
| fclose(fp); |
| } |
| |
| /* |
| * Next the classes... |
| */ |
| |
| if ((scut = find_public(doc, doc, "class")) != NULL) |
| { |
| if (xml) |
| fprintf(out, "<Node id=\"%d\">\n" |
| "<Path>Documentation/index.html</Path>\n" |
| "<Anchor>CLASSES</Anchor>\n" |
| "<Name>Classes</Name>\n" |
| "<Subnodes>\n", xmlid ++); |
| else |
| fprintf(out, "<li><a href=\"%s#CLASSES\"%s>Classes</a>" |
| "<ul class=\"code\">\n", |
| target ? target : "", targetattr); |
| |
| while (scut) |
| { |
| name = mxmlElementGetAttr(scut, "name"); |
| description = mxmlFindElement(scut, scut, "description", |
| NULL, NULL, MXML_DESCEND_FIRST); |
| |
| if (xml) |
| { |
| fprintf(out, "<Node id=\"%d\">\n" |
| "<Path>Documentation/index.html</Path>\n" |
| "<Anchor>%s</Anchor>\n" |
| "<Name>%s</Name>\n" |
| "</Node>\n", xmlid ++, name, name); |
| } |
| else |
| { |
| fprintf(out, "\t<li><a href=\"%s#%s\"%s title=\"", |
| target ? target : "", name, targetattr); |
| write_description(out, description, "", 1); |
| fprintf(out, "\">%s</a></li>\n", name); |
| } |
| |
| scut = find_public(scut, doc, "class"); |
| } |
| |
| if (xml) |
| fputs("</Subnodes></Node>\n", out); |
| else |
| fputs("</ul></li>\n", out); |
| } |
| |
| /* |
| * Functions... |
| */ |
| |
| if ((function = find_public(doc, doc, "function")) != NULL) |
| { |
| if (xml) |
| fprintf(out, "<Node id=\"%d\">\n" |
| "<Path>Documentation/index.html</Path>\n" |
| "<Anchor>FUNCTIONS</Anchor>\n" |
| "<Name>Functions</Name>\n" |
| "<Subnodes>\n", xmlid ++); |
| else |
| fprintf(out, "<li><a href=\"%s#FUNCTIONS\"%s>Functions</a>" |
| "<ul class=\"code\">\n", target ? target : "", targetattr); |
| |
| while (function) |
| { |
| name = mxmlElementGetAttr(function, "name"); |
| description = mxmlFindElement(function, function, "description", |
| NULL, NULL, MXML_DESCEND_FIRST); |
| |
| if (xml) |
| { |
| fprintf(out, "<Node id=\"%d\">\n" |
| "<Path>Documentation/index.html</Path>\n" |
| "<Anchor>%s</Anchor>\n" |
| "<Name>%s</Name>\n" |
| "</Node>\n", xmlid ++, name, name); |
| } |
| else |
| { |
| fprintf(out, "\t<li><a href=\"%s#%s\"%s title=\"", |
| target ? target : "", name, targetattr); |
| write_description(out, description, "", 1); |
| fprintf(out, "\">%s</a></li>\n", name); |
| } |
| |
| function = find_public(function, doc, "function"); |
| } |
| |
| if (xml) |
| fputs("</Subnodes></Node>\n", out); |
| else |
| fputs("</ul></li>\n", out); |
| } |
| |
| /* |
| * Data types... |
| */ |
| |
| if ((scut = find_public(doc, doc, "typedef")) != NULL) |
| { |
| if (xml) |
| fprintf(out, "<Node id=\"%d\">\n" |
| "<Path>Documentation/index.html</Path>\n" |
| "<Anchor>TYPES</Anchor>\n" |
| "<Name>Data Types</Name>\n" |
| "<Subnodes>\n", xmlid ++); |
| else |
| fprintf(out, "<li><a href=\"%s#TYPES\"%s>Data Types</a>" |
| "<ul class=\"code\">\n", target ? target : "", targetattr); |
| |
| while (scut) |
| { |
| name = mxmlElementGetAttr(scut, "name"); |
| description = mxmlFindElement(scut, scut, "description", |
| NULL, NULL, MXML_DESCEND_FIRST); |
| |
| if (xml) |
| { |
| fprintf(out, "<Node id=\"%d\">\n" |
| "<Path>Documentation/index.html</Path>\n" |
| "<Anchor>%s</Anchor>\n" |
| "<Name>%s</Name>\n" |
| "</Node>\n", xmlid ++, name, name); |
| } |
| else |
| { |
| fprintf(out, "\t<li><a href=\"%s#%s\"%s title=\"", |
| target ? target : "", name, targetattr); |
| write_description(out, description, "", 1); |
| fprintf(out, "\">%s</a></li>\n", name); |
| } |
| |
| scut = find_public(scut, doc, "typedef"); |
| } |
| |
| if (xml) |
| fputs("</Subnodes></Node>\n", out); |
| else |
| fputs("</ul></li>\n", out); |
| } |
| |
| /* |
| * Structures... |
| */ |
| |
| if ((scut = find_public(doc, doc, "struct")) != NULL) |
| { |
| if (xml) |
| fprintf(out, "<Node id=\"%d\">\n" |
| "<Path>Documentation/index.html</Path>\n" |
| "<Anchor>STRUCTURES</Anchor>\n" |
| "<Name>Structures</Name>\n" |
| "<Subnodes>\n", xmlid ++); |
| else |
| fprintf(out, "<li><a href=\"%s#STRUCTURES\"%s>Structures</a>" |
| "<ul class=\"code\">\n", target ? target : "", targetattr); |
| |
| while (scut) |
| { |
| name = mxmlElementGetAttr(scut, "name"); |
| description = mxmlFindElement(scut, scut, "description", |
| NULL, NULL, MXML_DESCEND_FIRST); |
| |
| if (xml) |
| { |
| fprintf(out, "<Node id=\"%d\">\n" |
| "<Path>Documentation/index.html</Path>\n" |
| "<Anchor>%s</Anchor>\n" |
| "<Name>%s</Name>\n" |
| "</Node>\n", xmlid ++, name, name); |
| } |
| else |
| { |
| fprintf(out, "\t<li><a href=\"%s#%s\"%s title=\"", |
| target ? target : "", name, targetattr); |
| write_description(out, description, "", 1); |
| fprintf(out, "\">%s</a></li>\n", name); |
| } |
| |
| scut = find_public(scut, doc, "struct"); |
| } |
| |
| if (xml) |
| fputs("</Subnodes></Node>\n", out); |
| else |
| fputs("</ul></li>\n", out); |
| } |
| |
| /* |
| * Unions... |
| */ |
| |
| if ((scut = find_public(doc, doc, "union")) != NULL) |
| { |
| if (xml) |
| fprintf(out, "<Node id=\"%d\">\n" |
| "<Path>Documentation/index.html</Path>\n" |
| "<Anchor>UNIONS</Anchor>\n" |
| "<Name>Unions</Name>\n" |
| "<Subnodes>\n", xmlid ++); |
| else |
| fprintf(out, |
| "<li><a href=\"%s#UNIONS\"%s>Unions</a><ul class=\"code\">\n", |
| target ? target : "", targetattr); |
| |
| while (scut) |
| { |
| name = mxmlElementGetAttr(scut, "name"); |
| description = mxmlFindElement(scut, scut, "description", |
| NULL, NULL, MXML_DESCEND_FIRST); |
| |
| if (xml) |
| { |
| fprintf(out, "<Node id=\"%d\">\n" |
| "<Path>Documentation/index.html</Path>\n" |
| "<Anchor>%s</Anchor>\n" |
| "<Name>%s</Name>\n" |
| "</Node>\n", xmlid ++, name, name); |
| } |
| else |
| { |
| fprintf(out, "\t<li><a href=\"%s#%s\"%s title=\"", |
| target ? target : "", name, targetattr); |
| write_description(out, description, "", 1); |
| fprintf(out, "\">%s</a></li>\n", name); |
| } |
| |
| scut = find_public(scut, doc, "union"); |
| } |
| |
| if (xml) |
| fputs("</Subnodes></Node>\n", out); |
| else |
| fputs("</ul></li>\n", out); |
| } |
| |
| /* |
| * Globals variables... |
| */ |
| |
| if ((arg = find_public(doc, doc, "variable")) != NULL) |
| { |
| if (xml) |
| fprintf(out, "<Node id=\"%d\">\n" |
| "<Path>Documentation/index.html</Path>\n" |
| "<Anchor>VARIABLES</Anchor>\n" |
| "<Name>Variables</Name>\n" |
| "<Subnodes>\n", xmlid ++); |
| else |
| fprintf(out, "<li><a href=\"%s#VARIABLES\"%s>Variables</a>" |
| "<ul class=\"code\">\n", target ? target : "", targetattr); |
| |
| while (arg) |
| { |
| name = mxmlElementGetAttr(arg, "name"); |
| description = mxmlFindElement(arg, arg, "description", |
| NULL, NULL, MXML_DESCEND_FIRST); |
| |
| if (xml) |
| { |
| fprintf(out, "<Node id=\"%d\">\n" |
| "<Path>Documentation/index.html</Path>\n" |
| "<Anchor>%s</Anchor>\n" |
| "<Name>%s</Name>\n" |
| "</Node>\n", xmlid ++, name, name); |
| } |
| else |
| { |
| fprintf(out, "\t<li><a href=\"%s#%s\"%s title=\"", |
| target ? target : "", name, targetattr); |
| write_description(out, description, "", 1); |
| fprintf(out, "\">%s</a></li>\n", name); |
| } |
| |
| arg = find_public(arg, doc, "variable"); |
| } |
| |
| if (xml) |
| fputs("</Subnodes></Node>\n", out); |
| else |
| fputs("</ul></li>\n", out); |
| } |
| |
| /* |
| * Enumerations/constants... |
| */ |
| |
| if ((scut = find_public(doc, doc, "enumeration")) != NULL) |
| { |
| if (xml) |
| fprintf(out, "<Node id=\"%d\">\n" |
| "<Path>Documentation/index.html</Path>\n" |
| "<Anchor>ENUMERATIONS</Anchor>\n" |
| "<Name>Constants</Name>\n" |
| "<Subnodes>\n", xmlid ++); |
| else |
| fprintf(out, "<li><a href=\"%s#ENUMERATIONS\"%s>Constants</a>" |
| "<ul class=\"code\">\n", target ? target : "", targetattr); |
| |
| while (scut) |
| { |
| name = mxmlElementGetAttr(scut, "name"); |
| description = mxmlFindElement(scut, scut, "description", |
| NULL, NULL, MXML_DESCEND_FIRST); |
| |
| if (xml) |
| { |
| fprintf(out, "<Node id=\"%d\">\n" |
| "<Path>Documentation/index.html</Path>\n" |
| "<Anchor>%s</Anchor>\n" |
| "<Name>%s</Name>\n" |
| "</Node>\n", xmlid ++, name, name); |
| } |
| else |
| { |
| fprintf(out, "\t<li><a href=\"%s#%s\"%s title=\"", |
| target ? target : "", name, targetattr); |
| write_description(out, description, "", 1); |
| fprintf(out, "\">%s</a></li>\n", name); |
| } |
| |
| scut = find_public(scut, doc, "enumeration"); |
| } |
| |
| if (xml) |
| fputs("</Subnodes></Node>\n", out); |
| else |
| fputs("</ul></li>\n", out); |
| } |
| |
| /* |
| * Close out the HTML table-of-contents list as needed... |
| */ |
| |
| if (!xml) |
| fputs("</ul>\n", out); |
| } |
| |
| |
| /* |
| * 'write_tokens()' - Write <Token> nodes for all APIs. |
| */ |
| |
| static void |
| write_tokens(FILE *out, /* I - Output file */ |
| mxml_node_t *doc, /* I - Document */ |
| const char *path) /* I - Path to help file */ |
| { |
| mxml_node_t *function, /* Current function */ |
| *scut, /* Struct/class/union/typedef */ |
| *arg, /* Current argument */ |
| *description, /* Description of function/var */ |
| *type, /* Type node */ |
| *node; /* Current child node */ |
| const char *name, /* Name of function/type */ |
| *cename, /* Current class/enum name */ |
| *defval; /* Default value for argument */ |
| char prefix; /* Prefix for declarations */ |
| |
| |
| /* |
| * Classes... |
| */ |
| |
| if ((scut = find_public(doc, doc, "class")) != NULL) |
| { |
| while (scut) |
| { |
| cename = mxmlElementGetAttr(scut, "name"); |
| description = mxmlFindElement(scut, scut, "description", |
| NULL, NULL, MXML_DESCEND_FIRST); |
| |
| fprintf(out, "<Token>\n" |
| "<Path>Documentation/%s</Path>\n" |
| "<Anchor>%s</Anchor>\n" |
| "<TokenIdentifier>//apple_ref/cpp/cl/%s</TokenIdentifier>\n" |
| "<Abstract>", path, cename, cename); |
| write_description(out, description, "", 1); |
| fputs("</Abstract>\n" |
| "</Token>\n", out); |
| |
| if ((function = find_public(scut, scut, "function")) != NULL) |
| { |
| while (function) |
| { |
| name = mxmlElementGetAttr(function, "name"); |
| description = mxmlFindElement(function, function, "description", |
| NULL, NULL, MXML_DESCEND_FIRST); |
| |
| fprintf(out, "<Token>\n" |
| "<Path>Documentation/%s</Path>\n" |
| "<Anchor>%s.%s</Anchor>\n" |
| "<TokenIdentifier>//apple_ref/cpp/clm/%s/%s", path, |
| cename, name, cename, name); |
| |
| arg = mxmlFindElement(function, function, "returnvalue", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| |
| if (arg && (type = mxmlFindElement(arg, arg, "type", NULL, |
| NULL, MXML_DESCEND_FIRST)) != NULL) |
| { |
| for (node = type->child; node; node = node->next) |
| fputs(node->value.text.string, out); |
| } |
| else if (strcmp(cename, name) && strcmp(cename, name + 1)) |
| fputs("void", out); |
| |
| fputs("/", out); |
| |
| for (arg = mxmlFindElement(function, function, "argument", NULL, NULL, |
| MXML_DESCEND_FIRST), prefix = '('; |
| arg; |
| arg = mxmlFindElement(arg, function, "argument", NULL, NULL, |
| MXML_NO_DESCEND), prefix = ',') |
| { |
| type = mxmlFindElement(arg, arg, "type", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| |
| putc(prefix, out); |
| |
| for (node = type->child; node; node = node->next) |
| fputs(node->value.text.string, out); |
| |
| fputs(mxmlElementGetAttr(arg, "name"), out); |
| } |
| |
| if (prefix == '(') |
| fputs("(void", out); |
| |
| fputs(")</TokenIdentifier>\n" |
| "<Abstract>", out); |
| write_description(out, description, "", 1); |
| fputs("</Abstract>\n" |
| "<Declaration>", out); |
| |
| arg = mxmlFindElement(function, function, "returnvalue", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| |
| if (arg) |
| write_element(out, doc, mxmlFindElement(arg, arg, "type", NULL, |
| NULL, MXML_DESCEND_FIRST), |
| OUTPUT_XML); |
| else if (strcmp(cename, name) && strcmp(cename, name + 1)) |
| fputs("void ", out); |
| |
| fputs(name, out); |
| |
| for (arg = mxmlFindElement(function, function, "argument", NULL, NULL, |
| MXML_DESCEND_FIRST), prefix = '('; |
| arg; |
| arg = mxmlFindElement(arg, function, "argument", NULL, NULL, |
| MXML_NO_DESCEND), prefix = ',') |
| { |
| type = mxmlFindElement(arg, arg, "type", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| |
| putc(prefix, out); |
| if (prefix == ',') |
| putc(' ', out); |
| |
| if (type->child) |
| write_element(out, doc, type, OUTPUT_XML); |
| |
| fputs(mxmlElementGetAttr(arg, "name"), out); |
| if ((defval = mxmlElementGetAttr(arg, "default")) != NULL) |
| fprintf(out, " %s", defval); |
| } |
| |
| if (prefix == '(') |
| fputs("(void);", out); |
| else |
| fputs(");", out); |
| |
| fputs("</Declaration>\n" |
| "</Token>\n", out); |
| |
| function = find_public(function, doc, "function"); |
| } |
| } |
| scut = find_public(scut, doc, "class"); |
| } |
| } |
| |
| /* |
| * Functions... |
| */ |
| |
| if ((function = find_public(doc, doc, "function")) != NULL) |
| { |
| while (function) |
| { |
| name = mxmlElementGetAttr(function, "name"); |
| description = mxmlFindElement(function, function, "description", |
| NULL, NULL, MXML_DESCEND_FIRST); |
| |
| fprintf(out, "<Token>\n" |
| "<Path>Documentation/%s</Path>\n" |
| "<Anchor>%s</Anchor>\n" |
| "<TokenIdentifier>//apple_ref/c/func/%s</TokenIdentifier>\n" |
| "<Abstract>", path, name, name); |
| write_description(out, description, "", 1); |
| fputs("</Abstract>\n" |
| "<Declaration>", out); |
| |
| arg = mxmlFindElement(function, function, "returnvalue", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| |
| if (arg) |
| write_element(out, doc, mxmlFindElement(arg, arg, "type", NULL, |
| NULL, MXML_DESCEND_FIRST), |
| OUTPUT_XML); |
| else // if (strcmp(cname, name) && strcmp(cname, name + 1)) |
| fputs("void ", out); |
| |
| fputs(name, out); |
| |
| for (arg = mxmlFindElement(function, function, "argument", NULL, NULL, |
| MXML_DESCEND_FIRST), prefix = '('; |
| arg; |
| arg = mxmlFindElement(arg, function, "argument", NULL, NULL, |
| MXML_NO_DESCEND), prefix = ',') |
| { |
| type = mxmlFindElement(arg, arg, "type", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| |
| putc(prefix, out); |
| if (prefix == ',') |
| putc(' ', out); |
| |
| if (type->child) |
| write_element(out, doc, type, OUTPUT_XML); |
| |
| fputs(mxmlElementGetAttr(arg, "name"), out); |
| if ((defval = mxmlElementGetAttr(arg, "default")) != NULL) |
| fprintf(out, " %s", defval); |
| } |
| |
| if (prefix == '(') |
| fputs("(void);", out); |
| else |
| fputs(");", out); |
| |
| fputs("</Declaration>\n" |
| "</Token>\n", out); |
| |
| function = find_public(function, doc, "function"); |
| } |
| } |
| |
| /* |
| * Data types... |
| */ |
| |
| if ((scut = find_public(doc, doc, "typedef")) != NULL) |
| { |
| while (scut) |
| { |
| name = mxmlElementGetAttr(scut, "name"); |
| description = mxmlFindElement(scut, scut, "description", |
| NULL, NULL, MXML_DESCEND_FIRST); |
| |
| fprintf(out, "<Token>\n" |
| "<Path>Documentation/%s</Path>\n" |
| "<Anchor>%s</Anchor>\n" |
| "<TokenIdentifier>//apple_ref/c/tdef/%s</TokenIdentifier>\n" |
| "<Abstract>", path, name, name); |
| write_description(out, description, "", 1); |
| fputs("</Abstract>\n" |
| "</Token>\n", out); |
| |
| scut = find_public(scut, doc, "typedef"); |
| } |
| } |
| |
| /* |
| * Structures... |
| */ |
| |
| if ((scut = find_public(doc, doc, "struct")) != NULL) |
| { |
| while (scut) |
| { |
| name = mxmlElementGetAttr(scut, "name"); |
| description = mxmlFindElement(scut, scut, "description", |
| NULL, NULL, MXML_DESCEND_FIRST); |
| |
| fprintf(out, "<Token>\n" |
| "<Path>Documentation/%s</Path>\n" |
| "<Anchor>%s</Anchor>\n" |
| "<TokenIdentifier>//apple_ref/c/tag/%s</TokenIdentifier>\n" |
| "<Abstract>", path, name, name); |
| write_description(out, description, "", 1); |
| fputs("</Abstract>\n" |
| "</Token>\n", out); |
| |
| scut = find_public(scut, doc, "struct"); |
| } |
| } |
| |
| /* |
| * Unions... |
| */ |
| |
| if ((scut = find_public(doc, doc, "union")) != NULL) |
| { |
| while (scut) |
| { |
| name = mxmlElementGetAttr(scut, "name"); |
| description = mxmlFindElement(scut, scut, "description", |
| NULL, NULL, MXML_DESCEND_FIRST); |
| |
| fprintf(out, "<Token>\n" |
| "<Path>Documentation/%s</Path>\n" |
| "<Anchor>%s</Anchor>\n" |
| "<TokenIdentifier>//apple_ref/c/tag/%s</TokenIdentifier>\n" |
| "<Abstract>", path, name, name); |
| write_description(out, description, "", 1); |
| fputs("</Abstract>\n" |
| "</Token>\n", out); |
| |
| scut = find_public(scut, doc, "union"); |
| } |
| } |
| |
| /* |
| * Globals variables... |
| */ |
| |
| if ((arg = find_public(doc, doc, "variable")) != NULL) |
| { |
| while (arg) |
| { |
| name = mxmlElementGetAttr(arg, "name"); |
| description = mxmlFindElement(arg, arg, "description", |
| NULL, NULL, MXML_DESCEND_FIRST); |
| |
| fprintf(out, "<Token>\n" |
| "<Path>Documentation/%s</Path>\n" |
| "<Anchor>%s</Anchor>\n" |
| "<TokenIdentifier>//apple_ref/c/data/%s</TokenIdentifier>\n" |
| "<Abstract>", path, name, name); |
| write_description(out, description, "", 1); |
| fputs("</Abstract>\n" |
| "</Token>\n", out); |
| |
| arg = find_public(arg, doc, "variable"); |
| } |
| } |
| |
| /* |
| * Enumerations/constants... |
| */ |
| |
| if ((scut = find_public(doc, doc, "enumeration")) != NULL) |
| { |
| while (scut) |
| { |
| cename = mxmlElementGetAttr(scut, "name"); |
| description = mxmlFindElement(scut, scut, "description", |
| NULL, NULL, MXML_DESCEND_FIRST); |
| |
| fprintf(out, "<Token>\n" |
| "<Path>Documentation/%s</Path>\n" |
| "<Anchor>%s</Anchor>\n" |
| "<TokenIdentifier>//apple_ref/c/tag/%s</TokenIdentifier>\n" |
| "<Abstract>", path, cename, cename); |
| write_description(out, description, "", 1); |
| fputs("</Abstract>\n" |
| "</Token>\n", out); |
| |
| for (arg = mxmlFindElement(scut, scut, "constant", NULL, NULL, |
| MXML_DESCEND_FIRST); |
| arg; |
| arg = mxmlFindElement(arg, scut, "constant", NULL, NULL, |
| MXML_NO_DESCEND)) |
| { |
| name = mxmlElementGetAttr(arg, "name"); |
| description = mxmlFindElement(arg, arg, "description", NULL, |
| NULL, MXML_DESCEND_FIRST); |
| fprintf(out, "<Token>\n" |
| "<Path>Documentation/%s</Path>\n" |
| "<Anchor>%s</Anchor>\n" |
| "<TokenIdentifier>//apple_ref/c/econst/%s</TokenIdentifier>\n" |
| "<Abstract>", path, cename, name); |
| write_description(out, description, "", 1); |
| fputs("</Abstract>\n" |
| "</Token>\n", out); |
| } |
| |
| scut = find_public(scut, doc, "enumeration"); |
| } |
| } |
| } |
| |
| |
| /* |
| * 'ws_cb()' - Whitespace callback for saving. |
| */ |
| |
| static const char * /* O - Whitespace string or NULL for none */ |
| ws_cb(mxml_node_t *node, /* I - Element node */ |
| int where) /* I - Where value */ |
| { |
| const char *name; /* Name of element */ |
| int depth; /* Depth of node */ |
| static const char *spaces = " "; |
| /* Whitespace (40 spaces) for indent */ |
| |
| |
| name = node->value.element.name; |
| |
| switch (where) |
| { |
| case MXML_WS_BEFORE_CLOSE : |
| if (strcmp(name, "argument") && |
| strcmp(name, "class") && |
| strcmp(name, "constant") && |
| strcmp(name, "enumeration") && |
| strcmp(name, "function") && |
| strcmp(name, "mxmldoc") && |
| strcmp(name, "namespace") && |
| strcmp(name, "returnvalue") && |
| strcmp(name, "struct") && |
| strcmp(name, "typedef") && |
| strcmp(name, "union") && |
| strcmp(name, "variable")) |
| return (NULL); |
| |
| for (depth = -4; node; node = node->parent, depth += 2); |
| if (depth > 40) |
| return (spaces); |
| else if (depth < 2) |
| return (NULL); |
| else |
| return (spaces + 40 - depth); |
| |
| case MXML_WS_AFTER_CLOSE : |
| return ("\n"); |
| |
| case MXML_WS_BEFORE_OPEN : |
| for (depth = -4; node; node = node->parent, depth += 2); |
| if (depth > 40) |
| return (spaces); |
| else if (depth < 2) |
| return (NULL); |
| else |
| return (spaces + 40 - depth); |
| |
| default : |
| case MXML_WS_AFTER_OPEN : |
| if (strcmp(name, "argument") && |
| strcmp(name, "class") && |
| strcmp(name, "constant") && |
| strcmp(name, "enumeration") && |
| strcmp(name, "function") && |
| strcmp(name, "mxmldoc") && |
| strcmp(name, "namespace") && |
| strcmp(name, "returnvalue") && |
| strcmp(name, "struct") && |
| strcmp(name, "typedef") && |
| strcmp(name, "union") && |
| strcmp(name, "variable") && |
| strncmp(name, "?xml", 4)) |
| return (NULL); |
| else |
| return ("\n"); |
| } |
| } |
| |
| |
| /* |
| * End of "$Id: mxmldoc.c 451 2014-01-04 21:50:06Z msweet $". |
| */ |