Save work on documentation.

Add SAX load APIs.

Add man page output for mxmldoc.

Add types for various callback functions.
This commit is contained in:
Michael R Sweet 2007-04-23 21:48:03 +00:00
parent 0f8052e766
commit bf73da6782
19 changed files with 2527 additions and 960 deletions

View File

@ -1,10 +1,11 @@
CHANGES - 2007-04-19
CHANGES - 2007-04-22
--------------------
CHANGES IN Mini-XML 2.3
- Added two exceptions to the LGPL to support static
linking of applications against Mini-XML
- The mxmldoc utility can now generate man pages, too.
- Added a mxmlNewXML() function
- Added a mxmlElementSetAttrf() function (STR #43)
- Added snprintf() emulation function for test program (STR

View File

@ -113,7 +113,7 @@ all: Makefile config.h $(TARGETS)
#
clean:
$(RM) $(OBJS) $(TARGETS)
$(RM) $(OBJS) $(TARGETS) doc/mxml.man
$(RM) mxmldoc-static libmxml.a
@ -349,6 +349,16 @@ valgrind: mxmldoc-static
>valgrind.html 2>valgrind.out
#
# doc/mxml.man
#
doc/mxml.man: mxmldoc-static mxml.xml
$(RM) doc/mxml.man
./mxmldoc-static --man mxml --title "Mini-XML API" \
--intro doc/intro.man mxml.xml >doc/mxml.man
#
# All object files depend on the makefile...
#

View File

@ -346,6 +346,7 @@ function:</p>
</pre>
<!-- NEED 20 -->
<h2>Changing Node Values</h2>
<p>All of the examples so far have concentrated on creating and
@ -483,5 +484,147 @@ function:</p>
mxmlIndexDelete(ind);
</pre>
<h2>SAX (Stream) Loading of Documents</h2>
<p>Mini-XML supports an implementation of the Simple API for XML
(SAX) which allows you to load and process an XML document as a
stream of nodes. Aside from allowing you to process XML documents of
any size, the Mini-XML implementation also allows you to retain
portions of the document in memory for later processing.</p>
<p>The <a href='#mxmlSAXLoad'><tt>mxmlSAXLoadFd</tt></a>, <a
href='#mxmlSAXLoadFile'><tt>mxmlSAXLoadFile</tt></a>, and <a
href='#mxmlSAXLoadString'><tt>mxmlSAXLoadString</tt></a> functions
provide the SAX loading APIs. Each function works like the
corresponding <tt>mxmlLoad</tt> function but uses a callback to
process each node as it is read.</p>
<p>The callback function receives the node, an event code, and
a user data pointer you supply:</p>
<pre>
void
sax_cb(mxml_node_t *node, mxml_sax_event_t event,
void *data)
{
... do something ...
}
</pre>
<p>The event will be one of the following:</p>
<ul>
<li><tt>MXML_SAX_CDATA</tt> - CDATA was just read</li>
<li><tt>MXML_SAX_COMMENT</tt> - A comment was just read</li>
<li><tt>MXML_SAX_DATA</tt> - Data (custom, integer, opaque, real, or text) was just read</li>
<li><tt>MXML_SAX_DIRECTIVE</tt> - A processing directive was just read</li>
<li><tt>MXML_SAX_ELEMENT_CLOSE</tt> - An open element was just read (<tt>&lt;element&gt;</tt>)</li>
<li><tt>MXML_SAX_ELEMENT_OPEN</tt> - A close element was just read (<tt>&lt;/element&gt;</tt>)</li>
</ul>
<p>Elements are <em>released</em> after the close element is
processed. All other nodes are released after they are processed.
The SAX callback can <em>retain</em> the node using the <a
href='#mxmlRetain'><tt>mxmlRetain</tt></a> function. For example,
the following SAX callback will retain all nodes, effectively
simulating a normal in-memory load:</p>
<pre>
void
sax_cb(mxml_node_t *node, mxml_sax_event_t event,
void *data)
{
if (event != MXML_SAX_ELEMENT_CLOSE)
mxmlRetain(node);
}
</pre>
<p>More typically the SAX callback will only retain a small portion
of the document that is needed for post-processing. For example, the
following SAX callback will retain the title and headings in an
XHTML file. It also retains the (parent) elements like <tt>&lt;html&gt;</tt>, <tt>&lt;head&gt;</tt>, and <tt>&lt;body&gt;</tt>, and processing
directives like <tt>&lt;?xml ... ?&gt;</tt> and <tt>&lt;!DOCTYPE ... &gt;</tt>:</p>
<!-- NEED 10 -->
<pre>
void
sax_cb(mxml_node_t *node,
mxml_sax_event_t event,
void *data)
{
if (event == MXML_SAX_ELEMENT_OPEN)
{
/*
* Retain headings and titles...
*/
const char *name = node->value.element.name;
if (!strcmp(name, "html") ||
!strcmp(name, "head") ||
!strcmp(name, "title") ||
!strcmp(name, "body") ||
!strcmp(name, "h1") ||
!strcmp(name, "h2") ||
!strcmp(name, "h3") ||
!strcmp(name, "h4") ||
!strcmp(name, "h5") ||
!strcmp(name, "h6"))
mxmlRetain(node);
}
else if (event == MXML_SAX_DIRECTIVE)
mxmlRetain(node);
else if (event == MXML_SAX_DATA &amp;&amp;
node->parent->ref_count > 1)
{
/*
* If the parent was retained, then retain
* this data node as well.
*/
mxmlRetain(node);
}
}
</pre>
<p>The resulting skeleton document tree can then be searched just
like one loaded using the <tt>mxmlLoad</tt> functions. For example,
a filter that reads an XHTML document from stdin and then shows the
title and headings in the document would look like:</p>
<pre>
mxml_node_t *doc, *title, *body, *heading;
doc = mxmlSAXLoadFd(NULL, 0,
MXML_TEXT_CALLBACK,
<b>sax_cb</b>, NULL);
title = mxmlFindElement(doc, doc, "title",
NULL, NULL,
MXML_DESCEND);
if (title)
print_children(title);
body = mxmlFindElement(doc, doc, "body",
NULL, NULL,
MXML_DESCEND);
if (body)
{
for (heading = body->child;
heading;
heading = heading->next)
print_children(heading);
}
</pre>
</body>
</html>

View File

@ -417,27 +417,31 @@ three constants:</p>
<li><tt>MXML_NO_DESCEND</tt> means to not to look at any
child nodes in the element hierarchy, just look at
siblings at the same level or parent nodes until the top
node or top-of-tree is reached. The previous node from
"group" would be the "node" element to the left, while
the next node from "group" would be the "node" element
to the right.<br><br></li>
node or top-of-tree is reached.
<li><tt>MXML_DESCEND_FIRST</tt> means that it is OK to
descend to the first child of a node, but not to descend
further when searching. You'll normally use this when
iterating through direct children of a parent node, e.g.
all of the "node" elements under the "?xml" parent node
in the example above. This mode is only applicable to
the search function; the walk functions treat this as
<tt>MXML_DESCEND</tt> since every call is a first
time.<br><br></li>
<p>The previous node from "group" would be the "node"
element to the left, while the next node from "group" would
be the "node" element to the right.<br><br></p></li>
<li><tt>MXML_DESCEND_FIRST</tt> means that it is OK to
descend to the first child of a node, but not to descend
further when searching. You'll normally use this when
iterating through direct children of a parent node, e.g. all
of the "node" and "group" elements under the "?xml" parent
node in the example above.
<p>This mode is only applicable to the search function; the
walk functions treat this as <tt>MXML_DESCEND</tt> since
every call is a first time.<br><br></p></li>
<li><tt>MXML_DESCEND</tt> means to keep descending until
you hit the bottom of the tree. The previous node from
"group" would be the "val3" node and the next node would
be the first node element under "group". If you were to
walk from the root node "?xml" to the end of the tree
with <tt>mxmlWalkNext()</tt>, the order would be:
be the first node element under "group".
<p>If you were to walk from the root node "?xml" to the end
of the tree with <tt>mxmlWalkNext()</tt>, the order would
be:</p>
<p><tt>?xml data node val1 node val2 node val3 group node
val4 node val5 node val6 node val7 node val8</tt></p>

View File

@ -148,9 +148,9 @@ appendices:</p>
<tt>mxmldoc(1)</tt> program to generate software
documentation.</li>
<li>Appendix A, "<a href='#LICENSE'>GNU
Library General Public License</a>", provides the terms
and conditions for using and distributing Mini-XML.</li>
<li>Appendix A, "<a href='#LICENSE'>Mini-XML License</a>",
provides the terms and conditions for using and distributing
Mini-XML.</li>
<li>Appendix B, "<a href='#RELNOTES'>Release Notes</a>",
lists the changes in each release of Mini-XML.</li>

View File

@ -1,23 +1,3 @@
.\"
.\" "$Id$"
.\"
.\" mxml man page for mini-XML, a small XML-like file parsing library.
.\"
.\" Copyright 2003-2005 by Michael Sweet.
.\"
.\" This program is free software; you can redistribute it and/or
.\" modify it under the terms of the GNU Library General Public
.\" License as published by the Free Software Foundation; either
.\" version 2, or (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.TH mxml 3 "mini-XML" "2 December 2005" "Michael Sweet"
.SH NAME
mxml \- mini-xml library
.SH INCLUDE FILE
#include <mxml.h>
.SH LIBRARY
@ -171,7 +151,4 @@ is used for a particular node or the entire tree:
.SH SEE ALSO
mxmldoc(1), Mini-XML Programmers Manual, http://www.easysw.com/~mike/mxml/
.SH COPYRIGHT
Copyright 2003-2005 by Michael Sweet.
.\"
.\" End of "$Id$".
.\"
Copyright 2003-2007 by Michael Sweet.

View File

@ -3,8 +3,6 @@
<h1 align='right'><a name='LICENSE'>A - Mini-XML License</a></h1>
<p align='center'>October 18, 2005</p>
<p>The Mini-XML library and included programs are provided under
the terms of the GNU Library General Public License (LGPL) with
the following exceptions:</p>
@ -32,9 +30,9 @@ the following exceptions:</p>
</ol>
<hr noshade>
<!-- NEW PAGE -->
<p align=center><big>GNU LIBRARY GENERAL PUBLIC LICENSE</big></p>
<p align=center><b>GNU LIBRARY GENERAL PUBLIC LICENSE</b></p>
<p align='center'>Version 2, June 1991
<br />Copyright (C) 1991 Free Software Foundation, Inc.
<br />59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
@ -43,7 +41,7 @@ this license document, but changing it is not allowed.
<br />[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]</p>
<p><big>Preamble</big></p>
<p><b>Preamble</b></p>
<p>The licenses for most software are designed to take away your freedom
to share and change it. By contrast, the GNU General Public Licenses
@ -145,8 +143,8 @@ library.</p>
ordinary General Public License rather than by this special
one.</p>
<p align='center'><big>TERMS AND CONDITIONS FOR COPYING,
DISTRIBUTION AND MODIFICATION</big></p>
<p align='center'><b>TERMS AND CONDITIONS FOR COPYING,
DISTRIBUTION AND MODIFICATION</b></p>
<p><strong>0.</strong> This License Agreement applies to any
software library which contains a notice placed by the copyright
@ -511,7 +509,7 @@ by the two goals of preserving the free status of all
derivatives of our free software and of promoting the sharing
and reuse of software generally.</p>
<p align='center'><big>NO WARRANTY</big></p>
<p align='center'><b>NO WARRANTY</b></p>
<p><strong>15.</strong> BECAUSE THE LIBRARY IS LICENSED FREE OF
CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT
@ -537,54 +535,61 @@ OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.</p>
<p align='center'><big>END OF TERMS AND CONDITIONS</big></p>
<p align='center'><b>END OF TERMS AND CONDITIONS</b></p>
<p><big>How to Apply These Terms to Your New Libraries</big></p>
<p><b>How to Apply These Terms to Your New Libraries</b></p>
<p>If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
<p>If you develop a new library, and you want it to be of the
greatest possible use to the public, we recommend making it free
software that everyone can redistribute and change. You can do so
by permitting redistribution under these terms (or, alternatively,
under the terms of the ordinary General Public License).
<p>To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<p>To apply these terms, attach the following notices to the
library. It is safest to attach them to the start of each source
file to most effectively convey the exclusion of warranty; and each
file should have at least the "copyright" line and a pointer to
where the full notice is found.
<pre>
<var>one line to give the library's name and an idea of what it does.</var>
<ul>
<p><var>one line to give the library's name and an idea of what it
does.</var><br>
Copyright (C) <var>year</var> <var>name of author</var>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
<p>This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation; either version 2.1 of
the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
<p>This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
<p>You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</pre>
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA
</ul>
<p>Also add information on how to contact you by electronic and paper mail.
<p>You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
<p>You should also get your employer (if you work as a programmer)
or your school, if any, to sign a "copyright disclaimer" for the
library, if necessary. Here is a sample; alter the names:
<pre>
Yoyodyne, Inc., hereby disclaims all copyright interest in
the library `Frob' (a library for tweaking knobs) written
by James Random Hacker.
<ul>
<var>signature of Ty Coon</var>, 1 April 1990
Ty Coon, President of Vice
</pre>
<p>Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James
Random Hacker.
<p><var>signature of Ty Coon</var>, 1 April 1990 Ty Coon, President
of Vice
</ul>
<p>That's all there is to it!

View File

@ -1,36 +1,26 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<!-- SECTION: Man Pages -->
<head>
<style type='text/css'><!--
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; }
pre { font-weight: bold; color: #7f0000; margin-left: 2em; }
h1.title, h2.title, h3.title { border-bottom: solid 2px #000000; }
--></style>
<title>mxmldoc</title>
</head>
<body>
<!-- NEW PAGE -->
<h2 class='title'><a name='mxmldoc.1'>mxmldoc(1)</a></h2>
<h3 _hd_omit_toc>Name</h3>
mxmldoc - mini-xml documentation generator
<h3 _hd_omit_toc>Synopsis</h3>
<b>mxmldoc
</b>[ --intro
<i>introfile.html
</i>] [ --section
<i>section
</i>] [ --title
<i>title
</i>] [
<i>filename.xml
</i>] [
<i>source file(s)
</i>] >
<i>filename.html
</i><h3 _hd_omit_toc>Description</h3>
<i>mxmldoc</i> scans the specified C and C++ source files to
<h1 align='right'><a name='MXMLDOC'>4 - Using the mxmldoc
Utility</a></h1>
<p>Originally developed to generate the Mini-XML and CUPS API
documentation, the <tt>mxmldoc(1)</tt> program converts C and C++
source files into an intermediate XML format and uses in-line
comments rather than comment headers to annotate functions, types,
and constants. This chapter describes how to use it.</p>
<h2>The Basics</h2>
<h2>Commenting Your Code</h2>
<h2>Creating HTML Documentation</h2>
<h2>Creating Man Pages</h2>
<h2>The XML Schema</h2>
<p><i>mxmldoc</i> scans the specified C and C++ source files to
produce an XML representation of globally accessible classes,
constants, enumerations, functions, structures, typedefs,
unions, and variables. The XML file is updated as necessary and

View File

@ -3,7 +3,7 @@
.\"
.\" mxmldoc man page for mini-XML, a small XML-like file parsing library.
.\"
.\" Copyright 2003-2005 by Michael Sweet.
.\" Copyright 2003-2007 by Michael Sweet.
.\"
.\" This program is free software; you can redistribute it and/or
.\" modify it under the terms of the GNU Library General Public
@ -15,13 +15,20 @@
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.TH mxmldoc 1 "mini-XML" "2 December 2005" "Michael Sweet"
.TH mxmldoc 1 "Mini-XML" "22 April 2007" "Michael Sweet"
.SH NAME
mxmldoc \- mini-xml documentation generator
.SH SYNOPSIS
.B mxmldoc
--no-output [
.I filename.xml
]
.I source file(s)
]
.br
.B mxmldoc
[ --intro
.I introfile.html
.I introfile
] [ --section
.I section
] [ --title
@ -32,26 +39,53 @@ mxmldoc \- mini-xml documentation generator
.I source file(s)
] >
.I filename.html
.br
.B mxmldoc
--man
.I manpage
[ --intro
.I introfile
] [ --section
.I section
] [ --title
.I title
] [
.I filename.xml
] [
.I source file(s)
] >
.I filename.man
.SH DESCRIPTION
\fImxmldoc\fR scans the specified C and C++ source files to
produce an XML representation of globally accessible classes,
constants, enumerations, functions, structures, typedefs,
unions, and variables. The XML file is updated as necessary and
a HTML representation of the XML file is written to the standard
output. If no source files are specified then the current XML
file is converted to HTML on the standard output.
\fImxmldoc\fR scans the specified C and C++ source files to produce
an XML representation of globally accessible classes, constants,
enumerations, functions, structures, typedefs, unions, and variables
- the XML file is updated as necessary. By default, a HTML
representation of the XML file is written to the standard output.
Use the \fI--no-output\fR option to disable the HTML output.
.PP
In general, any C or C++ source code is handled by
\fImxmldoc\fR, however it was specifically written to handle
code with documentation that is formatted according to the CUPS
Configuration Management Plan which is available at
"http://www.cups.org/documentation.php".
Man page source can be generated using the \fI--man\fR option.
.PP
If no source files are specified then the current XML file is
converted to the standard output.
.PP
In general, any C or C++ source code is handled by \fImxmldoc\fR,
however it was specifically written to handle code with
documentation that is formatted according to the CUPS Developer
Guide which is available at "http://www.cups.org/documentation.php".
.SH OPTIONS
.TP 5
\--intro introfile.html
\--intro introfile
.br
Inserts the specified file at the top of the output documentation.
.TP 5
\--man manpage
.br
Generated a man page instead of HTML documentation.
.TP 5
\--no-output
.br
Disables generation of documentation on the standard output.
.TP 5
\--section section
.br
Sets the section/keywords in the output documentation.
@ -62,7 +96,7 @@ Sets the title of the output documentation.
.SH SEE ALSO
mxml(3), Mini-XML Programmers Manual, http://www.easysw.com/~mike/mxml/
.SH COPYRIGHT
Copyright 2003-2005 by Michael Sweet.
Copyright 2003-2007 by Michael Sweet.
.\"
.\" End of "$Id$".
.\"

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,9 @@
<li>Added two exceptions to the LGPL to support static
linking of applications against Mini-XML</li>
<li>The mxmldoc utility can now generate man pages,
too.</li>
<li>Added a mxmlNewXML() function</li>
<li>Added a mxmlElementSetAttrf() function (STR #43)</li>

View File

@ -145,6 +145,8 @@ mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */
* is replaced by the new formatted string. The formatted string value is
* copied into the element node. This function does nothing if the node
* is not an element.
*
* @since Mini-XML 2.3@
*/
void

View File

@ -24,6 +24,12 @@
* 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.
* mxmlSAXLoadFd() - Load a file descriptor into an XML node tree
* using a SAX callback.
* mxmlSAXLoadFile() - Load a file into an XML node tree
* using a SAX callback.
* mxmlSAXLoadString() - Load a string into an XML node tree
* using a SAX callback.
* mxmlSetCustomHandlers() - Set the handling functions for custom data.
* mxmlSetErrorCallback() - Set the error message callback.
* mxmlSetWrapMargin() - Set the the wrap margin when saving XML data.
@ -75,16 +81,19 @@
/*
* Structures...
* Types and structures...
*/
typedef struct mxml_fdbuf_s /**** File descriptor buffer (@private@) ****/
typedef int (*_mxml_getc_cb_t)(void *, int *);
typedef int (*_mxml_putc_cb_t)(int, void *);
typedef struct _mxml_fdbuf_s /**** File descriptor buffer ****/
{
int fd; /* File descriptor */
unsigned char *current, /* Current position in buffer */
*end, /* End of buffer */
buffer[8192]; /* Character buffer */
} mxml_fdbuf_t;
} _mxml_fdbuf_t;
/*
@ -117,32 +126,32 @@ 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_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 *));
_mxml_getc_cb_t getc_cb);
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 *));
mxml_load_cb_t cb,
_mxml_getc_cb_t getc_cb,
mxml_sax_cb_t sax_cb, void *sax_data);
static int mxml_parse_element(mxml_node_t *node, void *p,
int *encoding,
int (*getc_cb)(void *, int *));
_mxml_getc_cb_t getc_cb);
static int mxml_string_getc(void *p, int *encoding);
static int mxml_string_putc(int ch, void *p);
static int mxml_write_name(const char *s, void *p,
int (*putc_cb)(int, void *));
_mxml_putc_cb_t putc_cb);
static int mxml_write_node(mxml_node_t *node, void *p,
const char *(*cb)(mxml_node_t *, int),
int col,
int (*putc_cb)(int, void *));
mxml_save_cb_t cb, int col,
_mxml_putc_cb_t putc_cb);
static int mxml_write_string(const char *s, void *p,
int (*putc_cb)(int, void *));
_mxml_putc_cb_t putc_cb);
static int mxml_write_ws(mxml_node_t *node, void *p,
const char *(*cb)(mxml_node_t *, int), int ws,
int col, int (*putc_cb)(int, void *));
mxml_save_cb_t cb, int ws,
int col, _mxml_putc_cb_t putc_cb);
/*
@ -161,12 +170,11 @@ static int mxml_write_ws(mxml_node_t *node, void *p,
*/
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 */
mxmlLoadFd(mxml_node_t *top, /* I - Top node */
int fd, /* I - File descriptor to read from */
mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */
{
mxml_fdbuf_t buf; /* File descriptor buffer */
_mxml_fdbuf_t buf; /* File descriptor buffer */
/*
@ -181,7 +189,7 @@ mxmlLoadFd(mxml_node_t *top, /* I - Top node */
* Read the XML data...
*/
return (mxml_load_data(top, &buf, cb, mxml_fd_getc));
return (mxml_load_data(top, &buf, cb, mxml_fd_getc, MXML_NO_CALLBACK, NULL));
}
@ -201,16 +209,15 @@ mxmlLoadFd(mxml_node_t *top, /* I - Top node */
*/
mxml_node_t * /* O - First node or NULL if the file could not be read. */
mxmlLoadFile(mxml_node_t *top, /* I - Top node */
FILE *fp, /* I - File to read from */
mxml_type_t (*cb)(mxml_node_t *node))
/* I - Callback function or MXML_NO_CALLBACK */
mxmlLoadFile(mxml_node_t *top, /* I - Top node */
FILE *fp, /* I - File to read from */
mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */
{
/*
* Read the XML data...
*/
return (mxml_load_data(top, fp, cb, mxml_file_getc));
return (mxml_load_data(top, fp, cb, mxml_file_getc, MXML_NO_CALLBACK, NULL));
}
@ -230,16 +237,16 @@ mxmlLoadFile(mxml_node_t *top, /* I - Top node */
*/
mxml_node_t * /* O - First node or NULL if the string has errors. */
mxmlLoadString(mxml_node_t *top, /* I - Top node */
const char *s, /* I - String to load */
mxml_type_t (*cb)(mxml_node_t *node))
/* I - Callback function or MXML_NO_CALLBACK */
mxmlLoadString(mxml_node_t *top, /* I - Top node */
const char *s, /* I - String to load */
mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */
{
/*
* Read the XML data...
*/
return (mxml_load_data(top, &s, cb, mxml_string_getc));
return (mxml_load_data(top, &s, cb, mxml_string_getc, MXML_NO_CALLBACK,
NULL));
}
@ -260,9 +267,9 @@ mxmlLoadString(mxml_node_t *top, /* I - Top node */
*/
char * /* O - Allocated string or NULL */
mxmlSaveAllocString(mxml_node_t *node, /* I - Node to write */
const char *(*cb)(mxml_node_t *node, int ws))
/* I - Whitespace callback or MXML_NO_CALLBACK */
mxmlSaveAllocString(
mxml_node_t *node, /* I - Node to write */
mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */
{
int bytes; /* Required bytes */
char buffer[8192]; /* Temporary buffer */
@ -317,13 +324,12 @@ mxmlSaveAllocString(mxml_node_t *node, /* I - Node to write */
*/
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 */
mxmlSaveFd(mxml_node_t *node, /* I - Node to write */
int fd, /* I - File descriptor to write to */
mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */
{
int col; /* Final column */
mxml_fdbuf_t buf; /* File descriptor buffer */
_mxml_fdbuf_t buf; /* File descriptor buffer */
/*
@ -364,10 +370,9 @@ mxmlSaveFd(mxml_node_t *node, /* I - Node to write */
*/
int /* O - 0 on success, -1 on error. */
mxmlSaveFile(mxml_node_t *node, /* I - Node to write */
FILE *fp, /* I - File to write to */
const char *(*cb)(mxml_node_t *node, int ws))
/* I - Whitespace callback or MXML_NO_CALLBACK */
mxmlSaveFile(mxml_node_t *node, /* I - Node to write */
FILE *fp, /* I - File to write to */
mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */
{
int col; /* Final column */
@ -406,11 +411,10 @@ mxmlSaveFile(mxml_node_t *node, /* I - Node to write */
*/
int /* O - Size of string */
mxmlSaveString(mxml_node_t *node, /* I - Node to write */
char *buffer, /* I - String buffer */
int bufsize, /* I - Size of string buffer */
const char *(*cb)(mxml_node_t *node, int ws))
/* I - Whitespace callback or MXML_NO_CALLBACK */
mxmlSaveString(mxml_node_t *node, /* I - Node to write */
char *buffer, /* I - String buffer */
int bufsize, /* I - Size of string buffer */
mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */
{
int col; /* Final column */
char *ptr[2]; /* Pointers for putc_cb */
@ -446,6 +450,130 @@ mxmlSaveString(mxml_node_t *node, /* I - Node to write */
}
/*
* 'mxmlSAXLoadFd()' - Load a file descriptor into an XML node tree
* using a SAX callback.
*
* 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.
*
* The SAX callback must call mxmlRetain() for any nodes that need to
* be kept for later use. Otherwise, nodes are deleted when the parent
* node is closed or after each data, comment, CDATA, or directive node.
*
* @since Mini-XML 2.3@
*/
mxml_node_t * /* O - First node or NULL if the file could not be read. */
mxmlSAXLoadFd(mxml_node_t *top, /* I - Top node */
int fd, /* I - File descriptor to read from */
mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */
mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */
void *sax_data) /* I - SAX user data */
{
_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, sax_cb, sax_data));
}
/*
* 'mxmlSAXLoadFile()' - Load a file into an XML node tree
* using a SAX callback.
*
* 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.
*
* The SAX callback must call mxmlRetain() for any nodes that need to
* be kept for later use. Otherwise, nodes are deleted when the parent
* node is closed or after each data, comment, CDATA, or directive node.
*
* @since Mini-XML 2.3@
*/
mxml_node_t * /* O - First node or NULL if the file could not be read. */
mxmlSAXLoadFile(
mxml_node_t *top, /* I - Top node */
FILE *fp, /* I - File to read from */
mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */
mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */
void *sax_data) /* I - SAX user data */
{
/*
* Read the XML data...
*/
return (mxml_load_data(top, fp, cb, mxml_file_getc, sax_cb, sax_data));
}
/*
* 'mxmlSAXLoadString()' - Load a string into an XML node tree
* using a SAX callback.
*
* The nodes in the specified string are added to the specified top node.
* If no top node is provided, the XML string MUST be well-formed with a
* single parent node like <?xml> for the entire string. 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.
*
* The SAX callback must call mxmlRetain() for any nodes that need to
* be kept for later use. Otherwise, nodes are deleted when the parent
* node is closed or after each data, comment, CDATA, or directive node.
*
* @since Mini-XML 2.3@
*/
mxml_node_t * /* O - First node or NULL if the string has errors. */
mxmlSAXLoadString(
mxml_node_t *top, /* I - Top node */
const char *s, /* I - String to load */
mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */
mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */
void *sax_data) /* I - SAX user data */
{
/*
* Read the XML data...
*/
return (mxml_load_data(top, &s, cb, mxml_string_getc, sax_cb, sax_data));
}
/*
* 'mxmlSetCustomHandlers()' - Set the handling functions for custom data.
*
@ -458,10 +586,9 @@ mxmlSaveString(mxml_node_t *node, /* I - Node to write */
*/
void
mxmlSetCustomHandlers(mxml_custom_load_cb_t load,
/* I - Load function */
mxml_custom_save_cb_t save)
/* I - Save function */
mxmlSetCustomHandlers(
mxml_custom_load_cb_t load, /* I - Load function */
mxml_custom_save_cb_t save) /* I - Save function */
{
mxml_custom_load_cb = load;
mxml_custom_save_cb = save;
@ -473,8 +600,7 @@ mxmlSetCustomHandlers(mxml_custom_load_cb_t load,
*/
void
mxmlSetErrorCallback(void (*cb)(const char *))
/* I - Error callback function */
mxmlSetErrorCallback(mxml_error_cb_t cb)/* I - Error callback function */
{
mxml_error_cb = cb;
}
@ -586,7 +712,7 @@ static int /* O - Character or EOF */
mxml_fd_getc(void *p, /* I - File descriptor buffer */
int *encoding) /* IO - Encoding */
{
mxml_fdbuf_t *buf; /* File descriptor buffer */
_mxml_fdbuf_t *buf; /* File descriptor buffer */
int ch, /* Current character */
temp; /* Temporary character */
@ -595,7 +721,7 @@ mxml_fd_getc(void *p, /* I - File descriptor buffer */
* Grab the next character in the buffer...
*/
buf = (mxml_fdbuf_t *)p;
buf = (_mxml_fdbuf_t *)p;
if (buf->current >= buf->end)
if (mxml_fd_read(buf) < 0)
@ -873,7 +999,7 @@ 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 */
_mxml_fdbuf_t *buf; /* File descriptor buffer */
/*
@ -881,7 +1007,7 @@ mxml_fd_putc(int ch, /* I - Character */
* 4 characters at the end so that we can avoid a lot of extra tests...
*/
buf = (mxml_fdbuf_t *)p;
buf = (_mxml_fdbuf_t *)p;
if (buf->current >= buf->end)
if (mxml_fd_write(buf) < 0)
@ -939,7 +1065,7 @@ mxml_fd_putc(int ch, /* I - Character */
*/
static int /* O - 0 on success, -1 on error */
mxml_fd_read(mxml_fdbuf_t *buf) /* I - File descriptor buffer */
mxml_fd_read(_mxml_fdbuf_t *buf) /* I - File descriptor buffer */
{
int bytes; /* Bytes read... */
@ -982,7 +1108,7 @@ mxml_fd_read(mxml_fdbuf_t *buf) /* I - File descriptor buffer */
*/
static int /* O - 0 on success, -1 on error */
mxml_fd_write(mxml_fdbuf_t *buf) /* I - File descriptor buffer */
mxml_fd_write(_mxml_fdbuf_t *buf) /* I - File descriptor buffer */
{
int bytes; /* Bytes written */
unsigned char *ptr; /* Pointer into buffer */
@ -1340,12 +1466,13 @@ mxml_get_entity(mxml_node_t *parent, /* I - Parent node */
*/
static mxml_node_t * /* O - First node or NULL if the file could not be read. */
mxml_load_data(mxml_node_t *top, /* I - Top node */
void *p, /* I - Pointer to data */
mxml_type_t (*cb)(mxml_node_t *),
/* I - Callback function or MXML_NO_CALLBACK */
int (*getc_cb)(void *, int *))
/* I - Read function */
mxml_load_data(
mxml_node_t *top, /* I - Top node */
void *p, /* I - Pointer to data */
mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */
_mxml_getc_cb_t getc_cb, /* I - Read function */
mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */
void *sax_data) /* I - SAX user data */
{
mxml_node_t *node, /* Current node */
*first, /* First node added */
@ -1470,6 +1597,14 @@ mxml_load_data(mxml_node_t *top, /* I - Top node */
goto error;
}
if (sax_cb)
{
(*sax_cb)(node, MXML_SAX_DATA, sax_data);
if (!mxmlRelease(node))
node = NULL;
}
if (!first && node)
first = node;
}
@ -1485,6 +1620,14 @@ mxml_load_data(mxml_node_t *top, /* I - Top node */
{
node = mxmlNewText(parent, whitespace, "");
if (sax_cb)
{
(*sax_cb)(node, MXML_SAX_DATA, sax_data);
if (!mxmlRelease(node))
node = NULL;
}
if (!first && node)
first = node;
@ -1571,6 +1714,14 @@ mxml_load_data(mxml_node_t *top, /* I - Top node */
break;
}
if (sax_cb)
{
(*sax_cb)(node, MXML_SAX_COMMENT, sax_data);
if (!mxmlRelease(node))
node = NULL;
}
if (!first)
first = node;
}
@ -1620,6 +1771,14 @@ mxml_load_data(mxml_node_t *top, /* I - Top node */
goto error;
}
if (sax_cb)
{
(*sax_cb)(node, MXML_SAX_CDATA, sax_data);
if (!mxmlRelease(node))
node = NULL;
}
if (!first)
first = node;
}
@ -1651,14 +1810,13 @@ mxml_load_data(mxml_node_t *top, /* I - Top node */
goto error;
}
/*
* Otherwise add this as an element under the current parent...
*/
*bufptr = '\0';
if ((parent = mxmlNewElement(parent, buffer)) == NULL)
if ((node = mxmlNewElement(parent, buffer)) == NULL)
{
/*
* Print error and return...
@ -1669,11 +1827,24 @@ mxml_load_data(mxml_node_t *top, /* I - Top node */
goto error;
}
if (!first)
first = parent;
if (sax_cb)
{
(*sax_cb)(node, MXML_SAX_DIRECTIVE, sax_data);
if (cb)
type = (*cb)(parent);
if (!mxmlRelease(node))
node = NULL;
}
if (node)
{
parent = node;
if (!first)
first = parent;
if (cb)
type = (*cb)(parent);
}
}
else if (buffer[0] == '!')
{
@ -1728,17 +1899,28 @@ mxml_load_data(mxml_node_t *top, /* I - Top node */
goto error;
}
if (!first)
first = node;
if (sax_cb)
{
(*sax_cb)(node, MXML_SAX_DIRECTIVE, sax_data);
/*
* Descend into this node, setting the value type as needed...
*/
if (!mxmlRelease(node))
node = NULL;
}
parent = node;
if (node)
{
/*
* Descend into this node, setting the value type as needed...
*/
if (cb)
type = (*cb)(parent);
if (!first)
first = node;
parent = node;
if (cb)
type = (*cb)(parent);
}
}
else if (buffer[0] == '/')
{
@ -1764,12 +1946,20 @@ mxml_load_data(mxml_node_t *top, /* I - Top node */
while (ch != '>' && ch != EOF)
ch = (*getc_cb)(p, &encoding);
node = parent;
parent = parent->parent;
if (sax_cb)
{
(*sax_cb)(node, MXML_SAX_ELEMENT_CLOSE, sax_data);
mxmlRelease(node);
}
/*
* Ascend into the parent and set the value type as needed...
*/
parent = parent->parent;
if (cb && parent)
type = (*cb)(parent);
}
@ -1790,9 +1980,6 @@ mxml_load_data(mxml_node_t *top, /* I - Top node */
goto error;
}
if (!first)
first = node;
if (isspace(ch))
ch = mxml_parse_element(node, p, &encoding, getc_cb);
else if (ch == '/')
@ -1808,6 +1995,12 @@ mxml_load_data(mxml_node_t *top, /* I - Top node */
ch = '/';
}
if (sax_cb)
(*sax_cb)(node, MXML_SAX_ELEMENT_OPEN, sax_data);
if (!first)
first = node;
if (ch == EOF)
break;
@ -1822,6 +2015,13 @@ mxml_load_data(mxml_node_t *top, /* I - Top node */
if (cb && parent)
type = (*cb)(parent);
}
else if (sax_cb)
{
(*sax_cb)(node, MXML_SAX_ELEMENT_CLOSE, sax_data);
if (!mxmlRelease(node) && first == node)
first = NULL;
}
}
bufptr = buffer;
@ -1899,12 +2099,11 @@ error:
*/
static int /* O - Terminating character */
mxml_parse_element(mxml_node_t *node, /* I - Element node */
void *p, /* I - Data to read from */
int *encoding,
/* IO - Encoding */
int (*getc_cb)(void *, int *))
/* I - Data callback */
mxml_parse_element(
mxml_node_t *node, /* I - Element node */
void *p, /* I - Data to read from */
int *encoding, /* IO - Encoding */
_mxml_getc_cb_t getc_cb) /* I - Data callback */
{
int ch, /* Current character in file */
quote; /* Quoting character */
@ -2551,12 +2750,11 @@ mxml_write_name(const char *s, /* I - Name to write */
*/
static int /* O - Column or -1 on error */
mxml_write_node(mxml_node_t *node, /* I - Node to write */
void *p, /* I - File to write to */
const char *(*cb)(mxml_node_t *, int),
/* I - Whitespace callback */
int col, /* I - Current column */
int (*putc_cb)(int, void *))
mxml_write_node(mxml_node_t *node, /* I - Node to write */
void *p, /* I - File to write to */
mxml_save_cb_t cb, /* I - Whitespace callback */
int col, /* I - Current column */
_mxml_putc_cb_t putc_cb)/* I - Output callback */
{
int i, /* Looping var */
width; /* Width of attr + value */
@ -2832,10 +3030,10 @@ mxml_write_node(mxml_node_t *node, /* I - Node to write */
*/
static int /* O - 0 on success, -1 on failure */
mxml_write_string(const char *s, /* I - String to write */
void *p, /* I - Write pointer */
int (*putc_cb)(int, void *))
/* I - Write callback */
mxml_write_string(
const char *s, /* I - String to write */
void *p, /* I - Write pointer */
_mxml_putc_cb_t putc_cb) /* I - Write callback */
{
const char *name; /* Entity name, if any */
@ -2872,14 +3070,12 @@ mxml_write_string(const char *s, /* I - String to write */
*/
static int /* O - New column */
mxml_write_ws(mxml_node_t *node, /* I - Current node */
void *p, /* I - Write pointer */
const char *(*cb)(mxml_node_t *, int),
/* I - Callback function */
int ws, /* I - Where value */
int col, /* I - Current column */
int (*putc_cb)(int, void *))
/* I - Write callback */
mxml_write_ws(mxml_node_t *node, /* I - Current node */
void *p, /* I - Write pointer */
mxml_save_cb_t cb, /* I - Callback function */
int ws, /* I - Where value */
int col, /* I - Current column */
_mxml_putc_cb_t putc_cb) /* I - Write callback */
{
const char *s; /* Whitespace string */

View File

@ -331,10 +331,10 @@ mxmlNewCDATA(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
*/
mxml_node_t * /* O - New node */
mxmlNewCustom(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
void *data, /* I - Pointer to data */
void (*destroy)(void *))
/* I - Function to destroy data */
mxmlNewCustom(
mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
void *data, /* I - Pointer to data */
mxml_custom_destroy_cb_t destroy) /* I - Function to destroy data */
{
mxml_node_t *node; /* New node */

View File

@ -3,7 +3,7 @@
*
* Node set functions for Mini-XML, a small XML-like file parsing library.
*
* Copyright 2003-2005 by Michael Sweet.
* Copyright 2003-2007 by Michael Sweet.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -44,10 +44,10 @@
*/
int /* O - 0 on success, -1 on failure */
mxmlSetCustom(mxml_node_t *node, /* I - Node to set */
void *data, /* I - New data pointer */
void (*destroy)(void *))
/* I - New destructor function */
mxmlSetCustom(
mxml_node_t *node, /* I - Node to set */
void *data, /* I - New data pointer */
mxml_custom_destroy_cb_t destroy) /* I - New destructor function */
{
/*
* Range check input...

52
mxml.h
View File

@ -71,6 +71,16 @@
* Data types...
*/
typedef enum mxml_sax_event_e /**** SAX event type. ****/
{
MXML_SAX_CDATA, /* CDATA node */
MXML_SAX_COMMENT, /* Comment node */
MXML_SAX_DATA, /* Data node */
MXML_SAX_DIRECTIVE, /* Processing directive node */
MXML_SAX_ELEMENT_CLOSE, /* Element closed */
MXML_SAX_ELEMENT_OPEN /* Element opened */
} mxml_sax_event_t;
typedef enum mxml_type_e /**** The XML node type. ****/
{
MXML_IGNORE = -1, /* Ignore/throw away node @since Mini-XML 2.3@ */
@ -82,6 +92,12 @@ typedef enum mxml_type_e /**** The XML node type. ****/
MXML_CUSTOM /* Custom data @since Mini-XML 2.1@ */
} mxml_type_t;
typedef void (*mxml_custom_destroy_cb_t)(void *);
/**** Custom data destructor ****/
typedef void (*mxml_error_cb_t)(const char *);
/**** Error callback function ****/
typedef struct mxml_attr_s /**** An XML element attribute value. ****/
{
char *name; /* Attribute name */
@ -104,8 +120,7 @@ typedef struct mxml_text_s /**** An XML text value. ****/
typedef struct mxml_custom_s /**** An XML custom value. @since Mini-XML 2.1@ ****/
{
void *data; /* Pointer to (allocated) custom data */
void (*destroy)(void *);
/* Pointer to destructor function */
mxml_custom_destroy_cb_t destroy; /* Pointer to destructor function */
} mxml_custom_t;
typedef union mxml_value_u /**** An XML node value. ****/
@ -146,6 +161,15 @@ typedef int (*mxml_custom_load_cb_t)(mxml_node_t *, const char *);
typedef char *(*mxml_custom_save_cb_t)(mxml_node_t *);
/**** Custom data save callback function ****/
typedef mxml_type_t (*mxml_load_cb_t)(mxml_node_t *);
/**** Load callback function ****/
typedef const char *(*mxml_save_cb_t)(mxml_node_t *, int);
/**** Save callback function ****/
typedef void (*mxml_sax_cb_t)(mxml_node_t *, mxml_sax_event_t, void *);
/**** SAX callback function ****/
/*
* C++ support...
@ -194,7 +218,7 @@ extern mxml_node_t *mxmlLoadString(mxml_node_t *top, const char *s,
mxml_type_t (*cb)(mxml_node_t *));
extern mxml_node_t *mxmlNewCDATA(mxml_node_t *parent, const char *string);
extern mxml_node_t *mxmlNewCustom(mxml_node_t *parent, void *data,
void (*destroy)(void *));
mxml_custom_destroy_cb_t destroy);
extern mxml_node_t *mxmlNewElement(mxml_node_t *parent, const char *name);
extern mxml_node_t *mxmlNewInteger(mxml_node_t *parent, int integer);
extern mxml_node_t *mxmlNewOpaque(mxml_node_t *parent, const char *opaque);
@ -212,21 +236,29 @@ extern int mxmlRelease(mxml_node_t *node);
extern void mxmlRemove(mxml_node_t *node);
extern int mxmlRetain(mxml_node_t *node);
extern char *mxmlSaveAllocString(mxml_node_t *node,
const char *(*cb)(mxml_node_t *, int));
mxml_save_cb_t cb);
extern int mxmlSaveFd(mxml_node_t *node, int fd,
const char *(*cb)(mxml_node_t *, int));
mxml_save_cb_t cb);
extern int mxmlSaveFile(mxml_node_t *node, FILE *fp,
const char *(*cb)(mxml_node_t *, int));
mxml_save_cb_t cb);
extern int mxmlSaveString(mxml_node_t *node, char *buffer,
int bufsize,
const char *(*cb)(mxml_node_t *, int));
int bufsize, mxml_save_cb_t cb);
extern mxml_node_t *mxmlSAXLoadFd(mxml_node_t *top, int fd,
mxml_type_t (*cb)(mxml_node_t *),
mxml_sax_cb_t sax, void *sax_data);
extern mxml_node_t *mxmlSAXLoadFile(mxml_node_t *top, FILE *fp,
mxml_type_t (*cb)(mxml_node_t *),
mxml_sax_cb_t sax, void *sax_data);
extern mxml_node_t *mxmlSAXLoadString(mxml_node_t *top, const char *s,
mxml_type_t (*cb)(mxml_node_t *),
mxml_sax_cb_t sax, void *sax_data);
extern int mxmlSetCDATA(mxml_node_t *node, const char *data);
extern int mxmlSetCustom(mxml_node_t *node, void *data,
void (*destroy)(void *));
mxml_custom_destroy_cb_t destroy);
extern void mxmlSetCustomHandlers(mxml_custom_load_cb_t load,
mxml_custom_save_cb_t save);
extern int mxmlSetElement(mxml_node_t *node, const char *name);
extern void mxmlSetErrorCallback(void (*cb)(const char *));
extern void mxmlSetErrorCallback(mxml_error_cb_t cb);
extern int mxmlSetInteger(mxml_node_t *node, int integer);
extern int mxmlSetOpaque(mxml_node_t *node, const char *opaque);
extern int mxmlSetReal(mxml_node_t *node, double real);

246
mxml.xml
View File

@ -82,7 +82,9 @@ not an element.</description>
If the named attribute already exists, the value of the attribute
is replaced by the new formatted string. The formatted string value is
copied into the element node. This function does nothing if the node
is not an element.</description>
is not an element.
@since Mini-XML 2.3@</description>
<argument name="node" direction="I">
<type>mxml_node_t *</type>
<description>Element node</description>
@ -285,6 +287,10 @@ child nodes of the specified type.</description>
<type>int</type>
<description>File descriptor to read from</description>
</argument>
<argument name="cb" direction="I">
<type>mxml_load_cb_t</type>
<description>Callback function or MXML_NO_CALLBACK</description>
</argument>
</function>
<function name="mxmlLoadFile">
<returnvalue>
@ -311,6 +317,10 @@ child nodes of the specified type.</description>
<type>FILE *</type>
<description>File to read from</description>
</argument>
<argument name="cb" direction="I">
<type>mxml_load_cb_t</type>
<description>Callback function or MXML_NO_CALLBACK</description>
</argument>
</function>
<function name="mxmlLoadString">
<returnvalue>
@ -337,6 +347,10 @@ child nodes of the specified type.</description>
<type>const char *</type>
<description>String to load</description>
</argument>
<argument name="cb" direction="I">
<type>mxml_load_cb_t</type>
<description>Callback function or MXML_NO_CALLBACK</description>
</argument>
</function>
<function name="mxmlNewCDATA">
<returnvalue>
@ -381,6 +395,10 @@ node is not dynamically allocated or is separately managed.
<type>void *</type>
<description>Pointer to data</description>
</argument>
<argument name="destroy" direction="I">
<type>mxml_custom_destroy_cb_t</type>
<description>Function to destroy data</description>
</argument>
</function>
<function name="mxmlNewElement">
<returnvalue>
@ -567,6 +585,141 @@ This function does nothing if the node has no parent.</description>
<description>Node</description>
</argument>
</function>
<function name="mxmlSAXLoadFd">
<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
using a SAX callback.
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.
The SAX callback must call mxmlRetain() for any nodes that need to
be kept for later use. Otherwise, nodes are deleted when the parent
node is closed or after each data, comment, CDATA, or directive node.
@since Mini-XML 2.3@</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" direction="I">
<type>mxml_load_cb_t</type>
<description>Callback function or MXML_NO_CALLBACK</description>
</argument>
<argument name="sax_cb" direction="I">
<type>mxml_sax_cb_t</type>
<description>SAX callback or MXML_NO_CALLBACK</description>
</argument>
<argument name="sax_data" direction="I">
<type>void *</type>
<description>SAX user data</description>
</argument>
</function>
<function name="mxmlSAXLoadFile">
<returnvalue>
<type>mxml_node_t *</type>
<description>First node or NULL if the file could not be read.</description>
</returnvalue>
<description>Load a file into an XML node tree
using a SAX callback.
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.
The SAX callback must call mxmlRetain() for any nodes that need to
be kept for later use. Otherwise, nodes are deleted when the parent
node is closed or after each data, comment, CDATA, or directive node.
@since Mini-XML 2.3@</description>
<argument name="top" direction="I">
<type>mxml_node_t *</type>
<description>Top node</description>
</argument>
<argument name="fp" direction="I">
<type>FILE *</type>
<description>File to read from</description>
</argument>
<argument name="cb" direction="I">
<type>mxml_load_cb_t</type>
<description>Callback function or MXML_NO_CALLBACK</description>
</argument>
<argument name="sax_cb" direction="I">
<type>mxml_sax_cb_t</type>
<description>SAX callback or MXML_NO_CALLBACK</description>
</argument>
<argument name="sax_data" direction="I">
<type>void *</type>
<description>SAX user data</description>
</argument>
</function>
<function name="mxmlSAXLoadString">
<returnvalue>
<type>mxml_node_t *</type>
<description>First node or NULL if the string has errors.</description>
</returnvalue>
<description>Load a string into an XML node tree
using a SAX callback.
The nodes in the specified string are added to the specified top node.
If no top node is provided, the XML string MUST be well-formed with a
single parent node like &lt;?xml&gt; for the entire string. 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.
The SAX callback must call mxmlRetain() for any nodes that need to
be kept for later use. Otherwise, nodes are deleted when the parent
node is closed or after each data, comment, CDATA, or directive node.
@since Mini-XML 2.3@</description>
<argument name="top" direction="I">
<type>mxml_node_t *</type>
<description>Top node</description>
</argument>
<argument name="s" direction="I">
<type>const char *</type>
<description>String to load</description>
</argument>
<argument name="cb" direction="I">
<type>mxml_load_cb_t</type>
<description>Callback function or MXML_NO_CALLBACK</description>
</argument>
<argument name="sax_cb" direction="I">
<type>mxml_sax_cb_t</type>
<description>SAX callback or MXML_NO_CALLBACK</description>
</argument>
<argument name="sax_data" direction="I">
<type>void *</type>
<description>SAX user data</description>
</argument>
</function>
<function name="mxmlSaveAllocString">
<returnvalue>
<type>char *</type>
@ -589,6 +742,10 @@ element tags.</description>
<type>mxml_node_t *</type>
<description>Node to write</description>
</argument>
<argument name="cb" direction="I">
<type>mxml_save_cb_t</type>
<description>Whitespace callback or MXML_NO_CALLBACK</description>
</argument>
</function>
<function name="mxmlSaveFd">
<returnvalue>
@ -610,6 +767,10 @@ element tags.</description>
<type>int</type>
<description>File descriptor to write to</description>
</argument>
<argument name="cb" direction="I">
<type>mxml_save_cb_t</type>
<description>Whitespace callback or MXML_NO_CALLBACK</description>
</argument>
</function>
<function name="mxmlSaveFile">
<returnvalue>
@ -631,6 +792,10 @@ element tags.</description>
<type>FILE *</type>
<description>File to write to</description>
</argument>
<argument name="cb" direction="I">
<type>mxml_save_cb_t</type>
<description>Whitespace callback or MXML_NO_CALLBACK</description>
</argument>
</function>
<function name="mxmlSaveString">
<returnvalue>
@ -660,6 +825,10 @@ element tags.</description>
<type>int</type>
<description>Size of string buffer</description>
</argument>
<argument name="cb" direction="I">
<type>mxml_save_cb_t</type>
<description>Whitespace callback or MXML_NO_CALLBACK</description>
</argument>
</function>
<function name="mxmlSetCDATA">
<returnvalue>
@ -698,6 +867,10 @@ The node is not changed if it is not a custom node.
<type>void *</type>
<description>New data pointer</description>
</argument>
<argument name="destroy" direction="I">
<type>mxml_custom_destroy_cb_t</type>
<description>New destructor function</description>
</argument>
</function>
<function name="mxmlSetCustomHandlers">
<description>Set the handling functions for custom data.
@ -735,6 +908,10 @@ The node is not changed if it is not an element node.</description>
</function>
<function name="mxmlSetErrorCallback">
<description>Set the error message callback.</description>
<argument name="cb" direction="I">
<type>mxml_error_cb_t</type>
<description>Error callback function</description>
</argument>
</function>
<function name="mxmlSetInteger">
<returnvalue>
@ -904,6 +1081,10 @@ the walk to the node's children.</description>
<type>struct mxml_attr_s</type>
<description>Data types...</description>
</typedef>
<typedef name="mxml_custom_destroy_cb_t">
<type>void(*)(void *)</type>
<description>Custom data destructor</description>
</typedef>
<typedef name="mxml_custom_load_cb_t">
<type>int(*)(mxml_node_t *, const char *)</type>
<description>Custom data load callback function</description>
@ -914,12 +1095,14 @@ the walk to the node's children.</description>
<type>void *</type>
<description>Pointer to (allocated) custom data</description>
</variable>
<variable name="destroy">
<type>mxml_custom_destroy_cb_t</type>
<description>Pointer to destructor function</description>
</variable>
</struct>
<typedef name="mxml_custom_save_cb_t">
<type>char *(*)(mxml_node_t *)</type>
<description>Custom data save callback function</description>
<description>C++ support...</description>
<description>End of &quot;$Id$&quot;.</description>
</typedef>
<typedef name="mxml_custom_t">
<type>struct mxml_custom_s</type>
@ -944,20 +1127,10 @@ the walk to the node's children.</description>
<type>struct mxml_element_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>unsigned char *current, *end,</type>
<description>Character 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 name="mxml_error_cb_t">
<type>void(*)(const char *)</type>
<description>Error callback function</description>
<description>An XML element attribute value.</description>
</typedef>
<struct name="mxml_index_s">
<description>An XML node index.</description>
@ -986,6 +1159,10 @@ the walk to the node's children.</description>
<type>struct mxml_index_s</type>
<description>An XML node index.</description>
</typedef>
<typedef name="mxml_load_cb_t">
<type>mxml_type_t(*)(mxml_node_t *)</type>
<description>Load callback function</description>
</typedef>
<struct name="mxml_node_s">
<description>An XML node.</description>
<variable name="child">
@ -1029,6 +1206,41 @@ the walk to the node's children.</description>
<type>struct mxml_node_s</type>
<description>An XML node.</description>
</typedef>
<typedef name="mxml_save_cb_t">
<type>const char *(*)(mxml_node_t *, int)</type>
<description>Save callback function</description>
</typedef>
<typedef name="mxml_sax_cb_t">
<type>void(*)(mxml_node_t *, mxml_sax_event_t, void *)</type>
<description>SAX callback function</description>
<description>C++ support...</description>
<description>End of &quot;$Id$&quot;.</description>
</typedef>
<enumeration name="mxml_sax_event_e">
<description>SAX event type.</description>
<constant name="MXML_SAX_CDATA">
<description>CDATA node</description>
</constant>
<constant name="MXML_SAX_COMMENT">
<description>Comment node</description>
</constant>
<constant name="MXML_SAX_DATA">
<description>Data node</description>
</constant>
<constant name="MXML_SAX_DIRECTIVE">
<description>Processing directive node</description>
</constant>
<constant name="MXML_SAX_ELEMENT_CLOSE">
<description>Element closed</description>
</constant>
<constant name="MXML_SAX_ELEMENT_OPEN">
<description>Element opened</description>
</constant>
</enumeration>
<typedef name="mxml_sax_event_t">
<type>enum mxml_sax_event_e</type>
<description>SAX event type.</description>
</typedef>
<struct name="mxml_text_s">
<description>An XML text value.</description>
<variable name="string">

1071
mxmldoc.c

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
*
* Test program for Mini-XML, a small XML-like file parsing library.
*
* Copyright 2003-2005 by Michael Sweet.
* Copyright 2003-2007 by Michael Sweet.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -18,6 +18,7 @@
* Contents:
*
* main() - Main entry for test program.
* sax_cb() - SAX callback.
* type_cb() - XML data type callback for mxmlLoadFile()...
* whitespace_cb() - Let the mxmlSaveFile() function know when to insert
* newlines and tabs...
@ -40,10 +41,18 @@
#endif /* !O_BINARY */
/*
* Globals...
*/
int event_counts[6];
/*
* Local functions...
*/
void sax_cb(mxml_node_t *node, mxml_sax_event_t event, void *data);
mxml_type_t type_cb(mxml_node_t *node);
const char *whitespace_cb(mxml_node_t *node, int where);
@ -523,6 +532,75 @@ main(int argc, /* I - Number of command-line args */
mxmlDelete(tree);
}
/*
* Test SAX methods...
*/
memset(event_counts, 0, sizeof(event_counts));
if (argv[1][0] == '<')
tree = mxmlSAXLoadString(NULL, argv[1], type_cb, sax_cb, NULL);
else if ((fp = fopen(argv[1], "rb")) == NULL)
{
perror(argv[1]);
return (1);
}
else
{
/*
* Read the file...
*/
tree = mxmlSAXLoadFile(NULL, fp, type_cb, sax_cb, NULL);
fclose(fp);
}
if (!strcmp(argv[1], "test.xml"))
{
if (event_counts[MXML_SAX_CDATA] != 1)
{
fprintf(stderr, "MXML_SAX_CDATA seen %d times, expected 1 times!\n",
event_counts[MXML_SAX_CDATA]);
return (1);
}
if (event_counts[MXML_SAX_COMMENT] != 1)
{
fprintf(stderr, "MXML_SAX_COMMENT seen %d times, expected 1 times!\n",
event_counts[MXML_SAX_COMMENT]);
return (1);
}
if (event_counts[MXML_SAX_DATA] != 61)
{
fprintf(stderr, "MXML_SAX_DATA seen %d times, expected 61 times!\n",
event_counts[MXML_SAX_DATA]);
return (1);
}
if (event_counts[MXML_SAX_DIRECTIVE] != 1)
{
fprintf(stderr, "MXML_SAX_DIRECTIVE seen %d times, expected 1 times!\n",
event_counts[MXML_SAX_DIRECTIVE]);
return (1);
}
if (event_counts[MXML_SAX_ELEMENT_CLOSE] != 20)
{
fprintf(stderr, "MXML_SAX_ELEMENT_CLOSE seen %d times, expected 20 times!\n",
event_counts[MXML_SAX_ELEMENT_CLOSE]);
return (1);
}
if (event_counts[MXML_SAX_ELEMENT_OPEN] != 20)
{
fprintf(stderr, "MXML_SAX_ELEMENT_OPEN seen %d times, expected 20 times!\n",
event_counts[MXML_SAX_ELEMENT_OPEN]);
return (1);
}
}
/*
* Return...
*/
@ -531,6 +609,23 @@ main(int argc, /* I - Number of command-line args */
}
/*
* 'sax_cb()' - Process nodes via SAX.
*/
void
sax_cb(mxml_node_t *node, /* I - Current node */
mxml_sax_event_t event, /* I - SAX event */
void *data) /* I - SAX user data */
{
/*
* This SAX callback just counts the different events.
*/
event_counts[event] ++;
}
/*
* 'type_cb()' - XML data type callback for mxmlLoadFile()...
*/