modules_k/xmpp/xode.c

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