/home/dko/projects/mobilec/tags/MobileC-v1.10.2/MobileC-v1.10.2/src/mxml-2.2.2/mxml-node.c

Go to the documentation of this file.
00001 /* SVN FILE INFO
00002  * $Revision: 207 $ : Last Committed Revision
00003  * $Date: 2008-07-11 17:55:19 -0700 (Fri, 11 Jul 2008) $ : Last Committed Date */
00004 /*
00005  * "$Id: mxml-node.c,v 1.1 2007/05/23 20:43:27 david_ko Exp $"
00006  *
00007  * Node support code for Mini-XML, a small XML-like file parsing library.
00008  *
00009  * Copyright 2003-2005 by Michael Sweet.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU Library General Public
00013  * License as published by the Free Software Foundation; either
00014  * version 2, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * Contents:
00022  *
00023  *   mxmlAdd()        - Add a node to a tree.
00024  *   mxmlDelete()     - Delete a node and all of its children.
00025  *   mxmlNewElement() - Create a new element node.
00026  *   mxmlNewInteger() - Create a new integer node.
00027  *   mxmlNewOpaque()  - Create a new opaque string.
00028  *   mxmlNewReal()    - Create a new real number node.
00029  *   mxmlNewText()    - Create a new text fragment node.
00030  *   mxmlNewTextf()   - Create a new formatted text fragment node.
00031  *   mxmlRemove()     - Remove a node from its parent.
00032  *   mxml_new()       - Create a new node.
00033  */
00034 
00035 /*
00036  * Include necessary headers...
00037  */
00038 
00039 #include "config.h"
00040 #include "mxml.h"
00041 
00042 
00043 /*
00044  * Local functions...
00045  */
00046 
00047 static mxml_node_t      *mxml_new(mxml_node_t *parent, mxml_type_t type);
00048 
00049 
00050 /*
00051  * 'mxmlAdd()' - Add a node to a tree.
00052  *
00053  * Adds the specified node to the parent. If the child argument is not
00054  * NULL, puts the new node before or after the specified child depending
00055  * on the value of the where argument. If the child argument is NULL,
00056  * puts the new node at the beginning of the child list (MXML_ADD_BEFORE)
00057  * or at the end of the child list (MXML_ADD_AFTER). The constant
00058  * MXML_ADD_TO_PARENT can be used to specify a NULL child pointer.
00059  */
00060 
00061 void
00062 mxmlAdd(mxml_node_t *parent,            /* I - Parent node */
00063         int         where,              /* I - Where to add, MXML_ADD_BEFORE or MXML_ADD_AFTER */
00064         mxml_node_t *child,             /* I - Child node for where or MXML_ADD_TO_PARENT */
00065         mxml_node_t *node)              /* I - Node to add */
00066 {
00067 #ifdef DEBUG
00068   fprintf(stderr, "mxmlAdd(parent=%p, where=%d, child=%p, node=%p)\n", parent,
00069           where, child, node);
00070 #endif /* DEBUG */
00071 
00072  /*
00073   * Range check input...
00074   */
00075 
00076   if (!parent || !node)
00077     return;
00078 
00079 #if DEBUG > 1
00080   fprintf(stderr, "    BEFORE: node->parent=%p\n", node->parent);
00081   if (parent)
00082   {
00083     fprintf(stderr, "    BEFORE: parent->child=%p\n", parent->child);
00084     fprintf(stderr, "    BEFORE: parent->last_child=%p\n", parent->last_child);
00085     fprintf(stderr, "    BEFORE: parent->prev=%p\n", parent->prev);
00086     fprintf(stderr, "    BEFORE: parent->next=%p\n", parent->next);
00087   }
00088 #endif /* DEBUG > 1 */
00089 
00090  /*
00091   * Remove the node from any existing parent...
00092   */
00093 
00094   if (node->parent)
00095     mxmlRemove(node);
00096 
00097  /*
00098   * Reset pointers...
00099   */
00100 
00101   node->parent = parent;
00102 
00103   switch (where)
00104   {
00105     case MXML_ADD_BEFORE :
00106         if (!child || child == parent->child || child->parent != parent)
00107         {
00108          /*
00109           * Insert as first node under parent...
00110           */
00111 
00112           node->next = parent->child;
00113 
00114           if (parent->child)
00115             parent->child->prev = node;
00116           else
00117             parent->last_child = node;
00118 
00119           parent->child = node;
00120         }
00121         else
00122         {
00123          /*
00124           * Insert node before this child...
00125           */
00126 
00127           node->next = child;
00128           node->prev = child->prev;
00129 
00130           if (child->prev)
00131             child->prev->next = node;
00132           else
00133             parent->child = node;
00134 
00135           child->prev = node;
00136         }
00137         break;
00138 
00139     case MXML_ADD_AFTER :
00140         if (!child || child == parent->last_child || child->parent != parent)
00141         {
00142          /*
00143           * Insert as last node under parent...
00144           */
00145 
00146           node->parent = parent;
00147           node->prev   = parent->last_child;
00148 
00149           if (parent->last_child)
00150             parent->last_child->next = node;
00151           else
00152             parent->child = node;
00153 
00154           parent->last_child = node;
00155         }
00156         else
00157         {
00158          /*
00159           * Insert node after this child...
00160           */
00161 
00162           node->prev = child;
00163           node->next = child->next;
00164 
00165           if (child->next)
00166             child->next->prev = node;
00167           else
00168             parent->last_child = node;
00169 
00170           child->next = node;
00171         }
00172         break;
00173   }
00174 
00175 #if DEBUG > 1
00176   fprintf(stderr, "    AFTER: node->parent=%p\n", node->parent);
00177   if (parent)
00178   {
00179     fprintf(stderr, "    AFTER: parent->child=%p\n", parent->child);
00180     fprintf(stderr, "    AFTER: parent->last_child=%p\n", parent->last_child);
00181     fprintf(stderr, "    AFTER: parent->prev=%p\n", parent->prev);
00182     fprintf(stderr, "    AFTER: parent->next=%p\n", parent->next);
00183   }
00184 #endif /* DEBUG > 1 */
00185 }
00186 
00187 
00188 /*
00189  * 'mxmlDelete()' - Delete a node and all of its children.
00190  *
00191  * If the specified node has a parent, this function first removes the
00192  * node from its parent using the mxmlRemove() function.
00193  */
00194 
00195 void
00196 mxmlDelete(mxml_node_t *node)           /* I - Node to delete */
00197 {
00198   int   i;                              /* Looping var */
00199 
00200 
00201 #ifdef DEBUG
00202   fprintf(stderr, "mxmlDelete(node=%p)\n", node);
00203 #endif /* DEBUG */
00204 
00205  /*
00206   * Range check input...
00207   */
00208 
00209   if (!node)
00210     return;
00211 
00212  /*
00213   * Remove the node from its parent, if any...
00214   */
00215 
00216   mxmlRemove(node);
00217 
00218  /*
00219   * Delete children...
00220   */
00221 
00222   while (node->child)
00223     mxmlDelete(node->child);
00224 
00225  /*
00226   * Now delete any node data...
00227   */
00228 
00229   switch (node->type)
00230   {
00231     case MXML_ELEMENT :
00232         if (node->value.element.name)
00233           free(node->value.element.name);
00234 
00235         if (node->value.element.num_attrs)
00236         {
00237           for (i = 0; i < node->value.element.num_attrs; i ++)
00238           {
00239             if (node->value.element.attrs[i].name)
00240               free(node->value.element.attrs[i].name);
00241             if (node->value.element.attrs[i].value)
00242               free(node->value.element.attrs[i].value);
00243           }
00244 
00245           free(node->value.element.attrs);
00246         }
00247         break;
00248     case MXML_INTEGER :
00249        /* Nothing to do */
00250         break;
00251     case MXML_OPAQUE :
00252         if (node->value.opaque)
00253           free(node->value.opaque);
00254         break;
00255     case MXML_REAL :
00256        /* Nothing to do */
00257         break;
00258     case MXML_TEXT :
00259         if (node->value.text.string)
00260           free(node->value.text.string);
00261         break;
00262     case MXML_CUSTOM :
00263         if (node->value.custom.data &&
00264             node->value.custom.destroy)
00265           (*(node->value.custom.destroy))(node->value.custom.data);
00266         break;
00267   }
00268 
00269  /*
00270   * Free this node...
00271   */
00272 
00273   free(node);
00274 }
00275 
00276 
00277 /*
00278  * 'mxmlNewCustom()' - Create a new custom data node.
00279  *
00280  * The new custom node is added to the end of the specified parent's child
00281  * list. The constant MXML_NO_PARENT can be used to specify that the new
00282  * element node has no parent. NULL can be passed when the data in the
00283  * node is not dynamically allocated or is separately managed.
00284  */
00285 
00286 mxml_node_t *                           /* O - New node */
00287 mxmlNewCustom(mxml_node_t *parent,      /* I - Parent node or MXML_NO_PARENT */
00288               void        *data,        /* I - Pointer to data */
00289               void        (*destroy)(void *))
00290                                         /* I - Function to destroy data */
00291 {
00292   mxml_node_t   *node;                  /* New node */
00293 
00294 
00295 #ifdef DEBUG
00296   fprintf(stderr, "mxmlNewCustom(parent=%p, data=%p, destroy=%p)\n", parent,
00297           data, destroy);
00298 #endif /* DEBUG */
00299 
00300  /*
00301   * Create the node and set the value...
00302   */
00303 
00304   if ((node = mxml_new(parent, MXML_CUSTOM)) != NULL)
00305   {
00306     node->value.custom.data    = data;
00307     node->value.custom.destroy = destroy;
00308   }
00309 
00310   return (node);
00311 }
00312 
00313 
00314 /*
00315  * 'mxmlNewElement()' - Create a new element node.
00316  *
00317  * The new element node is added to the end of the specified parent's child
00318  * list. The constant MXML_NO_PARENT can be used to specify that the new
00319  * element node has no parent.
00320  */
00321 
00322 mxml_node_t *                           /* O - New node */
00323 mxmlNewElement(mxml_node_t *parent,     /* I - Parent node or MXML_NO_PARENT */
00324                const char  *name)       /* I - Name of element */
00325 {
00326   mxml_node_t   *node;                  /* New node */
00327 
00328 
00329 #ifdef DEBUG
00330   fprintf(stderr, "mxmlNewElement(parent=%p, name=\"%s\")\n", parent,
00331           name ? name : "(null)");
00332 #endif /* DEBUG */
00333 
00334  /*
00335   * Range check input...
00336   */
00337 
00338   if (!name)
00339     return (NULL);
00340 
00341  /*
00342   * Create the node and set the element name...
00343   */
00344 
00345   if ((node = mxml_new(parent, MXML_ELEMENT)) != NULL)
00346     node->value.element.name = strdup(name);
00347 
00348   return (node);
00349 }
00350 
00351 
00352 /*
00353  * 'mxmlNewInteger()' - Create a new integer node.
00354  *
00355  * The new integer node is added to the end of the specified parent's child
00356  * list. The constant MXML_NO_PARENT can be used to specify that the new
00357  * integer node has no parent.
00358  */
00359 
00360 mxml_node_t *                           /* O - New node */
00361 mxmlNewInteger(mxml_node_t *parent,     /* I - Parent node or MXML_NO_PARENT */
00362                int         integer)     /* I - Integer value */
00363 {
00364   mxml_node_t   *node;                  /* New node */
00365 
00366 
00367 #ifdef DEBUG
00368   fprintf(stderr, "mxmlNewInteger(parent=%p, integer=%d)\n", parent, integer);
00369 #endif /* DEBUG */
00370 
00371  /*
00372   * Create the node and set the element name...
00373   */
00374 
00375   if ((node = mxml_new(parent, MXML_INTEGER)) != NULL)
00376     node->value.integer = integer;
00377 
00378   return (node);
00379 }
00380 
00381 
00382 /*
00383  * 'mxmlNewOpaque()' - Create a new opaque string.
00384  *
00385  * The new opaque node is added to the end of the specified parent's child
00386  * list. The constant MXML_NO_PARENT can be used to specify that the new
00387  * opaque node has no parent. The opaque string must be nul-terminated and
00388  * is copied into the new node.
00389  */
00390 
00391 mxml_node_t *                           /* O - New node */
00392 mxmlNewOpaque(mxml_node_t *parent,      /* I - Parent node or MXML_NO_PARENT */
00393               const char  *opaque)      /* I - Opaque string */
00394 {
00395   mxml_node_t   *node;                  /* New node */
00396 
00397 
00398 #ifdef DEBUG
00399   fprintf(stderr, "mxmlNewOpaque(parent=%p, opaque=\"%s\")\n", parent,
00400           opaque ? opaque : "(null)");
00401 #endif /* DEBUG */
00402 
00403  /*
00404   * Range check input...
00405   */
00406 
00407   if (!opaque)
00408     return (NULL);
00409 
00410  /*
00411   * Create the node and set the element name...
00412   */
00413 
00414   if ((node = mxml_new(parent, MXML_OPAQUE)) != NULL)
00415     node->value.opaque = strdup(opaque);
00416 
00417   return (node);
00418 }
00419 
00420 
00421 /*
00422  * 'mxmlNewReal()' - Create a new real number node.
00423  *
00424  * The new real number node is added to the end of the specified parent's
00425  * child list. The constant MXML_NO_PARENT can be used to specify that
00426  * the new real number node has no parent.
00427  */
00428 
00429 mxml_node_t *                           /* O - New node */
00430 mxmlNewReal(mxml_node_t *parent,        /* I - Parent node or MXML_NO_PARENT */
00431             double      real)           /* I - Real number value */
00432 {
00433   mxml_node_t   *node;                  /* New node */
00434 
00435 
00436 #ifdef DEBUG
00437   fprintf(stderr, "mxmlNewReal(parent=%p, real=%g)\n", parent, real);
00438 #endif /* DEBUG */
00439 
00440  /*
00441   * Create the node and set the element name...
00442   */
00443 
00444   if ((node = mxml_new(parent, MXML_REAL)) != NULL)
00445     node->value.real = real;
00446 
00447   return (node);
00448 }
00449 
00450 
00451 /*
00452  * 'mxmlNewText()' - Create a new text fragment node.
00453  *
00454  * The new text node is added to the end of the specified parent's child
00455  * list. The constant MXML_NO_PARENT can be used to specify that the new
00456  * text node has no parent. The whitespace parameter is used to specify
00457  * whether leading whitespace is present before the node. The text
00458  * string must be nul-terminated and is copied into the new node.  
00459  */
00460 
00461 mxml_node_t *                           /* O - New node */
00462 mxmlNewText(mxml_node_t *parent,        /* I - Parent node or MXML_NO_PARENT */
00463             int         whitespace,     /* I - 1 = leading whitespace, 0 = no whitespace */
00464             const char  *string)        /* I - String */
00465 {
00466   mxml_node_t   *node;                  /* New node */
00467 
00468 
00469 #ifdef DEBUG
00470   fprintf(stderr, "mxmlNewText(parent=%p, whitespace=%d, string=\"%s\")\n",
00471           parent, whitespace, string ? string : "(null)");
00472 #endif /* DEBUG */
00473 
00474  /*
00475   * Range check input...
00476   */
00477 
00478   if (!string)
00479     return (NULL);
00480 
00481  /*
00482   * Create the node and set the text value...
00483   */
00484 
00485   if ((node = mxml_new(parent, MXML_TEXT)) != NULL)
00486   {
00487     node->value.text.whitespace = whitespace;
00488     node->value.text.string     = strdup(string);
00489   }
00490 
00491   return (node);
00492 }
00493 
00494 
00495 /*
00496  * 'mxmlNewTextf()' - Create a new formatted text fragment node.
00497  *
00498  * The new text node is added to the end of the specified parent's child
00499  * list. The constant MXML_NO_PARENT can be used to specify that the new
00500  * text node has no parent. The whitespace parameter is used to specify
00501  * whether leading whitespace is present before the node. The format
00502  * string must be nul-terminated and is formatted into the new node.  
00503  */
00504 
00505 mxml_node_t *                           /* O - New node */
00506 mxmlNewTextf(mxml_node_t *parent,       /* I - Parent node or MXML_NO_PARENT */
00507              int         whitespace,    /* I - 1 = leading whitespace, 0 = no whitespace */
00508              const char  *format,       /* I - Printf-style frmat string */
00509              ...)                       /* I - Additional args as needed */
00510 {
00511   mxml_node_t   *node;                  /* New node */
00512   va_list       ap;                     /* Pointer to arguments */
00513 
00514 
00515 #ifdef DEBUG
00516   fprintf(stderr, "mxmlNewTextf(parent=%p, whitespace=%d, format=\"%s\", ...)\n",
00517           parent, whitespace, format ? format : "(null)");
00518 #endif /* DEBUG */
00519 
00520  /*
00521   * Range check input...
00522   */
00523 
00524   if (!format)
00525     return (NULL);
00526 
00527  /*
00528   * Create the node and set the text value...
00529   */
00530 
00531   if ((node = mxml_new(parent, MXML_TEXT)) != NULL)
00532   {
00533     va_start(ap, format);
00534 
00535     node->value.text.whitespace = whitespace;
00536     node->value.text.string     = mxml_strdupf(format, ap);
00537 
00538     va_end(ap);
00539   }
00540 
00541   return (node);
00542 }
00543 
00544 
00545 /*
00546  * 'mxmlRemove()' - Remove a node from its parent.
00547  *
00548  * Does not free memory used by the node - use mxmlDelete() for that.
00549  * This function does nothing if the node has no parent.
00550  */
00551 
00552 void
00553 mxmlRemove(mxml_node_t *node)           /* I - Node to remove */
00554 {
00555 #ifdef DEBUG
00556   fprintf(stderr, "mxmlRemove(node=%p)\n", node);
00557 #endif /* DEBUG */
00558 
00559  /*
00560   * Range check input...
00561   */
00562 
00563   if (!node || !node->parent)
00564     return;
00565 
00566  /*
00567   * Remove from parent...
00568   */
00569 
00570 #if DEBUG > 1
00571   fprintf(stderr, "    BEFORE: node->parent=%p\n", node->parent);
00572   if (node->parent)
00573   {
00574     fprintf(stderr, "    BEFORE: node->parent->child=%p\n", node->parent->child);
00575     fprintf(stderr, "    BEFORE: node->parent->last_child=%p\n", node->parent->last_child);
00576   }
00577   fprintf(stderr, "    BEFORE: node->child=%p\n", node->child);
00578   fprintf(stderr, "    BEFORE: node->last_child=%p\n", node->last_child);
00579   fprintf(stderr, "    BEFORE: node->prev=%p\n", node->prev);
00580   fprintf(stderr, "    BEFORE: node->next=%p\n", node->next);
00581 #endif /* DEBUG > 1 */
00582 
00583   if (node->prev)
00584     node->prev->next = node->next;
00585   else
00586     node->parent->child = node->next;
00587 
00588   if (node->next)
00589     node->next->prev = node->prev;
00590   else
00591     node->parent->last_child = node->prev;
00592 
00593   node->parent = NULL;
00594   node->prev   = NULL;
00595   node->next   = NULL;
00596 
00597 #if DEBUG > 1
00598   fprintf(stderr, "    AFTER: node->parent=%p\n", node->parent);
00599   if (node->parent)
00600   {
00601     fprintf(stderr, "    AFTER: node->parent->child=%p\n", node->parent->child);
00602     fprintf(stderr, "    AFTER: node->parent->last_child=%p\n", node->parent->last_child);
00603   }
00604   fprintf(stderr, "    AFTER: node->child=%p\n", node->child);
00605   fprintf(stderr, "    AFTER: node->last_child=%p\n", node->last_child);
00606   fprintf(stderr, "    AFTER: node->prev=%p\n", node->prev);
00607   fprintf(stderr, "    AFTER: node->next=%p\n", node->next);
00608 #endif /* DEBUG > 1 */
00609 }
00610 
00611 
00612 /*
00613  * 'mxml_new()' - Create a new node.
00614  */
00615 
00616 static mxml_node_t *                    /* O - New node */
00617 mxml_new(mxml_node_t *parent,           /* I - Parent node */
00618          mxml_type_t type)              /* I - Node type */
00619 {
00620   mxml_node_t   *node;                  /* New node */
00621 
00622 
00623 #if DEBUG > 1
00624   fprintf(stderr, "mxml_new(parent=%p, type=%d)\n", parent, type);
00625 #endif /* DEBUG > 1 */
00626 
00627  /*
00628   * Allocate memory for the node...
00629   */
00630 
00631   if ((node = calloc(1, sizeof(mxml_node_t))) == NULL)
00632   {
00633 #if DEBUG > 1
00634     fputs("    returning NULL\n", stderr);
00635 #endif /* DEBUG > 1 */
00636 
00637     return (NULL);
00638   }
00639 
00640 #if DEBUG > 1
00641   fprintf(stderr, "    returning %p\n", node);
00642 #endif /* DEBUG > 1 */
00643 
00644  /*
00645   * Set the node type...
00646   */
00647 
00648   node->type = type;
00649 
00650  /*
00651   * Add to the parent if present...
00652   */
00653 
00654   if (parent)
00655     mxmlAdd(parent, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, node);
00656 
00657  /*
00658   * Return the new node...
00659   */
00660 
00661   return (node);
00662 }
00663 
00664 
00665 /*
00666  * End of "$Id: mxml-node.c,v 1.1 2007/05/23 20:43:27 david_ko Exp $".
00667  */

Generated on Fri Jul 11 17:59:45 2008 for Mobile-C by  doxygen 1.5.4