xode.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  1. /*
  2. * $Id$
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. *
  18. * Jabber
  19. * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
  20. */
  21. /*! \file
  22. * \ingroup xmpp
  23. */
  24. #include "xode.h"
  25. static int _xode_strcmp(const char *a, const char *b)
  26. {
  27. if(a == NULL || b == NULL) return -1;
  28. return strcmp(a,b);
  29. }
  30. /*! \brief Internal routines */
  31. static xode _xode_new(xode_pool p, const char* name, unsigned int type)
  32. {
  33. xode result = NULL;
  34. if (type > XODE_TYPE_LAST)
  35. return NULL;
  36. if (type != XODE_TYPE_CDATA && name == NULL)
  37. return NULL;
  38. if (p == NULL)
  39. {
  40. p = xode_pool_heap(1*1024);
  41. }
  42. /* Allocate & zero memory */
  43. result = (xode)xode_pool_malloc(p, sizeof(_xode));
  44. memset(result, '\0', sizeof(_xode));
  45. /* Initialize fields */
  46. if (type != XODE_TYPE_CDATA)
  47. result->name = xode_pool_strdup(p,name);
  48. result->type = type;
  49. result->p = p;
  50. return result;
  51. }
  52. static xode _xode_appendsibling(xode lastsibling, const char* name, unsigned int type)
  53. {
  54. xode result;
  55. result = _xode_new(xode_get_pool(lastsibling), name, type);
  56. if (result != NULL)
  57. {
  58. /* Setup sibling pointers */
  59. result->prev = lastsibling;
  60. lastsibling->next = result;
  61. }
  62. return result;
  63. }
  64. static xode _xode_insert(xode parent, const char* name, unsigned int type)
  65. {
  66. xode result;
  67. if(parent == NULL || name == NULL) return NULL;
  68. /* If parent->firstchild is NULL, simply create a new node for the first child */
  69. if (parent->firstchild == NULL)
  70. {
  71. result = _xode_new(parent->p, name, type);
  72. parent->firstchild = result;
  73. }
  74. /* Otherwise, append this to the lastchild */
  75. else
  76. {
  77. result= _xode_appendsibling(parent->lastchild, name, type);
  78. }
  79. result->parent = parent;
  80. parent->lastchild = result;
  81. return result;
  82. }
  83. static xode _xode_search(xode firstsibling, const char* name, unsigned int type)
  84. {
  85. xode current;
  86. /* Walk the sibling list, looking for a XODE_TYPE_TAG xode with
  87. the specified name */
  88. current = firstsibling;
  89. while (current != NULL)
  90. {
  91. if (name != NULL && (current->type == type) && (_xode_strcmp(current->name, name) == 0))
  92. return current;
  93. else
  94. current = current->next;
  95. }
  96. return NULL;
  97. }
  98. static char* _xode_merge(xode_pool p, char* dest, unsigned int destsize, const char* src, unsigned int srcsize)
  99. {
  100. char* result;
  101. result = (char*)xode_pool_malloc(p, destsize + srcsize + 1);
  102. memcpy(result, dest, destsize);
  103. memcpy(result+destsize, src, srcsize);
  104. result[destsize + srcsize] = '\0';
  105. /* WARNING: major ugly hack: since we're throwing the old data away, let's jump in the xode_pool and subtract it from the size, this is for xmlstream's big-node checking */
  106. p->size -= destsize;
  107. return result;
  108. }
  109. static void _xode_hidesibling(xode child)
  110. {
  111. if(child == NULL)
  112. return;
  113. if(child->prev != NULL)
  114. child->prev->next = child->next;
  115. if(child->next != NULL)
  116. child->next->prev = child->prev;
  117. }
  118. static void _xode_tag2str(xode_spool s, xode node, int flag)
  119. {
  120. xode tmp;
  121. if(flag==0 || flag==1)
  122. {
  123. xode_spooler(s,"<",xode_get_name(node),s);
  124. tmp = xode_get_firstattrib(node);
  125. while(tmp) {
  126. xode_spooler(s," ",xode_get_name(tmp),"='",xode_strescape(xode_get_pool(node),xode_get_data(tmp)),"'",s);
  127. tmp = xode_get_nextsibling(tmp);
  128. }
  129. if(flag==0)
  130. xode_spool_add(s,"/>");
  131. else
  132. xode_spool_add(s,">");
  133. }
  134. else
  135. {
  136. xode_spooler(s,"</",xode_get_name(node),">",s);
  137. }
  138. }
  139. static xode_spool _xode_tospool(xode node)
  140. {
  141. xode_spool s;
  142. int level=0,dir=0;
  143. xode tmp;
  144. if(!node || xode_get_type(node) != XODE_TYPE_TAG)
  145. return NULL;
  146. s = xode_spool_newfrompool(xode_get_pool(node));
  147. if(!s) return(NULL);
  148. while(1)
  149. {
  150. if(dir==0)
  151. {
  152. if(xode_get_type(node) == XODE_TYPE_TAG)
  153. {
  154. if(xode_has_children(node))
  155. {
  156. _xode_tag2str(s,node,1);
  157. node = xode_get_firstchild(node);
  158. level++;
  159. continue;
  160. }
  161. else
  162. {
  163. _xode_tag2str(s,node,0);
  164. }
  165. }
  166. else
  167. {
  168. xode_spool_add(s,xode_strescape(xode_get_pool(node),xode_get_data(node)));
  169. }
  170. }
  171. tmp = xode_get_nextsibling(node);
  172. if(!tmp)
  173. {
  174. node = xode_get_parent(node);
  175. level--;
  176. if(level>=0) _xode_tag2str(s,node,2);
  177. if(level<1) break;
  178. dir = 1;
  179. }
  180. else
  181. {
  182. node = tmp;
  183. dir = 0;
  184. }
  185. }
  186. return s;
  187. }
  188. /* External routines */
  189. /*
  190. * xode_new_tag -- create a tag node
  191. * Automatically creates a memory xode_pool for the node.
  192. *
  193. * parameters
  194. * name -- name of the tag
  195. *
  196. * returns
  197. * a pointer to the tag node
  198. * or NULL if it was unsuccessful
  199. */
  200. xode xode_new(const char* name)
  201. {
  202. return _xode_new(NULL, name, XODE_TYPE_TAG);
  203. }
  204. /*
  205. * alias for 'xode_new'
  206. */
  207. xode xode_new_tag(const char* name)
  208. {
  209. return _xode_new(NULL, name, XODE_TYPE_TAG);
  210. }
  211. /*
  212. * xode_new_tag_pool -- create a tag node within given pool
  213. *
  214. * parameters
  215. * p -- previously created memory pool
  216. * name -- name of the tag
  217. *
  218. * returns
  219. * a pointer to the tag node
  220. * or NULL if it was unsuccessful
  221. */
  222. xode xode_new_frompool(xode_pool p, const char* name)
  223. {
  224. return _xode_new(p, name, XODE_TYPE_TAG);
  225. }
  226. /*
  227. * xode_insert_tag -- append a child tag to a tag
  228. *
  229. * parameters
  230. * parent -- pointer to the parent tag
  231. * name -- name of the child tag
  232. *
  233. * returns
  234. * a pointer to the child tag node
  235. * or NULL if it was unsuccessful
  236. */
  237. xode xode_insert_tag(xode parent, const char* name)
  238. {
  239. return _xode_insert(parent, name, XODE_TYPE_TAG);
  240. }
  241. /*
  242. * xode_insert_cdata -- append character data to a tag
  243. * If last child of the parent is CDATA, merges CDATA nodes. Otherwise
  244. * creates a CDATA node, and appends it to the parent's child list.
  245. *
  246. * parameters
  247. * parent -- parent tag
  248. * CDATA -- character data
  249. * size -- size of CDATA
  250. * or -1 for null-terminated CDATA strings
  251. *
  252. * returns
  253. * a pointer to the child CDATA node
  254. * or NULL if it was unsuccessful
  255. */
  256. xode xode_insert_cdata(xode parent, const char* CDATA, unsigned int size)
  257. {
  258. xode result;
  259. if(CDATA == NULL || parent == NULL)
  260. return NULL;
  261. if(size == -1)
  262. size = strlen(CDATA);
  263. if ((parent->lastchild != NULL) && (parent->lastchild->type == XODE_TYPE_CDATA))
  264. {
  265. result = parent->lastchild;
  266. result->data = _xode_merge(result->p, result->data, result->data_sz, CDATA, size);
  267. result->data_sz = result->data_sz + size;
  268. }
  269. else
  270. {
  271. result = _xode_insert(parent, "", XODE_TYPE_CDATA);
  272. if (result != NULL)
  273. {
  274. result->data = (char*)xode_pool_malloc(result->p, size + 1);
  275. memcpy(result->data, CDATA, size);
  276. result->data[size] = '\0';
  277. result->data_sz = size;
  278. }
  279. }
  280. return result;
  281. }
  282. /*
  283. * xode_gettag -- find given tag in an xode tree
  284. *
  285. * parameters
  286. * parent -- pointer to the parent tag
  287. * name -- "name" for the child tag of that name
  288. * "name/name" for a sub child (recurses)
  289. * "?attrib" to match the first tag with that attrib defined
  290. * "?attrib=value" to match the first tag with that attrib and value
  291. * or any combination: "name/name/?attrib", etc
  292. *
  293. * results
  294. * a pointer to the tag matching search criteria
  295. * or NULL if search was unsuccessful
  296. */
  297. xode xode_get_tag(xode parent, const char* name)
  298. {
  299. char *str, *slash, *qmark, *equals;
  300. xode step, ret;
  301. if(parent == NULL || parent->firstchild == NULL || name == NULL || name == '\0') return NULL;
  302. if(strstr(name, "/") == NULL && strstr(name,"?") == NULL)
  303. return _xode_search(parent->firstchild, name, XODE_TYPE_TAG);
  304. /* jer's note: why can't I modify the name directly, why do I have to strdup it? damn c grrr! */
  305. str = strdup(name);
  306. slash = strstr(str, "/");
  307. qmark = strstr(str, "?");
  308. equals = strstr(str, "=");
  309. if(qmark != NULL && (slash == NULL || qmark < slash))
  310. { /* of type ?attrib */
  311. *qmark = '\0';
  312. qmark++;
  313. if(equals != NULL)
  314. {
  315. *equals = '\0';
  316. equals++;
  317. }
  318. for(step = parent->firstchild; step != NULL; step = xode_get_nextsibling(step))
  319. {
  320. if(xode_get_type(step) != XODE_TYPE_TAG)
  321. continue;
  322. if(*str != '\0')
  323. if(_xode_strcmp(xode_get_name(step),str) != 0)
  324. continue;
  325. if(xode_get_attrib(step,qmark) == NULL)
  326. continue;
  327. if(equals != NULL && _xode_strcmp(xode_get_attrib(step,qmark),equals) != 0)
  328. continue;
  329. break;
  330. }
  331. free(str);
  332. return step;
  333. }
  334. *slash = '\0';
  335. ++slash;
  336. for(step = parent->firstchild; step != NULL; step = xode_get_nextsibling(step))
  337. {
  338. if(xode_get_type(step) != XODE_TYPE_TAG) continue;
  339. if(_xode_strcmp(xode_get_name(step),str) != 0)
  340. continue;
  341. ret = xode_get_tag(step, slash);
  342. if(ret != NULL)
  343. {
  344. free(str);
  345. return ret;
  346. }
  347. }
  348. free(str);
  349. return NULL;
  350. }
  351. /* return the cdata from any tag */
  352. char *xode_get_tagdata(xode parent, const char *name)
  353. {
  354. xode tag;
  355. tag = xode_get_tag(parent, name);
  356. if(tag == NULL) return NULL;
  357. return xode_get_data(tag);
  358. }
  359. void xode_put_attrib(xode owner, const char* name, const char* value)
  360. {
  361. xode attrib;
  362. if(owner == NULL || name == NULL || value == NULL) return;
  363. /* If there are no existing attributes, allocate a new one to start
  364. the list */
  365. if (owner->firstattrib == NULL)
  366. {
  367. attrib = _xode_new(owner->p, name, XODE_TYPE_ATTRIB);
  368. owner->firstattrib = attrib;
  369. owner->lastattrib = attrib;
  370. }
  371. else
  372. {
  373. attrib = _xode_search(owner->firstattrib, name, XODE_TYPE_ATTRIB);
  374. if(attrib == NULL)
  375. {
  376. attrib = _xode_appendsibling(owner->lastattrib, name, XODE_TYPE_ATTRIB);
  377. owner->lastattrib = attrib;
  378. }
  379. }
  380. /* Update the value of the attribute */
  381. attrib->data_sz = strlen(value);
  382. attrib->data = xode_pool_strdup(owner->p, value);
  383. }
  384. char* xode_get_attrib(xode owner, const char* name)
  385. {
  386. xode attrib;
  387. if (owner != NULL && owner->firstattrib != NULL)
  388. {
  389. attrib = _xode_search(owner->firstattrib, name, XODE_TYPE_ATTRIB);
  390. if (attrib != NULL)
  391. return (char*)attrib->data;
  392. }
  393. return NULL;
  394. }
  395. void xode_put_vattrib(xode owner, const char* name, void *value)
  396. {
  397. xode attrib;
  398. if (owner != NULL)
  399. {
  400. attrib = _xode_search(owner->firstattrib, name, XODE_TYPE_ATTRIB);
  401. if (attrib == NULL)
  402. {
  403. xode_put_attrib(owner, name, "");
  404. attrib = _xode_search(owner->firstattrib, name, XODE_TYPE_ATTRIB);
  405. }
  406. if (attrib != NULL)
  407. attrib->firstchild = (xode)value;
  408. }
  409. }
  410. void* xode_get_vattrib(xode owner, const char* name)
  411. {
  412. xode attrib;
  413. if (owner != NULL && owner->firstattrib != NULL)
  414. {
  415. attrib = _xode_search(owner->firstattrib, name, XODE_TYPE_ATTRIB);
  416. if (attrib != NULL)
  417. return (void*)attrib->firstchild;
  418. }
  419. return NULL;
  420. }
  421. xode xode_get_firstattrib(xode parent)
  422. {
  423. if (parent != NULL)
  424. return parent->firstattrib;
  425. return NULL;
  426. }
  427. xode xode_get_firstchild(xode parent)
  428. {
  429. if (parent != NULL)
  430. return parent->firstchild;
  431. return NULL;
  432. }
  433. xode xode_get_lastchild(xode parent)
  434. {
  435. if (parent != NULL)
  436. return parent->lastchild;
  437. return NULL;
  438. }
  439. xode xode_get_nextsibling(xode sibling)
  440. {
  441. if (sibling != NULL)
  442. return sibling->next;
  443. return NULL;
  444. }
  445. xode xode_get_prevsibling(xode sibling)
  446. {
  447. if (sibling != NULL)
  448. return sibling->prev;
  449. return NULL;
  450. }
  451. xode xode_get_parent(xode node)
  452. {
  453. if (node != NULL)
  454. return node->parent;
  455. return NULL;
  456. }
  457. char* xode_get_name(xode node)
  458. {
  459. if (node != NULL)
  460. return node->name;
  461. return NULL;
  462. }
  463. char* xode_get_data(xode node)
  464. {
  465. xode cur;
  466. if(node == NULL) return NULL;
  467. if(xode_get_type(node) == XODE_TYPE_TAG) /* loop till we find a CDATA */
  468. {
  469. for(cur = xode_get_firstchild(node); cur != NULL; cur = xode_get_nextsibling(cur))
  470. if(xode_get_type(cur) == XODE_TYPE_CDATA)
  471. return cur->data;
  472. }else{
  473. return node->data;
  474. }
  475. return NULL;
  476. }
  477. int xode_get_datasz(xode node)
  478. {
  479. if( node == NULL )
  480. {
  481. return (int)(long)NULL;
  482. }
  483. else if(xode_get_type(node) == XODE_TYPE_TAG) /* loop till we find a CDATA */
  484. {
  485. xode cur;
  486. for(cur = xode_get_firstchild(node); cur != NULL; cur = xode_get_nextsibling(cur))
  487. if(xode_get_type(cur) == XODE_TYPE_CDATA)
  488. return cur->data_sz;
  489. }else{
  490. return node->data_sz;
  491. }
  492. return (int)(long)NULL;
  493. }
  494. int xode_get_type(xode node)
  495. {
  496. if (node != NULL)
  497. {
  498. return node->type;
  499. }
  500. return (int)(long)NULL;
  501. }
  502. int xode_has_children(xode node)
  503. {
  504. if ((node != NULL) && (node->firstchild != NULL))
  505. return 1;
  506. return 0;
  507. }
  508. int xode_has_attribs(xode node)
  509. {
  510. if ((node != NULL) && (node->firstattrib != NULL))
  511. return 1;
  512. return 0;
  513. }
  514. xode_pool xode_get_pool(xode node)
  515. {
  516. if (node != NULL)
  517. return node->p;
  518. return (xode_pool)NULL;
  519. }
  520. void xode_hide(xode child)
  521. {
  522. xode parent;
  523. if(child == NULL || child->parent == NULL)
  524. return;
  525. parent = child->parent;
  526. /* first fix up at the child level */
  527. _xode_hidesibling(child);
  528. /* next fix up at the parent level */
  529. if(parent->firstchild == child)
  530. parent->firstchild = child->next;
  531. if(parent->lastchild == child)
  532. parent->lastchild = child->prev;
  533. }
  534. void xode_hide_attrib(xode parent, const char *name)
  535. {
  536. xode attrib;
  537. if(parent == NULL || parent->firstattrib == NULL || name == NULL)
  538. return;
  539. attrib = _xode_search(parent->firstattrib, name, XODE_TYPE_ATTRIB);
  540. if(attrib == NULL)
  541. return;
  542. /* first fix up at the child level */
  543. _xode_hidesibling(attrib);
  544. /* next fix up at the parent level */
  545. if(parent->firstattrib == attrib)
  546. parent->firstattrib = attrib->next;
  547. if(parent->lastattrib == attrib)
  548. parent->lastattrib = attrib->prev;
  549. }
  550. /*
  551. * xode2str -- convert given xode tree into a string
  552. *
  553. * parameters
  554. * node -- pointer to the xode structure
  555. *
  556. * results
  557. * a pointer to the created string
  558. * or NULL if it was unsuccessful
  559. */
  560. char *xode_to_str(xode node)
  561. {
  562. return xode_spool_tostr(_xode_tospool(node));
  563. }
  564. /* loop through both a and b comparing everything, attribs, cdata, children, etc */
  565. int xode_cmp(xode a, xode b)
  566. {
  567. int ret = 0;
  568. while(1)
  569. {
  570. if(a == NULL && b == NULL)
  571. return 0;
  572. if(a == NULL || b == NULL)
  573. return -1;
  574. if(xode_get_type(a) != xode_get_type(b))
  575. return -1;
  576. switch(xode_get_type(a))
  577. {
  578. case XODE_TYPE_ATTRIB:
  579. ret = _xode_strcmp(xode_get_name(a), xode_get_name(b));
  580. if(ret != 0)
  581. return -1;
  582. ret = _xode_strcmp(xode_get_data(a), xode_get_data(b));
  583. if(ret != 0)
  584. return -1;
  585. break;
  586. case XODE_TYPE_TAG:
  587. ret = _xode_strcmp(xode_get_name(a), xode_get_name(b));
  588. if(ret != 0)
  589. return -1;
  590. ret = xode_cmp(xode_get_firstattrib(a), xode_get_firstattrib(b));
  591. if(ret != 0)
  592. return -1;
  593. ret = xode_cmp(xode_get_firstchild(a), xode_get_firstchild(b));
  594. if(ret != 0)
  595. return -1;
  596. break;
  597. case XODE_TYPE_CDATA:
  598. ret = _xode_strcmp(xode_get_data(a), xode_get_data(b));
  599. if(ret != 0)
  600. return -1;
  601. }
  602. a = xode_get_nextsibling(a);
  603. b = xode_get_nextsibling(b);
  604. }
  605. }
  606. xode xode_insert_tagnode(xode parent, xode node)
  607. {
  608. xode child;
  609. child = xode_insert_tag(parent, xode_get_name(node));
  610. if (xode_has_attribs(node))
  611. xode_insert_node(child, xode_get_firstattrib(node));
  612. if (xode_has_children(node))
  613. xode_insert_node(child, xode_get_firstchild(node));
  614. return child;
  615. }
  616. /* places copy of node and node's siblings in parent */
  617. void xode_insert_node(xode parent, xode node)
  618. {
  619. if(node == NULL || parent == NULL)
  620. return;
  621. while(node != NULL)
  622. {
  623. switch(xode_get_type(node))
  624. {
  625. case XODE_TYPE_ATTRIB:
  626. xode_put_attrib(parent, xode_get_name(node), xode_get_data(node));
  627. break;
  628. case XODE_TYPE_TAG:
  629. xode_insert_tagnode(parent, node);
  630. break;
  631. case XODE_TYPE_CDATA:
  632. xode_insert_cdata(parent, xode_get_data(node), xode_get_datasz(node));
  633. }
  634. node = xode_get_nextsibling(node);
  635. }
  636. }
  637. /* produce full duplicate of x with a new xode_pool, x must be a tag! */
  638. xode xode_dup(xode x)
  639. {
  640. xode x2;
  641. if(x == NULL)
  642. return NULL;
  643. x2 = xode_new(xode_get_name(x));
  644. if (xode_has_attribs(x))
  645. xode_insert_node(x2, xode_get_firstattrib(x));
  646. if (xode_has_children(x))
  647. xode_insert_node(x2, xode_get_firstchild(x));
  648. return x2;
  649. }
  650. xode xode_dup_frompool(xode_pool p, xode x)
  651. {
  652. xode x2;
  653. if(x == NULL)
  654. return NULL;
  655. x2 = xode_new_frompool(p, xode_get_name(x));
  656. if (xode_has_attribs(x))
  657. xode_insert_node(x2, xode_get_firstattrib(x));
  658. if (xode_has_children(x))
  659. xode_insert_node(x2, xode_get_firstchild(x));
  660. return x2;
  661. }
  662. xode xode_wrap(xode x,const char *wrapper)
  663. {
  664. xode wrap;
  665. if(x==NULL||wrapper==NULL) return NULL;
  666. wrap=xode_new_frompool(xode_get_pool(x),wrapper);
  667. if(wrap==NULL) return NULL;
  668. wrap->firstchild=x;
  669. wrap->lastchild=x;
  670. x->parent=wrap;
  671. return wrap;
  672. }
  673. void xode_free(xode node)
  674. {
  675. if(node == NULL)
  676. return;
  677. xode_pool_free(node->p);
  678. }
  679. void
  680. _xode_to_prettystr( xode_spool s, xode x, int deep )
  681. {
  682. int i;
  683. xode y;
  684. if(xode_get_type(x) != XODE_TYPE_TAG) return;
  685. for(i=0; i<deep; i++) xode_spool_add(s, "\t");
  686. xode_spooler( s , "<" , xode_get_name(x) , s );
  687. y = xode_get_firstattrib(x);
  688. while( y )
  689. {
  690. xode_spooler( s , " " , xode_get_name(y) , "='", xode_get_data(y) , "'" , s );
  691. y = xode_get_nextsibling( y );
  692. }
  693. xode_spool_add(s,">");
  694. xode_spool_add(s,"\n");
  695. if( xode_get_data(x))
  696. {
  697. for(i=0; i<=deep; i++) xode_spool_add(s, "\t");
  698. xode_spool_add( s , xode_get_data(x));
  699. }
  700. y = xode_get_firstchild(x);
  701. while( y )
  702. {
  703. _xode_to_prettystr(s , y, deep+1);
  704. y = xode_get_nextsibling(y);
  705. xode_spool_add(s,"\n");
  706. }
  707. for(i=0; i<deep; i++) xode_spool_add(s, "\t");
  708. xode_spooler( s , "</" , xode_get_name(x) , ">" , s );
  709. return;
  710. }
  711. char *
  712. xode_to_prettystr( xode x )
  713. {
  714. xode_spool s;
  715. if( !x) return NULL;
  716. s = xode_spool_newfrompool( xode_get_pool(x));
  717. _xode_to_prettystr( s , x, 0 );
  718. return xode_spool_tostr(s);
  719. }