mxml-node.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874
  1. /*
  2. * Node 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 void mxml_free(mxml_node_t *node);
  20. static mxml_node_t *mxml_new(mxml_node_t *parent, mxml_type_t type);
  21. /*
  22. * 'mxmlAdd()' - Add a node to a tree.
  23. *
  24. * Adds the specified node to the parent. If the child argument is not
  25. * @code NULL@, puts the new node before or after the specified child depending
  26. * on the value of the where argument. If the child argument is @code NULL@,
  27. * puts the new node at the beginning of the child list (@code MXML_ADD_BEFORE@)
  28. * or at the end of the child list (@code MXML_ADD_AFTER@). The constant
  29. * @code MXML_ADD_TO_PARENT@ can be used to specify a @code NULL@ child pointer.
  30. */
  31. void
  32. mxmlAdd(mxml_node_t *parent, /* I - Parent node */
  33. int where, /* I - Where to add, @code MXML_ADD_BEFORE@ or @code MXML_ADD_AFTER@ */
  34. mxml_node_t *child, /* I - Child node for where or @code MXML_ADD_TO_PARENT@ */
  35. mxml_node_t *node) /* I - Node to add */
  36. {
  37. #ifdef DEBUG
  38. fprintf(stderr, "mxmlAdd(parent=%p, where=%d, child=%p, node=%p)\n", parent,
  39. where, child, node);
  40. #endif /* DEBUG */
  41. /*
  42. * Range check input...
  43. */
  44. if (!parent || !node)
  45. return;
  46. #if DEBUG > 1
  47. fprintf(stderr, " BEFORE: node->parent=%p\n", node->parent);
  48. if (parent)
  49. {
  50. fprintf(stderr, " BEFORE: parent->child=%p\n", parent->child);
  51. fprintf(stderr, " BEFORE: parent->last_child=%p\n", parent->last_child);
  52. fprintf(stderr, " BEFORE: parent->prev=%p\n", parent->prev);
  53. fprintf(stderr, " BEFORE: parent->next=%p\n", parent->next);
  54. }
  55. #endif /* DEBUG > 1 */
  56. /*
  57. * Remove the node from any existing parent...
  58. */
  59. if (node->parent)
  60. mxmlRemove(node);
  61. /*
  62. * Reset pointers...
  63. */
  64. node->parent = parent;
  65. switch (where)
  66. {
  67. case MXML_ADD_BEFORE :
  68. if (!child || child == parent->child || child->parent != parent)
  69. {
  70. /*
  71. * Insert as first node under parent...
  72. */
  73. node->next = parent->child;
  74. if (parent->child)
  75. parent->child->prev = node;
  76. else
  77. parent->last_child = node;
  78. parent->child = node;
  79. }
  80. else
  81. {
  82. /*
  83. * Insert node before this child...
  84. */
  85. node->next = child;
  86. node->prev = child->prev;
  87. if (child->prev)
  88. child->prev->next = node;
  89. else
  90. parent->child = node;
  91. child->prev = node;
  92. }
  93. break;
  94. case MXML_ADD_AFTER :
  95. if (!child || child == parent->last_child || child->parent != parent)
  96. {
  97. /*
  98. * Insert as last node under parent...
  99. */
  100. node->parent = parent;
  101. node->prev = parent->last_child;
  102. if (parent->last_child)
  103. parent->last_child->next = node;
  104. else
  105. parent->child = node;
  106. parent->last_child = node;
  107. }
  108. else
  109. {
  110. /*
  111. * Insert node after this child...
  112. */
  113. node->prev = child;
  114. node->next = child->next;
  115. if (child->next)
  116. child->next->prev = node;
  117. else
  118. parent->last_child = node;
  119. child->next = node;
  120. }
  121. break;
  122. }
  123. #if DEBUG > 1
  124. fprintf(stderr, " AFTER: node->parent=%p\n", node->parent);
  125. if (parent)
  126. {
  127. fprintf(stderr, " AFTER: parent->child=%p\n", parent->child);
  128. fprintf(stderr, " AFTER: parent->last_child=%p\n", parent->last_child);
  129. fprintf(stderr, " AFTER: parent->prev=%p\n", parent->prev);
  130. fprintf(stderr, " AFTER: parent->next=%p\n", parent->next);
  131. }
  132. #endif /* DEBUG > 1 */
  133. }
  134. /*
  135. * 'mxmlDelete()' - Delete a node and all of its children.
  136. *
  137. * If the specified node has a parent, this function first removes the
  138. * node from its parent using the @link mxmlRemove@ function.
  139. */
  140. void
  141. mxmlDelete(mxml_node_t *node) /* I - Node to delete */
  142. {
  143. mxml_node_t *current, /* Current node */
  144. *next; /* Next node */
  145. #ifdef DEBUG
  146. fprintf(stderr, "mxmlDelete(node=%p)\n", node);
  147. #endif /* DEBUG */
  148. /*
  149. * Range check input...
  150. */
  151. if (!node)
  152. return;
  153. /*
  154. * Remove the node from its parent, if any...
  155. */
  156. mxmlRemove(node);
  157. /*
  158. * Delete children...
  159. */
  160. for (current = node->child; current; current = next)
  161. {
  162. /*
  163. * Get the next node...
  164. */
  165. if ((next = current->child) != NULL)
  166. {
  167. /*
  168. * Free parent nodes after child nodes have been freed...
  169. */
  170. current->child = NULL;
  171. continue;
  172. }
  173. if ((next = current->next) == NULL)
  174. {
  175. /*
  176. * Next node is the parent, which we'll free as needed...
  177. */
  178. if ((next = current->parent) == node)
  179. next = NULL;
  180. }
  181. /*
  182. * Free child...
  183. */
  184. mxml_free(current);
  185. }
  186. /*
  187. * Then free the memory used by the parent node...
  188. */
  189. mxml_free(node);
  190. }
  191. /*
  192. * 'mxmlGetRefCount()' - Get the current reference (use) count for a node.
  193. *
  194. * The initial reference count of new nodes is 1. Use the @link mxmlRetain@
  195. * and @link mxmlRelease@ functions to increment and decrement a node's
  196. * reference count.
  197. *
  198. * @since Mini-XML 2.7@.
  199. */
  200. int /* O - Reference count */
  201. mxmlGetRefCount(mxml_node_t *node) /* I - Node */
  202. {
  203. /*
  204. * Range check input...
  205. */
  206. if (!node)
  207. return (0);
  208. /*
  209. * Return the reference count...
  210. */
  211. return (node->ref_count);
  212. }
  213. /*
  214. * 'mxmlNewCDATA()' - Create a new CDATA node.
  215. *
  216. * The new CDATA node is added to the end of the specified parent's child
  217. * list. The constant @code MXML_NO_PARENT@ can be used to specify that the new
  218. * CDATA node has no parent. The data string must be nul-terminated and
  219. * is copied into the new node. CDATA nodes currently use the
  220. * @code MXML_ELEMENT@ type.
  221. *
  222. * @since Mini-XML 2.3@
  223. */
  224. mxml_node_t * /* O - New node */
  225. mxmlNewCDATA(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */
  226. const char *data) /* I - Data string */
  227. {
  228. mxml_node_t *node; /* New node */
  229. #ifdef DEBUG
  230. fprintf(stderr, "mxmlNewCDATA(parent=%p, data=\"%s\")\n",
  231. parent, data ? data : "(null)");
  232. #endif /* DEBUG */
  233. /*
  234. * Range check input...
  235. */
  236. if (!data)
  237. return (NULL);
  238. /*
  239. * Create the node and set the name value...
  240. */
  241. if ((node = mxml_new(parent, MXML_ELEMENT)) != NULL)
  242. node->value.element.name = _mxml_strdupf("![CDATA[%s", data);
  243. return (node);
  244. }
  245. /*
  246. * 'mxmlNewCustom()' - Create a new custom data node.
  247. *
  248. * The new custom node is added to the end of the specified parent's child
  249. * list. The constant @code MXML_NO_PARENT@ can be used to specify that the new
  250. * element node has no parent. @code NULL@ can be passed when the data in the
  251. * node is not dynamically allocated or is separately managed.
  252. *
  253. * @since Mini-XML 2.1@
  254. */
  255. mxml_node_t * /* O - New node */
  256. mxmlNewCustom(
  257. mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */
  258. void *data, /* I - Pointer to data */
  259. mxml_custom_destroy_cb_t destroy) /* I - Function to destroy data */
  260. {
  261. mxml_node_t *node; /* New node */
  262. #ifdef DEBUG
  263. fprintf(stderr, "mxmlNewCustom(parent=%p, data=%p, destroy=%p)\n", parent,
  264. data, destroy);
  265. #endif /* DEBUG */
  266. /*
  267. * Create the node and set the value...
  268. */
  269. if ((node = mxml_new(parent, MXML_CUSTOM)) != NULL)
  270. {
  271. node->value.custom.data = data;
  272. node->value.custom.destroy = destroy;
  273. }
  274. return (node);
  275. }
  276. /*
  277. * 'mxmlNewElement()' - Create a new element node.
  278. *
  279. * The new element node is added to the end of the specified parent's child
  280. * list. The constant @code MXML_NO_PARENT@ can be used to specify that the new
  281. * element node has no parent.
  282. */
  283. mxml_node_t * /* O - New node */
  284. mxmlNewElement(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */
  285. const char *name) /* I - Name of element */
  286. {
  287. mxml_node_t *node; /* New node */
  288. #ifdef DEBUG
  289. fprintf(stderr, "mxmlNewElement(parent=%p, name=\"%s\")\n", parent,
  290. name ? name : "(null)");
  291. #endif /* DEBUG */
  292. /*
  293. * Range check input...
  294. */
  295. if (!name)
  296. return (NULL);
  297. /*
  298. * Create the node and set the element name...
  299. */
  300. if ((node = mxml_new(parent, MXML_ELEMENT)) != NULL)
  301. node->value.element.name = strdup(name);
  302. return (node);
  303. }
  304. /*
  305. * 'mxmlNewInteger()' - Create a new integer node.
  306. *
  307. * The new integer node is added to the end of the specified parent's child
  308. * list. The constant @code MXML_NO_PARENT@ can be used to specify that the new
  309. * integer node has no parent.
  310. */
  311. mxml_node_t * /* O - New node */
  312. mxmlNewInteger(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */
  313. int integer) /* I - Integer value */
  314. {
  315. mxml_node_t *node; /* New node */
  316. #ifdef DEBUG
  317. fprintf(stderr, "mxmlNewInteger(parent=%p, integer=%d)\n", parent, integer);
  318. #endif /* DEBUG */
  319. /*
  320. * Create the node and set the element name...
  321. */
  322. if ((node = mxml_new(parent, MXML_INTEGER)) != NULL)
  323. node->value.integer = integer;
  324. return (node);
  325. }
  326. /*
  327. * 'mxmlNewOpaque()' - Create a new opaque string.
  328. *
  329. * The new opaque string node is added to the end of the specified parent's
  330. * child list. The constant @code MXML_NO_PARENT@ can be used to specify that
  331. * the new opaque string node has no parent. The opaque string must be nul-
  332. * terminated and is copied into the new node.
  333. */
  334. mxml_node_t * /* O - New node */
  335. mxmlNewOpaque(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */
  336. const char *opaque) /* I - Opaque string */
  337. {
  338. mxml_node_t *node; /* New node */
  339. #ifdef DEBUG
  340. fprintf(stderr, "mxmlNewOpaque(parent=%p, opaque=\"%s\")\n", parent,
  341. opaque ? opaque : "(null)");
  342. #endif /* DEBUG */
  343. /*
  344. * Range check input...
  345. */
  346. if (!opaque)
  347. return (NULL);
  348. /*
  349. * Create the node and set the element name...
  350. */
  351. if ((node = mxml_new(parent, MXML_OPAQUE)) != NULL)
  352. node->value.opaque = strdup(opaque);
  353. return (node);
  354. }
  355. /*
  356. * 'mxmlNewOpaquef()' - Create a new formatted opaque string node.
  357. *
  358. * The new opaque string node is added to the end of the specified parent's
  359. * child list. The constant @code MXML_NO_PARENT@ can be used to specify that
  360. * the new opaque string node has no parent. The format string must be
  361. * nul-terminated and is formatted into the new node.
  362. */
  363. mxml_node_t * /* O - New node */
  364. mxmlNewOpaquef(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */
  365. const char *format, /* I - Printf-style format string */
  366. ...) /* I - Additional args as needed */
  367. {
  368. mxml_node_t *node; /* New node */
  369. va_list ap; /* Pointer to arguments */
  370. #ifdef DEBUG
  371. fprintf(stderr, "mxmlNewOpaquef(parent=%p, format=\"%s\", ...)\n", parent, format ? format : "(null)");
  372. #endif /* DEBUG */
  373. /*
  374. * Range check input...
  375. */
  376. if (!format)
  377. return (NULL);
  378. /*
  379. * Create the node and set the text value...
  380. */
  381. if ((node = mxml_new(parent, MXML_OPAQUE)) != NULL)
  382. {
  383. va_start(ap, format);
  384. node->value.opaque = _mxml_vstrdupf(format, ap);
  385. va_end(ap);
  386. }
  387. return (node);
  388. }
  389. /*
  390. * 'mxmlNewReal()' - Create a new real number node.
  391. *
  392. * The new real number node is added to the end of the specified parent's
  393. * child list. The constant @code MXML_NO_PARENT@ can be used to specify that
  394. * the new real number node has no parent.
  395. */
  396. mxml_node_t * /* O - New node */
  397. mxmlNewReal(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */
  398. double real) /* I - Real number value */
  399. {
  400. mxml_node_t *node; /* New node */
  401. #ifdef DEBUG
  402. fprintf(stderr, "mxmlNewReal(parent=%p, real=%g)\n", parent, real);
  403. #endif /* DEBUG */
  404. /*
  405. * Create the node and set the element name...
  406. */
  407. if ((node = mxml_new(parent, MXML_REAL)) != NULL)
  408. node->value.real = real;
  409. return (node);
  410. }
  411. /*
  412. * 'mxmlNewText()' - Create a new text fragment node.
  413. *
  414. * The new text node is added to the end of the specified parent's child
  415. * list. The constant @code MXML_NO_PARENT@ can be used to specify that the new
  416. * text node has no parent. The whitespace parameter is used to specify
  417. * whether leading whitespace is present before the node. The text
  418. * string must be nul-terminated and is copied into the new node.
  419. */
  420. mxml_node_t * /* O - New node */
  421. mxmlNewText(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */
  422. int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */
  423. const char *string) /* I - String */
  424. {
  425. mxml_node_t *node; /* New node */
  426. #ifdef DEBUG
  427. fprintf(stderr, "mxmlNewText(parent=%p, whitespace=%d, string=\"%s\")\n",
  428. parent, whitespace, string ? string : "(null)");
  429. #endif /* DEBUG */
  430. /*
  431. * Range check input...
  432. */
  433. if (!string)
  434. return (NULL);
  435. /*
  436. * Create the node and set the text value...
  437. */
  438. if ((node = mxml_new(parent, MXML_TEXT)) != NULL)
  439. {
  440. node->value.text.whitespace = whitespace;
  441. node->value.text.string = strdup(string);
  442. }
  443. return (node);
  444. }
  445. /*
  446. * 'mxmlNewTextf()' - Create a new formatted text fragment node.
  447. *
  448. * The new text node is added to the end of the specified parent's child
  449. * list. The constant @code MXML_NO_PARENT@ can be used to specify that the new
  450. * text node has no parent. The whitespace parameter is used to specify
  451. * whether leading whitespace is present before the node. The format
  452. * string must be nul-terminated and is formatted into the new node.
  453. */
  454. mxml_node_t * /* O - New node */
  455. mxmlNewTextf(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */
  456. int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */
  457. const char *format, /* I - Printf-style format string */
  458. ...) /* I - Additional args as needed */
  459. {
  460. mxml_node_t *node; /* New node */
  461. va_list ap; /* Pointer to arguments */
  462. #ifdef DEBUG
  463. fprintf(stderr, "mxmlNewTextf(parent=%p, whitespace=%d, format=\"%s\", ...)\n",
  464. parent, whitespace, format ? format : "(null)");
  465. #endif /* DEBUG */
  466. /*
  467. * Range check input...
  468. */
  469. if (!format)
  470. return (NULL);
  471. /*
  472. * Create the node and set the text value...
  473. */
  474. if ((node = mxml_new(parent, MXML_TEXT)) != NULL)
  475. {
  476. va_start(ap, format);
  477. node->value.text.whitespace = whitespace;
  478. node->value.text.string = _mxml_vstrdupf(format, ap);
  479. va_end(ap);
  480. }
  481. return (node);
  482. }
  483. /*
  484. * 'mxmlRemove()' - Remove a node from its parent.
  485. *
  486. * This function does not free memory used by the node - use @link mxmlDelete@
  487. * for that. This function does nothing if the node has no parent.
  488. */
  489. void
  490. mxmlRemove(mxml_node_t *node) /* I - Node to remove */
  491. {
  492. #ifdef DEBUG
  493. fprintf(stderr, "mxmlRemove(node=%p)\n", node);
  494. #endif /* DEBUG */
  495. /*
  496. * Range check input...
  497. */
  498. if (!node || !node->parent)
  499. return;
  500. /*
  501. * Remove from parent...
  502. */
  503. #if DEBUG > 1
  504. fprintf(stderr, " BEFORE: node->parent=%p\n", node->parent);
  505. if (node->parent)
  506. {
  507. fprintf(stderr, " BEFORE: node->parent->child=%p\n", node->parent->child);
  508. fprintf(stderr, " BEFORE: node->parent->last_child=%p\n", node->parent->last_child);
  509. }
  510. fprintf(stderr, " BEFORE: node->child=%p\n", node->child);
  511. fprintf(stderr, " BEFORE: node->last_child=%p\n", node->last_child);
  512. fprintf(stderr, " BEFORE: node->prev=%p\n", node->prev);
  513. fprintf(stderr, " BEFORE: node->next=%p\n", node->next);
  514. #endif /* DEBUG > 1 */
  515. if (node->prev)
  516. node->prev->next = node->next;
  517. else
  518. node->parent->child = node->next;
  519. if (node->next)
  520. node->next->prev = node->prev;
  521. else
  522. node->parent->last_child = node->prev;
  523. node->parent = NULL;
  524. node->prev = NULL;
  525. node->next = NULL;
  526. #if DEBUG > 1
  527. fprintf(stderr, " AFTER: node->parent=%p\n", node->parent);
  528. if (node->parent)
  529. {
  530. fprintf(stderr, " AFTER: node->parent->child=%p\n", node->parent->child);
  531. fprintf(stderr, " AFTER: node->parent->last_child=%p\n", node->parent->last_child);
  532. }
  533. fprintf(stderr, " AFTER: node->child=%p\n", node->child);
  534. fprintf(stderr, " AFTER: node->last_child=%p\n", node->last_child);
  535. fprintf(stderr, " AFTER: node->prev=%p\n", node->prev);
  536. fprintf(stderr, " AFTER: node->next=%p\n", node->next);
  537. #endif /* DEBUG > 1 */
  538. }
  539. /*
  540. * 'mxmlNewXML()' - Create a new XML document tree.
  541. *
  542. * The "version" argument specifies the version number to put in the
  543. * ?xml element node. If @code NULL@, version "1.0" is assumed.
  544. *
  545. * @since Mini-XML 2.3@
  546. */
  547. mxml_node_t * /* O - New ?xml node */
  548. mxmlNewXML(const char *version) /* I - Version number to use */
  549. {
  550. char element[1024]; /* Element text */
  551. snprintf(element, sizeof(element), "?xml version=\"%s\" encoding=\"utf-8\"?",
  552. version ? version : "1.0");
  553. return (mxmlNewElement(NULL, element));
  554. }
  555. /*
  556. * 'mxmlRelease()' - Release a node.
  557. *
  558. * When the reference count reaches zero, the node (and any children)
  559. * is deleted via @link mxmlDelete@.
  560. *
  561. * @since Mini-XML 2.3@
  562. */
  563. int /* O - New reference count */
  564. mxmlRelease(mxml_node_t *node) /* I - Node */
  565. {
  566. if (node)
  567. {
  568. if ((-- node->ref_count) <= 0)
  569. {
  570. mxmlDelete(node);
  571. return (0);
  572. }
  573. else
  574. return (node->ref_count);
  575. }
  576. else
  577. return (-1);
  578. }
  579. /*
  580. * 'mxmlRetain()' - Retain a node.
  581. *
  582. * @since Mini-XML 2.3@
  583. */
  584. int /* O - New reference count */
  585. mxmlRetain(mxml_node_t *node) /* I - Node */
  586. {
  587. if (node)
  588. return (++ node->ref_count);
  589. else
  590. return (-1);
  591. }
  592. /*
  593. * 'mxml_free()' - Free the memory used by a node.
  594. *
  595. * Note: Does not free child nodes, does not remove from parent.
  596. */
  597. static void
  598. mxml_free(mxml_node_t *node) /* I - Node */
  599. {
  600. int i; /* Looping var */
  601. switch (node->type)
  602. {
  603. case MXML_ELEMENT :
  604. if (node->value.element.name)
  605. free(node->value.element.name);
  606. if (node->value.element.num_attrs)
  607. {
  608. for (i = 0; i < node->value.element.num_attrs; i ++)
  609. {
  610. if (node->value.element.attrs[i].name)
  611. free(node->value.element.attrs[i].name);
  612. if (node->value.element.attrs[i].value)
  613. free(node->value.element.attrs[i].value);
  614. }
  615. free(node->value.element.attrs);
  616. }
  617. break;
  618. case MXML_INTEGER :
  619. /* Nothing to do */
  620. break;
  621. case MXML_OPAQUE :
  622. if (node->value.opaque)
  623. free(node->value.opaque);
  624. break;
  625. case MXML_REAL :
  626. /* Nothing to do */
  627. break;
  628. case MXML_TEXT :
  629. if (node->value.text.string)
  630. free(node->value.text.string);
  631. break;
  632. case MXML_CUSTOM :
  633. if (node->value.custom.data &&
  634. node->value.custom.destroy)
  635. (*(node->value.custom.destroy))(node->value.custom.data);
  636. break;
  637. default :
  638. break;
  639. }
  640. /*
  641. * Free this node...
  642. */
  643. free(node);
  644. }
  645. /*
  646. * 'mxml_new()' - Create a new node.
  647. */
  648. static mxml_node_t * /* O - New node */
  649. mxml_new(mxml_node_t *parent, /* I - Parent node */
  650. mxml_type_t type) /* I - Node type */
  651. {
  652. mxml_node_t *node; /* New node */
  653. #if DEBUG > 1
  654. fprintf(stderr, "mxml_new(parent=%p, type=%d)\n", parent, type);
  655. #endif /* DEBUG > 1 */
  656. /*
  657. * Allocate memory for the node...
  658. */
  659. if ((node = calloc(1, sizeof(mxml_node_t))) == NULL)
  660. {
  661. #if DEBUG > 1
  662. fputs(" returning NULL\n", stderr);
  663. #endif /* DEBUG > 1 */
  664. return (NULL);
  665. }
  666. #if DEBUG > 1
  667. fprintf(stderr, " returning %p\n", node);
  668. #endif /* DEBUG > 1 */
  669. /*
  670. * Set the node type...
  671. */
  672. node->type = type;
  673. node->ref_count = 1;
  674. /*
  675. * Add to the parent if present...
  676. */
  677. if (parent)
  678. mxmlAdd(parent, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, node);
  679. /*
  680. * Return the new node...
  681. */
  682. return (node);
  683. }