/home/dko/projects/mobilec/trunk/src/mxml-2.2.2/mxml-node.c

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

Generated on Fri May 16 14:49:54 2008 for Mobile-C by  doxygen 1.5.4