00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "libxode.h"
00021
00022 static int _xode_strcmp(const char *a, const char *b)
00023 {
00024 if(a == NULL || b == NULL) return -1;
00025
00026 return strcmp(a,b);
00027 }
00028
00029
00030 static xode _xode_new(xode_pool p, const char* name, unsigned int type)
00031 {
00032 xode result = NULL;
00033 if (type > XODE_TYPE_LAST)
00034 return NULL;
00035
00036 if (type != XODE_TYPE_CDATA && name == NULL)
00037 return NULL;
00038
00039 if (p == NULL)
00040 {
00041 p = xode_pool_heap(1*1024);
00042 }
00043
00044
00045 result = (xode)xode_pool_malloc(p, sizeof(_xode));
00046 memset(result, '\0', sizeof(_xode));
00047
00048
00049 if (type != XODE_TYPE_CDATA)
00050 result->name = xode_pool_strdup(p,name);
00051 result->type = type;
00052 result->p = p;
00053 return result;
00054 }
00055
00056 static xode _xode_appendsibling(xode lastsibling, const char* name, unsigned int type)
00057 {
00058 xode result;
00059
00060 result = _xode_new(xode_get_pool(lastsibling), name, type);
00061 if (result != NULL)
00062 {
00063
00064 result->prev = lastsibling;
00065 lastsibling->next = result;
00066 }
00067 return result;
00068 }
00069
00070 static xode _xode_insert(xode parent, const char* name, unsigned int type)
00071 {
00072 xode result;
00073
00074 if(parent == NULL || name == NULL) return NULL;
00075
00076
00077 if (parent->firstchild == NULL)
00078 {
00079 result = _xode_new(parent->p, name, type);
00080 parent->firstchild = result;
00081 }
00082
00083 else
00084 {
00085 result= _xode_appendsibling(parent->lastchild, name, type);
00086 }
00087 result->parent = parent;
00088 parent->lastchild = result;
00089 return result;
00090
00091 }
00092
00093 static xode _xode_search(xode firstsibling, const char* name, unsigned int type)
00094 {
00095 xode current;
00096
00097
00098
00099 current = firstsibling;
00100 while (current != NULL)
00101 {
00102 if (name != NULL && (current->type == type) && (_xode_strcmp(current->name, name) == 0))
00103 return current;
00104 else
00105 current = current->next;
00106 }
00107 return NULL;
00108 }
00109
00110 static char* _xode_merge(xode_pool p, char* dest, unsigned int destsize, const char* src, unsigned int srcsize)
00111 {
00112 char* result;
00113 result = (char*)xode_pool_malloc(p, destsize + srcsize + 1);
00114 memcpy(result, dest, destsize);
00115 memcpy(result+destsize, src, srcsize);
00116 result[destsize + srcsize] = '\0';
00117
00118
00119 p->size -= destsize;
00120
00121 return result;
00122 }
00123
00124 static void _xode_hidesibling(xode child)
00125 {
00126 if(child == NULL)
00127 return;
00128
00129 if(child->prev != NULL)
00130 child->prev->next = child->next;
00131 if(child->next != NULL)
00132 child->next->prev = child->prev;
00133 }
00134
00135 static void _xode_tag2str(xode_spool s, xode node, int flag)
00136 {
00137 xode tmp;
00138
00139 if(flag==0 || flag==1)
00140 {
00141 xode_spooler(s,"<",xode_get_name(node),s);
00142 tmp = xode_get_firstattrib(node);
00143 while(tmp) {
00144 xode_spooler(s," ",xode_get_name(tmp),"='",xode_strescape(xode_get_pool(node),xode_get_data(tmp)),"'",s);
00145 tmp = xode_get_nextsibling(tmp);
00146 }
00147 if(flag==0)
00148 xode_spool_add(s,"/>");
00149 else
00150 xode_spool_add(s,">");
00151 }
00152 else
00153 {
00154 xode_spooler(s,"</",xode_get_name(node),">",s);
00155 }
00156 }
00157
00158 static xode_spool _xode_tospool(xode node)
00159 {
00160 xode_spool s;
00161 int level=0,dir=0;
00162 xode tmp;
00163
00164 if(!node || xode_get_type(node) != XODE_TYPE_TAG)
00165 return NULL;
00166
00167 s = xode_spool_newfrompool(xode_get_pool(node));
00168 if(!s) return(NULL);
00169
00170 while(1)
00171 {
00172 if(dir==0)
00173 {
00174 if(xode_get_type(node) == XODE_TYPE_TAG)
00175 {
00176 if(xode_has_children(node))
00177 {
00178 _xode_tag2str(s,node,1);
00179 node = xode_get_firstchild(node);
00180 level++;
00181 continue;
00182 }
00183 else
00184 {
00185 _xode_tag2str(s,node,0);
00186 }
00187 }
00188 else
00189 {
00190 xode_spool_add(s,xode_strescape(xode_get_pool(node),xode_get_data(node)));
00191 }
00192 }
00193
00194 tmp = xode_get_nextsibling(node);
00195 if(!tmp)
00196 {
00197 node = xode_get_parent(node);
00198 level--;
00199 if(level>=0) _xode_tag2str(s,node,2);
00200 if(level<1) break;
00201 dir = 1;
00202 }
00203 else
00204 {
00205 node = tmp;
00206 dir = 0;
00207 }
00208 }
00209
00210 return s;
00211 }
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228 xode xode_new(const char* name)
00229 {
00230 return _xode_new(NULL, name, XODE_TYPE_TAG);
00231 }
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245 xode xode_new_frompool(xode_pool p, const char* name)
00246 {
00247 return _xode_new(p, name, XODE_TYPE_TAG);
00248 }
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262 xode xode_insert_tag(xode parent, const char* name)
00263 {
00264 return _xode_insert(parent, name, XODE_TYPE_TAG);
00265 }
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283 xode xode_insert_cdata(xode parent, const char* CDATA, unsigned int size)
00284 {
00285 xode result;
00286
00287 if(CDATA == NULL || parent == NULL)
00288 return NULL;
00289
00290 if(size == -1)
00291 size = strlen(CDATA);
00292
00293 if ((parent->lastchild != NULL) && (parent->lastchild->type == XODE_TYPE_CDATA))
00294 {
00295 result = parent->lastchild;
00296 result->data = _xode_merge(result->p, result->data, result->data_sz, CDATA, size);
00297 result->data_sz = result->data_sz + size;
00298 }
00299 else
00300 {
00301 result = _xode_insert(parent, "", XODE_TYPE_CDATA);
00302 if (result != NULL)
00303 {
00304 result->data = (char*)xode_pool_malloc(result->p, size + 1);
00305 memcpy(result->data, CDATA, size);
00306 result->data[size] = '\0';
00307 result->data_sz = size;
00308 }
00309 }
00310
00311 return result;
00312 }
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330 xode xode_get_tag(xode parent, const char* name)
00331 {
00332 char *str, *slash, *qmark, *equals;
00333 xode step, ret;
00334
00335 if(parent == NULL || parent->firstchild == NULL || name == NULL || name == '\0') return NULL;
00336
00337 if(strstr(name, "/") == NULL && strstr(name,"?") == NULL)
00338 return _xode_search(parent->firstchild, name, XODE_TYPE_TAG);
00339
00340
00341 str = strdup(name);
00342 slash = strstr(str, "/");
00343 qmark = strstr(str, "?");
00344 equals = strstr(str, "=");
00345
00346 if(qmark != NULL && (slash == NULL || qmark < slash))
00347 {
00348
00349 *qmark = '\0';
00350 qmark++;
00351 if(equals != NULL)
00352 {
00353 *equals = '\0';
00354 equals++;
00355 }
00356
00357 for(step = parent->firstchild; step != NULL; step = xode_get_nextsibling(step))
00358 {
00359 if(xode_get_type(step) != XODE_TYPE_TAG)
00360 continue;
00361
00362 if(*str != '\0')
00363 if(_xode_strcmp(xode_get_name(step),str) != 0)
00364 continue;
00365
00366 if(xode_get_attrib(step,qmark) == NULL)
00367 continue;
00368
00369 if(equals != NULL && _xode_strcmp(xode_get_attrib(step,qmark),equals) != 0)
00370 continue;
00371
00372 break;
00373 }
00374
00375 free(str);
00376 return step;
00377 }
00378
00379
00380 *slash = '\0';
00381 ++slash;
00382
00383 for(step = parent->firstchild; step != NULL; step = xode_get_nextsibling(step))
00384 {
00385 if(xode_get_type(step) != XODE_TYPE_TAG) continue;
00386
00387 if(_xode_strcmp(xode_get_name(step),str) != 0)
00388 continue;
00389
00390 ret = xode_get_tag(step, slash);
00391 if(ret != NULL)
00392 {
00393 free(str);
00394 return ret;
00395 }
00396 }
00397
00398 free(str);
00399 return NULL;
00400 }
00401
00402
00403
00404 char *xode_get_tagdata(xode parent, const char *name)
00405 {
00406 xode tag;
00407
00408 tag = xode_get_tag(parent, name);
00409 if(tag == NULL) return NULL;
00410
00411 return xode_get_data(tag);
00412 }
00413
00414
00415 void xode_put_attrib(xode owner, const char* name, const char* value)
00416 {
00417 xode attrib;
00418
00419 if(owner == NULL || name == NULL || value == NULL) return;
00420
00421
00422
00423 if (owner->firstattrib == NULL)
00424 {
00425 attrib = _xode_new(owner->p, name, XODE_TYPE_ATTRIB);
00426 owner->firstattrib = attrib;
00427 owner->lastattrib = attrib;
00428 }
00429 else
00430 {
00431 attrib = _xode_search(owner->firstattrib, name, XODE_TYPE_ATTRIB);
00432 if(attrib == NULL)
00433 {
00434 attrib = _xode_appendsibling(owner->lastattrib, name, XODE_TYPE_ATTRIB);
00435 owner->lastattrib = attrib;
00436 }
00437 }
00438
00439 attrib->data_sz = strlen(value);
00440 attrib->data = xode_pool_strdup(owner->p, value);
00441
00442 }
00443
00444 char* xode_get_attrib(xode owner, const char* name)
00445 {
00446 xode attrib;
00447
00448 if (owner != NULL && owner->firstattrib != NULL)
00449 {
00450 attrib = _xode_search(owner->firstattrib, name, XODE_TYPE_ATTRIB);
00451 if (attrib != NULL)
00452 return (char*)attrib->data;
00453 }
00454 return NULL;
00455 }
00456
00457 void xode_put_vattrib(xode owner, const char* name, void *value)
00458 {
00459 xode attrib;
00460
00461 if (owner != NULL)
00462 {
00463 attrib = _xode_search(owner->firstattrib, name, XODE_TYPE_ATTRIB);
00464 if (attrib == NULL)
00465 {
00466 xode_put_attrib(owner, name, "");
00467 attrib = _xode_search(owner->firstattrib, name, XODE_TYPE_ATTRIB);
00468 }
00469 if (attrib != NULL)
00470 attrib->firstchild = (xode)value;
00471 }
00472 }
00473
00474 void* xode_get_vattrib(xode owner, const char* name)
00475 {
00476 xode attrib;
00477
00478 if (owner != NULL && owner->firstattrib != NULL)
00479 {
00480 attrib = _xode_search(owner->firstattrib, name, XODE_TYPE_ATTRIB);
00481 if (attrib != NULL)
00482 return (void*)attrib->firstchild;
00483 }
00484 return NULL;
00485 }
00486
00487 xode xode_get_firstattrib(xode parent)
00488 {
00489 if (parent != NULL)
00490 return parent->firstattrib;
00491 return NULL;
00492 }
00493
00494 xode xode_get_firstchild(xode parent)
00495 {
00496 if (parent != NULL)
00497 return parent->firstchild;
00498 return NULL;
00499 }
00500
00501 xode xode_get_lastchild(xode parent)
00502 {
00503 if (parent != NULL)
00504 return parent->lastchild;
00505 return NULL;
00506 }
00507
00508 xode xode_get_nextsibling(xode sibling)
00509 {
00510 if (sibling != NULL)
00511 return sibling->next;
00512 return NULL;
00513 }
00514
00515 xode xode_get_prevsibling(xode sibling)
00516 {
00517 if (sibling != NULL)
00518 return sibling->prev;
00519 return NULL;
00520 }
00521
00522 xode xode_get_parent(xode node)
00523 {
00524 if (node != NULL)
00525 return node->parent;
00526 return NULL;
00527 }
00528
00529 char* xode_get_name(xode node)
00530 {
00531 if (node != NULL)
00532 return node->name;
00533 return NULL;
00534 }
00535
00536 char* xode_get_data(xode node)
00537 {
00538 xode cur;
00539
00540 if(node == NULL) return NULL;
00541
00542 if(xode_get_type(node) == XODE_TYPE_TAG)
00543 {
00544 for(cur = xode_get_firstchild(node); cur != NULL; cur = xode_get_nextsibling(cur))
00545 if(xode_get_type(cur) == XODE_TYPE_CDATA)
00546 return cur->data;
00547 }else{
00548 return node->data;
00549 }
00550 return NULL;
00551 }
00552
00553 int xode_get_datasz(xode node)
00554 {
00555
00556 if( node == NULL )
00557 {
00558 return (int)NULL;
00559 }
00560 else if(xode_get_type(node) == XODE_TYPE_TAG)
00561 {
00562 xode cur;
00563 for(cur = xode_get_firstchild(node); cur != NULL; cur = xode_get_nextsibling(cur))
00564 if(xode_get_type(cur) == XODE_TYPE_CDATA)
00565 return cur->data_sz;
00566 }else{
00567 return node->data_sz;
00568 }
00569 return (int)NULL;
00570 }
00571
00572 int xode_get_type(xode node)
00573 {
00574 if (node != NULL)
00575 {
00576 return node->type;
00577 }
00578 return (int)NULL;
00579 }
00580
00581 int xode_has_children(xode node)
00582 {
00583 if ((node != NULL) && (node->firstchild != NULL))
00584 return 1;
00585 return 0;
00586 }
00587
00588 int xode_has_attribs(xode node)
00589 {
00590 if ((node != NULL) && (node->firstattrib != NULL))
00591 return 1;
00592 return 0;
00593 }
00594
00595 xode_pool xode_get_pool(xode node)
00596 {
00597 if (node != NULL)
00598 return node->p;
00599 return (xode_pool)NULL;
00600 }
00601
00602 void xode_hide(xode child)
00603 {
00604 xode parent;
00605
00606 if(child == NULL || child->parent == NULL)
00607 return;
00608
00609 parent = child->parent;
00610
00611
00612 _xode_hidesibling(child);
00613
00614
00615 if(parent->firstchild == child)
00616 parent->firstchild = child->next;
00617 if(parent->lastchild == child)
00618 parent->lastchild = child->prev;
00619 }
00620
00621 void xode_hide_attrib(xode parent, const char *name)
00622 {
00623 xode attrib;
00624
00625 if(parent == NULL || parent->firstattrib == NULL || name == NULL)
00626 return;
00627
00628 attrib = _xode_search(parent->firstattrib, name, XODE_TYPE_ATTRIB);
00629 if(attrib == NULL)
00630 return;
00631
00632
00633 _xode_hidesibling(attrib);
00634
00635
00636 if(parent->firstattrib == attrib)
00637 parent->firstattrib = attrib->next;
00638 if(parent->lastattrib == attrib)
00639 parent->lastattrib = attrib->prev;
00640 }
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654 char *xode_to_str(xode node)
00655 {
00656 return xode_spool_tostr(_xode_tospool(node));
00657 }
00658
00659
00660
00661 int xode_cmp(xode a, xode b)
00662 {
00663 int ret = 0;
00664
00665 while(1)
00666 {
00667 if(a == NULL && b == NULL)
00668 return 0;
00669
00670 if(a == NULL || b == NULL)
00671 return -1;
00672
00673 if(xode_get_type(a) != xode_get_type(b))
00674 return -1;
00675
00676 switch(xode_get_type(a))
00677 {
00678 case XODE_TYPE_ATTRIB:
00679 ret = _xode_strcmp(xode_get_name(a), xode_get_name(b));
00680 if(ret != 0)
00681 return -1;
00682 ret = _xode_strcmp(xode_get_data(a), xode_get_data(b));
00683 if(ret != 0)
00684 return -1;
00685 break;
00686 case XODE_TYPE_TAG:
00687 ret = _xode_strcmp(xode_get_name(a), xode_get_name(b));
00688 if(ret != 0)
00689 return -1;
00690 ret = xode_cmp(xode_get_firstattrib(a), xode_get_firstattrib(b));
00691 if(ret != 0)
00692 return -1;
00693 ret = xode_cmp(xode_get_firstchild(a), xode_get_firstchild(b));
00694 if(ret != 0)
00695 return -1;
00696 break;
00697 case XODE_TYPE_CDATA:
00698 ret = _xode_strcmp(xode_get_data(a), xode_get_data(b));
00699 if(ret != 0)
00700 return -1;
00701 }
00702 a = xode_get_nextsibling(a);
00703 b = xode_get_nextsibling(b);
00704 }
00705 }
00706
00707
00708 xode xode_insert_tagnode(xode parent, xode node)
00709 {
00710 xode child;
00711
00712 child = xode_insert_tag(parent, xode_get_name(node));
00713 if (xode_has_attribs(node))
00714 xode_insert_node(child, xode_get_firstattrib(node));
00715 if (xode_has_children(node))
00716 xode_insert_node(child, xode_get_firstchild(node));
00717
00718 return child;
00719 }
00720
00721
00722 void xode_insert_node(xode parent, xode node)
00723 {
00724 if(node == NULL || parent == NULL)
00725 return;
00726
00727 while(node != NULL)
00728 {
00729 switch(xode_get_type(node))
00730 {
00731 case XODE_TYPE_ATTRIB:
00732 xode_put_attrib(parent, xode_get_name(node), xode_get_data(node));
00733 break;
00734 case XODE_TYPE_TAG:
00735 xode_insert_tagnode(parent, node);
00736 break;
00737 case XODE_TYPE_CDATA:
00738 xode_insert_cdata(parent, xode_get_data(node), xode_get_datasz(node));
00739 }
00740 node = xode_get_nextsibling(node);
00741 }
00742 }
00743
00744
00745
00746 xode xode_dup(xode x)
00747 {
00748 xode x2;
00749
00750 if(x == NULL)
00751 return NULL;
00752
00753 x2 = xode_new(xode_get_name(x));
00754
00755 if (xode_has_attribs(x))
00756 xode_insert_node(x2, xode_get_firstattrib(x));
00757 if (xode_has_children(x))
00758 xode_insert_node(x2, xode_get_firstchild(x));
00759
00760 return x2;
00761 }
00762
00763 xode xode_dup_frompool(xode_pool p, xode x)
00764 {
00765 xode x2;
00766
00767 if(x == NULL)
00768 return NULL;
00769
00770 x2 = xode_new_frompool(p, xode_get_name(x));
00771
00772 if (xode_has_attribs(x))
00773 xode_insert_node(x2, xode_get_firstattrib(x));
00774 if (xode_has_children(x))
00775 xode_insert_node(x2, xode_get_firstchild(x));
00776
00777 return x2;
00778 }
00779
00780 xode xode_wrap(xode x,const char *wrapper)
00781 {
00782 xode wrap;
00783 if(x==NULL||wrapper==NULL) return NULL;
00784 wrap=xode_new_frompool(xode_get_pool(x),wrapper);
00785 if(wrap==NULL) return NULL;
00786 wrap->firstchild=x;
00787 wrap->lastchild=x;
00788 x->parent=wrap;
00789 return wrap;
00790 }
00791
00792 void xode_free(xode node)
00793 {
00794 if(node == NULL)
00795 return;
00796
00797 xode_pool_free(node->p);
00798 }
00799
00800
00801 void
00802 _xode_to_prettystr( xode_spool s, xode x, int deep )
00803 {
00804 int i;
00805 xode y;
00806
00807 if(xode_get_type(x) != XODE_TYPE_TAG) return;
00808
00809 for(i=0; i<deep; i++) xode_spool_add(s, "\t");
00810
00811 xode_spooler( s , "<" , xode_get_name(x) , s );
00812
00813 y = xode_get_firstattrib(x);
00814 while( y )
00815 {
00816 xode_spooler( s , " " , xode_get_name(y) , "='", xode_get_data(y) , "'" , s );
00817
00818 y = xode_get_nextsibling( y );
00819 }
00820 xode_spool_add(s,">");
00821 xode_spool_add(s,"\n");
00822
00823 if( xode_get_data(x))
00824 {
00825 for(i=0; i<=deep; i++) xode_spool_add(s, "\t");
00826 xode_spool_add( s , xode_get_data(x));
00827 }
00828
00829 y = xode_get_firstchild(x);
00830 while( y )
00831 {
00832 _xode_to_prettystr(s , y, deep+1);
00833 y = xode_get_nextsibling(y);
00834 xode_spool_add(s,"\n");
00835 }
00836
00837 for(i=0; i<deep; i++) xode_spool_add(s, "\t");
00838 xode_spooler( s , "</" , xode_get_name(x) , ">" , s );
00839
00840 return;
00841 }
00842
00843 char *
00844 xode_to_prettystr( xode x )
00845 {
00846 xode_spool s;
00847
00848 if( !x) return NULL;
00849
00850 s = xode_spool_newfrompool( xode_get_pool(x));
00851
00852 _xode_to_prettystr( s , x, 0 );
00853
00854 return xode_spool_tostr(s);
00855 }
00856