Added mxml library

This commit is contained in:
pelya
2011-03-24 16:53:27 +02:00
parent b8be901b25
commit 870193c7db
18 changed files with 8071 additions and 0 deletions

View File

@@ -0,0 +1,97 @@
/*
* "$Id: config.h.in 387 2009-04-18 17:05:52Z mike $"
*
* Configuration file for Mini-XML, a small XML-like file parsing library.
*
* Copyright 2003-2009 by Michael Sweet.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/*
* Include necessary headers...
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
/*
* Version number...
*/
#define MXML_VERSION "2.6"
/*
* Inline function support...
*/
/* #define inline */
/*
* Long long support...
*/
#define HAVE_LONG_LONG 1
/*
* Do we have the snprintf() and vsnprintf() functions?
*/
#define HAVE_SNPRINTF 1
#define HAVE_VSNPRINTF 1
/*
* Do we have the strXXX() functions?
*/
#define HAVE_STRDUP 1
/*
* Do we have threading support?
*/
#define HAVE_PTHREAD_H 1
/*
* Define prototypes for string functions as needed...
*/
# ifndef HAVE_STRDUP
extern char *_mxml_strdup(const char *);
# define strdup _mxml_strdup
# endif /* !HAVE_STRDUP */
extern char *_mxml_strdupf(const char *, ...);
extern char *_mxml_vstrdupf(const char *, va_list);
# ifndef HAVE_SNPRINTF
extern int _mxml_snprintf(char *, size_t, const char *, ...);
# define snprintf _mxml_snprintf
# endif /* !HAVE_SNPRINTF */
# ifndef HAVE_VSNPRINTF
extern int _mxml_vsnprintf(char *, size_t, const char *, va_list);
# define vsnprintf _mxml_vsnprintf
# endif /* !HAVE_VSNPRINTF */
/*
* End of "$Id: config.h.in 387 2009-04-18 17:05:52Z mike $".
*/

View File

@@ -0,0 +1,321 @@
/*
* "$Id: mxml-attr.c 308 2007-09-15 20:04:56Z mike $"
*
* Attribute support code for Mini-XML, a small XML-like file parsing library.
*
* Copyright 2003-2007 by Michael Sweet.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Contents:
*
* mxmlElementDeleteAttr() - Delete an attribute.
* mxmlElementGetAttr() - Get an attribute.
* mxmlElementSetAttr() - Set an attribute.
* mxmlElementSetAttrf() - Set an attribute with a formatted value.
* mxml_set_attr() - Set or add an attribute name/value pair.
*/
/*
* Include necessary headers...
*/
#include "config.h"
#include "mxml.h"
/*
* Local functions...
*/
static int mxml_set_attr(mxml_node_t *node, const char *name,
char *value);
/*
* 'mxmlElementDeleteAttr()' - Delete an attribute.
*
* @since Mini-XML 2.4@
*/
void
mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */
const char *name)/* I - Attribute name */
{
int i; /* Looping var */
mxml_attr_t *attr; /* Cirrent attribute */
#ifdef DEBUG
fprintf(stderr, "mxmlElementDeleteAttr(node=%p, name=\"%s\")\n",
node, name ? name : "(null)");
#endif /* DEBUG */
/*
* Range check input...
*/
if (!node || node->type != MXML_ELEMENT || !name)
return;
/*
* Look for the attribute...
*/
for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
i > 0;
i --, attr ++)
{
#ifdef DEBUG
printf(" %s=\"%s\"\n", attr->name, attr->value);
#endif /* DEBUG */
if (!strcmp(attr->name, name))
{
/*
* Delete this attribute...
*/
free(attr->name);
free(attr->value);
i --;
if (i > 0)
memmove(attr, attr + 1, i * sizeof(mxml_attr_t));
node->value.element.num_attrs --;
return;
}
}
}
/*
* 'mxmlElementGetAttr()' - Get an attribute.
*
* This function returns NULL if the node is not an element or the
* named attribute does not exist.
*/
const char * /* O - Attribute value or NULL */
mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */
const char *name) /* I - Name of attribute */
{
int i; /* Looping var */
mxml_attr_t *attr; /* Cirrent attribute */
#ifdef DEBUG
fprintf(stderr, "mxmlElementGetAttr(node=%p, name=\"%s\")\n",
node, name ? name : "(null)");
#endif /* DEBUG */
/*
* Range check input...
*/
if (!node || node->type != MXML_ELEMENT || !name)
return (NULL);
/*
* Look for the attribute...
*/
for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
i > 0;
i --, attr ++)
{
#ifdef DEBUG
printf(" %s=\"%s\"\n", attr->name, attr->value);
#endif /* DEBUG */
if (!strcmp(attr->name, name))
{
#ifdef DEBUG
printf(" Returning \"%s\"!\n", attr->value);
#endif /* DEBUG */
return (attr->value);
}
}
/*
* Didn't find attribute, so return NULL...
*/
#ifdef DEBUG
puts(" Returning NULL!\n");
#endif /* DEBUG */
return (NULL);
}
/*
* 'mxmlElementSetAttr()' - Set an attribute.
*
* If the named attribute already exists, the value of the attribute
* is replaced by the new string value. The string value is copied
* into the element node. This function does nothing if the node is
* not an element.
*/
void
mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */
const char *name, /* I - Name of attribute */
const char *value) /* I - Attribute value */
{
char *valuec; /* Copy of value */
#ifdef DEBUG
fprintf(stderr, "mxmlElementSetAttr(node=%p, name=\"%s\", value=\"%s\")\n",
node, name ? name : "(null)", value ? value : "(null)");
#endif /* DEBUG */
/*
* Range check input...
*/
if (!node || node->type != MXML_ELEMENT || !name)
return;
if (value)
valuec = strdup(value);
else
valuec = NULL;
if (mxml_set_attr(node, name, valuec))
free(valuec);
}
/*
* 'mxmlElementSetAttrf()' - Set an attribute with a formatted value.
*
* If the named attribute already exists, the value of the attribute
* is replaced by the new formatted string. The formatted string value is
* copied into the element node. This function does nothing if the node
* is not an element.
*
* @since Mini-XML 2.3@
*/
void
mxmlElementSetAttrf(mxml_node_t *node, /* I - Element node */
const char *name, /* I - Name of attribute */
const char *format,/* I - Printf-style attribute value */
...) /* I - Additional arguments as needed */
{
va_list ap; /* Argument pointer */
char *value; /* Value */
#ifdef DEBUG
fprintf(stderr,
"mxmlElementSetAttrf(node=%p, name=\"%s\", format=\"%s\", ...)\n",
node, name ? name : "(null)", format ? format : "(null)");
#endif /* DEBUG */
/*
* Range check input...
*/
if (!node || node->type != MXML_ELEMENT || !name || !format)
return;
/*
* Format the value...
*/
va_start(ap, format);
value = _mxml_vstrdupf(format, ap);
va_end(ap);
if (!value)
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))
free(value);
}
/*
* 'mxml_set_attr()' - Set or add an attribute name/value pair.
*/
static int /* O - 0 on success, -1 on failure */
mxml_set_attr(mxml_node_t *node, /* I - Element node */
const char *name, /* I - Attribute name */
char *value) /* I - Attribute value */
{
int i; /* Looping var */
mxml_attr_t *attr; /* New attribute */
/*
* Look for the attribute...
*/
for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
i > 0;
i --, attr ++)
if (!strcmp(attr->name, name))
{
/*
* Free the old value as needed...
*/
if (attr->value)
free(attr->value);
attr->value = value;
return (0);
}
/*
* Add a new attribute...
*/
if (node->value.element.num_attrs == 0)
attr = malloc(sizeof(mxml_attr_t));
else
attr = realloc(node->value.element.attrs,
(node->value.element.num_attrs + 1) * sizeof(mxml_attr_t));
if (!attr)
{
mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
name, node->value.element.name);
return (-1);
}
node->value.element.attrs = attr;
attr += node->value.element.num_attrs;
if ((attr->name = strdup(name)) == NULL)
{
mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
name, node->value.element.name);
return (-1);
}
attr->value = value;
node->value.element.num_attrs ++;
return (0);
}
/*
* End of "$Id: mxml-attr.c 308 2007-09-15 20:04:56Z mike $".
*/

View File

@@ -0,0 +1,462 @@
/*
* "$Id: mxml-entity.c 385 2009-03-19 05:38:52Z mike $"
*
* Character entity support code for Mini-XML, a small XML-like
* file parsing library.
*
* Copyright 2003-2009 by Michael Sweet.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Contents:
*
* mxmlEntityAddCallback() - Add a callback to convert entities to
* Unicode.
* mxmlEntityGetName() - Get the name that corresponds to the
* character value.
* mxmlEntityGetValue() - Get the character corresponding to a named
* entity.
* mxmlEntityRemoveCallback() - Remove a callback.
* _mxml_entity_cb() - Lookup standard (X)HTML entities.
*/
/*
* Include necessary headers...
*/
#include "mxml-private.h"
/*
* 'mxmlEntityAddCallback()' - Add a callback to convert entities to Unicode.
*/
int /* O - 0 on success, -1 on failure */
mxmlEntityAddCallback(
mxml_entity_cb_t cb) /* I - Callback function to add */
{
_mxml_global_t *global = _mxml_global();
/* Global data */
if (global->num_entity_cbs < (int)(sizeof(global->entity_cbs) / sizeof(global->entity_cbs[0])))
{
global->entity_cbs[global->num_entity_cbs] = cb;
global->num_entity_cbs ++;
return (0);
}
else
{
mxml_error("Unable to add entity callback!");
return (-1);
}
}
/*
* 'mxmlEntityGetName()' - Get the name that corresponds to the character value.
*
* If val does not need to be represented by a named entity, NULL is returned.
*/
const char * /* O - Entity name or NULL */
mxmlEntityGetName(int val) /* I - Character value */
{
switch (val)
{
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 */
{
int 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])(name)) >= 0)
return (ch);
return (-1);
}
/*
* 'mxmlEntityRemoveCallback()' - Remove a callback.
*/
void
mxmlEntityRemoveCallback(
mxml_entity_cb_t cb) /* I - Callback function to remove */
{
int 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]));
return;
}
}
/*
* '_mxml_entity_cb()' - Lookup standard (X)HTML entities.
*/
int /* O - Unicode value or -1 */
_mxml_entity_cb(const char *name) /* I - Entity name */
{
int diff, /* Difference between names */
current, /* Current entity in search */
first, /* First entity in search */
last; /* Last entity in search */
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 }
};
/*
* Do a binary search for the named entity...
*/
first = 0;
last = (int)(sizeof(entities) / sizeof(entities[0]) - 1);
while ((last - first) > 1)
{
current = (first + last) / 2;
if ((diff = strcmp(name, entities[current].name)) == 0)
return (entities[current].val);
else if (diff < 0)
last = current;
else
first = current;
}
/*
* If we get here, there is a small chance that there is still
* a match; check first and last...
*/
if (!strcmp(name, entities[first].name))
return (entities[first].val);
else if (!strcmp(name, entities[last].name))
return (entities[last].val);
else
return (-1);
}
/*
* End of "$Id: mxml-entity.c 385 2009-03-19 05:38:52Z mike $".
*/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,649 @@
/*
* "$Id: mxml-index.c 184 2005-01-29 07:21:44Z mike $"
*
* Index support code for Mini-XML, a small XML-like file parsing library.
*
* Copyright 2003-2005 by Michael Sweet.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Contents:
*
* mxmlIndexDelete() - Delete an index.
* mxmlIndexEnum() - Return the next node in the index.
* mxmlIndexFind() - Find the next matching node.
* mxmlIndexNew() - Create a new index.
* mxmlIndexReset() - Reset the enumeration/find pointer in the index and
* return the first node in the index.
* index_compare() - Compare two nodes.
* index_find() - Compare a node with index values.
* index_sort() - Sort the nodes in the index...
*/
/*
* Include necessary headers...
*/
#include "config.h"
#include "mxml.h"
/*
* Sort functions...
*/
static int index_compare(mxml_index_t *ind, mxml_node_t *first,
mxml_node_t *second);
static int index_find(mxml_index_t *ind, const char *element,
const char *value, mxml_node_t *node);
static void index_sort(mxml_index_t *ind, int left, int right);
/*
* 'mxmlIndexDelete()' - Delete an index.
*/
void
mxmlIndexDelete(mxml_index_t *ind) /* I - Index to delete */
{
/*
* Range check input..
*/
if (!ind)
return;
/*
* Free memory...
*/
if (ind->attr)
free(ind->attr);
if (ind->alloc_nodes)
free(ind->nodes);
free(ind);
}
/*
* 'mxmlIndexEnum()' - Return the next node in the index.
*
* Nodes are returned in the sorted order of the index.
*/
mxml_node_t * /* O - Next node or NULL if there is none */
mxmlIndexEnum(mxml_index_t *ind) /* I - Index to enumerate */
{
/*
* Range check input...
*/
if (!ind)
return (NULL);
/*
* Return the next node...
*/
if (ind->cur_node < ind->num_nodes)
return (ind->nodes[ind->cur_node ++]);
else
return (NULL);
}
/*
* 'mxmlIndexFind()' - Find the next matching node.
*
* You should call mxmlIndexReset() prior to using this function for
* the first time with a particular set of "element" and "value"
* strings. Passing NULL for both "element" and "value" is equivalent
* to calling mxmlIndexEnum().
*/
mxml_node_t * /* O - Node or NULL if none found */
mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */
const char *element, /* I - Element name to find, if any */
const char *value) /* I - Attribute value, if any */
{
int diff, /* Difference between names */
current, /* Current entity in search */
first, /* First entity in search */
last; /* Last entity in search */
#ifdef DEBUG
printf("mxmlIndexFind(ind=%p, element=\"%s\", value=\"%s\")\n",
ind, element ? element : "(null)", value ? value : "(null)");
#endif /* DEBUG */
/*
* Range check input...
*/
if (!ind || (!ind->attr && value))
{
#ifdef DEBUG
puts(" returning NULL...");
printf(" ind->attr=\"%s\"\n", ind->attr ? ind->attr : "(null)");
#endif /* DEBUG */
return (NULL);
}
/*
* If both element and value are NULL, just enumerate the nodes in the
* index...
*/
if (!element && !value)
return (mxmlIndexEnum(ind));
/*
* If there are no nodes in the index, return NULL...
*/
if (!ind->num_nodes)
{
#ifdef DEBUG
puts(" returning NULL...");
puts(" no nodes!");
#endif /* DEBUG */
return (NULL);
}
/*
* If cur_node == 0, then find the first matching node...
*/
if (ind->cur_node == 0)
{
/*
* Find the first node using a modified binary search algorithm...
*/
first = 0;
last = ind->num_nodes - 1;
#ifdef DEBUG
printf(" find first time, num_nodes=%d...\n", ind->num_nodes);
#endif /* DEBUG */
while ((last - first) > 1)
{
current = (first + last) / 2;
#ifdef DEBUG
printf(" first=%d, last=%d, current=%d\n", first, last, current);
#endif /* DEBUG */
if ((diff = index_find(ind, element, value, ind->nodes[current])) == 0)
{
/*
* Found a match, move back to find the first...
*/
#ifdef DEBUG
puts(" match!");
#endif /* DEBUG */
while (current > 0 &&
!index_find(ind, element, value, ind->nodes[current - 1]))
current --;
#ifdef DEBUG
printf(" returning first match=%d\n", current);
#endif /* DEBUG */
/*
* Return the first match and save the index to the next...
*/
ind->cur_node = current + 1;
return (ind->nodes[current]);
}
else if (diff < 0)
last = current;
else
first = current;
#ifdef DEBUG
printf(" diff=%d\n", diff);
#endif /* DEBUG */
}
/*
* If we get this far, then we found exactly 0 or 1 matches...
*/
for (current = first; current <= last; current ++)
if (!index_find(ind, element, value, ind->nodes[current]))
{
/*
* Found exactly one (or possibly two) match...
*/
#ifdef DEBUG
printf(" returning only match %d...\n", current);
#endif /* DEBUG */
ind->cur_node = current + 1;
return (ind->nodes[current]);
}
/*
* No matches...
*/
ind->cur_node = ind->num_nodes;
#ifdef DEBUG
puts(" returning NULL...");
#endif /* DEBUG */
return (NULL);
}
else if (ind->cur_node < ind->num_nodes &&
!index_find(ind, element, value, ind->nodes[ind->cur_node]))
{
/*
* Return the next matching node...
*/
#ifdef DEBUG
printf(" returning next match %d...\n", ind->cur_node);
#endif /* DEBUG */
return (ind->nodes[ind->cur_node ++]);
}
/*
* If we get this far, then we have no matches...
*/
ind->cur_node = ind->num_nodes;
#ifdef DEBUG
puts(" returning NULL...");
#endif /* DEBUG */
return (NULL);
}
/*
* 'mxmlIndexNew()' - Create a new index.
*
* The index will contain all nodes that contain the named element and/or
* attribute. If both "element" and "attr" are NULL, then the index will
* contain a sorted list of the elements in the node tree. Nodes are
* sorted by element name and optionally by attribute value if the "attr"
* argument is not NULL.
*/
mxml_index_t * /* O - New index */
mxmlIndexNew(mxml_node_t *node, /* I - XML node tree */
const char *element, /* I - Element to index or NULL for all */
const char *attr) /* I - Attribute to index or NULL for none */
{
mxml_index_t *ind; /* New index */
mxml_node_t *current, /* Current node in index */
**temp; /* Temporary node pointer array */
/*
* Range check input...
*/
#ifdef DEBUG
printf("mxmlIndexNew(node=%p, element=\"%s\", attr=\"%s\")\n",
node, element ? element : "(null)", attr ? attr : "(null)");
#endif /* DEBUG */
if (!node)
return (NULL);
/*
* Create a new index...
*/
if ((ind = calloc(1, sizeof(mxml_index_t))) == NULL)
{
mxml_error("Unable to allocate %d bytes for index - %s",
sizeof(mxml_index_t), strerror(errno));
return (NULL);
}
if (attr)
ind->attr = strdup(attr);
if (!element && !attr)
current = node;
else
current = mxmlFindElement(node, node, element, attr, NULL, MXML_DESCEND);
while (current)
{
if (ind->num_nodes >= ind->alloc_nodes)
{
if (!ind->alloc_nodes)
temp = malloc(64 * sizeof(mxml_node_t *));
else
temp = realloc(ind->nodes, (ind->alloc_nodes + 64) * sizeof(mxml_node_t *));
if (!temp)
{
/*
* Unable to allocate memory for the index, so abort...
*/
mxml_error("Unable to allocate %d bytes for index: %s",
(ind->alloc_nodes + 64) * sizeof(mxml_node_t *),
strerror(errno));
mxmlIndexDelete(ind);
return (NULL);
}
ind->nodes = temp;
ind->alloc_nodes += 64;
}
ind->nodes[ind->num_nodes ++] = current;
current = mxmlFindElement(current, node, element, attr, NULL, MXML_DESCEND);
}
/*
* Sort nodes based upon the search criteria...
*/
#ifdef DEBUG
{
int i; /* Looping var */
printf("%d node(s) in index.\n\n", ind->num_nodes);
if (attr)
{
printf("Node Address Element %s\n", attr);
puts("-------- -------- -------------- ------------------------------");
for (i = 0; i < ind->num_nodes; i ++)
printf("%8d %-8p %-14.14s %s\n", i, ind->nodes[i],
ind->nodes[i]->value.element.name,
mxmlElementGetAttr(ind->nodes[i], attr));
}
else
{
puts("Node Address Element");
puts("-------- -------- --------------");
for (i = 0; i < ind->num_nodes; i ++)
printf("%8d %-8p %s\n", i, ind->nodes[i],
ind->nodes[i]->value.element.name);
}
putchar('\n');
}
#endif /* DEBUG */
if (ind->num_nodes > 1)
index_sort(ind, 0, ind->num_nodes - 1);
#ifdef DEBUG
{
int i; /* Looping var */
puts("After sorting:\n");
if (attr)
{
printf("Node Address Element %s\n", attr);
puts("-------- -------- -------------- ------------------------------");
for (i = 0; i < ind->num_nodes; i ++)
printf("%8d %-8p %-14.14s %s\n", i, ind->nodes[i],
ind->nodes[i]->value.element.name,
mxmlElementGetAttr(ind->nodes[i], attr));
}
else
{
puts("Node Address Element");
puts("-------- -------- --------------");
for (i = 0; i < ind->num_nodes; i ++)
printf("%8d %-8p %s\n", i, ind->nodes[i],
ind->nodes[i]->value.element.name);
}
putchar('\n');
}
#endif /* DEBUG */
/*
* Return the new index...
*/
return (ind);
}
/*
* 'mxmlIndexReset()' - Reset the enumeration/find pointer in the index and
* return the first node in the index.
*
* This function should be called prior to using mxmlIndexEnum() or
* mxmlIndexFind() for the first time.
*/
mxml_node_t * /* O - First node or NULL if there is none */
mxmlIndexReset(mxml_index_t *ind) /* I - Index to reset */
{
#ifdef DEBUG
printf("mxmlIndexReset(ind=%p)\n", ind);
#endif /* DEBUG */
/*
* Range check input...
*/
if (!ind)
return (NULL);
/*
* Set the index to the first element...
*/
ind->cur_node = 0;
/*
* Return the first node...
*/
if (ind->num_nodes)
return (ind->nodes[0]);
else
return (NULL);
}
/*
* 'index_compare()' - Compare two nodes.
*/
static int /* O - Result of comparison */
index_compare(mxml_index_t *ind, /* I - Index */
mxml_node_t *first, /* I - First node */
mxml_node_t *second) /* I - Second node */
{
int diff; /* Difference */
/*
* Check the element name...
*/
if ((diff = strcmp(first->value.element.name,
second->value.element.name)) != 0)
return (diff);
/*
* Check the attribute value...
*/
if (ind->attr)
{
if ((diff = strcmp(mxmlElementGetAttr(first, ind->attr),
mxmlElementGetAttr(second, ind->attr))) != 0)
return (diff);
}
/*
* No difference, return 0...
*/
return (0);
}
/*
* 'index_find()' - Compare a node with index values.
*/
static int /* O - Result of comparison */
index_find(mxml_index_t *ind, /* I - Index */
const char *element, /* I - Element name or NULL */
const char *value, /* I - Attribute value or NULL */
mxml_node_t *node) /* I - Node */
{
int diff; /* Difference */
/*
* Check the element name...
*/
if (element)
{
if ((diff = strcmp(element, node->value.element.name)) != 0)
return (diff);
}
/*
* Check the attribute value...
*/
if (value)
{
if ((diff = strcmp(value, mxmlElementGetAttr(node, ind->attr))) != 0)
return (diff);
}
/*
* No difference, return 0...
*/
return (0);
}
/*
* 'index_sort()' - Sort the nodes in the index...
*
* This function implements the classic quicksort algorithm...
*/
static void
index_sort(mxml_index_t *ind, /* I - Index to sort */
int left, /* I - Left node in partition */
int right) /* I - Right node in partition */
{
mxml_node_t *pivot, /* Pivot node */
*temp; /* Swap node */
int templ, /* Temporary left node */
tempr; /* Temporary right node */
/*
* Loop until we have sorted all the way to the right...
*/
do
{
/*
* Sort the pivot in the current partition...
*/
pivot = ind->nodes[left];
for (templ = left, tempr = right; templ < tempr;)
{
/*
* Move left while left node <= pivot node...
*/
while ((templ < right) &&
index_compare(ind, ind->nodes[templ], pivot) <= 0)
templ ++;
/*
* Move right while right node > pivot node...
*/
while ((tempr > left) &&
index_compare(ind, ind->nodes[tempr], pivot) > 0)
tempr --;
/*
* Swap nodes if needed...
*/
if (templ < tempr)
{
temp = ind->nodes[templ];
ind->nodes[templ] = ind->nodes[tempr];
ind->nodes[tempr] = temp;
}
}
/*
* When we get here, the right (tempr) node is the new position for the
* pivot node...
*/
if (index_compare(ind, pivot, ind->nodes[tempr]) > 0)
{
ind->nodes[left] = ind->nodes[tempr];
ind->nodes[tempr] = pivot;
}
/*
* Recursively sort the left partition as needed...
*/
if (left < (tempr - 1))
index_sort(ind, left, tempr - 1);
}
while (right > (left = tempr + 1));
}
/*
* End of "$Id: mxml-index.c 184 2005-01-29 07:21:44Z mike $".
*/

View File

@@ -0,0 +1,780 @@
/*
* "$Id: mxml-node.c 363 2008-10-26 18:28:05Z mike $"
*
* Node support code for Mini-XML, a small XML-like file parsing library.
*
* Copyright 2003-2007 by Michael Sweet.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Contents:
*
* mxmlAdd() - Add a node to a tree.
* mxmlDelete() - Delete a node and all of its children.
* mxmlNewCDATA() - Create a new CDATA node.
* mxmlNewCustom() - Create a new custom data node.
* mxmlNewElement() - Create a new element node.
* mxmlNewInteger() - Create a new integer node.
* mxmlNewOpaque() - Create a new opaque string.
* mxmlNewReal() - Create a new real number node.
* mxmlNewText() - Create a new text fragment node.
* mxmlNewTextf() - Create a new formatted text fragment node.
* mxmlNewXML() - Create a new XML document tree.
* mxmlRelease() - Release a node.
* mxmlRemove() - Remove a node from its parent.
* mxmlRetain() - Retain a node.
* mxml_new() - Create a new node.
*/
/*
* Include necessary headers...
*/
#include "config.h"
#include "mxml.h"
/*
* Local functions...
*/
static mxml_node_t *mxml_new(mxml_node_t *parent, mxml_type_t type);
/*
* 'mxmlAdd()' - Add a node to a tree.
*
* Adds the specified node to the parent. If the child argument is not
* NULL, puts the new node before or after the specified child depending
* on the value of the where argument. If the child argument is NULL,
* puts the new node at the beginning of the child list (MXML_ADD_BEFORE)
* or at the end of the child list (MXML_ADD_AFTER). The constant
* MXML_ADD_TO_PARENT can be used to specify a NULL child pointer.
*/
void
mxmlAdd(mxml_node_t *parent, /* I - Parent node */
int where, /* I - Where to add, MXML_ADD_BEFORE or MXML_ADD_AFTER */
mxml_node_t *child, /* I - Child node for where or MXML_ADD_TO_PARENT */
mxml_node_t *node) /* I - Node to add */
{
#ifdef DEBUG
fprintf(stderr, "mxmlAdd(parent=%p, where=%d, child=%p, node=%p)\n", parent,
where, child, node);
#endif /* DEBUG */
/*
* Range check input...
*/
if (!parent || !node)
return;
#if DEBUG > 1
fprintf(stderr, " BEFORE: node->parent=%p\n", node->parent);
if (parent)
{
fprintf(stderr, " BEFORE: parent->child=%p\n", parent->child);
fprintf(stderr, " BEFORE: parent->last_child=%p\n", parent->last_child);
fprintf(stderr, " BEFORE: parent->prev=%p\n", parent->prev);
fprintf(stderr, " BEFORE: parent->next=%p\n", parent->next);
}
#endif /* DEBUG > 1 */
/*
* Remove the node from any existing parent...
*/
if (node->parent)
mxmlRemove(node);
/*
* Reset pointers...
*/
node->parent = parent;
switch (where)
{
case MXML_ADD_BEFORE :
if (!child || child == parent->child || child->parent != parent)
{
/*
* Insert as first node under parent...
*/
node->next = parent->child;
if (parent->child)
parent->child->prev = node;
else
parent->last_child = node;
parent->child = node;
}
else
{
/*
* Insert node before this child...
*/
node->next = child;
node->prev = child->prev;
if (child->prev)
child->prev->next = node;
else
parent->child = node;
child->prev = node;
}
break;
case MXML_ADD_AFTER :
if (!child || child == parent->last_child || child->parent != parent)
{
/*
* Insert as last node under parent...
*/
node->parent = parent;
node->prev = parent->last_child;
if (parent->last_child)
parent->last_child->next = node;
else
parent->child = node;
parent->last_child = node;
}
else
{
/*
* Insert node after this child...
*/
node->prev = child;
node->next = child->next;
if (child->next)
child->next->prev = node;
else
parent->last_child = node;
child->next = node;
}
break;
}
#if DEBUG > 1
fprintf(stderr, " AFTER: node->parent=%p\n", node->parent);
if (parent)
{
fprintf(stderr, " AFTER: parent->child=%p\n", parent->child);
fprintf(stderr, " AFTER: parent->last_child=%p\n", parent->last_child);
fprintf(stderr, " AFTER: parent->prev=%p\n", parent->prev);
fprintf(stderr, " AFTER: parent->next=%p\n", parent->next);
}
#endif /* DEBUG > 1 */
}
/*
* 'mxmlDelete()' - Delete a node and all of its children.
*
* If the specified node has a parent, this function first removes the
* node from its parent using the mxmlRemove() function.
*/
void
mxmlDelete(mxml_node_t *node) /* I - Node to delete */
{
int i; /* Looping var */
#ifdef DEBUG
fprintf(stderr, "mxmlDelete(node=%p)\n", node);
#endif /* DEBUG */
/*
* Range check input...
*/
if (!node)
return;
/*
* Remove the node from its parent, if any...
*/
mxmlRemove(node);
/*
* Delete children...
*/
while (node->child)
mxmlDelete(node->child);
/*
* Now delete any node data...
*/
switch (node->type)
{
case MXML_ELEMENT :
if (node->value.element.name)
free(node->value.element.name);
if (node->value.element.num_attrs)
{
for (i = 0; i < node->value.element.num_attrs; i ++)
{
if (node->value.element.attrs[i].name)
free(node->value.element.attrs[i].name);
if (node->value.element.attrs[i].value)
free(node->value.element.attrs[i].value);
}
free(node->value.element.attrs);
}
break;
case MXML_INTEGER :
/* Nothing to do */
break;
case MXML_OPAQUE :
if (node->value.opaque)
free(node->value.opaque);
break;
case MXML_REAL :
/* Nothing to do */
break;
case MXML_TEXT :
if (node->value.text.string)
free(node->value.text.string);
break;
case MXML_CUSTOM :
if (node->value.custom.data &&
node->value.custom.destroy)
(*(node->value.custom.destroy))(node->value.custom.data);
break;
default :
break;
}
/*
* Free this node...
*/
free(node);
}
/*
* 'mxmlNewCDATA()' - Create a new CDATA node.
*
* The new CDATA 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
* CDATA node has no parent. The data string must be nul-terminated and
* is copied into the new node. CDATA nodes use the MXML_ELEMENT type.
*
* @since Mini-XML 2.3@
*/
mxml_node_t * /* O - New node */
mxmlNewCDATA(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
const char *data) /* I - Data string */
{
mxml_node_t *node; /* New node */
#ifdef DEBUG
fprintf(stderr, "mxmlNewCDATA(parent=%p, data=\"%s\")\n",
parent, data ? data : "(null)");
#endif /* DEBUG */
/*
* Range check input...
*/
if (!data)
return (NULL);
/*
* Create the node and set the name value...
*/
if ((node = mxml_new(parent, MXML_ELEMENT)) != NULL)
node->value.element.name = _mxml_strdupf("![CDATA[%s]]", data);
return (node);
}
/*
* '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.
*
* @since Mini-XML 2.1@
*/
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_node_t *node; /* New node */
#ifdef DEBUG
fprintf(stderr, "mxmlNewCustom(parent=%p, data=%p, destroy=%p)\n", parent,
data, destroy);
#endif /* DEBUG */
/*
* Create the node and set the value...
*/
if ((node = mxml_new(parent, MXML_CUSTOM)) != NULL)
{
node->value.custom.data = data;
node->value.custom.destroy = destroy;
}
return (node);
}
/*
* 'mxmlNewElement()' - Create a new element node.
*
* The new element 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.
*/
mxml_node_t * /* O - New node */
mxmlNewElement(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
const char *name) /* I - Name of element */
{
mxml_node_t *node; /* New node */
#ifdef DEBUG
fprintf(stderr, "mxmlNewElement(parent=%p, name=\"%s\")\n", parent,
name ? name : "(null)");
#endif /* DEBUG */
/*
* Range check input...
*/
if (!name)
return (NULL);
/*
* Create the node and set the element name...
*/
if ((node = mxml_new(parent, MXML_ELEMENT)) != NULL)
node->value.element.name = strdup(name);
return (node);
}
/*
* 'mxmlNewInteger()' - Create a new integer node.
*
* The new integer 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
* integer node has no parent.
*/
mxml_node_t * /* O - New node */
mxmlNewInteger(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
int integer) /* I - Integer value */
{
mxml_node_t *node; /* New node */
#ifdef DEBUG
fprintf(stderr, "mxmlNewInteger(parent=%p, integer=%d)\n", parent, integer);
#endif /* DEBUG */
/*
* Create the node and set the element name...
*/
if ((node = mxml_new(parent, MXML_INTEGER)) != NULL)
node->value.integer = integer;
return (node);
}
/*
* 'mxmlNewOpaque()' - Create a new opaque string.
*
* The new opaque 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
* opaque node has no parent. The opaque string must be nul-terminated and
* is copied into the new node.
*/
mxml_node_t * /* O - New node */
mxmlNewOpaque(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
const char *opaque) /* I - Opaque string */
{
mxml_node_t *node; /* New node */
#ifdef DEBUG
fprintf(stderr, "mxmlNewOpaque(parent=%p, opaque=\"%s\")\n", parent,
opaque ? opaque : "(null)");
#endif /* DEBUG */
/*
* Range check input...
*/
if (!opaque)
return (NULL);
/*
* Create the node and set the element name...
*/
if ((node = mxml_new(parent, MXML_OPAQUE)) != NULL)
node->value.opaque = strdup(opaque);
return (node);
}
/*
* 'mxmlNewReal()' - Create a new real number node.
*
* The new real number 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 real number node has no parent.
*/
mxml_node_t * /* O - New node */
mxmlNewReal(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
double real) /* I - Real number value */
{
mxml_node_t *node; /* New node */
#ifdef DEBUG
fprintf(stderr, "mxmlNewReal(parent=%p, real=%g)\n", parent, real);
#endif /* DEBUG */
/*
* Create the node and set the element name...
*/
if ((node = mxml_new(parent, MXML_REAL)) != NULL)
node->value.real = real;
return (node);
}
/*
* 'mxmlNewText()' - Create a new text fragment node.
*
* The new text 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
* text node has no parent. The whitespace parameter is used to specify
* whether leading whitespace is present before the node. The text
* string must be nul-terminated and is copied into the new node.
*/
mxml_node_t * /* O - New node */
mxmlNewText(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */
const char *string) /* I - String */
{
mxml_node_t *node; /* New node */
#ifdef DEBUG
fprintf(stderr, "mxmlNewText(parent=%p, whitespace=%d, string=\"%s\")\n",
parent, whitespace, string ? string : "(null)");
#endif /* DEBUG */
/*
* Range check input...
*/
if (!string)
return (NULL);
/*
* Create the node and set the text value...
*/
if ((node = mxml_new(parent, MXML_TEXT)) != NULL)
{
node->value.text.whitespace = whitespace;
node->value.text.string = strdup(string);
}
return (node);
}
/*
* 'mxmlNewTextf()' - Create a new formatted text fragment node.
*
* The new text 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
* text node has no parent. The whitespace parameter is used to specify
* whether leading whitespace is present before the node. The format
* string must be nul-terminated and is formatted into the new node.
*/
mxml_node_t * /* O - New node */
mxmlNewTextf(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */
const char *format, /* I - Printf-style frmat string */
...) /* I - Additional args as needed */
{
mxml_node_t *node; /* New node */
va_list ap; /* Pointer to arguments */
#ifdef DEBUG
fprintf(stderr, "mxmlNewTextf(parent=%p, whitespace=%d, format=\"%s\", ...)\n",
parent, whitespace, format ? format : "(null)");
#endif /* DEBUG */
/*
* Range check input...
*/
if (!format)
return (NULL);
/*
* Create the node and set the text value...
*/
if ((node = mxml_new(parent, MXML_TEXT)) != NULL)
{
va_start(ap, format);
node->value.text.whitespace = whitespace;
node->value.text.string = _mxml_vstrdupf(format, ap);
va_end(ap);
}
return (node);
}
/*
* 'mxmlRemove()' - Remove a node from its parent.
*
* Does not free memory used by the node - use mxmlDelete() for that.
* This function does nothing if the node has no parent.
*/
void
mxmlRemove(mxml_node_t *node) /* I - Node to remove */
{
#ifdef DEBUG
fprintf(stderr, "mxmlRemove(node=%p)\n", node);
#endif /* DEBUG */
/*
* Range check input...
*/
if (!node || !node->parent)
return;
/*
* Remove from parent...
*/
#if DEBUG > 1
fprintf(stderr, " BEFORE: node->parent=%p\n", node->parent);
if (node->parent)
{
fprintf(stderr, " BEFORE: node->parent->child=%p\n", node->parent->child);
fprintf(stderr, " BEFORE: node->parent->last_child=%p\n", node->parent->last_child);
}
fprintf(stderr, " BEFORE: node->child=%p\n", node->child);
fprintf(stderr, " BEFORE: node->last_child=%p\n", node->last_child);
fprintf(stderr, " BEFORE: node->prev=%p\n", node->prev);
fprintf(stderr, " BEFORE: node->next=%p\n", node->next);
#endif /* DEBUG > 1 */
if (node->prev)
node->prev->next = node->next;
else
node->parent->child = node->next;
if (node->next)
node->next->prev = node->prev;
else
node->parent->last_child = node->prev;
node->parent = NULL;
node->prev = NULL;
node->next = NULL;
#if DEBUG > 1
fprintf(stderr, " AFTER: node->parent=%p\n", node->parent);
if (node->parent)
{
fprintf(stderr, " AFTER: node->parent->child=%p\n", node->parent->child);
fprintf(stderr, " AFTER: node->parent->last_child=%p\n", node->parent->last_child);
}
fprintf(stderr, " AFTER: node->child=%p\n", node->child);
fprintf(stderr, " AFTER: node->last_child=%p\n", node->last_child);
fprintf(stderr, " AFTER: node->prev=%p\n", node->prev);
fprintf(stderr, " AFTER: node->next=%p\n", node->next);
#endif /* DEBUG > 1 */
}
/*
* 'mxmlNewXML()' - Create a new XML document tree.
*
* The "version" argument specifies the version number to put in the
* ?xml element node. If NULL, version 1.0 is assumed.
*
* @since Mini-XML 2.3@
*/
mxml_node_t * /* O - New ?xml node */
mxmlNewXML(const char *version) /* I - Version number to use */
{
char element[1024]; /* Element text */
snprintf(element, sizeof(element), "?xml version=\"%s\" encoding=\"utf-8\"?",
version ? version : "1.0");
return (mxmlNewElement(NULL, element));
}
/*
* 'mxmlRelease()' - Release a node.
*
* When the reference count reaches zero, the node (and any children)
* is deleted via mxmlDelete().
*
* @since Mini-XML 2.3@
*/
int /* O - New reference count */
mxmlRelease(mxml_node_t *node) /* I - Node */
{
if (node)
{
if ((-- node->ref_count) <= 0)
{
mxmlDelete(node);
return (0);
}
else
return (node->ref_count);
}
else
return (-1);
}
/*
* 'mxmlRetain()' - Retain a node.
*
* @since Mini-XML 2.3@
*/
int /* O - New reference count */
mxmlRetain(mxml_node_t *node) /* I - Node */
{
if (node)
return (++ node->ref_count);
else
return (-1);
}
/*
* 'mxml_new()' - Create a new node.
*/
static mxml_node_t * /* O - New node */
mxml_new(mxml_node_t *parent, /* I - Parent node */
mxml_type_t type) /* I - Node type */
{
mxml_node_t *node; /* New node */
#if DEBUG > 1
fprintf(stderr, "mxml_new(parent=%p, type=%d)\n", parent, type);
#endif /* DEBUG > 1 */
/*
* Allocate memory for the node...
*/
if ((node = calloc(1, sizeof(mxml_node_t))) == NULL)
{
#if DEBUG > 1
fputs(" returning NULL\n", stderr);
#endif /* DEBUG > 1 */
return (NULL);
}
#if DEBUG > 1
fprintf(stderr, " returning %p\n", node);
#endif /* DEBUG > 1 */
/*
* Set the node type...
*/
node->type = type;
node->ref_count = 1;
/*
* Add to the parent if present...
*/
if (parent)
mxmlAdd(parent, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, node);
/*
* Return the new node...
*/
return (node);
}
/*
* End of "$Id: mxml-node.c 363 2008-10-26 18:28:05Z mike $".
*/

View File

@@ -0,0 +1,285 @@
/*
* "$Id: mxml-private.c 315 2007-11-22 18:01:52Z mike $"
*
* Private functions for Mini-XML, a small XML-like file parsing library.
*
* Copyright 2003-2007 by Michael Sweet.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Contents:
*
* mxml_error() - Display an error message.
* mxml_integer_cb() - Default callback for integer values.
* mxml_opaque_cb() - Default callback for opaque values.
* mxml_real_cb() - Default callback for real number values.
* _mxml_global() - Get global data.
*/
/*
* Include necessary headers...
*/
#include "mxml-private.h"
/*
* '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)(s);
else
fprintf(stderr, "mxml: %s\n", s);
}
/*
* 'mxml_ignore_cb()' - Default callback for ignored values.
*/
mxml_type_t /* O - Node type */
mxml_ignore_cb(mxml_node_t *node) /* I - Current node */
{
(void)node;
return (MXML_IGNORE);
}
/*
* 'mxml_integer_cb()' - Default callback for integer values.
*/
mxml_type_t /* O - Node type */
mxml_integer_cb(mxml_node_t *node) /* I - Current node */
{
(void)node;
return (MXML_INTEGER);
}
/*
* 'mxml_opaque_cb()' - Default callback for opaque values.
*/
mxml_type_t /* O - Node type */
mxml_opaque_cb(mxml_node_t *node) /* I - Current node */
{
(void)node;
return (MXML_OPAQUE);
}
/*
* 'mxml_real_cb()' - Default callback for real number values.
*/
mxml_type_t /* O - Node type */
mxml_real_cb(mxml_node_t *node) /* I - Current node */
{
(void)node;
return (MXML_REAL);
}
#ifdef HAVE_PTHREAD_H /**** POSIX threading ****/
# include <pthread.h>
static pthread_key_t _mxml_key = -1; /* Thread local storage key */
static pthread_once_t _mxml_key_once = PTHREAD_ONCE_INIT;
/* One-time initialization object */
static void _mxml_init(void);
static void _mxml_destructor(void *g);
/*
* '_mxml_global()' - Get global data.
*/
_mxml_global_t * /* O - Global data */
_mxml_global(void)
{
_mxml_global_t *global; /* Global data */
pthread_once(&_mxml_key_once, _mxml_init);
if ((global = (_mxml_global_t *)pthread_getspecific(_mxml_key)) == NULL)
{
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);
}
/*
* '_mxml_init()' - Initialize global data...
*/
static void
_mxml_init(void)
{
pthread_key_create(&_mxml_key, _mxml_destructor);
}
/*
* '_mxml_destructor()' - Free memory used for globals...
*/
static void
_mxml_destructor(void *g) /* I - Global data */
{
free(g);
}
#elif defined(WIN32) /**** WIN32 threading ****/
# include <windows.h>
static DWORD _mxml_tls_index; /* Index for global storage */
/*
* 'DllMain()' - Main entry for library.
*/
BOOL WINAPI /* O - Success/failure */
DllMain(HINSTANCE hinst, /* I - DLL module handle */
DWORD reason, /* I - Reason */
LPVOID reserved) /* I - Unused */
{
_mxml_global_t *global; /* Global data */
(void)hinst;
(void)reserved;
switch (reason)
{
case DLL_PROCESS_ATTACH : /* Called on library initialization */
if ((_mxml_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES)
return (FALSE);
break;
case DLL_THREAD_DETACH : /* Called when a thread terminates */
if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)
free(global);
break;
case DLL_PROCESS_DETACH : /* Called when library is unloaded */
if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)
free(global);
TlsFree(_mxml_tls_index);
break;
default:
break;
}
return (TRUE);
}
/*
* '_mxml_global()' - Get global data.
*/
_mxml_global_t * /* O - Global data */
_mxml_global(void)
{
_mxml_global_t *global; /* Global data */
if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) == NULL)
{
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);
}
return (global);
}
#else /**** No threading ****/
/*
* '_mxml_global()' - Get global data.
*/
_mxml_global_t * /* O - Global data */
_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 */
};
return (&global);
}
#endif /* HAVE_PTHREAD_H */
/*
* End of "$Id: mxml-private.c 315 2007-11-22 18:01:52Z mike $".
*/

View File

@@ -0,0 +1,52 @@
/*
* "$Id: mxml-private.h 309 2007-09-21 04:46:02Z mike $"
*
* Private definitions for Mini-XML, a small XML-like file parsing library.
*
* Copyright 2007 by Michael Sweet.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/*
* Include necessary headers...
*/
#include "config.h"
#include "mxml.h"
/*
* Global, per-thread data...
*/
typedef struct _mxml_global_s
{
void (*error_cb)(const char *);
int num_entity_cbs;
int (*entity_cbs[100])(const char *name);
int wrap;
mxml_custom_load_cb_t custom_load_cb;
mxml_custom_save_cb_t custom_save_cb;
} _mxml_global_t;
/*
* Functions...
*/
extern _mxml_global_t *_mxml_global(void);
extern int _mxml_entity_cb(const char *name);
/*
* End of "$Id: mxml-private.h 309 2007-09-21 04:46:02Z mike $".
*/

View File

@@ -0,0 +1,201 @@
/*
* "$Id: mxml-search.c 297 2007-09-09 07:16:52Z mike $"
*
* Search/navigation functions for Mini-XML, a small XML-like file
* parsing library.
*
* Copyright 2003-2007 by Michael Sweet.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Contents:
*
* mxmlFindElement() - Find the named element.
* mxmlWalkNext() - Walk to the next logical node in the tree.
* mxmlWalkPrev() - Walk to the previous logical node in the tree.
*/
/*
* Include necessary headers...
*/
#include "config.h"
#include "mxml.h"
/*
* 'mxmlFindElement()' - Find the named element.
*
* The search is constrained by the name, attribute name, and value; any
* NULL names or values are treated as wildcards, so different kinds of
* searches can be implemented by looking for all elements of a given name
* or all elements with a specific attribute. The descend argument determines
* whether the search descends into child nodes; normally you will use
* MXML_DESCEND_FIRST for the initial search and MXML_NO_DESCEND to find
* additional direct descendents of the node. The top node argument
* constrains the search to a particular node's children.
*/
mxml_node_t * /* O - Element node or NULL */
mxmlFindElement(mxml_node_t *node, /* I - Current node */
mxml_node_t *top, /* I - Top node */
const char *name, /* I - Element name or NULL for any */
const char *attr, /* I - Attribute name, or NULL for none */
const char *value, /* I - Attribute value, or NULL for any */
int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */
{
const char *temp; /* Current attribute value */
/*
* Range check input...
*/
if (!node || !top || (!attr && value))
return (NULL);
/*
* Start with the next node...
*/
node = mxmlWalkNext(node, top, descend);
/*
* Loop until we find a matching element...
*/
while (node != NULL)
{
/*
* See if this node matches...
*/
if (node->type == MXML_ELEMENT &&
node->value.element.name &&
(!name || !strcmp(node->value.element.name, name)))
{
/*
* See if we need to check for an attribute...
*/
if (!attr)
return (node); /* No attribute search, return it... */
/*
* Check for the attribute...
*/
if ((temp = mxmlElementGetAttr(node, attr)) != NULL)
{
/*
* OK, we have the attribute, does it match?
*/
if (!value || !strcmp(value, temp))
return (node); /* Yes, return it... */
}
}
/*
* No match, move on to the next node...
*/
if (descend == MXML_DESCEND)
node = mxmlWalkNext(node, top, MXML_DESCEND);
else
node = node->next;
}
return (NULL);
}
/*
* 'mxmlWalkNext()' - Walk to the next logical node in the tree.
*
* The descend argument controls whether the first child is considered
* to be the next node. The top node argument constrains the walk to
* the node's children.
*/
mxml_node_t * /* O - Next node or NULL */
mxmlWalkNext(mxml_node_t *node, /* I - Current node */
mxml_node_t *top, /* I - Top node */
int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */
{
if (!node)
return (NULL);
else if (node->child && descend)
return (node->child);
else if (node == top)
return (NULL);
else if (node->next)
return (node->next);
else if (node->parent && node->parent != top)
{
node = node->parent;
while (!node->next)
if (node->parent == top || !node->parent)
return (NULL);
else
node = node->parent;
return (node->next);
}
else
return (NULL);
}
/*
* 'mxmlWalkPrev()' - Walk to the previous logical node in the tree.
*
* The descend argument controls whether the previous node's last child
* is considered to be the previous node. The top node argument constrains
* the walk to the node's children.
*/
mxml_node_t * /* O - Previous node or NULL */
mxmlWalkPrev(mxml_node_t *node, /* I - Current node */
mxml_node_t *top, /* I - Top node */
int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */
{
if (!node || node == top)
return (NULL);
else if (node->prev)
{
if (node->prev->last_child && descend)
{
/*
* Find the last child under the previous node...
*/
node = node->prev->last_child;
while (node->last_child)
node = node->last_child;
return (node);
}
else
return (node->prev);
}
else if (node->parent != top)
return (node->parent);
else
return (NULL);
}
/*
* End of "$Id: mxml-search.c 297 2007-09-09 07:16:52Z mike $".
*/

View File

@@ -0,0 +1,294 @@
/*
* "$Id: mxml-set.c 270 2007-04-23 21:48:03Z mike $"
*
* Node set functions for Mini-XML, a small XML-like file parsing library.
*
* Copyright 2003-2007 by Michael Sweet.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Contents:
*
* mxmlSetCustom() - Set the data and destructor of a custom data node.
* mxmlSetCDATA() - Set the element name of a CDATA node.
* mxmlSetElement() - Set the name of an element node.
* mxmlSetInteger() - Set the value of an integer node.
* mxmlSetOpaque() - Set the value of an opaque node.
* mxmlSetReal() - Set the value of a real number node.
* mxmlSetText() - Set the value of a text node.
* mxmlSetTextf() - Set the value of a text node to a formatted string.
*/
/*
* Include necessary headers...
*/
#include "config.h"
#include "mxml.h"
/*
* 'mxmlSetCustom()' - Set the data and destructor of a custom data node.
*
* The node is not changed if it is not a custom node.
*
* @since Mini-XML 2.1@
*/
int /* O - 0 on success, -1 on failure */
mxmlSetCustom(
mxml_node_t *node, /* I - Node to set */
void *data, /* I - New data pointer */
mxml_custom_destroy_cb_t destroy) /* I - New destructor function */
{
/*
* Range check input...
*/
if (!node || node->type != MXML_CUSTOM)
return (-1);
/*
* 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);
node->value.custom.data = data;
node->value.custom.destroy = destroy;
return (0);
}
/*
* 'mxmlSetCDATA()' - Set the element name of a CDATA node.
*
* The node is not changed if it is not a CDATA element node.
*
* @since Mini-XML 2.3@
*/
int /* O - 0 on success, -1 on failure */
mxmlSetCDATA(mxml_node_t *node, /* I - Node to set */
const char *data) /* I - New data string */
{
/*
* Range check input...
*/
if (!node || node->type != MXML_ELEMENT || !data ||
strncmp(node->value.element.name, "![CDATA[", 8))
return (-1);
/*
* Free any old element value and set the new value...
*/
if (node->value.element.name)
free(node->value.element.name);
node->value.element.name = _mxml_strdupf("![CDATA[%s]]", data);
return (0);
}
/*
* 'mxmlSetElement()' - Set the name of an element node.
*
* The node is not changed if it is not an element node.
*/
int /* O - 0 on success, -1 on failure */
mxmlSetElement(mxml_node_t *node, /* I - Node to set */
const char *name) /* I - New name string */
{
/*
* Range check input...
*/
if (!node || node->type != MXML_ELEMENT || !name)
return (-1);
/*
* Free any old element value and set the new value...
*/
if (node->value.element.name)
free(node->value.element.name);
node->value.element.name = strdup(name);
return (0);
}
/*
* 'mxmlSetInteger()' - Set the value of an integer node.
*
* The node is not changed if it is not an integer node.
*/
int /* O - 0 on success, -1 on failure */
mxmlSetInteger(mxml_node_t *node, /* I - Node to set */
int integer) /* I - Integer value */
{
/*
* Range check input...
*/
if (!node || node->type != MXML_INTEGER)
return (-1);
/*
* Set the new value and return...
*/
node->value.integer = integer;
return (0);
}
/*
* 'mxmlSetOpaque()' - Set the value of an opaque node.
*
* The node is not changed if it is not an opaque node.
*/
int /* O - 0 on success, -1 on failure */
mxmlSetOpaque(mxml_node_t *node, /* I - Node to set */
const char *opaque) /* I - Opaque string */
{
/*
* Range check input...
*/
if (!node || node->type != MXML_OPAQUE || !opaque)
return (-1);
/*
* Free any old opaque value and set the new value...
*/
if (node->value.opaque)
free(node->value.opaque);
node->value.opaque = strdup(opaque);
return (0);
}
/*
* 'mxmlSetReal()' - Set the value of a real number node.
*
* The node is not changed if it is not a real number node.
*/
int /* O - 0 on success, -1 on failure */
mxmlSetReal(mxml_node_t *node, /* I - Node to set */
double real) /* I - Real number value */
{
/*
* Range check input...
*/
if (!node || node->type != MXML_REAL)
return (-1);
/*
* Set the new value and return...
*/
node->value.real = real;
return (0);
}
/*
* 'mxmlSetText()' - Set the value of a text node.
*
* The node is not changed if it is not a text node.
*/
int /* O - 0 on success, -1 on failure */
mxmlSetText(mxml_node_t *node, /* I - Node to set */
int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */
const char *string) /* I - String */
{
/*
* Range check input...
*/
if (!node || node->type != MXML_TEXT || !string)
return (-1);
/*
* Free any old string value and set the new value...
*/
if (node->value.text.string)
free(node->value.text.string);
node->value.text.whitespace = whitespace;
node->value.text.string = strdup(string);
return (0);
}
/*
* 'mxmlSetTextf()' - Set the value of a text node to a formatted string.
*
* The node is not changed if it is not a text node.
*/
int /* O - 0 on success, -1 on failure */
mxmlSetTextf(mxml_node_t *node, /* I - Node to set */
int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */
const char *format, /* I - Printf-style format string */
...) /* I - Additional arguments as needed */
{
va_list ap; /* Pointer to arguments */
/*
* Range check input...
*/
if (!node || node->type != MXML_TEXT || !format)
return (-1);
/*
* Free any old string value and set the new value...
*/
if (node->value.text.string)
free(node->value.text.string);
va_start(ap, format);
node->value.text.whitespace = whitespace;
node->value.text.string = _mxml_strdupf(format, ap);
va_end(ap);
return (0);
}
/*
* End of "$Id: mxml-set.c 270 2007-04-23 21:48:03Z mike $".
*/

View File

@@ -0,0 +1,462 @@
/*
* "$Id: mxml-string.c 387 2009-04-18 17:05:52Z mike $"
*
* String functions for Mini-XML, a small XML-like file parsing library.
*
* Copyright 2003-2009 by Michael Sweet.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Contents:
*
* _mxml_snprintf() - Format a string.
* _mxml_strdup() - Duplicate a string.
* _mxml_strdupf() - Format and duplicate a string.
* _mxml_vsnprintf() - Format a string into a fixed size buffer.
* _mxml_vstrdupf() - Format and duplicate a string.
*/
/*
* Include necessary headers...
*/
#include "config.h"
#ifndef HAVE_SNPRINTF
/*
* '_mxml_snprintf()' - Format a string.
*/
int /* O - Number of bytes formatted */
_mxml_snprintf(char *buffer, /* I - Output buffer */
size_t bufsize, /* I - Size of output buffer */
const char *format, /* I - Printf-style format string */
...) /* I - Additional arguments as needed */
{
va_list ap; /* Argument list */
int bytes; /* Number of bytes formatted */
va_start(ap, format);
bytes = vsnprintf(buffer, bufsize, format, ap);
va_end(ap);
return (bytes);
}
#endif /* !HAVE_SNPRINTF */
/*
* '_mxml_strdup()' - Duplicate a string.
*/
#ifndef HAVE_STRDUP
char * /* O - New string pointer */
_mxml_strdup(const char *s) /* I - String to duplicate */
{
char *t; /* New string pointer */
if (s == NULL)
return (NULL);
if ((t = malloc(strlen(s) + 1)) == NULL)
return (NULL);
return (strcpy(t, s));
}
#endif /* !HAVE_STRDUP */
/*
* '_mxml_strdupf()' - Format and duplicate a string.
*/
char * /* O - New string pointer */
_mxml_strdupf(const char *format, /* I - Printf-style format string */
...) /* I - Additional arguments as needed */
{
va_list ap; /* Pointer to additional arguments */
char *s; /* Pointer to formatted string */
/*
* Get a pointer to the additional arguments, format the string,
* and return it...
*/
va_start(ap, format);
s = _mxml_vstrdupf(format, ap);
va_end(ap);
return (s);
}
#ifndef HAVE_VSNPRINTF
/*
* '_mxml_vsnprintf()' - Format a string into a fixed size buffer.
*/
int /* O - Number of bytes formatted */
_mxml_vsnprintf(char *buffer, /* O - Output buffer */
size_t bufsize, /* O - Size of output buffer */
const char *format, /* I - Printf-style format string */
va_list ap) /* I - Pointer to additional arguments */
{
char *bufptr, /* Pointer to position in buffer */
*bufend, /* Pointer to end of buffer */
sign, /* Sign of format width */
size, /* Size character (h, l, L) */
type; /* Format type character */
int width, /* Width of field */
prec; /* Number of characters of precision */
char tformat[100], /* Temporary format string for sprintf() */
*tptr, /* Pointer into temporary format */
temp[1024]; /* Buffer for formatted numbers */
char *s; /* Pointer to string */
int slen; /* Length of string */
int bytes; /* Total number of bytes needed */
/*
* Loop through the format string, formatting as needed...
*/
bufptr = buffer;
bufend = buffer + bufsize - 1;
bytes = 0;
while (*format)
{
if (*format == '%')
{
tptr = tformat;
*tptr++ = *format++;
if (*format == '%')
{
if (bufptr && bufptr < bufend) *bufptr++ = *format;
bytes ++;
format ++;
continue;
}
else if (strchr(" -+#\'", *format))
{
*tptr++ = *format;
sign = *format++;
}
else
sign = 0;
if (*format == '*')
{
/*
* Get width from argument...
*/
format ++;
width = va_arg(ap, int);
snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
tptr += strlen(tptr);
}
else
{
width = 0;
while (isdigit(*format & 255))
{
if (tptr < (tformat + sizeof(tformat) - 1))
*tptr++ = *format;
width = width * 10 + *format++ - '0';
}
}
if (*format == '.')
{
if (tptr < (tformat + sizeof(tformat) - 1))
*tptr++ = *format;
format ++;
if (*format == '*')
{
/*
* Get precision from argument...
*/
format ++;
prec = va_arg(ap, int);
snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
tptr += strlen(tptr);
}
else
{
prec = 0;
while (isdigit(*format & 255))
{
if (tptr < (tformat + sizeof(tformat) - 1))
*tptr++ = *format;
prec = prec * 10 + *format++ - '0';
}
}
}
else
prec = -1;
if (*format == 'l' && format[1] == 'l')
{
size = 'L';
if (tptr < (tformat + sizeof(tformat) - 2))
{
*tptr++ = 'l';
*tptr++ = 'l';
}
format += 2;
}
else if (*format == 'h' || *format == 'l' || *format == 'L')
{
if (tptr < (tformat + sizeof(tformat) - 1))
*tptr++ = *format;
size = *format++;
}
if (!*format)
break;
if (tptr < (tformat + sizeof(tformat) - 1))
*tptr++ = *format;
type = *format++;
*tptr = '\0';
switch (type)
{
case 'E' : /* Floating point formats */
case 'G' :
case 'e' :
case 'f' :
case 'g' :
if ((width + 2) > sizeof(temp))
break;
sprintf(temp, tformat, va_arg(ap, double));
bytes += strlen(temp);
if (bufptr)
{
if ((bufptr + strlen(temp)) > bufend)
{
strncpy(bufptr, temp, (size_t)(bufend - bufptr));
bufptr = bufend;
}
else
{
strcpy(bufptr, temp);
bufptr += strlen(temp);
}
}
break;
case 'B' : /* Integer formats */
case 'X' :
case 'b' :
case 'd' :
case 'i' :
case 'o' :
case 'u' :
case 'x' :
if ((width + 2) > sizeof(temp))
break;
#ifdef HAVE_LONG_LONG
if (size == 'L')
sprintf(temp, tformat, va_arg(ap, long long));
else
#endif /* HAVE_LONG_LONG */
sprintf(temp, tformat, va_arg(ap, int));
bytes += strlen(temp);
if (bufptr)
{
if ((bufptr + strlen(temp)) > bufend)
{
strncpy(bufptr, temp, (size_t)(bufend - bufptr));
bufptr = bufend;
}
else
{
strcpy(bufptr, temp);
bufptr += strlen(temp);
}
}
break;
case 'p' : /* Pointer value */
if ((width + 2) > sizeof(temp))
break;
sprintf(temp, tformat, va_arg(ap, void *));
bytes += strlen(temp);
if (bufptr)
{
if ((bufptr + strlen(temp)) > bufend)
{
strncpy(bufptr, temp, (size_t)(bufend - bufptr));
bufptr = bufend;
}
else
{
strcpy(bufptr, temp);
bufptr += strlen(temp);
}
}
break;
case 'c' : /* Character or character array */
bytes += width;
if (bufptr)
{
if (width <= 1)
*bufptr++ = va_arg(ap, int);
else
{
if ((bufptr + width) > bufend)
width = bufend - bufptr;
memcpy(bufptr, va_arg(ap, char *), (size_t)width);
bufptr += width;
}
}
break;
case 's' : /* String */
if ((s = va_arg(ap, char *)) == NULL)
s = "(null)";
slen = strlen(s);
if (slen > width && prec != width)
width = slen;
bytes += width;
if (bufptr)
{
if ((bufptr + width) > bufend)
width = bufend - bufptr;
if (slen > width)
slen = width;
if (sign == '-')
{
strncpy(bufptr, s, (size_t)slen);
memset(bufptr + slen, ' ', (size_t)(width - slen));
}
else
{
memset(bufptr, ' ', (size_t)(width - slen));
strncpy(bufptr + width - slen, s, (size_t)slen);
}
bufptr += width;
}
break;
case 'n' : /* Output number of chars so far */
*(va_arg(ap, int *)) = bytes;
break;
}
}
else
{
bytes ++;
if (bufptr && bufptr < bufend)
*bufptr++ = *format;
format ++;
}
}
/*
* Nul-terminate the string and return the number of characters needed.
*/
*bufptr = '\0';
return (bytes);
}
#endif /* !HAVE_VSNPRINTF */
/*
* '_mxml_vstrdupf()' - Format and duplicate a string.
*/
char * /* O - New string pointer */
_mxml_vstrdupf(const char *format, /* I - Printf-style format string */
va_list ap) /* I - Pointer to additional arguments */
{
int bytes; /* Number of bytes required */
char *buffer, /* String buffer */
temp[256]; /* Small buffer for first vsnprintf */
/*
* First format with a tiny buffer; this will tell us how many bytes are
* needed...
*/
bytes = vsnprintf(temp, sizeof(temp), format, ap);
if (bytes < sizeof(temp))
{
/*
* Hey, the formatted string fits in the tiny buffer, so just dup that...
*/
return (strdup(temp));
}
/*
* Allocate memory for the whole thing and reformat to the new, larger
* buffer...
*/
if ((buffer = calloc(1, bytes + 1)) != NULL)
vsnprintf(buffer, bytes + 1, format, ap);
/*
* Return the new string...
*/
return (buffer);
}
/*
* End of "$Id: mxml-string.c 387 2009-04-18 17:05:52Z mike $".
*/