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