Home | History | Annotate | Download | only in libxml2
      1 /*
      2  * xpath.c: XML Path Language implementation
      3  *          XPath is a language for addressing parts of an XML document,
      4  *          designed to be used by both XSLT and XPointer
      5  *f
      6  * Reference: W3C Recommendation 16 November 1999
      7  *     http://www.w3.org/TR/1999/REC-xpath-19991116
      8  * Public reference:
      9  *     http://www.w3.org/TR/xpath
     10  *
     11  * See Copyright for the status of this software
     12  *
     13  * Author: daniel (at) veillard.com
     14  *
     15  */
     16 
     17 #define IN_LIBXML
     18 #include "libxml.h"
     19 
     20 #include <string.h>
     21 
     22 #ifdef HAVE_SYS_TYPES_H
     23 #include <sys/types.h>
     24 #endif
     25 #ifdef HAVE_MATH_H
     26 #include <math.h>
     27 #endif
     28 #ifdef HAVE_FLOAT_H
     29 #include <float.h>
     30 #endif
     31 #ifdef HAVE_CTYPE_H
     32 #include <ctype.h>
     33 #endif
     34 #ifdef HAVE_SIGNAL_H
     35 #include <signal.h>
     36 #endif
     37 
     38 #include <libxml/xmlmemory.h>
     39 #include <libxml/tree.h>
     40 #include <libxml/valid.h>
     41 #include <libxml/xpath.h>
     42 #include <libxml/xpathInternals.h>
     43 #include <libxml/parserInternals.h>
     44 #include <libxml/hash.h>
     45 #ifdef LIBXML_XPTR_ENABLED
     46 #include <libxml/xpointer.h>
     47 #endif
     48 #ifdef LIBXML_DEBUG_ENABLED
     49 #include <libxml/debugXML.h>
     50 #endif
     51 #include <libxml/xmlerror.h>
     52 #include <libxml/threads.h>
     53 #include <libxml/globals.h>
     54 #ifdef LIBXML_PATTERN_ENABLED
     55 #include <libxml/pattern.h>
     56 #endif
     57 
     58 #include "buf.h"
     59 
     60 #ifdef LIBXML_PATTERN_ENABLED
     61 #define XPATH_STREAMING
     62 #endif
     63 
     64 #define TODO								\
     65     xmlGenericError(xmlGenericErrorContext,				\
     66 	    "Unimplemented block at %s:%d\n",				\
     67             __FILE__, __LINE__);
     68 
     69 /**
     70  * WITH_TIM_SORT:
     71  *
     72  * Use the Timsort algorithm provided in timsort.h to sort
     73  * nodeset as this is a great improvement over the old Shell sort
     74  * used in xmlXPathNodeSetSort()
     75  */
     76 #define WITH_TIM_SORT
     77 
     78 /*
     79 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
     80 * If defined, this will use xmlXPathCmpNodesExt() instead of
     81 * xmlXPathCmpNodes(). The new function is optimized comparison of
     82 * non-element nodes; actually it will speed up comparison only if
     83 * xmlXPathOrderDocElems() was called in order to index the elements of
     84 * a tree in document order; Libxslt does such an indexing, thus it will
     85 * benefit from this optimization.
     86 */
     87 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
     88 
     89 /*
     90 * XP_OPTIMIZED_FILTER_FIRST:
     91 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
     92 * in a way, that it stop evaluation at the first node.
     93 */
     94 #define XP_OPTIMIZED_FILTER_FIRST
     95 
     96 /*
     97 * XP_DEBUG_OBJ_USAGE:
     98 * Internal flag to enable tracking of how much XPath objects have been
     99 * created.
    100 */
    101 /* #define XP_DEBUG_OBJ_USAGE */
    102 
    103 /*
    104  * XPATH_MAX_STEPS:
    105  * when compiling an XPath expression we arbitrary limit the maximum
    106  * number of step operation in the compiled expression. 1000000 is
    107  * an insanely large value which should never be reached under normal
    108  * circumstances
    109  */
    110 #define XPATH_MAX_STEPS 1000000
    111 
    112 /*
    113  * XPATH_MAX_STACK_DEPTH:
    114  * when evaluating an XPath expression we arbitrary limit the maximum
    115  * number of object allowed to be pushed on the stack. 1000000 is
    116  * an insanely large value which should never be reached under normal
    117  * circumstances
    118  */
    119 #define XPATH_MAX_STACK_DEPTH 1000000
    120 
    121 /*
    122  * XPATH_MAX_NODESET_LENGTH:
    123  * when evaluating an XPath expression nodesets are created and we
    124  * arbitrary limit the maximum length of those node set. 10000000 is
    125  * an insanely large value which should never be reached under normal
    126  * circumstances, one would first need to construct an in memory tree
    127  * with more than 10 millions nodes.
    128  */
    129 #define XPATH_MAX_NODESET_LENGTH 10000000
    130 
    131 /*
    132  * TODO:
    133  * There are a few spots where some tests are done which depend upon ascii
    134  * data.  These should be enhanced for full UTF8 support (see particularly
    135  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
    136  */
    137 
    138 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
    139 /**
    140  * xmlXPathCmpNodesExt:
    141  * @node1:  the first node
    142  * @node2:  the second node
    143  *
    144  * Compare two nodes w.r.t document order.
    145  * This one is optimized for handling of non-element nodes.
    146  *
    147  * Returns -2 in case of error 1 if first point < second point, 0 if
    148  *         it's the same node, -1 otherwise
    149  */
    150 static int
    151 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
    152     int depth1, depth2;
    153     int misc = 0, precedence1 = 0, precedence2 = 0;
    154     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
    155     xmlNodePtr cur, root;
    156     long l1, l2;
    157 
    158     if ((node1 == NULL) || (node2 == NULL))
    159 	return(-2);
    160 
    161     if (node1 == node2)
    162 	return(0);
    163 
    164     /*
    165      * a couple of optimizations which will avoid computations in most cases
    166      */
    167     switch (node1->type) {
    168 	case XML_ELEMENT_NODE:
    169 	    if (node2->type == XML_ELEMENT_NODE) {
    170 		if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
    171 		    (0 > (long) node2->content) &&
    172 		    (node1->doc == node2->doc))
    173 		{
    174 		    l1 = -((long) node1->content);
    175 		    l2 = -((long) node2->content);
    176 		    if (l1 < l2)
    177 			return(1);
    178 		    if (l1 > l2)
    179 			return(-1);
    180 		} else
    181 		    goto turtle_comparison;
    182 	    }
    183 	    break;
    184 	case XML_ATTRIBUTE_NODE:
    185 	    precedence1 = 1; /* element is owner */
    186 	    miscNode1 = node1;
    187 	    node1 = node1->parent;
    188 	    misc = 1;
    189 	    break;
    190 	case XML_TEXT_NODE:
    191 	case XML_CDATA_SECTION_NODE:
    192 	case XML_COMMENT_NODE:
    193 	case XML_PI_NODE: {
    194 	    miscNode1 = node1;
    195 	    /*
    196 	    * Find nearest element node.
    197 	    */
    198 	    if (node1->prev != NULL) {
    199 		do {
    200 		    node1 = node1->prev;
    201 		    if (node1->type == XML_ELEMENT_NODE) {
    202 			precedence1 = 3; /* element in prev-sibl axis */
    203 			break;
    204 		    }
    205 		    if (node1->prev == NULL) {
    206 			precedence1 = 2; /* element is parent */
    207 			/*
    208 			* URGENT TODO: Are there any cases, where the
    209 			* parent of such a node is not an element node?
    210 			*/
    211 			node1 = node1->parent;
    212 			break;
    213 		    }
    214 		} while (1);
    215 	    } else {
    216 		precedence1 = 2; /* element is parent */
    217 		node1 = node1->parent;
    218 	    }
    219 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
    220 		(0 <= (long) node1->content)) {
    221 		/*
    222 		* Fallback for whatever case.
    223 		*/
    224 		node1 = miscNode1;
    225 		precedence1 = 0;
    226 	    } else
    227 		misc = 1;
    228 	}
    229 	    break;
    230 	case XML_NAMESPACE_DECL:
    231 	    /*
    232 	    * TODO: why do we return 1 for namespace nodes?
    233 	    */
    234 	    return(1);
    235 	default:
    236 	    break;
    237     }
    238     switch (node2->type) {
    239 	case XML_ELEMENT_NODE:
    240 	    break;
    241 	case XML_ATTRIBUTE_NODE:
    242 	    precedence2 = 1; /* element is owner */
    243 	    miscNode2 = node2;
    244 	    node2 = node2->parent;
    245 	    misc = 1;
    246 	    break;
    247 	case XML_TEXT_NODE:
    248 	case XML_CDATA_SECTION_NODE:
    249 	case XML_COMMENT_NODE:
    250 	case XML_PI_NODE: {
    251 	    miscNode2 = node2;
    252 	    if (node2->prev != NULL) {
    253 		do {
    254 		    node2 = node2->prev;
    255 		    if (node2->type == XML_ELEMENT_NODE) {
    256 			precedence2 = 3; /* element in prev-sibl axis */
    257 			break;
    258 		    }
    259 		    if (node2->prev == NULL) {
    260 			precedence2 = 2; /* element is parent */
    261 			node2 = node2->parent;
    262 			break;
    263 		    }
    264 		} while (1);
    265 	    } else {
    266 		precedence2 = 2; /* element is parent */
    267 		node2 = node2->parent;
    268 	    }
    269 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
    270 		(0 <= (long) node2->content))
    271 	    {
    272 		node2 = miscNode2;
    273 		precedence2 = 0;
    274 	    } else
    275 		misc = 1;
    276 	}
    277 	    break;
    278 	case XML_NAMESPACE_DECL:
    279 	    return(1);
    280 	default:
    281 	    break;
    282     }
    283     if (misc) {
    284 	if (node1 == node2) {
    285 	    if (precedence1 == precedence2) {
    286 		/*
    287 		* The ugly case; but normally there aren't many
    288 		* adjacent non-element nodes around.
    289 		*/
    290 		cur = miscNode2->prev;
    291 		while (cur != NULL) {
    292 		    if (cur == miscNode1)
    293 			return(1);
    294 		    if (cur->type == XML_ELEMENT_NODE)
    295 			return(-1);
    296 		    cur = cur->prev;
    297 		}
    298 		return (-1);
    299 	    } else {
    300 		/*
    301 		* Evaluate based on higher precedence wrt to the element.
    302 		* TODO: This assumes attributes are sorted before content.
    303 		*   Is this 100% correct?
    304 		*/
    305 		if (precedence1 < precedence2)
    306 		    return(1);
    307 		else
    308 		    return(-1);
    309 	    }
    310 	}
    311 	/*
    312 	* Special case: One of the helper-elements is contained by the other.
    313 	* <foo>
    314 	*   <node2>
    315 	*     <node1>Text-1(precedence1 == 2)</node1>
    316 	*   </node2>
    317 	*   Text-6(precedence2 == 3)
    318 	* </foo>
    319 	*/
    320 	if ((precedence2 == 3) && (precedence1 > 1)) {
    321 	    cur = node1->parent;
    322 	    while (cur) {
    323 		if (cur == node2)
    324 		    return(1);
    325 		cur = cur->parent;
    326 	    }
    327 	}
    328 	if ((precedence1 == 3) && (precedence2 > 1)) {
    329 	    cur = node2->parent;
    330 	    while (cur) {
    331 		if (cur == node1)
    332 		    return(-1);
    333 		cur = cur->parent;
    334 	    }
    335 	}
    336     }
    337 
    338     /*
    339      * Speedup using document order if availble.
    340      */
    341     if ((node1->type == XML_ELEMENT_NODE) &&
    342 	(node2->type == XML_ELEMENT_NODE) &&
    343 	(0 > (long) node1->content) &&
    344 	(0 > (long) node2->content) &&
    345 	(node1->doc == node2->doc)) {
    346 
    347 	l1 = -((long) node1->content);
    348 	l2 = -((long) node2->content);
    349 	if (l1 < l2)
    350 	    return(1);
    351 	if (l1 > l2)
    352 	    return(-1);
    353     }
    354 
    355 turtle_comparison:
    356 
    357     if (node1 == node2->prev)
    358 	return(1);
    359     if (node1 == node2->next)
    360 	return(-1);
    361     /*
    362      * compute depth to root
    363      */
    364     for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
    365 	if (cur->parent == node1)
    366 	    return(1);
    367 	depth2++;
    368     }
    369     root = cur;
    370     for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
    371 	if (cur->parent == node2)
    372 	    return(-1);
    373 	depth1++;
    374     }
    375     /*
    376      * Distinct document (or distinct entities :-( ) case.
    377      */
    378     if (root != cur) {
    379 	return(-2);
    380     }
    381     /*
    382      * get the nearest common ancestor.
    383      */
    384     while (depth1 > depth2) {
    385 	depth1--;
    386 	node1 = node1->parent;
    387     }
    388     while (depth2 > depth1) {
    389 	depth2--;
    390 	node2 = node2->parent;
    391     }
    392     while (node1->parent != node2->parent) {
    393 	node1 = node1->parent;
    394 	node2 = node2->parent;
    395 	/* should not happen but just in case ... */
    396 	if ((node1 == NULL) || (node2 == NULL))
    397 	    return(-2);
    398     }
    399     /*
    400      * Find who's first.
    401      */
    402     if (node1 == node2->prev)
    403 	return(1);
    404     if (node1 == node2->next)
    405 	return(-1);
    406     /*
    407      * Speedup using document order if availble.
    408      */
    409     if ((node1->type == XML_ELEMENT_NODE) &&
    410 	(node2->type == XML_ELEMENT_NODE) &&
    411 	(0 > (long) node1->content) &&
    412 	(0 > (long) node2->content) &&
    413 	(node1->doc == node2->doc)) {
    414 
    415 	l1 = -((long) node1->content);
    416 	l2 = -((long) node2->content);
    417 	if (l1 < l2)
    418 	    return(1);
    419 	if (l1 > l2)
    420 	    return(-1);
    421     }
    422 
    423     for (cur = node1->next;cur != NULL;cur = cur->next)
    424 	if (cur == node2)
    425 	    return(1);
    426     return(-1); /* assume there is no sibling list corruption */
    427 }
    428 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
    429 
    430 /*
    431  * Wrapper for the Timsort argorithm from timsort.h
    432  */
    433 #ifdef WITH_TIM_SORT
    434 #define SORT_NAME libxml_domnode
    435 #define SORT_TYPE xmlNodePtr
    436 /**
    437  * wrap_cmp:
    438  * @x: a node
    439  * @y: another node
    440  *
    441  * Comparison function for the Timsort implementation
    442  *
    443  * Returns -2 in case of error -1 if first point < second point, 0 if
    444  *         it's the same node, +1 otherwise
    445  */
    446 static
    447 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
    448 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
    449     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
    450     {
    451         int res = xmlXPathCmpNodesExt(x, y);
    452         return res == -2 ? res : -res;
    453     }
    454 #else
    455     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
    456     {
    457         int res = xmlXPathCmpNodes(x, y);
    458         return res == -2 ? res : -res;
    459     }
    460 #endif
    461 #define SORT_CMP(x, y)  (wrap_cmp(x, y))
    462 #include "timsort.h"
    463 #endif /* WITH_TIM_SORT */
    464 
    465 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
    466 
    467 /************************************************************************
    468  *									*
    469  *			Floating point stuff				*
    470  *									*
    471  ************************************************************************/
    472 
    473 #ifndef TRIO_REPLACE_STDIO
    474 #define TRIO_PUBLIC static
    475 #endif
    476 #include "trionan.c"
    477 
    478 /*
    479  * The lack of portability of this section of the libc is annoying !
    480  */
    481 double xmlXPathNAN = 0;
    482 double xmlXPathPINF = 1;
    483 double xmlXPathNINF = -1;
    484 static double xmlXPathNZERO = 0; /* not exported from headers */
    485 static int xmlXPathInitialized = 0;
    486 
    487 /**
    488  * xmlXPathInit:
    489  *
    490  * Initialize the XPath environment
    491  */
    492 void
    493 xmlXPathInit(void) {
    494     if (xmlXPathInitialized) return;
    495 
    496     xmlXPathPINF = trio_pinf();
    497     xmlXPathNINF = trio_ninf();
    498     xmlXPathNAN = trio_nan();
    499     xmlXPathNZERO = trio_nzero();
    500 
    501     xmlXPathInitialized = 1;
    502 }
    503 
    504 /**
    505  * xmlXPathIsNaN:
    506  * @val:  a double value
    507  *
    508  * Provides a portable isnan() function to detect whether a double
    509  * is a NotaNumber. Based on trio code
    510  * http://sourceforge.net/projects/ctrio/
    511  *
    512  * Returns 1 if the value is a NaN, 0 otherwise
    513  */
    514 int
    515 xmlXPathIsNaN(double val) {
    516     return(trio_isnan(val));
    517 }
    518 
    519 /**
    520  * xmlXPathIsInf:
    521  * @val:  a double value
    522  *
    523  * Provides a portable isinf() function to detect whether a double
    524  * is a +Infinite or -Infinite. Based on trio code
    525  * http://sourceforge.net/projects/ctrio/
    526  *
    527  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
    528  */
    529 int
    530 xmlXPathIsInf(double val) {
    531     return(trio_isinf(val));
    532 }
    533 
    534 #endif /* SCHEMAS or XPATH */
    535 #ifdef LIBXML_XPATH_ENABLED
    536 /**
    537  * xmlXPathGetSign:
    538  * @val:  a double value
    539  *
    540  * Provides a portable function to detect the sign of a double
    541  * Modified from trio code
    542  * http://sourceforge.net/projects/ctrio/
    543  *
    544  * Returns 1 if the value is Negative, 0 if positive
    545  */
    546 static int
    547 xmlXPathGetSign(double val) {
    548     return(trio_signbit(val));
    549 }
    550 
    551 
    552 /*
    553  * TODO: when compatibility allows remove all "fake node libxslt" strings
    554  *       the test should just be name[0] = ' '
    555  */
    556 #ifdef DEBUG_XPATH_EXPRESSION
    557 #define DEBUG_STEP
    558 #define DEBUG_EXPR
    559 #define DEBUG_EVAL_COUNTS
    560 #endif
    561 
    562 static xmlNs xmlXPathXMLNamespaceStruct = {
    563     NULL,
    564     XML_NAMESPACE_DECL,
    565     XML_XML_NAMESPACE,
    566     BAD_CAST "xml",
    567     NULL,
    568     NULL
    569 };
    570 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
    571 #ifndef LIBXML_THREAD_ENABLED
    572 /*
    573  * Optimizer is disabled only when threaded apps are detected while
    574  * the library ain't compiled for thread safety.
    575  */
    576 static int xmlXPathDisableOptimizer = 0;
    577 #endif
    578 
    579 /************************************************************************
    580  *									*
    581  *			Error handling routines				*
    582  *									*
    583  ************************************************************************/
    584 
    585 /**
    586  * XP_ERRORNULL:
    587  * @X:  the error code
    588  *
    589  * Macro to raise an XPath error and return NULL.
    590  */
    591 #define XP_ERRORNULL(X)							\
    592     { xmlXPathErr(ctxt, X); return(NULL); }
    593 
    594 /*
    595  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
    596  */
    597 static const char *xmlXPathErrorMessages[] = {
    598     "Ok\n",
    599     "Number encoding\n",
    600     "Unfinished literal\n",
    601     "Start of literal\n",
    602     "Expected $ for variable reference\n",
    603     "Undefined variable\n",
    604     "Invalid predicate\n",
    605     "Invalid expression\n",
    606     "Missing closing curly brace\n",
    607     "Unregistered function\n",
    608     "Invalid operand\n",
    609     "Invalid type\n",
    610     "Invalid number of arguments\n",
    611     "Invalid context size\n",
    612     "Invalid context position\n",
    613     "Memory allocation error\n",
    614     "Syntax error\n",
    615     "Resource error\n",
    616     "Sub resource error\n",
    617     "Undefined namespace prefix\n",
    618     "Encoding error\n",
    619     "Char out of XML range\n",
    620     "Invalid or incomplete context\n",
    621     "Stack usage error\n",
    622     "Forbidden variable\n",
    623     "?? Unknown error ??\n"	/* Must be last in the list! */
    624 };
    625 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
    626 		   sizeof(xmlXPathErrorMessages[0])) - 1)
    627 /**
    628  * xmlXPathErrMemory:
    629  * @ctxt:  an XPath context
    630  * @extra:  extra informations
    631  *
    632  * Handle a redefinition of attribute error
    633  */
    634 static void
    635 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
    636 {
    637     if (ctxt != NULL) {
    638         if (extra) {
    639             xmlChar buf[200];
    640 
    641             xmlStrPrintf(buf, 200,
    642                          "Memory allocation failed : %s\n",
    643                          extra);
    644             ctxt->lastError.message = (char *) xmlStrdup(buf);
    645         } else {
    646             ctxt->lastError.message = (char *)
    647 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
    648         }
    649         ctxt->lastError.domain = XML_FROM_XPATH;
    650         ctxt->lastError.code = XML_ERR_NO_MEMORY;
    651 	if (ctxt->error != NULL)
    652 	    ctxt->error(ctxt->userData, &ctxt->lastError);
    653     } else {
    654         if (extra)
    655             __xmlRaiseError(NULL, NULL, NULL,
    656                             NULL, NULL, XML_FROM_XPATH,
    657                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
    658                             extra, NULL, NULL, 0, 0,
    659                             "Memory allocation failed : %s\n", extra);
    660         else
    661             __xmlRaiseError(NULL, NULL, NULL,
    662                             NULL, NULL, XML_FROM_XPATH,
    663                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
    664                             NULL, NULL, NULL, 0, 0,
    665                             "Memory allocation failed\n");
    666     }
    667 }
    668 
    669 /**
    670  * xmlXPathPErrMemory:
    671  * @ctxt:  an XPath parser context
    672  * @extra:  extra informations
    673  *
    674  * Handle a redefinition of attribute error
    675  */
    676 static void
    677 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
    678 {
    679     if (ctxt == NULL)
    680 	xmlXPathErrMemory(NULL, extra);
    681     else {
    682 	ctxt->error = XPATH_MEMORY_ERROR;
    683 	xmlXPathErrMemory(ctxt->context, extra);
    684     }
    685 }
    686 
    687 /**
    688  * xmlXPathErr:
    689  * @ctxt:  a XPath parser context
    690  * @error:  the error code
    691  *
    692  * Handle an XPath error
    693  */
    694 void
    695 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
    696 {
    697     if ((error < 0) || (error > MAXERRNO))
    698 	error = MAXERRNO;
    699     if (ctxt == NULL) {
    700 	__xmlRaiseError(NULL, NULL, NULL,
    701 			NULL, NULL, XML_FROM_XPATH,
    702 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    703 			XML_ERR_ERROR, NULL, 0,
    704 			NULL, NULL, NULL, 0, 0,
    705 			"%s", xmlXPathErrorMessages[error]);
    706 	return;
    707     }
    708     ctxt->error = error;
    709     if (ctxt->context == NULL) {
    710 	__xmlRaiseError(NULL, NULL, NULL,
    711 			NULL, NULL, XML_FROM_XPATH,
    712 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    713 			XML_ERR_ERROR, NULL, 0,
    714 			(const char *) ctxt->base, NULL, NULL,
    715 			ctxt->cur - ctxt->base, 0,
    716 			"%s", xmlXPathErrorMessages[error]);
    717 	return;
    718     }
    719 
    720     /* cleanup current last error */
    721     xmlResetError(&ctxt->context->lastError);
    722 
    723     ctxt->context->lastError.domain = XML_FROM_XPATH;
    724     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
    725                            XPATH_EXPRESSION_OK;
    726     ctxt->context->lastError.level = XML_ERR_ERROR;
    727     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
    728     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
    729     ctxt->context->lastError.node = ctxt->context->debugNode;
    730     if (ctxt->context->error != NULL) {
    731 	ctxt->context->error(ctxt->context->userData,
    732 	                     &ctxt->context->lastError);
    733     } else {
    734 	__xmlRaiseError(NULL, NULL, NULL,
    735 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
    736 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    737 			XML_ERR_ERROR, NULL, 0,
    738 			(const char *) ctxt->base, NULL, NULL,
    739 			ctxt->cur - ctxt->base, 0,
    740 			"%s", xmlXPathErrorMessages[error]);
    741     }
    742 
    743 }
    744 
    745 /**
    746  * xmlXPatherror:
    747  * @ctxt:  the XPath Parser context
    748  * @file:  the file name
    749  * @line:  the line number
    750  * @no:  the error number
    751  *
    752  * Formats an error message.
    753  */
    754 void
    755 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
    756               int line ATTRIBUTE_UNUSED, int no) {
    757     xmlXPathErr(ctxt, no);
    758 }
    759 
    760 /************************************************************************
    761  *									*
    762  *			Utilities					*
    763  *									*
    764  ************************************************************************/
    765 
    766 /**
    767  * xsltPointerList:
    768  *
    769  * Pointer-list for various purposes.
    770  */
    771 typedef struct _xmlPointerList xmlPointerList;
    772 typedef xmlPointerList *xmlPointerListPtr;
    773 struct _xmlPointerList {
    774     void **items;
    775     int number;
    776     int size;
    777 };
    778 /*
    779 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
    780 * and here, we should make the functions public.
    781 */
    782 static int
    783 xmlPointerListAddSize(xmlPointerListPtr list,
    784 		       void *item,
    785 		       int initialSize)
    786 {
    787     if (list->items == NULL) {
    788 	if (initialSize <= 0)
    789 	    initialSize = 1;
    790 	list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
    791 	if (list->items == NULL) {
    792 	    xmlXPathErrMemory(NULL,
    793 		"xmlPointerListCreate: allocating item\n");
    794 	    return(-1);
    795 	}
    796 	list->number = 0;
    797 	list->size = initialSize;
    798     } else if (list->size <= list->number) {
    799         if (list->size > 50000000) {
    800 	    xmlXPathErrMemory(NULL,
    801 		"xmlPointerListAddSize: re-allocating item\n");
    802             return(-1);
    803         }
    804 	list->size *= 2;
    805 	list->items = (void **) xmlRealloc(list->items,
    806 	    list->size * sizeof(void *));
    807 	if (list->items == NULL) {
    808 	    xmlXPathErrMemory(NULL,
    809 		"xmlPointerListAddSize: re-allocating item\n");
    810 	    list->size = 0;
    811 	    return(-1);
    812 	}
    813     }
    814     list->items[list->number++] = item;
    815     return(0);
    816 }
    817 
    818 /**
    819  * xsltPointerListCreate:
    820  *
    821  * Creates an xsltPointerList structure.
    822  *
    823  * Returns a xsltPointerList structure or NULL in case of an error.
    824  */
    825 static xmlPointerListPtr
    826 xmlPointerListCreate(int initialSize)
    827 {
    828     xmlPointerListPtr ret;
    829 
    830     ret = xmlMalloc(sizeof(xmlPointerList));
    831     if (ret == NULL) {
    832 	xmlXPathErrMemory(NULL,
    833 	    "xmlPointerListCreate: allocating item\n");
    834 	return (NULL);
    835     }
    836     memset(ret, 0, sizeof(xmlPointerList));
    837     if (initialSize > 0) {
    838 	xmlPointerListAddSize(ret, NULL, initialSize);
    839 	ret->number = 0;
    840     }
    841     return (ret);
    842 }
    843 
    844 /**
    845  * xsltPointerListFree:
    846  *
    847  * Frees the xsltPointerList structure. This does not free
    848  * the content of the list.
    849  */
    850 static void
    851 xmlPointerListFree(xmlPointerListPtr list)
    852 {
    853     if (list == NULL)
    854 	return;
    855     if (list->items != NULL)
    856 	xmlFree(list->items);
    857     xmlFree(list);
    858 }
    859 
    860 /************************************************************************
    861  *									*
    862  *			Parser Types					*
    863  *									*
    864  ************************************************************************/
    865 
    866 /*
    867  * Types are private:
    868  */
    869 
    870 typedef enum {
    871     XPATH_OP_END=0,
    872     XPATH_OP_AND,
    873     XPATH_OP_OR,
    874     XPATH_OP_EQUAL,
    875     XPATH_OP_CMP,
    876     XPATH_OP_PLUS,
    877     XPATH_OP_MULT,
    878     XPATH_OP_UNION,
    879     XPATH_OP_ROOT,
    880     XPATH_OP_NODE,
    881     XPATH_OP_RESET, /* 10 */
    882     XPATH_OP_COLLECT,
    883     XPATH_OP_VALUE, /* 12 */
    884     XPATH_OP_VARIABLE,
    885     XPATH_OP_FUNCTION,
    886     XPATH_OP_ARG,
    887     XPATH_OP_PREDICATE,
    888     XPATH_OP_FILTER, /* 17 */
    889     XPATH_OP_SORT /* 18 */
    890 #ifdef LIBXML_XPTR_ENABLED
    891     ,XPATH_OP_RANGETO
    892 #endif
    893 } xmlXPathOp;
    894 
    895 typedef enum {
    896     AXIS_ANCESTOR = 1,
    897     AXIS_ANCESTOR_OR_SELF,
    898     AXIS_ATTRIBUTE,
    899     AXIS_CHILD,
    900     AXIS_DESCENDANT,
    901     AXIS_DESCENDANT_OR_SELF,
    902     AXIS_FOLLOWING,
    903     AXIS_FOLLOWING_SIBLING,
    904     AXIS_NAMESPACE,
    905     AXIS_PARENT,
    906     AXIS_PRECEDING,
    907     AXIS_PRECEDING_SIBLING,
    908     AXIS_SELF
    909 } xmlXPathAxisVal;
    910 
    911 typedef enum {
    912     NODE_TEST_NONE = 0,
    913     NODE_TEST_TYPE = 1,
    914     NODE_TEST_PI = 2,
    915     NODE_TEST_ALL = 3,
    916     NODE_TEST_NS = 4,
    917     NODE_TEST_NAME = 5
    918 } xmlXPathTestVal;
    919 
    920 typedef enum {
    921     NODE_TYPE_NODE = 0,
    922     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
    923     NODE_TYPE_TEXT = XML_TEXT_NODE,
    924     NODE_TYPE_PI = XML_PI_NODE
    925 } xmlXPathTypeVal;
    926 
    927 typedef struct _xmlXPathStepOp xmlXPathStepOp;
    928 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
    929 struct _xmlXPathStepOp {
    930     xmlXPathOp op;		/* The identifier of the operation */
    931     int ch1;			/* First child */
    932     int ch2;			/* Second child */
    933     int value;
    934     int value2;
    935     int value3;
    936     void *value4;
    937     void *value5;
    938     void *cache;
    939     void *cacheURI;
    940 };
    941 
    942 struct _xmlXPathCompExpr {
    943     int nbStep;			/* Number of steps in this expression */
    944     int maxStep;		/* Maximum number of steps allocated */
    945     xmlXPathStepOp *steps;	/* ops for computation of this expression */
    946     int last;			/* index of last step in expression */
    947     xmlChar *expr;		/* the expression being computed */
    948     xmlDictPtr dict;		/* the dictionary to use if any */
    949 #ifdef DEBUG_EVAL_COUNTS
    950     int nb;
    951     xmlChar *string;
    952 #endif
    953 #ifdef XPATH_STREAMING
    954     xmlPatternPtr stream;
    955 #endif
    956 };
    957 
    958 /************************************************************************
    959  *									*
    960  *			Forward declarations				*
    961  *									*
    962  ************************************************************************/
    963 static void
    964 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
    965 static void
    966 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
    967 static int
    968 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
    969                         xmlXPathStepOpPtr op, xmlNodePtr *first);
    970 static int
    971 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
    972 			    xmlXPathStepOpPtr op,
    973 			    int isPredicate);
    974 
    975 /************************************************************************
    976  *									*
    977  *			Parser Type functions				*
    978  *									*
    979  ************************************************************************/
    980 
    981 /**
    982  * xmlXPathNewCompExpr:
    983  *
    984  * Create a new Xpath component
    985  *
    986  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
    987  */
    988 static xmlXPathCompExprPtr
    989 xmlXPathNewCompExpr(void) {
    990     xmlXPathCompExprPtr cur;
    991 
    992     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
    993     if (cur == NULL) {
    994         xmlXPathErrMemory(NULL, "allocating component\n");
    995 	return(NULL);
    996     }
    997     memset(cur, 0, sizeof(xmlXPathCompExpr));
    998     cur->maxStep = 10;
    999     cur->nbStep = 0;
   1000     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
   1001 	                                   sizeof(xmlXPathStepOp));
   1002     if (cur->steps == NULL) {
   1003         xmlXPathErrMemory(NULL, "allocating steps\n");
   1004 	xmlFree(cur);
   1005 	return(NULL);
   1006     }
   1007     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
   1008     cur->last = -1;
   1009 #ifdef DEBUG_EVAL_COUNTS
   1010     cur->nb = 0;
   1011 #endif
   1012     return(cur);
   1013 }
   1014 
   1015 /**
   1016  * xmlXPathFreeCompExpr:
   1017  * @comp:  an XPATH comp
   1018  *
   1019  * Free up the memory allocated by @comp
   1020  */
   1021 void
   1022 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
   1023 {
   1024     xmlXPathStepOpPtr op;
   1025     int i;
   1026 
   1027     if (comp == NULL)
   1028         return;
   1029     if (comp->dict == NULL) {
   1030 	for (i = 0; i < comp->nbStep; i++) {
   1031 	    op = &comp->steps[i];
   1032 	    if (op->value4 != NULL) {
   1033 		if (op->op == XPATH_OP_VALUE)
   1034 		    xmlXPathFreeObject(op->value4);
   1035 		else
   1036 		    xmlFree(op->value4);
   1037 	    }
   1038 	    if (op->value5 != NULL)
   1039 		xmlFree(op->value5);
   1040 	}
   1041     } else {
   1042 	for (i = 0; i < comp->nbStep; i++) {
   1043 	    op = &comp->steps[i];
   1044 	    if (op->value4 != NULL) {
   1045 		if (op->op == XPATH_OP_VALUE)
   1046 		    xmlXPathFreeObject(op->value4);
   1047 	    }
   1048 	}
   1049         xmlDictFree(comp->dict);
   1050     }
   1051     if (comp->steps != NULL) {
   1052         xmlFree(comp->steps);
   1053     }
   1054 #ifdef DEBUG_EVAL_COUNTS
   1055     if (comp->string != NULL) {
   1056         xmlFree(comp->string);
   1057     }
   1058 #endif
   1059 #ifdef XPATH_STREAMING
   1060     if (comp->stream != NULL) {
   1061         xmlFreePatternList(comp->stream);
   1062     }
   1063 #endif
   1064     if (comp->expr != NULL) {
   1065         xmlFree(comp->expr);
   1066     }
   1067 
   1068     xmlFree(comp);
   1069 }
   1070 
   1071 /**
   1072  * xmlXPathCompExprAdd:
   1073  * @comp:  the compiled expression
   1074  * @ch1: first child index
   1075  * @ch2: second child index
   1076  * @op:  an op
   1077  * @value:  the first int value
   1078  * @value2:  the second int value
   1079  * @value3:  the third int value
   1080  * @value4:  the first string value
   1081  * @value5:  the second string value
   1082  *
   1083  * Add a step to an XPath Compiled Expression
   1084  *
   1085  * Returns -1 in case of failure, the index otherwise
   1086  */
   1087 static int
   1088 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
   1089    xmlXPathOp op, int value,
   1090    int value2, int value3, void *value4, void *value5) {
   1091     if (comp->nbStep >= comp->maxStep) {
   1092 	xmlXPathStepOp *real;
   1093 
   1094         if (comp->maxStep >= XPATH_MAX_STEPS) {
   1095 	    xmlXPathErrMemory(NULL, "adding step\n");
   1096 	    return(-1);
   1097         }
   1098 	comp->maxStep *= 2;
   1099 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
   1100 		                      comp->maxStep * sizeof(xmlXPathStepOp));
   1101 	if (real == NULL) {
   1102 	    comp->maxStep /= 2;
   1103 	    xmlXPathErrMemory(NULL, "adding step\n");
   1104 	    return(-1);
   1105 	}
   1106 	comp->steps = real;
   1107     }
   1108     comp->last = comp->nbStep;
   1109     comp->steps[comp->nbStep].ch1 = ch1;
   1110     comp->steps[comp->nbStep].ch2 = ch2;
   1111     comp->steps[comp->nbStep].op = op;
   1112     comp->steps[comp->nbStep].value = value;
   1113     comp->steps[comp->nbStep].value2 = value2;
   1114     comp->steps[comp->nbStep].value3 = value3;
   1115     if ((comp->dict != NULL) &&
   1116         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
   1117 	 (op == XPATH_OP_COLLECT))) {
   1118         if (value4 != NULL) {
   1119 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
   1120 	        (void *)xmlDictLookup(comp->dict, value4, -1);
   1121 	    xmlFree(value4);
   1122 	} else
   1123 	    comp->steps[comp->nbStep].value4 = NULL;
   1124         if (value5 != NULL) {
   1125 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
   1126 	        (void *)xmlDictLookup(comp->dict, value5, -1);
   1127 	    xmlFree(value5);
   1128 	} else
   1129 	    comp->steps[comp->nbStep].value5 = NULL;
   1130     } else {
   1131 	comp->steps[comp->nbStep].value4 = value4;
   1132 	comp->steps[comp->nbStep].value5 = value5;
   1133     }
   1134     comp->steps[comp->nbStep].cache = NULL;
   1135     return(comp->nbStep++);
   1136 }
   1137 
   1138 /**
   1139  * xmlXPathCompSwap:
   1140  * @comp:  the compiled expression
   1141  * @op: operation index
   1142  *
   1143  * Swaps 2 operations in the compiled expression
   1144  */
   1145 static void
   1146 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
   1147     int tmp;
   1148 
   1149 #ifndef LIBXML_THREAD_ENABLED
   1150     /*
   1151      * Since this manipulates possibly shared variables, this is
   1152      * disabled if one detects that the library is used in a multithreaded
   1153      * application
   1154      */
   1155     if (xmlXPathDisableOptimizer)
   1156 	return;
   1157 #endif
   1158 
   1159     tmp = op->ch1;
   1160     op->ch1 = op->ch2;
   1161     op->ch2 = tmp;
   1162 }
   1163 
   1164 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
   1165     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
   1166 	                (op), (val), (val2), (val3), (val4), (val5))
   1167 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
   1168     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
   1169 	                (op), (val), (val2), (val3), (val4), (val5))
   1170 
   1171 #define PUSH_LEAVE_EXPR(op, val, val2)					\
   1172 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
   1173 
   1174 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
   1175 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
   1176 
   1177 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
   1178 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
   1179 			(val), (val2), 0 ,NULL ,NULL)
   1180 
   1181 /************************************************************************
   1182  *									*
   1183  *		XPath object cache structures				*
   1184  *									*
   1185  ************************************************************************/
   1186 
   1187 /* #define XP_DEFAULT_CACHE_ON */
   1188 
   1189 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
   1190 
   1191 typedef struct _xmlXPathContextCache xmlXPathContextCache;
   1192 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
   1193 struct _xmlXPathContextCache {
   1194     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
   1195     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
   1196     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
   1197     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
   1198     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
   1199     int maxNodeset;
   1200     int maxString;
   1201     int maxBoolean;
   1202     int maxNumber;
   1203     int maxMisc;
   1204 #ifdef XP_DEBUG_OBJ_USAGE
   1205     int dbgCachedAll;
   1206     int dbgCachedNodeset;
   1207     int dbgCachedString;
   1208     int dbgCachedBool;
   1209     int dbgCachedNumber;
   1210     int dbgCachedPoint;
   1211     int dbgCachedRange;
   1212     int dbgCachedLocset;
   1213     int dbgCachedUsers;
   1214     int dbgCachedXSLTTree;
   1215     int dbgCachedUndefined;
   1216 
   1217 
   1218     int dbgReusedAll;
   1219     int dbgReusedNodeset;
   1220     int dbgReusedString;
   1221     int dbgReusedBool;
   1222     int dbgReusedNumber;
   1223     int dbgReusedPoint;
   1224     int dbgReusedRange;
   1225     int dbgReusedLocset;
   1226     int dbgReusedUsers;
   1227     int dbgReusedXSLTTree;
   1228     int dbgReusedUndefined;
   1229 
   1230 #endif
   1231 };
   1232 
   1233 /************************************************************************
   1234  *									*
   1235  *		Debugging related functions				*
   1236  *									*
   1237  ************************************************************************/
   1238 
   1239 #define STRANGE							\
   1240     xmlGenericError(xmlGenericErrorContext,				\
   1241 	    "Internal error at %s:%d\n",				\
   1242             __FILE__, __LINE__);
   1243 
   1244 #ifdef LIBXML_DEBUG_ENABLED
   1245 static void
   1246 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
   1247     int i;
   1248     char shift[100];
   1249 
   1250     for (i = 0;((i < depth) && (i < 25));i++)
   1251         shift[2 * i] = shift[2 * i + 1] = ' ';
   1252     shift[2 * i] = shift[2 * i + 1] = 0;
   1253     if (cur == NULL) {
   1254 	fprintf(output, "%s", shift);
   1255 	fprintf(output, "Node is NULL !\n");
   1256 	return;
   1257 
   1258     }
   1259 
   1260     if ((cur->type == XML_DOCUMENT_NODE) ||
   1261 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
   1262 	fprintf(output, "%s", shift);
   1263 	fprintf(output, " /\n");
   1264     } else if (cur->type == XML_ATTRIBUTE_NODE)
   1265 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
   1266     else
   1267 	xmlDebugDumpOneNode(output, cur, depth);
   1268 }
   1269 static void
   1270 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
   1271     xmlNodePtr tmp;
   1272     int i;
   1273     char shift[100];
   1274 
   1275     for (i = 0;((i < depth) && (i < 25));i++)
   1276         shift[2 * i] = shift[2 * i + 1] = ' ';
   1277     shift[2 * i] = shift[2 * i + 1] = 0;
   1278     if (cur == NULL) {
   1279 	fprintf(output, "%s", shift);
   1280 	fprintf(output, "Node is NULL !\n");
   1281 	return;
   1282 
   1283     }
   1284 
   1285     while (cur != NULL) {
   1286 	tmp = cur;
   1287 	cur = cur->next;
   1288 	xmlDebugDumpOneNode(output, tmp, depth);
   1289     }
   1290 }
   1291 
   1292 static void
   1293 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
   1294     int i;
   1295     char shift[100];
   1296 
   1297     for (i = 0;((i < depth) && (i < 25));i++)
   1298         shift[2 * i] = shift[2 * i + 1] = ' ';
   1299     shift[2 * i] = shift[2 * i + 1] = 0;
   1300 
   1301     if (cur == NULL) {
   1302 	fprintf(output, "%s", shift);
   1303 	fprintf(output, "NodeSet is NULL !\n");
   1304 	return;
   1305 
   1306     }
   1307 
   1308     if (cur != NULL) {
   1309 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
   1310 	for (i = 0;i < cur->nodeNr;i++) {
   1311 	    fprintf(output, "%s", shift);
   1312 	    fprintf(output, "%d", i + 1);
   1313 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
   1314 	}
   1315     }
   1316 }
   1317 
   1318 static void
   1319 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
   1320     int i;
   1321     char shift[100];
   1322 
   1323     for (i = 0;((i < depth) && (i < 25));i++)
   1324         shift[2 * i] = shift[2 * i + 1] = ' ';
   1325     shift[2 * i] = shift[2 * i + 1] = 0;
   1326 
   1327     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
   1328 	fprintf(output, "%s", shift);
   1329 	fprintf(output, "Value Tree is NULL !\n");
   1330 	return;
   1331 
   1332     }
   1333 
   1334     fprintf(output, "%s", shift);
   1335     fprintf(output, "%d", i + 1);
   1336     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
   1337 }
   1338 #if defined(LIBXML_XPTR_ENABLED)
   1339 static void
   1340 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
   1341     int i;
   1342     char shift[100];
   1343 
   1344     for (i = 0;((i < depth) && (i < 25));i++)
   1345         shift[2 * i] = shift[2 * i + 1] = ' ';
   1346     shift[2 * i] = shift[2 * i + 1] = 0;
   1347 
   1348     if (cur == NULL) {
   1349 	fprintf(output, "%s", shift);
   1350 	fprintf(output, "LocationSet is NULL !\n");
   1351 	return;
   1352 
   1353     }
   1354 
   1355     for (i = 0;i < cur->locNr;i++) {
   1356 	fprintf(output, "%s", shift);
   1357         fprintf(output, "%d : ", i + 1);
   1358 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
   1359     }
   1360 }
   1361 #endif /* LIBXML_XPTR_ENABLED */
   1362 
   1363 /**
   1364  * xmlXPathDebugDumpObject:
   1365  * @output:  the FILE * to dump the output
   1366  * @cur:  the object to inspect
   1367  * @depth:  indentation level
   1368  *
   1369  * Dump the content of the object for debugging purposes
   1370  */
   1371 void
   1372 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
   1373     int i;
   1374     char shift[100];
   1375 
   1376     if (output == NULL) return;
   1377 
   1378     for (i = 0;((i < depth) && (i < 25));i++)
   1379         shift[2 * i] = shift[2 * i + 1] = ' ';
   1380     shift[2 * i] = shift[2 * i + 1] = 0;
   1381 
   1382 
   1383     fprintf(output, "%s", shift);
   1384 
   1385     if (cur == NULL) {
   1386         fprintf(output, "Object is empty (NULL)\n");
   1387 	return;
   1388     }
   1389     switch(cur->type) {
   1390         case XPATH_UNDEFINED:
   1391 	    fprintf(output, "Object is uninitialized\n");
   1392 	    break;
   1393         case XPATH_NODESET:
   1394 	    fprintf(output, "Object is a Node Set :\n");
   1395 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
   1396 	    break;
   1397 	case XPATH_XSLT_TREE:
   1398 	    fprintf(output, "Object is an XSLT value tree :\n");
   1399 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
   1400 	    break;
   1401         case XPATH_BOOLEAN:
   1402 	    fprintf(output, "Object is a Boolean : ");
   1403 	    if (cur->boolval) fprintf(output, "true\n");
   1404 	    else fprintf(output, "false\n");
   1405 	    break;
   1406         case XPATH_NUMBER:
   1407 	    switch (xmlXPathIsInf(cur->floatval)) {
   1408 	    case 1:
   1409 		fprintf(output, "Object is a number : Infinity\n");
   1410 		break;
   1411 	    case -1:
   1412 		fprintf(output, "Object is a number : -Infinity\n");
   1413 		break;
   1414 	    default:
   1415 		if (xmlXPathIsNaN(cur->floatval)) {
   1416 		    fprintf(output, "Object is a number : NaN\n");
   1417 		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
   1418 		    fprintf(output, "Object is a number : 0\n");
   1419 		} else {
   1420 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
   1421 		}
   1422 	    }
   1423 	    break;
   1424         case XPATH_STRING:
   1425 	    fprintf(output, "Object is a string : ");
   1426 	    xmlDebugDumpString(output, cur->stringval);
   1427 	    fprintf(output, "\n");
   1428 	    break;
   1429 	case XPATH_POINT:
   1430 	    fprintf(output, "Object is a point : index %d in node", cur->index);
   1431 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
   1432 	    fprintf(output, "\n");
   1433 	    break;
   1434 	case XPATH_RANGE:
   1435 	    if ((cur->user2 == NULL) ||
   1436 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
   1437 		fprintf(output, "Object is a collapsed range :\n");
   1438 		fprintf(output, "%s", shift);
   1439 		if (cur->index >= 0)
   1440 		    fprintf(output, "index %d in ", cur->index);
   1441 		fprintf(output, "node\n");
   1442 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
   1443 			              depth + 1);
   1444 	    } else  {
   1445 		fprintf(output, "Object is a range :\n");
   1446 		fprintf(output, "%s", shift);
   1447 		fprintf(output, "From ");
   1448 		if (cur->index >= 0)
   1449 		    fprintf(output, "index %d in ", cur->index);
   1450 		fprintf(output, "node\n");
   1451 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
   1452 			              depth + 1);
   1453 		fprintf(output, "%s", shift);
   1454 		fprintf(output, "To ");
   1455 		if (cur->index2 >= 0)
   1456 		    fprintf(output, "index %d in ", cur->index2);
   1457 		fprintf(output, "node\n");
   1458 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
   1459 			              depth + 1);
   1460 		fprintf(output, "\n");
   1461 	    }
   1462 	    break;
   1463 	case XPATH_LOCATIONSET:
   1464 #if defined(LIBXML_XPTR_ENABLED)
   1465 	    fprintf(output, "Object is a Location Set:\n");
   1466 	    xmlXPathDebugDumpLocationSet(output,
   1467 		    (xmlLocationSetPtr) cur->user, depth);
   1468 #endif
   1469 	    break;
   1470 	case XPATH_USERS:
   1471 	    fprintf(output, "Object is user defined\n");
   1472 	    break;
   1473     }
   1474 }
   1475 
   1476 static void
   1477 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
   1478 	                     xmlXPathStepOpPtr op, int depth) {
   1479     int i;
   1480     char shift[100];
   1481 
   1482     for (i = 0;((i < depth) && (i < 25));i++)
   1483         shift[2 * i] = shift[2 * i + 1] = ' ';
   1484     shift[2 * i] = shift[2 * i + 1] = 0;
   1485 
   1486     fprintf(output, "%s", shift);
   1487     if (op == NULL) {
   1488 	fprintf(output, "Step is NULL\n");
   1489 	return;
   1490     }
   1491     switch (op->op) {
   1492         case XPATH_OP_END:
   1493 	    fprintf(output, "END"); break;
   1494         case XPATH_OP_AND:
   1495 	    fprintf(output, "AND"); break;
   1496         case XPATH_OP_OR:
   1497 	    fprintf(output, "OR"); break;
   1498         case XPATH_OP_EQUAL:
   1499 	     if (op->value)
   1500 		 fprintf(output, "EQUAL =");
   1501 	     else
   1502 		 fprintf(output, "EQUAL !=");
   1503 	     break;
   1504         case XPATH_OP_CMP:
   1505 	     if (op->value)
   1506 		 fprintf(output, "CMP <");
   1507 	     else
   1508 		 fprintf(output, "CMP >");
   1509 	     if (!op->value2)
   1510 		 fprintf(output, "=");
   1511 	     break;
   1512         case XPATH_OP_PLUS:
   1513 	     if (op->value == 0)
   1514 		 fprintf(output, "PLUS -");
   1515 	     else if (op->value == 1)
   1516 		 fprintf(output, "PLUS +");
   1517 	     else if (op->value == 2)
   1518 		 fprintf(output, "PLUS unary -");
   1519 	     else if (op->value == 3)
   1520 		 fprintf(output, "PLUS unary - -");
   1521 	     break;
   1522         case XPATH_OP_MULT:
   1523 	     if (op->value == 0)
   1524 		 fprintf(output, "MULT *");
   1525 	     else if (op->value == 1)
   1526 		 fprintf(output, "MULT div");
   1527 	     else
   1528 		 fprintf(output, "MULT mod");
   1529 	     break;
   1530         case XPATH_OP_UNION:
   1531 	     fprintf(output, "UNION"); break;
   1532         case XPATH_OP_ROOT:
   1533 	     fprintf(output, "ROOT"); break;
   1534         case XPATH_OP_NODE:
   1535 	     fprintf(output, "NODE"); break;
   1536         case XPATH_OP_RESET:
   1537 	     fprintf(output, "RESET"); break;
   1538         case XPATH_OP_SORT:
   1539 	     fprintf(output, "SORT"); break;
   1540         case XPATH_OP_COLLECT: {
   1541 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
   1542 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
   1543 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
   1544 	    const xmlChar *prefix = op->value4;
   1545 	    const xmlChar *name = op->value5;
   1546 
   1547 	    fprintf(output, "COLLECT ");
   1548 	    switch (axis) {
   1549 		case AXIS_ANCESTOR:
   1550 		    fprintf(output, " 'ancestors' "); break;
   1551 		case AXIS_ANCESTOR_OR_SELF:
   1552 		    fprintf(output, " 'ancestors-or-self' "); break;
   1553 		case AXIS_ATTRIBUTE:
   1554 		    fprintf(output, " 'attributes' "); break;
   1555 		case AXIS_CHILD:
   1556 		    fprintf(output, " 'child' "); break;
   1557 		case AXIS_DESCENDANT:
   1558 		    fprintf(output, " 'descendant' "); break;
   1559 		case AXIS_DESCENDANT_OR_SELF:
   1560 		    fprintf(output, " 'descendant-or-self' "); break;
   1561 		case AXIS_FOLLOWING:
   1562 		    fprintf(output, " 'following' "); break;
   1563 		case AXIS_FOLLOWING_SIBLING:
   1564 		    fprintf(output, " 'following-siblings' "); break;
   1565 		case AXIS_NAMESPACE:
   1566 		    fprintf(output, " 'namespace' "); break;
   1567 		case AXIS_PARENT:
   1568 		    fprintf(output, " 'parent' "); break;
   1569 		case AXIS_PRECEDING:
   1570 		    fprintf(output, " 'preceding' "); break;
   1571 		case AXIS_PRECEDING_SIBLING:
   1572 		    fprintf(output, " 'preceding-sibling' "); break;
   1573 		case AXIS_SELF:
   1574 		    fprintf(output, " 'self' "); break;
   1575 	    }
   1576 	    switch (test) {
   1577                 case NODE_TEST_NONE:
   1578 		    fprintf(output, "'none' "); break;
   1579                 case NODE_TEST_TYPE:
   1580 		    fprintf(output, "'type' "); break;
   1581                 case NODE_TEST_PI:
   1582 		    fprintf(output, "'PI' "); break;
   1583                 case NODE_TEST_ALL:
   1584 		    fprintf(output, "'all' "); break;
   1585                 case NODE_TEST_NS:
   1586 		    fprintf(output, "'namespace' "); break;
   1587                 case NODE_TEST_NAME:
   1588 		    fprintf(output, "'name' "); break;
   1589 	    }
   1590 	    switch (type) {
   1591                 case NODE_TYPE_NODE:
   1592 		    fprintf(output, "'node' "); break;
   1593                 case NODE_TYPE_COMMENT:
   1594 		    fprintf(output, "'comment' "); break;
   1595                 case NODE_TYPE_TEXT:
   1596 		    fprintf(output, "'text' "); break;
   1597                 case NODE_TYPE_PI:
   1598 		    fprintf(output, "'PI' "); break;
   1599 	    }
   1600 	    if (prefix != NULL)
   1601 		fprintf(output, "%s:", prefix);
   1602 	    if (name != NULL)
   1603 		fprintf(output, "%s", (const char *) name);
   1604 	    break;
   1605 
   1606         }
   1607 	case XPATH_OP_VALUE: {
   1608 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
   1609 
   1610 	    fprintf(output, "ELEM ");
   1611 	    xmlXPathDebugDumpObject(output, object, 0);
   1612 	    goto finish;
   1613 	}
   1614 	case XPATH_OP_VARIABLE: {
   1615 	    const xmlChar *prefix = op->value5;
   1616 	    const xmlChar *name = op->value4;
   1617 
   1618 	    if (prefix != NULL)
   1619 		fprintf(output, "VARIABLE %s:%s", prefix, name);
   1620 	    else
   1621 		fprintf(output, "VARIABLE %s", name);
   1622 	    break;
   1623 	}
   1624 	case XPATH_OP_FUNCTION: {
   1625 	    int nbargs = op->value;
   1626 	    const xmlChar *prefix = op->value5;
   1627 	    const xmlChar *name = op->value4;
   1628 
   1629 	    if (prefix != NULL)
   1630 		fprintf(output, "FUNCTION %s:%s(%d args)",
   1631 			prefix, name, nbargs);
   1632 	    else
   1633 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
   1634 	    break;
   1635 	}
   1636         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
   1637         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
   1638         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
   1639 #ifdef LIBXML_XPTR_ENABLED
   1640         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
   1641 #endif
   1642 	default:
   1643         fprintf(output, "UNKNOWN %d\n", op->op); return;
   1644     }
   1645     fprintf(output, "\n");
   1646 finish:
   1647     if (op->ch1 >= 0)
   1648 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
   1649     if (op->ch2 >= 0)
   1650 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
   1651 }
   1652 
   1653 /**
   1654  * xmlXPathDebugDumpCompExpr:
   1655  * @output:  the FILE * for the output
   1656  * @comp:  the precompiled XPath expression
   1657  * @depth:  the indentation level.
   1658  *
   1659  * Dumps the tree of the compiled XPath expression.
   1660  */
   1661 void
   1662 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
   1663 	                  int depth) {
   1664     int i;
   1665     char shift[100];
   1666 
   1667     if ((output == NULL) || (comp == NULL)) return;
   1668 
   1669     for (i = 0;((i < depth) && (i < 25));i++)
   1670         shift[2 * i] = shift[2 * i + 1] = ' ';
   1671     shift[2 * i] = shift[2 * i + 1] = 0;
   1672 
   1673     fprintf(output, "%s", shift);
   1674 
   1675     fprintf(output, "Compiled Expression : %d elements\n",
   1676 	    comp->nbStep);
   1677     i = comp->last;
   1678     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
   1679 }
   1680 
   1681 #ifdef XP_DEBUG_OBJ_USAGE
   1682 
   1683 /*
   1684 * XPath object usage related debugging variables.
   1685 */
   1686 static int xmlXPathDebugObjCounterUndefined = 0;
   1687 static int xmlXPathDebugObjCounterNodeset = 0;
   1688 static int xmlXPathDebugObjCounterBool = 0;
   1689 static int xmlXPathDebugObjCounterNumber = 0;
   1690 static int xmlXPathDebugObjCounterString = 0;
   1691 static int xmlXPathDebugObjCounterPoint = 0;
   1692 static int xmlXPathDebugObjCounterRange = 0;
   1693 static int xmlXPathDebugObjCounterLocset = 0;
   1694 static int xmlXPathDebugObjCounterUsers = 0;
   1695 static int xmlXPathDebugObjCounterXSLTTree = 0;
   1696 static int xmlXPathDebugObjCounterAll = 0;
   1697 
   1698 static int xmlXPathDebugObjTotalUndefined = 0;
   1699 static int xmlXPathDebugObjTotalNodeset = 0;
   1700 static int xmlXPathDebugObjTotalBool = 0;
   1701 static int xmlXPathDebugObjTotalNumber = 0;
   1702 static int xmlXPathDebugObjTotalString = 0;
   1703 static int xmlXPathDebugObjTotalPoint = 0;
   1704 static int xmlXPathDebugObjTotalRange = 0;
   1705 static int xmlXPathDebugObjTotalLocset = 0;
   1706 static int xmlXPathDebugObjTotalUsers = 0;
   1707 static int xmlXPathDebugObjTotalXSLTTree = 0;
   1708 static int xmlXPathDebugObjTotalAll = 0;
   1709 
   1710 static int xmlXPathDebugObjMaxUndefined = 0;
   1711 static int xmlXPathDebugObjMaxNodeset = 0;
   1712 static int xmlXPathDebugObjMaxBool = 0;
   1713 static int xmlXPathDebugObjMaxNumber = 0;
   1714 static int xmlXPathDebugObjMaxString = 0;
   1715 static int xmlXPathDebugObjMaxPoint = 0;
   1716 static int xmlXPathDebugObjMaxRange = 0;
   1717 static int xmlXPathDebugObjMaxLocset = 0;
   1718 static int xmlXPathDebugObjMaxUsers = 0;
   1719 static int xmlXPathDebugObjMaxXSLTTree = 0;
   1720 static int xmlXPathDebugObjMaxAll = 0;
   1721 
   1722 /* REVISIT TODO: Make this static when committing */
   1723 static void
   1724 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
   1725 {
   1726     if (ctxt != NULL) {
   1727 	if (ctxt->cache != NULL) {
   1728 	    xmlXPathContextCachePtr cache =
   1729 		(xmlXPathContextCachePtr) ctxt->cache;
   1730 
   1731 	    cache->dbgCachedAll = 0;
   1732 	    cache->dbgCachedNodeset = 0;
   1733 	    cache->dbgCachedString = 0;
   1734 	    cache->dbgCachedBool = 0;
   1735 	    cache->dbgCachedNumber = 0;
   1736 	    cache->dbgCachedPoint = 0;
   1737 	    cache->dbgCachedRange = 0;
   1738 	    cache->dbgCachedLocset = 0;
   1739 	    cache->dbgCachedUsers = 0;
   1740 	    cache->dbgCachedXSLTTree = 0;
   1741 	    cache->dbgCachedUndefined = 0;
   1742 
   1743 	    cache->dbgReusedAll = 0;
   1744 	    cache->dbgReusedNodeset = 0;
   1745 	    cache->dbgReusedString = 0;
   1746 	    cache->dbgReusedBool = 0;
   1747 	    cache->dbgReusedNumber = 0;
   1748 	    cache->dbgReusedPoint = 0;
   1749 	    cache->dbgReusedRange = 0;
   1750 	    cache->dbgReusedLocset = 0;
   1751 	    cache->dbgReusedUsers = 0;
   1752 	    cache->dbgReusedXSLTTree = 0;
   1753 	    cache->dbgReusedUndefined = 0;
   1754 	}
   1755     }
   1756 
   1757     xmlXPathDebugObjCounterUndefined = 0;
   1758     xmlXPathDebugObjCounterNodeset = 0;
   1759     xmlXPathDebugObjCounterBool = 0;
   1760     xmlXPathDebugObjCounterNumber = 0;
   1761     xmlXPathDebugObjCounterString = 0;
   1762     xmlXPathDebugObjCounterPoint = 0;
   1763     xmlXPathDebugObjCounterRange = 0;
   1764     xmlXPathDebugObjCounterLocset = 0;
   1765     xmlXPathDebugObjCounterUsers = 0;
   1766     xmlXPathDebugObjCounterXSLTTree = 0;
   1767     xmlXPathDebugObjCounterAll = 0;
   1768 
   1769     xmlXPathDebugObjTotalUndefined = 0;
   1770     xmlXPathDebugObjTotalNodeset = 0;
   1771     xmlXPathDebugObjTotalBool = 0;
   1772     xmlXPathDebugObjTotalNumber = 0;
   1773     xmlXPathDebugObjTotalString = 0;
   1774     xmlXPathDebugObjTotalPoint = 0;
   1775     xmlXPathDebugObjTotalRange = 0;
   1776     xmlXPathDebugObjTotalLocset = 0;
   1777     xmlXPathDebugObjTotalUsers = 0;
   1778     xmlXPathDebugObjTotalXSLTTree = 0;
   1779     xmlXPathDebugObjTotalAll = 0;
   1780 
   1781     xmlXPathDebugObjMaxUndefined = 0;
   1782     xmlXPathDebugObjMaxNodeset = 0;
   1783     xmlXPathDebugObjMaxBool = 0;
   1784     xmlXPathDebugObjMaxNumber = 0;
   1785     xmlXPathDebugObjMaxString = 0;
   1786     xmlXPathDebugObjMaxPoint = 0;
   1787     xmlXPathDebugObjMaxRange = 0;
   1788     xmlXPathDebugObjMaxLocset = 0;
   1789     xmlXPathDebugObjMaxUsers = 0;
   1790     xmlXPathDebugObjMaxXSLTTree = 0;
   1791     xmlXPathDebugObjMaxAll = 0;
   1792 
   1793 }
   1794 
   1795 static void
   1796 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
   1797 			      xmlXPathObjectType objType)
   1798 {
   1799     int isCached = 0;
   1800 
   1801     if (ctxt != NULL) {
   1802 	if (ctxt->cache != NULL) {
   1803 	    xmlXPathContextCachePtr cache =
   1804 		(xmlXPathContextCachePtr) ctxt->cache;
   1805 
   1806 	    isCached = 1;
   1807 
   1808 	    cache->dbgReusedAll++;
   1809 	    switch (objType) {
   1810 		case XPATH_UNDEFINED:
   1811 		    cache->dbgReusedUndefined++;
   1812 		    break;
   1813 		case XPATH_NODESET:
   1814 		    cache->dbgReusedNodeset++;
   1815 		    break;
   1816 		case XPATH_BOOLEAN:
   1817 		    cache->dbgReusedBool++;
   1818 		    break;
   1819 		case XPATH_NUMBER:
   1820 		    cache->dbgReusedNumber++;
   1821 		    break;
   1822 		case XPATH_STRING:
   1823 		    cache->dbgReusedString++;
   1824 		    break;
   1825 		case XPATH_POINT:
   1826 		    cache->dbgReusedPoint++;
   1827 		    break;
   1828 		case XPATH_RANGE:
   1829 		    cache->dbgReusedRange++;
   1830 		    break;
   1831 		case XPATH_LOCATIONSET:
   1832 		    cache->dbgReusedLocset++;
   1833 		    break;
   1834 		case XPATH_USERS:
   1835 		    cache->dbgReusedUsers++;
   1836 		    break;
   1837 		case XPATH_XSLT_TREE:
   1838 		    cache->dbgReusedXSLTTree++;
   1839 		    break;
   1840 		default:
   1841 		    break;
   1842 	    }
   1843 	}
   1844     }
   1845 
   1846     switch (objType) {
   1847 	case XPATH_UNDEFINED:
   1848 	    if (! isCached)
   1849 		xmlXPathDebugObjTotalUndefined++;
   1850 	    xmlXPathDebugObjCounterUndefined++;
   1851 	    if (xmlXPathDebugObjCounterUndefined >
   1852 		xmlXPathDebugObjMaxUndefined)
   1853 		xmlXPathDebugObjMaxUndefined =
   1854 		    xmlXPathDebugObjCounterUndefined;
   1855 	    break;
   1856 	case XPATH_NODESET:
   1857 	    if (! isCached)
   1858 		xmlXPathDebugObjTotalNodeset++;
   1859 	    xmlXPathDebugObjCounterNodeset++;
   1860 	    if (xmlXPathDebugObjCounterNodeset >
   1861 		xmlXPathDebugObjMaxNodeset)
   1862 		xmlXPathDebugObjMaxNodeset =
   1863 		    xmlXPathDebugObjCounterNodeset;
   1864 	    break;
   1865 	case XPATH_BOOLEAN:
   1866 	    if (! isCached)
   1867 		xmlXPathDebugObjTotalBool++;
   1868 	    xmlXPathDebugObjCounterBool++;
   1869 	    if (xmlXPathDebugObjCounterBool >
   1870 		xmlXPathDebugObjMaxBool)
   1871 		xmlXPathDebugObjMaxBool =
   1872 		    xmlXPathDebugObjCounterBool;
   1873 	    break;
   1874 	case XPATH_NUMBER:
   1875 	    if (! isCached)
   1876 		xmlXPathDebugObjTotalNumber++;
   1877 	    xmlXPathDebugObjCounterNumber++;
   1878 	    if (xmlXPathDebugObjCounterNumber >
   1879 		xmlXPathDebugObjMaxNumber)
   1880 		xmlXPathDebugObjMaxNumber =
   1881 		    xmlXPathDebugObjCounterNumber;
   1882 	    break;
   1883 	case XPATH_STRING:
   1884 	    if (! isCached)
   1885 		xmlXPathDebugObjTotalString++;
   1886 	    xmlXPathDebugObjCounterString++;
   1887 	    if (xmlXPathDebugObjCounterString >
   1888 		xmlXPathDebugObjMaxString)
   1889 		xmlXPathDebugObjMaxString =
   1890 		    xmlXPathDebugObjCounterString;
   1891 	    break;
   1892 	case XPATH_POINT:
   1893 	    if (! isCached)
   1894 		xmlXPathDebugObjTotalPoint++;
   1895 	    xmlXPathDebugObjCounterPoint++;
   1896 	    if (xmlXPathDebugObjCounterPoint >
   1897 		xmlXPathDebugObjMaxPoint)
   1898 		xmlXPathDebugObjMaxPoint =
   1899 		    xmlXPathDebugObjCounterPoint;
   1900 	    break;
   1901 	case XPATH_RANGE:
   1902 	    if (! isCached)
   1903 		xmlXPathDebugObjTotalRange++;
   1904 	    xmlXPathDebugObjCounterRange++;
   1905 	    if (xmlXPathDebugObjCounterRange >
   1906 		xmlXPathDebugObjMaxRange)
   1907 		xmlXPathDebugObjMaxRange =
   1908 		    xmlXPathDebugObjCounterRange;
   1909 	    break;
   1910 	case XPATH_LOCATIONSET:
   1911 	    if (! isCached)
   1912 		xmlXPathDebugObjTotalLocset++;
   1913 	    xmlXPathDebugObjCounterLocset++;
   1914 	    if (xmlXPathDebugObjCounterLocset >
   1915 		xmlXPathDebugObjMaxLocset)
   1916 		xmlXPathDebugObjMaxLocset =
   1917 		    xmlXPathDebugObjCounterLocset;
   1918 	    break;
   1919 	case XPATH_USERS:
   1920 	    if (! isCached)
   1921 		xmlXPathDebugObjTotalUsers++;
   1922 	    xmlXPathDebugObjCounterUsers++;
   1923 	    if (xmlXPathDebugObjCounterUsers >
   1924 		xmlXPathDebugObjMaxUsers)
   1925 		xmlXPathDebugObjMaxUsers =
   1926 		    xmlXPathDebugObjCounterUsers;
   1927 	    break;
   1928 	case XPATH_XSLT_TREE:
   1929 	    if (! isCached)
   1930 		xmlXPathDebugObjTotalXSLTTree++;
   1931 	    xmlXPathDebugObjCounterXSLTTree++;
   1932 	    if (xmlXPathDebugObjCounterXSLTTree >
   1933 		xmlXPathDebugObjMaxXSLTTree)
   1934 		xmlXPathDebugObjMaxXSLTTree =
   1935 		    xmlXPathDebugObjCounterXSLTTree;
   1936 	    break;
   1937 	default:
   1938 	    break;
   1939     }
   1940     if (! isCached)
   1941 	xmlXPathDebugObjTotalAll++;
   1942     xmlXPathDebugObjCounterAll++;
   1943     if (xmlXPathDebugObjCounterAll >
   1944 	xmlXPathDebugObjMaxAll)
   1945 	xmlXPathDebugObjMaxAll =
   1946 	    xmlXPathDebugObjCounterAll;
   1947 }
   1948 
   1949 static void
   1950 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
   1951 			      xmlXPathObjectType objType)
   1952 {
   1953     int isCached = 0;
   1954 
   1955     if (ctxt != NULL) {
   1956 	if (ctxt->cache != NULL) {
   1957 	    xmlXPathContextCachePtr cache =
   1958 		(xmlXPathContextCachePtr) ctxt->cache;
   1959 
   1960 	    isCached = 1;
   1961 
   1962 	    cache->dbgCachedAll++;
   1963 	    switch (objType) {
   1964 		case XPATH_UNDEFINED:
   1965 		    cache->dbgCachedUndefined++;
   1966 		    break;
   1967 		case XPATH_NODESET:
   1968 		    cache->dbgCachedNodeset++;
   1969 		    break;
   1970 		case XPATH_BOOLEAN:
   1971 		    cache->dbgCachedBool++;
   1972 		    break;
   1973 		case XPATH_NUMBER:
   1974 		    cache->dbgCachedNumber++;
   1975 		    break;
   1976 		case XPATH_STRING:
   1977 		    cache->dbgCachedString++;
   1978 		    break;
   1979 		case XPATH_POINT:
   1980 		    cache->dbgCachedPoint++;
   1981 		    break;
   1982 		case XPATH_RANGE:
   1983 		    cache->dbgCachedRange++;
   1984 		    break;
   1985 		case XPATH_LOCATIONSET:
   1986 		    cache->dbgCachedLocset++;
   1987 		    break;
   1988 		case XPATH_USERS:
   1989 		    cache->dbgCachedUsers++;
   1990 		    break;
   1991 		case XPATH_XSLT_TREE:
   1992 		    cache->dbgCachedXSLTTree++;
   1993 		    break;
   1994 		default:
   1995 		    break;
   1996 	    }
   1997 
   1998 	}
   1999     }
   2000     switch (objType) {
   2001 	case XPATH_UNDEFINED:
   2002 	    xmlXPathDebugObjCounterUndefined--;
   2003 	    break;
   2004 	case XPATH_NODESET:
   2005 	    xmlXPathDebugObjCounterNodeset--;
   2006 	    break;
   2007 	case XPATH_BOOLEAN:
   2008 	    xmlXPathDebugObjCounterBool--;
   2009 	    break;
   2010 	case XPATH_NUMBER:
   2011 	    xmlXPathDebugObjCounterNumber--;
   2012 	    break;
   2013 	case XPATH_STRING:
   2014 	    xmlXPathDebugObjCounterString--;
   2015 	    break;
   2016 	case XPATH_POINT:
   2017 	    xmlXPathDebugObjCounterPoint--;
   2018 	    break;
   2019 	case XPATH_RANGE:
   2020 	    xmlXPathDebugObjCounterRange--;
   2021 	    break;
   2022 	case XPATH_LOCATIONSET:
   2023 	    xmlXPathDebugObjCounterLocset--;
   2024 	    break;
   2025 	case XPATH_USERS:
   2026 	    xmlXPathDebugObjCounterUsers--;
   2027 	    break;
   2028 	case XPATH_XSLT_TREE:
   2029 	    xmlXPathDebugObjCounterXSLTTree--;
   2030 	    break;
   2031 	default:
   2032 	    break;
   2033     }
   2034     xmlXPathDebugObjCounterAll--;
   2035 }
   2036 
   2037 /* REVISIT TODO: Make this static when committing */
   2038 static void
   2039 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
   2040 {
   2041     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
   2042 	reqXSLTTree, reqUndefined;
   2043     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
   2044 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
   2045     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
   2046 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
   2047     int leftObjs = xmlXPathDebugObjCounterAll;
   2048 
   2049     reqAll = xmlXPathDebugObjTotalAll;
   2050     reqNodeset = xmlXPathDebugObjTotalNodeset;
   2051     reqString = xmlXPathDebugObjTotalString;
   2052     reqBool = xmlXPathDebugObjTotalBool;
   2053     reqNumber = xmlXPathDebugObjTotalNumber;
   2054     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
   2055     reqUndefined = xmlXPathDebugObjTotalUndefined;
   2056 
   2057     printf("# XPath object usage:\n");
   2058 
   2059     if (ctxt != NULL) {
   2060 	if (ctxt->cache != NULL) {
   2061 	    xmlXPathContextCachePtr cache =
   2062 		(xmlXPathContextCachePtr) ctxt->cache;
   2063 
   2064 	    reAll = cache->dbgReusedAll;
   2065 	    reqAll += reAll;
   2066 	    reNodeset = cache->dbgReusedNodeset;
   2067 	    reqNodeset += reNodeset;
   2068 	    reString = cache->dbgReusedString;
   2069 	    reqString += reString;
   2070 	    reBool = cache->dbgReusedBool;
   2071 	    reqBool += reBool;
   2072 	    reNumber = cache->dbgReusedNumber;
   2073 	    reqNumber += reNumber;
   2074 	    reXSLTTree = cache->dbgReusedXSLTTree;
   2075 	    reqXSLTTree += reXSLTTree;
   2076 	    reUndefined = cache->dbgReusedUndefined;
   2077 	    reqUndefined += reUndefined;
   2078 
   2079 	    caAll = cache->dbgCachedAll;
   2080 	    caBool = cache->dbgCachedBool;
   2081 	    caNodeset = cache->dbgCachedNodeset;
   2082 	    caString = cache->dbgCachedString;
   2083 	    caNumber = cache->dbgCachedNumber;
   2084 	    caXSLTTree = cache->dbgCachedXSLTTree;
   2085 	    caUndefined = cache->dbgCachedUndefined;
   2086 
   2087 	    if (cache->nodesetObjs)
   2088 		leftObjs -= cache->nodesetObjs->number;
   2089 	    if (cache->stringObjs)
   2090 		leftObjs -= cache->stringObjs->number;
   2091 	    if (cache->booleanObjs)
   2092 		leftObjs -= cache->booleanObjs->number;
   2093 	    if (cache->numberObjs)
   2094 		leftObjs -= cache->numberObjs->number;
   2095 	    if (cache->miscObjs)
   2096 		leftObjs -= cache->miscObjs->number;
   2097 	}
   2098     }
   2099 
   2100     printf("# all\n");
   2101     printf("#   total  : %d\n", reqAll);
   2102     printf("#   left  : %d\n", leftObjs);
   2103     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
   2104     printf("#   reused : %d\n", reAll);
   2105     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
   2106 
   2107     printf("# node-sets\n");
   2108     printf("#   total  : %d\n", reqNodeset);
   2109     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
   2110     printf("#   reused : %d\n", reNodeset);
   2111     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
   2112 
   2113     printf("# strings\n");
   2114     printf("#   total  : %d\n", reqString);
   2115     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
   2116     printf("#   reused : %d\n", reString);
   2117     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
   2118 
   2119     printf("# booleans\n");
   2120     printf("#   total  : %d\n", reqBool);
   2121     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
   2122     printf("#   reused : %d\n", reBool);
   2123     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
   2124 
   2125     printf("# numbers\n");
   2126     printf("#   total  : %d\n", reqNumber);
   2127     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
   2128     printf("#   reused : %d\n", reNumber);
   2129     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
   2130 
   2131     printf("# XSLT result tree fragments\n");
   2132     printf("#   total  : %d\n", reqXSLTTree);
   2133     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
   2134     printf("#   reused : %d\n", reXSLTTree);
   2135     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
   2136 
   2137     printf("# undefined\n");
   2138     printf("#   total  : %d\n", reqUndefined);
   2139     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
   2140     printf("#   reused : %d\n", reUndefined);
   2141     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
   2142 
   2143 }
   2144 
   2145 #endif /* XP_DEBUG_OBJ_USAGE */
   2146 
   2147 #endif /* LIBXML_DEBUG_ENABLED */
   2148 
   2149 /************************************************************************
   2150  *									*
   2151  *			XPath object caching				*
   2152  *									*
   2153  ************************************************************************/
   2154 
   2155 /**
   2156  * xmlXPathNewCache:
   2157  *
   2158  * Create a new object cache
   2159  *
   2160  * Returns the xmlXPathCache just allocated.
   2161  */
   2162 static xmlXPathContextCachePtr
   2163 xmlXPathNewCache(void)
   2164 {
   2165     xmlXPathContextCachePtr ret;
   2166 
   2167     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
   2168     if (ret == NULL) {
   2169         xmlXPathErrMemory(NULL, "creating object cache\n");
   2170 	return(NULL);
   2171     }
   2172     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
   2173     ret->maxNodeset = 100;
   2174     ret->maxString = 100;
   2175     ret->maxBoolean = 100;
   2176     ret->maxNumber = 100;
   2177     ret->maxMisc = 100;
   2178     return(ret);
   2179 }
   2180 
   2181 static void
   2182 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
   2183 {
   2184     int i;
   2185     xmlXPathObjectPtr obj;
   2186 
   2187     if (list == NULL)
   2188 	return;
   2189 
   2190     for (i = 0; i < list->number; i++) {
   2191 	obj = list->items[i];
   2192 	/*
   2193 	* Note that it is already assured that we don't need to
   2194 	* look out for namespace nodes in the node-set.
   2195 	*/
   2196 	if (obj->nodesetval != NULL) {
   2197 	    if (obj->nodesetval->nodeTab != NULL)
   2198 		xmlFree(obj->nodesetval->nodeTab);
   2199 	    xmlFree(obj->nodesetval);
   2200 	}
   2201 	xmlFree(obj);
   2202 #ifdef XP_DEBUG_OBJ_USAGE
   2203 	xmlXPathDebugObjCounterAll--;
   2204 #endif
   2205     }
   2206     xmlPointerListFree(list);
   2207 }
   2208 
   2209 static void
   2210 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
   2211 {
   2212     if (cache == NULL)
   2213 	return;
   2214     if (cache->nodesetObjs)
   2215 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
   2216     if (cache->stringObjs)
   2217 	xmlXPathCacheFreeObjectList(cache->stringObjs);
   2218     if (cache->booleanObjs)
   2219 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
   2220     if (cache->numberObjs)
   2221 	xmlXPathCacheFreeObjectList(cache->numberObjs);
   2222     if (cache->miscObjs)
   2223 	xmlXPathCacheFreeObjectList(cache->miscObjs);
   2224     xmlFree(cache);
   2225 }
   2226 
   2227 /**
   2228  * xmlXPathContextSetCache:
   2229  *
   2230  * @ctxt:  the XPath context
   2231  * @active: enables/disables (creates/frees) the cache
   2232  * @value: a value with semantics dependant on @options
   2233  * @options: options (currently only the value 0 is used)
   2234  *
   2235  * Creates/frees an object cache on the XPath context.
   2236  * If activates XPath objects (xmlXPathObject) will be cached internally
   2237  * to be reused.
   2238  * @options:
   2239  *   0: This will set the XPath object caching:
   2240  *      @value:
   2241  *        This will set the maximum number of XPath objects
   2242  *        to be cached per slot
   2243  *        There are 5 slots for: node-set, string, number, boolean, and
   2244  *        misc objects. Use <0 for the default number (100).
   2245  *   Other values for @options have currently no effect.
   2246  *
   2247  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
   2248  */
   2249 int
   2250 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
   2251 			int active,
   2252 			int value,
   2253 			int options)
   2254 {
   2255     if (ctxt == NULL)
   2256 	return(-1);
   2257     if (active) {
   2258 	xmlXPathContextCachePtr cache;
   2259 
   2260 	if (ctxt->cache == NULL) {
   2261 	    ctxt->cache = xmlXPathNewCache();
   2262 	    if (ctxt->cache == NULL)
   2263 		return(-1);
   2264 	}
   2265 	cache = (xmlXPathContextCachePtr) ctxt->cache;
   2266 	if (options == 0) {
   2267 	    if (value < 0)
   2268 		value = 100;
   2269 	    cache->maxNodeset = value;
   2270 	    cache->maxString = value;
   2271 	    cache->maxNumber = value;
   2272 	    cache->maxBoolean = value;
   2273 	    cache->maxMisc = value;
   2274 	}
   2275     } else if (ctxt->cache != NULL) {
   2276 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
   2277 	ctxt->cache = NULL;
   2278     }
   2279     return(0);
   2280 }
   2281 
   2282 /**
   2283  * xmlXPathCacheWrapNodeSet:
   2284  * @ctxt: the XPath context
   2285  * @val:  the NodePtr value
   2286  *
   2287  * This is the cached version of xmlXPathWrapNodeSet().
   2288  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
   2289  *
   2290  * Returns the created or reused object.
   2291  */
   2292 static xmlXPathObjectPtr
   2293 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
   2294 {
   2295     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
   2296 	xmlXPathContextCachePtr cache =
   2297 	    (xmlXPathContextCachePtr) ctxt->cache;
   2298 
   2299 	if ((cache->miscObjs != NULL) &&
   2300 	    (cache->miscObjs->number != 0))
   2301 	{
   2302 	    xmlXPathObjectPtr ret;
   2303 
   2304 	    ret = (xmlXPathObjectPtr)
   2305 		cache->miscObjs->items[--cache->miscObjs->number];
   2306 	    ret->type = XPATH_NODESET;
   2307 	    ret->nodesetval = val;
   2308 #ifdef XP_DEBUG_OBJ_USAGE
   2309 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   2310 #endif
   2311 	    return(ret);
   2312 	}
   2313     }
   2314 
   2315     return(xmlXPathWrapNodeSet(val));
   2316 
   2317 }
   2318 
   2319 /**
   2320  * xmlXPathCacheWrapString:
   2321  * @ctxt: the XPath context
   2322  * @val:  the xmlChar * value
   2323  *
   2324  * This is the cached version of xmlXPathWrapString().
   2325  * Wraps the @val string into an XPath object.
   2326  *
   2327  * Returns the created or reused object.
   2328  */
   2329 static xmlXPathObjectPtr
   2330 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
   2331 {
   2332     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
   2333 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2334 
   2335 	if ((cache->stringObjs != NULL) &&
   2336 	    (cache->stringObjs->number != 0))
   2337 	{
   2338 
   2339 	    xmlXPathObjectPtr ret;
   2340 
   2341 	    ret = (xmlXPathObjectPtr)
   2342 		cache->stringObjs->items[--cache->stringObjs->number];
   2343 	    ret->type = XPATH_STRING;
   2344 	    ret->stringval = val;
   2345 #ifdef XP_DEBUG_OBJ_USAGE
   2346 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2347 #endif
   2348 	    return(ret);
   2349 	} else if ((cache->miscObjs != NULL) &&
   2350 	    (cache->miscObjs->number != 0))
   2351 	{
   2352 	    xmlXPathObjectPtr ret;
   2353 	    /*
   2354 	    * Fallback to misc-cache.
   2355 	    */
   2356 	    ret = (xmlXPathObjectPtr)
   2357 		cache->miscObjs->items[--cache->miscObjs->number];
   2358 
   2359 	    ret->type = XPATH_STRING;
   2360 	    ret->stringval = val;
   2361 #ifdef XP_DEBUG_OBJ_USAGE
   2362 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2363 #endif
   2364 	    return(ret);
   2365 	}
   2366     }
   2367     return(xmlXPathWrapString(val));
   2368 }
   2369 
   2370 /**
   2371  * xmlXPathCacheNewNodeSet:
   2372  * @ctxt: the XPath context
   2373  * @val:  the NodePtr value
   2374  *
   2375  * This is the cached version of xmlXPathNewNodeSet().
   2376  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
   2377  * it with the single Node @val
   2378  *
   2379  * Returns the created or reused object.
   2380  */
   2381 static xmlXPathObjectPtr
   2382 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
   2383 {
   2384     if ((ctxt != NULL) && (ctxt->cache)) {
   2385 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2386 
   2387 	if ((cache->nodesetObjs != NULL) &&
   2388 	    (cache->nodesetObjs->number != 0))
   2389 	{
   2390 	    xmlXPathObjectPtr ret;
   2391 	    /*
   2392 	    * Use the nodset-cache.
   2393 	    */
   2394 	    ret = (xmlXPathObjectPtr)
   2395 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
   2396 	    ret->type = XPATH_NODESET;
   2397 	    ret->boolval = 0;
   2398 	    if (val) {
   2399 		if ((ret->nodesetval->nodeMax == 0) ||
   2400 		    (val->type == XML_NAMESPACE_DECL))
   2401 		{
   2402 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
   2403 		} else {
   2404 		    ret->nodesetval->nodeTab[0] = val;
   2405 		    ret->nodesetval->nodeNr = 1;
   2406 		}
   2407 	    }
   2408 #ifdef XP_DEBUG_OBJ_USAGE
   2409 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   2410 #endif
   2411 	    return(ret);
   2412 	} else if ((cache->miscObjs != NULL) &&
   2413 	    (cache->miscObjs->number != 0))
   2414 	{
   2415 	    xmlXPathObjectPtr ret;
   2416 	    /*
   2417 	    * Fallback to misc-cache.
   2418 	    */
   2419 
   2420 	    ret = (xmlXPathObjectPtr)
   2421 		cache->miscObjs->items[--cache->miscObjs->number];
   2422 
   2423 	    ret->type = XPATH_NODESET;
   2424 	    ret->boolval = 0;
   2425 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
   2426 	    if (ret->nodesetval == NULL) {
   2427 		ctxt->lastError.domain = XML_FROM_XPATH;
   2428 		ctxt->lastError.code = XML_ERR_NO_MEMORY;
   2429 		return(NULL);
   2430 	    }
   2431 #ifdef XP_DEBUG_OBJ_USAGE
   2432 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   2433 #endif
   2434 	    return(ret);
   2435 	}
   2436     }
   2437     return(xmlXPathNewNodeSet(val));
   2438 }
   2439 
   2440 /**
   2441  * xmlXPathCacheNewCString:
   2442  * @ctxt: the XPath context
   2443  * @val:  the char * value
   2444  *
   2445  * This is the cached version of xmlXPathNewCString().
   2446  * Acquire an xmlXPathObjectPtr of type string and of value @val
   2447  *
   2448  * Returns the created or reused object.
   2449  */
   2450 static xmlXPathObjectPtr
   2451 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
   2452 {
   2453     if ((ctxt != NULL) && (ctxt->cache)) {
   2454 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2455 
   2456 	if ((cache->stringObjs != NULL) &&
   2457 	    (cache->stringObjs->number != 0))
   2458 	{
   2459 	    xmlXPathObjectPtr ret;
   2460 
   2461 	    ret = (xmlXPathObjectPtr)
   2462 		cache->stringObjs->items[--cache->stringObjs->number];
   2463 
   2464 	    ret->type = XPATH_STRING;
   2465 	    ret->stringval = xmlStrdup(BAD_CAST val);
   2466 #ifdef XP_DEBUG_OBJ_USAGE
   2467 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2468 #endif
   2469 	    return(ret);
   2470 	} else if ((cache->miscObjs != NULL) &&
   2471 	    (cache->miscObjs->number != 0))
   2472 	{
   2473 	    xmlXPathObjectPtr ret;
   2474 
   2475 	    ret = (xmlXPathObjectPtr)
   2476 		cache->miscObjs->items[--cache->miscObjs->number];
   2477 
   2478 	    ret->type = XPATH_STRING;
   2479 	    ret->stringval = xmlStrdup(BAD_CAST val);
   2480 #ifdef XP_DEBUG_OBJ_USAGE
   2481 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2482 #endif
   2483 	    return(ret);
   2484 	}
   2485     }
   2486     return(xmlXPathNewCString(val));
   2487 }
   2488 
   2489 /**
   2490  * xmlXPathCacheNewString:
   2491  * @ctxt: the XPath context
   2492  * @val:  the xmlChar * value
   2493  *
   2494  * This is the cached version of xmlXPathNewString().
   2495  * Acquire an xmlXPathObjectPtr of type string and of value @val
   2496  *
   2497  * Returns the created or reused object.
   2498  */
   2499 static xmlXPathObjectPtr
   2500 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
   2501 {
   2502     if ((ctxt != NULL) && (ctxt->cache)) {
   2503 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2504 
   2505 	if ((cache->stringObjs != NULL) &&
   2506 	    (cache->stringObjs->number != 0))
   2507 	{
   2508 	    xmlXPathObjectPtr ret;
   2509 
   2510 	    ret = (xmlXPathObjectPtr)
   2511 		cache->stringObjs->items[--cache->stringObjs->number];
   2512 	    ret->type = XPATH_STRING;
   2513 	    if (val != NULL)
   2514 		ret->stringval = xmlStrdup(val);
   2515 	    else
   2516 		ret->stringval = xmlStrdup((const xmlChar *)"");
   2517 #ifdef XP_DEBUG_OBJ_USAGE
   2518 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2519 #endif
   2520 	    return(ret);
   2521 	} else if ((cache->miscObjs != NULL) &&
   2522 	    (cache->miscObjs->number != 0))
   2523 	{
   2524 	    xmlXPathObjectPtr ret;
   2525 
   2526 	    ret = (xmlXPathObjectPtr)
   2527 		cache->miscObjs->items[--cache->miscObjs->number];
   2528 
   2529 	    ret->type = XPATH_STRING;
   2530 	    if (val != NULL)
   2531 		ret->stringval = xmlStrdup(val);
   2532 	    else
   2533 		ret->stringval = xmlStrdup((const xmlChar *)"");
   2534 #ifdef XP_DEBUG_OBJ_USAGE
   2535 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2536 #endif
   2537 	    return(ret);
   2538 	}
   2539     }
   2540     return(xmlXPathNewString(val));
   2541 }
   2542 
   2543 /**
   2544  * xmlXPathCacheNewBoolean:
   2545  * @ctxt: the XPath context
   2546  * @val:  the boolean value
   2547  *
   2548  * This is the cached version of xmlXPathNewBoolean().
   2549  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
   2550  *
   2551  * Returns the created or reused object.
   2552  */
   2553 static xmlXPathObjectPtr
   2554 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
   2555 {
   2556     if ((ctxt != NULL) && (ctxt->cache)) {
   2557 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2558 
   2559 	if ((cache->booleanObjs != NULL) &&
   2560 	    (cache->booleanObjs->number != 0))
   2561 	{
   2562 	    xmlXPathObjectPtr ret;
   2563 
   2564 	    ret = (xmlXPathObjectPtr)
   2565 		cache->booleanObjs->items[--cache->booleanObjs->number];
   2566 	    ret->type = XPATH_BOOLEAN;
   2567 	    ret->boolval = (val != 0);
   2568 #ifdef XP_DEBUG_OBJ_USAGE
   2569 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
   2570 #endif
   2571 	    return(ret);
   2572 	} else if ((cache->miscObjs != NULL) &&
   2573 	    (cache->miscObjs->number != 0))
   2574 	{
   2575 	    xmlXPathObjectPtr ret;
   2576 
   2577 	    ret = (xmlXPathObjectPtr)
   2578 		cache->miscObjs->items[--cache->miscObjs->number];
   2579 
   2580 	    ret->type = XPATH_BOOLEAN;
   2581 	    ret->boolval = (val != 0);
   2582 #ifdef XP_DEBUG_OBJ_USAGE
   2583 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
   2584 #endif
   2585 	    return(ret);
   2586 	}
   2587     }
   2588     return(xmlXPathNewBoolean(val));
   2589 }
   2590 
   2591 /**
   2592  * xmlXPathCacheNewFloat:
   2593  * @ctxt: the XPath context
   2594  * @val:  the double value
   2595  *
   2596  * This is the cached version of xmlXPathNewFloat().
   2597  * Acquires an xmlXPathObjectPtr of type double and of value @val
   2598  *
   2599  * Returns the created or reused object.
   2600  */
   2601 static xmlXPathObjectPtr
   2602 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
   2603 {
   2604      if ((ctxt != NULL) && (ctxt->cache)) {
   2605 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2606 
   2607 	if ((cache->numberObjs != NULL) &&
   2608 	    (cache->numberObjs->number != 0))
   2609 	{
   2610 	    xmlXPathObjectPtr ret;
   2611 
   2612 	    ret = (xmlXPathObjectPtr)
   2613 		cache->numberObjs->items[--cache->numberObjs->number];
   2614 	    ret->type = XPATH_NUMBER;
   2615 	    ret->floatval = val;
   2616 #ifdef XP_DEBUG_OBJ_USAGE
   2617 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
   2618 #endif
   2619 	    return(ret);
   2620 	} else if ((cache->miscObjs != NULL) &&
   2621 	    (cache->miscObjs->number != 0))
   2622 	{
   2623 	    xmlXPathObjectPtr ret;
   2624 
   2625 	    ret = (xmlXPathObjectPtr)
   2626 		cache->miscObjs->items[--cache->miscObjs->number];
   2627 
   2628 	    ret->type = XPATH_NUMBER;
   2629 	    ret->floatval = val;
   2630 #ifdef XP_DEBUG_OBJ_USAGE
   2631 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
   2632 #endif
   2633 	    return(ret);
   2634 	}
   2635     }
   2636     return(xmlXPathNewFloat(val));
   2637 }
   2638 
   2639 /**
   2640  * xmlXPathCacheConvertString:
   2641  * @ctxt: the XPath context
   2642  * @val:  an XPath object
   2643  *
   2644  * This is the cached version of xmlXPathConvertString().
   2645  * Converts an existing object to its string() equivalent
   2646  *
   2647  * Returns a created or reused object, the old one is freed (cached)
   2648  *         (or the operation is done directly on @val)
   2649  */
   2650 
   2651 static xmlXPathObjectPtr
   2652 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2653     xmlChar *res = NULL;
   2654 
   2655     if (val == NULL)
   2656 	return(xmlXPathCacheNewCString(ctxt, ""));
   2657 
   2658     switch (val->type) {
   2659     case XPATH_UNDEFINED:
   2660 #ifdef DEBUG_EXPR
   2661 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
   2662 #endif
   2663 	break;
   2664     case XPATH_NODESET:
   2665     case XPATH_XSLT_TREE:
   2666 	res = xmlXPathCastNodeSetToString(val->nodesetval);
   2667 	break;
   2668     case XPATH_STRING:
   2669 	return(val);
   2670     case XPATH_BOOLEAN:
   2671 	res = xmlXPathCastBooleanToString(val->boolval);
   2672 	break;
   2673     case XPATH_NUMBER:
   2674 	res = xmlXPathCastNumberToString(val->floatval);
   2675 	break;
   2676     case XPATH_USERS:
   2677     case XPATH_POINT:
   2678     case XPATH_RANGE:
   2679     case XPATH_LOCATIONSET:
   2680 	TODO;
   2681 	break;
   2682     }
   2683     xmlXPathReleaseObject(ctxt, val);
   2684     if (res == NULL)
   2685 	return(xmlXPathCacheNewCString(ctxt, ""));
   2686     return(xmlXPathCacheWrapString(ctxt, res));
   2687 }
   2688 
   2689 /**
   2690  * xmlXPathCacheObjectCopy:
   2691  * @ctxt: the XPath context
   2692  * @val:  the original object
   2693  *
   2694  * This is the cached version of xmlXPathObjectCopy().
   2695  * Acquire a copy of a given object
   2696  *
   2697  * Returns a created or reused created object.
   2698  */
   2699 static xmlXPathObjectPtr
   2700 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
   2701 {
   2702     if (val == NULL)
   2703 	return(NULL);
   2704 
   2705     if (XP_HAS_CACHE(ctxt)) {
   2706 	switch (val->type) {
   2707 	    case XPATH_NODESET:
   2708 		return(xmlXPathCacheWrapNodeSet(ctxt,
   2709 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
   2710 	    case XPATH_STRING:
   2711 		return(xmlXPathCacheNewString(ctxt, val->stringval));
   2712 	    case XPATH_BOOLEAN:
   2713 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
   2714 	    case XPATH_NUMBER:
   2715 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
   2716 	    default:
   2717 		break;
   2718 	}
   2719     }
   2720     return(xmlXPathObjectCopy(val));
   2721 }
   2722 
   2723 /**
   2724  * xmlXPathCacheConvertBoolean:
   2725  * @ctxt: the XPath context
   2726  * @val:  an XPath object
   2727  *
   2728  * This is the cached version of xmlXPathConvertBoolean().
   2729  * Converts an existing object to its boolean() equivalent
   2730  *
   2731  * Returns a created or reused object, the old one is freed (or the operation
   2732  *         is done directly on @val)
   2733  */
   2734 static xmlXPathObjectPtr
   2735 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2736     xmlXPathObjectPtr ret;
   2737 
   2738     if (val == NULL)
   2739 	return(xmlXPathCacheNewBoolean(ctxt, 0));
   2740     if (val->type == XPATH_BOOLEAN)
   2741 	return(val);
   2742     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
   2743     xmlXPathReleaseObject(ctxt, val);
   2744     return(ret);
   2745 }
   2746 
   2747 /**
   2748  * xmlXPathCacheConvertNumber:
   2749  * @ctxt: the XPath context
   2750  * @val:  an XPath object
   2751  *
   2752  * This is the cached version of xmlXPathConvertNumber().
   2753  * Converts an existing object to its number() equivalent
   2754  *
   2755  * Returns a created or reused object, the old one is freed (or the operation
   2756  *         is done directly on @val)
   2757  */
   2758 static xmlXPathObjectPtr
   2759 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2760     xmlXPathObjectPtr ret;
   2761 
   2762     if (val == NULL)
   2763 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
   2764     if (val->type == XPATH_NUMBER)
   2765 	return(val);
   2766     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
   2767     xmlXPathReleaseObject(ctxt, val);
   2768     return(ret);
   2769 }
   2770 
   2771 /************************************************************************
   2772  *									*
   2773  *		Parser stacks related functions and macros		*
   2774  *									*
   2775  ************************************************************************/
   2776 
   2777 /**
   2778  * xmlXPathSetFrame:
   2779  * @ctxt: an XPath parser context
   2780  *
   2781  * Set the callee evaluation frame
   2782  *
   2783  * Returns the previous frame value to be restored once done
   2784  */
   2785 static int
   2786 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
   2787     int ret;
   2788 
   2789     if (ctxt == NULL)
   2790         return(0);
   2791     ret = ctxt->valueFrame;
   2792     ctxt->valueFrame = ctxt->valueNr;
   2793     return(ret);
   2794 }
   2795 
   2796 /**
   2797  * xmlXPathPopFrame:
   2798  * @ctxt: an XPath parser context
   2799  * @frame: the previous frame value
   2800  *
   2801  * Remove the callee evaluation frame
   2802  */
   2803 static void
   2804 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
   2805     if (ctxt == NULL)
   2806         return;
   2807     if (ctxt->valueNr < ctxt->valueFrame) {
   2808         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
   2809     }
   2810     ctxt->valueFrame = frame;
   2811 }
   2812 
   2813 /**
   2814  * valuePop:
   2815  * @ctxt: an XPath evaluation context
   2816  *
   2817  * Pops the top XPath object from the value stack
   2818  *
   2819  * Returns the XPath object just removed
   2820  */
   2821 xmlXPathObjectPtr
   2822 valuePop(xmlXPathParserContextPtr ctxt)
   2823 {
   2824     xmlXPathObjectPtr ret;
   2825 
   2826     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
   2827         return (NULL);
   2828 
   2829     if (ctxt->valueNr <= ctxt->valueFrame) {
   2830         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
   2831         return (NULL);
   2832     }
   2833 
   2834     ctxt->valueNr--;
   2835     if (ctxt->valueNr > 0)
   2836         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
   2837     else
   2838         ctxt->value = NULL;
   2839     ret = ctxt->valueTab[ctxt->valueNr];
   2840     ctxt->valueTab[ctxt->valueNr] = NULL;
   2841     return (ret);
   2842 }
   2843 /**
   2844  * valuePush:
   2845  * @ctxt:  an XPath evaluation context
   2846  * @value:  the XPath object
   2847  *
   2848  * Pushes a new XPath object on top of the value stack
   2849  *
   2850  * returns the number of items on the value stack
   2851  */
   2852 int
   2853 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
   2854 {
   2855     if ((ctxt == NULL) || (value == NULL)) return(-1);
   2856     if (ctxt->valueNr >= ctxt->valueMax) {
   2857         xmlXPathObjectPtr *tmp;
   2858 
   2859         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
   2860             xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
   2861             ctxt->error = XPATH_MEMORY_ERROR;
   2862             return (0);
   2863         }
   2864         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
   2865                                              2 * ctxt->valueMax *
   2866                                              sizeof(ctxt->valueTab[0]));
   2867         if (tmp == NULL) {
   2868             xmlXPathErrMemory(NULL, "pushing value\n");
   2869             ctxt->error = XPATH_MEMORY_ERROR;
   2870             return (0);
   2871         }
   2872         ctxt->valueMax *= 2;
   2873 	ctxt->valueTab = tmp;
   2874     }
   2875     ctxt->valueTab[ctxt->valueNr] = value;
   2876     ctxt->value = value;
   2877     return (ctxt->valueNr++);
   2878 }
   2879 
   2880 /**
   2881  * xmlXPathPopBoolean:
   2882  * @ctxt:  an XPath parser context
   2883  *
   2884  * Pops a boolean from the stack, handling conversion if needed.
   2885  * Check error with #xmlXPathCheckError.
   2886  *
   2887  * Returns the boolean
   2888  */
   2889 int
   2890 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
   2891     xmlXPathObjectPtr obj;
   2892     int ret;
   2893 
   2894     obj = valuePop(ctxt);
   2895     if (obj == NULL) {
   2896 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2897 	return(0);
   2898     }
   2899     if (obj->type != XPATH_BOOLEAN)
   2900 	ret = xmlXPathCastToBoolean(obj);
   2901     else
   2902         ret = obj->boolval;
   2903     xmlXPathReleaseObject(ctxt->context, obj);
   2904     return(ret);
   2905 }
   2906 
   2907 /**
   2908  * xmlXPathPopNumber:
   2909  * @ctxt:  an XPath parser context
   2910  *
   2911  * Pops a number from the stack, handling conversion if needed.
   2912  * Check error with #xmlXPathCheckError.
   2913  *
   2914  * Returns the number
   2915  */
   2916 double
   2917 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
   2918     xmlXPathObjectPtr obj;
   2919     double ret;
   2920 
   2921     obj = valuePop(ctxt);
   2922     if (obj == NULL) {
   2923 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2924 	return(0);
   2925     }
   2926     if (obj->type != XPATH_NUMBER)
   2927 	ret = xmlXPathCastToNumber(obj);
   2928     else
   2929         ret = obj->floatval;
   2930     xmlXPathReleaseObject(ctxt->context, obj);
   2931     return(ret);
   2932 }
   2933 
   2934 /**
   2935  * xmlXPathPopString:
   2936  * @ctxt:  an XPath parser context
   2937  *
   2938  * Pops a string from the stack, handling conversion if needed.
   2939  * Check error with #xmlXPathCheckError.
   2940  *
   2941  * Returns the string
   2942  */
   2943 xmlChar *
   2944 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
   2945     xmlXPathObjectPtr obj;
   2946     xmlChar * ret;
   2947 
   2948     obj = valuePop(ctxt);
   2949     if (obj == NULL) {
   2950 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2951 	return(NULL);
   2952     }
   2953     ret = xmlXPathCastToString(obj);	/* this does required strdup */
   2954     /* TODO: needs refactoring somewhere else */
   2955     if (obj->stringval == ret)
   2956 	obj->stringval = NULL;
   2957     xmlXPathReleaseObject(ctxt->context, obj);
   2958     return(ret);
   2959 }
   2960 
   2961 /**
   2962  * xmlXPathPopNodeSet:
   2963  * @ctxt:  an XPath parser context
   2964  *
   2965  * Pops a node-set from the stack, handling conversion if needed.
   2966  * Check error with #xmlXPathCheckError.
   2967  *
   2968  * Returns the node-set
   2969  */
   2970 xmlNodeSetPtr
   2971 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
   2972     xmlXPathObjectPtr obj;
   2973     xmlNodeSetPtr ret;
   2974 
   2975     if (ctxt == NULL) return(NULL);
   2976     if (ctxt->value == NULL) {
   2977 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2978 	return(NULL);
   2979     }
   2980     if (!xmlXPathStackIsNodeSet(ctxt)) {
   2981 	xmlXPathSetTypeError(ctxt);
   2982 	return(NULL);
   2983     }
   2984     obj = valuePop(ctxt);
   2985     ret = obj->nodesetval;
   2986 #if 0
   2987     /* to fix memory leak of not clearing obj->user */
   2988     if (obj->boolval && obj->user != NULL)
   2989         xmlFreeNodeList((xmlNodePtr) obj->user);
   2990 #endif
   2991     obj->nodesetval = NULL;
   2992     xmlXPathReleaseObject(ctxt->context, obj);
   2993     return(ret);
   2994 }
   2995 
   2996 /**
   2997  * xmlXPathPopExternal:
   2998  * @ctxt:  an XPath parser context
   2999  *
   3000  * Pops an external object from the stack, handling conversion if needed.
   3001  * Check error with #xmlXPathCheckError.
   3002  *
   3003  * Returns the object
   3004  */
   3005 void *
   3006 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
   3007     xmlXPathObjectPtr obj;
   3008     void * ret;
   3009 
   3010     if ((ctxt == NULL) || (ctxt->value == NULL)) {
   3011 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   3012 	return(NULL);
   3013     }
   3014     if (ctxt->value->type != XPATH_USERS) {
   3015 	xmlXPathSetTypeError(ctxt);
   3016 	return(NULL);
   3017     }
   3018     obj = valuePop(ctxt);
   3019     ret = obj->user;
   3020     obj->user = NULL;
   3021     xmlXPathReleaseObject(ctxt->context, obj);
   3022     return(ret);
   3023 }
   3024 
   3025 /*
   3026  * Macros for accessing the content. Those should be used only by the parser,
   3027  * and not exported.
   3028  *
   3029  * Dirty macros, i.e. one need to make assumption on the context to use them
   3030  *
   3031  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
   3032  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
   3033  *           in ISO-Latin or UTF-8.
   3034  *           This should be used internally by the parser
   3035  *           only to compare to ASCII values otherwise it would break when
   3036  *           running with UTF-8 encoding.
   3037  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
   3038  *           to compare on ASCII based substring.
   3039  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
   3040  *           strings within the parser.
   3041  *   CURRENT Returns the current char value, with the full decoding of
   3042  *           UTF-8 if we are using this mode. It returns an int.
   3043  *   NEXT    Skip to the next character, this does the proper decoding
   3044  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
   3045  *           It returns the pointer to the current xmlChar.
   3046  */
   3047 
   3048 #define CUR (*ctxt->cur)
   3049 #define SKIP(val) ctxt->cur += (val)
   3050 #define NXT(val) ctxt->cur[(val)]
   3051 #define CUR_PTR ctxt->cur
   3052 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
   3053 
   3054 #define COPY_BUF(l,b,i,v)                                              \
   3055     if (l == 1) b[i++] = (xmlChar) v;                                  \
   3056     else i += xmlCopyChar(l,&b[i],v)
   3057 
   3058 #define NEXTL(l)  ctxt->cur += l
   3059 
   3060 #define SKIP_BLANKS							\
   3061     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
   3062 
   3063 #define CURRENT (*ctxt->cur)
   3064 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
   3065 
   3066 
   3067 #ifndef DBL_DIG
   3068 #define DBL_DIG 16
   3069 #endif
   3070 #ifndef DBL_EPSILON
   3071 #define DBL_EPSILON 1E-9
   3072 #endif
   3073 
   3074 #define UPPER_DOUBLE 1E9
   3075 #define LOWER_DOUBLE 1E-5
   3076 #define	LOWER_DOUBLE_EXP 5
   3077 
   3078 #define INTEGER_DIGITS DBL_DIG
   3079 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
   3080 #define EXPONENT_DIGITS (3 + 2)
   3081 
   3082 /**
   3083  * xmlXPathFormatNumber:
   3084  * @number:     number to format
   3085  * @buffer:     output buffer
   3086  * @buffersize: size of output buffer
   3087  *
   3088  * Convert the number into a string representation.
   3089  */
   3090 static void
   3091 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
   3092 {
   3093     switch (xmlXPathIsInf(number)) {
   3094     case 1:
   3095 	if (buffersize > (int)sizeof("Infinity"))
   3096 	    snprintf(buffer, buffersize, "Infinity");
   3097 	break;
   3098     case -1:
   3099 	if (buffersize > (int)sizeof("-Infinity"))
   3100 	    snprintf(buffer, buffersize, "-Infinity");
   3101 	break;
   3102     default:
   3103 	if (xmlXPathIsNaN(number)) {
   3104 	    if (buffersize > (int)sizeof("NaN"))
   3105 		snprintf(buffer, buffersize, "NaN");
   3106 	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
   3107 	    snprintf(buffer, buffersize, "0");
   3108 	} else if (number == ((int) number)) {
   3109 	    char work[30];
   3110 	    char *ptr, *cur;
   3111 	    int value = (int) number;
   3112 
   3113             ptr = &buffer[0];
   3114 	    if (value == 0) {
   3115 		*ptr++ = '0';
   3116 	    } else {
   3117 		snprintf(work, 29, "%d", value);
   3118 		cur = &work[0];
   3119 		while ((*cur) && (ptr - buffer < buffersize)) {
   3120 		    *ptr++ = *cur++;
   3121 		}
   3122 	    }
   3123 	    if (ptr - buffer < buffersize) {
   3124 		*ptr = 0;
   3125 	    } else if (buffersize > 0) {
   3126 		ptr--;
   3127 		*ptr = 0;
   3128 	    }
   3129 	} else {
   3130 	    /*
   3131 	      For the dimension of work,
   3132 	          DBL_DIG is number of significant digits
   3133 		  EXPONENT is only needed for "scientific notation"
   3134 	          3 is sign, decimal point, and terminating zero
   3135 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
   3136 	      Note that this dimension is slightly (a few characters)
   3137 	      larger than actually necessary.
   3138 	    */
   3139 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
   3140 	    int integer_place, fraction_place;
   3141 	    char *ptr;
   3142 	    char *after_fraction;
   3143 	    double absolute_value;
   3144 	    int size;
   3145 
   3146 	    absolute_value = fabs(number);
   3147 
   3148 	    /*
   3149 	     * First choose format - scientific or regular floating point.
   3150 	     * In either case, result is in work, and after_fraction points
   3151 	     * just past the fractional part.
   3152 	    */
   3153 	    if ( ((absolute_value > UPPER_DOUBLE) ||
   3154 		  (absolute_value < LOWER_DOUBLE)) &&
   3155 		 (absolute_value != 0.0) ) {
   3156 		/* Use scientific notation */
   3157 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
   3158 		fraction_place = DBL_DIG - 1;
   3159 		size = snprintf(work, sizeof(work),"%*.*e",
   3160 			 integer_place, fraction_place, number);
   3161 		while ((size > 0) && (work[size] != 'e')) size--;
   3162 
   3163 	    }
   3164 	    else {
   3165 		/* Use regular notation */
   3166 		if (absolute_value > 0.0) {
   3167 		    integer_place = (int)log10(absolute_value);
   3168 		    if (integer_place > 0)
   3169 		        fraction_place = DBL_DIG - integer_place - 1;
   3170 		    else
   3171 		        fraction_place = DBL_DIG - integer_place;
   3172 		} else {
   3173 		    fraction_place = 1;
   3174 		}
   3175 		size = snprintf(work, sizeof(work), "%0.*f",
   3176 				fraction_place, number);
   3177 	    }
   3178 
   3179 	    /* Remove leading spaces sometimes inserted by snprintf */
   3180 	    while (work[0] == ' ') {
   3181 	        for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
   3182 		size--;
   3183 	    }
   3184 
   3185 	    /* Remove fractional trailing zeroes */
   3186 	    after_fraction = work + size;
   3187 	    ptr = after_fraction;
   3188 	    while (*(--ptr) == '0')
   3189 		;
   3190 	    if (*ptr != '.')
   3191 	        ptr++;
   3192 	    while ((*ptr++ = *after_fraction++) != 0);
   3193 
   3194 	    /* Finally copy result back to caller */
   3195 	    size = strlen(work) + 1;
   3196 	    if (size > buffersize) {
   3197 		work[buffersize - 1] = 0;
   3198 		size = buffersize;
   3199 	    }
   3200 	    memmove(buffer, work, size);
   3201 	}
   3202 	break;
   3203     }
   3204 }
   3205 
   3206 
   3207 /************************************************************************
   3208  *									*
   3209  *			Routines to handle NodeSets			*
   3210  *									*
   3211  ************************************************************************/
   3212 
   3213 /**
   3214  * xmlXPathOrderDocElems:
   3215  * @doc:  an input document
   3216  *
   3217  * Call this routine to speed up XPath computation on static documents.
   3218  * This stamps all the element nodes with the document order
   3219  * Like for line information, the order is kept in the element->content
   3220  * field, the value stored is actually - the node number (starting at -1)
   3221  * to be able to differentiate from line numbers.
   3222  *
   3223  * Returns the number of elements found in the document or -1 in case
   3224  *    of error.
   3225  */
   3226 long
   3227 xmlXPathOrderDocElems(xmlDocPtr doc) {
   3228     long count = 0;
   3229     xmlNodePtr cur;
   3230 
   3231     if (doc == NULL)
   3232 	return(-1);
   3233     cur = doc->children;
   3234     while (cur != NULL) {
   3235 	if (cur->type == XML_ELEMENT_NODE) {
   3236 	    cur->content = (void *) (-(++count));
   3237 	    if (cur->children != NULL) {
   3238 		cur = cur->children;
   3239 		continue;
   3240 	    }
   3241 	}
   3242 	if (cur->next != NULL) {
   3243 	    cur = cur->next;
   3244 	    continue;
   3245 	}
   3246 	do {
   3247 	    cur = cur->parent;
   3248 	    if (cur == NULL)
   3249 		break;
   3250 	    if (cur == (xmlNodePtr) doc) {
   3251 		cur = NULL;
   3252 		break;
   3253 	    }
   3254 	    if (cur->next != NULL) {
   3255 		cur = cur->next;
   3256 		break;
   3257 	    }
   3258 	} while (cur != NULL);
   3259     }
   3260     return(count);
   3261 }
   3262 
   3263 /**
   3264  * xmlXPathCmpNodes:
   3265  * @node1:  the first node
   3266  * @node2:  the second node
   3267  *
   3268  * Compare two nodes w.r.t document order
   3269  *
   3270  * Returns -2 in case of error 1 if first point < second point, 0 if
   3271  *         it's the same node, -1 otherwise
   3272  */
   3273 int
   3274 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
   3275     int depth1, depth2;
   3276     int attr1 = 0, attr2 = 0;
   3277     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
   3278     xmlNodePtr cur, root;
   3279 
   3280     if ((node1 == NULL) || (node2 == NULL))
   3281 	return(-2);
   3282     /*
   3283      * a couple of optimizations which will avoid computations in most cases
   3284      */
   3285     if (node1 == node2)		/* trivial case */
   3286 	return(0);
   3287     if (node1->type == XML_ATTRIBUTE_NODE) {
   3288 	attr1 = 1;
   3289 	attrNode1 = node1;
   3290 	node1 = node1->parent;
   3291     }
   3292     if (node2->type == XML_ATTRIBUTE_NODE) {
   3293 	attr2 = 1;
   3294 	attrNode2 = node2;
   3295 	node2 = node2->parent;
   3296     }
   3297     if (node1 == node2) {
   3298 	if (attr1 == attr2) {
   3299 	    /* not required, but we keep attributes in order */
   3300 	    if (attr1 != 0) {
   3301 	        cur = attrNode2->prev;
   3302 		while (cur != NULL) {
   3303 		    if (cur == attrNode1)
   3304 		        return (1);
   3305 		    cur = cur->prev;
   3306 		}
   3307 		return (-1);
   3308 	    }
   3309 	    return(0);
   3310 	}
   3311 	if (attr2 == 1)
   3312 	    return(1);
   3313 	return(-1);
   3314     }
   3315     if ((node1->type == XML_NAMESPACE_DECL) ||
   3316         (node2->type == XML_NAMESPACE_DECL))
   3317 	return(1);
   3318     if (node1 == node2->prev)
   3319 	return(1);
   3320     if (node1 == node2->next)
   3321 	return(-1);
   3322 
   3323     /*
   3324      * Speedup using document order if availble.
   3325      */
   3326     if ((node1->type == XML_ELEMENT_NODE) &&
   3327 	(node2->type == XML_ELEMENT_NODE) &&
   3328 	(0 > (long) node1->content) &&
   3329 	(0 > (long) node2->content) &&
   3330 	(node1->doc == node2->doc)) {
   3331 	long l1, l2;
   3332 
   3333 	l1 = -((long) node1->content);
   3334 	l2 = -((long) node2->content);
   3335 	if (l1 < l2)
   3336 	    return(1);
   3337 	if (l1 > l2)
   3338 	    return(-1);
   3339     }
   3340 
   3341     /*
   3342      * compute depth to root
   3343      */
   3344     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
   3345 	if (cur == node1)
   3346 	    return(1);
   3347 	depth2++;
   3348     }
   3349     root = cur;
   3350     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
   3351 	if (cur == node2)
   3352 	    return(-1);
   3353 	depth1++;
   3354     }
   3355     /*
   3356      * Distinct document (or distinct entities :-( ) case.
   3357      */
   3358     if (root != cur) {
   3359 	return(-2);
   3360     }
   3361     /*
   3362      * get the nearest common ancestor.
   3363      */
   3364     while (depth1 > depth2) {
   3365 	depth1--;
   3366 	node1 = node1->parent;
   3367     }
   3368     while (depth2 > depth1) {
   3369 	depth2--;
   3370 	node2 = node2->parent;
   3371     }
   3372     while (node1->parent != node2->parent) {
   3373 	node1 = node1->parent;
   3374 	node2 = node2->parent;
   3375 	/* should not happen but just in case ... */
   3376 	if ((node1 == NULL) || (node2 == NULL))
   3377 	    return(-2);
   3378     }
   3379     /*
   3380      * Find who's first.
   3381      */
   3382     if (node1 == node2->prev)
   3383 	return(1);
   3384     if (node1 == node2->next)
   3385 	return(-1);
   3386     /*
   3387      * Speedup using document order if availble.
   3388      */
   3389     if ((node1->type == XML_ELEMENT_NODE) &&
   3390 	(node2->type == XML_ELEMENT_NODE) &&
   3391 	(0 > (long) node1->content) &&
   3392 	(0 > (long) node2->content) &&
   3393 	(node1->doc == node2->doc)) {
   3394 	long l1, l2;
   3395 
   3396 	l1 = -((long) node1->content);
   3397 	l2 = -((long) node2->content);
   3398 	if (l1 < l2)
   3399 	    return(1);
   3400 	if (l1 > l2)
   3401 	    return(-1);
   3402     }
   3403 
   3404     for (cur = node1->next;cur != NULL;cur = cur->next)
   3405 	if (cur == node2)
   3406 	    return(1);
   3407     return(-1); /* assume there is no sibling list corruption */
   3408 }
   3409 
   3410 /**
   3411  * xmlXPathNodeSetSort:
   3412  * @set:  the node set
   3413  *
   3414  * Sort the node set in document order
   3415  */
   3416 void
   3417 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
   3418 #ifndef WITH_TIM_SORT
   3419     int i, j, incr, len;
   3420     xmlNodePtr tmp;
   3421 #endif
   3422 
   3423     if (set == NULL)
   3424 	return;
   3425 
   3426 #ifndef WITH_TIM_SORT
   3427     /*
   3428      * Use the old Shell's sort implementation to sort the node-set
   3429      * Timsort ought to be quite faster
   3430      */
   3431     len = set->nodeNr;
   3432     for (incr = len / 2; incr > 0; incr /= 2) {
   3433 	for (i = incr; i < len; i++) {
   3434 	    j = i - incr;
   3435 	    while (j >= 0) {
   3436 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   3437 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
   3438 			set->nodeTab[j + incr]) == -1)
   3439 #else
   3440 		if (xmlXPathCmpNodes(set->nodeTab[j],
   3441 			set->nodeTab[j + incr]) == -1)
   3442 #endif
   3443 		{
   3444 		    tmp = set->nodeTab[j];
   3445 		    set->nodeTab[j] = set->nodeTab[j + incr];
   3446 		    set->nodeTab[j + incr] = tmp;
   3447 		    j -= incr;
   3448 		} else
   3449 		    break;
   3450 	    }
   3451 	}
   3452     }
   3453 #else /* WITH_TIM_SORT */
   3454     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
   3455 #endif /* WITH_TIM_SORT */
   3456 }
   3457 
   3458 #define XML_NODESET_DEFAULT	10
   3459 /**
   3460  * xmlXPathNodeSetDupNs:
   3461  * @node:  the parent node of the namespace XPath node
   3462  * @ns:  the libxml namespace declaration node.
   3463  *
   3464  * Namespace node in libxml don't match the XPath semantic. In a node set
   3465  * the namespace nodes are duplicated and the next pointer is set to the
   3466  * parent node in the XPath semantic.
   3467  *
   3468  * Returns the newly created object.
   3469  */
   3470 static xmlNodePtr
   3471 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
   3472     xmlNsPtr cur;
   3473 
   3474     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
   3475 	return(NULL);
   3476     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
   3477 	return((xmlNodePtr) ns);
   3478 
   3479     /*
   3480      * Allocate a new Namespace and fill the fields.
   3481      */
   3482     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
   3483     if (cur == NULL) {
   3484         xmlXPathErrMemory(NULL, "duplicating namespace\n");
   3485 	return(NULL);
   3486     }
   3487     memset(cur, 0, sizeof(xmlNs));
   3488     cur->type = XML_NAMESPACE_DECL;
   3489     if (ns->href != NULL)
   3490 	cur->href = xmlStrdup(ns->href);
   3491     if (ns->prefix != NULL)
   3492 	cur->prefix = xmlStrdup(ns->prefix);
   3493     cur->next = (xmlNsPtr) node;
   3494     return((xmlNodePtr) cur);
   3495 }
   3496 
   3497 /**
   3498  * xmlXPathNodeSetFreeNs:
   3499  * @ns:  the XPath namespace node found in a nodeset.
   3500  *
   3501  * Namespace nodes in libxml don't match the XPath semantic. In a node set
   3502  * the namespace nodes are duplicated and the next pointer is set to the
   3503  * parent node in the XPath semantic. Check if such a node needs to be freed
   3504  */
   3505 void
   3506 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
   3507     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
   3508 	return;
   3509 
   3510     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
   3511 	if (ns->href != NULL)
   3512 	    xmlFree((xmlChar *)ns->href);
   3513 	if (ns->prefix != NULL)
   3514 	    xmlFree((xmlChar *)ns->prefix);
   3515 	xmlFree(ns);
   3516     }
   3517 }
   3518 
   3519 /**
   3520  * xmlXPathNodeSetCreate:
   3521  * @val:  an initial xmlNodePtr, or NULL
   3522  *
   3523  * Create a new xmlNodeSetPtr of type double and of value @val
   3524  *
   3525  * Returns the newly created object.
   3526  */
   3527 xmlNodeSetPtr
   3528 xmlXPathNodeSetCreate(xmlNodePtr val) {
   3529     xmlNodeSetPtr ret;
   3530 
   3531     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
   3532     if (ret == NULL) {
   3533         xmlXPathErrMemory(NULL, "creating nodeset\n");
   3534 	return(NULL);
   3535     }
   3536     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
   3537     if (val != NULL) {
   3538         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3539 					     sizeof(xmlNodePtr));
   3540 	if (ret->nodeTab == NULL) {
   3541 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
   3542 	    xmlFree(ret);
   3543 	    return(NULL);
   3544 	}
   3545 	memset(ret->nodeTab, 0 ,
   3546 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3547         ret->nodeMax = XML_NODESET_DEFAULT;
   3548 	if (val->type == XML_NAMESPACE_DECL) {
   3549 	    xmlNsPtr ns = (xmlNsPtr) val;
   3550 
   3551 	    ret->nodeTab[ret->nodeNr++] =
   3552 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3553 	} else
   3554 	    ret->nodeTab[ret->nodeNr++] = val;
   3555     }
   3556     return(ret);
   3557 }
   3558 
   3559 /**
   3560  * xmlXPathNodeSetCreateSize:
   3561  * @size:  the initial size of the set
   3562  *
   3563  * Create a new xmlNodeSetPtr of type double and of value @val
   3564  *
   3565  * Returns the newly created object.
   3566  */
   3567 static xmlNodeSetPtr
   3568 xmlXPathNodeSetCreateSize(int size) {
   3569     xmlNodeSetPtr ret;
   3570 
   3571     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
   3572     if (ret == NULL) {
   3573         xmlXPathErrMemory(NULL, "creating nodeset\n");
   3574 	return(NULL);
   3575     }
   3576     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
   3577     if (size < XML_NODESET_DEFAULT)
   3578 	size = XML_NODESET_DEFAULT;
   3579     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
   3580     if (ret->nodeTab == NULL) {
   3581 	xmlXPathErrMemory(NULL, "creating nodeset\n");
   3582 	xmlFree(ret);
   3583 	return(NULL);
   3584     }
   3585     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
   3586     ret->nodeMax = size;
   3587     return(ret);
   3588 }
   3589 
   3590 /**
   3591  * xmlXPathNodeSetContains:
   3592  * @cur:  the node-set
   3593  * @val:  the node
   3594  *
   3595  * checks whether @cur contains @val
   3596  *
   3597  * Returns true (1) if @cur contains @val, false (0) otherwise
   3598  */
   3599 int
   3600 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
   3601     int i;
   3602 
   3603     if ((cur == NULL) || (val == NULL)) return(0);
   3604     if (val->type == XML_NAMESPACE_DECL) {
   3605 	for (i = 0; i < cur->nodeNr; i++) {
   3606 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
   3607 		xmlNsPtr ns1, ns2;
   3608 
   3609 		ns1 = (xmlNsPtr) val;
   3610 		ns2 = (xmlNsPtr) cur->nodeTab[i];
   3611 		if (ns1 == ns2)
   3612 		    return(1);
   3613 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
   3614 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
   3615 		    return(1);
   3616 	    }
   3617 	}
   3618     } else {
   3619 	for (i = 0; i < cur->nodeNr; i++) {
   3620 	    if (cur->nodeTab[i] == val)
   3621 		return(1);
   3622 	}
   3623     }
   3624     return(0);
   3625 }
   3626 
   3627 /**
   3628  * xmlXPathNodeSetAddNs:
   3629  * @cur:  the initial node set
   3630  * @node:  the hosting node
   3631  * @ns:  a the namespace node
   3632  *
   3633  * add a new namespace node to an existing NodeSet
   3634  *
   3635  * Returns 0 in case of success and -1 in case of error
   3636  */
   3637 int
   3638 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
   3639     int i;
   3640 
   3641 
   3642     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
   3643         (ns->type != XML_NAMESPACE_DECL) ||
   3644 	(node->type != XML_ELEMENT_NODE))
   3645 	return(-1);
   3646 
   3647     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3648     /*
   3649      * prevent duplicates
   3650      */
   3651     for (i = 0;i < cur->nodeNr;i++) {
   3652         if ((cur->nodeTab[i] != NULL) &&
   3653 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
   3654 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
   3655 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
   3656 	    return(0);
   3657     }
   3658 
   3659     /*
   3660      * grow the nodeTab if needed
   3661      */
   3662     if (cur->nodeMax == 0) {
   3663         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3664 					     sizeof(xmlNodePtr));
   3665 	if (cur->nodeTab == NULL) {
   3666 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3667 	    return(-1);
   3668 	}
   3669 	memset(cur->nodeTab, 0 ,
   3670 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3671         cur->nodeMax = XML_NODESET_DEFAULT;
   3672     } else if (cur->nodeNr == cur->nodeMax) {
   3673         xmlNodePtr *temp;
   3674 
   3675         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   3676             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
   3677             return(-1);
   3678         }
   3679 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
   3680 				      sizeof(xmlNodePtr));
   3681 	if (temp == NULL) {
   3682 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3683 	    return(-1);
   3684 	}
   3685         cur->nodeMax *= 2;
   3686 	cur->nodeTab = temp;
   3687     }
   3688     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
   3689     return(0);
   3690 }
   3691 
   3692 /**
   3693  * xmlXPathNodeSetAdd:
   3694  * @cur:  the initial node set
   3695  * @val:  a new xmlNodePtr
   3696  *
   3697  * add a new xmlNodePtr to an existing NodeSet
   3698  *
   3699  * Returns 0 in case of success, and -1 in case of error
   3700  */
   3701 int
   3702 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
   3703     int i;
   3704 
   3705     if ((cur == NULL) || (val == NULL)) return(-1);
   3706 
   3707     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3708     /*
   3709      * prevent duplicates
   3710      */
   3711     for (i = 0;i < cur->nodeNr;i++)
   3712         if (cur->nodeTab[i] == val) return(0);
   3713 
   3714     /*
   3715      * grow the nodeTab if needed
   3716      */
   3717     if (cur->nodeMax == 0) {
   3718         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3719 					     sizeof(xmlNodePtr));
   3720 	if (cur->nodeTab == NULL) {
   3721 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3722 	    return(-1);
   3723 	}
   3724 	memset(cur->nodeTab, 0 ,
   3725 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3726         cur->nodeMax = XML_NODESET_DEFAULT;
   3727     } else if (cur->nodeNr == cur->nodeMax) {
   3728         xmlNodePtr *temp;
   3729 
   3730         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   3731             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
   3732             return(-1);
   3733         }
   3734 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
   3735 				      sizeof(xmlNodePtr));
   3736 	if (temp == NULL) {
   3737 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3738 	    return(-1);
   3739 	}
   3740         cur->nodeMax *= 2;
   3741 	cur->nodeTab = temp;
   3742     }
   3743     if (val->type == XML_NAMESPACE_DECL) {
   3744 	xmlNsPtr ns = (xmlNsPtr) val;
   3745 
   3746 	cur->nodeTab[cur->nodeNr++] =
   3747 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3748     } else
   3749 	cur->nodeTab[cur->nodeNr++] = val;
   3750     return(0);
   3751 }
   3752 
   3753 /**
   3754  * xmlXPathNodeSetAddUnique:
   3755  * @cur:  the initial node set
   3756  * @val:  a new xmlNodePtr
   3757  *
   3758  * add a new xmlNodePtr to an existing NodeSet, optimized version
   3759  * when we are sure the node is not already in the set.
   3760  *
   3761  * Returns 0 in case of success and -1 in case of failure
   3762  */
   3763 int
   3764 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
   3765     if ((cur == NULL) || (val == NULL)) return(-1);
   3766 
   3767     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3768     /*
   3769      * grow the nodeTab if needed
   3770      */
   3771     if (cur->nodeMax == 0) {
   3772         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3773 					     sizeof(xmlNodePtr));
   3774 	if (cur->nodeTab == NULL) {
   3775 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3776 	    return(-1);
   3777 	}
   3778 	memset(cur->nodeTab, 0 ,
   3779 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3780         cur->nodeMax = XML_NODESET_DEFAULT;
   3781     } else if (cur->nodeNr == cur->nodeMax) {
   3782         xmlNodePtr *temp;
   3783 
   3784         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   3785             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
   3786             return(-1);
   3787         }
   3788 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
   3789 				      sizeof(xmlNodePtr));
   3790 	if (temp == NULL) {
   3791 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3792 	    return(-1);
   3793 	}
   3794 	cur->nodeTab = temp;
   3795         cur->nodeMax *= 2;
   3796     }
   3797     if (val->type == XML_NAMESPACE_DECL) {
   3798 	xmlNsPtr ns = (xmlNsPtr) val;
   3799 
   3800 	cur->nodeTab[cur->nodeNr++] =
   3801 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3802     } else
   3803 	cur->nodeTab[cur->nodeNr++] = val;
   3804     return(0);
   3805 }
   3806 
   3807 /**
   3808  * xmlXPathNodeSetMerge:
   3809  * @val1:  the first NodeSet or NULL
   3810  * @val2:  the second NodeSet
   3811  *
   3812  * Merges two nodesets, all nodes from @val2 are added to @val1
   3813  * if @val1 is NULL, a new set is created and copied from @val2
   3814  *
   3815  * Returns @val1 once extended or NULL in case of error.
   3816  */
   3817 xmlNodeSetPtr
   3818 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
   3819     int i, j, initNr, skip;
   3820     xmlNodePtr n1, n2;
   3821 
   3822     if (val2 == NULL) return(val1);
   3823     if (val1 == NULL) {
   3824 	val1 = xmlXPathNodeSetCreate(NULL);
   3825     if (val1 == NULL)
   3826         return (NULL);
   3827 #if 0
   3828 	/*
   3829 	* TODO: The optimization won't work in every case, since
   3830 	*  those nasty namespace nodes need to be added with
   3831 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
   3832 	*  memcpy is not possible.
   3833 	*  If there was a flag on the nodesetval, indicating that
   3834 	*  some temporary nodes are in, that would be helpfull.
   3835 	*/
   3836 	/*
   3837 	* Optimization: Create an equally sized node-set
   3838 	* and memcpy the content.
   3839 	*/
   3840 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
   3841 	if (val1 == NULL)
   3842 	    return(NULL);
   3843 	if (val2->nodeNr != 0) {
   3844 	    if (val2->nodeNr == 1)
   3845 		*(val1->nodeTab) = *(val2->nodeTab);
   3846 	    else {
   3847 		memcpy(val1->nodeTab, val2->nodeTab,
   3848 		    val2->nodeNr * sizeof(xmlNodePtr));
   3849 	    }
   3850 	    val1->nodeNr = val2->nodeNr;
   3851 	}
   3852 	return(val1);
   3853 #endif
   3854     }
   3855 
   3856     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3857     initNr = val1->nodeNr;
   3858 
   3859     for (i = 0;i < val2->nodeNr;i++) {
   3860 	n2 = val2->nodeTab[i];
   3861 	/*
   3862 	 * check against duplicates
   3863 	 */
   3864 	skip = 0;
   3865 	for (j = 0; j < initNr; j++) {
   3866 	    n1 = val1->nodeTab[j];
   3867 	    if (n1 == n2) {
   3868 		skip = 1;
   3869 		break;
   3870 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
   3871 		       (n2->type == XML_NAMESPACE_DECL)) {
   3872 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
   3873 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
   3874 			((xmlNsPtr) n2)->prefix)))
   3875 		{
   3876 		    skip = 1;
   3877 		    break;
   3878 		}
   3879 	    }
   3880 	}
   3881 	if (skip)
   3882 	    continue;
   3883 
   3884 	/*
   3885 	 * grow the nodeTab if needed
   3886 	 */
   3887 	if (val1->nodeMax == 0) {
   3888 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3889 						    sizeof(xmlNodePtr));
   3890 	    if (val1->nodeTab == NULL) {
   3891 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3892 		return(NULL);
   3893 	    }
   3894 	    memset(val1->nodeTab, 0 ,
   3895 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3896 	    val1->nodeMax = XML_NODESET_DEFAULT;
   3897 	} else if (val1->nodeNr == val1->nodeMax) {
   3898 	    xmlNodePtr *temp;
   3899 
   3900             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   3901                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
   3902                 return(NULL);
   3903             }
   3904 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
   3905 					     sizeof(xmlNodePtr));
   3906 	    if (temp == NULL) {
   3907 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3908 		return(NULL);
   3909 	    }
   3910 	    val1->nodeTab = temp;
   3911 	    val1->nodeMax *= 2;
   3912 	}
   3913 	if (n2->type == XML_NAMESPACE_DECL) {
   3914 	    xmlNsPtr ns = (xmlNsPtr) n2;
   3915 
   3916 	    val1->nodeTab[val1->nodeNr++] =
   3917 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3918 	} else
   3919 	    val1->nodeTab[val1->nodeNr++] = n2;
   3920     }
   3921 
   3922     return(val1);
   3923 }
   3924 
   3925 
   3926 /**
   3927  * xmlXPathNodeSetMergeAndClear:
   3928  * @set1:  the first NodeSet or NULL
   3929  * @set2:  the second NodeSet
   3930  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
   3931  *
   3932  * Merges two nodesets, all nodes from @set2 are added to @set1
   3933  * if @set1 is NULL, a new set is created and copied from @set2.
   3934  * Checks for duplicate nodes. Clears set2.
   3935  *
   3936  * Returns @set1 once extended or NULL in case of error.
   3937  */
   3938 static xmlNodeSetPtr
   3939 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
   3940 			     int hasNullEntries)
   3941 {
   3942     if ((set1 == NULL) && (hasNullEntries == 0)) {
   3943 	/*
   3944 	* Note that doing a memcpy of the list, namespace nodes are
   3945 	* just assigned to set1, since set2 is cleared anyway.
   3946 	*/
   3947 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
   3948 	if (set1 == NULL)
   3949 	    return(NULL);
   3950 	if (set2->nodeNr != 0) {
   3951 	    memcpy(set1->nodeTab, set2->nodeTab,
   3952 		set2->nodeNr * sizeof(xmlNodePtr));
   3953 	    set1->nodeNr = set2->nodeNr;
   3954 	}
   3955     } else {
   3956 	int i, j, initNbSet1;
   3957 	xmlNodePtr n1, n2;
   3958 
   3959 	if (set1 == NULL)
   3960             set1 = xmlXPathNodeSetCreate(NULL);
   3961         if (set1 == NULL)
   3962             return (NULL);
   3963 
   3964 	initNbSet1 = set1->nodeNr;
   3965 	for (i = 0;i < set2->nodeNr;i++) {
   3966 	    n2 = set2->nodeTab[i];
   3967 	    /*
   3968 	    * Skip NULLed entries.
   3969 	    */
   3970 	    if (n2 == NULL)
   3971 		continue;
   3972 	    /*
   3973 	    * Skip duplicates.
   3974 	    */
   3975 	    for (j = 0; j < initNbSet1; j++) {
   3976 		n1 = set1->nodeTab[j];
   3977 		if (n1 == n2) {
   3978 		    goto skip_node;
   3979 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
   3980 		    (n2->type == XML_NAMESPACE_DECL))
   3981 		{
   3982 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
   3983 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
   3984 			((xmlNsPtr) n2)->prefix)))
   3985 		    {
   3986 			/*
   3987 			* Free the namespace node.
   3988 			*/
   3989 			set2->nodeTab[i] = NULL;
   3990 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
   3991 			goto skip_node;
   3992 		    }
   3993 		}
   3994 	    }
   3995 	    /*
   3996 	    * grow the nodeTab if needed
   3997 	    */
   3998 	    if (set1->nodeMax == 0) {
   3999 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
   4000 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
   4001 		if (set1->nodeTab == NULL) {
   4002 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   4003 		    return(NULL);
   4004 		}
   4005 		memset(set1->nodeTab, 0,
   4006 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   4007 		set1->nodeMax = XML_NODESET_DEFAULT;
   4008 	    } else if (set1->nodeNr >= set1->nodeMax) {
   4009 		xmlNodePtr *temp;
   4010 
   4011                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   4012                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
   4013                     return(NULL);
   4014                 }
   4015 		temp = (xmlNodePtr *) xmlRealloc(
   4016 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
   4017 		if (temp == NULL) {
   4018 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   4019 		    return(NULL);
   4020 		}
   4021 		set1->nodeTab = temp;
   4022 		set1->nodeMax *= 2;
   4023 	    }
   4024 	    if (n2->type == XML_NAMESPACE_DECL) {
   4025 		xmlNsPtr ns = (xmlNsPtr) n2;
   4026 
   4027 		set1->nodeTab[set1->nodeNr++] =
   4028 		    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   4029 	    } else
   4030 		set1->nodeTab[set1->nodeNr++] = n2;
   4031 skip_node:
   4032 	    {}
   4033 	}
   4034     }
   4035     set2->nodeNr = 0;
   4036     return(set1);
   4037 }
   4038 
   4039 /**
   4040  * xmlXPathNodeSetMergeAndClearNoDupls:
   4041  * @set1:  the first NodeSet or NULL
   4042  * @set2:  the second NodeSet
   4043  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
   4044  *
   4045  * Merges two nodesets, all nodes from @set2 are added to @set1
   4046  * if @set1 is NULL, a new set is created and copied from @set2.
   4047  * Doesn't chack for duplicate nodes. Clears set2.
   4048  *
   4049  * Returns @set1 once extended or NULL in case of error.
   4050  */
   4051 static xmlNodeSetPtr
   4052 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
   4053 				    int hasNullEntries)
   4054 {
   4055     if (set2 == NULL)
   4056 	return(set1);
   4057     if ((set1 == NULL) && (hasNullEntries == 0)) {
   4058 	/*
   4059 	* Note that doing a memcpy of the list, namespace nodes are
   4060 	* just assigned to set1, since set2 is cleared anyway.
   4061 	*/
   4062 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
   4063 	if (set1 == NULL)
   4064 	    return(NULL);
   4065 	if (set2->nodeNr != 0) {
   4066 	    memcpy(set1->nodeTab, set2->nodeTab,
   4067 		set2->nodeNr * sizeof(xmlNodePtr));
   4068 	    set1->nodeNr = set2->nodeNr;
   4069 	}
   4070     } else {
   4071 	int i;
   4072 	xmlNodePtr n2;
   4073 
   4074 	if (set1 == NULL)
   4075 	    set1 = xmlXPathNodeSetCreate(NULL);
   4076         if (set1 == NULL)
   4077             return (NULL);
   4078 
   4079 	for (i = 0;i < set2->nodeNr;i++) {
   4080 	    n2 = set2->nodeTab[i];
   4081 	    /*
   4082 	    * Skip NULLed entries.
   4083 	    */
   4084 	    if (n2 == NULL)
   4085 		continue;
   4086 	    if (set1->nodeMax == 0) {
   4087 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
   4088 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
   4089 		if (set1->nodeTab == NULL) {
   4090 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   4091 		    return(NULL);
   4092 		}
   4093 		memset(set1->nodeTab, 0,
   4094 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   4095 		set1->nodeMax = XML_NODESET_DEFAULT;
   4096 	    } else if (set1->nodeNr >= set1->nodeMax) {
   4097 		xmlNodePtr *temp;
   4098 
   4099                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   4100                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
   4101                     return(NULL);
   4102                 }
   4103 		temp = (xmlNodePtr *) xmlRealloc(
   4104 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
   4105 		if (temp == NULL) {
   4106 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   4107 		    return(NULL);
   4108 		}
   4109 		set1->nodeTab = temp;
   4110 		set1->nodeMax *= 2;
   4111 	    }
   4112 	    set1->nodeTab[set1->nodeNr++] = n2;
   4113 	}
   4114     }
   4115     set2->nodeNr = 0;
   4116     return(set1);
   4117 }
   4118 
   4119 /**
   4120  * xmlXPathNodeSetDel:
   4121  * @cur:  the initial node set
   4122  * @val:  an xmlNodePtr
   4123  *
   4124  * Removes an xmlNodePtr from an existing NodeSet
   4125  */
   4126 void
   4127 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
   4128     int i;
   4129 
   4130     if (cur == NULL) return;
   4131     if (val == NULL) return;
   4132 
   4133     /*
   4134      * find node in nodeTab
   4135      */
   4136     for (i = 0;i < cur->nodeNr;i++)
   4137         if (cur->nodeTab[i] == val) break;
   4138 
   4139     if (i >= cur->nodeNr) {	/* not found */
   4140 #ifdef DEBUG
   4141         xmlGenericError(xmlGenericErrorContext,
   4142 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
   4143 		val->name);
   4144 #endif
   4145         return;
   4146     }
   4147     if ((cur->nodeTab[i] != NULL) &&
   4148 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
   4149 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
   4150     cur->nodeNr--;
   4151     for (;i < cur->nodeNr;i++)
   4152         cur->nodeTab[i] = cur->nodeTab[i + 1];
   4153     cur->nodeTab[cur->nodeNr] = NULL;
   4154 }
   4155 
   4156 /**
   4157  * xmlXPathNodeSetRemove:
   4158  * @cur:  the initial node set
   4159  * @val:  the index to remove
   4160  *
   4161  * Removes an entry from an existing NodeSet list.
   4162  */
   4163 void
   4164 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
   4165     if (cur == NULL) return;
   4166     if (val >= cur->nodeNr) return;
   4167     if ((cur->nodeTab[val] != NULL) &&
   4168 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
   4169 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
   4170     cur->nodeNr--;
   4171     for (;val < cur->nodeNr;val++)
   4172         cur->nodeTab[val] = cur->nodeTab[val + 1];
   4173     cur->nodeTab[cur->nodeNr] = NULL;
   4174 }
   4175 
   4176 /**
   4177  * xmlXPathFreeNodeSet:
   4178  * @obj:  the xmlNodeSetPtr to free
   4179  *
   4180  * Free the NodeSet compound (not the actual nodes !).
   4181  */
   4182 void
   4183 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
   4184     if (obj == NULL) return;
   4185     if (obj->nodeTab != NULL) {
   4186 	int i;
   4187 
   4188 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
   4189 	for (i = 0;i < obj->nodeNr;i++)
   4190 	    if ((obj->nodeTab[i] != NULL) &&
   4191 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
   4192 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
   4193 	xmlFree(obj->nodeTab);
   4194     }
   4195     xmlFree(obj);
   4196 }
   4197 
   4198 /**
   4199  * xmlXPathNodeSetClear:
   4200  * @set:  the node set to clear
   4201  *
   4202  * Clears the list from all temporary XPath objects (e.g. namespace nodes
   4203  * are feed), but does *not* free the list itself. Sets the length of the
   4204  * list to 0.
   4205  */
   4206 static void
   4207 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
   4208 {
   4209     if ((set == NULL) || (set->nodeNr <= 0))
   4210 	return;
   4211     else if (hasNsNodes) {
   4212 	int i;
   4213 	xmlNodePtr node;
   4214 
   4215 	for (i = 0; i < set->nodeNr; i++) {
   4216 	    node = set->nodeTab[i];
   4217 	    if ((node != NULL) &&
   4218 		(node->type == XML_NAMESPACE_DECL))
   4219 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   4220 	}
   4221     }
   4222     set->nodeNr = 0;
   4223 }
   4224 
   4225 /**
   4226  * xmlXPathNodeSetClearFromPos:
   4227  * @set: the node set to be cleared
   4228  * @pos: the start position to clear from
   4229  *
   4230  * Clears the list from temporary XPath objects (e.g. namespace nodes
   4231  * are feed) starting with the entry at @pos, but does *not* free the list
   4232  * itself. Sets the length of the list to @pos.
   4233  */
   4234 static void
   4235 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
   4236 {
   4237     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
   4238 	return;
   4239     else if ((hasNsNodes)) {
   4240 	int i;
   4241 	xmlNodePtr node;
   4242 
   4243 	for (i = pos; i < set->nodeNr; i++) {
   4244 	    node = set->nodeTab[i];
   4245 	    if ((node != NULL) &&
   4246 		(node->type == XML_NAMESPACE_DECL))
   4247 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   4248 	}
   4249     }
   4250     set->nodeNr = pos;
   4251 }
   4252 
   4253 /**
   4254  * xmlXPathFreeValueTree:
   4255  * @obj:  the xmlNodeSetPtr to free
   4256  *
   4257  * Free the NodeSet compound and the actual tree, this is different
   4258  * from xmlXPathFreeNodeSet()
   4259  */
   4260 static void
   4261 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
   4262     int i;
   4263 
   4264     if (obj == NULL) return;
   4265 
   4266     if (obj->nodeTab != NULL) {
   4267 	for (i = 0;i < obj->nodeNr;i++) {
   4268 	    if (obj->nodeTab[i] != NULL) {
   4269 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
   4270 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
   4271 		} else {
   4272 		    xmlFreeNodeList(obj->nodeTab[i]);
   4273 		}
   4274 	    }
   4275 	}
   4276 	xmlFree(obj->nodeTab);
   4277     }
   4278     xmlFree(obj);
   4279 }
   4280 
   4281 #if defined(DEBUG) || defined(DEBUG_STEP)
   4282 /**
   4283  * xmlGenericErrorContextNodeSet:
   4284  * @output:  a FILE * for the output
   4285  * @obj:  the xmlNodeSetPtr to display
   4286  *
   4287  * Quick display of a NodeSet
   4288  */
   4289 void
   4290 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
   4291     int i;
   4292 
   4293     if (output == NULL) output = xmlGenericErrorContext;
   4294     if (obj == NULL)  {
   4295         fprintf(output, "NodeSet == NULL !\n");
   4296 	return;
   4297     }
   4298     if (obj->nodeNr == 0) {
   4299         fprintf(output, "NodeSet is empty\n");
   4300 	return;
   4301     }
   4302     if (obj->nodeTab == NULL) {
   4303 	fprintf(output, " nodeTab == NULL !\n");
   4304 	return;
   4305     }
   4306     for (i = 0; i < obj->nodeNr; i++) {
   4307         if (obj->nodeTab[i] == NULL) {
   4308 	    fprintf(output, " NULL !\n");
   4309 	    return;
   4310         }
   4311 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
   4312 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
   4313 	    fprintf(output, " /");
   4314 	else if (obj->nodeTab[i]->name == NULL)
   4315 	    fprintf(output, " noname!");
   4316 	else fprintf(output, " %s", obj->nodeTab[i]->name);
   4317     }
   4318     fprintf(output, "\n");
   4319 }
   4320 #endif
   4321 
   4322 /**
   4323  * xmlXPathNewNodeSet:
   4324  * @val:  the NodePtr value
   4325  *
   4326  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
   4327  * it with the single Node @val
   4328  *
   4329  * Returns the newly created object.
   4330  */
   4331 xmlXPathObjectPtr
   4332 xmlXPathNewNodeSet(xmlNodePtr val) {
   4333     xmlXPathObjectPtr ret;
   4334 
   4335     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4336     if (ret == NULL) {
   4337         xmlXPathErrMemory(NULL, "creating nodeset\n");
   4338 	return(NULL);
   4339     }
   4340     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4341     ret->type = XPATH_NODESET;
   4342     ret->boolval = 0;
   4343     ret->nodesetval = xmlXPathNodeSetCreate(val);
   4344     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   4345 #ifdef XP_DEBUG_OBJ_USAGE
   4346     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
   4347 #endif
   4348     return(ret);
   4349 }
   4350 
   4351 /**
   4352  * xmlXPathNewValueTree:
   4353  * @val:  the NodePtr value
   4354  *
   4355  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
   4356  * it with the tree root @val
   4357  *
   4358  * Returns the newly created object.
   4359  */
   4360 xmlXPathObjectPtr
   4361 xmlXPathNewValueTree(xmlNodePtr val) {
   4362     xmlXPathObjectPtr ret;
   4363 
   4364     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4365     if (ret == NULL) {
   4366         xmlXPathErrMemory(NULL, "creating result value tree\n");
   4367 	return(NULL);
   4368     }
   4369     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4370     ret->type = XPATH_XSLT_TREE;
   4371     ret->boolval = 0;
   4372     ret->user = (void *) val;
   4373     ret->nodesetval = xmlXPathNodeSetCreate(val);
   4374 #ifdef XP_DEBUG_OBJ_USAGE
   4375     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
   4376 #endif
   4377     return(ret);
   4378 }
   4379 
   4380 /**
   4381  * xmlXPathNewNodeSetList:
   4382  * @val:  an existing NodeSet
   4383  *
   4384  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
   4385  * it with the Nodeset @val
   4386  *
   4387  * Returns the newly created object.
   4388  */
   4389 xmlXPathObjectPtr
   4390 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
   4391 {
   4392     xmlXPathObjectPtr ret;
   4393     int i;
   4394 
   4395     if (val == NULL)
   4396         ret = NULL;
   4397     else if (val->nodeTab == NULL)
   4398         ret = xmlXPathNewNodeSet(NULL);
   4399     else {
   4400         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
   4401         if (ret) {
   4402             for (i = 1; i < val->nodeNr; ++i) {
   4403                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
   4404 		    < 0) break;
   4405 	    }
   4406 	}
   4407     }
   4408 
   4409     return (ret);
   4410 }
   4411 
   4412 /**
   4413  * xmlXPathWrapNodeSet:
   4414  * @val:  the NodePtr value
   4415  *
   4416  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
   4417  *
   4418  * Returns the newly created object.
   4419  */
   4420 xmlXPathObjectPtr
   4421 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
   4422     xmlXPathObjectPtr ret;
   4423 
   4424     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4425     if (ret == NULL) {
   4426         xmlXPathErrMemory(NULL, "creating node set object\n");
   4427 	return(NULL);
   4428     }
   4429     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4430     ret->type = XPATH_NODESET;
   4431     ret->nodesetval = val;
   4432 #ifdef XP_DEBUG_OBJ_USAGE
   4433     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
   4434 #endif
   4435     return(ret);
   4436 }
   4437 
   4438 /**
   4439  * xmlXPathFreeNodeSetList:
   4440  * @obj:  an existing NodeSetList object
   4441  *
   4442  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
   4443  * the list contrary to xmlXPathFreeObject().
   4444  */
   4445 void
   4446 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
   4447     if (obj == NULL) return;
   4448 #ifdef XP_DEBUG_OBJ_USAGE
   4449     xmlXPathDebugObjUsageReleased(NULL, obj->type);
   4450 #endif
   4451     xmlFree(obj);
   4452 }
   4453 
   4454 /**
   4455  * xmlXPathDifference:
   4456  * @nodes1:  a node-set
   4457  * @nodes2:  a node-set
   4458  *
   4459  * Implements the EXSLT - Sets difference() function:
   4460  *    node-set set:difference (node-set, node-set)
   4461  *
   4462  * Returns the difference between the two node sets, or nodes1 if
   4463  *         nodes2 is empty
   4464  */
   4465 xmlNodeSetPtr
   4466 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4467     xmlNodeSetPtr ret;
   4468     int i, l1;
   4469     xmlNodePtr cur;
   4470 
   4471     if (xmlXPathNodeSetIsEmpty(nodes2))
   4472 	return(nodes1);
   4473 
   4474     ret = xmlXPathNodeSetCreate(NULL);
   4475     if (xmlXPathNodeSetIsEmpty(nodes1))
   4476 	return(ret);
   4477 
   4478     l1 = xmlXPathNodeSetGetLength(nodes1);
   4479 
   4480     for (i = 0; i < l1; i++) {
   4481 	cur = xmlXPathNodeSetItem(nodes1, i);
   4482 	if (!xmlXPathNodeSetContains(nodes2, cur)) {
   4483 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
   4484 	        break;
   4485 	}
   4486     }
   4487     return(ret);
   4488 }
   4489 
   4490 /**
   4491  * xmlXPathIntersection:
   4492  * @nodes1:  a node-set
   4493  * @nodes2:  a node-set
   4494  *
   4495  * Implements the EXSLT - Sets intersection() function:
   4496  *    node-set set:intersection (node-set, node-set)
   4497  *
   4498  * Returns a node set comprising the nodes that are within both the
   4499  *         node sets passed as arguments
   4500  */
   4501 xmlNodeSetPtr
   4502 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4503     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
   4504     int i, l1;
   4505     xmlNodePtr cur;
   4506 
   4507     if (ret == NULL)
   4508         return(ret);
   4509     if (xmlXPathNodeSetIsEmpty(nodes1))
   4510 	return(ret);
   4511     if (xmlXPathNodeSetIsEmpty(nodes2))
   4512 	return(ret);
   4513 
   4514     l1 = xmlXPathNodeSetGetLength(nodes1);
   4515 
   4516     for (i = 0; i < l1; i++) {
   4517 	cur = xmlXPathNodeSetItem(nodes1, i);
   4518 	if (xmlXPathNodeSetContains(nodes2, cur)) {
   4519 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
   4520 	        break;
   4521 	}
   4522     }
   4523     return(ret);
   4524 }
   4525 
   4526 /**
   4527  * xmlXPathDistinctSorted:
   4528  * @nodes:  a node-set, sorted by document order
   4529  *
   4530  * Implements the EXSLT - Sets distinct() function:
   4531  *    node-set set:distinct (node-set)
   4532  *
   4533  * Returns a subset of the nodes contained in @nodes, or @nodes if
   4534  *         it is empty
   4535  */
   4536 xmlNodeSetPtr
   4537 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
   4538     xmlNodeSetPtr ret;
   4539     xmlHashTablePtr hash;
   4540     int i, l;
   4541     xmlChar * strval;
   4542     xmlNodePtr cur;
   4543 
   4544     if (xmlXPathNodeSetIsEmpty(nodes))
   4545 	return(nodes);
   4546 
   4547     ret = xmlXPathNodeSetCreate(NULL);
   4548     if (ret == NULL)
   4549         return(ret);
   4550     l = xmlXPathNodeSetGetLength(nodes);
   4551     hash = xmlHashCreate (l);
   4552     for (i = 0; i < l; i++) {
   4553 	cur = xmlXPathNodeSetItem(nodes, i);
   4554 	strval = xmlXPathCastNodeToString(cur);
   4555 	if (xmlHashLookup(hash, strval) == NULL) {
   4556 	    xmlHashAddEntry(hash, strval, strval);
   4557 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
   4558 	        break;
   4559 	} else {
   4560 	    xmlFree(strval);
   4561 	}
   4562     }
   4563     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
   4564     return(ret);
   4565 }
   4566 
   4567 /**
   4568  * xmlXPathDistinct:
   4569  * @nodes:  a node-set
   4570  *
   4571  * Implements the EXSLT - Sets distinct() function:
   4572  *    node-set set:distinct (node-set)
   4573  * @nodes is sorted by document order, then #exslSetsDistinctSorted
   4574  * is called with the sorted node-set
   4575  *
   4576  * Returns a subset of the nodes contained in @nodes, or @nodes if
   4577  *         it is empty
   4578  */
   4579 xmlNodeSetPtr
   4580 xmlXPathDistinct (xmlNodeSetPtr nodes) {
   4581     if (xmlXPathNodeSetIsEmpty(nodes))
   4582 	return(nodes);
   4583 
   4584     xmlXPathNodeSetSort(nodes);
   4585     return(xmlXPathDistinctSorted(nodes));
   4586 }
   4587 
   4588 /**
   4589  * xmlXPathHasSameNodes:
   4590  * @nodes1:  a node-set
   4591  * @nodes2:  a node-set
   4592  *
   4593  * Implements the EXSLT - Sets has-same-nodes function:
   4594  *    boolean set:has-same-node(node-set, node-set)
   4595  *
   4596  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
   4597  *         otherwise
   4598  */
   4599 int
   4600 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4601     int i, l;
   4602     xmlNodePtr cur;
   4603 
   4604     if (xmlXPathNodeSetIsEmpty(nodes1) ||
   4605 	xmlXPathNodeSetIsEmpty(nodes2))
   4606 	return(0);
   4607 
   4608     l = xmlXPathNodeSetGetLength(nodes1);
   4609     for (i = 0; i < l; i++) {
   4610 	cur = xmlXPathNodeSetItem(nodes1, i);
   4611 	if (xmlXPathNodeSetContains(nodes2, cur))
   4612 	    return(1);
   4613     }
   4614     return(0);
   4615 }
   4616 
   4617 /**
   4618  * xmlXPathNodeLeadingSorted:
   4619  * @nodes: a node-set, sorted by document order
   4620  * @node: a node
   4621  *
   4622  * Implements the EXSLT - Sets leading() function:
   4623  *    node-set set:leading (node-set, node-set)
   4624  *
   4625  * Returns the nodes in @nodes that precede @node in document order,
   4626  *         @nodes if @node is NULL or an empty node-set if @nodes
   4627  *         doesn't contain @node
   4628  */
   4629 xmlNodeSetPtr
   4630 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4631     int i, l;
   4632     xmlNodePtr cur;
   4633     xmlNodeSetPtr ret;
   4634 
   4635     if (node == NULL)
   4636 	return(nodes);
   4637 
   4638     ret = xmlXPathNodeSetCreate(NULL);
   4639     if (ret == NULL)
   4640         return(ret);
   4641     if (xmlXPathNodeSetIsEmpty(nodes) ||
   4642 	(!xmlXPathNodeSetContains(nodes, node)))
   4643 	return(ret);
   4644 
   4645     l = xmlXPathNodeSetGetLength(nodes);
   4646     for (i = 0; i < l; i++) {
   4647 	cur = xmlXPathNodeSetItem(nodes, i);
   4648 	if (cur == node)
   4649 	    break;
   4650 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
   4651 	    break;
   4652     }
   4653     return(ret);
   4654 }
   4655 
   4656 /**
   4657  * xmlXPathNodeLeading:
   4658  * @nodes:  a node-set
   4659  * @node:  a node
   4660  *
   4661  * Implements the EXSLT - Sets leading() function:
   4662  *    node-set set:leading (node-set, node-set)
   4663  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
   4664  * is called.
   4665  *
   4666  * Returns the nodes in @nodes that precede @node in document order,
   4667  *         @nodes if @node is NULL or an empty node-set if @nodes
   4668  *         doesn't contain @node
   4669  */
   4670 xmlNodeSetPtr
   4671 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4672     xmlXPathNodeSetSort(nodes);
   4673     return(xmlXPathNodeLeadingSorted(nodes, node));
   4674 }
   4675 
   4676 /**
   4677  * xmlXPathLeadingSorted:
   4678  * @nodes1:  a node-set, sorted by document order
   4679  * @nodes2:  a node-set, sorted by document order
   4680  *
   4681  * Implements the EXSLT - Sets leading() function:
   4682  *    node-set set:leading (node-set, node-set)
   4683  *
   4684  * Returns the nodes in @nodes1 that precede the first node in @nodes2
   4685  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4686  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4687  */
   4688 xmlNodeSetPtr
   4689 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4690     if (xmlXPathNodeSetIsEmpty(nodes2))
   4691 	return(nodes1);
   4692     return(xmlXPathNodeLeadingSorted(nodes1,
   4693 				     xmlXPathNodeSetItem(nodes2, 1)));
   4694 }
   4695 
   4696 /**
   4697  * xmlXPathLeading:
   4698  * @nodes1:  a node-set
   4699  * @nodes2:  a node-set
   4700  *
   4701  * Implements the EXSLT - Sets leading() function:
   4702  *    node-set set:leading (node-set, node-set)
   4703  * @nodes1 and @nodes2 are sorted by document order, then
   4704  * #exslSetsLeadingSorted is called.
   4705  *
   4706  * Returns the nodes in @nodes1 that precede the first node in @nodes2
   4707  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4708  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4709  */
   4710 xmlNodeSetPtr
   4711 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4712     if (xmlXPathNodeSetIsEmpty(nodes2))
   4713 	return(nodes1);
   4714     if (xmlXPathNodeSetIsEmpty(nodes1))
   4715 	return(xmlXPathNodeSetCreate(NULL));
   4716     xmlXPathNodeSetSort(nodes1);
   4717     xmlXPathNodeSetSort(nodes2);
   4718     return(xmlXPathNodeLeadingSorted(nodes1,
   4719 				     xmlXPathNodeSetItem(nodes2, 1)));
   4720 }
   4721 
   4722 /**
   4723  * xmlXPathNodeTrailingSorted:
   4724  * @nodes: a node-set, sorted by document order
   4725  * @node: a node
   4726  *
   4727  * Implements the EXSLT - Sets trailing() function:
   4728  *    node-set set:trailing (node-set, node-set)
   4729  *
   4730  * Returns the nodes in @nodes that follow @node in document order,
   4731  *         @nodes if @node is NULL or an empty node-set if @nodes
   4732  *         doesn't contain @node
   4733  */
   4734 xmlNodeSetPtr
   4735 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4736     int i, l;
   4737     xmlNodePtr cur;
   4738     xmlNodeSetPtr ret;
   4739 
   4740     if (node == NULL)
   4741 	return(nodes);
   4742 
   4743     ret = xmlXPathNodeSetCreate(NULL);
   4744     if (ret == NULL)
   4745         return(ret);
   4746     if (xmlXPathNodeSetIsEmpty(nodes) ||
   4747 	(!xmlXPathNodeSetContains(nodes, node)))
   4748 	return(ret);
   4749 
   4750     l = xmlXPathNodeSetGetLength(nodes);
   4751     for (i = l - 1; i >= 0; i--) {
   4752 	cur = xmlXPathNodeSetItem(nodes, i);
   4753 	if (cur == node)
   4754 	    break;
   4755 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
   4756 	    break;
   4757     }
   4758     xmlXPathNodeSetSort(ret);	/* bug 413451 */
   4759     return(ret);
   4760 }
   4761 
   4762 /**
   4763  * xmlXPathNodeTrailing:
   4764  * @nodes:  a node-set
   4765  * @node:  a node
   4766  *
   4767  * Implements the EXSLT - Sets trailing() function:
   4768  *    node-set set:trailing (node-set, node-set)
   4769  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
   4770  * is called.
   4771  *
   4772  * Returns the nodes in @nodes that follow @node in document order,
   4773  *         @nodes if @node is NULL or an empty node-set if @nodes
   4774  *         doesn't contain @node
   4775  */
   4776 xmlNodeSetPtr
   4777 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4778     xmlXPathNodeSetSort(nodes);
   4779     return(xmlXPathNodeTrailingSorted(nodes, node));
   4780 }
   4781 
   4782 /**
   4783  * xmlXPathTrailingSorted:
   4784  * @nodes1:  a node-set, sorted by document order
   4785  * @nodes2:  a node-set, sorted by document order
   4786  *
   4787  * Implements the EXSLT - Sets trailing() function:
   4788  *    node-set set:trailing (node-set, node-set)
   4789  *
   4790  * Returns the nodes in @nodes1 that follow the first node in @nodes2
   4791  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4792  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4793  */
   4794 xmlNodeSetPtr
   4795 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4796     if (xmlXPathNodeSetIsEmpty(nodes2))
   4797 	return(nodes1);
   4798     return(xmlXPathNodeTrailingSorted(nodes1,
   4799 				      xmlXPathNodeSetItem(nodes2, 0)));
   4800 }
   4801 
   4802 /**
   4803  * xmlXPathTrailing:
   4804  * @nodes1:  a node-set
   4805  * @nodes2:  a node-set
   4806  *
   4807  * Implements the EXSLT - Sets trailing() function:
   4808  *    node-set set:trailing (node-set, node-set)
   4809  * @nodes1 and @nodes2 are sorted by document order, then
   4810  * #xmlXPathTrailingSorted is called.
   4811  *
   4812  * Returns the nodes in @nodes1 that follow the first node in @nodes2
   4813  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4814  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4815  */
   4816 xmlNodeSetPtr
   4817 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4818     if (xmlXPathNodeSetIsEmpty(nodes2))
   4819 	return(nodes1);
   4820     if (xmlXPathNodeSetIsEmpty(nodes1))
   4821 	return(xmlXPathNodeSetCreate(NULL));
   4822     xmlXPathNodeSetSort(nodes1);
   4823     xmlXPathNodeSetSort(nodes2);
   4824     return(xmlXPathNodeTrailingSorted(nodes1,
   4825 				      xmlXPathNodeSetItem(nodes2, 0)));
   4826 }
   4827 
   4828 /************************************************************************
   4829  *									*
   4830  *		Routines to handle extra functions			*
   4831  *									*
   4832  ************************************************************************/
   4833 
   4834 /**
   4835  * xmlXPathRegisterFunc:
   4836  * @ctxt:  the XPath context
   4837  * @name:  the function name
   4838  * @f:  the function implementation or NULL
   4839  *
   4840  * Register a new function. If @f is NULL it unregisters the function
   4841  *
   4842  * Returns 0 in case of success, -1 in case of error
   4843  */
   4844 int
   4845 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
   4846 		     xmlXPathFunction f) {
   4847     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
   4848 }
   4849 
   4850 /**
   4851  * xmlXPathRegisterFuncNS:
   4852  * @ctxt:  the XPath context
   4853  * @name:  the function name
   4854  * @ns_uri:  the function namespace URI
   4855  * @f:  the function implementation or NULL
   4856  *
   4857  * Register a new function. If @f is NULL it unregisters the function
   4858  *
   4859  * Returns 0 in case of success, -1 in case of error
   4860  */
   4861 int
   4862 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   4863 		       const xmlChar *ns_uri, xmlXPathFunction f) {
   4864     if (ctxt == NULL)
   4865 	return(-1);
   4866     if (name == NULL)
   4867 	return(-1);
   4868 
   4869     if (ctxt->funcHash == NULL)
   4870 	ctxt->funcHash = xmlHashCreate(0);
   4871     if (ctxt->funcHash == NULL)
   4872 	return(-1);
   4873     if (f == NULL)
   4874         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
   4875     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
   4876 }
   4877 
   4878 /**
   4879  * xmlXPathRegisterFuncLookup:
   4880  * @ctxt:  the XPath context
   4881  * @f:  the lookup function
   4882  * @funcCtxt:  the lookup data
   4883  *
   4884  * Registers an external mechanism to do function lookup.
   4885  */
   4886 void
   4887 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
   4888 			    xmlXPathFuncLookupFunc f,
   4889 			    void *funcCtxt) {
   4890     if (ctxt == NULL)
   4891 	return;
   4892     ctxt->funcLookupFunc = f;
   4893     ctxt->funcLookupData = funcCtxt;
   4894 }
   4895 
   4896 /**
   4897  * xmlXPathFunctionLookup:
   4898  * @ctxt:  the XPath context
   4899  * @name:  the function name
   4900  *
   4901  * Search in the Function array of the context for the given
   4902  * function.
   4903  *
   4904  * Returns the xmlXPathFunction or NULL if not found
   4905  */
   4906 xmlXPathFunction
   4907 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
   4908     if (ctxt == NULL)
   4909 	return (NULL);
   4910 
   4911     if (ctxt->funcLookupFunc != NULL) {
   4912 	xmlXPathFunction ret;
   4913 	xmlXPathFuncLookupFunc f;
   4914 
   4915 	f = ctxt->funcLookupFunc;
   4916 	ret = f(ctxt->funcLookupData, name, NULL);
   4917 	if (ret != NULL)
   4918 	    return(ret);
   4919     }
   4920     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
   4921 }
   4922 
   4923 /**
   4924  * xmlXPathFunctionLookupNS:
   4925  * @ctxt:  the XPath context
   4926  * @name:  the function name
   4927  * @ns_uri:  the function namespace URI
   4928  *
   4929  * Search in the Function array of the context for the given
   4930  * function.
   4931  *
   4932  * Returns the xmlXPathFunction or NULL if not found
   4933  */
   4934 xmlXPathFunction
   4935 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   4936 			 const xmlChar *ns_uri) {
   4937     xmlXPathFunction ret;
   4938 
   4939     if (ctxt == NULL)
   4940 	return(NULL);
   4941     if (name == NULL)
   4942 	return(NULL);
   4943 
   4944     if (ctxt->funcLookupFunc != NULL) {
   4945 	xmlXPathFuncLookupFunc f;
   4946 
   4947 	f = ctxt->funcLookupFunc;
   4948 	ret = f(ctxt->funcLookupData, name, ns_uri);
   4949 	if (ret != NULL)
   4950 	    return(ret);
   4951     }
   4952 
   4953     if (ctxt->funcHash == NULL)
   4954 	return(NULL);
   4955 
   4956     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
   4957     return(ret);
   4958 }
   4959 
   4960 /**
   4961  * xmlXPathRegisteredFuncsCleanup:
   4962  * @ctxt:  the XPath context
   4963  *
   4964  * Cleanup the XPath context data associated to registered functions
   4965  */
   4966 void
   4967 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
   4968     if (ctxt == NULL)
   4969 	return;
   4970 
   4971     xmlHashFree(ctxt->funcHash, NULL);
   4972     ctxt->funcHash = NULL;
   4973 }
   4974 
   4975 /************************************************************************
   4976  *									*
   4977  *			Routines to handle Variables			*
   4978  *									*
   4979  ************************************************************************/
   4980 
   4981 /**
   4982  * xmlXPathRegisterVariable:
   4983  * @ctxt:  the XPath context
   4984  * @name:  the variable name
   4985  * @value:  the variable value or NULL
   4986  *
   4987  * Register a new variable value. If @value is NULL it unregisters
   4988  * the variable
   4989  *
   4990  * Returns 0 in case of success, -1 in case of error
   4991  */
   4992 int
   4993 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
   4994 			 xmlXPathObjectPtr value) {
   4995     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
   4996 }
   4997 
   4998 /**
   4999  * xmlXPathRegisterVariableNS:
   5000  * @ctxt:  the XPath context
   5001  * @name:  the variable name
   5002  * @ns_uri:  the variable namespace URI
   5003  * @value:  the variable value or NULL
   5004  *
   5005  * Register a new variable value. If @value is NULL it unregisters
   5006  * the variable
   5007  *
   5008  * Returns 0 in case of success, -1 in case of error
   5009  */
   5010 int
   5011 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   5012 			   const xmlChar *ns_uri,
   5013 			   xmlXPathObjectPtr value) {
   5014     if (ctxt == NULL)
   5015 	return(-1);
   5016     if (name == NULL)
   5017 	return(-1);
   5018 
   5019     if (ctxt->varHash == NULL)
   5020 	ctxt->varHash = xmlHashCreate(0);
   5021     if (ctxt->varHash == NULL)
   5022 	return(-1);
   5023     if (value == NULL)
   5024         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
   5025 	                           (xmlHashDeallocator)xmlXPathFreeObject));
   5026     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
   5027 			       (void *) value,
   5028 			       (xmlHashDeallocator)xmlXPathFreeObject));
   5029 }
   5030 
   5031 /**
   5032  * xmlXPathRegisterVariableLookup:
   5033  * @ctxt:  the XPath context
   5034  * @f:  the lookup function
   5035  * @data:  the lookup data
   5036  *
   5037  * register an external mechanism to do variable lookup
   5038  */
   5039 void
   5040 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
   5041 	 xmlXPathVariableLookupFunc f, void *data) {
   5042     if (ctxt == NULL)
   5043 	return;
   5044     ctxt->varLookupFunc = f;
   5045     ctxt->varLookupData = data;
   5046 }
   5047 
   5048 /**
   5049  * xmlXPathVariableLookup:
   5050  * @ctxt:  the XPath context
   5051  * @name:  the variable name
   5052  *
   5053  * Search in the Variable array of the context for the given
   5054  * variable value.
   5055  *
   5056  * Returns a copy of the value or NULL if not found
   5057  */
   5058 xmlXPathObjectPtr
   5059 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
   5060     if (ctxt == NULL)
   5061 	return(NULL);
   5062 
   5063     if (ctxt->varLookupFunc != NULL) {
   5064 	xmlXPathObjectPtr ret;
   5065 
   5066 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
   5067 	        (ctxt->varLookupData, name, NULL);
   5068 	return(ret);
   5069     }
   5070     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
   5071 }
   5072 
   5073 /**
   5074  * xmlXPathVariableLookupNS:
   5075  * @ctxt:  the XPath context
   5076  * @name:  the variable name
   5077  * @ns_uri:  the variable namespace URI
   5078  *
   5079  * Search in the Variable array of the context for the given
   5080  * variable value.
   5081  *
   5082  * Returns the a copy of the value or NULL if not found
   5083  */
   5084 xmlXPathObjectPtr
   5085 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   5086 			 const xmlChar *ns_uri) {
   5087     if (ctxt == NULL)
   5088 	return(NULL);
   5089 
   5090     if (ctxt->varLookupFunc != NULL) {
   5091 	xmlXPathObjectPtr ret;
   5092 
   5093 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
   5094 	        (ctxt->varLookupData, name, ns_uri);
   5095 	if (ret != NULL) return(ret);
   5096     }
   5097 
   5098     if (ctxt->varHash == NULL)
   5099 	return(NULL);
   5100     if (name == NULL)
   5101 	return(NULL);
   5102 
   5103     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
   5104 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
   5105 }
   5106 
   5107 /**
   5108  * xmlXPathRegisteredVariablesCleanup:
   5109  * @ctxt:  the XPath context
   5110  *
   5111  * Cleanup the XPath context data associated to registered variables
   5112  */
   5113 void
   5114 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
   5115     if (ctxt == NULL)
   5116 	return;
   5117 
   5118     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
   5119     ctxt->varHash = NULL;
   5120 }
   5121 
   5122 /**
   5123  * xmlXPathRegisterNs:
   5124  * @ctxt:  the XPath context
   5125  * @prefix:  the namespace prefix cannot be NULL or empty string
   5126  * @ns_uri:  the namespace name
   5127  *
   5128  * Register a new namespace. If @ns_uri is NULL it unregisters
   5129  * the namespace
   5130  *
   5131  * Returns 0 in case of success, -1 in case of error
   5132  */
   5133 int
   5134 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
   5135 			   const xmlChar *ns_uri) {
   5136     if (ctxt == NULL)
   5137 	return(-1);
   5138     if (prefix == NULL)
   5139 	return(-1);
   5140     if (prefix[0] == 0)
   5141 	return(-1);
   5142 
   5143     if (ctxt->nsHash == NULL)
   5144 	ctxt->nsHash = xmlHashCreate(10);
   5145     if (ctxt->nsHash == NULL)
   5146 	return(-1);
   5147     if (ns_uri == NULL)
   5148         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
   5149 	                          (xmlHashDeallocator)xmlFree));
   5150     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
   5151 			      (xmlHashDeallocator)xmlFree));
   5152 }
   5153 
   5154 /**
   5155  * xmlXPathNsLookup:
   5156  * @ctxt:  the XPath context
   5157  * @prefix:  the namespace prefix value
   5158  *
   5159  * Search in the namespace declaration array of the context for the given
   5160  * namespace name associated to the given prefix
   5161  *
   5162  * Returns the value or NULL if not found
   5163  */
   5164 const xmlChar *
   5165 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
   5166     if (ctxt == NULL)
   5167 	return(NULL);
   5168     if (prefix == NULL)
   5169 	return(NULL);
   5170 
   5171 #ifdef XML_XML_NAMESPACE
   5172     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
   5173 	return(XML_XML_NAMESPACE);
   5174 #endif
   5175 
   5176     if (ctxt->namespaces != NULL) {
   5177 	int i;
   5178 
   5179 	for (i = 0;i < ctxt->nsNr;i++) {
   5180 	    if ((ctxt->namespaces[i] != NULL) &&
   5181 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
   5182 		return(ctxt->namespaces[i]->href);
   5183 	}
   5184     }
   5185 
   5186     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
   5187 }
   5188 
   5189 /**
   5190  * xmlXPathRegisteredNsCleanup:
   5191  * @ctxt:  the XPath context
   5192  *
   5193  * Cleanup the XPath context data associated to registered variables
   5194  */
   5195 void
   5196 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
   5197     if (ctxt == NULL)
   5198 	return;
   5199 
   5200     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
   5201     ctxt->nsHash = NULL;
   5202 }
   5203 
   5204 /************************************************************************
   5205  *									*
   5206  *			Routines to handle Values			*
   5207  *									*
   5208  ************************************************************************/
   5209 
   5210 /* Allocations are terrible, one needs to optimize all this !!! */
   5211 
   5212 /**
   5213  * xmlXPathNewFloat:
   5214  * @val:  the double value
   5215  *
   5216  * Create a new xmlXPathObjectPtr of type double and of value @val
   5217  *
   5218  * Returns the newly created object.
   5219  */
   5220 xmlXPathObjectPtr
   5221 xmlXPathNewFloat(double val) {
   5222     xmlXPathObjectPtr ret;
   5223 
   5224     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5225     if (ret == NULL) {
   5226         xmlXPathErrMemory(NULL, "creating float object\n");
   5227 	return(NULL);
   5228     }
   5229     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5230     ret->type = XPATH_NUMBER;
   5231     ret->floatval = val;
   5232 #ifdef XP_DEBUG_OBJ_USAGE
   5233     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
   5234 #endif
   5235     return(ret);
   5236 }
   5237 
   5238 /**
   5239  * xmlXPathNewBoolean:
   5240  * @val:  the boolean value
   5241  *
   5242  * Create a new xmlXPathObjectPtr of type boolean and of value @val
   5243  *
   5244  * Returns the newly created object.
   5245  */
   5246 xmlXPathObjectPtr
   5247 xmlXPathNewBoolean(int val) {
   5248     xmlXPathObjectPtr ret;
   5249 
   5250     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5251     if (ret == NULL) {
   5252         xmlXPathErrMemory(NULL, "creating boolean object\n");
   5253 	return(NULL);
   5254     }
   5255     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5256     ret->type = XPATH_BOOLEAN;
   5257     ret->boolval = (val != 0);
   5258 #ifdef XP_DEBUG_OBJ_USAGE
   5259     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
   5260 #endif
   5261     return(ret);
   5262 }
   5263 
   5264 /**
   5265  * xmlXPathNewString:
   5266  * @val:  the xmlChar * value
   5267  *
   5268  * Create a new xmlXPathObjectPtr of type string and of value @val
   5269  *
   5270  * Returns the newly created object.
   5271  */
   5272 xmlXPathObjectPtr
   5273 xmlXPathNewString(const xmlChar *val) {
   5274     xmlXPathObjectPtr ret;
   5275 
   5276     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5277     if (ret == NULL) {
   5278         xmlXPathErrMemory(NULL, "creating string object\n");
   5279 	return(NULL);
   5280     }
   5281     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5282     ret->type = XPATH_STRING;
   5283     if (val != NULL)
   5284 	ret->stringval = xmlStrdup(val);
   5285     else
   5286 	ret->stringval = xmlStrdup((const xmlChar *)"");
   5287 #ifdef XP_DEBUG_OBJ_USAGE
   5288     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5289 #endif
   5290     return(ret);
   5291 }
   5292 
   5293 /**
   5294  * xmlXPathWrapString:
   5295  * @val:  the xmlChar * value
   5296  *
   5297  * Wraps the @val string into an XPath object.
   5298  *
   5299  * Returns the newly created object.
   5300  */
   5301 xmlXPathObjectPtr
   5302 xmlXPathWrapString (xmlChar *val) {
   5303     xmlXPathObjectPtr ret;
   5304 
   5305     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5306     if (ret == NULL) {
   5307         xmlXPathErrMemory(NULL, "creating string object\n");
   5308 	return(NULL);
   5309     }
   5310     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5311     ret->type = XPATH_STRING;
   5312     ret->stringval = val;
   5313 #ifdef XP_DEBUG_OBJ_USAGE
   5314     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5315 #endif
   5316     return(ret);
   5317 }
   5318 
   5319 /**
   5320  * xmlXPathNewCString:
   5321  * @val:  the char * value
   5322  *
   5323  * Create a new xmlXPathObjectPtr of type string and of value @val
   5324  *
   5325  * Returns the newly created object.
   5326  */
   5327 xmlXPathObjectPtr
   5328 xmlXPathNewCString(const char *val) {
   5329     xmlXPathObjectPtr ret;
   5330 
   5331     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5332     if (ret == NULL) {
   5333         xmlXPathErrMemory(NULL, "creating string object\n");
   5334 	return(NULL);
   5335     }
   5336     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5337     ret->type = XPATH_STRING;
   5338     ret->stringval = xmlStrdup(BAD_CAST val);
   5339 #ifdef XP_DEBUG_OBJ_USAGE
   5340     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5341 #endif
   5342     return(ret);
   5343 }
   5344 
   5345 /**
   5346  * xmlXPathWrapCString:
   5347  * @val:  the char * value
   5348  *
   5349  * Wraps a string into an XPath object.
   5350  *
   5351  * Returns the newly created object.
   5352  */
   5353 xmlXPathObjectPtr
   5354 xmlXPathWrapCString (char * val) {
   5355     return(xmlXPathWrapString((xmlChar *)(val)));
   5356 }
   5357 
   5358 /**
   5359  * xmlXPathWrapExternal:
   5360  * @val:  the user data
   5361  *
   5362  * Wraps the @val data into an XPath object.
   5363  *
   5364  * Returns the newly created object.
   5365  */
   5366 xmlXPathObjectPtr
   5367 xmlXPathWrapExternal (void *val) {
   5368     xmlXPathObjectPtr ret;
   5369 
   5370     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5371     if (ret == NULL) {
   5372         xmlXPathErrMemory(NULL, "creating user object\n");
   5373 	return(NULL);
   5374     }
   5375     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5376     ret->type = XPATH_USERS;
   5377     ret->user = val;
   5378 #ifdef XP_DEBUG_OBJ_USAGE
   5379     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
   5380 #endif
   5381     return(ret);
   5382 }
   5383 
   5384 /**
   5385  * xmlXPathObjectCopy:
   5386  * @val:  the original object
   5387  *
   5388  * allocate a new copy of a given object
   5389  *
   5390  * Returns the newly created object.
   5391  */
   5392 xmlXPathObjectPtr
   5393 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
   5394     xmlXPathObjectPtr ret;
   5395 
   5396     if (val == NULL)
   5397 	return(NULL);
   5398 
   5399     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5400     if (ret == NULL) {
   5401         xmlXPathErrMemory(NULL, "copying object\n");
   5402 	return(NULL);
   5403     }
   5404     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
   5405 #ifdef XP_DEBUG_OBJ_USAGE
   5406     xmlXPathDebugObjUsageRequested(NULL, val->type);
   5407 #endif
   5408     switch (val->type) {
   5409 	case XPATH_BOOLEAN:
   5410 	case XPATH_NUMBER:
   5411 	case XPATH_POINT:
   5412 	case XPATH_RANGE:
   5413 	    break;
   5414 	case XPATH_STRING:
   5415 	    ret->stringval = xmlStrdup(val->stringval);
   5416 	    break;
   5417 	case XPATH_XSLT_TREE:
   5418 #if 0
   5419 /*
   5420   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
   5421   this previous handling is no longer correct, and can cause some serious
   5422   problems (ref. bug 145547)
   5423 */
   5424 	    if ((val->nodesetval != NULL) &&
   5425 		(val->nodesetval->nodeTab != NULL)) {
   5426 		xmlNodePtr cur, tmp;
   5427 		xmlDocPtr top;
   5428 
   5429 		ret->boolval = 1;
   5430 		top =  xmlNewDoc(NULL);
   5431 		top->name = (char *)
   5432 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
   5433 		ret->user = top;
   5434 		if (top != NULL) {
   5435 		    top->doc = top;
   5436 		    cur = val->nodesetval->nodeTab[0]->children;
   5437 		    while (cur != NULL) {
   5438 			tmp = xmlDocCopyNode(cur, top, 1);
   5439 			xmlAddChild((xmlNodePtr) top, tmp);
   5440 			cur = cur->next;
   5441 		    }
   5442 		}
   5443 
   5444 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
   5445 	    } else
   5446 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
   5447 	    /* Deallocate the copied tree value */
   5448 	    break;
   5449 #endif
   5450 	case XPATH_NODESET:
   5451 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
   5452 	    /* Do not deallocate the copied tree value */
   5453 	    ret->boolval = 0;
   5454 	    break;
   5455 	case XPATH_LOCATIONSET:
   5456 #ifdef LIBXML_XPTR_ENABLED
   5457 	{
   5458 	    xmlLocationSetPtr loc = val->user;
   5459 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
   5460 	    break;
   5461 	}
   5462 #endif
   5463         case XPATH_USERS:
   5464 	    ret->user = val->user;
   5465 	    break;
   5466         case XPATH_UNDEFINED:
   5467 	    xmlGenericError(xmlGenericErrorContext,
   5468 		    "xmlXPathObjectCopy: unsupported type %d\n",
   5469 		    val->type);
   5470 	    break;
   5471     }
   5472     return(ret);
   5473 }
   5474 
   5475 /**
   5476  * xmlXPathFreeObject:
   5477  * @obj:  the object to free
   5478  *
   5479  * Free up an xmlXPathObjectPtr object.
   5480  */
   5481 void
   5482 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
   5483     if (obj == NULL) return;
   5484     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
   5485 	if (obj->boolval) {
   5486 #if 0
   5487 	    if (obj->user != NULL) {
   5488                 xmlXPathFreeNodeSet(obj->nodesetval);
   5489 		xmlFreeNodeList((xmlNodePtr) obj->user);
   5490 	    } else
   5491 #endif
   5492 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
   5493 	    if (obj->nodesetval != NULL)
   5494 		xmlXPathFreeValueTree(obj->nodesetval);
   5495 	} else {
   5496 	    if (obj->nodesetval != NULL)
   5497 		xmlXPathFreeNodeSet(obj->nodesetval);
   5498 	}
   5499 #ifdef LIBXML_XPTR_ENABLED
   5500     } else if (obj->type == XPATH_LOCATIONSET) {
   5501 	if (obj->user != NULL)
   5502 	    xmlXPtrFreeLocationSet(obj->user);
   5503 #endif
   5504     } else if (obj->type == XPATH_STRING) {
   5505 	if (obj->stringval != NULL)
   5506 	    xmlFree(obj->stringval);
   5507     }
   5508 #ifdef XP_DEBUG_OBJ_USAGE
   5509     xmlXPathDebugObjUsageReleased(NULL, obj->type);
   5510 #endif
   5511     xmlFree(obj);
   5512 }
   5513 
   5514 /**
   5515  * xmlXPathReleaseObject:
   5516  * @obj:  the xmlXPathObjectPtr to free or to cache
   5517  *
   5518  * Depending on the state of the cache this frees the given
   5519  * XPath object or stores it in the cache.
   5520  */
   5521 static void
   5522 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
   5523 {
   5524 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
   5525 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
   5526     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
   5527 
   5528 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
   5529 
   5530     if (obj == NULL)
   5531 	return;
   5532     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
   5533 	 xmlXPathFreeObject(obj);
   5534     } else {
   5535 	xmlXPathContextCachePtr cache =
   5536 	    (xmlXPathContextCachePtr) ctxt->cache;
   5537 
   5538 	switch (obj->type) {
   5539 	    case XPATH_NODESET:
   5540 	    case XPATH_XSLT_TREE:
   5541 		if (obj->nodesetval != NULL) {
   5542 		    if (obj->boolval) {
   5543 			/*
   5544 			* It looks like the @boolval is used for
   5545 			* evaluation if this an XSLT Result Tree Fragment.
   5546 			* TODO: Check if this assumption is correct.
   5547 			*/
   5548 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
   5549 			xmlXPathFreeValueTree(obj->nodesetval);
   5550 			obj->nodesetval = NULL;
   5551 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
   5552 			(XP_CACHE_WANTS(cache->nodesetObjs,
   5553 					cache->maxNodeset)))
   5554 		    {
   5555 			XP_CACHE_ADD(cache->nodesetObjs, obj);
   5556 			goto obj_cached;
   5557 		    } else {
   5558 			xmlXPathFreeNodeSet(obj->nodesetval);
   5559 			obj->nodesetval = NULL;
   5560 		    }
   5561 		}
   5562 		break;
   5563 	    case XPATH_STRING:
   5564 		if (obj->stringval != NULL)
   5565 		    xmlFree(obj->stringval);
   5566 
   5567 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
   5568 		    XP_CACHE_ADD(cache->stringObjs, obj);
   5569 		    goto obj_cached;
   5570 		}
   5571 		break;
   5572 	    case XPATH_BOOLEAN:
   5573 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
   5574 		    XP_CACHE_ADD(cache->booleanObjs, obj);
   5575 		    goto obj_cached;
   5576 		}
   5577 		break;
   5578 	    case XPATH_NUMBER:
   5579 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
   5580 		    XP_CACHE_ADD(cache->numberObjs, obj);
   5581 		    goto obj_cached;
   5582 		}
   5583 		break;
   5584 #ifdef LIBXML_XPTR_ENABLED
   5585 	    case XPATH_LOCATIONSET:
   5586 		if (obj->user != NULL) {
   5587 		    xmlXPtrFreeLocationSet(obj->user);
   5588 		}
   5589 		goto free_obj;
   5590 #endif
   5591 	    default:
   5592 		goto free_obj;
   5593 	}
   5594 
   5595 	/*
   5596 	* Fallback to adding to the misc-objects slot.
   5597 	*/
   5598 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
   5599 	    XP_CACHE_ADD(cache->miscObjs, obj);
   5600 	} else
   5601 	    goto free_obj;
   5602 
   5603 obj_cached:
   5604 
   5605 #ifdef XP_DEBUG_OBJ_USAGE
   5606 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
   5607 #endif
   5608 
   5609 	if (obj->nodesetval != NULL) {
   5610 	    xmlNodeSetPtr tmpset = obj->nodesetval;
   5611 
   5612 	    /*
   5613 	    * TODO: Due to those nasty ns-nodes, we need to traverse
   5614 	    *  the list and free the ns-nodes.
   5615 	    * URGENT TODO: Check if it's actually slowing things down.
   5616 	    *  Maybe we shouldn't try to preserve the list.
   5617 	    */
   5618 	    if (tmpset->nodeNr > 1) {
   5619 		int i;
   5620 		xmlNodePtr node;
   5621 
   5622 		for (i = 0; i < tmpset->nodeNr; i++) {
   5623 		    node = tmpset->nodeTab[i];
   5624 		    if ((node != NULL) &&
   5625 			(node->type == XML_NAMESPACE_DECL))
   5626 		    {
   5627 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   5628 		    }
   5629 		}
   5630 	    } else if (tmpset->nodeNr == 1) {
   5631 		if ((tmpset->nodeTab[0] != NULL) &&
   5632 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
   5633 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
   5634 	    }
   5635 	    tmpset->nodeNr = 0;
   5636 	    memset(obj, 0, sizeof(xmlXPathObject));
   5637 	    obj->nodesetval = tmpset;
   5638 	} else
   5639 	    memset(obj, 0, sizeof(xmlXPathObject));
   5640 
   5641 	return;
   5642 
   5643 free_obj:
   5644 	/*
   5645 	* Cache is full; free the object.
   5646 	*/
   5647 	if (obj->nodesetval != NULL)
   5648 	    xmlXPathFreeNodeSet(obj->nodesetval);
   5649 #ifdef XP_DEBUG_OBJ_USAGE
   5650 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
   5651 #endif
   5652 	xmlFree(obj);
   5653     }
   5654     return;
   5655 }
   5656 
   5657 
   5658 /************************************************************************
   5659  *									*
   5660  *			Type Casting Routines				*
   5661  *									*
   5662  ************************************************************************/
   5663 
   5664 /**
   5665  * xmlXPathCastBooleanToString:
   5666  * @val:  a boolean
   5667  *
   5668  * Converts a boolean to its string value.
   5669  *
   5670  * Returns a newly allocated string.
   5671  */
   5672 xmlChar *
   5673 xmlXPathCastBooleanToString (int val) {
   5674     xmlChar *ret;
   5675     if (val)
   5676 	ret = xmlStrdup((const xmlChar *) "true");
   5677     else
   5678 	ret = xmlStrdup((const xmlChar *) "false");
   5679     return(ret);
   5680 }
   5681 
   5682 /**
   5683  * xmlXPathCastNumberToString:
   5684  * @val:  a number
   5685  *
   5686  * Converts a number to its string value.
   5687  *
   5688  * Returns a newly allocated string.
   5689  */
   5690 xmlChar *
   5691 xmlXPathCastNumberToString (double val) {
   5692     xmlChar *ret;
   5693     switch (xmlXPathIsInf(val)) {
   5694     case 1:
   5695 	ret = xmlStrdup((const xmlChar *) "Infinity");
   5696 	break;
   5697     case -1:
   5698 	ret = xmlStrdup((const xmlChar *) "-Infinity");
   5699 	break;
   5700     default:
   5701 	if (xmlXPathIsNaN(val)) {
   5702 	    ret = xmlStrdup((const xmlChar *) "NaN");
   5703 	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
   5704 	    ret = xmlStrdup((const xmlChar *) "0");
   5705 	} else {
   5706 	    /* could be improved */
   5707 	    char buf[100];
   5708 	    xmlXPathFormatNumber(val, buf, 99);
   5709 	    buf[99] = 0;
   5710 	    ret = xmlStrdup((const xmlChar *) buf);
   5711 	}
   5712     }
   5713     return(ret);
   5714 }
   5715 
   5716 /**
   5717  * xmlXPathCastNodeToString:
   5718  * @node:  a node
   5719  *
   5720  * Converts a node to its string value.
   5721  *
   5722  * Returns a newly allocated string.
   5723  */
   5724 xmlChar *
   5725 xmlXPathCastNodeToString (xmlNodePtr node) {
   5726 xmlChar *ret;
   5727     if ((ret = xmlNodeGetContent(node)) == NULL)
   5728 	ret = xmlStrdup((const xmlChar *) "");
   5729     return(ret);
   5730 }
   5731 
   5732 /**
   5733  * xmlXPathCastNodeSetToString:
   5734  * @ns:  a node-set
   5735  *
   5736  * Converts a node-set to its string value.
   5737  *
   5738  * Returns a newly allocated string.
   5739  */
   5740 xmlChar *
   5741 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
   5742     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
   5743 	return(xmlStrdup((const xmlChar *) ""));
   5744 
   5745     if (ns->nodeNr > 1)
   5746 	xmlXPathNodeSetSort(ns);
   5747     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
   5748 }
   5749 
   5750 /**
   5751  * xmlXPathCastToString:
   5752  * @val:  an XPath object
   5753  *
   5754  * Converts an existing object to its string() equivalent
   5755  *
   5756  * Returns the allocated string value of the object, NULL in case of error.
   5757  *         It's up to the caller to free the string memory with xmlFree().
   5758  */
   5759 xmlChar *
   5760 xmlXPathCastToString(xmlXPathObjectPtr val) {
   5761     xmlChar *ret = NULL;
   5762 
   5763     if (val == NULL)
   5764 	return(xmlStrdup((const xmlChar *) ""));
   5765     switch (val->type) {
   5766 	case XPATH_UNDEFINED:
   5767 #ifdef DEBUG_EXPR
   5768 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
   5769 #endif
   5770 	    ret = xmlStrdup((const xmlChar *) "");
   5771 	    break;
   5772         case XPATH_NODESET:
   5773         case XPATH_XSLT_TREE:
   5774 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
   5775 	    break;
   5776 	case XPATH_STRING:
   5777 	    return(xmlStrdup(val->stringval));
   5778         case XPATH_BOOLEAN:
   5779 	    ret = xmlXPathCastBooleanToString(val->boolval);
   5780 	    break;
   5781 	case XPATH_NUMBER: {
   5782 	    ret = xmlXPathCastNumberToString(val->floatval);
   5783 	    break;
   5784 	}
   5785 	case XPATH_USERS:
   5786 	case XPATH_POINT:
   5787 	case XPATH_RANGE:
   5788 	case XPATH_LOCATIONSET:
   5789 	    TODO
   5790 	    ret = xmlStrdup((const xmlChar *) "");
   5791 	    break;
   5792     }
   5793     return(ret);
   5794 }
   5795 
   5796 /**
   5797  * xmlXPathConvertString:
   5798  * @val:  an XPath object
   5799  *
   5800  * Converts an existing object to its string() equivalent
   5801  *
   5802  * Returns the new object, the old one is freed (or the operation
   5803  *         is done directly on @val)
   5804  */
   5805 xmlXPathObjectPtr
   5806 xmlXPathConvertString(xmlXPathObjectPtr val) {
   5807     xmlChar *res = NULL;
   5808 
   5809     if (val == NULL)
   5810 	return(xmlXPathNewCString(""));
   5811 
   5812     switch (val->type) {
   5813     case XPATH_UNDEFINED:
   5814 #ifdef DEBUG_EXPR
   5815 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
   5816 #endif
   5817 	break;
   5818     case XPATH_NODESET:
   5819     case XPATH_XSLT_TREE:
   5820 	res = xmlXPathCastNodeSetToString(val->nodesetval);
   5821 	break;
   5822     case XPATH_STRING:
   5823 	return(val);
   5824     case XPATH_BOOLEAN:
   5825 	res = xmlXPathCastBooleanToString(val->boolval);
   5826 	break;
   5827     case XPATH_NUMBER:
   5828 	res = xmlXPathCastNumberToString(val->floatval);
   5829 	break;
   5830     case XPATH_USERS:
   5831     case XPATH_POINT:
   5832     case XPATH_RANGE:
   5833     case XPATH_LOCATIONSET:
   5834 	TODO;
   5835 	break;
   5836     }
   5837     xmlXPathFreeObject(val);
   5838     if (res == NULL)
   5839 	return(xmlXPathNewCString(""));
   5840     return(xmlXPathWrapString(res));
   5841 }
   5842 
   5843 /**
   5844  * xmlXPathCastBooleanToNumber:
   5845  * @val:  a boolean
   5846  *
   5847  * Converts a boolean to its number value
   5848  *
   5849  * Returns the number value
   5850  */
   5851 double
   5852 xmlXPathCastBooleanToNumber(int val) {
   5853     if (val)
   5854 	return(1.0);
   5855     return(0.0);
   5856 }
   5857 
   5858 /**
   5859  * xmlXPathCastStringToNumber:
   5860  * @val:  a string
   5861  *
   5862  * Converts a string to its number value
   5863  *
   5864  * Returns the number value
   5865  */
   5866 double
   5867 xmlXPathCastStringToNumber(const xmlChar * val) {
   5868     return(xmlXPathStringEvalNumber(val));
   5869 }
   5870 
   5871 /**
   5872  * xmlXPathCastNodeToNumber:
   5873  * @node:  a node
   5874  *
   5875  * Converts a node to its number value
   5876  *
   5877  * Returns the number value
   5878  */
   5879 double
   5880 xmlXPathCastNodeToNumber (xmlNodePtr node) {
   5881     xmlChar *strval;
   5882     double ret;
   5883 
   5884     if (node == NULL)
   5885 	return(xmlXPathNAN);
   5886     strval = xmlXPathCastNodeToString(node);
   5887     if (strval == NULL)
   5888 	return(xmlXPathNAN);
   5889     ret = xmlXPathCastStringToNumber(strval);
   5890     xmlFree(strval);
   5891 
   5892     return(ret);
   5893 }
   5894 
   5895 /**
   5896  * xmlXPathCastNodeSetToNumber:
   5897  * @ns:  a node-set
   5898  *
   5899  * Converts a node-set to its number value
   5900  *
   5901  * Returns the number value
   5902  */
   5903 double
   5904 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
   5905     xmlChar *str;
   5906     double ret;
   5907 
   5908     if (ns == NULL)
   5909 	return(xmlXPathNAN);
   5910     str = xmlXPathCastNodeSetToString(ns);
   5911     ret = xmlXPathCastStringToNumber(str);
   5912     xmlFree(str);
   5913     return(ret);
   5914 }
   5915 
   5916 /**
   5917  * xmlXPathCastToNumber:
   5918  * @val:  an XPath object
   5919  *
   5920  * Converts an XPath object to its number value
   5921  *
   5922  * Returns the number value
   5923  */
   5924 double
   5925 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
   5926     double ret = 0.0;
   5927 
   5928     if (val == NULL)
   5929 	return(xmlXPathNAN);
   5930     switch (val->type) {
   5931     case XPATH_UNDEFINED:
   5932 #ifdef DEGUB_EXPR
   5933 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
   5934 #endif
   5935 	ret = xmlXPathNAN;
   5936 	break;
   5937     case XPATH_NODESET:
   5938     case XPATH_XSLT_TREE:
   5939 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
   5940 	break;
   5941     case XPATH_STRING:
   5942 	ret = xmlXPathCastStringToNumber(val->stringval);
   5943 	break;
   5944     case XPATH_NUMBER:
   5945 	ret = val->floatval;
   5946 	break;
   5947     case XPATH_BOOLEAN:
   5948 	ret = xmlXPathCastBooleanToNumber(val->boolval);
   5949 	break;
   5950     case XPATH_USERS:
   5951     case XPATH_POINT:
   5952     case XPATH_RANGE:
   5953     case XPATH_LOCATIONSET:
   5954 	TODO;
   5955 	ret = xmlXPathNAN;
   5956 	break;
   5957     }
   5958     return(ret);
   5959 }
   5960 
   5961 /**
   5962  * xmlXPathConvertNumber:
   5963  * @val:  an XPath object
   5964  *
   5965  * Converts an existing object to its number() equivalent
   5966  *
   5967  * Returns the new object, the old one is freed (or the operation
   5968  *         is done directly on @val)
   5969  */
   5970 xmlXPathObjectPtr
   5971 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
   5972     xmlXPathObjectPtr ret;
   5973 
   5974     if (val == NULL)
   5975 	return(xmlXPathNewFloat(0.0));
   5976     if (val->type == XPATH_NUMBER)
   5977 	return(val);
   5978     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
   5979     xmlXPathFreeObject(val);
   5980     return(ret);
   5981 }
   5982 
   5983 /**
   5984  * xmlXPathCastNumberToBoolean:
   5985  * @val:  a number
   5986  *
   5987  * Converts a number to its boolean value
   5988  *
   5989  * Returns the boolean value
   5990  */
   5991 int
   5992 xmlXPathCastNumberToBoolean (double val) {
   5993      if (xmlXPathIsNaN(val) || (val == 0.0))
   5994 	 return(0);
   5995      return(1);
   5996 }
   5997 
   5998 /**
   5999  * xmlXPathCastStringToBoolean:
   6000  * @val:  a string
   6001  *
   6002  * Converts a string to its boolean value
   6003  *
   6004  * Returns the boolean value
   6005  */
   6006 int
   6007 xmlXPathCastStringToBoolean (const xmlChar *val) {
   6008     if ((val == NULL) || (xmlStrlen(val) == 0))
   6009 	return(0);
   6010     return(1);
   6011 }
   6012 
   6013 /**
   6014  * xmlXPathCastNodeSetToBoolean:
   6015  * @ns:  a node-set
   6016  *
   6017  * Converts a node-set to its boolean value
   6018  *
   6019  * Returns the boolean value
   6020  */
   6021 int
   6022 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
   6023     if ((ns == NULL) || (ns->nodeNr == 0))
   6024 	return(0);
   6025     return(1);
   6026 }
   6027 
   6028 /**
   6029  * xmlXPathCastToBoolean:
   6030  * @val:  an XPath object
   6031  *
   6032  * Converts an XPath object to its boolean value
   6033  *
   6034  * Returns the boolean value
   6035  */
   6036 int
   6037 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
   6038     int ret = 0;
   6039 
   6040     if (val == NULL)
   6041 	return(0);
   6042     switch (val->type) {
   6043     case XPATH_UNDEFINED:
   6044 #ifdef DEBUG_EXPR
   6045 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
   6046 #endif
   6047 	ret = 0;
   6048 	break;
   6049     case XPATH_NODESET:
   6050     case XPATH_XSLT_TREE:
   6051 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
   6052 	break;
   6053     case XPATH_STRING:
   6054 	ret = xmlXPathCastStringToBoolean(val->stringval);
   6055 	break;
   6056     case XPATH_NUMBER:
   6057 	ret = xmlXPathCastNumberToBoolean(val->floatval);
   6058 	break;
   6059     case XPATH_BOOLEAN:
   6060 	ret = val->boolval;
   6061 	break;
   6062     case XPATH_USERS:
   6063     case XPATH_POINT:
   6064     case XPATH_RANGE:
   6065     case XPATH_LOCATIONSET:
   6066 	TODO;
   6067 	ret = 0;
   6068 	break;
   6069     }
   6070     return(ret);
   6071 }
   6072 
   6073 
   6074 /**
   6075  * xmlXPathConvertBoolean:
   6076  * @val:  an XPath object
   6077  *
   6078  * Converts an existing object to its boolean() equivalent
   6079  *
   6080  * Returns the new object, the old one is freed (or the operation
   6081  *         is done directly on @val)
   6082  */
   6083 xmlXPathObjectPtr
   6084 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
   6085     xmlXPathObjectPtr ret;
   6086 
   6087     if (val == NULL)
   6088 	return(xmlXPathNewBoolean(0));
   6089     if (val->type == XPATH_BOOLEAN)
   6090 	return(val);
   6091     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
   6092     xmlXPathFreeObject(val);
   6093     return(ret);
   6094 }
   6095 
   6096 /************************************************************************
   6097  *									*
   6098  *		Routines to handle XPath contexts			*
   6099  *									*
   6100  ************************************************************************/
   6101 
   6102 /**
   6103  * xmlXPathNewContext:
   6104  * @doc:  the XML document
   6105  *
   6106  * Create a new xmlXPathContext
   6107  *
   6108  * Returns the xmlXPathContext just allocated. The caller will need to free it.
   6109  */
   6110 xmlXPathContextPtr
   6111 xmlXPathNewContext(xmlDocPtr doc) {
   6112     xmlXPathContextPtr ret;
   6113 
   6114     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
   6115     if (ret == NULL) {
   6116         xmlXPathErrMemory(NULL, "creating context\n");
   6117 	return(NULL);
   6118     }
   6119     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
   6120     ret->doc = doc;
   6121     ret->node = NULL;
   6122 
   6123     ret->varHash = NULL;
   6124 
   6125     ret->nb_types = 0;
   6126     ret->max_types = 0;
   6127     ret->types = NULL;
   6128 
   6129     ret->funcHash = xmlHashCreate(0);
   6130 
   6131     ret->nb_axis = 0;
   6132     ret->max_axis = 0;
   6133     ret->axis = NULL;
   6134 
   6135     ret->nsHash = NULL;
   6136     ret->user = NULL;
   6137 
   6138     ret->contextSize = -1;
   6139     ret->proximityPosition = -1;
   6140 
   6141 #ifdef XP_DEFAULT_CACHE_ON
   6142     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
   6143 	xmlXPathFreeContext(ret);
   6144 	return(NULL);
   6145     }
   6146 #endif
   6147 
   6148     xmlXPathRegisterAllFunctions(ret);
   6149 
   6150     return(ret);
   6151 }
   6152 
   6153 /**
   6154  * xmlXPathFreeContext:
   6155  * @ctxt:  the context to free
   6156  *
   6157  * Free up an xmlXPathContext
   6158  */
   6159 void
   6160 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
   6161     if (ctxt == NULL) return;
   6162 
   6163     if (ctxt->cache != NULL)
   6164 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
   6165     xmlXPathRegisteredNsCleanup(ctxt);
   6166     xmlXPathRegisteredFuncsCleanup(ctxt);
   6167     xmlXPathRegisteredVariablesCleanup(ctxt);
   6168     xmlResetError(&ctxt->lastError);
   6169     xmlFree(ctxt);
   6170 }
   6171 
   6172 /************************************************************************
   6173  *									*
   6174  *		Routines to handle XPath parser contexts		*
   6175  *									*
   6176  ************************************************************************/
   6177 
   6178 #define CHECK_CTXT(ctxt)						\
   6179     if (ctxt == NULL) {						\
   6180 	__xmlRaiseError(NULL, NULL, NULL,				\
   6181 		NULL, NULL, XML_FROM_XPATH,				\
   6182 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
   6183 		__FILE__, __LINE__,					\
   6184 		NULL, NULL, NULL, 0, 0,					\
   6185 		"NULL context pointer\n");				\
   6186 	return(NULL);							\
   6187     }									\
   6188 
   6189 #define CHECK_CTXT_NEG(ctxt)						\
   6190     if (ctxt == NULL) {						\
   6191 	__xmlRaiseError(NULL, NULL, NULL,				\
   6192 		NULL, NULL, XML_FROM_XPATH,				\
   6193 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
   6194 		__FILE__, __LINE__,					\
   6195 		NULL, NULL, NULL, 0, 0,					\
   6196 		"NULL context pointer\n");				\
   6197 	return(-1);							\
   6198     }									\
   6199 
   6200 
   6201 #define CHECK_CONTEXT(ctxt)						\
   6202     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
   6203         (ctxt->doc->children == NULL)) {				\
   6204 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
   6205 	return(NULL);							\
   6206     }
   6207 
   6208 
   6209 /**
   6210  * xmlXPathNewParserContext:
   6211  * @str:  the XPath expression
   6212  * @ctxt:  the XPath context
   6213  *
   6214  * Create a new xmlXPathParserContext
   6215  *
   6216  * Returns the xmlXPathParserContext just allocated.
   6217  */
   6218 xmlXPathParserContextPtr
   6219 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
   6220     xmlXPathParserContextPtr ret;
   6221 
   6222     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
   6223     if (ret == NULL) {
   6224         xmlXPathErrMemory(ctxt, "creating parser context\n");
   6225 	return(NULL);
   6226     }
   6227     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
   6228     ret->cur = ret->base = str;
   6229     ret->context = ctxt;
   6230 
   6231     ret->comp = xmlXPathNewCompExpr();
   6232     if (ret->comp == NULL) {
   6233 	xmlFree(ret->valueTab);
   6234 	xmlFree(ret);
   6235 	return(NULL);
   6236     }
   6237     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
   6238         ret->comp->dict = ctxt->dict;
   6239 	xmlDictReference(ret->comp->dict);
   6240     }
   6241 
   6242     return(ret);
   6243 }
   6244 
   6245 /**
   6246  * xmlXPathCompParserContext:
   6247  * @comp:  the XPath compiled expression
   6248  * @ctxt:  the XPath context
   6249  *
   6250  * Create a new xmlXPathParserContext when processing a compiled expression
   6251  *
   6252  * Returns the xmlXPathParserContext just allocated.
   6253  */
   6254 static xmlXPathParserContextPtr
   6255 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
   6256     xmlXPathParserContextPtr ret;
   6257 
   6258     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
   6259     if (ret == NULL) {
   6260         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
   6261 	return(NULL);
   6262     }
   6263     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
   6264 
   6265     /* Allocate the value stack */
   6266     ret->valueTab = (xmlXPathObjectPtr *)
   6267                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
   6268     if (ret->valueTab == NULL) {
   6269 	xmlFree(ret);
   6270 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
   6271 	return(NULL);
   6272     }
   6273     ret->valueNr = 0;
   6274     ret->valueMax = 10;
   6275     ret->value = NULL;
   6276     ret->valueFrame = 0;
   6277 
   6278     ret->context = ctxt;
   6279     ret->comp = comp;
   6280 
   6281     return(ret);
   6282 }
   6283 
   6284 /**
   6285  * xmlXPathFreeParserContext:
   6286  * @ctxt:  the context to free
   6287  *
   6288  * Free up an xmlXPathParserContext
   6289  */
   6290 void
   6291 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
   6292     if (ctxt->valueTab != NULL) {
   6293         xmlFree(ctxt->valueTab);
   6294     }
   6295     if (ctxt->comp != NULL) {
   6296 #ifdef XPATH_STREAMING
   6297 	if (ctxt->comp->stream != NULL) {
   6298 	    xmlFreePatternList(ctxt->comp->stream);
   6299 	    ctxt->comp->stream = NULL;
   6300 	}
   6301 #endif
   6302 	xmlXPathFreeCompExpr(ctxt->comp);
   6303     }
   6304     xmlFree(ctxt);
   6305 }
   6306 
   6307 /************************************************************************
   6308  *									*
   6309  *		The implicit core function library			*
   6310  *									*
   6311  ************************************************************************/
   6312 
   6313 /**
   6314  * xmlXPathNodeValHash:
   6315  * @node:  a node pointer
   6316  *
   6317  * Function computing the beginning of the string value of the node,
   6318  * used to speed up comparisons
   6319  *
   6320  * Returns an int usable as a hash
   6321  */
   6322 static unsigned int
   6323 xmlXPathNodeValHash(xmlNodePtr node) {
   6324     int len = 2;
   6325     const xmlChar * string = NULL;
   6326     xmlNodePtr tmp = NULL;
   6327     unsigned int ret = 0;
   6328 
   6329     if (node == NULL)
   6330 	return(0);
   6331 
   6332     if (node->type == XML_DOCUMENT_NODE) {
   6333 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
   6334 	if (tmp == NULL)
   6335 	    node = node->children;
   6336 	else
   6337 	    node = tmp;
   6338 
   6339 	if (node == NULL)
   6340 	    return(0);
   6341     }
   6342 
   6343     switch (node->type) {
   6344 	case XML_COMMENT_NODE:
   6345 	case XML_PI_NODE:
   6346 	case XML_CDATA_SECTION_NODE:
   6347 	case XML_TEXT_NODE:
   6348 	    string = node->content;
   6349 	    if (string == NULL)
   6350 		return(0);
   6351 	    if (string[0] == 0)
   6352 		return(0);
   6353 	    return(((unsigned int) string[0]) +
   6354 		   (((unsigned int) string[1]) << 8));
   6355 	case XML_NAMESPACE_DECL:
   6356 	    string = ((xmlNsPtr)node)->href;
   6357 	    if (string == NULL)
   6358 		return(0);
   6359 	    if (string[0] == 0)
   6360 		return(0);
   6361 	    return(((unsigned int) string[0]) +
   6362 		   (((unsigned int) string[1]) << 8));
   6363 	case XML_ATTRIBUTE_NODE:
   6364 	    tmp = ((xmlAttrPtr) node)->children;
   6365 	    break;
   6366 	case XML_ELEMENT_NODE:
   6367 	    tmp = node->children;
   6368 	    break;
   6369 	default:
   6370 	    return(0);
   6371     }
   6372     while (tmp != NULL) {
   6373 	switch (tmp->type) {
   6374 	    case XML_COMMENT_NODE:
   6375 	    case XML_PI_NODE:
   6376 	    case XML_CDATA_SECTION_NODE:
   6377 	    case XML_TEXT_NODE:
   6378 		string = tmp->content;
   6379 		break;
   6380 	    case XML_NAMESPACE_DECL:
   6381 		string = ((xmlNsPtr)tmp)->href;
   6382 		break;
   6383 	    default:
   6384 		break;
   6385 	}
   6386 	if ((string != NULL) && (string[0] != 0)) {
   6387 	    if (len == 1) {
   6388 		return(ret + (((unsigned int) string[0]) << 8));
   6389 	    }
   6390 	    if (string[1] == 0) {
   6391 		len = 1;
   6392 		ret = (unsigned int) string[0];
   6393 	    } else {
   6394 		return(((unsigned int) string[0]) +
   6395 		       (((unsigned int) string[1]) << 8));
   6396 	    }
   6397 	}
   6398 	/*
   6399 	 * Skip to next node
   6400 	 */
   6401 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
   6402 	    if (tmp->children->type != XML_ENTITY_DECL) {
   6403 		tmp = tmp->children;
   6404 		continue;
   6405 	    }
   6406 	}
   6407 	if (tmp == node)
   6408 	    break;
   6409 
   6410 	if (tmp->next != NULL) {
   6411 	    tmp = tmp->next;
   6412 	    continue;
   6413 	}
   6414 
   6415 	do {
   6416 	    tmp = tmp->parent;
   6417 	    if (tmp == NULL)
   6418 		break;
   6419 	    if (tmp == node) {
   6420 		tmp = NULL;
   6421 		break;
   6422 	    }
   6423 	    if (tmp->next != NULL) {
   6424 		tmp = tmp->next;
   6425 		break;
   6426 	    }
   6427 	} while (tmp != NULL);
   6428     }
   6429     return(ret);
   6430 }
   6431 
   6432 /**
   6433  * xmlXPathStringHash:
   6434  * @string:  a string
   6435  *
   6436  * Function computing the beginning of the string value of the node,
   6437  * used to speed up comparisons
   6438  *
   6439  * Returns an int usable as a hash
   6440  */
   6441 static unsigned int
   6442 xmlXPathStringHash(const xmlChar * string) {
   6443     if (string == NULL)
   6444 	return((unsigned int) 0);
   6445     if (string[0] == 0)
   6446 	return(0);
   6447     return(((unsigned int) string[0]) +
   6448 	   (((unsigned int) string[1]) << 8));
   6449 }
   6450 
   6451 /**
   6452  * xmlXPathCompareNodeSetFloat:
   6453  * @ctxt:  the XPath Parser context
   6454  * @inf:  less than (1) or greater than (0)
   6455  * @strict:  is the comparison strict
   6456  * @arg:  the node set
   6457  * @f:  the value
   6458  *
   6459  * Implement the compare operation between a nodeset and a number
   6460  *     @ns < @val    (1, 1, ...
   6461  *     @ns <= @val   (1, 0, ...
   6462  *     @ns > @val    (0, 1, ...
   6463  *     @ns >= @val   (0, 0, ...
   6464  *
   6465  * If one object to be compared is a node-set and the other is a number,
   6466  * then the comparison will be true if and only if there is a node in the
   6467  * node-set such that the result of performing the comparison on the number
   6468  * to be compared and on the result of converting the string-value of that
   6469  * node to a number using the number function is true.
   6470  *
   6471  * Returns 0 or 1 depending on the results of the test.
   6472  */
   6473 static int
   6474 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6475 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
   6476     int i, ret = 0;
   6477     xmlNodeSetPtr ns;
   6478     xmlChar *str2;
   6479 
   6480     if ((f == NULL) || (arg == NULL) ||
   6481 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
   6482 	xmlXPathReleaseObject(ctxt->context, arg);
   6483 	xmlXPathReleaseObject(ctxt->context, f);
   6484         return(0);
   6485     }
   6486     ns = arg->nodesetval;
   6487     if (ns != NULL) {
   6488 	for (i = 0;i < ns->nodeNr;i++) {
   6489 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6490 	     if (str2 != NULL) {
   6491 		 valuePush(ctxt,
   6492 			   xmlXPathCacheNewString(ctxt->context, str2));
   6493 		 xmlFree(str2);
   6494 		 xmlXPathNumberFunction(ctxt, 1);
   6495 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
   6496 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
   6497 		 if (ret)
   6498 		     break;
   6499 	     }
   6500 	}
   6501     }
   6502     xmlXPathReleaseObject(ctxt->context, arg);
   6503     xmlXPathReleaseObject(ctxt->context, f);
   6504     return(ret);
   6505 }
   6506 
   6507 /**
   6508  * xmlXPathCompareNodeSetString:
   6509  * @ctxt:  the XPath Parser context
   6510  * @inf:  less than (1) or greater than (0)
   6511  * @strict:  is the comparison strict
   6512  * @arg:  the node set
   6513  * @s:  the value
   6514  *
   6515  * Implement the compare operation between a nodeset and a string
   6516  *     @ns < @val    (1, 1, ...
   6517  *     @ns <= @val   (1, 0, ...
   6518  *     @ns > @val    (0, 1, ...
   6519  *     @ns >= @val   (0, 0, ...
   6520  *
   6521  * If one object to be compared is a node-set and the other is a string,
   6522  * then the comparison will be true if and only if there is a node in
   6523  * the node-set such that the result of performing the comparison on the
   6524  * string-value of the node and the other string is true.
   6525  *
   6526  * Returns 0 or 1 depending on the results of the test.
   6527  */
   6528 static int
   6529 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6530 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
   6531     int i, ret = 0;
   6532     xmlNodeSetPtr ns;
   6533     xmlChar *str2;
   6534 
   6535     if ((s == NULL) || (arg == NULL) ||
   6536 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
   6537 	xmlXPathReleaseObject(ctxt->context, arg);
   6538 	xmlXPathReleaseObject(ctxt->context, s);
   6539         return(0);
   6540     }
   6541     ns = arg->nodesetval;
   6542     if (ns != NULL) {
   6543 	for (i = 0;i < ns->nodeNr;i++) {
   6544 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6545 	     if (str2 != NULL) {
   6546 		 valuePush(ctxt,
   6547 			   xmlXPathCacheNewString(ctxt->context, str2));
   6548 		 xmlFree(str2);
   6549 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
   6550 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
   6551 		 if (ret)
   6552 		     break;
   6553 	     }
   6554 	}
   6555     }
   6556     xmlXPathReleaseObject(ctxt->context, arg);
   6557     xmlXPathReleaseObject(ctxt->context, s);
   6558     return(ret);
   6559 }
   6560 
   6561 /**
   6562  * xmlXPathCompareNodeSets:
   6563  * @inf:  less than (1) or greater than (0)
   6564  * @strict:  is the comparison strict
   6565  * @arg1:  the first node set object
   6566  * @arg2:  the second node set object
   6567  *
   6568  * Implement the compare operation on nodesets:
   6569  *
   6570  * If both objects to be compared are node-sets, then the comparison
   6571  * will be true if and only if there is a node in the first node-set
   6572  * and a node in the second node-set such that the result of performing
   6573  * the comparison on the string-values of the two nodes is true.
   6574  * ....
   6575  * When neither object to be compared is a node-set and the operator
   6576  * is <=, <, >= or >, then the objects are compared by converting both
   6577  * objects to numbers and comparing the numbers according to IEEE 754.
   6578  * ....
   6579  * The number function converts its argument to a number as follows:
   6580  *  - a string that consists of optional whitespace followed by an
   6581  *    optional minus sign followed by a Number followed by whitespace
   6582  *    is converted to the IEEE 754 number that is nearest (according
   6583  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
   6584  *    represented by the string; any other string is converted to NaN
   6585  *
   6586  * Conclusion all nodes need to be converted first to their string value
   6587  * and then the comparison must be done when possible
   6588  */
   6589 static int
   6590 xmlXPathCompareNodeSets(int inf, int strict,
   6591 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
   6592     int i, j, init = 0;
   6593     double val1;
   6594     double *values2;
   6595     int ret = 0;
   6596     xmlNodeSetPtr ns1;
   6597     xmlNodeSetPtr ns2;
   6598 
   6599     if ((arg1 == NULL) ||
   6600 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
   6601 	xmlXPathFreeObject(arg2);
   6602         return(0);
   6603     }
   6604     if ((arg2 == NULL) ||
   6605 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
   6606 	xmlXPathFreeObject(arg1);
   6607 	xmlXPathFreeObject(arg2);
   6608         return(0);
   6609     }
   6610 
   6611     ns1 = arg1->nodesetval;
   6612     ns2 = arg2->nodesetval;
   6613 
   6614     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
   6615 	xmlXPathFreeObject(arg1);
   6616 	xmlXPathFreeObject(arg2);
   6617 	return(0);
   6618     }
   6619     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
   6620 	xmlXPathFreeObject(arg1);
   6621 	xmlXPathFreeObject(arg2);
   6622 	return(0);
   6623     }
   6624 
   6625     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
   6626     if (values2 == NULL) {
   6627         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6628 	xmlXPathFreeObject(arg1);
   6629 	xmlXPathFreeObject(arg2);
   6630 	return(0);
   6631     }
   6632     for (i = 0;i < ns1->nodeNr;i++) {
   6633 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
   6634 	if (xmlXPathIsNaN(val1))
   6635 	    continue;
   6636 	for (j = 0;j < ns2->nodeNr;j++) {
   6637 	    if (init == 0) {
   6638 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
   6639 	    }
   6640 	    if (xmlXPathIsNaN(values2[j]))
   6641 		continue;
   6642 	    if (inf && strict)
   6643 		ret = (val1 < values2[j]);
   6644 	    else if (inf && !strict)
   6645 		ret = (val1 <= values2[j]);
   6646 	    else if (!inf && strict)
   6647 		ret = (val1 > values2[j]);
   6648 	    else if (!inf && !strict)
   6649 		ret = (val1 >= values2[j]);
   6650 	    if (ret)
   6651 		break;
   6652 	}
   6653 	if (ret)
   6654 	    break;
   6655 	init = 1;
   6656     }
   6657     xmlFree(values2);
   6658     xmlXPathFreeObject(arg1);
   6659     xmlXPathFreeObject(arg2);
   6660     return(ret);
   6661 }
   6662 
   6663 /**
   6664  * xmlXPathCompareNodeSetValue:
   6665  * @ctxt:  the XPath Parser context
   6666  * @inf:  less than (1) or greater than (0)
   6667  * @strict:  is the comparison strict
   6668  * @arg:  the node set
   6669  * @val:  the value
   6670  *
   6671  * Implement the compare operation between a nodeset and a value
   6672  *     @ns < @val    (1, 1, ...
   6673  *     @ns <= @val   (1, 0, ...
   6674  *     @ns > @val    (0, 1, ...
   6675  *     @ns >= @val   (0, 0, ...
   6676  *
   6677  * If one object to be compared is a node-set and the other is a boolean,
   6678  * then the comparison will be true if and only if the result of performing
   6679  * the comparison on the boolean and on the result of converting
   6680  * the node-set to a boolean using the boolean function is true.
   6681  *
   6682  * Returns 0 or 1 depending on the results of the test.
   6683  */
   6684 static int
   6685 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6686 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
   6687     if ((val == NULL) || (arg == NULL) ||
   6688 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6689         return(0);
   6690 
   6691     switch(val->type) {
   6692         case XPATH_NUMBER:
   6693 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
   6694         case XPATH_NODESET:
   6695         case XPATH_XSLT_TREE:
   6696 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
   6697         case XPATH_STRING:
   6698 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
   6699         case XPATH_BOOLEAN:
   6700 	    valuePush(ctxt, arg);
   6701 	    xmlXPathBooleanFunction(ctxt, 1);
   6702 	    valuePush(ctxt, val);
   6703 	    return(xmlXPathCompareValues(ctxt, inf, strict));
   6704 	default:
   6705 	    TODO
   6706     }
   6707     return(0);
   6708 }
   6709 
   6710 /**
   6711  * xmlXPathEqualNodeSetString:
   6712  * @arg:  the nodeset object argument
   6713  * @str:  the string to compare to.
   6714  * @neq:  flag to show whether for '=' (0) or '!=' (1)
   6715  *
   6716  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   6717  * If one object to be compared is a node-set and the other is a string,
   6718  * then the comparison will be true if and only if there is a node in
   6719  * the node-set such that the result of performing the comparison on the
   6720  * string-value of the node and the other string is true.
   6721  *
   6722  * Returns 0 or 1 depending on the results of the test.
   6723  */
   6724 static int
   6725 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
   6726 {
   6727     int i;
   6728     xmlNodeSetPtr ns;
   6729     xmlChar *str2;
   6730     unsigned int hash;
   6731 
   6732     if ((str == NULL) || (arg == NULL) ||
   6733         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6734         return (0);
   6735     ns = arg->nodesetval;
   6736     /*
   6737      * A NULL nodeset compared with a string is always false
   6738      * (since there is no node equal, and no node not equal)
   6739      */
   6740     if ((ns == NULL) || (ns->nodeNr <= 0) )
   6741         return (0);
   6742     hash = xmlXPathStringHash(str);
   6743     for (i = 0; i < ns->nodeNr; i++) {
   6744         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
   6745             str2 = xmlNodeGetContent(ns->nodeTab[i]);
   6746             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
   6747                 xmlFree(str2);
   6748 		if (neq)
   6749 		    continue;
   6750                 return (1);
   6751 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
   6752 		if (neq)
   6753 		    continue;
   6754                 return (1);
   6755             } else if (neq) {
   6756 		if (str2 != NULL)
   6757 		    xmlFree(str2);
   6758 		return (1);
   6759 	    }
   6760             if (str2 != NULL)
   6761                 xmlFree(str2);
   6762         } else if (neq)
   6763 	    return (1);
   6764     }
   6765     return (0);
   6766 }
   6767 
   6768 /**
   6769  * xmlXPathEqualNodeSetFloat:
   6770  * @arg:  the nodeset object argument
   6771  * @f:  the float to compare to
   6772  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
   6773  *
   6774  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   6775  * If one object to be compared is a node-set and the other is a number,
   6776  * then the comparison will be true if and only if there is a node in
   6777  * the node-set such that the result of performing the comparison on the
   6778  * number to be compared and on the result of converting the string-value
   6779  * of that node to a number using the number function is true.
   6780  *
   6781  * Returns 0 or 1 depending on the results of the test.
   6782  */
   6783 static int
   6784 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
   6785     xmlXPathObjectPtr arg, double f, int neq) {
   6786   int i, ret=0;
   6787   xmlNodeSetPtr ns;
   6788   xmlChar *str2;
   6789   xmlXPathObjectPtr val;
   6790   double v;
   6791 
   6792     if ((arg == NULL) ||
   6793 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6794         return(0);
   6795 
   6796     ns = arg->nodesetval;
   6797     if (ns != NULL) {
   6798 	for (i=0;i<ns->nodeNr;i++) {
   6799 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6800 	    if (str2 != NULL) {
   6801 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
   6802 		xmlFree(str2);
   6803 		xmlXPathNumberFunction(ctxt, 1);
   6804 		val = valuePop(ctxt);
   6805 		v = val->floatval;
   6806 		xmlXPathReleaseObject(ctxt->context, val);
   6807 		if (!xmlXPathIsNaN(v)) {
   6808 		    if ((!neq) && (v==f)) {
   6809 			ret = 1;
   6810 			break;
   6811 		    } else if ((neq) && (v!=f)) {
   6812 			ret = 1;
   6813 			break;
   6814 		    }
   6815 		} else {	/* NaN is unequal to any value */
   6816 		    if (neq)
   6817 			ret = 1;
   6818 		}
   6819 	    }
   6820 	}
   6821     }
   6822 
   6823     return(ret);
   6824 }
   6825 
   6826 
   6827 /**
   6828  * xmlXPathEqualNodeSets:
   6829  * @arg1:  first nodeset object argument
   6830  * @arg2:  second nodeset object argument
   6831  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
   6832  *
   6833  * Implement the equal / not equal operation on XPath nodesets:
   6834  * @arg1 == @arg2  or  @arg1 != @arg2
   6835  * If both objects to be compared are node-sets, then the comparison
   6836  * will be true if and only if there is a node in the first node-set and
   6837  * a node in the second node-set such that the result of performing the
   6838  * comparison on the string-values of the two nodes is true.
   6839  *
   6840  * (needless to say, this is a costly operation)
   6841  *
   6842  * Returns 0 or 1 depending on the results of the test.
   6843  */
   6844 static int
   6845 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
   6846     int i, j;
   6847     unsigned int *hashs1;
   6848     unsigned int *hashs2;
   6849     xmlChar **values1;
   6850     xmlChar **values2;
   6851     int ret = 0;
   6852     xmlNodeSetPtr ns1;
   6853     xmlNodeSetPtr ns2;
   6854 
   6855     if ((arg1 == NULL) ||
   6856 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
   6857         return(0);
   6858     if ((arg2 == NULL) ||
   6859 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
   6860         return(0);
   6861 
   6862     ns1 = arg1->nodesetval;
   6863     ns2 = arg2->nodesetval;
   6864 
   6865     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
   6866 	return(0);
   6867     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
   6868 	return(0);
   6869 
   6870     /*
   6871      * for equal, check if there is a node pertaining to both sets
   6872      */
   6873     if (neq == 0)
   6874 	for (i = 0;i < ns1->nodeNr;i++)
   6875 	    for (j = 0;j < ns2->nodeNr;j++)
   6876 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
   6877 		    return(1);
   6878 
   6879     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
   6880     if (values1 == NULL) {
   6881         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6882 	return(0);
   6883     }
   6884     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
   6885     if (hashs1 == NULL) {
   6886         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6887 	xmlFree(values1);
   6888 	return(0);
   6889     }
   6890     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
   6891     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
   6892     if (values2 == NULL) {
   6893         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6894 	xmlFree(hashs1);
   6895 	xmlFree(values1);
   6896 	return(0);
   6897     }
   6898     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
   6899     if (hashs2 == NULL) {
   6900         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6901 	xmlFree(hashs1);
   6902 	xmlFree(values1);
   6903 	xmlFree(values2);
   6904 	return(0);
   6905     }
   6906     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
   6907     for (i = 0;i < ns1->nodeNr;i++) {
   6908 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
   6909 	for (j = 0;j < ns2->nodeNr;j++) {
   6910 	    if (i == 0)
   6911 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
   6912 	    if (hashs1[i] != hashs2[j]) {
   6913 		if (neq) {
   6914 		    ret = 1;
   6915 		    break;
   6916 		}
   6917 	    }
   6918 	    else {
   6919 		if (values1[i] == NULL)
   6920 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
   6921 		if (values2[j] == NULL)
   6922 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
   6923 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
   6924 		if (ret)
   6925 		    break;
   6926 	    }
   6927 	}
   6928 	if (ret)
   6929 	    break;
   6930     }
   6931     for (i = 0;i < ns1->nodeNr;i++)
   6932 	if (values1[i] != NULL)
   6933 	    xmlFree(values1[i]);
   6934     for (j = 0;j < ns2->nodeNr;j++)
   6935 	if (values2[j] != NULL)
   6936 	    xmlFree(values2[j]);
   6937     xmlFree(values1);
   6938     xmlFree(values2);
   6939     xmlFree(hashs1);
   6940     xmlFree(hashs2);
   6941     return(ret);
   6942 }
   6943 
   6944 static int
   6945 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
   6946   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
   6947     int ret = 0;
   6948     /*
   6949      *At this point we are assured neither arg1 nor arg2
   6950      *is a nodeset, so we can just pick the appropriate routine.
   6951      */
   6952     switch (arg1->type) {
   6953         case XPATH_UNDEFINED:
   6954 #ifdef DEBUG_EXPR
   6955 	    xmlGenericError(xmlGenericErrorContext,
   6956 		    "Equal: undefined\n");
   6957 #endif
   6958 	    break;
   6959         case XPATH_BOOLEAN:
   6960 	    switch (arg2->type) {
   6961 	        case XPATH_UNDEFINED:
   6962 #ifdef DEBUG_EXPR
   6963 		    xmlGenericError(xmlGenericErrorContext,
   6964 			    "Equal: undefined\n");
   6965 #endif
   6966 		    break;
   6967 		case XPATH_BOOLEAN:
   6968 #ifdef DEBUG_EXPR
   6969 		    xmlGenericError(xmlGenericErrorContext,
   6970 			    "Equal: %d boolean %d \n",
   6971 			    arg1->boolval, arg2->boolval);
   6972 #endif
   6973 		    ret = (arg1->boolval == arg2->boolval);
   6974 		    break;
   6975 		case XPATH_NUMBER:
   6976 		    ret = (arg1->boolval ==
   6977 			   xmlXPathCastNumberToBoolean(arg2->floatval));
   6978 		    break;
   6979 		case XPATH_STRING:
   6980 		    if ((arg2->stringval == NULL) ||
   6981 			(arg2->stringval[0] == 0)) ret = 0;
   6982 		    else
   6983 			ret = 1;
   6984 		    ret = (arg1->boolval == ret);
   6985 		    break;
   6986 		case XPATH_USERS:
   6987 		case XPATH_POINT:
   6988 		case XPATH_RANGE:
   6989 		case XPATH_LOCATIONSET:
   6990 		    TODO
   6991 		    break;
   6992 		case XPATH_NODESET:
   6993 		case XPATH_XSLT_TREE:
   6994 		    break;
   6995 	    }
   6996 	    break;
   6997         case XPATH_NUMBER:
   6998 	    switch (arg2->type) {
   6999 	        case XPATH_UNDEFINED:
   7000 #ifdef DEBUG_EXPR
   7001 		    xmlGenericError(xmlGenericErrorContext,
   7002 			    "Equal: undefined\n");
   7003 #endif
   7004 		    break;
   7005 		case XPATH_BOOLEAN:
   7006 		    ret = (arg2->boolval==
   7007 			   xmlXPathCastNumberToBoolean(arg1->floatval));
   7008 		    break;
   7009 		case XPATH_STRING:
   7010 		    valuePush(ctxt, arg2);
   7011 		    xmlXPathNumberFunction(ctxt, 1);
   7012 		    arg2 = valuePop(ctxt);
   7013 		    /* no break on purpose */
   7014 		case XPATH_NUMBER:
   7015 		    /* Hand check NaN and Infinity equalities */
   7016 		    if (xmlXPathIsNaN(arg1->floatval) ||
   7017 			    xmlXPathIsNaN(arg2->floatval)) {
   7018 		        ret = 0;
   7019 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
   7020 		        if (xmlXPathIsInf(arg2->floatval) == 1)
   7021 			    ret = 1;
   7022 			else
   7023 			    ret = 0;
   7024 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
   7025 			if (xmlXPathIsInf(arg2->floatval) == -1)
   7026 			    ret = 1;
   7027 			else
   7028 			    ret = 0;
   7029 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
   7030 			if (xmlXPathIsInf(arg1->floatval) == 1)
   7031 			    ret = 1;
   7032 			else
   7033 			    ret = 0;
   7034 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
   7035 			if (xmlXPathIsInf(arg1->floatval) == -1)
   7036 			    ret = 1;
   7037 			else
   7038 			    ret = 0;
   7039 		    } else {
   7040 		        ret = (arg1->floatval == arg2->floatval);
   7041 		    }
   7042 		    break;
   7043 		case XPATH_USERS:
   7044 		case XPATH_POINT:
   7045 		case XPATH_RANGE:
   7046 		case XPATH_LOCATIONSET:
   7047 		    TODO
   7048 		    break;
   7049 		case XPATH_NODESET:
   7050 		case XPATH_XSLT_TREE:
   7051 		    break;
   7052 	    }
   7053 	    break;
   7054         case XPATH_STRING:
   7055 	    switch (arg2->type) {
   7056 	        case XPATH_UNDEFINED:
   7057 #ifdef DEBUG_EXPR
   7058 		    xmlGenericError(xmlGenericErrorContext,
   7059 			    "Equal: undefined\n");
   7060 #endif
   7061 		    break;
   7062 		case XPATH_BOOLEAN:
   7063 		    if ((arg1->stringval == NULL) ||
   7064 			(arg1->stringval[0] == 0)) ret = 0;
   7065 		    else
   7066 			ret = 1;
   7067 		    ret = (arg2->boolval == ret);
   7068 		    break;
   7069 		case XPATH_STRING:
   7070 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
   7071 		    break;
   7072 		case XPATH_NUMBER:
   7073 		    valuePush(ctxt, arg1);
   7074 		    xmlXPathNumberFunction(ctxt, 1);
   7075 		    arg1 = valuePop(ctxt);
   7076 		    /* Hand check NaN and Infinity equalities */
   7077 		    if (xmlXPathIsNaN(arg1->floatval) ||
   7078 			    xmlXPathIsNaN(arg2->floatval)) {
   7079 		        ret = 0;
   7080 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
   7081 			if (xmlXPathIsInf(arg2->floatval) == 1)
   7082 			    ret = 1;
   7083 			else
   7084 			    ret = 0;
   7085 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
   7086 			if (xmlXPathIsInf(arg2->floatval) == -1)
   7087 			    ret = 1;
   7088 			else
   7089 			    ret = 0;
   7090 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
   7091 			if (xmlXPathIsInf(arg1->floatval) == 1)
   7092 			    ret = 1;
   7093 			else
   7094 			    ret = 0;
   7095 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
   7096 			if (xmlXPathIsInf(arg1->floatval) == -1)
   7097 			    ret = 1;
   7098 			else
   7099 			    ret = 0;
   7100 		    } else {
   7101 		        ret = (arg1->floatval == arg2->floatval);
   7102 		    }
   7103 		    break;
   7104 		case XPATH_USERS:
   7105 		case XPATH_POINT:
   7106 		case XPATH_RANGE:
   7107 		case XPATH_LOCATIONSET:
   7108 		    TODO
   7109 		    break;
   7110 		case XPATH_NODESET:
   7111 		case XPATH_XSLT_TREE:
   7112 		    break;
   7113 	    }
   7114 	    break;
   7115         case XPATH_USERS:
   7116 	case XPATH_POINT:
   7117 	case XPATH_RANGE:
   7118 	case XPATH_LOCATIONSET:
   7119 	    TODO
   7120 	    break;
   7121 	case XPATH_NODESET:
   7122 	case XPATH_XSLT_TREE:
   7123 	    break;
   7124     }
   7125     xmlXPathReleaseObject(ctxt->context, arg1);
   7126     xmlXPathReleaseObject(ctxt->context, arg2);
   7127     return(ret);
   7128 }
   7129 
   7130 /**
   7131  * xmlXPathEqualValues:
   7132  * @ctxt:  the XPath Parser context
   7133  *
   7134  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   7135  *
   7136  * Returns 0 or 1 depending on the results of the test.
   7137  */
   7138 int
   7139 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
   7140     xmlXPathObjectPtr arg1, arg2, argtmp;
   7141     int ret = 0;
   7142 
   7143     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7144     arg2 = valuePop(ctxt);
   7145     arg1 = valuePop(ctxt);
   7146     if ((arg1 == NULL) || (arg2 == NULL)) {
   7147 	if (arg1 != NULL)
   7148 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7149 	else
   7150 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7151 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7152     }
   7153 
   7154     if (arg1 == arg2) {
   7155 #ifdef DEBUG_EXPR
   7156         xmlGenericError(xmlGenericErrorContext,
   7157 		"Equal: by pointer\n");
   7158 #endif
   7159 	xmlXPathFreeObject(arg1);
   7160         return(1);
   7161     }
   7162 
   7163     /*
   7164      *If either argument is a nodeset, it's a 'special case'
   7165      */
   7166     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7167       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7168 	/*
   7169 	 *Hack it to assure arg1 is the nodeset
   7170 	 */
   7171 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
   7172 		argtmp = arg2;
   7173 		arg2 = arg1;
   7174 		arg1 = argtmp;
   7175 	}
   7176 	switch (arg2->type) {
   7177 	    case XPATH_UNDEFINED:
   7178 #ifdef DEBUG_EXPR
   7179 		xmlGenericError(xmlGenericErrorContext,
   7180 			"Equal: undefined\n");
   7181 #endif
   7182 		break;
   7183 	    case XPATH_NODESET:
   7184 	    case XPATH_XSLT_TREE:
   7185 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
   7186 		break;
   7187 	    case XPATH_BOOLEAN:
   7188 		if ((arg1->nodesetval == NULL) ||
   7189 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
   7190 		else
   7191 		    ret = 1;
   7192 		ret = (ret == arg2->boolval);
   7193 		break;
   7194 	    case XPATH_NUMBER:
   7195 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
   7196 		break;
   7197 	    case XPATH_STRING:
   7198 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
   7199 		break;
   7200 	    case XPATH_USERS:
   7201 	    case XPATH_POINT:
   7202 	    case XPATH_RANGE:
   7203 	    case XPATH_LOCATIONSET:
   7204 		TODO
   7205 		break;
   7206 	}
   7207 	xmlXPathReleaseObject(ctxt->context, arg1);
   7208 	xmlXPathReleaseObject(ctxt->context, arg2);
   7209 	return(ret);
   7210     }
   7211 
   7212     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
   7213 }
   7214 
   7215 /**
   7216  * xmlXPathNotEqualValues:
   7217  * @ctxt:  the XPath Parser context
   7218  *
   7219  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   7220  *
   7221  * Returns 0 or 1 depending on the results of the test.
   7222  */
   7223 int
   7224 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
   7225     xmlXPathObjectPtr arg1, arg2, argtmp;
   7226     int ret = 0;
   7227 
   7228     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7229     arg2 = valuePop(ctxt);
   7230     arg1 = valuePop(ctxt);
   7231     if ((arg1 == NULL) || (arg2 == NULL)) {
   7232 	if (arg1 != NULL)
   7233 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7234 	else
   7235 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7236 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7237     }
   7238 
   7239     if (arg1 == arg2) {
   7240 #ifdef DEBUG_EXPR
   7241         xmlGenericError(xmlGenericErrorContext,
   7242 		"NotEqual: by pointer\n");
   7243 #endif
   7244 	xmlXPathReleaseObject(ctxt->context, arg1);
   7245         return(0);
   7246     }
   7247 
   7248     /*
   7249      *If either argument is a nodeset, it's a 'special case'
   7250      */
   7251     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7252       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7253 	/*
   7254 	 *Hack it to assure arg1 is the nodeset
   7255 	 */
   7256 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
   7257 		argtmp = arg2;
   7258 		arg2 = arg1;
   7259 		arg1 = argtmp;
   7260 	}
   7261 	switch (arg2->type) {
   7262 	    case XPATH_UNDEFINED:
   7263 #ifdef DEBUG_EXPR
   7264 		xmlGenericError(xmlGenericErrorContext,
   7265 			"NotEqual: undefined\n");
   7266 #endif
   7267 		break;
   7268 	    case XPATH_NODESET:
   7269 	    case XPATH_XSLT_TREE:
   7270 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
   7271 		break;
   7272 	    case XPATH_BOOLEAN:
   7273 		if ((arg1->nodesetval == NULL) ||
   7274 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
   7275 		else
   7276 		    ret = 1;
   7277 		ret = (ret != arg2->boolval);
   7278 		break;
   7279 	    case XPATH_NUMBER:
   7280 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
   7281 		break;
   7282 	    case XPATH_STRING:
   7283 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
   7284 		break;
   7285 	    case XPATH_USERS:
   7286 	    case XPATH_POINT:
   7287 	    case XPATH_RANGE:
   7288 	    case XPATH_LOCATIONSET:
   7289 		TODO
   7290 		break;
   7291 	}
   7292 	xmlXPathReleaseObject(ctxt->context, arg1);
   7293 	xmlXPathReleaseObject(ctxt->context, arg2);
   7294 	return(ret);
   7295     }
   7296 
   7297     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
   7298 }
   7299 
   7300 /**
   7301  * xmlXPathCompareValues:
   7302  * @ctxt:  the XPath Parser context
   7303  * @inf:  less than (1) or greater than (0)
   7304  * @strict:  is the comparison strict
   7305  *
   7306  * Implement the compare operation on XPath objects:
   7307  *     @arg1 < @arg2    (1, 1, ...
   7308  *     @arg1 <= @arg2   (1, 0, ...
   7309  *     @arg1 > @arg2    (0, 1, ...
   7310  *     @arg1 >= @arg2   (0, 0, ...
   7311  *
   7312  * When neither object to be compared is a node-set and the operator is
   7313  * <=, <, >=, >, then the objects are compared by converted both objects
   7314  * to numbers and comparing the numbers according to IEEE 754. The <
   7315  * comparison will be true if and only if the first number is less than the
   7316  * second number. The <= comparison will be true if and only if the first
   7317  * number is less than or equal to the second number. The > comparison
   7318  * will be true if and only if the first number is greater than the second
   7319  * number. The >= comparison will be true if and only if the first number
   7320  * is greater than or equal to the second number.
   7321  *
   7322  * Returns 1 if the comparison succeeded, 0 if it failed
   7323  */
   7324 int
   7325 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
   7326     int ret = 0, arg1i = 0, arg2i = 0;
   7327     xmlXPathObjectPtr arg1, arg2;
   7328 
   7329     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7330     arg2 = valuePop(ctxt);
   7331     arg1 = valuePop(ctxt);
   7332     if ((arg1 == NULL) || (arg2 == NULL)) {
   7333 	if (arg1 != NULL)
   7334 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7335 	else
   7336 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7337 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7338     }
   7339 
   7340     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7341       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7342 	/*
   7343 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
   7344 	 * are not freed from within this routine; they will be freed from the
   7345 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
   7346 	 */
   7347 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
   7348 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
   7349 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
   7350 	} else {
   7351 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7352 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
   7353 			                          arg1, arg2);
   7354 	    } else {
   7355 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
   7356 			                          arg2, arg1);
   7357 	    }
   7358 	}
   7359 	return(ret);
   7360     }
   7361 
   7362     if (arg1->type != XPATH_NUMBER) {
   7363 	valuePush(ctxt, arg1);
   7364 	xmlXPathNumberFunction(ctxt, 1);
   7365 	arg1 = valuePop(ctxt);
   7366     }
   7367     if (arg1->type != XPATH_NUMBER) {
   7368 	xmlXPathFreeObject(arg1);
   7369 	xmlXPathFreeObject(arg2);
   7370 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7371     }
   7372     if (arg2->type != XPATH_NUMBER) {
   7373 	valuePush(ctxt, arg2);
   7374 	xmlXPathNumberFunction(ctxt, 1);
   7375 	arg2 = valuePop(ctxt);
   7376     }
   7377     if (arg2->type != XPATH_NUMBER) {
   7378 	xmlXPathReleaseObject(ctxt->context, arg1);
   7379 	xmlXPathReleaseObject(ctxt->context, arg2);
   7380 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7381     }
   7382     /*
   7383      * Add tests for infinity and nan
   7384      * => feedback on 3.4 for Inf and NaN
   7385      */
   7386     /* Hand check NaN and Infinity comparisons */
   7387     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
   7388 	ret=0;
   7389     } else {
   7390 	arg1i=xmlXPathIsInf(arg1->floatval);
   7391 	arg2i=xmlXPathIsInf(arg2->floatval);
   7392 	if (inf && strict) {
   7393 	    if ((arg1i == -1 && arg2i != -1) ||
   7394 		(arg2i == 1 && arg1i != 1)) {
   7395 		ret = 1;
   7396 	    } else if (arg1i == 0 && arg2i == 0) {
   7397 		ret = (arg1->floatval < arg2->floatval);
   7398 	    } else {
   7399 		ret = 0;
   7400 	    }
   7401 	}
   7402 	else if (inf && !strict) {
   7403 	    if (arg1i == -1 || arg2i == 1) {
   7404 		ret = 1;
   7405 	    } else if (arg1i == 0 && arg2i == 0) {
   7406 		ret = (arg1->floatval <= arg2->floatval);
   7407 	    } else {
   7408 		ret = 0;
   7409 	    }
   7410 	}
   7411 	else if (!inf && strict) {
   7412 	    if ((arg1i == 1 && arg2i != 1) ||
   7413 		(arg2i == -1 && arg1i != -1)) {
   7414 		ret = 1;
   7415 	    } else if (arg1i == 0 && arg2i == 0) {
   7416 		ret = (arg1->floatval > arg2->floatval);
   7417 	    } else {
   7418 		ret = 0;
   7419 	    }
   7420 	}
   7421 	else if (!inf && !strict) {
   7422 	    if (arg1i == 1 || arg2i == -1) {
   7423 		ret = 1;
   7424 	    } else if (arg1i == 0 && arg2i == 0) {
   7425 		ret = (arg1->floatval >= arg2->floatval);
   7426 	    } else {
   7427 		ret = 0;
   7428 	    }
   7429 	}
   7430     }
   7431     xmlXPathReleaseObject(ctxt->context, arg1);
   7432     xmlXPathReleaseObject(ctxt->context, arg2);
   7433     return(ret);
   7434 }
   7435 
   7436 /**
   7437  * xmlXPathValueFlipSign:
   7438  * @ctxt:  the XPath Parser context
   7439  *
   7440  * Implement the unary - operation on an XPath object
   7441  * The numeric operators convert their operands to numbers as if
   7442  * by calling the number function.
   7443  */
   7444 void
   7445 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
   7446     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
   7447     CAST_TO_NUMBER;
   7448     CHECK_TYPE(XPATH_NUMBER);
   7449     if (xmlXPathIsNaN(ctxt->value->floatval))
   7450         ctxt->value->floatval=xmlXPathNAN;
   7451     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
   7452         ctxt->value->floatval=xmlXPathNINF;
   7453     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
   7454         ctxt->value->floatval=xmlXPathPINF;
   7455     else if (ctxt->value->floatval == 0) {
   7456         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
   7457 	    ctxt->value->floatval = xmlXPathNZERO;
   7458 	else
   7459 	    ctxt->value->floatval = 0;
   7460     }
   7461     else
   7462         ctxt->value->floatval = - ctxt->value->floatval;
   7463 }
   7464 
   7465 /**
   7466  * xmlXPathAddValues:
   7467  * @ctxt:  the XPath Parser context
   7468  *
   7469  * Implement the add operation on XPath objects:
   7470  * The numeric operators convert their operands to numbers as if
   7471  * by calling the number function.
   7472  */
   7473 void
   7474 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
   7475     xmlXPathObjectPtr arg;
   7476     double val;
   7477 
   7478     arg = valuePop(ctxt);
   7479     if (arg == NULL)
   7480 	XP_ERROR(XPATH_INVALID_OPERAND);
   7481     val = xmlXPathCastToNumber(arg);
   7482     xmlXPathReleaseObject(ctxt->context, arg);
   7483     CAST_TO_NUMBER;
   7484     CHECK_TYPE(XPATH_NUMBER);
   7485     ctxt->value->floatval += val;
   7486 }
   7487 
   7488 /**
   7489  * xmlXPathSubValues:
   7490  * @ctxt:  the XPath Parser context
   7491  *
   7492  * Implement the subtraction operation on XPath objects:
   7493  * The numeric operators convert their operands to numbers as if
   7494  * by calling the number function.
   7495  */
   7496 void
   7497 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
   7498     xmlXPathObjectPtr arg;
   7499     double val;
   7500 
   7501     arg = valuePop(ctxt);
   7502     if (arg == NULL)
   7503 	XP_ERROR(XPATH_INVALID_OPERAND);
   7504     val = xmlXPathCastToNumber(arg);
   7505     xmlXPathReleaseObject(ctxt->context, arg);
   7506     CAST_TO_NUMBER;
   7507     CHECK_TYPE(XPATH_NUMBER);
   7508     ctxt->value->floatval -= val;
   7509 }
   7510 
   7511 /**
   7512  * xmlXPathMultValues:
   7513  * @ctxt:  the XPath Parser context
   7514  *
   7515  * Implement the multiply operation on XPath objects:
   7516  * The numeric operators convert their operands to numbers as if
   7517  * by calling the number function.
   7518  */
   7519 void
   7520 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
   7521     xmlXPathObjectPtr arg;
   7522     double val;
   7523 
   7524     arg = valuePop(ctxt);
   7525     if (arg == NULL)
   7526 	XP_ERROR(XPATH_INVALID_OPERAND);
   7527     val = xmlXPathCastToNumber(arg);
   7528     xmlXPathReleaseObject(ctxt->context, arg);
   7529     CAST_TO_NUMBER;
   7530     CHECK_TYPE(XPATH_NUMBER);
   7531     ctxt->value->floatval *= val;
   7532 }
   7533 
   7534 /**
   7535  * xmlXPathDivValues:
   7536  * @ctxt:  the XPath Parser context
   7537  *
   7538  * Implement the div operation on XPath objects @arg1 / @arg2:
   7539  * The numeric operators convert their operands to numbers as if
   7540  * by calling the number function.
   7541  */
   7542 void
   7543 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
   7544     xmlXPathObjectPtr arg;
   7545     double val;
   7546 
   7547     arg = valuePop(ctxt);
   7548     if (arg == NULL)
   7549 	XP_ERROR(XPATH_INVALID_OPERAND);
   7550     val = xmlXPathCastToNumber(arg);
   7551     xmlXPathReleaseObject(ctxt->context, arg);
   7552     CAST_TO_NUMBER;
   7553     CHECK_TYPE(XPATH_NUMBER);
   7554     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
   7555 	ctxt->value->floatval = xmlXPathNAN;
   7556     else if (val == 0 && xmlXPathGetSign(val) != 0) {
   7557 	if (ctxt->value->floatval == 0)
   7558 	    ctxt->value->floatval = xmlXPathNAN;
   7559 	else if (ctxt->value->floatval > 0)
   7560 	    ctxt->value->floatval = xmlXPathNINF;
   7561 	else if (ctxt->value->floatval < 0)
   7562 	    ctxt->value->floatval = xmlXPathPINF;
   7563     }
   7564     else if (val == 0) {
   7565 	if (ctxt->value->floatval == 0)
   7566 	    ctxt->value->floatval = xmlXPathNAN;
   7567 	else if (ctxt->value->floatval > 0)
   7568 	    ctxt->value->floatval = xmlXPathPINF;
   7569 	else if (ctxt->value->floatval < 0)
   7570 	    ctxt->value->floatval = xmlXPathNINF;
   7571     } else
   7572 	ctxt->value->floatval /= val;
   7573 }
   7574 
   7575 /**
   7576  * xmlXPathModValues:
   7577  * @ctxt:  the XPath Parser context
   7578  *
   7579  * Implement the mod operation on XPath objects: @arg1 / @arg2
   7580  * The numeric operators convert their operands to numbers as if
   7581  * by calling the number function.
   7582  */
   7583 void
   7584 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
   7585     xmlXPathObjectPtr arg;
   7586     double arg1, arg2;
   7587 
   7588     arg = valuePop(ctxt);
   7589     if (arg == NULL)
   7590 	XP_ERROR(XPATH_INVALID_OPERAND);
   7591     arg2 = xmlXPathCastToNumber(arg);
   7592     xmlXPathReleaseObject(ctxt->context, arg);
   7593     CAST_TO_NUMBER;
   7594     CHECK_TYPE(XPATH_NUMBER);
   7595     arg1 = ctxt->value->floatval;
   7596     if (arg2 == 0)
   7597 	ctxt->value->floatval = xmlXPathNAN;
   7598     else {
   7599 	ctxt->value->floatval = fmod(arg1, arg2);
   7600     }
   7601 }
   7602 
   7603 /************************************************************************
   7604  *									*
   7605  *		The traversal functions					*
   7606  *									*
   7607  ************************************************************************/
   7608 
   7609 /*
   7610  * A traversal function enumerates nodes along an axis.
   7611  * Initially it must be called with NULL, and it indicates
   7612  * termination on the axis by returning NULL.
   7613  */
   7614 typedef xmlNodePtr (*xmlXPathTraversalFunction)
   7615                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
   7616 
   7617 /*
   7618  * xmlXPathTraversalFunctionExt:
   7619  * A traversal function enumerates nodes along an axis.
   7620  * Initially it must be called with NULL, and it indicates
   7621  * termination on the axis by returning NULL.
   7622  * The context node of the traversal is specified via @contextNode.
   7623  */
   7624 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
   7625                     (xmlNodePtr cur, xmlNodePtr contextNode);
   7626 
   7627 /*
   7628  * xmlXPathNodeSetMergeFunction:
   7629  * Used for merging node sets in xmlXPathCollectAndTest().
   7630  */
   7631 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
   7632 		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
   7633 
   7634 
   7635 /**
   7636  * xmlXPathNextSelf:
   7637  * @ctxt:  the XPath Parser context
   7638  * @cur:  the current node in the traversal
   7639  *
   7640  * Traversal function for the "self" direction
   7641  * The self axis contains just the context node itself
   7642  *
   7643  * Returns the next element following that axis
   7644  */
   7645 xmlNodePtr
   7646 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7647     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7648     if (cur == NULL)
   7649         return(ctxt->context->node);
   7650     return(NULL);
   7651 }
   7652 
   7653 /**
   7654  * xmlXPathNextChild:
   7655  * @ctxt:  the XPath Parser context
   7656  * @cur:  the current node in the traversal
   7657  *
   7658  * Traversal function for the "child" direction
   7659  * The child axis contains the children of the context node in document order.
   7660  *
   7661  * Returns the next element following that axis
   7662  */
   7663 xmlNodePtr
   7664 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7665     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7666     if (cur == NULL) {
   7667 	if (ctxt->context->node == NULL) return(NULL);
   7668 	switch (ctxt->context->node->type) {
   7669             case XML_ELEMENT_NODE:
   7670             case XML_TEXT_NODE:
   7671             case XML_CDATA_SECTION_NODE:
   7672             case XML_ENTITY_REF_NODE:
   7673             case XML_ENTITY_NODE:
   7674             case XML_PI_NODE:
   7675             case XML_COMMENT_NODE:
   7676             case XML_NOTATION_NODE:
   7677             case XML_DTD_NODE:
   7678 		return(ctxt->context->node->children);
   7679             case XML_DOCUMENT_NODE:
   7680             case XML_DOCUMENT_TYPE_NODE:
   7681             case XML_DOCUMENT_FRAG_NODE:
   7682             case XML_HTML_DOCUMENT_NODE:
   7683 #ifdef LIBXML_DOCB_ENABLED
   7684 	    case XML_DOCB_DOCUMENT_NODE:
   7685 #endif
   7686 		return(((xmlDocPtr) ctxt->context->node)->children);
   7687 	    case XML_ELEMENT_DECL:
   7688 	    case XML_ATTRIBUTE_DECL:
   7689 	    case XML_ENTITY_DECL:
   7690             case XML_ATTRIBUTE_NODE:
   7691 	    case XML_NAMESPACE_DECL:
   7692 	    case XML_XINCLUDE_START:
   7693 	    case XML_XINCLUDE_END:
   7694 		return(NULL);
   7695 	}
   7696 	return(NULL);
   7697     }
   7698     if ((cur->type == XML_DOCUMENT_NODE) ||
   7699         (cur->type == XML_HTML_DOCUMENT_NODE))
   7700 	return(NULL);
   7701     return(cur->next);
   7702 }
   7703 
   7704 /**
   7705  * xmlXPathNextChildElement:
   7706  * @ctxt:  the XPath Parser context
   7707  * @cur:  the current node in the traversal
   7708  *
   7709  * Traversal function for the "child" direction and nodes of type element.
   7710  * The child axis contains the children of the context node in document order.
   7711  *
   7712  * Returns the next element following that axis
   7713  */
   7714 static xmlNodePtr
   7715 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7716     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7717     if (cur == NULL) {
   7718 	cur = ctxt->context->node;
   7719 	if (cur == NULL) return(NULL);
   7720 	/*
   7721 	* Get the first element child.
   7722 	*/
   7723 	switch (cur->type) {
   7724             case XML_ELEMENT_NODE:
   7725 	    case XML_DOCUMENT_FRAG_NODE:
   7726 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
   7727             case XML_ENTITY_NODE:
   7728 		cur = cur->children;
   7729 		if (cur != NULL) {
   7730 		    if (cur->type == XML_ELEMENT_NODE)
   7731 			return(cur);
   7732 		    do {
   7733 			cur = cur->next;
   7734 		    } while ((cur != NULL) &&
   7735 			(cur->type != XML_ELEMENT_NODE));
   7736 		    return(cur);
   7737 		}
   7738 		return(NULL);
   7739             case XML_DOCUMENT_NODE:
   7740             case XML_HTML_DOCUMENT_NODE:
   7741 #ifdef LIBXML_DOCB_ENABLED
   7742 	    case XML_DOCB_DOCUMENT_NODE:
   7743 #endif
   7744 		return(xmlDocGetRootElement((xmlDocPtr) cur));
   7745 	    default:
   7746 		return(NULL);
   7747 	}
   7748 	return(NULL);
   7749     }
   7750     /*
   7751     * Get the next sibling element node.
   7752     */
   7753     switch (cur->type) {
   7754 	case XML_ELEMENT_NODE:
   7755 	case XML_TEXT_NODE:
   7756 	case XML_ENTITY_REF_NODE:
   7757 	case XML_ENTITY_NODE:
   7758 	case XML_CDATA_SECTION_NODE:
   7759 	case XML_PI_NODE:
   7760 	case XML_COMMENT_NODE:
   7761 	case XML_XINCLUDE_END:
   7762 	    break;
   7763 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
   7764 	default:
   7765 	    return(NULL);
   7766     }
   7767     if (cur->next != NULL) {
   7768 	if (cur->next->type == XML_ELEMENT_NODE)
   7769 	    return(cur->next);
   7770 	cur = cur->next;
   7771 	do {
   7772 	    cur = cur->next;
   7773 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
   7774 	return(cur);
   7775     }
   7776     return(NULL);
   7777 }
   7778 
   7779 #if 0
   7780 /**
   7781  * xmlXPathNextDescendantOrSelfElemParent:
   7782  * @ctxt:  the XPath Parser context
   7783  * @cur:  the current node in the traversal
   7784  *
   7785  * Traversal function for the "descendant-or-self" axis.
   7786  * Additionally it returns only nodes which can be parents of
   7787  * element nodes.
   7788  *
   7789  *
   7790  * Returns the next element following that axis
   7791  */
   7792 static xmlNodePtr
   7793 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
   7794 				       xmlNodePtr contextNode)
   7795 {
   7796     if (cur == NULL) {
   7797 	if (contextNode == NULL)
   7798 	    return(NULL);
   7799 	switch (contextNode->type) {
   7800 	    case XML_ELEMENT_NODE:
   7801 	    case XML_XINCLUDE_START:
   7802 	    case XML_DOCUMENT_FRAG_NODE:
   7803 	    case XML_DOCUMENT_NODE:
   7804 #ifdef LIBXML_DOCB_ENABLED
   7805 	    case XML_DOCB_DOCUMENT_NODE:
   7806 #endif
   7807 	    case XML_HTML_DOCUMENT_NODE:
   7808 		return(contextNode);
   7809 	    default:
   7810 		return(NULL);
   7811 	}
   7812 	return(NULL);
   7813     } else {
   7814 	xmlNodePtr start = cur;
   7815 
   7816 	while (cur != NULL) {
   7817 	    switch (cur->type) {
   7818 		case XML_ELEMENT_NODE:
   7819 		/* TODO: OK to have XInclude here? */
   7820 		case XML_XINCLUDE_START:
   7821 		case XML_DOCUMENT_FRAG_NODE:
   7822 		    if (cur != start)
   7823 			return(cur);
   7824 		    if (cur->children != NULL) {
   7825 			cur = cur->children;
   7826 			continue;
   7827 		    }
   7828 		    break;
   7829 		/* Not sure if we need those here. */
   7830 		case XML_DOCUMENT_NODE:
   7831 #ifdef LIBXML_DOCB_ENABLED
   7832 		case XML_DOCB_DOCUMENT_NODE:
   7833 #endif
   7834 		case XML_HTML_DOCUMENT_NODE:
   7835 		    if (cur != start)
   7836 			return(cur);
   7837 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
   7838 		default:
   7839 		    break;
   7840 	    }
   7841 
   7842 next_sibling:
   7843 	    if ((cur == NULL) || (cur == contextNode))
   7844 		return(NULL);
   7845 	    if (cur->next != NULL) {
   7846 		cur = cur->next;
   7847 	    } else {
   7848 		cur = cur->parent;
   7849 		goto next_sibling;
   7850 	    }
   7851 	}
   7852     }
   7853     return(NULL);
   7854 }
   7855 #endif
   7856 
   7857 /**
   7858  * xmlXPathNextDescendant:
   7859  * @ctxt:  the XPath Parser context
   7860  * @cur:  the current node in the traversal
   7861  *
   7862  * Traversal function for the "descendant" direction
   7863  * the descendant axis contains the descendants of the context node in document
   7864  * order; a descendant is a child or a child of a child and so on.
   7865  *
   7866  * Returns the next element following that axis
   7867  */
   7868 xmlNodePtr
   7869 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7870     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7871     if (cur == NULL) {
   7872 	if (ctxt->context->node == NULL)
   7873 	    return(NULL);
   7874 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   7875 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
   7876 	    return(NULL);
   7877 
   7878         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
   7879 	    return(ctxt->context->doc->children);
   7880         return(ctxt->context->node->children);
   7881     }
   7882 
   7883     if (cur->type == XML_NAMESPACE_DECL)
   7884         return(NULL);
   7885     if (cur->children != NULL) {
   7886 	/*
   7887 	 * Do not descend on entities declarations
   7888 	 */
   7889 	if (cur->children->type != XML_ENTITY_DECL) {
   7890 	    cur = cur->children;
   7891 	    /*
   7892 	     * Skip DTDs
   7893 	     */
   7894 	    if (cur->type != XML_DTD_NODE)
   7895 		return(cur);
   7896 	}
   7897     }
   7898 
   7899     if (cur == ctxt->context->node) return(NULL);
   7900 
   7901     while (cur->next != NULL) {
   7902 	cur = cur->next;
   7903 	if ((cur->type != XML_ENTITY_DECL) &&
   7904 	    (cur->type != XML_DTD_NODE))
   7905 	    return(cur);
   7906     }
   7907 
   7908     do {
   7909         cur = cur->parent;
   7910 	if (cur == NULL) break;
   7911 	if (cur == ctxt->context->node) return(NULL);
   7912 	if (cur->next != NULL) {
   7913 	    cur = cur->next;
   7914 	    return(cur);
   7915 	}
   7916     } while (cur != NULL);
   7917     return(cur);
   7918 }
   7919 
   7920 /**
   7921  * xmlXPathNextDescendantOrSelf:
   7922  * @ctxt:  the XPath Parser context
   7923  * @cur:  the current node in the traversal
   7924  *
   7925  * Traversal function for the "descendant-or-self" direction
   7926  * the descendant-or-self axis contains the context node and the descendants
   7927  * of the context node in document order; thus the context node is the first
   7928  * node on the axis, and the first child of the context node is the second node
   7929  * on the axis
   7930  *
   7931  * Returns the next element following that axis
   7932  */
   7933 xmlNodePtr
   7934 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7935     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7936     if (cur == NULL)
   7937         return(ctxt->context->node);
   7938 
   7939     if (ctxt->context->node == NULL)
   7940         return(NULL);
   7941     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   7942         (ctxt->context->node->type == XML_NAMESPACE_DECL))
   7943         return(NULL);
   7944 
   7945     return(xmlXPathNextDescendant(ctxt, cur));
   7946 }
   7947 
   7948 /**
   7949  * xmlXPathNextParent:
   7950  * @ctxt:  the XPath Parser context
   7951  * @cur:  the current node in the traversal
   7952  *
   7953  * Traversal function for the "parent" direction
   7954  * The parent axis contains the parent of the context node, if there is one.
   7955  *
   7956  * Returns the next element following that axis
   7957  */
   7958 xmlNodePtr
   7959 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7960     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7961     /*
   7962      * the parent of an attribute or namespace node is the element
   7963      * to which the attribute or namespace node is attached
   7964      * Namespace handling !!!
   7965      */
   7966     if (cur == NULL) {
   7967 	if (ctxt->context->node == NULL) return(NULL);
   7968 	switch (ctxt->context->node->type) {
   7969             case XML_ELEMENT_NODE:
   7970             case XML_TEXT_NODE:
   7971             case XML_CDATA_SECTION_NODE:
   7972             case XML_ENTITY_REF_NODE:
   7973             case XML_ENTITY_NODE:
   7974             case XML_PI_NODE:
   7975             case XML_COMMENT_NODE:
   7976             case XML_NOTATION_NODE:
   7977             case XML_DTD_NODE:
   7978 	    case XML_ELEMENT_DECL:
   7979 	    case XML_ATTRIBUTE_DECL:
   7980 	    case XML_XINCLUDE_START:
   7981 	    case XML_XINCLUDE_END:
   7982 	    case XML_ENTITY_DECL:
   7983 		if (ctxt->context->node->parent == NULL)
   7984 		    return((xmlNodePtr) ctxt->context->doc);
   7985 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
   7986 		    ((ctxt->context->node->parent->name[0] == ' ') ||
   7987 		     (xmlStrEqual(ctxt->context->node->parent->name,
   7988 				 BAD_CAST "fake node libxslt"))))
   7989 		    return(NULL);
   7990 		return(ctxt->context->node->parent);
   7991             case XML_ATTRIBUTE_NODE: {
   7992 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
   7993 
   7994 		return(att->parent);
   7995 	    }
   7996             case XML_DOCUMENT_NODE:
   7997             case XML_DOCUMENT_TYPE_NODE:
   7998             case XML_DOCUMENT_FRAG_NODE:
   7999             case XML_HTML_DOCUMENT_NODE:
   8000 #ifdef LIBXML_DOCB_ENABLED
   8001 	    case XML_DOCB_DOCUMENT_NODE:
   8002 #endif
   8003                 return(NULL);
   8004 	    case XML_NAMESPACE_DECL: {
   8005 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
   8006 
   8007 		if ((ns->next != NULL) &&
   8008 		    (ns->next->type != XML_NAMESPACE_DECL))
   8009 		    return((xmlNodePtr) ns->next);
   8010                 return(NULL);
   8011 	    }
   8012 	}
   8013     }
   8014     return(NULL);
   8015 }
   8016 
   8017 /**
   8018  * xmlXPathNextAncestor:
   8019  * @ctxt:  the XPath Parser context
   8020  * @cur:  the current node in the traversal
   8021  *
   8022  * Traversal function for the "ancestor" direction
   8023  * the ancestor axis contains the ancestors of the context node; the ancestors
   8024  * of the context node consist of the parent of context node and the parent's
   8025  * parent and so on; the nodes are ordered in reverse document order; thus the
   8026  * parent is the first node on the axis, and the parent's parent is the second
   8027  * node on the axis
   8028  *
   8029  * Returns the next element following that axis
   8030  */
   8031 xmlNodePtr
   8032 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8033     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8034     /*
   8035      * the parent of an attribute or namespace node is the element
   8036      * to which the attribute or namespace node is attached
   8037      * !!!!!!!!!!!!!
   8038      */
   8039     if (cur == NULL) {
   8040 	if (ctxt->context->node == NULL) return(NULL);
   8041 	switch (ctxt->context->node->type) {
   8042             case XML_ELEMENT_NODE:
   8043             case XML_TEXT_NODE:
   8044             case XML_CDATA_SECTION_NODE:
   8045             case XML_ENTITY_REF_NODE:
   8046             case XML_ENTITY_NODE:
   8047             case XML_PI_NODE:
   8048             case XML_COMMENT_NODE:
   8049 	    case XML_DTD_NODE:
   8050 	    case XML_ELEMENT_DECL:
   8051 	    case XML_ATTRIBUTE_DECL:
   8052 	    case XML_ENTITY_DECL:
   8053             case XML_NOTATION_NODE:
   8054 	    case XML_XINCLUDE_START:
   8055 	    case XML_XINCLUDE_END:
   8056 		if (ctxt->context->node->parent == NULL)
   8057 		    return((xmlNodePtr) ctxt->context->doc);
   8058 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
   8059 		    ((ctxt->context->node->parent->name[0] == ' ') ||
   8060 		     (xmlStrEqual(ctxt->context->node->parent->name,
   8061 				 BAD_CAST "fake node libxslt"))))
   8062 		    return(NULL);
   8063 		return(ctxt->context->node->parent);
   8064             case XML_ATTRIBUTE_NODE: {
   8065 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
   8066 
   8067 		return(tmp->parent);
   8068 	    }
   8069             case XML_DOCUMENT_NODE:
   8070             case XML_DOCUMENT_TYPE_NODE:
   8071             case XML_DOCUMENT_FRAG_NODE:
   8072             case XML_HTML_DOCUMENT_NODE:
   8073 #ifdef LIBXML_DOCB_ENABLED
   8074 	    case XML_DOCB_DOCUMENT_NODE:
   8075 #endif
   8076                 return(NULL);
   8077 	    case XML_NAMESPACE_DECL: {
   8078 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
   8079 
   8080 		if ((ns->next != NULL) &&
   8081 		    (ns->next->type != XML_NAMESPACE_DECL))
   8082 		    return((xmlNodePtr) ns->next);
   8083 		/* Bad, how did that namespace end up here ? */
   8084                 return(NULL);
   8085 	    }
   8086 	}
   8087 	return(NULL);
   8088     }
   8089     if (cur == ctxt->context->doc->children)
   8090 	return((xmlNodePtr) ctxt->context->doc);
   8091     if (cur == (xmlNodePtr) ctxt->context->doc)
   8092 	return(NULL);
   8093     switch (cur->type) {
   8094 	case XML_ELEMENT_NODE:
   8095 	case XML_TEXT_NODE:
   8096 	case XML_CDATA_SECTION_NODE:
   8097 	case XML_ENTITY_REF_NODE:
   8098 	case XML_ENTITY_NODE:
   8099 	case XML_PI_NODE:
   8100 	case XML_COMMENT_NODE:
   8101 	case XML_NOTATION_NODE:
   8102 	case XML_DTD_NODE:
   8103         case XML_ELEMENT_DECL:
   8104         case XML_ATTRIBUTE_DECL:
   8105         case XML_ENTITY_DECL:
   8106 	case XML_XINCLUDE_START:
   8107 	case XML_XINCLUDE_END:
   8108 	    if (cur->parent == NULL)
   8109 		return(NULL);
   8110 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
   8111 		((cur->parent->name[0] == ' ') ||
   8112 		 (xmlStrEqual(cur->parent->name,
   8113 			      BAD_CAST "fake node libxslt"))))
   8114 		return(NULL);
   8115 	    return(cur->parent);
   8116 	case XML_ATTRIBUTE_NODE: {
   8117 	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
   8118 
   8119 	    return(att->parent);
   8120 	}
   8121 	case XML_NAMESPACE_DECL: {
   8122 	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
   8123 
   8124 	    if ((ns->next != NULL) &&
   8125 	        (ns->next->type != XML_NAMESPACE_DECL))
   8126 	        return((xmlNodePtr) ns->next);
   8127 	    /* Bad, how did that namespace end up here ? */
   8128             return(NULL);
   8129 	}
   8130 	case XML_DOCUMENT_NODE:
   8131 	case XML_DOCUMENT_TYPE_NODE:
   8132 	case XML_DOCUMENT_FRAG_NODE:
   8133 	case XML_HTML_DOCUMENT_NODE:
   8134 #ifdef LIBXML_DOCB_ENABLED
   8135 	case XML_DOCB_DOCUMENT_NODE:
   8136 #endif
   8137 	    return(NULL);
   8138     }
   8139     return(NULL);
   8140 }
   8141 
   8142 /**
   8143  * xmlXPathNextAncestorOrSelf:
   8144  * @ctxt:  the XPath Parser context
   8145  * @cur:  the current node in the traversal
   8146  *
   8147  * Traversal function for the "ancestor-or-self" direction
   8148  * he ancestor-or-self axis contains the context node and ancestors of
   8149  * the context node in reverse document order; thus the context node is
   8150  * the first node on the axis, and the context node's parent the second;
   8151  * parent here is defined the same as with the parent axis.
   8152  *
   8153  * Returns the next element following that axis
   8154  */
   8155 xmlNodePtr
   8156 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8157     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8158     if (cur == NULL)
   8159         return(ctxt->context->node);
   8160     return(xmlXPathNextAncestor(ctxt, cur));
   8161 }
   8162 
   8163 /**
   8164  * xmlXPathNextFollowingSibling:
   8165  * @ctxt:  the XPath Parser context
   8166  * @cur:  the current node in the traversal
   8167  *
   8168  * Traversal function for the "following-sibling" direction
   8169  * The following-sibling axis contains the following siblings of the context
   8170  * node in document order.
   8171  *
   8172  * Returns the next element following that axis
   8173  */
   8174 xmlNodePtr
   8175 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8176     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8177     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   8178 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
   8179 	return(NULL);
   8180     if (cur == (xmlNodePtr) ctxt->context->doc)
   8181         return(NULL);
   8182     if (cur == NULL)
   8183         return(ctxt->context->node->next);
   8184     return(cur->next);
   8185 }
   8186 
   8187 /**
   8188  * xmlXPathNextPrecedingSibling:
   8189  * @ctxt:  the XPath Parser context
   8190  * @cur:  the current node in the traversal
   8191  *
   8192  * Traversal function for the "preceding-sibling" direction
   8193  * The preceding-sibling axis contains the preceding siblings of the context
   8194  * node in reverse document order; the first preceding sibling is first on the
   8195  * axis; the sibling preceding that node is the second on the axis and so on.
   8196  *
   8197  * Returns the next element following that axis
   8198  */
   8199 xmlNodePtr
   8200 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8201     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8202     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   8203 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
   8204 	return(NULL);
   8205     if (cur == (xmlNodePtr) ctxt->context->doc)
   8206         return(NULL);
   8207     if (cur == NULL)
   8208         return(ctxt->context->node->prev);
   8209     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
   8210 	cur = cur->prev;
   8211 	if (cur == NULL)
   8212 	    return(ctxt->context->node->prev);
   8213     }
   8214     return(cur->prev);
   8215 }
   8216 
   8217 /**
   8218  * xmlXPathNextFollowing:
   8219  * @ctxt:  the XPath Parser context
   8220  * @cur:  the current node in the traversal
   8221  *
   8222  * Traversal function for the "following" direction
   8223  * The following axis contains all nodes in the same document as the context
   8224  * node that are after the context node in document order, excluding any
   8225  * descendants and excluding attribute nodes and namespace nodes; the nodes
   8226  * are ordered in document order
   8227  *
   8228  * Returns the next element following that axis
   8229  */
   8230 xmlNodePtr
   8231 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8232     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8233     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
   8234         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
   8235         return(cur->children);
   8236 
   8237     if (cur == NULL) {
   8238         cur = ctxt->context->node;
   8239         if (cur->type == XML_NAMESPACE_DECL)
   8240             return(NULL);
   8241         if (cur->type == XML_ATTRIBUTE_NODE)
   8242             cur = cur->parent;
   8243     }
   8244     if (cur == NULL) return(NULL) ; /* ERROR */
   8245     if (cur->next != NULL) return(cur->next) ;
   8246     do {
   8247         cur = cur->parent;
   8248         if (cur == NULL) break;
   8249         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
   8250         if (cur->next != NULL) return(cur->next);
   8251     } while (cur != NULL);
   8252     return(cur);
   8253 }
   8254 
   8255 /*
   8256  * xmlXPathIsAncestor:
   8257  * @ancestor:  the ancestor node
   8258  * @node:  the current node
   8259  *
   8260  * Check that @ancestor is a @node's ancestor
   8261  *
   8262  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
   8263  */
   8264 static int
   8265 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
   8266     if ((ancestor == NULL) || (node == NULL)) return(0);
   8267     if (node->type == XML_NAMESPACE_DECL)
   8268         return(0);
   8269     if (ancestor->type == XML_NAMESPACE_DECL)
   8270         return(0);
   8271     /* nodes need to be in the same document */
   8272     if (ancestor->doc != node->doc) return(0);
   8273     /* avoid searching if ancestor or node is the root node */
   8274     if (ancestor == (xmlNodePtr) node->doc) return(1);
   8275     if (node == (xmlNodePtr) ancestor->doc) return(0);
   8276     while (node->parent != NULL) {
   8277         if (node->parent == ancestor)
   8278             return(1);
   8279 	node = node->parent;
   8280     }
   8281     return(0);
   8282 }
   8283 
   8284 /**
   8285  * xmlXPathNextPreceding:
   8286  * @ctxt:  the XPath Parser context
   8287  * @cur:  the current node in the traversal
   8288  *
   8289  * Traversal function for the "preceding" direction
   8290  * the preceding axis contains all nodes in the same document as the context
   8291  * node that are before the context node in document order, excluding any
   8292  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
   8293  * ordered in reverse document order
   8294  *
   8295  * Returns the next element following that axis
   8296  */
   8297 xmlNodePtr
   8298 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
   8299 {
   8300     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8301     if (cur == NULL) {
   8302         cur = ctxt->context->node;
   8303         if (cur->type == XML_NAMESPACE_DECL)
   8304             return(NULL);
   8305         if (cur->type == XML_ATTRIBUTE_NODE)
   8306             return(cur->parent);
   8307     }
   8308     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
   8309 	return (NULL);
   8310     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
   8311 	cur = cur->prev;
   8312     do {
   8313         if (cur->prev != NULL) {
   8314             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
   8315             return (cur);
   8316         }
   8317 
   8318         cur = cur->parent;
   8319         if (cur == NULL)
   8320             return (NULL);
   8321         if (cur == ctxt->context->doc->children)
   8322             return (NULL);
   8323     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
   8324     return (cur);
   8325 }
   8326 
   8327 /**
   8328  * xmlXPathNextPrecedingInternal:
   8329  * @ctxt:  the XPath Parser context
   8330  * @cur:  the current node in the traversal
   8331  *
   8332  * Traversal function for the "preceding" direction
   8333  * the preceding axis contains all nodes in the same document as the context
   8334  * node that are before the context node in document order, excluding any
   8335  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
   8336  * ordered in reverse document order
   8337  * This is a faster implementation but internal only since it requires a
   8338  * state kept in the parser context: ctxt->ancestor.
   8339  *
   8340  * Returns the next element following that axis
   8341  */
   8342 static xmlNodePtr
   8343 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
   8344                               xmlNodePtr cur)
   8345 {
   8346     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8347     if (cur == NULL) {
   8348         cur = ctxt->context->node;
   8349         if (cur == NULL)
   8350             return (NULL);
   8351         if (cur->type == XML_NAMESPACE_DECL)
   8352             return (NULL);
   8353         ctxt->ancestor = cur->parent;
   8354     }
   8355     if (cur->type == XML_NAMESPACE_DECL)
   8356         return(NULL);
   8357     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
   8358 	cur = cur->prev;
   8359     while (cur->prev == NULL) {
   8360         cur = cur->parent;
   8361         if (cur == NULL)
   8362             return (NULL);
   8363         if (cur == ctxt->context->doc->children)
   8364             return (NULL);
   8365         if (cur != ctxt->ancestor)
   8366             return (cur);
   8367         ctxt->ancestor = cur->parent;
   8368     }
   8369     cur = cur->prev;
   8370     while (cur->last != NULL)
   8371         cur = cur->last;
   8372     return (cur);
   8373 }
   8374 
   8375 /**
   8376  * xmlXPathNextNamespace:
   8377  * @ctxt:  the XPath Parser context
   8378  * @cur:  the current attribute in the traversal
   8379  *
   8380  * Traversal function for the "namespace" direction
   8381  * the namespace axis contains the namespace nodes of the context node;
   8382  * the order of nodes on this axis is implementation-defined; the axis will
   8383  * be empty unless the context node is an element
   8384  *
   8385  * We keep the XML namespace node at the end of the list.
   8386  *
   8387  * Returns the next element following that axis
   8388  */
   8389 xmlNodePtr
   8390 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8391     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8392     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
   8393     if (cur == NULL) {
   8394         if (ctxt->context->tmpNsList != NULL)
   8395 	    xmlFree(ctxt->context->tmpNsList);
   8396 	ctxt->context->tmpNsList =
   8397 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
   8398 	ctxt->context->tmpNsNr = 0;
   8399 	if (ctxt->context->tmpNsList != NULL) {
   8400 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
   8401 		ctxt->context->tmpNsNr++;
   8402 	    }
   8403 	}
   8404 	return((xmlNodePtr) xmlXPathXMLNamespace);
   8405     }
   8406     if (ctxt->context->tmpNsNr > 0) {
   8407 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
   8408     } else {
   8409 	if (ctxt->context->tmpNsList != NULL)
   8410 	    xmlFree(ctxt->context->tmpNsList);
   8411 	ctxt->context->tmpNsList = NULL;
   8412 	return(NULL);
   8413     }
   8414 }
   8415 
   8416 /**
   8417  * xmlXPathNextAttribute:
   8418  * @ctxt:  the XPath Parser context
   8419  * @cur:  the current attribute in the traversal
   8420  *
   8421  * Traversal function for the "attribute" direction
   8422  * TODO: support DTD inherited default attributes
   8423  *
   8424  * Returns the next element following that axis
   8425  */
   8426 xmlNodePtr
   8427 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8428     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8429     if (ctxt->context->node == NULL)
   8430 	return(NULL);
   8431     if (ctxt->context->node->type != XML_ELEMENT_NODE)
   8432 	return(NULL);
   8433     if (cur == NULL) {
   8434         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
   8435 	    return(NULL);
   8436         return((xmlNodePtr)ctxt->context->node->properties);
   8437     }
   8438     return((xmlNodePtr)cur->next);
   8439 }
   8440 
   8441 /************************************************************************
   8442  *									*
   8443  *		NodeTest Functions					*
   8444  *									*
   8445  ************************************************************************/
   8446 
   8447 #define IS_FUNCTION			200
   8448 
   8449 
   8450 /************************************************************************
   8451  *									*
   8452  *		Implicit tree core function library			*
   8453  *									*
   8454  ************************************************************************/
   8455 
   8456 /**
   8457  * xmlXPathRoot:
   8458  * @ctxt:  the XPath Parser context
   8459  *
   8460  * Initialize the context to the root of the document
   8461  */
   8462 void
   8463 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
   8464     if ((ctxt == NULL) || (ctxt->context == NULL))
   8465 	return;
   8466     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
   8467     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8468 	ctxt->context->node));
   8469 }
   8470 
   8471 /************************************************************************
   8472  *									*
   8473  *		The explicit core function library			*
   8474  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
   8475  *									*
   8476  ************************************************************************/
   8477 
   8478 
   8479 /**
   8480  * xmlXPathLastFunction:
   8481  * @ctxt:  the XPath Parser context
   8482  * @nargs:  the number of arguments
   8483  *
   8484  * Implement the last() XPath function
   8485  *    number last()
   8486  * The last function returns the number of nodes in the context node list.
   8487  */
   8488 void
   8489 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8490     CHECK_ARITY(0);
   8491     if (ctxt->context->contextSize >= 0) {
   8492 	valuePush(ctxt,
   8493 	    xmlXPathCacheNewFloat(ctxt->context,
   8494 		(double) ctxt->context->contextSize));
   8495 #ifdef DEBUG_EXPR
   8496 	xmlGenericError(xmlGenericErrorContext,
   8497 		"last() : %d\n", ctxt->context->contextSize);
   8498 #endif
   8499     } else {
   8500 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
   8501     }
   8502 }
   8503 
   8504 /**
   8505  * xmlXPathPositionFunction:
   8506  * @ctxt:  the XPath Parser context
   8507  * @nargs:  the number of arguments
   8508  *
   8509  * Implement the position() XPath function
   8510  *    number position()
   8511  * The position function returns the position of the context node in the
   8512  * context node list. The first position is 1, and so the last position
   8513  * will be equal to last().
   8514  */
   8515 void
   8516 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8517     CHECK_ARITY(0);
   8518     if (ctxt->context->proximityPosition >= 0) {
   8519 	valuePush(ctxt,
   8520 	      xmlXPathCacheNewFloat(ctxt->context,
   8521 		(double) ctxt->context->proximityPosition));
   8522 #ifdef DEBUG_EXPR
   8523 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
   8524 		ctxt->context->proximityPosition);
   8525 #endif
   8526     } else {
   8527 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
   8528     }
   8529 }
   8530 
   8531 /**
   8532  * xmlXPathCountFunction:
   8533  * @ctxt:  the XPath Parser context
   8534  * @nargs:  the number of arguments
   8535  *
   8536  * Implement the count() XPath function
   8537  *    number count(node-set)
   8538  */
   8539 void
   8540 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8541     xmlXPathObjectPtr cur;
   8542 
   8543     CHECK_ARITY(1);
   8544     if ((ctxt->value == NULL) ||
   8545 	((ctxt->value->type != XPATH_NODESET) &&
   8546 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8547 	XP_ERROR(XPATH_INVALID_TYPE);
   8548     cur = valuePop(ctxt);
   8549 
   8550     if ((cur == NULL) || (cur->nodesetval == NULL))
   8551 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
   8552     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
   8553 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8554 	    (double) cur->nodesetval->nodeNr));
   8555     } else {
   8556 	if ((cur->nodesetval->nodeNr != 1) ||
   8557 	    (cur->nodesetval->nodeTab == NULL)) {
   8558 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
   8559 	} else {
   8560 	    xmlNodePtr tmp;
   8561 	    int i = 0;
   8562 
   8563 	    tmp = cur->nodesetval->nodeTab[0];
   8564 	    if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
   8565 		tmp = tmp->children;
   8566 		while (tmp != NULL) {
   8567 		    tmp = tmp->next;
   8568 		    i++;
   8569 		}
   8570 	    }
   8571 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
   8572 	}
   8573     }
   8574     xmlXPathReleaseObject(ctxt->context, cur);
   8575 }
   8576 
   8577 /**
   8578  * xmlXPathGetElementsByIds:
   8579  * @doc:  the document
   8580  * @ids:  a whitespace separated list of IDs
   8581  *
   8582  * Selects elements by their unique ID.
   8583  *
   8584  * Returns a node-set of selected elements.
   8585  */
   8586 static xmlNodeSetPtr
   8587 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
   8588     xmlNodeSetPtr ret;
   8589     const xmlChar *cur = ids;
   8590     xmlChar *ID;
   8591     xmlAttrPtr attr;
   8592     xmlNodePtr elem = NULL;
   8593 
   8594     if (ids == NULL) return(NULL);
   8595 
   8596     ret = xmlXPathNodeSetCreate(NULL);
   8597     if (ret == NULL)
   8598         return(ret);
   8599 
   8600     while (IS_BLANK_CH(*cur)) cur++;
   8601     while (*cur != 0) {
   8602 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
   8603 	    cur++;
   8604 
   8605         ID = xmlStrndup(ids, cur - ids);
   8606 	if (ID != NULL) {
   8607 	    /*
   8608 	     * We used to check the fact that the value passed
   8609 	     * was an NCName, but this generated much troubles for
   8610 	     * me and Aleksey Sanin, people blatantly violated that
   8611 	     * constaint, like Visa3D spec.
   8612 	     * if (xmlValidateNCName(ID, 1) == 0)
   8613 	     */
   8614 	    attr = xmlGetID(doc, ID);
   8615 	    if (attr != NULL) {
   8616 		if (attr->type == XML_ATTRIBUTE_NODE)
   8617 		    elem = attr->parent;
   8618 		else if (attr->type == XML_ELEMENT_NODE)
   8619 		    elem = (xmlNodePtr) attr;
   8620 		else
   8621 		    elem = NULL;
   8622 		if (elem != NULL)
   8623 		    xmlXPathNodeSetAdd(ret, elem);
   8624 	    }
   8625 	    xmlFree(ID);
   8626 	}
   8627 
   8628 	while (IS_BLANK_CH(*cur)) cur++;
   8629 	ids = cur;
   8630     }
   8631     return(ret);
   8632 }
   8633 
   8634 /**
   8635  * xmlXPathIdFunction:
   8636  * @ctxt:  the XPath Parser context
   8637  * @nargs:  the number of arguments
   8638  *
   8639  * Implement the id() XPath function
   8640  *    node-set id(object)
   8641  * The id function selects elements by their unique ID
   8642  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
   8643  * then the result is the union of the result of applying id to the
   8644  * string value of each of the nodes in the argument node-set. When the
   8645  * argument to id is of any other type, the argument is converted to a
   8646  * string as if by a call to the string function; the string is split
   8647  * into a whitespace-separated list of tokens (whitespace is any sequence
   8648  * of characters matching the production S); the result is a node-set
   8649  * containing the elements in the same document as the context node that
   8650  * have a unique ID equal to any of the tokens in the list.
   8651  */
   8652 void
   8653 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8654     xmlChar *tokens;
   8655     xmlNodeSetPtr ret;
   8656     xmlXPathObjectPtr obj;
   8657 
   8658     CHECK_ARITY(1);
   8659     obj = valuePop(ctxt);
   8660     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   8661     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
   8662 	xmlNodeSetPtr ns;
   8663 	int i;
   8664 
   8665 	ret = xmlXPathNodeSetCreate(NULL);
   8666         /*
   8667          * FIXME -- in an out-of-memory condition this will behave badly.
   8668          * The solution is not clear -- we already popped an item from
   8669          * ctxt, so the object is in a corrupt state.
   8670          */
   8671 
   8672 	if (obj->nodesetval != NULL) {
   8673 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
   8674 		tokens =
   8675 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
   8676 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
   8677 		ret = xmlXPathNodeSetMerge(ret, ns);
   8678 		xmlXPathFreeNodeSet(ns);
   8679 		if (tokens != NULL)
   8680 		    xmlFree(tokens);
   8681 	    }
   8682 	}
   8683 	xmlXPathReleaseObject(ctxt->context, obj);
   8684 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
   8685 	return;
   8686     }
   8687     obj = xmlXPathCacheConvertString(ctxt->context, obj);
   8688     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
   8689     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
   8690     xmlXPathReleaseObject(ctxt->context, obj);
   8691     return;
   8692 }
   8693 
   8694 /**
   8695  * xmlXPathLocalNameFunction:
   8696  * @ctxt:  the XPath Parser context
   8697  * @nargs:  the number of arguments
   8698  *
   8699  * Implement the local-name() XPath function
   8700  *    string local-name(node-set?)
   8701  * The local-name function returns a string containing the local part
   8702  * of the name of the node in the argument node-set that is first in
   8703  * document order. If the node-set is empty or the first node has no
   8704  * name, an empty string is returned. If the argument is omitted it
   8705  * defaults to the context node.
   8706  */
   8707 void
   8708 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8709     xmlXPathObjectPtr cur;
   8710 
   8711     if (ctxt == NULL) return;
   8712 
   8713     if (nargs == 0) {
   8714 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8715 	    ctxt->context->node));
   8716 	nargs = 1;
   8717     }
   8718 
   8719     CHECK_ARITY(1);
   8720     if ((ctxt->value == NULL) ||
   8721 	((ctxt->value->type != XPATH_NODESET) &&
   8722 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8723 	XP_ERROR(XPATH_INVALID_TYPE);
   8724     cur = valuePop(ctxt);
   8725 
   8726     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
   8727 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8728     } else {
   8729 	int i = 0; /* Should be first in document order !!!!! */
   8730 	switch (cur->nodesetval->nodeTab[i]->type) {
   8731 	case XML_ELEMENT_NODE:
   8732 	case XML_ATTRIBUTE_NODE:
   8733 	case XML_PI_NODE:
   8734 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
   8735 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8736 	    else
   8737 		valuePush(ctxt,
   8738 		      xmlXPathCacheNewString(ctxt->context,
   8739 			cur->nodesetval->nodeTab[i]->name));
   8740 	    break;
   8741 	case XML_NAMESPACE_DECL:
   8742 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   8743 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
   8744 	    break;
   8745 	default:
   8746 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8747 	}
   8748     }
   8749     xmlXPathReleaseObject(ctxt->context, cur);
   8750 }
   8751 
   8752 /**
   8753  * xmlXPathNamespaceURIFunction:
   8754  * @ctxt:  the XPath Parser context
   8755  * @nargs:  the number of arguments
   8756  *
   8757  * Implement the namespace-uri() XPath function
   8758  *    string namespace-uri(node-set?)
   8759  * The namespace-uri function returns a string containing the
   8760  * namespace URI of the expanded name of the node in the argument
   8761  * node-set that is first in document order. If the node-set is empty,
   8762  * the first node has no name, or the expanded name has no namespace
   8763  * URI, an empty string is returned. If the argument is omitted it
   8764  * defaults to the context node.
   8765  */
   8766 void
   8767 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8768     xmlXPathObjectPtr cur;
   8769 
   8770     if (ctxt == NULL) return;
   8771 
   8772     if (nargs == 0) {
   8773 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8774 	    ctxt->context->node));
   8775 	nargs = 1;
   8776     }
   8777     CHECK_ARITY(1);
   8778     if ((ctxt->value == NULL) ||
   8779 	((ctxt->value->type != XPATH_NODESET) &&
   8780 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8781 	XP_ERROR(XPATH_INVALID_TYPE);
   8782     cur = valuePop(ctxt);
   8783 
   8784     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
   8785 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8786     } else {
   8787 	int i = 0; /* Should be first in document order !!!!! */
   8788 	switch (cur->nodesetval->nodeTab[i]->type) {
   8789 	case XML_ELEMENT_NODE:
   8790 	case XML_ATTRIBUTE_NODE:
   8791 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
   8792 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8793 	    else
   8794 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   8795 			  cur->nodesetval->nodeTab[i]->ns->href));
   8796 	    break;
   8797 	default:
   8798 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8799 	}
   8800     }
   8801     xmlXPathReleaseObject(ctxt->context, cur);
   8802 }
   8803 
   8804 /**
   8805  * xmlXPathNameFunction:
   8806  * @ctxt:  the XPath Parser context
   8807  * @nargs:  the number of arguments
   8808  *
   8809  * Implement the name() XPath function
   8810  *    string name(node-set?)
   8811  * The name function returns a string containing a QName representing
   8812  * the name of the node in the argument node-set that is first in document
   8813  * order. The QName must represent the name with respect to the namespace
   8814  * declarations in effect on the node whose name is being represented.
   8815  * Typically, this will be the form in which the name occurred in the XML
   8816  * source. This need not be the case if there are namespace declarations
   8817  * in effect on the node that associate multiple prefixes with the same
   8818  * namespace. However, an implementation may include information about
   8819  * the original prefix in its representation of nodes; in this case, an
   8820  * implementation can ensure that the returned string is always the same
   8821  * as the QName used in the XML source. If the argument it omitted it
   8822  * defaults to the context node.
   8823  * Libxml keep the original prefix so the "real qualified name" used is
   8824  * returned.
   8825  */
   8826 static void
   8827 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
   8828 {
   8829     xmlXPathObjectPtr cur;
   8830 
   8831     if (nargs == 0) {
   8832 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8833 	    ctxt->context->node));
   8834         nargs = 1;
   8835     }
   8836 
   8837     CHECK_ARITY(1);
   8838     if ((ctxt->value == NULL) ||
   8839         ((ctxt->value->type != XPATH_NODESET) &&
   8840          (ctxt->value->type != XPATH_XSLT_TREE)))
   8841         XP_ERROR(XPATH_INVALID_TYPE);
   8842     cur = valuePop(ctxt);
   8843 
   8844     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
   8845         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8846     } else {
   8847         int i = 0;              /* Should be first in document order !!!!! */
   8848 
   8849         switch (cur->nodesetval->nodeTab[i]->type) {
   8850             case XML_ELEMENT_NODE:
   8851             case XML_ATTRIBUTE_NODE:
   8852 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
   8853 		    valuePush(ctxt,
   8854 			xmlXPathCacheNewCString(ctxt->context, ""));
   8855 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
   8856                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
   8857 		    valuePush(ctxt,
   8858 		        xmlXPathCacheNewString(ctxt->context,
   8859 			    cur->nodesetval->nodeTab[i]->name));
   8860 		} else {
   8861 		    xmlChar *fullname;
   8862 
   8863 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
   8864 				     cur->nodesetval->nodeTab[i]->ns->prefix,
   8865 				     NULL, 0);
   8866 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
   8867 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
   8868 		    if (fullname == NULL) {
   8869 			XP_ERROR(XPATH_MEMORY_ERROR);
   8870 		    }
   8871 		    valuePush(ctxt, xmlXPathCacheWrapString(
   8872 			ctxt->context, fullname));
   8873                 }
   8874                 break;
   8875             default:
   8876 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8877 		    cur->nodesetval->nodeTab[i]));
   8878                 xmlXPathLocalNameFunction(ctxt, 1);
   8879         }
   8880     }
   8881     xmlXPathReleaseObject(ctxt->context, cur);
   8882 }
   8883 
   8884 
   8885 /**
   8886  * xmlXPathStringFunction:
   8887  * @ctxt:  the XPath Parser context
   8888  * @nargs:  the number of arguments
   8889  *
   8890  * Implement the string() XPath function
   8891  *    string string(object?)
   8892  * The string function converts an object to a string as follows:
   8893  *    - A node-set is converted to a string by returning the value of
   8894  *      the node in the node-set that is first in document order.
   8895  *      If the node-set is empty, an empty string is returned.
   8896  *    - A number is converted to a string as follows
   8897  *      + NaN is converted to the string NaN
   8898  *      + positive zero is converted to the string 0
   8899  *      + negative zero is converted to the string 0
   8900  *      + positive infinity is converted to the string Infinity
   8901  *      + negative infinity is converted to the string -Infinity
   8902  *      + if the number is an integer, the number is represented in
   8903  *        decimal form as a Number with no decimal point and no leading
   8904  *        zeros, preceded by a minus sign (-) if the number is negative
   8905  *      + otherwise, the number is represented in decimal form as a
   8906  *        Number including a decimal point with at least one digit
   8907  *        before the decimal point and at least one digit after the
   8908  *        decimal point, preceded by a minus sign (-) if the number
   8909  *        is negative; there must be no leading zeros before the decimal
   8910  *        point apart possibly from the one required digit immediately
   8911  *        before the decimal point; beyond the one required digit
   8912  *        after the decimal point there must be as many, but only as
   8913  *        many, more digits as are needed to uniquely distinguish the
   8914  *        number from all other IEEE 754 numeric values.
   8915  *    - The boolean false value is converted to the string false.
   8916  *      The boolean true value is converted to the string true.
   8917  *
   8918  * If the argument is omitted, it defaults to a node-set with the
   8919  * context node as its only member.
   8920  */
   8921 void
   8922 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8923     xmlXPathObjectPtr cur;
   8924 
   8925     if (ctxt == NULL) return;
   8926     if (nargs == 0) {
   8927     valuePush(ctxt,
   8928 	xmlXPathCacheWrapString(ctxt->context,
   8929 	    xmlXPathCastNodeToString(ctxt->context->node)));
   8930 	return;
   8931     }
   8932 
   8933     CHECK_ARITY(1);
   8934     cur = valuePop(ctxt);
   8935     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   8936     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
   8937 }
   8938 
   8939 /**
   8940  * xmlXPathStringLengthFunction:
   8941  * @ctxt:  the XPath Parser context
   8942  * @nargs:  the number of arguments
   8943  *
   8944  * Implement the string-length() XPath function
   8945  *    number string-length(string?)
   8946  * The string-length returns the number of characters in the string
   8947  * (see [3.6 Strings]). If the argument is omitted, it defaults to
   8948  * the context node converted to a string, in other words the value
   8949  * of the context node.
   8950  */
   8951 void
   8952 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8953     xmlXPathObjectPtr cur;
   8954 
   8955     if (nargs == 0) {
   8956         if ((ctxt == NULL) || (ctxt->context == NULL))
   8957 	    return;
   8958 	if (ctxt->context->node == NULL) {
   8959 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
   8960 	} else {
   8961 	    xmlChar *content;
   8962 
   8963 	    content = xmlXPathCastNodeToString(ctxt->context->node);
   8964 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8965 		xmlUTF8Strlen(content)));
   8966 	    xmlFree(content);
   8967 	}
   8968 	return;
   8969     }
   8970     CHECK_ARITY(1);
   8971     CAST_TO_STRING;
   8972     CHECK_TYPE(XPATH_STRING);
   8973     cur = valuePop(ctxt);
   8974     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8975 	xmlUTF8Strlen(cur->stringval)));
   8976     xmlXPathReleaseObject(ctxt->context, cur);
   8977 }
   8978 
   8979 /**
   8980  * xmlXPathConcatFunction:
   8981  * @ctxt:  the XPath Parser context
   8982  * @nargs:  the number of arguments
   8983  *
   8984  * Implement the concat() XPath function
   8985  *    string concat(string, string, string*)
   8986  * The concat function returns the concatenation of its arguments.
   8987  */
   8988 void
   8989 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8990     xmlXPathObjectPtr cur, newobj;
   8991     xmlChar *tmp;
   8992 
   8993     if (ctxt == NULL) return;
   8994     if (nargs < 2) {
   8995 	CHECK_ARITY(2);
   8996     }
   8997 
   8998     CAST_TO_STRING;
   8999     cur = valuePop(ctxt);
   9000     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
   9001 	xmlXPathReleaseObject(ctxt->context, cur);
   9002 	return;
   9003     }
   9004     nargs--;
   9005 
   9006     while (nargs > 0) {
   9007 	CAST_TO_STRING;
   9008 	newobj = valuePop(ctxt);
   9009 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
   9010 	    xmlXPathReleaseObject(ctxt->context, newobj);
   9011 	    xmlXPathReleaseObject(ctxt->context, cur);
   9012 	    XP_ERROR(XPATH_INVALID_TYPE);
   9013 	}
   9014 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
   9015 	newobj->stringval = cur->stringval;
   9016 	cur->stringval = tmp;
   9017 	xmlXPathReleaseObject(ctxt->context, newobj);
   9018 	nargs--;
   9019     }
   9020     valuePush(ctxt, cur);
   9021 }
   9022 
   9023 /**
   9024  * xmlXPathContainsFunction:
   9025  * @ctxt:  the XPath Parser context
   9026  * @nargs:  the number of arguments
   9027  *
   9028  * Implement the contains() XPath function
   9029  *    boolean contains(string, string)
   9030  * The contains function returns true if the first argument string
   9031  * contains the second argument string, and otherwise returns false.
   9032  */
   9033 void
   9034 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9035     xmlXPathObjectPtr hay, needle;
   9036 
   9037     CHECK_ARITY(2);
   9038     CAST_TO_STRING;
   9039     CHECK_TYPE(XPATH_STRING);
   9040     needle = valuePop(ctxt);
   9041     CAST_TO_STRING;
   9042     hay = valuePop(ctxt);
   9043 
   9044     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
   9045 	xmlXPathReleaseObject(ctxt->context, hay);
   9046 	xmlXPathReleaseObject(ctxt->context, needle);
   9047 	XP_ERROR(XPATH_INVALID_TYPE);
   9048     }
   9049     if (xmlStrstr(hay->stringval, needle->stringval))
   9050 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   9051     else
   9052 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   9053     xmlXPathReleaseObject(ctxt->context, hay);
   9054     xmlXPathReleaseObject(ctxt->context, needle);
   9055 }
   9056 
   9057 /**
   9058  * xmlXPathStartsWithFunction:
   9059  * @ctxt:  the XPath Parser context
   9060  * @nargs:  the number of arguments
   9061  *
   9062  * Implement the starts-with() XPath function
   9063  *    boolean starts-with(string, string)
   9064  * The starts-with function returns true if the first argument string
   9065  * starts with the second argument string, and otherwise returns false.
   9066  */
   9067 void
   9068 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9069     xmlXPathObjectPtr hay, needle;
   9070     int n;
   9071 
   9072     CHECK_ARITY(2);
   9073     CAST_TO_STRING;
   9074     CHECK_TYPE(XPATH_STRING);
   9075     needle = valuePop(ctxt);
   9076     CAST_TO_STRING;
   9077     hay = valuePop(ctxt);
   9078 
   9079     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
   9080 	xmlXPathReleaseObject(ctxt->context, hay);
   9081 	xmlXPathReleaseObject(ctxt->context, needle);
   9082 	XP_ERROR(XPATH_INVALID_TYPE);
   9083     }
   9084     n = xmlStrlen(needle->stringval);
   9085     if (xmlStrncmp(hay->stringval, needle->stringval, n))
   9086         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   9087     else
   9088         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   9089     xmlXPathReleaseObject(ctxt->context, hay);
   9090     xmlXPathReleaseObject(ctxt->context, needle);
   9091 }
   9092 
   9093 /**
   9094  * xmlXPathSubstringFunction:
   9095  * @ctxt:  the XPath Parser context
   9096  * @nargs:  the number of arguments
   9097  *
   9098  * Implement the substring() XPath function
   9099  *    string substring(string, number, number?)
   9100  * The substring function returns the substring of the first argument
   9101  * starting at the position specified in the second argument with
   9102  * length specified in the third argument. For example,
   9103  * substring("12345",2,3) returns "234". If the third argument is not
   9104  * specified, it returns the substring starting at the position specified
   9105  * in the second argument and continuing to the end of the string. For
   9106  * example, substring("12345",2) returns "2345".  More precisely, each
   9107  * character in the string (see [3.6 Strings]) is considered to have a
   9108  * numeric position: the position of the first character is 1, the position
   9109  * of the second character is 2 and so on. The returned substring contains
   9110  * those characters for which the position of the character is greater than
   9111  * or equal to the second argument and, if the third argument is specified,
   9112  * less than the sum of the second and third arguments; the comparisons
   9113  * and addition used for the above follow the standard IEEE 754 rules. Thus:
   9114  *  - substring("12345", 1.5, 2.6) returns "234"
   9115  *  - substring("12345", 0, 3) returns "12"
   9116  *  - substring("12345", 0 div 0, 3) returns ""
   9117  *  - substring("12345", 1, 0 div 0) returns ""
   9118  *  - substring("12345", -42, 1 div 0) returns "12345"
   9119  *  - substring("12345", -1 div 0, 1 div 0) returns ""
   9120  */
   9121 void
   9122 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9123     xmlXPathObjectPtr str, start, len;
   9124     double le=0, in;
   9125     int i, l, m;
   9126     xmlChar *ret;
   9127 
   9128     if (nargs < 2) {
   9129 	CHECK_ARITY(2);
   9130     }
   9131     if (nargs > 3) {
   9132 	CHECK_ARITY(3);
   9133     }
   9134     /*
   9135      * take care of possible last (position) argument
   9136     */
   9137     if (nargs == 3) {
   9138 	CAST_TO_NUMBER;
   9139 	CHECK_TYPE(XPATH_NUMBER);
   9140 	len = valuePop(ctxt);
   9141 	le = len->floatval;
   9142 	xmlXPathReleaseObject(ctxt->context, len);
   9143     }
   9144 
   9145     CAST_TO_NUMBER;
   9146     CHECK_TYPE(XPATH_NUMBER);
   9147     start = valuePop(ctxt);
   9148     in = start->floatval;
   9149     xmlXPathReleaseObject(ctxt->context, start);
   9150     CAST_TO_STRING;
   9151     CHECK_TYPE(XPATH_STRING);
   9152     str = valuePop(ctxt);
   9153     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
   9154 
   9155     /*
   9156      * If last pos not present, calculate last position
   9157     */
   9158     if (nargs != 3) {
   9159 	le = (double)m;
   9160 	if (in < 1.0)
   9161 	    in = 1.0;
   9162     }
   9163 
   9164     /* Need to check for the special cases where either
   9165      * the index is NaN, the length is NaN, or both
   9166      * arguments are infinity (relying on Inf + -Inf = NaN)
   9167      */
   9168     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
   9169         /*
   9170          * To meet the requirements of the spec, the arguments
   9171 	 * must be converted to integer format before
   9172 	 * initial index calculations are done
   9173          *
   9174          * First we go to integer form, rounding up
   9175 	 * and checking for special cases
   9176          */
   9177         i = (int) in;
   9178         if (((double)i)+0.5 <= in) i++;
   9179 
   9180 	if (xmlXPathIsInf(le) == 1) {
   9181 	    l = m;
   9182 	    if (i < 1)
   9183 		i = 1;
   9184 	}
   9185 	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
   9186 	    l = 0;
   9187 	else {
   9188 	    l = (int) le;
   9189 	    if (((double)l)+0.5 <= le) l++;
   9190 	}
   9191 
   9192 	/* Now we normalize inidices */
   9193         i -= 1;
   9194         l += i;
   9195         if (i < 0)
   9196             i = 0;
   9197         if (l > m)
   9198             l = m;
   9199 
   9200         /* number of chars to copy */
   9201         l -= i;
   9202 
   9203         ret = xmlUTF8Strsub(str->stringval, i, l);
   9204     }
   9205     else {
   9206         ret = NULL;
   9207     }
   9208     if (ret == NULL)
   9209 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   9210     else {
   9211 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
   9212 	xmlFree(ret);
   9213     }
   9214     xmlXPathReleaseObject(ctxt->context, str);
   9215 }
   9216 
   9217 /**
   9218  * xmlXPathSubstringBeforeFunction:
   9219  * @ctxt:  the XPath Parser context
   9220  * @nargs:  the number of arguments
   9221  *
   9222  * Implement the substring-before() XPath function
   9223  *    string substring-before(string, string)
   9224  * The substring-before function returns the substring of the first
   9225  * argument string that precedes the first occurrence of the second
   9226  * argument string in the first argument string, or the empty string
   9227  * if the first argument string does not contain the second argument
   9228  * string. For example, substring-before("1999/04/01","/") returns 1999.
   9229  */
   9230 void
   9231 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9232   xmlXPathObjectPtr str;
   9233   xmlXPathObjectPtr find;
   9234   xmlBufPtr target;
   9235   const xmlChar *point;
   9236   int offset;
   9237 
   9238   CHECK_ARITY(2);
   9239   CAST_TO_STRING;
   9240   find = valuePop(ctxt);
   9241   CAST_TO_STRING;
   9242   str = valuePop(ctxt);
   9243 
   9244   target = xmlBufCreate();
   9245   if (target) {
   9246     point = xmlStrstr(str->stringval, find->stringval);
   9247     if (point) {
   9248       offset = (int)(point - str->stringval);
   9249       xmlBufAdd(target, str->stringval, offset);
   9250     }
   9251     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9252 	xmlBufContent(target)));
   9253     xmlBufFree(target);
   9254   }
   9255   xmlXPathReleaseObject(ctxt->context, str);
   9256   xmlXPathReleaseObject(ctxt->context, find);
   9257 }
   9258 
   9259 /**
   9260  * xmlXPathSubstringAfterFunction:
   9261  * @ctxt:  the XPath Parser context
   9262  * @nargs:  the number of arguments
   9263  *
   9264  * Implement the substring-after() XPath function
   9265  *    string substring-after(string, string)
   9266  * The substring-after function returns the substring of the first
   9267  * argument string that follows the first occurrence of the second
   9268  * argument string in the first argument string, or the empty stringi
   9269  * if the first argument string does not contain the second argument
   9270  * string. For example, substring-after("1999/04/01","/") returns 04/01,
   9271  * and substring-after("1999/04/01","19") returns 99/04/01.
   9272  */
   9273 void
   9274 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9275   xmlXPathObjectPtr str;
   9276   xmlXPathObjectPtr find;
   9277   xmlBufPtr target;
   9278   const xmlChar *point;
   9279   int offset;
   9280 
   9281   CHECK_ARITY(2);
   9282   CAST_TO_STRING;
   9283   find = valuePop(ctxt);
   9284   CAST_TO_STRING;
   9285   str = valuePop(ctxt);
   9286 
   9287   target = xmlBufCreate();
   9288   if (target) {
   9289     point = xmlStrstr(str->stringval, find->stringval);
   9290     if (point) {
   9291       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
   9292       xmlBufAdd(target, &str->stringval[offset],
   9293 		   xmlStrlen(str->stringval) - offset);
   9294     }
   9295     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9296 	xmlBufContent(target)));
   9297     xmlBufFree(target);
   9298   }
   9299   xmlXPathReleaseObject(ctxt->context, str);
   9300   xmlXPathReleaseObject(ctxt->context, find);
   9301 }
   9302 
   9303 /**
   9304  * xmlXPathNormalizeFunction:
   9305  * @ctxt:  the XPath Parser context
   9306  * @nargs:  the number of arguments
   9307  *
   9308  * Implement the normalize-space() XPath function
   9309  *    string normalize-space(string?)
   9310  * The normalize-space function returns the argument string with white
   9311  * space normalized by stripping leading and trailing whitespace
   9312  * and replacing sequences of whitespace characters by a single
   9313  * space. Whitespace characters are the same allowed by the S production
   9314  * in XML. If the argument is omitted, it defaults to the context
   9315  * node converted to a string, in other words the value of the context node.
   9316  */
   9317 void
   9318 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9319   xmlXPathObjectPtr obj = NULL;
   9320   xmlChar *source = NULL;
   9321   xmlBufPtr target;
   9322   xmlChar blank;
   9323 
   9324   if (ctxt == NULL) return;
   9325   if (nargs == 0) {
   9326     /* Use current context node */
   9327       valuePush(ctxt,
   9328 	  xmlXPathCacheWrapString(ctxt->context,
   9329 	    xmlXPathCastNodeToString(ctxt->context->node)));
   9330     nargs = 1;
   9331   }
   9332 
   9333   CHECK_ARITY(1);
   9334   CAST_TO_STRING;
   9335   CHECK_TYPE(XPATH_STRING);
   9336   obj = valuePop(ctxt);
   9337   source = obj->stringval;
   9338 
   9339   target = xmlBufCreate();
   9340   if (target && source) {
   9341 
   9342     /* Skip leading whitespaces */
   9343     while (IS_BLANK_CH(*source))
   9344       source++;
   9345 
   9346     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
   9347     blank = 0;
   9348     while (*source) {
   9349       if (IS_BLANK_CH(*source)) {
   9350 	blank = 0x20;
   9351       } else {
   9352 	if (blank) {
   9353 	  xmlBufAdd(target, &blank, 1);
   9354 	  blank = 0;
   9355 	}
   9356 	xmlBufAdd(target, source, 1);
   9357       }
   9358       source++