mxml-set.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. /*
  2. * Node set functions 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. * 'mxmlSetCDATA()' - Set the element name of a CDATA node.
  18. *
  19. * The node is not changed if it (or its first child) is not a CDATA element node.
  20. *
  21. * @since Mini-XML 2.3@
  22. */
  23. int /* O - 0 on success, -1 on failure */
  24. mxmlSetCDATA(mxml_node_t *node, /* I - Node to set */
  25. const char *data) /* I - New data string */
  26. {
  27. char *s; /* New element name */
  28. /*
  29. * Range check input...
  30. */
  31. if (node && node->type == MXML_ELEMENT &&
  32. strncmp(node->value.element.name, "![CDATA[", 8) &&
  33. node->child && node->child->type == MXML_ELEMENT &&
  34. !strncmp(node->child->value.element.name, "![CDATA[", 8))
  35. node = node->child;
  36. if (!node || node->type != MXML_ELEMENT ||
  37. strncmp(node->value.element.name, "![CDATA[", 8))
  38. {
  39. mxml_error("Wrong node type.");
  40. return (-1);
  41. }
  42. else if (!data)
  43. {
  44. mxml_error("NULL string not allowed.");
  45. return (-1);
  46. }
  47. if (data == (node->value.element.name + 8))
  48. {
  49. /*
  50. * Don't change the value...
  51. */
  52. return (0);
  53. }
  54. /*
  55. * Allocate the new value, free any old element value, and set the new value...
  56. */
  57. if ((s = _mxml_strdupf("![CDATA[%s", data)) == NULL)
  58. {
  59. mxml_error("Unable to allocate memory for CDATA.");
  60. return (-1);
  61. }
  62. free(node->value.element.name);
  63. node->value.element.name = s;
  64. return (0);
  65. }
  66. /*
  67. * 'mxmlSetCustom()' - Set the data and destructor of a custom data node.
  68. *
  69. * The node is not changed if it (or its first child) is not a custom node.
  70. *
  71. * @since Mini-XML 2.1@
  72. */
  73. int /* O - 0 on success, -1 on failure */
  74. mxmlSetCustom(
  75. mxml_node_t *node, /* I - Node to set */
  76. void *data, /* I - New data pointer */
  77. mxml_custom_destroy_cb_t destroy) /* I - New destructor function */
  78. {
  79. /*
  80. * Range check input...
  81. */
  82. if (node && node->type == MXML_ELEMENT &&
  83. node->child && node->child->type == MXML_CUSTOM)
  84. node = node->child;
  85. if (!node || node->type != MXML_CUSTOM)
  86. {
  87. mxml_error("Wrong node type.");
  88. return (-1);
  89. }
  90. if (data == node->value.custom.data)
  91. {
  92. node->value.custom.destroy = destroy;
  93. return (0);
  94. }
  95. /*
  96. * Free any old element value and set the new value...
  97. */
  98. if (node->value.custom.data && node->value.custom.destroy)
  99. (*(node->value.custom.destroy))(node->value.custom.data);
  100. node->value.custom.data = data;
  101. node->value.custom.destroy = destroy;
  102. return (0);
  103. }
  104. /*
  105. * 'mxmlSetElement()' - Set the name of an element node.
  106. *
  107. * The node is not changed if it is not an element node.
  108. */
  109. int /* O - 0 on success, -1 on failure */
  110. mxmlSetElement(mxml_node_t *node, /* I - Node to set */
  111. const char *name) /* I - New name string */
  112. {
  113. char *s; /* New name string */
  114. /*
  115. * Range check input...
  116. */
  117. if (!node || node->type != MXML_ELEMENT)
  118. {
  119. mxml_error("Wrong node type.");
  120. return (-1);
  121. }
  122. else if (!name)
  123. {
  124. mxml_error("NULL string not allowed.");
  125. return (-1);
  126. }
  127. if (name == node->value.element.name)
  128. return (0);
  129. /*
  130. * Free any old element value and set the new value...
  131. */
  132. if ((s = strdup(name)) == NULL)
  133. {
  134. mxml_error("Unable to allocate memory for element name.");
  135. return (-1);
  136. }
  137. free(node->value.element.name);
  138. node->value.element.name = s;
  139. return (0);
  140. }
  141. /*
  142. * 'mxmlSetInteger()' - Set the value of an integer node.
  143. *
  144. * The node is not changed if it (or its first child) is not an integer node.
  145. */
  146. int /* O - 0 on success, -1 on failure */
  147. mxmlSetInteger(mxml_node_t *node, /* I - Node to set */
  148. int integer) /* I - Integer value */
  149. {
  150. /*
  151. * Range check input...
  152. */
  153. if (node && node->type == MXML_ELEMENT &&
  154. node->child && node->child->type == MXML_INTEGER)
  155. node = node->child;
  156. if (!node || node->type != MXML_INTEGER)
  157. {
  158. mxml_error("Wrong node type.");
  159. return (-1);
  160. }
  161. /*
  162. * Set the new value and return...
  163. */
  164. node->value.integer = integer;
  165. return (0);
  166. }
  167. /*
  168. * 'mxmlSetOpaque()' - Set the value of an opaque node.
  169. *
  170. * The node is not changed if it (or its first child) is not an opaque node.
  171. */
  172. int /* O - 0 on success, -1 on failure */
  173. mxmlSetOpaque(mxml_node_t *node, /* I - Node to set */
  174. const char *opaque) /* I - Opaque string */
  175. {
  176. char *s; /* New opaque string */
  177. /*
  178. * Range check input...
  179. */
  180. if (node && node->type == MXML_ELEMENT &&
  181. node->child && node->child->type == MXML_OPAQUE)
  182. node = node->child;
  183. if (!node || node->type != MXML_OPAQUE)
  184. {
  185. mxml_error("Wrong node type.");
  186. return (-1);
  187. }
  188. else if (!opaque)
  189. {
  190. mxml_error("NULL string not allowed.");
  191. return (-1);
  192. }
  193. if (node->value.opaque == opaque)
  194. return (0);
  195. /*
  196. * Free any old opaque value and set the new value...
  197. */
  198. if ((s = strdup(opaque)) == NULL)
  199. {
  200. mxml_error("Unable to allocate memory for opaque string.");
  201. return (-1);
  202. }
  203. free(node->value.opaque);
  204. node->value.opaque = s;
  205. return (0);
  206. }
  207. /*
  208. * 'mxmlSetOpaquef()' - Set the value of an opaque string node to a formatted string.
  209. *
  210. * The node is not changed if it (or its first child) is not an opaque node.
  211. *
  212. * @since Mini-XML 2.11@
  213. */
  214. int /* O - 0 on success, -1 on failure */
  215. mxmlSetOpaquef(mxml_node_t *node, /* I - Node to set */
  216. const char *format, /* I - Printf-style format string */
  217. ...) /* I - Additional arguments as needed */
  218. {
  219. va_list ap; /* Pointer to arguments */
  220. char *s; /* Temporary string */
  221. /*
  222. * Range check input...
  223. */
  224. if (node && node->type == MXML_ELEMENT &&
  225. node->child && node->child->type == MXML_OPAQUE)
  226. node = node->child;
  227. if (!node || node->type != MXML_OPAQUE)
  228. {
  229. mxml_error("Wrong node type.");
  230. return (-1);
  231. }
  232. else if (!format)
  233. {
  234. mxml_error("NULL string not allowed.");
  235. return (-1);
  236. }
  237. /*
  238. * Format the new string, free any old string value, and set the new value...
  239. */
  240. va_start(ap, format);
  241. s = _mxml_vstrdupf(format, ap);
  242. va_end(ap);
  243. if (!s)
  244. {
  245. mxml_error("Unable to allocate memory for opaque string.");
  246. return (-1);
  247. }
  248. free(node->value.opaque);
  249. node->value.opaque = s;
  250. return (0);
  251. }
  252. /*
  253. * 'mxmlSetReal()' - Set the value of a real number node.
  254. *
  255. * The node is not changed if it (or its first child) is not a real number node.
  256. */
  257. int /* O - 0 on success, -1 on failure */
  258. mxmlSetReal(mxml_node_t *node, /* I - Node to set */
  259. double real) /* I - Real number value */
  260. {
  261. /*
  262. * Range check input...
  263. */
  264. if (node && node->type == MXML_ELEMENT &&
  265. node->child && node->child->type == MXML_REAL)
  266. node = node->child;
  267. if (!node || node->type != MXML_REAL)
  268. {
  269. mxml_error("Wrong node type.");
  270. return (-1);
  271. }
  272. /*
  273. * Set the new value and return...
  274. */
  275. node->value.real = real;
  276. return (0);
  277. }
  278. /*
  279. * 'mxmlSetText()' - Set the value of a text node.
  280. *
  281. * The node is not changed if it (or its first child) is not a text node.
  282. */
  283. int /* O - 0 on success, -1 on failure */
  284. mxmlSetText(mxml_node_t *node, /* I - Node to set */
  285. int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */
  286. const char *string) /* I - String */
  287. {
  288. char *s; /* New string */
  289. /*
  290. * Range check input...
  291. */
  292. if (node && node->type == MXML_ELEMENT &&
  293. node->child && node->child->type == MXML_TEXT)
  294. node = node->child;
  295. if (!node || node->type != MXML_TEXT)
  296. {
  297. mxml_error("Wrong node type.");
  298. return (-1);
  299. }
  300. else if (!string)
  301. {
  302. mxml_error("NULL string not allowed.");
  303. return (-1);
  304. }
  305. if (string == node->value.text.string)
  306. {
  307. node->value.text.whitespace = whitespace;
  308. return (0);
  309. }
  310. /*
  311. * Free any old string value and set the new value...
  312. */
  313. if ((s = strdup(string)) == NULL)
  314. {
  315. mxml_error("Unable to allocate memory for text string.");
  316. return (-1);
  317. }
  318. free(node->value.text.string);
  319. node->value.text.whitespace = whitespace;
  320. node->value.text.string = s;
  321. return (0);
  322. }
  323. /*
  324. * 'mxmlSetTextf()' - Set the value of a text node to a formatted string.
  325. *
  326. * The node is not changed if it (or its first child) is not a text node.
  327. */
  328. int /* O - 0 on success, -1 on failure */
  329. mxmlSetTextf(mxml_node_t *node, /* I - Node to set */
  330. int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */
  331. const char *format, /* I - Printf-style format string */
  332. ...) /* I - Additional arguments as needed */
  333. {
  334. va_list ap; /* Pointer to arguments */
  335. char *s; /* Temporary string */
  336. /*
  337. * Range check input...
  338. */
  339. if (node && node->type == MXML_ELEMENT &&
  340. node->child && node->child->type == MXML_TEXT)
  341. node = node->child;
  342. if (!node || node->type != MXML_TEXT)
  343. {
  344. mxml_error("Wrong node type.");
  345. return (-1);
  346. }
  347. else if (!format)
  348. {
  349. mxml_error("NULL string not allowed.");
  350. return (-1);
  351. }
  352. /*
  353. * Free any old string value and set the new value...
  354. */
  355. va_start(ap, format);
  356. s = _mxml_vstrdupf(format, ap);
  357. va_end(ap);
  358. if (!s)
  359. {
  360. mxml_error("Unable to allocate memory for text string.");
  361. return (-1);
  362. }
  363. free(node->value.text.string);
  364. node->value.text.whitespace = whitespace;
  365. node->value.text.string = s;
  366. return (0);
  367. }
  368. /*
  369. * 'mxmlSetUserData()' - Set the user data pointer for a node.
  370. *
  371. * @since Mini-XML 2.7@
  372. */
  373. int /* O - 0 on success, -1 on failure */
  374. mxmlSetUserData(mxml_node_t *node, /* I - Node to set */
  375. void *data) /* I - User data pointer */
  376. {
  377. /*
  378. * Range check input...
  379. */
  380. if (!node)
  381. return (-1);
  382. /*
  383. * Set the user data pointer and return...
  384. */
  385. node->user_data = data;
  386. return (0);
  387. }