mxml-attr.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. /*
  2. * Attribute support code for Mini-XML, a small XML file parsing library.
  3. *
  4. * https://www.msweet.org/mxml
  5. *
  6. * Copyright © 2003-2021 by Michael R Sweet.
  7. *
  8. * Licensed under Apache License v2.0. See the file "LICENSE" for more
  9. * information.
  10. */
  11. /*
  12. * Include necessary headers...
  13. */
  14. #include "config.h"
  15. #include "mxml-private.h"
  16. /*
  17. * Local functions...
  18. */
  19. static int mxml_set_attr(mxml_node_t *node, const char *name, char *value);
  20. /*
  21. * 'mxmlElementDeleteAttr()' - Delete an attribute.
  22. *
  23. * @since Mini-XML 2.4@
  24. */
  25. void
  26. mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */
  27. const char *name)/* I - Attribute name */
  28. {
  29. int i; /* Looping var */
  30. _mxml_attr_t *attr; /* Cirrent attribute */
  31. #ifdef DEBUG
  32. fprintf(stderr, "mxmlElementDeleteAttr(node=%p, name=\"%s\")\n",
  33. node, name ? name : "(null)");
  34. #endif /* DEBUG */
  35. /*
  36. * Range check input...
  37. */
  38. if (!node || node->type != MXML_ELEMENT || !name)
  39. return;
  40. /*
  41. * Look for the attribute...
  42. */
  43. for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
  44. i > 0;
  45. i --, attr ++)
  46. {
  47. #ifdef DEBUG
  48. printf(" %s=\"%s\"\n", attr->name, attr->value);
  49. #endif /* DEBUG */
  50. if (!strcmp(attr->name, name))
  51. {
  52. /*
  53. * Delete this attribute...
  54. */
  55. free(attr->name);
  56. free(attr->value);
  57. i --;
  58. if (i > 0)
  59. memmove(attr, attr + 1, i * sizeof(_mxml_attr_t));
  60. node->value.element.num_attrs --;
  61. if (node->value.element.num_attrs == 0)
  62. free(node->value.element.attrs);
  63. return;
  64. }
  65. }
  66. }
  67. /*
  68. * 'mxmlElementGetAttr()' - Get an attribute.
  69. *
  70. * This function returns @code NULL@ if the node is not an element or the
  71. * named attribute does not exist.
  72. */
  73. const char * /* O - Attribute value or @code NULL@ */
  74. mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */
  75. const char *name) /* I - Name of attribute */
  76. {
  77. int i; /* Looping var */
  78. _mxml_attr_t *attr; /* Cirrent attribute */
  79. #ifdef DEBUG
  80. fprintf(stderr, "mxmlElementGetAttr(node=%p, name=\"%s\")\n",
  81. node, name ? name : "(null)");
  82. #endif /* DEBUG */
  83. /*
  84. * Range check input...
  85. */
  86. if (!node || node->type != MXML_ELEMENT || !name)
  87. return (NULL);
  88. /*
  89. * Look for the attribute...
  90. */
  91. for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
  92. i > 0;
  93. i --, attr ++)
  94. {
  95. #ifdef DEBUG
  96. printf(" %s=\"%s\"\n", attr->name, attr->value);
  97. #endif /* DEBUG */
  98. if (!strcmp(attr->name, name))
  99. {
  100. #ifdef DEBUG
  101. printf(" Returning \"%s\"!\n", attr->value);
  102. #endif /* DEBUG */
  103. return (attr->value);
  104. }
  105. }
  106. /*
  107. * Didn't find attribute, so return NULL...
  108. */
  109. #ifdef DEBUG
  110. puts(" Returning NULL!\n");
  111. #endif /* DEBUG */
  112. return (NULL);
  113. }
  114. /*
  115. * 'mxmlElementGetAttrByIndex()' - Get an element attribute by index.
  116. *
  117. * The index ("idx") is 0-based. @code NULL@ is returned if the specified index
  118. * is out of range.
  119. *
  120. * @since Mini-XML 2.11@
  121. */
  122. const char * /* O - Attribute value */
  123. mxmlElementGetAttrByIndex(
  124. mxml_node_t *node, /* I - Node */
  125. int idx, /* I - Attribute index, starting at 0 */
  126. const char **name) /* O - Attribute name */
  127. {
  128. if (!node || node->type != MXML_ELEMENT || idx < 0 || idx >= node->value.element.num_attrs)
  129. return (NULL);
  130. if (name)
  131. *name = node->value.element.attrs[idx].name;
  132. return (node->value.element.attrs[idx].value);
  133. }
  134. /*
  135. * 'mxmlElementGetAttrCount()' - Get the number of element attributes.
  136. *
  137. * @since Mini-XML 2.11@
  138. */
  139. int /* O - Number of attributes */
  140. mxmlElementGetAttrCount(
  141. mxml_node_t *node) /* I - Node */
  142. {
  143. if (node && node->type == MXML_ELEMENT)
  144. return (node->value.element.num_attrs);
  145. else
  146. return (0);
  147. }
  148. /*
  149. * 'mxmlElementSetAttr()' - Set an attribute.
  150. *
  151. * If the named attribute already exists, the value of the attribute
  152. * is replaced by the new string value. The string value is copied
  153. * into the element node. This function does nothing if the node is
  154. * not an element.
  155. */
  156. void
  157. mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */
  158. const char *name, /* I - Name of attribute */
  159. const char *value) /* I - Attribute value */
  160. {
  161. char *valuec; /* Copy of value */
  162. #ifdef DEBUG
  163. fprintf(stderr, "mxmlElementSetAttr(node=%p, name=\"%s\", value=\"%s\")\n",
  164. node, name ? name : "(null)", value ? value : "(null)");
  165. #endif /* DEBUG */
  166. /*
  167. * Range check input...
  168. */
  169. if (!node || node->type != MXML_ELEMENT || !name)
  170. return;
  171. if (value)
  172. {
  173. if ((valuec = strdup(value)) == NULL)
  174. {
  175. mxml_error("Unable to allocate memory for attribute '%s' in element %s.", name, node->value.element.name);
  176. return;
  177. }
  178. }
  179. else
  180. valuec = NULL;
  181. if (mxml_set_attr(node, name, valuec))
  182. free(valuec);
  183. }
  184. /*
  185. * 'mxmlElementSetAttrf()' - Set an attribute with a formatted value.
  186. *
  187. * If the named attribute already exists, the value of the attribute
  188. * is replaced by the new formatted string. The formatted string value is
  189. * copied into the element node. This function does nothing if the node
  190. * is not an element.
  191. *
  192. * @since Mini-XML 2.3@
  193. */
  194. void
  195. mxmlElementSetAttrf(mxml_node_t *node, /* I - Element node */
  196. const char *name, /* I - Name of attribute */
  197. const char *format,/* I - Printf-style attribute value */
  198. ...) /* I - Additional arguments as needed */
  199. {
  200. va_list ap; /* Argument pointer */
  201. char *value; /* Value */
  202. #ifdef DEBUG
  203. fprintf(stderr,
  204. "mxmlElementSetAttrf(node=%p, name=\"%s\", format=\"%s\", ...)\n",
  205. node, name ? name : "(null)", format ? format : "(null)");
  206. #endif /* DEBUG */
  207. /*
  208. * Range check input...
  209. */
  210. if (!node || node->type != MXML_ELEMENT || !name || !format)
  211. return;
  212. /*
  213. * Format the value...
  214. */
  215. va_start(ap, format);
  216. value = _mxml_vstrdupf(format, ap);
  217. va_end(ap);
  218. if (!value)
  219. mxml_error("Unable to allocate memory for attribute '%s' in element %s.",
  220. name, node->value.element.name);
  221. else if (mxml_set_attr(node, name, value))
  222. free(value);
  223. }
  224. /*
  225. * 'mxml_set_attr()' - Set or add an attribute name/value pair.
  226. */
  227. static int /* O - 0 on success, -1 on failure */
  228. mxml_set_attr(mxml_node_t *node, /* I - Element node */
  229. const char *name, /* I - Attribute name */
  230. char *value) /* I - Attribute value */
  231. {
  232. int i; /* Looping var */
  233. _mxml_attr_t *attr; /* New attribute */
  234. /*
  235. * Look for the attribute...
  236. */
  237. for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
  238. i > 0;
  239. i --, attr ++)
  240. if (!strcmp(attr->name, name))
  241. {
  242. /*
  243. * Free the old value as needed...
  244. */
  245. free(attr->value);
  246. attr->value = value;
  247. return (0);
  248. }
  249. /*
  250. * Add a new attribute...
  251. */
  252. if (node->value.element.num_attrs == 0)
  253. attr = malloc(sizeof(_mxml_attr_t));
  254. else
  255. attr = realloc(node->value.element.attrs,
  256. (node->value.element.num_attrs + 1) * sizeof(_mxml_attr_t));
  257. if (!attr)
  258. {
  259. mxml_error("Unable to allocate memory for attribute '%s' in element %s.",
  260. name, node->value.element.name);
  261. return (-1);
  262. }
  263. node->value.element.attrs = attr;
  264. attr += node->value.element.num_attrs;
  265. if ((attr->name = strdup(name)) == NULL)
  266. {
  267. mxml_error("Unable to allocate memory for attribute '%s' in element %s.",
  268. name, node->value.element.name);
  269. return (-1);
  270. }
  271. attr->value = value;
  272. node->value.element.num_attrs ++;
  273. return (0);
  274. }