source: trunk/third/jwgc/lib/libxode/xode.c @ 22406

Revision 22406, 19.6 KB checked in by ghudson, 19 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r22405, which included commits to RCS files with non-trunk default branches.
Line 
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
22static int _xode_strcmp(const char *a, const char *b)
23{
24    if(a == NULL || b == NULL) return -1;
25
26    return strcmp(a,b);
27}
28
29/* Internal routines */
30static xode _xode_new(xode_pool p, const char* name, unsigned int type)
31{
32    xode result = NULL;
33    if (type > XODE_TYPE_LAST)
34        return NULL;
35
36    if (type != XODE_TYPE_CDATA && name == NULL)
37        return NULL;
38
39    if (p == NULL)
40    {
41        p = xode_pool_heap(1*1024);
42    }
43
44    /* Allocate & zero memory */
45    result = (xode)xode_pool_malloc(p, sizeof(_xode));
46    memset(result, '\0', sizeof(_xode));
47
48    /* Initialize fields */
49    if (type != XODE_TYPE_CDATA)
50        result->name = xode_pool_strdup(p,name);
51    result->type = type;
52    result->p = p;
53    return result;
54}
55
56static xode _xode_appendsibling(xode lastsibling, const char* name, unsigned int type)
57{
58    xode result;
59
60    result = _xode_new(xode_get_pool(lastsibling), name, type);
61    if (result != NULL)
62    {
63        /* Setup sibling pointers */
64        result->prev = lastsibling;
65        lastsibling->next = result;
66    }
67    return result;
68}
69
70static xode _xode_insert(xode parent, const char* name, unsigned int type)
71{
72    xode result;
73
74    if(parent == NULL || name == NULL) return NULL;
75
76    /* If parent->firstchild is NULL, simply create a new node for the first child */
77    if (parent->firstchild == NULL)
78    {
79        result = _xode_new(parent->p, name, type);
80        parent->firstchild = result;
81    }
82    /* Otherwise, append this to the lastchild */
83    else
84    {
85        result= _xode_appendsibling(parent->lastchild, name, type);
86    }
87    result->parent = parent;
88    parent->lastchild = result;
89    return result;
90
91}
92
93static xode _xode_search(xode firstsibling, const char* name, unsigned int type)
94{
95    xode current;
96
97    /* Walk the sibling list, looking for a XODE_TYPE_TAG xode with
98    the specified name */
99    current = firstsibling;
100    while (current != NULL)
101    {
102        if (name != NULL && (current->type == type) && (_xode_strcmp(current->name, name) == 0))
103            return current;
104        else
105            current = current->next;
106    }
107    return NULL;
108}
109
110static char* _xode_merge(xode_pool p, char* dest, unsigned int destsize, const char* src, unsigned int srcsize)
111{
112    char* result;
113    result = (char*)xode_pool_malloc(p, destsize + srcsize + 1);
114    memcpy(result, dest, destsize);
115    memcpy(result+destsize, src, srcsize);
116    result[destsize + srcsize] = '\0';
117
118    /* 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 */
119    p->size -= destsize;
120
121    return result;
122}
123
124static void _xode_hidesibling(xode child)
125{
126    if(child == NULL)
127        return;
128
129    if(child->prev != NULL)
130        child->prev->next = child->next;
131    if(child->next != NULL)
132        child->next->prev = child->prev;
133}
134
135static void _xode_tag2str(xode_spool s, xode node, int flag)
136{
137    xode tmp;
138
139    if(flag==0 || flag==1)
140    {
141            xode_spooler(s,"<",xode_get_name(node),s);
142            tmp = xode_get_firstattrib(node);
143            while(tmp) {
144                xode_spooler(s," ",xode_get_name(tmp),"='",xode_strescape(xode_get_pool(node),xode_get_data(tmp)),"'",s);
145                tmp = xode_get_nextsibling(tmp);
146            }
147            if(flag==0)
148                xode_spool_add(s,"/>");
149            else
150                xode_spool_add(s,">");
151    }
152    else
153    {
154            xode_spooler(s,"</",xode_get_name(node),">",s);
155    }
156}
157
158static xode_spool _xode_tospool(xode node)
159{
160    xode_spool s;
161    int level=0,dir=0;
162    xode tmp;
163
164    if(!node || xode_get_type(node) != XODE_TYPE_TAG)
165        return NULL;
166
167    s = xode_spool_newfrompool(xode_get_pool(node));
168    if(!s) return(NULL);
169
170    while(1)
171    {
172        if(dir==0)
173        {
174            if(xode_get_type(node) == XODE_TYPE_TAG)
175            {
176                        if(xode_has_children(node))
177                {
178                            _xode_tag2str(s,node,1);
179                            node = xode_get_firstchild(node);
180                            level++;
181                            continue;
182                        }
183                else
184                {
185                            _xode_tag2str(s,node,0);
186                        }
187                }
188            else
189            {
190                        xode_spool_add(s,xode_strescape(xode_get_pool(node),xode_get_data(node)));
191                }
192            }
193
194        tmp = xode_get_nextsibling(node);
195            if(!tmp)
196        {
197                node = xode_get_parent(node);
198                level--;
199                if(level>=0) _xode_tag2str(s,node,2);
200                if(level<1) break;
201                dir = 1;
202            }
203        else
204        {
205                node = tmp;
206                dir = 0;
207            }
208    }
209
210    return s;
211}
212
213
214/* External routines */
215
216
217/*
218 *  xode_new_tag -- create a tag node
219 *  Automatically creates a memory xode_pool for the node.
220 *
221 *  parameters
222 *      name -- name of the tag
223 *
224 *  returns
225 *      a pointer to the tag node
226 *      or NULL if it was unsuccessfull
227 */
228xode xode_new(const char* name)
229{
230    return _xode_new(NULL, name, XODE_TYPE_TAG);
231}
232
233
234/*
235 *  xode_new_tag_pool -- create a tag node within given pool
236 *
237 *  parameters
238 *      p -- previously created memory pool
239 *      name -- name of the tag
240 *
241 *  returns
242 *      a pointer to the tag node
243 *      or NULL if it was unsuccessfull
244 */
245xode xode_new_frompool(xode_pool p, const char* name)
246{
247    return _xode_new(p, name, XODE_TYPE_TAG);
248}
249
250
251/*
252 *  xode_insert_tag -- append a child tag to a tag
253 *
254 *  parameters
255 *      parent -- pointer to the parent tag
256 *      name -- name of the child tag
257 *
258 *  returns
259 *      a pointer to the child tag node
260 *      or NULL if it was unsuccessfull
261 */
262xode xode_insert_tag(xode parent, const char* name)
263{
264    return _xode_insert(parent, name, XODE_TYPE_TAG);
265}
266
267
268/*
269 *  xode_insert_cdata -- append character data to a tag
270 *  If last child of the parent is CDATA, merges CDATA nodes. Otherwise
271 *  creates a CDATA node, and appends it to the parent's child list.
272 *
273 *  parameters
274 *      parent -- parent tag
275 *      CDATA -- character data
276 *      size -- size of CDATA
277 *              or -1 for null-terminated CDATA strings
278 *
279 *  returns
280 *      a pointer to the child CDATA node
281 *      or NULL if it was unsuccessfull
282 */
283xode xode_insert_cdata(xode parent, const char* CDATA, unsigned int size)
284{
285    xode result;
286
287    if(CDATA == NULL || parent == NULL)
288        return NULL;
289
290    if(size == -1)
291        size = strlen(CDATA);
292
293    if ((parent->lastchild != NULL) && (parent->lastchild->type == XODE_TYPE_CDATA))
294    {
295        result = parent->lastchild;
296        result->data = _xode_merge(result->p, result->data, result->data_sz, CDATA, size);
297        result->data_sz = result->data_sz + size;
298    }
299    else
300    {
301        result = _xode_insert(parent, "", XODE_TYPE_CDATA);
302        if (result != NULL)
303        {
304            result->data = (char*)xode_pool_malloc(result->p, size + 1);
305            memcpy(result->data, CDATA, size);
306            result->data[size] = '\0';
307            result->data_sz = size;
308        }
309    }
310
311    return result;
312}
313
314
315/*
316 *  xode_gettag -- find given tag in an xode tree
317 *
318 *  parameters
319 *      parent -- pointer to the parent tag
320 *      name -- "name" for the child tag of that name
321 *              "name/name" for a sub child (recurses)
322 *              "?attrib" to match the first tag with that attrib defined
323 *              "?attrib=value" to match the first tag with that attrib and value
324 *              or any combination: "name/name/?attrib", etc
325 *
326 *  results
327 *      a pointer to the tag matching search criteria
328 *      or NULL if search was unsuccessfull
329 */
330xode xode_get_tag(xode parent, const char* name)
331{
332    char *str, *slash, *qmark, *equals;
333    xode step, ret;
334
335    if(parent == NULL || parent->firstchild == NULL || name == NULL || name == '\0') return NULL;
336
337    if(strstr(name, "/") == NULL && strstr(name,"?") == NULL)
338        return _xode_search(parent->firstchild, name, XODE_TYPE_TAG);
339
340    /* jer's note: why can't I modify the name directly, why do I have to strdup it?  damn c grrr! */
341    str = strdup(name);
342    slash = strstr(str, "/");
343    qmark = strstr(str, "?");
344    equals = strstr(str, "=");
345
346    if(qmark != NULL && (slash == NULL || qmark < slash))
347    { /* of type ?attrib */
348
349        *qmark = '\0';
350        qmark++;
351        if(equals != NULL)
352        {
353            *equals = '\0';
354            equals++;
355        }
356
357        for(step = parent->firstchild; step != NULL; step = xode_get_nextsibling(step))
358        {
359            if(xode_get_type(step) != XODE_TYPE_TAG)
360                continue;
361
362            if(*str != '\0')
363                if(_xode_strcmp(xode_get_name(step),str) != 0)
364                    continue;
365
366            if(xode_get_attrib(step,qmark) == NULL)
367                continue;
368
369            if(equals != NULL && _xode_strcmp(xode_get_attrib(step,qmark),equals) != 0)
370                continue;
371
372            break;
373        }
374
375        free(str);
376        return step;
377    }
378
379
380    *slash = '\0';
381    ++slash;
382
383    for(step = parent->firstchild; step != NULL; step = xode_get_nextsibling(step))
384    {
385        if(xode_get_type(step) != XODE_TYPE_TAG) continue;
386
387        if(_xode_strcmp(xode_get_name(step),str) != 0)
388            continue;
389
390        ret = xode_get_tag(step, slash);
391        if(ret != NULL)
392        {
393            free(str);
394            return ret;
395        }
396    }
397
398    free(str);
399    return NULL;
400}
401
402
403/* return the cdata from any tag */
404char *xode_get_tagdata(xode parent, const char *name)
405{
406    xode tag;
407
408    tag = xode_get_tag(parent, name);
409    if(tag == NULL) return NULL;
410
411    return xode_get_data(tag);
412}
413
414
415void xode_put_attrib(xode owner, const char* name, const char* value)
416{
417    xode attrib;
418
419    if(owner == NULL || name == NULL || value == NULL) return;
420
421    /* If there are no existing attributs, allocate a new one to start
422    the list */
423    if (owner->firstattrib == NULL)
424    {
425        attrib = _xode_new(owner->p, name, XODE_TYPE_ATTRIB);
426        owner->firstattrib = attrib;
427        owner->lastattrib  = attrib;
428    }
429    else
430    {
431        attrib = _xode_search(owner->firstattrib, name, XODE_TYPE_ATTRIB);
432        if(attrib == NULL)
433        {
434            attrib = _xode_appendsibling(owner->lastattrib, name, XODE_TYPE_ATTRIB);
435            owner->lastattrib = attrib;
436        }
437    }
438    /* Update the value of the attribute */
439    attrib->data_sz = strlen(value);
440    attrib->data    = xode_pool_strdup(owner->p, value);
441
442}
443
444char* xode_get_attrib(xode owner, const char* name)
445{
446    xode attrib;
447
448    if (owner != NULL && owner->firstattrib != NULL)
449    {
450        attrib = _xode_search(owner->firstattrib, name, XODE_TYPE_ATTRIB);
451        if (attrib != NULL)
452            return (char*)attrib->data;
453    }
454    return NULL;
455}
456
457void xode_put_vattrib(xode owner, const char* name, void *value)
458{
459    xode attrib;
460
461    if (owner != NULL)
462    {
463        attrib = _xode_search(owner->firstattrib, name, XODE_TYPE_ATTRIB);
464        if (attrib == NULL)
465        {
466            xode_put_attrib(owner, name, "");
467            attrib = _xode_search(owner->firstattrib, name, XODE_TYPE_ATTRIB);
468        }
469        if (attrib != NULL)
470            attrib->firstchild = (xode)value;
471    }
472}
473
474void* xode_get_vattrib(xode owner, const char* name)
475{
476    xode attrib;
477
478    if (owner != NULL && owner->firstattrib != NULL)
479    {
480        attrib = _xode_search(owner->firstattrib, name, XODE_TYPE_ATTRIB);
481        if (attrib != NULL)
482            return (void*)attrib->firstchild;
483    }
484    return NULL;
485}
486
487xode xode_get_firstattrib(xode parent)
488{
489    if (parent != NULL)
490        return parent->firstattrib;
491    return NULL;
492}
493
494xode xode_get_firstchild(xode parent)
495{
496    if (parent != NULL)
497        return parent->firstchild;
498    return NULL;
499}
500
501xode xode_get_lastchild(xode parent)
502{
503    if (parent != NULL)
504        return parent->lastchild;
505    return NULL;
506}
507
508xode xode_get_nextsibling(xode sibling)
509{
510    if (sibling != NULL)
511        return sibling->next;
512    return NULL;
513}
514
515xode xode_get_prevsibling(xode sibling)
516{
517    if (sibling != NULL)
518        return sibling->prev;
519    return NULL;
520}
521
522xode xode_get_parent(xode node)
523{
524    if (node != NULL)
525        return node->parent;
526    return NULL;
527}
528
529char* xode_get_name(xode node)
530{
531    if (node != NULL)
532        return node->name;
533    return NULL;
534}
535
536char* xode_get_data(xode node)
537{
538    xode cur;
539
540    if(node == NULL) return NULL;
541
542    if(xode_get_type(node) == XODE_TYPE_TAG) /* loop till we find a CDATA */
543    {
544        for(cur = xode_get_firstchild(node); cur != NULL; cur = xode_get_nextsibling(cur))
545            if(xode_get_type(cur) == XODE_TYPE_CDATA)
546                return cur->data;
547    }else{
548        return node->data;
549    }
550    return NULL;
551}
552
553int xode_get_datasz(xode node)
554{
555       
556    if( node == NULL )
557    {
558        return (int)NULL;           
559    }       
560    else if(xode_get_type(node) == XODE_TYPE_TAG) /* loop till we find a CDATA */
561    {
562        xode cur;       
563        for(cur = xode_get_firstchild(node); cur != NULL; cur = xode_get_nextsibling(cur))
564            if(xode_get_type(cur) == XODE_TYPE_CDATA)
565                return cur->data_sz;
566    }else{
567        return node->data_sz;
568    }
569    return (int)NULL;
570}
571
572int xode_get_type(xode node)
573{
574    if (node != NULL)
575    {
576        return node->type;
577    }
578    return (int)NULL;
579}
580
581int xode_has_children(xode node)
582{
583    if ((node != NULL) && (node->firstchild != NULL))
584        return 1;
585    return 0;
586}
587
588int xode_has_attribs(xode node)
589{
590    if ((node != NULL) && (node->firstattrib != NULL))
591        return 1;
592    return 0;
593}
594
595xode_pool xode_get_pool(xode node)
596{
597    if (node != NULL)
598        return node->p;
599    return (xode_pool)NULL;
600}
601
602void xode_hide(xode child)
603{
604    xode parent;
605
606    if(child == NULL || child->parent == NULL)
607        return;
608
609    parent = child->parent;
610
611    /* first fix up at the child level */
612    _xode_hidesibling(child);
613
614    /* next fix up at the parent level */
615    if(parent->firstchild == child)
616        parent->firstchild = child->next;
617    if(parent->lastchild == child)
618        parent->lastchild = child->prev;
619}
620
621void xode_hide_attrib(xode parent, const char *name)
622{
623    xode attrib;
624
625    if(parent == NULL || parent->firstattrib == NULL || name == NULL)
626        return;
627
628    attrib = _xode_search(parent->firstattrib, name, XODE_TYPE_ATTRIB);
629    if(attrib == NULL)
630        return;
631
632    /* first fix up at the child level */
633    _xode_hidesibling(attrib);
634
635    /* next fix up at the parent level */
636    if(parent->firstattrib == attrib)
637        parent->firstattrib = attrib->next;
638    if(parent->lastattrib == attrib)
639        parent->lastattrib = attrib->prev;
640}
641
642
643
644/*
645 *  xode2str -- convert given xode tree into a string
646 *
647 *  parameters
648 *      node -- pointer to the xode structure
649 *
650 *  results
651 *      a pointer to the created string
652 *      or NULL if it was unsuccessfull
653 */
654char *xode_to_str(xode node)
655{
656     return xode_spool_tostr(_xode_tospool(node));
657}
658
659
660/* loop through both a and b comparing everything, attribs, cdata, children, etc */
661int xode_cmp(xode a, xode b)
662{
663    int ret = 0;
664
665    while(1)
666    {
667        if(a == NULL && b == NULL)
668            return 0;
669
670        if(a == NULL || b == NULL)
671            return -1;
672
673        if(xode_get_type(a) != xode_get_type(b))
674            return -1;
675
676        switch(xode_get_type(a))
677        {
678        case XODE_TYPE_ATTRIB:
679            ret = _xode_strcmp(xode_get_name(a), xode_get_name(b));
680            if(ret != 0)
681                return -1;
682            ret = _xode_strcmp(xode_get_data(a), xode_get_data(b));
683            if(ret != 0)
684                return -1;
685            break;
686        case XODE_TYPE_TAG:
687            ret = _xode_strcmp(xode_get_name(a), xode_get_name(b));
688            if(ret != 0)
689                return -1;
690            ret = xode_cmp(xode_get_firstattrib(a), xode_get_firstattrib(b));
691            if(ret != 0)
692                return -1;
693            ret = xode_cmp(xode_get_firstchild(a), xode_get_firstchild(b));
694            if(ret != 0)
695                return -1;
696            break;
697        case XODE_TYPE_CDATA:
698            ret = _xode_strcmp(xode_get_data(a), xode_get_data(b));
699            if(ret != 0)
700                return -1;
701        }
702        a = xode_get_nextsibling(a);
703        b = xode_get_nextsibling(b);
704    }
705}
706
707
708xode xode_insert_tagnode(xode parent, xode node)
709{
710    xode child;
711
712    child = xode_insert_tag(parent, xode_get_name(node));
713    if (xode_has_attribs(node))
714        xode_insert_node(child, xode_get_firstattrib(node));
715    if (xode_has_children(node))
716        xode_insert_node(child, xode_get_firstchild(node));
717
718    return child;
719}
720
721/* places copy of node and node's siblings in parent */
722void xode_insert_node(xode parent, xode node)
723{
724    if(node == NULL || parent == NULL)
725        return;
726
727    while(node != NULL)
728    {
729        switch(xode_get_type(node))
730        {
731        case XODE_TYPE_ATTRIB:
732            xode_put_attrib(parent, xode_get_name(node), xode_get_data(node));
733            break;
734        case XODE_TYPE_TAG:
735            xode_insert_tagnode(parent, node);
736            break;
737        case XODE_TYPE_CDATA:
738            xode_insert_cdata(parent, xode_get_data(node), xode_get_datasz(node));
739        }
740        node = xode_get_nextsibling(node);
741    }
742}
743
744
745/* produce full duplicate of x with a new xode_pool, x must be a tag! */
746xode xode_dup(xode x)
747{
748    xode x2;
749
750    if(x == NULL)
751        return NULL;
752
753    x2 = xode_new(xode_get_name(x));
754
755    if (xode_has_attribs(x))
756        xode_insert_node(x2, xode_get_firstattrib(x));
757    if (xode_has_children(x))
758        xode_insert_node(x2, xode_get_firstchild(x));
759
760    return x2;
761}
762
763xode xode_dup_frompool(xode_pool p, xode x)
764{
765    xode x2;
766
767    if(x == NULL)
768        return NULL;
769
770    x2 = xode_new_frompool(p, xode_get_name(x));
771
772    if (xode_has_attribs(x))
773        xode_insert_node(x2, xode_get_firstattrib(x));
774    if (xode_has_children(x))
775        xode_insert_node(x2, xode_get_firstchild(x));
776
777    return x2;
778}
779
780xode xode_wrap(xode x,const char *wrapper)
781{
782    xode wrap;
783    if(x==NULL||wrapper==NULL) return NULL;
784    wrap=xode_new_frompool(xode_get_pool(x),wrapper);
785    if(wrap==NULL) return NULL;
786    wrap->firstchild=x;
787    wrap->lastchild=x;
788    x->parent=wrap;
789    return wrap;
790}
791
792void xode_free(xode node)
793{
794    if(node == NULL)
795        return;
796
797    xode_pool_free(node->p);
798}
799
800
801void
802_xode_to_prettystr( xode_spool s, xode x, int deep )
803{
804        int i;
805        xode y;
806
807        if(xode_get_type(x) != XODE_TYPE_TAG) return;
808       
809        for(i=0; i<deep; i++) xode_spool_add(s, "\t"); 
810
811        xode_spooler( s , "<" , xode_get_name(x) ,  s );
812
813        y = xode_get_firstattrib(x);
814        while( y )
815        {
816                xode_spooler( s , " " , xode_get_name(y) , "='", xode_get_data(y) , "'" , s );
817
818                y = xode_get_nextsibling( y );
819        }
820        xode_spool_add(s,">");
821        xode_spool_add(s,"\n");
822               
823        if( xode_get_data(x))
824        {
825                for(i=0; i<=deep; i++) xode_spool_add(s, "\t");
826                xode_spool_add( s , xode_get_data(x));
827        }
828                       
829        y = xode_get_firstchild(x);
830        while( y )
831        {
832                _xode_to_prettystr(s , y, deep+1);
833                y = xode_get_nextsibling(y);
834                xode_spool_add(s,"\n");
835        }
836               
837        for(i=0; i<deep; i++) xode_spool_add(s, "\t"); 
838        xode_spooler( s , "</" , xode_get_name(x) , ">" , s );
839
840        return;
841}
842
843char *
844xode_to_prettystr( xode x )
845{
846        xode_spool s;
847
848        if( !x) return NULL;
849       
850        s = xode_spool_newfrompool( xode_get_pool(x));
851
852        _xode_to_prettystr( s , x, 0 );
853
854        return xode_spool_tostr(s);
855}
856
Note: See TracBrowser for help on using the repository browser.