File:  [ELWIX - Embedded LightWeight unIX -] / gpl / axl / src / axl_node.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Fri Feb 17 12:50:03 2012 UTC (12 years, 4 months ago) by misho
Branches: axl, MAIN
CVS tags: HEAD, AXL0_6_7
version 0.6.7

    1: /*
    2:  *  LibAxl:  Another XML library
    3:  *  Copyright (C) 2006 Advanced Software Production Line, S.L.
    4:  *
    5:  *  This program is free software; you can redistribute it and/or
    6:  *  modify it under the terms of the GNU Lesser General Public License
    7:  *  as published by the Free Software Foundation; either version 2.1 of
    8:  *  the License, or (at your option) any later version.
    9:  *
   10:  *  This program is distributed in the hope that it will be useful,
   11:  *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
   12:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
   13:  *  GNU Lesser General Public License for more details.
   14:  *
   15:  *  You should have received a copy of the GNU Lesser General Public
   16:  *  License along with this program; if not, write to the Free
   17:  *  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   18:  *  02111-1307 USA
   19:  *  
   20:  *  You may find a copy of the license under this software is released
   21:  *  at COPYING file. This is LGPL software: you are welcome to
   22:  *  develop proprietary applications using this library without any
   23:  *  royalty or fee but returning back any change, improvement or
   24:  *  addition in the form of source code, project image, documentation
   25:  *  patches, etc. 
   26:  *
   27:  *  For commercial support on build XML enabled solutions contact us:
   28:  *          
   29:  *      Postal address:
   30:  *         Advanced Software Production Line, S.L.
   31:  *         Edificio Alius A, Oficina 102,
   32:  *         C/ Antonio Suarez Nº 10,
   33:  *         Alcalá de Henares 28802 Madrid
   34:  *         Spain
   35:  *
   36:  *      Email address:
   37:  *         info@aspl.es - http://www.aspl.es/xml
   38:  */
   39: 
   40: #include <axl.h>
   41: #define LOG_DOMAIN "axl-node"
   42: 
   43: /**
   44:  * \defgroup axl_node_module Axl Node: Xml node interface functions to use and manipulate xml nodes inside documents.
   45:  */
   46: 
   47: /** 
   48:  * \addtogroup axl_node_module
   49:  * @{
   50:  */
   51: 
   52: struct _axlAttrCursor {
   53: 	axlPointer     data;
   54: 	int            count;
   55: 	axlNode      * node;
   56: };
   57: 
   58: /** 
   59:  * @internal Axl content representation used to store comments, xml
   60:  * content, CDATA content and entity references.
   61:  */
   62: typedef struct _axlNodeContent axlNodeContent;
   63: 
   64: struct _axlNodeContent {
   65: 	/** 
   66: 	 * @internal
   67: 	 *
   68: 	 * @brief Pointer which holds current content inside the xml
   69: 	 * node.
   70: 	 */
   71: 	char          * content;
   72: 	/** 
   73: 	 * @internal
   74: 	 *
   75: 	 * @brief Current content size stored on the given axlNode.
   76: 	 */
   77: 	int             content_size;
   78: 	
   79: };
   80: 
   81: /** 
   82:  * @internal Type representation to hold node attributes while they
   83:  * are fewer.
   84:  */
   85: typedef struct _axlNodeAttr axlNodeAttr;
   86: 
   87: struct _axlNodeAttr {
   88: 	/** 
   89: 	 * @internal Node attribute name.
   90: 	 */
   91: 	char        * attribute;
   92: 
   93: 	/** 
   94: 	 * @internal Node attribute value.
   95: 	 */
   96: 	char        * value;
   97: 
   98: 	/** 
   99: 	 * @internal Flags the attribute pair to be considered from a
  100: 	 * factory.
  101: 	 */
  102: 	axl_bool          from_factory;
  103: 
  104: 	/** 
  105: 	 * @internal Next attribute.
  106: 	 */
  107: 	axlNodeAttr * next;
  108: };
  109: 
  110: /** 
  111:  * @internal Function that allows to copy all attributes found on the
  112:  * list received.
  113:  * 
  114:  * @param list The attribute list to copy.
  115:  * 
  116:  * @return A newly allocated attribute list.
  117:  */
  118: axlNodeAttr * __axl_node_copy_attr_list (axlNodeAttr * list)
  119: {
  120: 	axlNodeAttr * result   = NULL;
  121: 
  122: 	/* if the list isn't defined, return NULL */
  123: 	if (list == NULL)
  124: 		return NULL;
  125: 
  126: 	/* alloc memory to hold attribute name and value, and
  127: 	 * copy it from the list */
  128: 	result             = axl_new (axlNodeAttr, 1);
  129: 	/* check allocated result */
  130: 	if (result == NULL)
  131: 		return NULL;
  132: 	result->attribute  = axl_strdup (list->attribute);
  133: 	result->value      = axl_strdup (list->value);
  134: 
  135: 	/* call to copy the rest of the list */
  136: 	result->next = __axl_node_copy_attr_list (list->next);
  137: 
  138: 	/* return result created */
  139: 	return result;
  140: }
  141: 
  142: /** 
  143:  * @internal Deallocs the attribute list received.
  144:  * 
  145:  * @param list The attribute list to copy.
  146:  * 
  147:  * @return A newly allocated attribute list.
  148:  */
  149: void __axl_node_free_attr_list (axlNodeAttr * attr)
  150: {
  151: 	axlNodeAttr * next;
  152: 
  153: 	/* if the list isn't defined, return NULL */
  154: 	if (attr == NULL)
  155: 		return;
  156: 
  157: 	/* copy all nodes */
  158: 	while (attr != NULL) {
  159: 		/* get the next attribute */
  160: 		next = attr->next;
  161: 
  162: 		/* free attribute description */
  163: 		if (! attr->from_factory) {
  164: 			axl_free (attr->attribute);
  165: 			axl_free (attr->value);
  166: 			axl_free (attr);
  167: 		} /* end if */
  168: 
  169: 		/* get the next */
  170: 		attr = next;
  171: 		
  172: 	} /* end while */
  173: 
  174: 	/* return result created */
  175: 	return;
  176: }
  177: 
  178: /** 
  179:  * @internal Function that allows to now if both lists represents the
  180:  * same set of attributes, even if they aren't ordered using the same.
  181:  * 
  182:  * @param attr The first attribute pointing to the rest of the
  183:  * attribute list.
  184:  *
  185:  * @param attr2 The second attribute pointing to the rest of the
  186:  * attribute list.
  187:  * 
  188:  * @return \ref axl_true if both lists are equal, otherwise \ref axl_false is
  189:  * returned.
  190:  */
  191: axl_bool __axl_node_attr_list_is_equal (axlNodeAttr * attr, axlNodeAttr * attr2)
  192: {
  193: 	axlNodeAttr * attrAux;
  194: 	axl_bool      found;
  195: 
  196: 	/* for each attribute found in the attribute list, check it on
  197: 	 * the second list */
  198: 	while (attr != NULL) {
  199: 		
  200: 		attrAux = attr2;
  201: 		found   = axl_false;
  202: 		while (attrAux != NULL) {
  203: 			
  204: 			/* check attribute */
  205: 			if (axl_cmp (attrAux->attribute, attr->attribute) &&
  206: 			    axl_cmp (attrAux->value, attr->value)) {
  207: 				/* attribute found, break the loop */
  208: 				found = axl_true;
  209: 				break;
  210: 			}
  211: 
  212: 			/* next attribute */
  213: 			attrAux = attrAux->next;
  214: 			
  215: 		} /* end while */
  216: 		
  217: 		/* check if the attribute was found */
  218: 		if (! found )
  219: 			return axl_false;
  220: 
  221: 		/* get the next */
  222: 		attr = attr->next;
  223: 		
  224: 	} /* end while */
  225: 
  226: 	/* all attributes was found, including its values, so, the
  227: 	 * list is equal */
  228: 	return axl_true;
  229: }
  230: 
  231: typedef enum {
  232: 	/** 
  233: 	 * @internal Signal axl library that the node was allocated by
  234: 	 * a factory not by the system alloc.
  235: 	 */
  236: 	NODE_FROM_FACTORY      = 1,
  237: 
  238: 	/** 
  239: 	 * @internal Signal axl library that the node node was
  240: 	 * allocated by a factory not by the system alloc.
  241: 	 */
  242: 	NODE_NAME_FROM_FACTORY = 1 << 2
  243: } axlNodeConf;
  244: 
  245: struct _axlNode {
  246: 	/** 
  247: 	 * @internal
  248: 	 *
  249: 	 * Node name that is the value found at the very begining of
  250: 	 * the node definition <name.../>
  251: 	 */
  252: 	char          * name;
  253: 
  254: 	/** 
  255: 	 * @internal Number of attributes stored. This value is used
  256: 	 * to now if the attributes are stored using a hash or a
  257: 	 * linked list. In the case it is equal or greater than 11, a
  258: 	 * hash is used to store attribute. Otherwise, a linked list
  259: 	 * (using axlAttrNode) is used.
  260: 	 */
  261: 	int             attr_num;
  262: 
  263: 	/** 
  264: 	 * @internal
  265: 	 * @brief The attributes this node has.
  266: 	 */
  267: 	axlPointer    * attributes;
  268: 
  269: 	/** 
  270: 	 * @internal A reference to the first child.
  271: 	 */
  272: 	axlItem      * first;
  273: 
  274: 	/** 
  275: 	 * @internal A reference to the last child.
  276: 	 */
  277: 	axlItem      * last;
  278: 
  279: 	/** 
  280: 	 * @internal A hash used to store arbitrary data associated to
  281: 	 * the node.
  282: 	 */
  283: 	axlHash       * annotate_data; 
  284: 
  285: 	/** 
  286: 	 * @internal Internal reference to the holder axlItem
  287: 	 * containing the axl node reference.
  288: 	 */
  289: 	axlItem       * holder;
  290: 	
  291: 	/** 
  292: 	 * @internal Value that contains flags for configuration.
  293: 	 */
  294: 	int             conf;
  295: };
  296: 
  297: struct _axlItem {
  298: 	/** 
  299: 	 * @internal A reference to the type that is being hold by the
  300: 	 * encapsulation reference.
  301: 	 */
  302: 	AxlItemType     type;
  303: 	
  304: 	/** 
  305: 	 * @internal The reference to the pointer that is actually
  306: 	 * stored.
  307: 	 */
  308: 	axlPointer      data;
  309: 
  310: 	/** 
  311: 	 * @internal
  312: 	 * A pointer to the parent node.
  313: 	 */
  314: 	axlNode       * parent;
  315: 
  316: 	/** 
  317: 	 * @internal
  318: 	 *
  319: 	 * A pointer to the brother node, the node that is found on
  320: 	 * the next position.
  321: 	 */
  322: 	axlItem       * next;
  323: 
  324: 	/** 
  325: 	 * @internal Stores a reference to the previous node inside
  326: 	 * the same level.
  327: 	 */
  328: 	axlItem       * previous;
  329: 
  330: 	/** 
  331: 	 * @internal
  332: 	 *
  333: 	 * Internal reference to the whole xml document where the node
  334: 	 * is contained.
  335: 	 */
  336: 	axlDoc        * doc;
  337: };
  338: 
  339: /** 
  340:  * @internal
  341:  *
  342:  * @brief Internal position function which ensures that nodes added
  343:  * will be added at the end of the list.
  344:  */
  345: int __axl_node_equal (axlPointer a, axlPointer b)
  346: {
  347: 	return 1;
  348: }
  349: 
  350: /** 
  351:  * @internal
  352:  *
  353:  * Internal function which allocates the enough memory to copy
  354:  * received content changing all escape sequences.
  355:  */
  356: char * __axl_node_content_copy_and_escape (const char * content, 
  357: 					   int          content_size, 
  358: 					   int          additional_size,
  359: 					   axl_bool     cdata)
  360: {
  361: 	int    iterator  = 0;
  362: 	int    iterator2 = 0;
  363: 	char * result;
  364: 	axl_return_val_if_fail (content, NULL);
  365: 
  366: 	/* allocate the memory to be returned */
  367: 	result = axl_new (char, content_size + additional_size + 1);
  368: 
  369: 	/* iterate over all content defined */
  370: 	while (iterator2 < content_size) {
  371: 		/* check for &apos; */
  372: 		if (content [iterator2] == '\'') {
  373: 			memcpy (result + iterator, "&apos;", 6);
  374: 			iterator += 6;
  375: 			iterator2++;
  376: 			continue;
  377: 		}
  378: 
  379: 		/* check for &quot; */
  380: 		if (content [iterator2] == '"') {
  381: 			memcpy (result + iterator, "&quot;", 6);
  382: 			iterator += 6;
  383: 			iterator2++;
  384: 			continue;
  385: 		}
  386: 
  387: 		/* check for &amp; */
  388: 		if (content [iterator2] == '&') {
  389: 			memcpy (result + iterator, "&amp;", 5);
  390: 			iterator += 5;
  391: 			iterator2++;
  392: 			continue;
  393: 		}
  394: 
  395: 		/* check for &gt; */
  396: 		if (content [iterator2] == '>') {
  397: 			memcpy (result + iterator, "&gt;", 4);
  398: 			iterator += 4;
  399: 			iterator2++;
  400: 			continue;
  401: 		}
  402: 
  403: 		/* check for &lt; */
  404: 		if (content [iterator2] == '<') {
  405: 			memcpy (result + iterator, "&lt;", 4);
  406: 			iterator += 4;
  407: 			iterator2++;
  408: 			continue;
  409: 		}
  410: 
  411: 		/* check for ]]> declaration */
  412: 		if (content [iterator2] == ']' && content [iterator2 + 1] == ']' && content [iterator2 + 2] == '>') {
  413: 			if (cdata) {
  414: 				memcpy (result + iterator, "]]>]]&gt;<![CDATA[", 18);
  415: 				iterator  += 18;
  416: 				iterator2 +=3;
  417: 			} else {
  418: 				memcpy (result + iterator, "]]&gt;", 6);
  419: 				iterator  += 6;
  420: 				iterator2 += 3;
  421: 			}
  422: 			continue;
  423: 		}
  424: 
  425: 		/* copy value received because it is not an escape
  426: 		 * sequence */
  427: 		memcpy (result + iterator, content + iterator2, 1);
  428: 
  429: 		/* update the iterator */
  430: 		iterator++;
  431: 		iterator2++;
  432: 	}
  433: 
  434: 	/* return results */
  435: 	return result;
  436: }
  437: 
  438: /** 
  439:  * @brief Replaces all entity references to its corresponding
  440:  * values. This function only implements translation for default
  441:  * recognized entities (&, <, >, ' and ").
  442:  *
  443:  * @param content The string content having escaped XML declarations
  444:  * such \&gt; or \&lt; which should be
  445:  * translated into its corresponding utf-8 symbol (for example > and
  446:  * <).
  447:  *
  448:  * @param content_size A non-optional reference to an integer variable
  449:  * which will hold the new size of the string returned. You can pass a
  450:  * variable initialized to 0 or -1 to let the function to calculate
  451:  * the initial string length (by using strlen).
  452:  *
  453:  * Because the substitution pattern applied on this operation makes
  454:  * not necessary to allocate memory, the function return the same
  455:  * string received, but with all values replaced. If you want to avoid
  456:  * this behaviour, use \ref axl_strdup before calling to this
  457:  * function.
  458:  *
  459:  * @return Returns the string modified or NULL if it fails.
  460:  */
  461: char * axl_node_content_translate_defaults (char * content, 
  462: 					    int  * content_size)
  463: {
  464: 	int     iterator  = 0;
  465: 	int     iterator2 = 0;
  466: 	
  467: 	axl_return_val_if_fail (content, NULL);
  468: 	axl_return_val_if_fail (content_size, NULL);
  469: 
  470: 	/* update string length if no data was provided */
  471: 	if (*content_size == 0 || *content_size == -1)
  472: 		*content_size = strlen (content);
  473: 
  474: 	/* iterate over all content defined */
  475: 	while (iterator < (*content_size)) {
  476: 		
  477: 		/* check for &apos; */
  478: 		if (axl_stream_cmp (content + iterator, "&apos;", 6)) {
  479: 			content [iterator2] = '\'';
  480: 			iterator2++;
  481: 			
  482: 			iterator += 6;
  483: 			continue;
  484: 		}
  485: 		
  486: 		/* check for &quot; */
  487: 		if (axl_stream_cmp (content + iterator, "&quot;", 6)) {
  488: 			content [iterator2] = '"';
  489: 			iterator2++;
  490: 			
  491: 			iterator += 6;
  492: 			continue;
  493: 		}
  494: 
  495: 		/* check for &amp; */
  496: 		if (axl_stream_cmp (content + iterator, "&amp;", 5)) {
  497: 			content [iterator2] = '&';
  498: 			iterator2++;
  499: 			
  500: 			iterator += 5;
  501: 			continue;
  502: 		}
  503: 
  504: 		/* check for &gt; */
  505: 		if (axl_stream_cmp (content + iterator, "&gt;", 4)) {
  506: 			content [iterator2] = '>';
  507: 			iterator2++;
  508: 			
  509: 			iterator += 4;
  510: 			continue;
  511: 		}
  512: 
  513: 		/* check for &lt; */
  514: 		if (axl_stream_cmp (content + iterator, "&lt;", 4)) {
  515: 			content [iterator2] = '<';
  516: 			iterator2++;
  517: 			
  518: 			iterator += 4;
  519: 			continue;
  520: 		}
  521: 
  522: 		/* copy move the content */
  523: 		if (iterator2 != iterator)
  524: 			content [iterator2] = content [iterator];
  525: 
  526: 		/* update the iterator */
  527: 		iterator++;
  528: 		iterator2++;
  529: 	}
  530: 
  531: 	/* return results, setting the new content size */
  532: 	*content_size       = iterator2;
  533: 	content [iterator2] = 0;
  534: 	return content;
  535: }
  536: 
  537: 
  538: 
  539: /** 
  540:  * @brief Creates a new \ref axlNode with the provided name.
  541:  *
  542:  * The function will perform a new local copy from the name reference
  543:  * received. See also \ref axl_node_create_ref for an explanation
  544:  * about how to save memory.
  545:  *
  546:  * @param name The name to be used for the node be created. The
  547:  * function doesn't check if the paramater received is null.
  548:  * 
  549:  * @return A newly allocated \ref axlNode reference, that must be
  550:  * deallocated by \ref axl_node_free.
  551:  */
  552: axlNode * axl_node_create (const char * name)
  553: {
  554: 
  555: 	axlNode * node;
  556: 
  557: 	/* init the node */
  558: 	node        = axl_new (axlNode, 1);
  559: 	node->name  = axl_strdup (name);
  560: 	
  561: 	return node;
  562: }
  563: 
  564: /** 
  565:  * @brief This function allows to create a xml node from the provided
  566:  * xml content (bootstraping XML content).
  567:  *
  568:  * This function is useful if it is required to create a node with a
  569:  * particular complex content, without going into the detail of
  570:  * creating all childs, attributes and content.
  571:  *
  572:  * Here is an example:
  573:  * \code
  574:  * axlError * error = NULL;
  575:  * axlNode  * node  = NULL;
  576:  * 
  577:  * // parse document 
  578:  * root = axl_node_parse_strings (error, 
  579:  *                                "<child>",
  580:  *                                "  <widget class=\"GtkLabel\" id=\"label4\">",
  581:  *                                "    <property name=\"visible\">True</property>",
  582:  *                                "    <property name=\"label\" translatable=\"yes\">&lt;b&gt;1. Seleccione el sistema:&lt;/b&gt;</property>",
  583:  *                                "    <property name=\"use_underline\">False</property>",
  584:  *                                "    <property name=\"use_markup\">True</property>",
  585:  *                                "    <property name=\"justify\">GTK_JUSTIFY_LEFT</property>",
  586:  *                                "    <property name=\"wrap\">False</property>",
  587:  *                                "    <property name=\"selectable\">False</property>",
  588:  *                                "    <property name=\"xalign\">0</property>",
  589:  *                                "    <property name=\"yalign\">0.5</property>",
  590:  *                                "    <property name=\"xpad\">0</property>",
  591:  *                                "    <property name=\"ypad\">0</property>",
  592:  *                                "    <property name=\"ellipsize\">PANGO_ELLIPSIZE_NONE</property>",
  593:  *                                "    <property name=\"width_chars\">-1</property>",
  594:  *                                "    <property name=\"single_line_mode\">False</property>",
  595:  *                                "    <property name=\"angle\">0</property>",
  596:  *                                "  </widget>",
  597:  *                                "  <packing>",
  598:  *                                "     <property name=\"padding\">0</property>",
  599:  *                                "     <property name=\"expand\">False</property>",
  600:  *                                "     <property name=\"fill\">False</property>",
  601:  *                                "  </packing>",
  602:  *                                "</child>",
  603:  *                                NULL);
  604:  * if (root == NULL) {
  605:  *	printf ("Error: unable to parse content, error: %s\n", axl_error_get (error));
  606:  *              axl_error_free (error);
  607:  *	return;
  608:  * }
  609:  *
  610:  * // once finished, free the node 
  611:  * axl_node_free (root);
  612:  * \endcode
  613:  * 
  614:  * @param error Optional error reference to report parsing error
  615:  * problems that can be found.
  616:  * 
  617:  * The function receives a set of strings, separate by comma, ended by
  618:  * NULL.
  619:  * 
  620:  * @return A newly allocated reference to the \ref axlNode or NULL if
  621:  * it fails. In such case, the error variable is filled with the error
  622:  * found.
  623:  */
  624: axlNode * axl_node_parse_strings      (axlError ** error, ...)
  625: {
  626: 	axlDoc   * doc;
  627: 	axlNode  * root;
  628: 	va_list    args;
  629: 	char     * string     = NULL;
  630: 	char     * stream     = NULL;
  631: 	char     * stream_aux = NULL;
  632: 	
  633: 	/* check incoming data */
  634: 	axl_return_val_if_fail (error, NULL);
  635: 	
  636: 	/* open the stdargs */
  637: 	va_start (args, error);
  638: 	
  639: 	while ((string = va_arg (args, char *)) != NULL) {
  640: 		stream_aux = stream;
  641: 		stream = axl_stream_concat (stream, string);
  642: 		if (stream_aux != NULL) {
  643: 			axl_free (stream_aux);
  644: 			stream_aux = NULL;
  645: 		}
  646: 	}
  647: 
  648: 	/* close the stdargs */
  649: 	va_end (args);
  650: 
  651: 	/* check that we have received, at least, an string
  652: 	 * parseable */
  653: 	if (stream == NULL)
  654: 		return NULL;
  655: 
  656: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "string to parse: %s", stream);
  657: 
  658: 	/* parse the string */
  659: 	doc = axl_doc_parse (stream, -1, error);
  660: 	if (doc == NULL) {
  661: 		/* free document */
  662: 		axl_free (stream);
  663: 		return NULL;
  664: 	}
  665: 
  666: 	/* free the stream */
  667: 	axl_free (stream);
  668: 
  669: 	/* deattach the root node */
  670: 	root = axl_doc_get_root (doc);
  671: 	axl_node_deattach (root);
  672: 
  673: 	/* do not free the document, rather, store it to be
  674: 	 * deallocated by the node just after it is deallocated. */
  675: 	axl_node_annotate_data_full (root, "__root_document", NULL, doc, (axlDestroyFunc) axl_doc_free);
  676: 
  677: 	/* return the node created */
  678: 	return root;
  679: }
  680: 
  681: /** 
  682:  * @brief Allows to create a complete node configuring not only the
  683:  * node but its content, using a printf-like format.
  684:  *
  685:  * This handy function, like \ref axl_node_parse_strings, allows to
  686:  * create complex xml structures providing inline content.
  687:  *
  688:  * Here is an example:
  689:  * \code
  690:  * axlNode * node = axl_node_parse (NULL, "<content attr='value' attr2='value'>This is content</content>");
  691:  * \endcode
  692:  *
  693:  * The previous call will create a node called <b>content</b> with the
  694:  * provided attributes and content, in one step.
  695:  *
  696:  * The node returned can be integrated into a xml document using usual
  697:  * API, for example: \ref axl_node_set_child or \ref axl_doc_set_root.
  698:  * 
  699:  * @param error The optional error reference holding the returned
  700:  * result.
  701:  *
  702:  * @param content The content to be used to create the node.
  703:  * 
  704:  * @return A reference to a newly allocated \ref axlNode or NULL if it
  705:  * fails. The \ref axlError is filled with the error found if provided
  706:  * by the caller.
  707:  */
  708: axlNode * axl_node_parse                    (axlError ** error, const char * content, ...)
  709: {
  710: 	char    * _content;
  711: 	va_list   args;
  712: 	axlDoc  * doc;
  713: 	axlNode * root;
  714: 
  715: 	/* open the stdargs */
  716: 	va_start (args, content);
  717: 	
  718: 	/* create the content */
  719: 	_content = axl_strdup_printfv (content, args);
  720: 
  721: 	/* close the stdargs */
  722: 	va_end (args);
  723: 
  724: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "parsing document:\n %s", _content);
  725: 
  726: 	/* parse the string */
  727: 	doc = axl_doc_parse (_content, -1, error);
  728: 	if (doc == NULL) {
  729: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "failed to parse document:\n %s", _content);
  730: 
  731: 		/* free document */
  732: 		axl_free (_content);
  733: 
  734: 		return NULL;
  735: 	}
  736: 
  737: 	/* free the content */
  738: 	axl_free (_content);
  739: 
  740: 	/* deattach the root node */
  741: 	root = axl_doc_get_root (doc);
  742: 	axl_node_deattach (root);
  743: 
  744: 	/* do not free the document, rather, store it to be
  745: 	 * deallocated by the node just after it is deallocated. */
  746: 	axl_node_annotate_data_full (root, "__root_document", NULL, doc, (axlDestroyFunc) axl_doc_free);
  747: 
  748: 	/* return the node created */
  749: 	return root;
  750: }
  751: 
  752: 
  753: /** 
  754:  * @brief Creates a new \ref axlNode but reusing the memory passed in
  755:  * by the name reference.
  756:  *
  757:  * This function works the same way like \ref axl_node_create, but
  758:  * previous one makes a local copy from the name provided. This means
  759:  * that, if you have allocated the reference being passed, the
  760:  * previous function will allocate again memory for the name
  761:  * reference.
  762:  *
  763:  * Obviously, for a few xml nodes this have none or little effect but,
  764:  * if your xml document have 100.000 nodes you save 100.000 extra
  765:  * memory allocations and deallocations. This may improve your
  766:  * application performace because memory
  767:  * fragmentation/allocations/deallocations are reduced.
  768:  *
  769:  * Keep in mind that this function should not be used with static strings. Example:
  770:  * \code
  771:  *    // propery node creation 
  772:  *    axlNode * node = axl_node_create ("test");
  773:  *  
  774:  *    // NOT PROPER node creation
  775:  *    axlNode * node = axl_node_create_ref ("test");
  776:  * \endcode
  777:  *
  778:  * @param name A user-space allocated memory representing the node
  779:  * name. The function doesn't check if the parameter received is null.
  780:  * 
  781:  * @return A newly created \ref axlNode reference that must be
  782:  * deallocated by \ref axl_node_free.
  783:  */
  784: axlNode * axl_node_create_ref         (char * name)
  785: {
  786: 	axlNode * node;
  787: 
  788: 	/* init the node */
  789: 	node        = axl_new (axlNode, 1);
  790: 	node->name  = name;
  791: 	
  792: 	/* return a reference to a new axlNode */
  793: 	return node;
  794: }
  795: 
  796: /** 
  797:  * @brief Allows to configure the node name, using the value provided. 
  798:  * 
  799:  * The function will dealloc the previous name stored, if found.
  800:  *
  801:  * @param node The node to be configured with a new name.
  802:  * 
  803:  * @param name The new name to configure on the node. Function will
  804:  * create a local copy from the new name provided. The function won't
  805:  * check the name parameter received to be a non-null pointer.
  806:  */
  807: void      axl_node_set_name                 (axlNode * node, const char * name)
  808: {
  809: 	/* check the name to be already configured and dealloc it */
  810: 	if (node->name != NULL && ! (node->conf & NODE_NAME_FROM_FACTORY))
  811: 		axl_free (node->name);
  812: 	
  813: 	/* alloc the new name */
  814: 	node->name = axl_strdup (name);
  815: 	node->conf &= ~NODE_NAME_FROM_FACTORY;
  816: 	
  817: 	return;
  818: }
  819: 
  820: /** 
  821:  * @brief Allows to configure the node name, using the value provided
  822:  * as a reference allocated and to be owned by the node.
  823:  * 
  824:  * The function will dealloc the previous name stored, if found.
  825:  *
  826:  * @param node The node to be configured with a new name.
  827:  * 
  828:  * @param name The new name to configure on the node. The value
  829:  * provided will be owned by the node. The function won't check the
  830:  * name parameter received to be a non-null pointer.
  831:  */
  832: void      axl_node_set_name_ref             (axlNode * node, char * name)
  833: {
  834: 	/* check the name to be already configured and dealloc it */
  835: 	if (node->name != NULL && ! (node->conf & NODE_NAME_FROM_FACTORY))
  836: 		axl_free (node->name);
  837: 
  838: 	/* alloc the new name */
  839: 	node->name = name;
  840: 	
  841: 	return;
  842: }
  843: 
  844: /** 
  845:  * @internal Allows to configure the xml node, flaging the string
  846:  * received to be owned by a factory. Do not use this API from your
  847:  * application. This is only useful for Axl Library internals.
  848:  * 
  849:  * @param node The xml node that is going to be configured.
  850:  *
  851:  * @param name The xml node name to be configured. Previous
  852:  * configuration won't be deallocated as it is supposed that this
  853:  * function is only used from inside axl library.
  854:  */
  855: void axl_node_set_name_from_factory (axlNode * node, char * name)
  856: {
  857: 	/* set node name */
  858: 	node->name = name;
  859: 
  860: 	/* update configuration */
  861: 	node->conf |= NODE_NAME_FROM_FACTORY;
  862: 	
  863: 	return;
  864: }
  865: 
  866: axlPointer __axl_node_copy_key (axlPointer key, axlDestroyFunc key_destroy, 
  867: 				axlPointer data, axlDestroyFunc data_destroy)
  868: {
  869: 	/* copy the key */
  870: 	return axl_strdup (key);
  871: }
  872: 
  873: axlPointer __axl_node_copy_value (axlPointer key, axlDestroyFunc key_destroy,
  874: 				  axlPointer data, axlDestroyFunc data_destroy)
  875: {
  876: 	/* copy data */
  877: 	return axl_strdup (data);
  878: }
  879: 
  880: /** 
  881:  * @brief Allows to perform a copy operation for the provided node.
  882:  *
  883:  * @param node The source node to copy.
  884:  *
  885:  * @param copy_attributes Signals the function to also copy node
  886:  * attributes into the newly created node.
  887:  *
  888:  * @param copy_childs Signals the function to also copy childs for the
  889:  * source node.
  890:  * 
  891:  * @return A newly created node copy or null if it fails. The function
  892:  * will fail if the node reference provided is null.
  893:  */
  894: axlNode * axl_node_copy                     (axlNode   * node,
  895: 					     axl_bool    copy_attributes,
  896: 					     axl_bool    copy_childs)
  897: {
  898: 	axlNode * result;
  899: 	axlItem * child;
  900: 	axlItem * copy;
  901: 	
  902: 
  903: 	axl_return_val_if_fail (node, NULL);
  904: 
  905: 	/* create the copy */
  906: 	result = axl_node_create (axl_node_get_name (node));
  907: 
  908: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node=<%s> (copy operation)",
  909: 		   result->name);
  910: 
  911: 	/* check for attributes */
  912: 	if (node->attributes != NULL && copy_attributes) {
  913: 		
  914: 		/* copy attribute configuration and attributes */
  915: 		result->attr_num = node->attr_num;
  916: 		if (node->attr_num >= 11) {
  917: 			/* copy attribute list supposing it is a
  918: 			 * hash */
  919: 			result->attributes = (axlPointer) axl_hash_copy ((axlHash *) node->attributes, 
  920: 									 /* key copy function */
  921: 									 __axl_node_copy_key,
  922: 									 /* value copy function */
  923: 									 __axl_node_copy_value);
  924: 		} else {
  925: 			/* copy attribute list */
  926: 			result->attributes = (axlPointer) __axl_node_copy_attr_list ((axlNodeAttr *) node->attributes);
  927: 		}
  928: 	}
  929: 
  930: 	/* check if child nodes must be also copied */
  931: 	if (copy_childs && (node->first != NULL)) {
  932: 
  933: 		/* copy all content inside */
  934: 		child = node->first;
  935: 		while (child != NULL) {
  936: 			
  937: 			/* copy the child found */
  938: 			copy       = axl_item_copy (child, result);
  939: 			
  940: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "  new item created (copy operation) with parent=<%s> and type=%d",
  941: 				   copy->parent->name,
  942: 				   axl_item_get_type (copy));
  943: 
  944: 			/* set the content */
  945: 			axl_item_set_child_ref (result, copy);
  946: 
  947: 			/* get the next element */
  948: 			child = child->next;
  949: 
  950: 		} /* end while */
  951: 	} /* end if */
  952: 	
  953: 	
  954: 	/* return the node created */
  955: 	return result;
  956: }
  957: 
  958: /** 
  959:  * @brief Allows to get the xml document (\ref axlDoc) where the
  960:  * provided xml node is stored.
  961:  * 
  962:  * @param node The node that is being requested to return is xml
  963:  * document reference.
  964:  * 
  965:  * @return The xml document reference or NULL if it is not already
  966:  * set. 
  967:  */
  968: axlDoc  * axl_node_get_doc                  (axlNode * node)
  969: {
  970: 	axl_return_val_if_fail (node, NULL);
  971: 	
  972: 	/* return the internal reference */
  973: 	return axl_item_get_doc (node->holder);
  974: }
  975: 
  976: /** 
  977:  * @internal
  978:  *
  979:  * This function is not provided to the public API because it is used
  980:  * by the Axl internals to set the root node for a provided xml node,
  981:  * that is usually the root document xml node.
  982:  * 
  983:  * @param node The node that is being configured to have, or being contained in, the provided xml document.
  984:  *
  985:  * @param doc The xml document that holds the node.
  986:  */
  987: void      axl_node_set_doc                  (axlNode * node, axlDoc * doc)
  988: {
  989: 	axlItem * item;
  990: 
  991: 	axl_return_if_fail (node);
  992: 	axl_return_if_fail (doc);
  993: 
  994: 	/* get the item reference */
  995: 	item = node->holder;
  996: 
  997: 	if (item == NULL) {
  998: 
  999: 		/* create an empty reference */
 1000: 		item         = axl_item_factory_get (axl_doc_get_item_factory (doc)); 
 1001: 		item->type   = ITEM_NODE | ITEM_FROM_FACTORY;
 1002: 		item->data   = node;
 1003: 		node->holder = item;
 1004: 		
 1005: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node received doesn't have a holder reference, creating ref=0x%x, node=0x%x, type=%d",
 1006: 			   item, node, item->type);
 1007: 	} /* end if */
 1008: 
 1009: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "setting doc to the item node");
 1010: 
 1011: 	/* call to set item at the document */
 1012: 	item->doc = doc;
 1013: 
 1014: 	return;
 1015: }
 1016: 
 1017: 
 1018: /** 
 1019:  * @internal
 1020:  * 
 1021:  * Support function to install attribute information provided into the
 1022:  * \ref axlNode provided.
 1023:  *
 1024:  * @return axl_true if the attribute was added, otherwise axl_false is
 1025:  * returned.
 1026:  */
 1027: axl_bool      __axl_node_set_attribute      (axlFactory * factory, 
 1028: 					     axlNode    * node, 
 1029: 					     char       * attribute, 
 1030: 					     char       * value, 
 1031: 					     axl_bool     from_factory)
 1032: {
 1033: 	axlNodeAttr * attr;
 1034: 	axlNodeAttr * next;
 1035: 
 1036: 	/* init attribute list */
 1037: 	/* do not init attribute list twice */
 1038: 	if (node->attributes == NULL) {
 1039: 		/* configure default axl attribute list */
 1040: 		node->attr_num   = 1;
 1041: 		
 1042: 		/* create the node */
 1043: 		if (from_factory)
 1044: 			attr = axl_factory_get (factory);
 1045: 		else
 1046: 			attr = axl_new (axlNodeAttr, 1);
 1047: 		attr->from_factory = from_factory;
 1048: 		attr->attribute    = attribute;
 1049: 		attr->value        = value;
 1050: 		
 1051: 		/* store the node */
 1052: 		node->attributes = (axlPointer) attr;
 1053: 
 1054: 		return axl_true;
 1055: 	}
 1056: 
 1057: 	/* store the attribute using the general case */
 1058: 	if (node->attr_num < 10) {
 1059: 
 1060: 		/* check if the attribute exists */
 1061: 		if (axl_node_has_attribute (node, attribute))
 1062: 			return axl_false;
 1063: 
 1064: 		/* create the node */
 1065: 		if (from_factory)
 1066: 			attr = axl_factory_get (factory);
 1067: 		else
 1068: 			attr = axl_new (axlNodeAttr, 1);
 1069: 		attr->from_factory = from_factory;
 1070: 		attr->attribute    = attribute;
 1071: 		attr->value        = value;
 1072: 
 1073: 		/* set the next to the new item to be the current first */
 1074: 		attr->next       = (axlNodeAttr *) node->attributes;
 1075: 
 1076: 		/* set the new first */
 1077: 		node->attributes = (axlPointer) attr;
 1078: 		
 1079: 	} else if (node->attr_num >= 10) {
 1080: 
 1081: 		/* check if the attribute exists */
 1082: 		if (axl_node_has_attribute (node, attribute))
 1083: 			return axl_false;
 1084: 		
 1085: 		/* check if we have to translate current attributes */
 1086: 		if (node->attr_num == 10) {
 1087: 			/* get a reference to current attribute list */
 1088: 			attr = (axlNodeAttr *) node->attributes;
 1089: 
 1090: 			/* create the hash */
 1091: 			node->attributes = (axlPointer) axl_hash_new_full (axl_hash_string, axl_hash_equal_string, 1);
 1092: 			
 1093: 			while (attr != NULL) {
 1094: 				/* add the attribute */	
 1095: 				axl_hash_insert_full ((axlHash *) node->attributes, 
 1096: 						      /* attribute name */
 1097: 						      attr->attribute, attr->from_factory ?  NULL : axl_free, 
 1098: 						      /* attribute value */
 1099: 						      attr->value, attr->from_factory ? NULL : axl_free);
 1100: 				/* free current node */
 1101: 				next = attr->next;
 1102: 				if (! attr->from_factory)
 1103: 					axl_free (attr);
 1104: 
 1105: 				/* get the next item to store */
 1106: 				attr = next;
 1107: 			} /* end while */
 1108: 
 1109: 		} /* end if */
 1110: 
 1111: 		/* add the attribute */	
 1112: 		axl_hash_insert_full ((axlHash *) node->attributes, 
 1113: 				      attribute, from_factory ? NULL : axl_free, 
 1114: 				      value, from_factory ? NULL : axl_free);				
 1115: 		
 1116: 	} /* end if */
 1117: 
 1118: 	/* update attribute count */
 1119: 	node->attr_num++;
 1120: 
 1121: 	return axl_true;
 1122: }
 1123: 
 1124: /** 
 1125:  * @brief Allows to configure an xml attribute on the given node.
 1126:  *
 1127:  * \code
 1128:  * <complex attr1='value'>
 1129:  *   ..
 1130:  * </complex>
 1131:  * \endcode
 1132:  *
 1133:  * It is not allowed to store the same attribute twice inside the same
 1134:  * node. If the function detects that a node is being set to have the
 1135:  * same attribute name several times, the attribute will be silently
 1136:  * not added.
 1137:  *
 1138:  * Values for the attribute name (<b>attribute</b>) and its associated
 1139:  * value can be deallocated once the function finish. This function
 1140:  * will perform a local copy.
 1141:  * 
 1142:  * @param node The \ref axlNode where the attribute will be installed.
 1143:  *
 1144:  * @param attribute The attribute name to configure. This value can't
 1145:  * be NULL.
 1146:  *
 1147:  * @param value The value associated to the attribute to be
 1148:  * configured. This value can't be NULL.
 1149:  */
 1150: void      axl_node_set_attribute      (axlNode    * node, 
 1151: 				       const char * attribute, 
 1152: 				       const char * value)
 1153: {
 1154: 	int    additional_size = 0;
 1155: 	char * _attr;
 1156: 	char * _value;
 1157: 
 1158: 	axl_return_if_fail (node);
 1159: 	axl_return_if_fail (attribute);
 1160: 	axl_return_if_fail (value);
 1161: 
 1162: 	/* check for empty attribute names */
 1163: 	if (attribute[0] == 0) {
 1164: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "skipping setting attribute with no name!");
 1165: 		return;
 1166: 	}
 1167: 
 1168: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "setting attribute: %s='%s'", attribute, value);
 1169: 
 1170: 	/* check attribute name */
 1171: 	if (axl_node_has_invalid_chars (attribute, strlen (attribute),
 1172: 					&additional_size)) {
 1173: 
 1174: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found attribute content with escapable, non-valid content");
 1175: 		_attr = __axl_node_content_copy_and_escape (attribute, 
 1176: 							    strlen (attribute),
 1177: 							    additional_size,
 1178: 							    axl_false);
 1179: 	}else {
 1180: 
 1181: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "'%s' is a valid string..", attribute);
 1182: 		_attr = axl_strdup (attribute);
 1183: 	}
 1184: 
 1185: 	/* check attribute value */
 1186: 	additional_size = 0;
 1187: 	if (axl_node_has_invalid_chars (value, strlen (value),
 1188: 					&additional_size)) {
 1189: 
 1190: 		_value = __axl_node_content_copy_and_escape (value, 
 1191: 							     strlen (value),
 1192: 							     additional_size,
 1193: 							     axl_false);
 1194: 	}else {
 1195: 		
 1196: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "'%s' is a valid string..", value);
 1197: 		_value = axl_strdup (value);
 1198: 	}
 1199: 
 1200: 	/* insert the attribute */
 1201: 	if (! __axl_node_set_attribute (NULL, node, _attr, _value, axl_false)) {
 1202: 		axl_free (_attr);
 1203: 		axl_free (_value);
 1204: 	} /* end if */
 1205: 	
 1206: 	return;
 1207: }
 1208: 
 1209: /** 
 1210:  * @brief Allows to install a new attribute pair, based on the
 1211:  * attribute name and the attribute value, without allocating memory
 1212:  * for them.
 1213:  * 
 1214:  * This function works the same way like \ref axl_node_set_attribute
 1215:  * but reusing memory allocated by the user space.
 1216:  * 
 1217:  * @param node The \ref axlNode where the attributes will be
 1218:  * installed.
 1219:  *
 1220:  * @param attribute The attribute name to be installed.
 1221:  *
 1222:  * @param value The attribute value to be installed.
 1223:  */
 1224: void      axl_node_set_attribute_ref  (axlNode * node, char * attribute, char * value)
 1225: {
 1226: 
 1227: 	axl_return_if_fail (node);
 1228: 	axl_return_if_fail (attribute);
 1229: 	axl_return_if_fail (value);
 1230: 
 1231: 	/* insert the attribute */
 1232: 	if (! __axl_node_set_attribute (NULL, node, attribute, value, axl_false)) {
 1233: 		axl_free (attribute);
 1234: 		axl_free (value);
 1235: 		return;
 1236: 	} /* end if */
 1237: 
 1238: 	return;
 1239: }
 1240: 
 1241: /** 
 1242:  * @internal Function that allows configuring attributes to the
 1243:  * selected node, notifying that they come from a factory and
 1244:  * shouldn't be deallocated in the usual way. This function shouldn't
 1245:  * be used by API consumers. This is only useful for Axl Library
 1246:  * internals.
 1247:  * 
 1248:  * @param node The node to be configured with the attribute values.
 1249:  *
 1250:  * @param attribute The attribute to configure.
 1251:  * @param value The attribute value to configure.
 1252:  */
 1253: void      axl_node_set_attribute_from_factory  (axlFactory * factory, 
 1254: 						axlNode    * node, 
 1255: 						char       * attribute, 
 1256: 						char       * value)
 1257: {
 1258: 	/* insert the attribute */
 1259: 	__axl_node_set_attribute (factory, node, attribute, value, axl_true);
 1260: 
 1261: 	return;
 1262: }
 1263: 
 1264: /** 
 1265:  * @brief Allows to check if a particular attribute is installed on
 1266:  * the given node.
 1267:  *
 1268:  * @param node The node where the attribute will be checked to be
 1269:  * configured.
 1270:  *
 1271:  * @param attribute The attribute to check.
 1272:  * 
 1273:  * @return A \ref axl_true if the attribute value is set, otherwise
 1274:  * \ref axl_false is returned.
 1275:  *
 1276:  * See also \ref HAS_ATTR.
 1277:  */
 1278: axl_bool          axl_node_has_attribute      (axlNode * node, const char * attribute)
 1279: {
 1280: 	axlNodeAttr * attr;
 1281: 
 1282: 	axl_return_val_if_fail (node,      axl_false);
 1283: 	axl_return_val_if_fail (attribute, axl_false);
 1284: 
 1285: 	/* check for empty hash */
 1286: 	if (node->attributes == NULL)
 1287: 		return axl_false;
 1288: 
 1289: 	if (node->attr_num <= 10) {
 1290: 		/* linked configuration */
 1291: 		attr = (axlNodeAttr *) node->attributes;
 1292: 		while (attr != NULL) {
 1293: 			/* check that the attribute is equal */
 1294: 			if (axl_cmp (attr->attribute, attribute))
 1295: 				return axl_true;
 1296: 
 1297: 			/* get the next attribute */
 1298: 			attr = attr->next;
 1299: 		} /* end while */
 1300: 
 1301: 		/* attribute not found */
 1302: 		return axl_false;
 1303: 	} /* end if */
 1304: 
 1305: 	/* hashed configuration */
 1306: 	return axl_hash_exists ((axlHash *) node->attributes, (axlPointer) attribute);
 1307: }
 1308: 
 1309: axl_bool __axl_node_remove_attribute_reinsert  (axlPointer key, axlPointer data, axlPointer user_data)
 1310: {
 1311: 	
 1312: 	/* re-add attributes into the node */
 1313: 	axl_node_set_attribute (user_data, key, data);
 1314: 
 1315: 	return axl_false; /* do not stop until process all nodes */
 1316: }
 1317: 
 1318: /** 
 1319:  * @brief Allows to remove the provided attribute, from the node
 1320:  * provided.
 1321:  * 
 1322:  * @param node The node to be updated by removing the attribute
 1323:  * provided.
 1324:  *
 1325:  * @param attribute The attribute to locate and remove.
 1326:  */
 1327: void      axl_node_remove_attribute         (axlNode    * node,
 1328: 					     const char * attribute)
 1329: {
 1330: 	axlNodeAttr * attr;
 1331: 	axlNodeAttr * previous;
 1332: 	axlHash     * temp;
 1333: 
 1334: 	axl_return_if_fail (node);
 1335: 	axl_return_if_fail (attribute);
 1336: 
 1337: 	/* check for empty hash */
 1338: 	if (node->attributes == NULL)
 1339: 		return;
 1340: 
 1341: 	if (node->attr_num <= 10) {
 1342: 		/* linked configuration */
 1343: 		attr     = (axlNodeAttr *) node->attributes;
 1344: 		previous = NULL;
 1345: 		while (attr != NULL) {
 1346: 			/* check that the attribute is equal */
 1347: 			if (axl_cmp (attr->attribute, attribute)) {
 1348: 				/* attribute found */
 1349: 				if (previous == NULL)
 1350: 					node->attributes = (axlPointer) attr->next;
 1351: 				else
 1352: 					previous->next = attr->next;
 1353: 
 1354: 				/* do not decrease attribute number
 1355: 				 * since it is used to know the kind
 1356: 				 * of store used. */
 1357: 
 1358: 				/* now dealloc the attribute */
 1359: 				if (! attr->from_factory) {
 1360: 					axl_free (attr->attribute);
 1361: 					axl_free (attr->value);
 1362: 					axl_free (attr);
 1363: 				} /* end if */
 1364: 
 1365: 				/* update attribute count */
 1366: 				node->attr_num--;
 1367: 				
 1368: 				return;
 1369: 			}
 1370: 
 1371: 			/* get the next attribute */
 1372: 			previous = attr;
 1373: 			attr     = attr->next;
 1374: 		} /* end while */
 1375: 
 1376: 		/* attribute not found */
 1377: 		return;
 1378: 	} /* end if */
 1379: 
 1380: 	/* hashed configuration */
 1381: 	axl_hash_remove ((axlHash *) node->attributes, (axlPointer) attribute);
 1382: 
 1383: 	/* update attributes stored */
 1384: 	
 1385: 	node->attr_num = axl_hash_items ((axlHash *) node->attributes);
 1386: 
 1387: 	/* if we have fewer than the provided number, rebuild structure */
 1388: 	if (node->attr_num == 10) {
 1389: 		/* reconvert attribute format */
 1390: 		temp = (axlHash *) node->attributes;
 1391: 		node->attributes = NULL;
 1392: 		node->attr_num   = 0;
 1393: 		
 1394: 		/* reinsert nodes */
 1395: 		axl_hash_foreach (temp, __axl_node_remove_attribute_reinsert, node);
 1396: 
 1397: 		/* release hash */
 1398: 		axl_hash_free (temp);
 1399: 
 1400: 		printf ("Number of items after reinserting..%d\n", node->attr_num);
 1401: 	} /* end if */
 1402: 	
 1403: 	return;
 1404: }
 1405: 
 1406: /** 
 1407:  * @brief Allows to get the number of attributes installed on the
 1408:  * provided node.
 1409:  * 
 1410:  * @param node The node that is requested to return the number of
 1411:  * attributes installed.
 1412:  * 
 1413:  * @return Number of attributes installed, or -1 if it fails.
 1414:  */
 1415: int       axl_node_num_attributes           (axlNode    * node)
 1416: {
 1417: 	axl_return_val_if_fail (node, -1);
 1418: 
 1419: 	if (node->attr_num <= 10) {
 1420: 		return node->attr_num;
 1421: 	} /* end if */
 1422: 
 1423: 	/* hashed configuration */
 1424: 	return axl_hash_items ((axlHash *) node->attributes);
 1425: }
 1426: 
 1427: /** 
 1428:  * @brief Allows to check if the provided node has attributes
 1429:  * installed.
 1430:  * 
 1431:  * @param node The node to be checked for attributes.
 1432:  * 
 1433:  * @return \ref axl_true if the node has attributes, otherwise \ref axl_false
 1434:  * is returned. The function also returns \ref axl_false if a null
 1435:  * reference for the node is provided.
 1436:  */
 1437: axl_bool      axl_node_has_attributes (axlNode * node)
 1438: {
 1439: 	axl_return_val_if_fail (node, axl_false);
 1440: 
 1441: 	/* return if the attributes reference is configured */
 1442: 	return (node->attributes != NULL);
 1443: }
 1444: 
 1445: /** 
 1446:  * @brief Allows to get current content of the provided attribute
 1447:  * inside the given node.
 1448:  *
 1449:  * It is recomended to call first to \ref axl_node_has_attribute to
 1450:  * ensure that the attribute to be reported its value already
 1451:  * exists. See also \ref ATTR_VALUE.
 1452:  *
 1453:  * @param node The \ref axlNode where the attribute value associated
 1454:  * will be returned.
 1455:  *
 1456:  * @param attribute The attribute that is being required for its
 1457:  * value.
 1458:  * 
 1459:  * @return A string containing the attribute value or NULL if
 1460:  * fails. Returned value must not be deallocated, it is a reference to
 1461:  * a local copy. Use \ref axl_strdup function to get a persistent
 1462:  * copy.
 1463:  */
 1464: const char    * axl_node_get_attribute_value (axlNode * node, const char * attribute)
 1465: {
 1466: 	axlNodeAttr * attr;
 1467: 
 1468: 	/* check values received */
 1469: 	axl_return_val_if_fail (node, NULL);
 1470: 	axl_return_val_if_fail (attribute, NULL);
 1471: 
 1472: 	/* check for empty hash */
 1473: 	if (node->attributes == NULL)
 1474: 		return NULL;
 1475: 
 1476: 	if (node->attr_num <= 10) {
 1477: 		/* linked configuration */
 1478: 		attr = (axlNodeAttr *) node->attributes;
 1479: 		while (attr != NULL) {
 1480: 			/* check that the attribute is equal */
 1481: 			if (axl_cmp (attr->attribute, attribute))
 1482: 				return attr->value;
 1483: 
 1484: 			/* get the next attribute */
 1485: 			attr = attr->next;
 1486: 		} /* end while */
 1487: 		
 1488: 		/* attribute not found */
 1489: 		return NULL;
 1490: 	} /* end if */
 1491: 
 1492: 	/* return value stored for the provided key */
 1493: 	return axl_hash_get ((axlHash *) node->attributes, (axlPointer) attribute);
 1494: }
 1495: 
 1496: /** 
 1497:  * @brief Gets an allocated copy for the value associated to the given
 1498:  * attribute.
 1499:  *
 1500:  * See \ref axl_node_get_attribute_value for more information. This
 1501:  * function works the same way but returning an already allocated
 1502:  * attribute value.
 1503:  * 
 1504:  * @param node The node where the attribute value is requested.
 1505:  *
 1506:  * @param attribute The attribute that is being requested.
 1507:  * 
 1508:  * @return A newly allocated reference that must be deallocated when
 1509:  * no longer needed calling to \ref axl_free.
 1510:  */
 1511: char    * axl_node_get_attribute_value_copy (axlNode    * node, 
 1512: 					     const char * attribute)
 1513: {
 1514: 	const char * _value;
 1515: 
 1516: 	/* get the attribute */
 1517: 	_value = axl_node_get_attribute_value (node, attribute);
 1518: 	axl_return_val_if_fail (_value, NULL);
 1519: 	
 1520: 	/* return a copy */
 1521: 	return axl_strdup (_value);
 1522: }
 1523: 
 1524: /** 
 1525:  * @brief Gets the attribute content for the provided attribute name,
 1526:  * at the provided node, but translating entity references found.
 1527:  *
 1528:  * This function works the same way like \ref
 1529:  * axl_node_get_attribute_value_copy, in the sense it returns a
 1530:  * dinamically allocated copy for the attribute value requested but,
 1531:  * at the same time, it returns the content with all entity references
 1532:  * already translated.
 1533:  *
 1534:  * @param node The \ref axlNode instance where the attribute content
 1535:  * will be returned.
 1536:  *
 1537:  * @param attribute The attribute name that is being requested.
 1538:  * 
 1539:  * @return The attribute content, already translated, for those
 1540:  * entities found. The function returns a dinamilly allocated string
 1541:  * so \ref axl_free must be used.
 1542:  */
 1543: char    * axl_node_get_attribute_value_trans (axlNode    * node, 
 1544: 					      const char * attribute)
 1545: {
 1546: 	char * _value;
 1547: 	int    size;
 1548: 
 1549: 	/* get the attribute */
 1550: 	_value = (char *) axl_node_get_attribute_value (node, attribute);
 1551: 	axl_return_val_if_fail (_value, NULL);
 1552: 
 1553: 	/* perform a local copy */
 1554: 	_value = axl_strdup (_value);
 1555: 	
 1556: 	/* return a copy */
 1557: 	size   = strlen (_value);
 1558: 	return axl_node_content_translate_defaults (_value, &size);
 1559: }
 1560: 
 1561: /** 
 1562:  * @brief Allows to get the value associated to the attribute
 1563:  * provided, inside the node selected, removing trailing and ending
 1564:  * white spaces (in the W3C sence: \\n, \\t, \\r, ' ').
 1565:  *
 1566:  * See \ref ATTR_VALUE_TRIMMED for a convenience macro.
 1567:  * 
 1568:  * @param node The node that is requested to return the associated 
 1569:  * value to the attribute.
 1570:  *
 1571:  * @param attribute The attribute that is being requested.
 1572:  * 
 1573:  * @return A reference to the attribute value or NULL if it fails. The
 1574:  * function doesn't return a copy, it returns a reference to the
 1575:  * internal value.
 1576:  */
 1577: const char    * axl_node_get_attribute_value_trimmed (axlNode    * node,
 1578: 						      const char * attribute)
 1579: {
 1580: 	char * _value;
 1581: 
 1582: 	/* get the attribute */
 1583: 	_value = (char *) axl_node_get_attribute_value (node, attribute);
 1584: 	axl_return_val_if_fail (_value, NULL);
 1585: 
 1586: 	/* trim the value */
 1587: 	axl_stream_trim (_value);
 1588: 
 1589: 	/* return value */
 1590: 	return _value;
 1591: }
 1592: 
 1593: /** 
 1594:  * @brief Convenience function that allows to check if a particular
 1595:  * attribute with a particular value is found at the provided node.
 1596:  *
 1597:  * This function will check if the attribute provided in the node is
 1598:  * found and in such case, if the value that is contained inside the
 1599:  * node is actually the same as the one provide to this function.
 1600:  *
 1601:  * You can also use hits macro associated: \ref HAS_ATTR_VALUE.
 1602:  * 
 1603:  * @param node The node that will be checked.
 1604:  * @param attribute The attribute to be checked.
 1605:  * @param value The value to checked if the attribute is found.
 1606:  * 
 1607:  * @return \ref axl_true if the node has the attribute with the
 1608:  * provided value.
 1609:  */
 1610: axl_bool axl_node_has_attribute_value       (axlNode    * node, 
 1611: 					     const char * attribute, 
 1612: 					     const char * value)
 1613: {
 1614: 	axl_return_val_if_fail (node,      axl_false);
 1615: 	axl_return_val_if_fail (attribute, axl_false);
 1616: 	axl_return_val_if_fail (value,     axl_false);
 1617: 
 1618: 	/* return if the attribute value found is the same */
 1619: 	return axl_cmp (axl_node_get_attribute_value (node, attribute), value);
 1620: }
 1621: 
 1622: /**
 1623:  * @}
 1624:  */
 1625: 
 1626: /**
 1627:  * \defgroup axl_node_annotate Axl Node Annotate: An interface that allows associate arbitrary data to a particular node, indexed as a hash.
 1628:  */
 1629: 
 1630: /** 
 1631:  * \addtogroup axl_node_annotate
 1632:  * @{
 1633:  */
 1634: 
 1635: /** 
 1636:  * @internal function which checks and initializes the hash used for
 1637:  * annotated data.
 1638:  */
 1639: void __init_node_annotation (axlNode * node)
 1640: {
 1641: 	if (node->annotate_data == NULL)
 1642: 		node->annotate_data =  axl_hash_new (axl_hash_string, axl_hash_equal_string);
 1643: 	return;
 1644: }
 1645: 
 1646: /** 
 1647:  * @brief Allows to store user defined data associated to the node
 1648:  * that is not visible from an XML perspective.
 1649:  *
 1650:  * This function allows to store data associated to the node and to
 1651:  * retrieve it later in an inherited fashion. This allows to store
 1652:  * semantic/metadata information while parsing xml documents.
 1653:  *
 1654:  * This function stores the given key using a hash,
 1655:  * associating the data provided on the given node. You can also check
 1656:  * the \ref axl_node_annotate_data_full which performs the same task
 1657:  * but allowing to provide key and data destroy functions.
 1658:  *
 1659:  * Once data is stored, it could be inherited by child nodes because
 1660:  * the access to it is done using \ref axl_node_annotate_get which can
 1661:  * configure the data lookup to into the particular node or its
 1662:  * parents.
 1663:  *
 1664:  * Additionally, you can also perform annotation using native types:
 1665:  * int, string and double. Check the following functions to do so.
 1666:  *
 1667:  * - \ref axl_node_annotate_int
 1668:  * - \ref axl_node_annotate_double
 1669:  * - \ref axl_node_annotate_string
 1670:  *
 1671:  * @param node The node where the annotated data will be stored.
 1672:  *
 1673:  * @param key The key under which the annotated data will be stored
 1674:  * (and indexed).
 1675:  *
 1676:  * @param data The data to be stored associated to the key provided.
 1677:  */
 1678: void      axl_node_annotate_data                 (axlNode     * node, 
 1679: 						 const char    * key,
 1680: 						 axlPointer    data)
 1681: {
 1682: 	axl_return_if_fail (node);
 1683: 
 1684: 	/* check and init node annotation */
 1685: 	__init_node_annotation (node);
 1686: 	
 1687: 	/* insert data */
 1688: 	axl_hash_insert (node->annotate_data, (axlPointer) key, data);
 1689: 
 1690: 	/* nothing more to do */
 1691: 	return;
 1692: }
 1693: 
 1694: /** 
 1695:  * @brief Allows to store user defined data associated to the node
 1696:  * that is not visible from an XML perspective.
 1697:  *
 1698:  * See \ref axl_node_annotate_data for a long explanation. This
 1699:  * function performs the same task as \ref axl_node_annotate_data but
 1700:  * allowing to set a key destroy and data destroy functions. They are
 1701:  * later used to deallocate key and data references.
 1702:  *
 1703:  * @param node The node where the annotated data will be stored.
 1704:  *
 1705:  * @param key The key under which the annotated data will be stored.
 1706:  *
 1707:  * @param key_destroy The destroy function to be called to deallocate
 1708:  * the key stored.
 1709:  *
 1710:  * @param data The data to be stored associated to the key provided.
 1711:  *
 1712:  * @param data_destroy The destroy function to be called to deallocate
 1713:  * the data provided.
 1714:  */
 1715: void      axl_node_annotate_data_full            (axlNode       * node,
 1716: 						 const char    * key,
 1717: 						 axlDestroyFunc  key_destroy,
 1718: 						 axlPointer      data,
 1719: 						 axlDestroyFunc  data_destroy)
 1720: {
 1721: 	axl_return_if_fail (node);
 1722: 
 1723: 	/* check and init node annotation */
 1724: 	__init_node_annotation (node);
 1725: 
 1726: 	/* insert data */
 1727: 	axl_hash_insert_full (node->annotate_data, (axlPointer) key, key_destroy, data, data_destroy);
 1728: 
 1729: 	/* nothing more to do */
 1730: 	return;
 1731: }
 1732: 
 1733: /** 
 1734:  * @brief Allows to perform a lookup for annotated data stored on the
 1735:  * provided node.
 1736:  * 
 1737:  * @param node The node where the lookup will be performed.
 1738:  *
 1739:  * @param key The key to lookup in the \ref axlNode reference.
 1740:  *
 1741:  * @param lookup_in_parent Once the lookup fails in the current node,
 1742:  * this variable allows to signal the function to also lookup the
 1743:  * value in the parent nodes recursively. This mechanism allows to
 1744:  * store data on parent nodes that are shared among all child nodes.
 1745:  *
 1746:  * @return The data associated to the key according to the lookup
 1747:  * configuration (lookup_in_parent and lookup_in_doc).
 1748:  */
 1749: axlPointer axl_node_annotate_get                 (axlNode     * node,
 1750: 						  const char  * key,
 1751: 						  axl_bool      lookup_in_parent)
 1752: {
 1753: 	axlPointer   result = NULL;
 1754: 	axlNode    * parent;
 1755: 	
 1756: 	/* check node received before nothing */
 1757: 	axl_return_val_if_fail (node, NULL);
 1758: 	axl_return_val_if_fail (key, NULL);
 1759: 	
 1760: 	/* lookup the data in the current node */
 1761: 	if (node->annotate_data != NULL) {
 1762: 		/* lookup the data */
 1763: 		result = axl_hash_get (node->annotate_data, (axlPointer) key);
 1764: 
 1765: 		/* check result returned */
 1766: 		if (result != NULL)
 1767: 			return result;
 1768: 	} /* end if */
 1769: 
 1770: 	/* check if we have to lookup the data in parent nodes */
 1771: 	if (lookup_in_parent) {
 1772: 		/* get the first parent reference */
 1773: 		parent = axl_item_get_parent (node->holder);
 1774: 		
 1775: 		/* for each parent, try to lookup the data */
 1776: 		while (parent != NULL) {
 1777: 			/* lookup the data */
 1778: 			if (parent->annotate_data)
 1779: 				result = axl_hash_get (parent->annotate_data, (axlPointer) key);
 1780: 
 1781: 			/* check result returned */
 1782: 			if (result != NULL)
 1783: 				return result;
 1784: 
 1785: 			/* get the next parent */
 1786: 			parent = axl_item_get_parent (parent->holder);
 1787: 		}
 1788: 	}
 1789: 
 1790: 	/* no node was found */
 1791: 	return result;
 1792: }
 1793: 
 1794: /** 
 1795:  * @internal definition to clasify node annotation.
 1796:  */
 1797: typedef enum {
 1798: 	/** 
 1799: 	 * @internal definition to clasify int elements.
 1800: 	 */
 1801: 	ANNOTATE_INT     = 0, 
 1802: 	/** 
 1803: 	 * @internal definition to clasify string elements.
 1804: 	 */
 1805: 	ANNOTATE_STRING  = 1, 
 1806: 	/** 
 1807: 	 * @internal definition to clasify int elements.
 1808: 	 */
 1809: 	ANNOTATE_DOUBLE  = 2
 1810: } AnnotateType;
 1811: 
 1812: typedef struct _AnnotateNodeData {
 1813: 	/** 
 1814: 	 * @internal type annotated.
 1815: 	 */
 1816: 	AnnotateType type;
 1817: 
 1818: 	/** 
 1819: 	 * @internal Value annotated: int, string or double.
 1820: 	 */
 1821: 	union {
 1822: 		int    int_value;
 1823: 		char * string_value;
 1824: 		double double_value;
 1825: 	} value;
 1826: } AnnotateNodeData;
 1827: 
 1828: void __axl_annotate_data_free (AnnotateNodeData * data)
 1829: {
 1830: 	if (data == NULL)
 1831: 		return;
 1832: 
 1833: 	/* free the string */
 1834: 	if (data->type == ANNOTATE_STRING)
 1835: 		axl_free (data->value.string_value);
 1836: 
 1837: 	/* free the data */
 1838: 	axl_free (data);
 1839: 
 1840: 	return;
 1841: }
 1842: 
 1843: /** 
 1844:  * @brief Allows to perform an annotation to the node at runtime,
 1845:  * storing a integer value.
 1846:  *
 1847:  * While using xml documents loaded into memory, each node could be
 1848:  * processed and annotated with particular information, indexed with a
 1849:  * key, that could be retrieved later for faster process.
 1850:  * 
 1851:  * This data annotation doesn't perform any modification to the xml
 1852:  * document in any form. It is just a programming support that allows
 1853:  * developers to avoid creating complex and independent structures to
 1854:  * the xml document while developing XML based solutions.
 1855:  * 
 1856:  * While using annotation support, you can use low level functions
 1857:  * that provide a simple way to store pointers associated to
 1858:  * particular nodes and retrieve them using:
 1859:  * 
 1860:  * - \ref axl_node_annotate_data_full
 1861:  * - \ref axl_node_annotate_data
 1862:  * - \ref axl_node_annotate_get
 1863:  *
 1864:  * However, additional functions are provided to store and retreive
 1865:  * easily integers, strings and double data annotated. See the
 1866:  * following:
 1867:  * 
 1868:  *  - \ref axl_node_annotate_int
 1869:  *  - \ref axl_node_annotate_string
 1870:  *  - \ref axl_node_annotate_double
 1871:  *
 1872:  * If you use this function to store an integer data you must use \ref
 1873:  * axl_node_annotate_get_int to retreive data stored. You can't use
 1874:  * \ref axl_node_annotate_get.
 1875:  * 
 1876:  * @param node The node where the annotation will be aplied.
 1877:  *
 1878:  * @param key The key to index the data annotated to the node.
 1879:  *
 1880:  * @param int_value An integer value that will be annotated to the
 1881:  * node received under the key provided.
 1882:  */
 1883: void       axl_node_annotate_int                 (axlNode    * node,
 1884: 						 const char * key,
 1885: 						 int          int_value)
 1886: {
 1887: 	AnnotateNodeData * data;
 1888: 	
 1889: 	/* check received values */
 1890: 	axl_return_if_fail (node);
 1891: 	axl_return_if_fail (key);
 1892: 
 1893: 	/* allocate the node */
 1894: 	data                  = axl_new (AnnotateNodeData, 1);
 1895: 	data->type            = ANNOTATE_INT;
 1896: 	data->value.int_value = int_value;
 1897: 
 1898: 	/* annotate the value */
 1899: 	axl_node_annotate_data_full (node, key, NULL, data, (axlDestroyFunc) __axl_annotate_data_free);
 1900: 	
 1901: 	return;
 1902: }
 1903: 
 1904: /** 
 1905:  * @brief Allows to perform an annotation to the node at runtime,
 1906:  * storing a string value.
 1907:  *
 1908:  * While using xml documents loaded into memory, each node could be
 1909:  * processed and annotated with particular information, indexed with a
 1910:  * key, that could be retrieved later for faster process.
 1911:  * 
 1912:  * This data annotation doesn't perform any modification to the xml
 1913:  * document in any form. It is just a programming support that allows
 1914:  * developers to avoid creating complex and independent structures to
 1915:  * the xml document while developing XML based solutions.
 1916:  * 
 1917:  * While using annotation support, you can use low level functions
 1918:  * that provide a simple way to store pointers associated to
 1919:  * particular nodes and retrieve them using:
 1920:  * 
 1921:  * - \ref axl_node_annotate_data_full
 1922:  * - \ref axl_node_annotate_data
 1923:  * - \ref axl_node_annotate_get
 1924:  *
 1925:  * However, additional functions are provided to store and retreive
 1926:  * easily integers, strings and double data annotated. See the
 1927:  * following:
 1928:  * 
 1929:  *  - \ref axl_node_annotate_int
 1930:  *  - \ref axl_node_annotate_string
 1931:  *  - \ref axl_node_annotate_double
 1932:  *
 1933:  * If you use this function to store a string data you must use \ref
 1934:  * axl_node_annotate_get_string to retreive data stored. You can't use \ref axl_node_annotate_get.
 1935:  *
 1936:  * @param node The node where the annotation will be aplied.
 1937:  *
 1938:  * @param key The key to index the data annotated to the node.
 1939:  *
 1940:  * @param string_value A string value that will be annotated to the
 1941:  * node received under the key provided. This value will be copied and
 1942:  * released once the node is deallocated.
 1943:  */
 1944: void       axl_node_annotate_string              (axlNode       * node,
 1945: 						 const char    * key,
 1946: 						 const char    * string_value)
 1947: {
 1948: 	AnnotateNodeData * data;
 1949: 	
 1950: 	/* check received values */
 1951: 	axl_return_if_fail (node);
 1952: 	axl_return_if_fail (key);
 1953: 	axl_return_if_fail (string_value);
 1954: 
 1955: 	/* allocate the node */
 1956: 	data                     = axl_new (AnnotateNodeData, 1);
 1957: 	data->type               = ANNOTATE_STRING;
 1958: 	data->value.string_value = axl_strdup (string_value);
 1959: 
 1960: 	/* annotate the value */
 1961: 	axl_node_annotate_data_full (node, key, NULL, data, (axlDestroyFunc) __axl_annotate_data_free);
 1962: 	
 1963: 	return;
 1964: }
 1965: 
 1966: /** 
 1967:  * @brief Allows to perform an annotation to the node at runtime,
 1968:  * storing a double value.
 1969:  *
 1970:  * While using xml documents loaded into memory, each node could be
 1971:  * processed and annotated with particular information, indexed with a
 1972:  * key, that could be retrieved later for faster process.
 1973:  * 
 1974:  * This data annotation doesn't perform any modification to the xml
 1975:  * document in any form. It is just a programming support that allows
 1976:  * developers to avoid creating complex and independent structures to
 1977:  * the xml document while developing XML based solutions.
 1978:  * 
 1979:  * While using annotation support, you can use low level functions
 1980:  * that provide a simple way to store pointers associated to
 1981:  * particular nodes and retrieve them using:
 1982:  * 
 1983:  * - \ref axl_node_annotate_data_full
 1984:  * - \ref axl_node_annotate_data
 1985:  * - \ref axl_node_annotate_get
 1986:  *
 1987:  * However, additional functions are provided to store and retreive
 1988:  * easily integers, strings and double data annotated. See the
 1989:  * following:
 1990:  * 
 1991:  *  - \ref axl_node_annotate_int
 1992:  *  - \ref axl_node_annotate_string
 1993:  *  - \ref axl_node_annotate_double
 1994:  *
 1995:  * If you use this function to store a double data you must use \ref
 1996:  * axl_node_annotate_get_double to retreive data stored. You can't use \ref axl_node_annotate_get.
 1997:  * 
 1998:  * @param node The node where the annotation will be aplied.
 1999:  *
 2000:  * @param key The key to index the data annotated to the node.
 2001:  *
 2002:  * @param double_value A string value that will be annotated to the node
 2003:  * received under the key provided.
 2004:  */
 2005: void       axl_node_annotate_double              (axlNode    * node,
 2006: 						 const char * key,
 2007: 						 double       double_value)
 2008: {
 2009: 	AnnotateNodeData * data;
 2010: 	
 2011: 	/* check received values */
 2012: 	axl_return_if_fail (node);
 2013: 	axl_return_if_fail (key);
 2014: 
 2015: 	/* allocate the node */
 2016: 	data                     = axl_new (AnnotateNodeData, 1);
 2017: 	data->type               = ANNOTATE_DOUBLE;
 2018: 	data->value.double_value = double_value;
 2019: 
 2020: 	/* annotate the value */
 2021: 	axl_node_annotate_data_full (node, key, NULL, data, (axlDestroyFunc) __axl_annotate_data_free);
 2022: 	
 2023: 	return;
 2024: }
 2025: 
 2026: /** 
 2027:  * @brief Allows to retrieve the annotated int value stored on the
 2028:  * particular node, under the provided key.
 2029:  * 
 2030:  * @param node The node that is required to return the annotated data.
 2031:  *
 2032:  * @param key The key to be used to lookup for the data annotated.
 2033:  *
 2034:  * @param lookup_in_parent Once the lookup fails, this variable allows
 2035:  * to signal the function to also lookup the value in the parent
 2036:  * nodes. This mechanism allows to store data on parent nodes that are
 2037:  * shared by child nodes.
 2038:  *
 2039:  * NOTE: To make this function work properly you must store double
 2040:  * values using \ref axl_node_annotate_int. Storing values using
 2041:  * other functions will lead to unpredictable results.
 2042:  * 
 2043:  * @return The integer value stored using \ref
 2044:  * axl_node_annotate_int. If the key provided doesn't exists, the
 2045:  * function returns 0.
 2046:  */
 2047: int        axl_node_annotate_get_int             (axlNode    * node,
 2048: 						  const char * key,
 2049: 						  axl_bool     lookup_in_parent)
 2050: {
 2051: 	AnnotateNodeData * data;
 2052: 	
 2053: 	/* check received values */
 2054: 	axl_return_val_if_fail (node, 0);
 2055: 	axl_return_val_if_fail (key, 0);
 2056: 
 2057: 	/* get the annotated data */
 2058: 	data = axl_node_annotate_get (node, key, lookup_in_parent);
 2059: 
 2060: 	/* check for null value. */
 2061: 	if (data == NULL)
 2062: 		return 0;
 2063: 
 2064: 	if (data->type != ANNOTATE_INT) {
 2065: 		/* drop a log */
 2066: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "accesing to a annotation data that isn't flaged as integer");
 2067: 		return 0;
 2068: 	}
 2069: 	
 2070: 	/* return the integer value inside */
 2071: 	return data->value.int_value;
 2072: }
 2073: 
 2074: /** 
 2075:  * @brief Allows to retrieve the annotated string value stored on the
 2076:  * particular node, under the provided key.
 2077:  * 
 2078:  * @param node The node that is required to return the annotated data.
 2079:  *
 2080:  * @param key The key to be used to lookup for the data annotated.
 2081:  *
 2082:  * @param lookup_in_parent Once the lookup fails, this variable allows
 2083:  * to signal the function to also lookup the value in the parent
 2084:  * nodes. This mechanism allows to store data on parent nodes that are
 2085:  * shared by child nodes.
 2086:  *
 2087:  * NOTE: To make this function work properly you must store double
 2088:  * values using \ref axl_node_annotate_string. Storing values using
 2089:  * other functions will lead to unpredictable results.
 2090:  * 
 2091:  * @return The string value stored using \ref
 2092:  * axl_node_annotate_string. If the key provided doesn't exists, the
 2093:  * function returns NULL.
 2094:  */
 2095: char *     axl_node_annotate_get_string          (axlNode    * node,
 2096: 						  const char * key,
 2097: 						  axl_bool     lookup_in_parent)
 2098: {
 2099: 	AnnotateNodeData * data;
 2100: 	
 2101: 	/* check received values */
 2102: 	axl_return_val_if_fail (node, NULL);
 2103: 	axl_return_val_if_fail (key, NULL);
 2104: 
 2105: 	/* get the annotated data */
 2106: 	data = axl_node_annotate_get (node, key, lookup_in_parent);
 2107: 
 2108: 	/* check for null value. */
 2109: 	if (data == NULL)
 2110: 		return NULL;
 2111: 
 2112: 	if (data->type != ANNOTATE_STRING) {
 2113: 		/* drop a log */
 2114: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "accesing to a annotation data that isn't flaged as string");
 2115: 		return NULL;
 2116: 	}
 2117: 	
 2118: 	/* return the string value inside */
 2119: 	return data->value.string_value;
 2120: }
 2121: 
 2122: /** 
 2123:  * @brief Allows to retrieve the annotated double value stored on the
 2124:  * particular node, under the provided key.
 2125:  * 
 2126:  * @param node The node that is required to return the annotated data.
 2127:  *
 2128:  * @param key The key to be used to lookup for the data annotated.
 2129:  *
 2130:  * @param lookup_in_parent Once the lookup fails, this variable allows
 2131:  * to signal the function to also lookup the value in the parent
 2132:  * nodes. This mechanism allows to store data on parent nodes that are
 2133:  * shared by child nodes.
 2134:  *
 2135:  * NOTE: To make this function work properly you must store double
 2136:  * values using \ref axl_node_annotate_double. Storing values using
 2137:  * other functions will lead to unpredictable results.
 2138:  * 
 2139:  * @return The double value stored using \ref
 2140:  * axl_node_annotate_double. If the key provided doesn't exists, the
 2141:  * function returns 0.0.
 2142:  */
 2143: double     axl_node_annotate_get_double          (axlNode    * node,
 2144: 						  const char * key,
 2145: 						  axl_bool     lookup_in_parent)
 2146: {
 2147: 	AnnotateNodeData * data;
 2148: 	
 2149: 	/* check received values */
 2150: 	axl_return_val_if_fail (node, 0.0);
 2151: 	axl_return_val_if_fail (key, 0.0);
 2152: 
 2153: 	/* get the annotated data */
 2154: 	data = axl_node_annotate_get (node, key, lookup_in_parent);
 2155: 
 2156: 	/* check for null value. */
 2157: 	if (data == NULL)
 2158: 		return 0.0;
 2159: 
 2160: 	if (data->type != ANNOTATE_DOUBLE) {
 2161: 		/* drop a log */
 2162: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "accesing to a annotation data that isn't flaged as double");
 2163: 		return 0.0;
 2164: 	}
 2165: 	
 2166: 	/* return the double value inside */
 2167: 	return data->value.double_value;
 2168: }
 2169: 
 2170: /**
 2171:  * @}
 2172:  */
 2173: 
 2174: /** 
 2175:  * \addtogroup axl_node_module
 2176:  * @{
 2177:  */
 2178: 
 2179: /** 
 2180:  * @brief Allows to configure the given node to be empty.
 2181:  *
 2182:  * A \ref axlNode is empty when it is known that the node doesn't have
 2183:  * any content inside it as a child element. If the node has content,
 2184:  * and the value provided to this function is \ref axl_true, the function
 2185:  * will deallocate the content inside.
 2186:  *
 2187:  * You can use this function to clear all the node content (\ref
 2188:  * ITEM_CONTENT and \ref ITEM_CDATA) found inside the node, as follows:
 2189:  * \code
 2190:  * // clear all content inside 
 2191:  * axl_node_set_is_empty (node, axl_true);
 2192:  * \endcode
 2193:  *
 2194:  * @param node The node to configure as empty.
 2195:  *
 2196:  * @param empty The value for emptyness to be used. axl_false will
 2197:  * mean that the node is not empty.
 2198:  */
 2199: void      axl_node_set_is_empty (axlNode * node, axl_bool empty)
 2200: {
 2201: 	axlItem * child;
 2202: 	axlItem * aux;
 2203: 	int       removed = 0;
 2204: 	int       count   = 0;
 2205: 
 2206: 	axl_return_if_fail (node);
 2207: 
 2208: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "received set to empty node=<%s> is_empty=\"%s\"",
 2209: 		   node->name, empty ? "true" : "false");
 2210: 
 2211: 	/* do no perform any operation if axl_false is received */
 2212: 	if (! empty)
 2213: 		return;
 2214: 
 2215: 	/* get the first child and eliminate all content */
 2216: 	child = node->first;
 2217: 	while (child != NULL) {
 2218: 
 2219: 		/* count each item found */
 2220: 		count++;
 2221: 
 2222: 		/* get a reference to the next */
 2223: 		aux = child->next;
 2224: 
 2225: 		/* check item node that represents content, and
 2226: 		 * therefore, an emptyless state */
 2227: 		if (axl_item_get_type (child) == ITEM_CONTENT || 
 2228: 		    axl_item_get_type (child) == ITEM_CDATA) {
 2229: 
 2230: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found item content and item CDATA..");
 2231: 
 2232: 			/* remove the node */
 2233: 			axl_item_remove (child, axl_true);
 2234: 
 2235: 			/* count each item removed */
 2236: 			removed++;
 2237: 			
 2238: 		} /* end if */
 2239: 
 2240: 		/* update to the next */
 2241: 		child = aux;
 2242: 		
 2243: 	} /* end while */
 2244: 
 2245: 	/* now check if items removed are equal to items counted */
 2246: 	if (removed == count) {
 2247: 		/* then clear node references */
 2248: 		node->first = NULL;
 2249: 		node->last  = NULL;
 2250: 	}
 2251: 	
 2252: 	return;
 2253: }
 2254: 
 2255: /** 
 2256:  * @brief Allows to get current xml node name.
 2257:  *
 2258:  * If it is required to check if the given \ref axlNode have a
 2259:  * particular name you can use the macro \ref NODE_CMP_NAME.
 2260:  *
 2261:  * Here is an example:
 2262:  * \code
 2263:  * void check_name (axlNode * node) {
 2264:  *     if (NODE_CMP_NAME (node, "data")) {
 2265:  *         // we got a xml node called "data" 
 2266:  *     }
 2267:  *   // the node doesn't have that name
 2268:  * }
 2269:  * \endcode
 2270:  *
 2271:  * @param node The \ref axlNode where the name will be returned.
 2272:  * 
 2273:  * @return A string reference containing the name. Returned value must
 2274:  * not deallocated. If a copy is required use \ref axl_strdup
 2275:  * function.
 2276:  */
 2277: const char    * axl_node_get_name           (axlNode * node)
 2278: {
 2279: 	axl_return_val_if_fail (node, NULL);
 2280: 
 2281: 	return node->name;
 2282: }
 2283: 
 2284: /** 
 2285:  * @brief Allows to get the parent xml node (\ref axlNode) of the
 2286:  * provided xml node reference.
 2287:  *
 2288:  * @param node The xml node that is requested to return its parent
 2289:  * node.
 2290:  * 
 2291:  * @return An internal reference to the parent node, that must not be
 2292:  * deallocated, or NULL if fails. The function will also return NULL
 2293:  * if the node provided is the document root. The function could only
 2294:  * fail if the provided reference is NULL.
 2295:  */
 2296: axlNode * axl_node_get_parent         (axlNode * node)
 2297: {
 2298: 	axl_return_val_if_fail (node, NULL);
 2299: 
 2300: 	/* if holder is NULL, no parent is posible */
 2301: 	if (node->holder == NULL) {
 2302: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "received a node without holder (an axlItem reference), unable to get the parent reference: %s", 
 2303: 			   node->name);
 2304: 		return NULL;
 2305: 	}
 2306: 
 2307: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "the node has a holder reference, returning current parent");
 2308: 	
 2309: 	/* return the parent */
 2310: 	return node->holder->parent;
 2311: }
 2312: 
 2313: /** 
 2314:  * @brief Allows to get the node that is located, at the same level,
 2315:  * on the next position on the child list.
 2316:  *
 2317:  * When a parent node holds more node childs, all of them have the
 2318:  * same parent child, and at the same time, all of them have a brother
 2319:  * relation. This relation makes that two nodes that are childs for a
 2320:  * parent node, are positioned sequentially as childs for the parent.
 2321:  *
 2322:  * This function allows to get the next child that is stored at the
 2323:  * next position, inside the same level, for the given child node.
 2324:  *
 2325:  * There are an alternative API that allows to get the next node,
 2326:  * following to the node selected, but providing the name to match. See
 2327:  * \ref axl_node_get_next_called.
 2328:  *
 2329:  * @param node The node to get the next xml node reference.
 2330:  * 
 2331:  * @return Returns an internal reference to the next xml node or NULL
 2332:  * if fails. The function will also return NULL if no next xml node is
 2333:  * found starting from the provided reference. The root node will
 2334:  * always returns a NULL reference.
 2335:  */
 2336: axlNode * axl_node_get_next           (axlNode * node)
 2337: {
 2338: 	axlItem * item;
 2339: 
 2340: 	axl_return_val_if_fail (node, NULL);
 2341: 
 2342: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "getting next node for=<%s>", axl_node_get_name (node));
 2343: 
 2344: 	if (node->holder == NULL) {
 2345: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "received a node without item holder (maybe it wasn't inserted into a xml document)");
 2346: 		return NULL;
 2347: 	}
 2348: 	
 2349: 	/* get the next axlNode situated at the same level of the
 2350: 	 * provided axlNode reference */
 2351: 	item = axl_item_get_next (node->holder);
 2352: 
 2353: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "%s", (item != NULL) ? "next item is defined, check if it is a node" : "next item isn't defined");
 2354: 	
 2355: 	/* while the item is not null and different from item node,
 2356: 	 * get the next */
 2357: 	while (item != NULL) {
 2358: 
 2359: 		/* get the item found */
 2360: 		if (axl_item_get_type (item) == ITEM_NODE)
 2361: 			return item->data;
 2362: 
 2363: 		/* get next item */
 2364: 		item = item->next;
 2365: 		
 2366: 	} /* end while */
 2367: 
 2368: 	/* or null if no reference is defined */
 2369: 	return NULL;
 2370: }
 2371: 
 2372: /** 
 2373:  * @brief Allows to get the next node, following to the node provided,
 2374:  * matching the given name.
 2375:  *
 2376:  * <i><b>NOTE:</b> This function isn't XML Namespace aware. You must
 2377:  * use \ref axl_ns_node_get_next_called instead. See \ref
 2378:  * axl_ns_doc_validate. </i>
 2379:  * 
 2380:  * @param node The node that is requested to return its next sibling
 2381:  * node.
 2382:  *
 2383:  * @param name The name to match for the next node.
 2384:  * 
 2385:  * @return A reference to the next node or NULL if it fails. The
 2386:  * returned reference mustn't be deallocated.
 2387:  */
 2388: axlNode * axl_node_get_next_called    (axlNode       * node, 
 2389: 				       const char    * name)
 2390: {
 2391: 	axlNode * next;
 2392: 	axl_return_val_if_fail (node, NULL);
 2393: 	axl_return_val_if_fail (name, NULL);
 2394: 
 2395: 	/* while there is a next node */
 2396: 	next = axl_node_get_next (node);
 2397: 	while (next != NULL) {
 2398: 		/* check the node */
 2399: 		if (NODE_CMP_NAME (next, name))
 2400: 			return next;
 2401: 
 2402: 		/* update to the next */
 2403: 		next = axl_node_get_next (next);
 2404: 	} /* end while */
 2405: 
 2406: 	/* no node was found */
 2407: 	return NULL;
 2408: }
 2409: 
 2410: /** 
 2411:  * @brief Allows to get the previous reference relative to the node
 2412:  * reference provided.
 2413:  *
 2414:  * See \ref axl_node_get_next. Previous reference is the considered
 2415:  * the previous node to the referenced provided that shares the same
 2416:  * parent and it is situated in the same level.
 2417:  * 
 2418:  * @param node The node where the previous reference to the previous
 2419:  * node will be returned.
 2420:  * 
 2421:  * @return The previous node reference or NULL if the node doesn't
 2422:  * have previous reference or NULL if the function fails (the function
 2423:  * only fails if the node reference provided is null).
 2424:  */
 2425: axlNode * axl_node_get_previous (axlNode * node)
 2426: {
 2427: 	axlItem * item;
 2428: 
 2429: 	axl_return_val_if_fail (node, NULL);
 2430: 
 2431: 	/* get the previous axlNode situated at the same level of the
 2432: 	 * provided axlNode reference */
 2433: 	item = axl_item_get_previous (node->holder);
 2434: 
 2435: 	/* while the item is not null and different from item node,
 2436: 	 * get the previous */
 2437: 	while ((item != NULL) && axl_item_get_type (item) !=ITEM_NODE)
 2438: 		item = axl_item_get_previous (item);
 2439: 
 2440: 	/* return the previous reference */
 2441: 	if (item != NULL)
 2442: 		return item->data;
 2443: 
 2444: 	/* or null if no reference is defined */
 2445: 	return NULL;
 2446: }
 2447: 
 2448: /** 
 2449:  * @brief Allows to get the previous node, preceding to the node
 2450:  * provided, matching the given name.
 2451:  *
 2452:  * <i><b>NOTE:</b> This function isn't XML Namespace aware. You must
 2453:  * use \ref axl_ns_node_get_previous_called instead. See \ref
 2454:  * axl_ns_doc_validate. </i>
 2455:  * 
 2456:  * @param node The node that is requested to return its previous sibling node.
 2457:  * @param name The name to match for the previous node.
 2458:  * 
 2459:  * @return A reference to the previous node or NULL if it fails. The
 2460:  * returned reference mustn't be deallocated.
 2461:  */ 
 2462: axlNode *  axl_node_get_previous_called     (axlNode       * node, 
 2463: 					     const char    * name)
 2464: {
 2465: 	axlNode * previous;
 2466: 
 2467: 	axl_return_val_if_fail (node, NULL);
 2468: 	axl_return_val_if_fail (name, NULL);
 2469: 
 2470: 	/* while there is a previous node */
 2471: 	previous = axl_node_get_previous (node);
 2472: 	while (previous != NULL) {
 2473: 		/* check the node */
 2474: 		if (NODE_CMP_NAME (previous, name))
 2475: 			return previous;
 2476: 
 2477: 		/* update to the next */
 2478: 		previous = axl_node_get_previous (previous);
 2479: 	} /* end while */
 2480: 
 2481: 	/* no node was found */
 2482: 	return NULL;
 2483: 
 2484: } 
 2485: 
 2486: 
 2487: /** 
 2488:  * @brief Allows to get the first child that holds the node.
 2489:  *
 2490:  * This function is considered inside the CHILDREN API, which is the
 2491:  * set of functions that are used to handle XML documents that have
 2492:  * node that contains more nodes or content, but not mixed.
 2493:  *
 2494:  * This function allows to get the first child found that is an \ref
 2495:  * axlNode. In the case your application is handling a document that
 2496:  * don't mix nodes and content at the same level inside another xml
 2497:  * nodes, you'll get the expected results.
 2498:  *
 2499:  * But, calling to this function on a node that contains content mixed
 2500:  * with another nodes, you will skip all items stored before the first
 2501:  * xml node found as child. 
 2502:  *
 2503:  * Let's see some examples to clarify this. Provided the following xml
 2504:  * document:
 2505:  *
 2506:  * \code
 2507:  * <document>
 2508:  *   <child>
 2509:  *     Content
 2510:  *   </child>
 2511:  * </document>
 2512:  * \endcode
 2513:  *
 2514:  * If you want to get a reference to the <b>child</b> node you can do
 2515:  * the following:
 2516:  * 
 2517:  * \code
 2518:  * // supposing the document is already loaded in "doc"
 2519:  * axlNode * node = axl_doc_get_root (doc);
 2520:  *
 2521:  * // get the first child 
 2522:  * node = axl_node_get_first_child (node);
 2523:  *
 2524:  * // now you have in "node" a reference to the child node.
 2525:  * \endcode
 2526:  *
 2527:  * However, in the case the previous content mix node with content as
 2528:  * follows:
 2529:  *
 2530:  * \code
 2531:  * <document>
 2532:  *   Some content previous to the first child.
 2533:  *   <child>
 2534:  *     Content
 2535:  *   </child>
 2536:  * </document>
 2537:  * \endcode
 2538:  *
 2539:  * Using this function will make you to skip the first content, that
 2540:  * is, <i>"Some content previous to the first child"</i>, which is found
 2541:  * before the &lt;child> node. In the case you want to have full
 2542:  * access to all items stored as child for a particular node, check
 2543:  * \ref axl_item_get_first_child.
 2544:  * 
 2545:  * @param node The node that is requested to return its first child.
 2546:  * 
 2547:  * @return The first child node or NULL if it has no child node.
 2548:  */
 2549: axlNode * axl_node_get_first_child    (axlNode * node)
 2550: {
 2551: 	axlItem * item;
 2552: 
 2553: 	/* check values */
 2554: 	axl_return_val_if_fail (node, NULL);
 2555: 
 2556: 	/* get first item child and lookup for the first child that is
 2557: 	 * a node */
 2558: 	item = node->first;
 2559: 	while (item != NULL) {
 2560: 		/* check the item type */
 2561: 		if (axl_item_get_type (item) == ITEM_NODE)
 2562: 			return item->data;
 2563: 
 2564: 		/* get the next */
 2565: 		item = item->next;
 2566: 	}
 2567: 
 2568: 	/* return NULL: no child axlNode was found */
 2569: 	return NULL;
 2570: }
 2571: 
 2572: /** 
 2573:  * @brief Allows to get the last child that holds the node.
 2574:  *
 2575:  * See also \ref axl_node_get_first_child and \ref axl_item_get_last_child.
 2576:  * 
 2577:  * @param node The node that is requested to return its last child.
 2578:  * 
 2579:  * @return The last child node or NULL if it has no child node.
 2580:  */
 2581: axlNode * axl_node_get_last_child     (axlNode * node)
 2582: {
 2583: 	axlItem * item;
 2584: 
 2585: 	/* check values */
 2586: 	axl_return_val_if_fail (node, NULL);
 2587: 
 2588: 	/* get first item child and lookup for the first child that is
 2589: 	 * a node */
 2590: 	item = node->last;
 2591: 	while (item != NULL) {
 2592: 		/* check the item type */
 2593: 		if (axl_item_get_type (item) == ITEM_NODE)
 2594: 			return item->data;
 2595: 
 2596: 		/* get the next */
 2597: 		item = item->previous;
 2598: 	}
 2599: 
 2600: 	/* return NULL: no child axlNode was found */
 2601: 	return NULL;
 2602: }
 2603: 
 2604: /** 
 2605:  * @brief Allows to check if the provided \ref axlNode is empty.
 2606:  *
 2607:  * If a node have content, this function will return \ref
 2608:  * axl_false. The content must not be confused with the node childs. A
 2609:  * xml node (\ref axlNode) could be empty but have childs at the same
 2610:  * time (\ref axl_node_have_childs).
 2611:  *
 2612:  * The following xml code snipet shows a xml &lt;data> node with
 2613:  * childs that have content, but the parent node, &lt;data> do not
 2614:  * have content, therefore is empty.
 2615:  *
 2616:  * \code
 2617:  * <data>
 2618:  *    <row>Some data</row>
 2619:  *    <row>More content</row>
 2620:  * </data>
 2621:  * \endcode
 2622:  *
 2623:  * A node that is empty will return NULL data once called to \ref
 2624:  * axl_node_get_content.
 2625:  * 
 2626:  * @param node The node to check for its empty status. 
 2627:  * 
 2628:  * @return \ref axl_true if the node is empty or \ref axl_false if
 2629:  * not.
 2630:  */
 2631: axl_bool          axl_node_is_empty        (axlNode * node)
 2632: {
 2633: 	axlItem * child;
 2634: 	axl_return_val_if_fail (node, axl_false);
 2635: 
 2636: 	/* get the first child */
 2637: 	child = node->first;
 2638: 	while (child != NULL) {
 2639: 		
 2640: 		/* check item node that represents content, and
 2641: 		 * therefore, an emptyless state */
 2642: 		if (axl_item_get_type (child) == ITEM_CONTENT || 
 2643: 		    axl_item_get_type (child) == ITEM_CDATA) {
 2644: 
 2645: 			/* the node has content */
 2646: 			return axl_false;
 2647: 			
 2648: 		} /* end if */
 2649: 
 2650: 		/* go to the next */
 2651: 		child = child->next;
 2652: 
 2653: 	} /* end while */
 2654: 
 2655: 	return axl_true;
 2656: }
 2657: 
 2658: /** 
 2659:  * @brief Allows to get current xml node content (\ref axlNode).
 2660:  * 
 2661:  * See \ref axl_node_is_empty for more details. This function allows
 2662:  * to get current xml node content, which is the free text enclosed
 2663:  * inside the node.
 2664:  *
 2665:  * Returned value is an internal reference to the content stored. So,
 2666:  * in the case a local copy is desired, you should check \ref
 2667:  * axl_node_get_content_copy. 
 2668:  *
 2669:  * Keep in mind that the content returned could have references like
 2670:  * "&amp;" or "&quot;" which are entities references not translated
 2671:  * into the application level values. 
 2672:  * 
 2673:  * This is done because while using the content, you may be interested
 2674:  * in getting the raw content to be passed to another xml parser which
 2675:  * is also able to process that entities.
 2676:  *
 2677:  * If you don't like this behaviour you can check \ref
 2678:  * axl_node_get_content_trans which returns a copy for the xml node
 2679:  * content with all entities references translated.
 2680:  *
 2681:  * Here is a summary of functions available to get the content of a
 2682:  * node:
 2683:  * 
 2684:  * - \ref axl_node_get_content_copy (the same like this function but
 2685:  * producing an independent copy)
 2686:  *
 2687:  * - \ref axl_node_get_content_trans (the same like this function but
 2688:  * translating all entity references and producing an indenpendent
 2689:  * copy).
 2690:  *
 2691:  * - \ref axl_node_get_content_trim (the same like this function but
 2692:  * removing initial and trailing white spaces in the W3C sense: spaces,
 2693:  * tabulars, carry returns and line feed values).
 2694:  * 
 2695:  * @param node The \ref axlNode node where the content will be retrieved.
 2696:  *
 2697:  * @param content_size Optional pointer to an integer variable where
 2698:  * the content size will be reported. If the variable is not set, the
 2699:  * function will not report the content size. If this value is
 2700:  * configured, it will contain the content size starting from 0 up to
 2701:  * the content size.
 2702:  * 
 2703:  * @return Current xml node content. You must not deallocate reference
 2704:  * returned. If you want a permanet copy you should use \ref
 2705:  * axl_node_get_content_copy. Keep in mind that the function will always
 2706:  * return an string reference. In the case the node has no content, an
 2707:  * empty string will be returned, not NULL.
 2708:  */
 2709: const char    * axl_node_get_content     (axlNode * node, int * content_size)
 2710: {
 2711: 	axlNodeContent * content;
 2712: 	axlItem        * child;
 2713: 
 2714: 	axl_return_val_if_fail (node, NULL);
 2715: 
 2716: 	/* get the first child */
 2717: 	child = node->first;
 2718: 	while (child != NULL) {
 2719: 		
 2720: 		/* check item node that represents content, and
 2721: 		 * therefore, an emptyless state */
 2722: 		if (axl_item_get_type (child) == ITEM_CONTENT || 
 2723: 		    axl_item_get_type (child) == ITEM_CDATA) {
 2724: 			/* cast a reference */
 2725: 			content = child->data;
 2726: 
 2727: 			/* return the content */
 2728: 			if (content_size != NULL)
 2729: 				*content_size = content->content_size;
 2730: 
 2731: 			/* return a local reference */
 2732: 			return content->content;
 2733: 		} /* end if */
 2734: 
 2735: 		/* get the next item */
 2736: 		child = child->next;
 2737: 
 2738: 	} /* end while */
 2739: 
 2740: 	/* set content size to zero */
 2741: 	if (content_size != NULL)
 2742: 		*content_size = 0;
 2743: 	return "";
 2744: }
 2745: 
 2746: /** 
 2747:  * @brief Allows to set content to the given \ref axlNode instance.
 2748:  *
 2749:  * The xml node content is that part defined inside two balanced xml tags,
 2750:  * using the same label. Here is an example:
 2751:  * \code
 2752:  * <data>
 2753:  *   Content inside the xml node.
 2754:  * </data>
 2755:  * \endcode
 2756:  *
 2757:  * The function perform a local copy from the content received, doing
 2758:  * all entity replacement required.
 2759:  *
 2760:  * The following table shows the set of characters that this function
 2761:  * will translate into its corresponding entity:
 2762:  *
 2763:  * <table>
 2764:  * <tr><td><b>Character</b></td><td>Entity name</td></tr>
 2765:  * <tr><td>'</td><td>&amp;apos;</td></tr>
 2766:  * <tr><td><</td><td>&amp;lt;</td></tr>
 2767:  * <tr><td>></td><td>&amp;gt;</td></tr>
 2768:  * <tr><td>&</td><td>&amp;amp;</td></tr>
 2769:  * <tr><td>"</td><td>&amp;quot;</td></tr>
 2770:  * </table>
 2771:  *
 2772:  * @param node The xml node, represented by an already initialized
 2773:  * \ref axlNode, where the node content will be set.
 2774:  *
 2775:  * @param content The content to set to the \ref axlNode. The function
 2776:  * will perform a local copy from it.
 2777:  *
 2778:  * @param content_size The content size that is being provided. If -1
 2779:  * is used, the function will use strlen function to get current
 2780:  * content size.
 2781:  */
 2782: void      axl_node_set_content        (axlNode    * node, 
 2783: 				       const char * content, 
 2784: 				       int          content_size)
 2785: {
 2786: 	axlNodeContent * itemContent;
 2787: 	int              additional_size = 0;
 2788: 
 2789: 	axl_return_if_fail (node);
 2790: 	axl_return_if_fail (content);
 2791: 
 2792: 	/* get current content in the case a -1 is provided */
 2793: 	if (content_size == -1)
 2794: 		content_size = strlen (content);
 2795: 
 2796: 	/* allocate the content */
 2797: 	itemContent  = axl_new (axlNodeContent, 1);
 2798: 
 2799: 	/* check if the string received have escapable characters */
 2800: 	if (axl_node_has_invalid_chars (content, content_size, 
 2801: 					&additional_size)) {
 2802: 		/* copy content */
 2803: 		itemContent->content        = __axl_node_content_copy_and_escape (content, 
 2804: 										  content_size, 
 2805: 										  additional_size,
 2806: 										  axl_false);
 2807: 		/* set node content size */
 2808: 		itemContent->content_size   = content_size + additional_size;
 2809: 	}else {
 2810: 		/* set current content */
 2811: 		itemContent->content_size   = content_size;
 2812: 		itemContent->content        = axl_new (char, content_size + 1);
 2813: 
 2814: 		/* copy content */
 2815: 		memcpy (itemContent->content, content, itemContent->content_size);
 2816: 	}
 2817: 
 2818: 	/* add it to the current node */
 2819: 	axl_item_set_child (node, ITEM_CONTENT, itemContent);
 2820: 	
 2821: 
 2822: 	/* job done */
 2823: 	return;
 2824: }
 2825: 
 2826: /** 
 2827:  * @internal Common implementation for axl_node_set_content_ref and
 2828:  * axl_node_set_content_from_factory.
 2829:  */
 2830: void __axl_node_set_content_common_ref (axlFactory     * factory, 
 2831: 					axlNode        * node, 
 2832: 					char           * content, 
 2833: 					int              content_size, 
 2834: 					axl_bool         from_factory,
 2835: 					axl_bool         cdata)
 2836: {
 2837: 	
 2838: 	axlNodeContent * itemContent;
 2839: 
 2840: 	axl_return_if_fail (node);
 2841: 	axl_return_if_fail (content);
 2842: 
 2843: 	/* get current content in the case a -1 is provided */
 2844: 	if (content_size == -1)
 2845: 		content_size = strlen (content);
 2846: 
 2847: 	/* create a content checking it it comes from the
 2848: 	 * factory. Because the string received could come from the
 2849: 	 * factory, already allocated, do not call to allocate */
 2850: 	if (from_factory && factory)
 2851: 		itemContent = axl_factory_get (factory);
 2852: 	else 
 2853: 		itemContent = axl_new (axlNodeContent, 1);
 2854: 		
 2855: 	/* configure content size */
 2856: 	itemContent->content_size = content_size;
 2857: 
 2858: 	/* set current content */
 2859: 	itemContent->content  = content;
 2860: 
 2861: 	if (from_factory) {
 2862: 		if (cdata) {
 2863: 			/* store it */
 2864: 			axl_item_set_child (node, ITEM_CDATA | ITEM_CONTENT_FROM_FACTORY, itemContent);
 2865: 		} else {
 2866: 			/* store it */
 2867: 			axl_item_set_child (node, ITEM_CONTENT | ITEM_CONTENT_FROM_FACTORY, itemContent);
 2868: 		}
 2869: 	} else {
 2870: 		/* store it */
 2871: 		if (cdata) {
 2872: 			/* store as cdata */
 2873: 			axl_item_set_child (node, ITEM_CDATA, itemContent);
 2874: 		} else {
 2875: 			/* store as parsed xml content */
 2876: 			axl_item_set_child (node, ITEM_CONTENT, itemContent);
 2877: 		}
 2878: 	} /* end if */
 2879: 
 2880: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "setting xml node (name: %s) content (size: %d) %s",
 2881: 		   node->name, itemContent->content_size, itemContent->content);
 2882: 
 2883: 	return;
 2884: }
 2885: 
 2886: /** 
 2887:  * @brief Set the content for the provided node, reusing the reference
 2888:  * provided, without making a local copy.
 2889:  *
 2890:  * This function works like \ref axl_node_set_content_ref but without
 2891:  * copy memory provided. This allows reduce memory allocations if the
 2892:  * memory was already allocated by the user space.
 2893:  *
 2894:  * Because this function doesn't perform a copy, if the content
 2895:  * received has to be escaped, the function will fail. To use this
 2896:  * function the caller must ensure that entity references are used to
 2897:  * especify the &, ', ", < or >.
 2898:  *
 2899:  * If the node have content already configured, it is deallocated,
 2900:  * configuring new content received.
 2901:  * 
 2902:  * @param node The \ref axlNode where the content will be set.
 2903:  *
 2904:  * @param content The user space allocated content to be set to the
 2905:  * node.
 2906:  *
 2907:  * @param content_size The content size.
 2908:  */
 2909: void      axl_node_set_content_ref    (axlNode * node, 
 2910: 				       char * content, 
 2911: 				       int content_size)
 2912: {
 2913: 
 2914: 	/* call to set content without signaling that the content
 2915: 	 * wasn't allocated by a factory. */
 2916: 	__axl_node_set_content_common_ref (NULL, node, content, content_size, axl_false, axl_false);
 2917: 	
 2918: 	/* job done */
 2919: 	return;	
 2920: }
 2921: 
 2922: /** 
 2923:  * @internal Internal API used by the axl doc module to signal that
 2924:  * the content was allocated though the string factory and shouldn't
 2925:  * be deallocated.
 2926:  */
 2927: void      axl_node_set_content_from_factory (axlFactory * factory,
 2928: 					     axlNode    * node,
 2929: 					     char       * content,
 2930: 					     int          content_size)
 2931: {
 2932: 	/* call to set content without signaling that the content was
 2933: 	 * allocated by a factory. */
 2934: 	__axl_node_set_content_common_ref (factory, node, content, content_size, axl_true, axl_false);
 2935: 	
 2936: 	/* job done */
 2937: 	return;
 2938: }
 2939: 
 2940: /** 
 2941:  * @brief Allows to store CDATA enclosed content on the provided node.
 2942:  *
 2943:  * Some characters are not allowed to be stored "as is" inside a
 2944:  * parseable XML document. The basic set of them are: &, ', ", < or >.
 2945:  *
 2946:  * In order to store content containing previous characters inside an
 2947:  * xml node, and to remain valid, functions like \ref
 2948:  * axl_node_set_content will translate those value, into the accepted
 2949:  * escape sequences. 
 2950:  *
 2951:  * As an alternative, the XML node content could be stored enclosed as
 2952:  * a CDATA section: <![CDATA[..]]>, which allows to store unparsed
 2953:  * characters, including those not allowed.
 2954:  *
 2955:  * NOTE: In the case content received includes a ]]> declaration, it
 2956:  * is escaped to allow it. This is provided not to allow nested CDATA
 2957:  * declarations which is not allowed by XML 1.0 standard but to allow
 2958:  * binary content to be stored that may include a ]]> declaration.
 2959:  * 
 2960:  * @param node The node where the CDATA will be stored.
 2961:  *
 2962:  * @param content The content to store.
 2963:  *
 2964:  * @param content_size The content size or -1 if required Axl to
 2965:  * figure out current sizes.
 2966:  */
 2967: void      axl_node_set_cdata_content  (axlNode    * node,
 2968: 				       const char * content,
 2969: 				       int          content_size)
 2970: {
 2971: 	char * copy;
 2972: 	int    additional_size = 0;
 2973: 
 2974: 	axl_return_if_fail (node);
 2975: 	axl_return_if_fail (content);
 2976: 
 2977: 	/* reconfigure content_size if found -1 value */
 2978: 	if (content_size == -1)
 2979: 		content_size = strlen (content);
 2980: 
 2981: 	if (axl_node_has_invalid_chars_cdata (content, content_size, &additional_size)) {
 2982: 		/* call to get escaped version */
 2983: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "CDATA found content to scape (content size: %d): '%s'",
 2984: 			   content_size, content);
 2985: 		copy          = __axl_node_content_copy_and_escape (content, content_size, additional_size, axl_true);
 2986: 		content_size += additional_size;
 2987: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "CDATA content escaped        (content size: %d): '%s'",
 2988: 			   content_size, copy);
 2989: 	} else {
 2990: 		/* call to set node content */	
 2991: 		copy = axl_strdup (content);
 2992: 	} /* end if */
 2993: 
 2994: 	/* set content */
 2995: 	__axl_node_set_content_common_ref (NULL, node, copy, content_size, axl_false, axl_true);
 2996: 
 2997: 	return;
 2998: }
 2999: 
 3000: /** 
 3001:  * @internal Internal API used by the axl doc module to signal that
 3002:  * the content was allocated though the string factory and shouldn't
 3003:  * be deallocated, and the content was found inside cdata
 3004:  * declarations.
 3005:  */
 3006: void      axl_node_set_cdata_content_from_factory (axlFactory * factory,
 3007: 						   axlNode    * node,
 3008: 						   char       * content,
 3009: 						   int          content_size)
 3010: {
 3011: 	/* call to set content without signaling that the content was
 3012: 	 * allocated by a factory. */
 3013: 	__axl_node_set_content_common_ref (factory, node, content, content_size, axl_true, axl_true);
 3014: 	
 3015: 	/* job done */
 3016: 	return;	
 3017: }
 3018: 
 3019: /** 
 3020:  * @brief Allows to configure a new comment (&lt;!-- xml comment -->) that will be
 3021:  * stored as a child for the node provided.
 3022:  * 
 3023:  * The comment will be placed at the end of the current child
 3024:  * list. So, if you want to place a xml comment before a xml node,
 3025:  * call first to this function and then to \ref axl_node_set_child.
 3026:  *
 3027:  * @param node The node that will contain the comment.
 3028:  *
 3029:  * @param comment The comment to be stored. The function will perform
 3030:  * a copy from it.
 3031:  *
 3032:  * @param comment_size The comment size or -1 to make the function to
 3033:  * calculate it.
 3034:  */
 3035: void      axl_node_set_comment        (axlNode * node,
 3036: 				       char * comment,
 3037: 				       int    comment_size)
 3038: {
 3039: 	axlNodeContent * content;
 3040: 
 3041: 	axl_return_if_fail (node);
 3042: 	axl_return_if_fail (comment);
 3043: 
 3044: 	/* check current coment size */
 3045: 	if (comment_size == -1)
 3046: 		comment_size = strlen (comment);
 3047: 
 3048: 	/* create the comment */
 3049: 	content               = axl_new (axlNodeContent, 1);
 3050: 	content->content      = axl_new (char, comment_size + 1);
 3051: 	content->content_size = comment_size;
 3052: 
 3053: 	/* copy the content */
 3054: 	memcpy (content->content, comment, comment_size);
 3055: 
 3056: 	/* now store it on the node */
 3057: 	axl_item_set_child (node, ITEM_COMMENT, content);
 3058: 
 3059: 	return;
 3060: }
 3061: 
 3062: 
 3063: /** 
 3064:  * @brief Allows to get a copy for the content stored inside the given
 3065:  * \ref axlNode reference. 
 3066:  *
 3067:  * This function works the same way than \ref axl_node_get_content but
 3068:  * returning a copy from the internal content, that the caller is
 3069:  * responsible of deallocating it.
 3070:  * 
 3071:  * @param node The \ref axlNode where the content is being required.
 3072:  *
 3073:  * @param content_size An optional reference to an integer variable
 3074:  * where the content size will be returned. The function will return
 3075:  * the content size (if the variable is defined) ranging from 0 up to
 3076:  * the content size.
 3077:  * 
 3078:  * @return A newly allocated string representing the node content. 
 3079:  */
 3080: char    * axl_node_get_content_copy (axlNode * node, int * content_size)
 3081: {
 3082: 	int          _content_size;
 3083: 	char       * result;
 3084: 	const char * content;
 3085: 
 3086: 	/* get the content and check if it is defined */
 3087: 	if (content_size)
 3088: 		content = axl_node_get_content (node, content_size);
 3089: 	else
 3090: 		content = axl_node_get_content (node, &_content_size);
 3091: 
 3092: 	/* check result */
 3093: 	if (content == NULL || strlen (content) == 0) {
 3094: 		return axl_strdup ("");
 3095: 	}
 3096: 
 3097: 	/* allocate enough memory for the result */
 3098: 	if (content_size) {
 3099: 		result = axl_new (char, (*content_size) + 1);
 3100: 		memcpy (result, content, *content_size);
 3101: 	}else {
 3102: 		result = axl_new (char, _content_size + 1);
 3103: 		memcpy (result, content, _content_size);
 3104: 	}
 3105:   	
 3106: 	/* return a newly allocated reference to the content */
 3107: 	return result;
 3108: }
 3109: 
 3110: /** 
 3111:  * @brief Allows to get the content inside the provided node, trimming
 3112:  * the head and trailing white spaces found.
 3113:  *
 3114:  * Note that calling to this function will modify the node content,
 3115:  * removing beginig and ending "white spaces" found. Once the function
 3116:  * is called, the node content will be returned by \ref
 3117:  * axl_node_get_content already trimmed.
 3118:  *
 3119:  * @param node The node where the content will be trimmed and
 3120:  * returned.
 3121:  *
 3122:  * @param content_size The node content size reference where the
 3123:  * content size will be reported.
 3124:  * 
 3125:  * @return The reference returned is an internal copy that must not be
 3126:  * deallocated. The function always return content. If the node has no
 3127:  * content, the function will return an empty string (but never a NULL
 3128:  * value).
 3129:  */
 3130: char    * axl_node_get_content_trim   (axlNode * node,
 3131: 				       int * content_size)
 3132: {
 3133: 	int    trimmed;
 3134: 
 3135: 	axlNodeContent * content;
 3136: 	axlItem        * child;
 3137: 
 3138: 	axl_return_val_if_fail (node, NULL);
 3139: 
 3140: 	/* get the first child */
 3141: 	child = node->first;
 3142: 	while (child != NULL) {
 3143: 		
 3144: 		/* check item node that represents content, and
 3145: 		 * therefore, an emptyless state */
 3146: 		if (axl_item_get_type (child) == ITEM_CONTENT || 
 3147: 		    axl_item_get_type (child) == ITEM_CDATA) {
 3148: 			/* cast a reference */
 3149: 			content = child->data;
 3150: 
 3151: 			/* trim the content */
 3152: 			axl_stream_trim_with_size (content->content, &trimmed);
 3153: 
 3154: 			/* updates current internal content size */
 3155: 			content->content_size -= trimmed;
 3156: 
 3157: 			/* return the content */
 3158: 			if (content_size != NULL)
 3159: 				*content_size = content->content_size;
 3160: 
 3161: 			/* return a local reference */
 3162: 			return content->content;
 3163: 		} /* end if */
 3164: 		
 3165: 		/* get the next item */
 3166: 		child = child->next;
 3167: 
 3168: 	} /* end while */
 3169: 
 3170: 	/* set content size to zero */
 3171: 	if (content_size != NULL)
 3172: 		*content_size = 0;
 3173: 	return "";
 3174: }
 3175: 
 3176: void axl_node_get_content_trans_count (axlItem * item, int * count, int *total_size)
 3177: {
 3178: 	axlNodeContent * content;
 3179: 
 3180: 	/* reset counters received */
 3181: 	(*count)      = 0;
 3182: 	(*total_size) = 0;
 3183: 	while (item != NULL) {
 3184: 
 3185: 		/* check item time stored and increase counting */
 3186: 		if (axl_item_get_type (item) == ITEM_CONTENT || 
 3187: 		    axl_item_get_type (item) == ITEM_CDATA) {
 3188: 			/* found item */
 3189: 			(*count)++;
 3190: 
 3191: 			/* update totals */
 3192: 			content     = item->data;
 3193: 			(*total_size) += content->content_size;
 3194: 		}
 3195: 		
 3196: 		/* next item */
 3197: 		item = item->next;
 3198: 	} /* end while */
 3199: 	
 3200: 	return;
 3201: }
 3202: 
 3203: 
 3204: void axl_node_get_content_trans_copy (axlItem * item, char * result)
 3205: {
 3206: 	axlNodeContent * content;
 3207: 	int              desp;
 3208: 
 3209: 	/* reset counters received */
 3210: 	desp = 0;
 3211: 	while (item != NULL) {
 3212: 
 3213: 		/* check item time stored and increase counting */
 3214: 		if (axl_item_get_type (item) == ITEM_CONTENT || 
 3215: 		    axl_item_get_type (item) == ITEM_CDATA) {
 3216: 			/* update totals */
 3217: 			content     = item->data;
 3218: 			
 3219: 			/* copy content */
 3220: 			memcpy (result + desp, content->content, content->content_size);
 3221: 
 3222: 			/* update iterator */
 3223: 			desp += content->content_size;
 3224: 		}
 3225: 		
 3226: 		/* next item */
 3227: 		item = item->next;
 3228: 	} /* end while */
 3229: 	
 3230: 	return;
 3231: }
 3232: 
 3233: /** 
 3234:  * @brief Allows to the get node content, performing a memory
 3235:  * allocation for the returned result, translating default entities
 3236:  * values with its replacement text.
 3237:  * 
 3238:  * @param node The XML node where the content is being requested to be
 3239:  * translated.
 3240:  *
 3241:  * @param content_size An optional reference to an integer variable to
 3242:  * return the node content size.
 3243:  * 
 3244:  * @return A newly allocated string, representing the node content,
 3245:  * with all entities references already translated into the
 3246:  * replacement text.
 3247:  */
 3248: char    * axl_node_get_content_trans (axlNode * node, int * content_size)
 3249: {
 3250: 	char    * result;
 3251: 	int       _content_size = 0;
 3252: 	int       count;
 3253: 	int       total_size;
 3254: 
 3255: 	/* check received reference */
 3256: 	axl_return_val_if_fail (node, NULL);
 3257: 
 3258: 	/* check if the node has one item content inside the node or
 3259: 	 * several CDATA or content items */
 3260: 	axl_node_get_content_trans_count (node->first, &count, &total_size);
 3261: 
 3262: 	/* accoring to the number of items found */
 3263: 	switch (count) {
 3264: 	case 0:
 3265: 		/* report content size */
 3266: 		if (content_size)
 3267: 			*content_size = 0;
 3268: 		/* nothing found return */
 3269: 		return NULL;
 3270: 	case 1:
 3271: 		/* get a copy for the node content, getting the node
 3272: 		 * content size. If the user don't provide a
 3273: 		 * reference, use a local one. */
 3274: 		if (content_size)
 3275: 			result = axl_node_get_content_copy (node, content_size);
 3276: 		else
 3277: 			result = axl_node_get_content_copy (node, &_content_size);
 3278: 		break;
 3279: 	default:
 3280: 		/* if reached this place, only positive values from 2
 3281: 		 * up to N are found */
 3282: 		result = axl_new (char, total_size + 1);
 3283: 		if (content_size)
 3284: 			*content_size = total_size;
 3285: 		else
 3286: 			_content_size = total_size;
 3287: 		
 3288: 		/* now copy all content found */
 3289: 		axl_node_get_content_trans_copy (node->first, result);
 3290: 	}
 3291: 	
 3292: 
 3293: 	/* check result returned */
 3294:         if (result == NULL || strlen (result) == 0) {
 3295: 		/* do not perform a copy here, it is already done by
 3296: 		 * get_content_copy, even in error */
 3297:                 return result;
 3298: 	}
 3299: 
 3300: 	/* translate all references that performs the entities to the
 3301: 	 * replacement text. */
 3302: 	if (content_size)
 3303: 		return axl_node_content_translate_defaults (result, content_size);
 3304: 	return axl_node_content_translate_defaults (result, &_content_size);
 3305: }
 3306: 
 3307: 
 3308: /** 
 3309:  * @brief Allows to configure a child node to the given parent.
 3310:  *
 3311:  * This is a fundamental function while building xml document inside
 3312:  * memory. The way the xml nodes are linked to conform the xml
 3313:  * document structure relay on this function. 
 3314:  * 
 3315:  * The idea is that every call to this function makes the <b>child
 3316:  * </b> xml node to be placed at the end of the current item child
 3317:  * set, that represents current child list for the provided
 3318:  * <b>parent</b>.
 3319:  *
 3320:  * One important question while using this function is that you must
 3321:  * not reuse the same xml node reference, adding it several time to
 3322:  * the same parent (or different parents). You must create a new xml
 3323:  * node reference (axl_node_create) for every call you do to this
 3324:  * function.
 3325:  * 
 3326:  * So, to build the following structure:
 3327:  * \code
 3328:  * <document>
 3329:  *   <child1 />
 3330:  *   <child2 />
 3331:  * </document>
 3332:  * \endcode
 3333:  * 
 3334:  * You must perform the following operations:
 3335:  * \code
 3336:  * axlNode * parent;
 3337:  * axlNode * child;
 3338:  * 
 3339:  * // create the parent node 
 3340:  * parent = axl_node_create ("document");
 3341:  *
 3342:  * // create the first child 
 3343:  * child = axl_node_create ("child1");
 3344:  *
 3345:  * // set it to the parent 
 3346:  * axl_node_set_child (parent, child);
 3347:  *
 3348:  * // create the second child 
 3349:  * child = axl_node_create ("child2");
 3350:  *
 3351:  * // set it to the parent 
 3352:  * axl_node_set_child (parent, child);
 3353:  *
 3354:  * \endcode
 3355:  *
 3356:  * See also \ref axl_node_set_child_after which could help you adding
 3357:  * new nodes not using a parent node as a reference but a brother
 3358:  * node.
 3359:  *
 3360:  * @param parent The parent node.
 3361:  *
 3362:  * @param child The child node. The child node must be a deep
 3363:  * copy. Passing several references, pointing to the same value, will
 3364:  * cause to seg fault the program at the time the parent child is
 3365:  * deallocated. 
 3366:  */
 3367: void      axl_node_set_child (axlNode * parent, axlNode * child)
 3368: {
 3369: 	axl_return_if_fail (parent);
 3370: 	axl_return_if_fail (child);
 3371: 
 3372: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "received parent=0x%x and child=0x%x",  parent, child);
 3373: 
 3374: 	/* set a xml node child */
 3375: 	axl_item_set_child (parent, ITEM_NODE, child);
 3376: 
 3377:         return;
 3378: }
 3379: 
 3380: /** 
 3381:  * @brief Sets a new child after the node provided, using it as a
 3382:  * reference.
 3383:  *
 3384:  * This function is useful to allow configuring new childs placed
 3385:  * after some particular node. The child configured will be placed
 3386:  * after the reference and child of the reference's parent node.
 3387:  * 
 3388:  * @param reference The xml node acting as a reference.
 3389:  * @param child The new xml node child to configure.
 3390:  */
 3391: void      axl_node_set_child_after    (axlNode * reference,
 3392: 				       axlNode * child)
 3393: {
 3394: 	/* call to the item implementation */
 3395: 	axl_item_set_after (reference->holder, ITEM_NODE, child);
 3396: 
 3397: 	return;
 3398: }
 3399: 
 3400: /** 
 3401:  * @brief Allows to replace a selected node with a new reference
 3402:  * inside its context (updating all references: next, previous and
 3403:  * parent).
 3404:  *
 3405:  * The \ref axlNode replaced will be unreference according to dealloc
 3406:  * value. 
 3407:  * 
 3408:  * @param node The node to be replaced by <b>new_node</b> reference.
 3409:  *
 3410:  * @param new_node The node that will replace <b>node</b> reference.
 3411:  *
 3412:  * @param dealloc Signal if <b>node</b> must be deallocated after the
 3413:  * replace operation.
 3414:  */
 3415: void      axl_node_replace             (axlNode   * node, 
 3416: 					axlNode   * new_node,
 3417: 					axl_bool    dealloc)
 3418: {
 3419: 	axlItem * p_item;
 3420: 
 3421: 	axl_return_if_fail (node);
 3422: 	axl_return_if_fail (new_node);
 3423: 
 3424: 	if (axl_item_get_parent (node->holder) == NULL) {
 3425: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "replacing the root node=<%s> with <%s>..", 
 3426: 			   axl_node_get_name (node), axl_node_get_name (new_node));
 3427: 		/* seems to be a root document */
 3428: 		if (axl_item_get_doc (node->holder) != NULL) {
 3429: 			axl_doc_set_root (axl_item_get_doc (node->holder), new_node);
 3430: 		}
 3431: 	} else {
 3432: 
 3433: 		/* check for holder reference */
 3434: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "replacing a non-root node=<%s> with <%s>..",
 3435: 			   axl_node_get_name (node), axl_node_get_name (new_node));
 3436: 		if (node->holder != NULL) {
 3437: 
 3438: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "axl item holder is defined for node=<%s>",
 3439: 				   axl_node_get_name (node));
 3440: 			/* get a reference to the holder item */
 3441: 			p_item       = node->holder;
 3442: 
 3443: 			/* configure the new node */
 3444: 			p_item->data = new_node;
 3445: 
 3446: 			/* nullify the holder reference, and configure
 3447: 			 * the holder reference in the node */
 3448: 			node->holder     = NULL;
 3449: 			new_node->holder = p_item;
 3450: 			
 3451: 		} /* end if */
 3452: 	}
 3453: 
 3454: 	/* dealloc node if configured so */
 3455: 	if (dealloc) {
 3456: 		/* free the node */
 3457: 		axl_node_free (node);
 3458: 	}
 3459: 	
 3460: 	return;
 3461: }
 3462: 
 3463: /** 
 3464:  * @brief Allows to remove the selected reference from the document
 3465:  * containing it.
 3466:  *
 3467:  * The function remove the selected reference from the document. If
 3468:  * the node asked to be removed is the root one, the node won't be
 3469:  * removed because the \ref axl_doc_set_root doesn't accept to remove
 3470:  * the root node.  
 3471:  *
 3472:  * All childs hold by the node removed from the document will also be
 3473:  * removed if dealloc is selected.
 3474:  * 
 3475:  * @param node The node to remove.
 3476:  *
 3477:  * @param dealloc \ref axl_true to also dealloc the memory used by the
 3478:  * node. Setting this parameter to \ref axl_false only unlinks the
 3479:  * node from the document making possible to reuse the node in another
 3480:  * part of the document or to move the node to a different document.
 3481:  */
 3482: void      axl_node_remove             (axlNode  * node,
 3483: 				       axl_bool   dealloc)
 3484: {
 3485: 	axlItem * item;
 3486: 	axl_return_if_fail (node);
 3487: 
 3488: 	/* get a reference to the item element */
 3489: 	item = node->holder;
 3490: 
 3491: 	/* check if the node is the root node of its document */
 3492: 	if (item != NULL && item->doc != NULL) {
 3493: 		if (axl_doc_get_root (item->doc) == node) {
 3494: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "attempting to dettach the root node from the document, nullify");
 3495: 			axl_doc_set_root (item->doc, NULL);
 3496: 		} /* end if */
 3497: 	} /* end if */
 3498: 	
 3499: 	if (axl_item_get_parent (item) != NULL) {
 3500: 
 3501: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "doing reference relocation (remove operation) for=<%s>",
 3502: 			   node->name);
 3503: 		
 3504: 		/* make previous node to point to the new node */
 3505: 		if (item->previous != NULL) {
 3506: 			item->previous->next = item->next;
 3507: 		}
 3508: 		
 3509: 		/* make next node to point to the new node */
 3510: 		if (item->next != NULL) {
 3511: 			item->next->previous = item->previous;
 3512: 		}
 3513: 
 3514: 		/* now, update the parent reference */
 3515: 		if (item->previous == NULL) {
 3516: 			/* seems the node is the first child of the parent,
 3517: 			 * update the reference */
 3518: 			item->parent->first = item->next;
 3519: 		}
 3520: 		
 3521: 		if (item->next == NULL) {
 3522: 			/* seems the node is the last child of the parent,
 3523: 			 * update the reference */
 3524: 			item->parent->last = item->previous;
 3525: 		}
 3526: 
 3527: 		if (item != NULL) {
 3528: 			/* disconnect the item */
 3529: 			item->previous = NULL;
 3530: 			item->next     = NULL;
 3531: 		} /* end if */
 3532: 
 3533: 	} /* end if */
 3534: 
 3535: 	/* dealloc node if configured so */
 3536: 	if (dealloc) {
 3537: 		/* free the node */
 3538: 		axl_node_free (node);
 3539: 	}
 3540: 	
 3541: 	return;
 3542: }
 3543: 
 3544: /** 
 3545:  * @brief Supposing the node is attached to a xml document (\ref
 3546:  * axlDoc), this function allows to deattach the node from the
 3547:  * document that is holding it.
 3548:  * 
 3549:  * This function is useful while requiring to reallocate nodes from
 3550:  * parent to parent, making the parent node that is holding it to
 3551:  * cancel its references to the node, decreasing all internal counts
 3552:  * to the node, etc.
 3553:  *
 3554:  * If the node isn't attached to any document, the function does
 3555:  * nothing.
 3556:  * 
 3557:  * @param node The node to deattach.
 3558:  */
 3559: void axl_node_deattach (axlNode * node)
 3560: {
 3561: 	axl_return_if_fail (node);
 3562: 
 3563: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "deattaching node..");
 3564: 
 3565: 	/* call to remove */
 3566: 	axl_node_remove (node, axl_false);
 3567: 
 3568: 	return;
 3569: }
 3570: 
 3571: /** 
 3572:  * @brief Allows to configure that the given node have child nodes.
 3573:  *
 3574:  * <b>DEPRECATED:</b> The function doesn't perform any operation. See
 3575:  * \ref axl_node_have_childs.
 3576:  * 
 3577:  * @param node The node to configure.
 3578:  *
 3579:  * @param childs The child configuration, \ref axl_true to notify that
 3580:  * the node have childs, otherwise, \ref axl_false is returned.
 3581:  */
 3582: void      axl_node_set_have_childs (axlNode * node, axl_bool childs)
 3583: {
 3584: 	/* do nothing */
 3585: 	return;
 3586: }
 3587: 
 3588: /** 
 3589:  * @brief Allows to get current childs configuration from the given
 3590:  * xml node (\ref axlNode).
 3591:  *
 3592:  * An xml node (represented by an \ref axlNode) is considered to have
 3593:  * childs only if it has more xml child nodes. The content is not
 3594:  * considered be a child. See \ref axl_node_is_empty for more
 3595:  * information.
 3596:  * 
 3597:  * @param node The \ref axlNode reference.
 3598:  * 
 3599:  * @return An \ref axl_true if the \ref axlNode have childs or \ref
 3600:  * axl_false if not.
 3601:  */
 3602: axl_bool          axl_node_have_childs        (axlNode * node)
 3603: {
 3604: 	axlItem * item;
 3605: 
 3606: 	axl_return_val_if_fail (node, axl_false);
 3607: 
 3608: 	item = node->first;
 3609: 	while (item != NULL) {
 3610: 		/* check item type */
 3611: 		if (axl_item_get_type (item) == ITEM_NODE)
 3612: 			return axl_true;
 3613: 
 3614: 		/* go to the next */
 3615: 		item = item->next;
 3616: 
 3617: 	} /* end while */
 3618: 
 3619: 	/* return axl_false because no item was found with ITEM_NODE
 3620: 	 * type */
 3621: 	return axl_false;
 3622: }
 3623: 
 3624: /** 
 3625:  * @internal Function that allows to check if the provided node have
 3626:  * childs, including in the list, nodes, comments, 
 3627:  * 
 3628:  * @param node 
 3629:  * 
 3630:  * @return 
 3631:  */
 3632: axl_bool          axl_node_have_childs_aux        (axlNode * node)
 3633: {
 3634: 	axlItem * item;
 3635: 
 3636: 	axl_return_val_if_fail (node, axl_false);
 3637: 
 3638: 	item = node->first;
 3639: 	while (item != NULL) {
 3640: 		/* check item type */
 3641: 		if (axl_item_get_type (item) == ITEM_NODE || 
 3642: 		    axl_item_get_type (item) == ITEM_PI || 
 3643: 		    axl_item_get_type (item) == ITEM_COMMENT)
 3644: 			return axl_true;
 3645: 
 3646: 		/* go to the next */
 3647: 		item = item->next;
 3648: 
 3649: 	} /* end while */
 3650: 
 3651: 	/* return axl_false because no item was found with ITEM_NODE
 3652: 	 * type */
 3653: 	return axl_false;
 3654: }
 3655: 
 3656: /** 
 3657:  * @brief Allows to get a particular child node from the given node
 3658:  * (\ref axlNode).
 3659:  *
 3660:  * <i><b>NOTE:</b> This function isn't XML Namespace aware. You must
 3661:  * use \ref axl_ns_node_get_child_called instead. See \ref
 3662:  * axl_ns_doc_validate. </i>
 3663:  * 
 3664:  * @param parent The parent node where the child will be looked up.
 3665:  *
 3666:  * @param name The name for the child to search.
 3667:  * 
 3668:  * @return A refernce to a \ref axlNode or NULL if no child exists
 3669:  * called by the name provided, inside the node provided.
 3670:  */
 3671: axlNode * axl_node_get_child_called   (axlNode * parent, const char * name)
 3672: {
 3673: 	axlNode * node;
 3674: 	axlItem * item;
 3675: 	
 3676: 	axl_return_val_if_fail (parent, NULL);
 3677: 	axl_return_val_if_fail (name, NULL);
 3678: 
 3679: 	/* if the child list is not defined, assume there is no node
 3680: 	 * called the name requested */
 3681: 	if (parent->first == NULL)
 3682: 		return NULL;
 3683: 	
 3684: 	/* if no childs, no result */
 3685: 	item = parent->first;
 3686: 	while (item != NULL) {
 3687: 		/* check item type */
 3688: 		if (axl_item_get_type (item) == ITEM_NODE) {
 3689: 			/* get a reference to the node */
 3690: 			node = item->data;
 3691: 
 3692: 			/* compare for find the child */ 
 3693: 			if (NODE_CMP_NAME (node, name))
 3694: 				return node;
 3695: 			
 3696: 		} /* end if */
 3697: 
 3698: 		/* next child */
 3699: 		item = axl_item_get_next (item);
 3700: 	}
 3701: 
 3702: 	/* no child was found */
 3703: 	return NULL;
 3704: }
 3705: 
 3706: /** 
 3707:  * @brief Allows to find the first child called <b>name</b>, inside
 3708:  * all childs (including its descendants) held by the parent provided.
 3709:  *
 3710:  * This function is similar to \ref axl_node_get_child_called but
 3711:  * though it will also look for a child node called as provided not
 3712:  * only in direct childs but also on its all descendants.
 3713:  *
 3714:  * If you are looking for a function to search for a particular child
 3715:  * node inside direct childs stored for the provided parent, then you
 3716:  * must use \ref axl_node_get_child_called.
 3717:  *
 3718:  * There is also a convenience function that allows to perform a
 3719:  * lookup using as a reference a document (using the root node from
 3720:  * it): \ref axl_doc_find_called.
 3721:  *
 3722:  * <i><b>NOTE:</b> This function isn't XML Namespace aware. You must
 3723:  * use \ref axl_ns_node_find_called instead. See \ref
 3724:  * axl_ns_doc_validate. </i>
 3725:  *
 3726:  * @param parent The parent where the lookup will be produced.
 3727:  *
 3728:  * @param name The name of the child to be looked up.
 3729:  * 
 3730:  * @return A reference to the node found (first instaned matching the
 3731:  * name) or NULL if it fails to find a child.
 3732:  */
 3733: axlNode * axl_node_find_called    (axlNode * parent, const char * name)
 3734: {
 3735: 	axlNode * node;
 3736: 	axlNode * child;
 3737: 
 3738: 	/* for the first child found */
 3739: 	node = axl_node_get_first_child (parent);
 3740: 	while (node != NULL) {
 3741: 		/* check and return the node found */
 3742: 		if (NODE_CMP_NAME (node, name))
 3743: 			return node;
 3744: 		
 3745: 		/* get next */
 3746: 		node = axl_node_get_next (node);
 3747: 	} /* end while */
 3748: 
 3749: 	/* now, for all childs, try to look for the node */
 3750: 	node = axl_node_get_first_child (parent);
 3751: 	while (node != NULL) {
 3752: 		/* make the search */
 3753: 		child = axl_node_find_called (node, name);
 3754: 		
 3755: 		/* child found, return the reference */
 3756: 		if (child != NULL)
 3757: 			return child;
 3758: 		
 3759: 		/* get next */
 3760: 		node = axl_node_get_next (node);
 3761: 	} /* end while */
 3762: 
 3763: 	/* child note found */
 3764: 	return NULL;
 3765: }
 3766: 
 3767: /** 
 3768:  * @brief Allows to get the child that is located at the given
 3769:  * position, inside the given parent node.
 3770:  *
 3771:  * @param parent The parent node where the child will be looked up.
 3772:  *
 3773:  * @param position The position where the child will be looked up. The
 3774:  * values for the position ranges from 0 up to (N - 1).
 3775:  * 
 3776:  * @return A reference to the child node \ref axlNode or NULL if fails. 
 3777:  */
 3778: axlNode * axl_node_get_child_nth      (axlNode * parent, int position)
 3779: {
 3780: 	int       iterator;
 3781: 	axlItem * item;
 3782: 
 3783: 	/* perform some environment checks */
 3784: 	axl_return_val_if_fail (parent, NULL);
 3785: 
 3786: 	/* check for first reference */
 3787: 	if (parent->first == NULL) {
 3788: 		return NULL;
 3789: 	}
 3790: 
 3791: 	/* get the first item */
 3792: 	item = parent->first;
 3793: 
 3794: 	/* get the first node found */
 3795: 	iterator = 0;
 3796: 	while (item != NULL) {
 3797: 		/* check the item type */
 3798: 		if (axl_item_get_type (item) == ITEM_NODE) {
 3799: 			if (iterator == position) {
 3800: 				return item->data;
 3801: 			} else
 3802: 				iterator++;
 3803: 		} /* end if */
 3804: 
 3805: 		/* get the next */
 3806: 		item = item->next;
 3807: 
 3808: 	} /* end while */
 3809: 
 3810: 	/* no first child found */
 3811: 	return NULL;
 3812: }
 3813: 
 3814: /** 
 3815:  * @brief Allows to get the number of childs that the provided node
 3816:  * has.
 3817:  * 
 3818:  * @param parent The node where the number of childs is being queried.
 3819:  * 
 3820:  * @return The number of childs or -1 if fails.
 3821:  */
 3822: int       axl_node_get_child_num      (axlNode * parent)
 3823: {
 3824: 	int       count;
 3825: 	axlItem * item;
 3826: 
 3827: 	/* perform some environment checks */
 3828: 	axl_return_val_if_fail (parent, -1);
 3829: 
 3830: 	/* init values */
 3831: 	count = 0;
 3832: 	item  = parent->first;
 3833: 
 3834: 	/* for each child inside the parent node */
 3835: 	while (item != NULL) {
 3836: 		
 3837: 		/* check item type */
 3838: 		if (axl_item_get_type (item) == ITEM_NODE)
 3839: 			count++;
 3840: 		
 3841: 		/* get the next */
 3842: 		item = item->next;
 3843: 
 3844: 	} /* end while */
 3845: 
 3846: 	/* return the number of chils */
 3847: 	return count;
 3848: }
 3849: 
 3850: 
 3851: /** 
 3852:  * @brief Allows to get childs nodes from the given xml node (\ref
 3853:  * axlNode).
 3854:  *
 3855:  * This function creates a newly allocated list. In the case you want
 3856:  * to iterate over all nodes, it is better to use something similar to
 3857:  * this:
 3858:  *
 3859:  * \code
 3860:  * axlNode * child;
 3861:  *
 3862:  * // get the first child 
 3863:  * child = axl_node_get_first_child (parent);
 3864:  * 
 3865:  * // iterate over all nodes 
 3866:  * while (child != NULL) {
 3867:  *
 3868:  *    // do something with the child 
 3869:  *    do_some_work (child);
 3870:  * 
 3871:  *    // update the reference to the next child
 3872:  *    child = axl_node_get_next (child);   
 3873:  * }
 3874:  * \endcode
 3875:  *
 3876:  * @param node The node where the childs will be returned.
 3877:  * 
 3878:  * @return An \ref axlList containing \ref axlNode items or NULL if it
 3879:  * fails. The list returned MUST be deallocated.
 3880:  */
 3881: axlList * axl_node_get_childs         (axlNode * node)
 3882: {
 3883: 	axlItem * child;
 3884: 	axlList * result;
 3885: 
 3886: 	axl_return_val_if_fail (node, NULL);
 3887: 	
 3888: 	/* create the result list without destroy function */
 3889: 	result  = axl_list_new (__axl_node_equal, NULL);
 3890: 	
 3891: 	/* get the first child */
 3892: 	child = node->first;
 3893: 
 3894: 	while (child != NULL) {
 3895: 		/* check the node type */
 3896: 		if (axl_item_get_type (child) == ITEM_NODE) {
 3897: 			/* add the child to the list */
 3898: 			axl_list_add (result, child->data);
 3899: 			
 3900: 		} /* end if */
 3901: 
 3902: 		/* update the reference to the next child */
 3903: 		child = child->next;
 3904: 	} /* end while */
 3905: 
 3906: 	/* return current childs */
 3907: 	return result;
 3908: }
 3909: 
 3910: axl_bool __axl_node_are_equal_attr (axlPointer key, 
 3911: 				    axlPointer value, 
 3912: 				    axlPointer user_data, 
 3913: 				    axlPointer user_data2)
 3914: {
 3915: 	char                * value2;
 3916: 	axl_bool                * result = user_data2;
 3917: 	
 3918: 	/* get the attr value and compare it with data */
 3919: 	value2 = axl_hash_get ((axlHash *) user_data, (char *) key);
 3920: 
 3921: 	if (! axl_cmp ((char *) value, value2)) {
 3922: 		/* flag that node attributes aren't equal */
 3923: 		(* result) = axl_false;
 3924: 
 3925: 		/* stop foreach */
 3926: 		return axl_true;
 3927: 	}
 3928: 			
 3929: 	/* make the process to continue */
 3930: 	return axl_false;
 3931: }
 3932: 
 3933: /** 
 3934:  * @brief Allows to check if the provided references represents two
 3935:  * equivalent nodes.
 3936:  *
 3937:  * The function will check node name, node content and node attributes
 3938:  * and its values.
 3939:  * 
 3940:  * @param node The node to check.
 3941:  * @param node2 The second node to check.
 3942:  * @param error Optional reference to an \ref axlError where the particular differ is reported.
 3943:  * 
 3944:  * @return axl_true if both nodes are equivalent or axl_false if not.
 3945:  */
 3946: axl_bool          axl_node_are_equal_full          (axlNode * node, axlNode * node2, axlError ** error)
 3947: {
 3948: 	axl_bool result;
 3949: 	
 3950: 	if (node == NULL) {
 3951: 		axl_error_report (error, -1, "Nodes differs because first node reference is NULL");
 3952: 		return axl_false;
 3953: 	} /* end if */
 3954: 	if (node2 == NULL) {
 3955: 		axl_error_report (error, -1, "Nodes differs because second node reference is NULL");
 3956: 		return axl_false;
 3957: 	} /* end if */
 3958: 
 3959: 	/* check document root name */
 3960: 	if (! axl_cmp (axl_node_get_name (node), axl_node_get_name (node2))) {
 3961: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node names aren't equal <%s> != <%s>",
 3962: 			   node->name, node2->name);
 3963: 		axl_error_report (error, -1, "node names aren't equal <%s> != <%s>",
 3964: 				  node->name, node2->name);
 3965: 		return axl_false;
 3966: 	}
 3967: 
 3968: 	/* check empty ness configuration */
 3969: 	if (axl_node_is_empty (node) != axl_node_is_empty (node2)) {
 3970: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "emptyness configuration differs <%s> != <%s>",
 3971: 			   node->name, node2->name);
 3972: 
 3973: 		axl_error_report (error, -1, "emptyness configuration differs <%s> != <%s>",
 3974: 				  node->name, node2->name);
 3975: 		return axl_false;
 3976: 	}
 3977: 	
 3978: 	/* check childs configuration */
 3979: 	if (axl_node_have_childs (node) != axl_node_have_childs (node2)) {
 3980: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "childs configuration differs <%s> != <%s>",
 3981: 			   node->name, node2->name);
 3982: 		axl_error_report (error, -1, "childs configuration differs <%s> != <%s>",
 3983: 				  node->name, node2->name);
 3984: 		return axl_false;
 3985: 	}
 3986: 
 3987: 	/* check childs number */
 3988: 	if (axl_node_get_child_num (node) != axl_node_get_child_num (node2)) {
 3989: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "child number differs <%s>(%d) != <%s>(%d)",
 3990: 			   node->name, axl_node_get_child_num (node), node2->name, axl_node_get_child_num (node2));
 3991: 		axl_error_report (error, -1, "childs configuration differs <%s> != <%s>",
 3992: 				  node->name, node2->name);
 3993: 		return axl_false;
 3994: 	}
 3995: 
 3996: 	/* check attribute values */
 3997: 	if ((node->attributes != NULL && node2->attributes != NULL)) {
 3998: 
 3999: 		/* check the number of attributes that has the hash */
 4000: 		if (node->attr_num != node2->attr_num) {
 4001: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "both nodes have different number of attributes (<%s>:%d != <%s>:%d)",
 4002: 				   node->name, node->attr_num, 
 4003: 				   node2->name, node2->attr_num);
 4004: 			axl_error_report (error, -1, "both nodes have different number of attributes (<%s>:%d != <%s>:%d)",
 4005: 				   node->name, node->attr_num, 
 4006: 				   node2->name, node2->attr_num);
 4007: 			return axl_false;
 4008: 		}
 4009: 
 4010: 		/* now both hashes */
 4011: 		result = axl_true;
 4012: 		if (node->attr_num <= 10) {
 4013: 			/* check both list are equal */
 4014: 			result = __axl_node_attr_list_is_equal ((axlNodeAttr *) node->attributes, (axlNodeAttr *) node2->attributes);
 4015: 		} else {
 4016: 			/* check both hashes are equal */
 4017: 			axl_hash_foreach2 ((axlHash *) node->attributes, __axl_node_are_equal_attr, (axlHash *) node2->attributes, &result);
 4018: 		}
 4019: 
 4020: 		if (! result) {
 4021: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node attributes differs <%s> != <%s>",
 4022: 				   node->name, node2->name);
 4023: 			axl_error_report (error, -1, "node attributes differs <%s> != <%s>",
 4024: 					  node->name, node2->name);
 4025: 			/* attribute missmatch */
 4026: 			return axl_false;
 4027: 		}
 4028: 	} else {
 4029: 		if (node->attributes == NULL && node2->attributes != NULL) {
 4030: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node <%s> has no attributes but <%s> has",
 4031: 				   axl_node_get_name (node), axl_node_get_name (node2));
 4032: 			axl_error_report (error, -1, "node <%s> has no attributes but <%s> has",
 4033: 					  axl_node_get_name (node), axl_node_get_name (node2));
 4034: 			return axl_false;
 4035: 		}
 4036: 
 4037: 		if (node2->attributes == NULL && node->attributes != NULL) {
 4038: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node <%s> has no attributes but <%s> has",
 4039: 				   axl_node_get_name (node2), axl_node_get_name (node));
 4040: 			axl_error_report (error, -1, "node <%s> has no attributes but <%s> has",
 4041: 					  axl_node_get_name (node2), axl_node_get_name (node));
 4042: 			return axl_false;
 4043: 		}
 4044: 
 4045: 	} /* end if */
 4046: 
 4047: 	/* both nodes seems to be equal */
 4048: 	return axl_true;
 4049: }
 4050: 
 4051: /** 
 4052:  * @brief Allows to check if the provided references represents two
 4053:  * equivalent nodes.
 4054:  *
 4055:  * The function will check node name, node content and node attributes
 4056:  * and its values.
 4057:  * 
 4058:  * @param node The node to check.
 4059:  * @param node2 The second node to check.
 4060:  * 
 4061:  * @return axl_true if both nodes are equivalent or axl_false if not.
 4062:  */
 4063: axl_bool          axl_node_are_equal          (axlNode * node, axlNode * node2)
 4064: {
 4065: 	/* use common implementation */
 4066: 	return axl_node_are_equal_full (node, node2, NULL);
 4067: }
 4068: 
 4069: /** 
 4070:  * @brief Allows to associate a PI element, including its content to
 4071:  * the provided node.
 4072:  *
 4073:  * See the following function for more information: \ref
 4074:  * axl_doc_add_pi_target.
 4075:  *
 4076:  * @param node The \ref axlNode where the PI element (\ref axlPI) will
 4077:  * be added.
 4078:  *
 4079:  * @param target The PI target name to add.
 4080:  *
 4081:  * @param content Optional PI content.
 4082:  */
 4083: void      axl_node_add_pi_target            (axlNode * node, 
 4084: 					     char * target, 
 4085: 					     char * content)
 4086: {
 4087: 	axlPI   * pi;
 4088: 
 4089: 	/* perform some environmental checks */
 4090: 	axl_return_if_fail (node);
 4091: 	axl_return_if_fail (target);
 4092: 
 4093: 	/* create the PI element */
 4094: 	pi = axl_pi_create (target, content);
 4095: 
 4096: 	/* set the new process instruction found */
 4097: 	axl_item_set_child (node, ITEM_PI, pi);
 4098: 
 4099: 	return;
 4100: }
 4101: 
 4102: 
 4103: /** 
 4104:  * @brief Allows to check if the provided Processing instruction
 4105:  * target is defined on the given xml node document (\ref axlNode).
 4106:  *
 4107:  * Processing instruction are a way to configure the xml node document
 4108:  * with processing information to instruct the application level that
 4109:  * is going to consume the XML information.
 4110:  *
 4111:  * @param node The \ref axlNode where the processing instruction will
 4112:  * be read.
 4113:  *
 4114:  * @param pi_target The process instruction name.
 4115:  * 
 4116:  * @return axl_true is the processing instruction is defined,
 4117:  * otherwise axl_false is returned.
 4118:  */
 4119: axl_bool          axl_node_has_pi_target            (axlNode * node, 
 4120: 						     char    * pi_target)
 4121: {
 4122: 	axlPI   * pi;
 4123: 	axlItem * item;
 4124: 	
 4125: 	axl_return_val_if_fail (node,      axl_false);
 4126: 	axl_return_val_if_fail (pi_target, axl_false);
 4127: 
 4128: 	/* assume the pi target doesn't exist if it is not
 4129: 	 * initialized */
 4130: 	item = node->first;
 4131: 	while (item != NULL) {
 4132: 		
 4133: 		/* check the type */
 4134: 		if (axl_item_get_type (item) == ITEM_PI) {
 4135: 			/* get a reference */
 4136: 			pi = item->data;
 4137: 
 4138: 			/* only check the first ocurrency */
 4139: 			if (axl_cmp (axl_pi_get_name (pi), pi_target))
 4140: 				return axl_true;
 4141: 		} /* end if */
 4142: 
 4143: 		/* get the next item */
 4144: 		item = item->next;
 4145: 
 4146: 	} /* end while */
 4147: 
 4148: 	return axl_false;
 4149: }
 4150: 
 4151: /** 
 4152:  * @brief Allows to get current processing instruction content.
 4153:  * 
 4154:  * @param node The document where the processing instruction is placed.
 4155:  *
 4156:  * @param pi_target The processing instruction target to get current
 4157:  * content.
 4158:  * 
 4159:  * @return An internal reference to the process instruction target
 4160:  * content. Value returned mustn't be deallocated
 4161:  */
 4162: char    * axl_node_get_pi_target_content    (axlNode * node, 
 4163: 					    char * pi_target)
 4164: {
 4165: 	axlPI   * pi;
 4166: 	axlItem * item;
 4167: 	
 4168: 	axl_return_val_if_fail (node,      NULL);
 4169: 	axl_return_val_if_fail (pi_target, NULL);
 4170: 
 4171: 	/* assume the pi target doesn't exist if it is not
 4172: 	 * initialized */
 4173: 	item = node->first;
 4174: 	while (item != NULL) {
 4175: 		
 4176: 		/* check the type */
 4177: 		if (axl_item_get_type (item) == ITEM_PI) {
 4178: 			/* get a reference */
 4179: 			pi = item->data;
 4180: 
 4181: 			/* only check the first ocurrency */
 4182: 			if (axl_cmp (axl_pi_get_name (pi), pi_target))
 4183: 				return axl_pi_get_content (pi);
 4184: 		} /* end if */
 4185: 
 4186: 		/* get the next item */
 4187: 		item = item->next;
 4188: 
 4189: 	} /* end while */
 4190: 
 4191: 	return NULL;
 4192: }
 4193: 
 4194: /** 
 4195:  * @brief Allows to transfer (move from) all childs (including
 4196:  * comments, content, PI, nodes, etc) from the old parent to the new
 4197:  * parent.
 4198:  *
 4199:  * This function is particular useful while moving content from nodes.
 4200:  * 
 4201:  * @param old_parent The old parent node where all childs will be
 4202:  * removed and placed in the new parent.
 4203:  *
 4204:  * @param new_parent The parent node where the content will be
 4205:  * placed. If the parent node already have childs, the content will be
 4206:  * appended.
 4207:  */
 4208: void      axl_node_transfer_childs          (axlNode * old_parent, 
 4209: 					     axlNode * new_parent)
 4210: {
 4211: 	axlItem * item;
 4212: 	axlItem * item_aux;
 4213: 	
 4214: 	/* get the first child for the old parent */
 4215: 	item = old_parent->first;
 4216: 	while (item != NULL) {
 4217: 
 4218: 		/* get a reference to the next before adding */
 4219: 		item_aux = item->next;
 4220: 
 4221: 		/* set the item to parent for the new node */
 4222: 		axl_item_set_child_ref (new_parent, item);
 4223: 
 4224: 		
 4225: 		/* get the next */
 4226: 		item = item_aux;
 4227: 
 4228: 	} /* end while */
 4229: 
 4230: 	/* clear reference from previous parent */
 4231: 	old_parent->first     = NULL;
 4232: 	old_parent->last      = NULL;
 4233: 	
 4234: 	return;
 4235: }
 4236: 
 4237: /** 
 4238:  * @internal Implementation for the public API provided to dump node content.
 4239:  */
 4240: axl_bool __axl_node_dump_common (axlNode * node, char ** content, int * size, axl_bool pretty_print, int level, int tabular)
 4241: {
 4242: 	int    _size;
 4243: 	int    index;
 4244: 	char * result;
 4245: 
 4246: 	/* check refererences received */
 4247: 	axl_return_val_if_fail (node,    axl_false);
 4248: 	axl_return_val_if_fail (content, axl_false);
 4249: 
 4250: 	/* get dump size */
 4251: 	_size = axl_node_get_flat_size (node, pretty_print, level, tabular);
 4252: 
 4253: 	/* dump the content */
 4254: 	result = axl_new (char, _size + 1);
 4255: 	index  = axl_node_dump_at (node, result, 0, pretty_print, level, tabular);
 4256: 
 4257: 	/* check result */
 4258: 	if (index != _size) {
 4259: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "failed to dump xml node, size dump operation mismatch: %d != %d", 
 4260: 			   index, _size);
 4261: 		/* free allocated result */
 4262: 		axl_free (result);
 4263: 
 4264: 		/* nullify content */
 4265: 		if (size)
 4266: 			*size = -1;
 4267: 		*content      = NULL;
 4268: 		
 4269: 		return axl_false;
 4270: 	} /* end if */
 4271: 
 4272: 	/* fill the size */
 4273: 	if (size)
 4274: 		*size = _size;
 4275: 	*content      = result;
 4276: 
 4277: 	/* return content */
 4278: 	return axl_true;
 4279: }
 4280: 
 4281: /** 
 4282:  * @brief Allows to dump the xml content taking as starting point the
 4283:  * xml node provided. 
 4284:  * 
 4285:  * @param node The \ref axlNode used as reference and starting point
 4286:  * to dump.
 4287:  *
 4288:  * @param content The reference where the result will be returned.
 4289:  *
 4290:  * @param size The reference where the document content size will be
 4291:  * returned. 
 4292:  *
 4293:  * @return The function returns \ref axl_true if the dump operation
 4294:  * was performed. Otherwise \ref axl_false is returned.
 4295:  */
 4296: axl_bool      axl_node_dump                    (axlNode  * node, 
 4297: 						char    ** content, 
 4298: 						int      * size)
 4299: {
 4300: 	/* use common implementation for all functions */
 4301: 	return __axl_node_dump_common (node, content, size, axl_false, 0, 0);
 4302: }
 4303: 
 4304: /** 
 4305:  * @brief Allows to perform a pretty print operation using as
 4306:  * reference (starting point) the node provided.
 4307:  * 
 4308:  * @param node The node to be used as reference for the dump operation.
 4309:  * 
 4310:  * @param content A reference to a user defined pointer where the
 4311:  * content will be placed. Non optional parameter.
 4312:  *
 4313:  * @param size A reference to a user defined pointer where the content
 4314:  * size will be placed. Optional parameter.
 4315:  * 
 4316:  * @param tabular How many spaces to be placed on each level.
 4317:  * 
 4318:  * @return \ref axl_true if the dump operation was properly done, otherwise
 4319:  * \ref axl_false is returned.
 4320:  */
 4321: axl_bool      axl_node_dump_pretty             (axlNode  * node,
 4322: 						char    ** content,
 4323: 						int      * size,
 4324: 						int        tabular)
 4325: {
 4326: 	/* use common implementation for all functions */
 4327: 	return __axl_node_dump_common (node, content, size, axl_true, 0, tabular);
 4328: }
 4329: 
 4330: /** 
 4331:  * @brief Allows to dump the xml document using as reference the node
 4332:  * provided, at the file path provided.
 4333:  * 
 4334:  * @param node The document node reference to use to build the
 4335:  * content.
 4336:  *
 4337:  * @param file_path File path where place the result.
 4338:  * 
 4339:  * @return \ref axl_true if the dump operation was done, otherwise \ref axl_false is
 4340:  * returned.
 4341:  */
 4342: axl_bool      axl_node_dump_to_file            (axlNode  * node,
 4343: 						char     * file_path)
 4344: {
 4345: 	char * content;
 4346: 	int    size;
 4347: 	FILE * fd;
 4348: 	int    written;
 4349: 
 4350: 	/* use common implementation for all functions */
 4351: 	if (!  __axl_node_dump_common (node, &content, &size, axl_true, 0, 0))
 4352: 		return axl_false;
 4353: 
 4354: 	/* open the file and check */
 4355: #if defined(AXL_OS_WIN32) && ! defined(__GNUC__)
 4356: 	if (fopen_s (&fd, file_path, "w") != 0) {
 4357: #else
 4358: 	if ((fd = fopen (file_path, "w")) == NULL) {
 4359: #endif
 4360: 		/* failed to open the file to dump the content */
 4361: 		axl_free (content);
 4362: 
 4363: 		return axl_false;
 4364: 	}
 4365: 
 4366: 	/* dump the content */
 4367: 	written = fwrite (content, 1, size, fd);
 4368: 
 4369: 	/* free the content */
 4370: 	axl_free (content);
 4371: 
 4372: 	/* close file */
 4373: 	fclose (fd);
 4374: 
 4375: 	/* return if we have failed to dump all the content to the
 4376: 	 * file or not. */
 4377: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "returning that the dump was: %s (written:%d == size:%d)", 
 4378: 		   (written == size) ? "OK" : "FAILED", 
 4379: 		   written, size);
 4380: 		   
 4381: 	return (written == size);
 4382: 		
 4383: }
 4384: 
 4385: /** 
 4386:  * @brief Allows to pretty print dump the xml document using as
 4387:  * reference the node provided, at the file path provided.
 4388:  * 
 4389:  * @param node The document node reference to use to build the
 4390:  * content.
 4391:  *
 4392:  * @param file_path File path where place the result.
 4393:  *
 4394:  * @param tabular How many spaces to be placed at each level.
 4395:  * 
 4396:  * @return \ref axl_true if the dump operation was done, otherwise \ref axl_false is
 4397:  * returned.
 4398:  */
 4399: axl_bool      axl_node_dump_pretty_to_file     (axlNode  * node,
 4400: 						char     * file_path,
 4401: 						int        tabular)
 4402: {
 4403: 	char * content;
 4404: 	int    size;
 4405: 	FILE * fd;
 4406: 	int    written;
 4407: 
 4408: 	/* use common implementation for all functions */
 4409: 	if (!  __axl_node_dump_common (node, &content, &size, axl_true, 0, tabular))
 4410: 		return axl_false;
 4411: 
 4412: 	/* open the file and check */
 4413: #if defined(AXL_OS_WIN32) && ! defined(__GNUC__)
 4414: 	if (fopen_s (&fd, file_path, "w") != 0) {
 4415: #else
 4416: 	if ((fd = fopen (file_path, "w")) == NULL) {
 4417: #endif
 4418: 		/* failed to open the file to dump the content */
 4419: 		axl_free (content);
 4420: 
 4421: 		return axl_false;
 4422: 	}
 4423: 
 4424: 	/* dump the content */
 4425: 	written = fwrite (content, 1, size, fd);
 4426: 
 4427: 	/* free the content */
 4428: 	axl_free (content);
 4429: 
 4430: 	/* close file */
 4431: 	fclose (fd);
 4432: 
 4433: 	/* return if we have failed to dump all the content to the
 4434: 	 * file or not. */
 4435: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "returning that the dump was: %s (written:%d == size:%d)", 
 4436: 		   (written == size) ? "OK" : "FAILED", 
 4437: 		   written, size);
 4438: 		   
 4439: 	return (written == size);
 4440: }
 4441: 
 4442: /** 
 4443:  * @brief Allows to get a list which contains \ref axlPI nodes,
 4444:  * representing all process instruction that the \ref axlNode (xml
 4445:  * document node) has.
 4446:  *
 4447:  * While using PI, you can use the following functions to get PI
 4448:  * information:
 4449:  * 
 4450:  *  - \ref axl_node_has_pi_target
 4451:  *  - \ref axl_node_get_pi_target_content
 4452:  *
 4453:  * However, this function will return first ocurrence for PI found
 4454:  * inside the xml document. If you don't use repeated PI elements, you
 4455:  * won't find problems, but, if you need to iterate ever all PI found
 4456:  * or you are using repeated PI, you can use this function as follows
 4457:  * to get current pi elements:
 4458:  *
 4459:  * \code
 4460:  * void show_all_pi (axlNode * node) 
 4461:  * {
 4462:  *      int       iterator;
 4463:  *      axlPI   * pi;
 4464:  *      axlList * PIs;
 4465:  *
 4466:  *      // get all PI target that the node has
 4467:  *      PIs      = axl_node_get_pi_target_list (node);
 4468:  *      iterator = 0;
 4469:  *
 4470:  *      while (iterator < axl_list_length (PIs)) {
 4471:  *            // get next pi stored 
 4472:  *            pi = axl_list_get_nth (PIs, iterator);
 4473:  *
 4474:  *            // do some stuff 
 4475:  *            printf ("PI found target name=%s, content=%s\n",
 4476:  *                    axl_pi_get_name (pi),
 4477:  *                    axl_pi_get_content (pi));
 4478:  *            
 4479:  *            // update the iterator
 4480:  *            iterator++;
 4481:  *      }
 4482:  *
 4483:  *      // once finished, free the list 
 4484:  *      axl_list_free (PIs);
 4485:  *      return;
 4486:  * }
 4487:  * \endcode
 4488:  * 
 4489:  * @param node The xml node (\ref axlNode) where the process
 4490:  * instruction will be returned.
 4491:  * 
 4492:  * @return A reference to the list of processing instruction that the
 4493:  * xml node (\ref axlNode) has. The returned list, if defined, must be
 4494:  * deallocated.
 4495:  */
 4496: axlList * axl_node_get_pi_target_list       (axlNode * node)
 4497: {
 4498: 	axlList * result = NULL;
 4499: 	axlItem * item;
 4500: 	
 4501: 	axl_return_val_if_fail (node, NULL);
 4502: 
 4503: 	/* assume the pi target doesn't exist if it is not
 4504: 	 * initialized */
 4505: 	item = node->first;
 4506: 	while (item != NULL) {
 4507: 		
 4508: 		/* check the type */
 4509: 		if (axl_item_get_type (item) == ITEM_PI) {
 4510: 			/* create the result list */
 4511: 			if (result == NULL)
 4512: 				result = axl_list_new (axl_list_always_return_1, (axlDestroyFunc) axl_pi_free);	 
 4513: 
 4514: 			/* add the list */
 4515: 			axl_list_add (result, item->data);
 4516: 			
 4517: 		} /* end if */
 4518: 
 4519: 		/* get the next item */
 4520: 		item = item->next;
 4521: 
 4522: 	} /* end while */
 4523: 
 4524: 	return result;
 4525: }
 4526: 
 4527: axl_bool __axl_node_get_flat_size_attributes_foreach (axlPointer attr, 
 4528: 						      axlPointer value, 
 4529: 						      axlPointer user_data)
 4530: {
 4531: 	int * length = user_data;
 4532: 
 4533: 	/* " attribute='value' */
 4534: 	(*length) += 4 + strlen ((char*) attr) + strlen ((char*) value);
 4535: 
 4536: 	/* make the process to continue */
 4537: 	return axl_false;
 4538: }
 4539: 
 4540: /** 
 4541:  * @internal
 4542:  * @brief Returns the space required to write the attribute part.
 4543:  */
 4544: int __axl_node_get_flat_size_attributes (axlNode * node)
 4545: {
 4546: 
 4547: 	int            length = 0;
 4548: 	axlNodeAttr  * attr   = NULL;
 4549: 	
 4550: 	/* if attribute list is not defined just return 0 */
 4551: 	if (node->attributes == NULL)
 4552: 		return 0;
 4553: 
 4554: 	/* perform a foreach and accumulate */
 4555: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "get flat size for node <%s>", 
 4556: 		   axl_node_get_name (node));
 4557: 	if (node->attr_num <= 10) {
 4558: 		/* get the first reference */
 4559: 		attr = (axlNodeAttr *) node->attributes;
 4560: 		while (attr != NULL) {
 4561: 			/* call to get length */
 4562: 			__axl_node_get_flat_size_attributes_foreach (attr->attribute, attr->value, &length);
 4563: 			
 4564: 			/* get the next */
 4565: 			attr = attr->next;
 4566: 		}
 4567: 		
 4568: 	} else {
 4569: 		/* perform a foreach */
 4570: 		axl_hash_foreach ((axlHash *) node->attributes, __axl_node_get_flat_size_attributes_foreach, &length);
 4571: 	}
 4572: 
 4573: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "after foreach flat size for node <%s> is %d", 
 4574: 		   axl_node_get_name (node), length);
 4575: 
 4576: 	/* return the length */
 4577: 	return length;
 4578: }
 4579: 
 4580: /** 
 4581:  * @internal
 4582:  *
 4583:  * Returns which the size that the node and its childs will hold if
 4584:  * the are represented into a flat xml stream.
 4585:  * 
 4586:  * @param node The node that is requested its stream xml size.
 4587:  *
 4588:  * @param pretty_print If pretty print is activated.
 4589:  *
 4590:  * @param level Which is the relative level of the node respected to
 4591:  * the root node.
 4592:  * 
 4593:  * @return The stream size or -1 if fails.
 4594:  */
 4595: int       axl_node_get_flat_size            (axlNode * node, axl_bool pretty_print, int level, int tabular)
 4596: {
 4597: 	int              result    = 0;
 4598: 	axlItem        * item;
 4599: 	axlNodeContent * content;
 4600: 	axl_bool         is_empty;
 4601: 	axl_bool         have_childs;
 4602: 
 4603: 	axl_return_val_if_fail (node, -1);
 4604: 
 4605: 	/* get values */
 4606: 	is_empty    = axl_node_is_empty (node);
 4607: 	have_childs = axl_node_have_childs_aux (node);
 4608: 
 4609: 	if (have_childs || (!have_childs && !is_empty)) {
 4610: 		/* the node is emtpy because it has no content but it has
 4611: 		 * childs:
 4612: 		 *
 4613: 		 * "<" + strlen (node-name) + ">" + ... + "</" + strlen (node-name) + ">" */
 4614: 		result = 5 + (2 * strlen (node->name)) + __axl_node_get_flat_size_attributes (node);
 4615: 		
 4616: 		/* check pretty_print */
 4617: 		if (pretty_print) {
 4618: 			/* two tabulations plus two carry return \r\n
 4619: 			 * on windows and \n on unix */
 4620: 			if (have_childs) 
 4621: 				result += (level * tabular * 2) + 2; 
 4622: 			else
 4623: 				result += (level * tabular) + 1; 
 4624: #ifdef __AXL_OS_WIN32__
 4625: 			if (have_childs)
 4626: 				result += 2;
 4627: 			else
 4628: 				result ++;
 4629: #endif
 4630: 		}
 4631: 	} else {
 4632: 		if (is_empty) {
 4633: 			/* "<" + strlen (node-name) + " />" */
 4634: 			result = strlen (node->name) + 4 + __axl_node_get_flat_size_attributes (node);
 4635: 			
 4636: 			/* check pretty print */
 4637: 			if (pretty_print) {
 4638: 				/* one tabular plus one carry return
 4639: 				 * \r\n on windows and \n on unix */
 4640: 				result += (level * tabular) + 1;
 4641: #ifdef __AXL_OS_WIN32__
 4642: 				result += 1;
 4643: #endif
 4644: 			}
 4645: 			
 4646: 			/* return sum */
 4647: 			return result;
 4648: 		}
 4649: 	}
 4650: 
 4651: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node=<%s> count=%d", node->name, result);
 4652: 	
 4653: 	/* get first child */
 4654: 	item = node->first;
 4655: 	while (item != NULL) {
 4656: 		/* according to the type, check a size */
 4657: 		switch (axl_item_get_type (item)) {
 4658: 		case ITEM_NODE:
 4659: 			/* count how many bytes the node holds */
 4660: 			result += axl_node_get_flat_size (item->data, pretty_print, level + 1, tabular);
 4661: 			break;
 4662: 		case ITEM_CONTENT:
 4663: 			/* content */
 4664: 			content = (axlNodeContent *) item->data;
 4665: 			result += content->content_size;
 4666: 			break;
 4667: 		case ITEM_CDATA:
 4668: 			/* content + '<![CDATA[' + ']]>' */
 4669: 			content = (axlNodeContent *) item->data;
 4670: 			result += content->content_size + 12;
 4671: 			break;
 4672: 		case ITEM_PI:
 4673: 			/* get current size */
 4674: 			result += axl_pi_get_size (item->data);
 4675: 			break;
 4676: 		case ITEM_COMMENT:
 4677: 			/* content + '<!-- ' + ' -->' */
 4678: 			content = (axlNodeContent *) item->data;
 4679: 
 4680: 			/* check if the content has already defined white spaces */
 4681: 			if (content->content[0] == ' ' && content->content[content->content_size - 1] == ' ')
 4682: 				result += content->content_size + 7;
 4683: 			else if (content->content[0] != ' ' && content->content[content->content_size - 1] == ' ')
 4684: 				result += content->content_size + 8;
 4685: 			else if (content->content[0] == ' ' && content->content[content->content_size - 1] != ' ')
 4686: 				result += content->content_size + 8;
 4687: 			else
 4688: 				result += content->content_size + 9;
 4689: 			if (pretty_print) {
 4690: 				/* tabular indent + \n */
 4691: 				result += ((level + 1) * tabular) + 1;
 4692: #ifdef __AXL_OS_WIN32__
 4693: 				/* \r\n */
 4694: 				result += 1;
 4695: #endif
 4696: 			}
 4697: 
 4698: 			break;
 4699: 		case ITEM_REF:
 4700: 			/* item ref + '&' + ';' */
 4701: 			content = (axlNodeContent *) item->data;
 4702: 			result += content->content_size + 2;
 4703: 			break;
 4704: 		case ITEM_FROM_FACTORY:
 4705: 		case ITEM_CONTENT_FROM_FACTORY:
 4706: 			/* never reached */
 4707: 			break;
 4708: 		}
 4709: 		/* get next item */
 4710: 		item = item->next;
 4711: 			
 4712: 	} /* end while */
 4713: 		
 4714: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "child processing finished for: parent=<%s>, count=%d", node->name, result);
 4715: 
 4716: 	/* return the result */
 4717: 	return result;
 4718: }
 4719: 
 4720: axl_bool __axl_node_dump_attributes_at_foreach (axlPointer key, 
 4721: 						axlPointer value, 
 4722: 						axlPointer user_data,
 4723: 						axlPointer user_data2)
 4724: {
 4725: 	char      * content    = user_data;
 4726: 	int       * _desp      = user_data2;
 4727: 	axl_bool    terminator = axl_false;
 4728: 	int         desp       = (*_desp);
 4729: 	int         length;
 4730: 
 4731: 	memcpy (content + desp, " ", 1);
 4732: 	desp += 1;
 4733: 	
 4734: 	length = strlen ((char*) key);
 4735: 	memcpy (content + desp, (char *) key, length);
 4736: 	desp += length;
 4737: 
 4738: 	/* check if the content contains a ' so, enclose the attribute
 4739: 	 * with " */
 4740: 	if (strstr (value, "'") == NULL) {
 4741: 		memcpy (content + desp, "='", 2);
 4742: 		desp += 2;
 4743: 	}else {
 4744: 		terminator = axl_true;
 4745: 		memcpy (content + desp, "=\"", 2);
 4746: 		desp += 2;
 4747: 	}
 4748: 	
 4749: 	length = strlen ((char*) value);
 4750: 	memcpy (content + desp, (char*) value, length);
 4751: 	desp += length;
 4752: 
 4753: 	/* dump attribute termination */
 4754: 	if (terminator) {
 4755: 		memcpy (content + desp, "\"", 1);
 4756: 	}else {
 4757: 		memcpy (content + desp, "'", 1);		
 4758: 	}
 4759: 	desp += 1;
 4760: 
 4761: 	/* update desp */
 4762: 	(*_desp) = desp;
 4763: 
 4764: 	/* make the process to continue */
 4765: 	return axl_false;
 4766: }
 4767: 
 4768: void __axl_node_dump_at_the_end (axlNodeAttr * attr, char * content, int * desp)
 4769: {
 4770: 	/* return if no attribute must be dumped */
 4771: 	if (attr == NULL)
 4772: 		return;
 4773: 
 4774: 	/* call to dump next attributes first */
 4775: 	__axl_node_dump_at_the_end (attr->next, content, desp);
 4776: 
 4777: 	/* now dump our attribute */
 4778: 	__axl_node_dump_attributes_at_foreach (attr->attribute, attr->value, content, desp);
 4779: 
 4780: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "dumping attribute: %s=%s", attr->attribute, attr->value);
 4781: 
 4782: 	return;
 4783: }
 4784: 
 4785: /** 
 4786:  * @internal
 4787:  * 
 4788:  * Internal support function which dumps current attribute
 4789:  * configuration into the given memory using the provided desp.
 4790:  */
 4791: int axl_node_dump_attributes_at (axlNode * node, char * content, int desp)
 4792: {
 4793: 	axlNodeAttr  * attr   = NULL;	
 4794: 
 4795: 	/* if attribute list is not defined just return 0 */
 4796: 	if (node->attributes == NULL)
 4797: 		return desp;
 4798: 
 4799: 	/* according to the attribute num */
 4800: 	if (node->attr_num <= 10) {
 4801: 		/* get the first reference */
 4802: 		attr = (axlNodeAttr *) node->attributes;
 4803: 		__axl_node_dump_at_the_end (attr, content, &desp);
 4804: 
 4805: 	} else {
 4806: 		/* foreach attribute dump */
 4807: 		axl_hash_foreach2 ((axlHash *) node->attributes, __axl_node_dump_attributes_at_foreach, content, &desp);
 4808: 	}
 4809: 
 4810: 	/* return the length */
 4811: 	return desp;
 4812: }
 4813: 
 4814: /** 
 4815:  * @internal Writes the indentation according to the tabular size and
 4816:  * the indent level.
 4817:  * 
 4818:  * @param content The reference to the content where the dump
 4819:  * operation will be performed.
 4820:  *
 4821:  * @param tabular The tabular size to be applied for each level.
 4822:  *
 4823:  * @param level The indent level to be applied.
 4824:  * 
 4825:  * @return The number of bytes written.
 4826:  */
 4827: int __axl_node_dump_at_write_indent (char * content, int tabular, int level)
 4828: {
 4829: 	int iterator = 0;
 4830: 
 4831: 	while (iterator < (tabular * level)) {
 4832: 		/* write tabular info */
 4833: 		memcpy (content + iterator, " ", 1);
 4834: 		
 4835: 		/* update iterator */
 4836: 		iterator++;
 4837: 	} /* end while */
 4838: 
 4839: 	return iterator;
 4840: }
 4841: 	
 4842: /* dump content */
 4843: int __axl_node_dump_items (axlItem * item, char * content, int level, axl_bool pretty_print, int desp, int tabular)
 4844: {
 4845: 
 4846: 	axlNodeContent * nodeContent;
 4847: 	char           * string_aux;
 4848: 
 4849: 	/* get first child */
 4850: 	while (item != NULL) {
 4851: 		/* according to the type, check a size */
 4852: 		switch (axl_item_get_type (item)) {
 4853: 		case ITEM_NODE:
 4854: 			/* write axl node content */
 4855: 			desp  = axl_node_dump_at (item->data, content, desp, pretty_print, level + 1, tabular);
 4856: 			break;
 4857: 		case ITEM_CONTENT:
 4858: 			/* write content information */
 4859: 			nodeContent = (axlNodeContent *)item->data;
 4860: 			memcpy (content + desp, nodeContent->content, nodeContent->content_size);
 4861: 			desp += nodeContent->content_size;
 4862: 			break;
 4863: 		case ITEM_CDATA:
 4864: 			/* write content information */
 4865: 			nodeContent = (axlNodeContent *)item->data;
 4866: 			
 4867: 			/* write cdata content */
 4868: 			memcpy (content + desp, "<![CDATA[", 9);
 4869: 			desp += 9;
 4870: 			
 4871: 			/* write content */
 4872: 			memcpy (content + desp, nodeContent->content, nodeContent->content_size);
 4873: 			desp += nodeContent->content_size;
 4874: 			
 4875: 			/* write cdata end */
 4876: 			memcpy (content + desp, "]]>", 3);
 4877: 			desp += 3;
 4878: 			break;
 4879: 		case ITEM_PI:
 4880: 			/* write pi start */
 4881: 			memcpy (content + desp, "<?", 2);
 4882: 			desp += 2;
 4883: 			
 4884: 			/* write pi name */
 4885: 			string_aux = axl_pi_get_name (item->data);
 4886: 			memcpy (content + desp, string_aux, strlen (string_aux));
 4887: 			desp += strlen (string_aux);
 4888: 			
 4889: 			/* write pi start */
 4890: 			memcpy (content + desp, " ", 1);
 4891: 			desp += 1;
 4892: 			
 4893: 			/* write pi content */
 4894: 			string_aux = axl_pi_get_content (item->data);
 4895: 			memcpy (content + desp, string_aux, strlen (string_aux));
 4896: 			desp += strlen (string_aux);
 4897: 			
 4898: 			/* write pi start */
 4899: 			memcpy (content + desp, "?>", 2);
 4900: 			desp += 2;
 4901: 			break;
 4902: 		case ITEM_COMMENT:
 4903: 
 4904: 			/* check for pretty print to write indent */
 4905: 			if (pretty_print) {
 4906: 				desp += __axl_node_dump_at_write_indent (content + desp, tabular, level + 1);
 4907: 			}
 4908: 
 4909: 			/* get a reference to the content */
 4910: 			nodeContent = (axlNodeContent *)item->data;
 4911: 
 4912: 			/* add an space if the content is found to not
 4913: 			 * have one */
 4914: 			if (nodeContent->content [0] == ' ') {
 4915: 				memcpy (content + desp, "<!--", 4);
 4916: 				desp += 4;
 4917: 			} else {
 4918: 				memcpy (content + desp, "<!-- ", 5);
 4919: 				desp += 5;
 4920: 			}
 4921: 			
 4922: 
 4923: 			
 4924: 			/* write content */
 4925: 			memcpy (content + desp, nodeContent->content, nodeContent->content_size);
 4926: 			desp += nodeContent->content_size;
 4927: 			
 4928: 			/* add an space if the content is found to not
 4929: 			 * have one */
 4930: 			if (nodeContent->content [nodeContent->content_size - 1] == ' ') {
 4931: 				memcpy (content + desp, "-->", 3);
 4932: 				desp += 3;
 4933: 			} else {
 4934: 				memcpy (content + desp, " -->", 4);
 4935: 				desp += 4;
 4936: 			} /* end if */
 4937: 
 4938: 			if (pretty_print) {
 4939: #ifdef __AXL_OS_WIN32__
 4940: 				memcpy (content + desp, "\r\n", 2);
 4941: 				desp += 2;
 4942: #else
 4943: 				memcpy (content + desp, "\n", 1);
 4944: 				desp += 1;
 4945: #endif
 4946: 			}
 4947: 
 4948: 			break;
 4949: 		case ITEM_REF:
 4950: 			/* content + '&' + ';' */
 4951: 			memcpy (content + desp, "&", 1);
 4952: 			desp += 1;
 4953: 			
 4954: 			/* get a reference to the content */
 4955: 			nodeContent = (axlNodeContent *)item->data;
 4956: 			
 4957: 			/* write content */
 4958: 			memcpy (content + desp, nodeContent->content, nodeContent->content_size);
 4959: 			desp += nodeContent->content_size;
 4960: 			
 4961: 			memcpy (content + desp, ";", 1);
 4962: 			desp += 1;
 4963: 			break;
 4964: 		case ITEM_FROM_FACTORY:
 4965: 		case ITEM_CONTENT_FROM_FACTORY:
 4966: 			/* never reached */
 4967: 			break;
 4968: 		}
 4969: 		
 4970: 		/* get next item */
 4971: 		item = item->next;
 4972: 		
 4973: 	} /* end while */
 4974: 
 4975: 	/* return desp calculated */
 4976: 	return desp;
 4977: 
 4978: } /* end __axl_node_dump_items */
 4979: 
 4980: /** 
 4981:  * @internal
 4982:  *
 4983:  * Writes the node information represented by the node provided at the
 4984:  * given position into the buffer provided.
 4985:  * 
 4986:  * @param node The node to dump and its childs.
 4987:  *
 4988:  * @param content The memory buffer where the content will be dumped.
 4989:  *
 4990:  * @param desp A memory desp where to dump the node content inside the
 4991:  * memory provided.
 4992:  * 
 4993:  * @return The new desp value to be used on the next dump.
 4994:  */
 4995: int       axl_node_dump_at                  (axlNode * node,
 4996: 					     char    * content,
 4997: 					     int       desp,
 4998: 					     axl_bool  pretty_print,
 4999: 					     int       level,
 5000: 					     int       tabular)
 5001: {
 5002: 	axlItem        * item;
 5003: 	axl_bool         have_childs;
 5004: 
 5005: 	axl_return_val_if_fail (node, -1);
 5006: 
 5007: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "dumping node=<%s> at %d", 
 5008: 		   axl_node_get_name (node), desp);
 5009: 
 5010: 	/* get current have childs status */
 5011: 	have_childs = axl_node_have_childs_aux (node);
 5012: 
 5013: 	/* check for pretty print and tabular */
 5014: 	if (pretty_print) {
 5015: 		desp += __axl_node_dump_at_write_indent (content + desp, tabular, level);
 5016: 	} /* end if */
 5017: 
 5018: 	/* check if the node is empty */
 5019: 	if (axl_node_is_empty (node)) {
 5020: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "the node <%s> is empty", 
 5021: 			   axl_node_get_name (node));
 5022: 
 5023: 		if (! have_childs) {
 5024: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "dumping an empty node without childs=<%s>",
 5025: 				   axl_node_get_name (node));
 5026: 			
 5027: 			/* "<" + strlen (node-name) + " />" */
 5028: 			memcpy (content + desp, "<", 1);
 5029: 			desp += 1;
 5030: 
 5031: 			memcpy (content + desp, node->name, strlen (node->name));
 5032: 			desp += strlen (node->name);
 5033: 
 5034: 			/* dump attribute values */
 5035: 			desp = axl_node_dump_attributes_at (node, content, desp);
 5036: 
 5037: 			memcpy (content + desp, " />", 3);
 5038: 			desp += 3;
 5039: 
 5040: 			/* write traling node information */
 5041: 			if (pretty_print) {
 5042: #ifdef __AXL_OS_WIN32__
 5043: 				memcpy (content + desp, "\r\n", 2);
 5044: 				desp += 2;
 5045: #else
 5046: 				memcpy (content + desp, "\n", 1);
 5047: 				desp += 1;
 5048: #endif
 5049: 			}
 5050: 
 5051: 			return desp;
 5052: 		}
 5053: 	}
 5054: 
 5055: 	/* the node is empty because it doesn't have content but it
 5056: 	 * has childs 
 5057: 	 * "<" + strlen (node-name) + ">" + strlen (node-content) + 
 5058: 	 * "</" + strlen (node-name) + ">" */
 5059: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "getting content for: <%s>", axl_node_get_name (node));
 5060: 
 5061: 	/* dump node start tag */
 5062: 	memcpy (content + desp, "<", 1);
 5063: 	desp += 1;
 5064: 
 5065: 	memcpy (content + desp, node->name, strlen (node->name));
 5066: 	desp += strlen (node->name);
 5067: 
 5068: 	/* dump attribute values */
 5069: 	desp = axl_node_dump_attributes_at (node, content, desp);
 5070: 
 5071: 	memcpy (content + desp, ">", 1);
 5072: 	desp += 1;
 5073: 
 5074: 	/* if the node have childs */
 5075: 	if (have_childs) {
 5076: 		
 5077: 		/* write traling node information */
 5078: 		if (pretty_print) {
 5079: #ifdef __AXL_OS_WIN32__
 5080: 			memcpy (content + desp, "\r\n", 2);
 5081: 			desp += 2;
 5082: #else
 5083: 			memcpy (content + desp, "\n", 1);
 5084: 			desp += 1;
 5085: #endif
 5086: 		} /* end if */
 5087: 
 5088: 		/* dump content */
 5089: 		item = node->first;
 5090: 		desp = __axl_node_dump_items (item, content, level, pretty_print, desp, tabular);
 5091: 		
 5092: 		/* check for pretty print and tabular */
 5093: 		if (pretty_print) {
 5094: 			desp += __axl_node_dump_at_write_indent (content + desp, tabular, level);
 5095: 		} /* end if */
 5096: 
 5097: 	}else {
 5098: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "the node is not empty and have no childs");
 5099: 
 5100: 		/* dump content */
 5101: 		item = node->first;
 5102: 		desp = __axl_node_dump_items (item, content, level, pretty_print, desp, tabular);
 5103: 	} /* end if */
 5104: 
 5105: 	/* dump close tag */
 5106: 	memcpy (content + desp,	"</", 2);
 5107: 	desp += 2;
 5108: 	
 5109: 	memcpy (content + desp, node->name, strlen (node->name));
 5110: 	desp += strlen (node->name);
 5111: 	
 5112: 	memcpy (content + desp,	">", 1);
 5113: 	desp += 1;
 5114: 
 5115: 	/* write traling node information */
 5116: 	if (pretty_print) {
 5117: #ifdef __AXL_OS_WIN32__
 5118: 		memcpy (content + desp, "\r\n", 2);
 5119: 		desp += 2;
 5120: #else
 5121: 		memcpy (content + desp, "\n", 1);
 5122: 		desp += 1;
 5123: #endif
 5124: 	}
 5125: 
 5126: 	/* return the result */
 5127: 	return desp;
 5128: }
 5129: 
 5130: /**
 5131:  * @internal Function used by axl_node_has_invalid_chars which also
 5132:  * provides features for CDATA sections.
 5133:  */
 5134: axl_bool      axl_node_has_invalid_chars_internal        (const char * content,
 5135: 							  int          content_size,
 5136: 							  int        * added_size,
 5137: 							  axl_bool     cdata)
 5138: {
 5139: 	int          iterator = 0;
 5140: 	axl_bool     result   = axl_false;
 5141: 	axl_return_val_if_fail (content, axl_false);
 5142: 
 5143: 	/* reset additional size value */
 5144: 	if (added_size != NULL)
 5145: 		*added_size = 0;
 5146: 
 5147: 	/* calculate the content size */
 5148: 	if (content_size == -1)
 5149: 		content_size = strlen (content);
 5150: 
 5151: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "checking valid sequence: content size=%d", content_size);
 5152: 
 5153: 	/* iterate over all content defined */
 5154: 	while (iterator < content_size) {
 5155: 		/* check for &apos; */
 5156: 		if (content [iterator] == '\'') {
 5157: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence='\\'");
 5158: 			result = axl_true;
 5159: 			if (added_size != NULL)
 5160: 				(*added_size) += 5;
 5161: 		}
 5162: 
 5163: 		/* check for &quot; */
 5164: 		if (content [iterator] == '"') {
 5165: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence='\"'");
 5166: 			result = axl_true;
 5167: 			if (added_size != NULL)
 5168: 				(*added_size) += 5;
 5169: 		}
 5170: 
 5171: 		/* check for &amp; */
 5172: 		if (content [iterator] == '&') {
 5173: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence='&'");
 5174: 			result = axl_true;
 5175: 			if (added_size != NULL)
 5176: 				(*added_size) += 4;
 5177: 		}
 5178: 
 5179: 		/* check for &gt; */
 5180: 		if (content [iterator] == '>') {
 5181: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence='>'");
 5182: 			result = axl_true;
 5183: 			if (added_size != NULL)
 5184: 				(*added_size) += 3;
 5185: 		}
 5186: 
 5187: 		/* check for &lt; */
 5188: 		if (content [iterator] == '<') {
 5189: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence='<'");
 5190: 			result = axl_true;
 5191: 			if (added_size != NULL)
 5192: 				(*added_size) += 3;
 5193: 		}
 5194: 
 5195: 		/* check for ]]> */
 5196: 		if (content [iterator] == ']' && content [iterator + 1] == ']' && content [iterator + 2] == '>') {
 5197: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence=']]>'");
 5198: 			result = axl_true;
 5199: 			if (cdata) {
 5200: 				/* inside CDATA section that is, we
 5201: 				 * have to escape this value and
 5202: 				 * reopen a new CDATA section to match
 5203: 				 * with the last terminator */
 5204: 				if (added_size != NULL)
 5205: 					(*added_size) += 15;
 5206: 			} else {
 5207: 				if (added_size != NULL)
 5208: 					(*added_size) += 3;
 5209: 			}
 5210: 			iterator += 3;
 5211: 			continue;
 5212: 		} /* end if */
 5213: 
 5214: 		/* update the iterator */
 5215: 		iterator++;
 5216: 	}
 5217: 
 5218: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "valid sequence checking result=%d: content size=%d, additional size=%d resul=%s", 
 5219: 		   result, content_size, (added_size != NULL) ? *added_size : 0, result ? "HAS INVALID SEQUENCES" : "HAS NO INVALID SEQUENCES");
 5220: 
 5221: 	/* return results */
 5222: 	return result;
 5223: }
 5224: 
 5225: /** 
 5226:  * @brief Allows to check if the provided string have invalid chars
 5227:  * that must be escaped by using the entity reference rather the value
 5228:  * itself.
 5229:  *
 5230:  * This function is useful in the sense it allows to know if a
 5231:  * particular content will contain elements not allowed by the XML 1.0
 5232:  * definition to be placed directly (like &, <, ;, ' and ").
 5233:  *
 5234:  *
 5235:  * This function use usually complemented with \ref axl_node_content_copy_and_escape. 
 5236:  * 
 5237:  * @param content The content to check.
 5238:  *
 5239:  * @param content_size The size of the content to be checked. If -1 is
 5240:  * provided, the function will calculate the content length.
 5241:  *
 5242:  * @param added_size An integer reference where the additional size
 5243:  * variable will be added. This additional size will be the space
 5244:  * required to replace non-valid characters with entity
 5245:  * references. This parameter is optional, so passing a NULL value is
 5246:  * allowed.
 5247:  * 
 5248:  * @return \ref axl_true if the string contains non valid chars
 5249:  * that must be escaped using entity references.
 5250:  */
 5251: axl_bool      axl_node_has_invalid_chars        (const char * content,
 5252: 						 int          content_size,
 5253: 						 int        * added_size)
 5254: {
 5255: 	/* call to internal implementation supposing this is for a
 5256: 	 * node without CDATA section */
 5257: 	return axl_node_has_invalid_chars_internal (content, content_size, added_size, axl_false);
 5258: }
 5259: 
 5260: /** 
 5261:  * @brief Allows to check if the provided string have escape sequences
 5262:  * that must be defined by using the entity reference rather the value
 5263:  * itself, taking into consideration the content will be used for a
 5264:  * <![CDATA[..]]> section.
 5265:  *
 5266:  * This function is useful in the sense it allows to know if a
 5267:  * particular content will contain elements not allowed by the XML 1.0
 5268:  * definition to be placed directly (like &, <, ;, ' and ").
 5269:  *
 5270:  * This function use usually complemented with \ref axl_node_content_copy_and_escape_cdata. 
 5271:  *
 5272:  * @param content The content to check.
 5273:  *
 5274:  * @param content_size The size of the content to be checked. If -1 is
 5275:  * provided, the function will calculate the content length.
 5276:  *
 5277:  * @param added_size An integer reference where the additional size
 5278:  * variable will be added. This additional size will be the space
 5279:  * required to replace non-valid characters with entity
 5280:  * references. This parameter is optional, so passing a NULL value is
 5281:  * allowed.
 5282:  * 
 5283:  * @return axl_true if the string contains non valid sequences that
 5284:  * must be escaped using entity references.
 5285:  */
 5286: axl_bool      axl_node_has_invalid_chars_cdata        (const char * content,
 5287: 						       int          content_size,
 5288: 						       int        * added_size)
 5289: {
 5290: 	/* call to internal implementation supposing this is for a
 5291: 	 * node with CDATA section */
 5292: 	return axl_node_has_invalid_chars_internal (content, content_size, added_size, axl_true);
 5293: }
 5294: 
 5295: /** 
 5296:  * @brief Allows to perform a copy from the content provided, doing an
 5297:  * xml character escaping for non allowed values (&, <, >, ' and ").
 5298:  *
 5299:  * This function must be used with \ref axl_node_has_invalid_chars to
 5300:  * check if the content has escapable chars an to get the additional
 5301:  * content that must be allocated by this function.
 5302:  *
 5303:  * Here is an example:
 5304:  * \code
 5305:  * char * content = "Some content with invalid chars & < >";
 5306:  * int    additional_size;
 5307:  * char * new_content
 5308:  *
 5309:  * if (axl_node_has_invalid_chars (content, strlen (content), &additional_size)) {
 5310:  *      // found that the string has invalid chars, escape them
 5311:  *      new_content = axl_node_content_copy_and_escape (content, strlen (content), additional_size);
 5312:  * } 
 5313:  *
 5314:  * \endcode
 5315:  * 
 5316:  * @param content The content to be escaped. If this parameter is
 5317:  * NULL, the function returns NULL.
 5318:  * 
 5319:  * @param content_size The content size for the first parameter.
 5320:  *
 5321:  * @param additional_size The additional size calculated from \ref axl_node_has_invalid_chars.
 5322:  *
 5323:  * @return A newly allocated string with all characters escaped. Use
 5324:  * \ref axl_free to dealloc the result.
 5325:  */
 5326: char * axl_node_content_copy_and_escape (const char * content, 
 5327: 					 int          content_size, 
 5328: 					 int          additional_size)
 5329: {
 5330: 	axl_return_val_if_fail (content, NULL);
 5331: 	
 5332: 	/* call to the internal implementation */
 5333: 	return __axl_node_content_copy_and_escape (content, content_size, additional_size, axl_false);
 5334: } 
 5335: 
 5336: /** 
 5337:  * @brief Allows to perform a copy for the content provided, doing an
 5338:  * xml character escaping for non allowed values (&, <, >, ' and ")
 5339:  * taking into consideration the content will be placed inside a
 5340:  * <![CDATA[..]]> declaration.
 5341:  *
 5342:  * This function must be used with \ref axl_node_has_invalid_chars_cdata to
 5343:  * check if the content has escapable chars an to get the additional
 5344:  * content that must be allocated by this function.
 5345:  *
 5346:  * Here is an example:
 5347:  * \code
 5348:  * char * content = "Some content with invalid chars & < >";
 5349:  * int    additional_size;
 5350:  * char * new_content
 5351:  *
 5352:  * if (axl_node_has_invalid_chars_cdata (content, strlen (content), &additional_size)) {
 5353:  *      // found that the string has invalid chars, escape them
 5354:  *      new_content = axl_node_content_copy_and_escape_cdata (content, strlen (content), additional_size);
 5355:  * } 
 5356:  * \endcode
 5357:  * 
 5358:  * @param content The content to be escaped. If this parameter is
 5359:  * null, the function returns NULL.
 5360:  * 
 5361:  * @param content_size The content size for the first parameter.
 5362:  *
 5363:  * @param additional_size The additional size calculated from \ref axl_node_has_invalid_chars_cdata.
 5364:  *
 5365:  * @return A newly allocated string with all characters escaped. Use
 5366:  * \ref axl_free to dealloc the result.
 5367:  */
 5368: char * axl_node_content_copy_and_escape_cdata (const char * content, 
 5369: 					       int          content_size, 
 5370: 					       int          additional_size)
 5371: {
 5372: 	axl_return_val_if_fail (content, NULL);
 5373: 	
 5374: 	/* call to the internal implementation */
 5375: 	return __axl_node_content_copy_and_escape (content, content_size, additional_size, axl_true);
 5376: } 
 5377: 
 5378: void __axl_node_free_internal (axlNode * node, axl_bool also_childs)
 5379: {
 5380: 	axlItem * item;
 5381: 	axlItem * itemAux;
 5382: 
 5383: 	axl_return_if_fail (node);
 5384: 
 5385: 	/* free current node */
 5386: 	if (node->name != NULL && ! (node->conf & NODE_NAME_FROM_FACTORY))
 5387: 		axl_free (node->name);
 5388: 
 5389: 	/* release memory hold by attributes */
 5390: 	if (node->attributes != NULL) {
 5391: 		if (node->attr_num <= 10)
 5392: 			__axl_node_free_attr_list ((axlNodeAttr *) node->attributes);
 5393: 		else 
 5394: 			axl_hash_free ((axlHash *) node->attributes);
 5395: 	}
 5396: 
 5397: 	/* release memory hold by childs */
 5398: 	if (node->first != NULL && also_childs) {
 5399: 		/* get the first item */
 5400: 		item = node->first;
 5401: 
 5402: 		/* foreach item stored */
 5403: 		while (item != NULL) {
 5404: 
 5405: 			/* get the next item */
 5406: 			itemAux = item->next;			
 5407: 
 5408: 			/* free the item */
 5409: 			axl_item_free (item, axl_true);
 5410: 			
 5411: 			/* update reference */
 5412: 			item = itemAux;
 5413: 
 5414: 		} /* end while */
 5415: 
 5416: 	} /* end if */
 5417: 
 5418: 	/* free the item itself */
 5419: 	if (node->holder != NULL) {
 5420: 		if ((node->holder->type & ITEM_FROM_FACTORY) == 0) {
 5421: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, 
 5422: 				   "item holder found to be not from a factory, dealloc reference=0x%x, node=0x%x, type=%d",
 5423: 				   node->holder, node, node->holder->type);
 5424: 			axl_free (node->holder);
 5425: 			node->holder = NULL;
 5426: 		}
 5427: 	}
 5428: 
 5429: 	/* do not free the node itself */
 5430: 	return;
 5431: }
 5432: 
 5433: /** 
 5434:  * @brief Destroy the given node provided by the reference.
 5435:  *
 5436:  * The function will check for nodes that are NULL references,
 5437:  * returning immediately.
 5438:  * 
 5439:  * @param node The node to destroy. 
 5440:  */
 5441: void axl_node_free (axlNode * node) 
 5442: {
 5443: 	axlHash * hash;
 5444: 	axl_return_if_fail (node);
 5445: 	
 5446: 	/* get a reference to the hash */
 5447: 	hash = node->annotate_data;
 5448: 
 5449: 	/* free internal content */
 5450: 	__axl_node_free_internal (node, axl_true);
 5451: 
 5452: 	/* free attributes */
 5453: 	if (! (node->conf & NODE_FROM_FACTORY))
 5454: 		axl_free (node);
 5455: 
 5456: 	/* annotate data deallocation must be done here because it is
 5457: 	 * used by the application user and the library to store
 5458: 	 * reference that could be pointing to internal structures
 5459: 	 * deallocated by the __axl_node_free_internal */
 5460: 	axl_hash_free (hash);
 5461: 
 5462: 	/* the node to release */
 5463: 	return;
 5464: }
 5465: 
 5466: /** 
 5467:  * @brief Allows to remove the provided node, optionally without
 5468:  * removing childs inside it.
 5469:  * 
 5470:  * @param node The node to deallocate.
 5471:  *
 5472:  * @param also_childs Signal the function to also dealloc childs or
 5473:  * not.
 5474:  */
 5475: void      axl_node_free_full       (axlNode * node, axl_bool also_childs)
 5476: {
 5477: 	axlHash * hash;
 5478: 	axl_return_if_fail (node);
 5479: 	
 5480: 	/* get a reference to the hash */
 5481: 	hash = node->annotate_data;
 5482: 
 5483: 	/* free node */
 5484: 	__axl_node_free_internal (node, axl_false);
 5485: 
 5486: 	/* free the node itself */
 5487: 	if (!(node->conf & NODE_FROM_FACTORY))
 5488: 		axl_free (node);
 5489: 
 5490: 	/* annotate data deallocation must be done here because it is
 5491: 	 * used by the application user and the library to store
 5492: 	 * reference that could be pointing to internal structures
 5493: 	 * deallocated by the __axl_node_free_internal */
 5494: 	axl_hash_free (hash);
 5495: 
 5496: 	return;
 5497: }
 5498: 
 5499: /**
 5500:  * @}
 5501:  */
 5502: 
 5503: /** 
 5504:  * \defgroup axl_node_attribute_cursor Axl Node Attribute iteration: An interface provided to iterate attribute nodes without knowing them.
 5505:  */
 5506: 
 5507: /** 
 5508:  * \addtogroup axl_node_attribute_cursor
 5509:  * @{
 5510:  */
 5511: 
 5512: 
 5513: /** 
 5514:  * @brief Allows to get a cursor to iterate attributes found in the
 5515:  * provided node in a linear and efficient way.
 5516:  *
 5517:  * The \ref axlAttrCursor could be used to iterate attributes
 5518:  * inside a particular node in an efficient way because it stores
 5519:  * current state (position), hiding all module details, providing
 5520:  * access to attributes without knowing them. Then using the following
 5521:  * functions you can modify the state (current position to get):
 5522:  * 
 5523:  *   - \ref axl_node_attr_cursor_first
 5524:  *   - \ref axl_node_attr_cursor_next
 5525:  *
 5526:  * Finally, the following functions are provided to get the key and
 5527:  * the value data associated to the current selected attribute,
 5528:  * pointed by the current status of the cursor:
 5529:  * 
 5530:  *   - \ref axl_node_attr_cursor_get_key (returns the key of the current attribute selected)
 5531:  *   - \ref axl_node_attr_cursor_get_value (returns the value of the current attribute selected)
 5532:  *
 5533:  * Here is an example:
 5534:  * \code
 5535:  * axlPointer           key;
 5536:  * axlPointer           value;
 5537:  * axlAttrCursor * cursor;
 5538:  * 
 5539:  * // create the cursor 
 5540:  * cursor   = axl_node_attr_cursor_new (node);
 5541:  *
 5542:  * // while there are more elements 
 5543:  * while (axl_node_attr_cursor_has_item (cursor)) {
 5544:  *
 5545:  *   // get the value and key
 5546:  *   key   = axl_node_attr_cursor_get_key   (cursor);
 5547:  *   value = axl_node_attr_cursor_get_value (cursor);
 5548:  *
 5549:  *   // get the next 
 5550:  *   axl_node_attr_cursor_next (cursor);
 5551:  *
 5552:  * } 
 5553:  *
 5554:  * // free the cursor 
 5555:  * axl_node_attr_cursor_free (cursor);
 5556:  * \endcode
 5557:  *
 5558:  * Once created the \ref axlAttrCursor you must release it and create
 5559:  * a new one if you modify your \ref axlNode attribute configuration
 5560:  * adding more items.
 5561:  * 
 5562:  * @param node The node that is requested to create the \ref
 5563:  * axlAttrCursor reference to iterate all attributes inside.
 5564:  * 
 5565:  * @return A newly created \ref axlAttrCursor used to iterate
 5566:  * attributes inside the node provided. Once finished you must call to
 5567:  * \ref axl_node_attr_cursor_free.
 5568:  */
 5569: axlAttrCursor * axl_node_attr_cursor_new       (axlNode * node)
 5570: {
 5571: 	axlAttrCursor * cursor;
 5572: 
 5573: 	axl_return_val_if_fail (node, NULL);
 5574: 
 5575: 	/* create and configure basics */
 5576: 	cursor        = axl_new (axlAttrCursor, 1);
 5577: 	cursor->node  = node;
 5578: 	cursor->count = node->attr_num;
 5579: 
 5580: 	/* according to the number of attributes configure the hash or
 5581: 	 * the linked attribte list */
 5582: 	if (cursor->count <= 10) {
 5583: 		/* just point to the first attribute (managed as AxlNodeAttr) */
 5584: 		cursor->data = node->attributes;		
 5585: 	} else {
 5586: 		/* create an axl hash cursor */
 5587: 		cursor->data = axl_hash_cursor_new ((axlHash *) node->attributes);
 5588: 	} /* end if */
 5589: 
 5590: 	/* return created cursor */
 5591: 	return cursor;
 5592: }
 5593: 
 5594: /** 
 5595:  * @brief Allows to configure the provided cursor to point to the
 5596:  * first attribute found inside the node.
 5597:  * 
 5598:  * @param cursor The cursor that is going to be configured.
 5599:  */
 5600: void                 axl_node_attr_cursor_first     (axlAttrCursor * cursor)
 5601: {
 5602: 	axl_return_if_fail (cursor);
 5603: 
 5604: 	/* check attribute configuration */
 5605: 	if (cursor->count != cursor->node->attr_num) {
 5606: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
 5607: 		return;
 5608: 	} /* end if */
 5609: 
 5610: 	if (cursor->count <= 10) {
 5611: 		/* just point to the first attribute (managed as AxlAttribute) */
 5612: 		cursor->data = cursor->node->attributes;		
 5613: 	} else {
 5614: 		/* make hash cursor to point to the first */ 
 5615: 		axl_hash_cursor_first (cursor->data);
 5616: 	} /* end if */
 5617: 	
 5618: 	return;
 5619: }
 5620: 
 5621: /** 
 5622:  * @brief Configures the provided attribute cursor to point to the
 5623:  * next attribute.
 5624:  * 
 5625:  * @param cursor The attribute cursor to be configured.
 5626:  */
 5627: void                 axl_node_attr_cursor_next      (axlAttrCursor * cursor)
 5628: {
 5629: 	axl_return_if_fail (cursor);
 5630: 
 5631: 	/* check attribute configuration */
 5632: 	if (cursor->count != cursor->node->attr_num) {
 5633: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
 5634: 		return;
 5635: 	} /* end if */
 5636: 
 5637: 	if (cursor->count <= 10) {
 5638: 		/* check null values */
 5639: 		if (cursor->data == NULL)
 5640: 			return;
 5641: 
 5642: 		/* just point to the first attribute (managed as AxlAttribute) */
 5643: 		cursor->data = ((axlNodeAttr *) cursor->data)->next;
 5644: 
 5645: 		return;
 5646: 	} /* end if */
 5647: 
 5648: 	/* make hash cursor to point to the first */ 
 5649: 	axl_hash_cursor_next (cursor->data);
 5650: 
 5651: 	
 5652: 	return;
 5653: }
 5654: 
 5655: /** 
 5656:  * @brief Allows to check if the is a next attribute, following
 5657:  * current attribute selected.
 5658:  * 
 5659:  * @param cursor The cursor to be configured.
 5660:  *
 5661:  * @return \ref axl_true if it has next element, otherwise \ref axl_false.
 5662:  */
 5663: axl_bool                 axl_node_attr_cursor_has_next  (axlAttrCursor * cursor)
 5664: {
 5665: 	axl_return_val_if_fail (cursor, axl_false);
 5666: 
 5667: 	if (cursor->count != cursor->node->attr_num) {
 5668: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
 5669: 		return axl_false;
 5670: 	} /* end if */
 5671: 
 5672: 	if (cursor->count <= 10) {
 5673: 		/* just point to the first attribute (managed as AxlAttribute) */
 5674: 		return (((axlNodeAttr *) cursor->data)->next) != NULL;
 5675: 	}  /* end if */
 5676: 	
 5677: 	/* make hash cursor to point to the first */ 
 5678: 	return axl_hash_cursor_has_next (cursor->data);
 5679: }
 5680: 
 5681: /** 
 5682:  * @brief Allows to check if the current position selected has an
 5683:  * attribute reference.
 5684:  * 
 5685:  * @param cursor The cursor that is being queried.
 5686:  *
 5687:  * @return \ref axl_true if it has item element, otherwise \ref axl_false.
 5688:  */
 5689: axl_bool                 axl_node_attr_cursor_has_item  (axlAttrCursor * cursor)
 5690: {
 5691: 	axl_return_val_if_fail (cursor, axl_false);
 5692: 
 5693: 	/* check attribute configuration */
 5694: 	if (cursor->count != cursor->node->attr_num) {
 5695: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
 5696: 		return axl_false;
 5697: 	} /* end if */
 5698: 
 5699: 	if (cursor->count <= 10) {
 5700: 		/* just point to the first attribute (managed as AxlAttribute) */
 5701: 		return cursor->data != NULL;
 5702: 	}  /* end if */
 5703: 	
 5704: 	/* make hash cursor to point to the first */ 
 5705: 	return axl_hash_cursor_has_item (cursor->data);
 5706: }
 5707: 
 5708: /** 
 5709:  * @brief Allows to get the attribute key associated to the current
 5710:  * attribute selected by the cursor.
 5711:  * 
 5712:  * @param cursor The cursor that is being queried.
 5713:  * 
 5714:  * @return A reference to the attribute key or NULL if it fails.
 5715:  */
 5716: const char *         axl_node_attr_cursor_get_key   (axlAttrCursor * cursor)
 5717: {
 5718: 	axl_return_val_if_fail (cursor, NULL);
 5719: 
 5720: 	/* check attribute configuration */
 5721: 	if (cursor->count != cursor->node->attr_num) {
 5722: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
 5723: 		return NULL;
 5724: 	} /* end if */
 5725: 
 5726: 	if (cursor->count <= 10) {
 5727: 		/* just point to the first attribute (managed as AxlAttribute) */
 5728: 		return ((axlNodeAttr *) cursor->data)->attribute;
 5729: 	}  /* end if */
 5730: 	
 5731: 	/* make hash cursor to point to the first */ 
 5732: 	return axl_hash_cursor_get_key (cursor->data);
 5733: }
 5734: 
 5735: /** 
 5736:  * @brief Allows to get the attribute value associated to the
 5737:  * attribute selected by the cursor.
 5738:  * 
 5739:  * @param cursor The cursor that is being queried.
 5740:  * 
 5741:  * @return A reference to the attribute value or NULL if it fails.
 5742:  */
 5743: const char *         axl_node_attr_cursor_get_value (axlAttrCursor * cursor)
 5744: {
 5745: 	axl_return_val_if_fail (cursor, NULL);
 5746: 
 5747: 	/* check attribute configuration */
 5748: 	if (cursor->count != cursor->node->attr_num) {
 5749: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
 5750: 		return NULL;
 5751: 	} /* end if */
 5752: 
 5753: 	if (cursor->count <= 10) {
 5754: 		/* just point to the first attribute (managed as AxlAttribute) */
 5755: 		return ((axlNodeAttr *) cursor->data)->value;
 5756: 	}  /* end if */
 5757: 	
 5758: 	/* make hash cursor to point to the first */ 
 5759: 	return axl_hash_cursor_get_value (cursor->data);	
 5760: }
 5761: 
 5762: /** 
 5763:  * @brief Allows to release \ref axlAttrCursor.
 5764:  * 
 5765:  * @param cursor The cursor to release.
 5766:  */
 5767: void                 axl_node_attr_cursor_free      (axlAttrCursor * cursor)
 5768: {
 5769: 	axl_return_if_fail (cursor);
 5770: 
 5771: 	/* free hash cursor */
 5772: 	if (cursor->count > 10)
 5773: 		axl_hash_cursor_free (cursor->data);
 5774: 
 5775: 	/* free the cursor */
 5776: 	axl_free (cursor);
 5777: 
 5778: 	return;
 5779: }
 5780: 
 5781: 
 5782: /** 
 5783:  * @internal Function that helps axl_node_attr_foreach to iterate all
 5784:  * attributes.
 5785:  */
 5786: axl_bool __axl_node_attr_foreach_aux (axlPointer key, axlPointer data, axlPointer user_data, axlPointer user_data2, axlPointer user_data3)
 5787: {
 5788: 	return ((axlNodeAttrForeachFunc) user_data) (key, data, user_data2, user_data3);
 5789: }
 5790: 
 5791: /** 
 5792:  * @brief Allows to provide a function which is called for each
 5793:  * attribute installed on the provided node.
 5794:  *
 5795:  * This function will allow you to operate on every attribute
 5796:  * installed, doing an foreach operation. This is an alternative API
 5797:  * to the \ref axlAttrCursor, which could be used to save allocations.
 5798:  * 
 5799:  * @param node The node for which the provided function will be called
 5800:  * for each attribute found.
 5801:  *
 5802:  * @param func The foreach function to be called.
 5803:  *
 5804:  * @param data User defined data to be passed to the foreach function.
 5805:  *
 5806:  * @param data2 Second user defined data to be passed to the foreach
 5807:  * function.
 5808:  */
 5809: void            axl_node_attr_foreach          (axlNode       * node, 
 5810: 						axlNodeAttrForeachFunc func, 
 5811: 						axlPointer      data,
 5812: 						axlPointer      data2)
 5813: {
 5814: 	axlNodeAttr * attr;
 5815: 	axl_return_if_fail (node);
 5816: 	axl_return_if_fail (func);
 5817: 	
 5818: 	/* if no attributes no foreach operation */
 5819: 	if (node->attributes == NULL)
 5820: 		return;
 5821: 
 5822: 	/* store the attribute using the general case */
 5823: 	if (node->attr_num < 11) {
 5824: 		/* handled as a simple list */
 5825: 		attr = (axlNodeAttr *) node->attributes;
 5826: 		while (attr != NULL) {
 5827: 			/* call to notify each attribute */
 5828: 			if (func (attr->attribute, attr->value, data, data2))
 5829: 				return;
 5830: 
 5831: 			/* get the next */
 5832: 			attr = attr->next;
 5833: 		} /* end while */
 5834: 	} else {
 5835: 		/* handled as a hash */
 5836: 		axl_hash_foreach3 ((axlHash *) node->attributes, __axl_node_attr_foreach_aux, func, data, data2);
 5837: 	} /* end if */
 5838: 
 5839: 	return;
 5840: }
 5841: 
 5842: /**
 5843:  * @}
 5844:  */
 5845: 
 5846: /**
 5847:  * \defgroup axl_item_module Axl Item: A basic item abstraction that represents a child node that could be another node, content, xml comment, etc.
 5848:  */
 5849: 
 5850: /** 
 5851:  * \addtogroup axl_item_module
 5852:  * @{
 5853:  */
 5854: 
 5855: /** 
 5856:  * @brief Allows to create an \ref axlItem, with the provided type and
 5857:  * holding the provided data.
 5858:  *
 5859:  * The function won't configure the parent node holding the
 5860:  * item. There is an alternative API that allows to create an \ref
 5861:  * axlItem without performing a copy: \ref axl_item_new_ref.
 5862:  *
 5863:  * @param type The type that will represent the \ref axlItem created.
 5864:  *
 5865:  * @param data Data associated to the axlItem. In the case the \ref
 5866:  * axlItem being created will represent content (\ref ITEM_CONTENT),
 5867:  * an entity ref (\ref ITEM_REF), a comment (\ref ITEM_COMMENT) or
 5868:  * cdata (\ref ITEM_CDATA), the function will create a local copy. In
 5869:  * the case of a \ref ITEM_NODE, the function will copy the entire
 5870:  * node, and all its childs.
 5871:  * 
 5872:  * @return A newly allocated \ref axlItem with no parent and holding
 5873:  * the data provided.
 5874:  */
 5875: axlItem     * axl_item_new             (AxlItemType type,
 5876: 					axlPointer  data)
 5877: {
 5878: 	axlItem        * item = NULL;
 5879: 	axlNode        * node;
 5880: 	axlNodeContent * content;
 5881: 
 5882: 	/* allocate an item type */
 5883: 	item         = axl_new (axlItem, 1);
 5884: 	item->type   = type;
 5885: 
 5886: 	switch (axl_item_get_type (item)) {
 5887: 	case ITEM_NODE:
 5888: 		/* item the node */
 5889: 		node                 = axl_node_copy (item->data, axl_true, axl_true);
 5890: 		node->holder         = item;
 5891: 		item->data           = node;
 5892: 		break;
 5893: 	case ITEM_CONTENT:
 5894: 	case ITEM_CDATA:
 5895: 	case ITEM_COMMENT:
 5896: 		/* item content */
 5897: 		content               = axl_new (axlNodeContent, 1);
 5898: 		content->content      = axl_strdup ((const char *) data);
 5899: 		content->content_size = strlen ((const char *) data);
 5900: 
 5901: 		/* item content */
 5902: 		item->data = content;
 5903: 		break;
 5904: 	case ITEM_PI:
 5905: 		/* item pi */
 5906: 		item->data = axl_pi_copy (data);
 5907: 		break;
 5908: 	case ITEM_REF:
 5909: 		/* not implemented yet */
 5910: 		break;
 5911: 	case ITEM_FROM_FACTORY:
 5912: 	case ITEM_CONTENT_FROM_FACTORY:
 5913: 		/* never reached */
 5914: 		break;
 5915: 	} /* end switch */
 5916: 
 5917: 	/* return item created */
 5918: 	return item;
 5919: }
 5920: 
 5921: /** 
 5922:  * @brief Allows to create an \ref axlItem, with the provided type and
 5923:  * holding the provided data.
 5924:  *
 5925:  * The function won't configure the parent node holding the item.
 5926:  *
 5927:  * @param type The type that will represent the \ref axlItem created.
 5928:  *
 5929:  * @param data Data associated to the axlItem. This function won't
 5930:  * perform any copy for the data received. The user calling to this
 5931:  * API must check that the data is only owned by the \ref axlItem
 5932:  * created (that is, used by this function).
 5933:  * 
 5934:  * @return A newly allocated \ref axlItem with no parent and holding
 5935:  * the data provided.
 5936:  */
 5937: axlItem     * axl_item_new_ref         (AxlItemType type,
 5938: 					axlPointer  data)
 5939: {
 5940: 	axlItem        * item = NULL;
 5941: 	axlNode        * node;
 5942: 	axlNodeContent * content;
 5943: 
 5944: 	/* allocate an item type */
 5945: 	item         = axl_new (axlItem, 1);
 5946: 	item->type   = type;
 5947: 
 5948: 	switch (axl_item_get_type (item)) {
 5949: 	case ITEM_NODE:
 5950: 		/* item the node */
 5951: 		node = data;
 5952: 		node->holder         = item;
 5953: 		item->data           = node;
 5954: 		break;
 5955: 	case ITEM_CONTENT:
 5956: 	case ITEM_CDATA:
 5957: 	case ITEM_COMMENT:
 5958: 		/* item content */
 5959: 		content               = axl_new (axlNodeContent, 1);
 5960: 		content->content      = data;
 5961: 		content->content_size = strlen ((const char *) data);
 5962: 
 5963: 		/* item content */
 5964: 		item->data = content;
 5965: 		break;
 5966: 	case ITEM_PI:
 5967: 		/* item pi */
 5968: 		item->data = data;
 5969: 		break;
 5970: 	case ITEM_REF:
 5971: 		/* not implemented yet */
 5972: 		break;
 5973: 	case ITEM_FROM_FACTORY:
 5974: 	case ITEM_CONTENT_FROM_FACTORY:
 5975: 		/* never reached */
 5976: 		break;
 5977: 	} /* end switch */
 5978: 
 5979: 	/* return item created */
 5980: 	return item;
 5981: }
 5982: 
 5983: 
 5984: /** 
 5985:  * @brief Allows to get the reference to the document that is holding
 5986:  * the provided item without taking into consideration the item type.
 5987:  * 
 5988:  * @param item The item that is required to return its document.
 5989:  * 
 5990:  * @return A reference to the \ref axlDoc that is holding the item.
 5991:  */
 5992: axlDoc  * axl_item_get_doc         (axlItem * item)
 5993: {
 5994: 	/* do not report an error since it is usual to have a node
 5995: 	 * without an item hold configured: for example after
 5996: 	 * axl_node_create */
 5997: 	if (item == NULL)
 5998: 		return NULL;
 5999: 
 6000: 	/* return the document reference */
 6001: 	return item->doc;
 6002: }
 6003: 
 6004: /** 
 6005:  * @internal Internal function that allows to configure the document
 6006:  * that is holding the item provided.
 6007:  * 
 6008:  * @param item The axlItem to be configured.
 6009:  * @param doc The axlDoc reference to configure.
 6010:  */
 6011: void      axl_item_set_doc         (axlItem * item, axlDoc * doc)
 6012: {
 6013: 	axl_return_if_fail (item);
 6014: 
 6015: 	/* configure document */
 6016: 	item->doc = doc;
 6017: 
 6018: 	return;
 6019: }
 6020: 
 6021: /** 
 6022:  * @brief Allows to get the parent that is containing the \ref axlItem
 6023:  * provider. The parent of a \ref axlItem is always a node.
 6024:  * 
 6025:  * @param item The \ref axlItem reference that is required to return
 6026:  * its parent.
 6027:  * 
 6028:  * @return A reference to the \ref axlNode.
 6029:  */
 6030: axlNode * axl_item_get_parent      (axlItem * item)
 6031: {
 6032: 	/* return that we don't have parent */
 6033: 	if (item == NULL)
 6034: 		return NULL;
 6035: 
 6036: 	/* return the parent */
 6037: 	return item->parent;
 6038: }
 6039: 
 6040: /** 
 6041:  * @brief Allows to get the following element that is next to the item
 6042:  * reference provided (\ref axlItem), and at the same level.
 6043:  * 
 6044:  * @param item The item that is required to return its next reference.
 6045:  * 
 6046:  * @return A reference to the next element or NULL if it fails or no
 6047:  * element is found next to the element provided.
 6048:  */
 6049: axlItem * axl_item_get_next        (axlItem * item)
 6050: {
 6051: 	axl_return_val_if_fail (item, NULL);
 6052: 
 6053: 	/* return the next element */
 6054: 	return item->next;
 6055: }
 6056: 
 6057: /** 
 6058:  * @brief Returns the following \ref axlItem to the \ref axlNode
 6059:  * reference, in the same level.
 6060:  * 
 6061:  * @param node The node that is required to return the following item
 6062:  * to it.
 6063:  * 
 6064:  * @return An reference to the following or NULL.
 6065:  */
 6066: axlItem * axl_item_node_next (axlNode * node)
 6067: {
 6068: 	axl_return_val_if_fail (node, NULL);
 6069: 
 6070: 	if (node->holder != NULL) {
 6071: 		/* return the next */
 6072: 		return node->holder->next;
 6073: 	}
 6074: 
 6075: 	/* no holder, no next */
 6076: 	return NULL;
 6077: 
 6078: }
 6079: 
 6080: /** 
 6081:  * @brief Allows to get the following element that is previous to the
 6082:  * item reference provided (\ref axlItem), and at the same level.
 6083:  * 
 6084:  * @param item The item that is required to return its previous
 6085:  * reference.
 6086:  * 
 6087:  * @return A reference to the previous element or NULL if it fails or
 6088:  * no element is found previous to the element provided.
 6089:  */
 6090: axlItem * axl_item_get_previous        (axlItem * item)
 6091: {
 6092: 	axl_return_val_if_fail (item, NULL);
 6093: 
 6094: 	/* return the previous element */
 6095: 	return item->previous;
 6096: }
 6097: 
 6098: /** 
 6099:  * @brief Returns the previous \ref axlItem to the \ref axlNode
 6100:  * reference, in the same level.
 6101:  * 
 6102:  * @param node The node that is required to return the previous item
 6103:  * to it.
 6104:  * 
 6105:  * @return An reference to the previous or NULL.
 6106:  */
 6107: axlItem * axl_item_node_previous (axlNode * node)
 6108: {
 6109: 	axl_return_val_if_fail (node, NULL);
 6110: 
 6111: 	if (node->holder != NULL) {
 6112: 		/* return the previousx */
 6113: 		return node->holder->previous;
 6114: 	}
 6115: 
 6116: 	/* no holder, no previous */
 6117: 	return NULL;
 6118: }
 6119: 
 6120: /** 
 6121:  * @brief Allows to get the \ref axlItem reference that is holding the
 6122:  * node provided.
 6123:  * 
 6124:  * @param node The node that is required to return its holding item.
 6125:  * 
 6126:  * @return The item reference or NULL if it fails or it isn't set.
 6127:  */
 6128: axlItem     * axl_item_node_holder     (axlNode * node)
 6129: {
 6130: 	axl_return_val_if_fail (node, NULL);
 6131: 
 6132: 	/* return the holder */
 6133: 	return node->holder;
 6134: }
 6135: 
 6136: /** 
 6137:  * @brief Allows to get the very first child item stored on the
 6138:  * provided \ref axlNode.
 6139:  *
 6140:  * This function is similar to \ref axl_node_get_first_child, but
 6141:  * returning the first \ref axlItem no matter its type.
 6142:  *
 6143:  * This function is mainly used inside the MIXED API where nodes are
 6144:  * expected to enclose content mixed with another xml nodes. See \ref
 6145:  * axl_node_get_first_child for more details.
 6146:  * 
 6147:  * @param node The \ref axlNode reference that is required to return
 6148:  * is first child reference (\ref axlItem).
 6149:  * 
 6150:  * @return The \ref axlItem reference or NULL if the axlNode is empty
 6151:  * (\ref axl_node_is_empty) and have no childs (\ref
 6152:  * axl_node_have_childs). The function also returns NULL if it fails
 6153:  * (when it receives a NULL reference).
 6154:  */
 6155: axlItem     * axl_item_get_first_child (axlNode * node)
 6156: {
 6157: 	/* check reference received */
 6158: 	axl_return_val_if_fail (node, NULL);
 6159: 
 6160: 	/* return the first item reference */
 6161: 	return node->first;
 6162: }
 6163: 
 6164: /** 
 6165:  * @brief Allows to get the very last child item stored on the
 6166:  * provided \ref axlNode.
 6167:  *
 6168:  * This function is similar to \ref axl_node_get_last_child, but
 6169:  * returning the last \ref axlItem no matter its type.
 6170:  *
 6171:  * This function is mainly used inside the MIXED API where nodes are
 6172:  * expected to enclose content mixed with another xml nodes. See \ref
 6173:  * axl_node_get_last_child for more details.
 6174:  * 
 6175:  * @param node The \ref axlNode reference that is required to return
 6176:  * is last child reference (\ref axlItem).
 6177:  * 
 6178:  * @return The \ref axlItem reference or NULL if the axlNode is empty
 6179:  * (\ref axl_node_is_empty) and have no childs (\ref
 6180:  * axl_node_have_childs). The function also returns NULL if it fails
 6181:  * (when it receives a NULL reference).
 6182:  */
 6183: axlItem     * axl_item_get_last_child  (axlNode * node) 
 6184: {
 6185: 	/* check reference received */
 6186: 	axl_return_val_if_fail (node, NULL);
 6187: 
 6188: 	/* return the last item reference */
 6189: 	return node->last;
 6190: }
 6191: 
 6192: /** 
 6193:  * @brief Allows to get the item type that represents the reference
 6194:  * received (\ref axlItem).
 6195:  *
 6196:  * Every \ref axlItem represents a particular content that could be
 6197:  * found inside an xml document parsed by the library (\ref
 6198:  * axlDoc). This function allows to return the type associated to the
 6199:  * element encapsulated by the \ref axlItem. See \ref AxlItemType for
 6200:  * more details.
 6201:  * 
 6202:  * @param item The reference that is required to return its type.
 6203:  * 
 6204:  * @return The type that is inside the reference or -1 if it fails.
 6205:  */
 6206: AxlItemType   axl_item_get_type        (axlItem * item)
 6207: {
 6208: 	/* return stored type */
 6209: 	return item->type & (~ (ITEM_FROM_FACTORY | ITEM_CONTENT_FROM_FACTORY));
 6210: }
 6211: 
 6212: /** 
 6213:  * @brief Returns the item data that is stored inside the \ref axlItem
 6214:  * received.
 6215:  *
 6216:  * According to the type that is representing the \ref axlItem
 6217:  * received, it will return a particular type. Check \ref AxlItemType
 6218:  * for more information.
 6219:  *
 6220:  * @param item The item that is required to return the data
 6221:  * encapsulated on it.
 6222:  * 
 6223:  * @return A pointer to the data stored, or NULL if it fails. The
 6224:  * pointer returned, in the case it is defined, mustn't be
 6225:  * released. It is a internal reference to the content.
 6226:  */
 6227: axlPointer axl_item_get_data (axlItem * item)
 6228: {
 6229: 	axl_return_val_if_fail (item, NULL);
 6230: 
 6231: 	/* return stored type */
 6232: 	return item->data;
 6233: }
 6234: 
 6235: /** 
 6236:  * @brief Convenience API that allows to get the content stored (and
 6237:  * its size) from the received \ref axlItem, supposing it is storing
 6238:  * an \ref ITEM_CONTENT, \ref ITEM_CDATA, \ref ITEM_COMMENT or \ref ITEM_REF.
 6239:  *
 6240:  * @param item The \ref axlItem that is supposed to store an item with
 6241:  * type: \ref ITEM_CONTENT, \ref ITEM_CDATA, \ref ITEM_COMMENT or \ref
 6242:  * ITEM_REF.
 6243:  *
 6244:  * @param size Optional variable reference. If defined, if returns the
 6245:  * content size.
 6246:  * 
 6247:  * @return An internal reference to the content stored and optionally
 6248:  * the content size notified on the variable received. In the case the
 6249:  * function receives an incompatible \ref axlItem (which is not \ref
 6250:  * ITEM_CONTENT, \ref ITEM_CDATA, \ref ITEM_COMMENT or \ref ITEM_REF),
 6251:  * the function will return NULL, and the optional variable will be
 6252:  * filled with -1.
 6253:  */
 6254: char        * axl_item_get_content     (axlItem * item, 
 6255: 					int     * size)
 6256: {
 6257: 	axlNodeContent * content;
 6258: 
 6259: 	/* check content received */
 6260: 	if (size != NULL)
 6261: 		*size = -1;
 6262: 	
 6263: 	/* check if the item reference is NULL */
 6264: 	axl_return_val_if_fail (item, 
 6265: 				NULL);
 6266: 	axl_return_val_if_fail (axl_item_get_type (item) != ITEM_NODE && axl_item_get_type (item) != ITEM_PI, 
 6267: 				NULL);
 6268: 
 6269: 	/* get the content */
 6270: 	content = item->data;
 6271: 
 6272: 	/* fill the size */
 6273: 	if (size != NULL)
 6274: 		*size = content->content_size;
 6275: 
 6276: 	/* return a pointer to the content */
 6277: 	return content->content;
 6278: }
 6279: 
 6280: /* prepare the item to be added to the xml document */
 6281: axlItem *  __axl_item_common_configure (axlNode * parent, AxlItemType type, axlPointer data)
 6282: {
 6283: 	axlNode * node = NULL;
 6284: 	axlItem * item = NULL;
 6285: 
 6286: 	/* return if the parent is defined */
 6287: 	axl_return_val_if_fail (parent, NULL);
 6288: 
 6289: 	/* check if the node received already have a pointer to a
 6290: 	 * holder created */
 6291: 	if (type & ITEM_NODE) {
 6292: 		/* get a reference to the node */
 6293: 		node = (axlNode *) data;
 6294: 
 6295: 		/* get a reference to the holder */
 6296: 		item = node->holder;
 6297: 
 6298: 		/* check if the current item was allocated from a
 6299: 		 * factory to ensure we don't loose that
 6300: 		 * information */
 6301: 		if ((item != NULL) && (item->type & ITEM_FROM_FACTORY)) 
 6302: 			type = type | ITEM_FROM_FACTORY;
 6303: 	}
 6304: 
 6305: 	/* create an item to hold the child, configuring the node, the
 6306: 	 * parent and the document */
 6307: 	if (item == NULL) {
 6308: 		if ((parent->holder != NULL) && (parent->holder->doc != NULL)) {
 6309: 			item = axl_item_factory_get (axl_doc_get_item_factory (parent->holder->doc));
 6310: 			type = type | ITEM_FROM_FACTORY; 
 6311: 		} else 
 6312: 			item   = axl_new (axlItem, 1);
 6313: 	}
 6314: 	item->type     = type;
 6315: 	item->data     = data;
 6316: 	item->doc      = (parent->holder != NULL) ? parent->holder->doc : NULL;
 6317: 
 6318: 	if (item->type & ITEM_NODE) {
 6319: 		/* now configure the item that will hold the new child */
 6320: 		node->holder  = item;
 6321: 	} /* end if */	
 6322: 	
 6323: 	/* return item created */
 6324: 	return item;
 6325: }
 6326: 
 6327: /** 
 6328:  * @internal Function that helps adding a new item to the provided
 6329:  * parent node.
 6330:  *
 6331:  * The new item will be added as flaged by the type provided. The
 6332:  * function isn't exposed to the public API because there are better
 6333:  * alternatives to add items to a \ref axlNode. Don't use this API
 6334:  * directly.
 6335:  * 
 6336:  * @param parent The axl node that will receive the new content.
 6337:  *
 6338:  * @param type The type to configure to the new item.
 6339:  *
 6340:  * @param data The data associated to the data being stored.
 6341:  *
 6342:  * NOTE: the function doesn't check data received as it is supposed to
 6343:  * receive calls from the library.
 6344:  */
 6345: void axl_item_set_child (axlNode * parent, AxlItemType type, axlPointer data)
 6346: {
 6347: 	axlItem * item;
 6348: 
 6349: 	/* prepare the item to be added to the xml document */
 6350: 	item = __axl_item_common_configure (parent, type, data);
 6351: 
 6352: 	/* call to set child with a created item */
 6353: 	axl_item_set_child_ref (parent, item);
 6354: 
 6355: 	return;
 6356: }
 6357: 
 6358: /** 
 6359:  * @brief Allows to configure xml content just after the item used as
 6360:  * reference.
 6361:  *
 6362:  * @param item The item used as reference to place the content after
 6363:  * it.
 6364:  *
 6365:  * @param type AxlItemType to configure the content to be placed.
 6366:  *
 6367:  * @param data Pointer that is associated to the type.
 6368:  */
 6369: void          axl_item_set_after       (axlItem * item,
 6370: 					AxlItemType type,
 6371: 					axlPointer data)
 6372: {
 6373: 	axlItem * new_item = NULL;
 6374: 
 6375: 	/* prepare the item to be added to the xml document */
 6376: 	new_item = __axl_item_common_configure (item->parent, type, data);
 6377: 
 6378: 	/* configure the parent node */
 6379: 	new_item->parent   = item->parent;
 6380: 
 6381: 	/* configure new item references */
 6382: 	new_item->previous = item;
 6383: 	new_item->next     = item->next;
 6384: 	
 6385: 	/* configure item references */
 6386: 	if (item->next != NULL)
 6387: 		item->next->previous = new_item;
 6388: 	else
 6389: 		item->parent->last  = new_item;
 6390: 	item->next = new_item;
 6391: 
 6392: 	return;
 6393: }
 6394: 
 6395: /* call to set child with a created item */
 6396: void axl_item_set_child_ref (axlNode * parent, axlItem * item)
 6397: {
 6398: 	axl_return_if_fail (parent);
 6399: 	axl_return_if_fail (item);
 6400: 
 6401: 	/* configure the parent node */
 6402: 	item->parent   = parent;
 6403: 
 6404: 	/* get the current last child */
 6405: 	if (parent->first == NULL) {
 6406: 		/* init first and last reference to the only one
 6407: 		 * child */
 6408: 		parent->first = item;
 6409: 		parent->last  = item;
 6410: 	}else {
 6411: 		/* configure the next item to the current last
 6412: 		 * child */
 6413: 		parent->last->next = item;
 6414: 
 6415: 		/* update the last child reference */
 6416: 		item->previous    = parent->last;
 6417: 		item->next        = NULL;
 6418: 		parent->last      = item;
 6419: 	}
 6420: 
 6421: 	return;
 6422: }
 6423: 
 6424: /** 
 6425:  * @brief Copy the reference provided creating a newly allocated
 6426:  * reference, including the content inside.
 6427:  * 
 6428:  * @param item The item to copy.
 6429:  *
 6430:  * @param set_parent Optionally, allows to provide the parent to be
 6431:  * configured to the item created. This is really required while
 6432:  * copying items that contains nodes.
 6433:  * 
 6434:  * @return A newly allocated \ref axlItem reference, containing the
 6435:  * same data (a deep copy) and optionally configured with the provided
 6436:  * parent.
 6437:  */
 6438: axlItem * axl_item_copy (axlItem * item, axlNode * set_parent)
 6439: {
 6440: 	axlItem        * copy;
 6441: 	axlNode        * node;
 6442: 	axlNodeContent * content;
 6443: 
 6444: 	/* check values received */
 6445: 	axl_return_val_if_fail (item, NULL);
 6446: 
 6447: 	/* allocate an copy type */
 6448: 	copy         = axl_new (axlItem, 1);
 6449: 	copy->type   = axl_item_get_type (item);
 6450: 	copy->parent = set_parent;
 6451: 
 6452: 	switch (axl_item_get_type (item)) {
 6453: 	case ITEM_NODE:
 6454: 		/* copy the node */
 6455: 		node                 = axl_node_copy (item->data, axl_true, axl_true);
 6456: 		node->holder         = copy;
 6457: 		copy->data           = node;
 6458: 		break;
 6459: 	case ITEM_CONTENT:
 6460: 	case ITEM_CDATA:
 6461: 	case ITEM_COMMENT:
 6462: 		/* copy content */
 6463: 		content               = axl_new (axlNodeContent, 1);
 6464: 		content->content      = axl_strdup (((axlNodeContent * ) item->data)->content);
 6465: 		content->content_size = ((axlNodeContent * ) item->data)->content_size;
 6466: 
 6467: 		/* copy content */
 6468: 		copy->data = content;
 6469: 		break;
 6470: 	case ITEM_PI:
 6471: 		/* copy pi */
 6472: 		copy->data = axl_pi_copy (item->data);
 6473: 		break;
 6474: 	case ITEM_REF:
 6475: 		/* not implemented yet */
 6476: 		break;
 6477: 	case ITEM_FROM_FACTORY:
 6478: 	case ITEM_CONTENT_FROM_FACTORY:
 6479: 		/* never reached */
 6480: 		break;
 6481: 	} /* end switch */
 6482: 
 6483: 	/* return copy created */
 6484: 	return copy;
 6485: }
 6486: 
 6487: /** 
 6488:  * @brief Allows to remove the \ref axlItem instance from the document
 6489:  * that is currently holding it, optionally deallocating the memory
 6490:  * used by the structure.
 6491:  * 
 6492:  * @param item The item to remove from its container (without taking
 6493:  * into consideration the item type).
 6494:  *
 6495:  * @param dealloc Deallocs the memory used by the \ref axlItem
 6496:  * reference.
 6497:  */
 6498: void          axl_item_remove          (axlItem   * item,
 6499: 					axl_bool    dealloc)
 6500: {
 6501: 
 6502: 	/* free the item */
 6503: 	axl_return_if_fail (item);
 6504: 
 6505: 	/* realloc references */
 6506: 	if (item->previous != NULL)
 6507: 		item->previous->next = item->next;
 6508: 
 6509: 	if (item->next != NULL)
 6510: 		item->next->previous = item->previous;
 6511: 
 6512: 	/* realloc parent references in the case of a node */
 6513: 	if (axl_item_get_type (item) == ITEM_NODE) {
 6514: 		if (item->previous == NULL)
 6515: 			item->parent->first = item->next;
 6516: 
 6517: 		if (item->next == NULL)
 6518: 			item->parent->last  = item->previous;
 6519: 	} /* end if */
 6520: 	
 6521: 	/* free the item */
 6522: 	item->next     = NULL;
 6523: 	item->previous = NULL;
 6524: 
 6525: 	if (dealloc) {
 6526: 		axl_item_free (item, axl_true);
 6527: 	} /* end if */
 6528: 
 6529: 	return;
 6530: 
 6531: } /* end axl_item_remove */
 6532: 
 6533: /** 
 6534:  * @brief Allows to replace the content held by the \ref axlItem
 6535:  * reference with a new \ref axlItem, updating all references, and
 6536:  * optionally, deallocating the memory used by the previous item
 6537:  * reference.
 6538:  * 
 6539:  * @param item The item to be replaced.
 6540:  *
 6541:  * @param new_item The new item to be placed where the previous one is
 6542:  * located.
 6543:  *
 6544:  * @param dealloc Signal to function to dealloc the memory hold the
 6545:  * the item replaced.
 6546:  */
 6547: void          axl_item_replace        (axlItem  * item, 
 6548: 				       axlItem  * new_item,
 6549: 				       axl_bool   dealloc)
 6550: {
 6551: 	/* free the item */
 6552: 	axl_return_if_fail (item);
 6553: 	axl_return_if_fail (new_item);
 6554: 
 6555: 	/* realloc references */
 6556: 	if (item->previous != NULL) {
 6557: 		item->previous->next = new_item;
 6558: 		new_item->previous   = item->previous;
 6559: 	}
 6560: 
 6561: 	if (item->next != NULL) {
 6562: 		item->next->previous = new_item;
 6563: 		new_item->next       = item->next;
 6564: 	}
 6565: 
 6566: 	/* realloc parent references in the case of a node */
 6567: 	if (axl_item_get_type (item) == ITEM_NODE) {
 6568: 		if (item->previous == NULL)
 6569: 			item->parent->first = new_item;
 6570: 
 6571: 		if (item->next == NULL)
 6572: 			item->parent->last = new_item;
 6573: 	} /* end if */
 6574: 
 6575: 	/* free the item */
 6576: 	item->next     = NULL;
 6577: 	item->previous = NULL;
 6578: 
 6579: 	/* configure values */
 6580: 	new_item->parent = item->parent;
 6581: 	new_item->doc    = item->doc;
 6582: 
 6583: 	if (dealloc) {
 6584: 		axl_item_free (item, axl_true);
 6585: 
 6586: 	} /* end if */
 6587: 
 6588: 	return;
 6589: 
 6590: } /* end axl_item_replace */
 6591: 
 6592: /** 
 6593:  * @brief Allows to transfer all childs contained inside the provided
 6594:  * \ref axlNode (old_parent) placed after the provided axlItem
 6595:  * (item_ref) on the same level.
 6596:  *
 6597:  * This function allows to manipulate a xml document loaded inside
 6598:  * memory, by transfering all childs (including xml nodes, xml
 6599:  * comments, content, process instructions and entity references) from
 6600:  * the selected parent (the old parent) provided by the
 6601:  * <i>old_parent</i> attribute, to be placed at the same level, where
 6602:  * the <i>item_ref</i> is situated following it.
 6603:  *
 6604:  * 
 6605:  * @param old_parent Previous parent, where the childs to be
 6606:  * transfered will be found.
 6607:  *
 6608:  * @param item_ref The \ref axlItem that will act as a reference
 6609:  * placing all childs following the item.
 6610:  */
 6611: void          axl_item_transfer_childs_after (axlNode * old_parent,
 6612: 					      axlItem * item_ref)
 6613: {
 6614: 	axlItem * item;
 6615: 	axlItem * item_aux;
 6616: 
 6617: 	/* get the first child for the old parent */
 6618: 	item = old_parent->first;
 6619: 
 6620: 	/* check if the parent node contains childs to be
 6621: 	 * transferred. If no child is found, just return */
 6622: 	if (item == NULL)
 6623: 		return;
 6624: 
 6625: 	/* remember previous next */
 6626: 	item_aux       = item_ref->next;
 6627: 	
 6628: 	/* make the first child to follow the item ref */
 6629: 	item_ref->next = item;
 6630: 	item->previous = item_ref;
 6631: 
 6632: 	/* set the next at the end of all items transferred, and the
 6633: 	 * new parent node */
 6634: 	while (item != NULL) {
 6635: 		/* configure the new parent */
 6636: 		item->parent = item_ref->parent;
 6637: 
 6638: 		/* check the item to be the last */
 6639: 		if (item->next == NULL) {
 6640: 			/* the last item was found, configure it */
 6641: 			item->next = item_aux;
 6642: 
 6643: 			/* configure it to point to the last item
 6644: 			 * transferred */
 6645: 			if (item_aux != NULL)
 6646: 				item_aux->previous = item;
 6647: 
 6648: 			/* break the loop! */
 6649: 			break;
 6650: 		} /* end if */
 6651: 
 6652: 		/* get the next */
 6653: 		item = item->next;
 6654: 		
 6655: 	} /* end while */
 6656: 
 6657: 	/* check that the item selected to be reference isn't the last
 6658: 	 * child inside new parent node. If it is, update the new
 6659: 	 * last */
 6660: 	if (item_aux == NULL) {
 6661: 		/* because item is pointing to the last item in the
 6662: 		 * level, use it as the new last */
 6663: 		item->parent->last = item;
 6664: 	} /* end if */
 6665: 
 6666: 	/* clear reference from previous parent */
 6667: 	old_parent->first     = NULL;
 6668: 	old_parent->last      = NULL;
 6669: 
 6670: 	return;
 6671: }
 6672: 
 6673: /** 
 6674:  * @brief Allows to check if both items are equal, considering the
 6675:  * item type and the content associated to the item type.
 6676:  *
 6677:  * @param item The first item to check.
 6678:  *
 6679:  * @param item2 The second item to check.
 6680:  * 
 6681:  * @param trimmed This paramenter allows to configure how the equal
 6682:  * check is performed for content element (\ref ITEM_CONTENT, \ref
 6683:  * ITEM_CDATA, \ref ITEM_COMMENT and \ref ITEM_REF).
 6684:  *
 6685:  * @param error Optional \ref axlError reference where textual
 6686:  * diagnostic is reported.
 6687:  *
 6688:  *
 6689:  * @return \ref axl_true if the both items represents the same
 6690:  * information, otherwise \ref axl_false is returned. If the function
 6691:  * receives a null value it will return axl_false.
 6692:  */
 6693: axl_bool          axl_item_are_equal_full      (axlItem    * item,
 6694: 						axlItem    * item2,
 6695: 						axl_bool     trimmed,
 6696: 						axlError  ** error)
 6697: {
 6698: 	axlNodeContent * content;
 6699: 	axlNodeContent * content2;
 6700: 
 6701: 	/* trim content */
 6702: 	char           * trim;
 6703: 	char           * trim2;
 6704: 	axl_bool         result;
 6705: 	
 6706: 	axl_return_val_if_fail (item, axl_false);
 6707: 	axl_return_val_if_fail (item2, axl_false);
 6708: 
 6709: 	/* basic type check */
 6710: 	if (axl_item_get_type (item) != axl_item_get_type (item2)) {
 6711: 		axl_error_report (error, -1, "Items types differs (%d != %d)", 
 6712: 				  axl_item_get_type (item), axl_item_get_type (item2));
 6713: 		return axl_false;
 6714: 	}
 6715: 
 6716: 	/* according the type */
 6717: 	switch (axl_item_get_type (item)) {
 6718: 	case ITEM_NODE:
 6719: 		/* check that both nodes are equal */
 6720: 		return axl_node_are_equal_full (item->data, item2->data, error);
 6721: 	case ITEM_CONTENT:
 6722: 	case ITEM_CDATA:
 6723: 	case ITEM_COMMENT:
 6724: 	case ITEM_REF:
 6725: 		/* get the contenet */
 6726: 		content  = item->data;
 6727: 		content2 = item2->data;
 6728: 
 6729: 		if (! trimmed) {
 6730: 			/* check first content length */
 6731: 			if (content->content_size != content2->content_size) {
 6732: 				axl_error_report (error, -1, "Items content size differs (%s:%d != %s:%d)", 
 6733: 						  content->content, 
 6734: 						  content->content_size, 
 6735: 						  content2->content,
 6736: 						  content2->content_size);
 6737: 				return axl_false;
 6738: 			}
 6739: 			
 6740: 			/* now check content value */
 6741: 			return axl_cmp (content->content, content2->content);
 6742: 		}else {
 6743: 			/* duplicate the content */
 6744: 			trim = axl_strdup (content->content);
 6745: 			trim2 = axl_strdup (content2->content);
 6746: 
 6747: 			/* trim content */
 6748: 			axl_stream_trim (trim);
 6749: 			axl_stream_trim (trim2);
 6750: 
 6751: 			/* do the comparision */
 6752: 			result = axl_cmp (trim, trim2);
 6753: 
 6754: 			if (! result) {
 6755: 				axl_error_report (error, -1, "Trimmed content differs ('%s' != '%s')", trim, trim2);
 6756: 			} /* end if */
 6757: 
 6758: 			/* free data */
 6759: 			axl_free (trim);
 6760: 			axl_free (trim2);
 6761: 			
 6762: 			return result;
 6763: 
 6764: 		}
 6765: 	case ITEM_PI:
 6766: 		/* pi case */
 6767: 		return axl_pi_are_equal (item->data, item2->data);
 6768: 	default:
 6769: 		/* no case identified, not equal */
 6770: 		break;
 6771: 	} /* end switch */
 6772: 	
 6773: 	axl_error_report (error, -1, "Item type not found, unable to check");
 6774: 	return axl_false;
 6775: }
 6776: 
 6777: /** 
 6778:  * @brief Allows to check if both items are equal, considering the
 6779:  * item type and the content associated to the item type.
 6780:  *
 6781:  *
 6782:  * @param item The first item to check.  
 6783:  *
 6784:  * @param item2 The second item to check.
 6785:  *
 6786:  * @param trimmed This paramenter allows to configure how equal
 6787:  * checking is performed for content element (\ref ITEM_CONTENT, \ref
 6788:  * ITEM_CDATA, \ref ITEM_COMMENT and \ref ITEM_REF).
 6789:  *
 6790:  * @return \ref axl_true if the both items represents the same
 6791:  * information, otherwise \ref axl_false is returned. If the function
 6792:  * receives a null value it will return axl_false.
 6793:  */
 6794: axl_bool          axl_item_are_equal      (axlItem   * item,
 6795: 					   axlItem   * item2,
 6796: 					   axl_bool    trimmed)
 6797: {
 6798: 	/* call to check if both items are equal */
 6799: 	return axl_item_are_equal_full (item, item2, trimmed, NULL);
 6800: }
 6801: 
 6802: /** 
 6803:  * @brief Allows to release the memory hold the item reference
 6804:  * provided, and the value stored inside it.
 6805:  * 
 6806:  * @param item The item to dealloc.
 6807:  *
 6808:  * @param dealloc \ref axl_true to also dealloc the value inside.
 6809:  */
 6810: void          axl_item_free           (axlItem  * item,
 6811: 				       axl_bool   dealloc)
 6812: {
 6813: 	axl_return_if_fail (item);
 6814: 
 6815: 	
 6816: 	/* according the type */
 6817: 	switch (axl_item_get_type (item)) {
 6818: 	case ITEM_NODE:
 6819: 		/* free the node */
 6820: 		axl_node_free (item->data);
 6821: 		break;
 6822: 	case ITEM_CONTENT:
 6823: 	case ITEM_CDATA:
 6824: 	case ITEM_COMMENT:
 6825: 	case ITEM_REF:
 6826: 		/* all of them, managed equally */
 6827: 
 6828: 		/* check and free content */
 6829: 		if ((item->type & ITEM_CONTENT_FROM_FACTORY) == 0) {
 6830: 			axl_free (((axlNodeContent *)item->data)->content);
 6831: 
 6832: 			/* free node */
 6833: 			axl_free ((axlNodeContent *)item->data);
 6834: 		}
 6835: 		
 6836: 		if ((item->type & ITEM_FROM_FACTORY) == 0)
 6837: 			axl_free (item);
 6838: 		break;
 6839: 	case ITEM_PI:
 6840: 		/* an process instruction */
 6841: 		axl_pi_free (item->data);
 6842: 		
 6843: 		/* free the item */
 6844: 		if ((item->type & ITEM_FROM_FACTORY) == 0)
 6845: 			axl_free (item);
 6846: 		break;
 6847: 	case ITEM_FROM_FACTORY:
 6848: 	case ITEM_CONTENT_FROM_FACTORY:
 6849: 		/* never reached */
 6850: 		break;
 6851: 		
 6852: 	} /* end switch */
 6853: 
 6854: 
 6855: 	return;
 6856: }
 6857: 
 6858: axlFactory * axl_item_factory_create (void)
 6859: {
 6860: 	return axl_factory_create (sizeof (axlItem));
 6861: }
 6862: 
 6863: axlItem        * axl_item_factory_get (axlFactory * factory)
 6864: {
 6865: 	return axl_factory_get (factory);
 6866: }
 6867: 
 6868: axlFactory * axl_node_factory_create (void)
 6869: {
 6870: 	return axl_factory_create (sizeof (axlNode));
 6871: }
 6872: 
 6873: axlNode    * axl_node_factory_get (axlFactory * factory)
 6874: {
 6875: 	/* get a node */
 6876: 	axlNode * node = axl_factory_get (factory);
 6877: 	
 6878: 	/* configure it */
 6879: 	node->conf = NODE_FROM_FACTORY;
 6880: 
 6881: 	return node;
 6882: }
 6883: 
 6884: axlFactory     * axl_item_content_factory_create (void)
 6885: {
 6886: 	/* create a factory for axlNodeContent elements */
 6887: 	return axl_factory_create (sizeof (axlNodeContent));
 6888: }
 6889: 
 6890: axlFactory     * axl_item_attr_factory_create (void)
 6891: {
 6892: 	/* create a factory for axlNodeAttr elements */
 6893: 	return axl_factory_create (sizeof (axlNodeAttr));
 6894: }
 6895: 
 6896: /* @} */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>