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++;
   9359     }
   9360     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9361 	xmlBufContent(target)));
   9362     xmlBufFree(target);
   9363   }
   9364   xmlXPathReleaseObject(ctxt->context, obj);
   9365 }
   9366 
   9367 /**
   9368  * xmlXPathTranslateFunction:
   9369  * @ctxt:  the XPath Parser context
   9370  * @nargs:  the number of arguments
   9371  *
   9372  * Implement the translate() XPath function
   9373  *    string translate(string, string, string)
   9374  * The translate function returns the first argument string with
   9375  * occurrences of characters in the second argument string replaced
   9376  * by the character at the corresponding position in the third argument
   9377  * string. For example, translate("bar","abc","ABC") returns the string
   9378  * BAr. If there is a character in the second argument string with no
   9379  * character at a corresponding position in the third argument string
   9380  * (because the second argument string is longer than the third argument
   9381  * string), then occurrences of that character in the first argument
   9382  * string are removed. For example, translate("--aaa--","abc-","ABC")
   9383  * returns "AAA". If a character occurs more than once in second
   9384  * argument string, then the first occurrence determines the replacement
   9385  * character. If the third argument string is longer than the second
   9386  * argument string, then excess characters are ignored.
   9387  */
   9388 void
   9389 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9390     xmlXPathObjectPtr str;
   9391     xmlXPathObjectPtr from;
   9392     xmlXPathObjectPtr to;
   9393     xmlBufPtr target;
   9394     int offset, max;
   9395     xmlChar ch;
   9396     const xmlChar *point;
   9397     xmlChar *cptr;
   9398 
   9399     CHECK_ARITY(3);
   9400 
   9401     CAST_TO_STRING;
   9402     to = valuePop(ctxt);
   9403     CAST_TO_STRING;
   9404     from = valuePop(ctxt);
   9405     CAST_TO_STRING;
   9406     str = valuePop(ctxt);
   9407 
   9408     target = xmlBufCreate();
   9409     if (target) {
   9410 	max = xmlUTF8Strlen(to->stringval);
   9411 	for (cptr = str->stringval; (ch=*cptr); ) {
   9412 	    offset = xmlUTF8Strloc(from->stringval, cptr);
   9413 	    if (offset >= 0) {
   9414 		if (offset < max) {
   9415 		    point = xmlUTF8Strpos(to->stringval, offset);
   9416 		    if (point)
   9417 			xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
   9418 		}
   9419 	    } else
   9420 		xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
   9421 
   9422 	    /* Step to next character in input */
   9423 	    cptr++;
   9424 	    if ( ch & 0x80 ) {
   9425 		/* if not simple ascii, verify proper format */
   9426 		if ( (ch & 0xc0) != 0xc0 ) {
   9427 		    xmlGenericError(xmlGenericErrorContext,
   9428 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
   9429                     /* not asserting an XPath error is probably better */
   9430 		    break;
   9431 		}
   9432 		/* then skip over remaining bytes for this char */
   9433 		while ( (ch <<= 1) & 0x80 )
   9434 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
   9435 			xmlGenericError(xmlGenericErrorContext,
   9436 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
   9437                         /* not asserting an XPath error is probably better */
   9438 			break;
   9439 		    }
   9440 		if (ch & 0x80) /* must have had error encountered */
   9441 		    break;
   9442 	    }
   9443 	}
   9444     }
   9445     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9446 	xmlBufContent(target)));
   9447     xmlBufFree(target);
   9448     xmlXPathReleaseObject(ctxt->context, str);
   9449     xmlXPathReleaseObject(ctxt->context, from);
   9450     xmlXPathReleaseObject(ctxt->context, to);
   9451 }
   9452 
   9453 /**
   9454  * xmlXPathBooleanFunction:
   9455  * @ctxt:  the XPath Parser context
   9456  * @nargs:  the number of arguments
   9457  *
   9458  * Implement the boolean() XPath function
   9459  *    boolean boolean(object)
   9460  * The boolean function converts its argument to a boolean as follows:
   9461  *    - a number is true if and only if it is neither positive or
   9462  *      negative zero nor NaN
   9463  *    - a node-set is true if and only if it is non-empty
   9464  *    - a string is true if and only if its length is non-zero
   9465  */
   9466 void
   9467 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9468     xmlXPathObjectPtr cur;
   9469 
   9470     CHECK_ARITY(1);
   9471     cur = valuePop(ctxt);
   9472     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   9473     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
   9474     valuePush(ctxt, cur);
   9475 }
   9476 
   9477 /**
   9478  * xmlXPathNotFunction:
   9479  * @ctxt:  the XPath Parser context
   9480  * @nargs:  the number of arguments
   9481  *
   9482  * Implement the not() XPath function
   9483  *    boolean not(boolean)
   9484  * The not function returns true if its argument is false,
   9485  * and false otherwise.
   9486  */
   9487 void
   9488 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9489     CHECK_ARITY(1);
   9490     CAST_TO_BOOLEAN;
   9491     CHECK_TYPE(XPATH_BOOLEAN);
   9492     ctxt->value->boolval = ! ctxt->value->boolval;
   9493 }
   9494 
   9495 /**
   9496  * xmlXPathTrueFunction:
   9497  * @ctxt:  the XPath Parser context
   9498  * @nargs:  the number of arguments
   9499  *
   9500  * Implement the true() XPath function
   9501  *    boolean true()
   9502  */
   9503 void
   9504 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9505     CHECK_ARITY(0);
   9506     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   9507 }
   9508 
   9509 /**
   9510  * xmlXPathFalseFunction:
   9511  * @ctxt:  the XPath Parser context
   9512  * @nargs:  the number of arguments
   9513  *
   9514  * Implement the false() XPath function
   9515  *    boolean false()
   9516  */
   9517 void
   9518 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9519     CHECK_ARITY(0);
   9520     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   9521 }
   9522 
   9523 /**
   9524  * xmlXPathLangFunction:
   9525  * @ctxt:  the XPath Parser context
   9526  * @nargs:  the number of arguments
   9527  *
   9528  * Implement the lang() XPath function
   9529  *    boolean lang(string)
   9530  * The lang function returns true or false depending on whether the
   9531  * language of the context node as specified by xml:lang attributes
   9532  * is the same as or is a sublanguage of the language specified by
   9533  * the argument string. The language of the context node is determined
   9534  * by the value of the xml:lang attribute on the context node, or, if
   9535  * the context node has no xml:lang attribute, by the value of the
   9536  * xml:lang attribute on the nearest ancestor of the context node that
   9537  * has an xml:lang attribute. If there is no such attribute, then lang
   9538  * returns false. If there is such an attribute, then lang returns
   9539  * true if the attribute value is equal to the argument ignoring case,
   9540  * or if there is some suffix starting with - such that the attribute
   9541  * value is equal to the argument ignoring that suffix of the attribute
   9542  * value and ignoring case.
   9543  */
   9544 void
   9545 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9546     xmlXPathObjectPtr val = NULL;
   9547     const xmlChar *theLang = NULL;
   9548     const xmlChar *lang;
   9549     int ret = 0;
   9550     int i;
   9551 
   9552     CHECK_ARITY(1);
   9553     CAST_TO_STRING;
   9554     CHECK_TYPE(XPATH_STRING);
   9555     val = valuePop(ctxt);
   9556     lang = val->stringval;
   9557     theLang = xmlNodeGetLang(ctxt->context->node);
   9558     if ((theLang != NULL) && (lang != NULL)) {
   9559         for (i = 0;lang[i] != 0;i++)
   9560 	    if (toupper(lang[i]) != toupper(theLang[i]))
   9561 	        goto not_equal;
   9562 	if ((theLang[i] == 0) || (theLang[i] == '-'))
   9563 	    ret = 1;
   9564     }
   9565 not_equal:
   9566     if (theLang != NULL)
   9567 	xmlFree((void *)theLang);
   9568 
   9569     xmlXPathReleaseObject(ctxt->context, val);
   9570     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
   9571 }
   9572 
   9573 /**
   9574  * xmlXPathNumberFunction:
   9575  * @ctxt:  the XPath Parser context
   9576  * @nargs:  the number of arguments
   9577  *
   9578  * Implement the number() XPath function
   9579  *    number number(object?)
   9580  */
   9581 void
   9582 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9583     xmlXPathObjectPtr cur;
   9584     double res;
   9585 
   9586     if (ctxt == NULL) return;
   9587     if (nargs == 0) {
   9588 	if (ctxt->context->node == NULL) {
   9589 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
   9590 	} else {
   9591 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
   9592 
   9593 	    res = xmlXPathStringEvalNumber(content);
   9594 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
   9595 	    xmlFree(content);
   9596 	}
   9597 	return;
   9598     }
   9599 
   9600     CHECK_ARITY(1);
   9601     cur = valuePop(ctxt);
   9602     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
   9603 }
   9604 
   9605 /**
   9606  * xmlXPathSumFunction:
   9607  * @ctxt:  the XPath Parser context
   9608  * @nargs:  the number of arguments
   9609  *
   9610  * Implement the sum() XPath function
   9611  *    number sum(node-set)
   9612  * The sum function returns the sum of the values of the nodes in
   9613  * the argument node-set.
   9614  */
   9615 void
   9616 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9617     xmlXPathObjectPtr cur;
   9618     int i;
   9619     double res = 0.0;
   9620 
   9621     CHECK_ARITY(1);
   9622     if ((ctxt->value == NULL) ||
   9623 	((ctxt->value->type != XPATH_NODESET) &&
   9624 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   9625 	XP_ERROR(XPATH_INVALID_TYPE);
   9626     cur = valuePop(ctxt);
   9627 
   9628     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
   9629 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
   9630 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
   9631 	}
   9632     }
   9633     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
   9634     xmlXPathReleaseObject(ctxt->context, cur);
   9635 }
   9636 
   9637 /*
   9638  * To assure working code on multiple platforms, we want to only depend
   9639  * upon the characteristic truncation of converting a floating point value
   9640  * to an integer.  Unfortunately, because of the different storage sizes
   9641  * of our internal floating point value (double) and integer (int), we
   9642  * can't directly convert (see bug 301162).  This macro is a messy
   9643  * 'workaround'
   9644  */
   9645 #define XTRUNC(f, v)            \
   9646     f = fmod((v), INT_MAX);     \
   9647     f = (v) - (f) + (double)((int)(f));
   9648 
   9649 /**
   9650  * xmlXPathFloorFunction:
   9651  * @ctxt:  the XPath Parser context
   9652  * @nargs:  the number of arguments
   9653  *
   9654  * Implement the floor() XPath function
   9655  *    number floor(number)
   9656  * The floor function returns the largest (closest to positive infinity)
   9657  * number that is not greater than the argument and that is an integer.
   9658  */
   9659 void
   9660 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9661     double f;
   9662 
   9663     CHECK_ARITY(1);
   9664     CAST_TO_NUMBER;
   9665     CHECK_TYPE(XPATH_NUMBER);
   9666 
   9667     XTRUNC(f, ctxt->value->floatval);
   9668     if (f != ctxt->value->floatval) {
   9669 	if (ctxt->value->floatval > 0)
   9670 	    ctxt->value->floatval = f;
   9671 	else
   9672 	    ctxt->value->floatval = f - 1;
   9673     }
   9674 }
   9675 
   9676 /**
   9677  * xmlXPathCeilingFunction:
   9678  * @ctxt:  the XPath Parser context
   9679  * @nargs:  the number of arguments
   9680  *
   9681  * Implement the ceiling() XPath function
   9682  *    number ceiling(number)
   9683  * The ceiling function returns the smallest (closest to negative infinity)
   9684  * number that is not less than the argument and that is an integer.
   9685  */
   9686 void
   9687 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9688     double f;
   9689 
   9690     CHECK_ARITY(1);
   9691     CAST_TO_NUMBER;
   9692     CHECK_TYPE(XPATH_NUMBER);
   9693 
   9694 #if 0
   9695     ctxt->value->floatval = ceil(ctxt->value->floatval);
   9696 #else
   9697     XTRUNC(f, ctxt->value->floatval);
   9698     if (f != ctxt->value->floatval) {
   9699 	if (ctxt->value->floatval > 0)
   9700 	    ctxt->value->floatval = f + 1;
   9701 	else {
   9702 	    if (ctxt->value->floatval < 0 && f == 0)
   9703 	        ctxt->value->floatval = xmlXPathNZERO;
   9704 	    else
   9705 	        ctxt->value->floatval = f;
   9706 	}
   9707 
   9708     }
   9709 #endif
   9710 }
   9711 
   9712 /**
   9713  * xmlXPathRoundFunction:
   9714  * @ctxt:  the XPath Parser context
   9715  * @nargs:  the number of arguments
   9716  *
   9717  * Implement the round() XPath function
   9718  *    number round(number)
   9719  * The round function returns the number that is closest to the
   9720  * argument and that is an integer. If there are two such numbers,
   9721  * then the one that is even is returned.
   9722  */
   9723 void
   9724 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9725     double f;
   9726 
   9727     CHECK_ARITY(1);
   9728     CAST_TO_NUMBER;
   9729     CHECK_TYPE(XPATH_NUMBER);
   9730 
   9731     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
   9732 	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
   9733 	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
   9734 	(ctxt->value->floatval == 0.0))
   9735 	return;
   9736 
   9737     XTRUNC(f, ctxt->value->floatval);
   9738     if (ctxt->value->floatval < 0) {
   9739 	if (ctxt->value->floatval < f - 0.5)
   9740 	    ctxt->value->floatval = f - 1;
   9741 	else
   9742 	    ctxt->value->floatval = f;
   9743 	if (ctxt->value->floatval == 0)
   9744 	    ctxt->value->floatval = xmlXPathNZERO;
   9745     } else {
   9746 	if (ctxt->value->floatval < f + 0.5)
   9747 	    ctxt->value->floatval = f;
   9748 	else
   9749 	    ctxt->value->floatval = f + 1;
   9750     }
   9751 }
   9752 
   9753 /************************************************************************
   9754  *									*
   9755  *			The Parser					*
   9756  *									*
   9757  ************************************************************************/
   9758 
   9759 /*
   9760  * a few forward declarations since we use a recursive call based
   9761  * implementation.
   9762  */
   9763 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
   9764 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
   9765 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
   9766 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
   9767 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
   9768 	                                  int qualified);
   9769 
   9770 /**
   9771  * xmlXPathCurrentChar:
   9772  * @ctxt:  the XPath parser context
   9773  * @cur:  pointer to the beginning of the char
   9774  * @len:  pointer to the length of the char read
   9775  *
   9776  * The current char value, if using UTF-8 this may actually span multiple
   9777  * bytes in the input buffer.
   9778  *
   9779  * Returns the current char value and its length
   9780  */
   9781 
   9782 static int
   9783 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
   9784     unsigned char c;
   9785     unsigned int val;
   9786     const xmlChar *cur;
   9787 
   9788     if (ctxt == NULL)
   9789 	return(0);
   9790     cur = ctxt->cur;
   9791 
   9792     /*
   9793      * We are supposed to handle UTF8, check it's valid
   9794      * From rfc2044: encoding of the Unicode values on UTF-8:
   9795      *
   9796      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
   9797      * 0000 0000-0000 007F   0xxxxxxx
   9798      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
   9799      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
   9800      *
   9801      * Check for the 0x110000 limit too
   9802      */
   9803     c = *cur;
   9804     if (c & 0x80) {
   9805 	if ((cur[1] & 0xc0) != 0x80)
   9806 	    goto encoding_error;
   9807 	if ((c & 0xe0) == 0xe0) {
   9808 
   9809 	    if ((cur[2] & 0xc0) != 0x80)
   9810 		goto encoding_error;
   9811 	    if ((c & 0xf0) == 0xf0) {
   9812 		if (((c & 0xf8) != 0xf0) ||
   9813 		    ((cur[3] & 0xc0) != 0x80))
   9814 		    goto encoding_error;
   9815 		/* 4-byte code */
   9816 		*len = 4;
   9817 		val = (cur[0] & 0x7) << 18;
   9818 		val |= (cur[1] & 0x3f) << 12;
   9819 		val |= (cur[2] & 0x3f) << 6;
   9820 		val |= cur[3] & 0x3f;
   9821 	    } else {
   9822 	      /* 3-byte code */
   9823 		*len = 3;
   9824 		val = (cur[0] & 0xf) << 12;
   9825 		val |= (cur[1] & 0x3f) << 6;
   9826 		val |= cur[2] & 0x3f;
   9827 	    }
   9828 	} else {
   9829 	  /* 2-byte code */
   9830 	    *len = 2;
   9831 	    val = (cur[0] & 0x1f) << 6;
   9832 	    val |= cur[1] & 0x3f;
   9833 	}
   9834 	if (!IS_CHAR(val)) {
   9835 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
   9836 	}
   9837 	return(val);
   9838     } else {
   9839 	/* 1-byte code */
   9840 	*len = 1;
   9841 	return((int) *cur);
   9842     }
   9843 encoding_error:
   9844     /*
   9845      * If we detect an UTF8 error that probably means that the
   9846      * input encoding didn't get properly advertised in the
   9847      * declaration header. Report the error and switch the encoding
   9848      * to ISO-Latin-1 (if you don't like this policy, just declare the
   9849      * encoding !)
   9850      */
   9851     *len = 0;
   9852     XP_ERROR0(XPATH_ENCODING_ERROR);
   9853 }
   9854 
   9855 /**
   9856  * xmlXPathParseNCName:
   9857  * @ctxt:  the XPath Parser context
   9858  *
   9859  * parse an XML namespace non qualified name.
   9860  *
   9861  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
   9862  *
   9863  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
   9864  *                       CombiningChar | Extender
   9865  *
   9866  * Returns the namespace name or NULL
   9867  */
   9868 
   9869 xmlChar *
   9870 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
   9871     const xmlChar *in;
   9872     xmlChar *ret;
   9873     int count = 0;
   9874 
   9875     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
   9876     /*
   9877      * Accelerator for simple ASCII names
   9878      */
   9879     in = ctxt->cur;
   9880     if (((*in >= 0x61) && (*in <= 0x7A)) ||
   9881 	((*in >= 0x41) && (*in <= 0x5A)) ||
   9882 	(*in == '_')) {
   9883 	in++;
   9884 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
   9885 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
   9886 	       ((*in >= 0x30) && (*in <= 0x39)) ||
   9887 	       (*in == '_') || (*in == '.') ||
   9888 	       (*in == '-'))
   9889 	    in++;
   9890 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
   9891             (*in == '[') || (*in == ']') || (*in == ':') ||
   9892             (*in == '@') || (*in == '*')) {
   9893 	    count = in - ctxt->cur;
   9894 	    if (count == 0)
   9895 		return(NULL);
   9896 	    ret = xmlStrndup(ctxt->cur, count);
   9897 	    ctxt->cur = in;
   9898 	    return(ret);
   9899 	}
   9900     }
   9901     return(xmlXPathParseNameComplex(ctxt, 0));
   9902 }
   9903 
   9904 
   9905 /**
   9906  * xmlXPathParseQName:
   9907  * @ctxt:  the XPath Parser context
   9908  * @prefix:  a xmlChar **
   9909  *
   9910  * parse an XML qualified name
   9911  *
   9912  * [NS 5] QName ::= (Prefix ':')? LocalPart
   9913  *
   9914  * [NS 6] Prefix ::= NCName
   9915  *
   9916  * [NS 7] LocalPart ::= NCName
   9917  *
   9918  * Returns the function returns the local part, and prefix is updated
   9919  *   to get the Prefix if any.
   9920  */
   9921 
   9922 static xmlChar *
   9923 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
   9924     xmlChar *ret = NULL;
   9925 
   9926     *prefix = NULL;
   9927     ret = xmlXPathParseNCName(ctxt);
   9928     if (ret && CUR == ':') {
   9929         *prefix = ret;
   9930 	NEXT;
   9931 	ret = xmlXPathParseNCName(ctxt);
   9932     }
   9933     return(ret);
   9934 }
   9935 
   9936 /**
   9937  * xmlXPathParseName:
   9938  * @ctxt:  the XPath Parser context
   9939  *
   9940  * parse an XML name
   9941  *
   9942  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
   9943  *                  CombiningChar | Extender
   9944  *
   9945  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
   9946  *
   9947  * Returns the namespace name or NULL
   9948  */
   9949 
   9950 xmlChar *
   9951 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
   9952     const xmlChar *in;
   9953     xmlChar *ret;
   9954     size_t count = 0;
   9955 
   9956     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
   9957     /*
   9958      * Accelerator for simple ASCII names
   9959      */
   9960     in = ctxt->cur;
   9961     if (((*in >= 0x61) && (*in <= 0x7A)) ||
   9962 	((*in >= 0x41) && (*in <= 0x5A)) ||
   9963 	(*in == '_') || (*in == ':')) {
   9964 	in++;
   9965 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
   9966 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
   9967 	       ((*in >= 0x30) && (*in <= 0x39)) ||
   9968 	       (*in == '_') || (*in == '-') ||
   9969 	       (*in == ':') || (*in == '.'))
   9970 	    in++;
   9971 	if ((*in > 0) && (*in < 0x80)) {
   9972 	    count = in - ctxt->cur;
   9973             if (count > XML_MAX_NAME_LENGTH) {
   9974                 ctxt->cur = in;
   9975                 XP_ERRORNULL(XPATH_EXPR_ERROR);
   9976             }
   9977 	    ret = xmlStrndup(ctxt->cur, count);
   9978 	    ctxt->cur = in;
   9979 	    return(ret);
   9980 	}
   9981     }
   9982     return(xmlXPathParseNameComplex(ctxt, 1));
   9983 }
   9984 
   9985 static xmlChar *
   9986 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
   9987     xmlChar buf[XML_MAX_NAMELEN + 5];
   9988     int len = 0, l;
   9989     int c;
   9990 
   9991     /*
   9992      * Handler for more complex cases
   9993      */
   9994     c = CUR_CHAR(l);
   9995     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
   9996         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
   9997         (c == '*') || /* accelerators */
   9998 	(!IS_LETTER(c) && (c != '_') &&
   9999          ((!qualified) || (c != ':')))) {
   10000 	return(NULL);
   10001     }
   10002 
   10003     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
   10004 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
   10005             (c == '.') || (c == '-') ||
   10006 	    (c == '_') || ((qualified) && (c == ':')) ||
   10007 	    (IS_COMBINING(c)) ||
   10008 	    (IS_EXTENDER(c)))) {
   10009 	COPY_BUF(l,buf,len,c);
   10010 	NEXTL(l);
   10011 	c = CUR_CHAR(l);
   10012 	if (len >= XML_MAX_NAMELEN) {
   10013 	    /*
   10014 	     * Okay someone managed to make a huge name, so he's ready to pay
   10015 	     * for the processing speed.
   10016 	     */
   10017 	    xmlChar *buffer;
   10018 	    int max = len * 2;
   10019 
   10020             if (len > XML_MAX_NAME_LENGTH) {
   10021                 XP_ERRORNULL(XPATH_EXPR_ERROR);
   10022             }
   10023 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
   10024 	    if (buffer == NULL) {
   10025 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
   10026 	    }
   10027 	    memcpy(buffer, buf, len);
   10028 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
   10029 		   (c == '.') || (c == '-') ||
   10030 		   (c == '_') || ((qualified) && (c == ':')) ||
   10031 		   (IS_COMBINING(c)) ||
   10032 		   (IS_EXTENDER(c))) {
   10033 		if (len + 10 > max) {
   10034                     if (max > XML_MAX_NAME_LENGTH) {
   10035                         XP_ERRORNULL(XPATH_EXPR_ERROR);
   10036                     }
   10037 		    max *= 2;
   10038 		    buffer = (xmlChar *) xmlRealloc(buffer,
   10039 			                            max * sizeof(xmlChar));
   10040 		    if (buffer == NULL) {
   10041 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
   10042 		    }
   10043 		}
   10044 		COPY_BUF(l,buffer,len,c);
   10045 		NEXTL(l);
   10046 		c = CUR_CHAR(l);
   10047 	    }
   10048 	    buffer[len] = 0;
   10049 	    return(buffer);
   10050 	}
   10051     }
   10052     if (len == 0)
   10053 	return(NULL);
   10054     return(xmlStrndup(buf, len));
   10055 }
   10056 
   10057 #define MAX_FRAC 20
   10058 
   10059 /*
   10060  * These are used as divisors for the fractional part of a number.
   10061  * Since the table includes 1.0 (representing '0' fractional digits),
   10062  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
   10063  */
   10064 static double my_pow10[MAX_FRAC+1] = {
   10065     1.0, 10.0, 100.0, 1000.0, 10000.0,
   10066     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
   10067     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
   10068     100000000000000.0,
   10069     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
   10070     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
   10071 };
   10072 
   10073 /**
   10074  * xmlXPathStringEvalNumber:
   10075  * @str:  A string to scan
   10076  *
   10077  *  [30a]  Float  ::= Number ('e' Digits?)?
   10078  *
   10079  *  [30]   Number ::=   Digits ('.' Digits?)?
   10080  *                    | '.' Digits
   10081  *  [31]   Digits ::=   [0-9]+
   10082  *
   10083  * Compile a Number in the string
   10084  * In complement of the Number expression, this function also handles
   10085  * negative values : '-' Number.
   10086  *
   10087  * Returns the double value.
   10088  */
   10089 double
   10090 xmlXPathStringEvalNumber(const xmlChar *str) {
   10091     const xmlChar *cur = str;
   10092     double ret;
   10093     int ok = 0;
   10094     int isneg = 0;
   10095     int exponent = 0;
   10096     int is_exponent_negative = 0;
   10097 #ifdef __GNUC__
   10098     unsigned long tmp = 0;
   10099     double temp;
   10100 #endif
   10101     if (cur == NULL) return(0);
   10102     while (IS_BLANK_CH(*cur)) cur++;
   10103     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
   10104         return(xmlXPathNAN);
   10105     }
   10106     if (*cur == '-') {
   10107 	isneg = 1;
   10108 	cur++;
   10109     }
   10110 
   10111 #ifdef __GNUC__
   10112     /*
   10113      * tmp/temp is a workaround against a gcc compiler bug
   10114      * http://veillard.com/gcc.bug
   10115      */
   10116     ret = 0;
   10117     while ((*cur >= '0') && (*cur <= '9')) {
   10118 	ret = ret * 10;
   10119 	tmp = (*cur - '0');
   10120 	ok = 1;
   10121 	cur++;
   10122 	temp = (double) tmp;
   10123 	ret = ret + temp;
   10124     }
   10125 #else
   10126     ret = 0;
   10127     while ((*cur >= '0') && (*cur <= '9')) {
   10128 	ret = ret * 10 + (*cur - '0');
   10129 	ok = 1;
   10130 	cur++;
   10131     }
   10132 #endif
   10133 
   10134     if (*cur == '.') {
   10135 	int v, frac = 0;
   10136 	double fraction = 0;
   10137 
   10138         cur++;
   10139 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
   10140 	    return(xmlXPathNAN);
   10141 	}
   10142 	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
   10143 	    v = (*cur - '0');
   10144 	    fraction = fraction * 10 + v;
   10145 	    frac = frac + 1;
   10146 	    cur++;
   10147 	}
   10148 	fraction /= my_pow10[frac];
   10149 	ret = ret + fraction;
   10150 	while ((*cur >= '0') && (*cur <= '9'))
   10151 	    cur++;
   10152     }
   10153     if ((*cur == 'e') || (*cur == 'E')) {
   10154       cur++;
   10155       if (*cur == '-') {
   10156 	is_exponent_negative = 1;
   10157 	cur++;
   10158       } else if (*cur == '+') {
   10159         cur++;
   10160       }
   10161       while ((*cur >= '0') && (*cur <= '9')) {
   10162 	exponent = exponent * 10 + (*cur - '0');
   10163 	cur++;
   10164       }
   10165     }
   10166     while (IS_BLANK_CH(*cur)) cur++;
   10167     if (*cur != 0) return(xmlXPathNAN);
   10168     if (isneg) ret = -ret;
   10169     if (is_exponent_negative) exponent = -exponent;
   10170     ret *= pow(10.0, (double)exponent);
   10171     return(ret);
   10172 }
   10173 
   10174 /**
   10175  * xmlXPathCompNumber:
   10176  * @ctxt:  the XPath Parser context
   10177  *
   10178  *  [30]   Number ::=   Digits ('.' Digits?)?
   10179  *                    | '.' Digits
   10180  *  [31]   Digits ::=   [0-9]+
   10181  *
   10182  * Compile a Number, then push it on the stack
   10183  *
   10184  */
   10185 static void
   10186 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
   10187 {
   10188     double ret = 0.0;
   10189     int ok = 0;
   10190     int exponent = 0;
   10191     int is_exponent_negative = 0;
   10192 #ifdef __GNUC__
   10193     unsigned long tmp = 0;
   10194     double temp;
   10195 #endif
   10196 
   10197     CHECK_ERROR;
   10198     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
   10199         XP_ERROR(XPATH_NUMBER_ERROR);
   10200     }
   10201 #ifdef __GNUC__
   10202     /*
   10203      * tmp/temp is a workaround against a gcc compiler bug
   10204      * http://veillard.com/gcc.bug
   10205      */
   10206     ret = 0;
   10207     while ((CUR >= '0') && (CUR <= '9')) {
   10208 	ret = ret * 10;
   10209 	tmp = (CUR - '0');
   10210         ok = 1;
   10211         NEXT;
   10212 	temp = (double) tmp;
   10213 	ret = ret + temp;
   10214     }
   10215 #else
   10216     ret = 0;
   10217     while ((CUR >= '0') && (CUR <= '9')) {
   10218 	ret = ret * 10 + (CUR - '0');
   10219 	ok = 1;
   10220 	NEXT;
   10221     }
   10222 #endif
   10223     if (CUR == '.') {
   10224 	int v, frac = 0;
   10225 	double fraction = 0;
   10226 
   10227         NEXT;
   10228         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
   10229             XP_ERROR(XPATH_NUMBER_ERROR);
   10230         }
   10231         while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
   10232 	    v = (CUR - '0');
   10233 	    fraction = fraction * 10 + v;
   10234 	    frac = frac + 1;
   10235             NEXT;
   10236         }
   10237         fraction /= my_pow10[frac];
   10238         ret = ret + fraction;
   10239         while ((CUR >= '0') && (CUR <= '9'))
   10240             NEXT;
   10241     }
   10242     if ((CUR == 'e') || (CUR == 'E')) {
   10243         NEXT;
   10244         if (CUR == '-') {
   10245             is_exponent_negative = 1;
   10246             NEXT;
   10247         } else if (CUR == '+') {
   10248 	    NEXT;
   10249 	}
   10250         while ((CUR >= '0') && (CUR <= '9')) {
   10251             exponent = exponent * 10 + (CUR - '0');
   10252             NEXT;
   10253         }
   10254         if (is_exponent_negative)
   10255             exponent = -exponent;
   10256         ret *= pow(10.0, (double) exponent);
   10257     }
   10258     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
   10259                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
   10260 }
   10261 
   10262 /**
   10263  * xmlXPathParseLiteral:
   10264  * @ctxt:  the XPath Parser context
   10265  *
   10266  * Parse a Literal
   10267  *
   10268  *  [29]   Literal ::=   '"' [^"]* '"'
   10269  *                    | "'" [^']* "'"
   10270  *
   10271  * Returns the value found or NULL in case of error
   10272  */
   10273 static xmlChar *
   10274 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
   10275     const xmlChar *q;
   10276     xmlChar *ret = NULL;
   10277 
   10278     if (CUR == '"') {
   10279         NEXT;
   10280 	q = CUR_PTR;
   10281 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
   10282 	    NEXT;
   10283 	if (!IS_CHAR_CH(CUR)) {
   10284 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
   10285 	} else {
   10286 	    ret = xmlStrndup(q, CUR_PTR - q);
   10287 	    NEXT;
   10288         }
   10289     } else if (CUR == '\'') {
   10290         NEXT;
   10291 	q = CUR_PTR;
   10292 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
   10293 	    NEXT;
   10294 	if (!IS_CHAR_CH(CUR)) {
   10295 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
   10296 	} else {
   10297 	    ret = xmlStrndup(q, CUR_PTR - q);
   10298 	    NEXT;
   10299         }
   10300     } else {
   10301 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
   10302     }
   10303     return(ret);
   10304 }
   10305 
   10306 /**
   10307  * xmlXPathCompLiteral:
   10308  * @ctxt:  the XPath Parser context
   10309  *
   10310  * Parse a Literal and push it on the stack.
   10311  *
   10312  *  [29]   Literal ::=   '"' [^"]* '"'
   10313  *                    | "'" [^']* "'"
   10314  *
   10315  * TODO: xmlXPathCompLiteral memory allocation could be improved.
   10316  */
   10317 static void
   10318 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
   10319     const xmlChar *q;
   10320     xmlChar *ret = NULL;
   10321 
   10322     if (CUR == '"') {
   10323         NEXT;
   10324 	q = CUR_PTR;
   10325 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
   10326 	    NEXT;
   10327 	if (!IS_CHAR_CH(CUR)) {
   10328 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
   10329 	} else {
   10330 	    ret = xmlStrndup(q, CUR_PTR - q);
   10331 	    NEXT;
   10332         }
   10333     } else if (CUR == '\'') {
   10334         NEXT;
   10335 	q = CUR_PTR;
   10336 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
   10337 	    NEXT;
   10338 	if (!IS_CHAR_CH(CUR)) {
   10339 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
   10340 	} else {
   10341 	    ret = xmlStrndup(q, CUR_PTR - q);
   10342 	    NEXT;
   10343         }
   10344     } else {
   10345 	XP_ERROR(XPATH_START_LITERAL_ERROR);
   10346     }
   10347     if (ret == NULL) return;
   10348     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
   10349 	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
   10350     xmlFree(ret);
   10351 }
   10352 
   10353 /**
   10354  * xmlXPathCompVariableReference:
   10355  * @ctxt:  the XPath Parser context
   10356  *
   10357  * Parse a VariableReference, evaluate it and push it on the stack.
   10358  *
   10359  * The variable bindings consist of a mapping from variable names
   10360  * to variable values. The value of a variable is an object, which can be
   10361  * of any of the types that are possible for the value of an expression,
   10362  * and may also be of additional types not specified here.
   10363  *
   10364  * Early evaluation is possible since:
   10365  * The variable bindings [...] used to evaluate a subexpression are
   10366  * always the same as those used to evaluate the containing expression.
   10367  *
   10368  *  [36]   VariableReference ::=   '$' QName
   10369  */
   10370 static void
   10371 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
   10372     xmlChar *name;
   10373     xmlChar *prefix;
   10374 
   10375     SKIP_BLANKS;
   10376     if (CUR != '$') {
   10377 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
   10378     }
   10379     NEXT;
   10380     name = xmlXPathParseQName(ctxt, &prefix);
   10381     if (name == NULL) {
   10382 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
   10383     }
   10384     ctxt->comp->last = -1;
   10385     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
   10386 	           name, prefix);
   10387     SKIP_BLANKS;
   10388     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
   10389 	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
   10390     }
   10391 }
   10392 
   10393 /**
   10394  * xmlXPathIsNodeType:
   10395  * @name:  a name string
   10396  *
   10397  * Is the name given a NodeType one.
   10398  *
   10399  *  [38]   NodeType ::=   'comment'
   10400  *                    | 'text'
   10401  *                    | 'processing-instruction'
   10402  *                    | 'node'
   10403  *
   10404  * Returns 1 if true 0 otherwise
   10405  */
   10406 int
   10407 xmlXPathIsNodeType(const xmlChar *name) {
   10408     if (name == NULL)
   10409 	return(0);
   10410 
   10411     if (xmlStrEqual(name, BAD_CAST "node"))
   10412 	return(1);
   10413     if (xmlStrEqual(name, BAD_CAST "text"))
   10414 	return(1);
   10415     if (xmlStrEqual(name, BAD_CAST "comment"))
   10416 	return(1);
   10417     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
   10418 	return(1);
   10419     return(0);
   10420 }
   10421 
   10422 /**
   10423  * xmlXPathCompFunctionCall:
   10424  * @ctxt:  the XPath Parser context
   10425  *
   10426  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
   10427  *  [17]   Argument ::=   Expr
   10428  *
   10429  * Compile a function call, the evaluation of all arguments are
   10430  * pushed on the stack
   10431  */
   10432 static void
   10433 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
   10434     xmlChar *name;
   10435     xmlChar *prefix;
   10436     int nbargs = 0;
   10437     int sort = 1;
   10438 
   10439     name = xmlXPathParseQName(ctxt, &prefix);
   10440     if (name == NULL) {
   10441 	xmlFree(prefix);
   10442 	XP_ERROR(XPATH_EXPR_ERROR);
   10443     }
   10444     SKIP_BLANKS;
   10445 #ifdef DEBUG_EXPR
   10446     if (prefix == NULL)
   10447 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
   10448 			name);
   10449     else
   10450 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
   10451 			prefix, name);
   10452 #endif
   10453 
   10454     if (CUR != '(') {
   10455 	XP_ERROR(XPATH_EXPR_ERROR);
   10456     }
   10457     NEXT;
   10458     SKIP_BLANKS;
   10459 
   10460     /*
   10461     * Optimization for count(): we don't need the node-set to be sorted.
   10462     */
   10463     if ((prefix == NULL) && (name[0] == 'c') &&
   10464 	xmlStrEqual(name, BAD_CAST "count"))
   10465     {
   10466 	sort = 0;
   10467     }
   10468     ctxt->comp->last = -1;
   10469     if (CUR != ')') {
   10470 	while (CUR != 0) {
   10471 	    int op1 = ctxt->comp->last;
   10472 	    ctxt->comp->last = -1;
   10473 	    xmlXPathCompileExpr(ctxt, sort);
   10474 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   10475 		xmlFree(name);
   10476 		xmlFree(prefix);
   10477 		return;
   10478 	    }
   10479 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
   10480 	    nbargs++;
   10481 	    if (CUR == ')') break;
   10482 	    if (CUR != ',') {
   10483 		XP_ERROR(XPATH_EXPR_ERROR);
   10484 	    }
   10485 	    NEXT;
   10486 	    SKIP_BLANKS;
   10487 	}
   10488     }
   10489     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
   10490 	           name, prefix);
   10491     NEXT;
   10492     SKIP_BLANKS;
   10493 }
   10494 
   10495 /**
   10496  * xmlXPathCompPrimaryExpr:
   10497  * @ctxt:  the XPath Parser context
   10498  *
   10499  *  [15]   PrimaryExpr ::=   VariableReference
   10500  *                | '(' Expr ')'
   10501  *                | Literal
   10502  *                | Number
   10503  *                | FunctionCall
   10504  *
   10505  * Compile a primary expression.
   10506  */
   10507 static void
   10508 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
   10509     SKIP_BLANKS;
   10510     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
   10511     else if (CUR == '(') {
   10512 	NEXT;
   10513 	SKIP_BLANKS;
   10514 	xmlXPathCompileExpr(ctxt, 1);
   10515 	CHECK_ERROR;
   10516 	if (CUR != ')') {
   10517 	    XP_ERROR(XPATH_EXPR_ERROR);
   10518 	}
   10519 	NEXT;
   10520 	SKIP_BLANKS;
   10521     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
   10522 	xmlXPathCompNumber(ctxt);
   10523     } else if ((CUR == '\'') || (CUR == '"')) {
   10524 	xmlXPathCompLiteral(ctxt);
   10525     } else {
   10526 	xmlXPathCompFunctionCall(ctxt);
   10527     }
   10528     SKIP_BLANKS;
   10529 }
   10530 
   10531 /**
   10532  * xmlXPathCompFilterExpr:
   10533  * @ctxt:  the XPath Parser context
   10534  *
   10535  *  [20]   FilterExpr ::=   PrimaryExpr
   10536  *               | FilterExpr Predicate
   10537  *
   10538  * Compile a filter expression.
   10539  * Square brackets are used to filter expressions in the same way that
   10540  * they are used in location paths. It is an error if the expression to
   10541  * be filtered does not evaluate to a node-set. The context node list
   10542  * used for evaluating the expression in square brackets is the node-set
   10543  * to be filtered listed in document order.
   10544  */
   10545 
   10546 static void
   10547 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
   10548     xmlXPathCompPrimaryExpr(ctxt);
   10549     CHECK_ERROR;
   10550     SKIP_BLANKS;
   10551 
   10552     while (CUR == '[') {
   10553 	xmlXPathCompPredicate(ctxt, 1);
   10554 	SKIP_BLANKS;
   10555     }
   10556 
   10557 
   10558 }
   10559 
   10560 /**
   10561  * xmlXPathScanName:
   10562  * @ctxt:  the XPath Parser context
   10563  *
   10564  * Trickery: parse an XML name but without consuming the input flow
   10565  * Needed to avoid insanity in the parser state.
   10566  *
   10567  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
   10568  *                  CombiningChar | Extender
   10569  *
   10570  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
   10571  *
   10572  * [6] Names ::= Name (S Name)*
   10573  *
   10574  * Returns the Name parsed or NULL
   10575  */
   10576 
   10577 static xmlChar *
   10578 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
   10579     int len = 0, l;
   10580     int c;
   10581     const xmlChar *cur;
   10582     xmlChar *ret;
   10583 
   10584     cur = ctxt->cur;
   10585 
   10586     c = CUR_CHAR(l);
   10587     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
   10588 	(!IS_LETTER(c) && (c != '_') &&
   10589          (c != ':'))) {
   10590 	return(NULL);
   10591     }
   10592 
   10593     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
   10594 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
   10595             (c == '.') || (c == '-') ||
   10596 	    (c == '_') || (c == ':') ||
   10597 	    (IS_COMBINING(c)) ||
   10598 	    (IS_EXTENDER(c)))) {
   10599 	len += l;
   10600 	NEXTL(l);
   10601 	c = CUR_CHAR(l);
   10602     }
   10603     ret = xmlStrndup(cur, ctxt->cur - cur);
   10604     ctxt->cur = cur;
   10605     return(ret);
   10606 }
   10607 
   10608 /**
   10609  * xmlXPathCompPathExpr:
   10610  * @ctxt:  the XPath Parser context
   10611  *
   10612  *  [19]   PathExpr ::=   LocationPath
   10613  *               | FilterExpr
   10614  *               | FilterExpr '/' RelativeLocationPath
   10615  *               | FilterExpr '//' RelativeLocationPath
   10616  *
   10617  * Compile a path expression.
   10618  * The / operator and // operators combine an arbitrary expression
   10619  * and a relative location path. It is an error if the expression
   10620  * does not evaluate to a node-set.
   10621  * The / operator does composition in the same way as when / is
   10622  * used in a location path. As in location paths, // is short for
   10623  * /descendant-or-self::node()/.
   10624  */
   10625 
   10626 static void
   10627 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
   10628     int lc = 1;           /* Should we branch to LocationPath ?         */
   10629     xmlChar *name = NULL; /* we may have to preparse a name to find out */
   10630 
   10631     SKIP_BLANKS;
   10632     if ((CUR == '$') || (CUR == '(') ||
   10633 	(IS_ASCII_DIGIT(CUR)) ||
   10634         (CUR == '\'') || (CUR == '"') ||
   10635 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
   10636 	lc = 0;
   10637     } else if (CUR == '*') {
   10638 	/* relative or absolute location path */
   10639 	lc = 1;
   10640     } else if (CUR == '/') {
   10641 	/* relative or absolute location path */
   10642 	lc = 1;
   10643     } else if (CUR == '@') {
   10644 	/* relative abbreviated attribute location path */
   10645 	lc = 1;
   10646     } else if (CUR == '.') {
   10647 	/* relative abbreviated attribute location path */
   10648 	lc = 1;
   10649     } else {
   10650 	/*
   10651 	 * Problem is finding if we have a name here whether it's:
   10652 	 *   - a nodetype
   10653 	 *   - a function call in which case it's followed by '('
   10654 	 *   - an axis in which case it's followed by ':'
   10655 	 *   - a element name
   10656 	 * We do an a priori analysis here rather than having to
   10657 	 * maintain parsed token content through the recursive function
   10658 	 * calls. This looks uglier but makes the code easier to
   10659 	 * read/write/debug.
   10660 	 */
   10661 	SKIP_BLANKS;
   10662 	name = xmlXPathScanName(ctxt);
   10663 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
   10664 #ifdef DEBUG_STEP
   10665 	    xmlGenericError(xmlGenericErrorContext,
   10666 		    "PathExpr: Axis\n");
   10667 #endif
   10668 	    lc = 1;
   10669 	    xmlFree(name);
   10670 	} else if (name != NULL) {
   10671 	    int len =xmlStrlen(name);
   10672 
   10673 
   10674 	    while (NXT(len) != 0) {
   10675 		if (NXT(len) == '/') {
   10676 		    /* element name */
   10677 #ifdef DEBUG_STEP
   10678 		    xmlGenericError(xmlGenericErrorContext,
   10679 			    "PathExpr: AbbrRelLocation\n");
   10680 #endif
   10681 		    lc = 1;
   10682 		    break;
   10683 		} else if (IS_BLANK_CH(NXT(len))) {
   10684 		    /* ignore blanks */
   10685 		    ;
   10686 		} else if (NXT(len) == ':') {
   10687 #ifdef DEBUG_STEP
   10688 		    xmlGenericError(xmlGenericErrorContext,
   10689 			    "PathExpr: AbbrRelLocation\n");
   10690 #endif
   10691 		    lc = 1;
   10692 		    break;
   10693 		} else if ((NXT(len) == '(')) {
   10694 		    /* Node Type or Function */
   10695 		    if (xmlXPathIsNodeType(name)) {
   10696 #ifdef DEBUG_STEP
   10697 		        xmlGenericError(xmlGenericErrorContext,
   10698 				"PathExpr: Type search\n");
   10699 #endif
   10700 			lc = 1;
   10701 #ifdef LIBXML_XPTR_ENABLED
   10702                     } else if (ctxt->xptr &&
   10703                                xmlStrEqual(name, BAD_CAST "range-to")) {
   10704                         lc = 1;
   10705 #endif
   10706 		    } else {
   10707 #ifdef DEBUG_STEP
   10708 		        xmlGenericError(xmlGenericErrorContext,
   10709 				"PathExpr: function call\n");
   10710 #endif
   10711 			lc = 0;
   10712 		    }
   10713                     break;
   10714 		} else if ((NXT(len) == '[')) {
   10715 		    /* element name */
   10716 #ifdef DEBUG_STEP
   10717 		    xmlGenericError(xmlGenericErrorContext,
   10718 			    "PathExpr: AbbrRelLocation\n");
   10719 #endif
   10720 		    lc = 1;
   10721 		    break;
   10722 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
   10723 			   (NXT(len) == '=')) {
   10724 		    lc = 1;
   10725 		    break;
   10726 		} else {
   10727 		    lc = 1;
   10728 		    break;
   10729 		}
   10730 		len++;
   10731 	    }
   10732 	    if (NXT(len) == 0) {
   10733 #ifdef DEBUG_STEP
   10734 		xmlGenericError(xmlGenericErrorContext,
   10735 			"PathExpr: AbbrRelLocation\n");
   10736 #endif
   10737 		/* element name */
   10738 		lc = 1;
   10739 	    }
   10740 	    xmlFree(name);
   10741 	} else {
   10742 	    /* make sure all cases are covered explicitly */
   10743 	    XP_ERROR(XPATH_EXPR_ERROR);
   10744 	}
   10745     }
   10746 
   10747     if (lc) {
   10748 	if (CUR == '/') {
   10749 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
   10750 	} else {
   10751 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
   10752 	}
   10753 	xmlXPathCompLocationPath(ctxt);
   10754     } else {
   10755 	xmlXPathCompFilterExpr(ctxt);
   10756 	CHECK_ERROR;
   10757 	if ((CUR == '/') && (NXT(1) == '/')) {
   10758 	    SKIP(2);
   10759 	    SKIP_BLANKS;
   10760 
   10761 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   10762 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   10763 	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
   10764 
   10765 	    xmlXPathCompRelativeLocationPath(ctxt);
   10766 	} else if (CUR == '/') {
   10767 	    xmlXPathCompRelativeLocationPath(ctxt);
   10768 	}
   10769     }
   10770     SKIP_BLANKS;
   10771 }
   10772 
   10773 /**
   10774  * xmlXPathCompUnionExpr:
   10775  * @ctxt:  the XPath Parser context
   10776  *
   10777  *  [18]   UnionExpr ::=   PathExpr
   10778  *               | UnionExpr '|' PathExpr
   10779  *
   10780  * Compile an union expression.
   10781  */
   10782 
   10783 static void
   10784 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
   10785     xmlXPathCompPathExpr(ctxt);
   10786     CHECK_ERROR;
   10787     SKIP_BLANKS;
   10788     while (CUR == '|') {
   10789 	int op1 = ctxt->comp->last;
   10790 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
   10791 
   10792 	NEXT;
   10793 	SKIP_BLANKS;
   10794 	xmlXPathCompPathExpr(ctxt);
   10795 
   10796 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
   10797 
   10798 	SKIP_BLANKS;
   10799     }
   10800 }
   10801 
   10802 /**
   10803  * xmlXPathCompUnaryExpr:
   10804  * @ctxt:  the XPath Parser context
   10805  *
   10806  *  [27]   UnaryExpr ::=   UnionExpr
   10807  *                   | '-' UnaryExpr
   10808  *
   10809  * Compile an unary expression.
   10810  */
   10811 
   10812 static void
   10813 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
   10814     int minus = 0;
   10815     int found = 0;
   10816 
   10817     SKIP_BLANKS;
   10818     while (CUR == '-') {
   10819         minus = 1 - minus;
   10820 	found = 1;
   10821 	NEXT;
   10822 	SKIP_BLANKS;
   10823     }
   10824 
   10825     xmlXPathCompUnionExpr(ctxt);
   10826     CHECK_ERROR;
   10827     if (found) {
   10828 	if (minus)
   10829 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
   10830 	else
   10831 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
   10832     }
   10833 }
   10834 
   10835 /**
   10836  * xmlXPathCompMultiplicativeExpr:
   10837  * @ctxt:  the XPath Parser context
   10838  *
   10839  *  [26]   MultiplicativeExpr ::=   UnaryExpr
   10840  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
   10841  *                   | MultiplicativeExpr 'div' UnaryExpr
   10842  *                   | MultiplicativeExpr 'mod' UnaryExpr
   10843  *  [34]   MultiplyOperator ::=   '*'
   10844  *
   10845  * Compile an Additive expression.
   10846  */
   10847 
   10848 static void
   10849 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
   10850     xmlXPathCompUnaryExpr(ctxt);
   10851     CHECK_ERROR;
   10852     SKIP_BLANKS;
   10853     while ((CUR == '*') ||
   10854            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
   10855            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
   10856 	int op = -1;
   10857 	int op1 = ctxt->comp->last;
   10858 
   10859         if (CUR == '*') {
   10860 	    op = 0;
   10861 	    NEXT;
   10862 	} else if (CUR == 'd') {
   10863 	    op = 1;
   10864 	    SKIP(3);
   10865 	} else if (CUR == 'm') {
   10866 	    op = 2;
   10867 	    SKIP(3);
   10868 	}
   10869 	SKIP_BLANKS;
   10870         xmlXPathCompUnaryExpr(ctxt);
   10871 	CHECK_ERROR;
   10872 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
   10873 	SKIP_BLANKS;
   10874     }
   10875 }
   10876 
   10877 /**
   10878  * xmlXPathCompAdditiveExpr:
   10879  * @ctxt:  the XPath Parser context
   10880  *
   10881  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
   10882  *                   | AdditiveExpr '+' MultiplicativeExpr
   10883  *                   | AdditiveExpr '-' MultiplicativeExpr
   10884  *
   10885  * Compile an Additive expression.
   10886  */
   10887 
   10888 static void
   10889 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
   10890 
   10891     xmlXPathCompMultiplicativeExpr(ctxt);
   10892     CHECK_ERROR;
   10893     SKIP_BLANKS;
   10894     while ((CUR == '+') || (CUR == '-')) {
   10895 	int plus;
   10896 	int op1 = ctxt->comp->last;
   10897 
   10898         if (CUR == '+') plus = 1;
   10899 	else plus = 0;
   10900 	NEXT;
   10901 	SKIP_BLANKS;
   10902         xmlXPathCompMultiplicativeExpr(ctxt);
   10903 	CHECK_ERROR;
   10904 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
   10905 	SKIP_BLANKS;
   10906     }
   10907 }
   10908 
   10909 /**
   10910  * xmlXPathCompRelationalExpr:
   10911  * @ctxt:  the XPath Parser context
   10912  *
   10913  *  [24]   RelationalExpr ::=   AdditiveExpr
   10914  *                 | RelationalExpr '<' AdditiveExpr
   10915  *                 | RelationalExpr '>' AdditiveExpr
   10916  *                 | RelationalExpr '<=' AdditiveExpr
   10917  *                 | RelationalExpr '>=' AdditiveExpr
   10918  *
   10919  *  A <= B > C is allowed ? Answer from James, yes with
   10920  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
   10921  *  which is basically what got implemented.
   10922  *
   10923  * Compile a Relational expression, then push the result
   10924  * on the stack
   10925  */
   10926 
   10927 static void
   10928 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
   10929     xmlXPathCompAdditiveExpr(ctxt);
   10930     CHECK_ERROR;
   10931     SKIP_BLANKS;
   10932     while ((CUR == '<') ||
   10933            (CUR == '>') ||
   10934            ((CUR == '<') && (NXT(1) == '=')) ||
   10935            ((CUR == '>') && (NXT(1) == '='))) {
   10936 	int inf, strict;
   10937 	int op1 = ctxt->comp->last;
   10938 
   10939         if (CUR == '<') inf = 1;
   10940 	else inf = 0;
   10941 	if (NXT(1) == '=') strict = 0;
   10942 	else strict = 1;
   10943 	NEXT;
   10944 	if (!strict) NEXT;
   10945 	SKIP_BLANKS;
   10946         xmlXPathCompAdditiveExpr(ctxt);
   10947 	CHECK_ERROR;
   10948 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
   10949 	SKIP_BLANKS;
   10950     }
   10951 }
   10952 
   10953 /**
   10954  * xmlXPathCompEqualityExpr:
   10955  * @ctxt:  the XPath Parser context
   10956  *
   10957  *  [23]   EqualityExpr ::=   RelationalExpr
   10958  *                 | EqualityExpr '=' RelationalExpr
   10959  *                 | EqualityExpr '!=' RelationalExpr
   10960  *
   10961  *  A != B != C is allowed ? Answer from James, yes with
   10962  *  (RelationalExpr = RelationalExpr) = RelationalExpr
   10963  *  (RelationalExpr != RelationalExpr) != RelationalExpr
   10964  *  which is basically what got implemented.
   10965  *
   10966  * Compile an Equality expression.
   10967  *
   10968  */
   10969 static void
   10970 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
   10971     xmlXPathCompRelationalExpr(ctxt);
   10972     CHECK_ERROR;
   10973     SKIP_BLANKS;
   10974     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
   10975 	int eq;
   10976 	int op1 = ctxt->comp->last;
   10977 
   10978         if (CUR == '=') eq = 1;
   10979 	else eq = 0;
   10980 	NEXT;
   10981 	if (!eq) NEXT;
   10982 	SKIP_BLANKS;
   10983         xmlXPathCompRelationalExpr(ctxt);
   10984 	CHECK_ERROR;
   10985 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
   10986 	SKIP_BLANKS;
   10987     }
   10988 }
   10989 
   10990 /**
   10991  * xmlXPathCompAndExpr:
   10992  * @ctxt:  the XPath Parser context
   10993  *
   10994  *  [22]   AndExpr ::=   EqualityExpr
   10995  *                 | AndExpr 'and' EqualityExpr
   10996  *
   10997  * Compile an AND expression.
   10998  *
   10999  */
   11000 static void
   11001 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
   11002     xmlXPathCompEqualityExpr(ctxt);
   11003     CHECK_ERROR;
   11004     SKIP_BLANKS;
   11005     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
   11006 	int op1 = ctxt->comp->last;
   11007         SKIP(3);
   11008 	SKIP_BLANKS;
   11009         xmlXPathCompEqualityExpr(ctxt);
   11010 	CHECK_ERROR;
   11011 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
   11012 	SKIP_BLANKS;
   11013     }
   11014 }
   11015 
   11016 /**
   11017  * xmlXPathCompileExpr:
   11018  * @ctxt:  the XPath Parser context
   11019  *
   11020  *  [14]   Expr ::=   OrExpr
   11021  *  [21]   OrExpr ::=   AndExpr
   11022  *                 | OrExpr 'or' AndExpr
   11023  *
   11024  * Parse and compile an expression
   11025  */
   11026 static void
   11027 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
   11028     xmlXPathCompAndExpr(ctxt);
   11029     CHECK_ERROR;
   11030     SKIP_BLANKS;
   11031     while ((CUR == 'o') && (NXT(1) == 'r')) {
   11032 	int op1 = ctxt->comp->last;
   11033         SKIP(2);
   11034 	SKIP_BLANKS;
   11035         xmlXPathCompAndExpr(ctxt);
   11036 	CHECK_ERROR;
   11037 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
   11038 	SKIP_BLANKS;
   11039     }
   11040     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
   11041 	/* more ops could be optimized too */
   11042 	/*
   11043 	* This is the main place to eliminate sorting for
   11044 	* operations which don't require a sorted node-set.
   11045 	* E.g. count().
   11046 	*/
   11047 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
   11048     }
   11049 }
   11050 
   11051 /**
   11052  * xmlXPathCompPredicate:
   11053  * @ctxt:  the XPath Parser context
   11054  * @filter:  act as a filter
   11055  *
   11056  *  [8]   Predicate ::=   '[' PredicateExpr ']'
   11057  *  [9]   PredicateExpr ::=   Expr
   11058  *
   11059  * Compile a predicate expression
   11060  */
   11061 static void
   11062 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
   11063     int op1 = ctxt->comp->last;
   11064 
   11065     SKIP_BLANKS;
   11066     if (CUR != '[') {
   11067 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
   11068     }
   11069     NEXT;
   11070     SKIP_BLANKS;
   11071 
   11072     ctxt->comp->last = -1;
   11073     /*
   11074     * This call to xmlXPathCompileExpr() will deactivate sorting
   11075     * of the predicate result.
   11076     * TODO: Sorting is still activated for filters, since I'm not
   11077     *  sure if needed. Normally sorting should not be needed, since
   11078     *  a filter can only diminish the number of items in a sequence,
   11079     *  but won't change its order; so if the initial sequence is sorted,
   11080     *  subsequent sorting is not needed.
   11081     */
   11082     if (! filter)
   11083 	xmlXPathCompileExpr(ctxt, 0);
   11084     else
   11085 	xmlXPathCompileExpr(ctxt, 1);
   11086     CHECK_ERROR;
   11087 
   11088     if (CUR != ']') {
   11089 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
   11090     }
   11091 
   11092     if (filter)
   11093 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
   11094     else
   11095 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
   11096 
   11097     NEXT;
   11098     SKIP_BLANKS;
   11099 }
   11100 
   11101 /**
   11102  * xmlXPathCompNodeTest:
   11103  * @ctxt:  the XPath Parser context
   11104  * @test:  pointer to a xmlXPathTestVal
   11105  * @type:  pointer to a xmlXPathTypeVal
   11106  * @prefix:  placeholder for a possible name prefix
   11107  *
   11108  * [7] NodeTest ::=   NameTest
   11109  *		    | NodeType '(' ')'
   11110  *		    | 'processing-instruction' '(' Literal ')'
   11111  *
   11112  * [37] NameTest ::=  '*'
   11113  *		    | NCName ':' '*'
   11114  *		    | QName
   11115  * [38] NodeType ::= 'comment'
   11116  *		   | 'text'
   11117  *		   | 'processing-instruction'
   11118  *		   | 'node'
   11119  *
   11120  * Returns the name found and updates @test, @type and @prefix appropriately
   11121  */
   11122 static xmlChar *
   11123 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
   11124 	             xmlXPathTypeVal *type, const xmlChar **prefix,
   11125 		     xmlChar *name) {
   11126     int blanks;
   11127 
   11128     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
   11129 	STRANGE;
   11130 	return(NULL);
   11131     }
   11132     *type = (xmlXPathTypeVal) 0;
   11133     *test = (xmlXPathTestVal) 0;
   11134     *prefix = NULL;
   11135     SKIP_BLANKS;
   11136 
   11137     if ((name == NULL) && (CUR == '*')) {
   11138 	/*
   11139 	 * All elements
   11140 	 */
   11141 	NEXT;
   11142 	*test = NODE_TEST_ALL;
   11143 	return(NULL);
   11144     }
   11145 
   11146     if (name == NULL)
   11147 	name = xmlXPathParseNCName(ctxt);
   11148     if (name == NULL) {
   11149 	XP_ERRORNULL(XPATH_EXPR_ERROR);
   11150     }
   11151 
   11152     blanks = IS_BLANK_CH(CUR);
   11153     SKIP_BLANKS;
   11154     if (CUR == '(') {
   11155 	NEXT;
   11156 	/*
   11157 	 * NodeType or PI search
   11158 	 */
   11159 	if (xmlStrEqual(name, BAD_CAST "comment"))
   11160 	    *type = NODE_TYPE_COMMENT;
   11161 	else if (xmlStrEqual(name, BAD_CAST "node"))
   11162 	    *type = NODE_TYPE_NODE;
   11163 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
   11164 	    *type = NODE_TYPE_PI;
   11165 	else if (xmlStrEqual(name, BAD_CAST "text"))
   11166 	    *type = NODE_TYPE_TEXT;
   11167 	else {
   11168 	    if (name != NULL)
   11169 		xmlFree(name);
   11170 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
   11171 	}
   11172 
   11173 	*test = NODE_TEST_TYPE;
   11174 
   11175 	SKIP_BLANKS;
   11176 	if (*type == NODE_TYPE_PI) {
   11177 	    /*
   11178 	     * Specific case: search a PI by name.
   11179 	     */
   11180 	    if (name != NULL)
   11181 		xmlFree(name);
   11182 	    name = NULL;
   11183 	    if (CUR != ')') {
   11184 		name = xmlXPathParseLiteral(ctxt);
   11185 		CHECK_ERROR NULL;
   11186 		*test = NODE_TEST_PI;
   11187 		SKIP_BLANKS;
   11188 	    }
   11189 	}
   11190 	if (CUR != ')') {
   11191 	    if (name != NULL)
   11192 		xmlFree(name);
   11193 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
   11194 	}
   11195 	NEXT;
   11196 	return(name);
   11197     }
   11198     *test = NODE_TEST_NAME;
   11199     if ((!blanks) && (CUR == ':')) {
   11200 	NEXT;
   11201 
   11202 	/*
   11203 	 * Since currently the parser context don't have a
   11204 	 * namespace list associated:
   11205 	 * The namespace name for this prefix can be computed
   11206 	 * only at evaluation time. The compilation is done
   11207 	 * outside of any context.
   11208 	 */
   11209 #if 0
   11210 	*prefix = xmlXPathNsLookup(ctxt->context, name);
   11211 	if (name != NULL)
   11212 	    xmlFree(name);
   11213 	if (*prefix == NULL) {
   11214 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
   11215 	}
   11216 #else
   11217 	*prefix = name;
   11218 #endif
   11219 
   11220 	if (CUR == '*') {
   11221 	    /*
   11222 	     * All elements
   11223 	     */
   11224 	    NEXT;
   11225 	    *test = NODE_TEST_ALL;
   11226 	    return(NULL);
   11227 	}
   11228 
   11229 	name = xmlXPathParseNCName(ctxt);
   11230 	if (name == NULL) {
   11231 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
   11232 	}
   11233     }
   11234     return(name);
   11235 }
   11236 
   11237 /**
   11238  * xmlXPathIsAxisName:
   11239  * @name:  a preparsed name token
   11240  *
   11241  * [6] AxisName ::=   'ancestor'
   11242  *                  | 'ancestor-or-self'
   11243  *                  | 'attribute'
   11244  *                  | 'child'
   11245  *                  | 'descendant'
   11246  *                  | 'descendant-or-self'
   11247  *                  | 'following'
   11248  *                  | 'following-sibling'
   11249  *                  | 'namespace'
   11250  *                  | 'parent'
   11251  *                  | 'preceding'
   11252  *                  | 'preceding-sibling'
   11253  *                  | 'self'
   11254  *
   11255  * Returns the axis or 0
   11256  */
   11257 static xmlXPathAxisVal
   11258 xmlXPathIsAxisName(const xmlChar *name) {
   11259     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
   11260     switch (name[0]) {
   11261 	case 'a':
   11262 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
   11263 		ret = AXIS_ANCESTOR;
   11264 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
   11265 		ret = AXIS_ANCESTOR_OR_SELF;
   11266 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
   11267 		ret = AXIS_ATTRIBUTE;
   11268 	    break;
   11269 	case 'c':
   11270 	    if (xmlStrEqual(name, BAD_CAST "child"))
   11271 		ret = AXIS_CHILD;
   11272 	    break;
   11273 	case 'd':
   11274 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
   11275 		ret = AXIS_DESCENDANT;
   11276 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
   11277 		ret = AXIS_DESCENDANT_OR_SELF;
   11278 	    break;
   11279 	case 'f':
   11280 	    if (xmlStrEqual(name, BAD_CAST "following"))
   11281 		ret = AXIS_FOLLOWING;
   11282 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
   11283 		ret = AXIS_FOLLOWING_SIBLING;
   11284 	    break;
   11285 	case 'n':
   11286 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
   11287 		ret = AXIS_NAMESPACE;
   11288 	    break;
   11289 	case 'p':
   11290 	    if (xmlStrEqual(name, BAD_CAST "parent"))
   11291 		ret = AXIS_PARENT;
   11292 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
   11293 		ret = AXIS_PRECEDING;
   11294 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
   11295 		ret = AXIS_PRECEDING_SIBLING;
   11296 	    break;
   11297 	case 's':
   11298 	    if (xmlStrEqual(name, BAD_CAST "self"))
   11299 		ret = AXIS_SELF;
   11300 	    break;
   11301     }
   11302     return(ret);
   11303 }
   11304 
   11305 /**
   11306  * xmlXPathCompStep:
   11307  * @ctxt:  the XPath Parser context
   11308  *
   11309  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
   11310  *                  | AbbreviatedStep
   11311  *
   11312  * [12] AbbreviatedStep ::=   '.' | '..'
   11313  *
   11314  * [5] AxisSpecifier ::= AxisName '::'
   11315  *                  | AbbreviatedAxisSpecifier
   11316  *
   11317  * [13] AbbreviatedAxisSpecifier ::= '@'?
   11318  *
   11319  * Modified for XPtr range support as:
   11320  *
   11321  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
   11322  *                     | AbbreviatedStep
   11323  *                     | 'range-to' '(' Expr ')' Predicate*
   11324  *
   11325  * Compile one step in a Location Path
   11326  * A location step of . is short for self::node(). This is
   11327  * particularly useful in conjunction with //. For example, the
   11328  * location path .//para is short for
   11329  * self::node()/descendant-or-self::node()/child::para
   11330  * and so will select all para descendant elements of the context
   11331  * node.
   11332  * Similarly, a location step of .. is short for parent::node().
   11333  * For example, ../title is short for parent::node()/child::title
   11334  * and so will select the title children of the parent of the context
   11335  * node.
   11336  */
   11337 static void
   11338 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
   11339 #ifdef LIBXML_XPTR_ENABLED
   11340     int rangeto = 0;
   11341     int op2 = -1;
   11342 #endif
   11343 
   11344     SKIP_BLANKS;
   11345     if ((CUR == '.') && (NXT(1) == '.')) {
   11346 	SKIP(2);
   11347 	SKIP_BLANKS;
   11348 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
   11349 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11350     } else if (CUR == '.') {
   11351 	NEXT;
   11352 	SKIP_BLANKS;
   11353     } else {
   11354 	xmlChar *name = NULL;
   11355 	const xmlChar *prefix = NULL;
   11356 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
   11357 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
   11358 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
   11359 	int op1;
   11360 
   11361 	/*
   11362 	 * The modification needed for XPointer change to the production
   11363 	 */
   11364 #ifdef LIBXML_XPTR_ENABLED
   11365 	if (ctxt->xptr) {
   11366 	    name = xmlXPathParseNCName(ctxt);
   11367 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
   11368                 op2 = ctxt->comp->last;
   11369 		xmlFree(name);
   11370 		SKIP_BLANKS;
   11371 		if (CUR != '(') {
   11372 		    XP_ERROR(XPATH_EXPR_ERROR);
   11373 		}
   11374 		NEXT;
   11375 		SKIP_BLANKS;
   11376 
   11377 		xmlXPathCompileExpr(ctxt, 1);
   11378 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
   11379 		CHECK_ERROR;
   11380 
   11381 		SKIP_BLANKS;
   11382 		if (CUR != ')') {
   11383 		    XP_ERROR(XPATH_EXPR_ERROR);
   11384 		}
   11385 		NEXT;
   11386 		rangeto = 1;
   11387 		goto eval_predicates;
   11388 	    }
   11389 	}
   11390 #endif
   11391 	if (CUR == '*') {
   11392 	    axis = AXIS_CHILD;
   11393 	} else {
   11394 	    if (name == NULL)
   11395 		name = xmlXPathParseNCName(ctxt);
   11396 	    if (name != NULL) {
   11397 		axis = xmlXPathIsAxisName(name);
   11398 		if (axis != 0) {
   11399 		    SKIP_BLANKS;
   11400 		    if ((CUR == ':') && (NXT(1) == ':')) {
   11401 			SKIP(2);
   11402 			xmlFree(name);
   11403 			name = NULL;
   11404 		    } else {
   11405 			/* an element name can conflict with an axis one :-\ */
   11406 			axis = AXIS_CHILD;
   11407 		    }
   11408 		} else {
   11409 		    axis = AXIS_CHILD;
   11410 		}
   11411 	    } else if (CUR == '@') {
   11412 		NEXT;
   11413 		axis = AXIS_ATTRIBUTE;
   11414 	    } else {
   11415 		axis = AXIS_CHILD;
   11416 	    }
   11417 	}
   11418 
   11419         if (ctxt->error != XPATH_EXPRESSION_OK) {
   11420             xmlFree(name);
   11421             return;
   11422         }
   11423 
   11424 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
   11425 	if (test == 0)
   11426 	    return;
   11427 
   11428         if ((prefix != NULL) && (ctxt->context != NULL) &&
   11429 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
   11430 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
   11431 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
   11432 	    }
   11433 	}
   11434 #ifdef DEBUG_STEP
   11435 	xmlGenericError(xmlGenericErrorContext,
   11436 		"Basis : computing new set\n");
   11437 #endif
   11438 
   11439 #ifdef DEBUG_STEP
   11440 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
   11441 	if (ctxt->value == NULL)
   11442 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
   11443 	else if (ctxt->value->nodesetval == NULL)
   11444 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
   11445 	else
   11446 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
   11447 #endif
   11448 
   11449 #ifdef LIBXML_XPTR_ENABLED
   11450 eval_predicates:
   11451 #endif
   11452 	op1 = ctxt->comp->last;
   11453 	ctxt->comp->last = -1;
   11454 
   11455 	SKIP_BLANKS;
   11456 	while (CUR == '[') {
   11457 	    xmlXPathCompPredicate(ctxt, 0);
   11458 	}
   11459 
   11460 #ifdef LIBXML_XPTR_ENABLED
   11461 	if (rangeto) {
   11462 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
   11463 	} else
   11464 #endif
   11465 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
   11466 			   test, type, (void *)prefix, (void *)name);
   11467 
   11468     }
   11469 #ifdef DEBUG_STEP
   11470     xmlGenericError(xmlGenericErrorContext, "Step : ");
   11471     if (ctxt->value == NULL)
   11472 	xmlGenericError(xmlGenericErrorContext, "no value\n");
   11473     else if (ctxt->value->nodesetval == NULL)
   11474 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
   11475     else
   11476 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
   11477 		ctxt->value->nodesetval);
   11478 #endif
   11479 }
   11480 
   11481 /**
   11482  * xmlXPathCompRelativeLocationPath:
   11483  * @ctxt:  the XPath Parser context
   11484  *
   11485  *  [3]   RelativeLocationPath ::=   Step
   11486  *                     | RelativeLocationPath '/' Step
   11487  *                     | AbbreviatedRelativeLocationPath
   11488  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
   11489  *
   11490  * Compile a relative location path.
   11491  */
   11492 static void
   11493 xmlXPathCompRelativeLocationPath
   11494 (xmlXPathParserContextPtr ctxt) {
   11495     SKIP_BLANKS;
   11496     if ((CUR == '/') && (NXT(1) == '/')) {
   11497 	SKIP(2);
   11498 	SKIP_BLANKS;
   11499 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11500 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11501     } else if (CUR == '/') {
   11502 	    NEXT;
   11503 	SKIP_BLANKS;
   11504     }
   11505     xmlXPathCompStep(ctxt);
   11506     CHECK_ERROR;
   11507     SKIP_BLANKS;
   11508     while (CUR == '/') {
   11509 	if ((CUR == '/') && (NXT(1) == '/')) {
   11510 	    SKIP(2);
   11511 	    SKIP_BLANKS;
   11512 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11513 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11514 	    xmlXPathCompStep(ctxt);
   11515 	} else if (CUR == '/') {
   11516 	    NEXT;
   11517 	    SKIP_BLANKS;
   11518 	    xmlXPathCompStep(ctxt);
   11519 	}
   11520 	SKIP_BLANKS;
   11521     }
   11522 }
   11523 
   11524 /**
   11525  * xmlXPathCompLocationPath:
   11526  * @ctxt:  the XPath Parser context
   11527  *
   11528  *  [1]   LocationPath ::=   RelativeLocationPath
   11529  *                     | AbsoluteLocationPath
   11530  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
   11531  *                     | AbbreviatedAbsoluteLocationPath
   11532  *  [10]   AbbreviatedAbsoluteLocationPath ::=
   11533  *                           '//' RelativeLocationPath
   11534  *
   11535  * Compile a location path
   11536  *
   11537  * // is short for /descendant-or-self::node()/. For example,
   11538  * //para is short for /descendant-or-self::node()/child::para and
   11539  * so will select any para element in the document (even a para element
   11540  * that is a document element will be selected by //para since the
   11541  * document element node is a child of the root node); div//para is
   11542  * short for div/descendant-or-self::node()/child::para and so will
   11543  * select all para descendants of div children.
   11544  */
   11545 static void
   11546 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
   11547     SKIP_BLANKS;
   11548     if (CUR != '/') {
   11549         xmlXPathCompRelativeLocationPath(ctxt);
   11550     } else {
   11551 	while (CUR == '/') {
   11552 	    if ((CUR == '/') && (NXT(1) == '/')) {
   11553 		SKIP(2);
   11554 		SKIP_BLANKS;
   11555 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11556 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11557 		xmlXPathCompRelativeLocationPath(ctxt);
   11558 	    } else if (CUR == '/') {
   11559 		NEXT;
   11560 		SKIP_BLANKS;
   11561 		if ((CUR != 0 ) &&
   11562 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
   11563 		     (CUR == '@') || (CUR == '*')))
   11564 		    xmlXPathCompRelativeLocationPath(ctxt);
   11565 	    }
   11566 	    CHECK_ERROR;
   11567 	}
   11568     }
   11569 }
   11570 
   11571 /************************************************************************
   11572  *									*
   11573  *		XPath precompiled expression evaluation			*
   11574  *									*
   11575  ************************************************************************/
   11576 
   11577 static int
   11578 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
   11579 
   11580 #ifdef DEBUG_STEP
   11581 static void
   11582 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
   11583 			  int nbNodes)
   11584 {
   11585     xmlGenericError(xmlGenericErrorContext, "new step : ");
   11586     switch (op->value) {
   11587         case AXIS_ANCESTOR:
   11588             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
   11589             break;
   11590         case AXIS_ANCESTOR_OR_SELF:
   11591             xmlGenericError(xmlGenericErrorContext,
   11592                             "axis 'ancestors-or-self' ");
   11593             break;
   11594         case AXIS_ATTRIBUTE:
   11595             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
   11596             break;
   11597         case AXIS_CHILD:
   11598             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
   11599             break;
   11600         case AXIS_DESCENDANT:
   11601             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
   11602             break;
   11603         case AXIS_DESCENDANT_OR_SELF:
   11604             xmlGenericError(xmlGenericErrorContext,
   11605                             "axis 'descendant-or-self' ");
   11606             break;
   11607         case AXIS_FOLLOWING:
   11608             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
   11609             break;
   11610         case AXIS_FOLLOWING_SIBLING:
   11611             xmlGenericError(xmlGenericErrorContext,
   11612                             "axis 'following-siblings' ");
   11613             break;
   11614         case AXIS_NAMESPACE:
   11615             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
   11616             break;
   11617         case AXIS_PARENT:
   11618             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
   11619             break;
   11620         case AXIS_PRECEDING:
   11621             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
   11622             break;
   11623         case AXIS_PRECEDING_SIBLING:
   11624             xmlGenericError(xmlGenericErrorContext,
   11625                             "axis 'preceding-sibling' ");
   11626             break;
   11627         case AXIS_SELF:
   11628             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
   11629             break;
   11630     }
   11631     xmlGenericError(xmlGenericErrorContext,
   11632 	" context contains %d nodes\n", nbNodes);
   11633     switch (op->value2) {
   11634         case NODE_TEST_NONE:
   11635             xmlGenericError(xmlGenericErrorContext,
   11636                             "           searching for none !!!\n");
   11637             break;
   11638         case NODE_TEST_TYPE:
   11639             xmlGenericError(xmlGenericErrorContext,
   11640                             "           searching for type %d\n", op->value3);
   11641             break;
   11642         case NODE_TEST_PI:
   11643             xmlGenericError(xmlGenericErrorContext,
   11644                             "           searching for PI !!!\n");
   11645             break;
   11646         case NODE_TEST_ALL:
   11647             xmlGenericError(xmlGenericErrorContext,
   11648                             "           searching for *\n");
   11649             break;
   11650         case NODE_TEST_NS:
   11651             xmlGenericError(xmlGenericErrorContext,
   11652                             "           searching for namespace %s\n",
   11653                             op->value5);
   11654             break;
   11655         case NODE_TEST_NAME:
   11656             xmlGenericError(xmlGenericErrorContext,
   11657                             "           searching for name %s\n", op->value5);
   11658             if (op->value4)
   11659                 xmlGenericError(xmlGenericErrorContext,
   11660                                 "           with namespace %s\n", op->value4);
   11661             break;
   11662     }
   11663     xmlGenericError(xmlGenericErrorContext, "Testing : ");
   11664 }
   11665 #endif /* DEBUG_STEP */
   11666 
   11667 static int
   11668 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
   11669 			    xmlXPathStepOpPtr op,
   11670 			    xmlNodeSetPtr set,
   11671 			    int contextSize,
   11672 			    int hasNsNodes)
   11673 {
   11674     if (op->ch1 != -1) {
   11675 	xmlXPathCompExprPtr comp = ctxt->comp;
   11676 	/*
   11677 	* Process inner predicates first.
   11678 	*/
   11679 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
   11680 	    /*
   11681 	    * TODO: raise an internal error.
   11682 	    */
   11683 	}
   11684 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
   11685 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
   11686 	CHECK_ERROR0;
   11687 	if (contextSize <= 0)
   11688 	    return(0);
   11689     }
   11690     if (op->ch2 != -1) {
   11691 	xmlXPathContextPtr xpctxt = ctxt->context;
   11692 	xmlNodePtr contextNode, oldContextNode;
   11693 	xmlDocPtr oldContextDoc;
   11694 	int i, res, contextPos = 0, newContextSize;
   11695 	xmlXPathStepOpPtr exprOp;
   11696 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
   11697 
   11698 #ifdef LIBXML_XPTR_ENABLED
   11699 	/*
   11700 	* URGENT TODO: Check the following:
   11701 	*  We don't expect location sets if evaluating prediates, right?
   11702 	*  Only filters should expect location sets, right?
   11703 	*/
   11704 #endif
   11705 	/*
   11706 	* SPEC XPath 1.0:
   11707 	*  "For each node in the node-set to be filtered, the
   11708 	*  PredicateExpr is evaluated with that node as the
   11709 	*  context node, with the number of nodes in the
   11710 	*  node-set as the context size, and with the proximity
   11711 	*  position of the node in the node-set with respect to
   11712 	*  the axis as the context position;"
   11713 	* @oldset is the node-set" to be filtered.
   11714 	*
   11715 	* SPEC XPath 1.0:
   11716 	*  "only predicates change the context position and
   11717 	*  context size (see [2.4 Predicates])."
   11718 	* Example:
   11719 	*   node-set  context pos
   11720 	*    nA         1
   11721 	*    nB         2
   11722 	*    nC         3
   11723 	*   After applying predicate [position() > 1] :
   11724 	*   node-set  context pos
   11725 	*    nB         1
   11726 	*    nC         2
   11727 	*/
   11728 	oldContextNode = xpctxt->node;
   11729 	oldContextDoc = xpctxt->doc;
   11730 	/*
   11731 	* Get the expression of this predicate.
   11732 	*/
   11733 	exprOp = &ctxt->comp->steps[op->ch2];
   11734 	newContextSize = 0;
   11735 	for (i = 0; i < set->nodeNr; i++) {
   11736 	    if (set->nodeTab[i] == NULL)
   11737 		continue;
   11738 
   11739 	    contextNode = set->nodeTab[i];
   11740 	    xpctxt->node = contextNode;
   11741 	    xpctxt->contextSize = contextSize;
   11742 	    xpctxt->proximityPosition = ++contextPos;
   11743 
   11744 	    /*
   11745 	    * Also set the xpath document in case things like
   11746 	    * key() are evaluated in the predicate.
   11747 	    */
   11748 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
   11749 		(contextNode->doc != NULL))
   11750 		xpctxt->doc = contextNode->doc;
   11751 	    /*
   11752 	    * Evaluate the predicate expression with 1 context node
   11753 	    * at a time; this node is packaged into a node set; this
   11754 	    * node set is handed over to the evaluation mechanism.
   11755 	    */
   11756 	    if (contextObj == NULL)
   11757 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
   11758 	    else {
   11759 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
   11760 		    contextNode) < 0) {
   11761 		    ctxt->error = XPATH_MEMORY_ERROR;
   11762 		    goto evaluation_exit;
   11763 		}
   11764 	    }
   11765 
   11766 	    valuePush(ctxt, contextObj);
   11767 
   11768 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
   11769 
   11770 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
   11771 		xmlXPathNodeSetClear(set, hasNsNodes);
   11772 		newContextSize = 0;
   11773 		goto evaluation_exit;
   11774 	    }
   11775 
   11776 	    if (res != 0) {
   11777 		newContextSize++;
   11778 	    } else {
   11779 		/*
   11780 		* Remove the entry from the initial node set.
   11781 		*/
   11782 		set->nodeTab[i] = NULL;
   11783 		if (contextNode->type == XML_NAMESPACE_DECL)
   11784 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
   11785 	    }
   11786 	    if (ctxt->value == contextObj) {
   11787 		/*
   11788 		* Don't free the temporary XPath object holding the
   11789 		* context node, in order to avoid massive recreation
   11790 		* inside this loop.
   11791 		*/
   11792 		valuePop(ctxt);
   11793 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
   11794 	    } else {
   11795 		/*
   11796 		* TODO: The object was lost in the evaluation machinery.
   11797 		*  Can this happen? Maybe in internal-error cases.
   11798 		*/
   11799 		contextObj = NULL;
   11800 	    }
   11801 	}
   11802 
   11803 	if (contextObj != NULL) {
   11804 	    if (ctxt->value == contextObj)
   11805 		valuePop(ctxt);
   11806 	    xmlXPathReleaseObject(xpctxt, contextObj);
   11807 	}
   11808 evaluation_exit:
   11809 	if (exprRes != NULL)
   11810 	    xmlXPathReleaseObject(ctxt->context, exprRes);
   11811 	/*
   11812 	* Reset/invalidate the context.
   11813 	*/
   11814 	xpctxt->node = oldContextNode;
   11815 	xpctxt->doc = oldContextDoc;
   11816 	xpctxt->contextSize = -1;
   11817 	xpctxt->proximityPosition = -1;
   11818 	return(newContextSize);
   11819     }
   11820     return(contextSize);
   11821 }
   11822 
   11823 static int
   11824 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
   11825 				      xmlXPathStepOpPtr op,
   11826 				      xmlNodeSetPtr set,
   11827 				      int contextSize,
   11828 				      int minPos,
   11829 				      int maxPos,
   11830 				      int hasNsNodes)
   11831 {
   11832     if (op->ch1 != -1) {
   11833 	xmlXPathCompExprPtr comp = ctxt->comp;
   11834 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
   11835 	    /*
   11836 	    * TODO: raise an internal error.
   11837 	    */
   11838 	}
   11839 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
   11840 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
   11841 	CHECK_ERROR0;
   11842 	if (contextSize <= 0)
   11843 	    return(0);
   11844     }
   11845     /*
   11846     * Check if the node set contains a sufficient number of nodes for
   11847     * the requested range.
   11848     */
   11849     if (contextSize < minPos) {
   11850 	xmlXPathNodeSetClear(set, hasNsNodes);
   11851 	return(0);
   11852     }
   11853     if (op->ch2 == -1) {
   11854 	/*
   11855 	* TODO: Can this ever happen?
   11856 	*/
   11857 	return (contextSize);
   11858     } else {
   11859 	xmlDocPtr oldContextDoc;
   11860 	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
   11861 	xmlXPathStepOpPtr exprOp;
   11862 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
   11863 	xmlNodePtr oldContextNode, contextNode = NULL;
   11864 	xmlXPathContextPtr xpctxt = ctxt->context;
   11865         int frame;
   11866 
   11867 #ifdef LIBXML_XPTR_ENABLED
   11868 	    /*
   11869 	    * URGENT TODO: Check the following:
   11870 	    *  We don't expect location sets if evaluating prediates, right?
   11871 	    *  Only filters should expect location sets, right?
   11872 	*/
   11873 #endif /* LIBXML_XPTR_ENABLED */
   11874 
   11875 	/*
   11876 	* Save old context.
   11877 	*/
   11878 	oldContextNode = xpctxt->node;
   11879 	oldContextDoc = xpctxt->doc;
   11880 	/*
   11881 	* Get the expression of this predicate.
   11882 	*/
   11883 	exprOp = &ctxt->comp->steps[op->ch2];
   11884 	for (i = 0; i < set->nodeNr; i++) {
   11885             xmlXPathObjectPtr tmp;
   11886 
   11887 	    if (set->nodeTab[i] == NULL)
   11888 		continue;
   11889 
   11890 	    contextNode = set->nodeTab[i];
   11891 	    xpctxt->node = contextNode;
   11892 	    xpctxt->contextSize = contextSize;
   11893 	    xpctxt->proximityPosition = ++contextPos;
   11894 
   11895 	    /*
   11896 	    * Initialize the new set.
   11897 	    * Also set the xpath document in case things like
   11898 	    * key() evaluation are attempted on the predicate
   11899 	    */
   11900 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
   11901 		(contextNode->doc != NULL))
   11902 		xpctxt->doc = contextNode->doc;
   11903 	    /*
   11904 	    * Evaluate the predicate expression with 1 context node
   11905 	    * at a time; this node is packaged into a node set; this
   11906 	    * node set is handed over to the evaluation mechanism.
   11907 	    */
   11908 	    if (contextObj == NULL)
   11909 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
   11910 	    else {
   11911 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
   11912 		    contextNode) < 0) {
   11913 		    ctxt->error = XPATH_MEMORY_ERROR;
   11914 		    goto evaluation_exit;
   11915 		}
   11916 	    }
   11917 
   11918             frame = xmlXPathSetFrame(ctxt);
   11919 	    valuePush(ctxt, contextObj);
   11920 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
   11921             tmp = valuePop(ctxt);
   11922             xmlXPathPopFrame(ctxt, frame);
   11923 
   11924 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
   11925                 while (tmp != contextObj) {
   11926                     /*
   11927                      * Free up the result
   11928                      * then pop off contextObj, which will be freed later
   11929                      */
   11930                     xmlXPathReleaseObject(xpctxt, tmp);
   11931                     tmp = valuePop(ctxt);
   11932                 }
   11933 		goto evaluation_error;
   11934 	    }
   11935             /* push the result back onto the stack */
   11936             valuePush(ctxt, tmp);
   11937 
   11938 	    if (res)
   11939 		pos++;
   11940 
   11941 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
   11942 		/*
   11943 		* Fits in the requested range.
   11944 		*/
   11945 		newContextSize++;
   11946 		if (minPos == maxPos) {
   11947 		    /*
   11948 		    * Only 1 node was requested.
   11949 		    */
   11950 		    if (contextNode->type == XML_NAMESPACE_DECL) {
   11951 			/*
   11952 			* As always: take care of those nasty
   11953 			* namespace nodes.
   11954 			*/
   11955 			set->nodeTab[i] = NULL;
   11956 		    }
   11957 		    xmlXPathNodeSetClear(set, hasNsNodes);
   11958 		    set->nodeNr = 1;
   11959 		    set->nodeTab[0] = contextNode;
   11960 		    goto evaluation_exit;
   11961 		}
   11962 		if (pos == maxPos) {
   11963 		    /*
   11964 		    * We are done.
   11965 		    */
   11966 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
   11967 		    goto evaluation_exit;
   11968 		}
   11969 	    } else {
   11970 		/*
   11971 		* Remove the entry from the initial node set.
   11972 		*/
   11973 		set->nodeTab[i] = NULL;
   11974 		if (contextNode->type == XML_NAMESPACE_DECL)
   11975 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
   11976 	    }
   11977 	    if (exprRes != NULL) {
   11978 		xmlXPathReleaseObject(ctxt->context, exprRes);
   11979 		exprRes = NULL;
   11980 	    }
   11981 	    if (ctxt->value == contextObj) {
   11982 		/*
   11983 		* Don't free the temporary XPath object holding the
   11984 		* context node, in order to avoid massive recreation
   11985 		* inside this loop.
   11986 		*/
   11987 		valuePop(ctxt);
   11988 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
   11989 	    } else {
   11990 		/*
   11991 		* The object was lost in the evaluation machinery.
   11992 		* Can this happen? Maybe in case of internal-errors.
   11993 		*/
   11994 		contextObj = NULL;
   11995 	    }
   11996 	}
   11997 	goto evaluation_exit;
   11998 
   11999 evaluation_error:
   12000 	xmlXPathNodeSetClear(set, hasNsNodes);
   12001 	newContextSize = 0;
   12002 
   12003 evaluation_exit:
   12004 	if (contextObj != NULL) {
   12005 	    if (ctxt->value == contextObj)
   12006 		valuePop(ctxt);
   12007 	    xmlXPathReleaseObject(xpctxt, contextObj);
   12008 	}
   12009 	if (exprRes != NULL)
   12010 	    xmlXPathReleaseObject(ctxt->context, exprRes);
   12011 	/*
   12012 	* Reset/invalidate the context.
   12013 	*/
   12014 	xpctxt->node = oldContextNode;
   12015 	xpctxt->doc = oldContextDoc;
   12016 	xpctxt->contextSize = -1;
   12017 	xpctxt->proximityPosition = -1;
   12018 	return(newContextSize);
   12019     }
   12020     return(contextSize);
   12021 }
   12022 
   12023 static int
   12024 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
   12025 			    xmlXPathStepOpPtr op,
   12026 			    int *maxPos)
   12027 {
   12028 
   12029     xmlXPathStepOpPtr exprOp;
   12030 
   12031     /*
   12032     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
   12033     */
   12034 
   12035     /*
   12036     * If not -1, then ch1 will point to:
   12037     * 1) For predicates (XPATH_OP_PREDICATE):
   12038     *    - an inner predicate operator
   12039     * 2) For filters (XPATH_OP_FILTER):
   12040     *    - an inner filter operater OR
   12041     *    - an expression selecting the node set.
   12042     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
   12043     */
   12044     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
   12045 	return(0);
   12046 
   12047     if (op->ch2 != -1) {
   12048 	exprOp = &ctxt->comp->steps[op->ch2];
   12049     } else
   12050 	return(0);
   12051 
   12052     if ((exprOp != NULL) &&
   12053 	(exprOp->op == XPATH_OP_VALUE) &&
   12054 	(exprOp->value4 != NULL) &&
   12055 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
   12056     {
   12057 	/*
   12058 	* We have a "[n]" predicate here.
   12059 	* TODO: Unfortunately this simplistic test here is not
   12060 	* able to detect a position() predicate in compound
   12061 	* expressions like "[@attr = 'a" and position() = 1],
   12062 	* and even not the usage of position() in
   12063 	* "[position() = 1]"; thus - obviously - a position-range,
   12064 	* like it "[position() < 5]", is also not detected.
   12065 	* Maybe we could rewrite the AST to ease the optimization.
   12066 	*/
   12067 	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
   12068 
   12069 	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
   12070 	    (float) *maxPos)
   12071 	{
   12072 	    return(1);
   12073 	}
   12074     }
   12075     return(0);
   12076 }
   12077 
   12078 static int
   12079 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
   12080                            xmlXPathStepOpPtr op,
   12081 			   xmlNodePtr * first, xmlNodePtr * last,
   12082 			   int toBool)
   12083 {
   12084 
   12085 #define XP_TEST_HIT \
   12086     if (hasAxisRange != 0) { \
   12087 	if (++pos == maxPos) { \
   12088 	    if (addNode(seq, cur) < 0) \
   12089 	        ctxt->error = XPATH_MEMORY_ERROR; \
   12090 	    goto axis_range_end; } \
   12091     } else { \
   12092 	if (addNode(seq, cur) < 0) \
   12093 	    ctxt->error = XPATH_MEMORY_ERROR; \
   12094 	if (breakOnFirstHit) goto first_hit; }
   12095 
   12096 #define XP_TEST_HIT_NS \
   12097     if (hasAxisRange != 0) { \
   12098 	if (++pos == maxPos) { \
   12099 	    hasNsNodes = 1; \
   12100 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
   12101 	        ctxt->error = XPATH_MEMORY_ERROR; \
   12102 	goto axis_range_end; } \
   12103     } else { \
   12104 	hasNsNodes = 1; \
   12105 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
   12106 	    ctxt->error = XPATH_MEMORY_ERROR; \
   12107 	if (breakOnFirstHit) goto first_hit; }
   12108 
   12109     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
   12110     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
   12111     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
   12112     const xmlChar *prefix = op->value4;
   12113     const xmlChar *name = op->value5;
   12114     const xmlChar *URI = NULL;
   12115 
   12116 #ifdef DEBUG_STEP
   12117     int nbMatches = 0, prevMatches = 0;
   12118 #endif
   12119     int total = 0, hasNsNodes = 0;
   12120     /* The popped object holding the context nodes */
   12121     xmlXPathObjectPtr obj;
   12122     /* The set of context nodes for the node tests */
   12123     xmlNodeSetPtr contextSeq;
   12124     int contextIdx;
   12125     xmlNodePtr contextNode;
   12126     /* The final resulting node set wrt to all context nodes */
   12127     xmlNodeSetPtr outSeq;
   12128     /*
   12129     * The temporary resulting node set wrt 1 context node.
   12130     * Used to feed predicate evaluation.
   12131     */
   12132     xmlNodeSetPtr seq;
   12133     xmlNodePtr cur;
   12134     /* First predicate operator */
   12135     xmlXPathStepOpPtr predOp;
   12136     int maxPos; /* The requested position() (when a "[n]" predicate) */
   12137     int hasPredicateRange, hasAxisRange, pos, size, newSize;
   12138     int breakOnFirstHit;
   12139 
   12140     xmlXPathTraversalFunction next = NULL;
   12141     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
   12142     xmlXPathNodeSetMergeFunction mergeAndClear;
   12143     xmlNodePtr oldContextNode;
   12144     xmlXPathContextPtr xpctxt = ctxt->context;
   12145 
   12146 
   12147     CHECK_TYPE0(XPATH_NODESET);
   12148     obj = valuePop(ctxt);
   12149     /*
   12150     * Setup namespaces.
   12151     */
   12152     if (prefix != NULL) {
   12153         URI = xmlXPathNsLookup(xpctxt, prefix);
   12154         if (URI == NULL) {
   12155 	    xmlXPathReleaseObject(xpctxt, obj);
   12156             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
   12157 	}
   12158     }
   12159     /*
   12160     * Setup axis.
   12161     *
   12162     * MAYBE FUTURE TODO: merging optimizations:
   12163     * - If the nodes to be traversed wrt to the initial nodes and
   12164     *   the current axis cannot overlap, then we could avoid searching
   12165     *   for duplicates during the merge.
   12166     *   But the question is how/when to evaluate if they cannot overlap.
   12167     *   Example: if we know that for two initial nodes, the one is
   12168     *   not in the ancestor-or-self axis of the other, then we could safely
   12169     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
   12170     *   the descendant-or-self axis.
   12171     */
   12172     mergeAndClear = xmlXPathNodeSetMergeAndClear;
   12173     switch (axis) {
   12174         case AXIS_ANCESTOR:
   12175             first = NULL;
   12176             next = xmlXPathNextAncestor;
   12177             break;
   12178         case AXIS_ANCESTOR_OR_SELF:
   12179             first = NULL;
   12180             next = xmlXPathNextAncestorOrSelf;
   12181             break;
   12182         case AXIS_ATTRIBUTE:
   12183             first = NULL;
   12184 	    last = NULL;
   12185             next = xmlXPathNextAttribute;
   12186 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12187             break;
   12188         case AXIS_CHILD:
   12189 	    last = NULL;
   12190 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
   12191 		(type == NODE_TYPE_NODE))
   12192 	    {
   12193 		/*
   12194 		* Optimization if an element node type is 'element'.
   12195 		*/
   12196 		next = xmlXPathNextChildElement;
   12197 	    } else
   12198 		next = xmlXPathNextChild;
   12199 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12200             break;
   12201         case AXIS_DESCENDANT:
   12202 	    last = NULL;
   12203             next = xmlXPathNextDescendant;
   12204             break;
   12205         case AXIS_DESCENDANT_OR_SELF:
   12206 	    last = NULL;
   12207             next = xmlXPathNextDescendantOrSelf;
   12208             break;
   12209         case AXIS_FOLLOWING:
   12210 	    last = NULL;
   12211             next = xmlXPathNextFollowing;
   12212             break;
   12213         case AXIS_FOLLOWING_SIBLING:
   12214 	    last = NULL;
   12215             next = xmlXPathNextFollowingSibling;
   12216             break;
   12217         case AXIS_NAMESPACE:
   12218             first = NULL;
   12219 	    last = NULL;
   12220             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
   12221 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12222             break;
   12223         case AXIS_PARENT:
   12224             first = NULL;
   12225             next = xmlXPathNextParent;
   12226             break;
   12227         case AXIS_PRECEDING:
   12228             first = NULL;
   12229             next = xmlXPathNextPrecedingInternal;
   12230             break;
   12231         case AXIS_PRECEDING_SIBLING:
   12232             first = NULL;
   12233             next = xmlXPathNextPrecedingSibling;
   12234             break;
   12235         case AXIS_SELF:
   12236             first = NULL;
   12237 	    last = NULL;
   12238             next = xmlXPathNextSelf;
   12239 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12240             break;
   12241     }
   12242 
   12243 #ifdef DEBUG_STEP
   12244     xmlXPathDebugDumpStepAxis(op,
   12245 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
   12246 #endif
   12247 
   12248     if (next == NULL) {
   12249 	xmlXPathReleaseObject(xpctxt, obj);
   12250         return(0);
   12251     }
   12252     contextSeq = obj->nodesetval;
   12253     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
   12254 	xmlXPathReleaseObject(xpctxt, obj);
   12255         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
   12256         return(0);
   12257     }
   12258     /*
   12259     * Predicate optimization ---------------------------------------------
   12260     * If this step has a last predicate, which contains a position(),
   12261     * then we'll optimize (although not exactly "position()", but only
   12262     * the  short-hand form, i.e., "[n]".
   12263     *
   12264     * Example - expression "/foo[parent::bar][1]":
   12265     *
   12266     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
   12267     *   ROOT                               -- op->ch1
   12268     *   PREDICATE                          -- op->ch2 (predOp)
   12269     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
   12270     *       SORT
   12271     *         COLLECT  'parent' 'name' 'node' bar
   12272     *           NODE
   12273     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
   12274     *
   12275     */
   12276     maxPos = 0;
   12277     predOp = NULL;
   12278     hasPredicateRange = 0;
   12279     hasAxisRange = 0;
   12280     if (op->ch2 != -1) {
   12281 	/*
   12282 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
   12283 	*/
   12284 	predOp = &ctxt->comp->steps[op->ch2];
   12285 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
   12286 	    if (predOp->ch1 != -1) {
   12287 		/*
   12288 		* Use the next inner predicate operator.
   12289 		*/
   12290 		predOp = &ctxt->comp->steps[predOp->ch1];
   12291 		hasPredicateRange = 1;
   12292 	    } else {
   12293 		/*
   12294 		* There's no other predicate than the [n] predicate.
   12295 		*/
   12296 		predOp = NULL;
   12297 		hasAxisRange = 1;
   12298 	    }
   12299 	}
   12300     }
   12301     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
   12302     /*
   12303     * Axis traversal -----------------------------------------------------
   12304     */
   12305     /*
   12306      * 2.3 Node Tests
   12307      *  - For the attribute axis, the principal node type is attribute.
   12308      *  - For the namespace axis, the principal node type is namespace.
   12309      *  - For other axes, the principal node type is element.
   12310      *
   12311      * A node test * is true for any node of the
   12312      * principal node type. For example, child::* will
   12313      * select all element children of the context node
   12314      */
   12315     oldContextNode = xpctxt->node;
   12316     addNode = xmlXPathNodeSetAddUnique;
   12317     outSeq = NULL;
   12318     seq = NULL;
   12319     contextNode = NULL;
   12320     contextIdx = 0;
   12321 
   12322 
   12323     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
   12324            (ctxt->error == XPATH_EXPRESSION_OK)) {
   12325 	xpctxt->node = contextSeq->nodeTab[contextIdx++];
   12326 
   12327 	if (seq == NULL) {
   12328 	    seq = xmlXPathNodeSetCreate(NULL);
   12329 	    if (seq == NULL) {
   12330 		total = 0;
   12331 		goto error;
   12332 	    }
   12333 	}
   12334 	/*
   12335 	* Traverse the axis and test the nodes.
   12336 	*/
   12337 	pos = 0;
   12338 	cur = NULL;
   12339 	hasNsNodes = 0;
   12340         do {
   12341             cur = next(ctxt, cur);
   12342             if (cur == NULL)
   12343                 break;
   12344 
   12345 	    /*
   12346 	    * QUESTION TODO: What does the "first" and "last" stuff do?
   12347 	    */
   12348             if ((first != NULL) && (*first != NULL)) {
   12349 		if (*first == cur)
   12350 		    break;
   12351 		if (((total % 256) == 0) &&
   12352 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   12353 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
   12354 #else
   12355 		    (xmlXPathCmpNodes(*first, cur) >= 0))
   12356 #endif
   12357 		{
   12358 		    break;
   12359 		}
   12360 	    }
   12361 	    if ((last != NULL) && (*last != NULL)) {
   12362 		if (*last == cur)
   12363 		    break;
   12364 		if (((total % 256) == 0) &&
   12365 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   12366 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
   12367 #else
   12368 		    (xmlXPathCmpNodes(cur, *last) >= 0))
   12369 #endif
   12370 		{
   12371 		    break;
   12372 		}
   12373 	    }
   12374 
   12375             total++;
   12376 
   12377 #ifdef DEBUG_STEP
   12378             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
   12379 #endif
   12380 
   12381 	    switch (test) {
   12382                 case NODE_TEST_NONE:
   12383 		    total = 0;
   12384                     STRANGE
   12385 		    goto error;
   12386                 case NODE_TEST_TYPE:
   12387 		    if (type == NODE_TYPE_NODE) {
   12388 			switch (cur->type) {
   12389 			    case XML_DOCUMENT_NODE:
   12390 			    case XML_HTML_DOCUMENT_NODE:
   12391 #ifdef LIBXML_DOCB_ENABLED
   12392 			    case XML_DOCB_DOCUMENT_NODE:
   12393 #endif
   12394 			    case XML_ELEMENT_NODE:
   12395 			    case XML_ATTRIBUTE_NODE:
   12396 			    case XML_PI_NODE:
   12397 			    case XML_COMMENT_NODE:
   12398 			    case XML_CDATA_SECTION_NODE:
   12399 			    case XML_TEXT_NODE:
   12400 				XP_TEST_HIT
   12401 				break;
   12402 			    case XML_NAMESPACE_DECL: {
   12403 				if (axis == AXIS_NAMESPACE) {
   12404 				    XP_TEST_HIT_NS
   12405 				} else {
   12406 	                            hasNsNodes = 1;
   12407 				    XP_TEST_HIT
   12408 				}
   12409 				break;
   12410                             }
   12411 			    default:
   12412 				break;
   12413 			}
   12414 		    } else if (cur->type == type) {
   12415 			if (cur->type == XML_NAMESPACE_DECL)
   12416 			    XP_TEST_HIT_NS
   12417 			else
   12418 			    XP_TEST_HIT
   12419 		    } else if ((type == NODE_TYPE_TEXT) &&
   12420 			 (cur->type == XML_CDATA_SECTION_NODE))
   12421 		    {
   12422 			XP_TEST_HIT
   12423 		    }
   12424 		    break;
   12425                 case NODE_TEST_PI:
   12426                     if ((cur->type == XML_PI_NODE) &&
   12427                         ((name == NULL) || xmlStrEqual(name, cur->name)))
   12428 		    {
   12429 			XP_TEST_HIT
   12430                     }
   12431                     break;
   12432                 case NODE_TEST_ALL:
   12433                     if (axis == AXIS_ATTRIBUTE) {
   12434                         if (cur->type == XML_ATTRIBUTE_NODE)
   12435 			{
   12436                             if (prefix == NULL)
   12437 			    {
   12438 				XP_TEST_HIT
   12439                             } else if ((cur->ns != NULL) &&
   12440 				(xmlStrEqual(URI, cur->ns->href)))
   12441 			    {
   12442 				XP_TEST_HIT
   12443                             }
   12444                         }
   12445                     } else if (axis == AXIS_NAMESPACE) {
   12446                         if (cur->type == XML_NAMESPACE_DECL)
   12447 			{
   12448 			    XP_TEST_HIT_NS
   12449                         }
   12450                     } else {
   12451                         if (cur->type == XML_ELEMENT_NODE) {
   12452                             if (prefix == NULL)
   12453 			    {
   12454 				XP_TEST_HIT
   12455 
   12456                             } else if ((cur->ns != NULL) &&
   12457 				(xmlStrEqual(URI, cur->ns->href)))
   12458 			    {
   12459 				XP_TEST_HIT
   12460                             }
   12461                         }
   12462                     }
   12463                     break;
   12464                 case NODE_TEST_NS:{
   12465                         TODO;
   12466                         break;
   12467                     }
   12468                 case NODE_TEST_NAME:
   12469                     if (axis == AXIS_ATTRIBUTE) {
   12470                         if (cur->type != XML_ATTRIBUTE_NODE)
   12471 			    break;
   12472 		    } else if (axis == AXIS_NAMESPACE) {
   12473                         if (cur->type != XML_NAMESPACE_DECL)
   12474 			    break;
   12475 		    } else {
   12476 		        if (cur->type != XML_ELEMENT_NODE)
   12477 			    break;
   12478 		    }
   12479                     switch (cur->type) {
   12480                         case XML_ELEMENT_NODE:
   12481                             if (xmlStrEqual(name, cur->name)) {
   12482                                 if (prefix == NULL) {
   12483                                     if (cur->ns == NULL)
   12484 				    {
   12485 					XP_TEST_HIT
   12486                                     }
   12487                                 } else {
   12488                                     if ((cur->ns != NULL) &&
   12489                                         (xmlStrEqual(URI, cur->ns->href)))
   12490 				    {
   12491 					XP_TEST_HIT
   12492                                     }
   12493                                 }
   12494                             }
   12495                             break;
   12496                         case XML_ATTRIBUTE_NODE:{
   12497                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
   12498 
   12499                                 if (xmlStrEqual(name, attr->name)) {
   12500                                     if (prefix == NULL) {
   12501                                         if ((attr->ns == NULL) ||
   12502                                             (attr->ns->prefix == NULL))
   12503 					{
   12504 					    XP_TEST_HIT
   12505                                         }
   12506                                     } else {
   12507                                         if ((attr->ns != NULL) &&
   12508                                             (xmlStrEqual(URI,
   12509 					      attr->ns->href)))
   12510 					{
   12511 					    XP_TEST_HIT
   12512                                         }
   12513                                     }
   12514                                 }
   12515                                 break;
   12516                             }
   12517                         case XML_NAMESPACE_DECL:
   12518                             if (cur->type == XML_NAMESPACE_DECL) {
   12519                                 xmlNsPtr ns = (xmlNsPtr) cur;
   12520 
   12521                                 if ((ns->prefix != NULL) && (name != NULL)
   12522                                     && (xmlStrEqual(ns->prefix, name)))
   12523 				{
   12524 				    XP_TEST_HIT_NS
   12525                                 }
   12526                             }
   12527                             break;
   12528                         default:
   12529                             break;
   12530                     }
   12531                     break;
   12532 	    } /* switch(test) */
   12533         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
   12534 
   12535 	goto apply_predicates;
   12536 
   12537 axis_range_end: /* ----------------------------------------------------- */
   12538 	/*
   12539 	* We have a "/foo[n]", and position() = n was reached.
   12540 	* Note that we can have as well "/foo/::parent::foo[1]", so
   12541 	* a duplicate-aware merge is still needed.
   12542 	* Merge with the result.
   12543 	*/
   12544 	if (outSeq == NULL) {
   12545 	    outSeq = seq;
   12546 	    seq = NULL;
   12547 	} else
   12548 	    outSeq = mergeAndClear(outSeq, seq, 0);
   12549 	/*
   12550 	* Break if only a true/false result was requested.
   12551 	*/
   12552 	if (toBool)
   12553 	    break;
   12554 	continue;
   12555 
   12556 first_hit: /* ---------------------------------------------------------- */
   12557 	/*
   12558 	* Break if only a true/false result was requested and
   12559 	* no predicates existed and a node test succeeded.
   12560 	*/
   12561 	if (outSeq == NULL) {
   12562 	    outSeq = seq;
   12563 	    seq = NULL;
   12564 	} else
   12565 	    outSeq = mergeAndClear(outSeq, seq, 0);
   12566 	break;
   12567 
   12568 #ifdef DEBUG_STEP
   12569 	if (seq != NULL)
   12570 	    nbMatches += seq->nodeNr;
   12571 #endif
   12572 
   12573 apply_predicates: /* --------------------------------------------------- */
   12574         if (ctxt->error != XPATH_EXPRESSION_OK)
   12575 	    goto error;
   12576 
   12577         /*
   12578 	* Apply predicates.
   12579 	*/
   12580         if ((predOp != NULL) && (seq->nodeNr > 0)) {
   12581 	    /*
   12582 	    * E.g. when we have a "/foo[some expression][n]".
   12583 	    */
   12584 	    /*
   12585 	    * QUESTION TODO: The old predicate evaluation took into
   12586 	    *  account location-sets.
   12587 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
   12588 	    *  Do we expect such a set here?
   12589 	    *  All what I learned now from the evaluation semantics
   12590 	    *  does not indicate that a location-set will be processed
   12591 	    *  here, so this looks OK.
   12592 	    */
   12593 	    /*
   12594 	    * Iterate over all predicates, starting with the outermost
   12595 	    * predicate.
   12596 	    * TODO: Problem: we cannot execute the inner predicates first
   12597 	    *  since we cannot go back *up* the operator tree!
   12598 	    *  Options we have:
   12599 	    *  1) Use of recursive functions (like is it currently done
   12600 	    *     via xmlXPathCompOpEval())
   12601 	    *  2) Add a predicate evaluation information stack to the
   12602 	    *     context struct
   12603 	    *  3) Change the way the operators are linked; we need a
   12604 	    *     "parent" field on xmlXPathStepOp
   12605 	    *
   12606 	    * For the moment, I'll try to solve this with a recursive
   12607 	    * function: xmlXPathCompOpEvalPredicate().
   12608 	    */
   12609 	    size = seq->nodeNr;
   12610 	    if (hasPredicateRange != 0)
   12611 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
   12612 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
   12613 	    else
   12614 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
   12615 		    predOp, seq, size, hasNsNodes);
   12616 
   12617 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   12618 		total = 0;
   12619 		goto error;
   12620 	    }
   12621 	    /*
   12622 	    * Add the filtered set of nodes to the result node set.
   12623 	    */
   12624 	    if (newSize == 0) {
   12625 		/*
   12626 		* The predicates filtered all nodes out.
   12627 		*/
   12628 		xmlXPathNodeSetClear(seq, hasNsNodes);
   12629 	    } else if (seq->nodeNr > 0) {
   12630 		/*
   12631 		* Add to result set.
   12632 		*/
   12633 		if (outSeq == NULL) {
   12634 		    if (size != newSize) {
   12635 			/*
   12636 			* We need to merge and clear here, since
   12637 			* the sequence will contained NULLed entries.
   12638 			*/
   12639 			outSeq = mergeAndClear(NULL, seq, 1);
   12640 		    } else {
   12641 			outSeq = seq;
   12642 			seq = NULL;
   12643 		    }
   12644 		} else
   12645 		    outSeq = mergeAndClear(outSeq, seq,
   12646 			(size != newSize) ? 1: 0);
   12647 		/*
   12648 		* Break if only a true/false result was requested.
   12649 		*/
   12650 		if (toBool)
   12651 		    break;
   12652 	    }
   12653         } else if (seq->nodeNr > 0) {
   12654 	    /*
   12655 	    * Add to result set.
   12656 	    */
   12657 	    if (outSeq == NULL) {
   12658 		outSeq = seq;
   12659 		seq = NULL;
   12660 	    } else {
   12661 		outSeq = mergeAndClear(outSeq, seq, 0);
   12662 	    }
   12663 	}
   12664     }
   12665 
   12666 error:
   12667     if ((obj->boolval) && (obj->user != NULL)) {
   12668 	/*
   12669 	* QUESTION TODO: What does this do and why?
   12670 	* TODO: Do we have to do this also for the "error"
   12671 	* cleanup further down?
   12672 	*/
   12673 	ctxt->value->boolval = 1;
   12674 	ctxt->value->user = obj->user;
   12675 	obj->user = NULL;
   12676 	obj->boolval = 0;
   12677     }
   12678     xmlXPathReleaseObject(xpctxt, obj);
   12679 
   12680     /*
   12681     * Ensure we return at least an emtpy set.
   12682     */
   12683     if (outSeq == NULL) {
   12684 	if ((seq != NULL) && (seq->nodeNr == 0))
   12685 	    outSeq = seq;
   12686 	else
   12687 	    outSeq = xmlXPathNodeSetCreate(NULL);
   12688         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
   12689     }
   12690     if ((seq != NULL) && (seq != outSeq)) {
   12691 	 xmlXPathFreeNodeSet(seq);
   12692     }
   12693     /*
   12694     * Hand over the result. Better to push the set also in
   12695     * case of errors.
   12696     */
   12697     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
   12698     /*
   12699     * Reset the context node.
   12700     */
   12701     xpctxt->node = oldContextNode;
   12702     /*
   12703     * When traversing the namespace axis in "toBool" mode, it's
   12704     * possible that tmpNsList wasn't freed.
   12705     */
   12706     if (xpctxt->tmpNsList != NULL) {
   12707         xmlFree(xpctxt->tmpNsList);
   12708         xpctxt->tmpNsList = NULL;
   12709     }
   12710 
   12711 #ifdef DEBUG_STEP
   12712     xmlGenericError(xmlGenericErrorContext,
   12713 	"\nExamined %d nodes, found %d nodes at that step\n",
   12714 	total, nbMatches);
   12715 #endif
   12716 
   12717     return(total);
   12718 }
   12719 
   12720 static int
   12721 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
   12722 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
   12723 
   12724 /**
   12725  * xmlXPathCompOpEvalFirst:
   12726  * @ctxt:  the XPath parser context with the compiled expression
   12727  * @op:  an XPath compiled operation
   12728  * @first:  the first elem found so far
   12729  *
   12730  * Evaluate the Precompiled XPath operation searching only the first
   12731  * element in document order
   12732  *
   12733  * Returns the number of examined objects.
   12734  */
   12735 static int
   12736 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
   12737                         xmlXPathStepOpPtr op, xmlNodePtr * first)
   12738 {
   12739     int total = 0, cur;
   12740     xmlXPathCompExprPtr comp;
   12741     xmlXPathObjectPtr arg1, arg2;
   12742 
   12743     CHECK_ERROR0;
   12744     comp = ctxt->comp;
   12745     switch (op->op) {
   12746         case XPATH_OP_END:
   12747             return (0);
   12748         case XPATH_OP_UNION:
   12749             total =
   12750                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
   12751                                         first);
   12752 	    CHECK_ERROR0;
   12753             if ((ctxt->value != NULL)
   12754                 && (ctxt->value->type == XPATH_NODESET)
   12755                 && (ctxt->value->nodesetval != NULL)
   12756                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
   12757                 /*
   12758                  * limit tree traversing to first node in the result
   12759                  */
   12760 		/*
   12761 		* OPTIMIZE TODO: This implicitely sorts
   12762 		*  the result, even if not needed. E.g. if the argument
   12763 		*  of the count() function, no sorting is needed.
   12764 		* OPTIMIZE TODO: How do we know if the node-list wasn't
   12765 		*  aready sorted?
   12766 		*/
   12767 		if (ctxt->value->nodesetval->nodeNr > 1)
   12768 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12769                 *first = ctxt->value->nodesetval->nodeTab[0];
   12770             }
   12771             cur =
   12772                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
   12773                                         first);
   12774 	    CHECK_ERROR0;
   12775             CHECK_TYPE0(XPATH_NODESET);
   12776             arg2 = valuePop(ctxt);
   12777 
   12778             CHECK_TYPE0(XPATH_NODESET);
   12779             arg1 = valuePop(ctxt);
   12780 
   12781             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   12782                                                     arg2->nodesetval);
   12783             valuePush(ctxt, arg1);
   12784 	    xmlXPathReleaseObject(ctxt->context, arg2);
   12785             /* optimizer */
   12786 	    if (total > cur)
   12787 		xmlXPathCompSwap(op);
   12788             return (total + cur);
   12789         case XPATH_OP_ROOT:
   12790             xmlXPathRoot(ctxt);
   12791             return (0);
   12792         case XPATH_OP_NODE:
   12793             if (op->ch1 != -1)
   12794                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12795 	    CHECK_ERROR0;
   12796             if (op->ch2 != -1)
   12797                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12798 	    CHECK_ERROR0;
   12799 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   12800 		ctxt->context->node));
   12801             return (total);
   12802         case XPATH_OP_RESET:
   12803             if (op->ch1 != -1)
   12804                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12805 	    CHECK_ERROR0;
   12806             if (op->ch2 != -1)
   12807                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12808 	    CHECK_ERROR0;
   12809             ctxt->context->node = NULL;
   12810             return (total);
   12811         case XPATH_OP_COLLECT:{
   12812                 if (op->ch1 == -1)
   12813                     return (total);
   12814 
   12815                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12816 		CHECK_ERROR0;
   12817 
   12818                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
   12819                 return (total);
   12820             }
   12821         case XPATH_OP_VALUE:
   12822             valuePush(ctxt,
   12823                       xmlXPathCacheObjectCopy(ctxt->context,
   12824 			(xmlXPathObjectPtr) op->value4));
   12825             return (0);
   12826         case XPATH_OP_SORT:
   12827             if (op->ch1 != -1)
   12828                 total +=
   12829                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
   12830                                             first);
   12831 	    CHECK_ERROR0;
   12832             if ((ctxt->value != NULL)
   12833                 && (ctxt->value->type == XPATH_NODESET)
   12834                 && (ctxt->value->nodesetval != NULL)
   12835 		&& (ctxt->value->nodesetval->nodeNr > 1))
   12836                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12837             return (total);
   12838 #ifdef XP_OPTIMIZED_FILTER_FIRST
   12839 	case XPATH_OP_FILTER:
   12840                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
   12841             return (total);
   12842 #endif
   12843         default:
   12844             return (xmlXPathCompOpEval(ctxt, op));
   12845     }
   12846 }
   12847 
   12848 /**
   12849  * xmlXPathCompOpEvalLast:
   12850  * @ctxt:  the XPath parser context with the compiled expression
   12851  * @op:  an XPath compiled operation
   12852  * @last:  the last elem found so far
   12853  *
   12854  * Evaluate the Precompiled XPath operation searching only the last
   12855  * element in document order
   12856  *
   12857  * Returns the number of nodes traversed
   12858  */
   12859 static int
   12860 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
   12861                        xmlNodePtr * last)
   12862 {
   12863     int total = 0, cur;
   12864     xmlXPathCompExprPtr comp;
   12865     xmlXPathObjectPtr arg1, arg2;
   12866     xmlNodePtr bak;
   12867     xmlDocPtr bakd;
   12868     int pp;
   12869     int cs;
   12870 
   12871     CHECK_ERROR0;
   12872     comp = ctxt->comp;
   12873     switch (op->op) {
   12874         case XPATH_OP_END:
   12875             return (0);
   12876         case XPATH_OP_UNION:
   12877 	    bakd = ctxt->context->doc;
   12878 	    bak = ctxt->context->node;
   12879 	    pp = ctxt->context->proximityPosition;
   12880 	    cs = ctxt->context->contextSize;
   12881             total =
   12882                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
   12883 	    CHECK_ERROR0;
   12884             if ((ctxt->value != NULL)
   12885                 && (ctxt->value->type == XPATH_NODESET)
   12886                 && (ctxt->value->nodesetval != NULL)
   12887                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
   12888                 /*
   12889                  * limit tree traversing to first node in the result
   12890                  */
   12891 		if (ctxt->value->nodesetval->nodeNr > 1)
   12892 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12893                 *last =
   12894                     ctxt->value->nodesetval->nodeTab[ctxt->value->
   12895                                                      nodesetval->nodeNr -
   12896                                                      1];
   12897             }
   12898 	    ctxt->context->doc = bakd;
   12899 	    ctxt->context->node = bak;
   12900 	    ctxt->context->proximityPosition = pp;
   12901 	    ctxt->context->contextSize = cs;
   12902             cur =
   12903                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
   12904 	    CHECK_ERROR0;
   12905             if ((ctxt->value != NULL)
   12906                 && (ctxt->value->type == XPATH_NODESET)
   12907                 && (ctxt->value->nodesetval != NULL)
   12908                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
   12909             }
   12910             CHECK_TYPE0(XPATH_NODESET);
   12911             arg2 = valuePop(ctxt);
   12912 
   12913             CHECK_TYPE0(XPATH_NODESET);
   12914             arg1 = valuePop(ctxt);
   12915 
   12916             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   12917                                                     arg2->nodesetval);
   12918             valuePush(ctxt, arg1);
   12919 	    xmlXPathReleaseObject(ctxt->context, arg2);
   12920             /* optimizer */
   12921 	    if (total > cur)
   12922 		xmlXPathCompSwap(op);
   12923             return (total + cur);
   12924         case XPATH_OP_ROOT:
   12925             xmlXPathRoot(ctxt);
   12926             return (0);
   12927         case XPATH_OP_NODE:
   12928             if (op->ch1 != -1)
   12929                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12930 	    CHECK_ERROR0;
   12931             if (op->ch2 != -1)
   12932                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12933 	    CHECK_ERROR0;
   12934 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   12935 		ctxt->context->node));
   12936             return (total);
   12937         case XPATH_OP_RESET:
   12938             if (op->ch1 != -1)
   12939                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12940 	    CHECK_ERROR0;
   12941             if (op->ch2 != -1)
   12942                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12943 	    CHECK_ERROR0;
   12944             ctxt->context->node = NULL;
   12945             return (total);
   12946         case XPATH_OP_COLLECT:{
   12947                 if (op->ch1 == -1)
   12948                     return (0);
   12949 
   12950                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12951 		CHECK_ERROR0;
   12952 
   12953                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
   12954                 return (total);
   12955             }
   12956         case XPATH_OP_VALUE:
   12957             valuePush(ctxt,
   12958                       xmlXPathCacheObjectCopy(ctxt->context,
   12959 			(xmlXPathObjectPtr) op->value4));
   12960             return (0);
   12961         case XPATH_OP_SORT:
   12962             if (op->ch1 != -1)
   12963                 total +=
   12964                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
   12965                                            last);
   12966 	    CHECK_ERROR0;
   12967             if ((ctxt->value != NULL)
   12968                 && (ctxt->value->type == XPATH_NODESET)
   12969                 && (ctxt->value->nodesetval != NULL)
   12970 		&& (ctxt->value->nodesetval->nodeNr > 1))
   12971                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12972             return (total);
   12973         default:
   12974             return (xmlXPathCompOpEval(ctxt, op));
   12975     }
   12976 }
   12977 
   12978 #ifdef XP_OPTIMIZED_FILTER_FIRST
   12979 static int
   12980 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
   12981 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
   12982 {
   12983     int total = 0;
   12984     xmlXPathCompExprPtr comp;
   12985     xmlXPathObjectPtr res;
   12986     xmlXPathObjectPtr obj;
   12987     xmlNodeSetPtr oldset;
   12988     xmlNodePtr oldnode;
   12989     xmlDocPtr oldDoc;
   12990     int i;
   12991 
   12992     CHECK_ERROR0;
   12993     comp = ctxt->comp;
   12994     /*
   12995     * Optimization for ()[last()] selection i.e. the last elem
   12996     */
   12997     if ((op->ch1 != -1) && (op->ch2 != -1) &&
   12998 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   12999 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
   13000 	int f = comp->steps[op->ch2].ch1;
   13001 
   13002 	if ((f != -1) &&
   13003 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
   13004 	    (comp->steps[f].value5 == NULL) &&
   13005 	    (comp->steps[f].value == 0) &&
   13006 	    (comp->steps[f].value4 != NULL) &&
   13007 	    (xmlStrEqual
   13008 	    (comp->steps[f].value4, BAD_CAST "last"))) {
   13009 	    xmlNodePtr last = NULL;
   13010 
   13011 	    total +=
   13012 		xmlXPathCompOpEvalLast(ctxt,
   13013 		    &comp->steps[op->ch1],
   13014 		    &last);
   13015 	    CHECK_ERROR0;
   13016 	    /*
   13017 	    * The nodeset should be in document order,
   13018 	    * Keep only the last value
   13019 	    */
   13020 	    if ((ctxt->value != NULL) &&
   13021 		(ctxt->value->type == XPATH_NODESET) &&
   13022 		(ctxt->value->nodesetval != NULL) &&
   13023 		(ctxt->value->nodesetval->nodeTab != NULL) &&
   13024 		(ctxt->value->nodesetval->nodeNr > 1)) {
   13025 		ctxt->value->nodesetval->nodeTab[0] =
   13026 		    ctxt->value->nodesetval->nodeTab[ctxt->
   13027 		    value->
   13028 		    nodesetval->
   13029 		    nodeNr -
   13030 		    1];
   13031 		ctxt->value->nodesetval->nodeNr = 1;
   13032 		*first = *(ctxt->value->nodesetval->nodeTab);
   13033 	    }
   13034 	    return (total);
   13035 	}
   13036     }
   13037 
   13038     if (op->ch1 != -1)
   13039 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13040     CHECK_ERROR0;
   13041     if (op->ch2 == -1)
   13042 	return (total);
   13043     if (ctxt->value == NULL)
   13044 	return (total);
   13045 
   13046 #ifdef LIBXML_XPTR_ENABLED
   13047     oldnode = ctxt->context->node;
   13048     /*
   13049     * Hum are we filtering the result of an XPointer expression
   13050     */
   13051     if (ctxt->value->type == XPATH_LOCATIONSET) {
   13052 	xmlXPathObjectPtr tmp = NULL;
   13053 	xmlLocationSetPtr newlocset = NULL;
   13054 	xmlLocationSetPtr oldlocset;
   13055 
   13056 	/*
   13057 	* Extract the old locset, and then evaluate the result of the
   13058 	* expression for all the element in the locset. use it to grow
   13059 	* up a new locset.
   13060 	*/
   13061 	CHECK_TYPE0(XPATH_LOCATIONSET);
   13062 	obj = valuePop(ctxt);
   13063 	oldlocset = obj->user;
   13064 	ctxt->context->node = NULL;
   13065 
   13066 	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   13067 	    ctxt->context->contextSize = 0;
   13068 	    ctxt->context->proximityPosition = 0;
   13069 	    if (op->ch2 != -1)
   13070 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13071 	    res = valuePop(ctxt);
   13072 	    if (res != NULL) {
   13073 		xmlXPathReleaseObject(ctxt->context, res);
   13074 	    }
   13075 	    valuePush(ctxt, obj);
   13076 	    CHECK_ERROR0;
   13077 	    return (total);
   13078 	}
   13079 	newlocset = xmlXPtrLocationSetCreate(NULL);
   13080 
   13081 	for (i = 0; i < oldlocset->locNr; i++) {
   13082 	    /*
   13083 	    * Run the evaluation with a node list made of a
   13084 	    * single item in the nodelocset.
   13085 	    */
   13086 	    ctxt->context->node = oldlocset->locTab[i]->user;
   13087 	    ctxt->context->contextSize = oldlocset->locNr;
   13088 	    ctxt->context->proximityPosition = i + 1;
   13089 	    if (tmp == NULL) {
   13090 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13091 		    ctxt->context->node);
   13092 	    } else {
   13093 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13094 		                             ctxt->context->node) < 0) {
   13095 		    ctxt->error = XPATH_MEMORY_ERROR;
   13096 		}
   13097 	    }
   13098 	    valuePush(ctxt, tmp);
   13099 	    if (op->ch2 != -1)
   13100 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13101 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   13102 		xmlXPathFreeObject(obj);
   13103 		return(0);
   13104 	    }
   13105 	    /*
   13106 	    * The result of the evaluation need to be tested to
   13107 	    * decided whether the filter succeeded or not
   13108 	    */
   13109 	    res = valuePop(ctxt);
   13110 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13111 		xmlXPtrLocationSetAdd(newlocset,
   13112 		    xmlXPathCacheObjectCopy(ctxt->context,
   13113 			oldlocset->locTab[i]));
   13114 	    }
   13115 	    /*
   13116 	    * Cleanup
   13117 	    */
   13118 	    if (res != NULL) {
   13119 		xmlXPathReleaseObject(ctxt->context, res);
   13120 	    }
   13121 	    if (ctxt->value == tmp) {
   13122 		valuePop(ctxt);
   13123 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13124 		/*
   13125 		* REVISIT TODO: Don't create a temporary nodeset
   13126 		* for everly iteration.
   13127 		*/
   13128 		/* OLD: xmlXPathFreeObject(res); */
   13129 	    } else
   13130 		tmp = NULL;
   13131 	    ctxt->context->node = NULL;
   13132 	    /*
   13133 	    * Only put the first node in the result, then leave.
   13134 	    */
   13135 	    if (newlocset->locNr > 0) {
   13136 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
   13137 		break;
   13138 	    }
   13139 	}
   13140 	if (tmp != NULL) {
   13141 	    xmlXPathReleaseObject(ctxt->context, tmp);
   13142 	}
   13143 	/*
   13144 	* The result is used as the new evaluation locset.
   13145 	*/
   13146 	xmlXPathReleaseObject(ctxt->context, obj);
   13147 	ctxt->context->node = NULL;
   13148 	ctxt->context->contextSize = -1;
   13149 	ctxt->context->proximityPosition = -1;
   13150 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   13151 	ctxt->context->node = oldnode;
   13152 	return (total);
   13153     }
   13154 #endif /* LIBXML_XPTR_ENABLED */
   13155 
   13156     /*
   13157     * Extract the old set, and then evaluate the result of the
   13158     * expression for all the element in the set. use it to grow
   13159     * up a new set.
   13160     */
   13161     CHECK_TYPE0(XPATH_NODESET);
   13162     obj = valuePop(ctxt);
   13163     oldset = obj->nodesetval;
   13164 
   13165     oldnode = ctxt->context->node;
   13166     oldDoc = ctxt->context->doc;
   13167     ctxt->context->node = NULL;
   13168 
   13169     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
   13170 	ctxt->context->contextSize = 0;
   13171 	ctxt->context->proximityPosition = 0;
   13172 	/* QUESTION TODO: Why was this code commented out?
   13173 	    if (op->ch2 != -1)
   13174 		total +=
   13175 		    xmlXPathCompOpEval(ctxt,
   13176 			&comp->steps[op->ch2]);
   13177 	    CHECK_ERROR0;
   13178 	    res = valuePop(ctxt);
   13179 	    if (res != NULL)
   13180 		xmlXPathFreeObject(res);
   13181 	*/
   13182 	valuePush(ctxt, obj);
   13183 	ctxt->context->node = oldnode;
   13184 	CHECK_ERROR0;
   13185     } else {
   13186 	xmlNodeSetPtr newset;
   13187 	xmlXPathObjectPtr tmp = NULL;
   13188 	/*
   13189 	* Initialize the new set.
   13190 	* Also set the xpath document in case things like
   13191 	* key() evaluation are attempted on the predicate
   13192 	*/
   13193 	newset = xmlXPathNodeSetCreate(NULL);
   13194         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
   13195 
   13196 	for (i = 0; i < oldset->nodeNr; i++) {
   13197 	    /*
   13198 	    * Run the evaluation with a node list made of
   13199 	    * a single item in the nodeset.
   13200 	    */
   13201 	    ctxt->context->node = oldset->nodeTab[i];
   13202 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
   13203 		(oldset->nodeTab[i]->doc != NULL))
   13204 		ctxt->context->doc = oldset->nodeTab[i]->doc;
   13205 	    if (tmp == NULL) {
   13206 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13207 		    ctxt->context->node);
   13208 	    } else {
   13209 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13210 		                             ctxt->context->node) < 0) {
   13211 		    ctxt->error = XPATH_MEMORY_ERROR;
   13212 		}
   13213 	    }
   13214 	    valuePush(ctxt, tmp);
   13215 	    ctxt->context->contextSize = oldset->nodeNr;
   13216 	    ctxt->context->proximityPosition = i + 1;
   13217 	    if (op->ch2 != -1)
   13218 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13219 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   13220 		xmlXPathFreeNodeSet(newset);
   13221 		xmlXPathFreeObject(obj);
   13222 		return(0);
   13223 	    }
   13224 	    /*
   13225 	    * The result of the evaluation needs to be tested to
   13226 	    * decide whether the filter succeeded or not
   13227 	    */
   13228 	    res = valuePop(ctxt);
   13229 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13230 		if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
   13231 		    ctxt->error = XPATH_MEMORY_ERROR;
   13232 	    }
   13233 	    /*
   13234 	    * Cleanup
   13235 	    */
   13236 	    if (res != NULL) {
   13237 		xmlXPathReleaseObject(ctxt->context, res);
   13238 	    }
   13239 	    if (ctxt->value == tmp) {
   13240 		valuePop(ctxt);
   13241 		/*
   13242 		* Don't free the temporary nodeset
   13243 		* in order to avoid massive recreation inside this
   13244 		* loop.
   13245 		*/
   13246 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13247 	    } else
   13248 		tmp = NULL;
   13249 	    ctxt->context->node = NULL;
   13250 	    /*
   13251 	    * Only put the first node in the result, then leave.
   13252 	    */
   13253 	    if (newset->nodeNr > 0) {
   13254 		*first = *(newset->nodeTab);
   13255 		break;
   13256 	    }
   13257 	}
   13258 	if (tmp != NULL) {
   13259 	    xmlXPathReleaseObject(ctxt->context, tmp);
   13260 	}
   13261 	/*
   13262 	* The result is used as the new evaluation set.
   13263 	*/
   13264 	xmlXPathReleaseObject(ctxt->context, obj);
   13265 	ctxt->context->node = NULL;
   13266 	ctxt->context->contextSize = -1;
   13267 	ctxt->context->proximityPosition = -1;
   13268 	/* may want to move this past the '}' later */
   13269 	ctxt->context->doc = oldDoc;
   13270 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
   13271     }
   13272     ctxt->context->node = oldnode;
   13273     return(total);
   13274 }
   13275 #endif /* XP_OPTIMIZED_FILTER_FIRST */
   13276 
   13277 /**
   13278  * xmlXPathCompOpEval:
   13279  * @ctxt:  the XPath parser context with the compiled expression
   13280  * @op:  an XPath compiled operation
   13281  *
   13282  * Evaluate the Precompiled XPath operation
   13283  * Returns the number of nodes traversed
   13284  */
   13285 static int
   13286 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
   13287 {
   13288     int total = 0;
   13289     int equal, ret;
   13290     xmlXPathCompExprPtr comp;
   13291     xmlXPathObjectPtr arg1, arg2;
   13292     xmlNodePtr bak;
   13293     xmlDocPtr bakd;
   13294     int pp;
   13295     int cs;
   13296 
   13297     CHECK_ERROR0;
   13298     comp = ctxt->comp;
   13299     switch (op->op) {
   13300         case XPATH_OP_END:
   13301             return (0);
   13302         case XPATH_OP_AND:
   13303 	    bakd = ctxt->context->doc;
   13304 	    bak = ctxt->context->node;
   13305 	    pp = ctxt->context->proximityPosition;
   13306 	    cs = ctxt->context->contextSize;
   13307             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13308 	    CHECK_ERROR0;
   13309             xmlXPathBooleanFunction(ctxt, 1);
   13310             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
   13311                 return (total);
   13312             arg2 = valuePop(ctxt);
   13313 	    ctxt->context->doc = bakd;
   13314 	    ctxt->context->node = bak;
   13315 	    ctxt->context->proximityPosition = pp;
   13316 	    ctxt->context->contextSize = cs;
   13317             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13318 	    if (ctxt->error) {
   13319 		xmlXPathFreeObject(arg2);
   13320 		return(0);
   13321 	    }
   13322             xmlXPathBooleanFunction(ctxt, 1);
   13323             arg1 = valuePop(ctxt);
   13324             arg1->boolval &= arg2->boolval;
   13325             valuePush(ctxt, arg1);
   13326 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13327             return (total);
   13328         case XPATH_OP_OR:
   13329 	    bakd = ctxt->context->doc;
   13330 	    bak = ctxt->context->node;
   13331 	    pp = ctxt->context->proximityPosition;
   13332 	    cs = ctxt->context->contextSize;
   13333             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13334 	    CHECK_ERROR0;
   13335             xmlXPathBooleanFunction(ctxt, 1);
   13336             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
   13337                 return (total);
   13338             arg2 = valuePop(ctxt);
   13339 	    ctxt->context->doc = bakd;
   13340 	    ctxt->context->node = bak;
   13341 	    ctxt->context->proximityPosition = pp;
   13342 	    ctxt->context->contextSize = cs;
   13343             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13344 	    if (ctxt->error) {
   13345 		xmlXPathFreeObject(arg2);
   13346 		return(0);
   13347 	    }
   13348             xmlXPathBooleanFunction(ctxt, 1);
   13349             arg1 = valuePop(ctxt);
   13350             arg1->boolval |= arg2->boolval;
   13351             valuePush(ctxt, arg1);
   13352 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13353             return (total);
   13354         case XPATH_OP_EQUAL:
   13355 	    bakd = ctxt->context->doc;
   13356 	    bak = ctxt->context->node;
   13357 	    pp = ctxt->context->proximityPosition;
   13358 	    cs = ctxt->context->contextSize;
   13359             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13360 	    CHECK_ERROR0;
   13361 	    ctxt->context->doc = bakd;
   13362 	    ctxt->context->node = bak;
   13363 	    ctxt->context->proximityPosition = pp;
   13364 	    ctxt->context->contextSize = cs;
   13365             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13366 	    CHECK_ERROR0;
   13367 	    if (op->value)
   13368 		equal = xmlXPathEqualValues(ctxt);
   13369 	    else
   13370 		equal = xmlXPathNotEqualValues(ctxt);
   13371 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
   13372             return (total);
   13373         case XPATH_OP_CMP:
   13374 	    bakd = ctxt->context->doc;
   13375 	    bak = ctxt->context->node;
   13376 	    pp = ctxt->context->proximityPosition;
   13377 	    cs = ctxt->context->contextSize;
   13378             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13379 	    CHECK_ERROR0;
   13380 	    ctxt->context->doc = bakd;
   13381 	    ctxt->context->node = bak;
   13382 	    ctxt->context->proximityPosition = pp;
   13383 	    ctxt->context->contextSize = cs;
   13384             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13385 	    CHECK_ERROR0;
   13386             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
   13387 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
   13388             return (total);
   13389         case XPATH_OP_PLUS:
   13390 	    bakd = ctxt->context->doc;
   13391 	    bak = ctxt->context->node;
   13392 	    pp = ctxt->context->proximityPosition;
   13393 	    cs = ctxt->context->contextSize;
   13394             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13395 	    CHECK_ERROR0;
   13396             if (op->ch2 != -1) {
   13397 		ctxt->context->doc = bakd;
   13398 		ctxt->context->node = bak;
   13399 		ctxt->context->proximityPosition = pp;
   13400 		ctxt->context->contextSize = cs;
   13401                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13402 	    }
   13403 	    CHECK_ERROR0;
   13404             if (op->value == 0)
   13405                 xmlXPathSubValues(ctxt);
   13406             else if (op->value == 1)
   13407                 xmlXPathAddValues(ctxt);
   13408             else if (op->value == 2)
   13409                 xmlXPathValueFlipSign(ctxt);
   13410             else if (op->value == 3) {
   13411                 CAST_TO_NUMBER;
   13412                 CHECK_TYPE0(XPATH_NUMBER);
   13413             }
   13414             return (total);
   13415         case XPATH_OP_MULT:
   13416 	    bakd = ctxt->context->doc;
   13417 	    bak = ctxt->context->node;
   13418 	    pp = ctxt->context->proximityPosition;
   13419 	    cs = ctxt->context->contextSize;
   13420             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13421 	    CHECK_ERROR0;
   13422 	    ctxt->context->doc = bakd;
   13423 	    ctxt->context->node = bak;
   13424 	    ctxt->context->proximityPosition = pp;
   13425 	    ctxt->context->contextSize = cs;
   13426             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13427 	    CHECK_ERROR0;
   13428             if (op->value == 0)
   13429                 xmlXPathMultValues(ctxt);
   13430             else if (op->value == 1)
   13431                 xmlXPathDivValues(ctxt);
   13432             else if (op->value == 2)
   13433                 xmlXPathModValues(ctxt);
   13434             return (total);
   13435         case XPATH_OP_UNION:
   13436 	    bakd = ctxt->context->doc;
   13437 	    bak = ctxt->context->node;
   13438 	    pp = ctxt->context->proximityPosition;
   13439 	    cs = ctxt->context->contextSize;
   13440             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13441 	    CHECK_ERROR0;
   13442 	    ctxt->context->doc = bakd;
   13443 	    ctxt->context->node = bak;
   13444 	    ctxt->context->proximityPosition = pp;
   13445 	    ctxt->context->contextSize = cs;
   13446             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13447 	    CHECK_ERROR0;
   13448             CHECK_TYPE0(XPATH_NODESET);
   13449             arg2 = valuePop(ctxt);
   13450 
   13451             CHECK_TYPE0(XPATH_NODESET);
   13452             arg1 = valuePop(ctxt);
   13453 
   13454 	    if ((arg1->nodesetval == NULL) ||
   13455 		((arg2->nodesetval != NULL) &&
   13456 		 (arg2->nodesetval->nodeNr != 0)))
   13457 	    {
   13458 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   13459 							arg2->nodesetval);
   13460 	    }
   13461 
   13462             valuePush(ctxt, arg1);
   13463 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13464             return (total);
   13465         case XPATH_OP_ROOT:
   13466             xmlXPathRoot(ctxt);
   13467             return (total);
   13468         case XPATH_OP_NODE:
   13469             if (op->ch1 != -1)
   13470                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13471 	    CHECK_ERROR0;
   13472             if (op->ch2 != -1)
   13473                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13474 	    CHECK_ERROR0;
   13475 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   13476 		ctxt->context->node));
   13477             return (total);
   13478         case XPATH_OP_RESET:
   13479             if (op->ch1 != -1)
   13480                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13481 	    CHECK_ERROR0;
   13482             if (op->ch2 != -1)
   13483                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13484 	    CHECK_ERROR0;
   13485             ctxt->context->node = NULL;
   13486             return (total);
   13487         case XPATH_OP_COLLECT:{
   13488                 if (op->ch1 == -1)
   13489                     return (total);
   13490 
   13491                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13492 		CHECK_ERROR0;
   13493 
   13494                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
   13495                 return (total);
   13496             }
   13497         case XPATH_OP_VALUE:
   13498             valuePush(ctxt,
   13499                       xmlXPathCacheObjectCopy(ctxt->context,
   13500 			(xmlXPathObjectPtr) op->value4));
   13501             return (total);
   13502         case XPATH_OP_VARIABLE:{
   13503 		xmlXPathObjectPtr val;
   13504 
   13505                 if (op->ch1 != -1)
   13506                     total +=
   13507                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13508                 if (op->value5 == NULL) {
   13509 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
   13510 		    if (val == NULL) {
   13511 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
   13512 			return(0);
   13513 		    }
   13514                     valuePush(ctxt, val);
   13515 		} else {
   13516                     const xmlChar *URI;
   13517 
   13518                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
   13519                     if (URI == NULL) {
   13520                         xmlGenericError(xmlGenericErrorContext,
   13521             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
   13522                                     (char *) op->value4, (char *)op->value5);
   13523                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
   13524                         return (total);
   13525                     }
   13526 		    val = xmlXPathVariableLookupNS(ctxt->context,
   13527                                                        op->value4, URI);
   13528 		    if (val == NULL) {
   13529 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
   13530 			return(0);
   13531 		    }
   13532                     valuePush(ctxt, val);
   13533                 }
   13534                 return (total);
   13535             }
   13536         case XPATH_OP_FUNCTION:{
   13537                 xmlXPathFunction func;
   13538                 const xmlChar *oldFunc, *oldFuncURI;
   13539 		int i;
   13540                 int frame;
   13541 
   13542                 frame = xmlXPathSetFrame(ctxt);
   13543                 if (op->ch1 != -1) {
   13544                     total +=
   13545                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13546                     if (ctxt->error != XPATH_EXPRESSION_OK) {
   13547                         xmlXPathPopFrame(ctxt, frame);
   13548                         return (total);
   13549                     }
   13550                 }
   13551 		if (ctxt->valueNr < ctxt->valueFrame + op->value) {
   13552 		    xmlGenericError(xmlGenericErrorContext,
   13553 			    "xmlXPathCompOpEval: parameter error\n");
   13554 		    ctxt->error = XPATH_INVALID_OPERAND;
   13555                     xmlXPathPopFrame(ctxt, frame);
   13556 		    return (total);
   13557 		}
   13558 		for (i = 0; i < op->value; i++) {
   13559 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
   13560 			xmlGenericError(xmlGenericErrorContext,
   13561 				"xmlXPathCompOpEval: parameter error\n");
   13562 			ctxt->error = XPATH_INVALID_OPERAND;
   13563                         xmlXPathPopFrame(ctxt, frame);
   13564 			return (total);
   13565 		    }
   13566                 }
   13567                 if (op->cache != NULL)
   13568                     XML_CAST_FPTR(func) = op->cache;
   13569                 else {
   13570                     const xmlChar *URI = NULL;
   13571 
   13572                     if (op->value5 == NULL)
   13573                         func =
   13574                             xmlXPathFunctionLookup(ctxt->context,
   13575                                                    op->value4);
   13576                     else {
   13577                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
   13578                         if (URI == NULL) {
   13579                             xmlGenericError(xmlGenericErrorContext,
   13580             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
   13581                                     (char *)op->value4, (char *)op->value5);
   13582                             xmlXPathPopFrame(ctxt, frame);
   13583                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
   13584                             return (total);
   13585                         }
   13586                         func = xmlXPathFunctionLookupNS(ctxt->context,
   13587                                                         op->value4, URI);
   13588                     }
   13589                     if (func == NULL) {
   13590                         xmlGenericError(xmlGenericErrorContext,
   13591                                 "xmlXPathCompOpEval: function %s not found\n",
   13592                                         (char *)op->value4);
   13593                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
   13594                     }
   13595                     op->cache = XML_CAST_FPTR(func);
   13596                     op->cacheURI = (void *) URI;
   13597                 }
   13598                 oldFunc = ctxt->context->function;
   13599                 oldFuncURI = ctxt->context->functionURI;
   13600                 ctxt->context->function = op->value4;
   13601                 ctxt->context->functionURI = op->cacheURI;
   13602                 func(ctxt, op->value);
   13603                 ctxt->context->function = oldFunc;
   13604                 ctxt->context->functionURI = oldFuncURI;
   13605                 xmlXPathPopFrame(ctxt, frame);
   13606                 return (total);
   13607             }
   13608         case XPATH_OP_ARG:
   13609 	    bakd = ctxt->context->doc;
   13610 	    bak = ctxt->context->node;
   13611 	    pp = ctxt->context->proximityPosition;
   13612 	    cs = ctxt->context->contextSize;
   13613             if (op->ch1 != -1) {
   13614                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13615                 ctxt->context->contextSize = cs;
   13616                 ctxt->context->proximityPosition = pp;
   13617                 ctxt->context->node = bak;
   13618                 ctxt->context->doc = bakd;
   13619 	        CHECK_ERROR0;
   13620             }
   13621             if (op->ch2 != -1) {
   13622                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13623                 ctxt->context->contextSize = cs;
   13624                 ctxt->context->proximityPosition = pp;
   13625                 ctxt->context->node = bak;
   13626                 ctxt->context->doc = bakd;
   13627 	        CHECK_ERROR0;
   13628 	    }
   13629             return (total);
   13630         case XPATH_OP_PREDICATE:
   13631         case XPATH_OP_FILTER:{
   13632                 xmlXPathObjectPtr res;
   13633                 xmlXPathObjectPtr obj, tmp;
   13634                 xmlNodeSetPtr newset = NULL;
   13635                 xmlNodeSetPtr oldset;
   13636                 xmlNodePtr oldnode;
   13637 		xmlDocPtr oldDoc;
   13638                 int i;
   13639 
   13640                 /*
   13641                  * Optimization for ()[1] selection i.e. the first elem
   13642                  */
   13643                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
   13644 #ifdef XP_OPTIMIZED_FILTER_FIRST
   13645 		    /*
   13646 		    * FILTER TODO: Can we assume that the inner processing
   13647 		    *  will result in an ordered list if we have an
   13648 		    *  XPATH_OP_FILTER?
   13649 		    *  What about an additional field or flag on
   13650 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
   13651 		    *  to assume anything, so it would be more robust and
   13652 		    *  easier to optimize.
   13653 		    */
   13654                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
   13655 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
   13656 #else
   13657 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   13658 #endif
   13659                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
   13660                     xmlXPathObjectPtr val;
   13661 
   13662                     val = comp->steps[op->ch2].value4;
   13663                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
   13664                         (val->floatval == 1.0)) {
   13665                         xmlNodePtr first = NULL;
   13666 
   13667                         total +=
   13668                             xmlXPathCompOpEvalFirst(ctxt,
   13669                                                     &comp->steps[op->ch1],
   13670                                                     &first);
   13671 			CHECK_ERROR0;
   13672                         /*
   13673                          * The nodeset should be in document order,
   13674                          * Keep only the first value
   13675                          */
   13676                         if ((ctxt->value != NULL) &&
   13677                             (ctxt->value->type == XPATH_NODESET) &&
   13678                             (ctxt->value->nodesetval != NULL) &&
   13679                             (ctxt->value->nodesetval->nodeNr > 1))
   13680                             ctxt->value->nodesetval->nodeNr = 1;
   13681                         return (total);
   13682                     }
   13683                 }
   13684                 /*
   13685                  * Optimization for ()[last()] selection i.e. the last elem
   13686                  */
   13687                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
   13688                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   13689                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
   13690                     int f = comp->steps[op->ch2].ch1;
   13691 
   13692                     if ((f != -1) &&
   13693                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
   13694                         (comp->steps[f].value5 == NULL) &&
   13695                         (comp->steps[f].value == 0) &&
   13696                         (comp->steps[f].value4 != NULL) &&
   13697                         (xmlStrEqual
   13698                          (comp->steps[f].value4, BAD_CAST "last"))) {
   13699                         xmlNodePtr last = NULL;
   13700 
   13701                         total +=
   13702                             xmlXPathCompOpEvalLast(ctxt,
   13703                                                    &comp->steps[op->ch1],
   13704                                                    &last);
   13705 			CHECK_ERROR0;
   13706                         /*
   13707                          * The nodeset should be in document order,
   13708                          * Keep only the last value
   13709                          */
   13710                         if ((ctxt->value != NULL) &&
   13711                             (ctxt->value->type == XPATH_NODESET) &&
   13712                             (ctxt->value->nodesetval != NULL) &&
   13713                             (ctxt->value->nodesetval->nodeTab != NULL) &&
   13714                             (ctxt->value->nodesetval->nodeNr > 1)) {
   13715                             ctxt->value->nodesetval->nodeTab[0] =
   13716                                 ctxt->value->nodesetval->nodeTab[ctxt->
   13717                                                                  value->
   13718                                                                  nodesetval->
   13719                                                                  nodeNr -
   13720                                                                  1];
   13721                             ctxt->value->nodesetval->nodeNr = 1;
   13722                         }
   13723                         return (total);
   13724                     }
   13725                 }
   13726 		/*
   13727 		* Process inner predicates first.
   13728 		* Example "index[parent::book][1]":
   13729 		* ...
   13730 		*   PREDICATE   <-- we are here "[1]"
   13731 		*     PREDICATE <-- process "[parent::book]" first
   13732 		*       SORT
   13733 		*         COLLECT  'parent' 'name' 'node' book
   13734 		*           NODE
   13735 		*     ELEM Object is a number : 1
   13736 		*/
   13737                 if (op->ch1 != -1)
   13738                     total +=
   13739                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13740 		CHECK_ERROR0;
   13741                 if (op->ch2 == -1)
   13742                     return (total);
   13743                 if (ctxt->value == NULL)
   13744                     return (total);
   13745 
   13746                 oldnode = ctxt->context->node;
   13747 
   13748 #ifdef LIBXML_XPTR_ENABLED
   13749                 /*
   13750                  * Hum are we filtering the result of an XPointer expression
   13751                  */
   13752                 if (ctxt->value->type == XPATH_LOCATIONSET) {
   13753                     xmlLocationSetPtr newlocset = NULL;
   13754                     xmlLocationSetPtr oldlocset;
   13755 
   13756                     /*
   13757                      * Extract the old locset, and then evaluate the result of the
   13758                      * expression for all the element in the locset. use it to grow
   13759                      * up a new locset.
   13760                      */
   13761                     CHECK_TYPE0(XPATH_LOCATIONSET);
   13762                     obj = valuePop(ctxt);
   13763                     oldlocset = obj->user;
   13764                     ctxt->context->node = NULL;
   13765 
   13766                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   13767                         ctxt->context->contextSize = 0;
   13768                         ctxt->context->proximityPosition = 0;
   13769                         if (op->ch2 != -1)
   13770                             total +=
   13771                                 xmlXPathCompOpEval(ctxt,
   13772                                                    &comp->steps[op->ch2]);
   13773                         res = valuePop(ctxt);
   13774                         if (res != NULL) {
   13775 			    xmlXPathReleaseObject(ctxt->context, res);
   13776 			}
   13777                         valuePush(ctxt, obj);
   13778                         CHECK_ERROR0;
   13779                         return (total);
   13780                     }
   13781                     newlocset = xmlXPtrLocationSetCreate(NULL);
   13782 
   13783                     for (i = 0; i < oldlocset->locNr; i++) {
   13784                         /*
   13785                          * Run the evaluation with a node list made of a
   13786                          * single item in the nodelocset.
   13787                          */
   13788                         ctxt->context->node = oldlocset->locTab[i]->user;
   13789                         ctxt->context->contextSize = oldlocset->locNr;
   13790                         ctxt->context->proximityPosition = i + 1;
   13791 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13792 			    ctxt->context->node);
   13793                         valuePush(ctxt, tmp);
   13794 
   13795                         if (op->ch2 != -1)
   13796                             total +=
   13797                                 xmlXPathCompOpEval(ctxt,
   13798                                                    &comp->steps[op->ch2]);
   13799 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13800 			    xmlXPathFreeObject(obj);
   13801 			    return(0);
   13802 			}
   13803 
   13804                         /*
   13805                          * The result of the evaluation need to be tested to
   13806                          * decided whether the filter succeeded or not
   13807                          */
   13808                         res = valuePop(ctxt);
   13809                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13810                             xmlXPtrLocationSetAdd(newlocset,
   13811                                                   xmlXPathObjectCopy
   13812                                                   (oldlocset->locTab[i]));
   13813                         }
   13814 
   13815                         /*
   13816                          * Cleanup
   13817                          */
   13818                         if (res != NULL) {
   13819 			    xmlXPathReleaseObject(ctxt->context, res);
   13820 			}
   13821                         if (ctxt->value == tmp) {
   13822                             res = valuePop(ctxt);
   13823 			    xmlXPathReleaseObject(ctxt->context, res);
   13824                         }
   13825 
   13826                         ctxt->context->node = NULL;
   13827                     }
   13828 
   13829                     /*
   13830                      * The result is used as the new evaluation locset.
   13831                      */
   13832 		    xmlXPathReleaseObject(ctxt->context, obj);
   13833                     ctxt->context->node = NULL;
   13834                     ctxt->context->contextSize = -1;
   13835                     ctxt->context->proximityPosition = -1;
   13836                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   13837                     ctxt->context->node = oldnode;
   13838                     return (total);
   13839                 }
   13840 #endif /* LIBXML_XPTR_ENABLED */
   13841 
   13842                 /*
   13843                  * Extract the old set, and then evaluate the result of the
   13844                  * expression for all the element in the set. use it to grow
   13845                  * up a new set.
   13846                  */
   13847                 CHECK_TYPE0(XPATH_NODESET);
   13848                 obj = valuePop(ctxt);
   13849                 oldset = obj->nodesetval;
   13850 
   13851                 oldnode = ctxt->context->node;
   13852 		oldDoc = ctxt->context->doc;
   13853                 ctxt->context->node = NULL;
   13854 
   13855                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
   13856                     ctxt->context->contextSize = 0;
   13857                     ctxt->context->proximityPosition = 0;
   13858 /*
   13859                     if (op->ch2 != -1)
   13860                         total +=
   13861                             xmlXPathCompOpEval(ctxt,
   13862                                                &comp->steps[op->ch2]);
   13863 		    CHECK_ERROR0;
   13864                     res = valuePop(ctxt);
   13865                     if (res != NULL)
   13866                         xmlXPathFreeObject(res);
   13867 */
   13868                     valuePush(ctxt, obj);
   13869                     ctxt->context->node = oldnode;
   13870                     CHECK_ERROR0;
   13871                 } else {
   13872 		    tmp = NULL;
   13873                     /*
   13874                      * Initialize the new set.
   13875 		     * Also set the xpath document in case things like
   13876 		     * key() evaluation are attempted on the predicate
   13877                      */
   13878                     newset = xmlXPathNodeSetCreate(NULL);
   13879 		    /*
   13880 		    * SPEC XPath 1.0:
   13881 		    *  "For each node in the node-set to be filtered, the
   13882 		    *  PredicateExpr is evaluated with that node as the
   13883 		    *  context node, with the number of nodes in the
   13884 		    *  node-set as the context size, and with the proximity
   13885 		    *  position of the node in the node-set with respect to
   13886 		    *  the axis as the context position;"
   13887 		    * @oldset is the node-set" to be filtered.
   13888 		    *
   13889 		    * SPEC XPath 1.0:
   13890 		    *  "only predicates change the context position and
   13891 		    *  context size (see [2.4 Predicates])."
   13892 		    * Example:
   13893 		    *   node-set  context pos
   13894 		    *    nA         1
   13895 		    *    nB         2
   13896 		    *    nC         3
   13897 		    *   After applying predicate [position() > 1] :
   13898 		    *   node-set  context pos
   13899 		    *    nB         1
   13900 		    *    nC         2
   13901 		    *
   13902 		    * removed the first node in the node-set, then
   13903 		    * the context position of the
   13904 		    */
   13905                     for (i = 0; i < oldset->nodeNr; i++) {
   13906                         /*
   13907                          * Run the evaluation with a node list made of
   13908                          * a single item in the nodeset.
   13909                          */
   13910                         ctxt->context->node = oldset->nodeTab[i];
   13911 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
   13912 			    (oldset->nodeTab[i]->doc != NULL))
   13913 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
   13914 			if (tmp == NULL) {
   13915 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13916 				ctxt->context->node);
   13917 			} else {
   13918 			    if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13919 				               ctxt->context->node) < 0) {
   13920 				ctxt->error = XPATH_MEMORY_ERROR;
   13921 			    }
   13922 			}
   13923                         valuePush(ctxt, tmp);
   13924                         ctxt->context->contextSize = oldset->nodeNr;
   13925                         ctxt->context->proximityPosition = i + 1;
   13926 			/*
   13927 			* Evaluate the predicate against the context node.
   13928 			* Can/should we optimize position() predicates
   13929 			* here (e.g. "[1]")?
   13930 			*/
   13931                         if (op->ch2 != -1)
   13932                             total +=
   13933                                 xmlXPathCompOpEval(ctxt,
   13934                                                    &comp->steps[op->ch2]);
   13935 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13936 			    xmlXPathFreeNodeSet(newset);
   13937 			    xmlXPathFreeObject(obj);
   13938 			    return(0);
   13939 			}
   13940 
   13941                         /*
   13942                          * The result of the evaluation needs to be tested to
   13943                          * decide whether the filter succeeded or not
   13944                          */
   13945 			/*
   13946 			* OPTIMIZE TODO: Can we use
   13947 			* xmlXPathNodeSetAdd*Unique()* instead?
   13948 			*/
   13949                         res = valuePop(ctxt);
   13950                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13951                             if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
   13952 			        < 0)
   13953 				ctxt->error = XPATH_MEMORY_ERROR;
   13954                         }
   13955 
   13956                         /*
   13957                          * Cleanup
   13958                          */
   13959                         if (res != NULL) {
   13960 			    xmlXPathReleaseObject(ctxt->context, res);
   13961 			}
   13962                         if (ctxt->value == tmp) {
   13963                             valuePop(ctxt);
   13964 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13965 			    /*
   13966 			    * Don't free the temporary nodeset
   13967 			    * in order to avoid massive recreation inside this
   13968 			    * loop.
   13969 			    */
   13970                         } else
   13971 			    tmp = NULL;
   13972                         ctxt->context->node = NULL;
   13973                     }
   13974 		    if (tmp != NULL)
   13975 			xmlXPathReleaseObject(ctxt->context, tmp);
   13976                     /*
   13977                      * The result is used as the new evaluation set.
   13978                      */
   13979 		    xmlXPathReleaseObject(ctxt->context, obj);
   13980                     ctxt->context->node = NULL;
   13981                     ctxt->context->contextSize = -1;
   13982                     ctxt->context->proximityPosition = -1;
   13983 		    /* may want to move this past the '}' later */
   13984 		    ctxt->context->doc = oldDoc;
   13985 		    valuePush(ctxt,
   13986 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
   13987                 }
   13988                 ctxt->context->node = oldnode;
   13989                 return (total);
   13990             }
   13991         case XPATH_OP_SORT:
   13992             if (op->ch1 != -1)
   13993                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13994 	    CHECK_ERROR0;
   13995             if ((ctxt->value != NULL) &&
   13996                 (ctxt->value->type == XPATH_NODESET) &&
   13997                 (ctxt->value->nodesetval != NULL) &&
   13998 		(ctxt->value->nodesetval->nodeNr > 1))
   13999 	    {
   14000                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   14001 	    }
   14002             return (total);
   14003 #ifdef LIBXML_XPTR_ENABLED
   14004         case XPATH_OP_RANGETO:{
   14005                 xmlXPathObjectPtr range;
   14006                 xmlXPathObjectPtr res, obj;
   14007                 xmlXPathObjectPtr tmp;
   14008                 xmlLocationSetPtr newlocset = NULL;
   14009 		    xmlLocationSetPtr oldlocset;
   14010                 xmlNodeSetPtr oldset;
   14011                 int i, j;
   14012 
   14013                 if (op->ch1 != -1) {
   14014                     total +=
   14015                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   14016                     CHECK_ERROR0;
   14017                 }
   14018                 if (ctxt->value == NULL) {
   14019                     XP_ERROR0(XPATH_INVALID_OPERAND);
   14020                 }
   14021                 if (op->ch2 == -1)
   14022                     return (total);
   14023 
   14024                 if (ctxt->value->type == XPATH_LOCATIONSET) {
   14025                     /*
   14026                      * Extract the old locset, and then evaluate the result of the
   14027                      * expression for all the element in the locset. use it to grow
   14028                      * up a new locset.
   14029                      */
   14030                     CHECK_TYPE0(XPATH_LOCATIONSET);
   14031                     obj = valuePop(ctxt);
   14032                     oldlocset = obj->user;
   14033 
   14034                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   14035 		        ctxt->context->node = NULL;
   14036                         ctxt->context->contextSize = 0;
   14037                         ctxt->context->proximityPosition = 0;
   14038                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
   14039                         res = valuePop(ctxt);
   14040                         if (res != NULL) {
   14041 			    xmlXPathReleaseObject(ctxt->context, res);
   14042 			}
   14043                         valuePush(ctxt, obj);
   14044                         CHECK_ERROR0;
   14045                         return (total);
   14046                     }
   14047                     newlocset = xmlXPtrLocationSetCreate(NULL);
   14048 
   14049                     for (i = 0; i < oldlocset->locNr; i++) {
   14050                         /*
   14051                          * Run the evaluation with a node list made of a
   14052                          * single item in the nodelocset.
   14053                          */
   14054                         ctxt->context->node = oldlocset->locTab[i]->user;
   14055                         ctxt->context->contextSize = oldlocset->locNr;
   14056                         ctxt->context->proximityPosition = i + 1;
   14057 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   14058 			    ctxt->context->node);
   14059                         valuePush(ctxt, tmp);
   14060 
   14061                         if (op->ch2 != -1)
   14062                             total +=
   14063                                 xmlXPathCompOpEval(ctxt,
   14064                                                    &comp->steps[op->ch2]);
   14065 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   14066 			    xmlXPathFreeObject(obj);
   14067 			    return(0);
   14068 			}
   14069 
   14070                         res = valuePop(ctxt);
   14071 			if (res->type == XPATH_LOCATIONSET) {
   14072 			    xmlLocationSetPtr rloc =
   14073 			        (xmlLocationSetPtr)res->user;
   14074 			    for (j=0; j<rloc->locNr; j++) {
   14075 			        range = xmlXPtrNewRange(
   14076 				  oldlocset->locTab[i]->user,
   14077 				  oldlocset->locTab[i]->index,
   14078 				  rloc->locTab[j]->user2,
   14079 				  rloc->locTab[j]->index2);
   14080 				if (range != NULL) {
   14081 				    xmlXPtrLocationSetAdd(newlocset, range);
   14082 				}
   14083 			    }
   14084 			} else {
   14085 			    range = xmlXPtrNewRangeNodeObject(
   14086 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
   14087                             if (range != NULL) {
   14088                                 xmlXPtrLocationSetAdd(newlocset,range);
   14089 			    }
   14090                         }
   14091 
   14092                         /*
   14093                          * Cleanup
   14094                          */
   14095                         if (res != NULL) {
   14096 			    xmlXPathReleaseObject(ctxt->context, res);
   14097 			}
   14098                         if (ctxt->value == tmp) {
   14099                             res = valuePop(ctxt);
   14100 			    xmlXPathReleaseObject(ctxt->context, res);
   14101                         }
   14102 
   14103                         ctxt->context->node = NULL;
   14104                     }
   14105 		} else {	/* Not a location set */
   14106                     CHECK_TYPE0(XPATH_NODESET);
   14107                     obj = valuePop(ctxt);
   14108                     oldset = obj->nodesetval;
   14109                     ctxt->context->node = NULL;
   14110 
   14111                     newlocset = xmlXPtrLocationSetCreate(NULL);
   14112 
   14113                     if (oldset != NULL) {
   14114                         for (i = 0; i < oldset->nodeNr; i++) {
   14115                             /*
   14116                              * Run the evaluation with a node list made of a single item
   14117                              * in the nodeset.
   14118                              */
   14119                             ctxt->context->node = oldset->nodeTab[i];
   14120 			    /*
   14121 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
   14122 			    */
   14123 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   14124 				ctxt->context->node);
   14125                             valuePush(ctxt, tmp);
   14126 
   14127                             if (op->ch2 != -1)
   14128                                 total +=
   14129                                     xmlXPathCompOpEval(ctxt,
   14130                                                    &comp->steps[op->ch2]);
   14131 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
   14132 				xmlXPathFreeObject(obj);
   14133 				return(0);
   14134 			    }
   14135 
   14136                             res = valuePop(ctxt);
   14137                             range =
   14138                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
   14139                                                       res);
   14140                             if (range != NULL) {
   14141                                 xmlXPtrLocationSetAdd(newlocset, range);
   14142                             }
   14143 
   14144                             /*
   14145                              * Cleanup
   14146                              */
   14147                             if (res != NULL) {
   14148 				xmlXPathReleaseObject(ctxt->context, res);
   14149 			    }
   14150                             if (ctxt->value == tmp) {
   14151                                 res = valuePop(ctxt);
   14152 				xmlXPathReleaseObject(ctxt->context, res);
   14153                             }
   14154 
   14155                             ctxt->context->node = NULL;
   14156                         }
   14157                     }
   14158                 }
   14159 
   14160                 /*
   14161                  * The result is used as the new evaluation set.
   14162                  */
   14163 		xmlXPathReleaseObject(ctxt->context, obj);
   14164                 ctxt->context->node = NULL;
   14165                 ctxt->context->contextSize = -1;
   14166                 ctxt->context->proximityPosition = -1;
   14167                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   14168                 return (total);
   14169             }
   14170 #endif /* LIBXML_XPTR_ENABLED */
   14171     }
   14172     xmlGenericError(xmlGenericErrorContext,
   14173                     "XPath: unknown precompiled operation %d\n", op->op);
   14174     ctxt->error = XPATH_INVALID_OPERAND;
   14175     return (total);
   14176 }
   14177 
   14178 /**
   14179  * xmlXPathCompOpEvalToBoolean:
   14180  * @ctxt:  the XPath parser context
   14181  *
   14182  * Evaluates if the expression evaluates to true.
   14183  *
   14184  * Returns 1 if true, 0 if false and -1 on API or internal errors.
   14185  */
   14186 static int
   14187 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
   14188 			    xmlXPathStepOpPtr op,
   14189 			    int isPredicate)
   14190 {
   14191     xmlXPathObjectPtr resObj = NULL;
   14192 
   14193 start:
   14194     /* comp = ctxt->comp; */
   14195     switch (op->op) {
   14196         case XPATH_OP_END:
   14197             return (0);
   14198 	case XPATH_OP_VALUE:
   14199 	    resObj = (xmlXPathObjectPtr) op->value4;
   14200 	    if (isPredicate)
   14201 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
   14202 	    return(xmlXPathCastToBoolean(resObj));
   14203 	case XPATH_OP_SORT:
   14204 	    /*
   14205 	    * We don't need sorting for boolean results. Skip this one.
   14206 	    */
   14207             if (op->ch1 != -1) {
   14208 		op = &ctxt->comp->steps[op->ch1];
   14209 		goto start;
   14210 	    }
   14211 	    return(0);
   14212 	case XPATH_OP_COLLECT:
   14213 	    if (op->ch1 == -1)
   14214 		return(0);
   14215 
   14216             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
   14217 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14218 		return(-1);
   14219 
   14220             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
   14221 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14222 		return(-1);
   14223 
   14224 	    resObj = valuePop(ctxt);
   14225 	    if (resObj == NULL)
   14226 		return(-1);
   14227 	    break;
   14228 	default:
   14229 	    /*
   14230 	    * Fallback to call xmlXPathCompOpEval().
   14231 	    */
   14232 	    xmlXPathCompOpEval(ctxt, op);
   14233 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14234 		return(-1);
   14235 
   14236 	    resObj = valuePop(ctxt);
   14237 	    if (resObj == NULL)
   14238 		return(-1);
   14239 	    break;
   14240     }
   14241 
   14242     if (resObj) {
   14243 	int res;
   14244 
   14245 	if (resObj->type == XPATH_BOOLEAN) {
   14246 	    res = resObj->boolval;
   14247 	} else if (isPredicate) {
   14248 	    /*
   14249 	    * For predicates a result of type "number" is handled
   14250 	    * differently:
   14251 	    * SPEC XPath 1.0:
   14252 	    * "If the result is a number, the result will be converted
   14253 	    *  to true if the number is equal to the context position
   14254 	    *  and will be converted to false otherwise;"
   14255 	    */
   14256 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
   14257 	} else {
   14258 	    res = xmlXPathCastToBoolean(resObj);
   14259 	}
   14260 	xmlXPathReleaseObject(ctxt->context, resObj);
   14261 	return(res);
   14262     }
   14263 
   14264     return(0);
   14265 }
   14266 
   14267 #ifdef XPATH_STREAMING
   14268 /**
   14269  * xmlXPathRunStreamEval:
   14270  * @ctxt:  the XPath parser context with the compiled expression
   14271  *
   14272  * Evaluate the Precompiled Streamable XPath expression in the given context.
   14273  */
   14274 static int
   14275 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
   14276 		      xmlXPathObjectPtr *resultSeq, int toBool)
   14277 {
   14278     int max_depth, min_depth;
   14279     int from_root;
   14280     int ret, depth;
   14281     int eval_all_nodes;
   14282     xmlNodePtr cur = NULL, limit = NULL;
   14283     xmlStreamCtxtPtr patstream = NULL;
   14284 
   14285     int nb_nodes = 0;
   14286 
   14287     if ((ctxt == NULL) || (comp == NULL))
   14288         return(-1);
   14289     max_depth = xmlPatternMaxDepth(comp);
   14290     if (max_depth == -1)
   14291         return(-1);
   14292     if (max_depth == -2)
   14293         max_depth = 10000;
   14294     min_depth = xmlPatternMinDepth(comp);
   14295     if (min_depth == -1)
   14296         return(-1);
   14297     from_root = xmlPatternFromRoot(comp);
   14298     if (from_root < 0)
   14299         return(-1);
   14300 #if 0
   14301     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
   14302 #endif
   14303 
   14304     if (! toBool) {
   14305 	if (resultSeq == NULL)
   14306 	    return(-1);
   14307 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
   14308 	if (*resultSeq == NULL)
   14309 	    return(-1);
   14310     }
   14311 
   14312     /*
   14313      * handle the special cases of "/" amd "." being matched
   14314      */
   14315     if (min_depth == 0) {
   14316 	if (from_root) {
   14317 	    /* Select "/" */
   14318 	    if (toBool)
   14319 		return(1);
   14320 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
   14321 		                     (xmlNodePtr) ctxt->doc);
   14322 	} else {
   14323 	    /* Select "self::node()" */
   14324 	    if (toBool)
   14325 		return(1);
   14326 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
   14327 	}
   14328     }
   14329     if (max_depth == 0) {
   14330 	return(0);
   14331     }
   14332 
   14333     if (from_root) {
   14334         cur = (xmlNodePtr)ctxt->doc;
   14335     } else if (ctxt->node != NULL) {
   14336         switch (ctxt->node->type) {
   14337             case XML_ELEMENT_NODE:
   14338             case XML_DOCUMENT_NODE:
   14339             case XML_DOCUMENT_FRAG_NODE:
   14340             case XML_HTML_DOCUMENT_NODE:
   14341 #ifdef LIBXML_DOCB_ENABLED
   14342             case XML_DOCB_DOCUMENT_NODE:
   14343 #endif
   14344 	        cur = ctxt->node;
   14345 		break;
   14346             case XML_ATTRIBUTE_NODE:
   14347             case XML_TEXT_NODE:
   14348             case XML_CDATA_SECTION_NODE:
   14349             case XML_ENTITY_REF_NODE:
   14350             case XML_ENTITY_NODE:
   14351             case XML_PI_NODE:
   14352             case XML_COMMENT_NODE:
   14353             case XML_NOTATION_NODE:
   14354             case XML_DTD_NODE:
   14355             case XML_DOCUMENT_TYPE_NODE:
   14356             case XML_ELEMENT_DECL:
   14357             case XML_ATTRIBUTE_DECL:
   14358             case XML_ENTITY_DECL:
   14359             case XML_NAMESPACE_DECL:
   14360             case XML_XINCLUDE_START:
   14361             case XML_XINCLUDE_END:
   14362 		break;
   14363 	}
   14364 	limit = cur;
   14365     }
   14366     if (cur == NULL) {
   14367         return(0);
   14368     }
   14369 
   14370     patstream = xmlPatternGetStreamCtxt(comp);
   14371     if (patstream == NULL) {
   14372 	/*
   14373 	* QUESTION TODO: Is this an error?
   14374 	*/
   14375 	return(0);
   14376     }
   14377 
   14378     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
   14379 
   14380     if (from_root) {
   14381 	ret = xmlStreamPush(patstream, NULL, NULL);
   14382 	if (ret < 0) {
   14383 	} else if (ret == 1) {
   14384 	    if (toBool)
   14385 		goto return_1;
   14386 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
   14387 	}
   14388     }
   14389     depth = 0;
   14390     goto scan_children;
   14391 next_node:
   14392     do {
   14393         nb_nodes++;
   14394 
   14395 	switch (cur->type) {
   14396 	    case XML_ELEMENT_NODE:
   14397 	    case XML_TEXT_NODE:
   14398 	    case XML_CDATA_SECTION_NODE:
   14399 	    case XML_COMMENT_NODE:
   14400 	    case XML_PI_NODE:
   14401 		if (cur->type == XML_ELEMENT_NODE) {
   14402 		    ret = xmlStreamPush(patstream, cur->name,
   14403 				(cur->ns ? cur->ns->href : NULL));
   14404 		} else if (eval_all_nodes)
   14405 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
   14406 		else
   14407 		    break;
   14408 
   14409 		if (ret < 0) {
   14410 		    /* NOP. */
   14411 		} else if (ret == 1) {
   14412 		    if (toBool)
   14413 			goto return_1;
   14414 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
   14415 		        < 0) {
   14416 			ctxt->lastError.domain = XML_FROM_XPATH;
   14417 			ctxt->lastError.code = XML_ERR_NO_MEMORY;
   14418 		    }
   14419 		}
   14420 		if ((cur->children == NULL) || (depth >= max_depth)) {
   14421 		    ret = xmlStreamPop(patstream);
   14422 		    while (cur->next != NULL) {
   14423 			cur = cur->next;
   14424 			if ((cur->type != XML_ENTITY_DECL) &&
   14425 			    (cur->type != XML_DTD_NODE))
   14426 			    goto next_node;
   14427 		    }
   14428 		}
   14429 	    default:
   14430 		break;
   14431 	}
   14432 
   14433 scan_children:
   14434 	if (cur->type == XML_NAMESPACE_DECL) break;
   14435 	if ((cur->children != NULL) && (depth < max_depth)) {
   14436 	    /*
   14437 	     * Do not descend on entities declarations
   14438 	     */
   14439 	    if (cur->children->type != XML_ENTITY_DECL) {
   14440 		cur = cur->children;
   14441 		depth++;
   14442 		/*
   14443 		 * Skip DTDs
   14444 		 */
   14445 		if (cur->type != XML_DTD_NODE)
   14446 		    continue;
   14447 	    }
   14448 	}
   14449 
   14450 	if (cur == limit)
   14451 	    break;
   14452 
   14453 	while (cur->next != NULL) {
   14454 	    cur = cur->next;
   14455 	    if ((cur->type != XML_ENTITY_DECL) &&
   14456 		(cur->type != XML_DTD_NODE))
   14457 		goto next_node;
   14458 	}
   14459 
   14460 	do {
   14461 	    cur = cur->parent;
   14462 	    depth--;
   14463 	    if ((cur == NULL) || (cur == limit))
   14464 	        goto done;
   14465 	    if (cur->type == XML_ELEMENT_NODE) {
   14466 		ret = xmlStreamPop(patstream);
   14467 	    } else if ((eval_all_nodes) &&
   14468 		((cur->type == XML_TEXT_NODE) ||
   14469 		 (cur->type == XML_CDATA_SECTION_NODE) ||
   14470 		 (cur->type == XML_COMMENT_NODE) ||
   14471 		 (cur->type == XML_PI_NODE)))
   14472 	    {
   14473 		ret = xmlStreamPop(patstream);
   14474 	    }
   14475 	    if (cur->next != NULL) {
   14476 		cur = cur->next;
   14477 		break;
   14478 	    }
   14479 	} while (cur != NULL);
   14480 
   14481     } while ((cur != NULL) && (depth >= 0));
   14482 
   14483 done:
   14484 
   14485 #if 0
   14486     printf("stream eval: checked %d nodes selected %d\n",
   14487            nb_nodes, retObj->nodesetval->nodeNr);
   14488 #endif
   14489 
   14490     if (patstream)
   14491 	xmlFreeStreamCtxt(patstream);
   14492     return(0);
   14493 
   14494 return_1:
   14495     if (patstream)
   14496 	xmlFreeStreamCtxt(patstream);
   14497     return(1);
   14498 }
   14499 #endif /* XPATH_STREAMING */
   14500 
   14501 /**
   14502  * xmlXPathRunEval:
   14503  * @ctxt:  the XPath parser context with the compiled expression
   14504  * @toBool:  evaluate to a boolean result
   14505  *
   14506  * Evaluate the Precompiled XPath expression in the given context.
   14507  */
   14508 static int
   14509 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
   14510 {
   14511     xmlXPathCompExprPtr comp;
   14512 
   14513     if ((ctxt == NULL) || (ctxt->comp == NULL))
   14514 	return(-1);
   14515 
   14516     if (ctxt->valueTab == NULL) {
   14517 	/* Allocate the value stack */
   14518 	ctxt->valueTab = (xmlXPathObjectPtr *)
   14519 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
   14520 	if (ctxt->valueTab == NULL) {
   14521 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
   14522 	    xmlFree(ctxt);
   14523 	}
   14524 	ctxt->valueNr = 0;
   14525 	ctxt->valueMax = 10;
   14526 	ctxt->value = NULL;
   14527         ctxt->valueFrame = 0;
   14528     }
   14529 #ifdef XPATH_STREAMING
   14530     if (ctxt->comp->stream) {
   14531 	int res;
   14532 
   14533 	if (toBool) {
   14534 	    /*
   14535 	    * Evaluation to boolean result.
   14536 	    */
   14537 	    res = xmlXPathRunStreamEval(ctxt->context,
   14538 		ctxt->comp->stream, NULL, 1);
   14539 	    if (res != -1)
   14540 		return(res);
   14541 	} else {
   14542 	    xmlXPathObjectPtr resObj = NULL;
   14543 
   14544 	    /*
   14545 	    * Evaluation to a sequence.
   14546 	    */
   14547 	    res = xmlXPathRunStreamEval(ctxt->context,
   14548 		ctxt->comp->stream, &resObj, 0);
   14549 
   14550 	    if ((res != -1) && (resObj != NULL)) {
   14551 		valuePush(ctxt, resObj);
   14552 		return(0);
   14553 	    }
   14554 	    if (resObj != NULL)
   14555 		xmlXPathReleaseObject(ctxt->context, resObj);
   14556 	}
   14557 	/*
   14558 	* QUESTION TODO: This falls back to normal XPath evaluation
   14559 	* if res == -1. Is this intended?
   14560 	*/
   14561     }
   14562 #endif
   14563     comp = ctxt->comp;
   14564     if (comp->last < 0) {
   14565 	xmlGenericError(xmlGenericErrorContext,
   14566 	    "xmlXPathRunEval: last is less than zero\n");
   14567 	return(-1);
   14568     }
   14569     if (toBool)
   14570 	return(xmlXPathCompOpEvalToBoolean(ctxt,
   14571 	    &comp->steps[comp->last], 0));
   14572     else
   14573 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
   14574 
   14575     return(0);
   14576 }
   14577 
   14578 /************************************************************************
   14579  *									*
   14580  *			Public interfaces				*
   14581  *									*
   14582  ************************************************************************/
   14583 
   14584 /**
   14585  * xmlXPathEvalPredicate:
   14586  * @ctxt:  the XPath context
   14587  * @res:  the Predicate Expression evaluation result
   14588  *
   14589  * Evaluate a predicate result for the current node.
   14590  * A PredicateExpr is evaluated by evaluating the Expr and converting
   14591  * the result to a boolean. If the result is a number, the result will
   14592  * be converted to true if the number is equal to the position of the
   14593  * context node in the context node list (as returned by the position
   14594  * function) and will be converted to false otherwise; if the result
   14595  * is not a number, then the result will be converted as if by a call
   14596  * to the boolean function.
   14597  *
   14598  * Returns 1 if predicate is true, 0 otherwise
   14599  */
   14600 int
   14601 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
   14602     if ((ctxt == NULL) || (res == NULL)) return(0);
   14603     switch (res->type) {
   14604         case XPATH_BOOLEAN:
   14605 	    return(res->boolval);
   14606         case XPATH_NUMBER:
   14607 	    return(res->floatval == ctxt->proximityPosition);
   14608         case XPATH_NODESET:
   14609         case XPATH_XSLT_TREE:
   14610 	    if (res->nodesetval == NULL)
   14611 		return(0);
   14612 	    return(res->nodesetval->nodeNr != 0);
   14613         case XPATH_STRING:
   14614 	    return((res->stringval != NULL) &&
   14615 	           (xmlStrlen(res->stringval) != 0));
   14616         default:
   14617 	    STRANGE
   14618     }
   14619     return(0);
   14620 }
   14621 
   14622 /**
   14623  * xmlXPathEvaluatePredicateResult:
   14624  * @ctxt:  the XPath Parser context
   14625  * @res:  the Predicate Expression evaluation result
   14626  *
   14627  * Evaluate a predicate result for the current node.
   14628  * A PredicateExpr is evaluated by evaluating the Expr and converting
   14629  * the result to a boolean. If the result is a number, the result will
   14630  * be converted to true if the number is equal to the position of the
   14631  * context node in the context node list (as returned by the position
   14632  * function) and will be converted to false otherwise; if the result
   14633  * is not a number, then the result will be converted as if by a call
   14634  * to the boolean function.
   14635  *
   14636  * Returns 1 if predicate is true, 0 otherwise
   14637  */
   14638 int
   14639 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
   14640                                 xmlXPathObjectPtr res) {
   14641     if ((ctxt == NULL) || (res == NULL)) return(0);
   14642     switch (res->type) {
   14643         case XPATH_BOOLEAN:
   14644 	    return(res->boolval);
   14645         case XPATH_NUMBER:
   14646 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
   14647 	    return((res->floatval == ctxt->context->proximityPosition) &&
   14648 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
   14649 #else
   14650 	    return(res->floatval == ctxt->context->proximityPosition);
   14651 #endif
   14652         case XPATH_NODESET:
   14653         case XPATH_XSLT_TREE:
   14654 	    if (res->nodesetval == NULL)
   14655 		return(0);
   14656 	    return(res->nodesetval->nodeNr != 0);
   14657         case XPATH_STRING:
   14658 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
   14659 #ifdef LIBXML_XPTR_ENABLED
   14660 	case XPATH_LOCATIONSET:{
   14661 	    xmlLocationSetPtr ptr = res->user;
   14662 	    if (ptr == NULL)
   14663 	        return(0);
   14664 	    return (ptr->locNr != 0);
   14665 	    }
   14666 #endif
   14667         default:
   14668 	    STRANGE
   14669     }
   14670     return(0);
   14671 }
   14672 
   14673 #ifdef XPATH_STREAMING
   14674 /**
   14675  * xmlXPathTryStreamCompile:
   14676  * @ctxt: an XPath context
   14677  * @str:  the XPath expression
   14678  *
   14679  * Try to compile the XPath expression as a streamable subset.
   14680  *
   14681  * Returns the compiled expression or NULL if failed to compile.
   14682  */
   14683 static xmlXPathCompExprPtr
   14684 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
   14685     /*
   14686      * Optimization: use streaming patterns when the XPath expression can
   14687      * be compiled to a stream lookup
   14688      */
   14689     xmlPatternPtr stream;
   14690     xmlXPathCompExprPtr comp;
   14691     xmlDictPtr dict = NULL;
   14692     const xmlChar **namespaces = NULL;
   14693     xmlNsPtr ns;
   14694     int i, j;
   14695 
   14696     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
   14697         (!xmlStrchr(str, '@'))) {
   14698 	const xmlChar *tmp;
   14699 
   14700 	/*
   14701 	 * We don't try to handle expressions using the verbose axis
   14702 	 * specifiers ("::"), just the simplied form at this point.
   14703 	 * Additionally, if there is no list of namespaces available and
   14704 	 *  there's a ":" in the expression, indicating a prefixed QName,
   14705 	 *  then we won't try to compile either. xmlPatterncompile() needs
   14706 	 *  to have a list of namespaces at compilation time in order to
   14707 	 *  compile prefixed name tests.
   14708 	 */
   14709 	tmp = xmlStrchr(str, ':');
   14710 	if ((tmp != NULL) &&
   14711 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
   14712 	    return(NULL);
   14713 
   14714 	if (ctxt != NULL) {
   14715 	    dict = ctxt->dict;
   14716 	    if (ctxt->nsNr > 0) {
   14717 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
   14718 		if (namespaces == NULL) {
   14719 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
   14720 		    return(NULL);
   14721 		}
   14722 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
   14723 		    ns = ctxt->namespaces[j];
   14724 		    namespaces[i++] = ns->href;
   14725 		    namespaces[i++] = ns->prefix;
   14726 		}
   14727 		namespaces[i++] = NULL;
   14728 		namespaces[i] = NULL;
   14729 	    }
   14730 	}
   14731 
   14732 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
   14733 			&namespaces[0]);
   14734 	if (namespaces != NULL) {
   14735 	    xmlFree((xmlChar **)namespaces);
   14736 	}
   14737 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
   14738 	    comp = xmlXPathNewCompExpr();
   14739 	    if (comp == NULL) {
   14740 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
   14741 		return(NULL);
   14742 	    }
   14743 	    comp->stream = stream;
   14744 	    comp->dict = dict;
   14745 	    if (comp->dict)
   14746 		xmlDictReference(comp->dict);
   14747 	    return(comp);
   14748 	}
   14749 	xmlFreePattern(stream);
   14750     }
   14751     return(NULL);
   14752 }
   14753 #endif /* XPATH_STREAMING */
   14754 
   14755 static void
   14756 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
   14757 {
   14758     /*
   14759     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
   14760     * internal representation.
   14761     */
   14762 
   14763     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
   14764         (op->ch1 != -1) &&
   14765         (op->ch2 == -1 /* no predicate */))
   14766     {
   14767         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
   14768 
   14769         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
   14770             ((xmlXPathAxisVal) prevop->value ==
   14771                 AXIS_DESCENDANT_OR_SELF) &&
   14772             (prevop->ch2 == -1) &&
   14773             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
   14774             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
   14775         {
   14776             /*
   14777             * This is a "descendant-or-self::node()" without predicates.
   14778             * Try to eliminate it.
   14779             */
   14780 
   14781             switch ((xmlXPathAxisVal) op->value) {
   14782                 case AXIS_CHILD:
   14783                 case AXIS_DESCENDANT:
   14784                     /*
   14785                     * Convert "descendant-or-self::node()/child::" or
   14786                     * "descendant-or-self::node()/descendant::" to
   14787                     * "descendant::"
   14788                     */
   14789                     op->ch1   = prevop->ch1;
   14790                     op->value = AXIS_DESCENDANT;
   14791                     break;
   14792                 case AXIS_SELF:
   14793                 case AXIS_DESCENDANT_OR_SELF:
   14794                     /*
   14795                     * Convert "descendant-or-self::node()/self::" or
   14796                     * "descendant-or-self::node()/descendant-or-self::" to
   14797                     * to "descendant-or-self::"
   14798                     */
   14799                     op->ch1   = prevop->ch1;
   14800                     op->value = AXIS_DESCENDANT_OR_SELF;
   14801                     break;
   14802                 default:
   14803                     break;
   14804             }
   14805 	}
   14806     }
   14807 
   14808     /* OP_VALUE has invalid ch1. */
   14809     if (op->op == XPATH_OP_VALUE)
   14810         return;
   14811 
   14812     /* Recurse */
   14813     if (op->ch1 != -1)
   14814         xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
   14815     if (op->ch2 != -1)
   14816 	xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
   14817 }
   14818 
   14819 /**
   14820  * xmlXPathCtxtCompile:
   14821  * @ctxt: an XPath context
   14822  * @str:  the XPath expression
   14823  *
   14824  * Compile an XPath expression
   14825  *
   14826  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
   14827  *         the caller has to free the object.
   14828  */
   14829 xmlXPathCompExprPtr
   14830 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
   14831     xmlXPathParserContextPtr pctxt;
   14832     xmlXPathCompExprPtr comp;
   14833 
   14834 #ifdef XPATH_STREAMING
   14835     comp = xmlXPathTryStreamCompile(ctxt, str);
   14836     if (comp != NULL)
   14837         return(comp);
   14838 #endif
   14839 
   14840     xmlXPathInit();
   14841 
   14842     pctxt = xmlXPathNewParserContext(str, ctxt);
   14843     if (pctxt == NULL)
   14844         return NULL;
   14845     xmlXPathCompileExpr(pctxt, 1);
   14846 
   14847     if( pctxt->error != XPATH_EXPRESSION_OK )
   14848     {
   14849         xmlXPathFreeParserContext(pctxt);
   14850         return(NULL);
   14851     }
   14852 
   14853     if (*pctxt->cur != 0) {
   14854 	/*
   14855 	 * aleksey: in some cases this line prints *second* error message
   14856 	 * (see bug #78858) and probably this should be fixed.
   14857 	 * However, we are not sure that all error messages are printed
   14858 	 * out in other places. It's not critical so we leave it as-is for now
   14859 	 */
   14860 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   14861 	comp = NULL;
   14862     } else {
   14863 	comp = pctxt->comp;
   14864 	pctxt->comp = NULL;
   14865     }
   14866     xmlXPathFreeParserContext(pctxt);
   14867 
   14868     if (comp != NULL) {
   14869 	comp->expr = xmlStrdup(str);
   14870 #ifdef DEBUG_EVAL_COUNTS
   14871 	comp->string = xmlStrdup(str);
   14872 	comp->nb = 0;
   14873 #endif
   14874 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
   14875 	    xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
   14876 	}
   14877     }
   14878     return(comp);
   14879 }
   14880 
   14881 /**
   14882  * xmlXPathCompile:
   14883  * @str:  the XPath expression
   14884  *
   14885  * Compile an XPath expression
   14886  *
   14887  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
   14888  *         the caller has to free the object.
   14889  */
   14890 xmlXPathCompExprPtr
   14891 xmlXPathCompile(const xmlChar *str) {
   14892     return(xmlXPathCtxtCompile(NULL, str));
   14893 }
   14894 
   14895 /**
   14896  * xmlXPathCompiledEvalInternal:
   14897  * @comp:  the compiled XPath expression
   14898  * @ctxt:  the XPath context
   14899  * @resObj: the resulting XPath object or NULL
   14900  * @toBool: 1 if only a boolean result is requested
   14901  *
   14902  * Evaluate the Precompiled XPath expression in the given context.
   14903  * The caller has to free @resObj.
   14904  *
   14905  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14906  *         the caller has to free the object.
   14907  */
   14908 static int
   14909 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
   14910 			     xmlXPathContextPtr ctxt,
   14911 			     xmlXPathObjectPtr *resObj,
   14912 			     int toBool)
   14913 {
   14914     xmlXPathParserContextPtr pctxt;
   14915 #ifndef LIBXML_THREAD_ENABLED
   14916     static int reentance = 0;
   14917 #endif
   14918     int res;
   14919 
   14920     CHECK_CTXT_NEG(ctxt)
   14921 
   14922     if (comp == NULL)
   14923 	return(-1);
   14924     xmlXPathInit();
   14925 
   14926 #ifndef LIBXML_THREAD_ENABLED
   14927     reentance++;
   14928     if (reentance > 1)
   14929 	xmlXPathDisableOptimizer = 1;
   14930 #endif
   14931 
   14932 #ifdef DEBUG_EVAL_COUNTS
   14933     comp->nb++;
   14934     if ((comp->string != NULL) && (comp->nb > 100)) {
   14935 	fprintf(stderr, "100 x %s\n", comp->string);
   14936 	comp->nb = 0;
   14937     }
   14938 #endif
   14939     pctxt = xmlXPathCompParserContext(comp, ctxt);
   14940     res = xmlXPathRunEval(pctxt, toBool);
   14941 
   14942     if (resObj) {
   14943 	if (pctxt->value == NULL) {
   14944 	    xmlGenericError(xmlGenericErrorContext,
   14945 		"xmlXPathCompiledEval: evaluation failed\n");
   14946 	    *resObj = NULL;
   14947 	} else {
   14948 	    *resObj = valuePop(pctxt);
   14949 	}
   14950     }
   14951 
   14952     /*
   14953     * Pop all remaining objects from the stack.
   14954     */
   14955     if (pctxt->valueNr > 0) {
   14956 	xmlXPathObjectPtr tmp;
   14957 	int stack = 0;
   14958 
   14959 	do {
   14960 	    tmp = valuePop(pctxt);
   14961 	    if (tmp != NULL) {
   14962 		stack++;
   14963 		xmlXPathReleaseObject(ctxt, tmp);
   14964 	    }
   14965 	} while (tmp != NULL);
   14966 	if ((stack != 0) &&
   14967 	    ((toBool) || ((resObj) && (*resObj))))
   14968 	{
   14969 	    xmlGenericError(xmlGenericErrorContext,
   14970 		"xmlXPathCompiledEval: %d objects left on the stack.\n",
   14971 		stack);
   14972 	}
   14973     }
   14974 
   14975     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
   14976 	xmlXPathFreeObject(*resObj);
   14977 	*resObj = NULL;
   14978     }
   14979     pctxt->comp = NULL;
   14980     xmlXPathFreeParserContext(pctxt);
   14981 #ifndef LIBXML_THREAD_ENABLED
   14982     reentance--;
   14983 #endif
   14984 
   14985     return(res);
   14986 }
   14987 
   14988 /**
   14989  * xmlXPathCompiledEval:
   14990  * @comp:  the compiled XPath expression
   14991  * @ctx:  the XPath context
   14992  *
   14993  * Evaluate the Precompiled XPath expression in the given context.
   14994  *
   14995  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14996  *         the caller has to free the object.
   14997  */
   14998 xmlXPathObjectPtr
   14999 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
   15000 {
   15001     xmlXPathObjectPtr res = NULL;
   15002 
   15003     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
   15004     return(res);
   15005 }
   15006 
   15007 /**
   15008  * xmlXPathCompiledEvalToBoolean:
   15009  * @comp:  the compiled XPath expression
   15010  * @ctxt:  the XPath context
   15011  *
   15012  * Applies the XPath boolean() function on the result of the given
   15013  * compiled expression.
   15014  *
   15015  * Returns 1 if the expression evaluated to true, 0 if to false and
   15016  *         -1 in API and internal errors.
   15017  */
   15018 int
   15019 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
   15020 			      xmlXPathContextPtr ctxt)
   15021 {
   15022     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
   15023 }
   15024 
   15025 /**
   15026  * xmlXPathEvalExpr:
   15027  * @ctxt:  the XPath Parser context
   15028  *
   15029  * Parse and evaluate an XPath expression in the given context,
   15030  * then push the result on the context stack
   15031  */
   15032 void
   15033 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
   15034 #ifdef XPATH_STREAMING
   15035     xmlXPathCompExprPtr comp;
   15036 #endif
   15037 
   15038     if (ctxt == NULL) return;
   15039 
   15040 #ifdef XPATH_STREAMING
   15041     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
   15042     if (comp != NULL) {
   15043         if (ctxt->comp != NULL)
   15044 	    xmlXPathFreeCompExpr(ctxt->comp);
   15045         ctxt->comp = comp;
   15046 	if (ctxt->cur != NULL)
   15047 	    while (*ctxt->cur != 0) ctxt->cur++;
   15048     } else
   15049 #endif
   15050     {
   15051 	xmlXPathCompileExpr(ctxt, 1);
   15052 	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
   15053 	    (ctxt->comp != NULL) &&
   15054 	    (ctxt->comp->nbStep > 1) &&
   15055 	    (ctxt->comp->last >= 0))
   15056 	{
   15057 	    xmlXPathOptimizeExpression(ctxt->comp,
   15058 		&ctxt->comp->steps[ctxt->comp->last]);
   15059 	}
   15060     }
   15061     CHECK_ERROR;
   15062     xmlXPathRunEval(ctxt, 0);
   15063 }
   15064 
   15065 /**
   15066  * xmlXPathEval:
   15067  * @str:  the XPath expression
   15068  * @ctx:  the XPath context
   15069  *
   15070  * Evaluate the XPath Location Path in the given context.
   15071  *
   15072  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   15073  *         the caller has to free the object.
   15074  */
   15075 xmlXPathObjectPtr
   15076 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
   15077     xmlXPathParserContextPtr ctxt;
   15078     xmlXPathObjectPtr res, tmp, init = NULL;
   15079     int stack = 0;
   15080 
   15081     CHECK_CTXT(ctx)
   15082 
   15083     xmlXPathInit();
   15084 
   15085     ctxt = xmlXPathNewParserContext(str, ctx);
   15086     if (ctxt == NULL)
   15087         return NULL;
   15088     xmlXPathEvalExpr(ctxt);
   15089 
   15090     if (ctxt->value == NULL) {
   15091 	xmlGenericError(xmlGenericErrorContext,
   15092 		"xmlXPathEval: evaluation failed\n");
   15093 	res = NULL;
   15094     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
   15095 #ifdef XPATH_STREAMING
   15096             && (ctxt->comp->stream == NULL)
   15097 #endif
   15098 	      ) {
   15099 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   15100 	res = NULL;
   15101     } else {
   15102 	res = valuePop(ctxt);
   15103     }
   15104 
   15105     do {
   15106         tmp = valuePop(ctxt);
   15107 	if (tmp != NULL) {
   15108 	    if (tmp != init)
   15109 		stack++;
   15110 	    xmlXPathReleaseObject(ctx, tmp);
   15111         }
   15112     } while (tmp != NULL);
   15113     if ((stack != 0) && (res != NULL)) {
   15114 	xmlGenericError(xmlGenericErrorContext,
   15115 		"xmlXPathEval: %d object left on the stack\n",
   15116 	        stack);
   15117     }
   15118     if (ctxt->error != XPATH_EXPRESSION_OK) {
   15119 	xmlXPathFreeObject(res);
   15120 	res = NULL;
   15121     }
   15122 
   15123     xmlXPathFreeParserContext(ctxt);
   15124     return(res);
   15125 }
   15126 
   15127 /**
   15128  * xmlXPathSetContextNode:
   15129  * @node: the node to to use as the context node
   15130  * @ctx:  the XPath context
   15131  *
   15132  * Sets 'node' as the context node. The node must be in the same
   15133  * document as that associated with the context.
   15134  *
   15135  * Returns -1 in case of error or 0 if successful
   15136  */
   15137 int
   15138 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
   15139     if ((node == NULL) || (ctx == NULL))
   15140         return(-1);
   15141 
   15142     if (node->doc == ctx->doc) {
   15143         ctx->node = node;
   15144 	return(0);
   15145     }
   15146     return(-1);
   15147 }
   15148 
   15149 /**
   15150  * xmlXPathNodeEval:
   15151  * @node: the node to to use as the context node
   15152  * @str:  the XPath expression
   15153  * @ctx:  the XPath context
   15154  *
   15155  * Evaluate the XPath Location Path in the given context. The node 'node'
   15156  * is set as the context node. The context node is not restored.
   15157  *
   15158  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   15159  *         the caller has to free the object.
   15160  */
   15161 xmlXPathObjectPtr
   15162 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
   15163     if (str == NULL)
   15164         return(NULL);
   15165     if (xmlXPathSetContextNode(node, ctx) < 0)
   15166         return(NULL);
   15167     return(xmlXPathEval(str, ctx));
   15168 }
   15169 
   15170 /**
   15171  * xmlXPathEvalExpression:
   15172  * @str:  the XPath expression
   15173  * @ctxt:  the XPath context
   15174  *
   15175  * Evaluate the XPath expression in the given context.
   15176  *
   15177  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   15178  *         the caller has to free the object.
   15179  */
   15180 xmlXPathObjectPtr
   15181 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
   15182     xmlXPathParserContextPtr pctxt;
   15183     xmlXPathObjectPtr res, tmp;
   15184     int stack = 0;
   15185 
   15186     CHECK_CTXT(ctxt)
   15187 
   15188     xmlXPathInit();
   15189 
   15190     pctxt = xmlXPathNewParserContext(str, ctxt);
   15191     if (pctxt == NULL)
   15192         return NULL;
   15193     xmlXPathEvalExpr(pctxt);
   15194 
   15195     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
   15196 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   15197 	res = NULL;
   15198     } else {
   15199 	res = valuePop(pctxt);
   15200     }
   15201     do {
   15202         tmp = valuePop(pctxt);
   15203 	if (tmp != NULL) {
   15204 	    xmlXPathReleaseObject(ctxt, tmp);
   15205 	    stack++;
   15206 	}
   15207     } while (tmp != NULL);
   15208     if ((stack != 0) && (res != NULL)) {
   15209 	xmlGenericError(xmlGenericErrorContext,
   15210 		"xmlXPathEvalExpression: %d object left on the stack\n",
   15211 	        stack);
   15212     }
   15213     xmlXPathFreeParserContext(pctxt);
   15214     return(res);
   15215 }
   15216 
   15217 /************************************************************************
   15218  *									*
   15219  *	Extra functions not pertaining to the XPath spec		*
   15220  *									*
   15221  ************************************************************************/
   15222 /**
   15223  * xmlXPathEscapeUriFunction:
   15224  * @ctxt:  the XPath Parser context
   15225  * @nargs:  the number of arguments
   15226  *
   15227  * Implement the escape-uri() XPath function
   15228  *    string escape-uri(string $str, bool $escape-reserved)
   15229  *
   15230  * This function applies the URI escaping rules defined in section 2 of [RFC
   15231  * 2396] to the string supplied as $uri-part, which typically represents all
   15232  * or part of a URI. The effect of the function is to replace any special
   15233  * character in the string by an escape sequence of the form %xx%yy...,
   15234  * where xxyy... is the hexadecimal representation of the octets used to
   15235  * represent the character in UTF-8.
   15236  *
   15237  * The set of characters that are escaped depends on the setting of the
   15238  * boolean argument $escape-reserved.
   15239  *
   15240  * If $escape-reserved is true, all characters are escaped other than lower
   15241  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
   15242  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
   15243  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
   15244  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
   15245  * A-F).
   15246  *
   15247  * If $escape-reserved is false, the behavior differs in that characters
   15248  * referred to in [RFC 2396] as reserved characters are not escaped. These
   15249  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
   15250  *
   15251  * [RFC 2396] does not define whether escaped URIs should use lower case or
   15252  * upper case for hexadecimal digits. To ensure that escaped URIs can be
   15253  * compared using string comparison functions, this function must always use
   15254  * the upper-case letters A-F.
   15255  *
   15256  * Generally, $escape-reserved should be set to true when escaping a string
   15257  * that is to form a single part of a URI, and to false when escaping an
   15258  * entire URI or URI reference.
   15259  *
   15260  * In the case of non-ascii characters, the string is encoded according to
   15261  * utf-8 and then converted according to RFC 2396.
   15262  *
   15263  * Examples
   15264  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
   15265  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
   15266  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
   15267  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
   15268  *
   15269  */
   15270 static void
   15271 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   15272     xmlXPathObjectPtr str;
   15273     int escape_reserved;
   15274     xmlBufPtr target;
   15275     xmlChar *cptr;
   15276     xmlChar escape[4];
   15277 
   15278     CHECK_ARITY(2);
   15279 
   15280     escape_reserved = xmlXPathPopBoolean(ctxt);
   15281 
   15282     CAST_TO_STRING;
   15283     str = valuePop(ctxt);
   15284 
   15285     target = xmlBufCreate();
   15286 
   15287     escape[0] = '%';
   15288     escape[3] = 0;
   15289 
   15290     if (target) {
   15291 	for (cptr = str->stringval; *cptr; cptr++) {
   15292 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
   15293 		(*cptr >= 'a' && *cptr <= 'z') ||
   15294 		(*cptr >= '0' && *cptr <= '9') ||
   15295 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
   15296 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
   15297 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
   15298 		(*cptr == '%' &&
   15299 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
   15300 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
   15301 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
   15302 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
   15303 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
   15304 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
   15305 		(!escape_reserved &&
   15306 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
   15307 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
   15308 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
   15309 		  *cptr == ','))) {
   15310 		xmlBufAdd(target, cptr, 1);
   15311 	    } else {
   15312 		if ((*cptr >> 4) < 10)
   15313 		    escape[1] = '0' + (*cptr >> 4);
   15314 		else
   15315 		    escape[1] = 'A' - 10 + (*cptr >> 4);
   15316 		if ((*cptr & 0xF) < 10)
   15317 		    escape[2] = '0' + (*cptr & 0xF);
   15318 		else
   15319 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
   15320 
   15321 		xmlBufAdd(target, &escape[0], 3);
   15322 	    }
   15323 	}
   15324     }
   15325     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   15326 	xmlBufContent(target)));
   15327     xmlBufFree(target);
   15328     xmlXPathReleaseObject(ctxt->context, str);
   15329 }
   15330 
   15331 /**
   15332  * xmlXPathRegisterAllFunctions:
   15333  * @ctxt:  the XPath context
   15334  *
   15335  * Registers all default XPath functions in this context
   15336  */
   15337 void
   15338 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
   15339 {
   15340     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
   15341                          xmlXPathBooleanFunction);
   15342     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
   15343                          xmlXPathCeilingFunction);
   15344     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
   15345                          xmlXPathCountFunction);
   15346     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
   15347                          xmlXPathConcatFunction);
   15348     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
   15349                          xmlXPathContainsFunction);
   15350     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
   15351                          xmlXPathIdFunction);
   15352     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
   15353                          xmlXPathFalseFunction);
   15354     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
   15355                          xmlXPathFloorFunction);
   15356     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
   15357                          xmlXPathLastFunction);
   15358     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
   15359                          xmlXPathLangFunction);
   15360     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
   15361                          xmlXPathLocalNameFunction);
   15362     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
   15363                          xmlXPathNotFunction);
   15364     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
   15365                          xmlXPathNameFunction);
   15366     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
   15367                          xmlXPathNamespaceURIFunction);
   15368     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
   15369                          xmlXPathNormalizeFunction);
   15370     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
   15371                          xmlXPathNumberFunction);
   15372     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
   15373                          xmlXPathPositionFunction);
   15374     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
   15375                          xmlXPathRoundFunction);
   15376     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
   15377                          xmlXPathStringFunction);
   15378     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
   15379                          xmlXPathStringLengthFunction);
   15380     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
   15381                          xmlXPathStartsWithFunction);
   15382     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
   15383                          xmlXPathSubstringFunction);
   15384     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
   15385                          xmlXPathSubstringBeforeFunction);
   15386     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
   15387                          xmlXPathSubstringAfterFunction);
   15388     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
   15389                          xmlXPathSumFunction);
   15390     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
   15391                          xmlXPathTrueFunction);
   15392     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
   15393                          xmlXPathTranslateFunction);
   15394 
   15395     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
   15396 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
   15397                          xmlXPathEscapeUriFunction);
   15398 }
   15399 
   15400 #endif /* LIBXML_XPATH_ENABLED */
   15401 #define bottom_xpath
   15402 #include "elfgcchack.h"
   15403