Add new mxmlLoadFd() and mxmlSaveFd() functions.

This commit is contained in:
Michael R Sweet 2004-07-11 13:14:07 +00:00
parent 666dd31820
commit 3cc3f8a63d
8 changed files with 913 additions and 70 deletions

View File

@ -1,5 +1,10 @@
CHANGES - 06/25/2004
-------------------
CHANGES - 07/11/2004
--------------------
CHANGES IN Mini-XML 2.1
- Added mxmlLoadFd() and mxmlSaveFd() functions.
CHANGES IN Mini-XML 2.0

View File

@ -2,7 +2,7 @@
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
<head>
<title>Documentation</title>
<meta name='creator' content='Mini-XML v2.0rc1'/>
<meta name='creator' content='Mini-XML v2.0'/>
<style><!--
h1, h2, h3, p { font-family: sans-serif; text-align: justify; }
tt, pre a:link, pre a:visited, tt a:link, tt a:visited { font-weight: bold; color: #7f0000; }
@ -56,6 +56,7 @@
<li><a href='#mxmlIndexFind'><tt>mxmlIndexFind()</tt></a></li>
<li><a href='#mxmlIndexNew'><tt>mxmlIndexNew()</tt></a></li>
<li><a href='#mxmlIndexReset'><tt>mxmlIndexReset()</tt></a></li>
<li><a href='#mxmlLoadFd'><tt>mxmlLoadFd()</tt></a></li>
<li><a href='#mxmlLoadFile'><tt>mxmlLoadFile()</tt></a></li>
<li><a href='#mxmlLoadString'><tt>mxmlLoadString()</tt></a></li>
<li><a href='#mxmlNewElement'><tt>mxmlNewElement()</tt></a></li>
@ -66,6 +67,7 @@
<li><a href='#mxmlNewTextf'><tt>mxmlNewTextf()</tt></a></li>
<li><a href='#mxmlRemove'><tt>mxmlRemove()</tt></a></li>
<li><a href='#mxmlSaveAllocString'><tt>mxmlSaveAllocString()</tt></a></li>
<li><a href='#mxmlSaveFd'><tt>mxmlSaveFd()</tt></a></li>
<li><a href='#mxmlSaveFile'><tt>mxmlSaveFile()</tt></a></li>
<li><a href='#mxmlSaveString'><tt>mxmlSaveString()</tt></a></li>
<li><a href='#mxmlSetElement'><tt>mxmlSetElement()</tt></a></li>
@ -424,6 +426,40 @@ mxmlIndexReset(
<h4>Returns</h4>
<p>First node or NULL if there is none</p>
<!-- NEW PAGE -->
<h3><a name='mxmlLoadFd'>mxmlLoadFd()</a></h3>
<hr noshade/>
<h4>Description</h4>
<p>Load a file descriptor into an XML node tree.
The nodes in the specified file are added to the specified top node.
If no top node is provided, the XML file MUST be well-formed with a
single parent node like &lt;?xml&gt; for the entire file. The callback
function returns the value type that should be used for child nodes.
If MXML_NO_CALLBACK is specified then all child nodes will be either
MXML_ELEMENT or MXML_TEXT nodes.
The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
child nodes of the specified type.</p>
<h4>Syntax</h4>
<pre>
<a href='#mxml_node_t'>mxml_node_t</a> *
mxmlLoadFd(
<a href='#mxml_node_t'>mxml_node_t</a> * top,
int fd,
<a href='#mxml_type_t'>mxml_type_t</a> (*cb)(mxml_node_t *node));
</pre>
<h4>Arguments</h4>
<p class='table'><table align='center' border='1' width='80%' cellpadding='5' cellspacing='0' width='80%'>
<thead><tr bgcolor='#cccccc'><th>Name</th><th>Description</th></tr></thead>
<tbody>
<tr><td><tt>top</tt></td><td>Top node</td></tr>
<tr><td><tt>fd</tt></td><td>File descriptor to read from</td></tr>
<tr><td><tt>(*cb)(mxml_node_t *node)</tt></td><td>Callback function or MXML_NO_CALLBACK</td></tr>
</tbody></table></p>
<h4>Returns</h4>
<p>First node or NULL if the file could not be read.</p>
<!-- NEW PAGE -->
<h3><a name='mxmlLoadFile'>mxmlLoadFile()</a></h3>
<hr noshade/>
<h4>Description</h4>
@ -684,7 +720,13 @@ This function returns a pointer to a string containing the textual
representation of the XML node tree. The string should be freed
using the free() function when you are done with it. NULL is returned
if the node would produce an empty string or if the string cannot be
allocated.</p>
allocated.
The callback argument specifies a function that returns a whitespace
string or NULL before and after each element. If MXML_NO_CALLBACK
is specified, whitespace will only be added before MXML_TEXT nodes
with leading whitespace and before attribute names inside opening
element tags.</p>
<h4>Syntax</h4>
<pre>
char *
@ -702,13 +744,42 @@ mxmlSaveAllocString(
<h4>Returns</h4>
<p>Allocated string or NULL</p>
<!-- NEW PAGE -->
<h3><a name='mxmlSaveFd'>mxmlSaveFd()</a></h3>
<hr noshade/>
<h4>Description</h4>
<p>Save an XML tree to a file descriptor.
The callback argument specifies a function that returns a whitespace
string or NULL before and after each element. If MXML_NO_CALLBACK
is specified, whitespace will only be added before MXML_TEXT nodes
with leading whitespace and before attribute names inside opening
element tags.</p>
<h4>Syntax</h4>
<pre>
int
mxmlSaveFd(
<a href='#mxml_node_t'>mxml_node_t</a> * node,
int fd,
const char * (*cb)(mxml_node_t *node, int ws));
</pre>
<h4>Arguments</h4>
<p class='table'><table align='center' border='1' width='80%' cellpadding='5' cellspacing='0' width='80%'>
<thead><tr bgcolor='#cccccc'><th>Name</th><th>Description</th></tr></thead>
<tbody>
<tr><td><tt>node</tt></td><td>Node to write</td></tr>
<tr><td><tt>fd</tt></td><td>File descriptor to write to</td></tr>
<tr><td><tt>(*cb)(mxml_node_t *node, int ws)</tt></td><td>Whitespace callback or MXML_NO_CALLBACK</td></tr>
</tbody></table></p>
<h4>Returns</h4>
<p>0 on success, -1 on error.</p>
<!-- NEW PAGE -->
<h3><a name='mxmlSaveFile'>mxmlSaveFile()</a></h3>
<hr noshade/>
<h4>Description</h4>
<p>Save an XML tree to a file.
The callback argument specifies a function that returns a whitespace
character or nul (0) before and after each element. If MXML_NO_CALLBACK
string or NULL before and after each element. If MXML_NO_CALLBACK
is specified, whitespace will only be added before MXML_TEXT nodes
with leading whitespace and before attribute names inside opening
element tags.</p>
@ -738,7 +809,13 @@ mxmlSaveFile(
This function returns the total number of bytes that would be
required for the string but only copies (bufsize - 1) characters
into the specified buffer.</p>
into the specified buffer.
The callback argument specifies a function that returns a whitespace
string or NULL before and after each element. If MXML_NO_CALLBACK
is specified, whitespace will only be added before MXML_TEXT nodes
with leading whitespace and before attribute names inside opening
element tags.</p>
<h4>Syntax</h4>
<pre>
int
@ -980,6 +1057,7 @@ mxmlWalkPrev(
<h2><a name='_structures'>Structures</a></h2>
<ul>
<li><a href='#mxml_attr_s'><tt>mxml_attr_s</tt></a></li>
<li><a href='#mxml_fdbuf_s'><tt>mxml_fdbuf_s</tt></a></li>
<li><a href='#mxml_index_s'><tt>mxml_index_s</tt></a></li>
<li><a href='#mxml_node_s'><tt>mxml_node_s</tt></a></li>
<li><a href='#mxml_text_s'><tt>mxml_text_s</tt></a></li>
@ -1006,6 +1084,28 @@ struct mxml_attr_s
<tr><td><tt>value</tt></td><td>Attribute value</td></tr>
</tbody></table></p>
<!-- NEW PAGE -->
<h3><a name='mxml_fdbuf_s'>mxml_fdbuf_s</a></h3>
<hr noshade/>
<h4>Description</h4>
<p>File descriptor buffer (@private)</p>
<h4>Definition</h4>
<pre>
struct mxml_fdbuf_s
{
end buffer[8192];
unsigned char * current;
int fd;
};
</pre>
<h4>Members</h4>
<p class='table'><table align='center' border='1' width='80%' cellpadding='5' cellspacing='0' width='80%'>
<thead><tr bgcolor='#cccccc'><th>Name</th><th>Description</th></tr></thead>
<tbody>
<tr><td><tt>buffer[8192]</tt></td><td>Character buffer</td></tr>
<tr><td><tt>current</tt></td><td>Current position in buffer</td></tr>
<tr><td><tt>fd</tt></td><td>File descriptor</td></tr>
</tbody></table></p>
<!-- NEW PAGE -->
<h3><a name='mxml_index_s'>mxml_index_s</a></h3>
<hr noshade/>
<h4>Description</h4>
@ -1108,6 +1208,7 @@ struct mxml_value_s
<ul>
<li><a href='#mxml_attr_t'><tt>mxml_attr_t</tt></a></li>
<li><a href='#mxml_element_t'><tt>mxml_element_t</tt></a></li>
<li><a href='#mxml_fdbuf_t'><tt>mxml_fdbuf_t</tt></a></li>
<li><a href='#mxml_index_t'><tt>mxml_index_t</tt></a></li>
<li><a href='#mxml_node_t'><tt>mxml_node_t</tt></a></li>
<li><a href='#mxml_text_t'><tt>mxml_text_t</tt></a></li>
@ -1133,6 +1234,15 @@ typedef struct <a href='#mxml_attr_s'>mxml_attr_s</a> mxml_attr_t;
typedef struct <a href='#mxml_value_s'>mxml_value_s</a> mxml_element_t;
</pre>
<!-- NEW PAGE -->
<h3><a name='mxml_fdbuf_t'>mxml_fdbuf_t</a></h3>
<hr noshade/>
<h4>Description</h4>
<p>File descriptor buffer (@private)</p>
<h4>Definition</h4>
<pre>
typedef struct <a href='#mxml_fdbuf_s'>mxml_fdbuf_s</a> mxml_fdbuf_t;
</pre>
<!-- NEW PAGE -->
<h3><a name='mxml_index_t'>mxml_index_t</a></h3>
<hr noshade/>
<h4>Description</h4>

View File

@ -3,6 +3,14 @@
<h1 align='right'><a name='RELNOTES'>B - Release Notes</a></h1>
<h2>Changes in Mini-XML 2.1</h2>
<ul>
<li>Added mxmlLoadFd() and mxmlSaveFd() functions.
</ul>
<h2>Changes in Mini-XML 2.0</h2>
<ul>

View File

@ -1,5 +1,5 @@
/*
* "$Id: mxml-file.c,v 1.33 2004/06/25 18:52:34 mike Exp $"
* "$Id: mxml-file.c,v 1.34 2004/07/11 13:14:07 mike Exp $"
*
* File loading code for Mini-XML, a small XML-like file parsing library.
*
@ -17,16 +17,22 @@
*
* Contents:
*
* mxmlLoadFd() - Load a file descriptor into an XML node tree.
* mxmlLoadFile() - Load a file into an XML node tree.
* mxmlLoadString() - Load a string into an XML node tree.
* mxmlSaveAllocString() - Save an XML node tree to an allocated string.
* mxmlSaveFd() - Save an XML tree to a file descriptor.
* mxmlSaveFile() - Save an XML tree to a file.
* mxmlSaveString() - Save an XML node tree to a string.
* mxmlSetErrorCallback() - Set the error message callback.
* mxml_add_char() - Add a character to a buffer, expanding as needed.
* mxml_get_entity() - Get the character corresponding to an entity...
* mxml_fd_getc() - Read a character from a file descriptor.
* mxml_fd_putc() - Write a character to a file descriptor.
* mxml_fd_read() - Read a buffer of data from a file descriptor.
* mxml_fd_write() - Write a buffer of data to a file descriptor.
* mxml_file_getc() - Get a character from a file.
* mxml_file_putc() - Write a character to a file.
* mxml_get_entity() - Get the character corresponding to an entity...
* 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.
@ -42,6 +48,11 @@
#include "config.h"
#include "mxml.h"
#ifdef WIN32
# include <io.h>
#else
# include <unistd.h>
#endif /* WIN32 */
/*
@ -53,6 +64,19 @@
#define ENCODE_UTF16LE 2 /* UTF-16 Little-Endian */
/*
* File descriptor buffer...
*/
typedef struct mxml_fdbuf_s /**** File descriptor buffer (@private) ****/
{
int fd; /* File descriptor */
unsigned char *current, /* Current position in buffer */
*end, /* End of buffer */
buffer[8192]; /* Character buffer */
} mxml_fdbuf_t;
/*
* Global error handler...
*/
@ -66,11 +90,15 @@ extern void (*mxml_error_cb)(const char *);
static int mxml_add_char(int ch, char **ptr, char **buffer,
int *bufsize);
static int mxml_fd_getc(void *p, int *encoding);
static int mxml_fd_putc(int ch, void *p);
static int mxml_fd_read(mxml_fdbuf_t *buf);
static int mxml_fd_write(mxml_fdbuf_t *buf);
static int mxml_file_getc(void *p, int *encoding);
static int mxml_file_putc(int ch, void *p);
static int mxml_get_entity(mxml_node_t *parent, void *p,
int *encoding,
int (*getc_cb)(void *, int *));
static int mxml_file_getc(void *p, int *encoding);
static int mxml_file_putc(int ch, void *p);
static mxml_node_t *mxml_load_data(mxml_node_t *top, void *p,
mxml_type_t (*cb)(mxml_node_t *),
int (*getc_cb)(void *, int *));
@ -92,6 +120,46 @@ static int mxml_write_ws(mxml_node_t *node, void *p,
int col, int (*putc_cb)(int, void *));
/*
* 'mxmlLoadFd()' - Load a file descriptor into an XML node tree.
*
* The nodes in the specified file are added to the specified top node.
* If no top node is provided, the XML file MUST be well-formed with a
* single parent node like <?xml> for the entire file. The callback
* function returns the value type that should be used for child nodes.
* If MXML_NO_CALLBACK is specified then all child nodes will be either
* MXML_ELEMENT or MXML_TEXT nodes.
*
* The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
* MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
* child nodes of the specified type.
*/
mxml_node_t * /* O - First node or NULL if the file could not be read. */
mxmlLoadFd(mxml_node_t *top, /* I - Top node */
int fd, /* I - File descriptor to read from */
mxml_type_t (*cb)(mxml_node_t *node))
/* I - Callback function or MXML_NO_CALLBACK */
{
mxml_fdbuf_t buf; /* File descriptor buffer */
/*
* Initialize the file descriptor buffer...
*/
buf.fd = fd;
buf.current = buf.buffer;
buf.end = buf.buffer;
/*
* Read the XML data...
*/
return (mxml_load_data(top, &buf, cb, mxml_fd_getc));
}
/*
* 'mxmlLoadFile()' - Load a file into an XML node tree.
*
@ -113,6 +181,10 @@ mxmlLoadFile(mxml_node_t *top, /* I - Top node */
mxml_type_t (*cb)(mxml_node_t *node))
/* I - Callback function or MXML_NO_CALLBACK */
{
/*
* Read the XML data...
*/
return (mxml_load_data(top, fp, cb, mxml_file_getc));
}
@ -138,6 +210,10 @@ mxmlLoadString(mxml_node_t *top, /* I - Top node */
mxml_type_t (*cb)(mxml_node_t *node))
/* I - Callback function or MXML_NO_CALLBACK */
{
/*
* Read the XML data...
*/
return (mxml_load_data(top, &s, cb, mxml_string_getc));
}
@ -150,6 +226,12 @@ mxmlLoadString(mxml_node_t *top, /* I - Top node */
* using the free() function when you are done with it. NULL is returned
* if the node would produce an empty string or if the string cannot be
* allocated.
*
* The callback argument specifies a function that returns a whitespace
* string or NULL before and after each element. If MXML_NO_CALLBACK
* is specified, whitespace will only be added before MXML_TEXT nodes
* with leading whitespace and before attribute names inside opening
* element tags.
*/
char * /* O - Allocated string or NULL */
@ -199,11 +281,58 @@ mxmlSaveAllocString(mxml_node_t *node, /* I - Node to write */
}
/*
* 'mxmlSaveFd()' - Save an XML tree to a file descriptor.
*
* The callback argument specifies a function that returns a whitespace
* string or NULL before and after each element. If MXML_NO_CALLBACK
* is specified, whitespace will only be added before MXML_TEXT nodes
* with leading whitespace and before attribute names inside opening
* element tags.
*/
int /* O - 0 on success, -1 on error. */
mxmlSaveFd(mxml_node_t *node, /* I - Node to write */
int fd, /* I - File descriptor to write to */
const char *(*cb)(mxml_node_t *node, int ws))
/* I - Whitespace callback or MXML_NO_CALLBACK */
{
int col; /* Final column */
mxml_fdbuf_t buf; /* File descriptor buffer */
/*
* Initialize the file descriptor buffer...
*/
buf.fd = fd;
buf.current = buf.buffer;
buf.end = buf.buffer + sizeof(buf.buffer) - 4;
/*
* Write the node...
*/
if ((col = mxml_write_node(node, &buf, cb, 0, mxml_fd_putc)) < 0)
return (-1);
if (col > 0)
if (mxml_fd_putc('\n', &buf) < 0)
return (-1);
/*
* Flush and return...
*/
return (mxml_fd_write(&buf));
}
/*
* 'mxmlSaveFile()' - Save an XML tree to a file.
*
* The callback argument specifies a function that returns a whitespace
* character or nul (0) before and after each element. If MXML_NO_CALLBACK
* string or NULL before and after each element. If MXML_NO_CALLBACK
* is specified, whitespace will only be added before MXML_TEXT nodes
* with leading whitespace and before attribute names inside opening
* element tags.
@ -243,6 +372,12 @@ mxmlSaveFile(mxml_node_t *node, /* I - Node to write */
* This function returns the total number of bytes that would be
* required for the string but only copies (bufsize - 1) characters
* into the specified buffer.
*
* The callback argument specifies a function that returns a whitespace
* string or NULL before and after each element. If MXML_NO_CALLBACK
* is specified, whitespace will only be added before MXML_TEXT nodes
* with leading whitespace and before attribute names inside opening
* element tags.
*/
int /* O - Size of string */
@ -379,59 +514,405 @@ mxml_add_char(int ch, /* I - Character to add */
/*
* 'mxml_get_entity()' - Get the character corresponding to an entity...
* 'mxml_fd_getc()' - Read a character from a file descriptor.
*/
static int /* O - Character value or EOF on error */
mxml_get_entity(mxml_node_t *parent, /* I - Parent node */
void *p, /* I - Pointer to source */
int *encoding, /* IO - Character encoding */
int (*getc_cb)(void *, int *))
/* I - Get character function */
static int /* O - Character or EOF */
mxml_fd_getc(void *p, /* I - File descriptor buffer */
int *encoding) /* IO - Encoding */
{
int ch; /* Current character */
char entity[64], /* Entity string */
*entptr; /* Pointer into entity */
mxml_fdbuf_t *buf; /* File descriptor buffer */
int ch, /* Current character */
temp; /* Temporary character */
entptr = entity;
/*
* Grab the next character in the buffer...
*/
while ((ch = (*getc_cb)(p, encoding)) != EOF)
if (ch > 126 || (!isalnum(ch) && ch != '#'))
break;
else if (entptr < (entity + sizeof(entity) - 1))
*entptr++ = ch;
else
{
mxml_error("Entity name too long under parent <%s>!",
parent ? parent->value.element.name : "null");
break;
}
buf = (mxml_fdbuf_t *)p;
*entptr = '\0';
if (buf->current >= buf->end)
if (mxml_fd_read(buf) < 0)
return (EOF);
if (ch != ';')
ch = *(buf->current)++;
switch (*encoding)
{
mxml_error("Character entity \"%s\" not terminated under parent <%s>!",
entity, parent ? parent->value.element.name : "null");
return (EOF);
}
case ENCODE_UTF8 :
/*
* Got a UTF-8 character; convert UTF-8 to Unicode and return...
*/
if (entity[1] == '#')
{
if (entity[2] == 'x')
ch = strtol(entity + 3, NULL, 16);
else
ch = strtol(entity + 2, NULL, 10);
if (!(ch & 0x80))
return (ch);
else if (ch == 0xfe)
{
/*
* UTF-16 big-endian BOM?
*/
if (buf->current >= buf->end)
if (mxml_fd_read(buf) < 0)
return (EOF);
ch = *(buf->current)++;
if (ch != 0xff)
return (EOF);
*encoding = ENCODE_UTF16BE;
return (mxml_fd_getc(p, encoding));
}
else if (ch == 0xff)
{
/*
* UTF-16 little-endian BOM?
*/
if (buf->current >= buf->end)
if (mxml_fd_read(buf) < 0)
return (EOF);
ch = *(buf->current)++;
if (ch != 0xfe)
return (EOF);
*encoding = ENCODE_UTF16LE;
return (mxml_fd_getc(p, encoding));
}
else if ((ch & 0xe0) == 0xc0)
{
/*
* Two-byte value...
*/
if (buf->current >= buf->end)
if (mxml_fd_read(buf) < 0)
return (EOF);
temp = *(buf->current)++;
if ((temp & 0xc0) != 0x80)
return (EOF);
ch = ((ch & 0x1f) << 6) | (temp & 0x3f);
}
else if ((ch & 0xf0) == 0xe0)
{
/*
* Three-byte value...
*/
if (buf->current >= buf->end)
if (mxml_fd_read(buf) < 0)
return (EOF);
temp = *(buf->current)++;
if ((temp & 0xc0) != 0x80)
return (EOF);
ch = ((ch & 0x0f) << 6) | (temp & 0x3f);
if (buf->current >= buf->end)
if (mxml_fd_read(buf) < 0)
return (EOF);
temp = *(buf->current)++;
if ((temp & 0xc0) != 0x80)
return (EOF);
ch = (ch << 6) | (temp & 0x3f);
}
else if ((ch & 0xf8) == 0xf0)
{
/*
* Four-byte value...
*/
if (buf->current >= buf->end)
if (mxml_fd_read(buf) < 0)
return (EOF);
temp = *(buf->current)++;
if ((temp & 0xc0) != 0x80)
return (EOF);
ch = ((ch & 0x07) << 6) | (temp & 0x3f);
if (buf->current >= buf->end)
if (mxml_fd_read(buf) < 0)
return (EOF);
temp = *(buf->current)++;
if ((temp & 0xc0) != 0x80)
return (EOF);
ch = (ch << 6) | (temp & 0x3f);
if (buf->current >= buf->end)
if (mxml_fd_read(buf) < 0)
return (EOF);
temp = *(buf->current)++;
if ((temp & 0xc0) != 0x80)
return (EOF);
ch = (ch << 6) | (temp & 0x3f);
}
else
return (EOF);
break;
case ENCODE_UTF16BE :
/*
* Read UTF-16 big-endian char...
*/
if (buf->current >= buf->end)
if (mxml_fd_read(buf) < 0)
return (EOF);
temp = *(buf->current)++;
ch = (ch << 8) | temp;
if (ch >= 0xd800 && ch <= 0xdbff)
{
/*
* Multi-word UTF-16 char...
*/
int lch;
if (buf->current >= buf->end)
if (mxml_fd_read(buf) < 0)
return (EOF);
lch = *(buf->current)++;
if (buf->current >= buf->end)
if (mxml_fd_read(buf) < 0)
return (EOF);
temp = *(buf->current)++;
lch = (lch << 8) | temp;
if (lch < 0xdc00 || lch >= 0xdfff)
return (EOF);
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
}
break;
case ENCODE_UTF16LE :
/*
* Read UTF-16 little-endian char...
*/
if (buf->current >= buf->end)
if (mxml_fd_read(buf) < 0)
return (EOF);
temp = *(buf->current)++;
ch |= (temp << 8);
if (ch >= 0xd800 && ch <= 0xdbff)
{
/*
* Multi-word UTF-16 char...
*/
int lch;
if (buf->current >= buf->end)
if (mxml_fd_read(buf) < 0)
return (EOF);
lch = *(buf->current)++;
if (buf->current >= buf->end)
if (mxml_fd_read(buf) < 0)
return (EOF);
temp = *(buf->current)++;
lch |= (temp << 8);
if (lch < 0xdc00 || lch >= 0xdfff)
return (EOF);
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
}
break;
}
else if ((ch = mxmlEntityGetValue(entity)) < 0)
mxml_error("Entity name \"%s;\" not supported under parent <%s>!",
entity, parent ? parent->value.element.name : "null");
return (ch);
}
/*
* 'mxml_fd_putc()' - Write a character to a file descriptor.
*/
static int /* O - 0 on success, -1 on error */
mxml_fd_putc(int ch, /* I - Character */
void *p) /* I - File descriptor buffer */
{
mxml_fdbuf_t *buf; /* File descriptor buffer */
/*
* Flush the write buffer as needed - note above that "end" still leaves
* 4 characters at the end so that we can avoid a lot of extra tests...
*/
buf = (mxml_fdbuf_t *)p;
if (buf->current >= buf->end)
if (mxml_fd_write(buf) < 0)
return (-1);
if (ch < 128)
{
/*
* Write ASCII character directly...
*/
*(buf->current)++ = ch;
}
else if (ch < 2048)
{
/*
* Two-byte UTF-8 character...
*/
*(buf->current)++ = 0xc0 | (ch >> 6);
*(buf->current)++ = 0x80 | (ch & 0x3f);
}
else if (ch < 65536)
{
/*
* Three-byte UTF-8 character...
*/
*(buf->current)++ = 0xe0 | (ch >> 12);
*(buf->current)++ = 0x80 | ((ch >> 6) & 0x3f);
*(buf->current)++ = 0x80 | (ch & 0x3f);
}
else
{
/*
* Four-byte UTF-8 character...
*/
*(buf->current)++ = 0xf0 | (ch >> 18);
*(buf->current)++ = 0x80 | ((ch >> 12) & 0x3f);
*(buf->current)++ = 0x80 | ((ch >> 6) & 0x3f);
*(buf->current)++ = 0x80 | (ch & 0x3f);
}
/*
* Return successfully...
*/
return (0);
}
/*
* 'mxml_fd_read()' - Read a buffer of data from a file descriptor.
*/
static int /* O - 0 on success, -1 on error */
mxml_fd_read(mxml_fdbuf_t *buf) /* I - File descriptor buffer */
{
int bytes; /* Bytes read... */
/*
* Range check input...
*/
if (!buf)
return (-1);
/*
* Read from the file descriptor...
*/
while ((bytes = read(buf->fd, buf->buffer, sizeof(buf->buffer))) < 0)
if (errno != EAGAIN && errno != EINTR)
return (-1);
if (bytes == 0)
return (-1);
/*
* Update the pointers and return success...
*/
buf->current = buf->buffer;
buf->end = buf->buffer + bytes;
return (0);
}
/*
* 'mxml_fd_write()' - Write a buffer of data to a file descriptor.
*/
static int /* O - 0 on success, -1 on error */
mxml_fd_write(mxml_fdbuf_t *buf) /* I - File descriptor buffer */
{
int bytes; /* Bytes written */
unsigned char *ptr; /* Pointer into buffer */
/*
* Range check...
*/
if (!buf)
return (-1);
/*
* Return 0 if there is nothing to write...
*/
if (buf->current == buf->buffer)
return (0);
/*
* Loop until we have written everything...
*/
for (ptr = buf->buffer; ptr < buf->current; ptr += bytes)
if ((bytes = write(buf->fd, ptr, buf->current - ptr)) < 0)
return (-1);
/*
* All done, reset pointers and return success...
*/
buf->current = buf->buffer;
return (0);
}
/*
* 'mxml_file_getc()' - Get a character from a file.
*/
@ -559,7 +1040,7 @@ mxml_file_getc(void *p, /* I - Pointer to file */
int lch = (getc(fp) << 8) | getc(fp);
if (ch < 0xdc00 || ch >= 0xdfff)
if (lch < 0xdc00 || lch >= 0xdfff)
return (EOF);
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
@ -581,7 +1062,7 @@ mxml_file_getc(void *p, /* I - Pointer to file */
int lch = getc(fp) | (getc(fp) << 8);
if (ch < 0xdc00 || ch >= 0xdfff)
if (lch < 0xdc00 || lch >= 0xdfff)
return (EOF);
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
@ -648,6 +1129,60 @@ mxml_file_putc(int ch, /* I - Character to write */
}
/*
* 'mxml_get_entity()' - Get the character corresponding to an entity...
*/
static int /* O - Character value or EOF on error */
mxml_get_entity(mxml_node_t *parent, /* I - Parent node */
void *p, /* I - Pointer to source */
int *encoding, /* IO - Character encoding */
int (*getc_cb)(void *, int *))
/* I - Get character function */
{
int ch; /* Current character */
char entity[64], /* Entity string */
*entptr; /* Pointer into entity */
entptr = entity;
while ((ch = (*getc_cb)(p, encoding)) != EOF)
if (ch > 126 || (!isalnum(ch) && ch != '#'))
break;
else if (entptr < (entity + sizeof(entity) - 1))
*entptr++ = ch;
else
{
mxml_error("Entity name too long under parent <%s>!",
parent ? parent->value.element.name : "null");
break;
}
*entptr = '\0';
if (ch != ';')
{
mxml_error("Character entity \"%s\" not terminated under parent <%s>!",
entity, parent ? parent->value.element.name : "null");
return (EOF);
}
if (entity[1] == '#')
{
if (entity[2] == 'x')
ch = strtol(entity + 3, NULL, 16);
else
ch = strtol(entity + 2, NULL, 10);
}
else if ((ch = mxmlEntityGetValue(entity)) < 0)
mxml_error("Entity name \"%s;\" not supported under parent <%s>!",
entity, parent ? parent->value.element.name : "null");
return (ch);
}
/*
* 'mxml_load_data()' - Load data into an XML node tree.
*/
@ -1419,7 +1954,7 @@ mxml_string_getc(void *p, /* I - Pointer to file */
lch = ((*s[0] & 255) << 8) | (*s[1] & 255);
(*s) += 2;
if (ch < 0xdc00 || ch >= 0xdfff)
if (lch < 0xdc00 || lch >= 0xdfff)
return (EOF);
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
@ -1457,7 +1992,7 @@ mxml_string_getc(void *p, /* I - Pointer to file */
lch = ((*s[1] & 255) << 8) | (*s[0] & 255);
(*s) += 2;
if (ch < 0xdc00 || ch >= 0xdfff)
if (lch < 0xdc00 || lch >= 0xdfff)
return (EOF);
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
@ -1636,7 +2171,6 @@ mxml_write_node(mxml_node_t *node, /* I - Node to write */
width; /* Width of attr + value */
mxml_attr_t *attr; /* Current attribute */
char s[255]; /* Temporary string */
int slen; /* Length of temporary string */
while (node != NULL)
@ -1936,5 +2470,5 @@ mxml_write_ws(mxml_node_t *node, /* I - Current node */
/*
* End of "$Id: mxml-file.c,v 1.33 2004/06/25 18:52:34 mike Exp $".
* End of "$Id: mxml-file.c,v 1.34 2004/07/11 13:14:07 mike Exp $".
*/

8
mxml.h
View File

@ -1,5 +1,5 @@
/*
* "$Id: mxml.h,v 1.21 2004/06/01 20:19:34 mike Exp $"
* "$Id: mxml.h,v 1.22 2004/07/11 13:14:07 mike Exp $"
*
* Header file for Mini-XML, a small XML-like file parsing library.
*
@ -161,6 +161,8 @@ extern mxml_node_t *mxmlIndexFind(mxml_index_t *ind,
extern mxml_index_t *mxmlIndexNew(mxml_node_t *node, const char *element,
const char *attr);
extern mxml_node_t *mxmlIndexReset(mxml_index_t *ind);
extern mxml_node_t *mxmlLoadFd(mxml_node_t *top, int fd,
mxml_type_t (*cb)(mxml_node_t *));
extern mxml_node_t *mxmlLoadFile(mxml_node_t *top, FILE *fp,
mxml_type_t (*cb)(mxml_node_t *));
extern mxml_node_t *mxmlLoadString(mxml_node_t *top, const char *s,
@ -180,6 +182,8 @@ __attribute__ ((__format__ (__printf__, 3, 4)))
extern void mxmlRemove(mxml_node_t *node);
extern char *mxmlSaveAllocString(mxml_node_t *node,
const char *(*cb)(mxml_node_t *, int));
extern int mxmlSaveFd(mxml_node_t *node, int fd,
const char *(*cb)(mxml_node_t *, int));
extern int mxmlSaveFile(mxml_node_t *node, FILE *fp,
const char *(*cb)(mxml_node_t *, int));
extern int mxmlSaveString(mxml_node_t *node, char *buffer,
@ -225,5 +229,5 @@ extern mxml_type_t mxml_real_cb(mxml_node_t *node);
/*
* End of "$Id: mxml.h,v 1.21 2004/06/01 20:19:34 mike Exp $".
* End of "$Id: mxml.h,v 1.22 2004/07/11 13:14:07 mike Exp $".
*/

View File

@ -243,6 +243,36 @@ mxmlIndexFind() for the first time.</description>
<description>Index to reset</description>
</argument>
</function>
<function name="mxmlLoadFd">
<returnvalue>
<type>mxml_node_t *</type>
<description>First node or NULL if the file could not be read.</description>
</returnvalue>
<description>Load a file descriptor into an XML node tree.
The nodes in the specified file are added to the specified top node.
If no top node is provided, the XML file MUST be well-formed with a
single parent node like &lt;?xml&gt; for the entire file. The callback
function returns the value type that should be used for child nodes.
If MXML_NO_CALLBACK is specified then all child nodes will be either
MXML_ELEMENT or MXML_TEXT nodes.
The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
child nodes of the specified type.</description>
<argument name="top" direction="I">
<type>mxml_node_t *</type>
<description>Top node</description>
</argument>
<argument name="fd" direction="I">
<type>int</type>
<description>File descriptor to read from</description>
</argument>
<argument name="(*cb)(mxml_node_t *node)" direction="I">
<type>mxml_type_t</type>
<description>Callback function or MXML_NO_CALLBACK</description>
</argument>
</function>
<function name="mxmlLoadFile">
<returnvalue>
<type>mxml_node_t *</type>
@ -454,7 +484,13 @@ This function returns a pointer to a string containing the textual
representation of the XML node tree. The string should be freed
using the free() function when you are done with it. NULL is returned
if the node would produce an empty string or if the string cannot be
allocated.</description>
allocated.
The callback argument specifies a function that returns a whitespace
string or NULL before and after each element. If MXML_NO_CALLBACK
is specified, whitespace will only be added before MXML_TEXT nodes
with leading whitespace and before attribute names inside opening
element tags.</description>
<argument name="node" direction="I">
<type>mxml_node_t *</type>
<description>Node to write</description>
@ -464,6 +500,31 @@ allocated.</description>
<description>Whitespace callback or MXML_NO_CALLBACK</description>
</argument>
</function>
<function name="mxmlSaveFd">
<returnvalue>
<type>int</type>
<description>0 on success, -1 on error.</description>
</returnvalue>
<description>Save an XML tree to a file descriptor.
The callback argument specifies a function that returns a whitespace
string or NULL before and after each element. If MXML_NO_CALLBACK
is specified, whitespace will only be added before MXML_TEXT nodes
with leading whitespace and before attribute names inside opening
element tags.</description>
<argument name="node" direction="I">
<type>mxml_node_t *</type>
<description>Node to write</description>
</argument>
<argument name="fd" direction="I">
<type>int</type>
<description>File descriptor to write to</description>
</argument>
<argument name="(*cb)(mxml_node_t *node, int ws)" direction="I">
<type>const char *</type>
<description>Whitespace callback or MXML_NO_CALLBACK</description>
</argument>
</function>
<function name="mxmlSaveFile">
<returnvalue>
<type>int</type>
@ -472,7 +533,7 @@ allocated.</description>
<description>Save an XML tree to a file.
The callback argument specifies a function that returns a whitespace
character or nul (0) before and after each element. If MXML_NO_CALLBACK
string or NULL before and after each element. If MXML_NO_CALLBACK
is specified, whitespace will only be added before MXML_TEXT nodes
with leading whitespace and before attribute names inside opening
element tags.</description>
@ -498,7 +559,13 @@ element tags.</description>
This function returns the total number of bytes that would be
required for the string but only copies (bufsize - 1) characters
into the specified buffer.</description>
into the specified buffer.
The callback argument specifies a function that returns a whitespace
string or NULL before and after each element. If MXML_NO_CALLBACK
is specified, whitespace will only be added before MXML_TEXT nodes
with leading whitespace and before attribute names inside opening
element tags.</description>
<argument name="node" direction="I">
<type>mxml_node_t *</type>
<description>Node to write</description>
@ -701,6 +768,25 @@ the walk to the node's children.</description>
<type>struct mxml_value_s</type>
<description>An XML element value.</description>
</typedef>
<struct name="mxml_fdbuf_s">
<description>File descriptor buffer (@private)</description>
<variable name="buffer[8192]">
<type>end</type>
<description>Character buffer</description>
</variable>
<variable name="current">
<type>unsigned char *</type>
<description>Current position in buffer</description>
</variable>
<variable name="fd">
<type>int</type>
<description>File descriptor</description>
</variable>
</struct>
<typedef name="mxml_fdbuf_t">
<type>struct mxml_fdbuf_s</type>
<description>File descriptor buffer (@private)</description>
</typedef>
<struct name="mxml_index_s">
<description>An XML node index.</description>
<variable name="alloc_nodes">

View File

@ -3,7 +3,7 @@
<keyword type="opaque">InputSlot</keyword>
<default type="opaque">Auto</default>
<text>Media Source</text>
<order type="real">10.0</order>
<order type="real">10.000000</order>
<choice>
<keyword type="opaque">Auto</keyword>
<text>Auto Tray Selection</text>
@ -12,16 +12,13 @@
<choice>
<keyword type="opaque">Upper</keyword>
<text>Tray 1</text>
<code type="opaque">&lt;&lt;/MediaPosition 0>>setpagedevice</code>
<code type="opaque">&lt;&lt;/MediaPosition 0&gt;&gt;setpagedevice</code>
</choice>
<choice>
<keyword type="opaque">Lower</keyword>
<text>Tray 2</text>
<code type="opaque">&lt;&lt;/MediaPosition 1>>setpagedevice</code>
<code type="opaque">&lt;&lt;/MediaPosition 1&gt;&gt;setpagedevice</code>
</choice>
</option>
<integer>123</integer>
<string>Now is the time for all good men to come to the aid of
their country.</string>
<string>Now is the time for all good men to come to the aid of their country.</string>

View File

@ -1,5 +1,5 @@
/*
* "$Id: testmxml.c,v 1.17 2004/05/16 18:25:20 mike Exp $"
* "$Id: testmxml.c,v 1.18 2004/07/11 13:14:07 mike Exp $"
*
* Test program for Mini-XML, a small XML-like file parsing library.
*
@ -29,6 +29,12 @@
#include "config.h"
#include "mxml.h"
#ifdef WIN32
# include <io.h>
#else
# include <unistd.h>
# include <fcntl.h>
#endif /* WIN32 */
/*
@ -49,6 +55,7 @@ main(int argc, /* I - Number of command-line args */
{
int i; /* Looping var */
FILE *fp; /* File to read */
int fd; /* File descriptor */
mxml_node_t *tree, /* XML tree */
*node; /* Node which should be in test.xml */
mxml_index_t *ind; /* XML index */
@ -456,11 +463,67 @@ main(int argc, /* I - Number of command-line args */
fputs(buffer, stderr);
/*
* Delete the tree and return...
* Delete the tree...
*/
mxmlDelete(tree);
/*
* Read from/write to file descriptors...
*/
if (argv[1][0] != '<')
{
/*
* Open the file again...
*/
if ((fd = open(argv[1], O_RDONLY)) < 0)
{
perror(argv[1]);
return (1);
}
/*
* Read the file...
*/
tree = mxmlLoadFd(NULL, fd, type_cb);
close(fd);
/*
* Create filename.xmlfd...
*/
snprintf(buffer, sizeof(buffer), "%sfd", argv[1]);
if ((fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
{
perror(buffer);
mxmlDelete(tree);
return (1);
}
/*
* Write the file...
*/
mxmlSaveFd(tree, fd, whitespace_cb);
close(fd);
/*
* Delete the tree...
*/
mxmlDelete(tree);
}
/*
* Return...
*/
return (0);
}
@ -502,7 +565,12 @@ const char * /* O - Whitespace string or NULL */
whitespace_cb(mxml_node_t *node, /* I - Element node */
int where) /* I - Open or close tag? */
{
const char *name; /* Name of element */
mxml_node_t *parent; /* Parent node */
int level; /* Indentation level */
const char *name; /* Name of element */
static const char *tabs = "\t\t\t\t\t\t\t\t";
/* Tabs for indentation */
/*
* We can conditionally break to a new line before or after any element.
@ -542,6 +610,37 @@ whitespace_cb(mxml_node_t *node, /* I - Element node */
else if (where == MXML_WS_AFTER_CLOSE)
return ("\n");
}
else if (!strcmp(name, "?xml"))
{
return (NULL);
}
else if (!strcmp(name, "option"))
{
if (where == MXML_WS_AFTER_OPEN || where == MXML_WS_AFTER_CLOSE)
return ("\n");
}
else if (!strcmp(name, "choice"))
{
if (where == MXML_WS_BEFORE_OPEN || where == MXML_WS_BEFORE_CLOSE)
return ("\t");
else
return ("\n");
}
else if (where == MXML_WS_BEFORE_OPEN)
{
for (level = -1, parent = node->parent;
parent;
level ++, parent = parent->parent);
if (level > 8)
level = 8;
return (tabs + 8 - level);
}
else if (where == MXML_WS_AFTER_CLOSE)
return ("\n");
else if (!strcmp(name, "code") && where == MXML_WS_AFTER_OPEN && !node->child)
return ("\n");
/*
* Return NULL for no added whitespace...
@ -552,5 +651,5 @@ whitespace_cb(mxml_node_t *node, /* I - Element node */
/*
* End of "$Id: testmxml.c,v 1.17 2004/05/16 18:25:20 mike Exp $".
* End of "$Id: testmxml.c,v 1.18 2004/07/11 13:14:07 mike Exp $".
*/