Mon, 26 Mar 2001 08:43:35 +0000
[gaim-migrate @ 1656]
fpmuller said this fixed solaris 2.6 builds
| 1347 | 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 | } |