Implement mxmlOptions APIs to normalize all of the load/save option stuff (Issue #312)

This commit is contained in:
Michael R Sweet 2024-03-18 21:46:14 -04:00
parent 726dc0dce7
commit e676eb35cb
No known key found for this signature in database
GPG Key ID: BE67C75EC81F3244
18 changed files with 1030 additions and 1298 deletions

View File

@ -9,6 +9,8 @@
`MXML_TYPE_DIRECTIVE` node types (Issue #250) `MXML_TYPE_DIRECTIVE` node types (Issue #250)
- Added `mxmlLoadFilename` and `mxmlSaveFilename` functions (Issue #291) - Added `mxmlLoadFilename` and `mxmlSaveFilename` functions (Issue #291)
- Added AFL fuzzing support (Issue #306) - Added AFL fuzzing support (Issue #306)
- Added `mxmlOptions` APIs to replace the long list of callbacks and options for
each of the load and save functions (Issue #312)
- Added string copy/free callbacks to support alternate memory management of - Added string copy/free callbacks to support alternate memory management of
strings. strings.
- Renamed `mxml_type_t` enumerations to `MXML_TYPE_xxx` (Issue #251) - Renamed `mxml_type_t` enumerations to `MXML_TYPE_xxx` (Issue #251)

View File

@ -150,8 +150,8 @@ BUILDROOT = $(DSTROOT)$(DESTDIR)
DOCFILES = doc/mxml.epub doc/mxml.html doc/mxml-cover.png \ DOCFILES = doc/mxml.epub doc/mxml.html doc/mxml-cover.png \
CHANGES.md LICENSE NOTICE README.md CHANGES.md LICENSE NOTICE README.md
PUBLIBOBJS = mxml-attr.o mxml-entity.o mxml-file.o mxml-get.o \ PUBLIBOBJS = mxml-attr.o mxml-file.o mxml-get.o mxml-index.o \
mxml-index.o mxml-node.o mxml-search.o mxml-set.o mxml-node.o mxml-options.o mxml-search.o mxml-set.o
LIBOBJS = $(PUBLIBOBJS) mxml-private.o LIBOBJS = $(PUBLIBOBJS) mxml-private.o
OBJS = testmxml.o $(LIBOBJS) OBJS = testmxml.o $(LIBOBJS)
ALLTARGETS = $(LIBMXML) testmxml ALLTARGETS = $(LIBMXML) testmxml

View File

@ -5,6 +5,9 @@ copyright: Copyright © 2003-2024, All Rights Reserved.
version: 4.0 version: 4.0
... ...
> TODO: Update for mxmlOptions APIs!
Introduction Introduction
============ ============

View File

@ -173,10 +173,7 @@ mxmlElementSetAttr(mxml_node_t *node, // I - Element node
if (value) if (value)
{ {
if ((valuec = _mxml_strcopy(value)) == NULL) if ((valuec = _mxml_strcopy(value)) == NULL)
{
_mxml_error("Unable to allocate memory for attribute '%s' in element %s.", name, node->value.element.name);
return; return;
}
} }
else else
{ {
@ -218,10 +215,11 @@ mxmlElementSetAttrf(mxml_node_t *node, // I - Element node
vsnprintf(buffer, sizeof(buffer), format, ap); vsnprintf(buffer, sizeof(buffer), format, ap);
va_end(ap); va_end(ap);
if ((value = _mxml_strcopy(buffer)) == NULL) if ((value = _mxml_strcopy(buffer)) != NULL)
_mxml_error("Unable to allocate memory for attribute '%s' in element %s.", name, node->value.element.name); {
else if (!mxml_set_attr(node, name, value)) if (!mxml_set_attr(node, name, value))
_mxml_strfree(value); _mxml_strfree(value);
}
} }
@ -253,19 +251,13 @@ mxml_set_attr(mxml_node_t *node, // I - Element node
// Add a new attribute... // Add a new attribute...
if ((attr = realloc(node->value.element.attrs, (node->value.element.num_attrs + 1) * sizeof(_mxml_attr_t))) == NULL) if ((attr = realloc(node->value.element.attrs, (node->value.element.num_attrs + 1) * sizeof(_mxml_attr_t))) == NULL)
{
_mxml_error("Unable to allocate memory for attribute '%s' in element %s.", name, node->value.element.name);
return (false); return (false);
}
node->value.element.attrs = attr; node->value.element.attrs = attr;
attr += node->value.element.num_attrs; attr += node->value.element.num_attrs;
if ((attr->name = _mxml_strcopy(name)) == NULL) if ((attr->name = _mxml_strcopy(name)) == NULL)
{
_mxml_error("Unable to allocate memory for attribute '%s' in element %s.", name, node->value.element.name);
return (false); return (false);
}
attr->value = value; attr->value = value;

View File

@ -1,433 +0,0 @@
//
// Character entity support code for Mini-XML, a small XML file parsing library.
//
// https://www.msweet.org/mxml
//
// Copyright © 2003-2024 by Michael R Sweet.
//
// Licensed under Apache License v2.0. See the file "LICENSE" for more
// information.
//
#include "mxml-private.h"
//
// 'mxmlEntityAddCallback()' - Add a callback to convert entities to Unicode.
//
// This function adds a callback to the current thread that converts named
// XML character entities to Unicode characters. The callback function `cb`
// accepts the callback data pointer `cbdata` and the entity name and returns a
// Unicode character value or `-1` if the entity is not known. For example, the
// following entity callback supports the "euro" entity:
//
// ```c
// int my_entity_cb(void *cbdata, const char *name)
// {
// if (!strcmp(name, "euro"))
// return (0x20ac);
// else
// return (-1);
// }
// ```
//
bool // O - `true` on success, `false` on failure
mxmlEntityAddCallback(
mxml_entity_cb_t cb, // I - Callback function to add
void *cbdata) // I - Callback data
{
_mxml_global_t *global = _mxml_global();
// Global data
if (global->num_entity_cbs < (sizeof(global->entity_cbs) / sizeof(global->entity_cbs[0])))
{
global->entity_cbs[global->num_entity_cbs] = cb;
global->entity_cbdatas[global->num_entity_cbs] = cbdata;
global->num_entity_cbs ++;
return (true);
}
else
{
_mxml_error("Unable to add entity callback!");
return (false);
}
}
//
// '_mxml_entity_string()' - Get the entity that corresponds to the character, if any.
//
const char * // O - Entity or `NULL` for none
_mxml_entity_string(int ch) // I - Character
{
switch (ch)
{
case '&' :
return ("&amp;");
case '<' :
return ("&lt;");
case '>' :
return ("&gt;");
case '\"' :
return ("&quot;");
default :
return (NULL);
}
}
//
// 'mxmlEntityGetValue()' - Get the character corresponding to a named entity.
//
// The entity name can also be a numeric constant. `-1` is returned if the
// name is not known.
//
int // O - Character value or `-1` on error
mxmlEntityGetValue(const char *name) // I - Entity name
{
size_t i; // Looping var
int ch; // Character value
_mxml_global_t *global = _mxml_global();
// Global data
for (i = 0; i < global->num_entity_cbs; i ++)
{
if ((ch = (global->entity_cbs[i])(global->entity_cbdatas[i], name)) >= 0)
return (ch);
}
return (-1);
}
//
// 'mxmlEntityRemoveCallback()' - Remove a callback.
//
void
mxmlEntityRemoveCallback(
mxml_entity_cb_t cb) // I - Callback function to remove
{
size_t i; // Looping var
_mxml_global_t *global = _mxml_global();
// Global data
for (i = 0; i < global->num_entity_cbs; i ++)
{
if (cb == global->entity_cbs[i])
{
// Remove the callback...
global->num_entity_cbs --;
if (i < global->num_entity_cbs)
{
memmove(global->entity_cbs + i, global->entity_cbs + i + 1, (global->num_entity_cbs - i) * sizeof(global->entity_cbs[0]));
memmove(global->entity_cbdatas + i, global->entity_cbdatas + i + 1, (global->num_entity_cbs - i) * sizeof(global->entity_cbdatas[0]));
}
return;
}
}
}
//
// '_mxml_entity_cb()' - Lookup standard (X)HTML entities.
//
int // O - Unicode value or -1
_mxml_entity_cb(void *cbdata, // I - Callback data (unused)
const char *name) // I - Entity name
{
size_t i; // Looping var
int diff; // Difference
static const struct
{
const char *name; // Entity name
int val; // Character value
} entities[] =
{
{ "AElig", 198 },
{ "Aacute", 193 },
{ "Acirc", 194 },
{ "Agrave", 192 },
{ "Alpha", 913 },
{ "Aring", 197 },
{ "Atilde", 195 },
{ "Auml", 196 },
{ "Beta", 914 },
{ "Ccedil", 199 },
{ "Chi", 935 },
{ "Dagger", 8225 },
{ "Delta", 916 },
{ "Dstrok", 208 },
{ "ETH", 208 },
{ "Eacute", 201 },
{ "Ecirc", 202 },
{ "Egrave", 200 },
{ "Epsilon", 917 },
{ "Eta", 919 },
{ "Euml", 203 },
{ "Gamma", 915 },
{ "Iacute", 205 },
{ "Icirc", 206 },
{ "Igrave", 204 },
{ "Iota", 921 },
{ "Iuml", 207 },
{ "Kappa", 922 },
{ "Lambda", 923 },
{ "Mu", 924 },
{ "Ntilde", 209 },
{ "Nu", 925 },
{ "OElig", 338 },
{ "Oacute", 211 },
{ "Ocirc", 212 },
{ "Ograve", 210 },
{ "Omega", 937 },
{ "Omicron", 927 },
{ "Oslash", 216 },
{ "Otilde", 213 },
{ "Ouml", 214 },
{ "Phi", 934 },
{ "Pi", 928 },
{ "Prime", 8243 },
{ "Psi", 936 },
{ "Rho", 929 },
{ "Scaron", 352 },
{ "Sigma", 931 },
{ "THORN", 222 },
{ "Tau", 932 },
{ "Theta", 920 },
{ "Uacute", 218 },
{ "Ucirc", 219 },
{ "Ugrave", 217 },
{ "Upsilon", 933 },
{ "Uuml", 220 },
{ "Xi", 926 },
{ "Yacute", 221 },
{ "Yuml", 376 },
{ "Zeta", 918 },
{ "aacute", 225 },
{ "acirc", 226 },
{ "acute", 180 },
{ "aelig", 230 },
{ "agrave", 224 },
{ "alefsym", 8501 },
{ "alpha", 945 },
{ "amp", '&' },
{ "and", 8743 },
{ "ang", 8736 },
{ "apos", '\'' },
{ "aring", 229 },
{ "asymp", 8776 },
{ "atilde", 227 },
{ "auml", 228 },
{ "bdquo", 8222 },
{ "beta", 946 },
{ "brkbar", 166 },
{ "brvbar", 166 },
{ "bull", 8226 },
{ "cap", 8745 },
{ "ccedil", 231 },
{ "cedil", 184 },
{ "cent", 162 },
{ "chi", 967 },
{ "circ", 710 },
{ "clubs", 9827 },
{ "cong", 8773 },
{ "copy", 169 },
{ "crarr", 8629 },
{ "cup", 8746 },
{ "curren", 164 },
{ "dArr", 8659 },
{ "dagger", 8224 },
{ "darr", 8595 },
{ "deg", 176 },
{ "delta", 948 },
{ "diams", 9830 },
{ "die", 168 },
{ "divide", 247 },
{ "eacute", 233 },
{ "ecirc", 234 },
{ "egrave", 232 },
{ "empty", 8709 },
{ "emsp", 8195 },
{ "ensp", 8194 },
{ "epsilon", 949 },
{ "equiv", 8801 },
{ "eta", 951 },
{ "eth", 240 },
{ "euml", 235 },
{ "euro", 8364 },
{ "exist", 8707 },
{ "fnof", 402 },
{ "forall", 8704 },
{ "frac12", 189 },
{ "frac14", 188 },
{ "frac34", 190 },
{ "frasl", 8260 },
{ "gamma", 947 },
{ "ge", 8805 },
{ "gt", '>' },
{ "hArr", 8660 },
{ "harr", 8596 },
{ "hearts", 9829 },
{ "hellip", 8230 },
{ "hibar", 175 },
{ "iacute", 237 },
{ "icirc", 238 },
{ "iexcl", 161 },
{ "igrave", 236 },
{ "image", 8465 },
{ "infin", 8734 },
{ "int", 8747 },
{ "iota", 953 },
{ "iquest", 191 },
{ "isin", 8712 },
{ "iuml", 239 },
{ "kappa", 954 },
{ "lArr", 8656 },
{ "lambda", 955 },
{ "lang", 9001 },
{ "laquo", 171 },
{ "larr", 8592 },
{ "lceil", 8968 },
{ "ldquo", 8220 },
{ "le", 8804 },
{ "lfloor", 8970 },
{ "lowast", 8727 },
{ "loz", 9674 },
{ "lrm", 8206 },
{ "lsaquo", 8249 },
{ "lsquo", 8216 },
{ "lt", '<' },
{ "macr", 175 },
{ "mdash", 8212 },
{ "micro", 181 },
{ "middot", 183 },
{ "minus", 8722 },
{ "mu", 956 },
{ "nabla", 8711 },
{ "nbsp", 160 },
{ "ndash", 8211 },
{ "ne", 8800 },
{ "ni", 8715 },
{ "not", 172 },
{ "notin", 8713 },
{ "nsub", 8836 },
{ "ntilde", 241 },
{ "nu", 957 },
{ "oacute", 243 },
{ "ocirc", 244 },
{ "oelig", 339 },
{ "ograve", 242 },
{ "oline", 8254 },
{ "omega", 969 },
{ "omicron", 959 },
{ "oplus", 8853 },
{ "or", 8744 },
{ "ordf", 170 },
{ "ordm", 186 },
{ "oslash", 248 },
{ "otilde", 245 },
{ "otimes", 8855 },
{ "ouml", 246 },
{ "para", 182 },
{ "part", 8706 },
{ "permil", 8240 },
{ "perp", 8869 },
{ "phi", 966 },
{ "pi", 960 },
{ "piv", 982 },
{ "plusmn", 177 },
{ "pound", 163 },
{ "prime", 8242 },
{ "prod", 8719 },
{ "prop", 8733 },
{ "psi", 968 },
{ "quot", '\"' },
{ "rArr", 8658 },
{ "radic", 8730 },
{ "rang", 9002 },
{ "raquo", 187 },
{ "rarr", 8594 },
{ "rceil", 8969 },
{ "rdquo", 8221 },
{ "real", 8476 },
{ "reg", 174 },
{ "rfloor", 8971 },
{ "rho", 961 },
{ "rlm", 8207 },
{ "rsaquo", 8250 },
{ "rsquo", 8217 },
{ "sbquo", 8218 },
{ "scaron", 353 },
{ "sdot", 8901 },
{ "sect", 167 },
{ "shy", 173 },
{ "sigma", 963 },
{ "sigmaf", 962 },
{ "sim", 8764 },
{ "spades", 9824 },
{ "sub", 8834 },
{ "sube", 8838 },
{ "sum", 8721 },
{ "sup", 8835 },
{ "sup1", 185 },
{ "sup2", 178 },
{ "sup3", 179 },
{ "supe", 8839 },
{ "szlig", 223 },
{ "tau", 964 },
{ "there4", 8756 },
{ "theta", 952 },
{ "thetasym", 977 },
{ "thinsp", 8201 },
{ "thorn", 254 },
{ "tilde", 732 },
{ "times", 215 },
{ "trade", 8482 },
{ "uArr", 8657 },
{ "uacute", 250 },
{ "uarr", 8593 },
{ "ucirc", 251 },
{ "ugrave", 249 },
{ "uml", 168 },
{ "upsih", 978 },
{ "upsilon", 965 },
{ "uuml", 252 },
{ "weierp", 8472 },
{ "xi", 958 },
{ "yacute", 253 },
{ "yen", 165 },
{ "yuml", 255 },
{ "zeta", 950 },
{ "zwj", 8205 },
{ "zwnj", 8204 }
};
(void)cbdata;
// Do a linear search for the named entity...
for (i = 0; i < (sizeof(entities) / sizeof(entities[0])); i ++)
{
if ((diff = strcmp(name, entities[i].name)) == 0)
return (entities[i].val);
else if (diff < 0)
break;
}
return (-1);
}

File diff suppressed because it is too large Load Diff

View File

@ -227,16 +227,12 @@ mxmlIndexNew(mxml_node_t *node, // I - XML node tree
// Create a new index... // Create a new index...
if ((ind = calloc(1, sizeof(mxml_index_t))) == NULL) if ((ind = calloc(1, sizeof(mxml_index_t))) == NULL)
{
_mxml_error("Unable to allocate memory for index.");
return (NULL); return (NULL);
}
if (attr) if (attr)
{ {
if ((ind->attr = _mxml_strcopy(attr)) == NULL) if ((ind->attr = _mxml_strcopy(attr)) == NULL)
{ {
_mxml_error("Unable to allocate memory for index attribute.");
free(ind); free(ind);
return (NULL); return (NULL);
} }
@ -254,7 +250,6 @@ mxmlIndexNew(mxml_node_t *node, // I - XML node tree
if ((temp = realloc(ind->nodes, (ind->alloc_nodes + 64) * sizeof(mxml_node_t *))) == NULL) if ((temp = realloc(ind->nodes, (ind->alloc_nodes + 64) * sizeof(mxml_node_t *))) == NULL)
{ {
// Unable to allocate memory for the index, so abort... // Unable to allocate memory for the index, so abort...
_mxml_error("Unable to allocate memory for index nodes.");
mxmlIndexDelete(ind); mxmlIndexDelete(ind);
return (NULL); return (NULL);
} }

View File

@ -210,7 +210,6 @@ mxmlNewCDATA(mxml_node_t *parent, // I - Parent node or `MXML_NO_PARENT`
{ {
if ((node->value.cdata = _mxml_strcopy(data)) == NULL) if ((node->value.cdata = _mxml_strcopy(data)) == NULL)
{ {
_mxml_error("Unable to allocate memory for CDATA.");
mxmlDelete(node); mxmlDelete(node);
return (NULL); return (NULL);
} }
@ -286,7 +285,6 @@ mxmlNewComment(mxml_node_t *parent, // I - Parent node or `MXML_NO_PARENT`
{ {
if ((node->value.comment = _mxml_strcopy(comment)) == NULL) if ((node->value.comment = _mxml_strcopy(comment)) == NULL)
{ {
_mxml_error("Unable to allocate memory for comment.");
mxmlDelete(node); mxmlDelete(node);
return (NULL); return (NULL);
} }
@ -339,27 +337,28 @@ mxmlNewCommentf(mxml_node_t *parent, // I - Parent node or `MXML_NO_PARENT`
// 'mxmlNewCustom()' - Create a new custom data node. // 'mxmlNewCustom()' - Create a new custom data node.
// //
// The new custom node is added to the end of the specified parent's child // The new custom node is added to the end of the specified parent's child
// list. The constant `MXML_NO_PARENT` can be used to specify that the new // list. The `free_cb` argument specifies a function to call to free the custom
// element node has no parent. `NULL` can be passed when the data in the // data when the node is deleted.
// node is not dynamically allocated or is separately managed.
// //
mxml_node_t * // O - New node mxml_node_t * // O - New node
mxmlNewCustom( mxmlNewCustom(
mxml_node_t *parent, // I - Parent node or `MXML_NO_PARENT` mxml_node_t *parent, // I - Parent node or `MXML_NO_PARENT`
void *data, // I - Pointer to data void *data, // I - Pointer to data
mxml_custom_destroy_cb_t destroy) // I - Function to destroy data mxml_custfree_cb_t free_cb, // I - Free callback function or `NULL` if none needed
void *free_cbdata) // I - Free callback data
{ {
mxml_node_t *node; // New node mxml_node_t *node; // New node
MXML_DEBUG("mxmlNewCustom(parent=%p, data=%p, destroy=%p)\n", parent, data, destroy); MXML_DEBUG("mxmlNewCustom(parent=%p, data=%p, free_cb=%p, free_cbdata=%p)\n", parent, data, free_cb, free_cbdata);
// Create the node and set the value... // Create the node and set the value...
if ((node = mxml_new(parent, MXML_TYPE_CUSTOM)) != NULL) if ((node = mxml_new(parent, MXML_TYPE_CUSTOM)) != NULL)
{ {
node->value.custom.data = data; node->value.custom.data = data;
node->value.custom.destroy = destroy; node->value.custom.free_cb = free_cb;
node->value.custom.free_cbdata = free_cbdata;
} }
return (node); return (node);
@ -394,7 +393,6 @@ mxmlNewDeclaration(
{ {
if ((node->value.declaration = _mxml_strcopy(declaration)) == NULL) if ((node->value.declaration = _mxml_strcopy(declaration)) == NULL)
{ {
_mxml_error("Unable to allocate memory for declaration.");
mxmlDelete(node); mxmlDelete(node);
return (NULL); return (NULL);
} }
@ -471,7 +469,6 @@ mxmlNewDirective(mxml_node_t *parent, // I - Parent node or `MXML_NO_PARENT`
{ {
if ((node->value.directive = _mxml_strcopy(directive)) == NULL) if ((node->value.directive = _mxml_strcopy(directive)) == NULL)
{ {
_mxml_error("Unable to allocate memory for processing instruction.");
mxmlDelete(node); mxmlDelete(node);
return (NULL); return (NULL);
} }
@ -893,8 +890,8 @@ mxml_free(mxml_node_t *node) // I - Node
_mxml_strfree(node->value.text.string); _mxml_strfree(node->value.text.string);
break; break;
case MXML_TYPE_CUSTOM : case MXML_TYPE_CUSTOM :
if (node->value.custom.data && node->value.custom.destroy) if (node->value.custom.data && node->value.custom.free_cb)
(*(node->value.custom.destroy))(node->value.custom.data); (node->value.custom.free_cb)(node->value.custom.free_cbdata, node->value.custom.data);
break; break;
default : default :
break; break;

519
mxml-options.c Normal file
View File

@ -0,0 +1,519 @@
//
// Options functions for Mini-XML, a small XML file parsing library.
//
// https://www.msweet.org/mxml
//
// Copyright © 2003-2024 by Michael R Sweet.
//
// Licensed under Apache License v2.0. See the file "LICENSE" for more
// information.
//
#include "mxml-private.h"
//
// 'mxmlOptionsDelete()' - Free load/save options.
//
void
mxmlOptionsDelete(
mxml_options_t *options) // I - Options
{
free(options);
}
//
// 'mxmlOptionsNew()' - Allocate load/save options.
//
mxml_options_t * // O - Options
mxmlOptionsNew(void)
{
mxml_options_t *options; // Options
if ((options = (mxml_options_t *)calloc(1, sizeof(mxml_options_t))) != NULL)
{
// Set default values...
options->type_value = MXML_TYPE_TEXT;
options->wrap = 72;
if ((options->loc = localeconv()) != NULL)
{
if (!options->loc->decimal_point || !strcmp(options->loc->decimal_point, "."))
options->loc = NULL;
else
options->loc_declen = strlen(options->loc->decimal_point);
}
}
return (options);
}
//
// 'mxmlOptionsSetCustomCallbacks()' - Set the custom data callbacks.
//
// This function sets the callbacks that are used for loading and saving custom
// data types. The load callback `load_cb` accepts the callback data pointer
// `cbdata`, a node pointer, and a data string and returns `true` on success and
// `false` on error, for example:
//
// ```c
// typedef struct
// {
// unsigned year, /* Year */
// month, /* Month */
// day, /* Day */
// hour, /* Hour */
// minute, /* Minute */
// second; /* Second */
// time_t unix; /* UNIX time */
// } iso_date_time_t;
//
// void
// my_custom_free_cb(void *cbdata, void *data)
// {
// free(data);
// }
//
// bool
// my_custom_load_cb(void *cbdata, mxml_node_t *node, const char *data)
// {
// iso_date_time_t *dt;
// struct tm tmdata;
//
// /* Allocate custom data structure ... */
// dt = calloc(1, sizeof(iso_date_time_t));
//
// /* Parse the data string... */
// if (sscanf(data, "%u-%u-%uT%u:%u:%uZ", &(dt->year), &(dt->month),
// &(dt->day), &(dt->hour), &(dt->minute), &(dt->second)) != 6)
// {
// /* Unable to parse date and time numbers... */
// free(dt);
// return (false);
// }
//
// /* Range check values... */
// if (dt->month < 1 || dt->month > 12 || dt->day < 1 || dt->day > 31 ||
// dt->hour < 0 || dt->hour > 23 || dt->minute < 0 || dt->minute > 59 ||
// dt->second < 0 || dt->second > 60)
// {
// /* Date information is out of range... */
// free(dt);
// return (false);
// }
//
// /* Convert ISO time to UNIX time in seconds... */
// tmdata.tm_year = dt->year - 1900;
// tmdata.tm_mon = dt->month - 1;
// tmdata.tm_day = dt->day;
// tmdata.tm_hour = dt->hour;
// tmdata.tm_min = dt->minute;
// tmdata.tm_sec = dt->second;
//
// dt->unix = gmtime(&tmdata);
//
// /* Set custom data and free function... */
// mxmlSetCustom(node, data, my_custom_free, /*cbdata*/NULL);
//
// /* Return with no errors... */
// return (true);
// }
// ```
//
// The save callback `save_cb` accepts the callback data pointer `cbdata` and a
// node pointer and returns a malloc'd string on success and `NULL` on error,
// for example:
//
// ```c
// char *
// my_custom_save_cb(void *cbdata, mxml_node_t *node)
// {
// char data[255];
// iso_date_time_t *dt;
//
// /* Get the custom data structure */
// dt = (iso_date_time_t *)mxmlGetCustom(node);
//
// /* Generate string version of the date/time... */
// snprintf(data, sizeof(data), "%04u-%02u-%02uT%02u:%02u:%02uZ",
// dt->year, dt->month, dt->day, dt->hour, dt->minute, dt->second);
//
// /* Duplicate the string and return... */
// return (strdup(data));
// }
// ```
//
void
mxmlOptionsSetCustomCallbacks(
mxml_options_t *options, // I - Options
mxml_custload_cb_t load_cb, // I - Custom load callback function
mxml_custsave_cb_t save_cb, // I - Custom save callback function
void *cbdata) // I - Custom callback data
{
if (options)
{
options->custload_cb = load_cb;
options->custsave_cb = save_cb;
options->cust_cbdata = cbdata;
}
}
//
// 'mxmlOptionsSetEntityCallback()' - Set the entity lookup callback to use when loading XML data.
//
// This function sets the callback that is used to lookup named XML character
// entities when loading XML data. The callback function `cb` accepts the
// callback data pointer `cbdata` and the entity name. The function returns a
// Unicode character value or `-1` if the entity is not known. For example, the
// following entity callback supports the "euro" entity:
//
// ```c
// int my_entity_cb(void *cbdata, const char *name)
// {
// if (!strcmp(name, "euro"))
// return (0x20ac);
// else
// return (-1);
// }
// ```
//
// Mini-XML supports the "amp", "gt", "lt", and "quot" character entities, which
// are required by the base XML specification.
//
void
mxmlOptionsSetEntityCallback(
mxml_options_t *options, // I - Options
mxml_entity_cb_t cb, // I - Entity callback function
void *cbdata) // I - Entity callback data
{
if (options)
{
options->entity_cb = cb;
options->entity_cbdata = cbdata;
}
}
//
// 'mxmlOptionsSetErrorCallback()' - Set the error message callback.
//
// This function sets a function to use when reporting errors. The callback
// `cb` accepts the data pointer `cbdata` and a string pointer containing the
// error message:
//
// ```c
// void my_error_cb(void *cbdata, const char *message)
// {
// fprintf(stderr, "myprogram: %s\n", message);
// }
// ```
//
// The default error callback writes the error message to the `stderr` file.
//
void
mxmlOptionsSetErrorCallback(
mxml_options_t *options, // I - Options
mxml_error_cb_t cb, // I - Error callback function
void *cbdata) // I - Error callback data
{
if (options)
{
options->error_cb = cb;
options->error_cbdata = cbdata;
}
}
//
// 'mxmlOptionsSetSAXCallback()' - Set the SAX callback to use when reading XML data.
//
// This function sets a SAX callback to use when reading XML data. The SAX
// callback function `cb` and associated callback data `cbdata` are used to
// enable the Simple API for XML streaming mode. The callback is called as the
// XML node tree is parsed and receives the `cbdata` pointer, the `mxml_node_t`
// pointer, and an event code. The function returns `true` to continue
// processing or `false` to stop:
//
// ```c
// bool
// sax_cb(void *cbdata, mxml_node_t *node,
// mxml_sax_event_t event)
// {
// ... do something ...
//
// /* Continue processing... */
// return (true);
// }
// ```
//
// The event will be one of the following:
//
// - `MXML_SAX_EVENT_CDATA`: CDATA was just read.
// - `MXML_SAX_EVENT_COMMENT`: A comment was just read.
// - `MXML_SAX_EVENT_DATA`: Data (integer, opaque, real, or text) was just read.
// - `MXML_SAX_EVENT_DECLARATION`: A declaration was just read.
// - `MXML_SAX_EVENT_DIRECTIVE`: A processing directive/instruction was just read.
// - `MXML_SAX_EVENT_ELEMENT_CLOSE` - A close element was just read \(`</element>`)
// - `MXML_SAX_EVENT_ELEMENT_OPEN` - An open element was just read \(`<element>`)
//
// Elements are *released* after the close element is processed. All other nodes
// are released after they are processed. The SAX callback can *retain* the node
// using the [mxmlRetain](@@) function.
//
void
mxmlOptionsSetSAXCallback(
mxml_options_t *options, // I - Options
mxml_sax_cb_t cb, // I - SAX callback function
void *cbdata) // I - SAX callback data
{
if (options)
{
options->sax_cb = cb;
options->sax_cbdata = cbdata;
}
}
//
// 'mxmlOptionsSetTypeCallback()' - Set the type callback for child/value nodes.
//
// The load callback function `cb` is called to obtain the node type child/value
// nodes and receives the `cbdata` pointer and the `mxml_node_t` pointer, for
// example:
//
// ```c
// mxml_type_t
// my_type_cb(void *cbdata, mxml_node_t *node)
// {
// const char *type;
//
// /*
// * You can lookup attributes and/or use the element name,
// * hierarchy, etc...
// */
//
// type = mxmlElementGetAttr(node, "type");
// if (type == NULL)
// type = mxmlGetElement(node);
// if (type == NULL)
// type = "text";
//
// if (!strcmp(type, "integer"))
// return (MXML_TYPE_INTEGER);
// else if (!strcmp(type, "opaque"))
// return (MXML_TYPE_OPAQUE);
// else if (!strcmp(type, "real"))
// return (MXML_TYPE_REAL);
// else
// return (MXML_TYPE_TEXT);
// }
// ```
//
void
mxmlOptionsSetTypeCallback(
mxml_options_t *options, // I - Options
mxml_type_cb_t cb, // I - Type callback function
void *cbdata) // I - Type callback data
{
if (options)
{
options->type_cb = cb;
options->type_cbdata = cbdata;
}
}
//
// 'mxmlOptionsSetTypeValue()' - Set the type to use for all child/value nodes.
//
// This functions sets a constant node type to use for all child/value nodes.
//
void
mxmlOptionsSetTypeValue(
mxml_options_t *options, // I - Options
mxml_type_t type) // I - Value node type
{
if (options)
{
options->type_cb = NULL;
options->type_value = type;
}
}
//
// 'mxmlOptionsSetWhitespaceCallback()' - Set the whitespace callback.
//
// This function sets the whitespace callback that is used when saving XML data.
// The callback function `cb` specifies a function that returns a whitespace
// string or `NULL` before and after each element. The function receives the
// callback data pointer `cbdata`, the `mxml_node_t` pointer, and a "when"
// value indicating where the whitespace is being added, for example:
//
// ```c
// const char *my_whitespace_cb(void *cbdata, mxml_node_t *node, mxml_ws_t when)
// {
// if (when == MXML_WS_BEFORE_OPEN || when == MXML_WS_AFTER_CLOSE)
// return ("\n");
// else
// return (NULL);
// }
// ```
//
void
mxmlOptionsSetWhitespaceCallback(
mxml_options_t *options, // I - Options
mxml_ws_cb_t cb, // I - Whitespace callback function
void *cbdata) // I - Whitespace callback data
{
if (options)
{
options->ws_cb = cb;
options->ws_cbdata = cbdata;
}
}
//
// 'mxmlOptionsSetWrapMargin()' - Set the wrap margin when saving XML data.
//
// This function sets the wrap margin used when saving XML data. Wrapping is
// disabled when `column` is `0`.
//
void
mxmlOptionsSetWrapMargin(
mxml_options_t *options, // I - Options
int column) // I - Wrap column
{
if (options)
options->wrap = column;
}
//
// '_mxml_entity_string()' - Get the entity that corresponds to the character, if any.
//
const char * // O - Entity or `NULL` for none
_mxml_entity_string(int ch) // I - Character
{
switch (ch)
{
case '&' :
return ("&amp;");
case '<' :
return ("&lt;");
case '>' :
return ("&gt;");
case '\"' :
return ("&quot;");
default :
return (NULL);
}
}
//
// '_mxml_entity_value()' - Get the character corresponding to a named entity.
//
// The entity name can also be a numeric constant. `-1` is returned if the
// name is not known.
//
int // O - Unicode character
_mxml_entity_value(
mxml_options_t *options, // I - Options
const char *name) // I - Entity name
{
int ch = -1; // Unicode character
if (!name)
{
// No name...
return (-1);
}
else if (*name == '#')
{
// Numeric entity...
if (name[1] == 'x')
ch = (int)strtol(name + 2, NULL, 16);
else
ch = (int)strtol(name + 1, NULL, 10);
}
else if (!strcmp(name, "amp"))
{
// Ampersand
ch = '&';
}
else if (!strcmp(name, "gt"))
{
// Greater than
ch = '>';
}
else if (!strcmp(name, "lt"))
{
// Less than
ch = '<';
}
else if (!strcmp(name, "quot"))
{
// Double quote
ch = '\"';
}
else if (options && options->entity_cb)
{
// Use callback
ch = (options->entity_cb)(options->entity_cbdata, name);
}
return (ch);
}
//
// '_mxml_error()' - Display an error message.
//
void
_mxml_error(mxml_options_t *options, // I - Load/save options
const char *format, // I - Printf-style format string
...) // I - Additional arguments as needed
{
va_list ap; // Pointer to arguments
char s[1024]; // Message string
// Range check input...
if (!format)
return;
// Format the error message string...
va_start(ap, format);
vsnprintf(s, sizeof(s), format, ap);
va_end(ap);
// And then display the error message...
if (options->error_cb)
(options->error_cb)(options->error_cbdata, s);
else
fprintf(stderr, "%s\n", s);
}

View File

@ -39,144 +39,6 @@
#endif // __sun #endif // __sun
//
// 'mxmlSetCustomHandlers()' - Set the custom data callbacks.
//
// This function sets the callbacks that are used for loading and saving custom
// data types. The load callback `load_cb` accepts the callback data pointer
// `cbdata`, a node pointer, and a data string and returns `true` on success and
// `false` on error, for example:
//
// ```c
// typedef struct
// {
// unsigned year, /* Year */
// month, /* Month */
// day, /* Day */
// hour, /* Hour */
// minute, /* Minute */
// second; /* Second */
// time_t unix; /* UNIX time */
// } iso_date_time_t;
//
// bool
// my_custom_load_cb(void *cbdata, mxml_node_t *node, const char *data)
// {
// iso_date_time_t *dt;
// struct tm tmdata;
//
// /* Allocate custom data structure ... */
// dt = calloc(1, sizeof(iso_date_time_t));
//
// /* Parse the data string... */
// if (sscanf(data, "%u-%u-%uT%u:%u:%uZ", &(dt->year), &(dt->month),
// &(dt->day), &(dt->hour), &(dt->minute), &(dt->second)) != 6)
// {
// /* Unable to parse date and time numbers... */
// free(dt);
// return (false);
// }
//
// /* Range check values... */
// if (dt->month < 1 || dt->month > 12 || dt->day < 1 || dt->day > 31 ||
// dt->hour < 0 || dt->hour > 23 || dt->minute < 0 || dt->minute > 59 ||
// dt->second < 0 || dt->second > 60)
// {
// /* Date information is out of range... */
// free(dt);
// return (false);
// }
//
// /* Convert ISO time to UNIX time in seconds... */
// tmdata.tm_year = dt->year - 1900;
// tmdata.tm_mon = dt->month - 1;
// tmdata.tm_day = dt->day;
// tmdata.tm_hour = dt->hour;
// tmdata.tm_min = dt->minute;
// tmdata.tm_sec = dt->second;
//
// dt->unix = gmtime(&tmdata);
//
// /* Set custom data and free function... */
// mxmlSetCustom(node, data, free);
//
// /* Return with no errors... */
// return (true);
// }
// ```
//
// The save callback `save_cb` accepts the callback data pointer `cbdata` and a
// node pointer and returns a malloc'd string on success and `NULL` on error,
// for example:
//
// ```c
// char *
// my_custom_save_cb(void *cbdata, mxml_node_t *node)
// {
// char data[255];
// iso_date_time_t *dt;
//
// /* Get the custom data structure */
// dt = (iso_date_time_t *)mxmlGetCustom(node);
//
// /* Generate string version of the date/time... */
// snprintf(data, sizeof(data), "%04u-%02u-%02uT%02u:%02u:%02uZ",
// dt->year, dt->month, dt->day, dt->hour, dt->minute, dt->second);
//
// /* Duplicate the string and return... */
// return (strdup(data));
// }
// ```
//
void
mxmlSetCustomCallbacks(
mxml_custom_load_cb_t load_cb, // I - Load callback function
mxml_custom_save_cb_t save_cb, // I - Save callback function
void *cbdata) // I - Callback data
{
_mxml_global_t *global = _mxml_global();
// Global data
global->custom_load_cb = load_cb;
global->custom_save_cb = save_cb;
global->custom_cbdata = cbdata;
}
//
// 'mxmlSetErrorCallback()' - Set the error message callback.
//
// This function sets a function to use when reporting errors. The callback
// `cb` accepts the data pointer `cbdata` and a string pointer containing the
// error message:
//
// ```c
// void my_error_cb(void *cbdata, const char *message)
// {
// fprintf(stderr, "myprogram: %s\n", message);
// }
// ```
//
// The default error callback writes the error message to the `stderr` file.
//
void
mxmlSetErrorCallback(
mxml_error_cb_t cb, // I - Error callback function
void *cbdata) // I - Error callback data
{
_mxml_global_t *global = _mxml_global();
// Global data
global->error_cb = cb;
global->error_cbdata = cbdata;
}
// //
// 'mxmlSetStringCallbacks()' - Set the string copy/free callback functions. // 'mxmlSetStringCallbacks()' - Set the string copy/free callback functions.
// //
@ -217,37 +79,6 @@ mxmlSetStringCallbacks(
} }
//
// '_mxml_error()' - Display an error message.
//
void
_mxml_error(const char *format, // I - Printf-style format string
...) // I - Additional arguments as needed
{
va_list ap; // Pointer to arguments
char s[1024]; // Message string
_mxml_global_t *global = _mxml_global();
// Global data
// Range check input...
if (!format)
return;
// Format the error message string...
va_start(ap, format);
vsnprintf(s, sizeof(s), format, ap);
va_end(ap);
// And then display the error message...
if (global->error_cb)
(*global->error_cb)(global->error_cbdata, s);
else
fprintf(stderr, "%s\n", s);
}
// //
// '_mxml_strcopy()' - Copy a string. // '_mxml_strcopy()' - Copy a string.
// //
@ -341,10 +172,6 @@ _mxml_global(void)
{ {
global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t)); global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t));
pthread_setspecific(_mxml_key, global); pthread_setspecific(_mxml_key, global);
global->num_entity_cbs = 1;
global->entity_cbs[0] = _mxml_entity_cb;
global->wrap = 72;
} }
return (global); return (global);
@ -425,10 +252,6 @@ _mxml_global(void)
{ {
global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t)); global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t));
global->num_entity_cbs = 1;
global->entity_cbs[0] = _mxml_entity_cb;
global->wrap = 72;
TlsSetValue(_mxml_tls_index, (LPVOID)global); TlsSetValue(_mxml_tls_index, (LPVOID)global);
} }
@ -446,12 +269,9 @@ _mxml_global(void)
{ {
static _mxml_global_t global = // Global data static _mxml_global_t global = // Global data
{ {
NULL, // error_cb NULL, // strcopy_cb
1, // num_entity_cbs NULL, // strfree_cb
{ _mxml_entity_cb }, // entity_cbs NULL, // str_cbdata
72, // wrap
NULL, // custom_load_cb
NULL // custom_save_cb
}; };

View File

@ -54,7 +54,8 @@ typedef struct _mxml_text_s // An XML text value.
typedef struct _mxml_custom_s // An XML custom value. typedef struct _mxml_custom_s // An XML custom value.
{ {
void *data; // Pointer to (allocated) custom data void *data; // Pointer to (allocated) custom data
mxml_custom_destroy_cb_t destroy; // Pointer to destructor function mxml_custfree_cb_t free_cb; // Free callback function
void *free_cbdata; // Free callback data
} _mxml_custom_t; } _mxml_custom_t;
typedef union _mxml_value_u // An XML node value. typedef union _mxml_value_u // An XML node value.
@ -84,7 +85,14 @@ struct _mxml_node_s // An XML node.
void *user_data; // User data void *user_data; // User data
}; };
struct _mxml_index_s // An XML node index. typedef struct _mxml_global_s // Global, per-thread data
{
mxml_strcopy_cb_t strcopy_cb; // String copy callback function
mxml_strfree_cb_t strfree_cb; // String free callback function
void *str_cbdata; // String callback data
} _mxml_global_t;
struct _mxml_index_s // An XML node index.
{ {
char *attr; // Attribute used for indexing or NULL char *attr; // Attribute used for indexing or NULL
size_t num_nodes; // Number of nodes in index size_t num_nodes; // Number of nodes in index
@ -93,25 +101,26 @@ struct _mxml_index_s // An XML node index.
mxml_node_t **nodes; // Node array mxml_node_t **nodes; // Node array
}; };
typedef struct _mxml_global_s // Global, per-thread data struct _mxml_options_s // XML options
{ {
mxml_custom_load_cb_t custom_load_cb; // Custom load callback function struct lconv *loc; // Locale data
mxml_custom_save_cb_t custom_save_cb; // Custom save callback function size_t loc_declen; // Length of decimal point string
void *custom_cbdata; // Custom callback data mxml_custload_cb_t custload_cb; // Custom load callback function
mxml_error_cb_t error_cb; // Error callback function mxml_custsave_cb_t custsave_cb; // Custom save callback function
void *error_cbdata; // Error callback data void *cust_cbdata; // Custom callback data
size_t num_entity_cbs; // Number of entity callbacks mxml_entity_cb_t entity_cb; // Entity callback function
mxml_entity_cb_t entity_cbs[100]; // Entity callback functions void *entity_cbdata; // Entity callback data
void *entity_cbdatas[100]; // Entity callback data mxml_error_cb_t error_cb; // Error callback function
struct lconv *loc; // Locale data void *error_cbdata; // Error callback data
size_t loc_declen; // Length of decimal point string mxml_sax_cb_t sax_cb; // SAX callback function
bool loc_set; // Locale data set? void *sax_cbdata; // SAX callback data
mxml_strcopy_cb_t strcopy_cb; // String copy callback function mxml_type_cb_t type_cb; // Type callback function
mxml_strfree_cb_t strfree_cb; // String free callback function void *type_cbdata; // Type callback data
void *str_cbdata; // String callback data mxml_type_t type_value; // Fixed type value (if no type callback)
int wrap; // Wrap margin int wrap; // Wrap margin
} _mxml_global_t; mxml_ws_cb_t ws_cb; // Whitespace callback function
void *ws_cbdata; // Whitespace callback data
};
// //
@ -119,9 +128,9 @@ typedef struct _mxml_global_s // Global, per-thread data
// //
extern _mxml_global_t *_mxml_global(void); extern _mxml_global_t *_mxml_global(void);
extern int _mxml_entity_cb(void *cbdata, const char *name);
extern const char *_mxml_entity_string(int ch); extern const char *_mxml_entity_string(int ch);
extern void _mxml_error(const char *format, ...) MXML_FORMAT(1,2); extern int _mxml_entity_value(mxml_options_t *options, const char *name);
extern void _mxml_error(mxml_options_t *options, const char *format, ...) MXML_FORMAT(2,3);
extern char *_mxml_strcopy(const char *s); extern char *_mxml_strcopy(const char *s);
extern void _mxml_strfree(char *s); extern void _mxml_strfree(char *s);

View File

@ -31,15 +31,9 @@ mxmlSetCDATA(mxml_node_t *node, // I - Node to set
node = node->child; node = node->child;
if (!node || node->type != MXML_TYPE_CDATA) if (!node || node->type != MXML_TYPE_CDATA)
{
_mxml_error("Wrong node type.");
return (false); return (false);
}
else if (!data) else if (!data)
{
_mxml_error("NULL string not allowed.");
return (false); return (false);
}
if (data == node->value.cdata) if (data == node->value.cdata)
{ {
@ -49,10 +43,7 @@ mxmlSetCDATA(mxml_node_t *node, // I - Node to set
// Allocate the new value, free any old element value, and set the new value... // Allocate the new value, free any old element value, and set the new value...
if ((s = _mxml_strcopy(data)) == NULL) if ((s = _mxml_strcopy(data)) == NULL)
{
_mxml_error("Unable to allocate memory for CDATA.");
return (false); return (false);
}
_mxml_strfree(node->value.cdata); _mxml_strfree(node->value.cdata);
node->value.cdata = s; node->value.cdata = s;
@ -83,15 +74,9 @@ mxmlSetCDATAf(mxml_node_t *node, // I - Node
node = node->child; node = node->child;
if (!node || node->type != MXML_TYPE_CDATA) if (!node || node->type != MXML_TYPE_CDATA)
{
_mxml_error("Wrong node type.");
return (false); return (false);
}
else if (!format) else if (!format)
{
_mxml_error("NULL string not allowed.");
return (false); return (false);
}
// Format the new string, free any old string value, and set the new value... // Format the new string, free any old string value, and set the new value...
va_start(ap, format); va_start(ap, format);
@ -99,10 +84,7 @@ mxmlSetCDATAf(mxml_node_t *node, // I - Node
va_end(ap); va_end(ap);
if ((s = _mxml_strcopy(buffer)) == NULL) if ((s = _mxml_strcopy(buffer)) == NULL)
{
_mxml_error("Unable to allocate memory for CDATA string.");
return (false); return (false);
}
_mxml_strfree(node->value.cdata); _mxml_strfree(node->value.cdata);
node->value.cdata = s; node->value.cdata = s;
@ -129,25 +111,16 @@ mxmlSetComment(mxml_node_t *node, // I - Node
node = node->child; node = node->child;
if (!node || node->type != MXML_TYPE_COMMENT) if (!node || node->type != MXML_TYPE_COMMENT)
{
_mxml_error("Wrong node type.");
return (false); return (false);
}
else if (!comment) else if (!comment)
{
_mxml_error("NULL comment not allowed.");
return (false); return (false);
}
if (comment == node->value.comment) if (comment == node->value.comment)
return (true); return (true);
// Free any old string value and set the new value... // Free any old string value and set the new value...
if ((s = _mxml_strcopy(comment)) == NULL) if ((s = _mxml_strcopy(comment)) == NULL)
{
_mxml_error("Unable to allocate memory for comment string.");
return (false); return (false);
}
_mxml_strfree(node->value.comment); _mxml_strfree(node->value.comment);
node->value.comment = s; node->value.comment = s;
@ -177,15 +150,9 @@ mxmlSetCommentf(mxml_node_t *node, // I - Node
node = node->child; node = node->child;
if (!node || node->type != MXML_TYPE_COMMENT) if (!node || node->type != MXML_TYPE_COMMENT)
{
_mxml_error("Wrong node type.");
return (false); return (false);
}
else if (!format) else if (!format)
{
_mxml_error("NULL string not allowed.");
return (false); return (false);
}
// Format the new string, free any old string value, and set the new value... // Format the new string, free any old string value, and set the new value...
va_start(ap, format); va_start(ap, format);
@ -193,10 +160,7 @@ mxmlSetCommentf(mxml_node_t *node, // I - Node
va_end(ap); va_end(ap);
if ((s = _mxml_strcopy(buffer)) == NULL) if ((s = _mxml_strcopy(buffer)) == NULL)
{
_mxml_error("Unable to allocate memory for comment string.");
return (false); return (false);
}
_mxml_strfree(node->value.comment); _mxml_strfree(node->value.comment);
node->value.comment = s; node->value.comment = s;
@ -215,32 +179,31 @@ mxmlSetCommentf(mxml_node_t *node, // I - Node
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
mxmlSetCustom( mxmlSetCustom(
mxml_node_t *node, // I - Node to set mxml_node_t *node, // I - Node to set
void *data, // I - New data pointer void *data, // I - New data pointer
mxml_custom_destroy_cb_t destroy_cb)// I - New destructor function mxml_custfree_cb_t free_cb, // I - Free callback function
void *free_cbdata) // I - Free callback data
{ {
// Range check input... // Range check input...
if (node && node->type == MXML_TYPE_ELEMENT && node->child && node->child->type == MXML_TYPE_CUSTOM) if (node && node->type == MXML_TYPE_ELEMENT && node->child && node->child->type == MXML_TYPE_CUSTOM)
node = node->child; node = node->child;
if (!node || node->type != MXML_TYPE_CUSTOM) if (!node || node->type != MXML_TYPE_CUSTOM)
{
_mxml_error("Wrong node type.");
return (false); return (false);
}
if (data == node->value.custom.data) if (data == node->value.custom.data)
{ goto set_free_callback;
node->value.custom.destroy = destroy_cb;
return (true);
}
// Free any old element value and set the new value... // Free any old element value and set the new value...
if (node->value.custom.data && node->value.custom.destroy) if (node->value.custom.data && node->value.custom.free_cb)
(*(node->value.custom.destroy))(node->value.custom.data); (node->value.custom.free_cb)(node->value.custom.free_cbdata, node->value.custom.data);
node->value.custom.data = data; node->value.custom.data = data;
node->value.custom.destroy = destroy_cb;
set_free_callback:
node->value.custom.free_cb = free_cb;
node->value.custom.free_cbdata = free_cbdata;
return (true); return (true);
} }
@ -265,25 +228,16 @@ mxmlSetDeclaration(
node = node->child; node = node->child;
if (!node || node->type != MXML_TYPE_DECLARATION) if (!node || node->type != MXML_TYPE_DECLARATION)
{
_mxml_error("Wrong node type.");
return (false); return (false);
}
else if (!declaration) else if (!declaration)
{
_mxml_error("NULL declaration not allowed.");
return (false); return (false);
}
if (declaration == node->value.declaration) if (declaration == node->value.declaration)
return (true); return (true);
// Free any old string value and set the new value... // Free any old string value and set the new value...
if ((s = _mxml_strcopy(declaration)) == NULL) if ((s = _mxml_strcopy(declaration)) == NULL)
{
_mxml_error("Unable to allocate memory for declaration string.");
return (false); return (false);
}
_mxml_strfree(node->value.declaration); _mxml_strfree(node->value.declaration);
node->value.declaration = s; node->value.declaration = s;
@ -313,15 +267,9 @@ mxmlSetDeclarationf(mxml_node_t *node, // I - Node
node = node->child; node = node->child;
if (!node || node->type != MXML_TYPE_COMMENT) if (!node || node->type != MXML_TYPE_COMMENT)
{
_mxml_error("Wrong node type.");
return (false); return (false);
}
else if (!format) else if (!format)
{
_mxml_error("NULL string not allowed.");
return (false); return (false);
}
// Format the new string, free any old string value, and set the new value... // Format the new string, free any old string value, and set the new value...
va_start(ap, format); va_start(ap, format);
@ -329,10 +277,7 @@ mxmlSetDeclarationf(mxml_node_t *node, // I - Node
va_end(ap); va_end(ap);
if ((s = _mxml_strcopy(buffer)) == NULL) if ((s = _mxml_strcopy(buffer)) == NULL)
{
_mxml_error("Unable to allocate memory for declaration string.");
return (false); return (false);
}
_mxml_strfree(node->value.declaration); _mxml_strfree(node->value.declaration);
node->value.declaration = s; node->value.declaration = s;
@ -359,25 +304,16 @@ mxmlSetDirective(mxml_node_t *node, // I - Node
node = node->child; node = node->child;
if (!node || node->type != MXML_TYPE_DIRECTIVE) if (!node || node->type != MXML_TYPE_DIRECTIVE)
{
_mxml_error("Wrong node type.");
return (false); return (false);
}
else if (!directive) else if (!directive)
{
_mxml_error("NULL directive not allowed.");
return (false); return (false);
}
if (directive == node->value.directive) if (directive == node->value.directive)
return (true); return (true);
// Free any old string value and set the new value... // Free any old string value and set the new value...
if ((s = _mxml_strcopy(directive)) == NULL) if ((s = _mxml_strcopy(directive)) == NULL)
{
_mxml_error("Unable to allocate memory for directive string.");
return (false); return (false);
}
_mxml_strfree(node->value.directive); _mxml_strfree(node->value.directive);
node->value.directive = s; node->value.directive = s;
@ -408,15 +344,9 @@ mxmlSetDirectivef(mxml_node_t *node, // I - Node
node = node->child; node = node->child;
if (!node || node->type != MXML_TYPE_DIRECTIVE) if (!node || node->type != MXML_TYPE_DIRECTIVE)
{
_mxml_error("Wrong node type.");
return (false); return (false);
}
else if (!format) else if (!format)
{
_mxml_error("NULL string not allowed.");
return (false); return (false);
}
// Format the new string, free any old string value, and set the new value... // Format the new string, free any old string value, and set the new value...
va_start(ap, format); va_start(ap, format);
@ -424,10 +354,7 @@ mxmlSetDirectivef(mxml_node_t *node, // I - Node
va_end(ap); va_end(ap);
if ((s = _mxml_strcopy(buffer)) == NULL) if ((s = _mxml_strcopy(buffer)) == NULL)
{
_mxml_error("Unable to allocate memory for directive string.");
return (false); return (false);
}
_mxml_strfree(node->value.directive); _mxml_strfree(node->value.directive);
node->value.directive = s; node->value.directive = s;
@ -452,25 +379,16 @@ mxmlSetElement(mxml_node_t *node, // I - Node to set
// Range check input... // Range check input...
if (!node || node->type != MXML_TYPE_ELEMENT) if (!node || node->type != MXML_TYPE_ELEMENT)
{
_mxml_error("Wrong node type.");
return (false); return (false);
}
else if (!name) else if (!name)
{
_mxml_error("NULL string not allowed.");
return (false); return (false);
}
if (name == node->value.element.name) if (name == node->value.element.name)
return (true); return (true);
// Free any old element value and set the new value... // Free any old element value and set the new value...
if ((s = _mxml_strcopy(name)) == NULL) if ((s = _mxml_strcopy(name)) == NULL)
{
_mxml_error("Unable to allocate memory for element name.");
return (false); return (false);
}
_mxml_strfree(node->value.element.name); _mxml_strfree(node->value.element.name);
node->value.element.name = s; node->value.element.name = s;
@ -495,10 +413,7 @@ mxmlSetInteger(mxml_node_t *node, // I - Node to set
node = node->child; node = node->child;
if (!node || node->type != MXML_TYPE_INTEGER) if (!node || node->type != MXML_TYPE_INTEGER)
{
_mxml_error("Wrong node type.");
return (false); return (false);
}
// Set the new value and return... // Set the new value and return...
node->value.integer = integer; node->value.integer = integer;
@ -526,25 +441,16 @@ mxmlSetOpaque(mxml_node_t *node, // I - Node to set
node = node->child; node = node->child;
if (!node || node->type != MXML_TYPE_OPAQUE) if (!node || node->type != MXML_TYPE_OPAQUE)
{
_mxml_error("Wrong node type.");
return (false); return (false);
}
else if (!opaque) else if (!opaque)
{
_mxml_error("NULL string not allowed.");
return (false); return (false);
}
if (node->value.opaque == opaque) if (node->value.opaque == opaque)
return (true); return (true);
// Free any old opaque value and set the new value... // Free any old opaque value and set the new value...
if ((s = _mxml_strcopy(opaque)) == NULL) if ((s = _mxml_strcopy(opaque)) == NULL)
{
_mxml_error("Unable to allocate memory for opaque string.");
return (false); return (false);
}
_mxml_strfree(node->value.opaque); _mxml_strfree(node->value.opaque);
node->value.opaque = s; node->value.opaque = s;
@ -575,15 +481,9 @@ mxmlSetOpaquef(mxml_node_t *node, // I - Node to set
node = node->child; node = node->child;
if (!node || node->type != MXML_TYPE_OPAQUE) if (!node || node->type != MXML_TYPE_OPAQUE)
{
_mxml_error("Wrong node type.");
return (false); return (false);
}
else if (!format) else if (!format)
{
_mxml_error("NULL string not allowed.");
return (false); return (false);
}
// Format the new string, free any old string value, and set the new value... // Format the new string, free any old string value, and set the new value...
va_start(ap, format); va_start(ap, format);
@ -591,10 +491,7 @@ mxmlSetOpaquef(mxml_node_t *node, // I - Node to set
va_end(ap); va_end(ap);
if ((s = _mxml_strcopy(buffer)) == NULL) if ((s = _mxml_strcopy(buffer)) == NULL)
{
_mxml_error("Unable to allocate memory for opaque string.");
return (false); return (false);
}
_mxml_strfree(node->value.opaque); _mxml_strfree(node->value.opaque);
node->value.opaque = s; node->value.opaque = s;
@ -619,10 +516,7 @@ mxmlSetReal(mxml_node_t *node, // I - Node to set
node = node->child; node = node->child;
if (!node || node->type != MXML_TYPE_REAL) if (!node || node->type != MXML_TYPE_REAL)
{
_mxml_error("Wrong node type.");
return (false); return (false);
}
// Set the new value and return... // Set the new value and return...
node->value.real = real; node->value.real = real;
@ -651,15 +545,9 @@ mxmlSetText(mxml_node_t *node, // I - Node to set
node = node->child; node = node->child;
if (!node || node->type != MXML_TYPE_TEXT) if (!node || node->type != MXML_TYPE_TEXT)
{
_mxml_error("Wrong node type.");
return (false); return (false);
}
else if (!string) else if (!string)
{
_mxml_error("NULL string not allowed.");
return (false); return (false);
}
if (string == node->value.text.string) if (string == node->value.text.string)
{ {
@ -669,10 +557,7 @@ mxmlSetText(mxml_node_t *node, // I - Node to set
// Free any old string value and set the new value... // Free any old string value and set the new value...
if ((s = _mxml_strcopy(string)) == NULL) if ((s = _mxml_strcopy(string)) == NULL)
{
_mxml_error("Unable to allocate memory for text string.");
return (false); return (false);
}
_mxml_strfree(node->value.text.string); _mxml_strfree(node->value.text.string);
@ -706,15 +591,9 @@ mxmlSetTextf(mxml_node_t *node, // I - Node to set
node = node->child; node = node->child;
if (!node || node->type != MXML_TYPE_TEXT) if (!node || node->type != MXML_TYPE_TEXT)
{
_mxml_error("Wrong node type.");
return (false); return (false);
}
else if (!format) else if (!format)
{
_mxml_error("NULL string not allowed.");
return (false); return (false);
}
// Free any old string value and set the new value... // Free any old string value and set the new value...
va_start(ap, format); va_start(ap, format);
@ -722,10 +601,7 @@ mxmlSetTextf(mxml_node_t *node, // I - Node to set
va_end(ap); va_end(ap);
if ((s = _mxml_strcopy(buffer)) == NULL) if ((s = _mxml_strcopy(buffer)) == NULL)
{
_mxml_error("Unable to allocate memory for text string.");
return (false); return (false);
}
_mxml_strfree(node->value.text.string); _mxml_strfree(node->value.text.string);

87
mxml.h
View File

@ -19,12 +19,6 @@
# include <ctype.h> # include <ctype.h>
# include <errno.h> # include <errno.h>
# include <limits.h> # include <limits.h>
# if defined(_WIN32) && !defined(__CUPS_SSIZE_T_DEFINED)
# define __CUPS_SSIZE_T_DEFINED
// Windows does not provide the ssize_t type, so map it to int64_t... */
typedef int64_t ssize_t; // @private@
# define SSIZE_MAX INT64_MAX
# endif // _WIN32 && !__CUPS_SSIZE_T_DEFINED
# ifdef __cplusplus # ifdef __cplusplus
extern "C" { extern "C" {
# endif // __cplusplus # endif // __cplusplus
@ -95,45 +89,46 @@ typedef enum mxml_ws_e // Whitespace periods
MXML_WS_AFTER_CLOSE, // Callback for after close tag MXML_WS_AFTER_CLOSE, // Callback for after close tag
} mxml_ws_t; } mxml_ws_t;
typedef void (*mxml_custom_destroy_cb_t)(void *);
// Custom data destructor
typedef void (*mxml_error_cb_t)(void *cbdata, const char *message); typedef void (*mxml_error_cb_t)(void *cbdata, const char *message);
// Error callback function // Error callback function
typedef struct _mxml_node_s mxml_node_t;// An XML node. typedef struct _mxml_node_s mxml_node_t;// An XML node
typedef struct _mxml_index_s mxml_index_t; typedef struct _mxml_index_s mxml_index_t;
// An XML node index. // An XML node index
typedef bool (*mxml_custom_load_cb_t)(void *cbdata, mxml_node_t *node, const char *s); typedef struct _mxml_options_s mxml_options_t;
// XML options
typedef void (*mxml_custfree_cb_t)(void *cbdata, void *custdata);
// Custom data destructor
typedef bool (*mxml_custload_cb_t)(void *cbdata, mxml_node_t *node, const char *s);
// Custom data load callback function // Custom data load callback function
typedef char *(*mxml_custom_save_cb_t)(void *cbdata, mxml_node_t *node); typedef char *(*mxml_custsave_cb_t)(void *cbdata, mxml_node_t *node);
// Custom data save callback function // Custom data save callback function
typedef int (*mxml_entity_cb_t)(void *cbdata, const char *name); typedef int (*mxml_entity_cb_t)(void *cbdata, const char *name);
// Entity callback function // Entity callback function
typedef mxml_type_t (*mxml_load_cb_t)(void *cbdata, mxml_node_t *node); typedef size_t (*mxml_io_cb_t)(void *cbdata, void *buffer, size_t bytes);
// Load callback function // Read/write callback function
typedef ssize_t (*mxml_read_cb_t)(void *cbdata, void *buffer, size_t bytes); typedef bool (*mxml_sax_cb_t)(void *cbdata, mxml_node_t *node, mxml_sax_event_t event);
// Read callback function // SAX callback function
typedef const char *(*mxml_save_cb_t)(void *cbdata, mxml_node_t *node, mxml_ws_t when);
// Save callback function
typedef char *(*mxml_strcopy_cb_t)(void *cbdata, const char *s); typedef char *(*mxml_strcopy_cb_t)(void *cbdata, const char *s);
// String copy/allocation callback // String copy/allocation callback
typedef void (*mxml_strfree_cb_t)(void *cbdata, char *s); typedef void (*mxml_strfree_cb_t)(void *cbdata, char *s);
// String free callback // String free callback
typedef ssize_t (*mxml_write_cb_t)(void *cbdata, const void *buffer, size_t bytes); typedef mxml_type_t (*mxml_type_cb_t)(void *cbdata, mxml_node_t *node);
// Write callback function // Type callback function
typedef const char *(*mxml_ws_cb_t)(void *cbdata, mxml_node_t *node, mxml_ws_t when);
// Whitespace callback function
typedef bool (*mxml_sax_cb_t)(void *cbdata, mxml_node_t *node, mxml_sax_event_t event);
// SAX callback function
// //
@ -150,9 +145,6 @@ extern const char *mxmlElementGetAttrByIndex(mxml_node_t *node, int idx, c
extern size_t mxmlElementGetAttrCount(mxml_node_t *node); extern size_t mxmlElementGetAttrCount(mxml_node_t *node);
extern void mxmlElementSetAttr(mxml_node_t *node, const char *name, const char *value); extern void mxmlElementSetAttr(mxml_node_t *node, const char *name, const char *value);
extern void mxmlElementSetAttrf(mxml_node_t *node, const char *name, const char *format, ...) MXML_FORMAT(3,4); extern void mxmlElementSetAttrf(mxml_node_t *node, const char *name, const char *format, ...) MXML_FORMAT(3,4);
extern bool mxmlEntityAddCallback(mxml_entity_cb_t cb, void *cbdata);
extern int mxmlEntityGetValue(const char *name);
extern void mxmlEntityRemoveCallback(mxml_entity_cb_t cb);
extern mxml_node_t *mxmlFindElement(mxml_node_t *node, mxml_node_t *top, const char *element, const char *attr, const char *value, mxml_descend_t descend); extern mxml_node_t *mxmlFindElement(mxml_node_t *node, mxml_node_t *top, const char *element, const char *attr, const char *value, mxml_descend_t descend);
extern mxml_node_t *mxmlFindPath(mxml_node_t *node, const char *path); extern mxml_node_t *mxmlFindPath(mxml_node_t *node, const char *path);
@ -183,17 +175,28 @@ extern size_t mxmlIndexGetCount(mxml_index_t *ind);
extern mxml_index_t *mxmlIndexNew(mxml_node_t *node, const char *element, const char *attr); extern mxml_index_t *mxmlIndexNew(mxml_node_t *node, const char *element, const char *attr);
extern mxml_node_t *mxmlIndexReset(mxml_index_t *ind); extern mxml_node_t *mxmlIndexReset(mxml_index_t *ind);
extern mxml_node_t *mxmlLoadFd(mxml_node_t *top, int fd, mxml_load_cb_t load_cb, void *load_cbdata, mxml_sax_cb_t sax_cb, void *sax_cbdata); extern mxml_node_t *mxmlLoadFd(mxml_node_t *top, mxml_options_t *options, int fd);
extern mxml_node_t *mxmlLoadFile(mxml_node_t *top, FILE *fp, mxml_load_cb_t load_cb, void *load_cbdata, mxml_sax_cb_t sax_cb, void *sax_cbdata); extern mxml_node_t *mxmlLoadFile(mxml_node_t *top, mxml_options_t *options, FILE *fp);
extern mxml_node_t *mxmlLoadFilename(mxml_node_t *top, const char *filename, mxml_load_cb_t load_cb, void *load_cbdata, mxml_sax_cb_t sax_cb, void *sax_cbdata); extern mxml_node_t *mxmlLoadFilename(mxml_node_t *top, mxml_options_t *options, const char *filename);
extern mxml_node_t *mxmlLoadIO(mxml_node_t *top, mxml_read_cb_t read_cb, void *read_cbdata, mxml_load_cb_t load_cb, void *load_cbdata, mxml_sax_cb_t sax_cb, void *sax_cbdata); extern mxml_node_t *mxmlLoadIO(mxml_node_t *top, mxml_options_t *options, mxml_io_cb_t io_cb, void *io_cbdata);
extern mxml_node_t *mxmlLoadString(mxml_node_t *top, const char *s, mxml_load_cb_t load_cb, void *load_cbdata, mxml_sax_cb_t sax_cb, void *sax_cbdata); extern mxml_node_t *mxmlLoadString(mxml_node_t *top, mxml_options_t *options, const char *s);
extern void mxmlOptionsDelete(mxml_options_t *options);
extern mxml_options_t *mxmlOptionsNew(void);
extern void mxmlOptionsSetCustomCallbacks(mxml_options_t *options, mxml_custload_cb_t load_cb, mxml_custsave_cb_t save_cb, void *cbdata);
extern void mxmlOptionsSetEntityCallback(mxml_options_t *options, mxml_entity_cb_t cb, void *cbdata);
extern void mxmlOptionsSetErrorCallback(mxml_options_t *options, mxml_error_cb_t cb, void *cbdata);
extern void mxmlOptionsSetSAXCallback(mxml_options_t *options, mxml_sax_cb_t cb, void *cbdata);
extern void mxmlOptionsSetTypeCallback(mxml_options_t *options, mxml_type_cb_t cb, void *cbdata);
extern void mxmlOptionsSetTypeValue(mxml_options_t *options, mxml_type_t type);
extern void mxmlOptionsSetWhitespaceCallback(mxml_options_t *options, mxml_ws_cb_t cb, void *cbdata);
extern void mxmlOptionsSetWrapMargin(mxml_options_t *options, int column);
extern mxml_node_t *mxmlNewCDATA(mxml_node_t *parent, const char *string); extern mxml_node_t *mxmlNewCDATA(mxml_node_t *parent, const char *string);
extern mxml_node_t *mxmlNewCDATAf(mxml_node_t *parent, const char *format, ...) MXML_FORMAT(2,3); extern mxml_node_t *mxmlNewCDATAf(mxml_node_t *parent, const char *format, ...) MXML_FORMAT(2,3);
extern mxml_node_t *mxmlNewComment(mxml_node_t *parent, const char *comment); extern mxml_node_t *mxmlNewComment(mxml_node_t *parent, const char *comment);
extern mxml_node_t *mxmlNewCommentf(mxml_node_t *parent, const char *format, ...) MXML_FORMAT(2,3); extern mxml_node_t *mxmlNewCommentf(mxml_node_t *parent, const char *format, ...) MXML_FORMAT(2,3);
extern mxml_node_t *mxmlNewCustom(mxml_node_t *parent, void *data, mxml_custom_destroy_cb_t destroy); extern mxml_node_t *mxmlNewCustom(mxml_node_t *parent, void *data, mxml_custfree_cb_t free_cb, void *free_cbdata);
extern mxml_node_t *mxmlNewDeclaration(mxml_node_t *parent, const char *declaration); extern mxml_node_t *mxmlNewDeclaration(mxml_node_t *parent, const char *declaration);
extern mxml_node_t *mxmlNewDeclarationf(mxml_node_t *parent, const char *format, ...) MXML_FORMAT(2,3); extern mxml_node_t *mxmlNewDeclarationf(mxml_node_t *parent, const char *format, ...) MXML_FORMAT(2,3);
extern mxml_node_t *mxmlNewDirective(mxml_node_t *parent, const char *directive); extern mxml_node_t *mxmlNewDirective(mxml_node_t *parent, const char *directive);
@ -211,12 +214,13 @@ extern int mxmlRelease(mxml_node_t *node);
extern void mxmlRemove(mxml_node_t *node); extern void mxmlRemove(mxml_node_t *node);
extern int mxmlRetain(mxml_node_t *node); extern int mxmlRetain(mxml_node_t *node);
extern char *mxmlSaveAllocString(mxml_node_t *node, mxml_save_cb_t save_cb, void *save_cbdata); extern char *mxmlSaveAllocString(mxml_node_t *node, mxml_options_t *options);
extern bool mxmlSaveFd(mxml_node_t *node, int fd, mxml_save_cb_t save_cb, void *save_cbdata); extern bool mxmlSaveFd(mxml_node_t *node, mxml_options_t *options, int fd);
extern bool mxmlSaveFile(mxml_node_t *node, FILE *fp, mxml_save_cb_t save_cb, void *save_cbdata); extern bool mxmlSaveFile(mxml_node_t *node, mxml_options_t *options, FILE *fp);
extern bool mxmlSaveFilename(mxml_node_t *node, const char *filename, mxml_save_cb_t save_cb, void *save_cbdata); extern bool mxmlSaveFilename(mxml_node_t *node, mxml_options_t *options, const char *filename);
extern bool mxmlSaveIO(mxml_node_t *node, mxml_write_cb_t write_cb, void *write_cbdata, mxml_save_cb_t save_cb, void *save_cbdata); extern bool mxmlSaveIO(mxml_node_t *node, mxml_options_t *options, mxml_io_cb_t io_cb, void *io_cbdata);
extern size_t mxmlSaveString(mxml_node_t *node, char *buffer, size_t bufsize, mxml_save_cb_t save_cb, void *save_cbdata); extern size_t mxmlSaveString(mxml_node_t *node, mxml_options_t *options, char *buffer, size_t bufsize);
extern bool mxmlSetCDATA(mxml_node_t *node, const char *data); extern bool mxmlSetCDATA(mxml_node_t *node, const char *data);
extern bool mxmlSetCDATAf(mxml_node_t *node, const char *format, ...) MXML_FORMAT(2,3); extern bool mxmlSetCDATAf(mxml_node_t *node, const char *format, ...) MXML_FORMAT(2,3);
extern bool mxmlSetComment(mxml_node_t *node, const char *comment); extern bool mxmlSetComment(mxml_node_t *node, const char *comment);
@ -225,10 +229,8 @@ extern bool mxmlSetDeclaration(mxml_node_t *node, const char *declaration);
extern bool mxmlSetDeclarationf(mxml_node_t *node, const char *format, ...) MXML_FORMAT(2,3); extern bool mxmlSetDeclarationf(mxml_node_t *node, const char *format, ...) MXML_FORMAT(2,3);
extern bool mxmlSetDirective(mxml_node_t *node, const char *directive); extern bool mxmlSetDirective(mxml_node_t *node, const char *directive);
extern bool mxmlSetDirectivef(mxml_node_t *node, const char *format, ...) MXML_FORMAT(2,3); extern bool mxmlSetDirectivef(mxml_node_t *node, const char *format, ...) MXML_FORMAT(2,3);
extern bool mxmlSetCustom(mxml_node_t *node, void *data, mxml_custom_destroy_cb_t destroy_cb); extern bool mxmlSetCustom(mxml_node_t *node, void *data, mxml_custfree_cb_t free_cb, void *free_cbdata);
extern void mxmlSetCustomCallbacks(mxml_custom_load_cb_t load_cb, mxml_custom_save_cb_t save_cb, void *cbdata);
extern bool mxmlSetElement(mxml_node_t *node, const char *name); extern bool mxmlSetElement(mxml_node_t *node, const char *name);
extern void mxmlSetErrorCallback(mxml_error_cb_t cb, void *cbdata);
extern bool mxmlSetInteger(mxml_node_t *node, long integer); extern bool mxmlSetInteger(mxml_node_t *node, long integer);
extern bool mxmlSetOpaque(mxml_node_t *node, const char *opaque); extern bool mxmlSetOpaque(mxml_node_t *node, const char *opaque);
extern bool mxmlSetOpaquef(mxml_node_t *node, const char *format, ...) MXML_FORMAT(2,3); extern bool mxmlSetOpaquef(mxml_node_t *node, const char *format, ...) MXML_FORMAT(2,3);
@ -237,7 +239,6 @@ extern void mxmlSetStringCallbacks(mxml_strcopy_cb_t strcopy_cb, mxml_strfree_c
extern bool mxmlSetText(mxml_node_t *node, bool whitespace, const char *string); extern bool mxmlSetText(mxml_node_t *node, bool whitespace, const char *string);
extern bool mxmlSetTextf(mxml_node_t *node, bool whitespace, const char *format, ...) MXML_FORMAT(3,4); extern bool mxmlSetTextf(mxml_node_t *node, bool whitespace, const char *format, ...) MXML_FORMAT(3,4);
extern bool mxmlSetUserData(mxml_node_t *node, void *data); extern bool mxmlSetUserData(mxml_node_t *node, void *data);
extern void mxmlSetWrapMargin(int column);
extern mxml_node_t *mxmlWalkNext(mxml_node_t *node, mxml_node_t *top, mxml_descend_t descend); extern mxml_node_t *mxmlWalkNext(mxml_node_t *node, mxml_node_t *top, mxml_descend_t descend);
extern mxml_node_t *mxmlWalkPrev(mxml_node_t *node, mxml_node_t *top, mxml_descend_t descend); extern mxml_node_t *mxmlWalkPrev(mxml_node_t *node, mxml_node_t *top, mxml_descend_t descend);

View File

@ -52,6 +52,7 @@ main(int argc, // I - Number of command-line args
int i; // Looping var int i; // Looping var
FILE *fp; // File to read FILE *fp; // File to read
int fd; // File descriptor int fd; // File descriptor
mxml_options_t *options; // Load/save options
mxml_node_t *xml, // <?xml ...?> node mxml_node_t *xml, // <?xml ...?> node
*tree, // Element tree *tree, // Element tree
*node; // Node which should be in test.xml *node; // Node which should be in test.xml
@ -83,8 +84,9 @@ main(int argc, // I - Number of command-line args
} }
// Test the basic functionality... // Test the basic functionality...
xml = mxmlNewXML("1.0"); options = mxmlOptionsNew();
tree = mxmlNewElement(xml, "element"); xml = mxmlNewXML("1.0");
tree = mxmlNewElement(xml, "element");
if (!tree) if (!tree)
{ {
@ -111,18 +113,18 @@ main(int argc, // I - Number of command-line args
mxmlNewReal(tree, 123.4); mxmlNewReal(tree, 123.4);
mxmlNewText(tree, 1, "text"); mxmlNewText(tree, 1, "text");
type = MXML_TYPE_TEXT; mxmlOptionsSetTypeValue(options, MXML_TYPE_TEXT);
mxmlLoadString(tree, "<group type='string'>string string string</group>", /*load_cb*/NULL, /*load_cbdata*/&type, /*sax_cb*/NULL, /*sax_cbdata*/NULL); mxmlLoadString(tree, options, "<group type='string'>string string string</group>");
type = MXML_TYPE_INTEGER; mxmlOptionsSetTypeValue(options, MXML_TYPE_INTEGER);
mxmlLoadString(tree, "<group type='integer'>1 2 3</group>", /*load_cb*/NULL, /*load_cbdata*/&type, /*sax_cb*/NULL, /*sax_cbdata*/NULL); mxmlLoadString(tree, options, "<group type='integer'>1 2 3</group>");
type = MXML_TYPE_REAL; mxmlOptionsSetTypeValue(options, MXML_TYPE_REAL);
mxmlLoadString(tree, "<group type='real'>1.0 2.0 3.0</group>", /*load_cb*/NULL, /*load_cbdata*/&type, /*sax_cb*/NULL, /*sax_cbdata*/NULL); mxmlLoadString(tree, options, "<group type='real'>1.0 2.0 3.0</group>");
type = MXML_TYPE_OPAQUE; mxmlOptionsSetTypeValue(options, MXML_TYPE_OPAQUE);
mxmlLoadString(tree, "<group>opaque opaque opaque</group>", /*load_cb*/NULL, /*load_cbdata*/&type, /*sax_cb*/NULL, /*sax_cbdata*/NULL); mxmlLoadString(tree, options, "<group>opaque opaque opaque</group>");
mxmlLoadString(tree, "<foo><bar><one><two>value<two>value2</two></two></one></bar></foo>", /*load_cb*/NULL, /*load_cbdata*/&type, /*sax_cb*/NULL, /*sax_cbdata*/NULL); mxmlLoadString(tree, options, "<foo><bar><one><two>value<two>value2</two></two></one></bar></foo>");
mxmlNewCDATA(tree, "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n"); mxmlNewCDATA(tree, "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n");
mxmlNewCDATA(tree, mxmlNewCDATA(tree,
@ -434,11 +436,13 @@ main(int argc, // I - Number of command-line args
mxmlDelete(xml); mxmlDelete(xml);
// Open the file/string using the default (MXML_NO_CALLBACK) callback... // Open the file/string using the default callback...
mxmlOptionsSetTypeValue(options, MXML_TYPE_TEXT);
if (argv[1][0] == '<') if (argv[1][0] == '<')
xml = mxmlLoadString(/*top*/NULL, argv[1], /*load_cb*/NULL, /*load_cbdata*/NULL, /*sax_cb*/NULL, /*sax_cbdata*/NULL); xml = mxmlLoadString(/*top*/NULL, options, argv[1]);
else else
xml = mxmlLoadFilename(/*top*/NULL, argv[1], /*load_cb*/NULL, /*load_cbdata*/NULL, /*sax_cb*/NULL, /*sax_cbdata*/NULL); xml = mxmlLoadFilename(/*top*/NULL, options, argv[1]);
if (!xml) if (!xml)
{ {
@ -459,7 +463,7 @@ main(int argc, // I - Number of command-line args
if (mxmlGetType(node) != MXML_TYPE_TEXT) if (mxmlGetType(node) != MXML_TYPE_TEXT)
{ {
fputs("No child node of group/option/keyword.\n", stderr); fputs("No child node of group/option/keyword.\n", stderr);
mxmlSaveFile(xml, stderr, /*save_cb*/NULL, /*save_cbdata*/NULL); mxmlSaveFile(xml, options, stderr);
mxmlDelete(xml); mxmlDelete(xml);
return (1); return (1);
} }
@ -475,10 +479,12 @@ main(int argc, // I - Number of command-line args
mxmlDelete(xml); mxmlDelete(xml);
// Open the file... // Open the file...
mxmlOptionsSetTypeCallback(options, type_cb, /*cbdata*/NULL);
if (argv[1][0] == '<') if (argv[1][0] == '<')
xml = mxmlLoadString(/*top*/NULL, argv[1], /*load_cb*/type_cb, /*load_cbdata*/NULL, /*sax_cb*/NULL, /*sax_cbdata*/NULL); xml = mxmlLoadString(/*top*/NULL, options, argv[1]);
else else
xml = mxmlLoadFilename(/*top*/NULL, argv[1], /*load_cb*/type_cb, /*load_cbdata*/NULL, /*sax_cb*/NULL, /*sax_cbdata*/NULL); xml = mxmlLoadFilename(/*top*/NULL, options, argv[1]);
if (!xml) if (!xml)
{ {
@ -505,10 +511,11 @@ main(int argc, // I - Number of command-line args
} }
// Print the XML tree... // Print the XML tree...
mxmlSaveFile(xml, stdout, whitespace_cb, /*save_cbdata*/NULL); mxmlOptionsSetWhitespaceCallback(options, whitespace_cb, /*cbdata*/NULL);
mxmlSaveFile(xml, options, stdout);
// Save the XML tree to a string and print it... // Save the XML tree to a string and print it...
if (mxmlSaveString(xml, buffer, sizeof(buffer), whitespace_cb, /*save_cbdata*/NULL) > 0) if (mxmlSaveString(xml, options, buffer, sizeof(buffer)) > 0)
{ {
if (argc == 3) if (argc == 3)
{ {
@ -532,7 +539,7 @@ main(int argc, // I - Number of command-line args
} }
// Read the file... // Read the file...
xml = mxmlLoadFd(/*top*/NULL, fd, type_cb, /*load_cbdata*/NULL, /*sax_cb*/NULL, /*sax_cbdata*/NULL); xml = mxmlLoadFd(/*top*/NULL, options, fd);
close(fd); close(fd);
@ -547,7 +554,7 @@ main(int argc, // I - Number of command-line args
} }
// Write the file... // Write the file...
mxmlSaveFd(xml, fd, whitespace_cb, /*save_cbdata*/NULL); mxmlSaveFd(xml, options, fd);
close(fd); close(fd);
@ -558,10 +565,12 @@ main(int argc, // I - Number of command-line args
// Test SAX methods... // Test SAX methods...
memset(event_counts, 0, sizeof(event_counts)); memset(event_counts, 0, sizeof(event_counts));
mxmlOptionsSetSAXCallback(options, sax_cb, /*cbdata*/NULL);
if (argv[1][0] == '<') if (argv[1][0] == '<')
mxmlRelease(mxmlLoadString(/*top*/NULL, argv[1], type_cb, /*load_cbdata*/NULL, sax_cb, /*sax_cbdata*/NULL)); mxmlRelease(mxmlLoadString(/*top*/NULL, options, argv[1]));
else else
mxmlRelease(mxmlLoadFilename(/*top*/NULL, argv[1], type_cb, /*load_cbdata*/NULL, sax_cb, /*sax_cbdata*/NULL)); mxmlRelease(mxmlLoadFilename(/*top*/NULL, options, argv[1]));
if (!strcmp(argv[1], "test.xml")) if (!strcmp(argv[1], "test.xml"))
{ {

View File

@ -8,9 +8,6 @@ EXPORTS
mxmlElementGetAttr mxmlElementGetAttr
mxmlElementSetAttr mxmlElementSetAttr
mxmlElementSetAttrf mxmlElementSetAttrf
mxmlEntityAddCallback
mxmlEntityGetValue
mxmlEntityRemoveCallback
mxmlFindElement mxmlFindElement
mxmlFindPath mxmlFindPath
mxmlGetCDATA mxmlGetCDATA
@ -59,6 +56,16 @@ EXPORTS
mxmlNewText mxmlNewText
mxmlNewTextf mxmlNewTextf
mxmlNewXML mxmlNewXML
mxmlOptionsDelete
mxmlOptionsNew
mxmlOptionsSetCustomCallbacks
mxmlOptionsSetEntityCallback
mxmlOptionsSetErrorCallback
mxmlOptionsSetSAXCallback
mxmlOptionsSetTypeCallback
mxmlOptionsSetTypeValue
mxmlOptionsSetWhitespaceCallback
mxmlOptionsSetWrapMargin
mxmlRelease mxmlRelease
mxmlRemove mxmlRemove
mxmlRetain mxmlRetain
@ -73,20 +80,18 @@ EXPORTS
mxmlSetComment mxmlSetComment
mxmlSetCommentf mxmlSetCommentf
mxmlSetCustom mxmlSetCustom
mxmlSetCustomCallbacks
mxmlSetDeclaration mxmlSetDeclaration
mxmlSetDeclarationf mxmlSetDeclarationf
mxmlSetDirective mxmlSetDirective
mxmlSetDirectivef mxmlSetDirectivef
mxmlSetElement mxmlSetElement
mxmlSetErrorCallback
mxmlSetInteger mxmlSetInteger
mxmlSetOpaque mxmlSetOpaque
mxmlSetOpaquef mxmlSetOpaquef
mxmlSetReal mxmlSetReal
mxmlSetStringCallbacks
mxmlSetText mxmlSetText
mxmlSetTextf mxmlSetTextf
mxmlSetUserData mxmlSetUserData
mxmlSetWrapMargin
mxmlWalkNext mxmlWalkNext
mxmlWalkPrev mxmlWalkPrev

View File

@ -191,11 +191,11 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\mxml-attr.c" /> <ClCompile Include="..\mxml-attr.c" />
<ClCompile Include="..\mxml-entity.c" />
<ClCompile Include="..\mxml-file.c" /> <ClCompile Include="..\mxml-file.c" />
<ClCompile Include="..\mxml-get.c" /> <ClCompile Include="..\mxml-get.c" />
<ClCompile Include="..\mxml-index.c" /> <ClCompile Include="..\mxml-index.c" />
<ClCompile Include="..\mxml-node.c" /> <ClCompile Include="..\mxml-node.c" />
<ClCompile Include="..\mxml-options.c" />
<ClCompile Include="..\mxml-private.c" /> <ClCompile Include="..\mxml-private.c" />
<ClCompile Include="..\mxml-search.c" /> <ClCompile Include="..\mxml-search.c" />
<ClCompile Include="..\mxml-set.c" /> <ClCompile Include="..\mxml-set.c" />

View File

@ -24,12 +24,12 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\mxml-attr.c" /> <ClCompile Include="..\mxml-attr.c" />
<ClCompile Include="..\mxml-entity.c" />
<ClCompile Include="..\mxml-file.c" /> <ClCompile Include="..\mxml-file.c" />
<ClCompile Include="..\mxml-get.c" /> <ClCompile Include="..\mxml-get.c" />
<ClCompile Include="..\mxml-index.c" /> <ClCompile Include="..\mxml-index.c" />
<ClCompile Include="..\mxml-node.c" /> <ClCompile Include="..\mxml-node.c" />
<ClCompile Include="..\mxml-private.c" /> <ClCompile Include="..\mxml-private.c" />
<ClCompile Include="..\mxml-options.c" />
<ClCompile Include="..\mxml-search.c" /> <ClCompile Include="..\mxml-search.c" />
<ClCompile Include="..\mxml-set.c" /> <ClCompile Include="..\mxml-set.c" />
</ItemGroup> </ItemGroup>

View File

@ -23,7 +23,6 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
272C00191E8C66C8007EBCAC /* mxml-attr.c in Sources */ = {isa = PBXBuildFile; fileRef = 272C000D1E8C66C8007EBCAC /* mxml-attr.c */; }; 272C00191E8C66C8007EBCAC /* mxml-attr.c in Sources */ = {isa = PBXBuildFile; fileRef = 272C000D1E8C66C8007EBCAC /* mxml-attr.c */; };
272C001A1E8C66C8007EBCAC /* mxml-entity.c in Sources */ = {isa = PBXBuildFile; fileRef = 272C000E1E8C66C8007EBCAC /* mxml-entity.c */; };
272C001B1E8C66C8007EBCAC /* mxml-file.c in Sources */ = {isa = PBXBuildFile; fileRef = 272C000F1E8C66C8007EBCAC /* mxml-file.c */; }; 272C001B1E8C66C8007EBCAC /* mxml-file.c in Sources */ = {isa = PBXBuildFile; fileRef = 272C000F1E8C66C8007EBCAC /* mxml-file.c */; };
272C001C1E8C66C8007EBCAC /* mxml-get.c in Sources */ = {isa = PBXBuildFile; fileRef = 272C00101E8C66C8007EBCAC /* mxml-get.c */; }; 272C001C1E8C66C8007EBCAC /* mxml-get.c in Sources */ = {isa = PBXBuildFile; fileRef = 272C00101E8C66C8007EBCAC /* mxml-get.c */; };
272C001D1E8C66C8007EBCAC /* mxml-index.c in Sources */ = {isa = PBXBuildFile; fileRef = 272C00111E8C66C8007EBCAC /* mxml-index.c */; }; 272C001D1E8C66C8007EBCAC /* mxml-index.c in Sources */ = {isa = PBXBuildFile; fileRef = 272C00111E8C66C8007EBCAC /* mxml-index.c */; };
@ -36,6 +35,7 @@
272C00261E8C66CF007EBCAC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 272C00251E8C66CF007EBCAC /* config.h */; }; 272C00261E8C66CF007EBCAC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 272C00251E8C66CF007EBCAC /* config.h */; };
272C00421E8C6B30007EBCAC /* testmxml.c in Sources */ = {isa = PBXBuildFile; fileRef = 272C00401E8C6B1B007EBCAC /* testmxml.c */; }; 272C00421E8C6B30007EBCAC /* testmxml.c in Sources */ = {isa = PBXBuildFile; fileRef = 272C00401E8C6B1B007EBCAC /* testmxml.c */; };
272C00501E8C6B89007EBCAC /* libmxml.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 272C00051E8C6664007EBCAC /* libmxml.a */; }; 272C00501E8C6B89007EBCAC /* libmxml.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 272C00051E8C6664007EBCAC /* libmxml.a */; };
27459CD92BA8BAC300EAF97D /* mxml-options.c in Sources */ = {isa = PBXBuildFile; fileRef = 27459CD82BA8BAC300EAF97D /* mxml-options.c */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@ -77,7 +77,6 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
272C00051E8C6664007EBCAC /* libmxml.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libmxml.a; sourceTree = BUILT_PRODUCTS_DIR; }; 272C00051E8C6664007EBCAC /* libmxml.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libmxml.a; sourceTree = BUILT_PRODUCTS_DIR; };
272C000D1E8C66C8007EBCAC /* mxml-attr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "mxml-attr.c"; path = "../mxml-attr.c"; sourceTree = "<group>"; }; 272C000D1E8C66C8007EBCAC /* mxml-attr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "mxml-attr.c"; path = "../mxml-attr.c"; sourceTree = "<group>"; };
272C000E1E8C66C8007EBCAC /* mxml-entity.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "mxml-entity.c"; path = "../mxml-entity.c"; sourceTree = "<group>"; };
272C000F1E8C66C8007EBCAC /* mxml-file.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "mxml-file.c"; path = "../mxml-file.c"; sourceTree = "<group>"; }; 272C000F1E8C66C8007EBCAC /* mxml-file.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "mxml-file.c"; path = "../mxml-file.c"; sourceTree = "<group>"; };
272C00101E8C66C8007EBCAC /* mxml-get.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "mxml-get.c"; path = "../mxml-get.c"; sourceTree = "<group>"; }; 272C00101E8C66C8007EBCAC /* mxml-get.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "mxml-get.c"; path = "../mxml-get.c"; sourceTree = "<group>"; };
272C00111E8C66C8007EBCAC /* mxml-index.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "mxml-index.c"; path = "../mxml-index.c"; sourceTree = "<group>"; }; 272C00111E8C66C8007EBCAC /* mxml-index.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "mxml-index.c"; path = "../mxml-index.c"; sourceTree = "<group>"; };
@ -92,6 +91,7 @@
272C00401E8C6B1B007EBCAC /* testmxml.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = testmxml.c; path = ../testmxml.c; sourceTree = "<group>"; }; 272C00401E8C6B1B007EBCAC /* testmxml.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = testmxml.c; path = ../testmxml.c; sourceTree = "<group>"; };
272C00551E8EF972007EBCAC /* libarchive.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libarchive.tbd; path = usr/lib/libarchive.tbd; sourceTree = SDKROOT; }; 272C00551E8EF972007EBCAC /* libarchive.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libarchive.tbd; path = usr/lib/libarchive.tbd; sourceTree = SDKROOT; };
272C005A1E943423007EBCAC /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; 272C005A1E943423007EBCAC /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
27459CD82BA8BAC300EAF97D /* mxml-options.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "mxml-options.c"; path = "../mxml-options.c"; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -128,11 +128,11 @@
272C00181E8C66C8007EBCAC /* mxml.h */, 272C00181E8C66C8007EBCAC /* mxml.h */,
272C00141E8C66C8007EBCAC /* mxml-private.h */, 272C00141E8C66C8007EBCAC /* mxml-private.h */,
272C000D1E8C66C8007EBCAC /* mxml-attr.c */, 272C000D1E8C66C8007EBCAC /* mxml-attr.c */,
272C000E1E8C66C8007EBCAC /* mxml-entity.c */,
272C000F1E8C66C8007EBCAC /* mxml-file.c */, 272C000F1E8C66C8007EBCAC /* mxml-file.c */,
272C00101E8C66C8007EBCAC /* mxml-get.c */, 272C00101E8C66C8007EBCAC /* mxml-get.c */,
272C00111E8C66C8007EBCAC /* mxml-index.c */, 272C00111E8C66C8007EBCAC /* mxml-index.c */,
272C00121E8C66C8007EBCAC /* mxml-node.c */, 272C00121E8C66C8007EBCAC /* mxml-node.c */,
27459CD82BA8BAC300EAF97D /* mxml-options.c */,
272C00131E8C66C8007EBCAC /* mxml-private.c */, 272C00131E8C66C8007EBCAC /* mxml-private.c */,
272C00151E8C66C8007EBCAC /* mxml-search.c */, 272C00151E8C66C8007EBCAC /* mxml-search.c */,
272C00161E8C66C8007EBCAC /* mxml-set.c */, 272C00161E8C66C8007EBCAC /* mxml-set.c */,
@ -226,7 +226,7 @@
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
BuildIndependentTargetsInParallel = YES; BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1520; LastUpgradeCheck = 1530;
ORGANIZATIONNAME = "Michael R Sweet"; ORGANIZATIONNAME = "Michael R Sweet";
TargetAttributes = { TargetAttributes = {
272C00041E8C6664007EBCAC = { 272C00041E8C6664007EBCAC = {
@ -271,7 +271,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
272C001A1E8C66C8007EBCAC /* mxml-entity.c in Sources */, 27459CD92BA8BAC300EAF97D /* mxml-options.c in Sources */,
272C001E1E8C66C8007EBCAC /* mxml-node.c in Sources */, 272C001E1E8C66C8007EBCAC /* mxml-node.c in Sources */,
272C001B1E8C66C8007EBCAC /* mxml-file.c in Sources */, 272C001B1E8C66C8007EBCAC /* mxml-file.c in Sources */,
272C001C1E8C66C8007EBCAC /* mxml-get.c in Sources */, 272C001C1E8C66C8007EBCAC /* mxml-get.c in Sources */,