mxml-attr.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  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-2019 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. valuec = strdup(value);
  173. else
  174. valuec = NULL;
  175. if (mxml_set_attr(node, name, valuec))
  176. free(valuec);
  177. }
  178. /*
  179. * 'mxmlElementSetAttrf()' - Set an attribute with a formatted value.
  180. *
  181. * If the named attribute already exists, the value of the attribute
  182. * is replaced by the new formatted string. The formatted string value is
  183. * copied into the element node. This function does nothing if the node
  184. * is not an element.
  185. *
  186. * @since Mini-XML 2.3@
  187. */
  188. void
  189. mxmlElementSetAttrf(mxml_node_t *node, /* I - Element node */
  190. const char *name, /* I - Name of attribute */
  191. const char *format,/* I - Printf-style attribute value */
  192. ...) /* I - Additional arguments as needed */
  193. {
  194. va_list ap; /* Argument pointer */
  195. char *value; /* Value */
  196. #ifdef DEBUG
  197. fprintf(stderr,
  198. "mxmlElementSetAttrf(node=%p, name=\"%s\", format=\"%s\", ...)\n",
  199. node, name ? name : "(null)", format ? format : "(null)");
  200. #endif /* DEBUG */
  201. /*
  202. * Range check input...
  203. */
  204. if (!node || node->type != MXML_ELEMENT || !name || !format)
  205. return;
  206. /*
  207. * Format the value...
  208. */
  209. va_start(ap, format);
  210. value = _mxml_vstrdupf(format, ap);
  211. va_end(ap);
  212. if (!value)
  213. mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
  214. name, node->value.element.name);
  215. else if (mxml_set_attr(node, name, value))
  216. free(value);
  217. }
  218. /*
  219. * 'mxml_set_attr()' - Set or add an attribute name/value pair.
  220. */
  221. static int /* O - 0 on success, -1 on failure */
  222. mxml_set_attr(mxml_node_t *node, /* I - Element node */
  223. const char *name, /* I - Attribute name */
  224. char *value) /* I - Attribute value */
  225. {
  226. int i; /* Looping var */
  227. _mxml_attr_t *attr; /* New attribute */
  228. /*
  229. * Look for the attribute...
  230. */
  231. for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
  232. i > 0;
  233. i --, attr ++)
  234. if (!strcmp(attr->name, name))
  235. {
  236. /*
  237. * Free the old value as needed...
  238. */
  239. if (attr->value)
  240. free(attr->value);
  241. attr->value = value;
  242. return (0);
  243. }
  244. /*
  245. * Add a new attribute...
  246. */
  247. if (node->value.element.num_attrs == 0)
  248. attr = malloc(sizeof(_mxml_attr_t));
  249. else
  250. attr = realloc(node->value.element.attrs,
  251. (node->value.element.num_attrs + 1) * sizeof(_mxml_attr_t));
  252. if (!attr)
  253. {
  254. mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
  255. name, node->value.element.name);
  256. return (-1);
  257. }
  258. node->value.element.attrs = attr;
  259. attr += node->value.element.num_attrs;
  260. if ((attr->name = strdup(name)) == NULL)
  261. {
  262. mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
  263. name, node->value.element.name);
  264. return (-1);
  265. }
  266. attr->value = value;
  267. node->value.element.num_attrs ++;
  268. return (0);
  269. }