commit
7a51d3c414
@ -0,0 +1,113 @@ |
||||
#
|
||||
# "$Id: Makefile.in,v 1.1 2003/06/03 19:46:30 mike Exp $"
|
||||
#
|
||||
# Makefile for mini-XML, a small XML-like file parsing library.
|
||||
#
|
||||
# Copyright 2003 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.
|
||||
#
|
||||
|
||||
#
|
||||
# Compiler tools definitions...
|
||||
#
|
||||
|
||||
AR = @AR@
|
||||
ARFLAGS = @ARFLAGS@
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@ @CPPFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
RANLIB = @RANLIB@
|
||||
SHELL = /bin/sh
|
||||
|
||||
|
||||
#
|
||||
# Configured directories...
|
||||
#
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
includedir = @includedir@
|
||||
libdir = @libdir@
|
||||
|
||||
|
||||
#
|
||||
# Rules...
|
||||
#
|
||||
|
||||
.SUFFIXES: .c .o |
||||
.c.o: |
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
|
||||
#
|
||||
# Targets...
|
||||
#
|
||||
|
||||
LIBOBJS = mxml-attr.o mxml-file.o mxml-node.o mxml-search.o
|
||||
OBJS = testmxml.o $(LIBOBJS)
|
||||
TARGETS = libmxml.a testmxml
|
||||
|
||||
|
||||
#
|
||||
# Make everything...
|
||||
#
|
||||
|
||||
all: $(TARGETS) |
||||
|
||||
|
||||
#
|
||||
# Clean everything...
|
||||
#
|
||||
|
||||
clean: |
||||
rm -f $(OBJS) $(TARGETS)
|
||||
rm -f *.bck *.bak
|
||||
rm -f config.cache config.log config.status
|
||||
rm -rf autom4te*.cache
|
||||
|
||||
|
||||
#
|
||||
# Install everything...
|
||||
#
|
||||
|
||||
install: $(TARGETS) |
||||
-mkdir -p $(libdir)
|
||||
cp libmxml.a $(libdir)
|
||||
-mkdir -p $(includedir)
|
||||
cp mxml.h $(includedir)
|
||||
|
||||
|
||||
#
|
||||
# libmxml.a
|
||||
#
|
||||
|
||||
libmxml.a: $(LIBOBJS) |
||||
rm -f $@
|
||||
$(AR) $(ARFLAGS) $@ $(LIBOBJS)
|
||||
$(RANLIB) $@
|
||||
|
||||
$(LIBOBJS): mxml.h |
||||
|
||||
|
||||
#
|
||||
# testmxml
|
||||
#
|
||||
|
||||
testmxml: libmxml.a testmxml.o |
||||
$(CC) $(LDFLAGS) -o $@ testmxml.o libmxml.a
|
||||
|
||||
testmxml.o: mxml.h |
||||
|
||||
|
||||
#
|
||||
# End of "$Id: Makefile.in,v 1.1 2003/06/03 19:46:30 mike Exp $".
|
||||
#
|
@ -0,0 +1,138 @@ |
||||
README - 06/03/2003 |
||||
------------------- |
||||
|
||||
|
||||
INTRODUCTION |
||||
|
||||
This README file describes the Mini-XML library version 0.9. |
||||
Mini-XML is a small XML parsing library that you can use to |
||||
read XML and XML-like data files in your application without |
||||
requiring large non-standard libraries. Mini-XML only |
||||
requires an ANSI C compatible compiler (GCC works, as do |
||||
most vendors' ANSI C compilers) and a "make" program. |
||||
|
||||
Mini-XML was created to support the basic hierarchy provided |
||||
by XML and some simple data types, but doesn't do validation |
||||
or other types of processing on the data. |
||||
|
||||
|
||||
BUILDING Mini-XML |
||||
|
||||
Mini-XML comes with an autoconf-based configure script; just |
||||
type the following command to get things going: |
||||
|
||||
./configure |
||||
|
||||
The default install prefix is /usr/local, which can be |
||||
overridden using the --prefix option: |
||||
|
||||
./configure --prefix=/foo |
||||
|
||||
Once you have configured the software, type "make" to do the |
||||
build and then run the test program to verify that things |
||||
are working, as follows: |
||||
|
||||
make |
||||
./testmxml test.xml |
||||
|
||||
|
||||
INSTALLING Mini-XML |
||||
|
||||
The "install" target will install Mini-XML in the lib and |
||||
include directories: |
||||
|
||||
make install |
||||
|
||||
Once you have installed it, use the "-lmxml" option to link |
||||
your application against it. |
||||
|
||||
|
||||
DOCUMENTATION |
||||
|
||||
The documentation is currently just in this README file. At |
||||
some point I'll probably do some proper documentation, but |
||||
for now just read here and look at the testmxml.c source |
||||
file for an example of reading and printing the contents of |
||||
an XML file to stdout. |
||||
|
||||
Mini-XML provides a single header file which you include: |
||||
|
||||
#include <mxml.h> |
||||
|
||||
Nodes are defined by the "mxml_node_t" structure; the "type" |
||||
member defines the node type (element, integer, opaque, |
||||
real, or text) which determines which value you want to look |
||||
at in the "value" union. New nodes can be created using the |
||||
"mxmlNewElement()", "mxmlNewInteger()", "mxmlNewOpaque()", |
||||
"mxmlNewReal()", and "mxmlNewText()" functions. Only |
||||
elements can have child nodes, and the top node must be an |
||||
element, usually "?xml". |
||||
|
||||
You load an XML file using the "mxmlLoadFile()" function: |
||||
|
||||
FILE *fp; |
||||
mxml_node_t *tree; |
||||
|
||||
fp = fopen("filename.xml", "r"); |
||||
tree = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK); |
||||
fclose(fp); |
||||
|
||||
Similarly, you save an XML file using the "mxmlSaveFile()" |
||||
function: |
||||
|
||||
FILE *fp; |
||||
mxml_node_t *tree; |
||||
|
||||
fp = fopen("filename.xml", "w"); |
||||
mxmlSaveFile(tree, fp); |
||||
fclose(fp); |
||||
|
||||
You can find a named element/node using the |
||||
"mxmlFindElement()" function: |
||||
|
||||
mxml_node_t *node = mxmlFindElement(tree, tree, "name"); |
||||
|
||||
You can also iterate with the same function: |
||||
|
||||
mxml_node_t *node; |
||||
|
||||
for (node = mxmlFindElement(tree, tree, "name"); |
||||
node != NULL; |
||||
node = mxmlFindElement(node, tree, "name")) |
||||
{ |
||||
... do something ... |
||||
} |
||||
|
||||
Finally, once you are done with the XML data, use the |
||||
"mxmlDelete()" function to free the memory that is used: |
||||
|
||||
mxmlDelete(tree); |
||||
|
||||
|
||||
GETTING HELP AND REPORTING PROBLEMS |
||||
|
||||
You can email me at "mxml@easysw.com" to report problems |
||||
and/or ask for help. Just don't expect an instant response, |
||||
as I get a *lot* of email... |
||||
|
||||
|
||||
LEGAL STUFF |
||||
|
||||
The Mini-XML library is Copyright 2003 by Michael Sweet. |
||||
|
||||
This library 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 of the License, or (at your option) any |
||||
later version. |
||||
|
||||
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 Library General Public License for |
||||
more details. |
||||
|
||||
You should have received a copy of the GNU Library General |
||||
Public License along with this library; if not, write to the |
||||
Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA |
||||
02139, USA. |
@ -0,0 +1,45 @@ |
||||
dnl |
||||
dnl "$Id: configure.in,v 1.1 2003/06/03 19:46:30 mike Exp $" |
||||
dnl |
||||
dnl Configuration script for mini-XML, a small XML-like file parsing library. |
||||
dnl |
||||
dnl Copyright 2003 by Michael Sweet. |
||||
dnl |
||||
dnl This program is free software; you can redistribute it and/or |
||||
dnl modify it under the terms of the GNU Library General Public |
||||
dnl License as published by the Free Software Foundation; either |
||||
dnl version 2, or (at your option) any later version. |
||||
dnl |
||||
dnl This program is distributed in the hope that it will be useful, |
||||
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
dnl GNU General Public License for more details. |
||||
dnl |
||||
|
||||
AC_INIT(mxml.h) |
||||
#AC_PREFIX_DEFAULT(/usr) |
||||
|
||||
dnl Checks for programs... |
||||
AC_PATH_PROG(AR,ar) |
||||
AC_PROG_CC |
||||
AC_PROG_CXX |
||||
AC_PROG_RANLIB |
||||
|
||||
dnl Flags for "ar" command... |
||||
case "`uname`" in |
||||
Darwin* | *BSD*) |
||||
ARFLAGS="-rcv" |
||||
;; |
||||
*) |
||||
ARFLAGS="crvs" |
||||
;; |
||||
esac |
||||
|
||||
AC_SUBST(ARFLAGS) |
||||
|
||||
dnl Output the makefile... |
||||
AC_OUTPUT(Makefile) |
||||
|
||||
dnl |
||||
dnl End of "$Id: configure.in,v 1.1 2003/06/03 19:46:30 mike Exp $". |
||||
dnl |
@ -0,0 +1,165 @@ |
||||
<HTML> |
||||
<HEAD> |
||||
<TITLE>Mini-XML Home Page</TITLE> |
||||
</HEAD> |
||||
<BODY> |
||||
|
||||
<SPAN STYLE="text-align: justify;"> |
||||
|
||||
<H1 ALIGN="CENTER">Mini-XML Home Page</H1> |
||||
|
||||
<P ALIGN="CENTER">Current Release: v0.9 ( <A |
||||
HREF="mxml-0.9.tar.gz">download 40k</A> )</P> |
||||
|
||||
<H2>Introduction</H2> |
||||
|
||||
<P>Mini-XML is a small XML parsing library that you can use to |
||||
read XML and XML-like data files in your application without |
||||
requiring large non-standard libraries. Mini-XML only requires |
||||
an ANSI C compatible compiler (GCC works, as do most vendors' |
||||
ANSI C compilers) and a "make" program. |
||||
|
||||
<P>Mini-XML was created to support the basic hierarchy provided |
||||
by XML and some simple data types, but doesn't do validation or |
||||
other types of processing on the data. |
||||
|
||||
<H2>Building Mini-XML</H2> |
||||
|
||||
<P>Mini-XML comes with an autoconf-based configure script; just |
||||
type the following command to get things going: |
||||
|
||||
<PRE> |
||||
./configure |
||||
</PRE> |
||||
|
||||
<P>The default install prefix is /usr/local, which can be |
||||
overridden using the --prefix option: |
||||
|
||||
<PRE> |
||||
./configure --prefix=/foo |
||||
</PRE> |
||||
|
||||
<P>Once you have configured the software, type "make" to do the |
||||
build and then run the test program to verify that things are |
||||
working, as follows: |
||||
|
||||
<PRE> |
||||
make |
||||
./testmxml test.xml |
||||
</PRE> |
||||
|
||||
<H2>Installing Mini-XML</H2> |
||||
|
||||
<P>The "install" target will install Mini-XML in the lib and |
||||
include directories: |
||||
|
||||
<PRE> |
||||
make install |
||||
</PRE> |
||||
|
||||
<P>Once you have installed it, use the "-lmxml" option to link |
||||
your application against it. |
||||
|
||||
<H2>Documentation</H2> |
||||
|
||||
<P>The documentation is currently just in this page. At |
||||
some point I'll probably do some proper documentation, but |
||||
for now just read here and look at the testmxml.c source |
||||
file for an example of reading and printing the contents of |
||||
an XML file to stdout. |
||||
|
||||
<P>Mini-XML provides a single header file which you include: |
||||
|
||||
<PRE> |
||||
#include <mxml.h> |
||||
</PRE> |
||||
|
||||
<P>Nodes are defined by the "mxml_node_t" structure; the "type" |
||||
member defines the node type (element, integer, opaque, |
||||
real, or text) which determines which value you want to look |
||||
at in the "value" union. New nodes can be created using the |
||||
"mxmlNewElement()", "mxmlNewInteger()", "mxmlNewOpaque()", |
||||
"mxmlNewReal()", and "mxmlNewText()" functions. Only |
||||
elements can have child nodes, and the top node must be an |
||||
element, usually "?xml". |
||||
|
||||
<P>You load an XML file using the "mxmlLoadFile()" function: |
||||
|
||||
<PRE> |
||||
FILE *fp; |
||||
mxml_node_t *tree; |
||||
|
||||
fp = fopen("filename.xml", "r"); |
||||
tree = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK); |
||||
fclose(fp); |
||||
</PRE> |
||||
|
||||
<P>Similarly, you save an XML file using the "mxmlSaveFile()" |
||||
function: |
||||
|
||||
<PRE> |
||||
FILE *fp; |
||||
mxml_node_t *tree; |
||||
|
||||
fp = fopen("filename.xml", "w"); |
||||
mxmlSaveFile(tree, fp); |
||||
fclose(fp); |
||||
</PRE> |
||||
|
||||
<P>You can find a named element/node using the |
||||
"mxmlFindElement()" function: |
||||
|
||||
<PRE> |
||||
mxml_node_t *node = mxmlFindElement(tree, tree, "name"); |
||||
</PRE> |
||||
|
||||
<P>You can also iterate with the same function: |
||||
|
||||
<PRE> |
||||
mxml_node_t *node; |
||||
|
||||
for (node = mxmlFindElement(tree, tree, "name"); |
||||
node != NULL; |
||||
node = mxmlFindElement(node, tree, "name")) |
||||
{ |
||||
... do something ... |
||||
} |
||||
</PRE> |
||||
|
||||
<P>Finally, once you are done with the XML data, use the |
||||
"mxmlDelete()" function to free the memory that is used: |
||||
|
||||
<PRE> |
||||
mxmlDelete(tree); |
||||
</PRE> |
||||
|
||||
<H2>Getting Help and Reporting Problems</H2> |
||||
|
||||
<P>You can email me at "mxml <I>at</I> easysw <I>dot</I> com" to |
||||
report problems and/or ask for help. Just don't expect an |
||||
instant response, as I get a *lot* of email... |
||||
|
||||
<H2>Legal Stuff</H2> |
||||
|
||||
<P>The Mini-XML library is Copyright 2003 by Michael Sweet. |
||||
|
||||
<P>This library 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 of the License, or (at your option) any |
||||
later version. |
||||
|
||||
<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 Library General Public License for |
||||
more details. |
||||
|
||||
<P>You should have received a copy of the GNU Library General |
||||
Public License along with this library; if not, write to the |
||||
Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA |
||||
02139, USA. |
||||
|
||||
</SPAN> |
||||
</BODY> |
||||
</HTML> |
@ -0,0 +1,151 @@ |
||||
/*
|
||||
* "$Id: mxml-attr.c,v 1.1 2003/06/03 19:46:30 mike Exp $" |
||||
* |
||||
* Attribute support code for mini-XML, a small XML-like file parsing library. |
||||
* |
||||
* Copyright 2003 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. |
||||
* |
||||
* Contents: |
||||
* |
||||
* mxmlElementGetAttr() - Get an attribute. |
||||
* mxmlElementSetAttr() - Set an attribute. |
||||
*/ |
||||
|
||||
/*
|
||||
* Include necessary headers... |
||||
*/ |
||||
|
||||
#include "mxml.h" |
||||
|
||||
|
||||
/*
|
||||
* 'mxmlElementGetAttr()' - Get an attribute. |
||||
*/ |
||||
|
||||
const char * /* O - Attribute value or NULL */ |
||||
mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */ |
||||
const char *name) /* I - Name of attribute */ |
||||
{ |
||||
int i; /* Looping var */ |
||||
mxml_attr_t *attr; /* Cirrent attribute */ |
||||
|
||||
|
||||
/*
|
||||
* Range check input... |
||||
*/ |
||||
|
||||
if (!node || node->type != MXML_ELEMENT || !name) |
||||
return (NULL); |
||||
|
||||
/*
|
||||
* Look for the attribute... |
||||
*/ |
||||
|
||||
for (i = node->value.element.num_attrs, attr = node->value.element.attrs; |
||||
i > 0; |
||||
i --, attr ++) |
||||
if (!strcmp(attr->name, name)) |
||||
return (attr->value); |
||||
|
||||
/*
|
||||
* Didn't find attribute, so return NULL... |
||||
*/ |
||||
|
||||
return (NULL); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* 'mxmlElementSetAttr()' - Set an attribute. |
||||
*/ |
||||
|
||||
void |
||||
mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */ |
||||
const char *name, /* I - Name of attribute */ |
||||
const char *value) /* I - Attribute value */ |
||||
{ |
||||
int i; /* Looping var */ |
||||
mxml_attr_t *attr; /* New attribute */ |
||||
|
||||
|
||||
/*
|
||||
* Range check input... |
||||
*/ |
||||
|
||||
if (!node || node->type != MXML_ELEMENT || !name || !value) |
||||
return; |
||||
|
||||
/*
|
||||
* Look for the attribute... |
||||
*/ |
||||
|
||||
for (i = node->value.element.num_attrs, attr = node->value.element.attrs; |
||||
i > 0; |
||||
i --, attr ++) |
||||
if (!strcmp(attr->name, name)) |
||||
{ |
||||
/*
|
||||
* Replace the attribute value and return... |
||||
*/ |
||||
|
||||
free(attr->value); |
||||
|
||||
attr->value = strdup(value); |
||||
|
||||
return; |
||||
} |
||||
|
||||
/*
|
||||
* Attribute not found, so add a new one... |
||||
*/ |
||||
|
||||
if (node->value.element.num_attrs == 0) |
||||
attr = malloc(sizeof(mxml_attr_t)); |
||||
else |
||||
attr = realloc(node->value.element.attrs, |
||||
(node->value.element.num_attrs + 1) * sizeof(mxml_attr_t)); |
||||
|
||||
if (!attr) |
||||
{ |
||||
fprintf(stderr, "Unable to allocate memory for attribute '%s' in element %s!\n", |
||||
name, node->value.element.name); |
||||
return; |
||||
} |
||||
|
||||
node->value.element.attrs = attr; |
||||
attr += node->value.element.num_attrs; |
||||
|
||||
attr->name = strdup(name); |
||||
attr->value = strdup(value); |
||||
|
||||
if (!attr->name || !attr->value) |
||||
{ |
||||
if (attr->name) |
||||
free(attr->name); |
||||
|
||||
if (attr->value) |
||||
free(attr->value); |
||||
|
||||
fprintf(stderr, "Unable to allocate memory for attribute '%s' in element %s!\n", |
||||
name, node->value.element.name); |
||||
|
||||
return; |
||||
} |
||||
|
||||
node->value.element.num_attrs ++; |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* End of "$Id: mxml-attr.c,v 1.1 2003/06/03 19:46:30 mike Exp $". |
||||
*/ |
@ -0,0 +1,636 @@ |
||||
/*
|
||||
* "$Id: mxml-file.c,v 1.1 2003/06/03 19:46:30 mike Exp $" |
||||
* |
||||
* File loading code for mini-XML, a small XML-like file parsing library. |
||||
* |
||||
* Copyright 2003 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. |
||||
* |
||||
* Contents: |
||||
* |
||||
* mxmlLoadFile() - Load a file into an XML node tree. |
||||
* mxmlSaveFile() - Save an XML tree to a file. |
||||
* mxml_parse_element() - Parse an element for any attributes... |
||||
* mxml_write_string() - Write a string, escaping & and < as needed. |
||||
*/ |
||||
|
||||
/*
|
||||
* Include necessary headers... |
||||
*/ |
||||
|
||||
#include "mxml.h" |
||||
|
||||
|
||||
/*
|
||||
* Local functions... |
||||
*/ |
||||
|
||||
static int mxml_parse_element(mxml_node_t *node, FILE *fp); |
||||
static int mxml_write_string(const char *s, FILE *fp); |
||||
|
||||
|
||||
/*
|
||||
* 'mxmlLoadFile()' - Load a file into an XML node tree. |
||||
*/ |
||||
|
||||
mxml_node_t * /* O - First node */ |
||||
mxmlLoadFile(mxml_node_t *top, /* I - Top node */ |
||||
FILE *fp, /* I - File to read from */ |
||||
mxml_type_t (*cb)(mxml_node_t *)) |
||||
/* I - Callback function */ |
||||
{ |
||||
mxml_node_t *node, /* Current node */ |
||||
*parent; /* Current parent node */ |
||||
int ch, /* Character from file */ |
||||
whitespace; /* Non-zero if whitespace seen */ |
||||
char buffer[16384], /* String buffer */ |
||||
*bufptr; /* Pointer into buffer */ |
||||
mxml_type_t type; /* Current node type */ |
||||
|
||||
|
||||
/*
|
||||
* Read elements and other nodes from the file... |
||||
*/ |
||||
|
||||
bufptr = buffer; |
||||
parent = top; |
||||
whitespace = 0; |
||||
|
||||
if (cb && parent) |
||||
type = (*cb)(parent); |
||||
else |
||||
type = MXML_TEXT; |
||||
|
||||
while ((ch = getc(fp)) != EOF) |
||||
{ |
||||
if ((ch == '<' || (isspace(ch) && type != MXML_OPAQUE)) && bufptr > buffer) |
||||
{ |
||||
/*
|
||||
* Add a new value node... |
||||
*/ |
||||
|
||||
*bufptr = '\0'; |
||||
bufptr = buffer; |
||||
|
||||
switch (type) |
||||
{ |
||||
case MXML_INTEGER : |
||||
node = mxmlNewInteger(parent, strtol(buffer, NULL, 0)); |
||||
break; |
||||
|
||||
case MXML_OPAQUE : |
||||
node = mxmlNewOpaque(parent, buffer); |
||||
break; |
||||
|
||||
case MXML_REAL : |
||||
node = mxmlNewReal(parent, strtod(buffer, NULL)); |
||||
break; |
||||
|
||||
case MXML_TEXT : |
||||
node = mxmlNewText(parent, whitespace, buffer); |
||||
break; |
||||
|
||||
default : /* Should never happen... */ |
||||
node = NULL; |
||||
break; |
||||
}
|
||||
|
||||
whitespace = isspace(ch) != 0; |
||||
|
||||
if (!node) |
||||
{ |
||||
/*
|
||||
* Just print error for now... |
||||
*/ |
||||
|
||||
fprintf(stderr, "Unable to add value node of type %d to parent <%s>!\n", |
||||
type, parent ? parent->value.element.name : "null"); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (ch == '<') |
||||
{ |
||||
/*
|
||||
* Start of open/close tag... |
||||
*/ |
||||
|
||||
bufptr = buffer; |
||||
|
||||
while ((ch = getc(fp)) != EOF) |
||||
if (isspace(ch) || ch == '>' || (ch == '/' && bufptr > buffer)) |
||||
break; |
||||
else if (bufptr < (buffer + sizeof(buffer) - 1)) |
||||
*bufptr++ = ch; |
||||
|
||||
*bufptr = '\0'; |
||||
bufptr = buffer; |
||||
|
||||
if (buffer[0] == '/') |
||||
{ |
||||
/*
|
||||
* Handle close tag... |
||||
*/ |
||||
|
||||
if (!parent || strcmp(buffer + 1, parent->value.element.name)) |
||||
{ |
||||
/*
|
||||
* Close tag doesn't match tree; print an error for now... |
||||
*/ |
||||
|
||||
fprintf(stderr, "Mismatched close tag <%s> under parent <%s>!\n", |
||||
buffer, parent->value.element.name); |
||||
break; |
||||
} |
||||
|
||||
/*
|
||||
* Keep reading until we see >... |
||||
*/ |
||||
|
||||
while (ch != '>' && ch != EOF) |
||||
ch = getc(fp); |
||||
|
||||
/*
|
||||
* Ascend into the parent and set the value type as needed... |
||||
*/ |
||||
|
||||
parent = parent->parent; |
||||
|
||||
if (cb) |
||||
type = (*cb)(parent); |
||||
} |
||||
else |
||||
{ |
||||
/*
|
||||
* Handle open tag... |
||||
*/ |
||||
|
||||
node = mxmlNewElement(parent, buffer); |
||||
|
||||
if (!node) |
||||
{ |
||||
/*
|
||||
* Just print error for now... |
||||
*/ |
||||
|
||||
fprintf(stderr, "Unable to add element node to parent <%s>!\n", |
||||
parent ? parent->value.element.name : "null"); |
||||
break; |
||||
} |
||||
|
||||
if (isspace(ch)) |
||||
ch = mxml_parse_element(node, fp); |
||||
else if (ch == '/') |
||||
{ |
||||
if ((ch = getc(fp)) != '>') |
||||
{ |
||||
fprintf(stderr, "Expected > but got '%c' instead for element <%s/>!\n", |
||||
ch, buffer); |
||||
break; |
||||
} |
||||
|
||||
ch = '/'; |
||||
} |
||||
|
||||
if (ch == EOF) |
||||
break; |
||||
|
||||
if (ch != '/') |
||||
{ |
||||
/*
|
||||
* Descend into this node, setting the value type as needed... |
||||
*/ |
||||
|
||||
parent = node; |
||||
|
||||
if (cb) |
||||
type = (*cb)(parent); |
||||
} |
||||
} |
||||
} |
||||
else if (ch == '&') |
||||
{ |
||||
/*
|
||||
* Add character entity to current buffer... Currently we only |
||||
* support <, &, &#nnn;, and &#xXXXX;... |
||||
*/ |
||||
|
||||
char entity[64], /* Entity string */ |
||||
*entptr; /* Pointer into entity */ |
||||
|
||||
|
||||
entity[0] = ch; |
||||
entptr = entity + 1; |
||||
|
||||
while ((ch = getc(fp)) != EOF) |
||||
if (!isalnum(ch) && ch != '#') |
||||
break; |
||||
else if (entptr < (entity + sizeof(entity) - 1)) |
||||
*entptr++ = ch; |
||||
else |
||||
{ |
||||
fprintf(stderr, "Entity name too long under parent <%s>!\n", |
||||
parent ? parent->value.element.name : "null"); |
||||
break; |
||||
} |
||||
|
||||
*entptr = '\0'; |
||||
|
||||
if (ch != ';') |
||||
{ |
||||
fprintf(stderr, "Entity name \"%s\" not terminated under parent <%s>!\n", |
||||
entity, parent ? parent->value.element.name : "null"); |
||||
break; |
||||
} |
||||
|
||||
if (entity[1] == '#') |
||||
{ |
||||
if (entity[2] == 'x') |
||||
ch = strtol(entity + 3, NULL, 16); |
||||
else |
||||
ch = strtol(entity + 2, NULL, 10); |
||||
} |
||||
else if (!strcmp(entity, "<")) |
||||
ch = '<'; |
||||
else if (!strcmp(entity, "&")) |
||||
ch = '&'; |
||||
else |
||||
{ |
||||
fprintf(stderr, "Entity name \"%s;\" not supported under parent <%s>!\n", |
||||
entity, parent ? parent->value.element.name : "null"); |
||||
break; |
||||
} |
||||
|
||||
if (ch < 128) |
||||
{ |
||||
/*
|
||||
* Plain ASCII doesn't need special encoding... |
||||
*/ |
||||
|
||||
if (bufptr < (buffer + sizeof(buffer) - 1)) |
||||
*bufptr++ = ch; |
||||
else |
||||
{ |
||||
fprintf(stderr, "String too long in file under parent <%s>!\n", |
||||
parent ? parent->value.element.name : "null"); |
||||
break; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
/*
|
||||
* Use UTF-8 encoding for the Unicode char... |
||||
*/ |
||||
|
||||
if (bufptr < (buffer + sizeof(buffer) - 5)) |
||||
{ |
||||
if (ch < 2048) |
||||
{ |
||||
*bufptr++ = 0xc0 | (ch >> 6); |
||||
*bufptr++ = 0x80 | (ch & 63); |
||||
} |
||||
else if (ch < 65536) |
||||
{ |
||||
*bufptr++ = 0xe0 | (ch >> 12); |
||||
*bufptr++ = 0x80 | ((ch >> 6) & 63); |
||||
*bufptr++ = 0x80 | (ch & 63); |
||||
} |
||||
else |
||||
{ |
||||
*bufptr++ = 0xf0 | (ch >> 18); |
||||
*bufptr++ = 0x80 | ((ch >> 12) & 63); |
||||
*bufptr++ = 0x80 | ((ch >> 6) & 63); |
||||
*bufptr++ = 0x80 | (ch & 63); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
fprintf(stderr, "String too long in file under parent <%s>!\n", |
||||
parent ? parent->value.element.name : "null"); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
else if (type == MXML_OPAQUE || !isspace(ch)) |
||||
{ |
||||
/*
|
||||
* Add character to current buffer... |
||||
*/ |
||||
|
||||
if (bufptr < (buffer + sizeof(buffer) - 1)) |
||||
*bufptr++ = ch; |
||||
else |
||||
{ |
||||
fprintf(stderr, "String too long in file under parent <%s>!\n", |
||||
parent ? parent->value.element.name : "null"); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Find the top element and return it... |
||||
*/ |
||||
|
||||
if (parent) |
||||
{ |
||||
while (parent->parent != top) |
||||
parent = parent->parent; |
||||
} |
||||
|
||||
return (parent); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* 'mxmlSaveFile()' - Save an XML tree to a file. |
||||
*/ |
||||
|
||||
int /* O - 0 on success, -1 on error */ |
||||
mxmlSaveFile(mxml_node_t *node, /* I - Node to write */ |
||||
FILE *fp) /* I - File to write to */ |
||||
{ |
||||
int i; /* Looping var */ |
||||
|
||||
|
||||
while (node != NULL) |
||||
{ |
||||
/*
|
||||
* Print the node value... |
||||
*/ |
||||
|
||||
switch (node->type) |
||||
{ |
||||
case MXML_ELEMENT : |
||||
if (fprintf(fp, "<%s", node->value.element.name) < 0) |
||||
return (-1); |
||||
|
||||
for (i = 0; i < node->value.element.num_attrs; i ++) |
||||
if (fprintf(fp, " %s=\"%s\"", node->value.element.attrs[i].name, |
||||
node->value.element.attrs[i].value) < 0) |
||||
return (-1); |
||||
|
||||
if (node->child) |
||||
{ |
||||
/*
|
||||
* The ?xml element is a special-case and has no end tag... |
||||
*/ |
||||
|
||||
if (node->value.element.name[0] == '?') |
||||
{ |
||||
if (fputs("?>\n", fp) < 0) |
||||
return (-1); |
||||
} |
||||
else if (putc('>', fp) < 0) |
||||
return (-1); |
||||
|
||||
if (mxmlSaveFile(node->child, fp) < 0) |
||||
return (-1); |
||||
|
||||
if (node->value.element.name[0] != '?') |
||||
if (fprintf(fp, "</%s>", node->value.element.name) < 0) |
||||
return (-1); |
||||
} |
||||
else if (fputs("/>", fp) < 0) |
||||
return (-1); |
||||
break; |
||||
|
||||
case MXML_INTEGER : |
||||
if (node->prev) |
||||
if (putc(' ', fp) < 0) |
||||
return (-1); |
||||
|
||||
if (fprintf(fp, "%d", node->value.integer) < 0) |
||||
return (-1); |
||||
break; |
||||
|
||||
case MXML_OPAQUE : |
||||
if (mxml_write_string(node->value.opaque, fp) < 0) |
||||
return (-1); |
||||
break; |
||||
|
||||
case MXML_REAL : |
||||
if (node->prev) |
||||
if (putc(' ', fp) < 0) |
||||
return (-1); |
||||
|
||||
if (fprintf(fp, "%f", node->value.real) < 0) |
||||
return (-1); |
||||
break; |
||||
|
||||
case MXML_TEXT : |
||||
if (node->value.text.whitespace) |
||||
if (putc(' ', fp) < 0) |
||||
return (-1); |
||||
|
||||
if (mxml_write_string(node->value.text.string, fp) < 0) |
||||
return (-1); |
||||
break; |
||||
} |
||||
|
||||
/*
|
||||
* Next node... |
||||
*/ |
||||
|
||||
node = node->next; |
||||
} |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* 'mxml_parse_element()' - Parse an element for any attributes... |
||||
*/ |
||||
|
||||
static int /* O - Terminating character */ |
||||
mxml_parse_element(mxml_node_t *node, /* I - Element node */ |
||||
FILE *fp) /* I - File to read from */ |
||||
{ |
||||
int ch, /* Current character in file */ |
||||
quote; /* Quoting character */ |
||||
char name[256], /* Attribute name */ |
||||
value[256], /* Attribute value */ |
||||
*ptr; /* Pointer into name/value */ |
||||
|
||||
|
||||
/*
|
||||
* Loop until we hit a >, /, ?, or EOF... |
||||
*/ |
||||
|
||||
while ((ch = getc(fp)) != EOF) |
||||
{ |
||||
/*
|
||||
* Skip leading whitespace... |
||||
*/ |
||||
|
||||
if (isspace(ch)) |
||||
continue; |
||||
|
||||
/*
|
||||
* Stop at /, ?, or >... |
||||
*/ |
||||
|
||||
if (ch == '/' || ch == '?') |
||||
{ |
||||
/*
|
||||
* Grab the > character and print an error if it isn't there... |
||||
*/ |
||||
|
||||
quote = getc(fp); |
||||
|
||||
if (quote != '>') |
||||
{ |
||||
fprintf(stderr, "Expected '>' after '%c' for element %s, but got '%c'!\n", |
||||
ch, node->value.element.name, quote); |
||||
ch = EOF; |
||||
} |
||||
|
||||
break; |
||||
} |
||||
else if (ch == '>') |
||||
break; |
||||
|
||||
/*
|
||||
* Read the attribute name... |
||||
*/ |
||||
|
||||
name[0] = ch; |
||||
ptr = name + 1; |
||||
|
||||
while ((ch = getc(fp)) != EOF) |
||||
if (isspace(ch) || ch == '=' || ch == '/' || ch == '>' || ch == '?') |
||||
break; |
||||
else if (ptr < (name + sizeof(name) - 1)) |
||||
*ptr++ = ch; |
||||
else |
||||
{ |
||||
fprintf(stderr, "Attribute name too long for element %s!\n", |
||||
node->value.element.name); |
||||
return (EOF); |
||||
} |
||||
|
||||
*ptr = '\0'; |
||||
|
||||
if (ch == '=') |
||||
{ |
||||
/*
|
||||
* Read the attribute value... |
||||
*/ |
||||
|
||||
if ((ch = getc(fp)) == EOF) |
||||
{ |
||||
fprintf(stderr, "Missing value for attribute '%s' in element %s!\n", |
||||
name, node->value.element.name); |
||||
return (EOF); |
||||
} |
||||
|
||||
if (ch == '\'' || ch == '\"') |
||||
{ |
||||
/*
|
||||
* Read quoted value... |
||||
*/ |
||||
|
||||
quote = ch; |
||||
ptr = value; |
||||
|
||||
while ((ch = getc(fp)) != EOF) |
||||
if (ch == quote) |
||||
break; |
||||
else if (ptr < (value + sizeof(value) - 1)) |
||||
*ptr++ = ch; |
||||
else |
||||
{ |
||||
fprintf(stderr, "Attribute value too long for attribute '%s' in element %s!\n", |
||||
name, node->value.element.name); |
||||
return (EOF); |
||||
} |
||||
|
||||
*ptr = '\0'; |
||||
} |
||||
else |
||||
{ |
||||
/*
|
||||
* Read unquoted value... |
||||
*/ |
||||
|
||||
value[0] = ch; |
||||
ptr = value + 1; |
||||
|
||||
while ((ch = getc(fp)) != EOF) |
||||
if (isspace(ch) || ch == '=' || ch == '/' || ch == '>') |
||||
break; |
||||
else if (ptr < (value + sizeof(value) - 1)) |
||||
*ptr++ = ch; |
||||
else |
||||
{ |
||||
fprintf(stderr, "Attribute value too long for attribute '%s' in element %s!\n", |
||||
name, node->value.element.name); |
||||
return (EOF); |
||||
} |
||||
|
||||
*ptr = '\0'; |
||||
} |
||||
} |
||||
else |
||||
value[0] = '\0'; |
||||
|
||||
/*
|
||||
* Save last character in case we need it... |
||||
*/ |
||||
|
||||
if (ch == '/' || ch == '>' || ch == '?') |
||||
ungetc(ch, fp); |
||||
|
||||
/*
|
||||
* Set the attribute... |
||||
*/ |
||||
|
||||
mxmlElementSetAttr(node, name, value); |
||||
} |
||||
|
||||
return (ch); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* 'mxml_write_string()' - Write a string, escaping & and < as needed. |
||||
*/ |
||||
|
||||
static int /* O - 0 on success, -1 on failure */ |
||||
mxml_write_string(const char *s, /* I - String to write */ |
||||
FILE *fp) /* I - File to write to */ |
||||
{ |
||||
while (*s) |
||||
{ |
||||
if (*s == '&') |
||||
{ |
||||
if (fputs("&", fp) < 0) |
||||
return (-1); |
||||
} |
||||
else if (*s == '<') |
||||
{ |
||||
if (fputs("<", fp) < 0) |
||||
return (-1); |
||||
} |
||||
else if (putc(*s, fp) < 0) |
||||
return (-1); |
||||
|
||||
s ++; |
||||
} |
||||
|
||||
return (0); |
||||
} |
||||
|
||||
|
||||
|
||||
/*
|
||||
* End of "$Id: mxml-file.c,v 1.1 2003/06/03 19:46:30 mike Exp $". |
||||
*/ |
@ -0,0 +1,331 @@ |
||||
/*
|
||||
* "$Id: mxml-node.c,v 1.1 2003/06/03 19:46:30 mike Exp $" |
||||
* |
||||
* Node support code for mini-XML, a small XML-like file parsing library. |
||||
* |
||||
* Copyright 2003 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. |
||||
* |
||||
* Contents: |
||||
* |
||||
* mxmlDelete() - Delete a node and all of its children. |
||||
* mxmlNewElement() - Create a new element node. |
||||
* mxmlNewInteger() - Create a new integer node. |
||||
* mxmlNewOpaque() - Create a new opaque string. |
||||
* mxmlNewReal() - Create a new real number node. |
||||
* mxmlNewText() - Create a new text fragment node. |
||||
* mxml_new() - Create a new node. |
||||
*/ |
||||
|
||||
/*
|
||||
* Include necessary headers... |
||||
*/ |
||||
|
||||
#include "mxml.h" |
||||
|
||||
|
||||
/*
|
||||
* Local functions... |
||||
*/ |
||||
|
||||
static mxml_node_t *mxml_new(mxml_node_t *parent, mxml_type_t type); |
||||
|
||||
|
||||
/*
|
||||
* 'mxmlDelete()' - Delete a node and all of its children. |
||||
*/ |
||||
|
||||
void |
||||
mxmlDelete(mxml_node_t *node) /* I - Node */ |
||||
{ |
||||
int i; /* Looping var */ |
||||
|
||||
|
||||
/*
|
||||
* Range check input... |
||||
*/ |
||||
|
||||
if (!node) |
||||
return; |
||||
|
||||
/*
|
||||
* Delete children first... |
||||
*/ |
||||
|
||||
while (node->child) |
||||
mxmlDelete(node->child); |
||||
|
||||
/*
|
||||
* Now delete any node data... |
||||
*/ |
||||
|
||||
switch (node->type) |
||||
{ |
||||
case MXML_ELEMENT : |
||||
if (node->value.element.name) |
||||
free(node->value.element.name); |
||||
|
||||
if (node->value.element.num_attrs) |
||||
{ |
||||
for (i = 0; i < node->value.element.num_attrs; i ++) |
||||
{ |
||||
if (node->value.element.attrs[i].name) |
||||
free(node->value.element.attrs[i].name); |
||||
if (node->value.element.attrs[i].value) |
||||
free(node->value.element.attrs[i].value); |
||||
} |
||||
|
||||
free(node->value.element.attrs); |
||||
} |
||||
break; |
||||
case MXML_INTEGER : |
||||
/* Nothing to do */ |
||||
break; |
||||
case MXML_OPAQUE : |
||||
if (node->value.opaque) |
||||
free(node->value.opaque); |
||||
break; |
||||
case MXML_REAL : |
||||
/* Nothing to do */ |
||||
break; |
||||
case MXML_TEXT : |
||||
if (node->value.text.string) |
||||
free(node->value.text.string); |
||||
break; |
||||
} |
||||
|
||||
/*
|
||||
* Remove from parent, if any... |
||||
*/ |
||||
|
||||
if (node->parent) |
||||
{ |
||||
if (node->prev) |
||||
node->prev->next = node->next; |
||||
else |
||||
node->parent->child = node->next; |
||||
|
||||
if (node->next) |
||||
node->next->prev = node->prev; |
||||
else |
||||
node->parent->last_child = node->prev; |
||||
} |
||||
|
||||
/*
|
||||
* Free this node... |
||||
*/ |
||||
|
||||
free(node); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* 'mxmlNewElement()' - Create a new element node. |
||||
*/ |
||||
|
||||
mxml_node_t * /* O - New node */ |
||||
mxmlNewElement(mxml_node_t *parent, /* I - Parent node */ |
||||
const char *name) /* I - Name of element */ |
||||
{ |
||||
mxml_node_t *node; /* New node */ |
||||
|
||||
|
||||
/*
|
||||
* Range check input... |
||||
*/ |
||||
|
||||
if (!name) |
||||
return (NULL); |
||||
|
||||
/*
|
||||
* Create the node and set the element name... |
||||
*/ |
||||
|
||||
if ((node = mxml_new(parent, MXML_ELEMENT)) != NULL) |
||||
node->value.element.name = strdup(name); |
||||
|
||||
return (node); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* 'mxmlNewInteger()' - Create a new integer node. |
||||
*/ |
||||
|
||||
mxml_node_t * /* O - New node */ |
||||
mxmlNewInteger(mxml_node_t *parent, /* I - Parent node */ |
||||
int integer) /* I - Integer value */ |
||||
{ |
||||
mxml_node_t *node; /* New node */ |
||||
|
||||
|
||||
/*
|
||||
* Range check input... |
||||
*/ |
||||
|
||||
if (!parent) |
||||
return (NULL); |
||||
|
||||
/*
|
||||
* Create the node and set the element name... |
||||
*/ |
||||
|
||||
if ((node = mxml_new(parent, MXML_INTEGER)) != NULL) |
||||
node->value.integer = integer; |
||||
|
||||
return (node); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* 'mxmlNewOpaque()' - Create a new opaque string. |
||||
*/ |
||||
|
||||
mxml_node_t * /* O - New node */ |
||||
mxmlNewOpaque(mxml_node_t *parent, /* I - Parent node */ |
||||
const char *opaque) /* I - Opaque string */ |
||||
{ |
||||
mxml_node_t *node; /* New node */ |
||||
|
||||
|
||||
/*
|
||||
* Range check input... |
||||
*/ |
||||
|
||||
if (!parent || !opaque) |
||||
return (NULL); |
||||
|
||||
/*
|
||||
* Create the node and set the element name... |
||||
*/ |
||||
|
||||
if ((node = mxml_new(parent, MXML_OPAQUE)) != NULL) |
||||
node->value.opaque = strdup(opaque); |
||||
|
||||
return (node); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* 'mxmlNewReal()' - Create a new real number node. |
||||
*/ |
||||
|
||||
mxml_node_t * /* O - New node */ |
||||
mxmlNewReal(mxml_node_t *parent, /* I - Parent node */ |
||||
double real) /* I - Real number value */ |
||||
{ |
||||
mxml_node_t *node; /* New node */ |
||||
|
||||
|
||||
/*
|
||||
* Range check input... |
||||
*/ |
||||
|
||||
if (!parent) |
||||
return (NULL); |
||||
|
||||
/*
|
||||
* Create the node and set the element name... |
||||
*/ |
||||
|
||||
if ((node = mxml_new(parent, MXML_REAL)) != NULL) |
||||
node->value.real = real; |
||||
|
||||
return (node); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* 'mxmlNewText()' - Create a new text fragment node. |
||||
*/ |
||||
|
||||
mxml_node_t * /* O - New node */ |
||||
mxmlNewText(mxml_node_t *parent, /* I - Parent node */ |
||||
int whitespace, /* I - Leading whitespace? */ |
||||
const char *string) /* I - String */ |
||||
{ |
||||
mxml_node_t *node; /* New node */ |
||||
|
||||
|
||||
/*
|
||||
* Range check input... |
||||
*/ |
||||
|
||||
if (!parent || !string) |
||||
return (NULL); |
||||
|
||||
/*
|
||||
* Create the node and set the text value... |
||||
*/ |
||||
|
||||
if ((node = mxml_new(parent, MXML_TEXT)) != NULL) |
||||
{ |
||||
node->value.text.whitespace = whitespace; |
||||
node->value.text.string = strdup(string); |
||||
} |
||||
|
||||
return (node); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* 'mxml_new()' - Create a new node. |
||||
*/ |
||||
|
||||
static mxml_node_t * /* O - New node */ |
||||
mxml_new(mxml_node_t *parent, /* I - Parent node */ |
||||
mxml_type_t type) /* I - Node type */ |
||||
{ |
||||
mxml_node_t *node; /* New node */ |
||||
|
||||
|
||||
/*
|
||||
* Allocate memory for the node... |
||||
*/ |
||||
|
||||
if ((node = calloc(1, sizeof(mxml_node_t))) == NULL) |
||||
return (NULL); |
||||
|
||||
/*
|
||||
* Set the node type... |
||||
*/ |
||||
|
||||
node->type = type; |
||||
|
||||
/*
|
||||
* Add to the parent if present... |
||||
*/ |
||||
|
||||
if (parent) |
||||
{ |
||||
node->parent = parent; |
||||
node->prev = parent->last_child; |
||||
|
||||
if (parent->last_child) |
||||
parent->last_child->next = node; |
||||
else |
||||
parent->child = node; |
||||
|
||||
parent->last_child = node; |
||||
} |
||||
|
||||
/*
|
||||
* Return the new node... |
||||
*/ |
||||
|
||||
return (node); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* End of "$Id: mxml-node.c,v 1.1 2003/06/03 19:46:30 mike Exp $". |
||||
*/ |
@ -0,0 +1,116 @@ |
||||
/*
|
||||
* "$Id: mxml-search.c,v 1.1 2003/06/03 19:46:30 mike Exp $" |
||||
* |
||||
* Search/navigation functions for mini-XML, a small XML-like file |
||||
* parsing library. |
||||
* |
||||
* Copyright 2003 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. |
||||
* |
||||
* Contents: |
||||
* |
||||
* mxmlFindElement() - Find the named element. |
||||
* mxmlWalkNext() - Walk to the next logical node in the tree. |
||||
* mxmlWalkPrev() - Walk to the previous logical node in the tree. |
||||
*/ |
||||
|
||||
/*
|
||||
* Include necessary headers... |
||||
*/ |
||||
|
||||
#include "mxml.h" |
||||
|
||||
|
||||
/*
|
||||
* 'mxmlFindElement()' - Find the named element. |
||||
*/ |
||||
|
||||
mxml_node_t * /* O - Element node or NULL */ |
||||
mxmlFindElement(mxml_node_t *node, /* I - Current node */ |
||||
mxml_node_t *top, /* I - Top node */ |
||||
const char *name) /* I - Element name */ |
||||
{ |
||||
/*
|
||||
* Start with the next node... |
||||
*/ |
||||
|
||||
node = mxmlWalkNext(node, top); |
||||
|
||||
/*
|
||||
* Loop until we find a matching element... |
||||
*/ |
||||
|
||||
while (node != NULL) |
||||
{ |
||||
/*
|
||||
* See if this node matches... |
||||
*/ |
||||
|
||||
if (node->type == MXML_ELEMENT && |
||||
node->value.element.name && |
||||
!strcmp(node->value.element.name, name)) |
||||
return (node); |
||||
|
||||
/*
|
||||
* Nope, move on to the next... |
||||
*/ |
||||
|
||||
node = mxmlWalkNext(node, top); |
||||
} |
||||
|
||||
return (NULL); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* 'mxmlWalkNext()' - Walk to the next logical node in the tree. |
||||
*/ |
||||
|
||||
mxml_node_t * /* O - Next node or NULL */ |
||||
mxmlWalkNext(mxml_node_t *node, /* I - Current node */ |
||||
mxml_node_t *top) /* I - Top node */ |
||||
{ |
||||
if (!node) |
||||
return (NULL); |
||||
else if (node->child) |
||||
return (node->child); |
||||
else if (node->next) |
||||
return (node->next); |
||||
else if (node->parent != top) |
||||
return (mxmlWalkNext(node->parent, top)); |
||||
else |
||||
return (NULL); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* 'mxmlWalkPrev()' - Walk to the previous logical node in the tree. |
||||
*/ |
||||
|
||||
mxml_node_t * /* O - Previous node or NULL */ |
||||
mxmlWalkPrev(mxml_node_t *node, /* I - Current node */ |
||||
mxml_node_t *top) /* I - Top node */ |
||||
{ |
||||
if (!node) |
||||
return (NULL); |
||||
else if (node->prev) |
||||
return (node->prev); |
||||
else if (node->parent != top) |
||||
return (node->parent); |
||||
else |
||||
return (NULL); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* End of "$Id: mxml-search.c,v 1.1 2003/06/03 19:46:30 mike Exp $". |
||||
*/ |
@ -0,0 +1,136 @@ |
||||
/*
|
||||
* "$Id: mxml.h,v 1.1 2003/06/03 19:46:30 mike Exp $" |
||||
* |
||||
* for mini-XML, a small XML-like file parsing library. |
||||
* |
||||
* Copyright 2003 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. |
||||
*/ |
||||
|
||||
/*
|
||||
* Prevent multiple inclusion... |
||||
*/ |
||||
|
||||
#ifndef _mxml_h_ |
||||
# define _mxml_h_ |
||||
|
||||
/*
|
||||
* Include necessary headers... |
||||
*/ |
||||
|
||||
# include <stdio.h> |
||||
# include <stdlib.h> |
||||
# include <string.h> |
||||
|
||||
|
||||
/*
|
||||
* Constants... |
||||
*/ |
||||
|
||||
# define MXML_NO_CALLBACK (mxml_type_t (*)(mxml_node_t *))0 |
||||
|
||||
|
||||
/*
|
||||
* Data types... |
||||
*/ |
||||
|
||||
typedef enum /**** Node Type ****/ |
||||
{ |
||||
MXML_ELEMENT, /* XML element with attributes */ |
||||
MXML_INTEGER, /* Integer value */ |
||||
MXML_OPAQUE, /* Opaque string */ |
||||
MXML_REAL, /* Real value */ |
||||
MXML_TEXT /* Text fragment */ |
||||
} mxml_type_t; |
||||
|
||||
typedef struct /**** Attribute Value ****/ |
||||
{ |
||||
char *name, /* Attribute name */ |
||||
*value; /* Attribute value */ |
||||
} mxml_attr_t; |
||||
|
||||
typedef struct /**** Element Value ****/ |
||||
{ |
||||
char *name; /* Name of element */ |
||||
int num_attrs; /* Number of attributes */ |
||||
mxml_attr_t *attrs; /* Attributes */ |
||||
} mxml_element_t; |
||||
|
||||
typedef struct mxml_node_str mxml_node_t; |
||||
|
||||
struct mxml_node_str /**** Node ****/ |
||||
{ |
||||
mxml_type_t type; /* Node type */ |
||||
mxml_node_t *next, /* Next node under same parent */ |
||||
*prev, /* Previous node under same parent */ |
||||
*parent, /* Parent node */ |
||||
*child, /* First child node */ |
||||
*last_child; /* Last child node */ |
||||
union |
||||
{ |
||||
mxml_element_t element; /* Element */ |
||||
int integer; /* Integer number */ |
||||
char *opaque; /* Opaque string */ |
||||
double real; /* Real number */ |
||||
struct |
||||
{ |
||||
int whitespace; /* Leading whitespace? */ |
||||
char *string; /* Fragment string */ |
||||
} text; /* Text fragment */ |
||||
} value; /* Node value */ |
||||
}; |
||||
|
||||
|
||||
/*
|
||||
* C++ support... |
||||
*/ |
||||
|
||||
# ifdef __cplusplus |
||||
extern "C" { |
||||
# endif /* __cplusplus */ |
||||
|
||||
/*
|
||||
* Prototypes... |
||||
*/ |
||||
|
||||
extern void mxmlDelete(mxml_node_t *node); |
||||
extern const char *mxmlElementGetAttr(mxml_node_t *node, const char *name); |
||||
extern void mxmlElementSetAttr(mxml_node_t *node, const char *name, |
||||
const char *value); |
||||
extern mxml_node_t *mxmlFindElement(mxml_node_t *node, mxml_node_t *top, |
||||
const char *name); |
||||
extern mxml_node_t *mxmlLoadFile(mxml_node_t *top, FILE *fp, |
||||
mxml_type_t (*cb)(mxml_node_t *)); |
||||
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); |
||||
extern mxml_node_t *mxmlNewReal(mxml_node_t *parent, double real); |
||||
extern mxml_node_t *mxmlNewText(mxml_node_t *parent, int whitespace, |
||||
const char *string); |
||||
extern int mxmlSaveFile(mxml_node_t *node, FILE *fp); |
||||
extern mxml_node_t *mxmlWalkNext(mxml_node_t *node, mxml_node_t *top); |
||||
extern mxml_node_t *mxmlWalkPrev(mxml_node_t *node, mxml_node_t *top); |
||||
|
||||
|
||||
/*
|
||||
* C++ support... |
||||
*/ |
||||
|
||||
# ifdef __cplusplus |
||||
} |
||||
# endif /* __cplusplus */ |
||||
#endif /* !_mxml_h_ */ |
||||
|
||||
|
||||
/*
|
||||
* End of "$Id: mxml.h,v 1.1 2003/06/03 19:46:30 mike Exp $". |
||||
*/ |
@ -0,0 +1,27 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<option> |
||||
<keyword type="opaque">InputSlot</keyword> |
||||
<default type="opaque">Auto</default> |
||||
<text>Media Source</text> |
||||
<order type="real">10.0</order> |
||||
<choice> |
||||
<keyword type="opaque">Auto</keyword> |
||||
<text>Auto Tray Selection</text> |
||||
<code type="opaque"/> |
||||
</choice> |
||||
<choice> |
||||
<keyword type="opaque">Upper</keyword> |
||||
<text>Tray 1</text> |
||||
<code type="opaque"><</MediaPosition 0>>setpagedevice</code> |
||||
</choice> |
||||
<choice> |
||||
<keyword type="opaque">Lower</keyword> |
||||
<text>Tray 2</text> |
||||
<code type="opaque"><</MediaPosition 1>>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> |
@ -0,0 +1,133 @@ |
||||
/*
|
||||
* "$Id: testmxml.c,v 1.1 2003/06/03 19:46:30 mike Exp $" |
||||
* |
||||
* Test program for mini-XML, a small XML-like file parsing library. |
||||
* |
||||
* Copyright 2003 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. |
||||
* |
||||
* Contents: |
||||
* |
||||
* main() - Main entry for test program. |
||||
* type_cb() - XML data type callback for mxmlLoadFile()... |
||||
*/ |
||||
|
||||
/*
|
||||
* Include necessary headers... |
||||
*/ |
||||
|
||||
#include "mxml.h" |
||||
|
||||
|
||||
/*
|
||||
* Local functions... |
||||
*/ |
||||
|
||||
mxml_type_t type_cb(mxml_node_t *node); |
||||
|
||||
|
||||
/*
|
||||
* 'main()' - Main entry for test program. |
||||
*/ |
||||
|
||||
int /* O - Exit status */ |
||||
main(int argc, /* I - Number of command-line args */ |
||||
char *argv[]) /* I - Command-line args */ |
||||
{ |
||||
FILE *fp; /* File to read */ |
||||
mxml_node_t *tree; /* XML tree */ |
||||
|
||||
|
||||
/*
|
||||
* Check arguments... |
||||
*/ |
||||
|
||||
if (argc != 2) |
||||
{ |
||||
fputs("Usage: testmxml filename.xml\n", stderr); |
||||
return (1); |
||||
} |
||||
|
||||
/*
|
||||
* Open the file... |
||||
*/ |
||||
|
||||
if ((fp = fopen(argv[1], "r")) == NULL) |
||||
{ |
||||
perror(argv[1]); |
||||
return (1); |
||||
} |
||||
|
||||
/*
|
||||
* Read the file... |
||||
*/ |
||||
|
||||
tree = mxmlLoadFile(NULL, fp, type_cb); |
||||
|
||||
fclose(fp); |
||||
|
||||
if (!tree) |
||||
{ |
||||
fputs("Unable to read XML file!\n", stderr); |
||||
return (1); |
||||
} |
||||
|
||||
/*
|
||||
* Print the XML tree... |
||||
*/ |
||||
|
||||
setbuf(stdout, NULL); |
||||
|
||||
mxmlSaveFile(tree, stdout); |
||||
puts(""); |
||||
|
||||
/*
|
||||
* Delete the tree and return... |
||||
*/ |
||||
|
||||
mxmlDelete(tree); |
||||
|
||||
return (0); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* 'type_cb()' - XML data type callback for mxmlLoadFile()... |
||||
*/ |
||||
|
||||
mxml_type_t /* O - Data type */ |
||||
type_cb(mxml_node_t *node) /* I - Element node */ |
||||
{ |
||||
const char *type; /* Type string */ |
||||
|
||||
|
||||
/*
|
||||
* You can lookup attributes and/or use the element name, hierarchy, etc... |
||||
*/ |
||||
|
||||
if ((type = mxmlElementGetAttr(node, "type")) == NULL) |
||||
type = node->value.element.name; |
||||
|
||||
if (!strcmp(type, "integer")) |
||||
return (MXML_INTEGER); |
||||
else if (!strcmp(type, "opaque")) |
||||
return (MXML_OPAQUE); |
||||
else if (!strcmp(type, "real")) |
||||
return (MXML_REAL); |
||||
else |
||||
return (MXML_TEXT); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* End of "$Id: testmxml.c,v 1.1 2003/06/03 19:46:30 mike Exp $". |
||||
*/ |
Loading…
Reference in new issue