tizen 2.4 release
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / tools / gator / daemon / mxml / mxml-node.c
1 /*
2  * "$Id: mxml-node.c 451 2014-01-04 21:50:06Z msweet $"
3  *
4  * Node support code for Mini-XML, a small XML-like file parsing library.
5  *
6  * Copyright 2003-2014 by Michael R Sweet.
7  *
8  * These coded instructions, statements, and computer programs are the
9  * property of Michael R Sweet and are protected by Federal copyright
10  * law.  Distribution and use rights are outlined in the file "COPYING"
11  * which should have been included with this file.  If this file is
12  * missing or damaged, see the license at:
13  *
14  *     http://www.msweet.org/projects.php/Mini-XML
15  */
16
17 /*
18  * Include necessary headers...
19  */
20
21 #include "config.h"
22 #include "mxml.h"
23
24
25 /*
26  * Local functions...
27  */
28
29 static mxml_node_t      *mxml_new(mxml_node_t *parent, mxml_type_t type);
30
31
32 /*
33  * 'mxmlAdd()' - Add a node to a tree.
34  *
35  * Adds the specified node to the parent. If the child argument is not
36  * NULL, puts the new node before or after the specified child depending
37  * on the value of the where argument. If the child argument is NULL,
38  * puts the new node at the beginning of the child list (MXML_ADD_BEFORE)
39  * or at the end of the child list (MXML_ADD_AFTER). The constant
40  * MXML_ADD_TO_PARENT can be used to specify a NULL child pointer.
41  */
42
43 void
44 mxmlAdd(mxml_node_t *parent,            /* I - Parent node */
45         int         where,              /* I - Where to add, MXML_ADD_BEFORE or MXML_ADD_AFTER */
46         mxml_node_t *child,             /* I - Child node for where or MXML_ADD_TO_PARENT */
47         mxml_node_t *node)              /* I - Node to add */
48 {
49 #ifdef DEBUG
50   fprintf(stderr, "mxmlAdd(parent=%p, where=%d, child=%p, node=%p)\n", parent,
51           where, child, node);
52 #endif /* DEBUG */
53
54  /*
55   * Range check input...
56   */
57
58   if (!parent || !node)
59     return;
60
61 #if DEBUG > 1
62   fprintf(stderr, "    BEFORE: node->parent=%p\n", node->parent);
63   if (parent)
64   {
65     fprintf(stderr, "    BEFORE: parent->child=%p\n", parent->child);
66     fprintf(stderr, "    BEFORE: parent->last_child=%p\n", parent->last_child);
67     fprintf(stderr, "    BEFORE: parent->prev=%p\n", parent->prev);
68     fprintf(stderr, "    BEFORE: parent->next=%p\n", parent->next);
69   }
70 #endif /* DEBUG > 1 */
71
72  /*
73   * Remove the node from any existing parent...
74   */
75
76   if (node->parent)
77     mxmlRemove(node);
78
79  /*
80   * Reset pointers...
81   */
82
83   node->parent = parent;
84
85   switch (where)
86   {
87     case MXML_ADD_BEFORE :
88         if (!child || child == parent->child || child->parent != parent)
89         {
90          /*
91           * Insert as first node under parent...
92           */
93
94           node->next = parent->child;
95
96           if (parent->child)
97             parent->child->prev = node;
98           else
99             parent->last_child = node;
100
101           parent->child = node;
102         }
103         else
104         {
105          /*
106           * Insert node before this child...
107           */
108
109           node->next = child;
110           node->prev = child->prev;
111
112           if (child->prev)
113             child->prev->next = node;
114           else
115             parent->child = node;
116
117           child->prev = node;
118         }
119         break;
120
121     case MXML_ADD_AFTER :
122         if (!child || child == parent->last_child || child->parent != parent)
123         {
124          /*
125           * Insert as last node under parent...
126           */
127
128           node->parent = parent;
129           node->prev   = parent->last_child;
130
131           if (parent->last_child)
132             parent->last_child->next = node;
133           else
134             parent->child = node;
135
136           parent->last_child = node;
137         }
138         else
139         {
140          /*
141           * Insert node after this child...
142           */
143
144           node->prev = child;
145           node->next = child->next;
146
147           if (child->next)
148             child->next->prev = node;
149           else
150             parent->last_child = node;
151
152           child->next = node;
153         }
154         break;
155   }
156
157 #if DEBUG > 1
158   fprintf(stderr, "    AFTER: node->parent=%p\n", node->parent);
159   if (parent)
160   {
161     fprintf(stderr, "    AFTER: parent->child=%p\n", parent->child);
162     fprintf(stderr, "    AFTER: parent->last_child=%p\n", parent->last_child);
163     fprintf(stderr, "    AFTER: parent->prev=%p\n", parent->prev);
164     fprintf(stderr, "    AFTER: parent->next=%p\n", parent->next);
165   }
166 #endif /* DEBUG > 1 */
167 }
168
169
170 /*
171  * 'mxmlDelete()' - Delete a node and all of its children.
172  *
173  * If the specified node has a parent, this function first removes the
174  * node from its parent using the mxmlRemove() function.
175  */
176
177 void
178 mxmlDelete(mxml_node_t *node)           /* I - Node to delete */
179 {
180   int   i;                              /* Looping var */
181
182
183 #ifdef DEBUG
184   fprintf(stderr, "mxmlDelete(node=%p)\n", node);
185 #endif /* DEBUG */
186
187  /*
188   * Range check input...
189   */
190
191   if (!node)
192     return;
193
194  /*
195   * Remove the node from its parent, if any...
196   */
197
198   mxmlRemove(node);
199
200  /*
201   * Delete children...
202   */
203
204   while (node->child)
205     mxmlDelete(node->child);
206
207  /*
208   * Now delete any node data...
209   */
210
211   switch (node->type)
212   {
213     case MXML_ELEMENT :
214         if (node->value.element.name)
215           free(node->value.element.name);
216
217         if (node->value.element.num_attrs)
218         {
219           for (i = 0; i < node->value.element.num_attrs; i ++)
220           {
221             if (node->value.element.attrs[i].name)
222               free(node->value.element.attrs[i].name);
223             if (node->value.element.attrs[i].value)
224               free(node->value.element.attrs[i].value);
225           }
226
227           free(node->value.element.attrs);
228         }
229         break;
230     case MXML_INTEGER :
231        /* Nothing to do */
232         break;
233     case MXML_OPAQUE :
234         if (node->value.opaque)
235           free(node->value.opaque);
236         break;
237     case MXML_REAL :
238        /* Nothing to do */
239         break;
240     case MXML_TEXT :
241         if (node->value.text.string)
242           free(node->value.text.string);
243         break;
244     case MXML_CUSTOM :
245         if (node->value.custom.data &&
246             node->value.custom.destroy)
247           (*(node->value.custom.destroy))(node->value.custom.data);
248         break;
249     default :
250         break;
251   }
252
253  /*
254   * Free this node...
255   */
256
257   free(node);
258 }
259
260
261 /*
262  * 'mxmlGetRefCount()' - Get the current reference (use) count for a node.
263  *
264  * The initial reference count of new nodes is 1. Use the @link mxmlRetain@
265  * and @link mxmlRelease@ functions to increment and decrement a node's
266  * reference count.
267  *
268  * @since Mini-XML 2.7@.
269  */
270
271 int                                     /* O - Reference count */
272 mxmlGetRefCount(mxml_node_t *node)      /* I - Node */
273 {
274  /*
275   * Range check input...
276   */
277
278   if (!node)
279     return (0);
280
281  /*
282   * Return the reference count...
283   */
284
285   return (node->ref_count);
286 }
287
288
289 /*
290  * 'mxmlNewCDATA()' - Create a new CDATA node.
291  *
292  * The new CDATA node is added to the end of the specified parent's child
293  * list. The constant MXML_NO_PARENT can be used to specify that the new
294  * CDATA node has no parent. The data string must be nul-terminated and
295  * is copied into the new node. CDATA nodes use the MXML_ELEMENT type.
296  *
297  * @since Mini-XML 2.3@
298  */
299
300 mxml_node_t *                           /* O - New node */
301 mxmlNewCDATA(mxml_node_t *parent,       /* I - Parent node or MXML_NO_PARENT */
302              const char  *data)         /* I - Data string */
303 {
304   mxml_node_t   *node;                  /* New node */
305
306
307 #ifdef DEBUG
308   fprintf(stderr, "mxmlNewCDATA(parent=%p, data=\"%s\")\n",
309           parent, data ? data : "(null)");
310 #endif /* DEBUG */
311
312  /*
313   * Range check input...
314   */
315
316   if (!data)
317     return (NULL);
318
319  /*
320   * Create the node and set the name value...
321   */
322
323   if ((node = mxml_new(parent, MXML_ELEMENT)) != NULL)
324     node->value.element.name = _mxml_strdupf("![CDATA[%s]]", data);
325
326   return (node);
327 }
328
329
330 /*
331  * 'mxmlNewCustom()' - Create a new custom data node.
332  *
333  * The new custom node is added to the end of the specified parent's child
334  * list. The constant MXML_NO_PARENT can be used to specify that the new
335  * element node has no parent. NULL can be passed when the data in the
336  * node is not dynamically allocated or is separately managed.
337  *
338  * @since Mini-XML 2.1@
339  */
340
341 mxml_node_t *                           /* O - New node */
342 mxmlNewCustom(
343     mxml_node_t              *parent,   /* I - Parent node or MXML_NO_PARENT */
344     void                     *data,     /* I - Pointer to data */
345     mxml_custom_destroy_cb_t destroy)   /* I - Function to destroy data */
346 {
347   mxml_node_t   *node;                  /* New node */
348
349
350 #ifdef DEBUG
351   fprintf(stderr, "mxmlNewCustom(parent=%p, data=%p, destroy=%p)\n", parent,
352           data, destroy);
353 #endif /* DEBUG */
354
355  /*
356   * Create the node and set the value...
357   */
358
359   if ((node = mxml_new(parent, MXML_CUSTOM)) != NULL)
360   {
361     node->value.custom.data    = data;
362     node->value.custom.destroy = destroy;
363   }
364
365   return (node);
366 }
367
368
369 /*
370  * 'mxmlNewElement()' - Create a new element node.
371  *
372  * The new element node is added to the end of the specified parent's child
373  * list. The constant MXML_NO_PARENT can be used to specify that the new
374  * element node has no parent.
375  */
376
377 mxml_node_t *                           /* O - New node */
378 mxmlNewElement(mxml_node_t *parent,     /* I - Parent node or MXML_NO_PARENT */
379                const char  *name)       /* I - Name of element */
380 {
381   mxml_node_t   *node;                  /* New node */
382
383
384 #ifdef DEBUG
385   fprintf(stderr, "mxmlNewElement(parent=%p, name=\"%s\")\n", parent,
386           name ? name : "(null)");
387 #endif /* DEBUG */
388
389  /*
390   * Range check input...
391   */
392
393   if (!name)
394     return (NULL);
395
396  /*
397   * Create the node and set the element name...
398   */
399
400   if ((node = mxml_new(parent, MXML_ELEMENT)) != NULL)
401     node->value.element.name = strdup(name);
402
403   return (node);
404 }
405
406
407 /*
408  * 'mxmlNewInteger()' - Create a new integer node.
409  *
410  * The new integer node is added to the end of the specified parent's child
411  * list. The constant MXML_NO_PARENT can be used to specify that the new
412  * integer node has no parent.
413  */
414
415 mxml_node_t *                           /* O - New node */
416 mxmlNewInteger(mxml_node_t *parent,     /* I - Parent node or MXML_NO_PARENT */
417                int         integer)     /* I - Integer value */
418 {
419   mxml_node_t   *node;                  /* New node */
420
421
422 #ifdef DEBUG
423   fprintf(stderr, "mxmlNewInteger(parent=%p, integer=%d)\n", parent, integer);
424 #endif /* DEBUG */
425
426  /*
427   * Create the node and set the element name...
428   */
429
430   if ((node = mxml_new(parent, MXML_INTEGER)) != NULL)
431     node->value.integer = integer;
432
433   return (node);
434 }
435
436
437 /*
438  * 'mxmlNewOpaque()' - Create a new opaque string.
439  *
440  * The new opaque node is added to the end of the specified parent's child
441  * list. The constant MXML_NO_PARENT can be used to specify that the new
442  * opaque node has no parent. The opaque string must be nul-terminated and
443  * is copied into the new node.
444  */
445
446 mxml_node_t *                           /* O - New node */
447 mxmlNewOpaque(mxml_node_t *parent,      /* I - Parent node or MXML_NO_PARENT */
448               const char  *opaque)      /* I - Opaque string */
449 {
450   mxml_node_t   *node;                  /* New node */
451
452
453 #ifdef DEBUG
454   fprintf(stderr, "mxmlNewOpaque(parent=%p, opaque=\"%s\")\n", parent,
455           opaque ? opaque : "(null)");
456 #endif /* DEBUG */
457
458  /*
459   * Range check input...
460   */
461
462   if (!opaque)
463     return (NULL);
464
465  /*
466   * Create the node and set the element name...
467   */
468
469   if ((node = mxml_new(parent, MXML_OPAQUE)) != NULL)
470     node->value.opaque = strdup(opaque);
471
472   return (node);
473 }
474
475
476 /*
477  * 'mxmlNewReal()' - Create a new real number node.
478  *
479  * The new real number node is added to the end of the specified parent's
480  * child list. The constant MXML_NO_PARENT can be used to specify that
481  * the new real number node has no parent.
482  */
483
484 mxml_node_t *                           /* O - New node */
485 mxmlNewReal(mxml_node_t *parent,        /* I - Parent node or MXML_NO_PARENT */
486             double      real)           /* I - Real number value */
487 {
488   mxml_node_t   *node;                  /* New node */
489
490
491 #ifdef DEBUG
492   fprintf(stderr, "mxmlNewReal(parent=%p, real=%g)\n", parent, real);
493 #endif /* DEBUG */
494
495  /*
496   * Create the node and set the element name...
497   */
498
499   if ((node = mxml_new(parent, MXML_REAL)) != NULL)
500     node->value.real = real;
501
502   return (node);
503 }
504
505
506 /*
507  * 'mxmlNewText()' - Create a new text fragment node.
508  *
509  * The new text node is added to the end of the specified parent's child
510  * list. The constant MXML_NO_PARENT can be used to specify that the new
511  * text node has no parent. The whitespace parameter is used to specify
512  * whether leading whitespace is present before the node. The text
513  * string must be nul-terminated and is copied into the new node.
514  */
515
516 mxml_node_t *                           /* O - New node */
517 mxmlNewText(mxml_node_t *parent,        /* I - Parent node or MXML_NO_PARENT */
518             int         whitespace,     /* I - 1 = leading whitespace, 0 = no whitespace */
519             const char  *string)        /* I - String */
520 {
521   mxml_node_t   *node;                  /* New node */
522
523
524 #ifdef DEBUG
525   fprintf(stderr, "mxmlNewText(parent=%p, whitespace=%d, string=\"%s\")\n",
526           parent, whitespace, string ? string : "(null)");
527 #endif /* DEBUG */
528
529  /*
530   * Range check input...
531   */
532
533   if (!string)
534     return (NULL);
535
536  /*
537   * Create the node and set the text value...
538   */
539
540   if ((node = mxml_new(parent, MXML_TEXT)) != NULL)
541   {
542     node->value.text.whitespace = whitespace;
543     node->value.text.string     = strdup(string);
544   }
545
546   return (node);
547 }
548
549
550 /*
551  * 'mxmlNewTextf()' - Create a new formatted text fragment node.
552  *
553  * The new text node is added to the end of the specified parent's child
554  * list. The constant MXML_NO_PARENT can be used to specify that the new
555  * text node has no parent. The whitespace parameter is used to specify
556  * whether leading whitespace is present before the node. The format
557  * string must be nul-terminated and is formatted into the new node.
558  */
559
560 mxml_node_t *                           /* O - New node */
561 mxmlNewTextf(mxml_node_t *parent,       /* I - Parent node or MXML_NO_PARENT */
562              int         whitespace,    /* I - 1 = leading whitespace, 0 = no whitespace */
563              const char  *format,       /* I - Printf-style frmat string */
564              ...)                       /* I - Additional args as needed */
565 {
566   mxml_node_t   *node;                  /* New node */
567   va_list       ap;                     /* Pointer to arguments */
568
569
570 #ifdef DEBUG
571   fprintf(stderr, "mxmlNewTextf(parent=%p, whitespace=%d, format=\"%s\", ...)\n",
572           parent, whitespace, format ? format : "(null)");
573 #endif /* DEBUG */
574
575  /*
576   * Range check input...
577   */
578
579   if (!format)
580     return (NULL);
581
582  /*
583   * Create the node and set the text value...
584   */
585
586   if ((node = mxml_new(parent, MXML_TEXT)) != NULL)
587   {
588     va_start(ap, format);
589
590     node->value.text.whitespace = whitespace;
591     node->value.text.string     = _mxml_vstrdupf(format, ap);
592
593     va_end(ap);
594   }
595
596   return (node);
597 }
598
599
600 /*
601  * 'mxmlRemove()' - Remove a node from its parent.
602  *
603  * Does not free memory used by the node - use mxmlDelete() for that.
604  * This function does nothing if the node has no parent.
605  */
606
607 void
608 mxmlRemove(mxml_node_t *node)           /* I - Node to remove */
609 {
610 #ifdef DEBUG
611   fprintf(stderr, "mxmlRemove(node=%p)\n", node);
612 #endif /* DEBUG */
613
614  /*
615   * Range check input...
616   */
617
618   if (!node || !node->parent)
619     return;
620
621  /*
622   * Remove from parent...
623   */
624
625 #if DEBUG > 1
626   fprintf(stderr, "    BEFORE: node->parent=%p\n", node->parent);
627   if (node->parent)
628   {
629     fprintf(stderr, "    BEFORE: node->parent->child=%p\n", node->parent->child);
630     fprintf(stderr, "    BEFORE: node->parent->last_child=%p\n", node->parent->last_child);
631   }
632   fprintf(stderr, "    BEFORE: node->child=%p\n", node->child);
633   fprintf(stderr, "    BEFORE: node->last_child=%p\n", node->last_child);
634   fprintf(stderr, "    BEFORE: node->prev=%p\n", node->prev);
635   fprintf(stderr, "    BEFORE: node->next=%p\n", node->next);
636 #endif /* DEBUG > 1 */
637
638   if (node->prev)
639     node->prev->next = node->next;
640   else
641     node->parent->child = node->next;
642
643   if (node->next)
644     node->next->prev = node->prev;
645   else
646     node->parent->last_child = node->prev;
647
648   node->parent = NULL;
649   node->prev   = NULL;
650   node->next   = NULL;
651
652 #if DEBUG > 1
653   fprintf(stderr, "    AFTER: node->parent=%p\n", node->parent);
654   if (node->parent)
655   {
656     fprintf(stderr, "    AFTER: node->parent->child=%p\n", node->parent->child);
657     fprintf(stderr, "    AFTER: node->parent->last_child=%p\n", node->parent->last_child);
658   }
659   fprintf(stderr, "    AFTER: node->child=%p\n", node->child);
660   fprintf(stderr, "    AFTER: node->last_child=%p\n", node->last_child);
661   fprintf(stderr, "    AFTER: node->prev=%p\n", node->prev);
662   fprintf(stderr, "    AFTER: node->next=%p\n", node->next);
663 #endif /* DEBUG > 1 */
664 }
665
666
667 /*
668  * 'mxmlNewXML()' - Create a new XML document tree.
669  *
670  * The "version" argument specifies the version number to put in the
671  * ?xml element node. If NULL, version 1.0 is assumed.
672  *
673  * @since Mini-XML 2.3@
674  */
675
676 mxml_node_t *                           /* O - New ?xml node */
677 mxmlNewXML(const char *version)         /* I - Version number to use */
678 {
679   char  element[1024];                  /* Element text */
680
681
682   snprintf(element, sizeof(element), "?xml version=\"%s\" encoding=\"utf-8\"?",
683            version ? version : "1.0");
684
685   return (mxmlNewElement(NULL, element));
686 }
687
688
689 /*
690  * 'mxmlRelease()' - Release a node.
691  *
692  * When the reference count reaches zero, the node (and any children)
693  * is deleted via mxmlDelete().
694  *
695  * @since Mini-XML 2.3@
696  */
697
698 int                                     /* O - New reference count */
699 mxmlRelease(mxml_node_t *node)          /* I - Node */
700 {
701   if (node)
702   {
703     if ((-- node->ref_count) <= 0)
704     {
705       mxmlDelete(node);
706       return (0);
707     }
708     else
709       return (node->ref_count);
710   }
711   else
712     return (-1);
713 }
714
715
716 /*
717  * 'mxmlRetain()' - Retain a node.
718  *
719  * @since Mini-XML 2.3@
720  */
721
722 int                                     /* O - New reference count */
723 mxmlRetain(mxml_node_t *node)           /* I - Node */
724 {
725   if (node)
726     return (++ node->ref_count);
727   else
728     return (-1);
729 }
730
731
732 /*
733  * 'mxml_new()' - Create a new node.
734  */
735
736 static mxml_node_t *                    /* O - New node */
737 mxml_new(mxml_node_t *parent,           /* I - Parent node */
738          mxml_type_t type)              /* I - Node type */
739 {
740   mxml_node_t   *node;                  /* New node */
741
742
743 #if DEBUG > 1
744   fprintf(stderr, "mxml_new(parent=%p, type=%d)\n", parent, type);
745 #endif /* DEBUG > 1 */
746
747  /*
748   * Allocate memory for the node...
749   */
750
751   if ((node = calloc(1, sizeof(mxml_node_t))) == NULL)
752   {
753 #if DEBUG > 1
754     fputs("    returning NULL\n", stderr);
755 #endif /* DEBUG > 1 */
756
757     return (NULL);
758   }
759
760 #if DEBUG > 1
761   fprintf(stderr, "    returning %p\n", node);
762 #endif /* DEBUG > 1 */
763
764  /*
765   * Set the node type...
766   */
767
768   node->type      = type;
769   node->ref_count = 1;
770
771  /*
772   * Add to the parent if present...
773   */
774
775   if (parent)
776     mxmlAdd(parent, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, node);
777
778  /*
779   * Return the new node...
780   */
781
782   return (node);
783 }
784
785
786 /*
787  * End of "$Id: mxml-node.c 451 2014-01-04 21:50:06Z msweet $".
788  */