File:  [ELWIX - Embedded LightWeight unIX -] / gpl / axl / src / axl_dtd.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: #include <axl_decl.h>
   40: #include <axl.h>
   41: 
   42: #define LOG_DOMAIN "axl-dtd"
   43: 
   44: struct _axlDtdElementListNode {
   45: 	NodeType     type;
   46: 	AxlDtdTimes  times;
   47: 	axlPointer   data;
   48: };
   49: 
   50: struct _axlDtdElementList {
   51: 	/** 
   52: 	 * @brief Allows to configure how is given top level
   53: 	 * configuration for nodes to be defined inside the xml
   54: 	 * document being configured. As defined in the XML 1.0
   55: 	 * Recomendation, available top level choices are: choice or
   56: 	 * sequence. 
   57: 	 *
   58: 	 * They allow to configure allowed nodes to be selected as
   59: 	 * childs, from a set of node names, called choice or to
   60: 	 * configure which are the set of nodes to be used, in a
   61: 	 * particular order, called sequence.
   62: 	 *
   63: 	 * This variable allows to configure which is the top level
   64: 	 * section configuration: either a choice or a sequence.
   65: 	 *
   66: 	 * Keep in mind that, having only one element inside the
   67: 	 * itemList, there is no difference between the sequence and
   68: 	 * the choice.
   69: 	 */
   70: 	AxlDtdNestedType      type;
   71: 	
   72: 	/** 
   73: 	 * @brief Allows to configure how many times is repeated a
   74: 	 * selection provided (by this element).
   75: 	 */
   76: 	AxlDtdTimes           times;
   77: 
   78: 	/** 
   79: 	 * @brief Item list, which contains more axlDtdElementList
   80: 	 * nodes, configuring elements allowed.
   81: 	 */
   82: 	axlList             * itemList;
   83: };
   84: 
   85: struct _axlDtdElement {
   86: 	/** 
   87: 	 * @brief The document type element declaration name. This is
   88: 	 * the name of the xml node being constrained.
   89: 	 */
   90: 	char                * name;
   91: 
   92: 	/** 
   93: 	 * @brief This is the type of the xml node being constrained.
   94: 	 */
   95: 	AxlDtdElementType     type;
   96: 	/** 
   97: 	 * @brief List of available items.
   98: 	 * 
   99: 	 * This variable holds current top level list selection. See
  100: 	 * axlDtdElementList.type variable.
  101: 	 */
  102: 	axlDtdElementList   * list;
  103: 
  104: 	/** 
  105: 	 * @brief Minimum item list count to be matched while using
  106: 	 * this DTD element rule.
  107: 	 */
  108: 	int                    minimum_match;
  109: };
  110: 
  111: struct _axlDtdAttributeDecl {
  112: 	/** 
  113: 	 * @brief Attribute name. This is the attribute value defined
  114: 	 * for the node.
  115: 	 */
  116: 	char                     * name;
  117: 	
  118: 	/** 
  119: 	 * @brief This is the attribute declaration type. It shows if 
  120: 	 */
  121: 	AxlDtdAttributeType        type;
  122: 
  123: 	/** 
  124: 	 * @brief Allows to model whoe is 
  125: 	 */
  126: 	AxlDtdAttributeDefaults    defaults;
  127: 	
  128: 	/** 
  129: 	 * @brief This is a default value for the <!ATTLIST
  130: 	 * declaration received, in the case a FIXED value is required
  131: 	 * or a default value is declarted.
  132: 	 */
  133: 	char                     * default_value;
  134: 
  135: 	/** 
  136: 	 * @brief Internal declaration for enum values defined for
  137: 	 * this rule. This list is only initialized in the case enum
  138: 	 * values are defined.
  139: 	 */
  140: 	axlList                  * enumvalues;
  141: 
  142: };
  143: 
  144: struct _axlDtdAttribute {
  145: 	/** 
  146: 	 * @brief The document attribute list declaration name. This
  147: 	 * is the name of the node that will receive the constrain
  148: 	 * defined.
  149: 	 */
  150: 	char           * name;
  151: 	
  152: 	/** 
  153: 	 * @brief This is the list of constrains defined for the
  154: 	 * node. It as list of \ref axlDtdAttributeDecl which defines
  155: 	 * the attribute that is declarted, if it is required, and the
  156: 	 * type of its content.
  157: 	 */
  158: 	axlList        * list;
  159: };
  160: 
  161: struct _axlDtdEntityExternalData {
  162: 	/** 
  163: 	 * @brief Contains the system literal reference. This is a URI
  164: 	 * reference to the resource pointed by the \ref axlDtdEntity
  165: 	 * definition.
  166: 	 */
  167: 	char * system_literal;
  168: 	/** 
  169: 	 * @brief Contains the public literal information associated
  170: 	 * to the entity definition.
  171: 	 */
  172: 	char * public_literal;
  173: 	/** 
  174: 	 * @brief Contains the NDATA information (a notation name
  175: 	 * reference).
  176: 	 */
  177: 	char * ndata;
  178: };
  179: 
  180: struct _axlDtdEntity {
  181: 	/** 
  182: 	 * @brief Contains the entity name.
  183: 	 */
  184: 	char           * name;
  185: 	
  186: 	/** 
  187: 	 * @brief Contains the entity type.
  188: 	 */
  189: 	axlDtdEntityType type;
  190: 
  191: 	/** 
  192: 	 * @brief Content of the entity definition ([9] EntityValue).
  193: 	 */
  194: 	char           * content;
  195: 	
  196: 	/** 
  197: 	 * @brief An entity definition can have a reference to a
  198: 	 * external resource. The following pointer contains
  199: 	 * information for the external resource pointed.
  200: 	 */
  201: 	axlDtdEntityExternalData * data;
  202: };
  203: 
  204: struct _axlDtd {
  205: 	/** 
  206: 	 * @brief Holds all entity definitions inside the DTD
  207: 	 * declaration (<!ENTITY..>).
  208: 	 */
  209: 	axlList       * entities;
  210: 
  211: 	/** 
  212: 	 * @brief All elements inside the DTD declaration
  213: 	 * (<!ELEMENT..> ).
  214: 	 */
  215: 	axlList       * elements;
  216: 
  217: 	/** 
  218: 	 * @brief All attribute type declerations inside the DTD
  219: 	 * (<!ATTLIST..>)
  220: 	 */
  221: 	axlList       * attributes;
  222: 
  223: 	/** 
  224: 	 * @brief The element root, for the given DTD declaration.
  225: 	 */
  226: 	axlDtdElement * root;
  227: 
  228: 	/** 
  229: 	 * @brief Internal flag that allows to notify that the DTD
  230: 	 * contains ID attribute declaration, making the DTD this
  231: 	 * references. 
  232: 	 */
  233: 	axl_bool       haveIdDecl;
  234: 
  235: 	/** 
  236: 	 * @brief Flag that the dtd declaration have attributes which
  237: 	 * are flaged as IDREF.
  238: 	 */
  239: 	axl_bool      haveIdRefDecl;
  240: };
  241: 
  242: /**
  243:  * \defgroup axl_dtd_module Axl DTD: Document type declaration interface (functions, validation, and DTD parsing)
  244:  */
  245: 
  246: 
  247: /** 
  248:  * \addtogroup axl_dtd_module
  249:  * @{
  250:  */
  251: 
  252: 
  253: /** 
  254:  * @internal
  255:  *
  256:  * Allows to create a new dtd element list item, which represents a
  257:  * content particule inside an item list or a item list. This allows
  258:  * the recursion defined on the XML 1.0 standard.
  259:  *
  260:  * The function receives the node name and a reference list. According
  261:  * to the values the function creates a node which contains a leaf
  262:  * value or a node which contains a reference to the a new list which
  263:  * is nested.
  264:  */
  265: axlDtdElementListNode * __create_axl_dtd_element_list (char * node_name,
  266: 						       axlDtdElementList * list)
  267: {
  268: 	axlDtdElementListNode * node;
  269: 
  270: 	node = axl_new (axlDtdElementListNode, 1);
  271: 
  272: 	/* create a node element reference */
  273: 	if (node_name != NULL) {
  274: 		node->data = node_name;
  275: 		node->type = AXL_ELEMENT_NODE;
  276: 		return node;
  277: 	}
  278: 
  279: 	/* create an element list reference */
  280: 	if (list != NULL) {
  281: 		node->data = list;
  282: 		node->type = AXL_ELEMENT_LIST;
  283: 		return node;
  284: 	}
  285: 
  286: 	/* if another type is requested, return NULL */
  287: 	return NULL;
  288: }
  289: 
  290: /** 
  291:  * @internal
  292:  *
  293:  * Support function used to destroy all items stored on a item list.
  294:  * 
  295:  * @param node 
  296:  */
  297: void __destroy_axl_dtd_element_list (axlDtdElementListNode * node)
  298: {
  299: 	if (node == NULL)
  300: 		return;
  301: 	/* free the reference to the leaf node if defined */
  302: 	if (node->type == AXL_ELEMENT_NODE)
  303: 		axl_free (node->data);
  304: 	
  305: 	/* do not do nothing if the reference is not element list */
  306: 	if (node->type == AXL_ELEMENT_LIST)
  307: 		axl_dtd_item_list_free (node->data);
  308: 
  309: 	/* free de node itself */
  310: 	axl_free (node);
  311: 	return;
  312: }
  313: 
  314: /** 
  315:  * @internal
  316:  *
  317:  * @brief Support function to \ref axl_dtd_parse which creates a new
  318:  * empty DTD reference.
  319:  * 
  320:  * 
  321:  * @return A newly allocated \ref axlDtd reference.
  322:  */
  323: axlDtd * __axl_dtd_new (void)
  324: {
  325: 	axlDtd * dtd;
  326: 
  327: 	/* create the DTD element and nothing else. The rest of items
  328: 	 * created on demand */
  329: 	dtd           = axl_new (axlDtd, 1);
  330: 
  331: 	return dtd;
  332: }
  333: 
  334: axl_bool __queue_items (axlPointer data, axlPointer _stack)
  335: {
  336: 	axlStack * stack = _stack;
  337: 
  338: 	/* queue the data */
  339: 	axl_stack_push (stack, data);
  340: 
  341: 	/* return axl_false to make the function to not stop */
  342: 	return axl_false;
  343: }
  344: 
  345: void __axl_dtd_queue_childs (axlStack * stack, axlNode * parent)
  346: {
  347: 	axlNode * child;
  348: 
  349: 	/* get the first child */
  350: 	child = axl_node_get_first_child (parent);
  351: 	while (child != NULL) {
  352: 
  353: 		/* queue the child */
  354: 		axl_stack_push (stack, child);
  355: 		
  356: 		/* get the next child */
  357: 		child = axl_node_get_next (child);
  358: 	} /* end while */
  359: 
  360: 	return;
  361: }
  362: 
  363: /** 
  364:  * @internal
  365:  *
  366:  * Support internal function which allows to queue all items inside an
  367:  * axlDtdElementList to be checked.
  368:  * 
  369:  * @param stack The stack where all data will be placed.
  370:  *
  371:  * @param dtd_element_list The dtd element list where the data will be
  372:  * extracted.
  373:  */
  374: void __axl_dtd_queue_items (axlStack * stack, axlList * list) 
  375: {
  376: 	/* call to queue items */
  377: 	axl_list_lookup (list, __queue_items, stack);
  378: 
  379: 	/* nothing more */
  380: 	return;
  381: }
  382: 
  383: /** 
  384:  * @internal
  385:  *
  386:  * Support function which allows to check if the provided two dtd
  387:  * elements are in fact, parent and child.
  388:  *
  389:  * DTD element have a parent-child relation based in the fact that the
  390:  * first define top level xml nodes that are followed, in the form of
  391:  * childs nodes, by other DTD elements that define more childs, etc...
  392:  *
  393:  * This function allows to check if the provided parent dtd element
  394:  * have references inside its content specification that proves that
  395:  * it is indeed a parent definition.
  396:  * 
  397:  * @param dtd_element_parent The supposed DTD parent element.
  398:  * @param dtd_element_child  The supposedd DTD child element.
  399:  * 
  400:  * @return \ref axl_true if the function can confirm that the parent-child
  401:  * relation exists, \ref axl_false if not or it could be proved.
  402:  */
  403: axl_bool     __axl_dtd_get_is_parent (axlDtdElement * dtd_element_parent,
  404: 				      axlDtdElement * dtd_element_child)
  405: {
  406: 	axlStack               * stack;
  407: 	axlDtdElementListNode  * node;
  408: 	axlDtdElementList      * list;
  409: 
  410: 	/* check for leaf nodes, that, by definition, could be a
  411: 	 * parent of nothing. */
  412: 	if (dtd_element_parent->list == NULL || dtd_element_parent->list->itemList == NULL) {
  413: 		return axl_false;
  414: 	}
  415: 
  416: 	/* prepare all elements inside the stack to be checked */
  417: 	stack = axl_stack_new (NULL);
  418: 	__axl_dtd_queue_items (stack, dtd_element_parent->list->itemList);
  419: 	
  420: 
  421: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "stack size to operate: %d, list: %d", 
  422: 		   axl_stack_size (stack),
  423: 		   axl_list_length (dtd_element_parent->list->itemList));
  424: 
  425: 	/* now search for a content particule that makes are reference
  426: 	 * to the child DTD element */
  427: 	do {
  428: 		node = axl_stack_pop (stack);
  429: 		switch (node->type) {
  430: 		case AXL_ELEMENT_NODE:
  431: 			/* leaf node case */
  432: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found a leaf node, checking it");
  433: 
  434: 			/* seems this is a final node */
  435: 			if (axl_cmp (node->data, dtd_element_child->name)) {
  436: 				/* seems that the content
  437: 				 * specification makes a reference to
  438: 				 * the child node. */
  439: 				axl_stack_free (stack);
  440: 				return axl_true;
  441: 			}
  442: 			break;
  443: 		case AXL_ELEMENT_LIST:
  444: 			/* a nested list case */
  445: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found a complex node queuing its internal elements, while checking parent=%s for child=%s",
  446: 				   dtd_element_parent->name, dtd_element_child->name);
  447: 			/* the item list read, is a complex value,
  448: 			 * queue all items inside to be inspected */
  449: 			list = node->data;
  450: 			__axl_dtd_queue_items (stack, list->itemList);
  451: 			break;
  452: 		case AXL_ELEMENT_NOT_DEFINED:
  453: 			/* do nothing */
  454: 			break;
  455: 		}
  456: 		
  457: 		/* iterate until all elements are evaluated */
  458: 	}while (! axl_stack_is_empty (stack));
  459: 
  460: 	/* deallocates no longer used stack */
  461: 	axl_stack_free (stack);
  462: 	
  463: 	/* either it isn't the parent or it can't be proved. */
  464: 	return axl_false;
  465: }
  466: 
  467: 
  468: /** 
  469:  * @internal
  470:  * 
  471:  * Support function which allows to get which is the most top root
  472:  * node for the provided set of DTD elements.
  473:  */
  474: axlDtdElement * __axl_dtd_get_new_root (axlDtd * dtd) 
  475: {
  476: 	int             iterator;
  477: 	axl_bool        change_detected;
  478: 
  479: 	axlDtdElement * dtd_element_aux;
  480: 	axlDtdElement * dtd_element_the_root_is_on_fire;
  481: 
  482: 	/* set the very first root node */
  483: 	dtd_element_the_root_is_on_fire = axl_list_get_nth (dtd->elements, 0);
  484: 	
  485: 	do {
  486: 		/* check which is the top */
  487: 		iterator        = 0;
  488: 		change_detected = axl_false;
  489: 		while (iterator < axl_list_length (dtd->elements)) {
  490: 			
  491: 			/* get the next reference */
  492: 			dtd_element_aux = axl_list_get_nth (dtd->elements, iterator);
  493: 			
  494: 			/* check which is the top */
  495: 			if (__axl_dtd_get_is_parent (dtd_element_aux,
  496: 						     dtd_element_the_root_is_on_fire)) {
  497: 				/* it seems that the new element is the root
  498: 				 * one, update the reference */
  499: 				dtd_element_the_root_is_on_fire = dtd_element_aux;
  500: 				change_detected = axl_true;
  501: 			}
  502: 			
  503: 			/* update inner loop iterator */
  504: 			iterator ++;
  505: 		} /* while end */
  506: 	}while (change_detected);
  507: 
  508: 	/* return the root found */
  509: 	return dtd_element_the_root_is_on_fire;
  510: }
  511: 
  512: /** 
  513:  * @internal 
  514:  *
  515:  * @brief Adds the axlDtdElement into the given axlDtd definition,
  516:  * checking that everything is properly configured, and ensuring that
  517:  * the root element gets properly configured.
  518:  * 
  519:  * @param dtd The \ref axlDtd object that will receive the
  520:  * axlDtdElement.
  521:  *
  522:  * @param stream The \ref axlStream object that will be destroyed if
  523:  * something wrong is found.
  524:  *
  525:  * @param element The axlDtdElement to be added to the give axlDtd
  526:  * object.
  527:  * 
  528:  * @return axl_true if the given axlDtdElement is compatible inside
  529:  * the axlDtd declaration or axl_false if a error is found.
  530:  */
  531: axl_bool     __axl_dtd_add_element (axlDtd * dtd, axlDtdElement * element, 
  532: 				    axlStream * stream, axlError ** error)
  533: {
  534: 	int             iterator        = 0;
  535: 	axlDtdElement * dtd_element_aux = NULL;
  536: 
  537: 	/* check that there is no element already named like the
  538: 	 * element received. If it is the case drop an error */
  539: 	while (iterator < axl_list_length (dtd->elements)) {
  540: 		dtd_element_aux = axl_list_get_nth (dtd->elements, iterator);
  541: 		if (axl_cmp (dtd_element_aux->name, element->name)) {
  542: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "DTD element for <%s> == <%s> was defined twice", 
  543: 				   dtd_element_aux->name, element->name);
  544: 
  545: 			axl_error_new (-1, "Find that an DTD element was defined twice (no more than one time is allowed)", 
  546: 				       stream, error);
  547: 			axl_stream_free (stream);
  548: 			return axl_false;
  549: 		}
  550: 
  551: 		/* update current iterator */
  552: 		iterator++;
  553: 	}
  554: 	
  555: 	/* add the new DTD element to the list */
  556: 	axl_list_add (dtd->elements, element);
  557: 	return axl_true;
  558: }
  559: 
  560: /** 
  561:  * @internal
  562:  * 
  563:  * Internal support function which adds the provided content particule
  564:  * to the dtd item list received. It also perform all operations
  565:  * required for the chunk_matched option received.
  566:  *
  567:  * In the case the function fails to do its work, it will deallocate
  568:  * the stream, filling the error received.
  569:  *
  570:  * According to the chunk matched value, the function will react
  571:  * adding the element and configuring current element list.
  572:  *
  573:  */
  574: axl_bool     __axl_dtd_element_content_particule_add (axlDtdElementList  * dtd_item_list, 
  575: 						      char               * string_aux, 
  576: 						      int                  chunk_matched, 
  577: 						      axlStream          * stream, 
  578: 						      axlError          **error)
  579: {
  580: 	axlDtdElementListNode * node;
  581: 
  582: 	/* check if the item list was creted or not */
  583: 	if (dtd_item_list->itemList == NULL) {
  584: 		dtd_item_list->itemList = axl_list_new (axl_list_always_return_1, 
  585: 							(axlDestroyFunc) __destroy_axl_dtd_element_list);
  586: 	}
  587: 
  588: 	/* create the node to be added */
  589: 	node = __create_axl_dtd_element_list (string_aux, NULL);
  590: 
  591: 	/* know add the element found */
  592: 	axl_list_add (dtd_item_list->itemList, node);
  593: 
  594: 	/* set configuration for item repetition */
  595: 	switch (chunk_matched) {
  596: 	case 4:
  597: 		/* one or many times */
  598: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "setting one to many repeat pattern: (+)");
  599: 		node->times = ONE_OR_MANY;
  600: 		break;
  601: 	case 5:
  602: 		/* zero or many times */
  603: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "setting zero to many repeat pattern: (*)");
  604: 		node->times = ZERO_OR_MANY;
  605: 		break;
  606: 	case 6:
  607: 		/* zero or one time */
  608: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "setting one to one repeat pattern: (?)");
  609: 		node->times = ZERO_OR_ONE;
  610: 		break;
  611: 	default:
  612: 		/* one and only one time */
  613: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "setting one and only one repeat pattern: ()");
  614: 		node->times = ONE_AND_ONLY_ONE;
  615: 	}
  616: 
  617: 	/* return that all is ok */
  618: 	return axl_true;
  619: }
  620: 
  621: 
  622: /** 
  623:  * @internal
  624:  * 
  625:  * @brief Support function which allows to get current repetition
  626:  * configuration.
  627:  * 
  628:  * @param stream The stream where the operation will be performed.
  629:  * 
  630:  * @return Current configuration read, the function will properly work
  631:  * if it is called when it is espected to find a content specification
  632:  * repetition. If not found, the \ref ONE_AND_ONLY_ONE is returned.
  633:  */
  634: AxlDtdTimes __axl_dtd_get_repetition_conf (axlStream * stream)
  635: {
  636: 	axl_return_val_if_fail (stream, ONE_AND_ONLY_ONE);
  637: 
  638: 	if (axl_stream_inspect (stream, "?", 1) > 0) {
  639: 
  640: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found '?' repetition conf");
  641: 		/* seems the content specification could appear zero
  642: 		 * or one time */
  643: 		return ZERO_OR_ONE;
  644: 
  645: 	} else if (axl_stream_inspect (stream, "+", 1) > 0) {
  646: 
  647: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found '+' repetition conf");
  648: 		/* seems the content specification must appear one up
  649: 		 * to many */
  650: 		return ONE_OR_MANY;
  651: 
  652: 	} else if (axl_stream_inspect (stream, "*", 1) > 0) {
  653: 
  654: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found '*' repetition conf");
  655: 		/* seems the content specification could appear zero
  656: 		 * up to many */
  657: 		return ZERO_OR_MANY;
  658: 	} 
  659: 
  660: 	/* the content specification must appear */
  661: 	return ONE_AND_ONLY_ONE;
  662: }
  663: 
  664: /** 
  665:  * @internal
  666:  *
  667:  * Support function which creates a child item list, insert it to the
  668:  * parent item list received.
  669:  * 
  670:  * @param parent 
  671:  * 
  672:  * @return 
  673:  */
  674: axlDtdElementList * __axl_dtd_create_and_queue (axlDtdElementList * parent)
  675: {
  676: 	axlDtdElementList     * child;
  677: 	axlDtdElementListNode * node;
  678: 	
  679: 	/* create the DTD item list */
  680: 	child       = axl_new (axlDtdElementList, 1);
  681: 
  682: 	/* make by default the item list to be defined as "not
  683: 	 * defined" until the first separator is found */
  684: 	child->type = STILL_UNDEF; 
  685: 	
  686: 	/* create a node that */
  687: 	node = __create_axl_dtd_element_list (NULL, child);
  688: 
  689: 	/* create the parent list reference if weren't */
  690: 	if (parent->itemList == NULL) {
  691: 		parent->itemList = axl_list_new (axl_list_always_return_1, 
  692: 						 (axlDestroyFunc) __destroy_axl_dtd_element_list);
  693: 	}
  694: 
  695: 	/* add the node */
  696: 	axl_list_add (parent->itemList, node);
  697: 
  698: 	/* return the new child created */
  699: 	return child;
  700: }
  701: 
  702: /** 
  703:  * @internal
  704:  *
  705:  * Updates current chunk readed information to allow perform a better
  706:  * code after calling this function.
  707:  *
  708:  */
  709: void __axl_dtd_element_spec_update_chunk_matched (axlStream * stream, 
  710: 						  int * chunk_matched)
  711: {
  712: 	/* check for for sequence or choice characters */
  713: 	if (axl_stream_inspect (stream, ",", 1) > 0) {
  714: 		/* flag that we have found a , (choice)
  715: 		 * separator */
  716: 		(*chunk_matched) = 1;
  717: 		
  718: 	} else if (axl_stream_inspect (stream, "|", 1) > 0) {
  719: 		/* flag that we have found a | (sequence)
  720: 		 * separator */
  721: 		(*chunk_matched) = 2;
  722: 
  723: 	} else if (axl_stream_inspect (stream, ")", 1) > 0) {
  724: 		/* flag that we have found a | (sequence)
  725: 		 * separator */
  726: 		(*chunk_matched) = 3;
  727: 		
  728: 	} else if (axl_stream_inspect (stream, "+", 1) > 0) {
  729: 		/* flag that we have found a | (sequence)
  730: 		 * separator */
  731: 		(*chunk_matched) = 4;
  732: 		
  733: 	} else if (axl_stream_inspect (stream, "*", 1) > 0) {
  734: 		/* flag that we have found a | (sequence)
  735: 		 * separator */
  736: 		(*chunk_matched) = 5;
  737: 		
  738: 	} else if (axl_stream_inspect (stream, "?", 1) > 0) {
  739: 		/* flag that we have found a | (sequence)
  740: 		 * separator */
  741: 		(*chunk_matched) = 6;
  742: 	}
  743: 
  744: 	return;
  745: }
  746: 
  747: /** 
  748:  * @internal
  749:  *
  750:  * Support function to read the content particule separator once the
  751:  * repeat pattern was found 
  752:  * 
  753:  */
  754: axl_bool     __axl_dtd_element_spec_update_chunk_matched_for_cp_separator (axlStream * stream, 
  755: 									   int * chunk_matched)
  756: {
  757: 	/* consume previous white spaces */
  758: 	AXL_CONSUME_SPACES (stream);
  759: 
  760: 	/* check for for sequence or choice characters */
  761: 	if (axl_stream_inspect (stream, ",", 1) > 0) {
  762: 		/* flag that we have found a , (choice)
  763: 		 * separator */
  764: 		(*chunk_matched) = 1;
  765: 		return axl_true;
  766: 		
  767: 	} else if (axl_stream_inspect (stream, "|", 1) > 0) {
  768: 		/* flag that we have found a | (sequence)
  769: 		 * separator */
  770: 		(*chunk_matched) = 2;
  771: 		return axl_true;
  772: 
  773: 	} else if (axl_stream_inspect (stream, ")", 1) > 0) {
  774: 		/* flag that we have found a | (sequence)
  775: 		 * separator */
  776: 		(*chunk_matched) = 3;
  777: 		return axl_true;
  778: 	}
  779: 	
  780: 	return axl_false;
  781: }
  782: 
  783: /** 
  784:  * @internal
  785:  *
  786:  * Support function which allows to read the next content particule.
  787:  */
  788: char * __axl_dtd_read_content_particule (axlStream  * stream, 
  789: 					 int        * chunk_matched,
  790: 					 axlStack   * dtd_item_stack, 
  791: 					 axlError  ** error)
  792: {
  793: 	char * string_aux;
  794: 
  795: 	/* read the spec particule stopping when a white space
  796: 	 * or other character is found */
  797: 	string_aux = axl_stream_get_until (stream, NULL, chunk_matched, axl_true, 8, 
  798: 					   /* basic, default delimiters: 0, 1, 2, 3 */
  799: 					   " ", ",", "|", ")",
  800: 					   /* repetition configuration: 4, 5, 6 */
  801: 					   "+", "*", "?",
  802: 					   /* new dtd item list being opened: 8 */
  803: 					   "(");
  804: 	if (string_aux == NULL) {
  805: 		axl_error_new (-1, "Expected to find a element content specification particule, but it wasn't found",
  806: 			       stream, error);
  807: 		axl_stack_free (dtd_item_stack);
  808: 		axl_stream_free (stream);
  809: 		return NULL;
  810: 	}
  811: 	
  812: 	/* check the user doesn't nest item list in a not
  813: 	 * proper way */
  814: 	if (*chunk_matched == 8) {
  815: 		axl_error_new (-1, "Found a not proper nesting item list for a DTD element, before using ( a separator must be used (CHOICE: |, SEQUENCE: ,)",
  816: 			       stream, error);
  817: 		axl_stack_free (dtd_item_stack);
  818: 		axl_stream_free (stream);
  819: 		return NULL;
  820: 	}
  821: 
  822: 	/* nullify stream internal reference */
  823: 	axl_stream_nullify (stream, LAST_CHUNK);
  824: 	
  825: 	/* return the content particule found */
  826: 	return string_aux;
  827: }
  828: 
  829: /** 
  830:  * @internal
  831:  *
  832:  * Support function which reads current <!ELEMENT specification,
  833:  * configuring it to the received axlDtdElement.
  834:  * 
  835:  * @param stream The stream where the axlDtdElement spec will be read.
  836:  *
  837:  * @param dtd_element The axlDtdElement that will receive the content
  838:  * spec.
  839:  *
  840:  * @param error An optional \ref axlError, where errors will be
  841:  * reported.
  842:  * 
  843:  * @return \ref axl_true if the content spec was properly read or \ref
  844:  * axl_false if not.
  845:  */
  846: axl_bool     __axl_dtd_read_element_spec (axlStream * stream, axlDtdElement * dtd_element, axlError ** error)
  847: {
  848: 	char              * string_aux;
  849: 	axl_bool            is_pcdata;
  850: 	int                 chunk_matched = -1;
  851: 	axlStack          * dtd_item_stack;
  852: 	axlDtdElementList * dtd_item_list;
  853: 	axl_bool            is_empty;
  854: 	
  855: 	
  856: 	/* create the stack used to control which is
  857: 	 * the current context for the items read for
  858: 	 * the xml DTD especification (pd, pd2, (pr|po), ..) */
  859: 	dtd_item_stack = axl_stack_new (NULL);
  860: 
  861: 	/* create the DTD item list */
  862: 	dtd_item_list       = axl_new (axlDtdElementList, 1);
  863: 
  864: 	/* by default, set still undef to change it once a separator
  865: 	 * is detected or the function ends. This will help to detect
  866: 	 * problems produced by people mixing content element
  867: 	 * separators. */
  868: 	dtd_item_list->type = STILL_UNDEF; 
  869: 
  870: 	/* set the content spec list to the dtd element read */
  871: 	dtd_element->list   = dtd_item_list;
  872: 	   
  873: 	/* push the item created */
  874: 	/* axl_stack_push (dtd_item_stack, dtd_item_list); */
  875: 	
  876: 	/* consume previous white spaces */
  877: 	AXL_CONSUME_SPACES (stream);
  878: 
  879: 	/* check that the content specification have an ( */
  880: 	if (! (axl_stream_inspect (stream, "(", 1))) {
  881: 		axl_error_new (-1, "Expected to find a element content specification opener \"(\", but it wasn't found",
  882: 			       stream, error);
  883: 		axl_stack_free (dtd_item_stack);
  884: 		axl_stream_free (stream);		
  885: 		return axl_false;
  886: 	}
  887: 	
  888: 	do {
  889: 		/* consume previous white spaces */
  890: 		AXL_CONSUME_SPACES (stream);
  891: 
  892: 		/* a new item list have been opened */
  893: 		if (axl_stream_inspect (stream, "(", 1) > 0) {
  894: 
  895: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found a DTD item list openining: %d",
  896: 				   axl_stack_size (dtd_item_stack));
  897: 
  898: 			/* a new item list is being defined, we have
  899: 			 * to queue current dtd_item_list and create a
  900: 			 * new item list */
  901: 			axl_stack_push (dtd_item_stack, dtd_item_list);
  902: 			
  903: 			/* create the DTD item list */
  904: 			dtd_item_list        = __axl_dtd_create_and_queue (dtd_item_list);
  905: 
  906: 			/* let's continue at the begining */
  907: 			continue;
  908: 		}
  909: 		
  910: 
  911: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "iterating again to get a new content particule (item list size: %d)",
  912: 			   axl_dtd_item_list_count (dtd_item_list));
  913: 
  914: 		/* read the next content particule: here is the chunk
  915: 		 * matched codes found: 
  916: 		 * basic, default delimiters: 
  917: 		 * 0, 1, 2, 3 -> " ", ",", "|", ")" 
  918: 		 * repetition configuration: 
  919: 		 * 4, 5, 6  -> "+", "*", "?",
  920: 		 * new dtd item list being opened: 
  921: 		 * 8 -> "(" */
  922: 		string_aux = __axl_dtd_read_content_particule (stream, &chunk_matched, dtd_item_stack, error);
  923: 		if (string_aux == NULL)
  924: 			return axl_false;
  925: 		
  926: 		/* check, and record, that the string read is
  927: 		 * PCDATA */
  928: 		is_pcdata = axl_cmp (string_aux, "#PCDATA");
  929: 
  930: 		/* add the item read if have something defined */
  931: 
  932: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found content spec particule: (size: %d) '%s'", 
  933: 			   strlen (string_aux),
  934: 			   string_aux);
  935: 
  936: 		/* check if the have matched a white space: next check is
  937: 		 * based on the call to axl_stream_get_until at the caller
  938: 		 * function: " " */
  939: 		if (chunk_matched == 0) {
  940: 
  941: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, 
  942: 				   "found white spaces as delimiter, consuming them (current chunk matched: %d)",
  943: 				   chunk_matched);
  944: 			
  945: 			/* consume previous white spaces */
  946: 			AXL_CONSUME_SPACES (stream);
  947: 
  948: 			/* update current chunk_matched to conform to
  949: 			 * an stream that have all elements really
  950: 			 * close: the following function tries to read
  951: 			 * and update chunk_matched variable to point
  952: 			 * to the value read for ",", "|", "+", "*",
  953: 			 * "?" and ")" because white spaces were found */
  954: 			__axl_dtd_element_spec_update_chunk_matched (stream, &chunk_matched);
  955: 
  956: 
  957: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, 
  958: 				   "current chunk matched before update (%d)",
  959: 				   chunk_matched);
  960: 		}
  961: 
  962: 		/* add the content particule found, this function
  963: 		 * already detect that a white space was found and
  964: 		 * consumes all white spaces found */
  965: 		if (!__axl_dtd_element_content_particule_add (dtd_item_list, string_aux, chunk_matched, stream, error))
  966: 			return axl_false;
  967: 
  968: 		if (chunk_matched == 4 || chunk_matched == 5 || chunk_matched == 6) {
  969: 			/* found a repetition pattern */
  970: 			if (! __axl_dtd_element_spec_update_chunk_matched_for_cp_separator (stream, &chunk_matched)) {
  971: 				axl_error_new (-1, "Before a repetition pattern (*,+,?) expected to find a content particule separator",
  972: 					       stream, error);
  973: 				axl_stack_free (dtd_item_stack);
  974: 				axl_stream_free (stream);		
  975: 				return axl_false;
  976: 			}
  977: 		}
  978: 
  979: 		/* set current sequence type accoring to separators
  980: 		 * used */
  981: 		switch (chunk_matched) {
  982: 		case 1:
  983: 			if (dtd_item_list->type == CHOICE) {
  984: 				axl_error_new (-1, "Detected that the DTD definition is mixing content particules separators at the same level ('|' and ','). First detected a sequence spec (,) but then detected a choice element (|)",
  985: 					       stream, error);
  986: 				axl_stack_free (dtd_item_stack);
  987: 				axl_stream_free (stream);		
  988: 				return axl_false;
  989: 			}
  990: 			dtd_item_list->type = SEQUENCE;
  991: 			break;
  992: 		case 2:
  993: 			if (dtd_item_list->type == SEQUENCE) {
  994: 				axl_error_new (-1, "Detected that the DTD definition is mixing content particules separators at the same level ('|' and ','). First detected a choice spec (|) but then detected a sequence element (,)",
  995: 					       stream, error);
  996: 				axl_stack_free (dtd_item_stack);
  997: 				axl_stream_free (stream);		
  998: 				return axl_false;
  999: 			}
 1000: 			dtd_item_list->type = CHOICE;
 1001: 			break;
 1002: 		}
 1003: 
 1004: 		/* set element type if a element list terminator was
 1005: 		 * found ( 3 = ')' = chunk_matched) */
 1006: 		if ((chunk_matched == 3) && is_pcdata) {
 1007: 			if (axl_list_length (dtd_item_list->itemList) == 1)
 1008: 				dtd_element->type = ELEMENT_TYPE_PCDATA;
 1009: 			else if (axl_list_length (dtd_item_list->itemList) > 1)
 1010: 				dtd_element->type = ELEMENT_TYPE_MIXED;
 1011: 		}
 1012: 
 1013: 		/* pop current element list header */
 1014: 		if (chunk_matched == 3) {
 1015: 			do {
 1016: 				__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found a DTD item list termination: stack status: %d",
 1017: 					   axl_stack_size (dtd_item_stack));
 1018: 				/* consume previous white spaces */
 1019: 				AXL_CONSUME_SPACES (stream);
 1020: 				dtd_item_list->times = __axl_dtd_get_repetition_conf (stream);
 1021: 
 1022: 				/* consume previous white spaces */
 1023: 				AXL_CONSUME_SPACES (stream);
 1024: 
 1025: 				if (axl_stream_inspect (stream, ",", 1) > 0) {
 1026: 					__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found a sequence (,) separator while reading terminator list");
 1027: 
 1028: 					chunk_matched = 1;
 1029: 				}
 1030: 				else if (axl_stream_inspect (stream, "|", 1) > 0) {
 1031: 					__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found a choice (|) separator while reading terminator list");
 1032: 					chunk_matched = 2;
 1033: 				}
 1034: 				
 1035: 				/* this means that a ) was found, we have to
 1036: 				 * pop current queue */
 1037: 				is_empty              = axl_stack_is_empty (dtd_item_stack);
 1038: 				if (! is_empty) {
 1039: 					dtd_item_list = axl_stack_pop (dtd_item_stack);
 1040: 					__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "getting the next item list in the stack, stack status: %d",
 1041: 						   axl_stack_size (dtd_item_stack));
 1042: 				}
 1043: 
 1044: 				/* special case: check if the next element to
 1045: 				 * be read is a new ) */
 1046: 				/* consume previous white spaces */
 1047: 				AXL_CONSUME_SPACES (stream);
 1048: 
 1049: 			}while ((axl_stream_inspect (stream, ")", 1) > 0) && !is_empty);
 1050: 
 1051: 			/* drop a log */
 1052: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "terminator sequence status: chunk matched=%d ans stack status: %d",
 1053: 				   chunk_matched, axl_stack_size (dtd_item_stack));
 1054: 
 1055: 		}
 1056: 
 1057: 		/* check if we have finished */
 1058: 	} while (chunk_matched != 3 || (! axl_stack_is_empty (dtd_item_stack)));
 1059: 
 1060: 
 1061: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "content spec terminated, now lookup for the termination");
 1062: 		
 1063: 	/* consume previous white spaces */
 1064: 	/* AXL_CONSUME_SPACES (stream);*/
 1065: 
 1066: 	/* read here repetition specification */
 1067: 	/* dtd_item_list->times = __axl_dtd_get_repetition_conf (stream); */
 1068: 	
 1069: 	/* set default content element separator */
 1070: 	if (dtd_item_list->type == STILL_UNDEF)
 1071: 		dtd_item_list->type = SEQUENCE;
 1072: 		
 1073: 	/* free the stack used */
 1074: 	axl_stack_free (dtd_item_stack);
 1075: 
 1076: 
 1077: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "DTD content element specification found and parsed ok");
 1078: 
 1079: 
 1080: 	/* content spec readed properly */
 1081: 	return axl_true;
 1082: }
 1083: 
 1084: /** 
 1085:  * @internal
 1086:  * 
 1087:  * Calculates the number of nodes to be matched at minimum for the
 1088:  * provided DTD element. 
 1089:  * 
 1090:  * @param element The DTD element to configure with its minimum item
 1091:  * count to be matched.
 1092:  */
 1093: int __axl_dtd_parse_element_get_compulsory_num (axlDtdElementList * list)
 1094: {
 1095: 	axlDtdElementListNode * itemNode;
 1096: 	int                     count    = 0;
 1097: 	int                     iterator = 0;
 1098: 
 1099: 	/* check for null parameters */
 1100: 	if (list == NULL)
 1101: 		return 0;
 1102: 
 1103: 	/* only count for repetitiong patterns that makes obligatory
 1104: 	 * to have childs */
 1105: 	if (list->times == ONE_AND_ONLY_ONE ||
 1106: 	    list->times == ONE_OR_MANY) {
 1107: 		
 1108: 		while (iterator < axl_list_length (list->itemList)) {
 1109: 			/* get the reference for the item node */
 1110: 			itemNode = axl_list_get_nth (list->itemList, iterator);
 1111: 			
 1112: 			/* check if the repetitiong patter is
 1113: 			 * compulsory */
 1114: 			if (itemNode->times == ONE_OR_MANY ||
 1115: 			    itemNode->times == ONE_AND_ONLY_ONE) {
 1116: 				/* check if we have an itemNode that has an
 1117: 				 * Node or a list */
 1118: 				if (itemNode->type == AXL_ELEMENT_NODE) {
 1119: 					/* we have an item node */
 1120: 					count++;
 1121: 					if (list->type == CHOICE) {
 1122: 						/* because we have a
 1123: 						 * choice list, once
 1124: 						 * validated one item,
 1125: 						 * it is the minimum
 1126: 						 * requirement. */
 1127: 						return count;
 1128: 					}
 1129: 				} else {
 1130: 					/* we have a list */
 1131: 					count += __axl_dtd_parse_element_get_compulsory_num (itemNode->data);
 1132: 				}
 1133: 			}
 1134: 			
 1135: 			/* update the index */
 1136: 			iterator++;
 1137: 		}
 1138: 	}
 1139: 		
 1140: 	/* return current count */
 1141: 	return count;
 1142: }
 1143: 
 1144: 
 1145: /** 
 1146:  * @internal
 1147:  *
 1148:  * Parses a document type element that it is expected to be found at
 1149:  * the given stream.
 1150:  * 
 1151:  * @param dtd The axlDtd where the element type readed must be added.
 1152:  *
 1153:  * @param stream The stream where the element type if expected to be found.
 1154:  *
 1155:  * @param error An axlError, optional, reference where error will be
 1156:  * reported.
 1157:  * 
 1158:  * @return axl_true if the element was parsed properly, axl_false if
 1159:  * not. The stream associated will be unrefered and the axlError
 1160:  * provided will be filled if an error is found.
 1161:  */
 1162: axl_bool     __axl_dtd_parse_element (axlDtd * dtd, axlStream * stream, axlError ** error)
 1163: {
 1164: 	char              * string_aux;
 1165: 	int                 matched_chunk = -1;
 1166: 	axlDtdElement     * element;
 1167: 
 1168: 	/* init the dtd element list */
 1169: 	if (dtd->elements == NULL)
 1170: 		dtd->elements = axl_list_new (axl_list_always_return_1, (axlDestroyFunc) axl_dtd_element_free);
 1171: 
 1172: 	/* consume previous white spaces */
 1173: 	AXL_CONSUME_SPACES (stream);
 1174: 
 1175: 	/* get for the first element declaration */
 1176: 	if (! (axl_stream_inspect (stream, "<!ELEMENT", 9) > 0)) {
 1177: 		axl_error_new (-1, "Expected to receive a <!ELEMENT, but it wasn't found", stream, error);
 1178: 		axl_stream_free (stream);
 1179: 		return axl_false;
 1180: 	}
 1181: 
 1182: 	/* consume previous white spaces */
 1183: 	AXL_CONSUME_SPACES (stream);
 1184: 	
 1185: 	/* get the element name */
 1186: 	string_aux = axl_stream_get_until (stream, NULL, &matched_chunk, axl_false, 3, ">", "(", " ", "<!ELEMENT");
 1187: 	if (string_aux == NULL) {
 1188: 		axl_error_new (-1, "Expected to receive a DTD element name for <!ELEMENT declaration, but not found", stream, error);
 1189: 		axl_stream_free (stream);
 1190: 		return axl_false;
 1191: 	}
 1192: 
 1193: 	/* check that the DTD have an element name and an element type */
 1194: 	if ((matched_chunk == 0) || (matched_chunk == 3)) {
 1195: 		axl_error_new (-1, "Found a DTD <!ELEMENT declaration, without content specification. Missing value, examples: EMPTY, ANY, (..)", stream, error);
 1196: 		axl_stream_free (stream);
 1197: 		return axl_false;
 1198: 	}
 1199: 
 1200: 	/* nullify internal stream content */
 1201: 	axl_stream_nullify (stream, LAST_CHUNK);
 1202: 	
 1203: 	/* create the DTD element */
 1204: 	element           = axl_new (axlDtdElement, 1);
 1205: 	element->name     = string_aux;
 1206: 
 1207: 	/* consume previous white spaces */
 1208: 	AXL_CONSUME_SPACES (stream);
 1209: 
 1210: 	/* now, check for the basic cases: ANY and EMPTY */
 1211: 	if (axl_stream_peek (stream, "EMPTY", 5) > 0) {
 1212: 		/* accept previous peek */
 1213: 		axl_stream_accept (stream);
 1214: 
 1215: 		/* found empty declaration */
 1216: 		element->type = ELEMENT_TYPE_EMPTY;
 1217: 
 1218: 	} else if (axl_stream_peek (stream, "ANY", 3) > 0) {
 1219: 		/* accept previous peek */
 1220: 		axl_stream_accept (stream);
 1221: 
 1222: 		/* found any declaration */
 1223: 		element->type = ELEMENT_TYPE_ANY;
 1224: 	} else {
 1225: 		/* complex element type declaration, let's roll now
 1226: 		 * get the element content type read current dtd
 1227: 		 * element spec. 
 1228: 		 *
 1229: 		 * By default, any comple element type definition,
 1230: 		 * have childrens, until PC data definition is found,
 1231: 		 * which leads to the two possible values: Mixed and
 1232: 		 * PcData */
 1233: 		element->type = ELEMENT_TYPE_CHILDREN;
 1234: 		if (!__axl_dtd_read_element_spec (stream, element, error))
 1235: 			return axl_false;
 1236: 	}
 1237: 
 1238: 	/* add element found */
 1239: 	if (! __axl_dtd_add_element (dtd, element, stream, error))
 1240: 		return axl_false;
 1241: 	
 1242: 	/* consume previous white spaces */
 1243: 	AXL_CONSUME_SPACES (stream);
 1244: 
 1245: 	/* check for the last DTD declaration */
 1246: 	if (! (axl_stream_inspect (stream, ">", 1))) {
 1247: 		axl_error_new (-1, "Unable to find last, > terminator for the DTD <!ELEMENT declaration", stream, error);
 1248: 		axl_stream_free (stream);
 1249: 		return axl_false;
 1250: 	}
 1251: 
 1252: 	/* now, count the number of obligatory elements, required for
 1253: 	 * the validation process */
 1254: 	element->minimum_match = __axl_dtd_parse_element_get_compulsory_num (element->list);
 1255: 
 1256: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found DTD element declaration read complete: minimum matching elements: %d",
 1257: 		   element->minimum_match);
 1258: 
 1259: 	/* element type declaration completely read */
 1260: 	return axl_true;
 1261: }
 1262: 
 1263: /** 
 1264:  * @internal
 1265:  * 
 1266:  * Destroy the provided reference and its associated data.
 1267:  * 
 1268:  * @param decl The reference declaration.
 1269:  */
 1270: void axl_dtd_attribute_decl_free (axlDtdAttributeDecl * decl)
 1271: {
 1272: 	/* free the rule name */
 1273: 	if (decl->name != NULL)
 1274: 		axl_free (decl->name);
 1275: 
 1276: 	/* free the default value */
 1277: 	if (decl->default_value != NULL)
 1278: 		axl_free (decl->default_value);
 1279: 
 1280: 	/* free enum declaration list if defined */
 1281: 	if (decl->enumvalues != NULL)
 1282: 		axl_list_free (decl->enumvalues);
 1283: 
 1284: 	/* free the node itself */
 1285: 	axl_free (decl);
 1286: 	
 1287: 	/* nothing more to do */
 1288: 	return;
 1289: }
 1290: 
 1291: /** 
 1292:  * @internal function to dealloc an single attribute set decleration.
 1293:  * 
 1294:  * @param attribute The reference to dealloc.
 1295:  */
 1296: void axl_dtd_attribute_free (axlDtdAttribute * attribute)
 1297: {
 1298: 	/* free the attribute list, name and the node itself */
 1299: 	axl_free (attribute->name);
 1300: 	axl_list_free (attribute->list);
 1301: 	axl_free (attribute);
 1302: 
 1303: 	return;
 1304: }
 1305: 
 1306: axl_bool __find_attr_decl (axlPointer _element, axlPointer data)
 1307: {
 1308: 	axlDtdAttributeDecl * decl = _element;
 1309: 	char                * name = data;
 1310: 
 1311: 	/* check the name */
 1312: 	if (axl_cmp (decl->name, name))
 1313: 		return axl_true;
 1314: 
 1315: 	/* it is not the element */
 1316: 	return axl_false;
 1317: }
 1318: 
 1319: /** 
 1320:  * @brief Allows to check if the stream contains a reference to a
 1321:  * entity, calling the resolver to get the replacement text to be
 1322:  * placed.
 1323:  * 
 1324:  * @param resolver The function to be called with the replacement
 1325:  * text. This function must return the replacement text or NULL if it
 1326:  * fails. Failing to return a reference resolution will make the
 1327:  * entity reference to appear as is.
 1328:  *
 1329:  * @param resolver The entity reference resolver function to be called
 1330:  * to solve references found.
 1331:  *
 1332:  * @param data User defined data provided to the function, passed
 1333:  * directly to the resolver function once executed.
 1334:  *
 1335:  * @param stream The stream where the entity reference could appear.
 1336:  *
 1337:  * @param prefix The reference prefix to recognize. Values allowed
 1338:  * are: % (DTD references) and & (general entity references).
 1339:  *
 1340:  * @param error Optional reference to the axlError to report textual
 1341:  * diagnostic errors.
 1342:  *
 1343:  * @return The function return \ref axl_false if some error while
 1344:  * resolving entity references was found. Otherwise the function
 1345:  * return axl_true.
 1346:  */
 1347: axl_bool axl_dtd_check_entity_ref_and_expand (axlDtdEntityResolver   resolver, 
 1348: 					      axlPointer             data,
 1349: 					      axlStream            * stream, 
 1350: 					      const char           * prefix,
 1351: 					      axlError            ** error)
 1352: 					  
 1353: {
 1354: 	char       * string_aux;
 1355: 	char       * new_value;
 1356: 	int          index;
 1357: 
 1358: 	/* check if we have an entity reference using the provided prefix */
 1359: 	index = axl_stream_get_index (stream);
 1360: 	if (! (axl_stream_inspect (stream, prefix, 1) > 0))
 1361: 		return axl_true;
 1362: 
 1363: 	/* get the entity reference until the end */
 1364: 	string_aux = axl_stream_get_until (stream, NULL, NULL, axl_true, 1, ";");
 1365: 	if (string_aux == NULL) {
 1366: 		axl_error_new (-1, "null value received while expecting to find the entity reference to resolve.", stream, error);
 1367: 		axl_stream_free (stream);
 1368: 		return axl_false;
 1369: 	} /* end if */
 1370: 
 1371: 	axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found entity reference: %s%s;...resolving", prefix, string_aux);
 1372: 
 1373: 	/* resolve the reference */
 1374: 	new_value = (char *) resolver (string_aux, data);
 1375: 	if (new_value == NULL) {
 1376: 		axl_stream_move (stream, index);
 1377: 		return axl_true;
 1378: 	} /* end if */
 1379: 
 1380: 	/* accept content consumed */
 1381: 	axl_stream_accept (stream);
 1382: 
 1383: 	axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "entity resolved to: %s", new_value);
 1384: 
 1385: 	/* place the replacement data at the start of the stream */
 1386: 	new_value = axl_strdup_printf ("%s ", new_value);
 1387: 	axl_stream_push (stream, new_value, strlen (new_value));
 1388: 	axl_free (new_value);
 1389: 	
 1390: 	return axl_true;
 1391: }
 1392: 
 1393: /** 
 1394:  * @internal Entity resolver used by __axl_dtd_parse_attlist.
 1395:  */
 1396: const char * __axl_dtd_entity_resolver (const char * entityName, axlPointer data)
 1397: {
 1398: 	/* return the entity resolution */
 1399: 	return axl_dtd_entity_value ((axlDtd *) data, entityName, PARAMETER_ENTITY);
 1400: } /* end if */
 1401: 
 1402: axlList * __axl_dtd_parse_enumvalues (const char * _enum_values)
 1403: {
 1404: 	char    ** result;
 1405: 	int        iterator;
 1406: 	axlList  * list;
 1407: 
 1408: 	result   = axl_stream_split (_enum_values, 1, "|");
 1409: 	iterator = 0;
 1410: 	list     = axl_list_new (axl_list_always_return_1, axl_free);
 1411: 
 1412: 	
 1413: 	while (result[iterator]) {
 1414: 		/* clean the enum value */
 1415: 		axl_stream_trim (result[iterator]);
 1416: 
 1417: 		/* add to the list */
 1418: 		axl_list_add (list, axl_strdup (result[iterator]));
 1419: 
 1420: 		/* update the iterator value */
 1421: 		iterator++;
 1422: 
 1423: 	} /* end while */
 1424: 	
 1425: 	/* free tokens */
 1426: 	axl_stream_freev (result);
 1427: 	
 1428: 	/* return the list */
 1429: 	return list;
 1430: }
 1431: 
 1432: /** 
 1433:  * @internal function used by \ref axl_dtd_attr_validation function to
 1434:  * lookup ATTLIST contraints flaged as unique ID.
 1435:  */
 1436: axl_bool __find_id_decl (axlPointer _element, axlPointer data)
 1437: {
 1438: 	/* return the comparision */
 1439: 	return (((axlDtdAttributeDecl *) _element)->type == TOKENIZED_TYPE_ID);
 1440: 	
 1441: } /* end __find_id_decl */
 1442: 
 1443: 
 1444: /** 
 1445:  * @internal
 1446:  * 
 1447:  * Parse the <!ATTLIST decleration, registering it into the provided
 1448:  * dtd element.
 1449:  */
 1450: axl_bool __axl_dtd_parse_attlist (axlDtd * dtd, axlStream * stream, axlError ** error)
 1451: {
 1452: 	char                * string_aux    = NULL;
 1453: 	int                   matched_chunk = -1;
 1454: 	axlDtdAttribute     * attribute     = NULL;
 1455: 	axlDtdAttributeDecl * decl          = NULL;
 1456: 	axlDtdAttributeDecl * declAux       = NULL;
 1457: 	char                * err_msg;
 1458: 
 1459: 	/* init the dtd attr list */
 1460: 	if (dtd->attributes == NULL)
 1461: 		dtd->attributes = axl_list_new (axl_list_always_return_1, (axlDestroyFunc) axl_dtd_attribute_free);
 1462: 
 1463: 	/* consume previous white spaces */
 1464: 	AXL_CONSUME_SPACES (stream);
 1465: 
 1466: 	/* get the element name */
 1467: 	string_aux = axl_stream_get_until (stream, NULL, &matched_chunk, axl_false, 1, " ");
 1468: 	if (string_aux == NULL) {
 1469: 		axl_error_new (-1, "Expected to receive a DTD attribute name for <!ATTLIST declaration, but not found", stream, error);
 1470: 		axl_stream_free (stream);
 1471: 		return axl_false;
 1472: 	}
 1473: 
 1474: 	axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found dtd attr declaration for node: <%s>", string_aux);
 1475: 
 1476: 	/* find the node that holds all attr declarations for the node found */
 1477: 	attribute         = axl_dtd_get_attr (dtd, string_aux);
 1478: 
 1479: 	/* check if found */
 1480: 	if (attribute == NULL) {
 1481: 		/* create the axlDtdAttribute holder */
 1482: 		attribute = axl_new (axlDtdAttribute, 1);
 1483: 
 1484: 		/* record the node to which the list of rules applies */
 1485: 		axl_stream_nullify (stream, LAST_CHUNK);
 1486: 		attribute->name   = string_aux;
 1487: 
 1488: 		/* init the attribute rule list */
 1489: 		attribute->list   = axl_list_new (axl_list_always_return_1, (axlDestroyFunc) axl_dtd_attribute_decl_free);
 1490: 
 1491: 		/* now configure this new attribute inside the dtd */
 1492: 		axl_list_add (dtd->attributes, attribute);
 1493: 	} /* end if */
 1494: 
 1495: 	/* now get the list of attributes */
 1496: 	while (1) {
 1497: 		axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "finding next att declaration");
 1498: 
 1499: 		/* consume previous white spaces */
 1500: 		AXL_CONSUME_SPACES (stream);
 1501: 
 1502: 		/* check if we have finished */
 1503: 		if (axl_stream_inspect (stream, ">", 1) > 0)
 1504: 			break;
 1505: 
 1506: 		/* get the attribute name the rules applies */
 1507: 		string_aux = axl_stream_get_until (stream, NULL, &matched_chunk, axl_false, 1, " ");
 1508: 		if (string_aux == NULL) {
 1509: 			axl_error_new (-1, "Expected to receive an attribute name for <!ATTLIST declaration, but not found", stream, error);
 1510: 			axl_stream_free (stream);
 1511: 			return axl_false;
 1512: 		}
 1513: 
 1514: 		/* nully the string and store it new rule created */
 1515: 		axl_stream_nullify (stream, LAST_CHUNK);
 1516: 
 1517: 		/* create a new attribute single constraint */
 1518: 		decl            = axl_new (axlDtdAttributeDecl, 1);
 1519: 		decl->name      = string_aux;
 1520: 
 1521: 		/* add the attribute constraint to the list */
 1522: 		axl_list_add (attribute->list, decl);
 1523: 
 1524: 		axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "find constraint for attribute name=%s", decl->name);
 1525: 
 1526: 		/* consume previous white spaces */
 1527: 		AXL_CONSUME_SPACES (stream);
 1528: 
 1529: 		axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "checking constraint type..");
 1530: 
 1531: 		/* check for an entity reference and expand the stream
 1532: 		 * content with its resolution */
 1533: 		if (! axl_dtd_check_entity_ref_and_expand (__axl_dtd_entity_resolver, dtd, stream, "%", error))
 1534: 			return axl_false;
 1535: 
 1536: 		axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "about to check attr constraint type, stream status: '%s'",
 1537: 			 axl_stream_get_following (stream, 30));
 1538: 		
 1539: 		/* now check the contraint type */
 1540: 		if (axl_stream_inspect (stream, "NOTATION", 8) > 0) {
 1541: 			/* parse notation declaration */
 1542: 		}else if (axl_stream_inspect (stream, "(", 1) > 0) {
 1543: 			/* parse enum declaration */
 1544: 			string_aux = axl_stream_get_until (stream, NULL, &matched_chunk, axl_true, 1, ")");
 1545: 			if (string_aux == NULL) {
 1546: 				axl_error_new (-1, "expected to find enum declaration but termination caracter ')' was not found", stream, error);
 1547: 				axl_stream_free (stream);
 1548: 				return axl_false;
 1549: 			} /* end if */
 1550: 			decl->type       = ENUMERATION_TYPE;
 1551: 			decl->enumvalues = __axl_dtd_parse_enumvalues (string_aux);
 1552: 		}else {
 1553: 			/* set the attribute type */
 1554: 			if (axl_stream_inspect (stream, "CDATA", 5) > 0) {
 1555: 				decl->type = CDATA_ATTRIBUTE;
 1556: 			} else if (axl_stream_inspect (stream, "IDREFS", 6) > 0) {
 1557: 				
 1558: 				/* flag the type */
 1559: 				decl->type = TOKENIZED_TYPE_IDREFS;
 1560: 
 1561: 				/* flag the dtd to have a IDREF declaration */
 1562: 				dtd->haveIdRefDecl = axl_true;
 1563: 			} else if (axl_stream_inspect (stream, "IDREF", 5) > 0) {
 1564: 				/* notify type found */
 1565: 				decl->type = TOKENIZED_TYPE_IDREF;
 1566: 
 1567: 				/* flag the dtd to have a IDREF declaration */
 1568: 				dtd->haveIdRefDecl = axl_true;
 1569: 				
 1570: 			} else if (axl_stream_inspect (stream, "ID", 2) > 0) {
 1571: 				
 1572: 				/* notify the type found */
 1573: 				decl->type      = TOKENIZED_TYPE_ID;
 1574: 
 1575: 				/* flag the dtd to have a ID declaration */
 1576: 				dtd->haveIdDecl = axl_true;
 1577: 				
 1578: 			} else if (axl_stream_inspect (stream, "ENTITY", 6) > 0)
 1579: 				decl->type = TOKENIZED_TYPE_ENTITY;
 1580: 			else if (axl_stream_inspect (stream, "ENTITIES", 8) > 0)
 1581: 				decl->type = TOKENIZED_TYPE_ENTITIES;
 1582: 			else if (axl_stream_inspect (stream, "NMTOKENS", 8) > 0)
 1583: 				decl->type = TOKENIZED_TYPE_NMTOKENS;
 1584: 			else if (axl_stream_inspect (stream, "NMTOKEN", 7) > 0)
 1585: 				decl->type = TOKENIZED_TYPE_NMTOKEN;
 1586: 			else {
 1587: 				axl_error_new (-1, "Unrecognied attr type declaration found, check your <!ATTLIST declaration", stream, error);
 1588: 				axl_stream_free (stream);
 1589: 				return axl_false;
 1590: 			} /* end if */
 1591: 		} /* end if */
 1592: 
 1593: 		/* consume previous white spaces */
 1594: 		AXL_CONSUME_SPACES (stream);
 1595: 
 1596: 		axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "checking default value declaration, stream status: '%s'",
 1597: 			 axl_stream_get_following (stream, 30));
 1598: 
 1599: 		/* get default declaration value */
 1600: 		if (axl_stream_inspect (stream, "#REQUIRED", 9) > 0) {
 1601: 			decl->defaults = ATT_REQUIRED;
 1602: 		} else if (axl_stream_inspect (stream, "#IMPLIED", 8) > 0) {
 1603: 			decl->defaults = ATT_IMPLIED;
 1604: 		} else {
 1605: 			decl->defaults = ATT_IMPLIED;
 1606: 			if (axl_stream_inspect (stream, "#FIXED", 6) > 0) {
 1607: 				decl->defaults = ATT_FIXED;
 1608: 
 1609: 				/* consume previous white spaces */
 1610: 				AXL_CONSUME_SPACES (stream);
 1611: 			}
 1612: 
 1613: 			/* check default value for this case */
 1614: 			if (! (axl_stream_peek (stream, "\"", 1) > 0 ||
 1615: 			       axl_stream_peek (stream, "'", 1) > 0)) {
 1616: 				err_msg = axl_strdup_printf ("Unable to find default attribute declaration (#REQUIRED, #IMPLIED, #FIXED)  for attribute %s, node <%s>",
 1617: 							     decl->name, attribute->name);
 1618: 				axl_error_new (-1, err_msg, stream, error);
 1619: 				axl_stream_free (stream);
 1620: 				axl_free (err_msg);
 1621: 				return axl_false;
 1622: 			} /* end if */
 1623: 		} /* end if */
 1624: 
 1625: 		/* check constraint for ID types */
 1626: 		if (decl->type == TOKENIZED_TYPE_ID) {
 1627: 			/* check that the node doesn't have any unique
 1628: 			 * id declared */
 1629: 
 1630: 			/* check if the node have TOKENIZED_TYPE_ID */
 1631: 			declAux = axl_list_lookup (attribute->list, __find_id_decl, NULL);
 1632: 			if (declAux != NULL && !axl_cmp (declAux->name, decl->name)) {
 1633: 				err_msg = axl_strdup_printf ("Found ATTLIST declaration, with several ID declarations <ATTLIST %s %s..",
 1634: 							     attribute->name, decl->name);
 1635: 				axl_error_new (-1, err_msg, stream, error);
 1636: 				axl_stream_free (stream);
 1637: 				axl_free (err_msg);
 1638: 				return axl_false;
 1639: 			} /* end if */
 1640: 			
 1641: 			/* check required and implied */
 1642: 			if (decl->defaults != ATT_REQUIRED && decl->defaults != ATT_IMPLIED) {
 1643: 				err_msg = axl_strdup_printf ("Found ATTLIST declaration, with ID, that don't have configured either #IMPLICIT or #REQUIRED for attribute %s, node <%s>",
 1644: 							     decl->name, attribute->name);
 1645: 				axl_error_new (-1, err_msg, stream, error);
 1646: 				axl_stream_free (stream);
 1647: 				axl_free (err_msg);
 1648: 				return axl_false;
 1649: 			} /* end if */
 1650: 		} /* end if */
 1651: 
 1652: 		/* consume previous white spaces */
 1653: 		AXL_CONSUME_SPACES (stream);
 1654: 
 1655: 		/* nullify to check this value later */
 1656: 		string_aux = NULL;
 1657: 		if (axl_stream_inspect (stream, "\"", 1) > 0) {
 1658: 			/* get until */
 1659: 			string_aux = axl_stream_get_until (stream, NULL, NULL, axl_true, 1, "\"");
 1660: 		} else if (axl_stream_inspect (stream, "'", 1) > 0) {
 1661: 			/* get until */
 1662: 			string_aux = axl_stream_get_until (stream, NULL, NULL, axl_true, 1, "\'");
 1663: 		} /* end if */
 1664: 
 1665: 		/* check if default value was found */
 1666: 		if (string_aux != NULL) {
 1667: 
 1668: 			/* found default value, check if we have an
 1669: 			 * enumeration type, enforcing that the value
 1670: 			 * defined to be inside the enumeration */
 1671: 			if (decl->type == ENUMERATION_TYPE) {
 1672: 				if (axl_list_lookup (decl->enumvalues, axl_list_find_string, string_aux) == NULL) {
 1673: 					axl_error_new (-1, 
 1674: 						       "Configured a default value for an attribute list which only accepts a set of enum values that do not containt it.",
 1675: 						       stream, error);
 1676: 					axl_stream_free (stream);
 1677: 					return axl_false;
 1678: 				} /* end if */
 1679: 			} /* end if */
 1680: 
 1681: 			/* nullify value and make string_aux to be
 1682: 			 * owned by the axlDtdAttributeDecl
 1683: 			 * reference */
 1684: 			axl_stream_nullify (stream, LAST_CHUNK);
 1685: 			decl->default_value = string_aux;
 1686: 		} /* end if */
 1687: 
 1688: 	} /* end while */
 1689:        	
 1690: 	/* properly parsed */
 1691: 	return axl_true;
 1692: }
 1693: 
 1694: /** 
 1695:  * @internal
 1696:  * 
 1697:  * Destroy the provided entity reference and all allocated memory.
 1698:  * 
 1699:  * @param entity The entity the deallocate.
 1700:  */
 1701: void axl_dtd_entity_free (axlDtdEntity * entity)
 1702: {
 1703: 	/* the entity reference */
 1704: 	axl_return_if_fail (entity);
 1705: 
 1706: 	/* free the entity name */
 1707: 	if (entity->name)
 1708: 		axl_free (entity->name);
 1709: 	
 1710: 	/* free the content */
 1711: 	if (entity->content)
 1712: 		axl_free (entity->content);
 1713: 
 1714: 	/* free external data if defined */
 1715: 	if (entity->data) {
 1716: 		/* free system literal */
 1717: 		if (entity->data->system_literal)
 1718: 			axl_free (entity->data->system_literal);
 1719: 		
 1720: 		/* free public literal */
 1721: 		if (entity->data->public_literal)
 1722: 			axl_free (entity->data->public_literal);
 1723: 
 1724: 		/* free ndata literal */
 1725: 		if (entity->data->ndata)
 1726: 			axl_free (entity->data->ndata);
 1727: 
 1728: 		/* free the node itself */
 1729: 		axl_free (entity->data);
 1730: 	}
 1731: 
 1732: 	/* free the node */
 1733: 	axl_free (entity);
 1734: 
 1735: 	return;
 1736: }
 1737: 
 1738: /** 
 1739:  * @internal
 1740:  *
 1741:  * Parses an entity definition from the current status of the stream
 1742:  * provided.
 1743:  */
 1744: axl_bool __axl_dtd_parse_entity (axlDtd * dtd, axlStream * stream, axlError ** error)
 1745: {
 1746: 	char         * string_aux;
 1747: 	int            matched_chunk;
 1748: 	axlDtdEntity * entity;
 1749: 
 1750: 	/* init the dtd element list */
 1751: 	if (dtd->entities == NULL)
 1752: 		dtd->entities = axl_list_new (axl_list_always_return_1, (axlDestroyFunc) axl_dtd_entity_free);
 1753: 	
 1754: 	/* consume previous white spaces */
 1755: 	AXL_CONSUME_SPACES (stream);
 1756: 
 1757: 	/* get for the first element declaration */
 1758: 	if (! (axl_stream_inspect (stream, "<!ENTITY", 8) > 0)) {
 1759: 		axl_error_new (-1, "Expected to receive a <!ENTITY, but it wasn't found", stream, error);
 1760: 		axl_stream_free (stream);
 1761: 		return axl_false;
 1762: 	}
 1763: 
 1764: 	/* consume previous white spaces */
 1765: 	AXL_CONSUME_SPACES (stream);
 1766: 
 1767: 	/* create a new entity */
 1768: 	entity = axl_new (axlDtdEntity, 1);
 1769: 
 1770: 	/* set the entity and return axl_true */
 1771: 	axl_list_add (dtd->entities, entity);
 1772: 
 1773: 	/* check for parameter entity definition */
 1774: 	if (axl_stream_inspect (stream, "%", 1) > 0) {
 1775: 		/* set the entity type */
 1776: 		entity->type = PARAMETER_ENTITY;
 1777: 		
 1778: 		/* consume previous white spaces */
 1779: 		AXL_CONSUME_SPACES (stream);
 1780: 
 1781: 	} else
 1782: 		entity->type = GENERAL_ENTITY;
 1783: 
 1784: 	/* get the element name */
 1785: 	string_aux = axl_stream_get_until (stream, NULL, &matched_chunk, axl_false, 1, " ");
 1786: 	if (string_aux == NULL) {
 1787: 		axl_error_new (-1, "Expected to receive a DTD entity name for <!ENTITY declaration, but not found", stream, error);
 1788: 		axl_stream_free (stream);
 1789: 		return axl_false;
 1790: 	}
 1791: 
 1792: 	/* set the name */
 1793: 	axl_stream_nullify (stream, LAST_CHUNK);
 1794: 	entity->name = string_aux;
 1795: 
 1796: 	/* consume previous white spaces */
 1797: 	AXL_CONSUME_SPACES (stream);
 1798: 
 1799: 	/* now check if we have an external reference */
 1800: 	if (axl_stream_inspect (stream, "PUBLIC", 6) > 0) {
 1801: 		/* we have a public external resource definition */
 1802: 		
 1803: 	}else if (axl_stream_inspect (stream, "SYSTEM", 6) > 0) {
 1804: 		/* we have a system definition */
 1805: 		
 1806: 	}else {
 1807: 		/* we have a plain value get the content remove next "
 1808: 		   and ' if defined */
 1809: 		if (! ((axl_stream_inspect (stream, "\"", 1) > 0))) {
 1810: 			if (! (axl_stream_inspect (stream, "\'", 1) > 0)) {
 1811: 				axl_error_new (-2, "Expected to find entity value initiator (\") or ('), every entity value must start with them", 
 1812: 					       stream, error);
 1813: 				axl_stream_free (stream);
 1814: 				return axl_false;
 1815: 			}
 1816: 			/* knowing that ' was matched, now get the attribute value */
 1817: 			string_aux = axl_stream_get_until (stream, NULL, &matched_chunk, axl_true, 1, "'");
 1818: 		}else {
 1819: 			/* knowhing that " was matched, now get the attribute value */
 1820: 			string_aux = axl_stream_get_until (stream, NULL, &matched_chunk, axl_true, 1, "\"");
 1821: 		}
 1822: 
 1823: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "entity value found: [%s]", string_aux);
 1824: 		
 1825: 		/* nullify internal reference so we have the
 1826: 		 * only one reference to entity content value
 1827: 		 * inside string_aux */
 1828: 		axl_stream_nullify (stream, LAST_CHUNK);
 1829: 
 1830: 		/* set the value */
 1831: 		entity->content = string_aux;
 1832: 	}
 1833: 
 1834: 	/* consume previous white spaces */
 1835: 	AXL_CONSUME_SPACES (stream);
 1836: 
 1837: 	/* check last item to parse */
 1838: 	if (! (axl_stream_inspect (stream, ">", 1) > 0)) {
 1839: 		axl_error_new (-2, "Expected to find entity definition terminator (>), but it wasn't found", 
 1840: 			       stream, error);
 1841: 		axl_stream_free (stream);
 1842: 		return axl_false;
 1843: 	}
 1844: 
 1845: 	return axl_true;
 1846: }
 1847: 
 1848: 
 1849: /** 
 1850:  * @internal
 1851:  * 
 1852:  * Implements DTD parsing, reading it from a direct buffer, or a file
 1853:  * path or a file handle.
 1854:  */
 1855: axlDtd * __axl_dtd_parse_common (const char * entity, int entity_size, 
 1856: 				 const char * file_path, int fd_handle, 
 1857: 				 axlError ** error)
 1858: {
 1859: 	axlStream * stream;
 1860: 	axlDtd    * dtd;
 1861: 	int         iterator;
 1862: 	
 1863: 	/* create the stream associated */
 1864: 	stream = axl_stream_new (entity, entity_size, file_path, fd_handle, error);
 1865: 	axl_return_val_if_fail (stream, NULL);
 1866: 
 1867: 	dtd    = __axl_dtd_new ();
 1868: 	axl_stream_link (stream, dtd, (axlDestroyFunc) axl_dtd_free);
 1869: 
 1870: 	iterator = 0;
 1871: 	while (axl_stream_remains (stream)) {
 1872: 		/* get rid from comments found */
 1873: 		if (! axl_doc_consume_comments (NULL, stream, error))
 1874: 			return NULL;
 1875: 		
 1876: 		/* check for element declaration */
 1877: 		if (axl_stream_peek (stream, "<!ELEMENT", 9) > 0) {
 1878: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found DTD element declaration");
 1879: 			/* found element declaration */
 1880: 			if (! __axl_dtd_parse_element (dtd, stream, error))
 1881: 				return NULL;
 1882: 			
 1883: 			continue;
 1884: 
 1885: 		}
 1886: 
 1887: 		/* check for attribute list declarations */
 1888: 		if (axl_stream_inspect (stream, "<!ATTLIST", 9) > 0) {
 1889: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found DTD attribute list declaration");
 1890: 
 1891: 			/* parse it */
 1892: 			if (! __axl_dtd_parse_attlist (dtd, stream, error))
 1893: 				return NULL;
 1894: 			
 1895: 			continue;
 1896: 		}
 1897: 
 1898: 		/* check for the entity declaration */
 1899: 		if (axl_stream_peek (stream, "<!ENTITY", 8) > 0) {
 1900: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found DTD entity declaration");
 1901: 
 1902: 			/* parse the entity definition */
 1903: 			if (! __axl_dtd_parse_entity (dtd, stream, error))
 1904: 				return NULL;
 1905: 
 1906: 			continue;
 1907: 		}
 1908: 
 1909: 		/* stop the loop */
 1910: 		if (iterator == 3) {
 1911: 			axl_error_new (-1, "unable to process DTD content, unable to find expected information (no <!ELEMENT, <!ATTLIST or <!ENTITY declaration)", stream, error);
 1912: 			axl_stream_free (stream);
 1913: 			return NULL;
 1914: 		}
 1915: 		iterator++;
 1916: 	}
 1917: 
 1918: 
 1919: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "DTD elements totally loaded, building references..");
 1920: 
 1921: 	/* update current root reference, the DTD root for the DTD
 1922: 	 * document already parsed */
 1923: 	if (dtd->elements != NULL) 
 1924: 		dtd->root = __axl_dtd_get_new_root (dtd);
 1925: 
 1926: 	/* check if the DTD has ID declarations if found IDREF
 1927: 	 * declarations */
 1928: 	if (! dtd->haveIdDecl && dtd->haveIdRefDecl) {
 1929: 		axl_error_new (-1, "DTD semantic error, found IDREF attribute declaration but no attribute ID declaration was found.", stream, error);
 1930: 		axl_stream_free (stream);
 1931: 		return NULL;
 1932: 	}
 1933: 	
 1934: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "DTD load COMPLETE");
 1935: 
 1936: 	axl_stream_unlink (stream);
 1937: 	axl_stream_free (stream);
 1938: 	return dtd;
 1939: }
 1940: 
 1941: /** 
 1942:  * @brief Allows to parse the provided entity, which is expected to
 1943:  * contain a DTD (Document Type Definition).
 1944:  * 
 1945:  * @param entity The document type definition to parse.
 1946:  *
 1947:  * @param entity_size The document size, or -1 to make the function to
 1948:  * figure out current size.
 1949:  *
 1950:  * @param error An optional \ref axlError where errors will be reported.
 1951:  * 
 1952:  * @return A newly allocated \ref axlDtd that must be deallocated when
 1953:  * no longer need with \ref axl_dtd_free. The function could return
 1954:  * NULL on failure detected. On that case, it is requred to check \ref
 1955:  * axlError variable, if defined.
 1956:  */
 1957: axlDtd   * axl_dtd_parse (const char * entity, 
 1958: 			  int          entity_size,
 1959: 			  axlError ** error)
 1960: {
 1961: 
 1962: 	return __axl_dtd_parse_common (entity, entity_size, NULL, -1, error);
 1963: }
 1964: 
 1965: /** 
 1966:  * @brief Allows to parse the provided DTD definition, which is found
 1967:  * on the provided file path.
 1968:  * 
 1969:  * @param file_path The file path where it is expected to receive a
 1970:  * DTD file.
 1971:  *
 1972:  * @param error An optional \ref axlError reference where all errors found will be reported.
 1973:  * 
 1974:  * @return A newly allocated \ref axlDtd instance or NULL if it fails.
 1975:  *
 1976:  * <b>Making a DTD to be inline loaded: </b><br>
 1977:  * 
 1978:  * It may be helpful to make the DTD definition available at your
 1979:  * binary, inline compiled, to avoid distributing DTD files along with
 1980:  * libraries, etc. This also solves installation problems like
 1981:  * provisioning a default location to make your application to find
 1982:  * such files.
 1983:  *
 1984:  * With the following command you can create an inline representation
 1985:  * from your DTD file:
 1986:  * \code
 1987:  * >> axl-knife --input your-file.dtd --dtd-to-c --output your-file.dtd.h --ifnewer
 1988:  * \endcode
 1989:  *
 1990:  * This will create a header with an C-macro style definition of your
 1991:  * DTD. Now, you can include it using:
 1992:  *
 1993:  * \code
 1994:  * #include <your-file.dtd.h>
 1995:  * \endcode
 1996:  *
 1997:  * In the case you are developing a library, it is recommended to do
 1998:  * such include at the body implementation (usually .c or .cpp files,
 1999:  * to avoid requiring your API consumers to also include your DTD
 2000:  * inline definition). 
 2001:  *
 2002:  * Now, to load your DTD file, use the following:
 2003:  *
 2004:  * \code
 2005:  * axlError * err = NULL;
 2006:  * axlDtd   * dtd = axl_dtd_parse (YOUR_FILE_DTD, -1, &err);
 2007:  * if (dtd == NULL) {
 2008:  *    // This won't happen unless axl-runtime error found, since axl-knife 
 2009:  *    // checks your dtd file before producing the in-line definition.
 2010:  *    // However, bug happens! check this.
 2011:  * }
 2012:  * \endcode
 2013:  */
 2014: axlDtd   * axl_dtd_parse_from_file (const char * file_path,
 2015: 				    axlError ** error)
 2016: {
 2017: 	return __axl_dtd_parse_common (NULL, -1, file_path, -1, error);
 2018: }
 2019: 
 2020: 
 2021: /** 
 2022:  * @internal
 2023:  * 
 2024:  * Support function for axl_dtd_validate which checks if the provided
 2025:  * parent have its childs configuration according to the values
 2026:  * expresed on the sequenced represented by the itemList.
 2027:  *
 2028:  * The function return axl_true if the validation was ok, or axl_false
 2029:  * if something have failed. It also creates an error, using the
 2030:  * optional axlError reference received.
 2031:  */
 2032: axl_bool     __axl_dtd_validate_sequence (axlNode            * parent, 
 2033: 					  int                * child_position,
 2034: 					  axlDtdElementList  * itemList, 
 2035: 					  axlError          ** error,
 2036: 					  axl_bool             try_match,
 2037: 					  axl_bool             top_level)
 2038: {
 2039: 	int                      iterator        = 0;
 2040: 	int                      child_pos       = *child_position;
 2041: 	axlNode                * node;
 2042: 	axlDtdElementListNode  * itemNode;
 2043: 	axl_bool                 status          = axl_false;
 2044: 	axl_bool                 one_matched;
 2045: 	AxlDtdTimes              times;
 2046: 	
 2047: 
 2048: 	axl_return_val_if_fail (parent, axl_false);
 2049: 	axl_return_val_if_fail (itemList, axl_false);
 2050: 
 2051: 
 2052: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "validating a sequence list: iterator=%d, item list count=%d, at child position=%d",
 2053: 		 iterator, axl_dtd_item_list_count (itemList), child_pos);
 2054: 
 2055: 	/* iterate over the sequence, checking its order */
 2056: 	while (iterator < axl_dtd_item_list_count (itemList)) {
 2057: 		
 2058: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "getting next item node from the DTD item list at: %d",
 2059: 			 iterator);
 2060: 		
 2061: 		/* get the item node specification */
 2062: 		itemNode    = axl_dtd_item_list_get_node (itemList, iterator);
 2063: 		one_matched = axl_false;
 2064: 		times       = axl_dtd_item_node_get_repeat (itemNode);
 2065: 
 2066: 		do {
 2067: 
 2068: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "getting node at child position: %d",
 2069: 				   child_pos);
 2070: 
 2071: 			/* get the node that is located at the same position
 2072: 			 * than the sequence */
 2073: 			if (child_pos < axl_node_get_child_num (parent)) {
 2074: 				node     = axl_node_get_child_nth (parent, child_pos);
 2075: 			} else
 2076: 				node     = NULL;
 2077: 
 2078: 			/* the node child list have ended, check if
 2079: 			 * this situation was expected */
 2080: 			if (node == NULL) {
 2081: 				__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "no more child nodes to validate at %d, for parent: %s, times: %d, iterator: %d, item count: %d",
 2082: 					   child_pos, axl_node_get_name (parent), times,
 2083: 					   iterator, axl_dtd_item_list_count (itemList));
 2084: 				/* check if we were working with a
 2085: 				 * list, which have matched at least
 2086: 				 * one item */
 2087: 				if (times == ONE_OR_MANY && one_matched && status) {
 2088: 					if ((iterator + 1) == axl_dtd_item_list_count (itemList)) {
 2089: 						*child_position = child_pos;
 2090: 						__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "sequence validated with child position (III): %d", child_pos);
 2091: 						return axl_true;
 2092: 					} 
 2093: 
 2094: 					/* reached this point we have
 2095: 					   matched a one to many with
 2096: 					   at least one match */
 2097: 					break;
 2098: 				}
 2099: 				
 2100: 				/* check that the rest of the
 2101: 				 * specification item is optional,
 2102: 				 * including the one used */
 2103: 				status = axl_true;
 2104: 				do {
 2105: 					if (times != ZERO_OR_MANY &&
 2106: 					    times != ZERO_OR_ONE) {
 2107: 
 2108: 						__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found item, inside the DTD item list, that is not optional: %d (repeat value: %d)", 
 2109: 							   iterator, times);
 2110: 						status = axl_false;
 2111: 						break;
 2112: 					}
 2113: 
 2114: 					/* update index and get the next item */
 2115: 					iterator++;
 2116: 					if (iterator < axl_dtd_item_list_count (itemList))
 2117: 						itemNode = axl_dtd_item_list_get_node (itemList, iterator);
 2118: 				}while (status && (iterator < axl_dtd_item_list_count (itemList)));
 2119: 
 2120: 				/* check status before checking the rest of the item spec */
 2121: 				if (status) {
 2122: 					*child_position = child_pos;
 2123: 
 2124: 					__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "sequence validated with child position (II): %d", child_pos);
 2125: 
 2126: 					return axl_true;
 2127: 				}
 2128: 				
 2129: 				/* check if a try match is being runned */
 2130: 				if (! try_match) {
 2131: 					axl_error_report (error, -1 , 
 2132: 						       "Found that DTD specifies more nodes to be hold by the parent (<%s>), but no more childs were found",
 2133: 						       axl_node_get_name (parent));
 2134: 				}
 2135: 
 2136: 				__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found that no nodes left to satisfy DTD validation operation");
 2137: 				*child_position = child_pos;
 2138: 				return axl_false;
 2139: 			}
 2140: 
 2141: 			/* check node type */
 2142: 			if (axl_dtd_item_node_get_type (itemNode) == AXL_ELEMENT_LIST) {
 2143: 
 2144: 				__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "the item node is an item list, dtd item list position: %d, child position: %d=<%s>",
 2145: 					 iterator, child_pos, axl_node_get_name (node));
 2146: 
 2147: 				/* element list found, validate its content */
 2148: 				if (! __axl_dtd_validate_item_list (axl_dtd_item_node_get_list (itemNode),
 2149: 								    parent, &child_pos, error, axl_false)) {
 2150: 					__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "sub item list validation have failed (not critical)");
 2151: 					/* check if we are the top
 2152: 					 * level list and the itemNode
 2153: 					 * checked is the last one
 2154: 					 * item on the item list */
 2155: 					if (top_level && ((iterator + 1) == axl_node_get_child_num (parent))) {
 2156: 						__axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "found that the last item list wasn't matched");
 2157: 						
 2158: 					}
 2159: 
 2160: 					*child_position = child_pos;
 2161: 					return axl_false;
 2162: 				}
 2163: 
 2164: 				__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "validated item list, child position after: %d",
 2165: 					   child_pos);
 2166: 				/* because child position updating and
 2167: 				 * repeat matching is already handled
 2168: 				 * by dtd_validate_item_list function
 2169: 				 * we just continue with the next
 2170: 				 * iteration */
 2171: 				break;
 2172: 
 2173: 			} else if (axl_dtd_item_node_get_type (itemNode) == AXL_ELEMENT_NODE) {
 2174: 				/* check the name against the spec */
 2175: 
 2176: 				__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, 
 2177: 					   "the item node is a final content particule definition: %s",
 2178: 					   axl_dtd_item_node_get_value (itemNode));
 2179: 
 2180: 				status = NODE_CMP_NAME (node, axl_dtd_item_node_get_value (itemNode));
 2181: 			}
 2182: 
 2183: 			/* check previous status */
 2184: 			if ((times == ONE_AND_ONLY_ONE) || 
 2185: 			    (times == ONE_OR_MANY && one_matched == axl_false)) {
 2186: 				if (! status) {
 2187: 					/* only report an upper level
 2188: 					 * error if we are not running
 2189: 					 * a try match */
 2190: 					if (! try_match) {
 2191: 
 2192: 						__axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, 
 2193: 							   "Found different node (<%s>) for a sequence expected (<%s>), at child position: %d, item list pos: %d",
 2194: 							   axl_node_get_name (node), 
 2195: 							   axl_dtd_item_node_get_value (itemNode),
 2196: 							   child_pos, iterator);
 2197: 						axl_error_report (error, -1, 
 2198: 								  "Found different node (<%s>) for a sequence expected (<%s>), at child position: %d, item list pos: %d",
 2199: 								  axl_node_get_name (node), 
 2200: 								  axl_dtd_item_node_get_value (itemNode),
 2201: 								  child_pos, iterator);
 2202: 					}
 2203: 					/* return that a match wasn't possible */
 2204: 					*child_position = child_pos;
 2205: 					return axl_false;			
 2206: 				}
 2207: 			}
 2208: 
 2209: 			/* according to the repetition pattern, update loop indexes */
 2210: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "updating child nodes references: %d, repeat type: %d, status=%d",
 2211: 				   child_pos, times, status);
 2212: 
 2213: 
 2214: 			/* one only item to match and exactly one */
 2215: 			if (times == ONE_AND_ONLY_ONE) {
 2216: 				child_pos++;
 2217: 				__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "updated child position to: %d, repeat type: %d, status=%d",
 2218: 					   child_pos, times, status);
 2219: 				break;
 2220: 			}
 2221: 
 2222: 			/* one or many items to match */
 2223: 			if (times == ONE_OR_MANY) { 
 2224: 
 2225: 				__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "matched one to many item node: status=%d one_matched=%d",
 2226: 					   status, one_matched);
 2227: 
 2228: 				/* if the match have failed and
 2229: 				 * previous matches was ok, it seems
 2230: 				 * we have reached the next
 2231: 				 * items. Just break the loop */
 2232: 				if (status == axl_false && one_matched == axl_true) 
 2233: 					break;
 2234: 
 2235: 				child_pos++;
 2236: 				one_matched = axl_true;
 2237: 				continue; /* don't break the loop */
 2238: 			}
 2239: 
 2240: 			/* zero or optionally one item to match */			
 2241: 			if (times == ZERO_OR_ONE) {
 2242: 				/* if previous status was ok, it seems
 2243: 				 * that we have matched the optional
 2244: 				 * character. In that case, move the
 2245: 				 * index to the following value. If
 2246: 				 * not, just break the loop. */
 2247: 				if (status == axl_true)
 2248: 					child_pos++;
 2249: 				break;
 2250: 			}
 2251: 
 2252: 			/* zero or many items to match */
 2253: 			if (times == ZERO_OR_MANY) {
 2254: 				if (status == axl_true) {
 2255: 					one_matched = axl_true;
 2256: 					child_pos++;
 2257: 					continue;
 2258: 				}
 2259: 				break;
 2260: 			}
 2261: 
 2262: 
 2263: 			/* until break the loop */
 2264: 		}while (axl_true);
 2265: 
 2266: 		/* update iterator index */
 2267: 		iterator++;
 2268: 	}
 2269: 
 2270: 	/* check if more nodes where specified than the DTD spec */
 2271: 	times = axl_dtd_item_list_repeat (itemList);
 2272: 	if ((times == ONE_OR_MANY || times == ONE_AND_ONLY_ONE) && 
 2273: 	    top_level && (child_pos  < axl_node_get_child_num (parent))) {
 2274: 
 2275: 		/* drop a log */
 2276: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "parent node <%s> have more childs=%d than the childs iterated=%d, top_level=%d",
 2277: 			   axl_node_get_name (parent),
 2278: 			   axl_node_get_child_num (parent),
 2279: 			   child_pos, top_level);
 2280: 
 2281: 		/* do not report an error found if a try match is
 2282: 		 * being run */
 2283: 		if (! try_match) {
 2284: 			axl_error_new (-1, "More childs, than the ones especified in the DTD, were found",
 2285: 				       NULL, error);
 2286: 		}
 2287: 		/* return that the match wasn't possible */
 2288: 		*child_position = child_pos;
 2289: 		return axl_false;
 2290: 	}
 2291: 
 2292: 	/* return that the sequence has been validated */
 2293: 	*child_position = child_pos;
 2294: 
 2295: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "sequence validated with child position (I): %d", child_pos);
 2296: 
 2297: 	return axl_true;
 2298: }
 2299: 
 2300: /** 
 2301:  * @internal
 2302:  * 
 2303:  * Internal support function to validate the choice list.
 2304:  */
 2305: axl_bool     __axl_dtd_validate_choice (axlNode             * parent, 
 2306: 					int                 * child_position, 
 2307: 					axlDtdElementList   * itemList, 
 2308: 					axlError           ** error,
 2309: 					axl_bool              try_match, 
 2310: 					axl_bool              top_level)
 2311: {
 2312: 	axlNode               * node;
 2313: 	axlDtdElementListNode * itemNode;
 2314: 	int                     iterator;
 2315: 	axl_bool                status;
 2316: 	AxlDtdTimes             times;
 2317: 	axl_bool                one_match;
 2318: 
 2319: 	
 2320: 	if (*child_position < axl_node_get_child_num (parent)) {
 2321: 		/* get a reference to be matched by the choice list */
 2322: 		node = axl_node_get_child_nth (parent, *child_position);
 2323: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "validated choice list at position: %d=<%s>", *child_position, axl_node_get_name (node));
 2324: 	} else {
 2325: 		/* tried to match a choice list with a child index
 2326: 		 * outside the maximum number of childs */
 2327: 		if (! try_match) {
 2328: 			axl_error_new (-1, "Unable to match choice list, it seems that the are not enough childs to validate the choice list",
 2329: 				       NULL, error);
 2330: 		}
 2331: 		return axl_false;
 2332: 	}
 2333: 
 2334: 	iterator = 0; 
 2335: 	while (iterator < axl_dtd_item_list_count (itemList)) {
 2336: 		/* get the DTD item list to match */
 2337: 		itemNode = axl_dtd_item_list_get_node   (itemList, iterator);
 2338: 		times    = axl_dtd_item_node_get_repeat (itemNode);
 2339: 
 2340: 		if (axl_dtd_item_node_get_type (itemNode) == AXL_ELEMENT_NODE) {
 2341: 			/* reset match configuration */
 2342: 			one_match = axl_false;
 2343: 		repeat_for_node:
 2344: 			/* a node was found */
 2345: 			status    = NODE_CMP_NAME (node, axl_dtd_item_node_get_value (itemNode));
 2346: 
 2347: 			/* know, if the node was matched check it
 2348: 			 * repetition configuration */
 2349: 			if (status) {
 2350: 				/* update child position */
 2351: 				(*child_position)++;
 2352: 
 2353: 				if (times == ONE_AND_ONLY_ONE || times == ZERO_OR_ONE) {
 2354: 					/* the node was matched and
 2355: 					 * the itemNode has a one and
 2356: 					 * only one configuration,
 2357: 					 * just return that the choice
 2358: 					 * list was matched */
 2359: 					return axl_true;
 2360: 				}
 2361: 				if (times == ONE_OR_MANY || times == ZERO_OR_MANY) {
 2362: 					/* because the node was matched, but the repetition
 2363: 					 * pattern allows to match more nodes we have to
 2364: 					 * iterate a bit more */
 2365: 					node = axl_node_get_child_nth (parent, *child_position);
 2366: 					if (node == NULL) {
 2367: 						/* because we already matched at least one item, 
 2368: 						 * we can assume that the itemNode was successfully 
 2369: 						 * matched for both cases (*) and (+). */
 2370: 						return axl_true;
 2371: 					}
 2372: 					/* flag the one match */
 2373: 					one_match = axl_true;
 2374: 					
 2375: 					/* if the node reference is
 2376: 					 * not NULL, try to match the
 2377: 					 * next item */
 2378: 					goto repeat_for_node;
 2379: 				}
 2380: 			} /* end if */
 2381: 			
 2382: 			/* before returning, that that we have matched
 2383: 			 * previously, at least, one node for
 2384: 			 * one-to-many and zero-to-many pattern */
 2385: 			if ((times == ONE_OR_MANY || times == ZERO_OR_MANY) && one_match) {
 2386: 				return axl_true;
 2387: 			}
 2388: 
 2389: 		} else if (axl_dtd_item_node_get_type (itemNode) == AXL_ELEMENT_LIST) {
 2390: 			/* an element list was found, call to validate it */
 2391: 			/* element list found, validate its content */
 2392: 			if (__axl_dtd_validate_item_list (axl_dtd_item_node_get_list (itemNode),
 2393: 							  parent, child_position, error, axl_false)) {
 2394: 				/* item list matched */
 2395: 				return axl_true;
 2396: 			}
 2397: 		}
 2398: 
 2399: 		/* no item was matched, update iterator indexes */
 2400: 		iterator++;
 2401: 	}
 2402: 
 2403: 	/* seems that the choice list wasn't matched */
 2404: 	if (! try_match) {
 2405: 		axl_error_new (-1, "Unable to match choice list, after checking all posibilities, choice list wasn't validated", 
 2406: 			       NULL, error);
 2407: 	}
 2408: 	return axl_false;
 2409: }
 2410: 
 2411: /** 
 2412:  * @internal 
 2413:  *
 2414:  * Tries to perform a validation, based on the item list received and
 2415:  * the repetition configuration.
 2416:  * 
 2417:  * @param itemList The item list containing DTD content spec
 2418:  * information used to validate.
 2419:  *
 2420:  * @param parent The parent node where the validation process is being
 2421:  * applied. The content spec refers to the childs the parent has.
 2422:  *
 2423:  * @param stack An stack used by the overall process to store the
 2424:  * subsequent parents to be validated. This stack must be released if
 2425:  * a error is found.
 2426:  *
 2427:  * @param error An optional axlError reference containing the error
 2428:  * textual diagnostic if found.
 2429:  * 
 2430:  * @return axl_true if the validation was ok, otherwise axl_false is
 2431:  * returned.
 2432:  */
 2433: axl_bool     __axl_dtd_validate_item_list (axlDtdElementList  * itemList,
 2434: 					   axlNode            * parent, 
 2435: 					   int                * child_position,
 2436: 					   axlError          ** error,
 2437: 					   axl_bool             top_level)
 2438: {
 2439: 	int          temp_child_pos;
 2440: 	axl_bool     status;
 2441: 	axl_bool     already_matched;
 2442: 
 2443: 
 2444: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "validating an item list with repeat pattern: %d, at %d, top level=%d",
 2445: 		   axl_dtd_item_list_repeat (itemList), *child_position, top_level);
 2446: 
 2447: 	/* now check repetition type */
 2448: 	switch (axl_dtd_item_list_repeat (itemList)) {
 2449: 	case ONE_AND_ONLY_ONE:
 2450: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found a (one and only one) spec..");
 2451: 		if (axl_dtd_item_list_type (itemList) == SEQUENCE) {
 2452: 
 2453: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "using a SEQUENCE form");
 2454: 			/* it is a choice, so the item list specifies
 2455: 			 * the nodes that could appear */
 2456: 			if (!__axl_dtd_validate_sequence (parent, child_position, itemList, error, 
 2457: 							  axl_false, top_level)) {
 2458: 				return axl_false;
 2459: 			}
 2460: 		}else {
 2461: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "using a CHOICE form");
 2462: 			/* it is a sequence, so, item list
 2463: 			 * specification represents the nodes, in the
 2464: 			 * order they must appear */
 2465: 			if (!__axl_dtd_validate_choice (parent, child_position, itemList, error,
 2466: 							axl_false, top_level)) {
 2467: 				return axl_false;
 2468: 			}
 2469: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "choice list was properly validated");
 2470: 		}
 2471: 		break;
 2472: 	case ZERO_OR_ONE:
 2473: 
 2474: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found a (zero or one) spec..");
 2475: 		if (axl_dtd_item_list_type (itemList) == SEQUENCE) {
 2476: 
 2477: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "using a SEQUENCE form, parent: <%s>",
 2478: 				   axl_node_get_name (parent));
 2479: 			/* because we are running a zero or one item
 2480: 			 * list matching, we don't care if it doesn't
 2481: 			 * match. In the case it match, the child
 2482: 			 * position is updated and next calls will be
 2483: 			 * properly aligned. In the match doesn't
 2484: 			 * happens, it also don't matter because the
 2485: 			 * pattern allow to not match */
 2486: 			temp_child_pos = *child_position;
 2487: 			if (!__axl_dtd_validate_sequence (parent, child_position, itemList, error, 
 2488: 							  axl_true, top_level)) {
 2489: 				/* check that the match wasn't
 2490: 				 * produced, at any level */
 2491: 				if (temp_child_pos != *child_position) {
 2492: 					__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "item list mismatch (%d != %d)", 
 2493: 						   temp_child_pos, *child_position);
 2494: 					axl_error_new (-1, "Found an DTD item list definition, that should be matched entirely or not, zero or one time, but it was matched partially",
 2495: 						       NULL, error);
 2496: 					return axl_false;
 2497: 				}
 2498: 
 2499: 				return axl_false;
 2500: 			}
 2501: 			
 2502: 		}else {
 2503: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "    using a CHOICE form");
 2504: 
 2505: 			/* it is a sequence, so, item list
 2506: 			 * specification represents the nodes, in the
 2507: 			 * order they must appear */
 2508: 			__axl_dtd_validate_choice (parent, child_position, itemList, error,
 2509: 						   axl_true, top_level);
 2510: 		}
 2511: 		break;
 2512: 	case ZERO_OR_MANY:
 2513: 
 2514: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found a (zero or many) spec..");
 2515: 		if (axl_dtd_item_list_type (itemList) == SEQUENCE) {
 2516: 
 2517: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "    using a SEQUENCE (size: %d) form ",
 2518: 				   axl_dtd_item_list_count (itemList));
 2519: 			/* one this case, several matches must be
 2520: 			 * tried, until the validation fails */
 2521: 			do {
 2522: 				temp_child_pos = *child_position;
 2523: 				status         = __axl_dtd_validate_sequence (parent, child_position, itemList, error, 
 2524: 									      axl_true, top_level);
 2525: 
 2526: 				__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "sequence match status=%d", status);
 2527: 				if (! status) {
 2528: 					/* check that the match wasn't
 2529: 					 * produced, at any level */
 2530: 					if ((temp_child_pos != *child_position)) {
 2531: 
 2532: 						__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "item list mismatch (%d != %d)", 
 2533: 							   temp_child_pos, *child_position);
 2534: 						axl_error_new (-1, "Found an DTD item list definition, that should be matched entirely or not, zero or many times, but it was matched partially",
 2535: 							       NULL, error);
 2536: 						return axl_false;
 2537: 					}
 2538: 				}
 2539: 			}while (status);
 2540: 		}else {
 2541: 
 2542: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "    using a CHOICE form");
 2543: 			/* it is a sequence, so, item list
 2544: 			 * specification represents the nodes, in the
 2545: 			 * order they must appear */
 2546: 			do {
 2547: 				status = __axl_dtd_validate_choice (parent, child_position, itemList, error,
 2548: 								    axl_true, top_level);
 2549: 			}while (status);
 2550: 		}
 2551: 		break;
 2552: 	case ONE_OR_MANY:
 2553: 		/* one or many sequence spec (+) */
 2554: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found a (zero or many) spec..");
 2555: 		if (axl_dtd_item_list_type (itemList) == SEQUENCE) {
 2556: 
 2557: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "    using a SEQUENCE (size: %d) form ",
 2558: 				   axl_dtd_item_list_count (itemList));
 2559: 
 2560: 			/* one this case, several matches must be
 2561: 			 * tried, until the validation fails */
 2562: 			already_matched = axl_false;
 2563: 			do {
 2564: 				temp_child_pos = *child_position;
 2565: 				/* try to match the one or many
 2566: 				   sequence according to the value
 2567: 				   stored inside already matched */
 2568: 				status         = __axl_dtd_validate_sequence (parent, child_position, itemList, error, 
 2569: 									      already_matched, top_level);
 2570: 
 2571: 				__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "sequence match status=%d", status);
 2572: 				if (! status) {
 2573: 					/* check that the match wasn't
 2574: 					 * produced, at any level */
 2575: 					if ((temp_child_pos != *child_position)) {
 2576: 
 2577: 						__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "item list mismatch, matched partially (%d != %d)", 
 2578: 							   temp_child_pos, *child_position);
 2579: 						axl_error_new (-1, 
 2580: 							       "Found an DTD item list definition, that should be matched entirely or not, one or many times, but it was matched partially",
 2581: 							       NULL, error);
 2582: 						return axl_false;
 2583: 					}
 2584: 				}else {
 2585: 					/* set that we have matched, at least, one item */
 2586: 					already_matched = axl_true;
 2587: 				}
 2588: 
 2589: 				
 2590: 
 2591: 			}while (status);
 2592: 		}else {
 2593: 
 2594: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "    using a CHOICE form");
 2595: 			/* it is a sequence, so, item list
 2596: 			 * specification represents the nodes, in the
 2597: 			 * order they must appear */
 2598: 			already_matched = axl_false;
 2599: 			do {
 2600: 				/* the next choice matching is done
 2601: 				 * according to the value stored in
 2602: 				 * already matched */
 2603: 				status = __axl_dtd_validate_choice (parent, child_position, itemList, error,
 2604: 								    already_matched, top_level);
 2605: 				/* if the validation successed, set
 2606: 				 * that next matched are not required
 2607: 				 * to be successful ones */
 2608: 				if (status)
 2609: 					already_matched = axl_true;
 2610: 			}while (status);
 2611: 		}
 2612: 		break;
 2613: 	default:
 2614: 		/* this case will never be reached */
 2615: #define INTERNAL_ERROR_01 "critical error reached a place that shows the dtd parser is not properly defining the repetition pattern for the current itemList."
 2616: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, INTERNAL_ERROR_01);
 2617: 		axl_error_new (-1, INTERNAL_ERROR_01, NULL, error);
 2618: 		return axl_false;
 2619: 	}
 2620: 
 2621: 
 2622: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "validate item list terminated, now check post-conditions, top_level=%d, item list type=%d, child pos=%d, childs num=%d",
 2623: 		   top_level, axl_dtd_item_list_type (itemList), *child_position, axl_node_get_child_num (parent));
 2624: 
 2625: 	/* check that, in the case that the choice item list is being
 2626: 	 * validated, ensure it has validated all nodes, especially if
 2627: 	 * we are the top level definition */
 2628: 	if (top_level && (axl_dtd_item_list_type (itemList) == CHOICE)) {
 2629: 		if (((*child_position) + 1) < axl_node_get_child_num (parent)) {
 2630: 		    
 2631: 
 2632: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "found that the choice list didn't cover all childs (%d), while parent=<%s> has: (%d)",
 2633: 				   (*child_position), axl_node_get_name (parent), axl_node_get_child_num (parent));
 2634: 			axl_error_new (-1, "Found that the validation process didn't cover all nodes, while using a choice list. This means that the xml document have more content than the DTD spec",
 2635: 				       NULL, error);
 2636: 			return axl_false;
 2637: 		}
 2638: 	}
 2639: 	
 2640: 	/* element type children validated */
 2641: 	return axl_true;       
 2642: }
 2643: 
 2644: /** 
 2645:  * @internal
 2646:  *
 2647:  * Support function validate parent nodes which are element type
 2648:  * children ones.
 2649:  */
 2650: axl_bool     __axl_dtd_validate_element_type_children (axlDtdElement  * element, 
 2651: 						       axlNode        * parent, 
 2652: 						       axl_bool         top_level,
 2653: 						       axlError      ** error)
 2654: {
 2655: 	axlDtdElementList * itemList;
 2656: 	int                 child_pos = 0;
 2657: 	char              * err_msg;
 2658: 
 2659: 	/* get a reference to the item list */
 2660: 	itemList = axl_dtd_get_item_list (element);
 2661: 
 2662: 	/* check for xml nodes with fewer content than the initially
 2663: 	 * expected. */
 2664: 	if (axl_node_get_child_num (parent) < element->minimum_match) {
 2665: 		err_msg = axl_strdup_printf ("Found that the parent node (<%s>) received doesn't contains enough xml nodes inside to get a proper validation (childs found (%d) != childs that should be found (%d)). This means that the xml document have fewer content than the DTD spec.",
 2666: 					     axl_node_get_name (parent), 
 2667: 					     axl_node_get_child_num (parent), 
 2668: 					     element->minimum_match);
 2669: 		axl_error_new (-1, err_msg, NULL, error);
 2670: 		axl_free (err_msg);
 2671: 		return axl_false;
 2672: 	}
 2673: 
 2674: 	/* validate the item list, starting from the child 0 */
 2675: 	if (__axl_dtd_validate_item_list (itemList, parent, &child_pos, error, top_level)) {
 2676: 		/* check if, at least, all minimum elements was
 2677: 		 * matched */
 2678: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "checking minimum node match: (%d < min: %d) (%d < childs: %d) node=<%s>", 
 2679: 			   child_pos, element->minimum_match,
 2680: 			   child_pos, axl_node_get_child_num (parent),
 2681: 			   axl_node_get_name (parent));
 2682: 			
 2683: 		if (child_pos < axl_node_get_child_num (parent)) {
 2684: 			axl_error_report (error, -1,
 2685: 					  "Found that the validation process didn't cover all nodes (%d < min:%d) (%d < childs:%d). All xml child nodes inside the parent=<%s> wasn't covered. This means that the xml document have more content than the DTD spec defines.",
 2686: 					  child_pos, element->minimum_match, child_pos, axl_node_get_child_num (parent), 
 2687: 					  axl_node_get_name (parent));
 2688: 			return axl_false;
 2689: 		}
 2690: 		/* seems that the minimum match */
 2691: 		return axl_true;
 2692: 	}
 2693: 
 2694: 	return axl_false;
 2695: }
 2696: 
 2697: /** 
 2698:  * @internal
 2699:  * Internal support function to validate #PCDATA nodes.
 2700:  */
 2701: axl_bool     __axl_dtd_validate_element_type_pcdata (axlDtdElement  * element, 
 2702: 						     axlNode        * parent, 
 2703: 						     axlStack       * stack, 
 2704: 						     axlError      ** error)
 2705: {
 2706: 	/* check for childs */
 2707: 	if (axl_node_have_childs (parent)) {
 2708: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "node <%s> should be #PCDATA and it contains childs",
 2709: 			   axl_node_get_name (parent));
 2710: 		axl_error_new (-1, 
 2711: 			       "Found a node for which its espeficiation makes it to be a node with only data and no childs, and it currently contains childs",
 2712: 			       NULL, error);
 2713: 		return axl_false;
 2714: 	}
 2715: 	
 2716: 	/* return that the validation was ok */
 2717: 	return axl_true;
 2718: }
 2719: 
 2720: /** 
 2721:  * @internal
 2722:  * 
 2723:  * Support function to validate empty nodes.
 2724:  */
 2725: axl_bool     __axl_dtd_validate_element_type_empty (axlDtdElement  * element,
 2726: 						    axlNode        * parent,
 2727: 						    axlStack       * stack,
 2728: 						    axlError      ** error)
 2729: {
 2730: 	char * err_msg;
 2731: 
 2732: 	/* check the node is indeed, empty */
 2733: 	if (! axl_node_is_empty (parent)) {
 2734: 		err_msg = axl_strdup_printf (
 2735: 			"Found a node <%s> that it is especified that must be empty, but it isn't",
 2736: 			axl_node_get_name (parent));
 2737: 		axl_error_new (-1, err_msg, NULL, error);
 2738: 		axl_free (err_msg);
 2739: 		return axl_false;
 2740: 	}
 2741: 
 2742: 	/* check the node doesn't have childs */
 2743: 	if (axl_node_have_childs (parent)) {
 2744: 		err_msg = axl_strdup_printf (
 2745: 			"Found a node <%s> that it is especified that must be empty, but it has childs",
 2746: 			axl_node_get_name (parent));
 2747: 		axl_error_new (-1, err_msg, NULL, error);
 2748: 		axl_free (err_msg);
 2749: 		return axl_false;
 2750: 	}
 2751: 	
 2752: 	/* return that the validation was ok */
 2753: 	return axl_true;
 2754: }
 2755: 
 2756: axl_bool __axl_dtd_attr_validate_foreach (const char * key, const char * value, axlPointer data, axlPointer data2)
 2757: {
 2758: 	axlDtdAttribute     * attribute = data;
 2759: 	axlError           ** error     = data2;
 2760: 	axlDtdAttributeDecl * decl;
 2761: 	char                * err_msg;
 2762: 
 2763: 	/* get declaration associated */
 2764: 	decl = axl_list_lookup (attribute->list, __find_attr_decl, (axlPointer) key);
 2765: 	
 2766: 	if (decl == NULL) {
 2767: 		/* found an error */
 2768: 		err_msg = axl_strdup_printf ("Found an attribute (%s) which is not specified by the attribute declaration for <%s>",
 2769: 					     key, attribute->name);
 2770: 		axl_error_new (-1, err_msg, NULL, error);
 2771: 		
 2772: 		/* free the cursor and the error message */
 2773: 		axl_free (err_msg);
 2774: 
 2775: 		/* return axl_true here because we want to stop the process */
 2776: 		return axl_true;
 2777: 		
 2778: 	} /* end if */
 2779: 
 2780: 	/* if the declaration is found, now check its
 2781: 	 * contraints */
 2782: 	axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "checking contraint for attribute: %s=%s", decl->name, value);
 2783: 	if (decl->type == CDATA_ATTRIBUTE) {
 2784: 		/* found free attribute declaration, go ahed */
 2785: 	} else if (decl->type == ENUMERATION_TYPE) {
 2786: 		/* found an enumeration type, check and return */
 2787: 		if (axl_list_lookup (decl->enumvalues, axl_list_find_string, (char *) value) == NULL) {
 2788: 			/* found an error */
 2789: 			err_msg = axl_strdup_printf ("Found an attribute (%s) with a value not allowed by the enum declaration (%s) for the node <%s>",
 2790: 						     key, value, attribute->name);
 2791: 			axl_error_new (-1, err_msg, NULL, error);
 2792: 			
 2793: 			/* free the cursor and the error message */
 2794: 			axl_free (err_msg);
 2795: 			return axl_true;
 2796: 		}
 2797: 	} else {
 2798: 		/* not supported yet */
 2799: 	}
 2800: 
 2801: 	/* return axl_false to continue with the process */
 2802: 	return axl_false;
 2803: }
 2804: 
 2805: axl_bool __axl_dtd_attr_validate_required (axlPointer element, axlPointer data)
 2806: {
 2807: 	axlNode             * node = data;
 2808: 	axlDtdAttributeDecl * decl = element;
 2809: 
 2810: 	switch (decl->defaults) {
 2811: 	case ATT_REQUIRED:
 2812: 		/* attribute required */
 2813: 		return !HAS_ATTR (node, decl->name);
 2814: 	case ATT_FIXED:
 2815: 		return !HAS_ATTR_VALUE (node, decl->name, decl->default_value);
 2816: 	default:
 2817: 		break;
 2818: 	} /* end switch */
 2819: 
 2820: 	/* return axl_false for this because it is not obligatory
 2821: 	 * to have the attribute defined. */
 2822: 	return axl_false;
 2823: }
 2824: 
 2825: /** 
 2826:  * @internal Functions which validates the attribute declaration for
 2827:  * the node provided, using attribute declarations found.
 2828:  * 
 2829:  * @param node The node to check for its attributes.
 2830:  *
 2831:  * @param dtd The dtd used to validate the node provided.
 2832:  *
 2833:  * @param error A reference to the axlError where the textual
 2834:  * diagnostic error will be reported.
 2835:  * 
 2836:  * @return axl_true if the node is validated, axl_false if not.
 2837:  */
 2838: axl_bool axl_dtd_attr_validate (axlNode * node, axlDtd * dtd, axlError ** error, axlHash * id_validation, axlList * idref_validation)
 2839: {
 2840: 	axlDtdAttribute     * attribute;
 2841: 	axlDtdAttributeDecl * decl;
 2842: 	char                * err_msg;
 2843: 	int                   iterator;
 2844: 	axlError            * _error = NULL;
 2845: 
 2846: 	/* find attribute contraints for the node */
 2847: 	attribute = axl_dtd_get_attr (dtd, axl_node_get_name (node));
 2848: 	if (attribute == NULL)
 2849: 		return axl_true;
 2850: 
 2851: 	/* we have an especification, run it */
 2852: 
 2853: 	/* for each attribute found, check against the spec */
 2854: 	axl_node_attr_foreach (node, __axl_dtd_attr_validate_foreach, attribute, &_error);
 2855: 
 2856: 	/* check the error */
 2857: 	if (! axl_error_was_ok (_error)) {
 2858: 		/* reconfigure error returned */
 2859: 		if (error != NULL)
 2860: 			*error = _error;
 2861: 		return axl_false;
 2862: 	} /* end if */
 2863: 		
 2864: 	
 2865: 	/* now, for each contraint, check that all required nodes
 2866: 	 * exists */
 2867: 	decl = axl_list_lookup (attribute->list, __axl_dtd_attr_validate_required, node);
 2868: 	if (decl != NULL) {
 2869: 		if (decl->defaults == ATT_FIXED)
 2870: 			err_msg = axl_strdup_printf ("attribute required '%s' (or its value), due to #FIXED declaration, not found for node <%s>", 
 2871: 						     decl->name, attribute->name);
 2872: 		else 
 2873: 			err_msg = axl_strdup_printf ("attribute required '%s', due to #REQUIRED declaration, not found for node <%s>", 
 2874: 						     decl->name, attribute->name);
 2875: 		axl_error_new (-1, err_msg, NULL, error);
 2876: 		axl_free (err_msg);
 2877: 		return axl_false;
 2878: 	} /* end if */
 2879: 
 2880: 	/* check declarations */
 2881: 	if (dtd->haveIdDecl) {
 2882: 
 2883: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found DTD has ID unique attribute declaration..");
 2884: 		
 2885: 		/* check if the node have TOKENIZED_TYPE_ID */
 2886: 		decl = axl_list_lookup (attribute->list, __find_id_decl, NULL);
 2887: 		
 2888: 		/* if we have a tokenized */
 2889: 		if (decl != NULL) {
 2890: 
 2891: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found ID unique attribute declaration %s=\"%s\"..",
 2892: 				   decl->name, ATTR_VALUE (node, decl->name));
 2893: 
 2894: 			/* check if the attribute value for the decl that is
 2895: 			 * flagged as ID is already found at the
 2896: 			 * id_validation */
 2897: 			if (axl_hash_exists (id_validation, (axlPointer) ATTR_VALUE (node, decl->name))) {
 2898: 				err_msg = axl_strdup_printf ("DTD declared the attribute '%s' as unique (ID) for the node %s, but was found used several times",
 2899: 							     decl->name, attribute->name);
 2900: 				axl_error_new (-1, err_msg, NULL, error);
 2901: 				axl_free (err_msg);
 2902: 				return axl_false;
 2903: 			} /* end if */
 2904: 			
 2905: 			/* seems the attribute was not used, nice!, store it */
 2906: 			axl_hash_insert (id_validation, (axlPointer) ATTR_VALUE (node, decl->name), (axlPointer) ATTR_VALUE (node, decl->name));
 2907: 		} /* end if */
 2908: 	} /* end if */
 2909: 
 2910: 	if (dtd->haveIdRefDecl) {
 2911: 		/* find the id ref declaration */
 2912: 		
 2913: 		iterator = 0;
 2914: 		while (iterator < axl_list_length (attribute->list)) {
 2915: 			
 2916: 			/* get the attribute declaration at the
 2917: 			 * particular position */
 2918: 			decl = axl_list_get_nth (attribute->list, iterator);
 2919: 			if (decl->type == TOKENIZED_TYPE_IDREF) {
 2920: 				/* found a reference, but do not check
 2921: 				 * it at this place becase the
 2922: 				 * reference could be placed at any
 2923: 				 * part in the document event after
 2924: 				 * the reference pointed is
 2925: 				 * defined. store and check later */
 2926: 				if (ATTR_VALUE (node, decl->name)) {
 2927: 					/* store the id ref reference
 2928: 					 * if defined */
 2929: 					axl_list_add (idref_validation, (axlPointer) ATTR_VALUE (node, decl->name));
 2930: 				}
 2931: 			} /* end if */
 2932: 
 2933: 			/* get the next */
 2934: 			iterator++;
 2935: 			
 2936: 		} /* end if */
 2937: 		
 2938: 	} /* end if */
 2939: 
 2940: 	axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "attributes validated for node=<%s>", attribute->name);
 2941: 	
 2942: 	return axl_true;
 2943: }
 2944: 
 2945: /** 
 2946:  * @internal Function used by axl_dtd_validate_references to ensure
 2947:  * that all references found point to a valid reference defined.
 2948:  */
 2949: axl_bool __axl_dtd_reference_check (axlPointer _element, axlPointer data)
 2950: {
 2951: #if defined(SHOW_DEBUG_LOG)
 2952: 	const char * value = _element;
 2953: 
 2954: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "checking id ref: %s", value);
 2955: #endif
 2956: 
 2957: 	return ! axl_hash_exists ((axlHash *) data, _element);
 2958: }
 2959: 
 2960: /** 
 2961:  * @internal Function that validates all references found (from IDREF
 2962:  * attribute) to unique references (defined by ID attributes).
 2963:  *
 2964:  */
 2965: axl_bool axl_dtd_validate_references (axlHash * id_validation, axlList * idref_validation, axlError ** error)
 2966: {
 2967: 	char * reference;
 2968: 	char * err_msg;
 2969: 	
 2970: 	/* if no empty at the valiadtion reference list, means not
 2971: 	 * reference was done, so there is no room for errors */
 2972: 	if (idref_validation == NULL) 
 2973: 		return axl_true;
 2974: 	
 2975: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "id_validation reference: 0x%x", id_validation);
 2976: 
 2977: 	/* find first reference not found */
 2978: 	reference = axl_list_lookup (idref_validation, __axl_dtd_reference_check, id_validation);
 2979: 	
 2980: 	if (reference != NULL) {
 2981: 		/* found a reference not defined, report it to the
 2982: 		 * application level */
 2983: 		err_msg = axl_strdup_printf ("Found a reference defined ('%s') which is not found in any ID attribute in the document",
 2984: 					     reference);
 2985: 		axl_error_new (-1, err_msg, NULL, error);
 2986: 		axl_free (err_msg);
 2987: 
 2988: 		return axl_false;
 2989: 	} /* end if */
 2990: 	
 2991: 	/* validation ok */
 2992: 	return axl_true;
 2993: }
 2994: 
 2995: /** 
 2996:  * @brief Allows to validate the given XML document (\ref axlDoc)
 2997:  * against the given document type definition (DTD, \ref axlDtd).
 2998:  *
 2999:  * This function allows to validate your XML documents providing the
 3000:  * document type definition, that was read using \ref axl_dtd_parse or
 3001:  * \ref axl_dtd_parse_from_file.
 3002:  *
 3003:  * Keep in mind that a document could be well-formed and valid. The
 3004:  * only difference is that valid XML document are those that, meet all
 3005:  * XML rules, but also are clasified and recognized as XML documents
 3006:  * with some particular structure, that is represented (or
 3007:  * constrained) with providing a DTD definition.
 3008:  *
 3009:  * @param doc The \ref axlDoc containing the XML document to be
 3010:  * validated.
 3011:  *
 3012:  * @param dtd The \ref axlDtd containing the DTD definition used to
 3013:  * validate the document.
 3014:  *
 3015:  * @param error An optional reference to a \ref axlError object where
 3016:  * validation errors are reported.
 3017:  *
 3018:  * @return axl_true if the document is valid, axl_false if not.
 3019:  */
 3020: axl_bool           axl_dtd_validate        (axlDoc * doc, axlDtd * dtd,
 3021: 					    axlError ** error)
 3022: {
 3023: 	axlNode            * parent;
 3024: 	axlStack           * stack;
 3025: 	axlHash            * id_validation = NULL;
 3026: 	axlList            * idref_validation = NULL;
 3027: 	
 3028: 	axlDtdElement      * element;
 3029: 	axl_bool             top_level;
 3030: 	char               * err_msg;
 3031: 	axl_bool             result;
 3032: 	
 3033: 	/* perform some checkings */
 3034: 	axl_return_val_if_fail (doc, axl_false);
 3035: 	axl_return_val_if_fail (dtd, axl_false);
 3036: 
 3037: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "starting DTD validation");
 3038: 
 3039: 	/* validate the very first root node */
 3040: 	parent  = axl_doc_get_root (doc);
 3041: 	element = axl_dtd_get_root (dtd);
 3042: 	if ((element != NULL) && ! NODE_CMP_NAME (parent, axl_dtd_get_element_name (element))) {
 3043: 
 3044: 		/* because a DTD document could have several top level
 3045: 		 * elements, ensure this is not the case */
 3046: 		element = axl_dtd_get_element (dtd, axl_node_get_name (parent));
 3047: 		if (element == NULL) { /*  || ! axl_dtd_element_is_toplevel (dtd, element)) { */
 3048: 			/* root node doesn't match */
 3049: 			err_msg = axl_strdup_printf ("Found that root node doesn't match (%s != %s!",
 3050: 						     axl_node_get_name (parent), 
 3051: 						     axl_dtd_get_element_name (element));
 3052: 			axl_error_new (-1, err_msg, NULL, error);
 3053: 			axl_free (err_msg);
 3054: 			return axl_false;
 3055: 
 3056: 		} /* end if */
 3057: 	} /* end if */
 3058: 
 3059: 	/* check if the node has DTD element declaration */
 3060: 	if (element == NULL) {
 3061: 		err_msg = axl_strdup_printf ("There is not DTD element declaration to validate the node <%s>", 
 3062: 					     axl_node_get_name (parent));
 3063: 		axl_error_new (-1, err_msg, NULL, error);
 3064: 		axl_free (err_msg);
 3065: 		return axl_false;
 3066: 	} /* end if */
 3067: 
 3068: 	/* check if the dtd contains a Id declaration */
 3069: 	if (dtd->haveIdDecl) {
 3070: 		/* seems the user have declarted ID attributes init the hash */
 3071: 		id_validation = axl_hash_new (axl_hash_string, axl_hash_equal_string);
 3072: 	} /* end if */
 3073: 
 3074: 	/* check if the dtd contains Id ref declarations */
 3075: 	if (dtd->haveIdRefDecl) {
 3076: 		/* create a list that could contain all references done */
 3077: 		idref_validation = axl_list_new (axl_list_always_return_1, NULL);
 3078: 	} /* end if */
 3079: 
 3080: 	/* check empty content spec */
 3081: 	if (axl_dtd_get_element_type (element) == ELEMENT_TYPE_EMPTY) {
 3082: 		/* check if the document provided have only one node */
 3083: 		result = axl_node_is_empty (parent) && !axl_node_have_childs (parent) && axl_dtd_attr_validate (parent, dtd, error, id_validation, idref_validation);
 3084: 
 3085: 		/* check references */
 3086: 		if (result)
 3087: 			result = axl_dtd_validate_references (id_validation, idref_validation, error);
 3088: 		
 3089: 		/* free and return */
 3090: 		axl_hash_free (id_validation);
 3091: 
 3092: 		/* free the list */
 3093: 		axl_list_free (idref_validation);
 3094: 		return result;
 3095: 	} /* end if */
 3096: 
 3097: 	/* queue initial nodes to validate */
 3098: 	stack     = axl_stack_new (NULL);
 3099: 	
 3100: 
 3101: 	/* set that the only top level node is the first one */
 3102: 	top_level = axl_true;
 3103: 
 3104: 	do {
 3105: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "doing a DTD iteration: <%s>...",
 3106: 			   axl_node_get_name (parent));
 3107: 
 3108: 		/* validate attributes */
 3109: 		if (! axl_dtd_attr_validate (parent, dtd, error, id_validation, idref_validation)) {
 3110: 			/* free the stack */
 3111: 			axl_stack_free (stack);
 3112: 
 3113: 			/* free id_validation */
 3114: 			axl_hash_free (id_validation);
 3115: 
 3116: 			/* free the list */
 3117: 			axl_list_free (idref_validation);
 3118: 			return axl_false;
 3119: 		}
 3120: 
 3121: 		/* reach this position, the <parent> reference contains
 3122: 		 * a reference to the parent node, which will be used
 3123: 		 * to validate current child content against current
 3124: 		 * configuration for dtd element constraining it.
 3125: 		 * 
 3126: 		 * equally, the <element> reference contains a dtd
 3127: 		 * reference to the already checked DTD element which
 3128: 		 * configure this parent node. */
 3129: 		switch (axl_dtd_get_element_type (element)) {
 3130: 		case ELEMENT_TYPE_PCDATA:
 3131: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "  find  PCDATA dtd element=%s: parent=<%s>, ",
 3132: 				   axl_dtd_get_element_name (element), 
 3133: 				   axl_node_get_name (parent));
 3134: 
 3135: 			/* ok, a leaf node was found, know it is
 3136: 			 * required to check that the node doesn't
 3137: 			 * have more childs and only have content,
 3138: 			 * that is, it is not empty  */
 3139: 			if (!__axl_dtd_validate_element_type_pcdata (element, parent, stack, error)) {
 3140: 				/* free id_validation */
 3141: 				axl_hash_free (id_validation);
 3142: 
 3143: 				/* free the stack */
 3144: 				axl_stack_free (stack);
 3145: 				
 3146: 				/* free the list */
 3147: 				axl_list_free (idref_validation);
 3148: 				return axl_false;
 3149: 			}
 3150: 			break;
 3151: 		case ELEMENT_TYPE_CHILDREN:
 3152: 
 3153: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "  find  CHILDREN dtd element");
 3154: 			/* ok, a parent node that have childs */
 3155: 			if (!__axl_dtd_validate_element_type_children (element, parent, top_level, error)) {
 3156: 				/* free id_validation */
 3157: 				axl_hash_free (id_validation);
 3158: 
 3159: 				/* free the stack */
 3160: 				axl_stack_free (stack);
 3161: 
 3162: 				/* free the list */
 3163: 				axl_list_free (idref_validation);
 3164: 				
 3165: 				return axl_false;
 3166: 			}
 3167: 			break;
 3168: 		case ELEMENT_TYPE_EMPTY:
 3169: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "  find  EMPTY dtd element");
 3170: 			/* the element especification is empty, the
 3171: 			 * node being validated must also be the
 3172: 			 * same */
 3173: 			if (!__axl_dtd_validate_element_type_empty (element, parent, stack, error)) {
 3174: 				/* free id_validation */
 3175: 				axl_hash_free (id_validation);
 3176: 
 3177: 				/* free the stack */
 3178: 				axl_stack_free (stack);
 3179: 
 3180: 				/* free the list */
 3181: 				axl_list_free (idref_validation);
 3182: 
 3183: 				return axl_false;
 3184: 			}
 3185: 			break;
 3186: 		case ELEMENT_TYPE_ANY:
 3187: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "  find  ANY dtd element");
 3188: 			/* the anything is allowed cased from this
 3189: 			 * parent node. */
 3190: 			goto continue_with_validation;
 3191: 		case ELEMENT_TYPE_MIXED:
 3192: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "  find  MIXED dtd element");
 3193: 
 3194: 			/* the mixed case, where nodes and PC data
 3195: 			 * could be mixed */
 3196: 			break;
 3197: 		default:
 3198: 			/* do not do any thing on this case */
 3199: 			break;
 3200: 		}
 3201: 			
 3202: 		/* queue more childs, as future parents to be
 3203: 		 * validated on the provided queue, only in the case
 3204: 		 * the parent node have childs */
 3205: 		if (axl_node_have_childs (parent)) {
 3206: 
 3207: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "parent node <%s> have childs, adding its childs (stack size: %d)",
 3208: 				   axl_node_get_name (parent),
 3209: 				   axl_stack_size (stack));
 3210: 
 3211: 			/* queue childs to be processed */
 3212: 			__axl_dtd_queue_childs (stack, parent);
 3213: 
 3214: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "parent node <%s> childs: %d, (stack size: %d)",
 3215: 				   axl_node_get_name (parent), axl_node_get_child_num (parent),
 3216: 				   axl_stack_size (stack));
 3217: 		}
 3218: 		
 3219: 		/* set the parent reference to NULL */
 3220: 		parent = NULL;
 3221: 			
 3222: 		/* update the reference to the new parent node, only
 3223: 		 * if there are new parents on the stack */
 3224: 	continue_with_validation:
 3225: 		if (! axl_stack_is_empty (stack)) {
 3226: 
 3227: 
 3228: 			/* get a new reference */
 3229: 			parent  = axl_stack_pop (stack);
 3230: 			
 3231: 			/* get a reference to the DTD element to used */
 3232: 			element = axl_dtd_get_element (dtd, axl_node_get_name (parent));
 3233: 			if (element == NULL) {
 3234: 				__axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "found that the node <%s> doesn't have DTD especification", 
 3235: 					   axl_node_get_name (parent));
 3236: 				/* prepare the error message */
 3237: 				err_msg = axl_strdup_printf ("Found a node <%s> that doesn't have a DTD element espefication to validate it, DTD validation failed",
 3238: 							     axl_node_get_name (parent));
 3239: 				axl_error_new (-1, err_msg, NULL, error);
 3240: 				axl_free (err_msg);
 3241: 
 3242: 				/* free id_validation */
 3243: 				axl_hash_free (id_validation);
 3244: 
 3245: 				/* free the list */
 3246: 				axl_list_free (idref_validation);
 3247: 
 3248: 				/* free the stack */
 3249: 				axl_stack_free (stack);
 3250: 				return axl_false;
 3251: 			} /* end if */
 3252: 		} /* end if */
 3253: 
 3254: 		/* set the top level status */
 3255: 		top_level = axl_false;
 3256: 		
 3257: 		/* until the stack is empty */
 3258: 	}while (parent != NULL);
 3259: 
 3260: 	/* check references */
 3261: 	result = axl_dtd_validate_references (id_validation, idref_validation, error);
 3262: 
 3263: 	/* deallocate stack used */
 3264: 	axl_stack_free (stack);
 3265: 
 3266: 	/* free id_validation */
 3267: 	axl_hash_free (id_validation);
 3268: 
 3269: 	/* free the list */
 3270: 	axl_list_free (idref_validation);
 3271: 
 3272: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "DTD validation, %s", result ? "ok" : "failed");
 3273: 
 3274: 	/* the document is valid */
 3275: 	return result;
 3276: }
 3277: 
 3278: /** 
 3279:  * @brief Allows to check if the provided two references represents
 3280:  * DTD documents with the same rules. 
 3281:  * 
 3282:  * @param dtd First reference to compare.
 3283:  * @param dtd2 Second reference to compare.
 3284:  *
 3285:  * @return axl_true if both references represent the same document. If
 3286:  * some of the references received are NULL the function returns
 3287:  * axl_false.
 3288:  *
 3289:  * NOTE: The function does not have the ability to perform a smart
 3290:  * equal operation like detecting DTD that are semantically
 3291:  * equivalent. It only checks internal structure. 
 3292:  */
 3293: axl_bool                 axl_dtd_are_equal        (axlDtd * dtd,
 3294: 						   axlDtd * dtd2)
 3295: {
 3296: 	int iterator;
 3297: 	int iterator2;
 3298: 	int iterator3;
 3299: 	axlDtdEntity          * entity,      * entity2;
 3300: 	axlDtdElement         * element,     * element2;
 3301: 	axlDtdElementListNode * node,        * node2;
 3302: 	axlDtdAttribute       * attribute,   * attribute2;
 3303: 	axlDtdAttributeDecl   * attr_decl,   * attr_decl2;
 3304: 
 3305: 	/* check references received */
 3306: 	if (dtd == NULL)
 3307: 		return axl_false;
 3308: 	if (dtd2 == NULL)
 3309: 		return axl_false;
 3310: 
 3311: 	/* check each rule inside both documents */
 3312: 	if (axl_list_length (dtd->entities) != axl_list_length (dtd2->entities))
 3313: 		return axl_false;
 3314: 	if (axl_list_length (dtd->elements) != axl_list_length (dtd2->elements))
 3315: 		return axl_false;
 3316: 	if (axl_list_length (dtd->attributes) != axl_list_length (dtd2->attributes))
 3317: 		return axl_false;
 3318: 	if (dtd->haveIdRefDecl != dtd2->haveIdRefDecl)
 3319: 		return axl_false;
 3320: 	if (dtd->haveIdDecl != dtd2->haveIdDecl)
 3321: 		return axl_false;
 3322: 
 3323: 	/* now check inner elements (ENTITIES) */
 3324: 	iterator = 0;
 3325: 	while (iterator < axl_list_length (dtd->entities)) {
 3326: 		/* get referneces */
 3327: 		entity  = axl_list_get_nth (dtd->entities, iterator);
 3328: 		entity2 = axl_list_get_nth (dtd2->entities, iterator);
 3329: 
 3330: 		/* check types */
 3331: 		if (entity->type != entity2->type)
 3332: 			return axl_false;
 3333: 
 3334: 		/* check names */
 3335: 		if (! axl_cmp (entity->name, entity2->name)) 
 3336: 			return axl_false;
 3337: 
 3338: 		/* check content */
 3339: 		if (! axl_cmp (entity->content, entity2->content))
 3340: 			return axl_false;
 3341: 
 3342: 		/* check external data */
 3343: 		if (entity->data == NULL && entity2->data != NULL)
 3344: 			return axl_false;
 3345: 		if (entity->data != NULL && entity2->data == NULL)
 3346: 			return axl_false;
 3347: 		if (entity->data != NULL && entity2->data != NULL) {
 3348: 			if (! axl_cmp (entity->data->system_literal, entity2->data->system_literal))
 3349: 				return axl_false;
 3350: 			if (! axl_cmp (entity->data->public_literal, entity2->data->public_literal))
 3351: 				return axl_false;
 3352: 			if (! axl_cmp (entity->data->ndata, entity2->data->ndata))
 3353: 				return axl_false;
 3354: 		} /* end if */
 3355: 
 3356: 		/* next iterator */
 3357: 		iterator++;
 3358: 	} /* end while */
 3359: 
 3360: 	/* now check inner elements (ELEMENTS) */
 3361: 	iterator = 0;
 3362: 	while (iterator < axl_list_length (dtd->elements)) {
 3363: 		/* get referneces */
 3364: 		element  = axl_list_get_nth (dtd->elements, iterator);
 3365: 		element2 = axl_list_get_nth (dtd2->elements, iterator);
 3366: 
 3367: 		/* check types */
 3368: 		if (element->type != element2->type)
 3369: 			return axl_false;
 3370: 
 3371: 		/* minimum match */
 3372: 		if (element->minimum_match != element2->minimum_match)
 3373: 			return axl_false;
 3374: 
 3375: 		/* check names */
 3376: 		if (! axl_cmp (element->name, element2->name)) 
 3377: 			return axl_false;
 3378: 
 3379: 		/* check element list */
 3380: 		if (element->list == NULL && element2->list != NULL)
 3381: 			return axl_false;
 3382: 		if (element->list != NULL && element2->list == NULL)
 3383: 			return axl_false;
 3384: 		if (element->list != NULL && element2->list != NULL) {
 3385: 
 3386: 			/* check internal values */
 3387: 			if (element->list->type != element2->list->type)
 3388: 				return axl_false;
 3389: 			if (element->list->times != element2->list->times)
 3390: 				return axl_false;
 3391: 
 3392: 			iterator2 = 0;
 3393: 			while (iterator2 < axl_list_length (element->list->itemList)) {
 3394: 				
 3395: 				/* get references */
 3396: 				node  = axl_list_get_nth (element->list->itemList, iterator2);
 3397: 				node2 = axl_list_get_nth (element2->list->itemList, iterator2);
 3398: 
 3399: 				if (node->type != node->type)
 3400: 					return axl_false;
 3401: 				if (node->times != node2->times)
 3402: 					return axl_false;
 3403: 				
 3404: 				/* next value */
 3405: 				iterator2++;
 3406: 
 3407: 			} /* end while */
 3408: 			
 3409: 		} /* end if */
 3410: 
 3411: 		/* next iterator */
 3412: 		iterator++;
 3413: 	} /* end while */
 3414: 
 3415: 	/* now check inner elements (ATTRIBUTES) */
 3416: 	iterator = 0;
 3417: 	while (iterator < axl_list_length (dtd->attributes)) {
 3418: 		/* get referneces */
 3419: 		attribute  = axl_list_get_nth (dtd->attributes, iterator);
 3420: 		attribute2 = axl_list_get_nth (dtd2->attributes, iterator);
 3421: 
 3422: 		/* check names */
 3423: 		if (! axl_cmp (attribute->name, attribute2->name)) 
 3424: 			return axl_false;
 3425: 
 3426: 		/* check values */
 3427: 		if (attribute->list == NULL && attribute2->list != NULL)
 3428: 			return axl_false;
 3429: 		if (attribute->list != NULL && attribute2->list == NULL)
 3430: 			return axl_false;
 3431: 		if (attribute->list != NULL && attribute2->list != NULL) {
 3432: 
 3433: 			/* check list length */
 3434: 			if (axl_list_length (attribute->list) != axl_list_length (attribute2->list))
 3435: 				return axl_false;
 3436: 
 3437: 			/* check internal values */
 3438: 			iterator2 = 0;
 3439: 			while (iterator2 < axl_list_length (attribute->list)) {
 3440: 				
 3441: 				/* get references */
 3442: 				attr_decl   = axl_list_get_nth (attribute->list,  iterator2);
 3443: 				attr_decl2  = axl_list_get_nth (attribute2->list, iterator2);
 3444: 
 3445: 				if (attr_decl->type != attr_decl2->type)
 3446: 					return axl_false;
 3447: 				if (attr_decl->defaults != attr_decl2->defaults)
 3448: 					return axl_false;
 3449: 				if (! axl_cmp (attr_decl->name, attr_decl2->name))
 3450: 					return axl_false;
 3451: 				
 3452: 				if (attr_decl->enumvalues == NULL && attr_decl2->enumvalues != NULL)
 3453: 					return axl_false;
 3454: 				if (attr_decl->enumvalues != NULL && attr_decl2->enumvalues == NULL)
 3455: 					return axl_false;
 3456: 				if (attr_decl->enumvalues != NULL && attr_decl2->enumvalues != NULL) {
 3457: 					if (axl_list_length (attr_decl->enumvalues) != axl_list_length (attr_decl2->enumvalues))
 3458: 						return axl_false;
 3459: 					iterator3 = 0;
 3460: 					while (iterator3 < axl_list_length (attr_decl->enumvalues)) {
 3461: 						/* check values */
 3462: 						if (! axl_cmp (axl_list_get_nth (attr_decl->enumvalues, iterator3),
 3463: 							       axl_list_get_nth (attr_decl2->enumvalues, iterator3)))
 3464: 							return axl_false;
 3465: 
 3466: 						/* next value */
 3467: 						iterator3++;
 3468: 					} /* end while */
 3469: 				} /* end if */
 3470: 				
 3471: 				/* next value */
 3472: 				iterator2++;
 3473: 
 3474: 			} /* end while */
 3475: 			
 3476: 		} /* end if */
 3477: 
 3478: 		/* next iterator */
 3479: 		iterator++;
 3480: 	} /* end while */
 3481: 
 3482: 	return axl_true;
 3483: 	
 3484: }
 3485: 
 3486: /** 
 3487:  * @brief Allows to get the root node for the provided DTD.
 3488:  *
 3489:  * Every DTD have a root node defined, which is the root node accepted
 3490:  * for the set of XML document considered to be valid under the
 3491:  * definition of the DTD provided.
 3492:  *
 3493:  * The value returned is the name of the root node that must have the
 3494:  * XML document being validated.
 3495:  * 
 3496:  * @param dtd The \ref axlDtd where the root node name will be
 3497:  * returned.
 3498:  * 
 3499:  * @return A reference to the internal representation of the root node
 3500:  * Value must not be deallocated.
 3501:  */
 3502: axlDtdElement  * axl_dtd_get_root        (axlDtd * dtd)
 3503: {
 3504: 	axl_return_val_if_fail (dtd, NULL);
 3505: 	
 3506: 	/* return current status for the root node */
 3507: 	if (dtd->root == NULL) {
 3508: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "dtd root element not defined");
 3509: 		return NULL;
 3510: 	}
 3511: 	return dtd->root;
 3512: }
 3513: 
 3514: /** 
 3515:  * @internal function used by \ref axl_dtd_get_element to perform node
 3516:  * lookups.
 3517:  */
 3518: axl_bool __find_dtd_element (axlPointer _element, axlPointer data)
 3519: {
 3520: 	axlDtdElement * element = _element;
 3521: 	char          * name    = data;
 3522: 
 3523: 	/* check the name */
 3524: 	if (axl_cmp (element->name, name))
 3525: 		return axl_true;
 3526: 
 3527: 	/* it is not the element */
 3528: 	return axl_false;
 3529: }
 3530: 
 3531: /** 
 3532:  * @brief Allows to get the DTD element (\ref axlDtdElement), inside
 3533:  * the provided DTD (\ref axlDtd), that represent the spefication for
 3534:  * the node called by the provided name.
 3535:  * 
 3536:  * @param dtd The DTD (\ref axlDtd) where the lookup will be
 3537:  * performed.
 3538:  *
 3539:  * @param name The element name to lookup.
 3540:  * 
 3541:  * @return A reference to the \ref axlDtdElement searched or NULL if
 3542:  * fails. The function also returns NULL if values received are NULL.
 3543:  */
 3544: axlDtdElement      * axl_dtd_get_element      (axlDtd * dtd, const char * name)
 3545: {
 3546: 
 3547: 	axl_return_val_if_fail (dtd, NULL);
 3548: 	axl_return_val_if_fail (name, NULL);
 3549: 
 3550: 	/* perform the lookup */
 3551: 	return axl_list_lookup (dtd->elements, __find_dtd_element, (axlPointer) name);
 3552: }
 3553: 
 3554: /** 
 3555:  * @internal function used by \ref axl_dtd_get_attr to perform node
 3556:  * lookups.
 3557:  */
 3558: axl_bool __find_dtd_attr (axlPointer _element, axlPointer data)
 3559: {
 3560: 	axlDtdAttribute * attr = _element;
 3561: 	char            * name = data;
 3562: 
 3563: 	/* check the name */
 3564: 	if (axl_cmp (attr->name, name))
 3565: 		return axl_true;
 3566: 
 3567: 	/* it is not the element */
 3568: 	return axl_false;
 3569: }
 3570: 
 3571: /** 
 3572:  * @brief Allows to get the set of attribute declerations for a
 3573:  * particular node. 
 3574:  *
 3575:  * The \ref axlDtdAttribute declaration contains all constraints
 3576:  * configured for attributes found for the particular xml node
 3577:  * (identified by <b>name</b>).
 3578:  * 
 3579:  * @param dtd A reference to the DTD document.
 3580:  *
 3581:  * @param nodeName The xml node that is requested to return all attribute
 3582:  * declarations.
 3583:  * 
 3584:  * @return A reference to the \ref axlDtdAttribute or NULL if it
 3585:  * fails.
 3586:  */
 3587: axlDtdAttribute    * axl_dtd_get_attr         (axlDtd * dtd,
 3588: 					       const char * nodeName)
 3589: {
 3590: 	axl_return_val_if_fail (dtd, NULL);
 3591: 	axl_return_val_if_fail (nodeName, NULL);
 3592: 
 3593: 	/* perform the lookup */
 3594: 	return axl_list_lookup (dtd->attributes, __find_dtd_attr, (axlPointer) nodeName);
 3595: }
 3596: 
 3597: /** 
 3598:  * @brief Allows to get the number of constraints that have been
 3599:  * configured for the particular node.
 3600:  * 
 3601:  * @param dtd The reference to the DTD document.
 3602:  *
 3603:  * @param nodeName The name of the node that is being asked for its
 3604:  * constraints.
 3605:  * 
 3606:  * @return 0 or the number of contraints. The function return -1 if
 3607:  * any of the parameter received is null.
 3608:  */
 3609: int                  axl_dtd_get_attr_contraints (axlDtd * dtd,
 3610: 						  const char * nodeName)
 3611: {
 3612: 	axlDtdAttribute * attr;
 3613: 
 3614: 	axl_return_val_if_fail (dtd, -1);
 3615: 	axl_return_val_if_fail (nodeName, -1);
 3616: 
 3617: 	/* get the attribute specification for the node */
 3618: 	attr = axl_dtd_get_attr (dtd, nodeName);
 3619: 
 3620: 	/* return the number of items */
 3621: 	return axl_list_length (attr->list);
 3622: }
 3623: 
 3624: /** 
 3625:  * @brief Returns the name of the provided \ref axlDtdElement.
 3626:  * 
 3627:  * @param element A reference to a \ref axlDtdElement where the name
 3628:  * will be returned.
 3629:  * 
 3630:  * @return A reference to the internal DTD element name. Returned
 3631:  * value mustn't be deallocated.
 3632:  */
 3633: char           * axl_dtd_get_element_name (axlDtdElement * element)
 3634: {
 3635: 	axl_return_val_if_fail (element,  NULL);
 3636: 
 3637: 	return element->name;
 3638: }
 3639: 
 3640: /** 
 3641:  * @brief Returns current element type for the provided \ref axlDtdElement.
 3642:  * 
 3643:  * @param element The axlDtdElement where its type will be returned.
 3644:  * 
 3645:  * @return Current element type for the provided node.
 3646:  */
 3647: AxlDtdElementType    axl_dtd_get_element_type (axlDtdElement * element)
 3648: {
 3649: 	axl_return_val_if_fail (element, ELEMENT_TYPE_UNKNOWN);
 3650: 	
 3651: 	return element->type;
 3652: }
 3653: 
 3654: /** 
 3655:  * @brief Returns current DTD content specification, represented by the Item list.
 3656:  * 
 3657:  * @param element The DTD element (\ref axlDtdElement) which is being
 3658:  * requested to return its \ref axlDtdElementList.
 3659:  * 
 3660:  * @return The \ref axlDtdElementList reference. The value returned
 3661:  * must not be deallocated. The function returns NULL if the reference received is NULL.
 3662:  */
 3663: axlDtdElementList  * axl_dtd_get_item_list    (axlDtdElement * element)
 3664: {
 3665: 	axl_return_val_if_fail (element, NULL);
 3666: 
 3667: 	return element->list; 
 3668: }
 3669: 
 3670: /** 
 3671:  * @brief Allows to check if the provided DTD ELEMENT representation
 3672:  * is a top level definition.
 3673:  * 
 3674:  * @param dtd The DTD document where the operation will be performed.
 3675:  * @param element The \ref axlDtdElement to check.
 3676:  * 
 3677:  * @return \ref axl_true if the dtd element is a top level element or
 3678:  * \ref axl_false if not. The function returns \ref axl_false if the
 3679:  * provided reference is NULL.
 3680:  */
 3681: axl_bool                    axl_dtd_element_is_toplevel (axlDtd * dtd, axlDtdElement * element)
 3682: {
 3683: 	/* support several top level definitions */
 3684: 	int             iterator;
 3685: 	axlDtdElement * dtd_element_aux;
 3686: 
 3687: 	axl_return_val_if_fail (dtd,     axl_false);
 3688: 	axl_return_val_if_fail (element, axl_false);
 3689: 
 3690: 	/* check which is the top */
 3691: 	iterator        = 0;
 3692: 	while (iterator < axl_list_length (dtd->elements)) {
 3693: 			
 3694: 		/* get the next reference */
 3695: 		dtd_element_aux = axl_list_get_nth (dtd->elements, iterator);
 3696: 			
 3697: 		/* check which is the top */
 3698: 		if (__axl_dtd_get_is_parent (dtd_element_aux, element)) {
 3699: 			/* the element provided have a parent */
 3700: 			return axl_false;
 3701: 		}
 3702: 			
 3703: 		/* update inner loop iterator */
 3704: 		iterator ++;
 3705: 	} /* while end */
 3706: 
 3707: 	/* return that the provided node doesn't have a parent node */
 3708: 	return axl_true;
 3709: }
 3710: 
 3711: /** 
 3712:  * @brief Returns the number of item nodes (\ref
 3713:  * axlDtdElementListNode) inside the item list received (\ref axlDtdElementList).
 3714:  * 
 3715:  * @param itemList The \ref axlDtdElementList where the count
 3716:  * operation is being requested.
 3717:  * 
 3718:  * @return The number of item list the provided \ref axlDtdElementList
 3719:  * reference has. The function return -1 if the provided reference is
 3720:  * NULL.
 3721:  */
 3722: int                  axl_dtd_item_list_count  (axlDtdElementList * itemList)
 3723: {
 3724: 	axl_return_val_if_fail (itemList, -1);
 3725: 
 3726: 	if (itemList->itemList == NULL)
 3727: 		return 0;
 3728: 
 3729: 	return axl_list_length (itemList->itemList);
 3730: }
 3731: 
 3732: /** 
 3733:  * @brief Allows to get current configuration for the provided item
 3734:  * list, which is the content specification for a DTD element.
 3735:  * 
 3736:  * @param itemList The item list where the operation will be
 3737:  * performed.
 3738:  * 
 3739:  * @return Current configuration (\ref SEQUENCE or a \ref CHOICE).
 3740:  */
 3741: AxlDtdNestedType     axl_dtd_item_list_type   (axlDtdElementList * itemList)
 3742: {
 3743: 	axl_return_val_if_fail (itemList, -1);
 3744: 
 3745: 	return itemList->type;
 3746: }
 3747: 
 3748: /** 
 3749:  * @brief Allows to get current configuration for DTD content spec
 3750:  * repetition.
 3751:  * 
 3752:  * @param itemList The content spec where the query will be performed.
 3753:  * 
 3754:  * @return Current configuration for times to be repeated DTD element
 3755:  * content specification.
 3756:  */
 3757: AxlDtdTimes          axl_dtd_item_list_repeat (axlDtdElementList * itemList)
 3758: {
 3759: 	axl_return_val_if_fail (itemList, DTD_TIMES_UNKNOWN);
 3760: 
 3761: 	/* returns current times configuration */
 3762: 	return itemList->times;
 3763: }
 3764: 
 3765: /** 
 3766:  * @brief Allows to get the provided item node reference (\ref
 3767:  * axlDtdElementListNode) from the provided item list (\ref
 3768:  * axlDtdElementList).
 3769:  *
 3770:  * Provided position ranges from 0 up to \ref axl_dtd_item_list_count.
 3771:  * 
 3772:  * @param itemList The itemList where the operation will be performed.
 3773:  * @param position The position where the item node will be looked up.
 3774:  * 
 3775:  * @return A reference to the \ref axlDtdElementListNode, or NULL if
 3776:  * there is no item node at the selected index.  The function return
 3777:  * NULL if the provided position is a non positive value or it is
 3778:  * greater than the current item list count (\ref
 3779:  * axl_dtd_item_list_count) or the provided item list reference is
 3780:  * NULL.
 3781:  */
 3782: axlDtdElementListNode * axl_dtd_item_list_get_node (axlDtdElementList * itemList, 
 3783: 						    int position)
 3784: {
 3785: 	axl_return_val_if_fail (itemList, NULL);
 3786: 	axl_return_val_if_fail (position >= 0, NULL);
 3787: 	axl_return_val_if_fail (position < axl_dtd_item_list_count (itemList), NULL);
 3788: 	
 3789: 	return axl_list_get_nth (itemList->itemList, position);
 3790: }
 3791: 
 3792: /** 
 3793:  * @brief Allows to get current node type for the provided DTD element
 3794:  * type content particule or item node (\ref axlDtdElementListNode).
 3795:  *
 3796:  * @param node The node where the type is being requested.
 3797:  * 
 3798:  * @return It returns if the item node contains a final leaf node,
 3799:  * making a reference to an explicit node naming that is allowed to be
 3800:  * used in the context where is found the provided \ref
 3801:  * axlDtdElementListNode or a \ref axlDtdElementList containing more
 3802:  * nodes or lists. 
 3803:  */
 3804: NodeType             axl_dtd_item_node_get_type (axlDtdElementListNode * node)
 3805: {
 3806: 	axl_return_val_if_fail (node, AXL_ELEMENT_NOT_DEFINED);
 3807: 	return node->type;
 3808: }
 3809: 
 3810: /** 
 3811:  * @brief Returns the item list inside the provided node.
 3812:  *
 3813:  * The node is supported to contain an item list reference or NULL
 3814:  * will be returned. Check \ref axl_dtd_item_node_get_type.
 3815:  * 
 3816:  * @param node The node where the operation will be performed.
 3817:  * 
 3818:  * @return The item list inside the node or NULL if fails.
 3819:  */
 3820: axlDtdElementList   * axl_dtd_item_node_get_list (axlDtdElementListNode * node)
 3821: {
 3822: 	axl_return_val_if_fail (node, NULL);
 3823: 	axl_return_val_if_fail (node->type == AXL_ELEMENT_LIST, NULL);
 3824: 
 3825: 	return node->data;
 3826: }
 3827: 
 3828: /** 
 3829:  * @brief Allows to get the dtd item list value, which represents the
 3830:  * node name that is being constrained/represented.
 3831:  * 
 3832:  * @param node The item node where the value is being requested.
 3833:  * 
 3834:  * @return The value inside the item node, supposing it contains an
 3835:  * leaf item node or NULL if fails. The value returned must not be
 3836:  * deallocated.
 3837:  */
 3838: char               * axl_dtd_item_node_get_value (axlDtdElementListNode * node)
 3839: {
 3840: 	axl_return_val_if_fail (node, NULL);
 3841: 	if (node->type != AXL_ELEMENT_NODE) 
 3842: 		return "requested-value-on-a-list";
 3843: 
 3844: 	return node->data;
 3845: }
 3846: 
 3847: /** 
 3848:  * @brief Allows to get current configuration for the provided content
 3849:  * particule for the times to be repeated.
 3850:  * 
 3851:  * @param node The content particule where the query will be
 3852:  * performed.
 3853:  * 
 3854:  * @return Return current repetition configuration. 
 3855:  */
 3856: AxlDtdTimes          axl_dtd_item_node_get_repeat (axlDtdElementListNode * node)
 3857: {
 3858: 	axlDtdElementList * list;
 3859: 
 3860: 	axl_return_val_if_fail (node, DTD_TIMES_UNKNOWN);
 3861: 
 3862: 
 3863: 	if (node->type == AXL_ELEMENT_NODE) {
 3864: 		/* return value requested */
 3865: 		return node->times;
 3866: 	}
 3867: 
 3868: 	if (node->type == AXL_ELEMENT_LIST) {
 3869: 		/* return the requested value for an item list */
 3870: 		list = node->data;
 3871: 		return list->times;
 3872: 	}
 3873: 	
 3874: 	/* return that we don't know man */
 3875: 	return DTD_TIMES_UNKNOWN;
 3876: }
 3877: 
 3878: 
 3879: /** 
 3880:  * @internal
 3881:  *
 3882:  * Internal function which allows to lookup the DTD entity reference
 3883:  * provided the name and the type.
 3884:  */
 3885: axlDtdEntity * __axl_dtd_entity_lookup (axlDtd            * dtd, 
 3886: 					const char        * name,
 3887: 					axlDtdEntityType    type)
 3888: {
 3889: 	axlDtdEntity  * entity;
 3890: 	int             iterator;
 3891: 	int             length;
 3892: 
 3893: 	/* check values received */
 3894: 	axl_return_val_if_fail (dtd,  NULL);
 3895: 	axl_return_val_if_fail (name, NULL);
 3896: 
 3897: 	/* lookup for the item */
 3898: 	iterator = 0;
 3899: 	length   = axl_list_length (dtd->entities);
 3900: 	while (iterator < length) {
 3901: 
 3902: 		/* get the entity at the provided position */
 3903: 		entity = axl_list_get_nth (dtd->entities, iterator);
 3904: 
 3905: 		/* check the type and the name */
 3906: 		if ((entity->type == type) && axl_cmp (entity->name, name))
 3907: 			return entity;
 3908: 		
 3909: 		/* update iterator */
 3910: 		iterator++;
 3911: 	} /* end while */
 3912: 
 3913: 	return NULL;
 3914: }
 3915: 
 3916: /** 
 3917:  * @brief Allows to check if the provided entity name, with the
 3918:  * provided type is defined on the given DTD object.
 3919:  * 
 3920:  * @param dtd The \ref axlDtd instance where the entity lookup will be
 3921:  * performed.
 3922:  *
 3923:  * @param name The entity name to lookup.
 3924:  *
 3925:  * @param type The entity type to lookup.
 3926:  * 
 3927:  * @return axl_true if an entity is found named as provided with the type
 3928:  * provided. Othewise, axl_false is returned.
 3929:  */
 3930: axl_bool                 axl_dtd_entity_exists    (axlDtd            * dtd, 
 3931: 						   const char        * name,
 3932: 						   axlDtdEntityType    type)
 3933: {
 3934: 	/* return if the entity exists */
 3935: 	return (__axl_dtd_entity_lookup (dtd, name, type) != NULL);
 3936: }
 3937: 
 3938: /** 
 3939:  * @brief Allows to get the content configured inside the entity that
 3940:  * is identified by the provided name and the provided type.
 3941:  * 
 3942:  * @param dtd The DTD where the lookup will be performed.
 3943:  *
 3944:  * @param name The entity name to lookup for its content.
 3945:  *
 3946:  * @param type The entity type to match.
 3947:  * 
 3948:  * @return An internal reference to the content associated to the
 3949:  * entity found or NULL. In case the content is defined (as return
 3950:  * value) it must not be deallocated.
 3951:  */
 3952: char               * axl_dtd_entity_value     (axlDtd            * dtd, 
 3953: 					       const char        * name,
 3954: 					       axlDtdEntityType    type)
 3955: {
 3956: 	axlDtdEntity * entity;
 3957: 
 3958: 	/* get the entity reference */
 3959: 	entity = __axl_dtd_entity_lookup (dtd, name, type);
 3960: 	
 3961: 	/* check the entity reference */
 3962: 	axl_return_val_if_fail (entity, NULL);
 3963: 
 3964: 	/* return the content */
 3965: 	return entity->content;
 3966: }
 3967: 
 3968: /** 
 3969:  * @brief Allows to destroy the provided \ref axlDtd  document.
 3970:  * 
 3971:  * @param dtd The \ref axlDtd document to destroy.
 3972:  */
 3973: void       axl_dtd_free  (axlDtd * dtd)
 3974: {
 3975: 	if (dtd == NULL) {
 3976: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "received a null DTD reference, doing nothing");
 3977: 		return;
 3978: 	}
 3979: 	
 3980: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "releasing the DTD reference");
 3981: 	/* free dtd elements */
 3982: 	if (dtd->elements)
 3983: 		axl_list_free (dtd->elements);
 3984: 
 3985: 	/* free entities */
 3986: 	if (dtd->entities)
 3987: 		axl_list_free (dtd->entities);
 3988: 
 3989: 	/* free attributes */
 3990: 	if (dtd->attributes)
 3991: 		axl_list_free (dtd->attributes);
 3992: 
 3993: 	/* free the node itself */
 3994: 	axl_free (dtd);
 3995: 
 3996: 	return;
 3997: }
 3998: 
 3999: 
 4000: /** 
 4001:  * @internal
 4002:  *
 4003:  * @brief Allows to release the memory hold by the given
 4004:  * axlDtdElement.
 4005:  * 
 4006:  * @param element The axlDtdElement to release.
 4007:  */
 4008: void       axl_dtd_element_free (axlDtdElement * element)
 4009: {
 4010: 	if (element == NULL)
 4011: 		return;
 4012: 
 4013: 	/* free element name */
 4014: 	if (element->name != NULL)
 4015: 		axl_free (element->name);
 4016: 
 4017: 	/* free element list definitions */
 4018: 	axl_dtd_item_list_free (element->list);
 4019: 	
 4020: 	/* free element itself */
 4021: 	axl_free (element);
 4022: 
 4023: 	return;
 4024: }
 4025: 
 4026: /** 
 4027:  * @internal 
 4028:  *
 4029:  * @brief Deallocates memory used by the \ref axlDtdElementList
 4030:  * reference.
 4031:  * 
 4032:  * @param list The reference to deallocate.
 4033:  */
 4034: void axl_dtd_item_list_free (axlDtdElementList * list)
 4035: {
 4036: 	if (list == NULL)
 4037: 		return;
 4038: 	
 4039: 	/* check and deallocate the list provided */
 4040: 	if (list->itemList != NULL)
 4041: 		axl_list_free (list->itemList);
 4042: 	
 4043: 	/* deallocates the node itself */
 4044: 	axl_free (list);
 4045: 	return;
 4046: }
 4047: 
 4048: /* @} */
 4049: 

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