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)
- Added `mxmlLoadFilename` and `mxmlSaveFilename` functions (Issue #291)
- 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
strings.
- 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 \
CHANGES.md LICENSE NOTICE README.md
PUBLIBOBJS = mxml-attr.o mxml-entity.o mxml-file.o mxml-get.o \
mxml-index.o mxml-node.o mxml-search.o mxml-set.o
PUBLIBOBJS = mxml-attr.o mxml-file.o mxml-get.o mxml-index.o \
mxml-node.o mxml-options.o mxml-search.o mxml-set.o
LIBOBJS = $(PUBLIBOBJS) mxml-private.o
OBJS = testmxml.o $(LIBOBJS)
ALLTARGETS = $(LIBMXML) testmxml

View File

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

View File

@ -173,11 +173,8 @@ mxmlElementSetAttr(mxml_node_t *node, // I - Element node
if (value)
{
if ((valuec = _mxml_strcopy(value)) == NULL)
{
_mxml_error("Unable to allocate memory for attribute '%s' in element %s.", name, node->value.element.name);
return;
}
}
else
{
valuec = NULL;
@ -218,10 +215,11 @@ mxmlElementSetAttrf(mxml_node_t *node, // I - Element node
vsnprintf(buffer, sizeof(buffer), format, ap);
va_end(ap);
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 ((value = _mxml_strcopy(buffer)) != NULL)
{
if (!mxml_set_attr(node, name, value))
_mxml_strfree(value);
}
}
@ -253,19 +251,13 @@ mxml_set_attr(mxml_node_t *node, // I - Element node
// Add a new attribute...
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);
}
node->value.element.attrs = attr;
attr += node->value.element.num_attrs;
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);
}
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...
if ((ind = calloc(1, sizeof(mxml_index_t))) == NULL)
{
_mxml_error("Unable to allocate memory for index.");
return (NULL);
}
if (attr)
{
if ((ind->attr = _mxml_strcopy(attr)) == NULL)
{
_mxml_error("Unable to allocate memory for index attribute.");
free(ind);
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)
{
// Unable to allocate memory for the index, so abort...
_mxml_error("Unable to allocate memory for index nodes.");
mxmlIndexDelete(ind);
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)
{
_mxml_error("Unable to allocate memory for CDATA.");
mxmlDelete(node);
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)
{
_mxml_error("Unable to allocate memory for comment.");
mxmlDelete(node);
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.
//
// 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
// element node has no parent. `NULL` can be passed when the data in the
// node is not dynamically allocated or is separately managed.
// list. The `free_cb` argument specifies a function to call to free the custom
// data when the node is deleted.
//
mxml_node_t * // O - New node
mxmlNewCustom(
mxml_node_t *parent, // I - Parent node or `MXML_NO_PARENT`
void *data, // I - Pointer to data
mxml_custom_destroy_cb_t destroy) // I - Function to destroy data
mxml_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_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...
if ((node = mxml_new(parent, MXML_TYPE_CUSTOM)) != NULL)
{
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);
@ -394,7 +393,6 @@ mxmlNewDeclaration(
{
if ((node->value.declaration = _mxml_strcopy(declaration)) == NULL)
{
_mxml_error("Unable to allocate memory for declaration.");
mxmlDelete(node);
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)
{
_mxml_error("Unable to allocate memory for processing instruction.");
mxmlDelete(node);
return (NULL);
}
@ -893,8 +890,8 @@ mxml_free(mxml_node_t *node) // I - Node
_mxml_strfree(node->value.text.string);
break;
case MXML_TYPE_CUSTOM :
if (node->value.custom.data && node->value.custom.destroy)
(*(node->value.custom.destroy))(node->value.custom.data);
if (node->value.custom.data && node->value.custom.free_cb)
(node->value.custom.free_cb)(node->value.custom.free_cbdata, node->value.custom.data);
break;
default :
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
//
// '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.
//
@ -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.
//
@ -341,10 +172,6 @@ _mxml_global(void)
{
global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t));
pthread_setspecific(_mxml_key, global);
global->num_entity_cbs = 1;
global->entity_cbs[0] = _mxml_entity_cb;
global->wrap = 72;
}
return (global);
@ -425,10 +252,6 @@ _mxml_global(void)
{
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);
}
@ -446,12 +269,9 @@ _mxml_global(void)
{
static _mxml_global_t global = // Global data
{
NULL, // error_cb
1, // num_entity_cbs
{ _mxml_entity_cb }, // entity_cbs
72, // wrap
NULL, // custom_load_cb
NULL // custom_save_cb
NULL, // strcopy_cb
NULL, // strfree_cb
NULL, // str_cbdata
};

View File

@ -54,7 +54,8 @@ typedef struct _mxml_text_s // An XML text value.
typedef struct _mxml_custom_s // An XML custom value.
{
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;
typedef union _mxml_value_u // An XML node value.
@ -84,6 +85,13 @@ struct _mxml_node_s // An XML node.
void *user_data; // User data
};
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
@ -93,25 +101,26 @@ struct _mxml_index_s // An XML node index.
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
mxml_custom_save_cb_t custom_save_cb; // Custom save callback function
void *custom_cbdata; // Custom callback data
mxml_error_cb_t error_cb; // Error callback function
void *error_cbdata; // Error callback data
size_t num_entity_cbs; // Number of entity callbacks
mxml_entity_cb_t entity_cbs[100]; // Entity callback functions
void *entity_cbdatas[100]; // Entity callback data
struct lconv *loc; // Locale data
size_t loc_declen; // Length of decimal point string
bool loc_set; // Locale data set?
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_custload_cb_t custload_cb; // Custom load callback function
mxml_custsave_cb_t custsave_cb; // Custom save callback function
void *cust_cbdata; // Custom callback data
mxml_entity_cb_t entity_cb; // Entity callback function
void *entity_cbdata; // Entity callback data
mxml_error_cb_t error_cb; // Error callback function
void *error_cbdata; // Error callback data
mxml_sax_cb_t sax_cb; // SAX callback function
void *sax_cbdata; // SAX callback data
mxml_type_cb_t type_cb; // Type callback function
void *type_cbdata; // Type callback data
mxml_type_t type_value; // Fixed type value (if no type callback)
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 int _mxml_entity_cb(void *cbdata, const char *name);
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 void _mxml_strfree(char *s);

View File

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

87
mxml.h
View File

@ -19,12 +19,6 @@
# include <ctype.h>
# include <errno.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
extern "C" {
# endif // __cplusplus
@ -95,45 +89,46 @@ typedef enum mxml_ws_e // Whitespace periods
MXML_WS_AFTER_CLOSE, // Callback for after close tag
} 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);
// 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;
// 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
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
typedef int (*mxml_entity_cb_t)(void *cbdata, const char *name);
// Entity callback function
typedef mxml_type_t (*mxml_load_cb_t)(void *cbdata, mxml_node_t *node);
// Load callback function
typedef size_t (*mxml_io_cb_t)(void *cbdata, void *buffer, size_t bytes);
// Read/write callback function
typedef ssize_t (*mxml_read_cb_t)(void *cbdata, void *buffer, size_t bytes);
// Read callback function
typedef const char *(*mxml_save_cb_t)(void *cbdata, mxml_node_t *node, mxml_ws_t when);
// Save callback function
typedef bool (*mxml_sax_cb_t)(void *cbdata, mxml_node_t *node, mxml_sax_event_t event);
// SAX callback function
typedef char *(*mxml_strcopy_cb_t)(void *cbdata, const char *s);
// String copy/allocation callback
typedef void (*mxml_strfree_cb_t)(void *cbdata, char *s);
// String free callback
typedef ssize_t (*mxml_write_cb_t)(void *cbdata, const void *buffer, size_t bytes);
// Write callback function
typedef mxml_type_t (*mxml_type_cb_t)(void *cbdata, mxml_node_t *node);
// 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 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 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 *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_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 *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 *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 *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 *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 *mxmlLoadFd(mxml_node_t *top, mxml_options_t *options, int fd);
extern mxml_node_t *mxmlLoadFile(mxml_node_t *top, mxml_options_t *options, FILE *fp);
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_options_t *options, mxml_io_cb_t io_cb, void *io_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 *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 *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 *mxmlNewDeclarationf(mxml_node_t *parent, const char *format, ...) MXML_FORMAT(2,3);
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 int mxmlRetain(mxml_node_t *node);
extern char *mxmlSaveAllocString(mxml_node_t *node, mxml_save_cb_t save_cb, void *save_cbdata);
extern bool mxmlSaveFd(mxml_node_t *node, int fd, mxml_save_cb_t save_cb, void *save_cbdata);
extern bool mxmlSaveFile(mxml_node_t *node, FILE *fp, mxml_save_cb_t save_cb, void *save_cbdata);
extern bool mxmlSaveFilename(mxml_node_t *node, const char *filename, mxml_save_cb_t save_cb, void *save_cbdata);
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 size_t mxmlSaveString(mxml_node_t *node, char *buffer, size_t bufsize, 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, mxml_options_t *options, int fd);
extern bool mxmlSaveFile(mxml_node_t *node, mxml_options_t *options, FILE *fp);
extern bool mxmlSaveFilename(mxml_node_t *node, mxml_options_t *options, const char *filename);
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, mxml_options_t *options, char *buffer, size_t bufsize);
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 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 mxmlSetDirective(mxml_node_t *node, const char *directive);
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 void mxmlSetCustomCallbacks(mxml_custom_load_cb_t load_cb, mxml_custom_save_cb_t save_cb, void *cbdata);
extern bool mxmlSetCustom(mxml_node_t *node, void *data, mxml_custfree_cb_t free_cb, void *free_cbdata);
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 mxmlSetOpaque(mxml_node_t *node, const char *opaque);
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 mxmlSetTextf(mxml_node_t *node, bool whitespace, const char *format, ...) MXML_FORMAT(3,4);
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 *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
FILE *fp; // File to read
int fd; // File descriptor
mxml_options_t *options; // Load/save options
mxml_node_t *xml, // <?xml ...?> node
*tree, // Element tree
*node; // Node which should be in test.xml
@ -83,6 +84,7 @@ main(int argc, // I - Number of command-line args
}
// Test the basic functionality...
options = mxmlOptionsNew();
xml = mxmlNewXML("1.0");
tree = mxmlNewElement(xml, "element");
@ -111,18 +113,18 @@ main(int argc, // I - Number of command-line args
mxmlNewReal(tree, 123.4);
mxmlNewText(tree, 1, "text");
type = MXML_TYPE_TEXT;
mxmlLoadString(tree, "<group type='string'>string string string</group>", /*load_cb*/NULL, /*load_cbdata*/&type, /*sax_cb*/NULL, /*sax_cbdata*/NULL);
mxmlOptionsSetTypeValue(options, MXML_TYPE_TEXT);
mxmlLoadString(tree, options, "<group type='string'>string string string</group>");
type = MXML_TYPE_INTEGER;
mxmlLoadString(tree, "<group type='integer'>1 2 3</group>", /*load_cb*/NULL, /*load_cbdata*/&type, /*sax_cb*/NULL, /*sax_cbdata*/NULL);
mxmlOptionsSetTypeValue(options, MXML_TYPE_INTEGER);
mxmlLoadString(tree, options, "<group type='integer'>1 2 3</group>");
type = 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);
mxmlOptionsSetTypeValue(options, MXML_TYPE_REAL);
mxmlLoadString(tree, options, "<group type='real'>1.0 2.0 3.0</group>");
type = MXML_TYPE_OPAQUE;
mxmlLoadString(tree, "<group>opaque opaque opaque</group>", /*load_cb*/NULL, /*load_cbdata*/&type, /*sax_cb*/NULL, /*sax_cbdata*/NULL);
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);
mxmlOptionsSetTypeValue(options, MXML_TYPE_OPAQUE);
mxmlLoadString(tree, options, "<group>opaque opaque opaque</group>");
mxmlLoadString(tree, options, "<foo><bar><one><two>value<two>value2</two></two></one></bar></foo>");
mxmlNewCDATA(tree, "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n");
mxmlNewCDATA(tree,
@ -434,11 +436,13 @@ main(int argc, // I - Number of command-line args
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] == '<')
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
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)
{
@ -459,7 +463,7 @@ main(int argc, // I - Number of command-line args
if (mxmlGetType(node) != MXML_TYPE_TEXT)
{
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);
return (1);
}
@ -475,10 +479,12 @@ main(int argc, // I - Number of command-line args
mxmlDelete(xml);
// Open the file...
mxmlOptionsSetTypeCallback(options, type_cb, /*cbdata*/NULL);
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
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)
{
@ -505,10 +511,11 @@ main(int argc, // I - Number of command-line args
}
// 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...
if (mxmlSaveString(xml, buffer, sizeof(buffer), whitespace_cb, /*save_cbdata*/NULL) > 0)
if (mxmlSaveString(xml, options, buffer, sizeof(buffer)) > 0)
{
if (argc == 3)
{
@ -532,7 +539,7 @@ main(int argc, // I - Number of command-line args
}
// 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);
@ -547,7 +554,7 @@ main(int argc, // I - Number of command-line args
}
// Write the file...
mxmlSaveFd(xml, fd, whitespace_cb, /*save_cbdata*/NULL);
mxmlSaveFd(xml, options, fd);
close(fd);
@ -558,10 +565,12 @@ main(int argc, // I - Number of command-line args
// Test SAX methods...
memset(event_counts, 0, sizeof(event_counts));
mxmlOptionsSetSAXCallback(options, sax_cb, /*cbdata*/NULL);
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
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"))
{

View File

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

View File

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

View File

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

View File

@ -23,7 +23,6 @@
/* Begin PBXBuildFile section */
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 */; };
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 */; };
@ -36,6 +35,7 @@
272C00261E8C66CF007EBCAC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 272C00251E8C66CF007EBCAC /* config.h */; };
272C00421E8C6B30007EBCAC /* testmxml.c in Sources */ = {isa = PBXBuildFile; fileRef = 272C00401E8C6B1B007EBCAC /* testmxml.c */; };
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 */
/* Begin PBXContainerItemProxy section */
@ -77,7 +77,6 @@
/* Begin PBXFileReference section */
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>"; };
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>"; };
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>"; };
@ -92,6 +91,7 @@
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; };
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 */
/* Begin PBXFrameworksBuildPhase section */
@ -128,11 +128,11 @@
272C00181E8C66C8007EBCAC /* mxml.h */,
272C00141E8C66C8007EBCAC /* mxml-private.h */,
272C000D1E8C66C8007EBCAC /* mxml-attr.c */,
272C000E1E8C66C8007EBCAC /* mxml-entity.c */,
272C000F1E8C66C8007EBCAC /* mxml-file.c */,
272C00101E8C66C8007EBCAC /* mxml-get.c */,
272C00111E8C66C8007EBCAC /* mxml-index.c */,
272C00121E8C66C8007EBCAC /* mxml-node.c */,
27459CD82BA8BAC300EAF97D /* mxml-options.c */,
272C00131E8C66C8007EBCAC /* mxml-private.c */,
272C00151E8C66C8007EBCAC /* mxml-search.c */,
272C00161E8C66C8007EBCAC /* mxml-set.c */,
@ -226,7 +226,7 @@
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1520;
LastUpgradeCheck = 1530;
ORGANIZATIONNAME = "Michael R Sweet";
TargetAttributes = {
272C00041E8C6664007EBCAC = {
@ -271,7 +271,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
272C001A1E8C66C8007EBCAC /* mxml-entity.c in Sources */,
27459CD92BA8BAC300EAF97D /* mxml-options.c in Sources */,
272C001E1E8C66C8007EBCAC /* mxml-node.c in Sources */,
272C001B1E8C66C8007EBCAC /* mxml-file.c in Sources */,
272C001C1E8C66C8007EBCAC /* mxml-get.c in Sources */,