diff --git a/CHANGES b/CHANGES
index 752015b..ff4c5ff 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,8 +1,10 @@
-CHANGES - 08/16/2005
+CHANGES - 09/21/2005
--------------------
CHANGES IN Mini-XML 2.2.3
+ - The mxmldoc program now supports --title and --intro
+ options.
- The mxmlLoad*() functions could leak a node on an error
(STR #27)
- The mxml_vsnprintf() function could get in an infinite
diff --git a/doc/mxml.html b/doc/mxml.html
index bab2930..c8030f9 100644
--- a/doc/mxml.html
+++ b/doc/mxml.html
@@ -1831,13 +1831,19 @@ Ty Coon, President of Vice
+- The mxmldoc program now supports --title and --intro options.
+- The mxmlLoad*() functions could leak a node on an error (STR #27)
+- The mxml_vsnprintf() function could get in an infinite loop on a
+ buffer overflow (STR #25)
- Added new mxmlNewCDATA() and mxmlSetCDATA() functions to create and
set CDATA nodes, which are really just special element nodes.
+- Added new MXML_IGNORE type and MXML_IGNORE_CB callback to ignore
+ non-element nodes (i.e. whitespace)
+- mxmlLoad*() did not treat custom data as opaque, so whitespace
+ characters would be lost.
-- Added new MXML_IGNORE type and MXML_IGNORE_CB callback to ignore
- non-element nodes (i.e. whitespace)
- mxmlLoad*() did not treat custom data as opaque, so whitespace
characters would be lost.
diff --git a/doc/mxmldoc.man b/doc/mxmldoc.man
index 482d0a6..149ac0d 100644
--- a/doc/mxmldoc.man
+++ b/doc/mxmldoc.man
@@ -15,13 +15,18 @@
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
-.TH mxmldoc 1 "mini-XML" "25 February 2005" "Michael Sweet"
+.TH mxmldoc 1 "mini-XML" "21 September 2005" "Michael Sweet"
.SH NAME
mxmldoc \- mini-xml documentation generator
.SH SYNOPSIS
.B mxmldoc
+[ --intro
+.I introfile.html
+] [ --title
+.I title
+] [
.I filename.xml
-[
+] [
.I source file(s)
] >
.I filename.html
@@ -39,6 +44,15 @@ In general, any C or C++ source code is handled by
code with documentation that is formatted according to the CUPS
Configuration Management Plan which is available at
"http://www.cups.org/documentation.php".
+.SH OPTIONS
+.TP 5
+\--intro introfile.html
+.br
+Inserts the specified file at the top of the output documentation.
+.TP 5
+\--title title
+.br
+Sets the title of the output documentation.
.SH SEE ALSO
mxml(3), Mini-XML Programmers Manual, http://www.easysw.com/~mike/mxml/
.SH COPYRIGHT
diff --git a/doc/relnotes.html b/doc/relnotes.html
index 7b62276..50e1af3 100644
--- a/doc/relnotes.html
+++ b/doc/relnotes.html
@@ -7,6 +7,9 @@
+ - The mxmldoc program now supports --title and --intro
+ options.
+
- The mxmlLoad*() functions could leak a node on an
error (STR #27)
diff --git a/mxmldoc.c b/mxmldoc.c
index 93d3ffd..f8e6eec 100644
--- a/mxmldoc.c
+++ b/mxmldoc.c
@@ -20,10 +20,12 @@
*
* main() - Main entry for test program.
* add_variable() - Add a variable or argument.
+ * new_documentation() - Create a new documentation tree.
* safe_strcpy() - Copy a string allowing for overlapping strings.
* scan_file() - Scan a source file.
* sort_node() - Insert a node sorted into a tree.
* update_comment() - Update a comment node.
+ * usage() - Show program usage...
* write_documentation() - Write HTML documentation.
* write_element() - Write an elements text nodes.
* write_string() - Write a string, quoting XHTML special chars
@@ -132,13 +134,17 @@
static mxml_node_t *add_variable(mxml_node_t *parent, const char *name,
mxml_node_t *type);
+static mxml_node_t *new_documentation(mxml_node_t **mxmldoc);
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 write_documentation(mxml_node_t *doc);
+static void usage(const char *option);
+static void write_documentation(const char *title,
+ const char *intro,
+ mxml_node_t *doc);
static void write_element(mxml_node_t *doc, mxml_node_t *element);
static void write_string(const char *s);
static const char *ws_cb(mxml_node_t *node, int where);
@@ -153,110 +159,153 @@ 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 *title; /* Title of documentation */
+ const char *introfile; /* Introduction file */
+ const char *xmlfile; /* XML file */
+ int update; /* Updated XML file */
/*
* Check arguments...
*/
- if (argc < 2)
- {
- fputs("Usage: mxmldoc filename.xml [source files] >filename.html\n", stderr);
- return (1);
- }
-
- /*
- * Read the XML documentation file, if it exists...
- */
-
- if ((fp = fopen(argv[1], "r")) != NULL)
- {
- /*
- * Read the existing XML file...
- */
-
- doc = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
+ title = NULL;
+ introfile = NULL;
+ xmlfile = NULL;
+ update = 0;
+ doc = NULL;
+ mxmldoc = NULL;
- fclose(fp);
+ for (i = 1; i < argc; i ++)
+ if (!strcmp(argv[i], "--title") && !title)
+ {
+ /*
+ * Set title...
+ */
- if (!doc)
+ i ++;
+ if (i < argc)
+ title = argv[i];
+ else
+ usage(NULL);
+ }
+ else if (!strcmp(argv[i], "--intro") && !introfile)
{
- mxmldoc = NULL;
+ /*
+ * Set intro file...
+ */
- fprintf(stderr, "mxmldoc: Unable to read the XML documentation file \"%s\"!\n",
- argv[1]);
+ i ++;
+ if (i < argc)
+ introfile = argv[i];
+ else
+ usage(NULL);
}
- else if ((mxmldoc = mxmlFindElement(doc, doc, "mxmldoc", NULL,
- NULL, MXML_DESCEND)) == NULL)
+ else if (argv[i][0] == '-')
{
- fprintf(stderr, "mxmldoc: XML documentation file \"%s\" is missing node!!\n",
- argv[1]);
+ /*
+ * Unknown/bad option...
+ */
- mxmlDelete(doc);
- doc = NULL;
+ usage(argv[i]);
}
- }
- else
- {
- doc = NULL;
- mxmldoc = NULL;
- }
+ else
+ {
+ /*
+ * Process XML or source file...
+ */
- if (!doc)
- {
- /*
- * Create an empty XML documentation file...
- */
+ len = strlen(argv[i]);
+ if (len > 4 && !strcmp(argv[i] + len - 4, ".xml"))
+ {
+ /*
+ * Set XML file...
+ */
- doc = mxmlNewElement(NULL, "?xml version=\"1.0\"?");
+ if (xmlfile)
+ usage(NULL);
- mxmldoc = mxmlNewElement(doc, "mxmldoc");
+ xmlfile = argv[i];
-#ifdef MXML_INCLUDE_SCHEMA
- /*
- * Currently we don't include the schema/namespace stuff with the
- * XML output since some validators don't seem to like it...
- */
+ if (!doc)
+ {
+ if ((fp = fopen(argv[i], "r")) != NULL)
+ {
+ /*
+ * Read the existing XML file...
+ */
- mxmlElementSetAttr(mxmldoc, "xmlns", "http://www.easysw.com");
- mxmlElementSetAttr(mxmldoc, "xmlns:xsi",
- "http://www.w3.org/2001/XMLSchema-instance");
- mxmlElementSetAttr(mxmldoc, "xsi:schemaLocation",
- "http://www.easysw.com/~mike/mxml/mxmldoc.xsd");
-#endif /* MXML_INCLUDE_SCHEMA */
- }
+ doc = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
- /*
- * Loop through all of the source files...
- */
+ fclose(fp);
- for (i = 2; i < argc; i ++)
- if ((fp = fopen(argv[i], "r")) == NULL)
- {
- fprintf(stderr, "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);
+ 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 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);
+ }
}
- else
- fclose(fp);
- if (argc > 2)
+ if (update && xmlfile)
{
/*
* Save the updated XML documentation file...
*/
- if ((fp = fopen(argv[1], "w")) != NULL)
+ if ((fp = fopen(xmlfile, "w")) != NULL)
{
/*
* Write over the existing XML file...
@@ -264,8 +313,8 @@ main(int argc, /* I - Number of command-line args */
if (mxmlSaveFile(doc, fp, ws_cb))
{
- fprintf(stderr, "Unable to write the XML documentation file \"%s\": %s!\n",
- argv[1], strerror(errno));
+ fprintf(stderr, "mxmldoc: Unable to write the XML documentation file \"%s\": %s!\n",
+ xmlfile, strerror(errno));
fclose(fp);
mxmlDelete(doc);
return (1);
@@ -275,8 +324,8 @@ main(int argc, /* I - Number of command-line args */
}
else
{
- fprintf(stderr, "Unable to create the XML documentation file \"%s\": %s!\n",
- argv[1], strerror(errno));
+ fprintf(stderr, "mxmldoc: Unable to create the XML documentation file \"%s\": %s!\n",
+ xmlfile, strerror(errno));
mxmlDelete(doc);
return (1);
}
@@ -286,7 +335,7 @@ main(int argc, /* I - Number of command-line args */
* Write HTML documentation...
*/
- write_documentation(mxmldoc);
+ write_documentation(title ? title : "Documentation", introfile, mxmldoc);
/*
* Delete the tree and return...
@@ -412,6 +461,40 @@ add_variable(mxml_node_t *parent, /* I - Parent node */
}
+/*
+ * '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 = mxmlNewElement(NULL, "?xml version=\"1.0\"?");
+
+ *mxmldoc = mxmlNewElement(doc, "mxmldoc");
+
+#ifdef MXML_INCLUDE_SCHEMA
+ /*
+ * Currently we don't include the schema/namespace stuff with the
+ * XML output since some validators don't seem to like it...
+ */
+
+ mxmlElementSetAttr(*mxmldoc, "xmlns", "http://www.easysw.com");
+ mxmlElementSetAttr(*mxmldoc, "xmlns:xsi",
+ "http://www.w3.org/2001/XMLSchema-instance");
+ mxmlElementSetAttr(*mxmldoc, "xsi:schemaLocation",
+ "http://www.easysw.com/~mike/mxml/mxmldoc.xsd");
+#endif /* MXML_INCLUDE_SCHEMA */
+
+ return (doc);
+}
+
/*
* 'safe_strcpy()' - Copy a string allowing for overlapping strings.
*/
@@ -1636,6 +1719,9 @@ sort_node(mxml_node_t *tree, /* I - Tree to sort into */
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 */
@@ -1792,14 +1878,38 @@ update_comment(mxml_node_t *parent, /* I - Parent node */
}
+/*
+ * '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(" --title title Set documentation title");
+ puts(" --intro introfile.html Set introduction file");
+
+ exit(1);
+}
+
+
/*
* 'write_documentation()' - Write HTML documentation.
*/
static void
-write_documentation(mxml_node_t *doc) /* I - XML documentation */
+write_documentation(
+ const char *title, /* I - Title */
+ const char *introfile, /* I - Intro file */
+ mxml_node_t *doc) /* I - XML documentation */
{
int i; /* Looping var */
+ FILE *fp; /* File */
+ char line[8192]; /* Line from file */
mxml_node_t *function, /* Current function */
*scut, /* Struct/class/union/typedef */
*arg, /* Current argument */
@@ -1823,19 +1933,35 @@ write_documentation(mxml_node_t *doc) /* I - XML documentation */
* Standard header...
*/
- puts("\n"
- "\n"
- "\n"
- "\tDocumentation\n"
- "\t\n"
- "\t\n"
- "\n"
- "");
+ printf("\n"
+ "\n"
+ "\n"
+ "\t%s\n"
+ "\t\n"
+ "\t\n"
+ "\n"
+ "\n", title);
+
+ /*
+ * Intro...
+ */
+
+ if (introfile && (fp = fopen(introfile, "r")) != NULL)
+ {
+ /*
+ * Insert intro file before contents...
+ */
+
+ while (fgets(line, sizeof(line), fp))
+ fputs(line, stdout);
+
+ fclose(fp);
+ }
/*
* Table of contents...