Mercurial > pidgin
comparison plugins/jabber/xmlnode.c @ 1347:afa63ac2fd84
[gaim-migrate @ 1357]
jabber for those not fortunate enough to have libjabber and libxode on their systems
committer: Tailor Script <tailor@pidgin.im>
author | Eric Warmenhoven <eric@warmenhoven.org> |
---|---|
date | Thu, 21 Dec 2000 14:54:13 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
1346:83f78eb7c472 | 1347:afa63ac2fd84 |
---|---|
1 /* | |
2 * This program is free software; you can redistribute it and/or modify | |
3 * it under the terms of the GNU General Public License as published by | |
4 * the Free Software Foundation; either version 2 of the License, or | |
5 * (at your option) any later version. | |
6 * | |
7 * This program is distributed in the hope that it will be useful, | |
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 * GNU General Public License for more details. | |
11 * | |
12 * You should have received a copy of the GNU General Public License | |
13 * along with this program; if not, write to the Free Software | |
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
15 * | |
16 * Jabber | |
17 * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/ | |
18 */ | |
19 | |
20 #include "libxode.h" | |
21 | |
22 /* Internal routines */ | |
23 xmlnode _xmlnode_new(pool p, const char* name, unsigned int type) | |
24 { | |
25 xmlnode result = NULL; | |
26 if (type > NTYPE_LAST) | |
27 return NULL; | |
28 | |
29 if (type != NTYPE_CDATA && name == NULL) | |
30 return NULL; | |
31 | |
32 if (p == NULL) | |
33 { | |
34 p = pool_heap(1*1024); | |
35 } | |
36 | |
37 /* Allocate & zero memory */ | |
38 result = (xmlnode)pmalloc(p, sizeof(_xmlnode)); | |
39 memset(result, '\0', sizeof(_xmlnode)); | |
40 | |
41 /* Initialize fields */ | |
42 if (type != NTYPE_CDATA) | |
43 result->name = pstrdup(p,name); | |
44 result->type = type; | |
45 result->p = p; | |
46 return result; | |
47 } | |
48 | |
49 static xmlnode _xmlnode_append_sibling(xmlnode lastsibling, const char* name, unsigned int type) | |
50 { | |
51 xmlnode result; | |
52 | |
53 result = _xmlnode_new(xmlnode_pool(lastsibling), name, type); | |
54 if (result != NULL) | |
55 { | |
56 /* Setup sibling pointers */ | |
57 result->prev = lastsibling; | |
58 lastsibling->next = result; | |
59 } | |
60 return result; | |
61 } | |
62 | |
63 static xmlnode _xmlnode_insert(xmlnode parent, const char* name, unsigned int type) | |
64 { | |
65 xmlnode result; | |
66 | |
67 if(parent == NULL || name == NULL) return NULL; | |
68 | |
69 /* If parent->firstchild is NULL, simply create a new node for the first child */ | |
70 if (parent->firstchild == NULL) | |
71 { | |
72 result = _xmlnode_new(parent->p, name, type); | |
73 parent->firstchild = result; | |
74 } | |
75 /* Otherwise, append this to the lastchild */ | |
76 else | |
77 { | |
78 result= _xmlnode_append_sibling(parent->lastchild, name, type); | |
79 } | |
80 result->parent = parent; | |
81 parent->lastchild = result; | |
82 return result; | |
83 | |
84 } | |
85 | |
86 static xmlnode _xmlnode_search(xmlnode firstsibling, const char* name, unsigned int type) | |
87 { | |
88 xmlnode current; | |
89 | |
90 /* Walk the sibling list, looking for a NTYPE_TAG xmlnode with | |
91 the specified name */ | |
92 current = firstsibling; | |
93 while (current != NULL) | |
94 { | |
95 if ((current->type == type) && (j_strcmp(current->name, name) == 0)) | |
96 return current; | |
97 else | |
98 current = current->next; | |
99 } | |
100 return NULL; | |
101 } | |
102 | |
103 static char* _xmlnode_merge(pool p, char* dest, unsigned int destsize, const char* src, unsigned int srcsize) | |
104 { | |
105 char* result; | |
106 result = (char*)pmalloc(p, destsize + srcsize + 1); | |
107 memcpy(result, dest, destsize); | |
108 memcpy(result+destsize, src, srcsize); | |
109 result[destsize + srcsize] = '\0'; | |
110 | |
111 /* WARNING: major ugly hack: since we're throwing the old data away, let's jump in the pool and subtract it from the size, this is for xmlstream's big-node checking */ | |
112 p->size -= destsize; | |
113 | |
114 return result; | |
115 } | |
116 | |
117 static void _xmlnode_hide_sibling(xmlnode child) | |
118 { | |
119 if(child == NULL) | |
120 return; | |
121 | |
122 if(child->prev != NULL) | |
123 child->prev->next = child->next; | |
124 if(child->next != NULL) | |
125 child->next->prev = child->prev; | |
126 } | |
127 | |
128 void _xmlnode_tag2str(spool s, xmlnode node, int flag) | |
129 { | |
130 xmlnode tmp; | |
131 | |
132 if(flag==0 || flag==1) | |
133 { | |
134 spooler(s,"<",xmlnode_get_name(node),s); | |
135 tmp = xmlnode_get_firstattrib(node); | |
136 while(tmp) { | |
137 spooler(s," ",xmlnode_get_name(tmp),"='",strescape(xmlnode_pool(node),xmlnode_get_data(tmp)),"'",s); | |
138 tmp = xmlnode_get_nextsibling(tmp); | |
139 } | |
140 if(flag==0) | |
141 spool_add(s,"/>"); | |
142 else | |
143 spool_add(s,">"); | |
144 } | |
145 else | |
146 { | |
147 spooler(s,"</",xmlnode_get_name(node),">",s); | |
148 } | |
149 } | |
150 | |
151 spool _xmlnode2spool(xmlnode node) | |
152 { | |
153 spool s; | |
154 int level=0,dir=0; | |
155 xmlnode tmp; | |
156 | |
157 if(!node || xmlnode_get_type(node)!=NTYPE_TAG) | |
158 return NULL; | |
159 | |
160 s = spool_new(xmlnode_pool(node)); | |
161 if(!s) return(NULL); | |
162 | |
163 while(1) | |
164 { | |
165 if(dir==0) | |
166 { | |
167 if(xmlnode_get_type(node) == NTYPE_TAG) | |
168 { | |
169 if(xmlnode_has_children(node)) | |
170 { | |
171 _xmlnode_tag2str(s,node,1); | |
172 node = xmlnode_get_firstchild(node); | |
173 level++; | |
174 continue; | |
175 } | |
176 else | |
177 { | |
178 _xmlnode_tag2str(s,node,0); | |
179 } | |
180 } | |
181 else | |
182 { | |
183 spool_add(s,strescape(xmlnode_pool(node),xmlnode_get_data(node))); | |
184 } | |
185 } | |
186 | |
187 tmp = xmlnode_get_nextsibling(node); | |
188 if(!tmp) | |
189 { | |
190 node = xmlnode_get_parent(node); | |
191 level--; | |
192 if(level>=0) _xmlnode_tag2str(s,node,2); | |
193 if(level<1) break; | |
194 dir = 1; | |
195 } | |
196 else | |
197 { | |
198 node = tmp; | |
199 dir = 0; | |
200 } | |
201 } | |
202 | |
203 return s; | |
204 } | |
205 | |
206 | |
207 /* External routines */ | |
208 | |
209 | |
210 /* | |
211 * xmlnode_new_tag -- create a tag node | |
212 * Automatically creates a memory pool for the node. | |
213 * | |
214 * parameters | |
215 * name -- name of the tag | |
216 * | |
217 * returns | |
218 * a pointer to the tag node | |
219 * or NULL if it was unsuccessfull | |
220 */ | |
221 xmlnode xmlnode_new_tag(const char* name) | |
222 { | |
223 return _xmlnode_new(NULL, name, NTYPE_TAG); | |
224 } | |
225 | |
226 | |
227 /* | |
228 * xmlnode_new_tag_pool -- create a tag node within given pool | |
229 * | |
230 * parameters | |
231 * p -- previously created memory pool | |
232 * name -- name of the tag | |
233 * | |
234 * returns | |
235 * a pointer to the tag node | |
236 * or NULL if it was unsuccessfull | |
237 */ | |
238 xmlnode xmlnode_new_tag_pool(pool p, const char* name) | |
239 { | |
240 return _xmlnode_new(p, name, NTYPE_TAG); | |
241 } | |
242 | |
243 | |
244 /* | |
245 * xmlnode_insert_tag -- append a child tag to a tag | |
246 * | |
247 * parameters | |
248 * parent -- pointer to the parent tag | |
249 * name -- name of the child tag | |
250 * | |
251 * returns | |
252 * a pointer to the child tag node | |
253 * or NULL if it was unsuccessfull | |
254 */ | |
255 xmlnode xmlnode_insert_tag(xmlnode parent, const char* name) | |
256 { | |
257 return _xmlnode_insert(parent, name, NTYPE_TAG); | |
258 } | |
259 | |
260 | |
261 /* | |
262 * xmlnode_insert_cdata -- append character data to a tag | |
263 * If last child of the parent is CDATA, merges CDATA nodes. Otherwise | |
264 * creates a CDATA node, and appends it to the parent's child list. | |
265 * | |
266 * parameters | |
267 * parent -- parent tag | |
268 * CDATA -- character data | |
269 * size -- size of CDATA | |
270 * or -1 for null-terminated CDATA strings | |
271 * | |
272 * returns | |
273 * a pointer to the child CDATA node | |
274 * or NULL if it was unsuccessfull | |
275 */ | |
276 xmlnode xmlnode_insert_cdata(xmlnode parent, const char* CDATA, unsigned int size) | |
277 { | |
278 xmlnode result; | |
279 | |
280 if(CDATA == NULL || parent == NULL) | |
281 return NULL; | |
282 | |
283 if(size == -1) | |
284 size = strlen(CDATA); | |
285 | |
286 if ((parent->lastchild != NULL) && (parent->lastchild->type == NTYPE_CDATA)) | |
287 { | |
288 result = parent->lastchild; | |
289 result->data = _xmlnode_merge(result->p, result->data, result->data_sz, CDATA, size); | |
290 result->data_sz = result->data_sz + size; | |
291 } | |
292 else | |
293 { | |
294 result = _xmlnode_insert(parent, "", NTYPE_CDATA); | |
295 if (result != NULL) | |
296 { | |
297 result->data = (char*)pmalloc(result->p, size + 1); | |
298 memcpy(result->data, CDATA, size); | |
299 result->data[size] = '\0'; | |
300 result->data_sz = size; | |
301 } | |
302 } | |
303 | |
304 return result; | |
305 } | |
306 | |
307 | |
308 /* | |
309 * xmlnode_get_tag -- find given tag in an xmlnode tree | |
310 * | |
311 * parameters | |
312 * parent -- pointer to the parent tag | |
313 * name -- "name" for the child tag of that name | |
314 * "name/name" for a sub child (recurses) | |
315 * "?attrib" to match the first tag with that attrib defined | |
316 * "?attrib=value" to match the first tag with that attrib and value | |
317 * or any combination: "name/name/?attrib", etc | |
318 * | |
319 * results | |
320 * a pointer to the tag matching search criteria | |
321 * or NULL if search was unsuccessfull | |
322 */ | |
323 xmlnode xmlnode_get_tag(xmlnode parent, const char* name) | |
324 { | |
325 char *str, *slash, *qmark, *equals; | |
326 xmlnode step, ret; | |
327 | |
328 if(parent == NULL || parent->firstchild == NULL || name == NULL || name == '\0') return NULL; | |
329 | |
330 if(strstr(name, "/") == NULL && strstr(name,"?") == NULL) | |
331 return _xmlnode_search(parent->firstchild, name, NTYPE_TAG); | |
332 | |
333 /* jer's note: why can't I modify the name directly, why do I have to strdup it? damn c grrr! */ | |
334 str = strdup(name); | |
335 slash = strstr(str, "/"); | |
336 qmark = strstr(str, "?"); | |
337 equals = strstr(str, "="); | |
338 | |
339 if(qmark != NULL && (slash == NULL || qmark < slash)) | |
340 { /* of type ?attrib */ | |
341 | |
342 *qmark = '\0'; | |
343 qmark++; | |
344 if(equals != NULL) | |
345 { | |
346 *equals = '\0'; | |
347 equals++; | |
348 } | |
349 | |
350 for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step)) | |
351 { | |
352 if(xmlnode_get_type(step) != NTYPE_TAG) | |
353 continue; | |
354 | |
355 if(*str != '\0') | |
356 if(j_strcmp(xmlnode_get_name(step),str) != 0) | |
357 continue; | |
358 | |
359 if(xmlnode_get_attrib(step,qmark) == NULL) | |
360 continue; | |
361 | |
362 if(equals != NULL && j_strcmp(xmlnode_get_attrib(step,qmark),equals) != 0) | |
363 continue; | |
364 | |
365 break; | |
366 } | |
367 | |
368 free(str); | |
369 return step; | |
370 } | |
371 | |
372 | |
373 *slash = '\0'; | |
374 ++slash; | |
375 | |
376 for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step)) | |
377 { | |
378 if(xmlnode_get_type(step) != NTYPE_TAG) continue; | |
379 | |
380 if(j_strcmp(xmlnode_get_name(step),str) != 0) | |
381 continue; | |
382 | |
383 ret = xmlnode_get_tag(step, slash); | |
384 if(ret != NULL) | |
385 { | |
386 free(str); | |
387 return ret; | |
388 } | |
389 } | |
390 | |
391 free(str); | |
392 return NULL; | |
393 } | |
394 | |
395 | |
396 /* return the cdata from any tag */ | |
397 char *xmlnode_get_tag_data(xmlnode parent, const char *name) | |
398 { | |
399 xmlnode tag; | |
400 | |
401 tag = xmlnode_get_tag(parent, name); | |
402 if(tag == NULL) return NULL; | |
403 | |
404 return xmlnode_get_data(tag); | |
405 } | |
406 | |
407 | |
408 void xmlnode_put_attrib(xmlnode owner, const char* name, const char* value) | |
409 { | |
410 xmlnode attrib; | |
411 | |
412 if(owner == NULL || name == NULL || value == NULL) return; | |
413 | |
414 /* If there are no existing attributs, allocate a new one to start | |
415 the list */ | |
416 if (owner->firstattrib == NULL) | |
417 { | |
418 attrib = _xmlnode_new(owner->p, name, NTYPE_ATTRIB); | |
419 owner->firstattrib = attrib; | |
420 owner->lastattrib = attrib; | |
421 } | |
422 else | |
423 { | |
424 attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB); | |
425 if(attrib == NULL) | |
426 { | |
427 attrib = _xmlnode_append_sibling(owner->lastattrib, name, NTYPE_ATTRIB); | |
428 owner->lastattrib = attrib; | |
429 } | |
430 } | |
431 /* Update the value of the attribute */ | |
432 attrib->data_sz = strlen(value); | |
433 attrib->data = pstrdup(owner->p, value); | |
434 | |
435 } | |
436 | |
437 char* xmlnode_get_attrib(xmlnode owner, const char* name) | |
438 { | |
439 xmlnode attrib; | |
440 | |
441 if (owner != NULL && owner->firstattrib != NULL) | |
442 { | |
443 attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB); | |
444 if (attrib != NULL) | |
445 return (char*)attrib->data; | |
446 } | |
447 return NULL; | |
448 } | |
449 | |
450 void xmlnode_put_vattrib(xmlnode owner, const char* name, void *value) | |
451 { | |
452 xmlnode attrib; | |
453 | |
454 if (owner != NULL) | |
455 { | |
456 attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB); | |
457 if (attrib == NULL) | |
458 { | |
459 xmlnode_put_attrib(owner, name, ""); | |
460 attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB); | |
461 } | |
462 if (attrib != NULL) | |
463 attrib->firstchild = (xmlnode)value; | |
464 } | |
465 } | |
466 | |
467 void* xmlnode_get_vattrib(xmlnode owner, const char* name) | |
468 { | |
469 xmlnode attrib; | |
470 | |
471 if (owner != NULL && owner->firstattrib != NULL) | |
472 { | |
473 attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB); | |
474 if (attrib != NULL) | |
475 return (void*)attrib->firstchild; | |
476 } | |
477 return NULL; | |
478 } | |
479 | |
480 xmlnode xmlnode_get_firstattrib(xmlnode parent) | |
481 { | |
482 if (parent != NULL) | |
483 return parent->firstattrib; | |
484 return NULL; | |
485 } | |
486 | |
487 xmlnode xmlnode_get_firstchild(xmlnode parent) | |
488 { | |
489 if (parent != NULL) | |
490 return parent->firstchild; | |
491 return NULL; | |
492 } | |
493 | |
494 xmlnode xmlnode_get_lastchild(xmlnode parent) | |
495 { | |
496 if (parent != NULL) | |
497 return parent->lastchild; | |
498 return NULL; | |
499 } | |
500 | |
501 xmlnode xmlnode_get_nextsibling(xmlnode sibling) | |
502 { | |
503 if (sibling != NULL) | |
504 return sibling->next; | |
505 return NULL; | |
506 } | |
507 | |
508 xmlnode xmlnode_get_prevsibling(xmlnode sibling) | |
509 { | |
510 if (sibling != NULL) | |
511 return sibling->prev; | |
512 return NULL; | |
513 } | |
514 | |
515 xmlnode xmlnode_get_parent(xmlnode node) | |
516 { | |
517 if (node != NULL) | |
518 return node->parent; | |
519 return NULL; | |
520 } | |
521 | |
522 char* xmlnode_get_name(xmlnode node) | |
523 { | |
524 if (node != NULL) | |
525 return node->name; | |
526 return NULL; | |
527 } | |
528 | |
529 char* xmlnode_get_data(xmlnode node) | |
530 { | |
531 xmlnode cur; | |
532 | |
533 if(node == NULL) return NULL; | |
534 | |
535 if(xmlnode_get_type(node) == NTYPE_TAG) /* loop till we find a CDATA */ | |
536 { | |
537 for(cur = xmlnode_get_firstchild(node); cur != NULL; cur = xmlnode_get_nextsibling(cur)) | |
538 if(xmlnode_get_type(cur) == NTYPE_CDATA) | |
539 return cur->data; | |
540 }else{ | |
541 return node->data; | |
542 } | |
543 return NULL; | |
544 } | |
545 | |
546 int xmlnode_get_datasz(xmlnode node) | |
547 { | |
548 if (node != NULL) | |
549 return node->data_sz; | |
550 return (int)NULL; | |
551 } | |
552 | |
553 int xmlnode_get_type(xmlnode node) | |
554 { | |
555 if (node != NULL) | |
556 return node->type; | |
557 return (int)NULL; | |
558 } | |
559 | |
560 int xmlnode_has_children(xmlnode node) | |
561 { | |
562 if ((node != NULL) && (node->firstchild != NULL)) | |
563 return 1; | |
564 return 0; | |
565 } | |
566 | |
567 int xmlnode_has_attribs(xmlnode node) | |
568 { | |
569 if ((node != NULL) && (node->firstattrib != NULL)) | |
570 return 1; | |
571 return 0; | |
572 } | |
573 | |
574 pool xmlnode_pool(xmlnode node) | |
575 { | |
576 if (node != NULL) | |
577 return node->p; | |
578 return (pool)NULL; | |
579 } | |
580 | |
581 void xmlnode_hide(xmlnode child) | |
582 { | |
583 xmlnode parent; | |
584 | |
585 if(child == NULL || child->parent == NULL) | |
586 return; | |
587 | |
588 parent = child->parent; | |
589 | |
590 /* first fix up at the child level */ | |
591 _xmlnode_hide_sibling(child); | |
592 | |
593 /* next fix up at the parent level */ | |
594 if(parent->firstchild == child) | |
595 parent->firstchild = child->next; | |
596 if(parent->lastchild == child) | |
597 parent->lastchild = child->prev; | |
598 } | |
599 | |
600 void xmlnode_hide_attrib(xmlnode parent, const char *name) | |
601 { | |
602 xmlnode attrib; | |
603 | |
604 if(parent == NULL || parent->firstattrib == NULL || name == NULL) | |
605 return; | |
606 | |
607 attrib = _xmlnode_search(parent->firstattrib, name, NTYPE_ATTRIB); | |
608 if(attrib == NULL) | |
609 return; | |
610 | |
611 /* first fix up at the child level */ | |
612 _xmlnode_hide_sibling(attrib); | |
613 | |
614 /* next fix up at the parent level */ | |
615 if(parent->firstattrib == attrib) | |
616 parent->firstattrib = attrib->next; | |
617 if(parent->lastattrib == attrib) | |
618 parent->lastattrib = attrib->prev; | |
619 } | |
620 | |
621 | |
622 | |
623 /* | |
624 * xmlnode2str -- convert given xmlnode tree into a string | |
625 * | |
626 * parameters | |
627 * node -- pointer to the xmlnode structure | |
628 * | |
629 * results | |
630 * a pointer to the created string | |
631 * or NULL if it was unsuccessfull | |
632 */ | |
633 char *xmlnode2str(xmlnode node) | |
634 { | |
635 return spool_print(_xmlnode2spool(node)); | |
636 } | |
637 | |
638 /* | |
639 * xmlnode2tstr -- convert given xmlnode tree into a newline terminated string | |
640 * | |
641 * parameters | |
642 * node -- pointer to the xmlnode structure | |
643 * | |
644 * results | |
645 * a pointer to the created string | |
646 * or NULL if it was unsuccessfull | |
647 */ | |
648 char* xmlnode2tstr(xmlnode node) | |
649 { | |
650 spool s = _xmlnode2spool(node); | |
651 if (s != NULL) | |
652 spool_add(s, "\n"); | |
653 return spool_print(s); | |
654 } | |
655 | |
656 | |
657 /* loop through both a and b comparing everything, attribs, cdata, children, etc */ | |
658 int xmlnode_cmp(xmlnode a, xmlnode b) | |
659 { | |
660 int ret = 0; | |
661 | |
662 while(1) | |
663 { | |
664 if(a == NULL && b == NULL) | |
665 return 0; | |
666 | |
667 if(a == NULL || b == NULL) | |
668 return -1; | |
669 | |
670 if(xmlnode_get_type(a) != xmlnode_get_type(b)) | |
671 return -1; | |
672 | |
673 switch(xmlnode_get_type(a)) | |
674 { | |
675 case NTYPE_ATTRIB: | |
676 ret = j_strcmp(xmlnode_get_name(a), xmlnode_get_name(b)); | |
677 if(ret != 0) | |
678 return -1; | |
679 ret = j_strcmp(xmlnode_get_data(a), xmlnode_get_data(b)); | |
680 if(ret != 0) | |
681 return -1; | |
682 break; | |
683 case NTYPE_TAG: | |
684 ret = j_strcmp(xmlnode_get_name(a), xmlnode_get_name(b)); | |
685 if(ret != 0) | |
686 return -1; | |
687 ret = xmlnode_cmp(xmlnode_get_firstattrib(a), xmlnode_get_firstattrib(b)); | |
688 if(ret != 0) | |
689 return -1; | |
690 ret = xmlnode_cmp(xmlnode_get_firstchild(a), xmlnode_get_firstchild(b)); | |
691 if(ret != 0) | |
692 return -1; | |
693 break; | |
694 case NTYPE_CDATA: | |
695 ret = j_strcmp(xmlnode_get_data(a), xmlnode_get_data(b)); | |
696 if(ret != 0) | |
697 return -1; | |
698 } | |
699 a = xmlnode_get_nextsibling(a); | |
700 b = xmlnode_get_nextsibling(b); | |
701 } | |
702 } | |
703 | |
704 | |
705 xmlnode xmlnode_insert_tag_node(xmlnode parent, xmlnode node) | |
706 { | |
707 xmlnode child; | |
708 | |
709 child = xmlnode_insert_tag(parent, xmlnode_get_name(node)); | |
710 if (xmlnode_has_attribs(node)) | |
711 xmlnode_insert_node(child, xmlnode_get_firstattrib(node)); | |
712 if (xmlnode_has_children(node)) | |
713 xmlnode_insert_node(child, xmlnode_get_firstchild(node)); | |
714 | |
715 return child; | |
716 } | |
717 | |
718 /* places copy of node and node's siblings in parent */ | |
719 void xmlnode_insert_node(xmlnode parent, xmlnode node) | |
720 { | |
721 if(node == NULL || parent == NULL) | |
722 return; | |
723 | |
724 while(node != NULL) | |
725 { | |
726 switch(xmlnode_get_type(node)) | |
727 { | |
728 case NTYPE_ATTRIB: | |
729 xmlnode_put_attrib(parent, xmlnode_get_name(node), xmlnode_get_data(node)); | |
730 break; | |
731 case NTYPE_TAG: | |
732 xmlnode_insert_tag_node(parent, node); | |
733 break; | |
734 case NTYPE_CDATA: | |
735 xmlnode_insert_cdata(parent, xmlnode_get_data(node), xmlnode_get_datasz(node)); | |
736 } | |
737 node = xmlnode_get_nextsibling(node); | |
738 } | |
739 } | |
740 | |
741 | |
742 /* produce full duplicate of x with a new pool, x must be a tag! */ | |
743 xmlnode xmlnode_dup(xmlnode x) | |
744 { | |
745 xmlnode x2; | |
746 | |
747 if(x == NULL) | |
748 return NULL; | |
749 | |
750 x2 = xmlnode_new_tag(xmlnode_get_name(x)); | |
751 | |
752 if (xmlnode_has_attribs(x)) | |
753 xmlnode_insert_node(x2, xmlnode_get_firstattrib(x)); | |
754 if (xmlnode_has_children(x)) | |
755 xmlnode_insert_node(x2, xmlnode_get_firstchild(x)); | |
756 | |
757 return x2; | |
758 } | |
759 | |
760 xmlnode xmlnode_dup_pool(pool p, xmlnode x) | |
761 { | |
762 xmlnode x2; | |
763 | |
764 if(x == NULL) | |
765 return NULL; | |
766 | |
767 x2 = xmlnode_new_tag_pool(p, xmlnode_get_name(x)); | |
768 | |
769 if (xmlnode_has_attribs(x)) | |
770 xmlnode_insert_node(x2, xmlnode_get_firstattrib(x)); | |
771 if (xmlnode_has_children(x)) | |
772 xmlnode_insert_node(x2, xmlnode_get_firstchild(x)); | |
773 | |
774 return x2; | |
775 } | |
776 | |
777 xmlnode xmlnode_wrap(xmlnode x,const char *wrapper) | |
778 { | |
779 xmlnode wrap; | |
780 if(x==NULL||wrapper==NULL) return NULL; | |
781 wrap=xmlnode_new_tag_pool(xmlnode_pool(x),wrapper); | |
782 if(wrap==NULL) return NULL; | |
783 wrap->firstchild=x; | |
784 wrap->lastchild=x; | |
785 x->parent=wrap; | |
786 return wrap; | |
787 } | |
788 | |
789 void xmlnode_free(xmlnode node) | |
790 { | |
791 if(node == NULL) | |
792 return; | |
793 | |
794 pool_free(node->p); | |
795 } |