Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

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