diff --git a/CHANGES b/CHANGES
index 8c994a3..af47caf 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,15 @@
-README - 09/28/2003
+README - 12/01/2003
-------------------
+CHANGES IN Mini-XML 1.3
+
+ - The mxmlElementSetAttr() function now allows for NULL
+ attribute values.
+ - The load and save functions now properly handle quoted
+ element and attribute name strings properly, e.g. for
+ !DOCTYPE declarations.
+
+
CHANGES IN Mini-XML 1.2
- Added new "set" methods to set the value of a node.
diff --git a/README b/README
index fdd7cbc..ee153eb 100644
--- a/README
+++ b/README
@@ -1,10 +1,10 @@
-README - 09/28/2003
+README - 12/01/2003
-------------------
INTRODUCTION
- This README file describes the Mini-XML library version 1.2.
+ This README file describes the Mini-XML library version 1.3.
Mini-XML is a small XML parsing library that you can use to
read XML and XML-like data files in your application without
@@ -14,8 +14,8 @@ INTRODUCTION
Mini-XML provides the following functionality:
- - Reading and writing of UTF-8 encoded XML files.
- - Reading and writing of UTF-8 encoded XML strings.
+ - Reading and writing of UTF-8 encoded XML files and
+ strings.
- Data is stored in a linked-list tree structure,
preserving the XML data hierarchy.
- Supports arbitrary element names, attributes, and
@@ -76,7 +76,7 @@ DOCUMENTATION
The documentation is currently a work in progress. Aside
from the information that follows, the "documentation.html"
page provides a handy reference and is automatically
- generated using Mini-XML. You can also look at the
+ generated using Mini-XML. You can also look at the
"testmxml.c" and "mxmldoc.c" source files for examples of
using Mini-XML.
diff --git a/index.html b/index.html
index ee225b9..3fbe165 100644
--- a/index.html
+++ b/index.html
@@ -16,11 +16,11 @@ href="../index.html">Back to Home Page ]
Mini-XML Home Page
-Current Release: v1.2, September 28, 2003
+
Current Release: v1.3, December 1, 2003
[ Download Source (.tar.gz 77k)
+href="mxml-1.3.tar.gz">Download Source (.tar.gz 77k)
| Download Linux RPM (.i386.rpm 67k)
+href="mxml-1.3-1.i386.rpm">Download Linux RPM (.i386.rpm 67k)
| Change Log | Documentation | Rate/Make Comments ]
@@ -36,7 +36,8 @@ ANSI C compilers) and a "make" program.
Mini-XML provides the following functionality:
- - Reading and writing of UTF-8 encoded XML files.
+ - Reading and writing of UTF-8 encoded XML files and
+ strings.
- Data is stored in a linked-list tree structure,
preserving the XML data hierarchy.
- Supports arbitrary element names, attributes, and
diff --git a/mxml-attr.c b/mxml-attr.c
index c120570..437579c 100644
--- a/mxml-attr.c
+++ b/mxml-attr.c
@@ -1,5 +1,5 @@
/*
- * "$Id: mxml-attr.c,v 1.4 2003/07/27 23:11:40 mike Exp $"
+ * "$Id: mxml-attr.c,v 1.5 2003/12/01 15:27:47 mike Exp $"
*
* Attribute support code for mini-XML, a small XML-like file parsing library.
*
@@ -91,7 +91,7 @@ mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */
* Range check input...
*/
- if (!node || node->type != MXML_ELEMENT || !name || !value)
+ if (!node || node->type != MXML_ELEMENT || !name)
return;
/*
@@ -109,7 +109,10 @@ mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */
free(attr->value);
- attr->value = strdup(value);
+ if (value)
+ attr->value = strdup(value);
+ else
+ attr->value = NULL;
return;
}
@@ -135,9 +138,12 @@ mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */
attr += node->value.element.num_attrs;
attr->name = strdup(name);
- attr->value = strdup(value);
+ if (value)
+ attr->value = strdup(value);
+ else
+ attr->value = NULL;
- if (!attr->name || !attr->value)
+ if (!attr->name || (!attr->value && value))
{
if (attr->name)
free(attr->name);
@@ -156,5 +162,5 @@ mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */
/*
- * End of "$Id: mxml-attr.c,v 1.4 2003/07/27 23:11:40 mike Exp $".
+ * End of "$Id: mxml-attr.c,v 1.5 2003/12/01 15:27:47 mike Exp $".
*/
diff --git a/mxml-file.c b/mxml-file.c
index 75124b1..8e5785b 100644
--- a/mxml-file.c
+++ b/mxml-file.c
@@ -1,5 +1,5 @@
/*
- * "$Id: mxml-file.c,v 1.21 2003/09/28 21:09:04 mike Exp $"
+ * "$Id: mxml-file.c,v 1.22 2003/12/01 15:27:47 mike Exp $"
*
* File loading code for mini-XML, a small XML-like file parsing library.
*
@@ -27,6 +27,7 @@
* mxml_load_data() - Load data into an XML node tree.
* mxml_parse_element() - Parse an element for any attributes...
* mxml_string_getc() - Get a character from a string.
+ * mxml_write_name() - Write a name string.
* mxml_write_node() - Save an XML node to a file.
* mxml_write_string() - Write a string, escaping & and < as needed.
* mxml_write_ws() - Do whitespace callback...
@@ -55,6 +56,8 @@ static int mxml_parse_element(mxml_node_t *node, void *p,
int (*getc_cb)(void *));
static int mxml_string_getc(void *p);
static int mxml_string_putc(int ch, void *p);
+static int mxml_write_name(const char *s, void *p,
+ int (*putc_cb)(int, void *));
static int mxml_write_node(mxml_node_t *node, void *p,
int (*cb)(mxml_node_t *, int),
int col,
@@ -896,15 +899,43 @@ mxml_parse_element(mxml_node_t *node, /* I - Element node */
name[0] = ch;
ptr = name + 1;
- while ((ch = (*getc_cb)(p)) != EOF)
- if (isspace(ch) || ch == '=' || ch == '/' || ch == '>' || ch == '?')
- break;
- else if (mxml_add_char(ch, &ptr, &name, &namesize))
+ if (ch == '\"' || ch == '\'')
+ {
+ /*
+ * Name is in quotes, so get a quoted string...
+ */
+
+ quote = ch;
+
+ while ((ch = (*getc_cb)(p)) != EOF)
{
- free(name);
- free(value);
- return (EOF);
+ if (mxml_add_char(ch, &ptr, &name, &namesize))
+ {
+ free(name);
+ free(value);
+ return (EOF);
+ }
+
+ if (ch == quote)
+ break;
}
+ }
+ else
+ {
+ /*
+ * Grab an normal, non-quoted name...
+ */
+
+ while ((ch = (*getc_cb)(p)) != EOF)
+ if (isspace(ch) || ch == '=' || ch == '/' || ch == '>' || ch == '?')
+ break;
+ else if (mxml_add_char(ch, &ptr, &name, &namesize))
+ {
+ free(name);
+ free(value);
+ return (EOF);
+ }
+ }
*ptr = '\0';
@@ -963,12 +994,24 @@ mxml_parse_element(mxml_node_t *node, /* I - Element node */
*ptr = '\0';
}
+
+ /*
+ * Set the attribute with the given string value...
+ */
+
+ mxmlElementSetAttr(node, name, value);
}
else
- value[0] = '\0';
+ {
+ /*
+ * Set the attribute with a NULL value...
+ */
+
+ mxmlElementSetAttr(node, name, NULL);
+ }
/*
- * Save last character in case we need it...
+ * Check the end character...
*/
if (ch == '/' || ch == '?')
@@ -990,12 +1033,6 @@ mxml_parse_element(mxml_node_t *node, /* I - Element node */
}
else if (ch == '>')
break;
-
- /*
- * Set the attribute...
- */
-
- mxmlElementSetAttr(node, name, value);
}
/*
@@ -1054,6 +1091,166 @@ mxml_string_putc(int ch, /* I - Character to write */
}
+/*
+ * 'mxml_write_name()' - Write a name string.
+ */
+
+static int /* O - 0 on success, -1 on failure */
+mxml_write_name(const char *s, /* I - Name to write */
+ void *p, /* I - Write pointer */
+ int (*putc_cb)(int, void *))
+ /* I - Write callback */
+{
+ char buf[255], /* Buffer */
+ *bufptr, /* Pointer into buffer */
+ quote; /* Quote character */
+
+
+ if (*s == '\"' || *s == '\'')
+ {
+ /*
+ * Write a quoted name string...
+ */
+
+ if ((*putc_cb)(*s, p) < 0)
+ return (-1);
+
+ quote = *s++;
+
+ while (*s && *s != quote)
+ {
+ if (*s == '&')
+ {
+ if ((*putc_cb)('&', p) < 0)
+ return (-1);
+ if ((*putc_cb)('a', p) < 0)
+ return (-1);
+ if ((*putc_cb)('m', p) < 0)
+ return (-1);
+ if ((*putc_cb)('p', p) < 0)
+ return (-1);
+ if ((*putc_cb)(';', p) < 0)
+ return (-1);
+ }
+ else if (*s == '<')
+ {
+ if ((*putc_cb)('&', p) < 0)
+ return (-1);
+ if ((*putc_cb)('l', p) < 0)
+ return (-1);
+ if ((*putc_cb)('t', p) < 0)
+ return (-1);
+ if ((*putc_cb)(';', p) < 0)
+ return (-1);
+ }
+ else if (*s == '>')
+ {
+ if ((*putc_cb)('&', p) < 0)
+ return (-1);
+ if ((*putc_cb)('g', p) < 0)
+ return (-1);
+ if ((*putc_cb)('t', p) < 0)
+ return (-1);
+ if ((*putc_cb)(';', p) < 0)
+ return (-1);
+ }
+ else if (*s == '\"')
+ {
+ if ((*putc_cb)('&', p) < 0)
+ return (-1);
+ if ((*putc_cb)('q', p) < 0)
+ return (-1);
+ if ((*putc_cb)('u', p) < 0)
+ return (-1);
+ if ((*putc_cb)('o', p) < 0)
+ return (-1);
+ if ((*putc_cb)('t', p) < 0)
+ return (-1);
+ if ((*putc_cb)(';', p) < 0)
+ return (-1);
+ }
+ 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...
+ */
+
+ if ((*putc_cb)('&', p) < 0)
+ return (-1);
+ if ((*putc_cb)('n', p) < 0)
+ return (-1);
+ if ((*putc_cb)('b', p) < 0)
+ return (-1);
+ if ((*putc_cb)('s', p) < 0)
+ return (-1);
+ if ((*putc_cb)('p', p) < 0)
+ return (-1);
+ if ((*putc_cb)(';', p) < 0)
+ return (-1);
+ }
+ else
+ {
+ sprintf(buf, "%x;", ch);
+
+ for (bufptr = buf; *bufptr; bufptr ++)
+ if ((*putc_cb)(*bufptr, p) < 0)
+ return (-1);
+ }
+ }
+ else if ((*putc_cb)(*s, p) < 0)
+ return (-1);
+
+ s ++;
+ }
+
+ /*
+ * Write the end quote...
+ */
+
+ if ((*putc_cb)(quote, p) < 0)
+ return (-1);
+ }
+ else
+ {
+ /*
+ * Write a non-quoted name string...
+ */
+
+ while (*s)
+ {
+ if ((*putc_cb)(*s, p) < 0)
+ return (-1);
+
+ s ++;
+ }
+ }
+
+ return (0);
+}
+
+
/*
* 'mxml_write_node()' - Save an XML node to a file.
*/
@@ -1066,7 +1263,8 @@ mxml_write_node(mxml_node_t *node, /* I - Node to write */
int col, /* I - Current column */
int (*putc_cb)(int, void *))
{
- int i; /* Looping var */
+ int i, /* Looping var */
+ width; /* Width of attr + value */
mxml_attr_t *attr; /* Current attribute */
char s[255]; /* Temporary string */
@@ -1084,7 +1282,7 @@ mxml_write_node(mxml_node_t *node, /* I - Node to write */
if ((*putc_cb)('<', p) < 0)
return (-1);
- if (mxml_write_string(node->value.element.name, p, putc_cb) < 0)
+ if (mxml_write_name(node->value.element.name, p, putc_cb) < 0)
return (-1);
col += strlen(node->value.element.name) + 1;
@@ -1093,7 +1291,12 @@ mxml_write_node(mxml_node_t *node, /* I - Node to write */
i > 0;
i --, attr ++)
{
- if ((col + strlen(attr->name) + strlen(attr->value) + 3) > MXML_WRAP)
+ width = strlen(attr->name);
+
+ if (attr->value)
+ width += strlen(attr->value) + 3;
+
+ if ((col + width) > MXML_WRAP)
{
if ((*putc_cb)('\n', p) < 0)
return (-1);
@@ -1108,18 +1311,22 @@ mxml_write_node(mxml_node_t *node, /* I - Node to write */
col ++;
}
- if (mxml_write_string(attr->name, p, putc_cb) < 0)
- return (-1);
- if ((*putc_cb)('=', p) < 0)
- return (-1);
- if ((*putc_cb)('\"', p) < 0)
- return (-1);
- if (mxml_write_string(attr->value, p, putc_cb) < 0)
+ if (mxml_write_name(attr->name, p, putc_cb) < 0)
return (-1);
- if ((*putc_cb)('\"', p) < 0)
- return (-1);
-
- col += strlen(attr->name) + strlen(attr->value) + 3;
+
+ if (attr->value)
+ {
+ if ((*putc_cb)('=', p) < 0)
+ return (-1);
+ if ((*putc_cb)('\"', p) < 0)
+ return (-1);
+ if (mxml_write_string(attr->value, p, putc_cb) < 0)
+ return (-1);
+ if ((*putc_cb)('\"', p) < 0)
+ return (-1);
+ }
+
+ col += width;
}
if (node->child)
@@ -1440,5 +1647,5 @@ mxml_write_ws(mxml_node_t *node, /* I - Current node */
/*
- * End of "$Id: mxml-file.c,v 1.21 2003/09/28 21:09:04 mike Exp $".
+ * End of "$Id: mxml-file.c,v 1.22 2003/12/01 15:27:47 mike Exp $".
*/