2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
|
|
|
|
// Attribute 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.
|
|
|
|
|
//
|
|
|
|
|
|
2019-01-05 01:02:48 +00:00
|
|
|
|
#include "mxml-private.h"
|
2003-06-03 19:46:29 +00:00
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
|
|
|
|
// Local functions...
|
|
|
|
|
//
|
2007-04-18 14:55:08 +00:00
|
|
|
|
|
2024-03-02 23:47:57 +00:00
|
|
|
|
static bool mxml_set_attr(mxml_node_t *node, const char *name, char *value);
|
2007-04-18 14:55:08 +00:00
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
2024-03-17 02:20:24 +00:00
|
|
|
|
// 'mxmlElementClearAttr()' - Remove an attribute from an element.
|
|
|
|
|
//
|
|
|
|
|
// This function removes the attribute `name` from the element `node`.
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
2007-09-15 20:03:15 +00:00
|
|
|
|
|
|
|
|
|
void
|
2024-03-13 13:59:47 +00:00
|
|
|
|
mxmlElementClearAttr(mxml_node_t *node, // I - Element
|
|
|
|
|
const char *name) // I - Attribute name
|
2007-09-15 20:03:15 +00:00
|
|
|
|
{
|
2024-03-02 23:47:57 +00:00
|
|
|
|
size_t i; // Looping var
|
2024-02-27 20:04:27 +00:00
|
|
|
|
_mxml_attr_t *attr; // Cirrent attribute
|
2007-09-15 20:03:15 +00:00
|
|
|
|
|
|
|
|
|
|
2024-03-13 13:59:47 +00:00
|
|
|
|
MXML_DEBUG("mxmlElementClearAttr(node=%p, name=\"%s\")\n", node, name ? name : "(null)");
|
2007-09-15 20:03:15 +00:00
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
// Range check input...
|
|
|
|
|
if (!node || node->type != MXML_TYPE_ELEMENT || !name)
|
2007-09-15 20:03:15 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
// Look for the attribute...
|
|
|
|
|
for (i = node->value.element.num_attrs, attr = node->value.element.attrs; i > 0; i --, attr ++)
|
2007-09-15 20:03:15 +00:00
|
|
|
|
{
|
2024-03-13 13:59:47 +00:00
|
|
|
|
MXML_DEBUG("mxmlElementClearAttr: %s=\"%s\"\n", attr->name, attr->value);
|
2007-09-15 20:03:15 +00:00
|
|
|
|
|
|
|
|
|
if (!strcmp(attr->name, name))
|
|
|
|
|
{
|
2024-02-27 20:04:27 +00:00
|
|
|
|
// Delete this attribute...
|
2024-03-07 19:06:50 +00:00
|
|
|
|
_mxml_strfree(attr->name);
|
|
|
|
|
_mxml_strfree(attr->value);
|
2007-09-15 20:03:15 +00:00
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
2024-03-17 02:20:24 +00:00
|
|
|
|
// 'mxmlElementGetAttr()' - Get the value of an attribute.
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
2024-03-17 02:20:24 +00:00
|
|
|
|
// This function gets the value for the attribute `name` from the element
|
|
|
|
|
// `node`. `NULL` is returned if the node is not an element or the named
|
|
|
|
|
// attribute does not exist.
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
2003-06-03 19:46:29 +00:00
|
|
|
|
|
2024-03-17 02:20:24 +00:00
|
|
|
|
const char * // O - Attribute value or `NULL`
|
2024-02-27 20:04:27 +00:00
|
|
|
|
mxmlElementGetAttr(mxml_node_t *node, // I - Element node
|
|
|
|
|
const char *name) // I - Name of attribute
|
2003-06-03 19:46:29 +00:00
|
|
|
|
{
|
2024-03-02 23:47:57 +00:00
|
|
|
|
size_t i; // Looping var
|
2024-02-27 20:04:27 +00:00
|
|
|
|
_mxml_attr_t *attr; // Cirrent attribute
|
2003-06-03 19:46:29 +00:00
|
|
|
|
|
2003-12-03 03:59:04 +00:00
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
MXML_DEBUG("mxmlElementGetAttr(node=%p, name=\"%s\")\n", node, name ? name : "(null)");
|
2003-06-03 19:46:29 +00:00
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
// Range check input...
|
|
|
|
|
if (!node || node->type != MXML_TYPE_ELEMENT || !name)
|
2003-06-03 19:46:29 +00:00
|
|
|
|
return (NULL);
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
// 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
|
|
|
|
{
|
2024-02-27 20:04:27 +00:00
|
|
|
|
MXML_DEBUG("mxmlElementGetAttr: %s=\"%s\"\n", attr->name, attr->value);
|
2005-06-09 13:20:57 +00:00
|
|
|
|
|
2003-06-03 19:46:29 +00:00
|
|
|
|
if (!strcmp(attr->name, name))
|
2005-06-09 13:20:57 +00:00
|
|
|
|
{
|
2024-02-27 20:04:27 +00:00
|
|
|
|
MXML_DEBUG("mxmlElementGetAttr: Returning \"%s\".\n", attr->value);
|
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
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
// Didn't find attribute, so return NULL...
|
|
|
|
|
MXML_DEBUG("mxmlElementGetAttr: Returning NULL.\n");
|
2005-06-09 13:20:57 +00:00
|
|
|
|
|
2003-06-03 19:46:29 +00:00
|
|
|
|
return (NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
2024-03-17 02:20:24 +00:00
|
|
|
|
// 'mxmlElementGetAttrByIndex()' - Get an attribute by index.
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
2024-03-17 02:20:24 +00:00
|
|
|
|
// This function returned the Nth (`idx`) attribute for element `node`. The
|
|
|
|
|
// attribute name is optionallly returned in the `name` argument. `NULL` is
|
|
|
|
|
// returned if node is not an element or the specified index is out of range.
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
2017-04-23 17:12:39 +00:00
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
const char * // O - Attribute value
|
2017-04-23 17:12:39 +00:00
|
|
|
|
mxmlElementGetAttrByIndex(
|
2024-03-19 15:22:41 +00:00
|
|
|
|
mxml_node_t *node, // I - Node
|
|
|
|
|
size_t idx, // I - Attribute index, starting at `0`
|
|
|
|
|
const char **name) // O - Attribute name or `NULL` to not return it
|
2017-04-23 17:12:39 +00:00
|
|
|
|
{
|
2024-03-19 15:22:41 +00:00
|
|
|
|
if (!node || node->type != MXML_TYPE_ELEMENT || idx >= node->value.element.num_attrs)
|
2017-04-23 17:12:39 +00:00
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
|
|
if (name)
|
|
|
|
|
*name = node->value.element.attrs[idx].name;
|
|
|
|
|
|
|
|
|
|
return (node->value.element.attrs[idx].value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
|
|
|
|
// 'mxmlElementGetAttrCount()' - Get the number of element attributes.
|
|
|
|
|
//
|
2024-03-17 02:20:24 +00:00
|
|
|
|
// This function returns the number of attributes for the element `node`. `0`
|
|
|
|
|
// is returned if the node is not an element or there are no attributes for the
|
|
|
|
|
// element.
|
|
|
|
|
//
|
2017-04-23 17:12:39 +00:00
|
|
|
|
|
2024-03-02 23:47:57 +00:00
|
|
|
|
size_t // O - Number of attributes
|
2017-04-23 17:12:39 +00:00
|
|
|
|
mxmlElementGetAttrCount(
|
2024-03-02 23:47:57 +00:00
|
|
|
|
mxml_node_t *node) // I - Node
|
2017-04-23 17:12:39 +00:00
|
|
|
|
{
|
2024-02-27 20:04:27 +00:00
|
|
|
|
if (node && node->type == MXML_TYPE_ELEMENT)
|
2017-04-23 17:12:39 +00:00
|
|
|
|
return (node->value.element.num_attrs);
|
|
|
|
|
else
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
2024-03-17 02:20:24 +00:00
|
|
|
|
// 'mxmlElementSetAttr()' - Set an attribute for an element.
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
2024-03-17 02:20:24 +00:00
|
|
|
|
// This function sets attribute `name` to the string `value` for the element
|
|
|
|
|
// `node`. If the named attribute already exists, the value of the attribute
|
|
|
|
|
// is replaced by the new string value. The string value is copied.
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
2003-06-03 19:46:29 +00:00
|
|
|
|
|
|
|
|
|
void
|
2024-02-27 20:04:27 +00:00
|
|
|
|
mxmlElementSetAttr(mxml_node_t *node, // I - Element node
|
|
|
|
|
const char *name, // I - Name of attribute
|
|
|
|
|
const char *value) // I - Attribute value
|
2003-06-03 19:46:29 +00:00
|
|
|
|
{
|
2024-02-27 20:04:27 +00:00
|
|
|
|
char *valuec; // Copy of value
|
2003-06-03 19:46:29 +00:00
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
MXML_DEBUG("mxmlElementSetAttr(node=%p, name=\"%s\", value=\"%s\")\n", node, name ? name : "(null)", value ? value : "(null)");
|
2003-12-03 03:59:04 +00:00
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
// Range check input...
|
|
|
|
|
if (!node || node->type != MXML_TYPE_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
|
|
|
|
{
|
2024-03-07 19:06:50 +00:00
|
|
|
|
if ((valuec = _mxml_strcopy(value)) == NULL)
|
2021-10-26 19:11:00 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2007-04-18 14:55:08 +00:00
|
|
|
|
else
|
2024-02-27 20:04:27 +00:00
|
|
|
|
{
|
2007-04-18 14:55:08 +00:00
|
|
|
|
valuec = NULL;
|
2024-02-27 20:04:27 +00:00
|
|
|
|
}
|
2007-04-18 14:55:08 +00:00
|
|
|
|
|
2024-03-02 23:47:57 +00:00
|
|
|
|
if (!mxml_set_attr(node, name, valuec))
|
2024-03-07 19:06:50 +00:00
|
|
|
|
_mxml_strfree(valuec);
|
2007-04-18 14:55:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
|
|
|
|
// 'mxmlElementSetAttrf()' - Set an attribute with a formatted value.
|
|
|
|
|
//
|
2024-03-17 02:20:24 +00:00
|
|
|
|
// This function sets attribute `name` to the formatted value of `format` for
|
|
|
|
|
// the element `node`. If the named attribute already exists, the value of the
|
|
|
|
|
// attribute is replaced by the new formatted string value.
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
2007-04-18 14:55:08 +00:00
|
|
|
|
|
|
|
|
|
void
|
2024-02-27 20:04:27 +00:00
|
|
|
|
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
|
2007-04-18 14:55:08 +00:00
|
|
|
|
{
|
2024-02-27 20:04:27 +00:00
|
|
|
|
va_list ap; // Argument pointer
|
|
|
|
|
char buffer[16384]; // Format buffer
|
|
|
|
|
char *value; // Value
|
2007-04-18 14:55:08 +00:00
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
MXML_DEBUG("mxmlElementSetAttrf(node=%p, name=\"%s\", format=\"%s\", ...)\n", node, name ? name : "(null)", format ? format : "(null)");
|
2007-04-18 14:55:08 +00:00
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
// Range check input...
|
|
|
|
|
if (!node || node->type != MXML_TYPE_ELEMENT || !name || !format)
|
2007-04-18 14:55:08 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
// Format the value...
|
2007-04-18 14:55:08 +00:00
|
|
|
|
va_start(ap, format);
|
2024-02-27 20:04:27 +00:00
|
|
|
|
vsnprintf(buffer, sizeof(buffer), format, ap);
|
2007-04-18 14:55:08 +00:00
|
|
|
|
va_end(ap);
|
|
|
|
|
|
2024-03-19 01:46:14 +00:00
|
|
|
|
if ((value = _mxml_strcopy(buffer)) != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (!mxml_set_attr(node, name, value))
|
|
|
|
|
_mxml_strfree(value);
|
|
|
|
|
}
|
2007-04-18 14:55:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
//
|
|
|
|
|
// 'mxml_set_attr()' - Set or add an attribute name/value pair.
|
|
|
|
|
//
|
2007-04-18 14:55:08 +00:00
|
|
|
|
|
2024-03-02 23:47:57 +00:00
|
|
|
|
static bool // O - `true` on success, `false` on failure
|
2024-02-27 20:04:27 +00:00
|
|
|
|
mxml_set_attr(mxml_node_t *node, // I - Element node
|
|
|
|
|
const char *name, // I - Attribute name
|
|
|
|
|
char *value) // I - Attribute value
|
2007-04-18 14:55:08 +00:00
|
|
|
|
{
|
2024-11-14 20:26:29 +00:00
|
|
|
|
size_t i; // Looping var
|
2024-02-27 20:04:27 +00:00
|
|
|
|
_mxml_attr_t *attr; // New attribute
|
2007-04-18 14:55:08 +00:00
|
|
|
|
|
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
// Look for the attribute...
|
|
|
|
|
for (i = node->value.element.num_attrs, attr = node->value.element.attrs; i > 0; i --, attr ++)
|
|
|
|
|
{
|
2003-06-03 19:46:29 +00:00
|
|
|
|
if (!strcmp(attr->name, name))
|
|
|
|
|
{
|
2024-02-27 20:04:27 +00:00
|
|
|
|
// Free the old value as needed...
|
2024-03-07 19:06:50 +00:00
|
|
|
|
_mxml_strfree(attr->value);
|
2007-04-18 14:55:08 +00:00
|
|
|
|
attr->value = value;
|
2003-06-03 19:46:29 +00:00
|
|
|
|
|
2024-03-02 23:47:57 +00:00
|
|
|
|
return (true);
|
2003-06-03 19:46:29 +00:00
|
|
|
|
}
|
2024-02-27 20:04:27 +00:00
|
|
|
|
}
|
2003-06-03 19:46:29 +00:00
|
|
|
|
|
2024-02-27 20:04:27 +00:00
|
|
|
|
// Add a new attribute...
|
2024-04-21 21:08:39 +00:00
|
|
|
|
if ((node->value.element.num_attrs % MXML_ALLOC_SIZE) == 0)
|
|
|
|
|
{
|
|
|
|
|
if ((attr = realloc(node->value.element.attrs, (node->value.element.num_attrs + MXML_ALLOC_SIZE) * sizeof(_mxml_attr_t))) == NULL)
|
|
|
|
|
return (false);
|
|
|
|
|
|
|
|
|
|
node->value.element.attrs = attr;
|
|
|
|
|
}
|
2003-06-03 19:46:29 +00:00
|
|
|
|
|
2024-04-21 21:08:39 +00:00
|
|
|
|
attr = node->value.element.attrs + node->value.element.num_attrs;
|
2003-06-03 19:46:29 +00:00
|
|
|
|
|
2024-03-07 19:06:50 +00:00
|
|
|
|
if ((attr->name = _mxml_strcopy(name)) == NULL)
|
2024-03-02 23:47:57 +00:00
|
|
|
|
return (false);
|
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
|
|
|
|
|
2024-03-02 23:47:57 +00:00
|
|
|
|
return (true);
|
2003-06-03 19:46:29 +00:00
|
|
|
|
}
|