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                          BAD_CAST "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 dictionnary 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 duplcates
   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 = 1;
   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 (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
   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 		    /* Note 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 		    } else {
   10702 #ifdef DEBUG_STEP
   10703 		        xmlGenericError(xmlGenericErrorContext,
   10704 				"PathExpr: function call\n");
   10705 #endif
   10706 			lc = 0;
   10707 		    }
   10708                     break;
   10709 		} else if ((NXT(len) == '[')) {
   10710 		    /* element name */
   10711 #ifdef DEBUG_STEP
   10712 		    xmlGenericError(xmlGenericErrorContext,
   10713 			    "PathExpr: AbbrRelLocation\n");
   10714 #endif
   10715 		    lc = 1;
   10716 		    break;
   10717 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
   10718 			   (NXT(len) == '=')) {
   10719 		    lc = 1;
   10720 		    break;
   10721 		} else {
   10722 		    lc = 1;
   10723 		    break;
   10724 		}
   10725 		len++;
   10726 	    }
   10727 	    if (NXT(len) == 0) {
   10728 #ifdef DEBUG_STEP
   10729 		xmlGenericError(xmlGenericErrorContext,
   10730 			"PathExpr: AbbrRelLocation\n");
   10731 #endif
   10732 		/* element name */
   10733 		lc = 1;
   10734 	    }
   10735 	    xmlFree(name);
   10736 	} else {
   10737 	    /* make sure all cases are covered explicitly */
   10738 	    XP_ERROR(XPATH_EXPR_ERROR);
   10739 	}
   10740     }
   10741 
   10742     if (lc) {
   10743 	if (CUR == '/') {
   10744 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
   10745 	} else {
   10746 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
   10747 	}
   10748 	xmlXPathCompLocationPath(ctxt);
   10749     } else {
   10750 	xmlXPathCompFilterExpr(ctxt);
   10751 	CHECK_ERROR;
   10752 	if ((CUR == '/') && (NXT(1) == '/')) {
   10753 	    SKIP(2);
   10754 	    SKIP_BLANKS;
   10755 
   10756 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   10757 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   10758 	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
   10759 
   10760 	    xmlXPathCompRelativeLocationPath(ctxt);
   10761 	} else if (CUR == '/') {
   10762 	    xmlXPathCompRelativeLocationPath(ctxt);
   10763 	}
   10764     }
   10765     SKIP_BLANKS;
   10766 }
   10767 
   10768 /**
   10769  * xmlXPathCompUnionExpr:
   10770  * @ctxt:  the XPath Parser context
   10771  *
   10772  *  [18]   UnionExpr ::=   PathExpr
   10773  *               | UnionExpr '|' PathExpr
   10774  *
   10775  * Compile an union expression.
   10776  */
   10777 
   10778 static void
   10779 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
   10780     xmlXPathCompPathExpr(ctxt);
   10781     CHECK_ERROR;
   10782     SKIP_BLANKS;
   10783     while (CUR == '|') {
   10784 	int op1 = ctxt->comp->last;
   10785 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
   10786 
   10787 	NEXT;
   10788 	SKIP_BLANKS;
   10789 	xmlXPathCompPathExpr(ctxt);
   10790 
   10791 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
   10792 
   10793 	SKIP_BLANKS;
   10794     }
   10795 }
   10796 
   10797 /**
   10798  * xmlXPathCompUnaryExpr:
   10799  * @ctxt:  the XPath Parser context
   10800  *
   10801  *  [27]   UnaryExpr ::=   UnionExpr
   10802  *                   | '-' UnaryExpr
   10803  *
   10804  * Compile an unary expression.
   10805  */
   10806 
   10807 static void
   10808 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
   10809     int minus = 0;
   10810     int found = 0;
   10811 
   10812     SKIP_BLANKS;
   10813     while (CUR == '-') {
   10814         minus = 1 - minus;
   10815 	found = 1;
   10816 	NEXT;
   10817 	SKIP_BLANKS;
   10818     }
   10819 
   10820     xmlXPathCompUnionExpr(ctxt);
   10821     CHECK_ERROR;
   10822     if (found) {
   10823 	if (minus)
   10824 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
   10825 	else
   10826 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
   10827     }
   10828 }
   10829 
   10830 /**
   10831  * xmlXPathCompMultiplicativeExpr:
   10832  * @ctxt:  the XPath Parser context
   10833  *
   10834  *  [26]   MultiplicativeExpr ::=   UnaryExpr
   10835  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
   10836  *                   | MultiplicativeExpr 'div' UnaryExpr
   10837  *                   | MultiplicativeExpr 'mod' UnaryExpr
   10838  *  [34]   MultiplyOperator ::=   '*'
   10839  *
   10840  * Compile an Additive expression.
   10841  */
   10842 
   10843 static void
   10844 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
   10845     xmlXPathCompUnaryExpr(ctxt);
   10846     CHECK_ERROR;
   10847     SKIP_BLANKS;
   10848     while ((CUR == '*') ||
   10849            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
   10850            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
   10851 	int op = -1;
   10852 	int op1 = ctxt->comp->last;
   10853 
   10854         if (CUR == '*') {
   10855 	    op = 0;
   10856 	    NEXT;
   10857 	} else if (CUR == 'd') {
   10858 	    op = 1;
   10859 	    SKIP(3);
   10860 	} else if (CUR == 'm') {
   10861 	    op = 2;
   10862 	    SKIP(3);
   10863 	}
   10864 	SKIP_BLANKS;
   10865         xmlXPathCompUnaryExpr(ctxt);
   10866 	CHECK_ERROR;
   10867 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
   10868 	SKIP_BLANKS;
   10869     }
   10870 }
   10871 
   10872 /**
   10873  * xmlXPathCompAdditiveExpr:
   10874  * @ctxt:  the XPath Parser context
   10875  *
   10876  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
   10877  *                   | AdditiveExpr '+' MultiplicativeExpr
   10878  *                   | AdditiveExpr '-' MultiplicativeExpr
   10879  *
   10880  * Compile an Additive expression.
   10881  */
   10882 
   10883 static void
   10884 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
   10885 
   10886     xmlXPathCompMultiplicativeExpr(ctxt);
   10887     CHECK_ERROR;
   10888     SKIP_BLANKS;
   10889     while ((CUR == '+') || (CUR == '-')) {
   10890 	int plus;
   10891 	int op1 = ctxt->comp->last;
   10892 
   10893         if (CUR == '+') plus = 1;
   10894 	else plus = 0;
   10895 	NEXT;
   10896 	SKIP_BLANKS;
   10897         xmlXPathCompMultiplicativeExpr(ctxt);
   10898 	CHECK_ERROR;
   10899 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
   10900 	SKIP_BLANKS;
   10901     }
   10902 }
   10903 
   10904 /**
   10905  * xmlXPathCompRelationalExpr:
   10906  * @ctxt:  the XPath Parser context
   10907  *
   10908  *  [24]   RelationalExpr ::=   AdditiveExpr
   10909  *                 | RelationalExpr '<' AdditiveExpr
   10910  *                 | RelationalExpr '>' AdditiveExpr
   10911  *                 | RelationalExpr '<=' AdditiveExpr
   10912  *                 | RelationalExpr '>=' AdditiveExpr
   10913  *
   10914  *  A <= B > C is allowed ? Answer from James, yes with
   10915  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
   10916  *  which is basically what got implemented.
   10917  *
   10918  * Compile a Relational expression, then push the result
   10919  * on the stack
   10920  */
   10921 
   10922 static void
   10923 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
   10924     xmlXPathCompAdditiveExpr(ctxt);
   10925     CHECK_ERROR;
   10926     SKIP_BLANKS;
   10927     while ((CUR == '<') ||
   10928            (CUR == '>') ||
   10929            ((CUR == '<') && (NXT(1) == '=')) ||
   10930            ((CUR == '>') && (NXT(1) == '='))) {
   10931 	int inf, strict;
   10932 	int op1 = ctxt->comp->last;
   10933 
   10934         if (CUR == '<') inf = 1;
   10935 	else inf = 0;
   10936 	if (NXT(1) == '=') strict = 0;
   10937 	else strict = 1;
   10938 	NEXT;
   10939 	if (!strict) NEXT;
   10940 	SKIP_BLANKS;
   10941         xmlXPathCompAdditiveExpr(ctxt);
   10942 	CHECK_ERROR;
   10943 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
   10944 	SKIP_BLANKS;
   10945     }
   10946 }
   10947 
   10948 /**
   10949  * xmlXPathCompEqualityExpr:
   10950  * @ctxt:  the XPath Parser context
   10951  *
   10952  *  [23]   EqualityExpr ::=   RelationalExpr
   10953  *                 | EqualityExpr '=' RelationalExpr
   10954  *                 | EqualityExpr '!=' RelationalExpr
   10955  *
   10956  *  A != B != C is allowed ? Answer from James, yes with
   10957  *  (RelationalExpr = RelationalExpr) = RelationalExpr
   10958  *  (RelationalExpr != RelationalExpr) != RelationalExpr
   10959  *  which is basically what got implemented.
   10960  *
   10961  * Compile an Equality expression.
   10962  *
   10963  */
   10964 static void
   10965 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
   10966     xmlXPathCompRelationalExpr(ctxt);
   10967     CHECK_ERROR;
   10968     SKIP_BLANKS;
   10969     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
   10970 	int eq;
   10971 	int op1 = ctxt->comp->last;
   10972 
   10973         if (CUR == '=') eq = 1;
   10974 	else eq = 0;
   10975 	NEXT;
   10976 	if (!eq) NEXT;
   10977 	SKIP_BLANKS;
   10978         xmlXPathCompRelationalExpr(ctxt);
   10979 	CHECK_ERROR;
   10980 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
   10981 	SKIP_BLANKS;
   10982     }
   10983 }
   10984 
   10985 /**
   10986  * xmlXPathCompAndExpr:
   10987  * @ctxt:  the XPath Parser context
   10988  *
   10989  *  [22]   AndExpr ::=   EqualityExpr
   10990  *                 | AndExpr 'and' EqualityExpr
   10991  *
   10992  * Compile an AND expression.
   10993  *
   10994  */
   10995 static void
   10996 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
   10997     xmlXPathCompEqualityExpr(ctxt);
   10998     CHECK_ERROR;
   10999     SKIP_BLANKS;
   11000     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
   11001 	int op1 = ctxt->comp->last;
   11002         SKIP(3);
   11003 	SKIP_BLANKS;
   11004         xmlXPathCompEqualityExpr(ctxt);
   11005 	CHECK_ERROR;
   11006 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
   11007 	SKIP_BLANKS;
   11008     }
   11009 }
   11010 
   11011 /**
   11012  * xmlXPathCompileExpr:
   11013  * @ctxt:  the XPath Parser context
   11014  *
   11015  *  [14]   Expr ::=   OrExpr
   11016  *  [21]   OrExpr ::=   AndExpr
   11017  *                 | OrExpr 'or' AndExpr
   11018  *
   11019  * Parse and compile an expression
   11020  */
   11021 static void
   11022 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
   11023     xmlXPathCompAndExpr(ctxt);
   11024     CHECK_ERROR;
   11025     SKIP_BLANKS;
   11026     while ((CUR == 'o') && (NXT(1) == 'r')) {
   11027 	int op1 = ctxt->comp->last;
   11028         SKIP(2);
   11029 	SKIP_BLANKS;
   11030         xmlXPathCompAndExpr(ctxt);
   11031 	CHECK_ERROR;
   11032 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
   11033 	SKIP_BLANKS;
   11034     }
   11035     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
   11036 	/* more ops could be optimized too */
   11037 	/*
   11038 	* This is the main place to eliminate sorting for
   11039 	* operations which don't require a sorted node-set.
   11040 	* E.g. count().
   11041 	*/
   11042 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
   11043     }
   11044 }
   11045 
   11046 /**
   11047  * xmlXPathCompPredicate:
   11048  * @ctxt:  the XPath Parser context
   11049  * @filter:  act as a filter
   11050  *
   11051  *  [8]   Predicate ::=   '[' PredicateExpr ']'
   11052  *  [9]   PredicateExpr ::=   Expr
   11053  *
   11054  * Compile a predicate expression
   11055  */
   11056 static void
   11057 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
   11058     int op1 = ctxt->comp->last;
   11059 
   11060     SKIP_BLANKS;
   11061     if (CUR != '[') {
   11062 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
   11063     }
   11064     NEXT;
   11065     SKIP_BLANKS;
   11066 
   11067     ctxt->comp->last = -1;
   11068     /*
   11069     * This call to xmlXPathCompileExpr() will deactivate sorting
   11070     * of the predicate result.
   11071     * TODO: Sorting is still activated for filters, since I'm not
   11072     *  sure if needed. Normally sorting should not be needed, since
   11073     *  a filter can only diminish the number of items in a sequence,
   11074     *  but won't change its order; so if the initial sequence is sorted,
   11075     *  subsequent sorting is not needed.
   11076     */
   11077     if (! filter)
   11078 	xmlXPathCompileExpr(ctxt, 0);
   11079     else
   11080 	xmlXPathCompileExpr(ctxt, 1);
   11081     CHECK_ERROR;
   11082 
   11083     if (CUR != ']') {
   11084 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
   11085     }
   11086 
   11087     if (filter)
   11088 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
   11089     else
   11090 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
   11091 
   11092     NEXT;
   11093     SKIP_BLANKS;
   11094 }
   11095 
   11096 /**
   11097  * xmlXPathCompNodeTest:
   11098  * @ctxt:  the XPath Parser context
   11099  * @test:  pointer to a xmlXPathTestVal
   11100  * @type:  pointer to a xmlXPathTypeVal
   11101  * @prefix:  placeholder for a possible name prefix
   11102  *
   11103  * [7] NodeTest ::=   NameTest
   11104  *		    | NodeType '(' ')'
   11105  *		    | 'processing-instruction' '(' Literal ')'
   11106  *
   11107  * [37] NameTest ::=  '*'
   11108  *		    | NCName ':' '*'
   11109  *		    | QName
   11110  * [38] NodeType ::= 'comment'
   11111  *		   | 'text'
   11112  *		   | 'processing-instruction'
   11113  *		   | 'node'
   11114  *
   11115  * Returns the name found and updates @test, @type and @prefix appropriately
   11116  */
   11117 static xmlChar *
   11118 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
   11119 	             xmlXPathTypeVal *type, const xmlChar **prefix,
   11120 		     xmlChar *name) {
   11121     int blanks;
   11122 
   11123     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
   11124 	STRANGE;
   11125 	return(NULL);
   11126     }
   11127     *type = (xmlXPathTypeVal) 0;
   11128     *test = (xmlXPathTestVal) 0;
   11129     *prefix = NULL;
   11130     SKIP_BLANKS;
   11131 
   11132     if ((name == NULL) && (CUR == '*')) {
   11133 	/*
   11134 	 * All elements
   11135 	 */
   11136 	NEXT;
   11137 	*test = NODE_TEST_ALL;
   11138 	return(NULL);
   11139     }
   11140 
   11141     if (name == NULL)
   11142 	name = xmlXPathParseNCName(ctxt);
   11143     if (name == NULL) {
   11144 	XP_ERRORNULL(XPATH_EXPR_ERROR);
   11145     }
   11146 
   11147     blanks = IS_BLANK_CH(CUR);
   11148     SKIP_BLANKS;
   11149     if (CUR == '(') {
   11150 	NEXT;
   11151 	/*
   11152 	 * NodeType or PI search
   11153 	 */
   11154 	if (xmlStrEqual(name, BAD_CAST "comment"))
   11155 	    *type = NODE_TYPE_COMMENT;
   11156 	else if (xmlStrEqual(name, BAD_CAST "node"))
   11157 	    *type = NODE_TYPE_NODE;
   11158 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
   11159 	    *type = NODE_TYPE_PI;
   11160 	else if (xmlStrEqual(name, BAD_CAST "text"))
   11161 	    *type = NODE_TYPE_TEXT;
   11162 	else {
   11163 	    if (name != NULL)
   11164 		xmlFree(name);
   11165 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
   11166 	}
   11167 
   11168 	*test = NODE_TEST_TYPE;
   11169 
   11170 	SKIP_BLANKS;
   11171 	if (*type == NODE_TYPE_PI) {
   11172 	    /*
   11173 	     * Specific case: search a PI by name.
   11174 	     */
   11175 	    if (name != NULL)
   11176 		xmlFree(name);
   11177 	    name = NULL;
   11178 	    if (CUR != ')') {
   11179 		name = xmlXPathParseLiteral(ctxt);
   11180 		CHECK_ERROR NULL;
   11181 		*test = NODE_TEST_PI;
   11182 		SKIP_BLANKS;
   11183 	    }
   11184 	}
   11185 	if (CUR != ')') {
   11186 	    if (name != NULL)
   11187 		xmlFree(name);
   11188 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
   11189 	}
   11190 	NEXT;
   11191 	return(name);
   11192     }
   11193     *test = NODE_TEST_NAME;
   11194     if ((!blanks) && (CUR == ':')) {
   11195 	NEXT;
   11196 
   11197 	/*
   11198 	 * Since currently the parser context don't have a
   11199 	 * namespace list associated:
   11200 	 * The namespace name for this prefix can be computed
   11201 	 * only at evaluation time. The compilation is done
   11202 	 * outside of any context.
   11203 	 */
   11204 #if 0
   11205 	*prefix = xmlXPathNsLookup(ctxt->context, name);
   11206 	if (name != NULL)
   11207 	    xmlFree(name);
   11208 	if (*prefix == NULL) {
   11209 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
   11210 	}
   11211 #else
   11212 	*prefix = name;
   11213 #endif
   11214 
   11215 	if (CUR == '*') {
   11216 	    /*
   11217 	     * All elements
   11218 	     */
   11219 	    NEXT;
   11220 	    *test = NODE_TEST_ALL;
   11221 	    return(NULL);
   11222 	}
   11223 
   11224 	name = xmlXPathParseNCName(ctxt);
   11225 	if (name == NULL) {
   11226 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
   11227 	}
   11228     }
   11229     return(name);
   11230 }
   11231 
   11232 /**
   11233  * xmlXPathIsAxisName:
   11234  * @name:  a preparsed name token
   11235  *
   11236  * [6] AxisName ::=   'ancestor'
   11237  *                  | 'ancestor-or-self'
   11238  *                  | 'attribute'
   11239  *                  | 'child'
   11240  *                  | 'descendant'
   11241  *                  | 'descendant-or-self'
   11242  *                  | 'following'
   11243  *                  | 'following-sibling'
   11244  *                  | 'namespace'
   11245  *                  | 'parent'
   11246  *                  | 'preceding'
   11247  *                  | 'preceding-sibling'
   11248  *                  | 'self'
   11249  *
   11250  * Returns the axis or 0
   11251  */
   11252 static xmlXPathAxisVal
   11253 xmlXPathIsAxisName(const xmlChar *name) {
   11254     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
   11255     switch (name[0]) {
   11256 	case 'a':
   11257 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
   11258 		ret = AXIS_ANCESTOR;
   11259 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
   11260 		ret = AXIS_ANCESTOR_OR_SELF;
   11261 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
   11262 		ret = AXIS_ATTRIBUTE;
   11263 	    break;
   11264 	case 'c':
   11265 	    if (xmlStrEqual(name, BAD_CAST "child"))
   11266 		ret = AXIS_CHILD;
   11267 	    break;
   11268 	case 'd':
   11269 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
   11270 		ret = AXIS_DESCENDANT;
   11271 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
   11272 		ret = AXIS_DESCENDANT_OR_SELF;
   11273 	    break;
   11274 	case 'f':
   11275 	    if (xmlStrEqual(name, BAD_CAST "following"))
   11276 		ret = AXIS_FOLLOWING;
   11277 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
   11278 		ret = AXIS_FOLLOWING_SIBLING;
   11279 	    break;
   11280 	case 'n':
   11281 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
   11282 		ret = AXIS_NAMESPACE;
   11283 	    break;
   11284 	case 'p':
   11285 	    if (xmlStrEqual(name, BAD_CAST "parent"))
   11286 		ret = AXIS_PARENT;
   11287 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
   11288 		ret = AXIS_PRECEDING;
   11289 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
   11290 		ret = AXIS_PRECEDING_SIBLING;
   11291 	    break;
   11292 	case 's':
   11293 	    if (xmlStrEqual(name, BAD_CAST "self"))
   11294 		ret = AXIS_SELF;
   11295 	    break;
   11296     }
   11297     return(ret);
   11298 }
   11299 
   11300 /**
   11301  * xmlXPathCompStep:
   11302  * @ctxt:  the XPath Parser context
   11303  *
   11304  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
   11305  *                  | AbbreviatedStep
   11306  *
   11307  * [12] AbbreviatedStep ::=   '.' | '..'
   11308  *
   11309  * [5] AxisSpecifier ::= AxisName '::'
   11310  *                  | AbbreviatedAxisSpecifier
   11311  *
   11312  * [13] AbbreviatedAxisSpecifier ::= '@'?
   11313  *
   11314  * Modified for XPtr range support as:
   11315  *
   11316  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
   11317  *                     | AbbreviatedStep
   11318  *                     | 'range-to' '(' Expr ')' Predicate*
   11319  *
   11320  * Compile one step in a Location Path
   11321  * A location step of . is short for self::node(). This is
   11322  * particularly useful in conjunction with //. For example, the
   11323  * location path .//para is short for
   11324  * self::node()/descendant-or-self::node()/child::para
   11325  * and so will select all para descendant elements of the context
   11326  * node.
   11327  * Similarly, a location step of .. is short for parent::node().
   11328  * For example, ../title is short for parent::node()/child::title
   11329  * and so will select the title children of the parent of the context
   11330  * node.
   11331  */
   11332 static void
   11333 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
   11334 #ifdef LIBXML_XPTR_ENABLED
   11335     int rangeto = 0;
   11336     int op2 = -1;
   11337 #endif
   11338 
   11339     SKIP_BLANKS;
   11340     if ((CUR == '.') && (NXT(1) == '.')) {
   11341 	SKIP(2);
   11342 	SKIP_BLANKS;
   11343 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
   11344 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11345     } else if (CUR == '.') {
   11346 	NEXT;
   11347 	SKIP_BLANKS;
   11348     } else {
   11349 	xmlChar *name = NULL;
   11350 	const xmlChar *prefix = NULL;
   11351 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
   11352 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
   11353 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
   11354 	int op1;
   11355 
   11356 	/*
   11357 	 * The modification needed for XPointer change to the production
   11358 	 */
   11359 #ifdef LIBXML_XPTR_ENABLED
   11360 	if (ctxt->xptr) {
   11361 	    name = xmlXPathParseNCName(ctxt);
   11362 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
   11363                 op2 = ctxt->comp->last;
   11364 		xmlFree(name);
   11365 		SKIP_BLANKS;
   11366 		if (CUR != '(') {
   11367 		    XP_ERROR(XPATH_EXPR_ERROR);
   11368 		}
   11369 		NEXT;
   11370 		SKIP_BLANKS;
   11371 
   11372 		xmlXPathCompileExpr(ctxt, 1);
   11373 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
   11374 		CHECK_ERROR;
   11375 
   11376 		SKIP_BLANKS;
   11377 		if (CUR != ')') {
   11378 		    XP_ERROR(XPATH_EXPR_ERROR);
   11379 		}
   11380 		NEXT;
   11381 		rangeto = 1;
   11382 		goto eval_predicates;
   11383 	    }
   11384 	}
   11385 #endif
   11386 	if (CUR == '*') {
   11387 	    axis = AXIS_CHILD;
   11388 	} else {
   11389 	    if (name == NULL)
   11390 		name = xmlXPathParseNCName(ctxt);
   11391 	    if (name != NULL) {
   11392 		axis = xmlXPathIsAxisName(name);
   11393 		if (axis != 0) {
   11394 		    SKIP_BLANKS;
   11395 		    if ((CUR == ':') && (NXT(1) == ':')) {
   11396 			SKIP(2);
   11397 			xmlFree(name);
   11398 			name = NULL;
   11399 		    } else {
   11400 			/* an element name can conflict with an axis one :-\ */
   11401 			axis = AXIS_CHILD;
   11402 		    }
   11403 		} else {
   11404 		    axis = AXIS_CHILD;
   11405 		}
   11406 	    } else if (CUR == '@') {
   11407 		NEXT;
   11408 		axis = AXIS_ATTRIBUTE;
   11409 	    } else {
   11410 		axis = AXIS_CHILD;
   11411 	    }
   11412 	}
   11413 
   11414         if (ctxt->error != XPATH_EXPRESSION_OK) {
   11415             xmlFree(name);
   11416             return;
   11417         }
   11418 
   11419 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
   11420 	if (test == 0)
   11421 	    return;
   11422 
   11423         if ((prefix != NULL) && (ctxt->context != NULL) &&
   11424 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
   11425 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
   11426 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
   11427 	    }
   11428 	}
   11429 #ifdef DEBUG_STEP
   11430 	xmlGenericError(xmlGenericErrorContext,
   11431 		"Basis : computing new set\n");
   11432 #endif
   11433 
   11434 #ifdef DEBUG_STEP
   11435 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
   11436 	if (ctxt->value == NULL)
   11437 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
   11438 	else if (ctxt->value->nodesetval == NULL)
   11439 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
   11440 	else
   11441 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
   11442 #endif
   11443 
   11444 #ifdef LIBXML_XPTR_ENABLED
   11445 eval_predicates:
   11446 #endif
   11447 	op1 = ctxt->comp->last;
   11448 	ctxt->comp->last = -1;
   11449 
   11450 	SKIP_BLANKS;
   11451 	while (CUR == '[') {
   11452 	    xmlXPathCompPredicate(ctxt, 0);
   11453 	}
   11454 
   11455 #ifdef LIBXML_XPTR_ENABLED
   11456 	if (rangeto) {
   11457 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
   11458 	} else
   11459 #endif
   11460 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
   11461 			   test, type, (void *)prefix, (void *)name);
   11462 
   11463     }
   11464 #ifdef DEBUG_STEP
   11465     xmlGenericError(xmlGenericErrorContext, "Step : ");
   11466     if (ctxt->value == NULL)
   11467 	xmlGenericError(xmlGenericErrorContext, "no value\n");
   11468     else if (ctxt->value->nodesetval == NULL)
   11469 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
   11470     else
   11471 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
   11472 		ctxt->value->nodesetval);
   11473 #endif
   11474 }
   11475 
   11476 /**
   11477  * xmlXPathCompRelativeLocationPath:
   11478  * @ctxt:  the XPath Parser context
   11479  *
   11480  *  [3]   RelativeLocationPath ::=   Step
   11481  *                     | RelativeLocationPath '/' Step
   11482  *                     | AbbreviatedRelativeLocationPath
   11483  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
   11484  *
   11485  * Compile a relative location path.
   11486  */
   11487 static void
   11488 xmlXPathCompRelativeLocationPath
   11489 (xmlXPathParserContextPtr ctxt) {
   11490     SKIP_BLANKS;
   11491     if ((CUR == '/') && (NXT(1) == '/')) {
   11492 	SKIP(2);
   11493 	SKIP_BLANKS;
   11494 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11495 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11496     } else if (CUR == '/') {
   11497 	    NEXT;
   11498 	SKIP_BLANKS;
   11499     }
   11500     xmlXPathCompStep(ctxt);
   11501     CHECK_ERROR;
   11502     SKIP_BLANKS;
   11503     while (CUR == '/') {
   11504 	if ((CUR == '/') && (NXT(1) == '/')) {
   11505 	    SKIP(2);
   11506 	    SKIP_BLANKS;
   11507 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11508 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11509 	    xmlXPathCompStep(ctxt);
   11510 	} else if (CUR == '/') {
   11511 	    NEXT;
   11512 	    SKIP_BLANKS;
   11513 	    xmlXPathCompStep(ctxt);
   11514 	}
   11515 	SKIP_BLANKS;
   11516     }
   11517 }
   11518 
   11519 /**
   11520  * xmlXPathCompLocationPath:
   11521  * @ctxt:  the XPath Parser context
   11522  *
   11523  *  [1]   LocationPath ::=   RelativeLocationPath
   11524  *                     | AbsoluteLocationPath
   11525  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
   11526  *                     | AbbreviatedAbsoluteLocationPath
   11527  *  [10]   AbbreviatedAbsoluteLocationPath ::=
   11528  *                           '//' RelativeLocationPath
   11529  *
   11530  * Compile a location path
   11531  *
   11532  * // is short for /descendant-or-self::node()/. For example,
   11533  * //para is short for /descendant-or-self::node()/child::para and
   11534  * so will select any para element in the document (even a para element
   11535  * that is a document element will be selected by //para since the
   11536  * document element node is a child of the root node); div//para is
   11537  * short for div/descendant-or-self::node()/child::para and so will
   11538  * select all para descendants of div children.
   11539  */
   11540 static void
   11541 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
   11542     SKIP_BLANKS;
   11543     if (CUR != '/') {
   11544         xmlXPathCompRelativeLocationPath(ctxt);
   11545     } else {
   11546 	while (CUR == '/') {
   11547 	    if ((CUR == '/') && (NXT(1) == '/')) {
   11548 		SKIP(2);
   11549 		SKIP_BLANKS;
   11550 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11551 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11552 		xmlXPathCompRelativeLocationPath(ctxt);
   11553 	    } else if (CUR == '/') {
   11554 		NEXT;
   11555 		SKIP_BLANKS;
   11556 		if ((CUR != 0 ) &&
   11557 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
   11558 		     (CUR == '@') || (CUR == '*')))
   11559 		    xmlXPathCompRelativeLocationPath(ctxt);
   11560 	    }
   11561 	    CHECK_ERROR;
   11562 	}
   11563     }
   11564 }
   11565 
   11566 /************************************************************************
   11567  *									*
   11568  *		XPath precompiled expression evaluation			*
   11569  *									*
   11570  ************************************************************************/
   11571 
   11572 static int
   11573 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
   11574 
   11575 #ifdef DEBUG_STEP
   11576 static void
   11577 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
   11578 			  int nbNodes)
   11579 {
   11580     xmlGenericError(xmlGenericErrorContext, "new step : ");
   11581     switch (op->value) {
   11582         case AXIS_ANCESTOR:
   11583             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
   11584             break;
   11585         case AXIS_ANCESTOR_OR_SELF:
   11586             xmlGenericError(xmlGenericErrorContext,
   11587                             "axis 'ancestors-or-self' ");
   11588             break;
   11589         case AXIS_ATTRIBUTE:
   11590             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
   11591             break;
   11592         case AXIS_CHILD:
   11593             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
   11594             break;
   11595         case AXIS_DESCENDANT:
   11596             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
   11597             break;
   11598         case AXIS_DESCENDANT_OR_SELF:
   11599             xmlGenericError(xmlGenericErrorContext,
   11600                             "axis 'descendant-or-self' ");
   11601             break;
   11602         case AXIS_FOLLOWING:
   11603             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
   11604             break;
   11605         case AXIS_FOLLOWING_SIBLING:
   11606             xmlGenericError(xmlGenericErrorContext,
   11607                             "axis 'following-siblings' ");
   11608             break;
   11609         case AXIS_NAMESPACE:
   11610             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
   11611             break;
   11612         case AXIS_PARENT:
   11613             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
   11614             break;
   11615         case AXIS_PRECEDING:
   11616             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
   11617             break;
   11618         case AXIS_PRECEDING_SIBLING:
   11619             xmlGenericError(xmlGenericErrorContext,
   11620                             "axis 'preceding-sibling' ");
   11621             break;
   11622         case AXIS_SELF:
   11623             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
   11624             break;
   11625     }
   11626     xmlGenericError(xmlGenericErrorContext,
   11627 	" context contains %d nodes\n", nbNodes);
   11628     switch (op->value2) {
   11629         case NODE_TEST_NONE:
   11630             xmlGenericError(xmlGenericErrorContext,
   11631                             "           searching for none !!!\n");
   11632             break;
   11633         case NODE_TEST_TYPE:
   11634             xmlGenericError(xmlGenericErrorContext,
   11635                             "           searching for type %d\n", op->value3);
   11636             break;
   11637         case NODE_TEST_PI:
   11638             xmlGenericError(xmlGenericErrorContext,
   11639                             "           searching for PI !!!\n");
   11640             break;
   11641         case NODE_TEST_ALL:
   11642             xmlGenericError(xmlGenericErrorContext,
   11643                             "           searching for *\n");
   11644             break;
   11645         case NODE_TEST_NS:
   11646             xmlGenericError(xmlGenericErrorContext,
   11647                             "           searching for namespace %s\n",
   11648                             op->value5);
   11649             break;
   11650         case NODE_TEST_NAME:
   11651             xmlGenericError(xmlGenericErrorContext,
   11652                             "           searching for name %s\n", op->value5);
   11653             if (op->value4)
   11654                 xmlGenericError(xmlGenericErrorContext,
   11655                                 "           with namespace %s\n", op->value4);
   11656             break;
   11657     }
   11658     xmlGenericError(xmlGenericErrorContext, "Testing : ");
   11659 }
   11660 #endif /* DEBUG_STEP */
   11661 
   11662 static int
   11663 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
   11664 			    xmlXPathStepOpPtr op,
   11665 			    xmlNodeSetPtr set,
   11666 			    int contextSize,
   11667 			    int hasNsNodes)
   11668 {
   11669     if (op->ch1 != -1) {
   11670 	xmlXPathCompExprPtr comp = ctxt->comp;
   11671 	/*
   11672 	* Process inner predicates first.
   11673 	*/
   11674 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
   11675 	    /*
   11676 	    * TODO: raise an internal error.
   11677 	    */
   11678 	}
   11679 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
   11680 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
   11681 	CHECK_ERROR0;
   11682 	if (contextSize <= 0)
   11683 	    return(0);
   11684     }
   11685     if (op->ch2 != -1) {
   11686 	xmlXPathContextPtr xpctxt = ctxt->context;
   11687 	xmlNodePtr contextNode, oldContextNode;
   11688 	xmlDocPtr oldContextDoc;
   11689 	int i, res, contextPos = 0, newContextSize;
   11690 	xmlXPathStepOpPtr exprOp;
   11691 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
   11692 
   11693 #ifdef LIBXML_XPTR_ENABLED
   11694 	/*
   11695 	* URGENT TODO: Check the following:
   11696 	*  We don't expect location sets if evaluating prediates, right?
   11697 	*  Only filters should expect location sets, right?
   11698 	*/
   11699 #endif
   11700 	/*
   11701 	* SPEC XPath 1.0:
   11702 	*  "For each node in the node-set to be filtered, the
   11703 	*  PredicateExpr is evaluated with that node as the
   11704 	*  context node, with the number of nodes in the
   11705 	*  node-set as the context size, and with the proximity
   11706 	*  position of the node in the node-set with respect to
   11707 	*  the axis as the context position;"
   11708 	* @oldset is the node-set" to be filtered.
   11709 	*
   11710 	* SPEC XPath 1.0:
   11711 	*  "only predicates change the context position and
   11712 	*  context size (see [2.4 Predicates])."
   11713 	* Example:
   11714 	*   node-set  context pos
   11715 	*    nA         1
   11716 	*    nB         2
   11717 	*    nC         3
   11718 	*   After applying predicate [position() > 1] :
   11719 	*   node-set  context pos
   11720 	*    nB         1
   11721 	*    nC         2
   11722 	*/
   11723 	oldContextNode = xpctxt->node;
   11724 	oldContextDoc = xpctxt->doc;
   11725 	/*
   11726 	* Get the expression of this predicate.
   11727 	*/
   11728 	exprOp = &ctxt->comp->steps[op->ch2];
   11729 	newContextSize = 0;
   11730 	for (i = 0; i < set->nodeNr; i++) {
   11731 	    if (set->nodeTab[i] == NULL)
   11732 		continue;
   11733 
   11734 	    contextNode = set->nodeTab[i];
   11735 	    xpctxt->node = contextNode;
   11736 	    xpctxt->contextSize = contextSize;
   11737 	    xpctxt->proximityPosition = ++contextPos;
   11738 
   11739 	    /*
   11740 	    * Also set the xpath document in case things like
   11741 	    * key() are evaluated in the predicate.
   11742 	    */
   11743 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
   11744 		(contextNode->doc != NULL))
   11745 		xpctxt->doc = contextNode->doc;
   11746 	    /*
   11747 	    * Evaluate the predicate expression with 1 context node
   11748 	    * at a time; this node is packaged into a node set; this
   11749 	    * node set is handed over to the evaluation mechanism.
   11750 	    */
   11751 	    if (contextObj == NULL)
   11752 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
   11753 	    else {
   11754 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
   11755 		    contextNode) < 0) {
   11756 		    ctxt->error = XPATH_MEMORY_ERROR;
   11757 		    goto evaluation_exit;
   11758 		}
   11759 	    }
   11760 
   11761 	    valuePush(ctxt, contextObj);
   11762 
   11763 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
   11764 
   11765 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
   11766 		xmlXPathNodeSetClear(set, hasNsNodes);
   11767 		newContextSize = 0;
   11768 		goto evaluation_exit;
   11769 	    }
   11770 
   11771 	    if (res != 0) {
   11772 		newContextSize++;
   11773 	    } else {
   11774 		/*
   11775 		* Remove the entry from the initial node set.
   11776 		*/
   11777 		set->nodeTab[i] = NULL;
   11778 		if (contextNode->type == XML_NAMESPACE_DECL)
   11779 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
   11780 	    }
   11781 	    if (ctxt->value == contextObj) {
   11782 		/*
   11783 		* Don't free the temporary XPath object holding the
   11784 		* context node, in order to avoid massive recreation
   11785 		* inside this loop.
   11786 		*/
   11787 		valuePop(ctxt);
   11788 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
   11789 	    } else {
   11790 		/*
   11791 		* TODO: The object was lost in the evaluation machinery.
   11792 		*  Can this happen? Maybe in internal-error cases.
   11793 		*/
   11794 		contextObj = NULL;
   11795 	    }
   11796 	}
   11797 
   11798 	if (contextObj != NULL) {
   11799 	    if (ctxt->value == contextObj)
   11800 		valuePop(ctxt);
   11801 	    xmlXPathReleaseObject(xpctxt, contextObj);
   11802 	}
   11803 evaluation_exit:
   11804 	if (exprRes != NULL)
   11805 	    xmlXPathReleaseObject(ctxt->context, exprRes);
   11806 	/*
   11807 	* Reset/invalidate the context.
   11808 	*/
   11809 	xpctxt->node = oldContextNode;
   11810 	xpctxt->doc = oldContextDoc;
   11811 	xpctxt->contextSize = -1;
   11812 	xpctxt->proximityPosition = -1;
   11813 	return(newContextSize);
   11814     }
   11815     return(contextSize);
   11816 }
   11817 
   11818 static int
   11819 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
   11820 				      xmlXPathStepOpPtr op,
   11821 				      xmlNodeSetPtr set,
   11822 				      int contextSize,
   11823 				      int minPos,
   11824 				      int maxPos,
   11825 				      int hasNsNodes)
   11826 {
   11827     if (op->ch1 != -1) {
   11828 	xmlXPathCompExprPtr comp = ctxt->comp;
   11829 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
   11830 	    /*
   11831 	    * TODO: raise an internal error.
   11832 	    */
   11833 	}
   11834 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
   11835 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
   11836 	CHECK_ERROR0;
   11837 	if (contextSize <= 0)
   11838 	    return(0);
   11839     }
   11840     /*
   11841     * Check if the node set contains a sufficient number of nodes for
   11842     * the requested range.
   11843     */
   11844     if (contextSize < minPos) {
   11845 	xmlXPathNodeSetClear(set, hasNsNodes);
   11846 	return(0);
   11847     }
   11848     if (op->ch2 == -1) {
   11849 	/*
   11850 	* TODO: Can this ever happen?
   11851 	*/
   11852 	return (contextSize);
   11853     } else {
   11854 	xmlDocPtr oldContextDoc;
   11855 	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
   11856 	xmlXPathStepOpPtr exprOp;
   11857 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
   11858 	xmlNodePtr oldContextNode, contextNode = NULL;
   11859 	xmlXPathContextPtr xpctxt = ctxt->context;
   11860         int frame;
   11861 
   11862 #ifdef LIBXML_XPTR_ENABLED
   11863 	    /*
   11864 	    * URGENT TODO: Check the following:
   11865 	    *  We don't expect location sets if evaluating prediates, right?
   11866 	    *  Only filters should expect location sets, right?
   11867 	*/
   11868 #endif /* LIBXML_XPTR_ENABLED */
   11869 
   11870 	/*
   11871 	* Save old context.
   11872 	*/
   11873 	oldContextNode = xpctxt->node;
   11874 	oldContextDoc = xpctxt->doc;
   11875 	/*
   11876 	* Get the expression of this predicate.
   11877 	*/
   11878 	exprOp = &ctxt->comp->steps[op->ch2];
   11879 	for (i = 0; i < set->nodeNr; i++) {
   11880             xmlXPathObjectPtr tmp;
   11881 
   11882 	    if (set->nodeTab[i] == NULL)
   11883 		continue;
   11884 
   11885 	    contextNode = set->nodeTab[i];
   11886 	    xpctxt->node = contextNode;
   11887 	    xpctxt->contextSize = contextSize;
   11888 	    xpctxt->proximityPosition = ++contextPos;
   11889 
   11890 	    /*
   11891 	    * Initialize the new set.
   11892 	    * Also set the xpath document in case things like
   11893 	    * key() evaluation are attempted on the predicate
   11894 	    */
   11895 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
   11896 		(contextNode->doc != NULL))
   11897 		xpctxt->doc = contextNode->doc;
   11898 	    /*
   11899 	    * Evaluate the predicate expression with 1 context node
   11900 	    * at a time; this node is packaged into a node set; this
   11901 	    * node set is handed over to the evaluation mechanism.
   11902 	    */
   11903 	    if (contextObj == NULL)
   11904 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
   11905 	    else {
   11906 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
   11907 		    contextNode) < 0) {
   11908 		    ctxt->error = XPATH_MEMORY_ERROR;
   11909 		    goto evaluation_exit;
   11910 		}
   11911 	    }
   11912 
   11913             frame = xmlXPathSetFrame(ctxt);
   11914 	    valuePush(ctxt, contextObj);
   11915 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
   11916             tmp = valuePop(ctxt);
   11917             xmlXPathPopFrame(ctxt, frame);
   11918 
   11919 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
   11920                 while (tmp != contextObj) {
   11921                     /*
   11922                      * Free up the result
   11923                      * then pop off contextObj, which will be freed later
   11924                      */
   11925                     xmlXPathReleaseObject(xpctxt, tmp);
   11926                     tmp = valuePop(ctxt);
   11927                 }
   11928 		goto evaluation_error;
   11929 	    }
   11930             /* push the result back onto the stack */
   11931             valuePush(ctxt, tmp);
   11932 
   11933 	    if (res)
   11934 		pos++;
   11935 
   11936 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
   11937 		/*
   11938 		* Fits in the requested range.
   11939 		*/
   11940 		newContextSize++;
   11941 		if (minPos == maxPos) {
   11942 		    /*
   11943 		    * Only 1 node was requested.
   11944 		    */
   11945 		    if (contextNode->type == XML_NAMESPACE_DECL) {
   11946 			/*
   11947 			* As always: take care of those nasty
   11948 			* namespace nodes.
   11949 			*/
   11950 			set->nodeTab[i] = NULL;
   11951 		    }
   11952 		    xmlXPathNodeSetClear(set, hasNsNodes);
   11953 		    set->nodeNr = 1;
   11954 		    set->nodeTab[0] = contextNode;
   11955 		    goto evaluation_exit;
   11956 		}
   11957 		if (pos == maxPos) {
   11958 		    /*
   11959 		    * We are done.
   11960 		    */
   11961 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
   11962 		    goto evaluation_exit;
   11963 		}
   11964 	    } else {
   11965 		/*
   11966 		* Remove the entry from the initial node set.
   11967 		*/
   11968 		set->nodeTab[i] = NULL;
   11969 		if (contextNode->type == XML_NAMESPACE_DECL)
   11970 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
   11971 	    }
   11972 	    if (exprRes != NULL) {
   11973 		xmlXPathReleaseObject(ctxt->context, exprRes);
   11974 		exprRes = NULL;
   11975 	    }
   11976 	    if (ctxt->value == contextObj) {
   11977 		/*
   11978 		* Don't free the temporary XPath object holding the
   11979 		* context node, in order to avoid massive recreation
   11980 		* inside this loop.
   11981 		*/
   11982 		valuePop(ctxt);
   11983 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
   11984 	    } else {
   11985 		/*
   11986 		* The object was lost in the evaluation machinery.
   11987 		* Can this happen? Maybe in case of internal-errors.
   11988 		*/
   11989 		contextObj = NULL;
   11990 	    }
   11991 	}
   11992 	goto evaluation_exit;
   11993 
   11994 evaluation_error:
   11995 	xmlXPathNodeSetClear(set, hasNsNodes);
   11996 	newContextSize = 0;
   11997 
   11998 evaluation_exit:
   11999 	if (contextObj != NULL) {
   12000 	    if (ctxt->value == contextObj)
   12001 		valuePop(ctxt);
   12002 	    xmlXPathReleaseObject(xpctxt, contextObj);
   12003 	}
   12004 	if (exprRes != NULL)
   12005 	    xmlXPathReleaseObject(ctxt->context, exprRes);
   12006 	/*
   12007 	* Reset/invalidate the context.
   12008 	*/
   12009 	xpctxt->node = oldContextNode;
   12010 	xpctxt->doc = oldContextDoc;
   12011 	xpctxt->contextSize = -1;
   12012 	xpctxt->proximityPosition = -1;
   12013 	return(newContextSize);
   12014     }
   12015     return(contextSize);
   12016 }
   12017 
   12018 static int
   12019 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
   12020 			    xmlXPathStepOpPtr op,
   12021 			    int *maxPos)
   12022 {
   12023 
   12024     xmlXPathStepOpPtr exprOp;
   12025 
   12026     /*
   12027     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
   12028     */
   12029 
   12030     /*
   12031     * If not -1, then ch1 will point to:
   12032     * 1) For predicates (XPATH_OP_PREDICATE):
   12033     *    - an inner predicate operator
   12034     * 2) For filters (XPATH_OP_FILTER):
   12035     *    - an inner filter operater OR
   12036     *    - an expression selecting the node set.
   12037     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
   12038     */
   12039     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
   12040 	return(0);
   12041 
   12042     if (op->ch2 != -1) {
   12043 	exprOp = &ctxt->comp->steps[op->ch2];
   12044     } else
   12045 	return(0);
   12046 
   12047     if ((exprOp != NULL) &&
   12048 	(exprOp->op == XPATH_OP_VALUE) &&
   12049 	(exprOp->value4 != NULL) &&
   12050 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
   12051     {
   12052 	/*
   12053 	* We have a "[n]" predicate here.
   12054 	* TODO: Unfortunately this simplistic test here is not
   12055 	* able to detect a position() predicate in compound
   12056 	* expressions like "[@attr = 'a" and position() = 1],
   12057 	* and even not the usage of position() in
   12058 	* "[position() = 1]"; thus - obviously - a position-range,
   12059 	* like it "[position() < 5]", is also not detected.
   12060 	* Maybe we could rewrite the AST to ease the optimization.
   12061 	*/
   12062 	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
   12063 
   12064 	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
   12065 	    (float) *maxPos)
   12066 	{
   12067 	    return(1);
   12068 	}
   12069     }
   12070     return(0);
   12071 }
   12072 
   12073 static int
   12074 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
   12075                            xmlXPathStepOpPtr op,
   12076 			   xmlNodePtr * first, xmlNodePtr * last,
   12077 			   int toBool)
   12078 {
   12079 
   12080 #define XP_TEST_HIT \
   12081     if (hasAxisRange != 0) { \
   12082 	if (++pos == maxPos) { \
   12083 	    if (addNode(seq, cur) < 0) \
   12084 	        ctxt->error = XPATH_MEMORY_ERROR; \
   12085 	    goto axis_range_end; } \
   12086     } else { \
   12087 	if (addNode(seq, cur) < 0) \
   12088 	    ctxt->error = XPATH_MEMORY_ERROR; \
   12089 	if (breakOnFirstHit) goto first_hit; }
   12090 
   12091 #define XP_TEST_HIT_NS \
   12092     if (hasAxisRange != 0) { \
   12093 	if (++pos == maxPos) { \
   12094 	    hasNsNodes = 1; \
   12095 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
   12096 	        ctxt->error = XPATH_MEMORY_ERROR; \
   12097 	goto axis_range_end; } \
   12098     } else { \
   12099 	hasNsNodes = 1; \
   12100 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
   12101 	    ctxt->error = XPATH_MEMORY_ERROR; \
   12102 	if (breakOnFirstHit) goto first_hit; }
   12103 
   12104     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
   12105     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
   12106     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
   12107     const xmlChar *prefix = op->value4;
   12108     const xmlChar *name = op->value5;
   12109     const xmlChar *URI = NULL;
   12110 
   12111 #ifdef DEBUG_STEP
   12112     int nbMatches = 0, prevMatches = 0;
   12113 #endif
   12114     int total = 0, hasNsNodes = 0;
   12115     /* The popped object holding the context nodes */
   12116     xmlXPathObjectPtr obj;
   12117     /* The set of context nodes for the node tests */
   12118     xmlNodeSetPtr contextSeq;
   12119     int contextIdx;
   12120     xmlNodePtr contextNode;
   12121     /* The final resulting node set wrt to all context nodes */
   12122     xmlNodeSetPtr outSeq;
   12123     /*
   12124     * The temporary resulting node set wrt 1 context node.
   12125     * Used to feed predicate evaluation.
   12126     */
   12127     xmlNodeSetPtr seq;
   12128     xmlNodePtr cur;
   12129     /* First predicate operator */
   12130     xmlXPathStepOpPtr predOp;
   12131     int maxPos; /* The requested position() (when a "[n]" predicate) */
   12132     int hasPredicateRange, hasAxisRange, pos, size, newSize;
   12133     int breakOnFirstHit;
   12134 
   12135     xmlXPathTraversalFunction next = NULL;
   12136     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
   12137     xmlXPathNodeSetMergeFunction mergeAndClear;
   12138     xmlNodePtr oldContextNode;
   12139     xmlXPathContextPtr xpctxt = ctxt->context;
   12140 
   12141 
   12142     CHECK_TYPE0(XPATH_NODESET);
   12143     obj = valuePop(ctxt);
   12144     /*
   12145     * Setup namespaces.
   12146     */
   12147     if (prefix != NULL) {
   12148         URI = xmlXPathNsLookup(xpctxt, prefix);
   12149         if (URI == NULL) {
   12150 	    xmlXPathReleaseObject(xpctxt, obj);
   12151             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
   12152 	}
   12153     }
   12154     /*
   12155     * Setup axis.
   12156     *
   12157     * MAYBE FUTURE TODO: merging optimizations:
   12158     * - If the nodes to be traversed wrt to the initial nodes and
   12159     *   the current axis cannot overlap, then we could avoid searching
   12160     *   for duplicates during the merge.
   12161     *   But the question is how/when to evaluate if they cannot overlap.
   12162     *   Example: if we know that for two initial nodes, the one is
   12163     *   not in the ancestor-or-self axis of the other, then we could safely
   12164     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
   12165     *   the descendant-or-self axis.
   12166     */
   12167     mergeAndClear = xmlXPathNodeSetMergeAndClear;
   12168     switch (axis) {
   12169         case AXIS_ANCESTOR:
   12170             first = NULL;
   12171             next = xmlXPathNextAncestor;
   12172             break;
   12173         case AXIS_ANCESTOR_OR_SELF:
   12174             first = NULL;
   12175             next = xmlXPathNextAncestorOrSelf;
   12176             break;
   12177         case AXIS_ATTRIBUTE:
   12178             first = NULL;
   12179 	    last = NULL;
   12180             next = xmlXPathNextAttribute;
   12181 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12182             break;
   12183         case AXIS_CHILD:
   12184 	    last = NULL;
   12185 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
   12186 		(type == NODE_TYPE_NODE))
   12187 	    {
   12188 		/*
   12189 		* Optimization if an element node type is 'element'.
   12190 		*/
   12191 		next = xmlXPathNextChildElement;
   12192 	    } else
   12193 		next = xmlXPathNextChild;
   12194 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12195             break;
   12196         case AXIS_DESCENDANT:
   12197 	    last = NULL;
   12198             next = xmlXPathNextDescendant;
   12199             break;
   12200         case AXIS_DESCENDANT_OR_SELF:
   12201 	    last = NULL;
   12202             next = xmlXPathNextDescendantOrSelf;
   12203             break;
   12204         case AXIS_FOLLOWING:
   12205 	    last = NULL;
   12206             next = xmlXPathNextFollowing;
   12207             break;
   12208         case AXIS_FOLLOWING_SIBLING:
   12209 	    last = NULL;
   12210             next = xmlXPathNextFollowingSibling;
   12211             break;
   12212         case AXIS_NAMESPACE:
   12213             first = NULL;
   12214 	    last = NULL;
   12215             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
   12216 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12217             break;
   12218         case AXIS_PARENT:
   12219             first = NULL;
   12220             next = xmlXPathNextParent;
   12221             break;
   12222         case AXIS_PRECEDING:
   12223             first = NULL;
   12224             next = xmlXPathNextPrecedingInternal;
   12225             break;
   12226         case AXIS_PRECEDING_SIBLING:
   12227             first = NULL;
   12228             next = xmlXPathNextPrecedingSibling;
   12229             break;
   12230         case AXIS_SELF:
   12231             first = NULL;
   12232 	    last = NULL;
   12233             next = xmlXPathNextSelf;
   12234 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12235             break;
   12236     }
   12237 
   12238 #ifdef DEBUG_STEP
   12239     xmlXPathDebugDumpStepAxis(op,
   12240 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
   12241 #endif
   12242 
   12243     if (next == NULL) {
   12244 	xmlXPathReleaseObject(xpctxt, obj);
   12245         return(0);
   12246     }
   12247     contextSeq = obj->nodesetval;
   12248     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
   12249 	xmlXPathReleaseObject(xpctxt, obj);
   12250         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
   12251         return(0);
   12252     }
   12253     /*
   12254     * Predicate optimization ---------------------------------------------
   12255     * If this step has a last predicate, which contains a position(),
   12256     * then we'll optimize (although not exactly "position()", but only
   12257     * the  short-hand form, i.e., "[n]".
   12258     *
   12259     * Example - expression "/foo[parent::bar][1]":
   12260     *
   12261     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
   12262     *   ROOT                               -- op->ch1
   12263     *   PREDICATE                          -- op->ch2 (predOp)
   12264     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
   12265     *       SORT
   12266     *         COLLECT  'parent' 'name' 'node' bar
   12267     *           NODE
   12268     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
   12269     *
   12270     */
   12271     maxPos = 0;
   12272     predOp = NULL;
   12273     hasPredicateRange = 0;
   12274     hasAxisRange = 0;
   12275     if (op->ch2 != -1) {
   12276 	/*
   12277 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
   12278 	*/
   12279 	predOp = &ctxt->comp->steps[op->ch2];
   12280 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
   12281 	    if (predOp->ch1 != -1) {
   12282 		/*
   12283 		* Use the next inner predicate operator.
   12284 		*/
   12285 		predOp = &ctxt->comp->steps[predOp->ch1];
   12286 		hasPredicateRange = 1;
   12287 	    } else {
   12288 		/*
   12289 		* There's no other predicate than the [n] predicate.
   12290 		*/
   12291 		predOp = NULL;
   12292 		hasAxisRange = 1;
   12293 	    }
   12294 	}
   12295     }
   12296     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
   12297     /*
   12298     * Axis traversal -----------------------------------------------------
   12299     */
   12300     /*
   12301      * 2.3 Node Tests
   12302      *  - For the attribute axis, the principal node type is attribute.
   12303      *  - For the namespace axis, the principal node type is namespace.
   12304      *  - For other axes, the principal node type is element.
   12305      *
   12306      * A node test * is true for any node of the
   12307      * principal node type. For example, child::* will
   12308      * select all element children of the context node
   12309      */
   12310     oldContextNode = xpctxt->node;
   12311     addNode = xmlXPathNodeSetAddUnique;
   12312     outSeq = NULL;
   12313     seq = NULL;
   12314     contextNode = NULL;
   12315     contextIdx = 0;
   12316 
   12317 
   12318     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
   12319            (ctxt->error == XPATH_EXPRESSION_OK)) {
   12320 	xpctxt->node = contextSeq->nodeTab[contextIdx++];
   12321 
   12322 	if (seq == NULL) {
   12323 	    seq = xmlXPathNodeSetCreate(NULL);
   12324 	    if (seq == NULL) {
   12325 		total = 0;
   12326 		goto error;
   12327 	    }
   12328 	}
   12329 	/*
   12330 	* Traverse the axis and test the nodes.
   12331 	*/
   12332 	pos = 0;
   12333 	cur = NULL;
   12334 	hasNsNodes = 0;
   12335         do {
   12336             cur = next(ctxt, cur);
   12337             if (cur == NULL)
   12338                 break;
   12339 
   12340 	    /*
   12341 	    * QUESTION TODO: What does the "first" and "last" stuff do?
   12342 	    */
   12343             if ((first != NULL) && (*first != NULL)) {
   12344 		if (*first == cur)
   12345 		    break;
   12346 		if (((total % 256) == 0) &&
   12347 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   12348 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
   12349 #else
   12350 		    (xmlXPathCmpNodes(*first, cur) >= 0))
   12351 #endif
   12352 		{
   12353 		    break;
   12354 		}
   12355 	    }
   12356 	    if ((last != NULL) && (*last != NULL)) {
   12357 		if (*last == cur)
   12358 		    break;
   12359 		if (((total % 256) == 0) &&
   12360 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   12361 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
   12362 #else
   12363 		    (xmlXPathCmpNodes(cur, *last) >= 0))
   12364 #endif
   12365 		{
   12366 		    break;
   12367 		}
   12368 	    }
   12369 
   12370             total++;
   12371 
   12372 #ifdef DEBUG_STEP
   12373             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
   12374 #endif
   12375 
   12376 	    switch (test) {
   12377                 case NODE_TEST_NONE:
   12378 		    total = 0;
   12379                     STRANGE
   12380 		    goto error;
   12381                 case NODE_TEST_TYPE:
   12382 		    /*
   12383 		    * TODO: Don't we need to use
   12384 		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
   12385 		    *  Surprisingly, some c14n tests fail, if we do this.
   12386 		    */
   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 			    case XML_NAMESPACE_DECL:
   12401 				XP_TEST_HIT
   12402 				break;
   12403 			    default:
   12404 				break;
   12405 			}
   12406 		    } else if (cur->type == type) {
   12407 			if (cur->type == XML_NAMESPACE_DECL)
   12408 			    XP_TEST_HIT_NS
   12409 			else
   12410 			    XP_TEST_HIT
   12411 		    } else if ((type == NODE_TYPE_TEXT) &&
   12412 			 (cur->type == XML_CDATA_SECTION_NODE))
   12413 		    {
   12414 			XP_TEST_HIT
   12415 		    }
   12416 		    break;
   12417                 case NODE_TEST_PI:
   12418                     if ((cur->type == XML_PI_NODE) &&
   12419                         ((name == NULL) || xmlStrEqual(name, cur->name)))
   12420 		    {
   12421 			XP_TEST_HIT
   12422                     }
   12423                     break;
   12424                 case NODE_TEST_ALL:
   12425                     if (axis == AXIS_ATTRIBUTE) {
   12426                         if (cur->type == XML_ATTRIBUTE_NODE)
   12427 			{
   12428                             if (prefix == NULL)
   12429 			    {
   12430 				XP_TEST_HIT
   12431                             } else if ((cur->ns != NULL) &&
   12432 				(xmlStrEqual(URI, cur->ns->href)))
   12433 			    {
   12434 				XP_TEST_HIT
   12435                             }
   12436                         }
   12437                     } else if (axis == AXIS_NAMESPACE) {
   12438                         if (cur->type == XML_NAMESPACE_DECL)
   12439 			{
   12440 			    XP_TEST_HIT_NS
   12441                         }
   12442                     } else {
   12443                         if (cur->type == XML_ELEMENT_NODE) {
   12444                             if (prefix == NULL)
   12445 			    {
   12446 				XP_TEST_HIT
   12447 
   12448                             } else if ((cur->ns != NULL) &&
   12449 				(xmlStrEqual(URI, cur->ns->href)))
   12450 			    {
   12451 				XP_TEST_HIT
   12452                             }
   12453                         }
   12454                     }
   12455                     break;
   12456                 case NODE_TEST_NS:{
   12457                         TODO;
   12458                         break;
   12459                     }
   12460                 case NODE_TEST_NAME:
   12461                     if (axis == AXIS_ATTRIBUTE) {
   12462                         if (cur->type != XML_ATTRIBUTE_NODE)
   12463 			    break;
   12464 		    } else if (axis == AXIS_NAMESPACE) {
   12465                         if (cur->type != XML_NAMESPACE_DECL)
   12466 			    break;
   12467 		    } else {
   12468 		        if (cur->type != XML_ELEMENT_NODE)
   12469 			    break;
   12470 		    }
   12471                     switch (cur->type) {
   12472                         case XML_ELEMENT_NODE:
   12473                             if (xmlStrEqual(name, cur->name)) {
   12474                                 if (prefix == NULL) {
   12475                                     if (cur->ns == NULL)
   12476 				    {
   12477 					XP_TEST_HIT
   12478                                     }
   12479                                 } else {
   12480                                     if ((cur->ns != NULL) &&
   12481                                         (xmlStrEqual(URI, cur->ns->href)))
   12482 				    {
   12483 					XP_TEST_HIT
   12484                                     }
   12485                                 }
   12486                             }
   12487                             break;
   12488                         case XML_ATTRIBUTE_NODE:{
   12489                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
   12490 
   12491                                 if (xmlStrEqual(name, attr->name)) {
   12492                                     if (prefix == NULL) {
   12493                                         if ((attr->ns == NULL) ||
   12494                                             (attr->ns->prefix == NULL))
   12495 					{
   12496 					    XP_TEST_HIT
   12497                                         }
   12498                                     } else {
   12499                                         if ((attr->ns != NULL) &&
   12500                                             (xmlStrEqual(URI,
   12501 					      attr->ns->href)))
   12502 					{
   12503 					    XP_TEST_HIT
   12504                                         }
   12505                                     }
   12506                                 }
   12507                                 break;
   12508                             }
   12509                         case XML_NAMESPACE_DECL:
   12510                             if (cur->type == XML_NAMESPACE_DECL) {
   12511                                 xmlNsPtr ns = (xmlNsPtr) cur;
   12512 
   12513                                 if ((ns->prefix != NULL) && (name != NULL)
   12514                                     && (xmlStrEqual(ns->prefix, name)))
   12515 				{
   12516 				    XP_TEST_HIT_NS
   12517                                 }
   12518                             }
   12519                             break;
   12520                         default:
   12521                             break;
   12522                     }
   12523                     break;
   12524 	    } /* switch(test) */
   12525         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
   12526 
   12527 	goto apply_predicates;
   12528 
   12529 axis_range_end: /* ----------------------------------------------------- */
   12530 	/*
   12531 	* We have a "/foo[n]", and position() = n was reached.
   12532 	* Note that we can have as well "/foo/::parent::foo[1]", so
   12533 	* a duplicate-aware merge is still needed.
   12534 	* Merge with the result.
   12535 	*/
   12536 	if (outSeq == NULL) {
   12537 	    outSeq = seq;
   12538 	    seq = NULL;
   12539 	} else
   12540 	    outSeq = mergeAndClear(outSeq, seq, 0);
   12541 	/*
   12542 	* Break if only a true/false result was requested.
   12543 	*/
   12544 	if (toBool)
   12545 	    break;
   12546 	continue;
   12547 
   12548 first_hit: /* ---------------------------------------------------------- */
   12549 	/*
   12550 	* Break if only a true/false result was requested and
   12551 	* no predicates existed and a node test succeeded.
   12552 	*/
   12553 	if (outSeq == NULL) {
   12554 	    outSeq = seq;
   12555 	    seq = NULL;
   12556 	} else
   12557 	    outSeq = mergeAndClear(outSeq, seq, 0);
   12558 	break;
   12559 
   12560 #ifdef DEBUG_STEP
   12561 	if (seq != NULL)
   12562 	    nbMatches += seq->nodeNr;
   12563 #endif
   12564 
   12565 apply_predicates: /* --------------------------------------------------- */
   12566         if (ctxt->error != XPATH_EXPRESSION_OK)
   12567 	    goto error;
   12568 
   12569         /*
   12570 	* Apply predicates.
   12571 	*/
   12572         if ((predOp != NULL) && (seq->nodeNr > 0)) {
   12573 	    /*
   12574 	    * E.g. when we have a "/foo[some expression][n]".
   12575 	    */
   12576 	    /*
   12577 	    * QUESTION TODO: The old predicate evaluation took into
   12578 	    *  account location-sets.
   12579 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
   12580 	    *  Do we expect such a set here?
   12581 	    *  All what I learned now from the evaluation semantics
   12582 	    *  does not indicate that a location-set will be processed
   12583 	    *  here, so this looks OK.
   12584 	    */
   12585 	    /*
   12586 	    * Iterate over all predicates, starting with the outermost
   12587 	    * predicate.
   12588 	    * TODO: Problem: we cannot execute the inner predicates first
   12589 	    *  since we cannot go back *up* the operator tree!
   12590 	    *  Options we have:
   12591 	    *  1) Use of recursive functions (like is it currently done
   12592 	    *     via xmlXPathCompOpEval())
   12593 	    *  2) Add a predicate evaluation information stack to the
   12594 	    *     context struct
   12595 	    *  3) Change the way the operators are linked; we need a
   12596 	    *     "parent" field on xmlXPathStepOp
   12597 	    *
   12598 	    * For the moment, I'll try to solve this with a recursive
   12599 	    * function: xmlXPathCompOpEvalPredicate().
   12600 	    */
   12601 	    size = seq->nodeNr;
   12602 	    if (hasPredicateRange != 0)
   12603 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
   12604 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
   12605 	    else
   12606 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
   12607 		    predOp, seq, size, hasNsNodes);
   12608 
   12609 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   12610 		total = 0;
   12611 		goto error;
   12612 	    }
   12613 	    /*
   12614 	    * Add the filtered set of nodes to the result node set.
   12615 	    */
   12616 	    if (newSize == 0) {
   12617 		/*
   12618 		* The predicates filtered all nodes out.
   12619 		*/
   12620 		xmlXPathNodeSetClear(seq, hasNsNodes);
   12621 	    } else if (seq->nodeNr > 0) {
   12622 		/*
   12623 		* Add to result set.
   12624 		*/
   12625 		if (outSeq == NULL) {
   12626 		    if (size != newSize) {
   12627 			/*
   12628 			* We need to merge and clear here, since
   12629 			* the sequence will contained NULLed entries.
   12630 			*/
   12631 			outSeq = mergeAndClear(NULL, seq, 1);
   12632 		    } else {
   12633 			outSeq = seq;
   12634 			seq = NULL;
   12635 		    }
   12636 		} else
   12637 		    outSeq = mergeAndClear(outSeq, seq,
   12638 			(size != newSize) ? 1: 0);
   12639 		/*
   12640 		* Break if only a true/false result was requested.
   12641 		*/
   12642 		if (toBool)
   12643 		    break;
   12644 	    }
   12645         } else if (seq->nodeNr > 0) {
   12646 	    /*
   12647 	    * Add to result set.
   12648 	    */
   12649 	    if (outSeq == NULL) {
   12650 		outSeq = seq;
   12651 		seq = NULL;
   12652 	    } else {
   12653 		outSeq = mergeAndClear(outSeq, seq, 0);
   12654 	    }
   12655 	}
   12656     }
   12657 
   12658 error:
   12659     if ((obj->boolval) && (obj->user != NULL)) {
   12660 	/*
   12661 	* QUESTION TODO: What does this do and why?
   12662 	* TODO: Do we have to do this also for the "error"
   12663 	* cleanup further down?
   12664 	*/
   12665 	ctxt->value->boolval = 1;
   12666 	ctxt->value->user = obj->user;
   12667 	obj->user = NULL;
   12668 	obj->boolval = 0;
   12669     }
   12670     xmlXPathReleaseObject(xpctxt, obj);
   12671 
   12672     /*
   12673     * Ensure we return at least an emtpy set.
   12674     */
   12675     if (outSeq == NULL) {
   12676 	if ((seq != NULL) && (seq->nodeNr == 0))
   12677 	    outSeq = seq;
   12678 	else
   12679 	    outSeq = xmlXPathNodeSetCreate(NULL);
   12680         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
   12681     }
   12682     if ((seq != NULL) && (seq != outSeq)) {
   12683 	 xmlXPathFreeNodeSet(seq);
   12684     }
   12685     /*
   12686     * Hand over the result. Better to push the set also in
   12687     * case of errors.
   12688     */
   12689     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
   12690     /*
   12691     * Reset the context node.
   12692     */
   12693     xpctxt->node = oldContextNode;
   12694 
   12695 #ifdef DEBUG_STEP
   12696     xmlGenericError(xmlGenericErrorContext,
   12697 	"\nExamined %d nodes, found %d nodes at that step\n",
   12698 	total, nbMatches);
   12699 #endif
   12700 
   12701     return(total);
   12702 }
   12703 
   12704 static int
   12705 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
   12706 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
   12707 
   12708 /**
   12709  * xmlXPathCompOpEvalFirst:
   12710  * @ctxt:  the XPath parser context with the compiled expression
   12711  * @op:  an XPath compiled operation
   12712  * @first:  the first elem found so far
   12713  *
   12714  * Evaluate the Precompiled XPath operation searching only the first
   12715  * element in document order
   12716  *
   12717  * Returns the number of examined objects.
   12718  */
   12719 static int
   12720 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
   12721                         xmlXPathStepOpPtr op, xmlNodePtr * first)
   12722 {
   12723     int total = 0, cur;
   12724     xmlXPathCompExprPtr comp;
   12725     xmlXPathObjectPtr arg1, arg2;
   12726 
   12727     CHECK_ERROR0;
   12728     comp = ctxt->comp;
   12729     switch (op->op) {
   12730         case XPATH_OP_END:
   12731             return (0);
   12732         case XPATH_OP_UNION:
   12733             total =
   12734                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
   12735                                         first);
   12736 	    CHECK_ERROR0;
   12737             if ((ctxt->value != NULL)
   12738                 && (ctxt->value->type == XPATH_NODESET)
   12739                 && (ctxt->value->nodesetval != NULL)
   12740                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
   12741                 /*
   12742                  * limit tree traversing to first node in the result
   12743                  */
   12744 		/*
   12745 		* OPTIMIZE TODO: This implicitely sorts
   12746 		*  the result, even if not needed. E.g. if the argument
   12747 		*  of the count() function, no sorting is needed.
   12748 		* OPTIMIZE TODO: How do we know if the node-list wasn't
   12749 		*  aready sorted?
   12750 		*/
   12751 		if (ctxt->value->nodesetval->nodeNr > 1)
   12752 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12753                 *first = ctxt->value->nodesetval->nodeTab[0];
   12754             }
   12755             cur =
   12756                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
   12757                                         first);
   12758 	    CHECK_ERROR0;
   12759             CHECK_TYPE0(XPATH_NODESET);
   12760             arg2 = valuePop(ctxt);
   12761 
   12762             CHECK_TYPE0(XPATH_NODESET);
   12763             arg1 = valuePop(ctxt);
   12764 
   12765             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   12766                                                     arg2->nodesetval);
   12767             valuePush(ctxt, arg1);
   12768 	    xmlXPathReleaseObject(ctxt->context, arg2);
   12769             /* optimizer */
   12770 	    if (total > cur)
   12771 		xmlXPathCompSwap(op);
   12772             return (total + cur);
   12773         case XPATH_OP_ROOT:
   12774             xmlXPathRoot(ctxt);
   12775             return (0);
   12776         case XPATH_OP_NODE:
   12777             if (op->ch1 != -1)
   12778                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12779 	    CHECK_ERROR0;
   12780             if (op->ch2 != -1)
   12781                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12782 	    CHECK_ERROR0;
   12783 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   12784 		ctxt->context->node));
   12785             return (total);
   12786         case XPATH_OP_RESET:
   12787             if (op->ch1 != -1)
   12788                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12789 	    CHECK_ERROR0;
   12790             if (op->ch2 != -1)
   12791                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12792 	    CHECK_ERROR0;
   12793             ctxt->context->node = NULL;
   12794             return (total);
   12795         case XPATH_OP_COLLECT:{
   12796                 if (op->ch1 == -1)
   12797                     return (total);
   12798 
   12799                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12800 		CHECK_ERROR0;
   12801 
   12802                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
   12803                 return (total);
   12804             }
   12805         case XPATH_OP_VALUE:
   12806             valuePush(ctxt,
   12807                       xmlXPathCacheObjectCopy(ctxt->context,
   12808 			(xmlXPathObjectPtr) op->value4));
   12809             return (0);
   12810         case XPATH_OP_SORT:
   12811             if (op->ch1 != -1)
   12812                 total +=
   12813                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
   12814                                             first);
   12815 	    CHECK_ERROR0;
   12816             if ((ctxt->value != NULL)
   12817                 && (ctxt->value->type == XPATH_NODESET)
   12818                 && (ctxt->value->nodesetval != NULL)
   12819 		&& (ctxt->value->nodesetval->nodeNr > 1))
   12820                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12821             return (total);
   12822 #ifdef XP_OPTIMIZED_FILTER_FIRST
   12823 	case XPATH_OP_FILTER:
   12824                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
   12825             return (total);
   12826 #endif
   12827         default:
   12828             return (xmlXPathCompOpEval(ctxt, op));
   12829     }
   12830 }
   12831 
   12832 /**
   12833  * xmlXPathCompOpEvalLast:
   12834  * @ctxt:  the XPath parser context with the compiled expression
   12835  * @op:  an XPath compiled operation
   12836  * @last:  the last elem found so far
   12837  *
   12838  * Evaluate the Precompiled XPath operation searching only the last
   12839  * element in document order
   12840  *
   12841  * Returns the number of nodes traversed
   12842  */
   12843 static int
   12844 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
   12845                        xmlNodePtr * last)
   12846 {
   12847     int total = 0, cur;
   12848     xmlXPathCompExprPtr comp;
   12849     xmlXPathObjectPtr arg1, arg2;
   12850     xmlNodePtr bak;
   12851     xmlDocPtr bakd;
   12852     int pp;
   12853     int cs;
   12854 
   12855     CHECK_ERROR0;
   12856     comp = ctxt->comp;
   12857     switch (op->op) {
   12858         case XPATH_OP_END:
   12859             return (0);
   12860         case XPATH_OP_UNION:
   12861 	    bakd = ctxt->context->doc;
   12862 	    bak = ctxt->context->node;
   12863 	    pp = ctxt->context->proximityPosition;
   12864 	    cs = ctxt->context->contextSize;
   12865             total =
   12866                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
   12867 	    CHECK_ERROR0;
   12868             if ((ctxt->value != NULL)
   12869                 && (ctxt->value->type == XPATH_NODESET)
   12870                 && (ctxt->value->nodesetval != NULL)
   12871                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
   12872                 /*
   12873                  * limit tree traversing to first node in the result
   12874                  */
   12875 		if (ctxt->value->nodesetval->nodeNr > 1)
   12876 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12877                 *last =
   12878                     ctxt->value->nodesetval->nodeTab[ctxt->value->
   12879                                                      nodesetval->nodeNr -
   12880                                                      1];
   12881             }
   12882 	    ctxt->context->doc = bakd;
   12883 	    ctxt->context->node = bak;
   12884 	    ctxt->context->proximityPosition = pp;
   12885 	    ctxt->context->contextSize = cs;
   12886             cur =
   12887                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
   12888 	    CHECK_ERROR0;
   12889             if ((ctxt->value != NULL)
   12890                 && (ctxt->value->type == XPATH_NODESET)
   12891                 && (ctxt->value->nodesetval != NULL)
   12892                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
   12893             }
   12894             CHECK_TYPE0(XPATH_NODESET);
   12895             arg2 = valuePop(ctxt);
   12896 
   12897             CHECK_TYPE0(XPATH_NODESET);
   12898             arg1 = valuePop(ctxt);
   12899 
   12900             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   12901                                                     arg2->nodesetval);
   12902             valuePush(ctxt, arg1);
   12903 	    xmlXPathReleaseObject(ctxt->context, arg2);
   12904             /* optimizer */
   12905 	    if (total > cur)
   12906 		xmlXPathCompSwap(op);
   12907             return (total + cur);
   12908         case XPATH_OP_ROOT:
   12909             xmlXPathRoot(ctxt);
   12910             return (0);
   12911         case XPATH_OP_NODE:
   12912             if (op->ch1 != -1)
   12913                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12914 	    CHECK_ERROR0;
   12915             if (op->ch2 != -1)
   12916                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12917 	    CHECK_ERROR0;
   12918 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   12919 		ctxt->context->node));
   12920             return (total);
   12921         case XPATH_OP_RESET:
   12922             if (op->ch1 != -1)
   12923                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12924 	    CHECK_ERROR0;
   12925             if (op->ch2 != -1)
   12926                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12927 	    CHECK_ERROR0;
   12928             ctxt->context->node = NULL;
   12929             return (total);
   12930         case XPATH_OP_COLLECT:{
   12931                 if (op->ch1 == -1)
   12932                     return (0);
   12933 
   12934                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12935 		CHECK_ERROR0;
   12936 
   12937                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
   12938                 return (total);
   12939             }
   12940         case XPATH_OP_VALUE:
   12941             valuePush(ctxt,
   12942                       xmlXPathCacheObjectCopy(ctxt->context,
   12943 			(xmlXPathObjectPtr) op->value4));
   12944             return (0);
   12945         case XPATH_OP_SORT:
   12946             if (op->ch1 != -1)
   12947                 total +=
   12948                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
   12949                                            last);
   12950 	    CHECK_ERROR0;
   12951             if ((ctxt->value != NULL)
   12952                 && (ctxt->value->type == XPATH_NODESET)
   12953                 && (ctxt->value->nodesetval != NULL)
   12954 		&& (ctxt->value->nodesetval->nodeNr > 1))
   12955                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12956             return (total);
   12957         default:
   12958             return (xmlXPathCompOpEval(ctxt, op));
   12959     }
   12960 }
   12961 
   12962 #ifdef XP_OPTIMIZED_FILTER_FIRST
   12963 static int
   12964 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
   12965 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
   12966 {
   12967     int total = 0;
   12968     xmlXPathCompExprPtr comp;
   12969     xmlXPathObjectPtr res;
   12970     xmlXPathObjectPtr obj;
   12971     xmlNodeSetPtr oldset;
   12972     xmlNodePtr oldnode;
   12973     xmlDocPtr oldDoc;
   12974     int i;
   12975 
   12976     CHECK_ERROR0;
   12977     comp = ctxt->comp;
   12978     /*
   12979     * Optimization for ()[last()] selection i.e. the last elem
   12980     */
   12981     if ((op->ch1 != -1) && (op->ch2 != -1) &&
   12982 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   12983 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
   12984 	int f = comp->steps[op->ch2].ch1;
   12985 
   12986 	if ((f != -1) &&
   12987 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
   12988 	    (comp->steps[f].value5 == NULL) &&
   12989 	    (comp->steps[f].value == 0) &&
   12990 	    (comp->steps[f].value4 != NULL) &&
   12991 	    (xmlStrEqual
   12992 	    (comp->steps[f].value4, BAD_CAST "last"))) {
   12993 	    xmlNodePtr last = NULL;
   12994 
   12995 	    total +=
   12996 		xmlXPathCompOpEvalLast(ctxt,
   12997 		    &comp->steps[op->ch1],
   12998 		    &last);
   12999 	    CHECK_ERROR0;
   13000 	    /*
   13001 	    * The nodeset should be in document order,
   13002 	    * Keep only the last value
   13003 	    */
   13004 	    if ((ctxt->value != NULL) &&
   13005 		(ctxt->value->type == XPATH_NODESET) &&
   13006 		(ctxt->value->nodesetval != NULL) &&
   13007 		(ctxt->value->nodesetval->nodeTab != NULL) &&
   13008 		(ctxt->value->nodesetval->nodeNr > 1)) {
   13009 		ctxt->value->nodesetval->nodeTab[0] =
   13010 		    ctxt->value->nodesetval->nodeTab[ctxt->
   13011 		    value->
   13012 		    nodesetval->
   13013 		    nodeNr -
   13014 		    1];
   13015 		ctxt->value->nodesetval->nodeNr = 1;
   13016 		*first = *(ctxt->value->nodesetval->nodeTab);
   13017 	    }
   13018 	    return (total);
   13019 	}
   13020     }
   13021 
   13022     if (op->ch1 != -1)
   13023 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13024     CHECK_ERROR0;
   13025     if (op->ch2 == -1)
   13026 	return (total);
   13027     if (ctxt->value == NULL)
   13028 	return (total);
   13029 
   13030 #ifdef LIBXML_XPTR_ENABLED
   13031     oldnode = ctxt->context->node;
   13032     /*
   13033     * Hum are we filtering the result of an XPointer expression
   13034     */
   13035     if (ctxt->value->type == XPATH_LOCATIONSET) {
   13036 	xmlXPathObjectPtr tmp = NULL;
   13037 	xmlLocationSetPtr newlocset = NULL;
   13038 	xmlLocationSetPtr oldlocset;
   13039 
   13040 	/*
   13041 	* Extract the old locset, and then evaluate the result of the
   13042 	* expression for all the element in the locset. use it to grow
   13043 	* up a new locset.
   13044 	*/
   13045 	CHECK_TYPE0(XPATH_LOCATIONSET);
   13046 	obj = valuePop(ctxt);
   13047 	oldlocset = obj->user;
   13048 	ctxt->context->node = NULL;
   13049 
   13050 	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   13051 	    ctxt->context->contextSize = 0;
   13052 	    ctxt->context->proximityPosition = 0;
   13053 	    if (op->ch2 != -1)
   13054 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13055 	    res = valuePop(ctxt);
   13056 	    if (res != NULL) {
   13057 		xmlXPathReleaseObject(ctxt->context, res);
   13058 	    }
   13059 	    valuePush(ctxt, obj);
   13060 	    CHECK_ERROR0;
   13061 	    return (total);
   13062 	}
   13063 	newlocset = xmlXPtrLocationSetCreate(NULL);
   13064 
   13065 	for (i = 0; i < oldlocset->locNr; i++) {
   13066 	    /*
   13067 	    * Run the evaluation with a node list made of a
   13068 	    * single item in the nodelocset.
   13069 	    */
   13070 	    ctxt->context->node = oldlocset->locTab[i]->user;
   13071 	    ctxt->context->contextSize = oldlocset->locNr;
   13072 	    ctxt->context->proximityPosition = i + 1;
   13073 	    if (tmp == NULL) {
   13074 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13075 		    ctxt->context->node);
   13076 	    } else {
   13077 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13078 		                             ctxt->context->node) < 0) {
   13079 		    ctxt->error = XPATH_MEMORY_ERROR;
   13080 		}
   13081 	    }
   13082 	    valuePush(ctxt, tmp);
   13083 	    if (op->ch2 != -1)
   13084 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13085 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   13086 		xmlXPathFreeObject(obj);
   13087 		return(0);
   13088 	    }
   13089 	    /*
   13090 	    * The result of the evaluation need to be tested to
   13091 	    * decided whether the filter succeeded or not
   13092 	    */
   13093 	    res = valuePop(ctxt);
   13094 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13095 		xmlXPtrLocationSetAdd(newlocset,
   13096 		    xmlXPathCacheObjectCopy(ctxt->context,
   13097 			oldlocset->locTab[i]));
   13098 	    }
   13099 	    /*
   13100 	    * Cleanup
   13101 	    */
   13102 	    if (res != NULL) {
   13103 		xmlXPathReleaseObject(ctxt->context, res);
   13104 	    }
   13105 	    if (ctxt->value == tmp) {
   13106 		valuePop(ctxt);
   13107 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13108 		/*
   13109 		* REVISIT TODO: Don't create a temporary nodeset
   13110 		* for everly iteration.
   13111 		*/
   13112 		/* OLD: xmlXPathFreeObject(res); */
   13113 	    } else
   13114 		tmp = NULL;
   13115 	    ctxt->context->node = NULL;
   13116 	    /*
   13117 	    * Only put the first node in the result, then leave.
   13118 	    */
   13119 	    if (newlocset->locNr > 0) {
   13120 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
   13121 		break;
   13122 	    }
   13123 	}
   13124 	if (tmp != NULL) {
   13125 	    xmlXPathReleaseObject(ctxt->context, tmp);
   13126 	}
   13127 	/*
   13128 	* The result is used as the new evaluation locset.
   13129 	*/
   13130 	xmlXPathReleaseObject(ctxt->context, obj);
   13131 	ctxt->context->node = NULL;
   13132 	ctxt->context->contextSize = -1;
   13133 	ctxt->context->proximityPosition = -1;
   13134 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   13135 	ctxt->context->node = oldnode;
   13136 	return (total);
   13137     }
   13138 #endif /* LIBXML_XPTR_ENABLED */
   13139 
   13140     /*
   13141     * Extract the old set, and then evaluate the result of the
   13142     * expression for all the element in the set. use it to grow
   13143     * up a new set.
   13144     */
   13145     CHECK_TYPE0(XPATH_NODESET);
   13146     obj = valuePop(ctxt);
   13147     oldset = obj->nodesetval;
   13148 
   13149     oldnode = ctxt->context->node;
   13150     oldDoc = ctxt->context->doc;
   13151     ctxt->context->node = NULL;
   13152 
   13153     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
   13154 	ctxt->context->contextSize = 0;
   13155 	ctxt->context->proximityPosition = 0;
   13156 	/* QUESTION TODO: Why was this code commented out?
   13157 	    if (op->ch2 != -1)
   13158 		total +=
   13159 		    xmlXPathCompOpEval(ctxt,
   13160 			&comp->steps[op->ch2]);
   13161 	    CHECK_ERROR0;
   13162 	    res = valuePop(ctxt);
   13163 	    if (res != NULL)
   13164 		xmlXPathFreeObject(res);
   13165 	*/
   13166 	valuePush(ctxt, obj);
   13167 	ctxt->context->node = oldnode;
   13168 	CHECK_ERROR0;
   13169     } else {
   13170 	xmlNodeSetPtr newset;
   13171 	xmlXPathObjectPtr tmp = NULL;
   13172 	/*
   13173 	* Initialize the new set.
   13174 	* Also set the xpath document in case things like
   13175 	* key() evaluation are attempted on the predicate
   13176 	*/
   13177 	newset = xmlXPathNodeSetCreate(NULL);
   13178         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
   13179 
   13180 	for (i = 0; i < oldset->nodeNr; i++) {
   13181 	    /*
   13182 	    * Run the evaluation with a node list made of
   13183 	    * a single item in the nodeset.
   13184 	    */
   13185 	    ctxt->context->node = oldset->nodeTab[i];
   13186 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
   13187 		(oldset->nodeTab[i]->doc != NULL))
   13188 		ctxt->context->doc = oldset->nodeTab[i]->doc;
   13189 	    if (tmp == NULL) {
   13190 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13191 		    ctxt->context->node);
   13192 	    } else {
   13193 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13194 		                             ctxt->context->node) < 0) {
   13195 		    ctxt->error = XPATH_MEMORY_ERROR;
   13196 		}
   13197 	    }
   13198 	    valuePush(ctxt, tmp);
   13199 	    ctxt->context->contextSize = oldset->nodeNr;
   13200 	    ctxt->context->proximityPosition = i + 1;
   13201 	    if (op->ch2 != -1)
   13202 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13203 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   13204 		xmlXPathFreeNodeSet(newset);
   13205 		xmlXPathFreeObject(obj);
   13206 		return(0);
   13207 	    }
   13208 	    /*
   13209 	    * The result of the evaluation needs to be tested to
   13210 	    * decide whether the filter succeeded or not
   13211 	    */
   13212 	    res = valuePop(ctxt);
   13213 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13214 		if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
   13215 		    ctxt->error = XPATH_MEMORY_ERROR;
   13216 	    }
   13217 	    /*
   13218 	    * Cleanup
   13219 	    */
   13220 	    if (res != NULL) {
   13221 		xmlXPathReleaseObject(ctxt->context, res);
   13222 	    }
   13223 	    if (ctxt->value == tmp) {
   13224 		valuePop(ctxt);
   13225 		/*
   13226 		* Don't free the temporary nodeset
   13227 		* in order to avoid massive recreation inside this
   13228 		* loop.
   13229 		*/
   13230 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13231 	    } else
   13232 		tmp = NULL;
   13233 	    ctxt->context->node = NULL;
   13234 	    /*
   13235 	    * Only put the first node in the result, then leave.
   13236 	    */
   13237 	    if (newset->nodeNr > 0) {
   13238 		*first = *(newset->nodeTab);
   13239 		break;
   13240 	    }
   13241 	}
   13242 	if (tmp != NULL) {
   13243 	    xmlXPathReleaseObject(ctxt->context, tmp);
   13244 	}
   13245 	/*
   13246 	* The result is used as the new evaluation set.
   13247 	*/
   13248 	xmlXPathReleaseObject(ctxt->context, obj);
   13249 	ctxt->context->node = NULL;
   13250 	ctxt->context->contextSize = -1;
   13251 	ctxt->context->proximityPosition = -1;
   13252 	/* may want to move this past the '}' later */
   13253 	ctxt->context->doc = oldDoc;
   13254 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
   13255     }
   13256     ctxt->context->node = oldnode;
   13257     return(total);
   13258 }
   13259 #endif /* XP_OPTIMIZED_FILTER_FIRST */
   13260 
   13261 /**
   13262  * xmlXPathCompOpEval:
   13263  * @ctxt:  the XPath parser context with the compiled expression
   13264  * @op:  an XPath compiled operation
   13265  *
   13266  * Evaluate the Precompiled XPath operation
   13267  * Returns the number of nodes traversed
   13268  */
   13269 static int
   13270 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
   13271 {
   13272     int total = 0;
   13273     int equal, ret;
   13274     xmlXPathCompExprPtr comp;
   13275     xmlXPathObjectPtr arg1, arg2;
   13276     xmlNodePtr bak;
   13277     xmlDocPtr bakd;
   13278     int pp;
   13279     int cs;
   13280 
   13281     CHECK_ERROR0;
   13282     comp = ctxt->comp;
   13283     switch (op->op) {
   13284         case XPATH_OP_END:
   13285             return (0);
   13286         case XPATH_OP_AND:
   13287 	    bakd = ctxt->context->doc;
   13288 	    bak = ctxt->context->node;
   13289 	    pp = ctxt->context->proximityPosition;
   13290 	    cs = ctxt->context->contextSize;
   13291             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13292 	    CHECK_ERROR0;
   13293             xmlXPathBooleanFunction(ctxt, 1);
   13294             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
   13295                 return (total);
   13296             arg2 = valuePop(ctxt);
   13297 	    ctxt->context->doc = bakd;
   13298 	    ctxt->context->node = bak;
   13299 	    ctxt->context->proximityPosition = pp;
   13300 	    ctxt->context->contextSize = cs;
   13301             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13302 	    if (ctxt->error) {
   13303 		xmlXPathFreeObject(arg2);
   13304 		return(0);
   13305 	    }
   13306             xmlXPathBooleanFunction(ctxt, 1);
   13307             arg1 = valuePop(ctxt);
   13308             arg1->boolval &= arg2->boolval;
   13309             valuePush(ctxt, arg1);
   13310 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13311             return (total);
   13312         case XPATH_OP_OR:
   13313 	    bakd = ctxt->context->doc;
   13314 	    bak = ctxt->context->node;
   13315 	    pp = ctxt->context->proximityPosition;
   13316 	    cs = ctxt->context->contextSize;
   13317             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13318 	    CHECK_ERROR0;
   13319             xmlXPathBooleanFunction(ctxt, 1);
   13320             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
   13321                 return (total);
   13322             arg2 = valuePop(ctxt);
   13323 	    ctxt->context->doc = bakd;
   13324 	    ctxt->context->node = bak;
   13325 	    ctxt->context->proximityPosition = pp;
   13326 	    ctxt->context->contextSize = cs;
   13327             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13328 	    if (ctxt->error) {
   13329 		xmlXPathFreeObject(arg2);
   13330 		return(0);
   13331 	    }
   13332             xmlXPathBooleanFunction(ctxt, 1);
   13333             arg1 = valuePop(ctxt);
   13334             arg1->boolval |= arg2->boolval;
   13335             valuePush(ctxt, arg1);
   13336 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13337             return (total);
   13338         case XPATH_OP_EQUAL:
   13339 	    bakd = ctxt->context->doc;
   13340 	    bak = ctxt->context->node;
   13341 	    pp = ctxt->context->proximityPosition;
   13342 	    cs = ctxt->context->contextSize;
   13343             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13344 	    CHECK_ERROR0;
   13345 	    ctxt->context->doc = bakd;
   13346 	    ctxt->context->node = bak;
   13347 	    ctxt->context->proximityPosition = pp;
   13348 	    ctxt->context->contextSize = cs;
   13349             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13350 	    CHECK_ERROR0;
   13351 	    if (op->value)
   13352 		equal = xmlXPathEqualValues(ctxt);
   13353 	    else
   13354 		equal = xmlXPathNotEqualValues(ctxt);
   13355 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
   13356             return (total);
   13357         case XPATH_OP_CMP:
   13358 	    bakd = ctxt->context->doc;
   13359 	    bak = ctxt->context->node;
   13360 	    pp = ctxt->context->proximityPosition;
   13361 	    cs = ctxt->context->contextSize;
   13362             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13363 	    CHECK_ERROR0;
   13364 	    ctxt->context->doc = bakd;
   13365 	    ctxt->context->node = bak;
   13366 	    ctxt->context->proximityPosition = pp;
   13367 	    ctxt->context->contextSize = cs;
   13368             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13369 	    CHECK_ERROR0;
   13370             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
   13371 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
   13372             return (total);
   13373         case XPATH_OP_PLUS:
   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             if (op->ch2 != -1) {
   13381 		ctxt->context->doc = bakd;
   13382 		ctxt->context->node = bak;
   13383 		ctxt->context->proximityPosition = pp;
   13384 		ctxt->context->contextSize = cs;
   13385                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13386 	    }
   13387 	    CHECK_ERROR0;
   13388             if (op->value == 0)
   13389                 xmlXPathSubValues(ctxt);
   13390             else if (op->value == 1)
   13391                 xmlXPathAddValues(ctxt);
   13392             else if (op->value == 2)
   13393                 xmlXPathValueFlipSign(ctxt);
   13394             else if (op->value == 3) {
   13395                 CAST_TO_NUMBER;
   13396                 CHECK_TYPE0(XPATH_NUMBER);
   13397             }
   13398             return (total);
   13399         case XPATH_OP_MULT:
   13400 	    bakd = ctxt->context->doc;
   13401 	    bak = ctxt->context->node;
   13402 	    pp = ctxt->context->proximityPosition;
   13403 	    cs = ctxt->context->contextSize;
   13404             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13405 	    CHECK_ERROR0;
   13406 	    ctxt->context->doc = bakd;
   13407 	    ctxt->context->node = bak;
   13408 	    ctxt->context->proximityPosition = pp;
   13409 	    ctxt->context->contextSize = cs;
   13410             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13411 	    CHECK_ERROR0;
   13412             if (op->value == 0)
   13413                 xmlXPathMultValues(ctxt);
   13414             else if (op->value == 1)
   13415                 xmlXPathDivValues(ctxt);
   13416             else if (op->value == 2)
   13417                 xmlXPathModValues(ctxt);
   13418             return (total);
   13419         case XPATH_OP_UNION:
   13420 	    bakd = ctxt->context->doc;
   13421 	    bak = ctxt->context->node;
   13422 	    pp = ctxt->context->proximityPosition;
   13423 	    cs = ctxt->context->contextSize;
   13424             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13425 	    CHECK_ERROR0;
   13426 	    ctxt->context->doc = bakd;
   13427 	    ctxt->context->node = bak;
   13428 	    ctxt->context->proximityPosition = pp;
   13429 	    ctxt->context->contextSize = cs;
   13430             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13431 	    CHECK_ERROR0;
   13432             CHECK_TYPE0(XPATH_NODESET);
   13433             arg2 = valuePop(ctxt);
   13434 
   13435             CHECK_TYPE0(XPATH_NODESET);
   13436             arg1 = valuePop(ctxt);
   13437 
   13438 	    if ((arg1->nodesetval == NULL) ||
   13439 		((arg2->nodesetval != NULL) &&
   13440 		 (arg2->nodesetval->nodeNr != 0)))
   13441 	    {
   13442 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   13443 							arg2->nodesetval);
   13444 	    }
   13445 
   13446             valuePush(ctxt, arg1);
   13447 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13448             return (total);
   13449         case XPATH_OP_ROOT:
   13450             xmlXPathRoot(ctxt);
   13451             return (total);
   13452         case XPATH_OP_NODE:
   13453             if (op->ch1 != -1)
   13454                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13455 	    CHECK_ERROR0;
   13456             if (op->ch2 != -1)
   13457                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13458 	    CHECK_ERROR0;
   13459 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   13460 		ctxt->context->node));
   13461             return (total);
   13462         case XPATH_OP_RESET:
   13463             if (op->ch1 != -1)
   13464                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13465 	    CHECK_ERROR0;
   13466             if (op->ch2 != -1)
   13467                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13468 	    CHECK_ERROR0;
   13469             ctxt->context->node = NULL;
   13470             return (total);
   13471         case XPATH_OP_COLLECT:{
   13472                 if (op->ch1 == -1)
   13473                     return (total);
   13474 
   13475                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13476 		CHECK_ERROR0;
   13477 
   13478                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
   13479                 return (total);
   13480             }
   13481         case XPATH_OP_VALUE:
   13482             valuePush(ctxt,
   13483                       xmlXPathCacheObjectCopy(ctxt->context,
   13484 			(xmlXPathObjectPtr) op->value4));
   13485             return (total);
   13486         case XPATH_OP_VARIABLE:{
   13487 		xmlXPathObjectPtr val;
   13488 
   13489                 if (op->ch1 != -1)
   13490                     total +=
   13491                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13492                 if (op->value5 == NULL) {
   13493 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
   13494 		    if (val == NULL) {
   13495 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
   13496 			return(0);
   13497 		    }
   13498                     valuePush(ctxt, val);
   13499 		} else {
   13500                     const xmlChar *URI;
   13501 
   13502                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
   13503                     if (URI == NULL) {
   13504                         xmlGenericError(xmlGenericErrorContext,
   13505             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
   13506                                     (char *) op->value4, (char *)op->value5);
   13507                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
   13508                         return (total);
   13509                     }
   13510 		    val = xmlXPathVariableLookupNS(ctxt->context,
   13511                                                        op->value4, URI);
   13512 		    if (val == NULL) {
   13513 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
   13514 			return(0);
   13515 		    }
   13516                     valuePush(ctxt, val);
   13517                 }
   13518                 return (total);
   13519             }
   13520         case XPATH_OP_FUNCTION:{
   13521                 xmlXPathFunction func;
   13522                 const xmlChar *oldFunc, *oldFuncURI;
   13523 		int i;
   13524                 int frame;
   13525 
   13526                 frame = xmlXPathSetFrame(ctxt);
   13527                 if (op->ch1 != -1) {
   13528                     total +=
   13529                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13530                     if (ctxt->error != XPATH_EXPRESSION_OK) {
   13531                         xmlXPathPopFrame(ctxt, frame);
   13532                         return (total);
   13533                     }
   13534                 }
   13535 		if (ctxt->valueNr < ctxt->valueFrame + op->value) {
   13536 		    xmlGenericError(xmlGenericErrorContext,
   13537 			    "xmlXPathCompOpEval: parameter error\n");
   13538 		    ctxt->error = XPATH_INVALID_OPERAND;
   13539                     xmlXPathPopFrame(ctxt, frame);
   13540 		    return (total);
   13541 		}
   13542 		for (i = 0; i < op->value; i++) {
   13543 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
   13544 			xmlGenericError(xmlGenericErrorContext,
   13545 				"xmlXPathCompOpEval: parameter error\n");
   13546 			ctxt->error = XPATH_INVALID_OPERAND;
   13547                         xmlXPathPopFrame(ctxt, frame);
   13548 			return (total);
   13549 		    }
   13550                 }
   13551                 if (op->cache != NULL)
   13552                     XML_CAST_FPTR(func) = op->cache;
   13553                 else {
   13554                     const xmlChar *URI = NULL;
   13555 
   13556                     if (op->value5 == NULL)
   13557                         func =
   13558                             xmlXPathFunctionLookup(ctxt->context,
   13559                                                    op->value4);
   13560                     else {
   13561                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
   13562                         if (URI == NULL) {
   13563                             xmlGenericError(xmlGenericErrorContext,
   13564             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
   13565                                     (char *)op->value4, (char *)op->value5);
   13566                             xmlXPathPopFrame(ctxt, frame);
   13567                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
   13568                             return (total);
   13569                         }
   13570                         func = xmlXPathFunctionLookupNS(ctxt->context,
   13571                                                         op->value4, URI);
   13572                     }
   13573                     if (func == NULL) {
   13574                         xmlGenericError(xmlGenericErrorContext,
   13575                                 "xmlXPathCompOpEval: function %s not found\n",
   13576                                         (char *)op->value4);
   13577                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
   13578                     }
   13579                     op->cache = XML_CAST_FPTR(func);
   13580                     op->cacheURI = (void *) URI;
   13581                 }
   13582                 oldFunc = ctxt->context->function;
   13583                 oldFuncURI = ctxt->context->functionURI;
   13584                 ctxt->context->function = op->value4;
   13585                 ctxt->context->functionURI = op->cacheURI;
   13586                 func(ctxt, op->value);
   13587                 ctxt->context->function = oldFunc;
   13588                 ctxt->context->functionURI = oldFuncURI;
   13589                 xmlXPathPopFrame(ctxt, frame);
   13590                 return (total);
   13591             }
   13592         case XPATH_OP_ARG:
   13593 	    bakd = ctxt->context->doc;
   13594 	    bak = ctxt->context->node;
   13595 	    pp = ctxt->context->proximityPosition;
   13596 	    cs = ctxt->context->contextSize;
   13597             if (op->ch1 != -1) {
   13598                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13599                 ctxt->context->contextSize = cs;
   13600                 ctxt->context->proximityPosition = pp;
   13601                 ctxt->context->node = bak;
   13602                 ctxt->context->doc = bakd;
   13603 	        CHECK_ERROR0;
   13604             }
   13605             if (op->ch2 != -1) {
   13606                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13607                 ctxt->context->contextSize = cs;
   13608                 ctxt->context->proximityPosition = pp;
   13609                 ctxt->context->node = bak;
   13610                 ctxt->context->doc = bakd;
   13611 	        CHECK_ERROR0;
   13612 	    }
   13613             return (total);
   13614         case XPATH_OP_PREDICATE:
   13615         case XPATH_OP_FILTER:{
   13616                 xmlXPathObjectPtr res;
   13617                 xmlXPathObjectPtr obj, tmp;
   13618                 xmlNodeSetPtr newset = NULL;
   13619                 xmlNodeSetPtr oldset;
   13620                 xmlNodePtr oldnode;
   13621 		xmlDocPtr oldDoc;
   13622                 int i;
   13623 
   13624                 /*
   13625                  * Optimization for ()[1] selection i.e. the first elem
   13626                  */
   13627                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
   13628 #ifdef XP_OPTIMIZED_FILTER_FIRST
   13629 		    /*
   13630 		    * FILTER TODO: Can we assume that the inner processing
   13631 		    *  will result in an ordered list if we have an
   13632 		    *  XPATH_OP_FILTER?
   13633 		    *  What about an additional field or flag on
   13634 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
   13635 		    *  to assume anything, so it would be more robust and
   13636 		    *  easier to optimize.
   13637 		    */
   13638                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
   13639 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
   13640 #else
   13641 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   13642 #endif
   13643                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
   13644                     xmlXPathObjectPtr val;
   13645 
   13646                     val = comp->steps[op->ch2].value4;
   13647                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
   13648                         (val->floatval == 1.0)) {
   13649                         xmlNodePtr first = NULL;
   13650 
   13651                         total +=
   13652                             xmlXPathCompOpEvalFirst(ctxt,
   13653                                                     &comp->steps[op->ch1],
   13654                                                     &first);
   13655 			CHECK_ERROR0;
   13656                         /*
   13657                          * The nodeset should be in document order,
   13658                          * Keep only the first value
   13659                          */
   13660                         if ((ctxt->value != NULL) &&
   13661                             (ctxt->value->type == XPATH_NODESET) &&
   13662                             (ctxt->value->nodesetval != NULL) &&
   13663                             (ctxt->value->nodesetval->nodeNr > 1))
   13664                             ctxt->value->nodesetval->nodeNr = 1;
   13665                         return (total);
   13666                     }
   13667                 }
   13668                 /*
   13669                  * Optimization for ()[last()] selection i.e. the last elem
   13670                  */
   13671                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
   13672                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   13673                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
   13674                     int f = comp->steps[op->ch2].ch1;
   13675 
   13676                     if ((f != -1) &&
   13677                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
   13678                         (comp->steps[f].value5 == NULL) &&
   13679                         (comp->steps[f].value == 0) &&
   13680                         (comp->steps[f].value4 != NULL) &&
   13681                         (xmlStrEqual
   13682                          (comp->steps[f].value4, BAD_CAST "last"))) {
   13683                         xmlNodePtr last = NULL;
   13684 
   13685                         total +=
   13686                             xmlXPathCompOpEvalLast(ctxt,
   13687                                                    &comp->steps[op->ch1],
   13688                                                    &last);
   13689 			CHECK_ERROR0;
   13690                         /*
   13691                          * The nodeset should be in document order,
   13692                          * Keep only the last value
   13693                          */
   13694                         if ((ctxt->value != NULL) &&
   13695                             (ctxt->value->type == XPATH_NODESET) &&
   13696                             (ctxt->value->nodesetval != NULL) &&
   13697                             (ctxt->value->nodesetval->nodeTab != NULL) &&
   13698                             (ctxt->value->nodesetval->nodeNr > 1)) {
   13699                             ctxt->value->nodesetval->nodeTab[0] =
   13700                                 ctxt->value->nodesetval->nodeTab[ctxt->
   13701                                                                  value->
   13702                                                                  nodesetval->
   13703                                                                  nodeNr -
   13704                                                                  1];
   13705                             ctxt->value->nodesetval->nodeNr = 1;
   13706                         }
   13707                         return (total);
   13708                     }
   13709                 }
   13710 		/*
   13711 		* Process inner predicates first.
   13712 		* Example "index[parent::book][1]":
   13713 		* ...
   13714 		*   PREDICATE   <-- we are here "[1]"
   13715 		*     PREDICATE <-- process "[parent::book]" first
   13716 		*       SORT
   13717 		*         COLLECT  'parent' 'name' 'node' book
   13718 		*           NODE
   13719 		*     ELEM Object is a number : 1
   13720 		*/
   13721                 if (op->ch1 != -1)
   13722                     total +=
   13723                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13724 		CHECK_ERROR0;
   13725                 if (op->ch2 == -1)
   13726                     return (total);
   13727                 if (ctxt->value == NULL)
   13728                     return (total);
   13729 
   13730                 oldnode = ctxt->context->node;
   13731 
   13732 #ifdef LIBXML_XPTR_ENABLED
   13733                 /*
   13734                  * Hum are we filtering the result of an XPointer expression
   13735                  */
   13736                 if (ctxt->value->type == XPATH_LOCATIONSET) {
   13737                     xmlLocationSetPtr newlocset = NULL;
   13738                     xmlLocationSetPtr oldlocset;
   13739 
   13740                     /*
   13741                      * Extract the old locset, and then evaluate the result of the
   13742                      * expression for all the element in the locset. use it to grow
   13743                      * up a new locset.
   13744                      */
   13745                     CHECK_TYPE0(XPATH_LOCATIONSET);
   13746                     obj = valuePop(ctxt);
   13747                     oldlocset = obj->user;
   13748                     ctxt->context->node = NULL;
   13749 
   13750                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   13751                         ctxt->context->contextSize = 0;
   13752                         ctxt->context->proximityPosition = 0;
   13753                         if (op->ch2 != -1)
   13754                             total +=
   13755                                 xmlXPathCompOpEval(ctxt,
   13756                                                    &comp->steps[op->ch2]);
   13757                         res = valuePop(ctxt);
   13758                         if (res != NULL) {
   13759 			    xmlXPathReleaseObject(ctxt->context, res);
   13760 			}
   13761                         valuePush(ctxt, obj);
   13762                         CHECK_ERROR0;
   13763                         return (total);
   13764                     }
   13765                     newlocset = xmlXPtrLocationSetCreate(NULL);
   13766 
   13767                     for (i = 0; i < oldlocset->locNr; i++) {
   13768                         /*
   13769                          * Run the evaluation with a node list made of a
   13770                          * single item in the nodelocset.
   13771                          */
   13772                         ctxt->context->node = oldlocset->locTab[i]->user;
   13773                         ctxt->context->contextSize = oldlocset->locNr;
   13774                         ctxt->context->proximityPosition = i + 1;
   13775 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13776 			    ctxt->context->node);
   13777                         valuePush(ctxt, tmp);
   13778 
   13779                         if (op->ch2 != -1)
   13780                             total +=
   13781                                 xmlXPathCompOpEval(ctxt,
   13782                                                    &comp->steps[op->ch2]);
   13783 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13784 			    xmlXPathFreeObject(obj);
   13785 			    return(0);
   13786 			}
   13787 
   13788                         /*
   13789                          * The result of the evaluation need to be tested to
   13790                          * decided whether the filter succeeded or not
   13791                          */
   13792                         res = valuePop(ctxt);
   13793                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13794                             xmlXPtrLocationSetAdd(newlocset,
   13795                                                   xmlXPathObjectCopy
   13796                                                   (oldlocset->locTab[i]));
   13797                         }
   13798 
   13799                         /*
   13800                          * Cleanup
   13801                          */
   13802                         if (res != NULL) {
   13803 			    xmlXPathReleaseObject(ctxt->context, res);
   13804 			}
   13805                         if (ctxt->value == tmp) {
   13806                             res = valuePop(ctxt);
   13807 			    xmlXPathReleaseObject(ctxt->context, res);
   13808                         }
   13809 
   13810                         ctxt->context->node = NULL;
   13811                     }
   13812 
   13813                     /*
   13814                      * The result is used as the new evaluation locset.
   13815                      */
   13816 		    xmlXPathReleaseObject(ctxt->context, obj);
   13817                     ctxt->context->node = NULL;
   13818                     ctxt->context->contextSize = -1;
   13819                     ctxt->context->proximityPosition = -1;
   13820                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   13821                     ctxt->context->node = oldnode;
   13822                     return (total);
   13823                 }
   13824 #endif /* LIBXML_XPTR_ENABLED */
   13825 
   13826                 /*
   13827                  * Extract the old set, and then evaluate the result of the
   13828                  * expression for all the element in the set. use it to grow
   13829                  * up a new set.
   13830                  */
   13831                 CHECK_TYPE0(XPATH_NODESET);
   13832                 obj = valuePop(ctxt);
   13833                 oldset = obj->nodesetval;
   13834 
   13835                 oldnode = ctxt->context->node;
   13836 		oldDoc = ctxt->context->doc;
   13837                 ctxt->context->node = NULL;
   13838 
   13839                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
   13840                     ctxt->context->contextSize = 0;
   13841                     ctxt->context->proximityPosition = 0;
   13842 /*
   13843                     if (op->ch2 != -1)
   13844                         total +=
   13845                             xmlXPathCompOpEval(ctxt,
   13846                                                &comp->steps[op->ch2]);
   13847 		    CHECK_ERROR0;
   13848                     res = valuePop(ctxt);
   13849                     if (res != NULL)
   13850                         xmlXPathFreeObject(res);
   13851 */
   13852                     valuePush(ctxt, obj);
   13853                     ctxt->context->node = oldnode;
   13854                     CHECK_ERROR0;
   13855                 } else {
   13856 		    tmp = NULL;
   13857                     /*
   13858                      * Initialize the new set.
   13859 		     * Also set the xpath document in case things like
   13860 		     * key() evaluation are attempted on the predicate
   13861                      */
   13862                     newset = xmlXPathNodeSetCreate(NULL);
   13863 		    /*
   13864 		    * SPEC XPath 1.0:
   13865 		    *  "For each node in the node-set to be filtered, the
   13866 		    *  PredicateExpr is evaluated with that node as the
   13867 		    *  context node, with the number of nodes in the
   13868 		    *  node-set as the context size, and with the proximity
   13869 		    *  position of the node in the node-set with respect to
   13870 		    *  the axis as the context position;"
   13871 		    * @oldset is the node-set" to be filtered.
   13872 		    *
   13873 		    * SPEC XPath 1.0:
   13874 		    *  "only predicates change the context position and
   13875 		    *  context size (see [2.4 Predicates])."
   13876 		    * Example:
   13877 		    *   node-set  context pos
   13878 		    *    nA         1
   13879 		    *    nB         2
   13880 		    *    nC         3
   13881 		    *   After applying predicate [position() > 1] :
   13882 		    *   node-set  context pos
   13883 		    *    nB         1
   13884 		    *    nC         2
   13885 		    *
   13886 		    * removed the first node in the node-set, then
   13887 		    * the context position of the
   13888 		    */
   13889                     for (i = 0; i < oldset->nodeNr; i++) {
   13890                         /*
   13891                          * Run the evaluation with a node list made of
   13892                          * a single item in the nodeset.
   13893                          */
   13894                         ctxt->context->node = oldset->nodeTab[i];
   13895 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
   13896 			    (oldset->nodeTab[i]->doc != NULL))
   13897 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
   13898 			if (tmp == NULL) {
   13899 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13900 				ctxt->context->node);
   13901 			} else {
   13902 			    if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13903 				               ctxt->context->node) < 0) {
   13904 				ctxt->error = XPATH_MEMORY_ERROR;
   13905 			    }
   13906 			}
   13907                         valuePush(ctxt, tmp);
   13908                         ctxt->context->contextSize = oldset->nodeNr;
   13909                         ctxt->context->proximityPosition = i + 1;
   13910 			/*
   13911 			* Evaluate the predicate against the context node.
   13912 			* Can/should we optimize position() predicates
   13913 			* here (e.g. "[1]")?
   13914 			*/
   13915                         if (op->ch2 != -1)
   13916                             total +=
   13917                                 xmlXPathCompOpEval(ctxt,
   13918                                                    &comp->steps[op->ch2]);
   13919 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13920 			    xmlXPathFreeNodeSet(newset);
   13921 			    xmlXPathFreeObject(obj);
   13922 			    return(0);
   13923 			}
   13924 
   13925                         /*
   13926                          * The result of the evaluation needs to be tested to
   13927                          * decide whether the filter succeeded or not
   13928                          */
   13929 			/*
   13930 			* OPTIMIZE TODO: Can we use
   13931 			* xmlXPathNodeSetAdd*Unique()* instead?
   13932 			*/
   13933                         res = valuePop(ctxt);
   13934                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13935                             if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
   13936 			        < 0)
   13937 				ctxt->error = XPATH_MEMORY_ERROR;
   13938                         }
   13939 
   13940                         /*
   13941                          * Cleanup
   13942                          */
   13943                         if (res != NULL) {
   13944 			    xmlXPathReleaseObject(ctxt->context, res);
   13945 			}
   13946                         if (ctxt->value == tmp) {
   13947                             valuePop(ctxt);
   13948 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13949 			    /*
   13950 			    * Don't free the temporary nodeset
   13951 			    * in order to avoid massive recreation inside this
   13952 			    * loop.
   13953 			    */
   13954                         } else
   13955 			    tmp = NULL;
   13956                         ctxt->context->node = NULL;
   13957                     }
   13958 		    if (tmp != NULL)
   13959 			xmlXPathReleaseObject(ctxt->context, tmp);
   13960                     /*
   13961                      * The result is used as the new evaluation set.
   13962                      */
   13963 		    xmlXPathReleaseObject(ctxt->context, obj);
   13964                     ctxt->context->node = NULL;
   13965                     ctxt->context->contextSize = -1;
   13966                     ctxt->context->proximityPosition = -1;
   13967 		    /* may want to move this past the '}' later */
   13968 		    ctxt->context->doc = oldDoc;
   13969 		    valuePush(ctxt,
   13970 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
   13971                 }
   13972                 ctxt->context->node = oldnode;
   13973                 return (total);
   13974             }
   13975         case XPATH_OP_SORT:
   13976             if (op->ch1 != -1)
   13977                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13978 	    CHECK_ERROR0;
   13979             if ((ctxt->value != NULL) &&
   13980                 (ctxt->value->type == XPATH_NODESET) &&
   13981                 (ctxt->value->nodesetval != NULL) &&
   13982 		(ctxt->value->nodesetval->nodeNr > 1))
   13983 	    {
   13984                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   13985 	    }
   13986             return (total);
   13987 #ifdef LIBXML_XPTR_ENABLED
   13988         case XPATH_OP_RANGETO:{
   13989                 xmlXPathObjectPtr range;
   13990                 xmlXPathObjectPtr res, obj;
   13991                 xmlXPathObjectPtr tmp;
   13992                 xmlLocationSetPtr newlocset = NULL;
   13993 		    xmlLocationSetPtr oldlocset;
   13994                 xmlNodeSetPtr oldset;
   13995                 int i, j;
   13996 
   13997                 if (op->ch1 != -1)
   13998                     total +=
   13999                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   14000                 if (op->ch2 == -1)
   14001                     return (total);
   14002 
   14003                 if (ctxt->value->type == XPATH_LOCATIONSET) {
   14004                     /*
   14005                      * Extract the old locset, and then evaluate the result of the
   14006                      * expression for all the element in the locset. use it to grow
   14007                      * up a new locset.
   14008                      */
   14009                     CHECK_TYPE0(XPATH_LOCATIONSET);
   14010                     obj = valuePop(ctxt);
   14011                     oldlocset = obj->user;
   14012 
   14013                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   14014 		        ctxt->context->node = NULL;
   14015                         ctxt->context->contextSize = 0;
   14016                         ctxt->context->proximityPosition = 0;
   14017                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
   14018                         res = valuePop(ctxt);
   14019                         if (res != NULL) {
   14020 			    xmlXPathReleaseObject(ctxt->context, res);
   14021 			}
   14022                         valuePush(ctxt, obj);
   14023                         CHECK_ERROR0;
   14024                         return (total);
   14025                     }
   14026                     newlocset = xmlXPtrLocationSetCreate(NULL);
   14027 
   14028                     for (i = 0; i < oldlocset->locNr; i++) {
   14029                         /*
   14030                          * Run the evaluation with a node list made of a
   14031                          * single item in the nodelocset.
   14032                          */
   14033                         ctxt->context->node = oldlocset->locTab[i]->user;
   14034                         ctxt->context->contextSize = oldlocset->locNr;
   14035                         ctxt->context->proximityPosition = i + 1;
   14036 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   14037 			    ctxt->context->node);
   14038                         valuePush(ctxt, tmp);
   14039 
   14040                         if (op->ch2 != -1)
   14041                             total +=
   14042                                 xmlXPathCompOpEval(ctxt,
   14043                                                    &comp->steps[op->ch2]);
   14044 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   14045 			    xmlXPathFreeObject(obj);
   14046 			    return(0);
   14047 			}
   14048 
   14049                         res = valuePop(ctxt);
   14050 			if (res->type == XPATH_LOCATIONSET) {
   14051 			    xmlLocationSetPtr rloc =
   14052 			        (xmlLocationSetPtr)res->user;
   14053 			    for (j=0; j<rloc->locNr; j++) {
   14054 			        range = xmlXPtrNewRange(
   14055 				  oldlocset->locTab[i]->user,
   14056 				  oldlocset->locTab[i]->index,
   14057 				  rloc->locTab[j]->user2,
   14058 				  rloc->locTab[j]->index2);
   14059 				if (range != NULL) {
   14060 				    xmlXPtrLocationSetAdd(newlocset, range);
   14061 				}
   14062 			    }
   14063 			} else {
   14064 			    range = xmlXPtrNewRangeNodeObject(
   14065 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
   14066                             if (range != NULL) {
   14067                                 xmlXPtrLocationSetAdd(newlocset,range);
   14068 			    }
   14069                         }
   14070 
   14071                         /*
   14072                          * Cleanup
   14073                          */
   14074                         if (res != NULL) {
   14075 			    xmlXPathReleaseObject(ctxt->context, res);
   14076 			}
   14077                         if (ctxt->value == tmp) {
   14078                             res = valuePop(ctxt);
   14079 			    xmlXPathReleaseObject(ctxt->context, res);
   14080                         }
   14081 
   14082                         ctxt->context->node = NULL;
   14083                     }
   14084 		} else {	/* Not a location set */
   14085                     CHECK_TYPE0(XPATH_NODESET);
   14086                     obj = valuePop(ctxt);
   14087                     oldset = obj->nodesetval;
   14088                     ctxt->context->node = NULL;
   14089 
   14090                     newlocset = xmlXPtrLocationSetCreate(NULL);
   14091 
   14092                     if (oldset != NULL) {
   14093                         for (i = 0; i < oldset->nodeNr; i++) {
   14094                             /*
   14095                              * Run the evaluation with a node list made of a single item
   14096                              * in the nodeset.
   14097                              */
   14098                             ctxt->context->node = oldset->nodeTab[i];
   14099 			    /*
   14100 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
   14101 			    */
   14102 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   14103 				ctxt->context->node);
   14104                             valuePush(ctxt, tmp);
   14105 
   14106                             if (op->ch2 != -1)
   14107                                 total +=
   14108                                     xmlXPathCompOpEval(ctxt,
   14109                                                    &comp->steps[op->ch2]);
   14110 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
   14111 				xmlXPathFreeObject(obj);
   14112 				return(0);
   14113 			    }
   14114 
   14115                             res = valuePop(ctxt);
   14116                             range =
   14117                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
   14118                                                       res);
   14119                             if (range != NULL) {
   14120                                 xmlXPtrLocationSetAdd(newlocset, range);
   14121                             }
   14122 
   14123                             /*
   14124                              * Cleanup
   14125                              */
   14126                             if (res != NULL) {
   14127 				xmlXPathReleaseObject(ctxt->context, res);
   14128 			    }
   14129                             if (ctxt->value == tmp) {
   14130                                 res = valuePop(ctxt);
   14131 				xmlXPathReleaseObject(ctxt->context, res);
   14132                             }
   14133 
   14134                             ctxt->context->node = NULL;
   14135                         }
   14136                     }
   14137                 }
   14138 
   14139                 /*
   14140                  * The result is used as the new evaluation set.
   14141                  */
   14142 		xmlXPathReleaseObject(ctxt->context, obj);
   14143                 ctxt->context->node = NULL;
   14144                 ctxt->context->contextSize = -1;
   14145                 ctxt->context->proximityPosition = -1;
   14146                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   14147                 return (total);
   14148             }
   14149 #endif /* LIBXML_XPTR_ENABLED */
   14150     }
   14151     xmlGenericError(xmlGenericErrorContext,
   14152                     "XPath: unknown precompiled operation %d\n", op->op);
   14153     ctxt->error = XPATH_INVALID_OPERAND;
   14154     return (total);
   14155 }
   14156 
   14157 /**
   14158  * xmlXPathCompOpEvalToBoolean:
   14159  * @ctxt:  the XPath parser context
   14160  *
   14161  * Evaluates if the expression evaluates to true.
   14162  *
   14163  * Returns 1 if true, 0 if false and -1 on API or internal errors.
   14164  */
   14165 static int
   14166 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
   14167 			    xmlXPathStepOpPtr op,
   14168 			    int isPredicate)
   14169 {
   14170     xmlXPathObjectPtr resObj = NULL;
   14171 
   14172 start:
   14173     /* comp = ctxt->comp; */
   14174     switch (op->op) {
   14175         case XPATH_OP_END:
   14176             return (0);
   14177 	case XPATH_OP_VALUE:
   14178 	    resObj = (xmlXPathObjectPtr) op->value4;
   14179 	    if (isPredicate)
   14180 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
   14181 	    return(xmlXPathCastToBoolean(resObj));
   14182 	case XPATH_OP_SORT:
   14183 	    /*
   14184 	    * We don't need sorting for boolean results. Skip this one.
   14185 	    */
   14186             if (op->ch1 != -1) {
   14187 		op = &ctxt->comp->steps[op->ch1];
   14188 		goto start;
   14189 	    }
   14190 	    return(0);
   14191 	case XPATH_OP_COLLECT:
   14192 	    if (op->ch1 == -1)
   14193 		return(0);
   14194 
   14195             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
   14196 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14197 		return(-1);
   14198 
   14199             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
   14200 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14201 		return(-1);
   14202 
   14203 	    resObj = valuePop(ctxt);
   14204 	    if (resObj == NULL)
   14205 		return(-1);
   14206 	    break;
   14207 	default:
   14208 	    /*
   14209 	    * Fallback to call xmlXPathCompOpEval().
   14210 	    */
   14211 	    xmlXPathCompOpEval(ctxt, op);
   14212 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14213 		return(-1);
   14214 
   14215 	    resObj = valuePop(ctxt);
   14216 	    if (resObj == NULL)
   14217 		return(-1);
   14218 	    break;
   14219     }
   14220 
   14221     if (resObj) {
   14222 	int res;
   14223 
   14224 	if (resObj->type == XPATH_BOOLEAN) {
   14225 	    res = resObj->boolval;
   14226 	} else if (isPredicate) {
   14227 	    /*
   14228 	    * For predicates a result of type "number" is handled
   14229 	    * differently:
   14230 	    * SPEC XPath 1.0:
   14231 	    * "If the result is a number, the result will be converted
   14232 	    *  to true if the number is equal to the context position
   14233 	    *  and will be converted to false otherwise;"
   14234 	    */
   14235 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
   14236 	} else {
   14237 	    res = xmlXPathCastToBoolean(resObj);
   14238 	}
   14239 	xmlXPathReleaseObject(ctxt->context, resObj);
   14240 	return(res);
   14241     }
   14242 
   14243     return(0);
   14244 }
   14245 
   14246 #ifdef XPATH_STREAMING
   14247 /**
   14248  * xmlXPathRunStreamEval:
   14249  * @ctxt:  the XPath parser context with the compiled expression
   14250  *
   14251  * Evaluate the Precompiled Streamable XPath expression in the given context.
   14252  */
   14253 static int
   14254 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
   14255 		      xmlXPathObjectPtr *resultSeq, int toBool)
   14256 {
   14257     int max_depth, min_depth;
   14258     int from_root;
   14259     int ret, depth;
   14260     int eval_all_nodes;
   14261     xmlNodePtr cur = NULL, limit = NULL;
   14262     xmlStreamCtxtPtr patstream = NULL;
   14263 
   14264     int nb_nodes = 0;
   14265 
   14266     if ((ctxt == NULL) || (comp == NULL))
   14267         return(-1);
   14268     max_depth = xmlPatternMaxDepth(comp);
   14269     if (max_depth == -1)
   14270         return(-1);
   14271     if (max_depth == -2)
   14272         max_depth = 10000;
   14273     min_depth = xmlPatternMinDepth(comp);
   14274     if (min_depth == -1)
   14275         return(-1);
   14276     from_root = xmlPatternFromRoot(comp);
   14277     if (from_root < 0)
   14278         return(-1);
   14279 #if 0
   14280     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
   14281 #endif
   14282 
   14283     if (! toBool) {
   14284 	if (resultSeq == NULL)
   14285 	    return(-1);
   14286 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
   14287 	if (*resultSeq == NULL)
   14288 	    return(-1);
   14289     }
   14290 
   14291     /*
   14292      * handle the special cases of "/" amd "." being matched
   14293      */
   14294     if (min_depth == 0) {
   14295 	if (from_root) {
   14296 	    /* Select "/" */
   14297 	    if (toBool)
   14298 		return(1);
   14299 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
   14300 		                     (xmlNodePtr) ctxt->doc);
   14301 	} else {
   14302 	    /* Select "self::node()" */
   14303 	    if (toBool)
   14304 		return(1);
   14305 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
   14306 	}
   14307     }
   14308     if (max_depth == 0) {
   14309 	return(0);
   14310     }
   14311 
   14312     if (from_root) {
   14313         cur = (xmlNodePtr)ctxt->doc;
   14314     } else if (ctxt->node != NULL) {
   14315         switch (ctxt->node->type) {
   14316             case XML_ELEMENT_NODE:
   14317             case XML_DOCUMENT_NODE:
   14318             case XML_DOCUMENT_FRAG_NODE:
   14319             case XML_HTML_DOCUMENT_NODE:
   14320 #ifdef LIBXML_DOCB_ENABLED
   14321             case XML_DOCB_DOCUMENT_NODE:
   14322 #endif
   14323 	        cur = ctxt->node;
   14324 		break;
   14325             case XML_ATTRIBUTE_NODE:
   14326             case XML_TEXT_NODE:
   14327             case XML_CDATA_SECTION_NODE:
   14328             case XML_ENTITY_REF_NODE:
   14329             case XML_ENTITY_NODE:
   14330             case XML_PI_NODE:
   14331             case XML_COMMENT_NODE:
   14332             case XML_NOTATION_NODE:
   14333             case XML_DTD_NODE:
   14334             case XML_DOCUMENT_TYPE_NODE:
   14335             case XML_ELEMENT_DECL:
   14336             case XML_ATTRIBUTE_DECL:
   14337             case XML_ENTITY_DECL:
   14338             case XML_NAMESPACE_DECL:
   14339             case XML_XINCLUDE_START:
   14340             case XML_XINCLUDE_END:
   14341 		break;
   14342 	}
   14343 	limit = cur;
   14344     }
   14345     if (cur == NULL) {
   14346         return(0);
   14347     }
   14348 
   14349     patstream = xmlPatternGetStreamCtxt(comp);
   14350     if (patstream == NULL) {
   14351 	/*
   14352 	* QUESTION TODO: Is this an error?
   14353 	*/
   14354 	return(0);
   14355     }
   14356 
   14357     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
   14358 
   14359     if (from_root) {
   14360 	ret = xmlStreamPush(patstream, NULL, NULL);
   14361 	if (ret < 0) {
   14362 	} else if (ret == 1) {
   14363 	    if (toBool)
   14364 		goto return_1;
   14365 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
   14366 	}
   14367     }
   14368     depth = 0;
   14369     goto scan_children;
   14370 next_node:
   14371     do {
   14372         nb_nodes++;
   14373 
   14374 	switch (cur->type) {
   14375 	    case XML_ELEMENT_NODE:
   14376 	    case XML_TEXT_NODE:
   14377 	    case XML_CDATA_SECTION_NODE:
   14378 	    case XML_COMMENT_NODE:
   14379 	    case XML_PI_NODE:
   14380 		if (cur->type == XML_ELEMENT_NODE) {
   14381 		    ret = xmlStreamPush(patstream, cur->name,
   14382 				(cur->ns ? cur->ns->href : NULL));
   14383 		} else if (eval_all_nodes)
   14384 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
   14385 		else
   14386 		    break;
   14387 
   14388 		if (ret < 0) {
   14389 		    /* NOP. */
   14390 		} else if (ret == 1) {
   14391 		    if (toBool)
   14392 			goto return_1;
   14393 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
   14394 		        < 0) {
   14395 			ctxt->lastError.domain = XML_FROM_XPATH;
   14396 			ctxt->lastError.code = XML_ERR_NO_MEMORY;
   14397 		    }
   14398 		}
   14399 		if ((cur->children == NULL) || (depth >= max_depth)) {
   14400 		    ret = xmlStreamPop(patstream);
   14401 		    while (cur->next != NULL) {
   14402 			cur = cur->next;
   14403 			if ((cur->type != XML_ENTITY_DECL) &&
   14404 			    (cur->type != XML_DTD_NODE))
   14405 			    goto next_node;
   14406 		    }
   14407 		}
   14408 	    default:
   14409 		break;
   14410 	}
   14411 
   14412 scan_children:
   14413 	if (cur->type == XML_NAMESPACE_DECL) break;
   14414 	if ((cur->children != NULL) && (depth < max_depth)) {
   14415 	    /*
   14416 	     * Do not descend on entities declarations
   14417 	     */
   14418 	    if (cur->children->type != XML_ENTITY_DECL) {
   14419 		cur = cur->children;
   14420 		depth++;
   14421 		/*
   14422 		 * Skip DTDs
   14423 		 */
   14424 		if (cur->type != XML_DTD_NODE)
   14425 		    continue;
   14426 	    }
   14427 	}
   14428 
   14429 	if (cur == limit)
   14430 	    break;
   14431 
   14432 	while (cur->next != NULL) {
   14433 	    cur = cur->next;
   14434 	    if ((cur->type != XML_ENTITY_DECL) &&
   14435 		(cur->type != XML_DTD_NODE))
   14436 		goto next_node;
   14437 	}
   14438 
   14439 	do {
   14440 	    cur = cur->parent;
   14441 	    depth--;
   14442 	    if ((cur == NULL) || (cur == limit))
   14443 	        goto done;
   14444 	    if (cur->type == XML_ELEMENT_NODE) {
   14445 		ret = xmlStreamPop(patstream);
   14446 	    } else if ((eval_all_nodes) &&
   14447 		((cur->type == XML_TEXT_NODE) ||
   14448 		 (cur->type == XML_CDATA_SECTION_NODE) ||
   14449 		 (cur->type == XML_COMMENT_NODE) ||
   14450 		 (cur->type == XML_PI_NODE)))
   14451 	    {
   14452 		ret = xmlStreamPop(patstream);
   14453 	    }
   14454 	    if (cur->next != NULL) {
   14455 		cur = cur->next;
   14456 		break;
   14457 	    }
   14458 	} while (cur != NULL);
   14459 
   14460     } while ((cur != NULL) && (depth >= 0));
   14461 
   14462 done:
   14463 
   14464 #if 0
   14465     printf("stream eval: checked %d nodes selected %d\n",
   14466            nb_nodes, retObj->nodesetval->nodeNr);
   14467 #endif
   14468 
   14469     if (patstream)
   14470 	xmlFreeStreamCtxt(patstream);
   14471     return(0);
   14472 
   14473 return_1:
   14474     if (patstream)
   14475 	xmlFreeStreamCtxt(patstream);
   14476     return(1);
   14477 }
   14478 #endif /* XPATH_STREAMING */
   14479 
   14480 /**
   14481  * xmlXPathRunEval:
   14482  * @ctxt:  the XPath parser context with the compiled expression
   14483  * @toBool:  evaluate to a boolean result
   14484  *
   14485  * Evaluate the Precompiled XPath expression in the given context.
   14486  */
   14487 static int
   14488 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
   14489 {
   14490     xmlXPathCompExprPtr comp;
   14491 
   14492     if ((ctxt == NULL) || (ctxt->comp == NULL))
   14493 	return(-1);
   14494 
   14495     if (ctxt->valueTab == NULL) {
   14496 	/* Allocate the value stack */
   14497 	ctxt->valueTab = (xmlXPathObjectPtr *)
   14498 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
   14499 	if (ctxt->valueTab == NULL) {
   14500 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
   14501 	    xmlFree(ctxt);
   14502 	}
   14503 	ctxt->valueNr = 0;
   14504 	ctxt->valueMax = 10;
   14505 	ctxt->value = NULL;
   14506         ctxt->valueFrame = 0;
   14507     }
   14508 #ifdef XPATH_STREAMING
   14509     if (ctxt->comp->stream) {
   14510 	int res;
   14511 
   14512 	if (toBool) {
   14513 	    /*
   14514 	    * Evaluation to boolean result.
   14515 	    */
   14516 	    res = xmlXPathRunStreamEval(ctxt->context,
   14517 		ctxt->comp->stream, NULL, 1);
   14518 	    if (res != -1)
   14519 		return(res);
   14520 	} else {
   14521 	    xmlXPathObjectPtr resObj = NULL;
   14522 
   14523 	    /*
   14524 	    * Evaluation to a sequence.
   14525 	    */
   14526 	    res = xmlXPathRunStreamEval(ctxt->context,
   14527 		ctxt->comp->stream, &resObj, 0);
   14528 
   14529 	    if ((res != -1) && (resObj != NULL)) {
   14530 		valuePush(ctxt, resObj);
   14531 		return(0);
   14532 	    }
   14533 	    if (resObj != NULL)
   14534 		xmlXPathReleaseObject(ctxt->context, resObj);
   14535 	}
   14536 	/*
   14537 	* QUESTION TODO: This falls back to normal XPath evaluation
   14538 	* if res == -1. Is this intended?
   14539 	*/
   14540     }
   14541 #endif
   14542     comp = ctxt->comp;
   14543     if (comp->last < 0) {
   14544 	xmlGenericError(xmlGenericErrorContext,
   14545 	    "xmlXPathRunEval: last is less than zero\n");
   14546 	return(-1);
   14547     }
   14548     if (toBool)
   14549 	return(xmlXPathCompOpEvalToBoolean(ctxt,
   14550 	    &comp->steps[comp->last], 0));
   14551     else
   14552 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
   14553 
   14554     return(0);
   14555 }
   14556 
   14557 /************************************************************************
   14558  *									*
   14559  *			Public interfaces				*
   14560  *									*
   14561  ************************************************************************/
   14562 
   14563 /**
   14564  * xmlXPathEvalPredicate:
   14565  * @ctxt:  the XPath context
   14566  * @res:  the Predicate Expression evaluation result
   14567  *
   14568  * Evaluate a predicate result for the current node.
   14569  * A PredicateExpr is evaluated by evaluating the Expr and converting
   14570  * the result to a boolean. If the result is a number, the result will
   14571  * be converted to true if the number is equal to the position of the
   14572  * context node in the context node list (as returned by the position
   14573  * function) and will be converted to false otherwise; if the result
   14574  * is not a number, then the result will be converted as if by a call
   14575  * to the boolean function.
   14576  *
   14577  * Returns 1 if predicate is true, 0 otherwise
   14578  */
   14579 int
   14580 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
   14581     if ((ctxt == NULL) || (res == NULL)) return(0);
   14582     switch (res->type) {
   14583         case XPATH_BOOLEAN:
   14584 	    return(res->boolval);
   14585         case XPATH_NUMBER:
   14586 	    return(res->floatval == ctxt->proximityPosition);
   14587         case XPATH_NODESET:
   14588         case XPATH_XSLT_TREE:
   14589 	    if (res->nodesetval == NULL)
   14590 		return(0);
   14591 	    return(res->nodesetval->nodeNr != 0);
   14592         case XPATH_STRING:
   14593 	    return((res->stringval != NULL) &&
   14594 	           (xmlStrlen(res->stringval) != 0));
   14595         default:
   14596 	    STRANGE
   14597     }
   14598     return(0);
   14599 }
   14600 
   14601 /**
   14602  * xmlXPathEvaluatePredicateResult:
   14603  * @ctxt:  the XPath Parser context
   14604  * @res:  the Predicate Expression evaluation result
   14605  *
   14606  * Evaluate a predicate result for the current node.
   14607  * A PredicateExpr is evaluated by evaluating the Expr and converting
   14608  * the result to a boolean. If the result is a number, the result will
   14609  * be converted to true if the number is equal to the position of the
   14610  * context node in the context node list (as returned by the position
   14611  * function) and will be converted to false otherwise; if the result
   14612  * is not a number, then the result will be converted as if by a call
   14613  * to the boolean function.
   14614  *
   14615  * Returns 1 if predicate is true, 0 otherwise
   14616  */
   14617 int
   14618 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
   14619                                 xmlXPathObjectPtr res) {
   14620     if ((ctxt == NULL) || (res == NULL)) return(0);
   14621     switch (res->type) {
   14622         case XPATH_BOOLEAN:
   14623 	    return(res->boolval);
   14624         case XPATH_NUMBER:
   14625 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
   14626 	    return((res->floatval == ctxt->context->proximityPosition) &&
   14627 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
   14628 #else
   14629 	    return(res->floatval == ctxt->context->proximityPosition);
   14630 #endif
   14631         case XPATH_NODESET:
   14632         case XPATH_XSLT_TREE:
   14633 	    if (res->nodesetval == NULL)
   14634 		return(0);
   14635 	    return(res->nodesetval->nodeNr != 0);
   14636         case XPATH_STRING:
   14637 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
   14638 #ifdef LIBXML_XPTR_ENABLED
   14639 	case XPATH_LOCATIONSET:{
   14640 	    xmlLocationSetPtr ptr = res->user;
   14641 	    if (ptr == NULL)
   14642 	        return(0);
   14643 	    return (ptr->locNr != 0);
   14644 	    }
   14645 #endif
   14646         default:
   14647 	    STRANGE
   14648     }
   14649     return(0);
   14650 }
   14651 
   14652 #ifdef XPATH_STREAMING
   14653 /**
   14654  * xmlXPathTryStreamCompile:
   14655  * @ctxt: an XPath context
   14656  * @str:  the XPath expression
   14657  *
   14658  * Try to compile the XPath expression as a streamable subset.
   14659  *
   14660  * Returns the compiled expression or NULL if failed to compile.
   14661  */
   14662 static xmlXPathCompExprPtr
   14663 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
   14664     /*
   14665      * Optimization: use streaming patterns when the XPath expression can
   14666      * be compiled to a stream lookup
   14667      */
   14668     xmlPatternPtr stream;
   14669     xmlXPathCompExprPtr comp;
   14670     xmlDictPtr dict = NULL;
   14671     const xmlChar **namespaces = NULL;
   14672     xmlNsPtr ns;
   14673     int i, j;
   14674 
   14675     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
   14676         (!xmlStrchr(str, '@'))) {
   14677 	const xmlChar *tmp;
   14678 
   14679 	/*
   14680 	 * We don't try to handle expressions using the verbose axis
   14681 	 * specifiers ("::"), just the simplied form at this point.
   14682 	 * Additionally, if there is no list of namespaces available and
   14683 	 *  there's a ":" in the expression, indicating a prefixed QName,
   14684 	 *  then we won't try to compile either. xmlPatterncompile() needs
   14685 	 *  to have a list of namespaces at compilation time in order to
   14686 	 *  compile prefixed name tests.
   14687 	 */
   14688 	tmp = xmlStrchr(str, ':');
   14689 	if ((tmp != NULL) &&
   14690 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
   14691 	    return(NULL);
   14692 
   14693 	if (ctxt != NULL) {
   14694 	    dict = ctxt->dict;
   14695 	    if (ctxt->nsNr > 0) {
   14696 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
   14697 		if (namespaces == NULL) {
   14698 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
   14699 		    return(NULL);
   14700 		}
   14701 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
   14702 		    ns = ctxt->namespaces[j];
   14703 		    namespaces[i++] = ns->href;
   14704 		    namespaces[i++] = ns->prefix;
   14705 		}
   14706 		namespaces[i++] = NULL;
   14707 		namespaces[i] = NULL;
   14708 	    }
   14709 	}
   14710 
   14711 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
   14712 			&namespaces[0]);
   14713 	if (namespaces != NULL) {
   14714 	    xmlFree((xmlChar **)namespaces);
   14715 	}
   14716 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
   14717 	    comp = xmlXPathNewCompExpr();
   14718 	    if (comp == NULL) {
   14719 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
   14720 		return(NULL);
   14721 	    }
   14722 	    comp->stream = stream;
   14723 	    comp->dict = dict;
   14724 	    if (comp->dict)
   14725 		xmlDictReference(comp->dict);
   14726 	    return(comp);
   14727 	}
   14728 	xmlFreePattern(stream);
   14729     }
   14730     return(NULL);
   14731 }
   14732 #endif /* XPATH_STREAMING */
   14733 
   14734 static void
   14735 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
   14736 {
   14737     /*
   14738     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
   14739     * internal representation.
   14740     */
   14741 
   14742     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
   14743         (op->ch1 != -1) &&
   14744         (op->ch2 == -1 /* no predicate */))
   14745     {
   14746         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
   14747 
   14748         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
   14749             ((xmlXPathAxisVal) prevop->value ==
   14750                 AXIS_DESCENDANT_OR_SELF) &&
   14751             (prevop->ch2 == -1) &&
   14752             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
   14753             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
   14754         {
   14755             /*
   14756             * This is a "descendant-or-self::node()" without predicates.
   14757             * Try to eliminate it.
   14758             */
   14759 
   14760             switch ((xmlXPathAxisVal) op->value) {
   14761                 case AXIS_CHILD:
   14762                 case AXIS_DESCENDANT:
   14763                     /*
   14764                     * Convert "descendant-or-self::node()/child::" or
   14765                     * "descendant-or-self::node()/descendant::" to
   14766                     * "descendant::"
   14767                     */
   14768                     op->ch1   = prevop->ch1;
   14769                     op->value = AXIS_DESCENDANT;
   14770                     break;
   14771                 case AXIS_SELF:
   14772                 case AXIS_DESCENDANT_OR_SELF:
   14773                     /*
   14774                     * Convert "descendant-or-self::node()/self::" or
   14775                     * "descendant-or-self::node()/descendant-or-self::" to
   14776                     * to "descendant-or-self::"
   14777                     */
   14778                     op->ch1   = prevop->ch1;
   14779                     op->value = AXIS_DESCENDANT_OR_SELF;
   14780                     break;
   14781                 default:
   14782                     break;
   14783             }
   14784 	}
   14785     }
   14786 
   14787     /* Recurse */
   14788     if (op->ch1 != -1)
   14789         xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
   14790     if (op->ch2 != -1)
   14791 	xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
   14792 }
   14793 
   14794 /**
   14795  * xmlXPathCtxtCompile:
   14796  * @ctxt: an XPath context
   14797  * @str:  the XPath expression
   14798  *
   14799  * Compile an XPath expression
   14800  *
   14801  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
   14802  *         the caller has to free the object.
   14803  */
   14804 xmlXPathCompExprPtr
   14805 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
   14806     xmlXPathParserContextPtr pctxt;
   14807     xmlXPathCompExprPtr comp;
   14808 
   14809 #ifdef XPATH_STREAMING
   14810     comp = xmlXPathTryStreamCompile(ctxt, str);
   14811     if (comp != NULL)
   14812         return(comp);
   14813 #endif
   14814 
   14815     xmlXPathInit();
   14816 
   14817     pctxt = xmlXPathNewParserContext(str, ctxt);
   14818     if (pctxt == NULL)
   14819         return NULL;
   14820     xmlXPathCompileExpr(pctxt, 1);
   14821 
   14822     if( pctxt->error != XPATH_EXPRESSION_OK )
   14823     {
   14824         xmlXPathFreeParserContext(pctxt);
   14825         return(NULL);
   14826     }
   14827 
   14828     if (*pctxt->cur != 0) {
   14829 	/*
   14830 	 * aleksey: in some cases this line prints *second* error message
   14831 	 * (see bug #78858) and probably this should be fixed.
   14832 	 * However, we are not sure that all error messages are printed
   14833 	 * out in other places. It's not critical so we leave it as-is for now
   14834 	 */
   14835 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   14836 	comp = NULL;
   14837     } else {
   14838 	comp = pctxt->comp;
   14839 	pctxt->comp = NULL;
   14840     }
   14841     xmlXPathFreeParserContext(pctxt);
   14842 
   14843     if (comp != NULL) {
   14844 	comp->expr = xmlStrdup(str);
   14845 #ifdef DEBUG_EVAL_COUNTS
   14846 	comp->string = xmlStrdup(str);
   14847 	comp->nb = 0;
   14848 #endif
   14849 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
   14850 	    xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
   14851 	}
   14852     }
   14853     return(comp);
   14854 }
   14855 
   14856 /**
   14857  * xmlXPathCompile:
   14858  * @str:  the XPath expression
   14859  *
   14860  * Compile an XPath expression
   14861  *
   14862  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
   14863  *         the caller has to free the object.
   14864  */
   14865 xmlXPathCompExprPtr
   14866 xmlXPathCompile(const xmlChar *str) {
   14867     return(xmlXPathCtxtCompile(NULL, str));
   14868 }
   14869 
   14870 /**
   14871  * xmlXPathCompiledEvalInternal:
   14872  * @comp:  the compiled XPath expression
   14873  * @ctxt:  the XPath context
   14874  * @resObj: the resulting XPath object or NULL
   14875  * @toBool: 1 if only a boolean result is requested
   14876  *
   14877  * Evaluate the Precompiled XPath expression in the given context.
   14878  * The caller has to free @resObj.
   14879  *
   14880  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14881  *         the caller has to free the object.
   14882  */
   14883 static int
   14884 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
   14885 			     xmlXPathContextPtr ctxt,
   14886 			     xmlXPathObjectPtr *resObj,
   14887 			     int toBool)
   14888 {
   14889     xmlXPathParserContextPtr pctxt;
   14890 #ifndef LIBXML_THREAD_ENABLED
   14891     static int reentance = 0;
   14892 #endif
   14893     int res;
   14894 
   14895     CHECK_CTXT_NEG(ctxt)
   14896 
   14897     if (comp == NULL)
   14898 	return(-1);
   14899     xmlXPathInit();
   14900 
   14901 #ifndef LIBXML_THREAD_ENABLED
   14902     reentance++;
   14903     if (reentance > 1)
   14904 	xmlXPathDisableOptimizer = 1;
   14905 #endif
   14906 
   14907 #ifdef DEBUG_EVAL_COUNTS
   14908     comp->nb++;
   14909     if ((comp->string != NULL) && (comp->nb > 100)) {
   14910 	fprintf(stderr, "100 x %s\n", comp->string);
   14911 	comp->nb = 0;
   14912     }
   14913 #endif
   14914     pctxt = xmlXPathCompParserContext(comp, ctxt);
   14915     res = xmlXPathRunEval(pctxt, toBool);
   14916 
   14917     if (resObj) {
   14918 	if (pctxt->value == NULL) {
   14919 	    xmlGenericError(xmlGenericErrorContext,
   14920 		"xmlXPathCompiledEval: evaluation failed\n");
   14921 	    *resObj = NULL;
   14922 	} else {
   14923 	    *resObj = valuePop(pctxt);
   14924 	}
   14925     }
   14926 
   14927     /*
   14928     * Pop all remaining objects from the stack.
   14929     */
   14930     if (pctxt->valueNr > 0) {
   14931 	xmlXPathObjectPtr tmp;
   14932 	int stack = 0;
   14933 
   14934 	do {
   14935 	    tmp = valuePop(pctxt);
   14936 	    if (tmp != NULL) {
   14937 		stack++;
   14938 		xmlXPathReleaseObject(ctxt, tmp);
   14939 	    }
   14940 	} while (tmp != NULL);
   14941 	if ((stack != 0) &&
   14942 	    ((toBool) || ((resObj) && (*resObj))))
   14943 	{
   14944 	    xmlGenericError(xmlGenericErrorContext,
   14945 		"xmlXPathCompiledEval: %d objects left on the stack.\n",
   14946 		stack);
   14947 	}
   14948     }
   14949 
   14950     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
   14951 	xmlXPathFreeObject(*resObj);
   14952 	*resObj = NULL;
   14953     }
   14954     pctxt->comp = NULL;
   14955     xmlXPathFreeParserContext(pctxt);
   14956 #ifndef LIBXML_THREAD_ENABLED
   14957     reentance--;
   14958 #endif
   14959 
   14960     return(res);
   14961 }
   14962 
   14963 /**
   14964  * xmlXPathCompiledEval:
   14965  * @comp:  the compiled XPath expression
   14966  * @ctx:  the XPath context
   14967  *
   14968  * Evaluate the Precompiled XPath expression in the given context.
   14969  *
   14970  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14971  *         the caller has to free the object.
   14972  */
   14973 xmlXPathObjectPtr
   14974 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
   14975 {
   14976     xmlXPathObjectPtr res = NULL;
   14977 
   14978     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
   14979     return(res);
   14980 }
   14981 
   14982 /**
   14983  * xmlXPathCompiledEvalToBoolean:
   14984  * @comp:  the compiled XPath expression
   14985  * @ctxt:  the XPath context
   14986  *
   14987  * Applies the XPath boolean() function on the result of the given
   14988  * compiled expression.
   14989  *
   14990  * Returns 1 if the expression evaluated to true, 0 if to false and
   14991  *         -1 in API and internal errors.
   14992  */
   14993 int
   14994 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
   14995 			      xmlXPathContextPtr ctxt)
   14996 {
   14997     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
   14998 }
   14999 
   15000 /**
   15001  * xmlXPathEvalExpr:
   15002  * @ctxt:  the XPath Parser context
   15003  *
   15004  * Parse and evaluate an XPath expression in the given context,
   15005  * then push the result on the context stack
   15006  */
   15007 void
   15008 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
   15009 #ifdef XPATH_STREAMING
   15010     xmlXPathCompExprPtr comp;
   15011 #endif
   15012 
   15013     if (ctxt == NULL) return;
   15014 
   15015 #ifdef XPATH_STREAMING
   15016     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
   15017     if (comp != NULL) {
   15018         if (ctxt->comp != NULL)
   15019 	    xmlXPathFreeCompExpr(ctxt->comp);
   15020         ctxt->comp = comp;
   15021 	if (ctxt->cur != NULL)
   15022 	    while (*ctxt->cur != 0) ctxt->cur++;
   15023     } else
   15024 #endif
   15025     {
   15026 	xmlXPathCompileExpr(ctxt, 1);
   15027 	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
   15028 	    (ctxt->comp != NULL) &&
   15029 	    (ctxt->comp->nbStep > 1) &&
   15030 	    (ctxt->comp->last >= 0))
   15031 	{
   15032 	    xmlXPathOptimizeExpression(ctxt->comp,
   15033 		&ctxt->comp->steps[ctxt->comp->last]);
   15034 	}
   15035     }
   15036     CHECK_ERROR;
   15037     xmlXPathRunEval(ctxt, 0);
   15038 }
   15039 
   15040 /**
   15041  * xmlXPathEval:
   15042  * @str:  the XPath expression
   15043  * @ctx:  the XPath context
   15044  *
   15045  * Evaluate the XPath Location Path in the given context.
   15046  *
   15047  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   15048  *         the caller has to free the object.
   15049  */
   15050 xmlXPathObjectPtr
   15051 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
   15052     xmlXPathParserContextPtr ctxt;
   15053     xmlXPathObjectPtr res, tmp, init = NULL;
   15054     int stack = 0;
   15055 
   15056     CHECK_CTXT(ctx)
   15057 
   15058     xmlXPathInit();
   15059 
   15060     ctxt = xmlXPathNewParserContext(str, ctx);
   15061     if (ctxt == NULL)
   15062         return NULL;
   15063     xmlXPathEvalExpr(ctxt);
   15064 
   15065     if (ctxt->value == NULL) {
   15066 	xmlGenericError(xmlGenericErrorContext,
   15067 		"xmlXPathEval: evaluation failed\n");
   15068 	res = NULL;
   15069     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
   15070 #ifdef XPATH_STREAMING
   15071             && (ctxt->comp->stream == NULL)
   15072 #endif
   15073 	      ) {
   15074 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   15075 	res = NULL;
   15076     } else {
   15077 	res = valuePop(ctxt);
   15078     }
   15079 
   15080     do {
   15081         tmp = valuePop(ctxt);
   15082 	if (tmp != NULL) {
   15083 	    if (tmp != init)
   15084 		stack++;
   15085 	    xmlXPathReleaseObject(ctx, tmp);
   15086         }
   15087     } while (tmp != NULL);
   15088     if ((stack != 0) && (res != NULL)) {
   15089 	xmlGenericError(xmlGenericErrorContext,
   15090 		"xmlXPathEval: %d object left on the stack\n",
   15091 	        stack);
   15092     }
   15093     if (ctxt->error != XPATH_EXPRESSION_OK) {
   15094 	xmlXPathFreeObject(res);
   15095 	res = NULL;
   15096     }
   15097 
   15098     xmlXPathFreeParserContext(ctxt);
   15099     return(res);
   15100 }
   15101 
   15102 /**
   15103  * xmlXPathSetContextNode:
   15104  * @node: the node to to use as the context node
   15105  * @ctx:  the XPath context
   15106  *
   15107  * Sets 'node' as the context node. The node must be in the same
   15108  * document as that associated with the context.
   15109  *
   15110  * Returns -1 in case of error or 0 if successful
   15111  */
   15112 int
   15113 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
   15114     if ((node == NULL) || (ctx == NULL))
   15115         return(-1);
   15116 
   15117     if (node->doc == ctx->doc) {
   15118         ctx->node = node;
   15119 	return(0);
   15120     }
   15121     return(-1);
   15122 }
   15123 
   15124 /**
   15125  * xmlXPathNodeEval:
   15126  * @node: the node to to use as the context node
   15127  * @str:  the XPath expression
   15128  * @ctx:  the XPath context
   15129  *
   15130  * Evaluate the XPath Location Path in the given context. The node 'node'
   15131  * is set as the context node. The context node is not restored.
   15132  *
   15133  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   15134  *         the caller has to free the object.
   15135  */
   15136 xmlXPathObjectPtr
   15137 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
   15138     if (str == NULL)
   15139         return(NULL);
   15140     if (xmlXPathSetContextNode(node, ctx) < 0)
   15141         return(NULL);
   15142     return(xmlXPathEval(str, ctx));
   15143 }
   15144 
   15145 /**
   15146  * xmlXPathEvalExpression:
   15147  * @str:  the XPath expression
   15148  * @ctxt:  the XPath context
   15149  *
   15150  * Evaluate the XPath expression in the given context.
   15151  *
   15152  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   15153  *         the caller has to free the object.
   15154  */
   15155 xmlXPathObjectPtr
   15156 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
   15157     xmlXPathParserContextPtr pctxt;
   15158     xmlXPathObjectPtr res, tmp;
   15159     int stack = 0;
   15160 
   15161     CHECK_CTXT(ctxt)
   15162 
   15163     xmlXPathInit();
   15164 
   15165     pctxt = xmlXPathNewParserContext(str, ctxt);
   15166     if (pctxt == NULL)
   15167         return NULL;
   15168     xmlXPathEvalExpr(pctxt);
   15169 
   15170     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
   15171 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   15172 	res = NULL;
   15173     } else {
   15174 	res = valuePop(pctxt);
   15175     }
   15176     do {
   15177         tmp = valuePop(pctxt);
   15178 	if (tmp != NULL) {
   15179 	    xmlXPathReleaseObject(ctxt, tmp);
   15180 	    stack++;
   15181 	}
   15182     } while (tmp != NULL);
   15183     if ((stack != 0) && (res != NULL)) {
   15184 	xmlGenericError(xmlGenericErrorContext,
   15185 		"xmlXPathEvalExpression: %d object left on the stack\n",
   15186 	        stack);
   15187     }
   15188     xmlXPathFreeParserContext(pctxt);
   15189     return(res);
   15190 }
   15191 
   15192 /************************************************************************
   15193  *									*
   15194  *	Extra functions not pertaining to the XPath spec		*
   15195  *									*
   15196  ************************************************************************/
   15197 /**
   15198  * xmlXPathEscapeUriFunction:
   15199  * @ctxt:  the XPath Parser context
   15200  * @nargs:  the number of arguments
   15201  *
   15202  * Implement the escape-uri() XPath function
   15203  *    string escape-uri(string $str, bool $escape-reserved)
   15204  *
   15205  * This function applies the URI escaping rules defined in section 2 of [RFC
   15206  * 2396] to the string supplied as $uri-part, which typically represents all
   15207  * or part of a URI. The effect of the function is to replace any special
   15208  * character in the string by an escape sequence of the form %xx%yy...,
   15209  * where xxyy... is the hexadecimal representation of the octets used to
   15210  * represent the character in UTF-8.
   15211  *
   15212  * The set of characters that are escaped depends on the setting of the
   15213  * boolean argument $escape-reserved.
   15214  *
   15215  * If $escape-reserved is true, all characters are escaped other than lower
   15216  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
   15217  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
   15218  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
   15219  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
   15220  * A-F).
   15221  *
   15222  * If $escape-reserved is false, the behavior differs in that characters
   15223  * referred to in [RFC 2396] as reserved characters are not escaped. These
   15224  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
   15225  *
   15226  * [RFC 2396] does not define whether escaped URIs should use lower case or
   15227  * upper case for hexadecimal digits. To ensure that escaped URIs can be
   15228  * compared using string comparison functions, this function must always use
   15229  * the upper-case letters A-F.
   15230  *
   15231  * Generally, $escape-reserved should be set to true when escaping a string
   15232  * that is to form a single part of a URI, and to false when escaping an
   15233  * entire URI or URI reference.
   15234  *
   15235  * In the case of non-ascii characters, the string is encoded according to
   15236  * utf-8 and then converted according to RFC 2396.
   15237  *
   15238  * Examples
   15239  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
   15240  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
   15241  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
   15242  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
   15243  *
   15244  */
   15245 static void
   15246 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   15247     xmlXPathObjectPtr str;
   15248     int escape_reserved;
   15249     xmlBufPtr target;
   15250     xmlChar *cptr;
   15251     xmlChar escape[4];
   15252 
   15253     CHECK_ARITY(2);
   15254 
   15255     escape_reserved = xmlXPathPopBoolean(ctxt);
   15256 
   15257     CAST_TO_STRING;
   15258     str = valuePop(ctxt);
   15259 
   15260     target = xmlBufCreate();
   15261 
   15262     escape[0] = '%';
   15263     escape[3] = 0;
   15264 
   15265     if (target) {
   15266 	for (cptr = str->stringval; *cptr; cptr++) {
   15267 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
   15268 		(*cptr >= 'a' && *cptr <= 'z') ||
   15269 		(*cptr >= '0' && *cptr <= '9') ||
   15270 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
   15271 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
   15272 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
   15273 		(*cptr == '%' &&
   15274 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
   15275 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
   15276 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
   15277 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
   15278 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
   15279 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
   15280 		(!escape_reserved &&
   15281 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
   15282 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
   15283 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
   15284 		  *cptr == ','))) {
   15285 		xmlBufAdd(target, cptr, 1);
   15286 	    } else {
   15287 		if ((*cptr >> 4) < 10)
   15288 		    escape[1] = '0' + (*cptr >> 4);
   15289 		else
   15290 		    escape[1] = 'A' - 10 + (*cptr >> 4);
   15291 		if ((*cptr & 0xF) < 10)
   15292 		    escape[2] = '0' + (*cptr & 0xF);
   15293 		else
   15294 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
   15295 
   15296 		xmlBufAdd(target, &escape[0], 3);
   15297 	    }
   15298 	}
   15299     }
   15300     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   15301 	xmlBufContent(target)));
   15302     xmlBufFree(target);
   15303     xmlXPathReleaseObject(ctxt->context, str);
   15304 }
   15305 
   15306 /**
   15307  * xmlXPathRegisterAllFunctions:
   15308  * @ctxt:  the XPath context
   15309  *
   15310  * Registers all default XPath functions in this context
   15311  */
   15312 void
   15313 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
   15314 {
   15315     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
   15316                          xmlXPathBooleanFunction);
   15317     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
   15318                          xmlXPathCeilingFunction);
   15319     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
   15320                          xmlXPathCountFunction);
   15321     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
   15322                          xmlXPathConcatFunction);
   15323     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
   15324                          xmlXPathContainsFunction);
   15325     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
   15326                          xmlXPathIdFunction);
   15327     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
   15328                          xmlXPathFalseFunction);
   15329     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
   15330                          xmlXPathFloorFunction);
   15331     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
   15332                          xmlXPathLastFunction);
   15333     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
   15334                          xmlXPathLangFunction);
   15335     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
   15336                          xmlXPathLocalNameFunction);
   15337     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
   15338                          xmlXPathNotFunction);
   15339     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
   15340                          xmlXPathNameFunction);
   15341     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
   15342                          xmlXPathNamespaceURIFunction);
   15343     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
   15344                          xmlXPathNormalizeFunction);
   15345     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
   15346                          xmlXPathNumberFunction);
   15347     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
   15348                          xmlXPathPositionFunction);
   15349     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
   15350                          xmlXPathRoundFunction);
   15351     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
   15352                          xmlXPathStringFunction);
   15353     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
   15354                          xmlXPathStringLengthFunction);
   15355     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
   15356                          xmlXPathStartsWithFunction);
   15357     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
   15358                          xmlXPathSubstringFunction);
   15359     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
   15360                          xmlXPathSubstringBeforeFunction);
   15361     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
   15362                          xmlXPathSubstringAfterFunction);
   15363     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
   15364                          xmlXPathSumFunction);
   15365     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
   15366                          xmlXPathTrueFunction);
   15367     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
   15368                          xmlXPathTranslateFunction);
   15369 
   15370     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
   15371 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
   15372                          xmlXPathEscapeUriFunction);
   15373 }
   15374 
   15375 #endif /* LIBXML_XPATH_ENABLED */
   15376 #define bottom_xpath
   15377 #include "elfgcchack.h"
   15378