2003-06-03 19:46:29 +00:00
|
|
|
|
/*
|
2017-03-22 18:51:16 +00:00
|
|
|
|
* Attribute support code for Mini-XML, a small XML file parsing library.
|
2003-06-03 19:46:29 +00:00
|
|
|
|
*
|
2019-01-05 01:44:51 +00:00
|
|
|
|
* https://www.msweet.org/mxml
|
2003-06-03 19:46:29 +00:00
|
|
|
|
*
|
2021-10-26 18:50:25 +00:00
|
|
|
|
* Copyright © 2003-2021 by Michael R Sweet.
|
2003-06-03 19:46:29 +00:00
|
|
|
|
*
|
2019-01-05 01:44:51 +00:00
|
|
|
|
* Licensed under Apache License v2.0. See the file "LICENSE" for more
|
|
|
|
|
* information.
|
2003-06-03 19:46:29 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Include necessary headers...
|
|
|
|
|
*/
|
|
|
|
|
|
2003-07-20 13:41:17 +00:00
|
|
|
|
#include "config.h"
|
2019-01-05 01:02:48 +00:00
|
|
|
|
#include "mxml-private.h"
|
2003-06-03 19:46:29 +00:00
|
|
|
|
|
|
|
|
|
|
2007-04-18 14:55:08 +00:00
|
|
|
|
/*
|
|
|
|
|
* Local functions...
|
|
|
|
|
*/
|
|
|
|
|
|
2019-01-05 01:02:48 +00:00
|
|
|
|
static int mxml_set_attr(mxml_node_t *node, const char *name, char *value);
|
2007-04-18 14:55:08 +00:00
|
|
|
|
|
|
|
|
|
|
2007-09-15 20:03:15 +00:00
|
|
|
|
/*
|
|
|
|
|
* '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 */
|
2019-01-05 01:02:48 +00:00
|
|
|
|
_mxml_attr_t *attr; /* Cirrent attribute */
|
2007-09-15 20:03:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#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)
|
2019-01-05 01:02:48 +00:00
|
|
|
|
memmove(attr, attr + 1, i * sizeof(_mxml_attr_t));
|
2007-09-15 20:03:15 +00:00
|
|
|
|
|
|
|
|
|
node->value.element.num_attrs --;
|
2013-11-12 04:29:23 +00:00
|
|
|
|
|
|
|
|
|
if (node->value.element.num_attrs == 0)
|
|
|
|
|
free(node->value.element.attrs);
|
2007-09-15 20:03:15 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-06-03 19:46:29 +00:00
|
|
|
|
/*
|
|
|
|
|
* 'mxmlElementGetAttr()' - Get an attribute.
|
2003-06-14 23:56:47 +00:00
|
|
|
|
*
|
2017-04-24 14:42:03 +00:00
|
|
|
|
* This function returns @code NULL@ if the node is not an element or the
|
2003-06-14 23:56:47 +00:00
|
|
|
|
* named attribute does not exist.
|
2003-06-03 19:46:29 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2017-04-24 14:42:03 +00:00
|
|
|
|
const char * /* O - Attribute value or @code NULL@ */
|
2003-06-03 19:46:29 +00:00
|
|
|
|
mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */
|
|
|
|
|
const char *name) /* I - Name of attribute */
|
|
|
|
|
{
|
2007-09-15 20:03:15 +00:00
|
|
|
|
int i; /* Looping var */
|
2019-01-05 01:02:48 +00:00
|
|
|
|
_mxml_attr_t *attr; /* Cirrent attribute */
|
2003-06-03 19:46:29 +00:00
|
|
|
|
|
|
|
|
|
|
2003-12-03 03:59:04 +00:00
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
fprintf(stderr, "mxmlElementGetAttr(node=%p, name=\"%s\")\n",
|
|
|
|
|
node, name ? name : "(null)");
|
|
|
|
|
#endif /* DEBUG */
|
|
|
|
|
|
2003-06-03 19:46:29 +00:00
|
|
|
|
/*
|
|
|
|
|
* 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 ++)
|
2005-06-09 13:20:57 +00:00
|
|
|
|
{
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
printf(" %s=\"%s\"\n", attr->name, attr->value);
|
|
|
|
|
#endif /* DEBUG */
|
|
|
|
|
|
2003-06-03 19:46:29 +00:00
|
|
|
|
if (!strcmp(attr->name, name))
|
2005-06-09 13:20:57 +00:00
|
|
|
|
{
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
printf(" Returning \"%s\"!\n", attr->value);
|
|
|
|
|
#endif /* DEBUG */
|
2003-06-03 19:46:29 +00:00
|
|
|
|
return (attr->value);
|
2005-06-09 13:20:57 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2003-06-03 19:46:29 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Didn't find attribute, so return NULL...
|
|
|
|
|
*/
|
|
|
|
|
|
2005-06-09 13:20:57 +00:00
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
puts(" Returning NULL!\n");
|
|
|
|
|
#endif /* DEBUG */
|
|
|
|
|
|
2003-06-03 19:46:29 +00:00
|
|
|
|
return (NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-04-23 17:12:39 +00:00
|
|
|
|
/*
|
|
|
|
|
* 'mxmlElementGetAttrByIndex()' - Get an element attribute by index.
|
|
|
|
|
*
|
|
|
|
|
* The index ("idx") is 0-based. @code NULL@ is returned if the specified index
|
|
|
|
|
* is out of range.
|
|
|
|
|
*
|
|
|
|
|
* @since Mini-XML 2.11@
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
const char * /* O - Attribute value */
|
|
|
|
|
mxmlElementGetAttrByIndex(
|
|
|
|
|
mxml_node_t *node, /* I - Node */
|
|
|
|
|
int idx, /* I - Attribute index, starting at 0 */
|
|
|
|
|
const char **name) /* O - Attribute name */
|
|
|
|
|
{
|
|
|
|
|
if (!node || node->type != MXML_ELEMENT || idx < 0 || idx >= node->value.element.num_attrs)
|
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
|
|
if (name)
|
|
|
|
|
*name = node->value.element.attrs[idx].name;
|
|
|
|
|
|
|
|
|
|
return (node->value.element.attrs[idx].value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 'mxmlElementGetAttrCount()' - Get the number of element attributes.
|
|
|
|
|
*
|
|
|
|
|
* @since Mini-XML 2.11@
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int /* O - Number of attributes */
|
|
|
|
|
mxmlElementGetAttrCount(
|
|
|
|
|
mxml_node_t *node) /* I - Node */
|
|
|
|
|
{
|
|
|
|
|
if (node && node->type == MXML_ELEMENT)
|
|
|
|
|
return (node->value.element.num_attrs);
|
|
|
|
|
else
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-06-03 19:46:29 +00:00
|
|
|
|
/*
|
|
|
|
|
* 'mxmlElementSetAttr()' - Set an attribute.
|
2003-06-14 23:56:47 +00:00
|
|
|
|
*
|
|
|
|
|
* 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.
|
2003-06-03 19:46:29 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */
|
|
|
|
|
const char *name, /* I - Name of attribute */
|
|
|
|
|
const char *value) /* I - Attribute value */
|
|
|
|
|
{
|
2007-04-18 14:55:08 +00:00
|
|
|
|
char *valuec; /* Copy of value */
|
2003-06-03 19:46:29 +00:00
|
|
|
|
|
|
|
|
|
|
2003-12-03 03:59:04 +00:00
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
fprintf(stderr, "mxmlElementSetAttr(node=%p, name=\"%s\", value=\"%s\")\n",
|
|
|
|
|
node, name ? name : "(null)", value ? value : "(null)");
|
|
|
|
|
#endif /* DEBUG */
|
|
|
|
|
|
2003-06-03 19:46:29 +00:00
|
|
|
|
/*
|
|
|
|
|
* Range check input...
|
|
|
|
|
*/
|
|
|
|
|
|
2003-12-01 15:27:47 +00:00
|
|
|
|
if (!node || node->type != MXML_ELEMENT || !name)
|
2003-06-03 19:46:29 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2007-04-18 14:55:08 +00:00
|
|
|
|
if (value)
|
2021-10-26 19:11:00 +00:00
|
|
|
|
{
|
|
|
|
|
if ((valuec = strdup(value)) == NULL)
|
|
|
|
|
{
|
|
|
|
|
mxml_error("Unable to allocate memory for attribute '%s' in element %s.", name, node->value.element.name);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-04-18 14:55:08 +00:00
|
|
|
|
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.
|
2007-04-23 21:48:03 +00:00
|
|
|
|
*
|
|
|
|
|
* @since Mini-XML 2.3@
|
2007-04-18 14:55:08 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
2007-09-15 20:04:56 +00:00
|
|
|
|
if (!value)
|
2021-10-26 19:11:00 +00:00
|
|
|
|
mxml_error("Unable to allocate memory for attribute '%s' in element %s.",
|
2007-04-18 14:55:08 +00:00
|
|
|
|
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 */
|
2019-01-05 01:02:48 +00:00
|
|
|
|
_mxml_attr_t *attr; /* New attribute */
|
2007-04-18 14:55:08 +00:00
|
|
|
|
|
|
|
|
|
|
2003-06-03 19:46:29 +00:00
|
|
|
|
/*
|
|
|
|
|
* 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))
|
|
|
|
|
{
|
|
|
|
|
/*
|
2007-04-18 14:55:08 +00:00
|
|
|
|
* Free the old value as needed...
|
2003-06-03 19:46:29 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2021-10-26 18:50:25 +00:00
|
|
|
|
free(attr->value);
|
2007-04-18 14:55:08 +00:00
|
|
|
|
attr->value = value;
|
2003-06-03 19:46:29 +00:00
|
|
|
|
|
2007-04-18 14:55:08 +00:00
|
|
|
|
return (0);
|
2003-06-03 19:46:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2007-04-18 14:55:08 +00:00
|
|
|
|
* Add a new attribute...
|
2003-06-03 19:46:29 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (node->value.element.num_attrs == 0)
|
2019-01-05 01:02:48 +00:00
|
|
|
|
attr = malloc(sizeof(_mxml_attr_t));
|
2003-06-03 19:46:29 +00:00
|
|
|
|
else
|
|
|
|
|
attr = realloc(node->value.element.attrs,
|
2019-01-05 01:02:48 +00:00
|
|
|
|
(node->value.element.num_attrs + 1) * sizeof(_mxml_attr_t));
|
2003-06-03 19:46:29 +00:00
|
|
|
|
|
|
|
|
|
if (!attr)
|
|
|
|
|
{
|
2021-10-26 19:11:00 +00:00
|
|
|
|
mxml_error("Unable to allocate memory for attribute '%s' in element %s.",
|
2003-12-03 03:59:04 +00:00
|
|
|
|
name, node->value.element.name);
|
2007-04-18 14:55:08 +00:00
|
|
|
|
return (-1);
|
2003-06-03 19:46:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
node->value.element.attrs = attr;
|
|
|
|
|
attr += node->value.element.num_attrs;
|
|
|
|
|
|
2007-04-18 14:55:08 +00:00
|
|
|
|
if ((attr->name = strdup(name)) == NULL)
|
2003-06-03 19:46:29 +00:00
|
|
|
|
{
|
2021-10-26 19:11:00 +00:00
|
|
|
|
mxml_error("Unable to allocate memory for attribute '%s' in element %s.",
|
2003-12-03 03:59:04 +00:00
|
|
|
|
name, node->value.element.name);
|
2007-04-18 14:55:08 +00:00
|
|
|
|
return (-1);
|
2003-06-03 19:46:29 +00:00
|
|
|
|
}
|
2007-04-18 14:55:08 +00:00
|
|
|
|
|
|
|
|
|
attr->value = value;
|
|
|
|
|
|
2003-06-03 19:46:29 +00:00
|
|
|
|
node->value.element.num_attrs ++;
|
2007-04-18 14:55:08 +00:00
|
|
|
|
|
|
|
|
|
return (0);
|
2003-06-03 19:46:29 +00:00
|
|
|
|
}
|