mxml/mxml-attr.c

272 lines
6.9 KiB
C
Raw Normal View History

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.
//
#include "mxml-private.h"
2003-06-03 19:46:29 +00:00
2024-02-27 20:04:27 +00:00
//
// Local functions...
//
static bool mxml_set_attr(mxml_node_t *node, const char *name, char *value);
2024-02-27 20:04:27 +00:00
//
// 'mxmlElementDeleteAttr()' - Delete an attribute.
//
void
2024-02-27 20:04:27 +00:00
mxmlElementDeleteAttr(mxml_node_t *node,// I - Element
const char *name)// I - Attribute name
{
size_t i; // Looping var
2024-02-27 20:04:27 +00:00
_mxml_attr_t *attr; // Cirrent attribute
2024-02-27 20:04:27 +00:00
MXML_DEBUG("mxmlElementDeleteAttr(node=%p, name=\"%s\")\n", node, name ? name : "(null)");
2024-02-27 20:04:27 +00:00
// Range check input...
if (!node || node->type != MXML_TYPE_ELEMENT || !name)
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 ++)
{
2024-02-27 20:04:27 +00:00
MXML_DEBUG("mxmlElementDeleteAttr: %s=\"%s\"\n", attr->name, attr->value);
if (!strcmp(attr->name, name))
{
2024-02-27 20:04:27 +00:00
// 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 --;
if (node->value.element.num_attrs == 0)
free(node->value.element.attrs);
return;
}
}
}
2024-02-27 20:04:27 +00:00
//
// 'mxmlElementGetAttr()' - Get an attribute.
//
// This function returns @code NULL@ if the node is not an element or the
// named attribute does not exist.
//
2003-06-03 19:46:29 +00:00
2024-02-27 20:04:27 +00:00
const char * // O - Attribute value or @code NULL@
mxmlElementGetAttr(mxml_node_t *node, // I - Element node
const char *name) // I - Name of attribute
2003-06-03 19:46:29 +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
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
//
// '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.
//
2024-02-27 20:04:27 +00:00
const char * // O - Attribute value
mxmlElementGetAttrByIndex(
2024-02-27 20:04:27 +00:00
mxml_node_t *node, // I - Node
int idx, // I - Attribute index, starting at 0
const char **name) // O - Attribute name
{
2024-02-27 20:04:27 +00:00
if (!node || node->type != MXML_TYPE_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);
}
2024-02-27 20:04:27 +00:00
//
// 'mxmlElementGetAttrCount()' - Get the number of element attributes.
//
size_t // O - Number of attributes
mxmlElementGetAttrCount(
mxml_node_t *node) // I - Node
{
2024-02-27 20:04:27 +00:00
if (node && node->type == MXML_TYPE_ELEMENT)
return (node->value.element.num_attrs);
else
return (0);
}
2024-02-27 20:04:27 +00:00
//
// '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.
//
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)");
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;
if (value)
{
if ((valuec = strdup(value)) == NULL)
{
mxml_error("Unable to allocate memory for attribute '%s' in element %s.", name, node->value.element.name);
return;
}
}
else
2024-02-27 20:04:27 +00:00
{
valuec = NULL;
2024-02-27 20:04:27 +00:00
}
if (!mxml_set_attr(node, name, valuec))
free(valuec);
}
2024-02-27 20:04:27 +00:00
//
// '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.
//
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
{
2024-02-27 20:04:27 +00:00
va_list ap; // Argument pointer
char buffer[16384]; // Format buffer
char *value; // Value
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)");
2024-02-27 20:04:27 +00:00
// Range check input...
if (!node || node->type != MXML_TYPE_ELEMENT || !name || !format)
return;
2024-02-27 20:04:27 +00:00
// Format the value...
va_start(ap, format);
2024-02-27 20:04:27 +00:00
vsnprintf(buffer, sizeof(buffer), format, ap);
va_end(ap);
2024-02-27 20:04:27 +00:00
if ((value = strdup(buffer)) == NULL)
mxml_error("Unable to allocate memory for attribute '%s' in element %s.", name, node->value.element.name);
else if (!mxml_set_attr(node, name, value))
free(value);
}
2024-02-27 20:04:27 +00:00
//
// 'mxml_set_attr()' - Set or add an attribute name/value pair.
//
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
{
2024-02-27 20:04:27 +00:00
int i; // Looping var
_mxml_attr_t *attr; // New attribute
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...
2021-10-26 18:50:25 +00:00
free(attr->value);
attr->value = value;
2003-06-03 19:46:29 +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...
attr = realloc(node->value.element.attrs, (node->value.element.num_attrs + 1) * sizeof(_mxml_attr_t));
2003-06-03 19:46:29 +00:00
if (!attr)
{
2024-02-27 20:04:27 +00:00
mxml_error("Unable to allocate memory for attribute '%s' in element %s.", name, node->value.element.name);
return (false);
2003-06-03 19:46:29 +00:00
}
node->value.element.attrs = attr;
attr += node->value.element.num_attrs;
if ((attr->name = strdup(name)) == NULL)
2003-06-03 19:46:29 +00:00
{
2024-02-27 20:04:27 +00:00
mxml_error("Unable to allocate memory for attribute '%s' in element %s.", name, node->value.element.name);
return (false);
2003-06-03 19:46:29 +00:00
}
attr->value = value;
2003-06-03 19:46:29 +00:00
node->value.element.num_attrs ++;
return (true);
2003-06-03 19:46:29 +00:00
}