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 /* To avoid EBCDIC trouble when parsing on zOS */
     18 #if defined(__MVS__)
     19 #pragma convert("ISO8859-1")
     20 #endif
     21 
     22 #define IN_LIBXML
     23 #include "libxml.h"
     24 
     25 #include <limits.h>
     26 #include <string.h>
     27 #include <stddef.h>
     28 
     29 #ifdef HAVE_SYS_TYPES_H
     30 #include <sys/types.h>
     31 #endif
     32 #ifdef HAVE_MATH_H
     33 #include <math.h>
     34 #endif
     35 #ifdef HAVE_FLOAT_H
     36 #include <float.h>
     37 #endif
     38 #ifdef HAVE_CTYPE_H
     39 #include <ctype.h>
     40 #endif
     41 #ifdef HAVE_SIGNAL_H
     42 #include <signal.h>
     43 #endif
     44 
     45 #include <libxml/xmlmemory.h>
     46 #include <libxml/tree.h>
     47 #include <libxml/valid.h>
     48 #include <libxml/xpath.h>
     49 #include <libxml/xpathInternals.h>
     50 #include <libxml/parserInternals.h>
     51 #include <libxml/hash.h>
     52 #ifdef LIBXML_XPTR_ENABLED
     53 #include <libxml/xpointer.h>
     54 #endif
     55 #ifdef LIBXML_DEBUG_ENABLED
     56 #include <libxml/debugXML.h>
     57 #endif
     58 #include <libxml/xmlerror.h>
     59 #include <libxml/threads.h>
     60 #include <libxml/globals.h>
     61 #ifdef LIBXML_PATTERN_ENABLED
     62 #include <libxml/pattern.h>
     63 #endif
     64 
     65 #include "buf.h"
     66 
     67 #ifdef LIBXML_PATTERN_ENABLED
     68 #define XPATH_STREAMING
     69 #endif
     70 
     71 #define TODO								\
     72     xmlGenericError(xmlGenericErrorContext,				\
     73 	    "Unimplemented block at %s:%d\n",				\
     74             __FILE__, __LINE__);
     75 
     76 /**
     77  * WITH_TIM_SORT:
     78  *
     79  * Use the Timsort algorithm provided in timsort.h to sort
     80  * nodeset as this is a great improvement over the old Shell sort
     81  * used in xmlXPathNodeSetSort()
     82  */
     83 #define WITH_TIM_SORT
     84 
     85 /*
     86 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
     87 * If defined, this will use xmlXPathCmpNodesExt() instead of
     88 * xmlXPathCmpNodes(). The new function is optimized comparison of
     89 * non-element nodes; actually it will speed up comparison only if
     90 * xmlXPathOrderDocElems() was called in order to index the elements of
     91 * a tree in document order; Libxslt does such an indexing, thus it will
     92 * benefit from this optimization.
     93 */
     94 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
     95 
     96 /*
     97 * XP_OPTIMIZED_FILTER_FIRST:
     98 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
     99 * in a way, that it stop evaluation at the first node.
    100 */
    101 #define XP_OPTIMIZED_FILTER_FIRST
    102 
    103 /*
    104 * XP_DEBUG_OBJ_USAGE:
    105 * Internal flag to enable tracking of how much XPath objects have been
    106 * created.
    107 */
    108 /* #define XP_DEBUG_OBJ_USAGE */
    109 
    110 /*
    111  * XPATH_MAX_STEPS:
    112  * when compiling an XPath expression we arbitrary limit the maximum
    113  * number of step operation in the compiled expression. 1000000 is
    114  * an insanely large value which should never be reached under normal
    115  * circumstances
    116  */
    117 #define XPATH_MAX_STEPS 1000000
    118 
    119 /*
    120  * XPATH_MAX_STACK_DEPTH:
    121  * when evaluating an XPath expression we arbitrary limit the maximum
    122  * number of object allowed to be pushed on the stack. 1000000 is
    123  * an insanely large value which should never be reached under normal
    124  * circumstances
    125  */
    126 #define XPATH_MAX_STACK_DEPTH 1000000
    127 
    128 /*
    129  * XPATH_MAX_NODESET_LENGTH:
    130  * when evaluating an XPath expression nodesets are created and we
    131  * arbitrary limit the maximum length of those node set. 10000000 is
    132  * an insanely large value which should never be reached under normal
    133  * circumstances, one would first need to construct an in memory tree
    134  * with more than 10 millions nodes.
    135  */
    136 #define XPATH_MAX_NODESET_LENGTH 10000000
    137 
    138 /*
    139  * TODO:
    140  * There are a few spots where some tests are done which depend upon ascii
    141  * data.  These should be enhanced for full UTF8 support (see particularly
    142  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
    143  */
    144 
    145 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
    146 /**
    147  * xmlXPathCmpNodesExt:
    148  * @node1:  the first node
    149  * @node2:  the second node
    150  *
    151  * Compare two nodes w.r.t document order.
    152  * This one is optimized for handling of non-element nodes.
    153  *
    154  * Returns -2 in case of error 1 if first point < second point, 0 if
    155  *         it's the same node, -1 otherwise
    156  */
    157 static int
    158 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
    159     int depth1, depth2;
    160     int misc = 0, precedence1 = 0, precedence2 = 0;
    161     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
    162     xmlNodePtr cur, root;
    163     ptrdiff_t l1, l2;
    164 
    165     if ((node1 == NULL) || (node2 == NULL))
    166 	return(-2);
    167 
    168     if (node1 == node2)
    169 	return(0);
    170 
    171     /*
    172      * a couple of optimizations which will avoid computations in most cases
    173      */
    174     switch (node1->type) {
    175 	case XML_ELEMENT_NODE:
    176 	    if (node2->type == XML_ELEMENT_NODE) {
    177 		if ((0 > (ptrdiff_t) node1->content) &&
    178 		    (0 > (ptrdiff_t) node2->content) &&
    179 		    (node1->doc == node2->doc))
    180 		{
    181 		    l1 = -((ptrdiff_t) node1->content);
    182 		    l2 = -((ptrdiff_t) node2->content);
    183 		    if (l1 < l2)
    184 			return(1);
    185 		    if (l1 > l2)
    186 			return(-1);
    187 		} else
    188 		    goto turtle_comparison;
    189 	    }
    190 	    break;
    191 	case XML_ATTRIBUTE_NODE:
    192 	    precedence1 = 1; /* element is owner */
    193 	    miscNode1 = node1;
    194 	    node1 = node1->parent;
    195 	    misc = 1;
    196 	    break;
    197 	case XML_TEXT_NODE:
    198 	case XML_CDATA_SECTION_NODE:
    199 	case XML_COMMENT_NODE:
    200 	case XML_PI_NODE: {
    201 	    miscNode1 = node1;
    202 	    /*
    203 	    * Find nearest element node.
    204 	    */
    205 	    if (node1->prev != NULL) {
    206 		do {
    207 		    node1 = node1->prev;
    208 		    if (node1->type == XML_ELEMENT_NODE) {
    209 			precedence1 = 3; /* element in prev-sibl axis */
    210 			break;
    211 		    }
    212 		    if (node1->prev == NULL) {
    213 			precedence1 = 2; /* element is parent */
    214 			/*
    215 			* URGENT TODO: Are there any cases, where the
    216 			* parent of such a node is not an element node?
    217 			*/
    218 			node1 = node1->parent;
    219 			break;
    220 		    }
    221 		} while (1);
    222 	    } else {
    223 		precedence1 = 2; /* element is parent */
    224 		node1 = node1->parent;
    225 	    }
    226 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
    227 		(0 <= (ptrdiff_t) node1->content)) {
    228 		/*
    229 		* Fallback for whatever case.
    230 		*/
    231 		node1 = miscNode1;
    232 		precedence1 = 0;
    233 	    } else
    234 		misc = 1;
    235 	}
    236 	    break;
    237 	case XML_NAMESPACE_DECL:
    238 	    /*
    239 	    * TODO: why do we return 1 for namespace nodes?
    240 	    */
    241 	    return(1);
    242 	default:
    243 	    break;
    244     }
    245     switch (node2->type) {
    246 	case XML_ELEMENT_NODE:
    247 	    break;
    248 	case XML_ATTRIBUTE_NODE:
    249 	    precedence2 = 1; /* element is owner */
    250 	    miscNode2 = node2;
    251 	    node2 = node2->parent;
    252 	    misc = 1;
    253 	    break;
    254 	case XML_TEXT_NODE:
    255 	case XML_CDATA_SECTION_NODE:
    256 	case XML_COMMENT_NODE:
    257 	case XML_PI_NODE: {
    258 	    miscNode2 = node2;
    259 	    if (node2->prev != NULL) {
    260 		do {
    261 		    node2 = node2->prev;
    262 		    if (node2->type == XML_ELEMENT_NODE) {
    263 			precedence2 = 3; /* element in prev-sibl axis */
    264 			break;
    265 		    }
    266 		    if (node2->prev == NULL) {
    267 			precedence2 = 2; /* element is parent */
    268 			node2 = node2->parent;
    269 			break;
    270 		    }
    271 		} while (1);
    272 	    } else {
    273 		precedence2 = 2; /* element is parent */
    274 		node2 = node2->parent;
    275 	    }
    276 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
    277 		(0 <= (ptrdiff_t) node2->content))
    278 	    {
    279 		node2 = miscNode2;
    280 		precedence2 = 0;
    281 	    } else
    282 		misc = 1;
    283 	}
    284 	    break;
    285 	case XML_NAMESPACE_DECL:
    286 	    return(1);
    287 	default:
    288 	    break;
    289     }
    290     if (misc) {
    291 	if (node1 == node2) {
    292 	    if (precedence1 == precedence2) {
    293 		/*
    294 		* The ugly case; but normally there aren't many
    295 		* adjacent non-element nodes around.
    296 		*/
    297 		cur = miscNode2->prev;
    298 		while (cur != NULL) {
    299 		    if (cur == miscNode1)
    300 			return(1);
    301 		    if (cur->type == XML_ELEMENT_NODE)
    302 			return(-1);
    303 		    cur = cur->prev;
    304 		}
    305 		return (-1);
    306 	    } else {
    307 		/*
    308 		* Evaluate based on higher precedence wrt to the element.
    309 		* TODO: This assumes attributes are sorted before content.
    310 		*   Is this 100% correct?
    311 		*/
    312 		if (precedence1 < precedence2)
    313 		    return(1);
    314 		else
    315 		    return(-1);
    316 	    }
    317 	}
    318 	/*
    319 	* Special case: One of the helper-elements is contained by the other.
    320 	* <foo>
    321 	*   <node2>
    322 	*     <node1>Text-1(precedence1 == 2)</node1>
    323 	*   </node2>
    324 	*   Text-6(precedence2 == 3)
    325 	* </foo>
    326 	*/
    327 	if ((precedence2 == 3) && (precedence1 > 1)) {
    328 	    cur = node1->parent;
    329 	    while (cur) {
    330 		if (cur == node2)
    331 		    return(1);
    332 		cur = cur->parent;
    333 	    }
    334 	}
    335 	if ((precedence1 == 3) && (precedence2 > 1)) {
    336 	    cur = node2->parent;
    337 	    while (cur) {
    338 		if (cur == node1)
    339 		    return(-1);
    340 		cur = cur->parent;
    341 	    }
    342 	}
    343     }
    344 
    345     /*
    346      * Speedup using document order if availble.
    347      */
    348     if ((node1->type == XML_ELEMENT_NODE) &&
    349 	(node2->type == XML_ELEMENT_NODE) &&
    350 	(0 > (ptrdiff_t) node1->content) &&
    351 	(0 > (ptrdiff_t) node2->content) &&
    352 	(node1->doc == node2->doc)) {
    353 
    354 	l1 = -((ptrdiff_t) node1->content);
    355 	l2 = -((ptrdiff_t) node2->content);
    356 	if (l1 < l2)
    357 	    return(1);
    358 	if (l1 > l2)
    359 	    return(-1);
    360     }
    361 
    362 turtle_comparison:
    363 
    364     if (node1 == node2->prev)
    365 	return(1);
    366     if (node1 == node2->next)
    367 	return(-1);
    368     /*
    369      * compute depth to root
    370      */
    371     for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
    372 	if (cur->parent == node1)
    373 	    return(1);
    374 	depth2++;
    375     }
    376     root = cur;
    377     for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
    378 	if (cur->parent == node2)
    379 	    return(-1);
    380 	depth1++;
    381     }
    382     /*
    383      * Distinct document (or distinct entities :-( ) case.
    384      */
    385     if (root != cur) {
    386 	return(-2);
    387     }
    388     /*
    389      * get the nearest common ancestor.
    390      */
    391     while (depth1 > depth2) {
    392 	depth1--;
    393 	node1 = node1->parent;
    394     }
    395     while (depth2 > depth1) {
    396 	depth2--;
    397 	node2 = node2->parent;
    398     }
    399     while (node1->parent != node2->parent) {
    400 	node1 = node1->parent;
    401 	node2 = node2->parent;
    402 	/* should not happen but just in case ... */
    403 	if ((node1 == NULL) || (node2 == NULL))
    404 	    return(-2);
    405     }
    406     /*
    407      * Find who's first.
    408      */
    409     if (node1 == node2->prev)
    410 	return(1);
    411     if (node1 == node2->next)
    412 	return(-1);
    413     /*
    414      * Speedup using document order if availble.
    415      */
    416     if ((node1->type == XML_ELEMENT_NODE) &&
    417 	(node2->type == XML_ELEMENT_NODE) &&
    418 	(0 > (ptrdiff_t) node1->content) &&
    419 	(0 > (ptrdiff_t) node2->content) &&
    420 	(node1->doc == node2->doc)) {
    421 
    422 	l1 = -((ptrdiff_t) node1->content);
    423 	l2 = -((ptrdiff_t) node2->content);
    424 	if (l1 < l2)
    425 	    return(1);
    426 	if (l1 > l2)
    427 	    return(-1);
    428     }
    429 
    430     for (cur = node1->next;cur != NULL;cur = cur->next)
    431 	if (cur == node2)
    432 	    return(1);
    433     return(-1); /* assume there is no sibling list corruption */
    434 }
    435 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
    436 
    437 /*
    438  * Wrapper for the Timsort argorithm from timsort.h
    439  */
    440 #ifdef WITH_TIM_SORT
    441 #define SORT_NAME libxml_domnode
    442 #define SORT_TYPE xmlNodePtr
    443 /**
    444  * wrap_cmp:
    445  * @x: a node
    446  * @y: another node
    447  *
    448  * Comparison function for the Timsort implementation
    449  *
    450  * Returns -2 in case of error -1 if first point < second point, 0 if
    451  *         it's the same node, +1 otherwise
    452  */
    453 static
    454 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
    455 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
    456     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
    457     {
    458         int res = xmlXPathCmpNodesExt(x, y);
    459         return res == -2 ? res : -res;
    460     }
    461 #else
    462     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
    463     {
    464         int res = xmlXPathCmpNodes(x, y);
    465         return res == -2 ? res : -res;
    466     }
    467 #endif
    468 #define SORT_CMP(x, y)  (wrap_cmp(x, y))
    469 #include "timsort.h"
    470 #endif /* WITH_TIM_SORT */
    471 
    472 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
    473 
    474 /************************************************************************
    475  *									*
    476  *			Floating point stuff				*
    477  *									*
    478  ************************************************************************/
    479 
    480 #ifndef NAN
    481 #define NAN (0.0 / 0.0)
    482 #endif
    483 
    484 #ifndef INFINITY
    485 #define INFINITY HUGE_VAL
    486 #endif
    487 
    488 double xmlXPathNAN = NAN;
    489 double xmlXPathPINF = INFINITY;
    490 double xmlXPathNINF = -INFINITY;
    491 
    492 /**
    493  * xmlXPathInit:
    494  *
    495  * Initialize the XPath environment
    496  *
    497  * Does nothing but must be kept as public function.
    498  */
    499 void
    500 xmlXPathInit(void) {
    501 }
    502 
    503 /**
    504  * xmlXPathIsNaN:
    505  * @val:  a double value
    506  *
    507  * Returns 1 if the value is a NaN, 0 otherwise
    508  */
    509 int
    510 xmlXPathIsNaN(double val) {
    511 #ifdef isnan
    512     return isnan(val);
    513 #else
    514     return !(val == val);
    515 #endif
    516 }
    517 
    518 /**
    519  * xmlXPathIsInf:
    520  * @val:  a double value
    521  *
    522  * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
    523  */
    524 int
    525 xmlXPathIsInf(double val) {
    526 #ifdef isinf
    527     return isinf(val) ? (val > 0 ? 1 : -1) : 0;
    528 #else
    529     if (val >= HUGE_VAL)
    530         return 1;
    531     if (val <= -HUGE_VAL)
    532         return -1;
    533     return 0;
    534 #endif
    535 }
    536 
    537 #endif /* SCHEMAS or XPATH */
    538 
    539 #ifdef LIBXML_XPATH_ENABLED
    540 
    541 /*
    542  * TODO: when compatibility allows remove all "fake node libxslt" strings
    543  *       the test should just be name[0] = ' '
    544  */
    545 #ifdef DEBUG_XPATH_EXPRESSION
    546 #define DEBUG_STEP
    547 #define DEBUG_EXPR
    548 #define DEBUG_EVAL_COUNTS
    549 #endif
    550 
    551 static xmlNs xmlXPathXMLNamespaceStruct = {
    552     NULL,
    553     XML_NAMESPACE_DECL,
    554     XML_XML_NAMESPACE,
    555     BAD_CAST "xml",
    556     NULL,
    557     NULL
    558 };
    559 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
    560 #ifndef LIBXML_THREAD_ENABLED
    561 /*
    562  * Optimizer is disabled only when threaded apps are detected while
    563  * the library ain't compiled for thread safety.
    564  */
    565 static int xmlXPathDisableOptimizer = 0;
    566 #endif
    567 
    568 /************************************************************************
    569  *									*
    570  *			Error handling routines				*
    571  *									*
    572  ************************************************************************/
    573 
    574 /**
    575  * XP_ERRORNULL:
    576  * @X:  the error code
    577  *
    578  * Macro to raise an XPath error and return NULL.
    579  */
    580 #define XP_ERRORNULL(X)							\
    581     { xmlXPathErr(ctxt, X); return(NULL); }
    582 
    583 /*
    584  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
    585  */
    586 static const char *xmlXPathErrorMessages[] = {
    587     "Ok\n",
    588     "Number encoding\n",
    589     "Unfinished literal\n",
    590     "Start of literal\n",
    591     "Expected $ for variable reference\n",
    592     "Undefined variable\n",
    593     "Invalid predicate\n",
    594     "Invalid expression\n",
    595     "Missing closing curly brace\n",
    596     "Unregistered function\n",
    597     "Invalid operand\n",
    598     "Invalid type\n",
    599     "Invalid number of arguments\n",
    600     "Invalid context size\n",
    601     "Invalid context position\n",
    602     "Memory allocation error\n",
    603     "Syntax error\n",
    604     "Resource error\n",
    605     "Sub resource error\n",
    606     "Undefined namespace prefix\n",
    607     "Encoding error\n",
    608     "Char out of XML range\n",
    609     "Invalid or incomplete context\n",
    610     "Stack usage error\n",
    611     "Forbidden variable\n",
    612     "?? Unknown error ??\n"	/* Must be last in the list! */
    613 };
    614 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
    615 		   sizeof(xmlXPathErrorMessages[0])) - 1)
    616 /**
    617  * xmlXPathErrMemory:
    618  * @ctxt:  an XPath context
    619  * @extra:  extra informations
    620  *
    621  * Handle a redefinition of attribute error
    622  */
    623 static void
    624 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
    625 {
    626     if (ctxt != NULL) {
    627         if (extra) {
    628             xmlChar buf[200];
    629 
    630             xmlStrPrintf(buf, 200,
    631                          "Memory allocation failed : %s\n",
    632                          extra);
    633             ctxt->lastError.message = (char *) xmlStrdup(buf);
    634         } else {
    635             ctxt->lastError.message = (char *)
    636 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
    637         }
    638         ctxt->lastError.domain = XML_FROM_XPATH;
    639         ctxt->lastError.code = XML_ERR_NO_MEMORY;
    640 	if (ctxt->error != NULL)
    641 	    ctxt->error(ctxt->userData, &ctxt->lastError);
    642     } else {
    643         if (extra)
    644             __xmlRaiseError(NULL, NULL, NULL,
    645                             NULL, NULL, XML_FROM_XPATH,
    646                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
    647                             extra, NULL, NULL, 0, 0,
    648                             "Memory allocation failed : %s\n", extra);
    649         else
    650             __xmlRaiseError(NULL, NULL, NULL,
    651                             NULL, NULL, XML_FROM_XPATH,
    652                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
    653                             NULL, NULL, NULL, 0, 0,
    654                             "Memory allocation failed\n");
    655     }
    656 }
    657 
    658 /**
    659  * xmlXPathPErrMemory:
    660  * @ctxt:  an XPath parser context
    661  * @extra:  extra informations
    662  *
    663  * Handle a redefinition of attribute error
    664  */
    665 static void
    666 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
    667 {
    668     if (ctxt == NULL)
    669 	xmlXPathErrMemory(NULL, extra);
    670     else {
    671 	ctxt->error = XPATH_MEMORY_ERROR;
    672 	xmlXPathErrMemory(ctxt->context, extra);
    673     }
    674 }
    675 
    676 /**
    677  * xmlXPathErr:
    678  * @ctxt:  a XPath parser context
    679  * @error:  the error code
    680  *
    681  * Handle an XPath error
    682  */
    683 void
    684 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
    685 {
    686     if ((error < 0) || (error > MAXERRNO))
    687 	error = MAXERRNO;
    688     if (ctxt == NULL) {
    689 	__xmlRaiseError(NULL, NULL, NULL,
    690 			NULL, NULL, XML_FROM_XPATH,
    691 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    692 			XML_ERR_ERROR, NULL, 0,
    693 			NULL, NULL, NULL, 0, 0,
    694 			"%s", xmlXPathErrorMessages[error]);
    695 	return;
    696     }
    697     ctxt->error = error;
    698     if (ctxt->context == NULL) {
    699 	__xmlRaiseError(NULL, NULL, NULL,
    700 			NULL, NULL, XML_FROM_XPATH,
    701 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    702 			XML_ERR_ERROR, NULL, 0,
    703 			(const char *) ctxt->base, NULL, NULL,
    704 			ctxt->cur - ctxt->base, 0,
    705 			"%s", xmlXPathErrorMessages[error]);
    706 	return;
    707     }
    708 
    709     /* cleanup current last error */
    710     xmlResetError(&ctxt->context->lastError);
    711 
    712     ctxt->context->lastError.domain = XML_FROM_XPATH;
    713     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
    714                            XPATH_EXPRESSION_OK;
    715     ctxt->context->lastError.level = XML_ERR_ERROR;
    716     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
    717     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
    718     ctxt->context->lastError.node = ctxt->context->debugNode;
    719     if (ctxt->context->error != NULL) {
    720 	ctxt->context->error(ctxt->context->userData,
    721 	                     &ctxt->context->lastError);
    722     } else {
    723 	__xmlRaiseError(NULL, NULL, NULL,
    724 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
    725 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    726 			XML_ERR_ERROR, NULL, 0,
    727 			(const char *) ctxt->base, NULL, NULL,
    728 			ctxt->cur - ctxt->base, 0,
    729 			"%s", xmlXPathErrorMessages[error]);
    730     }
    731 
    732 }
    733 
    734 /**
    735  * xmlXPatherror:
    736  * @ctxt:  the XPath Parser context
    737  * @file:  the file name
    738  * @line:  the line number
    739  * @no:  the error number
    740  *
    741  * Formats an error message.
    742  */
    743 void
    744 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
    745               int line ATTRIBUTE_UNUSED, int no) {
    746     xmlXPathErr(ctxt, no);
    747 }
    748 
    749 /************************************************************************
    750  *									*
    751  *			Utilities					*
    752  *									*
    753  ************************************************************************/
    754 
    755 /**
    756  * xsltPointerList:
    757  *
    758  * Pointer-list for various purposes.
    759  */
    760 typedef struct _xmlPointerList xmlPointerList;
    761 typedef xmlPointerList *xmlPointerListPtr;
    762 struct _xmlPointerList {
    763     void **items;
    764     int number;
    765     int size;
    766 };
    767 /*
    768 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
    769 * and here, we should make the functions public.
    770 */
    771 static int
    772 xmlPointerListAddSize(xmlPointerListPtr list,
    773 		       void *item,
    774 		       int initialSize)
    775 {
    776     if (list->items == NULL) {
    777 	if (initialSize <= 0)
    778 	    initialSize = 1;
    779 	list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
    780 	if (list->items == NULL) {
    781 	    xmlXPathErrMemory(NULL,
    782 		"xmlPointerListCreate: allocating item\n");
    783 	    return(-1);
    784 	}
    785 	list->number = 0;
    786 	list->size = initialSize;
    787     } else if (list->size <= list->number) {
    788         if (list->size > 50000000) {
    789 	    xmlXPathErrMemory(NULL,
    790 		"xmlPointerListAddSize: re-allocating item\n");
    791             return(-1);
    792         }
    793 	list->size *= 2;
    794 	list->items = (void **) xmlRealloc(list->items,
    795 	    list->size * sizeof(void *));
    796 	if (list->items == NULL) {
    797 	    xmlXPathErrMemory(NULL,
    798 		"xmlPointerListAddSize: re-allocating item\n");
    799 	    list->size = 0;
    800 	    return(-1);
    801 	}
    802     }
    803     list->items[list->number++] = item;
    804     return(0);
    805 }
    806 
    807 /**
    808  * xsltPointerListCreate:
    809  *
    810  * Creates an xsltPointerList structure.
    811  *
    812  * Returns a xsltPointerList structure or NULL in case of an error.
    813  */
    814 static xmlPointerListPtr
    815 xmlPointerListCreate(int initialSize)
    816 {
    817     xmlPointerListPtr ret;
    818 
    819     ret = xmlMalloc(sizeof(xmlPointerList));
    820     if (ret == NULL) {
    821 	xmlXPathErrMemory(NULL,
    822 	    "xmlPointerListCreate: allocating item\n");
    823 	return (NULL);
    824     }
    825     memset(ret, 0, sizeof(xmlPointerList));
    826     if (initialSize > 0) {
    827 	xmlPointerListAddSize(ret, NULL, initialSize);
    828 	ret->number = 0;
    829     }
    830     return (ret);
    831 }
    832 
    833 /**
    834  * xsltPointerListFree:
    835  *
    836  * Frees the xsltPointerList structure. This does not free
    837  * the content of the list.
    838  */
    839 static void
    840 xmlPointerListFree(xmlPointerListPtr list)
    841 {
    842     if (list == NULL)
    843 	return;
    844     if (list->items != NULL)
    845 	xmlFree(list->items);
    846     xmlFree(list);
    847 }
    848 
    849 /************************************************************************
    850  *									*
    851  *			Parser Types					*
    852  *									*
    853  ************************************************************************/
    854 
    855 /*
    856  * Types are private:
    857  */
    858 
    859 typedef enum {
    860     XPATH_OP_END=0,
    861     XPATH_OP_AND,
    862     XPATH_OP_OR,
    863     XPATH_OP_EQUAL,
    864     XPATH_OP_CMP,
    865     XPATH_OP_PLUS,
    866     XPATH_OP_MULT,
    867     XPATH_OP_UNION,
    868     XPATH_OP_ROOT,
    869     XPATH_OP_NODE,
    870     XPATH_OP_RESET, /* 10 */
    871     XPATH_OP_COLLECT,
    872     XPATH_OP_VALUE, /* 12 */
    873     XPATH_OP_VARIABLE,
    874     XPATH_OP_FUNCTION,
    875     XPATH_OP_ARG,
    876     XPATH_OP_PREDICATE,
    877     XPATH_OP_FILTER, /* 17 */
    878     XPATH_OP_SORT /* 18 */
    879 #ifdef LIBXML_XPTR_ENABLED
    880     ,XPATH_OP_RANGETO
    881 #endif
    882 } xmlXPathOp;
    883 
    884 typedef enum {
    885     AXIS_ANCESTOR = 1,
    886     AXIS_ANCESTOR_OR_SELF,
    887     AXIS_ATTRIBUTE,
    888     AXIS_CHILD,
    889     AXIS_DESCENDANT,
    890     AXIS_DESCENDANT_OR_SELF,
    891     AXIS_FOLLOWING,
    892     AXIS_FOLLOWING_SIBLING,
    893     AXIS_NAMESPACE,
    894     AXIS_PARENT,
    895     AXIS_PRECEDING,
    896     AXIS_PRECEDING_SIBLING,
    897     AXIS_SELF
    898 } xmlXPathAxisVal;
    899 
    900 typedef enum {
    901     NODE_TEST_NONE = 0,
    902     NODE_TEST_TYPE = 1,
    903     NODE_TEST_PI = 2,
    904     NODE_TEST_ALL = 3,
    905     NODE_TEST_NS = 4,
    906     NODE_TEST_NAME = 5
    907 } xmlXPathTestVal;
    908 
    909 typedef enum {
    910     NODE_TYPE_NODE = 0,
    911     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
    912     NODE_TYPE_TEXT = XML_TEXT_NODE,
    913     NODE_TYPE_PI = XML_PI_NODE
    914 } xmlXPathTypeVal;
    915 
    916 typedef struct _xmlXPathStepOp xmlXPathStepOp;
    917 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
    918 struct _xmlXPathStepOp {
    919     xmlXPathOp op;		/* The identifier of the operation */
    920     int ch1;			/* First child */
    921     int ch2;			/* Second child */
    922     int value;
    923     int value2;
    924     int value3;
    925     void *value4;
    926     void *value5;
    927     xmlXPathFunction cache;
    928     void *cacheURI;
    929 };
    930 
    931 struct _xmlXPathCompExpr {
    932     int nbStep;			/* Number of steps in this expression */
    933     int maxStep;		/* Maximum number of steps allocated */
    934     xmlXPathStepOp *steps;	/* ops for computation of this expression */
    935     int last;			/* index of last step in expression */
    936     xmlChar *expr;		/* the expression being computed */
    937     xmlDictPtr dict;		/* the dictionary to use if any */
    938 #ifdef DEBUG_EVAL_COUNTS
    939     int nb;
    940     xmlChar *string;
    941 #endif
    942 #ifdef XPATH_STREAMING
    943     xmlPatternPtr stream;
    944 #endif
    945 };
    946 
    947 /************************************************************************
    948  *									*
    949  *			Forward declarations				*
    950  *									*
    951  ************************************************************************/
    952 static void
    953 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
    954 static void
    955 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
    956 static int
    957 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
    958                         xmlXPathStepOpPtr op, xmlNodePtr *first);
    959 static int
    960 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
    961 			    xmlXPathStepOpPtr op,
    962 			    int isPredicate);
    963 static void
    964 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
    965 
    966 /************************************************************************
    967  *									*
    968  *			Parser Type functions				*
    969  *									*
    970  ************************************************************************/
    971 
    972 /**
    973  * xmlXPathNewCompExpr:
    974  *
    975  * Create a new Xpath component
    976  *
    977  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
    978  */
    979 static xmlXPathCompExprPtr
    980 xmlXPathNewCompExpr(void) {
    981     xmlXPathCompExprPtr cur;
    982 
    983     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
    984     if (cur == NULL) {
    985         xmlXPathErrMemory(NULL, "allocating component\n");
    986 	return(NULL);
    987     }
    988     memset(cur, 0, sizeof(xmlXPathCompExpr));
    989     cur->maxStep = 10;
    990     cur->nbStep = 0;
    991     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
    992 	                                   sizeof(xmlXPathStepOp));
    993     if (cur->steps == NULL) {
    994         xmlXPathErrMemory(NULL, "allocating steps\n");
    995 	xmlFree(cur);
    996 	return(NULL);
    997     }
    998     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
    999     cur->last = -1;
   1000 #ifdef DEBUG_EVAL_COUNTS
   1001     cur->nb = 0;
   1002 #endif
   1003     return(cur);
   1004 }
   1005 
   1006 /**
   1007  * xmlXPathFreeCompExpr:
   1008  * @comp:  an XPATH comp
   1009  *
   1010  * Free up the memory allocated by @comp
   1011  */
   1012 void
   1013 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
   1014 {
   1015     xmlXPathStepOpPtr op;
   1016     int i;
   1017 
   1018     if (comp == NULL)
   1019         return;
   1020     if (comp->dict == NULL) {
   1021 	for (i = 0; i < comp->nbStep; i++) {
   1022 	    op = &comp->steps[i];
   1023 	    if (op->value4 != NULL) {
   1024 		if (op->op == XPATH_OP_VALUE)
   1025 		    xmlXPathFreeObject(op->value4);
   1026 		else
   1027 		    xmlFree(op->value4);
   1028 	    }
   1029 	    if (op->value5 != NULL)
   1030 		xmlFree(op->value5);
   1031 	}
   1032     } else {
   1033 	for (i = 0; i < comp->nbStep; i++) {
   1034 	    op = &comp->steps[i];
   1035 	    if (op->value4 != NULL) {
   1036 		if (op->op == XPATH_OP_VALUE)
   1037 		    xmlXPathFreeObject(op->value4);
   1038 	    }
   1039 	}
   1040         xmlDictFree(comp->dict);
   1041     }
   1042     if (comp->steps != NULL) {
   1043         xmlFree(comp->steps);
   1044     }
   1045 #ifdef DEBUG_EVAL_COUNTS
   1046     if (comp->string != NULL) {
   1047         xmlFree(comp->string);
   1048     }
   1049 #endif
   1050 #ifdef XPATH_STREAMING
   1051     if (comp->stream != NULL) {
   1052         xmlFreePatternList(comp->stream);
   1053     }
   1054 #endif
   1055     if (comp->expr != NULL) {
   1056         xmlFree(comp->expr);
   1057     }
   1058 
   1059     xmlFree(comp);
   1060 }
   1061 
   1062 /**
   1063  * xmlXPathCompExprAdd:
   1064  * @comp:  the compiled expression
   1065  * @ch1: first child index
   1066  * @ch2: second child index
   1067  * @op:  an op
   1068  * @value:  the first int value
   1069  * @value2:  the second int value
   1070  * @value3:  the third int value
   1071  * @value4:  the first string value
   1072  * @value5:  the second string value
   1073  *
   1074  * Add a step to an XPath Compiled Expression
   1075  *
   1076  * Returns -1 in case of failure, the index otherwise
   1077  */
   1078 static int
   1079 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
   1080    xmlXPathOp op, int value,
   1081    int value2, int value3, void *value4, void *value5) {
   1082     if (comp->nbStep >= comp->maxStep) {
   1083 	xmlXPathStepOp *real;
   1084 
   1085         if (comp->maxStep >= XPATH_MAX_STEPS) {
   1086 	    xmlXPathErrMemory(NULL, "adding step\n");
   1087 	    return(-1);
   1088         }
   1089 	comp->maxStep *= 2;
   1090 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
   1091 		                      comp->maxStep * sizeof(xmlXPathStepOp));
   1092 	if (real == NULL) {
   1093 	    comp->maxStep /= 2;
   1094 	    xmlXPathErrMemory(NULL, "adding step\n");
   1095 	    return(-1);
   1096 	}
   1097 	comp->steps = real;
   1098     }
   1099     comp->last = comp->nbStep;
   1100     comp->steps[comp->nbStep].ch1 = ch1;
   1101     comp->steps[comp->nbStep].ch2 = ch2;
   1102     comp->steps[comp->nbStep].op = op;
   1103     comp->steps[comp->nbStep].value = value;
   1104     comp->steps[comp->nbStep].value2 = value2;
   1105     comp->steps[comp->nbStep].value3 = value3;
   1106     if ((comp->dict != NULL) &&
   1107         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
   1108 	 (op == XPATH_OP_COLLECT))) {
   1109         if (value4 != NULL) {
   1110 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
   1111 	        (void *)xmlDictLookup(comp->dict, value4, -1);
   1112 	    xmlFree(value4);
   1113 	} else
   1114 	    comp->steps[comp->nbStep].value4 = NULL;
   1115         if (value5 != NULL) {
   1116 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
   1117 	        (void *)xmlDictLookup(comp->dict, value5, -1);
   1118 	    xmlFree(value5);
   1119 	} else
   1120 	    comp->steps[comp->nbStep].value5 = NULL;
   1121     } else {
   1122 	comp->steps[comp->nbStep].value4 = value4;
   1123 	comp->steps[comp->nbStep].value5 = value5;
   1124     }
   1125     comp->steps[comp->nbStep].cache = NULL;
   1126     return(comp->nbStep++);
   1127 }
   1128 
   1129 /**
   1130  * xmlXPathCompSwap:
   1131  * @comp:  the compiled expression
   1132  * @op: operation index
   1133  *
   1134  * Swaps 2 operations in the compiled expression
   1135  */
   1136 static void
   1137 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
   1138     int tmp;
   1139 
   1140 #ifndef LIBXML_THREAD_ENABLED
   1141     /*
   1142      * Since this manipulates possibly shared variables, this is
   1143      * disabled if one detects that the library is used in a multithreaded
   1144      * application
   1145      */
   1146     if (xmlXPathDisableOptimizer)
   1147 	return;
   1148 #endif
   1149 
   1150     tmp = op->ch1;
   1151     op->ch1 = op->ch2;
   1152     op->ch2 = tmp;
   1153 }
   1154 
   1155 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
   1156     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
   1157 	                (op), (val), (val2), (val3), (val4), (val5))
   1158 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
   1159     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
   1160 	                (op), (val), (val2), (val3), (val4), (val5))
   1161 
   1162 #define PUSH_LEAVE_EXPR(op, val, val2)					\
   1163 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
   1164 
   1165 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
   1166 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
   1167 
   1168 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
   1169 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
   1170 			(val), (val2), 0 ,NULL ,NULL)
   1171 
   1172 /************************************************************************
   1173  *									*
   1174  *		XPath object cache structures				*
   1175  *									*
   1176  ************************************************************************/
   1177 
   1178 /* #define XP_DEFAULT_CACHE_ON */
   1179 
   1180 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
   1181 
   1182 typedef struct _xmlXPathContextCache xmlXPathContextCache;
   1183 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
   1184 struct _xmlXPathContextCache {
   1185     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
   1186     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
   1187     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
   1188     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
   1189     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
   1190     int maxNodeset;
   1191     int maxString;
   1192     int maxBoolean;
   1193     int maxNumber;
   1194     int maxMisc;
   1195 #ifdef XP_DEBUG_OBJ_USAGE
   1196     int dbgCachedAll;
   1197     int dbgCachedNodeset;
   1198     int dbgCachedString;
   1199     int dbgCachedBool;
   1200     int dbgCachedNumber;
   1201     int dbgCachedPoint;
   1202     int dbgCachedRange;
   1203     int dbgCachedLocset;
   1204     int dbgCachedUsers;
   1205     int dbgCachedXSLTTree;
   1206     int dbgCachedUndefined;
   1207 
   1208 
   1209     int dbgReusedAll;
   1210     int dbgReusedNodeset;
   1211     int dbgReusedString;
   1212     int dbgReusedBool;
   1213     int dbgReusedNumber;
   1214     int dbgReusedPoint;
   1215     int dbgReusedRange;
   1216     int dbgReusedLocset;
   1217     int dbgReusedUsers;
   1218     int dbgReusedXSLTTree;
   1219     int dbgReusedUndefined;
   1220 
   1221 #endif
   1222 };
   1223 
   1224 /************************************************************************
   1225  *									*
   1226  *		Debugging related functions				*
   1227  *									*
   1228  ************************************************************************/
   1229 
   1230 #define STRANGE							\
   1231     xmlGenericError(xmlGenericErrorContext,				\
   1232 	    "Internal error at %s:%d\n",				\
   1233             __FILE__, __LINE__);
   1234 
   1235 #ifdef LIBXML_DEBUG_ENABLED
   1236 static void
   1237 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
   1238     int i;
   1239     char shift[100];
   1240 
   1241     for (i = 0;((i < depth) && (i < 25));i++)
   1242         shift[2 * i] = shift[2 * i + 1] = ' ';
   1243     shift[2 * i] = shift[2 * i + 1] = 0;
   1244     if (cur == NULL) {
   1245 	fprintf(output, "%s", shift);
   1246 	fprintf(output, "Node is NULL !\n");
   1247 	return;
   1248 
   1249     }
   1250 
   1251     if ((cur->type == XML_DOCUMENT_NODE) ||
   1252 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
   1253 	fprintf(output, "%s", shift);
   1254 	fprintf(output, " /\n");
   1255     } else if (cur->type == XML_ATTRIBUTE_NODE)
   1256 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
   1257     else
   1258 	xmlDebugDumpOneNode(output, cur, depth);
   1259 }
   1260 static void
   1261 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
   1262     xmlNodePtr tmp;
   1263     int i;
   1264     char shift[100];
   1265 
   1266     for (i = 0;((i < depth) && (i < 25));i++)
   1267         shift[2 * i] = shift[2 * i + 1] = ' ';
   1268     shift[2 * i] = shift[2 * i + 1] = 0;
   1269     if (cur == NULL) {
   1270 	fprintf(output, "%s", shift);
   1271 	fprintf(output, "Node is NULL !\n");
   1272 	return;
   1273 
   1274     }
   1275 
   1276     while (cur != NULL) {
   1277 	tmp = cur;
   1278 	cur = cur->next;
   1279 	xmlDebugDumpOneNode(output, tmp, depth);
   1280     }
   1281 }
   1282 
   1283 static void
   1284 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
   1285     int i;
   1286     char shift[100];
   1287 
   1288     for (i = 0;((i < depth) && (i < 25));i++)
   1289         shift[2 * i] = shift[2 * i + 1] = ' ';
   1290     shift[2 * i] = shift[2 * i + 1] = 0;
   1291 
   1292     if (cur == NULL) {
   1293 	fprintf(output, "%s", shift);
   1294 	fprintf(output, "NodeSet is NULL !\n");
   1295 	return;
   1296 
   1297     }
   1298 
   1299     if (cur != NULL) {
   1300 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
   1301 	for (i = 0;i < cur->nodeNr;i++) {
   1302 	    fprintf(output, "%s", shift);
   1303 	    fprintf(output, "%d", i + 1);
   1304 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
   1305 	}
   1306     }
   1307 }
   1308 
   1309 static void
   1310 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
   1311     int i;
   1312     char shift[100];
   1313 
   1314     for (i = 0;((i < depth) && (i < 25));i++)
   1315         shift[2 * i] = shift[2 * i + 1] = ' ';
   1316     shift[2 * i] = shift[2 * i + 1] = 0;
   1317 
   1318     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
   1319 	fprintf(output, "%s", shift);
   1320 	fprintf(output, "Value Tree is NULL !\n");
   1321 	return;
   1322 
   1323     }
   1324 
   1325     fprintf(output, "%s", shift);
   1326     fprintf(output, "%d", i + 1);
   1327     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
   1328 }
   1329 #if defined(LIBXML_XPTR_ENABLED)
   1330 static void
   1331 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
   1332     int i;
   1333     char shift[100];
   1334 
   1335     for (i = 0;((i < depth) && (i < 25));i++)
   1336         shift[2 * i] = shift[2 * i + 1] = ' ';
   1337     shift[2 * i] = shift[2 * i + 1] = 0;
   1338 
   1339     if (cur == NULL) {
   1340 	fprintf(output, "%s", shift);
   1341 	fprintf(output, "LocationSet is NULL !\n");
   1342 	return;
   1343 
   1344     }
   1345 
   1346     for (i = 0;i < cur->locNr;i++) {
   1347 	fprintf(output, "%s", shift);
   1348         fprintf(output, "%d : ", i + 1);
   1349 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
   1350     }
   1351 }
   1352 #endif /* LIBXML_XPTR_ENABLED */
   1353 
   1354 /**
   1355  * xmlXPathDebugDumpObject:
   1356  * @output:  the FILE * to dump the output
   1357  * @cur:  the object to inspect
   1358  * @depth:  indentation level
   1359  *
   1360  * Dump the content of the object for debugging purposes
   1361  */
   1362 void
   1363 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
   1364     int i;
   1365     char shift[100];
   1366 
   1367     if (output == NULL) return;
   1368 
   1369     for (i = 0;((i < depth) && (i < 25));i++)
   1370         shift[2 * i] = shift[2 * i + 1] = ' ';
   1371     shift[2 * i] = shift[2 * i + 1] = 0;
   1372 
   1373 
   1374     fprintf(output, "%s", shift);
   1375 
   1376     if (cur == NULL) {
   1377         fprintf(output, "Object is empty (NULL)\n");
   1378 	return;
   1379     }
   1380     switch(cur->type) {
   1381         case XPATH_UNDEFINED:
   1382 	    fprintf(output, "Object is uninitialized\n");
   1383 	    break;
   1384         case XPATH_NODESET:
   1385 	    fprintf(output, "Object is a Node Set :\n");
   1386 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
   1387 	    break;
   1388 	case XPATH_XSLT_TREE:
   1389 	    fprintf(output, "Object is an XSLT value tree :\n");
   1390 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
   1391 	    break;
   1392         case XPATH_BOOLEAN:
   1393 	    fprintf(output, "Object is a Boolean : ");
   1394 	    if (cur->boolval) fprintf(output, "true\n");
   1395 	    else fprintf(output, "false\n");
   1396 	    break;
   1397         case XPATH_NUMBER:
   1398 	    switch (xmlXPathIsInf(cur->floatval)) {
   1399 	    case 1:
   1400 		fprintf(output, "Object is a number : Infinity\n");
   1401 		break;
   1402 	    case -1:
   1403 		fprintf(output, "Object is a number : -Infinity\n");
   1404 		break;
   1405 	    default:
   1406 		if (xmlXPathIsNaN(cur->floatval)) {
   1407 		    fprintf(output, "Object is a number : NaN\n");
   1408 		} else if (cur->floatval == 0) {
   1409                     /* Omit sign for negative zero. */
   1410 		    fprintf(output, "Object is a number : 0\n");
   1411 		} else {
   1412 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
   1413 		}
   1414 	    }
   1415 	    break;
   1416         case XPATH_STRING:
   1417 	    fprintf(output, "Object is a string : ");
   1418 	    xmlDebugDumpString(output, cur->stringval);
   1419 	    fprintf(output, "\n");
   1420 	    break;
   1421 	case XPATH_POINT:
   1422 	    fprintf(output, "Object is a point : index %d in node", cur->index);
   1423 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
   1424 	    fprintf(output, "\n");
   1425 	    break;
   1426 	case XPATH_RANGE:
   1427 	    if ((cur->user2 == NULL) ||
   1428 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
   1429 		fprintf(output, "Object is a collapsed range :\n");
   1430 		fprintf(output, "%s", shift);
   1431 		if (cur->index >= 0)
   1432 		    fprintf(output, "index %d in ", cur->index);
   1433 		fprintf(output, "node\n");
   1434 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
   1435 			              depth + 1);
   1436 	    } else  {
   1437 		fprintf(output, "Object is a range :\n");
   1438 		fprintf(output, "%s", shift);
   1439 		fprintf(output, "From ");
   1440 		if (cur->index >= 0)
   1441 		    fprintf(output, "index %d in ", cur->index);
   1442 		fprintf(output, "node\n");
   1443 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
   1444 			              depth + 1);
   1445 		fprintf(output, "%s", shift);
   1446 		fprintf(output, "To ");
   1447 		if (cur->index2 >= 0)
   1448 		    fprintf(output, "index %d in ", cur->index2);
   1449 		fprintf(output, "node\n");
   1450 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
   1451 			              depth + 1);
   1452 		fprintf(output, "\n");
   1453 	    }
   1454 	    break;
   1455 	case XPATH_LOCATIONSET:
   1456 #if defined(LIBXML_XPTR_ENABLED)
   1457 	    fprintf(output, "Object is a Location Set:\n");
   1458 	    xmlXPathDebugDumpLocationSet(output,
   1459 		    (xmlLocationSetPtr) cur->user, depth);
   1460 #endif
   1461 	    break;
   1462 	case XPATH_USERS:
   1463 	    fprintf(output, "Object is user defined\n");
   1464 	    break;
   1465     }
   1466 }
   1467 
   1468 static void
   1469 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
   1470 	                     xmlXPathStepOpPtr op, int depth) {
   1471     int i;
   1472     char shift[100];
   1473 
   1474     for (i = 0;((i < depth) && (i < 25));i++)
   1475         shift[2 * i] = shift[2 * i + 1] = ' ';
   1476     shift[2 * i] = shift[2 * i + 1] = 0;
   1477 
   1478     fprintf(output, "%s", shift);
   1479     if (op == NULL) {
   1480 	fprintf(output, "Step is NULL\n");
   1481 	return;
   1482     }
   1483     switch (op->op) {
   1484         case XPATH_OP_END:
   1485 	    fprintf(output, "END"); break;
   1486         case XPATH_OP_AND:
   1487 	    fprintf(output, "AND"); break;
   1488         case XPATH_OP_OR:
   1489 	    fprintf(output, "OR"); break;
   1490         case XPATH_OP_EQUAL:
   1491 	     if (op->value)
   1492 		 fprintf(output, "EQUAL =");
   1493 	     else
   1494 		 fprintf(output, "EQUAL !=");
   1495 	     break;
   1496         case XPATH_OP_CMP:
   1497 	     if (op->value)
   1498 		 fprintf(output, "CMP <");
   1499 	     else
   1500 		 fprintf(output, "CMP >");
   1501 	     if (!op->value2)
   1502 		 fprintf(output, "=");
   1503 	     break;
   1504         case XPATH_OP_PLUS:
   1505 	     if (op->value == 0)
   1506 		 fprintf(output, "PLUS -");
   1507 	     else if (op->value == 1)
   1508 		 fprintf(output, "PLUS +");
   1509 	     else if (op->value == 2)
   1510 		 fprintf(output, "PLUS unary -");
   1511 	     else if (op->value == 3)
   1512 		 fprintf(output, "PLUS unary - -");
   1513 	     break;
   1514         case XPATH_OP_MULT:
   1515 	     if (op->value == 0)
   1516 		 fprintf(output, "MULT *");
   1517 	     else if (op->value == 1)
   1518 		 fprintf(output, "MULT div");
   1519 	     else
   1520 		 fprintf(output, "MULT mod");
   1521 	     break;
   1522         case XPATH_OP_UNION:
   1523 	     fprintf(output, "UNION"); break;
   1524         case XPATH_OP_ROOT:
   1525 	     fprintf(output, "ROOT"); break;
   1526         case XPATH_OP_NODE:
   1527 	     fprintf(output, "NODE"); break;
   1528         case XPATH_OP_RESET:
   1529 	     fprintf(output, "RESET"); break;
   1530         case XPATH_OP_SORT:
   1531 	     fprintf(output, "SORT"); break;
   1532         case XPATH_OP_COLLECT: {
   1533 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
   1534 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
   1535 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
   1536 	    const xmlChar *prefix = op->value4;
   1537 	    const xmlChar *name = op->value5;
   1538 
   1539 	    fprintf(output, "COLLECT ");
   1540 	    switch (axis) {
   1541 		case AXIS_ANCESTOR:
   1542 		    fprintf(output, " 'ancestors' "); break;
   1543 		case AXIS_ANCESTOR_OR_SELF:
   1544 		    fprintf(output, " 'ancestors-or-self' "); break;
   1545 		case AXIS_ATTRIBUTE:
   1546 		    fprintf(output, " 'attributes' "); break;
   1547 		case AXIS_CHILD:
   1548 		    fprintf(output, " 'child' "); break;
   1549 		case AXIS_DESCENDANT:
   1550 		    fprintf(output, " 'descendant' "); break;
   1551 		case AXIS_DESCENDANT_OR_SELF:
   1552 		    fprintf(output, " 'descendant-or-self' "); break;
   1553 		case AXIS_FOLLOWING:
   1554 		    fprintf(output, " 'following' "); break;
   1555 		case AXIS_FOLLOWING_SIBLING:
   1556 		    fprintf(output, " 'following-siblings' "); break;
   1557 		case AXIS_NAMESPACE:
   1558 		    fprintf(output, " 'namespace' "); break;
   1559 		case AXIS_PARENT:
   1560 		    fprintf(output, " 'parent' "); break;
   1561 		case AXIS_PRECEDING:
   1562 		    fprintf(output, " 'preceding' "); break;
   1563 		case AXIS_PRECEDING_SIBLING:
   1564 		    fprintf(output, " 'preceding-sibling' "); break;
   1565 		case AXIS_SELF:
   1566 		    fprintf(output, " 'self' "); break;
   1567 	    }
   1568 	    switch (test) {
   1569                 case NODE_TEST_NONE:
   1570 		    fprintf(output, "'none' "); break;
   1571                 case NODE_TEST_TYPE:
   1572 		    fprintf(output, "'type' "); break;
   1573                 case NODE_TEST_PI:
   1574 		    fprintf(output, "'PI' "); break;
   1575                 case NODE_TEST_ALL:
   1576 		    fprintf(output, "'all' "); break;
   1577                 case NODE_TEST_NS:
   1578 		    fprintf(output, "'namespace' "); break;
   1579                 case NODE_TEST_NAME:
   1580 		    fprintf(output, "'name' "); break;
   1581 	    }
   1582 	    switch (type) {
   1583                 case NODE_TYPE_NODE:
   1584 		    fprintf(output, "'node' "); break;
   1585                 case NODE_TYPE_COMMENT:
   1586 		    fprintf(output, "'comment' "); break;
   1587                 case NODE_TYPE_TEXT:
   1588 		    fprintf(output, "'text' "); break;
   1589                 case NODE_TYPE_PI:
   1590 		    fprintf(output, "'PI' "); break;
   1591 	    }
   1592 	    if (prefix != NULL)
   1593 		fprintf(output, "%s:", prefix);
   1594 	    if (name != NULL)
   1595 		fprintf(output, "%s", (const char *) name);
   1596 	    break;
   1597 
   1598         }
   1599 	case XPATH_OP_VALUE: {
   1600 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
   1601 
   1602 	    fprintf(output, "ELEM ");
   1603 	    xmlXPathDebugDumpObject(output, object, 0);
   1604 	    goto finish;
   1605 	}
   1606 	case XPATH_OP_VARIABLE: {
   1607 	    const xmlChar *prefix = op->value5;
   1608 	    const xmlChar *name = op->value4;
   1609 
   1610 	    if (prefix != NULL)
   1611 		fprintf(output, "VARIABLE %s:%s", prefix, name);
   1612 	    else
   1613 		fprintf(output, "VARIABLE %s", name);
   1614 	    break;
   1615 	}
   1616 	case XPATH_OP_FUNCTION: {
   1617 	    int nbargs = op->value;
   1618 	    const xmlChar *prefix = op->value5;
   1619 	    const xmlChar *name = op->value4;
   1620 
   1621 	    if (prefix != NULL)
   1622 		fprintf(output, "FUNCTION %s:%s(%d args)",
   1623 			prefix, name, nbargs);
   1624 	    else
   1625 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
   1626 	    break;
   1627 	}
   1628         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
   1629         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
   1630         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
   1631 #ifdef LIBXML_XPTR_ENABLED
   1632         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
   1633 #endif
   1634 	default:
   1635         fprintf(output, "UNKNOWN %d\n", op->op); return;
   1636     }
   1637     fprintf(output, "\n");
   1638 finish:
   1639     if (op->ch1 >= 0)
   1640 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
   1641     if (op->ch2 >= 0)
   1642 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
   1643 }
   1644 
   1645 /**
   1646  * xmlXPathDebugDumpCompExpr:
   1647  * @output:  the FILE * for the output
   1648  * @comp:  the precompiled XPath expression
   1649  * @depth:  the indentation level.
   1650  *
   1651  * Dumps the tree of the compiled XPath expression.
   1652  */
   1653 void
   1654 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
   1655 	                  int depth) {
   1656     int i;
   1657     char shift[100];
   1658 
   1659     if ((output == NULL) || (comp == NULL)) return;
   1660 
   1661     for (i = 0;((i < depth) && (i < 25));i++)
   1662         shift[2 * i] = shift[2 * i + 1] = ' ';
   1663     shift[2 * i] = shift[2 * i + 1] = 0;
   1664 
   1665     fprintf(output, "%s", shift);
   1666 
   1667 #ifdef XPATH_STREAMING
   1668     if (comp->stream) {
   1669         fprintf(output, "Streaming Expression\n");
   1670     } else
   1671 #endif
   1672     {
   1673         fprintf(output, "Compiled Expression : %d elements\n",
   1674                 comp->nbStep);
   1675         i = comp->last;
   1676         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
   1677     }
   1678 }
   1679 
   1680 #ifdef XP_DEBUG_OBJ_USAGE
   1681 
   1682 /*
   1683 * XPath object usage related debugging variables.
   1684 */
   1685 static int xmlXPathDebugObjCounterUndefined = 0;
   1686 static int xmlXPathDebugObjCounterNodeset = 0;
   1687 static int xmlXPathDebugObjCounterBool = 0;
   1688 static int xmlXPathDebugObjCounterNumber = 0;
   1689 static int xmlXPathDebugObjCounterString = 0;
   1690 static int xmlXPathDebugObjCounterPoint = 0;
   1691 static int xmlXPathDebugObjCounterRange = 0;
   1692 static int xmlXPathDebugObjCounterLocset = 0;
   1693 static int xmlXPathDebugObjCounterUsers = 0;
   1694 static int xmlXPathDebugObjCounterXSLTTree = 0;
   1695 static int xmlXPathDebugObjCounterAll = 0;
   1696 
   1697 static int xmlXPathDebugObjTotalUndefined = 0;
   1698 static int xmlXPathDebugObjTotalNodeset = 0;
   1699 static int xmlXPathDebugObjTotalBool = 0;
   1700 static int xmlXPathDebugObjTotalNumber = 0;
   1701 static int xmlXPathDebugObjTotalString = 0;
   1702 static int xmlXPathDebugObjTotalPoint = 0;
   1703 static int xmlXPathDebugObjTotalRange = 0;
   1704 static int xmlXPathDebugObjTotalLocset = 0;
   1705 static int xmlXPathDebugObjTotalUsers = 0;
   1706 static int xmlXPathDebugObjTotalXSLTTree = 0;
   1707 static int xmlXPathDebugObjTotalAll = 0;
   1708 
   1709 static int xmlXPathDebugObjMaxUndefined = 0;
   1710 static int xmlXPathDebugObjMaxNodeset = 0;
   1711 static int xmlXPathDebugObjMaxBool = 0;
   1712 static int xmlXPathDebugObjMaxNumber = 0;
   1713 static int xmlXPathDebugObjMaxString = 0;
   1714 static int xmlXPathDebugObjMaxPoint = 0;
   1715 static int xmlXPathDebugObjMaxRange = 0;
   1716 static int xmlXPathDebugObjMaxLocset = 0;
   1717 static int xmlXPathDebugObjMaxUsers = 0;
   1718 static int xmlXPathDebugObjMaxXSLTTree = 0;
   1719 static int xmlXPathDebugObjMaxAll = 0;
   1720 
   1721 /* REVISIT TODO: Make this static when committing */
   1722 static void
   1723 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
   1724 {
   1725     if (ctxt != NULL) {
   1726 	if (ctxt->cache != NULL) {
   1727 	    xmlXPathContextCachePtr cache =
   1728 		(xmlXPathContextCachePtr) ctxt->cache;
   1729 
   1730 	    cache->dbgCachedAll = 0;
   1731 	    cache->dbgCachedNodeset = 0;
   1732 	    cache->dbgCachedString = 0;
   1733 	    cache->dbgCachedBool = 0;
   1734 	    cache->dbgCachedNumber = 0;
   1735 	    cache->dbgCachedPoint = 0;
   1736 	    cache->dbgCachedRange = 0;
   1737 	    cache->dbgCachedLocset = 0;
   1738 	    cache->dbgCachedUsers = 0;
   1739 	    cache->dbgCachedXSLTTree = 0;
   1740 	    cache->dbgCachedUndefined = 0;
   1741 
   1742 	    cache->dbgReusedAll = 0;
   1743 	    cache->dbgReusedNodeset = 0;
   1744 	    cache->dbgReusedString = 0;
   1745 	    cache->dbgReusedBool = 0;
   1746 	    cache->dbgReusedNumber = 0;
   1747 	    cache->dbgReusedPoint = 0;
   1748 	    cache->dbgReusedRange = 0;
   1749 	    cache->dbgReusedLocset = 0;
   1750 	    cache->dbgReusedUsers = 0;
   1751 	    cache->dbgReusedXSLTTree = 0;
   1752 	    cache->dbgReusedUndefined = 0;
   1753 	}
   1754     }
   1755 
   1756     xmlXPathDebugObjCounterUndefined = 0;
   1757     xmlXPathDebugObjCounterNodeset = 0;
   1758     xmlXPathDebugObjCounterBool = 0;
   1759     xmlXPathDebugObjCounterNumber = 0;
   1760     xmlXPathDebugObjCounterString = 0;
   1761     xmlXPathDebugObjCounterPoint = 0;
   1762     xmlXPathDebugObjCounterRange = 0;
   1763     xmlXPathDebugObjCounterLocset = 0;
   1764     xmlXPathDebugObjCounterUsers = 0;
   1765     xmlXPathDebugObjCounterXSLTTree = 0;
   1766     xmlXPathDebugObjCounterAll = 0;
   1767 
   1768     xmlXPathDebugObjTotalUndefined = 0;
   1769     xmlXPathDebugObjTotalNodeset = 0;
   1770     xmlXPathDebugObjTotalBool = 0;
   1771     xmlXPathDebugObjTotalNumber = 0;
   1772     xmlXPathDebugObjTotalString = 0;
   1773     xmlXPathDebugObjTotalPoint = 0;
   1774     xmlXPathDebugObjTotalRange = 0;
   1775     xmlXPathDebugObjTotalLocset = 0;
   1776     xmlXPathDebugObjTotalUsers = 0;
   1777     xmlXPathDebugObjTotalXSLTTree = 0;
   1778     xmlXPathDebugObjTotalAll = 0;
   1779 
   1780     xmlXPathDebugObjMaxUndefined = 0;
   1781     xmlXPathDebugObjMaxNodeset = 0;
   1782     xmlXPathDebugObjMaxBool = 0;
   1783     xmlXPathDebugObjMaxNumber = 0;
   1784     xmlXPathDebugObjMaxString = 0;
   1785     xmlXPathDebugObjMaxPoint = 0;
   1786     xmlXPathDebugObjMaxRange = 0;
   1787     xmlXPathDebugObjMaxLocset = 0;
   1788     xmlXPathDebugObjMaxUsers = 0;
   1789     xmlXPathDebugObjMaxXSLTTree = 0;
   1790     xmlXPathDebugObjMaxAll = 0;
   1791 
   1792 }
   1793 
   1794 static void
   1795 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
   1796 			      xmlXPathObjectType objType)
   1797 {
   1798     int isCached = 0;
   1799 
   1800     if (ctxt != NULL) {
   1801 	if (ctxt->cache != NULL) {
   1802 	    xmlXPathContextCachePtr cache =
   1803 		(xmlXPathContextCachePtr) ctxt->cache;
   1804 
   1805 	    isCached = 1;
   1806 
   1807 	    cache->dbgReusedAll++;
   1808 	    switch (objType) {
   1809 		case XPATH_UNDEFINED:
   1810 		    cache->dbgReusedUndefined++;
   1811 		    break;
   1812 		case XPATH_NODESET:
   1813 		    cache->dbgReusedNodeset++;
   1814 		    break;
   1815 		case XPATH_BOOLEAN:
   1816 		    cache->dbgReusedBool++;
   1817 		    break;
   1818 		case XPATH_NUMBER:
   1819 		    cache->dbgReusedNumber++;
   1820 		    break;
   1821 		case XPATH_STRING:
   1822 		    cache->dbgReusedString++;
   1823 		    break;
   1824 		case XPATH_POINT:
   1825 		    cache->dbgReusedPoint++;
   1826 		    break;
   1827 		case XPATH_RANGE:
   1828 		    cache->dbgReusedRange++;
   1829 		    break;
   1830 		case XPATH_LOCATIONSET:
   1831 		    cache->dbgReusedLocset++;
   1832 		    break;
   1833 		case XPATH_USERS:
   1834 		    cache->dbgReusedUsers++;
   1835 		    break;
   1836 		case XPATH_XSLT_TREE:
   1837 		    cache->dbgReusedXSLTTree++;
   1838 		    break;
   1839 		default:
   1840 		    break;
   1841 	    }
   1842 	}
   1843     }
   1844 
   1845     switch (objType) {
   1846 	case XPATH_UNDEFINED:
   1847 	    if (! isCached)
   1848 		xmlXPathDebugObjTotalUndefined++;
   1849 	    xmlXPathDebugObjCounterUndefined++;
   1850 	    if (xmlXPathDebugObjCounterUndefined >
   1851 		xmlXPathDebugObjMaxUndefined)
   1852 		xmlXPathDebugObjMaxUndefined =
   1853 		    xmlXPathDebugObjCounterUndefined;
   1854 	    break;
   1855 	case XPATH_NODESET:
   1856 	    if (! isCached)
   1857 		xmlXPathDebugObjTotalNodeset++;
   1858 	    xmlXPathDebugObjCounterNodeset++;
   1859 	    if (xmlXPathDebugObjCounterNodeset >
   1860 		xmlXPathDebugObjMaxNodeset)
   1861 		xmlXPathDebugObjMaxNodeset =
   1862 		    xmlXPathDebugObjCounterNodeset;
   1863 	    break;
   1864 	case XPATH_BOOLEAN:
   1865 	    if (! isCached)
   1866 		xmlXPathDebugObjTotalBool++;
   1867 	    xmlXPathDebugObjCounterBool++;
   1868 	    if (xmlXPathDebugObjCounterBool >
   1869 		xmlXPathDebugObjMaxBool)
   1870 		xmlXPathDebugObjMaxBool =
   1871 		    xmlXPathDebugObjCounterBool;
   1872 	    break;
   1873 	case XPATH_NUMBER:
   1874 	    if (! isCached)
   1875 		xmlXPathDebugObjTotalNumber++;
   1876 	    xmlXPathDebugObjCounterNumber++;
   1877 	    if (xmlXPathDebugObjCounterNumber >
   1878 		xmlXPathDebugObjMaxNumber)
   1879 		xmlXPathDebugObjMaxNumber =
   1880 		    xmlXPathDebugObjCounterNumber;
   1881 	    break;
   1882 	case XPATH_STRING:
   1883 	    if (! isCached)
   1884 		xmlXPathDebugObjTotalString++;
   1885 	    xmlXPathDebugObjCounterString++;
   1886 	    if (xmlXPathDebugObjCounterString >
   1887 		xmlXPathDebugObjMaxString)
   1888 		xmlXPathDebugObjMaxString =
   1889 		    xmlXPathDebugObjCounterString;
   1890 	    break;
   1891 	case XPATH_POINT:
   1892 	    if (! isCached)
   1893 		xmlXPathDebugObjTotalPoint++;
   1894 	    xmlXPathDebugObjCounterPoint++;
   1895 	    if (xmlXPathDebugObjCounterPoint >
   1896 		xmlXPathDebugObjMaxPoint)
   1897 		xmlXPathDebugObjMaxPoint =
   1898 		    xmlXPathDebugObjCounterPoint;
   1899 	    break;
   1900 	case XPATH_RANGE:
   1901 	    if (! isCached)
   1902 		xmlXPathDebugObjTotalRange++;
   1903 	    xmlXPathDebugObjCounterRange++;
   1904 	    if (xmlXPathDebugObjCounterRange >
   1905 		xmlXPathDebugObjMaxRange)
   1906 		xmlXPathDebugObjMaxRange =
   1907 		    xmlXPathDebugObjCounterRange;
   1908 	    break;
   1909 	case XPATH_LOCATIONSET:
   1910 	    if (! isCached)
   1911 		xmlXPathDebugObjTotalLocset++;
   1912 	    xmlXPathDebugObjCounterLocset++;
   1913 	    if (xmlXPathDebugObjCounterLocset >
   1914 		xmlXPathDebugObjMaxLocset)
   1915 		xmlXPathDebugObjMaxLocset =
   1916 		    xmlXPathDebugObjCounterLocset;
   1917 	    break;
   1918 	case XPATH_USERS:
   1919 	    if (! isCached)
   1920 		xmlXPathDebugObjTotalUsers++;
   1921 	    xmlXPathDebugObjCounterUsers++;
   1922 	    if (xmlXPathDebugObjCounterUsers >
   1923 		xmlXPathDebugObjMaxUsers)
   1924 		xmlXPathDebugObjMaxUsers =
   1925 		    xmlXPathDebugObjCounterUsers;
   1926 	    break;
   1927 	case XPATH_XSLT_TREE:
   1928 	    if (! isCached)
   1929 		xmlXPathDebugObjTotalXSLTTree++;
   1930 	    xmlXPathDebugObjCounterXSLTTree++;
   1931 	    if (xmlXPathDebugObjCounterXSLTTree >
   1932 		xmlXPathDebugObjMaxXSLTTree)
   1933 		xmlXPathDebugObjMaxXSLTTree =
   1934 		    xmlXPathDebugObjCounterXSLTTree;
   1935 	    break;
   1936 	default:
   1937 	    break;
   1938     }
   1939     if (! isCached)
   1940 	xmlXPathDebugObjTotalAll++;
   1941     xmlXPathDebugObjCounterAll++;
   1942     if (xmlXPathDebugObjCounterAll >
   1943 	xmlXPathDebugObjMaxAll)
   1944 	xmlXPathDebugObjMaxAll =
   1945 	    xmlXPathDebugObjCounterAll;
   1946 }
   1947 
   1948 static void
   1949 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
   1950 			      xmlXPathObjectType objType)
   1951 {
   1952     int isCached = 0;
   1953 
   1954     if (ctxt != NULL) {
   1955 	if (ctxt->cache != NULL) {
   1956 	    xmlXPathContextCachePtr cache =
   1957 		(xmlXPathContextCachePtr) ctxt->cache;
   1958 
   1959 	    isCached = 1;
   1960 
   1961 	    cache->dbgCachedAll++;
   1962 	    switch (objType) {
   1963 		case XPATH_UNDEFINED:
   1964 		    cache->dbgCachedUndefined++;
   1965 		    break;
   1966 		case XPATH_NODESET:
   1967 		    cache->dbgCachedNodeset++;
   1968 		    break;
   1969 		case XPATH_BOOLEAN:
   1970 		    cache->dbgCachedBool++;
   1971 		    break;
   1972 		case XPATH_NUMBER:
   1973 		    cache->dbgCachedNumber++;
   1974 		    break;
   1975 		case XPATH_STRING:
   1976 		    cache->dbgCachedString++;
   1977 		    break;
   1978 		case XPATH_POINT:
   1979 		    cache->dbgCachedPoint++;
   1980 		    break;
   1981 		case XPATH_RANGE:
   1982 		    cache->dbgCachedRange++;
   1983 		    break;
   1984 		case XPATH_LOCATIONSET:
   1985 		    cache->dbgCachedLocset++;
   1986 		    break;
   1987 		case XPATH_USERS:
   1988 		    cache->dbgCachedUsers++;
   1989 		    break;
   1990 		case XPATH_XSLT_TREE:
   1991 		    cache->dbgCachedXSLTTree++;
   1992 		    break;
   1993 		default:
   1994 		    break;
   1995 	    }
   1996 
   1997 	}
   1998     }
   1999     switch (objType) {
   2000 	case XPATH_UNDEFINED:
   2001 	    xmlXPathDebugObjCounterUndefined--;
   2002 	    break;
   2003 	case XPATH_NODESET:
   2004 	    xmlXPathDebugObjCounterNodeset--;
   2005 	    break;
   2006 	case XPATH_BOOLEAN:
   2007 	    xmlXPathDebugObjCounterBool--;
   2008 	    break;
   2009 	case XPATH_NUMBER:
   2010 	    xmlXPathDebugObjCounterNumber--;
   2011 	    break;
   2012 	case XPATH_STRING:
   2013 	    xmlXPathDebugObjCounterString--;
   2014 	    break;
   2015 	case XPATH_POINT:
   2016 	    xmlXPathDebugObjCounterPoint--;
   2017 	    break;
   2018 	case XPATH_RANGE:
   2019 	    xmlXPathDebugObjCounterRange--;
   2020 	    break;
   2021 	case XPATH_LOCATIONSET:
   2022 	    xmlXPathDebugObjCounterLocset--;
   2023 	    break;
   2024 	case XPATH_USERS:
   2025 	    xmlXPathDebugObjCounterUsers--;
   2026 	    break;
   2027 	case XPATH_XSLT_TREE:
   2028 	    xmlXPathDebugObjCounterXSLTTree--;
   2029 	    break;
   2030 	default:
   2031 	    break;
   2032     }
   2033     xmlXPathDebugObjCounterAll--;
   2034 }
   2035 
   2036 /* REVISIT TODO: Make this static when committing */
   2037 static void
   2038 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
   2039 {
   2040     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
   2041 	reqXSLTTree, reqUndefined;
   2042     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
   2043 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
   2044     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
   2045 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
   2046     int leftObjs = xmlXPathDebugObjCounterAll;
   2047 
   2048     reqAll = xmlXPathDebugObjTotalAll;
   2049     reqNodeset = xmlXPathDebugObjTotalNodeset;
   2050     reqString = xmlXPathDebugObjTotalString;
   2051     reqBool = xmlXPathDebugObjTotalBool;
   2052     reqNumber = xmlXPathDebugObjTotalNumber;
   2053     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
   2054     reqUndefined = xmlXPathDebugObjTotalUndefined;
   2055 
   2056     printf("# XPath object usage:\n");
   2057 
   2058     if (ctxt != NULL) {
   2059 	if (ctxt->cache != NULL) {
   2060 	    xmlXPathContextCachePtr cache =
   2061 		(xmlXPathContextCachePtr) ctxt->cache;
   2062 
   2063 	    reAll = cache->dbgReusedAll;
   2064 	    reqAll += reAll;
   2065 	    reNodeset = cache->dbgReusedNodeset;
   2066 	    reqNodeset += reNodeset;
   2067 	    reString = cache->dbgReusedString;
   2068 	    reqString += reString;
   2069 	    reBool = cache->dbgReusedBool;
   2070 	    reqBool += reBool;
   2071 	    reNumber = cache->dbgReusedNumber;
   2072 	    reqNumber += reNumber;
   2073 	    reXSLTTree = cache->dbgReusedXSLTTree;
   2074 	    reqXSLTTree += reXSLTTree;
   2075 	    reUndefined = cache->dbgReusedUndefined;
   2076 	    reqUndefined += reUndefined;
   2077 
   2078 	    caAll = cache->dbgCachedAll;
   2079 	    caBool = cache->dbgCachedBool;
   2080 	    caNodeset = cache->dbgCachedNodeset;
   2081 	    caString = cache->dbgCachedString;
   2082 	    caNumber = cache->dbgCachedNumber;
   2083 	    caXSLTTree = cache->dbgCachedXSLTTree;
   2084 	    caUndefined = cache->dbgCachedUndefined;
   2085 
   2086 	    if (cache->nodesetObjs)
   2087 		leftObjs -= cache->nodesetObjs->number;
   2088 	    if (cache->stringObjs)
   2089 		leftObjs -= cache->stringObjs->number;
   2090 	    if (cache->booleanObjs)
   2091 		leftObjs -= cache->booleanObjs->number;
   2092 	    if (cache->numberObjs)
   2093 		leftObjs -= cache->numberObjs->number;
   2094 	    if (cache->miscObjs)
   2095 		leftObjs -= cache->miscObjs->number;
   2096 	}
   2097     }
   2098 
   2099     printf("# all\n");
   2100     printf("#   total  : %d\n", reqAll);
   2101     printf("#   left  : %d\n", leftObjs);
   2102     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
   2103     printf("#   reused : %d\n", reAll);
   2104     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
   2105 
   2106     printf("# node-sets\n");
   2107     printf("#   total  : %d\n", reqNodeset);
   2108     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
   2109     printf("#   reused : %d\n", reNodeset);
   2110     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
   2111 
   2112     printf("# strings\n");
   2113     printf("#   total  : %d\n", reqString);
   2114     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
   2115     printf("#   reused : %d\n", reString);
   2116     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
   2117 
   2118     printf("# booleans\n");
   2119     printf("#   total  : %d\n", reqBool);
   2120     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
   2121     printf("#   reused : %d\n", reBool);
   2122     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
   2123 
   2124     printf("# numbers\n");
   2125     printf("#   total  : %d\n", reqNumber);
   2126     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
   2127     printf("#   reused : %d\n", reNumber);
   2128     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
   2129 
   2130     printf("# XSLT result tree fragments\n");
   2131     printf("#   total  : %d\n", reqXSLTTree);
   2132     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
   2133     printf("#   reused : %d\n", reXSLTTree);
   2134     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
   2135 
   2136     printf("# undefined\n");
   2137     printf("#   total  : %d\n", reqUndefined);
   2138     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
   2139     printf("#   reused : %d\n", reUndefined);
   2140     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
   2141 
   2142 }
   2143 
   2144 #endif /* XP_DEBUG_OBJ_USAGE */
   2145 
   2146 #endif /* LIBXML_DEBUG_ENABLED */
   2147 
   2148 /************************************************************************
   2149  *									*
   2150  *			XPath object caching				*
   2151  *									*
   2152  ************************************************************************/
   2153 
   2154 /**
   2155  * xmlXPathNewCache:
   2156  *
   2157  * Create a new object cache
   2158  *
   2159  * Returns the xmlXPathCache just allocated.
   2160  */
   2161 static xmlXPathContextCachePtr
   2162 xmlXPathNewCache(void)
   2163 {
   2164     xmlXPathContextCachePtr ret;
   2165 
   2166     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
   2167     if (ret == NULL) {
   2168         xmlXPathErrMemory(NULL, "creating object cache\n");
   2169 	return(NULL);
   2170     }
   2171     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
   2172     ret->maxNodeset = 100;
   2173     ret->maxString = 100;
   2174     ret->maxBoolean = 100;
   2175     ret->maxNumber = 100;
   2176     ret->maxMisc = 100;
   2177     return(ret);
   2178 }
   2179 
   2180 static void
   2181 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
   2182 {
   2183     int i;
   2184     xmlXPathObjectPtr obj;
   2185 
   2186     if (list == NULL)
   2187 	return;
   2188 
   2189     for (i = 0; i < list->number; i++) {
   2190 	obj = list->items[i];
   2191 	/*
   2192 	* Note that it is already assured that we don't need to
   2193 	* look out for namespace nodes in the node-set.
   2194 	*/
   2195 	if (obj->nodesetval != NULL) {
   2196 	    if (obj->nodesetval->nodeTab != NULL)
   2197 		xmlFree(obj->nodesetval->nodeTab);
   2198 	    xmlFree(obj->nodesetval);
   2199 	}
   2200 	xmlFree(obj);
   2201 #ifdef XP_DEBUG_OBJ_USAGE
   2202 	xmlXPathDebugObjCounterAll--;
   2203 #endif
   2204     }
   2205     xmlPointerListFree(list);
   2206 }
   2207 
   2208 static void
   2209 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
   2210 {
   2211     if (cache == NULL)
   2212 	return;
   2213     if (cache->nodesetObjs)
   2214 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
   2215     if (cache->stringObjs)
   2216 	xmlXPathCacheFreeObjectList(cache->stringObjs);
   2217     if (cache->booleanObjs)
   2218 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
   2219     if (cache->numberObjs)
   2220 	xmlXPathCacheFreeObjectList(cache->numberObjs);
   2221     if (cache->miscObjs)
   2222 	xmlXPathCacheFreeObjectList(cache->miscObjs);
   2223     xmlFree(cache);
   2224 }
   2225 
   2226 /**
   2227  * xmlXPathContextSetCache:
   2228  *
   2229  * @ctxt:  the XPath context
   2230  * @active: enables/disables (creates/frees) the cache
   2231  * @value: a value with semantics dependant on @options
   2232  * @options: options (currently only the value 0 is used)
   2233  *
   2234  * Creates/frees an object cache on the XPath context.
   2235  * If activates XPath objects (xmlXPathObject) will be cached internally
   2236  * to be reused.
   2237  * @options:
   2238  *   0: This will set the XPath object caching:
   2239  *      @value:
   2240  *        This will set the maximum number of XPath objects
   2241  *        to be cached per slot
   2242  *        There are 5 slots for: node-set, string, number, boolean, and
   2243  *        misc objects. Use <0 for the default number (100).
   2244  *   Other values for @options have currently no effect.
   2245  *
   2246  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
   2247  */
   2248 int
   2249 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
   2250 			int active,
   2251 			int value,
   2252 			int options)
   2253 {
   2254     if (ctxt == NULL)
   2255 	return(-1);
   2256     if (active) {
   2257 	xmlXPathContextCachePtr cache;
   2258 
   2259 	if (ctxt->cache == NULL) {
   2260 	    ctxt->cache = xmlXPathNewCache();
   2261 	    if (ctxt->cache == NULL)
   2262 		return(-1);
   2263 	}
   2264 	cache = (xmlXPathContextCachePtr) ctxt->cache;
   2265 	if (options == 0) {
   2266 	    if (value < 0)
   2267 		value = 100;
   2268 	    cache->maxNodeset = value;
   2269 	    cache->maxString = value;
   2270 	    cache->maxNumber = value;
   2271 	    cache->maxBoolean = value;
   2272 	    cache->maxMisc = value;
   2273 	}
   2274     } else if (ctxt->cache != NULL) {
   2275 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
   2276 	ctxt->cache = NULL;
   2277     }
   2278     return(0);
   2279 }
   2280 
   2281 /**
   2282  * xmlXPathCacheWrapNodeSet:
   2283  * @ctxt: the XPath context
   2284  * @val:  the NodePtr value
   2285  *
   2286  * This is the cached version of xmlXPathWrapNodeSet().
   2287  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
   2288  *
   2289  * Returns the created or reused object.
   2290  */
   2291 static xmlXPathObjectPtr
   2292 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
   2293 {
   2294     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
   2295 	xmlXPathContextCachePtr cache =
   2296 	    (xmlXPathContextCachePtr) ctxt->cache;
   2297 
   2298 	if ((cache->miscObjs != NULL) &&
   2299 	    (cache->miscObjs->number != 0))
   2300 	{
   2301 	    xmlXPathObjectPtr ret;
   2302 
   2303 	    ret = (xmlXPathObjectPtr)
   2304 		cache->miscObjs->items[--cache->miscObjs->number];
   2305 	    ret->type = XPATH_NODESET;
   2306 	    ret->nodesetval = val;
   2307 #ifdef XP_DEBUG_OBJ_USAGE
   2308 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   2309 #endif
   2310 	    return(ret);
   2311 	}
   2312     }
   2313 
   2314     return(xmlXPathWrapNodeSet(val));
   2315 
   2316 }
   2317 
   2318 /**
   2319  * xmlXPathCacheWrapString:
   2320  * @ctxt: the XPath context
   2321  * @val:  the xmlChar * value
   2322  *
   2323  * This is the cached version of xmlXPathWrapString().
   2324  * Wraps the @val string into an XPath object.
   2325  *
   2326  * Returns the created or reused object.
   2327  */
   2328 static xmlXPathObjectPtr
   2329 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
   2330 {
   2331     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
   2332 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2333 
   2334 	if ((cache->stringObjs != NULL) &&
   2335 	    (cache->stringObjs->number != 0))
   2336 	{
   2337 
   2338 	    xmlXPathObjectPtr ret;
   2339 
   2340 	    ret = (xmlXPathObjectPtr)
   2341 		cache->stringObjs->items[--cache->stringObjs->number];
   2342 	    ret->type = XPATH_STRING;
   2343 	    ret->stringval = val;
   2344 #ifdef XP_DEBUG_OBJ_USAGE
   2345 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2346 #endif
   2347 	    return(ret);
   2348 	} else if ((cache->miscObjs != NULL) &&
   2349 	    (cache->miscObjs->number != 0))
   2350 	{
   2351 	    xmlXPathObjectPtr ret;
   2352 	    /*
   2353 	    * Fallback to misc-cache.
   2354 	    */
   2355 	    ret = (xmlXPathObjectPtr)
   2356 		cache->miscObjs->items[--cache->miscObjs->number];
   2357 
   2358 	    ret->type = XPATH_STRING;
   2359 	    ret->stringval = val;
   2360 #ifdef XP_DEBUG_OBJ_USAGE
   2361 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2362 #endif
   2363 	    return(ret);
   2364 	}
   2365     }
   2366     return(xmlXPathWrapString(val));
   2367 }
   2368 
   2369 /**
   2370  * xmlXPathCacheNewNodeSet:
   2371  * @ctxt: the XPath context
   2372  * @val:  the NodePtr value
   2373  *
   2374  * This is the cached version of xmlXPathNewNodeSet().
   2375  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
   2376  * it with the single Node @val
   2377  *
   2378  * Returns the created or reused object.
   2379  */
   2380 static xmlXPathObjectPtr
   2381 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
   2382 {
   2383     if ((ctxt != NULL) && (ctxt->cache)) {
   2384 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2385 
   2386 	if ((cache->nodesetObjs != NULL) &&
   2387 	    (cache->nodesetObjs->number != 0))
   2388 	{
   2389 	    xmlXPathObjectPtr ret;
   2390 	    /*
   2391 	    * Use the nodset-cache.
   2392 	    */
   2393 	    ret = (xmlXPathObjectPtr)
   2394 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
   2395 	    ret->type = XPATH_NODESET;
   2396 	    ret->boolval = 0;
   2397 	    if (val) {
   2398 		if ((ret->nodesetval->nodeMax == 0) ||
   2399 		    (val->type == XML_NAMESPACE_DECL))
   2400 		{
   2401 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
   2402 		} else {
   2403 		    ret->nodesetval->nodeTab[0] = val;
   2404 		    ret->nodesetval->nodeNr = 1;
   2405 		}
   2406 	    }
   2407 #ifdef XP_DEBUG_OBJ_USAGE
   2408 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   2409 #endif
   2410 	    return(ret);
   2411 	} else if ((cache->miscObjs != NULL) &&
   2412 	    (cache->miscObjs->number != 0))
   2413 	{
   2414 	    xmlXPathObjectPtr ret;
   2415 	    /*
   2416 	    * Fallback to misc-cache.
   2417 	    */
   2418 
   2419 	    ret = (xmlXPathObjectPtr)
   2420 		cache->miscObjs->items[--cache->miscObjs->number];
   2421 
   2422 	    ret->type = XPATH_NODESET;
   2423 	    ret->boolval = 0;
   2424 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
   2425 	    if (ret->nodesetval == NULL) {
   2426 		ctxt->lastError.domain = XML_FROM_XPATH;
   2427 		ctxt->lastError.code = XML_ERR_NO_MEMORY;
   2428 		return(NULL);
   2429 	    }
   2430 #ifdef XP_DEBUG_OBJ_USAGE
   2431 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   2432 #endif
   2433 	    return(ret);
   2434 	}
   2435     }
   2436     return(xmlXPathNewNodeSet(val));
   2437 }
   2438 
   2439 /**
   2440  * xmlXPathCacheNewCString:
   2441  * @ctxt: the XPath context
   2442  * @val:  the char * value
   2443  *
   2444  * This is the cached version of xmlXPathNewCString().
   2445  * Acquire an xmlXPathObjectPtr of type string and of value @val
   2446  *
   2447  * Returns the created or reused object.
   2448  */
   2449 static xmlXPathObjectPtr
   2450 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
   2451 {
   2452     if ((ctxt != NULL) && (ctxt->cache)) {
   2453 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2454 
   2455 	if ((cache->stringObjs != NULL) &&
   2456 	    (cache->stringObjs->number != 0))
   2457 	{
   2458 	    xmlXPathObjectPtr ret;
   2459 
   2460 	    ret = (xmlXPathObjectPtr)
   2461 		cache->stringObjs->items[--cache->stringObjs->number];
   2462 
   2463 	    ret->type = XPATH_STRING;
   2464 	    ret->stringval = xmlStrdup(BAD_CAST val);
   2465 #ifdef XP_DEBUG_OBJ_USAGE
   2466 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2467 #endif
   2468 	    return(ret);
   2469 	} else if ((cache->miscObjs != NULL) &&
   2470 	    (cache->miscObjs->number != 0))
   2471 	{
   2472 	    xmlXPathObjectPtr ret;
   2473 
   2474 	    ret = (xmlXPathObjectPtr)
   2475 		cache->miscObjs->items[--cache->miscObjs->number];
   2476 
   2477 	    ret->type = XPATH_STRING;
   2478 	    ret->stringval = xmlStrdup(BAD_CAST val);
   2479 #ifdef XP_DEBUG_OBJ_USAGE
   2480 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2481 #endif
   2482 	    return(ret);
   2483 	}
   2484     }
   2485     return(xmlXPathNewCString(val));
   2486 }
   2487 
   2488 /**
   2489  * xmlXPathCacheNewString:
   2490  * @ctxt: the XPath context
   2491  * @val:  the xmlChar * value
   2492  *
   2493  * This is the cached version of xmlXPathNewString().
   2494  * Acquire an xmlXPathObjectPtr of type string and of value @val
   2495  *
   2496  * Returns the created or reused object.
   2497  */
   2498 static xmlXPathObjectPtr
   2499 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
   2500 {
   2501     if ((ctxt != NULL) && (ctxt->cache)) {
   2502 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2503 
   2504 	if ((cache->stringObjs != NULL) &&
   2505 	    (cache->stringObjs->number != 0))
   2506 	{
   2507 	    xmlXPathObjectPtr ret;
   2508 
   2509 	    ret = (xmlXPathObjectPtr)
   2510 		cache->stringObjs->items[--cache->stringObjs->number];
   2511 	    ret->type = XPATH_STRING;
   2512 	    if (val != NULL)
   2513 		ret->stringval = xmlStrdup(val);
   2514 	    else
   2515 		ret->stringval = xmlStrdup((const xmlChar *)"");
   2516 #ifdef XP_DEBUG_OBJ_USAGE
   2517 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2518 #endif
   2519 	    return(ret);
   2520 	} else if ((cache->miscObjs != NULL) &&
   2521 	    (cache->miscObjs->number != 0))
   2522 	{
   2523 	    xmlXPathObjectPtr ret;
   2524 
   2525 	    ret = (xmlXPathObjectPtr)
   2526 		cache->miscObjs->items[--cache->miscObjs->number];
   2527 
   2528 	    ret->type = XPATH_STRING;
   2529 	    if (val != NULL)
   2530 		ret->stringval = xmlStrdup(val);
   2531 	    else
   2532 		ret->stringval = xmlStrdup((const xmlChar *)"");
   2533 #ifdef XP_DEBUG_OBJ_USAGE
   2534 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2535 #endif
   2536 	    return(ret);
   2537 	}
   2538     }
   2539     return(xmlXPathNewString(val));
   2540 }
   2541 
   2542 /**
   2543  * xmlXPathCacheNewBoolean:
   2544  * @ctxt: the XPath context
   2545  * @val:  the boolean value
   2546  *
   2547  * This is the cached version of xmlXPathNewBoolean().
   2548  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
   2549  *
   2550  * Returns the created or reused object.
   2551  */
   2552 static xmlXPathObjectPtr
   2553 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
   2554 {
   2555     if ((ctxt != NULL) && (ctxt->cache)) {
   2556 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2557 
   2558 	if ((cache->booleanObjs != NULL) &&
   2559 	    (cache->booleanObjs->number != 0))
   2560 	{
   2561 	    xmlXPathObjectPtr ret;
   2562 
   2563 	    ret = (xmlXPathObjectPtr)
   2564 		cache->booleanObjs->items[--cache->booleanObjs->number];
   2565 	    ret->type = XPATH_BOOLEAN;
   2566 	    ret->boolval = (val != 0);
   2567 #ifdef XP_DEBUG_OBJ_USAGE
   2568 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
   2569 #endif
   2570 	    return(ret);
   2571 	} else if ((cache->miscObjs != NULL) &&
   2572 	    (cache->miscObjs->number != 0))
   2573 	{
   2574 	    xmlXPathObjectPtr ret;
   2575 
   2576 	    ret = (xmlXPathObjectPtr)
   2577 		cache->miscObjs->items[--cache->miscObjs->number];
   2578 
   2579 	    ret->type = XPATH_BOOLEAN;
   2580 	    ret->boolval = (val != 0);
   2581 #ifdef XP_DEBUG_OBJ_USAGE
   2582 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
   2583 #endif
   2584 	    return(ret);
   2585 	}
   2586     }
   2587     return(xmlXPathNewBoolean(val));
   2588 }
   2589 
   2590 /**
   2591  * xmlXPathCacheNewFloat:
   2592  * @ctxt: the XPath context
   2593  * @val:  the double value
   2594  *
   2595  * This is the cached version of xmlXPathNewFloat().
   2596  * Acquires an xmlXPathObjectPtr of type double and of value @val
   2597  *
   2598  * Returns the created or reused object.
   2599  */
   2600 static xmlXPathObjectPtr
   2601 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
   2602 {
   2603      if ((ctxt != NULL) && (ctxt->cache)) {
   2604 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2605 
   2606 	if ((cache->numberObjs != NULL) &&
   2607 	    (cache->numberObjs->number != 0))
   2608 	{
   2609 	    xmlXPathObjectPtr ret;
   2610 
   2611 	    ret = (xmlXPathObjectPtr)
   2612 		cache->numberObjs->items[--cache->numberObjs->number];
   2613 	    ret->type = XPATH_NUMBER;
   2614 	    ret->floatval = val;
   2615 #ifdef XP_DEBUG_OBJ_USAGE
   2616 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
   2617 #endif
   2618 	    return(ret);
   2619 	} else if ((cache->miscObjs != NULL) &&
   2620 	    (cache->miscObjs->number != 0))
   2621 	{
   2622 	    xmlXPathObjectPtr ret;
   2623 
   2624 	    ret = (xmlXPathObjectPtr)
   2625 		cache->miscObjs->items[--cache->miscObjs->number];
   2626 
   2627 	    ret->type = XPATH_NUMBER;
   2628 	    ret->floatval = val;
   2629 #ifdef XP_DEBUG_OBJ_USAGE
   2630 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
   2631 #endif
   2632 	    return(ret);
   2633 	}
   2634     }
   2635     return(xmlXPathNewFloat(val));
   2636 }
   2637 
   2638 /**
   2639  * xmlXPathCacheConvertString:
   2640  * @ctxt: the XPath context
   2641  * @val:  an XPath object
   2642  *
   2643  * This is the cached version of xmlXPathConvertString().
   2644  * Converts an existing object to its string() equivalent
   2645  *
   2646  * Returns a created or reused object, the old one is freed (cached)
   2647  *         (or the operation is done directly on @val)
   2648  */
   2649 
   2650 static xmlXPathObjectPtr
   2651 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2652     xmlChar *res = NULL;
   2653 
   2654     if (val == NULL)
   2655 	return(xmlXPathCacheNewCString(ctxt, ""));
   2656 
   2657     switch (val->type) {
   2658     case XPATH_UNDEFINED:
   2659 #ifdef DEBUG_EXPR
   2660 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
   2661 #endif
   2662 	break;
   2663     case XPATH_NODESET:
   2664     case XPATH_XSLT_TREE:
   2665 	res = xmlXPathCastNodeSetToString(val->nodesetval);
   2666 	break;
   2667     case XPATH_STRING:
   2668 	return(val);
   2669     case XPATH_BOOLEAN:
   2670 	res = xmlXPathCastBooleanToString(val->boolval);
   2671 	break;
   2672     case XPATH_NUMBER:
   2673 	res = xmlXPathCastNumberToString(val->floatval);
   2674 	break;
   2675     case XPATH_USERS:
   2676     case XPATH_POINT:
   2677     case XPATH_RANGE:
   2678     case XPATH_LOCATIONSET:
   2679 	TODO;
   2680 	break;
   2681     }
   2682     xmlXPathReleaseObject(ctxt, val);
   2683     if (res == NULL)
   2684 	return(xmlXPathCacheNewCString(ctxt, ""));
   2685     return(xmlXPathCacheWrapString(ctxt, res));
   2686 }
   2687 
   2688 /**
   2689  * xmlXPathCacheObjectCopy:
   2690  * @ctxt: the XPath context
   2691  * @val:  the original object
   2692  *
   2693  * This is the cached version of xmlXPathObjectCopy().
   2694  * Acquire a copy of a given object
   2695  *
   2696  * Returns a created or reused created object.
   2697  */
   2698 static xmlXPathObjectPtr
   2699 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
   2700 {
   2701     if (val == NULL)
   2702 	return(NULL);
   2703 
   2704     if (XP_HAS_CACHE(ctxt)) {
   2705 	switch (val->type) {
   2706 	    case XPATH_NODESET:
   2707 		return(xmlXPathCacheWrapNodeSet(ctxt,
   2708 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
   2709 	    case XPATH_STRING:
   2710 		return(xmlXPathCacheNewString(ctxt, val->stringval));
   2711 	    case XPATH_BOOLEAN:
   2712 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
   2713 	    case XPATH_NUMBER:
   2714 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
   2715 	    default:
   2716 		break;
   2717 	}
   2718     }
   2719     return(xmlXPathObjectCopy(val));
   2720 }
   2721 
   2722 /**
   2723  * xmlXPathCacheConvertBoolean:
   2724  * @ctxt: the XPath context
   2725  * @val:  an XPath object
   2726  *
   2727  * This is the cached version of xmlXPathConvertBoolean().
   2728  * Converts an existing object to its boolean() equivalent
   2729  *
   2730  * Returns a created or reused object, the old one is freed (or the operation
   2731  *         is done directly on @val)
   2732  */
   2733 static xmlXPathObjectPtr
   2734 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2735     xmlXPathObjectPtr ret;
   2736 
   2737     if (val == NULL)
   2738 	return(xmlXPathCacheNewBoolean(ctxt, 0));
   2739     if (val->type == XPATH_BOOLEAN)
   2740 	return(val);
   2741     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
   2742     xmlXPathReleaseObject(ctxt, val);
   2743     return(ret);
   2744 }
   2745 
   2746 /**
   2747  * xmlXPathCacheConvertNumber:
   2748  * @ctxt: the XPath context
   2749  * @val:  an XPath object
   2750  *
   2751  * This is the cached version of xmlXPathConvertNumber().
   2752  * Converts an existing object to its number() equivalent
   2753  *
   2754  * Returns a created or reused object, the old one is freed (or the operation
   2755  *         is done directly on @val)
   2756  */
   2757 static xmlXPathObjectPtr
   2758 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2759     xmlXPathObjectPtr ret;
   2760 
   2761     if (val == NULL)
   2762 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
   2763     if (val->type == XPATH_NUMBER)
   2764 	return(val);
   2765     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
   2766     xmlXPathReleaseObject(ctxt, val);
   2767     return(ret);
   2768 }
   2769 
   2770 /************************************************************************
   2771  *									*
   2772  *		Parser stacks related functions and macros		*
   2773  *									*
   2774  ************************************************************************/
   2775 
   2776 /**
   2777  * xmlXPathSetFrame:
   2778  * @ctxt: an XPath parser context
   2779  *
   2780  * Set the callee evaluation frame
   2781  *
   2782  * Returns the previous frame value to be restored once done
   2783  */
   2784 static int
   2785 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
   2786     int ret;
   2787 
   2788     if (ctxt == NULL)
   2789         return(0);
   2790     ret = ctxt->valueFrame;
   2791     ctxt->valueFrame = ctxt->valueNr;
   2792     return(ret);
   2793 }
   2794 
   2795 /**
   2796  * xmlXPathPopFrame:
   2797  * @ctxt: an XPath parser context
   2798  * @frame: the previous frame value
   2799  *
   2800  * Remove the callee evaluation frame
   2801  */
   2802 static void
   2803 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
   2804     if (ctxt == NULL)
   2805         return;
   2806     if (ctxt->valueNr < ctxt->valueFrame) {
   2807         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
   2808     }
   2809     ctxt->valueFrame = frame;
   2810 }
   2811 
   2812 /**
   2813  * valuePop:
   2814  * @ctxt: an XPath evaluation context
   2815  *
   2816  * Pops the top XPath object from the value stack
   2817  *
   2818  * Returns the XPath object just removed
   2819  */
   2820 xmlXPathObjectPtr
   2821 valuePop(xmlXPathParserContextPtr ctxt)
   2822 {
   2823     xmlXPathObjectPtr ret;
   2824 
   2825     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
   2826         return (NULL);
   2827 
   2828     if (ctxt->valueNr <= ctxt->valueFrame) {
   2829         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
   2830         return (NULL);
   2831     }
   2832 
   2833     ctxt->valueNr--;
   2834     if (ctxt->valueNr > 0)
   2835         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
   2836     else
   2837         ctxt->value = NULL;
   2838     ret = ctxt->valueTab[ctxt->valueNr];
   2839     ctxt->valueTab[ctxt->valueNr] = NULL;
   2840     return (ret);
   2841 }
   2842 /**
   2843  * valuePush:
   2844  * @ctxt:  an XPath evaluation context
   2845  * @value:  the XPath object
   2846  *
   2847  * Pushes a new XPath object on top of the value stack
   2848  *
   2849  * returns the number of items on the value stack
   2850  */
   2851 int
   2852 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
   2853 {
   2854     if ((ctxt == NULL) || (value == NULL)) return(-1);
   2855     if (ctxt->valueNr >= ctxt->valueMax) {
   2856         xmlXPathObjectPtr *tmp;
   2857 
   2858         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
   2859             xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
   2860             ctxt->error = XPATH_MEMORY_ERROR;
   2861             return (0);
   2862         }
   2863         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
   2864                                              2 * ctxt->valueMax *
   2865                                              sizeof(ctxt->valueTab[0]));
   2866         if (tmp == NULL) {
   2867             xmlXPathErrMemory(NULL, "pushing value\n");
   2868             ctxt->error = XPATH_MEMORY_ERROR;
   2869             return (0);
   2870         }
   2871         ctxt->valueMax *= 2;
   2872 	ctxt->valueTab = tmp;
   2873     }
   2874     ctxt->valueTab[ctxt->valueNr] = value;
   2875     ctxt->value = value;
   2876     return (ctxt->valueNr++);
   2877 }
   2878 
   2879 /**
   2880  * xmlXPathPopBoolean:
   2881  * @ctxt:  an XPath parser context
   2882  *
   2883  * Pops a boolean from the stack, handling conversion if needed.
   2884  * Check error with #xmlXPathCheckError.
   2885  *
   2886  * Returns the boolean
   2887  */
   2888 int
   2889 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
   2890     xmlXPathObjectPtr obj;
   2891     int ret;
   2892 
   2893     obj = valuePop(ctxt);
   2894     if (obj == NULL) {
   2895 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2896 	return(0);
   2897     }
   2898     if (obj->type != XPATH_BOOLEAN)
   2899 	ret = xmlXPathCastToBoolean(obj);
   2900     else
   2901         ret = obj->boolval;
   2902     xmlXPathReleaseObject(ctxt->context, obj);
   2903     return(ret);
   2904 }
   2905 
   2906 /**
   2907  * xmlXPathPopNumber:
   2908  * @ctxt:  an XPath parser context
   2909  *
   2910  * Pops a number from the stack, handling conversion if needed.
   2911  * Check error with #xmlXPathCheckError.
   2912  *
   2913  * Returns the number
   2914  */
   2915 double
   2916 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
   2917     xmlXPathObjectPtr obj;
   2918     double ret;
   2919 
   2920     obj = valuePop(ctxt);
   2921     if (obj == NULL) {
   2922 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2923 	return(0);
   2924     }
   2925     if (obj->type != XPATH_NUMBER)
   2926 	ret = xmlXPathCastToNumber(obj);
   2927     else
   2928         ret = obj->floatval;
   2929     xmlXPathReleaseObject(ctxt->context, obj);
   2930     return(ret);
   2931 }
   2932 
   2933 /**
   2934  * xmlXPathPopString:
   2935  * @ctxt:  an XPath parser context
   2936  *
   2937  * Pops a string from the stack, handling conversion if needed.
   2938  * Check error with #xmlXPathCheckError.
   2939  *
   2940  * Returns the string
   2941  */
   2942 xmlChar *
   2943 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
   2944     xmlXPathObjectPtr obj;
   2945     xmlChar * ret;
   2946 
   2947     obj = valuePop(ctxt);
   2948     if (obj == NULL) {
   2949 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2950 	return(NULL);
   2951     }
   2952     ret = xmlXPathCastToString(obj);	/* this does required strdup */
   2953     /* TODO: needs refactoring somewhere else */
   2954     if (obj->stringval == ret)
   2955 	obj->stringval = NULL;
   2956     xmlXPathReleaseObject(ctxt->context, obj);
   2957     return(ret);
   2958 }
   2959 
   2960 /**
   2961  * xmlXPathPopNodeSet:
   2962  * @ctxt:  an XPath parser context
   2963  *
   2964  * Pops a node-set from the stack, handling conversion if needed.
   2965  * Check error with #xmlXPathCheckError.
   2966  *
   2967  * Returns the node-set
   2968  */
   2969 xmlNodeSetPtr
   2970 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
   2971     xmlXPathObjectPtr obj;
   2972     xmlNodeSetPtr ret;
   2973 
   2974     if (ctxt == NULL) return(NULL);
   2975     if (ctxt->value == NULL) {
   2976 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2977 	return(NULL);
   2978     }
   2979     if (!xmlXPathStackIsNodeSet(ctxt)) {
   2980 	xmlXPathSetTypeError(ctxt);
   2981 	return(NULL);
   2982     }
   2983     obj = valuePop(ctxt);
   2984     ret = obj->nodesetval;
   2985 #if 0
   2986     /* to fix memory leak of not clearing obj->user */
   2987     if (obj->boolval && obj->user != NULL)
   2988         xmlFreeNodeList((xmlNodePtr) obj->user);
   2989 #endif
   2990     obj->nodesetval = NULL;
   2991     xmlXPathReleaseObject(ctxt->context, obj);
   2992     return(ret);
   2993 }
   2994 
   2995 /**
   2996  * xmlXPathPopExternal:
   2997  * @ctxt:  an XPath parser context
   2998  *
   2999  * Pops an external object from the stack, handling conversion if needed.
   3000  * Check error with #xmlXPathCheckError.
   3001  *
   3002  * Returns the object
   3003  */
   3004 void *
   3005 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
   3006     xmlXPathObjectPtr obj;
   3007     void * ret;
   3008 
   3009     if ((ctxt == NULL) || (ctxt->value == NULL)) {
   3010 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   3011 	return(NULL);
   3012     }
   3013     if (ctxt->value->type != XPATH_USERS) {
   3014 	xmlXPathSetTypeError(ctxt);
   3015 	return(NULL);
   3016     }
   3017     obj = valuePop(ctxt);
   3018     ret = obj->user;
   3019     obj->user = NULL;
   3020     xmlXPathReleaseObject(ctxt->context, obj);
   3021     return(ret);
   3022 }
   3023 
   3024 /*
   3025  * Macros for accessing the content. Those should be used only by the parser,
   3026  * and not exported.
   3027  *
   3028  * Dirty macros, i.e. one need to make assumption on the context to use them
   3029  *
   3030  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
   3031  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
   3032  *           in ISO-Latin or UTF-8.
   3033  *           This should be used internally by the parser
   3034  *           only to compare to ASCII values otherwise it would break when
   3035  *           running with UTF-8 encoding.
   3036  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
   3037  *           to compare on ASCII based substring.
   3038  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
   3039  *           strings within the parser.
   3040  *   CURRENT Returns the current char value, with the full decoding of
   3041  *           UTF-8 if we are using this mode. It returns an int.
   3042  *   NEXT    Skip to the next character, this does the proper decoding
   3043  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
   3044  *           It returns the pointer to the current xmlChar.
   3045  */
   3046 
   3047 #define CUR (*ctxt->cur)
   3048 #define SKIP(val) ctxt->cur += (val)
   3049 #define NXT(val) ctxt->cur[(val)]
   3050 #define CUR_PTR ctxt->cur
   3051 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
   3052 
   3053 #define COPY_BUF(l,b,i,v)                                              \
   3054     if (l == 1) b[i++] = (xmlChar) v;                                  \
   3055     else i += xmlCopyChar(l,&b[i],v)
   3056 
   3057 #define NEXTL(l)  ctxt->cur += l
   3058 
   3059 #define SKIP_BLANKS							\
   3060     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
   3061 
   3062 #define CURRENT (*ctxt->cur)
   3063 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
   3064 
   3065 
   3066 #ifndef DBL_DIG
   3067 #define DBL_DIG 16
   3068 #endif
   3069 #ifndef DBL_EPSILON
   3070 #define DBL_EPSILON 1E-9
   3071 #endif
   3072 
   3073 #define UPPER_DOUBLE 1E9
   3074 #define LOWER_DOUBLE 1E-5
   3075 #define	LOWER_DOUBLE_EXP 5
   3076 
   3077 #define INTEGER_DIGITS DBL_DIG
   3078 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
   3079 #define EXPONENT_DIGITS (3 + 2)
   3080 
   3081 /**
   3082  * xmlXPathFormatNumber:
   3083  * @number:     number to format
   3084  * @buffer:     output buffer
   3085  * @buffersize: size of output buffer
   3086  *
   3087  * Convert the number into a string representation.
   3088  */
   3089 static void
   3090 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
   3091 {
   3092     switch (xmlXPathIsInf(number)) {
   3093     case 1:
   3094 	if (buffersize > (int)sizeof("Infinity"))
   3095 	    snprintf(buffer, buffersize, "Infinity");
   3096 	break;
   3097     case -1:
   3098 	if (buffersize > (int)sizeof("-Infinity"))
   3099 	    snprintf(buffer, buffersize, "-Infinity");
   3100 	break;
   3101     default:
   3102 	if (xmlXPathIsNaN(number)) {
   3103 	    if (buffersize > (int)sizeof("NaN"))
   3104 		snprintf(buffer, buffersize, "NaN");
   3105 	} else if (number == 0) {
   3106             /* Omit sign for negative zero. */
   3107 	    snprintf(buffer, buffersize, "0");
   3108 	} else if ((number > INT_MIN) && (number < INT_MAX) &&
   3109                    (number == (int) number)) {
   3110 	    char work[30];
   3111 	    char *ptr, *cur;
   3112 	    int value = (int) number;
   3113 
   3114             ptr = &buffer[0];
   3115 	    if (value == 0) {
   3116 		*ptr++ = '0';
   3117 	    } else {
   3118 		snprintf(work, 29, "%d", value);
   3119 		cur = &work[0];
   3120 		while ((*cur) && (ptr - buffer < buffersize)) {
   3121 		    *ptr++ = *cur++;
   3122 		}
   3123 	    }
   3124 	    if (ptr - buffer < buffersize) {
   3125 		*ptr = 0;
   3126 	    } else if (buffersize > 0) {
   3127 		ptr--;
   3128 		*ptr = 0;
   3129 	    }
   3130 	} else {
   3131 	    /*
   3132 	      For the dimension of work,
   3133 	          DBL_DIG is number of significant digits
   3134 		  EXPONENT is only needed for "scientific notation"
   3135 	          3 is sign, decimal point, and terminating zero
   3136 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
   3137 	      Note that this dimension is slightly (a few characters)
   3138 	      larger than actually necessary.
   3139 	    */
   3140 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
   3141 	    int integer_place, fraction_place;
   3142 	    char *ptr;
   3143 	    char *after_fraction;
   3144 	    double absolute_value;
   3145 	    int size;
   3146 
   3147 	    absolute_value = fabs(number);
   3148 
   3149 	    /*
   3150 	     * First choose format - scientific or regular floating point.
   3151 	     * In either case, result is in work, and after_fraction points
   3152 	     * just past the fractional part.
   3153 	    */
   3154 	    if ( ((absolute_value > UPPER_DOUBLE) ||
   3155 		  (absolute_value < LOWER_DOUBLE)) &&
   3156 		 (absolute_value != 0.0) ) {
   3157 		/* Use scientific notation */
   3158 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
   3159 		fraction_place = DBL_DIG - 1;
   3160 		size = snprintf(work, sizeof(work),"%*.*e",
   3161 			 integer_place, fraction_place, number);
   3162 		while ((size > 0) && (work[size] != 'e')) size--;
   3163 
   3164 	    }
   3165 	    else {
   3166 		/* Use regular notation */
   3167 		if (absolute_value > 0.0) {
   3168 		    integer_place = (int)log10(absolute_value);
   3169 		    if (integer_place > 0)
   3170 		        fraction_place = DBL_DIG - integer_place - 1;
   3171 		    else
   3172 		        fraction_place = DBL_DIG - integer_place;
   3173 		} else {
   3174 		    fraction_place = 1;
   3175 		}
   3176 		size = snprintf(work, sizeof(work), "%0.*f",
   3177 				fraction_place, number);
   3178 	    }
   3179 
   3180 	    /* Remove leading spaces sometimes inserted by snprintf */
   3181 	    while (work[0] == ' ') {
   3182 	        for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
   3183 		size--;
   3184 	    }
   3185 
   3186 	    /* Remove fractional trailing zeroes */
   3187 	    after_fraction = work + size;
   3188 	    ptr = after_fraction;
   3189 	    while (*(--ptr) == '0')
   3190 		;
   3191 	    if (*ptr != '.')
   3192 	        ptr++;
   3193 	    while ((*ptr++ = *after_fraction++) != 0);
   3194 
   3195 	    /* Finally copy result back to caller */
   3196 	    size = strlen(work) + 1;
   3197 	    if (size > buffersize) {
   3198 		work[buffersize - 1] = 0;
   3199 		size = buffersize;
   3200 	    }
   3201 	    memmove(buffer, work, size);
   3202 	}
   3203 	break;
   3204     }
   3205 }
   3206 
   3207 
   3208 /************************************************************************
   3209  *									*
   3210  *			Routines to handle NodeSets			*
   3211  *									*
   3212  ************************************************************************/
   3213 
   3214 /**
   3215  * xmlXPathOrderDocElems:
   3216  * @doc:  an input document
   3217  *
   3218  * Call this routine to speed up XPath computation on static documents.
   3219  * This stamps all the element nodes with the document order
   3220  * Like for line information, the order is kept in the element->content
   3221  * field, the value stored is actually - the node number (starting at -1)
   3222  * to be able to differentiate from line numbers.
   3223  *
   3224  * Returns the number of elements found in the document or -1 in case
   3225  *    of error.
   3226  */
   3227 long
   3228 xmlXPathOrderDocElems(xmlDocPtr doc) {
   3229     ptrdiff_t count = 0;
   3230     xmlNodePtr cur;
   3231 
   3232     if (doc == NULL)
   3233 	return(-1);
   3234     cur = doc->children;
   3235     while (cur != NULL) {
   3236 	if (cur->type == XML_ELEMENT_NODE) {
   3237 	    cur->content = (void *) (-(++count));
   3238 	    if (cur->children != NULL) {
   3239 		cur = cur->children;
   3240 		continue;
   3241 	    }
   3242 	}
   3243 	if (cur->next != NULL) {
   3244 	    cur = cur->next;
   3245 	    continue;
   3246 	}
   3247 	do {
   3248 	    cur = cur->parent;
   3249 	    if (cur == NULL)
   3250 		break;
   3251 	    if (cur == (xmlNodePtr) doc) {
   3252 		cur = NULL;
   3253 		break;
   3254 	    }
   3255 	    if (cur->next != NULL) {
   3256 		cur = cur->next;
   3257 		break;
   3258 	    }
   3259 	} while (cur != NULL);
   3260     }
   3261     return((long) count);
   3262 }
   3263 
   3264 /**
   3265  * xmlXPathCmpNodes:
   3266  * @node1:  the first node
   3267  * @node2:  the second node
   3268  *
   3269  * Compare two nodes w.r.t document order
   3270  *
   3271  * Returns -2 in case of error 1 if first point < second point, 0 if
   3272  *         it's the same node, -1 otherwise
   3273  */
   3274 int
   3275 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
   3276     int depth1, depth2;
   3277     int attr1 = 0, attr2 = 0;
   3278     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
   3279     xmlNodePtr cur, root;
   3280 
   3281     if ((node1 == NULL) || (node2 == NULL))
   3282 	return(-2);
   3283     /*
   3284      * a couple of optimizations which will avoid computations in most cases
   3285      */
   3286     if (node1 == node2)		/* trivial case */
   3287 	return(0);
   3288     if (node1->type == XML_ATTRIBUTE_NODE) {
   3289 	attr1 = 1;
   3290 	attrNode1 = node1;
   3291 	node1 = node1->parent;
   3292     }
   3293     if (node2->type == XML_ATTRIBUTE_NODE) {
   3294 	attr2 = 1;
   3295 	attrNode2 = node2;
   3296 	node2 = node2->parent;
   3297     }
   3298     if (node1 == node2) {
   3299 	if (attr1 == attr2) {
   3300 	    /* not required, but we keep attributes in order */
   3301 	    if (attr1 != 0) {
   3302 	        cur = attrNode2->prev;
   3303 		while (cur != NULL) {
   3304 		    if (cur == attrNode1)
   3305 		        return (1);
   3306 		    cur = cur->prev;
   3307 		}
   3308 		return (-1);
   3309 	    }
   3310 	    return(0);
   3311 	}
   3312 	if (attr2 == 1)
   3313 	    return(1);
   3314 	return(-1);
   3315     }
   3316     if ((node1->type == XML_NAMESPACE_DECL) ||
   3317         (node2->type == XML_NAMESPACE_DECL))
   3318 	return(1);
   3319     if (node1 == node2->prev)
   3320 	return(1);
   3321     if (node1 == node2->next)
   3322 	return(-1);
   3323 
   3324     /*
   3325      * Speedup using document order if availble.
   3326      */
   3327     if ((node1->type == XML_ELEMENT_NODE) &&
   3328 	(node2->type == XML_ELEMENT_NODE) &&
   3329 	(0 > (ptrdiff_t) node1->content) &&
   3330 	(0 > (ptrdiff_t) node2->content) &&
   3331 	(node1->doc == node2->doc)) {
   3332 	ptrdiff_t l1, l2;
   3333 
   3334 	l1 = -((ptrdiff_t) node1->content);
   3335 	l2 = -((ptrdiff_t) node2->content);
   3336 	if (l1 < l2)
   3337 	    return(1);
   3338 	if (l1 > l2)
   3339 	    return(-1);
   3340     }
   3341 
   3342     /*
   3343      * compute depth to root
   3344      */
   3345     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
   3346 	if (cur->parent == node1)
   3347 	    return(1);
   3348 	depth2++;
   3349     }
   3350     root = cur;
   3351     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
   3352 	if (cur->parent == node2)
   3353 	    return(-1);
   3354 	depth1++;
   3355     }
   3356     /*
   3357      * Distinct document (or distinct entities :-( ) case.
   3358      */
   3359     if (root != cur) {
   3360 	return(-2);
   3361     }
   3362     /*
   3363      * get the nearest common ancestor.
   3364      */
   3365     while (depth1 > depth2) {
   3366 	depth1--;
   3367 	node1 = node1->parent;
   3368     }
   3369     while (depth2 > depth1) {
   3370 	depth2--;
   3371 	node2 = node2->parent;
   3372     }
   3373     while (node1->parent != node2->parent) {
   3374 	node1 = node1->parent;
   3375 	node2 = node2->parent;
   3376 	/* should not happen but just in case ... */
   3377 	if ((node1 == NULL) || (node2 == NULL))
   3378 	    return(-2);
   3379     }
   3380     /*
   3381      * Find who's first.
   3382      */
   3383     if (node1 == node2->prev)
   3384 	return(1);
   3385     if (node1 == node2->next)
   3386 	return(-1);
   3387     /*
   3388      * Speedup using document order if availble.
   3389      */
   3390     if ((node1->type == XML_ELEMENT_NODE) &&
   3391 	(node2->type == XML_ELEMENT_NODE) &&
   3392 	(0 > (ptrdiff_t) node1->content) &&
   3393 	(0 > (ptrdiff_t) node2->content) &&
   3394 	(node1->doc == node2->doc)) {
   3395 	ptrdiff_t l1, l2;
   3396 
   3397 	l1 = -((ptrdiff_t) node1->content);
   3398 	l2 = -((ptrdiff_t) node2->content);
   3399 	if (l1 < l2)
   3400 	    return(1);
   3401 	if (l1 > l2)
   3402 	    return(-1);
   3403     }
   3404 
   3405     for (cur = node1->next;cur != NULL;cur = cur->next)
   3406 	if (cur == node2)
   3407 	    return(1);
   3408     return(-1); /* assume there is no sibling list corruption */
   3409 }
   3410 
   3411 /**
   3412  * xmlXPathNodeSetSort:
   3413  * @set:  the node set
   3414  *
   3415  * Sort the node set in document order
   3416  */
   3417 void
   3418 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
   3419 #ifndef WITH_TIM_SORT
   3420     int i, j, incr, len;
   3421     xmlNodePtr tmp;
   3422 #endif
   3423 
   3424     if (set == NULL)
   3425 	return;
   3426 
   3427 #ifndef WITH_TIM_SORT
   3428     /*
   3429      * Use the old Shell's sort implementation to sort the node-set
   3430      * Timsort ought to be quite faster
   3431      */
   3432     len = set->nodeNr;
   3433     for (incr = len / 2; incr > 0; incr /= 2) {
   3434 	for (i = incr; i < len; i++) {
   3435 	    j = i - incr;
   3436 	    while (j >= 0) {
   3437 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   3438 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
   3439 			set->nodeTab[j + incr]) == -1)
   3440 #else
   3441 		if (xmlXPathCmpNodes(set->nodeTab[j],
   3442 			set->nodeTab[j + incr]) == -1)
   3443 #endif
   3444 		{
   3445 		    tmp = set->nodeTab[j];
   3446 		    set->nodeTab[j] = set->nodeTab[j + incr];
   3447 		    set->nodeTab[j + incr] = tmp;
   3448 		    j -= incr;
   3449 		} else
   3450 		    break;
   3451 	    }
   3452 	}
   3453     }
   3454 #else /* WITH_TIM_SORT */
   3455     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
   3456 #endif /* WITH_TIM_SORT */
   3457 }
   3458 
   3459 #define XML_NODESET_DEFAULT	10
   3460 /**
   3461  * xmlXPathNodeSetDupNs:
   3462  * @node:  the parent node of the namespace XPath node
   3463  * @ns:  the libxml namespace declaration node.
   3464  *
   3465  * Namespace node in libxml don't match the XPath semantic. In a node set
   3466  * the namespace nodes are duplicated and the next pointer is set to the
   3467  * parent node in the XPath semantic.
   3468  *
   3469  * Returns the newly created object.
   3470  */
   3471 static xmlNodePtr
   3472 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
   3473     xmlNsPtr cur;
   3474 
   3475     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
   3476 	return(NULL);
   3477     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
   3478 	return((xmlNodePtr) ns);
   3479 
   3480     /*
   3481      * Allocate a new Namespace and fill the fields.
   3482      */
   3483     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
   3484     if (cur == NULL) {
   3485         xmlXPathErrMemory(NULL, "duplicating namespace\n");
   3486 	return(NULL);
   3487     }
   3488     memset(cur, 0, sizeof(xmlNs));
   3489     cur->type = XML_NAMESPACE_DECL;
   3490     if (ns->href != NULL)
   3491 	cur->href = xmlStrdup(ns->href);
   3492     if (ns->prefix != NULL)
   3493 	cur->prefix = xmlStrdup(ns->prefix);
   3494     cur->next = (xmlNsPtr) node;
   3495     return((xmlNodePtr) cur);
   3496 }
   3497 
   3498 /**
   3499  * xmlXPathNodeSetFreeNs:
   3500  * @ns:  the XPath namespace node found in a nodeset.
   3501  *
   3502  * Namespace nodes in libxml don't match the XPath semantic. In a node set
   3503  * the namespace nodes are duplicated and the next pointer is set to the
   3504  * parent node in the XPath semantic. Check if such a node needs to be freed
   3505  */
   3506 void
   3507 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
   3508     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
   3509 	return;
   3510 
   3511     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
   3512 	if (ns->href != NULL)
   3513 	    xmlFree((xmlChar *)ns->href);
   3514 	if (ns->prefix != NULL)
   3515 	    xmlFree((xmlChar *)ns->prefix);
   3516 	xmlFree(ns);
   3517     }
   3518 }
   3519 
   3520 /**
   3521  * xmlXPathNodeSetCreate:
   3522  * @val:  an initial xmlNodePtr, or NULL
   3523  *
   3524  * Create a new xmlNodeSetPtr of type double and of value @val
   3525  *
   3526  * Returns the newly created object.
   3527  */
   3528 xmlNodeSetPtr
   3529 xmlXPathNodeSetCreate(xmlNodePtr val) {
   3530     xmlNodeSetPtr ret;
   3531 
   3532     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
   3533     if (ret == NULL) {
   3534         xmlXPathErrMemory(NULL, "creating nodeset\n");
   3535 	return(NULL);
   3536     }
   3537     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
   3538     if (val != NULL) {
   3539         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3540 					     sizeof(xmlNodePtr));
   3541 	if (ret->nodeTab == NULL) {
   3542 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
   3543 	    xmlFree(ret);
   3544 	    return(NULL);
   3545 	}
   3546 	memset(ret->nodeTab, 0 ,
   3547 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3548         ret->nodeMax = XML_NODESET_DEFAULT;
   3549 	if (val->type == XML_NAMESPACE_DECL) {
   3550 	    xmlNsPtr ns = (xmlNsPtr) val;
   3551 
   3552 	    ret->nodeTab[ret->nodeNr++] =
   3553 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3554 	} else
   3555 	    ret->nodeTab[ret->nodeNr++] = val;
   3556     }
   3557     return(ret);
   3558 }
   3559 
   3560 /**
   3561  * xmlXPathNodeSetCreateSize:
   3562  * @size:  the initial size of the set
   3563  *
   3564  * Create a new xmlNodeSetPtr of type double and of value @val
   3565  *
   3566  * Returns the newly created object.
   3567  */
   3568 static xmlNodeSetPtr
   3569 xmlXPathNodeSetCreateSize(int size) {
   3570     xmlNodeSetPtr ret;
   3571 
   3572     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
   3573     if (ret == NULL) {
   3574         xmlXPathErrMemory(NULL, "creating nodeset\n");
   3575 	return(NULL);
   3576     }
   3577     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
   3578     if (size < XML_NODESET_DEFAULT)
   3579 	size = XML_NODESET_DEFAULT;
   3580     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
   3581     if (ret->nodeTab == NULL) {
   3582 	xmlXPathErrMemory(NULL, "creating nodeset\n");
   3583 	xmlFree(ret);
   3584 	return(NULL);
   3585     }
   3586     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
   3587     ret->nodeMax = size;
   3588     return(ret);
   3589 }
   3590 
   3591 /**
   3592  * xmlXPathNodeSetContains:
   3593  * @cur:  the node-set
   3594  * @val:  the node
   3595  *
   3596  * checks whether @cur contains @val
   3597  *
   3598  * Returns true (1) if @cur contains @val, false (0) otherwise
   3599  */
   3600 int
   3601 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
   3602     int i;
   3603 
   3604     if ((cur == NULL) || (val == NULL)) return(0);
   3605     if (val->type == XML_NAMESPACE_DECL) {
   3606 	for (i = 0; i < cur->nodeNr; i++) {
   3607 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
   3608 		xmlNsPtr ns1, ns2;
   3609 
   3610 		ns1 = (xmlNsPtr) val;
   3611 		ns2 = (xmlNsPtr) cur->nodeTab[i];
   3612 		if (ns1 == ns2)
   3613 		    return(1);
   3614 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
   3615 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
   3616 		    return(1);
   3617 	    }
   3618 	}
   3619     } else {
   3620 	for (i = 0; i < cur->nodeNr; i++) {
   3621 	    if (cur->nodeTab[i] == val)
   3622 		return(1);
   3623 	}
   3624     }
   3625     return(0);
   3626 }
   3627 
   3628 /**
   3629  * xmlXPathNodeSetAddNs:
   3630  * @cur:  the initial node set
   3631  * @node:  the hosting node
   3632  * @ns:  a the namespace node
   3633  *
   3634  * add a new namespace node to an existing NodeSet
   3635  *
   3636  * Returns 0 in case of success and -1 in case of error
   3637  */
   3638 int
   3639 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
   3640     int i;
   3641 
   3642 
   3643     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
   3644         (ns->type != XML_NAMESPACE_DECL) ||
   3645 	(node->type != XML_ELEMENT_NODE))
   3646 	return(-1);
   3647 
   3648     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3649     /*
   3650      * prevent duplicates
   3651      */
   3652     for (i = 0;i < cur->nodeNr;i++) {
   3653         if ((cur->nodeTab[i] != NULL) &&
   3654 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
   3655 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
   3656 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
   3657 	    return(0);
   3658     }
   3659 
   3660     /*
   3661      * grow the nodeTab if needed
   3662      */
   3663     if (cur->nodeMax == 0) {
   3664         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3665 					     sizeof(xmlNodePtr));
   3666 	if (cur->nodeTab == NULL) {
   3667 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3668 	    return(-1);
   3669 	}
   3670 	memset(cur->nodeTab, 0 ,
   3671 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3672         cur->nodeMax = XML_NODESET_DEFAULT;
   3673     } else if (cur->nodeNr == cur->nodeMax) {
   3674         xmlNodePtr *temp;
   3675 
   3676         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   3677             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
   3678             return(-1);
   3679         }
   3680 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
   3681 				      sizeof(xmlNodePtr));
   3682 	if (temp == NULL) {
   3683 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3684 	    return(-1);
   3685 	}
   3686         cur->nodeMax *= 2;
   3687 	cur->nodeTab = temp;
   3688     }
   3689     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
   3690     return(0);
   3691 }
   3692 
   3693 /**
   3694  * xmlXPathNodeSetAdd:
   3695  * @cur:  the initial node set
   3696  * @val:  a new xmlNodePtr
   3697  *
   3698  * add a new xmlNodePtr to an existing NodeSet
   3699  *
   3700  * Returns 0 in case of success, and -1 in case of error
   3701  */
   3702 int
   3703 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
   3704     int i;
   3705 
   3706     if ((cur == NULL) || (val == NULL)) return(-1);
   3707 
   3708     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3709     /*
   3710      * prevent duplicates
   3711      */
   3712     for (i = 0;i < cur->nodeNr;i++)
   3713         if (cur->nodeTab[i] == val) return(0);
   3714 
   3715     /*
   3716      * grow the nodeTab if needed
   3717      */
   3718     if (cur->nodeMax == 0) {
   3719         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3720 					     sizeof(xmlNodePtr));
   3721 	if (cur->nodeTab == NULL) {
   3722 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3723 	    return(-1);
   3724 	}
   3725 	memset(cur->nodeTab, 0 ,
   3726 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3727         cur->nodeMax = XML_NODESET_DEFAULT;
   3728     } else if (cur->nodeNr == cur->nodeMax) {
   3729         xmlNodePtr *temp;
   3730 
   3731         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   3732             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
   3733             return(-1);
   3734         }
   3735 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
   3736 				      sizeof(xmlNodePtr));
   3737 	if (temp == NULL) {
   3738 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3739 	    return(-1);
   3740 	}
   3741         cur->nodeMax *= 2;
   3742 	cur->nodeTab = temp;
   3743     }
   3744     if (val->type == XML_NAMESPACE_DECL) {
   3745 	xmlNsPtr ns = (xmlNsPtr) val;
   3746 
   3747 	cur->nodeTab[cur->nodeNr++] =
   3748 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3749     } else
   3750 	cur->nodeTab[cur->nodeNr++] = val;
   3751     return(0);
   3752 }
   3753 
   3754 /**
   3755  * xmlXPathNodeSetAddUnique:
   3756  * @cur:  the initial node set
   3757  * @val:  a new xmlNodePtr
   3758  *
   3759  * add a new xmlNodePtr to an existing NodeSet, optimized version
   3760  * when we are sure the node is not already in the set.
   3761  *
   3762  * Returns 0 in case of success and -1 in case of failure
   3763  */
   3764 int
   3765 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
   3766     if ((cur == NULL) || (val == NULL)) return(-1);
   3767 
   3768     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3769     /*
   3770      * grow the nodeTab if needed
   3771      */
   3772     if (cur->nodeMax == 0) {
   3773         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3774 					     sizeof(xmlNodePtr));
   3775 	if (cur->nodeTab == NULL) {
   3776 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3777 	    return(-1);
   3778 	}
   3779 	memset(cur->nodeTab, 0 ,
   3780 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3781         cur->nodeMax = XML_NODESET_DEFAULT;
   3782     } else if (cur->nodeNr == cur->nodeMax) {
   3783         xmlNodePtr *temp;
   3784 
   3785         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   3786             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
   3787             return(-1);
   3788         }
   3789 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
   3790 				      sizeof(xmlNodePtr));
   3791 	if (temp == NULL) {
   3792 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3793 	    return(-1);
   3794 	}
   3795 	cur->nodeTab = temp;
   3796         cur->nodeMax *= 2;
   3797     }
   3798     if (val->type == XML_NAMESPACE_DECL) {
   3799 	xmlNsPtr ns = (xmlNsPtr) val;
   3800 
   3801 	cur->nodeTab[cur->nodeNr++] =
   3802 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3803     } else
   3804 	cur->nodeTab[cur->nodeNr++] = val;
   3805     return(0);
   3806 }
   3807 
   3808 /**
   3809  * xmlXPathNodeSetMerge:
   3810  * @val1:  the first NodeSet or NULL
   3811  * @val2:  the second NodeSet
   3812  *
   3813  * Merges two nodesets, all nodes from @val2 are added to @val1
   3814  * if @val1 is NULL, a new set is created and copied from @val2
   3815  *
   3816  * Returns @val1 once extended or NULL in case of error.
   3817  */
   3818 xmlNodeSetPtr
   3819 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
   3820     int i, j, initNr, skip;
   3821     xmlNodePtr n1, n2;
   3822 
   3823     if (val2 == NULL) return(val1);
   3824     if (val1 == NULL) {
   3825 	val1 = xmlXPathNodeSetCreate(NULL);
   3826     if (val1 == NULL)
   3827         return (NULL);
   3828 #if 0
   3829 	/*
   3830 	* TODO: The optimization won't work in every case, since
   3831 	*  those nasty namespace nodes need to be added with
   3832 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
   3833 	*  memcpy is not possible.
   3834 	*  If there was a flag on the nodesetval, indicating that
   3835 	*  some temporary nodes are in, that would be helpfull.
   3836 	*/
   3837 	/*
   3838 	* Optimization: Create an equally sized node-set
   3839 	* and memcpy the content.
   3840 	*/
   3841 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
   3842 	if (val1 == NULL)
   3843 	    return(NULL);
   3844 	if (val2->nodeNr != 0) {
   3845 	    if (val2->nodeNr == 1)
   3846 		*(val1->nodeTab) = *(val2->nodeTab);
   3847 	    else {
   3848 		memcpy(val1->nodeTab, val2->nodeTab,
   3849 		    val2->nodeNr * sizeof(xmlNodePtr));
   3850 	    }
   3851 	    val1->nodeNr = val2->nodeNr;
   3852 	}
   3853 	return(val1);
   3854 #endif
   3855     }
   3856 
   3857     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3858     initNr = val1->nodeNr;
   3859 
   3860     for (i = 0;i < val2->nodeNr;i++) {
   3861 	n2 = val2->nodeTab[i];
   3862 	/*
   3863 	 * check against duplicates
   3864 	 */
   3865 	skip = 0;
   3866 	for (j = 0; j < initNr; j++) {
   3867 	    n1 = val1->nodeTab[j];
   3868 	    if (n1 == n2) {
   3869 		skip = 1;
   3870 		break;
   3871 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
   3872 		       (n2->type == XML_NAMESPACE_DECL)) {
   3873 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
   3874 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
   3875 			((xmlNsPtr) n2)->prefix)))
   3876 		{
   3877 		    skip = 1;
   3878 		    break;
   3879 		}
   3880 	    }
   3881 	}
   3882 	if (skip)
   3883 	    continue;
   3884 
   3885 	/*
   3886 	 * grow the nodeTab if needed
   3887 	 */
   3888 	if (val1->nodeMax == 0) {
   3889 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3890 						    sizeof(xmlNodePtr));
   3891 	    if (val1->nodeTab == NULL) {
   3892 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3893 		return(NULL);
   3894 	    }
   3895 	    memset(val1->nodeTab, 0 ,
   3896 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3897 	    val1->nodeMax = XML_NODESET_DEFAULT;
   3898 	} else if (val1->nodeNr == val1->nodeMax) {
   3899 	    xmlNodePtr *temp;
   3900 
   3901             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   3902                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
   3903                 return(NULL);
   3904             }
   3905 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
   3906 					     sizeof(xmlNodePtr));
   3907 	    if (temp == NULL) {
   3908 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3909 		return(NULL);
   3910 	    }
   3911 	    val1->nodeTab = temp;
   3912 	    val1->nodeMax *= 2;
   3913 	}
   3914 	if (n2->type == XML_NAMESPACE_DECL) {
   3915 	    xmlNsPtr ns = (xmlNsPtr) n2;
   3916 
   3917 	    val1->nodeTab[val1->nodeNr++] =
   3918 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3919 	} else
   3920 	    val1->nodeTab[val1->nodeNr++] = n2;
   3921     }
   3922 
   3923     return(val1);
   3924 }
   3925 
   3926 
   3927 /**
   3928  * xmlXPathNodeSetMergeAndClear:
   3929  * @set1:  the first NodeSet or NULL
   3930  * @set2:  the second NodeSet
   3931  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
   3932  *
   3933  * Merges two nodesets, all nodes from @set2 are added to @set1
   3934  * if @set1 is NULL, a new set is created and copied from @set2.
   3935  * Checks for duplicate nodes. Clears set2.
   3936  *
   3937  * Returns @set1 once extended or NULL in case of error.
   3938  */
   3939 static xmlNodeSetPtr
   3940 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
   3941 			     int hasNullEntries)
   3942 {
   3943     if ((set1 == NULL) && (hasNullEntries == 0)) {
   3944 	/*
   3945 	* Note that doing a memcpy of the list, namespace nodes are
   3946 	* just assigned to set1, since set2 is cleared anyway.
   3947 	*/
   3948 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
   3949 	if (set1 == NULL)
   3950 	    return(NULL);
   3951 	if (set2->nodeNr != 0) {
   3952 	    memcpy(set1->nodeTab, set2->nodeTab,
   3953 		set2->nodeNr * sizeof(xmlNodePtr));
   3954 	    set1->nodeNr = set2->nodeNr;
   3955 	}
   3956     } else {
   3957 	int i, j, initNbSet1;
   3958 	xmlNodePtr n1, n2;
   3959 
   3960 	if (set1 == NULL)
   3961             set1 = xmlXPathNodeSetCreate(NULL);
   3962         if (set1 == NULL)
   3963             return (NULL);
   3964 
   3965 	initNbSet1 = set1->nodeNr;
   3966 	for (i = 0;i < set2->nodeNr;i++) {
   3967 	    n2 = set2->nodeTab[i];
   3968 	    /*
   3969 	    * Skip NULLed entries.
   3970 	    */
   3971 	    if (n2 == NULL)
   3972 		continue;
   3973 	    /*
   3974 	    * Skip duplicates.
   3975 	    */
   3976 	    for (j = 0; j < initNbSet1; j++) {
   3977 		n1 = set1->nodeTab[j];
   3978 		if (n1 == n2) {
   3979 		    goto skip_node;
   3980 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
   3981 		    (n2->type == XML_NAMESPACE_DECL))
   3982 		{
   3983 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
   3984 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
   3985 			((xmlNsPtr) n2)->prefix)))
   3986 		    {
   3987 			/*
   3988 			* Free the namespace node.
   3989 			*/
   3990 			set2->nodeTab[i] = NULL;
   3991 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
   3992 			goto skip_node;
   3993 		    }
   3994 		}
   3995 	    }
   3996 	    /*
   3997 	    * grow the nodeTab if needed
   3998 	    */
   3999 	    if (set1->nodeMax == 0) {
   4000 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
   4001 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
   4002 		if (set1->nodeTab == NULL) {
   4003 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   4004 		    return(NULL);
   4005 		}
   4006 		memset(set1->nodeTab, 0,
   4007 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   4008 		set1->nodeMax = XML_NODESET_DEFAULT;
   4009 	    } else if (set1->nodeNr >= set1->nodeMax) {
   4010 		xmlNodePtr *temp;
   4011 
   4012                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   4013                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
   4014                     return(NULL);
   4015                 }
   4016 		temp = (xmlNodePtr *) xmlRealloc(
   4017 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
   4018 		if (temp == NULL) {
   4019 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   4020 		    return(NULL);
   4021 		}
   4022 		set1->nodeTab = temp;
   4023 		set1->nodeMax *= 2;
   4024 	    }
   4025 	    set1->nodeTab[set1->nodeNr++] = n2;
   4026 skip_node:
   4027 	    {}
   4028 	}
   4029     }
   4030     set2->nodeNr = 0;
   4031     return(set1);
   4032 }
   4033 
   4034 /**
   4035  * xmlXPathNodeSetMergeAndClearNoDupls:
   4036  * @set1:  the first NodeSet or NULL
   4037  * @set2:  the second NodeSet
   4038  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
   4039  *
   4040  * Merges two nodesets, all nodes from @set2 are added to @set1
   4041  * if @set1 is NULL, a new set is created and copied from @set2.
   4042  * Doesn't chack for duplicate nodes. Clears set2.
   4043  *
   4044  * Returns @set1 once extended or NULL in case of error.
   4045  */
   4046 static xmlNodeSetPtr
   4047 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
   4048 				    int hasNullEntries)
   4049 {
   4050     if (set2 == NULL)
   4051 	return(set1);
   4052     if ((set1 == NULL) && (hasNullEntries == 0)) {
   4053 	/*
   4054 	* Note that doing a memcpy of the list, namespace nodes are
   4055 	* just assigned to set1, since set2 is cleared anyway.
   4056 	*/
   4057 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
   4058 	if (set1 == NULL)
   4059 	    return(NULL);
   4060 	if (set2->nodeNr != 0) {
   4061 	    memcpy(set1->nodeTab, set2->nodeTab,
   4062 		set2->nodeNr * sizeof(xmlNodePtr));
   4063 	    set1->nodeNr = set2->nodeNr;
   4064 	}
   4065     } else {
   4066 	int i;
   4067 	xmlNodePtr n2;
   4068 
   4069 	if (set1 == NULL)
   4070 	    set1 = xmlXPathNodeSetCreate(NULL);
   4071         if (set1 == NULL)
   4072             return (NULL);
   4073 
   4074 	for (i = 0;i < set2->nodeNr;i++) {
   4075 	    n2 = set2->nodeTab[i];
   4076 	    /*
   4077 	    * Skip NULLed entries.
   4078 	    */
   4079 	    if (n2 == NULL)
   4080 		continue;
   4081 	    if (set1->nodeMax == 0) {
   4082 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
   4083 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
   4084 		if (set1->nodeTab == NULL) {
   4085 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   4086 		    return(NULL);
   4087 		}
   4088 		memset(set1->nodeTab, 0,
   4089 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   4090 		set1->nodeMax = XML_NODESET_DEFAULT;
   4091 	    } else if (set1->nodeNr >= set1->nodeMax) {
   4092 		xmlNodePtr *temp;
   4093 
   4094                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   4095                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
   4096                     return(NULL);
   4097                 }
   4098 		temp = (xmlNodePtr *) xmlRealloc(
   4099 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
   4100 		if (temp == NULL) {
   4101 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   4102 		    return(NULL);
   4103 		}
   4104 		set1->nodeTab = temp;
   4105 		set1->nodeMax *= 2;
   4106 	    }
   4107 	    set1->nodeTab[set1->nodeNr++] = n2;
   4108 	}
   4109     }
   4110     set2->nodeNr = 0;
   4111     return(set1);
   4112 }
   4113 
   4114 /**
   4115  * xmlXPathNodeSetDel:
   4116  * @cur:  the initial node set
   4117  * @val:  an xmlNodePtr
   4118  *
   4119  * Removes an xmlNodePtr from an existing NodeSet
   4120  */
   4121 void
   4122 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
   4123     int i;
   4124 
   4125     if (cur == NULL) return;
   4126     if (val == NULL) return;
   4127 
   4128     /*
   4129      * find node in nodeTab
   4130      */
   4131     for (i = 0;i < cur->nodeNr;i++)
   4132         if (cur->nodeTab[i] == val) break;
   4133 
   4134     if (i >= cur->nodeNr) {	/* not found */
   4135 #ifdef DEBUG
   4136         xmlGenericError(xmlGenericErrorContext,
   4137 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
   4138 		val->name);
   4139 #endif
   4140         return;
   4141     }
   4142     if ((cur->nodeTab[i] != NULL) &&
   4143 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
   4144 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
   4145     cur->nodeNr--;
   4146     for (;i < cur->nodeNr;i++)
   4147         cur->nodeTab[i] = cur->nodeTab[i + 1];
   4148     cur->nodeTab[cur->nodeNr] = NULL;
   4149 }
   4150 
   4151 /**
   4152  * xmlXPathNodeSetRemove:
   4153  * @cur:  the initial node set
   4154  * @val:  the index to remove
   4155  *
   4156  * Removes an entry from an existing NodeSet list.
   4157  */
   4158 void
   4159 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
   4160     if (cur == NULL) return;
   4161     if (val >= cur->nodeNr) return;
   4162     if ((cur->nodeTab[val] != NULL) &&
   4163 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
   4164 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
   4165     cur->nodeNr--;
   4166     for (;val < cur->nodeNr;val++)
   4167         cur->nodeTab[val] = cur->nodeTab[val + 1];
   4168     cur->nodeTab[cur->nodeNr] = NULL;
   4169 }
   4170 
   4171 /**
   4172  * xmlXPathFreeNodeSet:
   4173  * @obj:  the xmlNodeSetPtr to free
   4174  *
   4175  * Free the NodeSet compound (not the actual nodes !).
   4176  */
   4177 void
   4178 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
   4179     if (obj == NULL) return;
   4180     if (obj->nodeTab != NULL) {
   4181 	int i;
   4182 
   4183 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
   4184 	for (i = 0;i < obj->nodeNr;i++)
   4185 	    if ((obj->nodeTab[i] != NULL) &&
   4186 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
   4187 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
   4188 	xmlFree(obj->nodeTab);
   4189     }
   4190     xmlFree(obj);
   4191 }
   4192 
   4193 /**
   4194  * xmlXPathNodeSetClearFromPos:
   4195  * @set: the node set to be cleared
   4196  * @pos: the start position to clear from
   4197  *
   4198  * Clears the list from temporary XPath objects (e.g. namespace nodes
   4199  * are feed) starting with the entry at @pos, but does *not* free the list
   4200  * itself. Sets the length of the list to @pos.
   4201  */
   4202 static void
   4203 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
   4204 {
   4205     if ((set == NULL) || (pos >= set->nodeNr))
   4206 	return;
   4207     else if ((hasNsNodes)) {
   4208 	int i;
   4209 	xmlNodePtr node;
   4210 
   4211 	for (i = pos; i < set->nodeNr; i++) {
   4212 	    node = set->nodeTab[i];
   4213 	    if ((node != NULL) &&
   4214 		(node->type == XML_NAMESPACE_DECL))
   4215 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   4216 	}
   4217     }
   4218     set->nodeNr = pos;
   4219 }
   4220 
   4221 /**
   4222  * xmlXPathNodeSetClear:
   4223  * @set:  the node set to clear
   4224  *
   4225  * Clears the list from all temporary XPath objects (e.g. namespace nodes
   4226  * are feed), but does *not* free the list itself. Sets the length of the
   4227  * list to 0.
   4228  */
   4229 static void
   4230 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
   4231 {
   4232     xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
   4233 }
   4234 
   4235 /**
   4236  * xmlXPathNodeSetKeepLast:
   4237  * @set: the node set to be cleared
   4238  *
   4239  * Move the last node to the first position and clear temporary XPath objects
   4240  * (e.g. namespace nodes) from all other nodes. Sets the length of the list
   4241  * to 1.
   4242  */
   4243 static void
   4244 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
   4245 {
   4246     int i;
   4247     xmlNodePtr node;
   4248 
   4249     if ((set == NULL) || (set->nodeNr <= 1))
   4250 	return;
   4251     for (i = 0; i < set->nodeNr - 1; i++) {
   4252         node = set->nodeTab[i];
   4253         if ((node != NULL) &&
   4254             (node->type == XML_NAMESPACE_DECL))
   4255             xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   4256     }
   4257     set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
   4258     set->nodeNr = 1;
   4259 }
   4260 
   4261 /**
   4262  * xmlXPathFreeValueTree:
   4263  * @obj:  the xmlNodeSetPtr to free
   4264  *
   4265  * Free the NodeSet compound and the actual tree, this is different
   4266  * from xmlXPathFreeNodeSet()
   4267  */
   4268 static void
   4269 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
   4270     int i;
   4271 
   4272     if (obj == NULL) return;
   4273 
   4274     if (obj->nodeTab != NULL) {
   4275 	for (i = 0;i < obj->nodeNr;i++) {
   4276 	    if (obj->nodeTab[i] != NULL) {
   4277 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
   4278 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
   4279 		} else {
   4280 		    xmlFreeNodeList(obj->nodeTab[i]);
   4281 		}
   4282 	    }
   4283 	}
   4284 	xmlFree(obj->nodeTab);
   4285     }
   4286     xmlFree(obj);
   4287 }
   4288 
   4289 #if defined(DEBUG) || defined(DEBUG_STEP)
   4290 /**
   4291  * xmlGenericErrorContextNodeSet:
   4292  * @output:  a FILE * for the output
   4293  * @obj:  the xmlNodeSetPtr to display
   4294  *
   4295  * Quick display of a NodeSet
   4296  */
   4297 void
   4298 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
   4299     int i;
   4300 
   4301     if (output == NULL) output = xmlGenericErrorContext;
   4302     if (obj == NULL)  {
   4303         fprintf(output, "NodeSet == NULL !\n");
   4304 	return;
   4305     }
   4306     if (obj->nodeNr == 0) {
   4307         fprintf(output, "NodeSet is empty\n");
   4308 	return;
   4309     }
   4310     if (obj->nodeTab == NULL) {
   4311 	fprintf(output, " nodeTab == NULL !\n");
   4312 	return;
   4313     }
   4314     for (i = 0; i < obj->nodeNr; i++) {
   4315         if (obj->nodeTab[i] == NULL) {
   4316 	    fprintf(output, " NULL !\n");
   4317 	    return;
   4318         }
   4319 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
   4320 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
   4321 	    fprintf(output, " /");
   4322 	else if (obj->nodeTab[i]->name == NULL)
   4323 	    fprintf(output, " noname!");
   4324 	else fprintf(output, " %s", obj->nodeTab[i]->name);
   4325     }
   4326     fprintf(output, "\n");
   4327 }
   4328 #endif
   4329 
   4330 /**
   4331  * xmlXPathNewNodeSet:
   4332  * @val:  the NodePtr value
   4333  *
   4334  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
   4335  * it with the single Node @val
   4336  *
   4337  * Returns the newly created object.
   4338  */
   4339 xmlXPathObjectPtr
   4340 xmlXPathNewNodeSet(xmlNodePtr val) {
   4341     xmlXPathObjectPtr ret;
   4342 
   4343     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4344     if (ret == NULL) {
   4345         xmlXPathErrMemory(NULL, "creating nodeset\n");
   4346 	return(NULL);
   4347     }
   4348     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4349     ret->type = XPATH_NODESET;
   4350     ret->boolval = 0;
   4351     ret->nodesetval = xmlXPathNodeSetCreate(val);
   4352     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   4353 #ifdef XP_DEBUG_OBJ_USAGE
   4354     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
   4355 #endif
   4356     return(ret);
   4357 }
   4358 
   4359 /**
   4360  * xmlXPathNewValueTree:
   4361  * @val:  the NodePtr value
   4362  *
   4363  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
   4364  * it with the tree root @val
   4365  *
   4366  * Returns the newly created object.
   4367  */
   4368 xmlXPathObjectPtr
   4369 xmlXPathNewValueTree(xmlNodePtr val) {
   4370     xmlXPathObjectPtr ret;
   4371 
   4372     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4373     if (ret == NULL) {
   4374         xmlXPathErrMemory(NULL, "creating result value tree\n");
   4375 	return(NULL);
   4376     }
   4377     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4378     ret->type = XPATH_XSLT_TREE;
   4379     ret->boolval = 0;
   4380     ret->user = (void *) val;
   4381     ret->nodesetval = xmlXPathNodeSetCreate(val);
   4382 #ifdef XP_DEBUG_OBJ_USAGE
   4383     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
   4384 #endif
   4385     return(ret);
   4386 }
   4387 
   4388 /**
   4389  * xmlXPathNewNodeSetList:
   4390  * @val:  an existing NodeSet
   4391  *
   4392  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
   4393  * it with the Nodeset @val
   4394  *
   4395  * Returns the newly created object.
   4396  */
   4397 xmlXPathObjectPtr
   4398 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
   4399 {
   4400     xmlXPathObjectPtr ret;
   4401     int i;
   4402 
   4403     if (val == NULL)
   4404         ret = NULL;
   4405     else if (val->nodeTab == NULL)
   4406         ret = xmlXPathNewNodeSet(NULL);
   4407     else {
   4408         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
   4409         if (ret) {
   4410             for (i = 1; i < val->nodeNr; ++i) {
   4411                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
   4412 		    < 0) break;
   4413 	    }
   4414 	}
   4415     }
   4416 
   4417     return (ret);
   4418 }
   4419 
   4420 /**
   4421  * xmlXPathWrapNodeSet:
   4422  * @val:  the NodePtr value
   4423  *
   4424  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
   4425  *
   4426  * Returns the newly created object.
   4427  */
   4428 xmlXPathObjectPtr
   4429 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
   4430     xmlXPathObjectPtr ret;
   4431 
   4432     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4433     if (ret == NULL) {
   4434         xmlXPathErrMemory(NULL, "creating node set object\n");
   4435 	return(NULL);
   4436     }
   4437     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4438     ret->type = XPATH_NODESET;
   4439     ret->nodesetval = val;
   4440 #ifdef XP_DEBUG_OBJ_USAGE
   4441     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
   4442 #endif
   4443     return(ret);
   4444 }
   4445 
   4446 /**
   4447  * xmlXPathFreeNodeSetList:
   4448  * @obj:  an existing NodeSetList object
   4449  *
   4450  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
   4451  * the list contrary to xmlXPathFreeObject().
   4452  */
   4453 void
   4454 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
   4455     if (obj == NULL) return;
   4456 #ifdef XP_DEBUG_OBJ_USAGE
   4457     xmlXPathDebugObjUsageReleased(NULL, obj->type);
   4458 #endif
   4459     xmlFree(obj);
   4460 }
   4461 
   4462 /**
   4463  * xmlXPathDifference:
   4464  * @nodes1:  a node-set
   4465  * @nodes2:  a node-set
   4466  *
   4467  * Implements the EXSLT - Sets difference() function:
   4468  *    node-set set:difference (node-set, node-set)
   4469  *
   4470  * Returns the difference between the two node sets, or nodes1 if
   4471  *         nodes2 is empty
   4472  */
   4473 xmlNodeSetPtr
   4474 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4475     xmlNodeSetPtr ret;
   4476     int i, l1;
   4477     xmlNodePtr cur;
   4478 
   4479     if (xmlXPathNodeSetIsEmpty(nodes2))
   4480 	return(nodes1);
   4481 
   4482     ret = xmlXPathNodeSetCreate(NULL);
   4483     if (xmlXPathNodeSetIsEmpty(nodes1))
   4484 	return(ret);
   4485 
   4486     l1 = xmlXPathNodeSetGetLength(nodes1);
   4487 
   4488     for (i = 0; i < l1; i++) {
   4489 	cur = xmlXPathNodeSetItem(nodes1, i);
   4490 	if (!xmlXPathNodeSetContains(nodes2, cur)) {
   4491 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
   4492 	        break;
   4493 	}
   4494     }
   4495     return(ret);
   4496 }
   4497 
   4498 /**
   4499  * xmlXPathIntersection:
   4500  * @nodes1:  a node-set
   4501  * @nodes2:  a node-set
   4502  *
   4503  * Implements the EXSLT - Sets intersection() function:
   4504  *    node-set set:intersection (node-set, node-set)
   4505  *
   4506  * Returns a node set comprising the nodes that are within both the
   4507  *         node sets passed as arguments
   4508  */
   4509 xmlNodeSetPtr
   4510 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4511     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
   4512     int i, l1;
   4513     xmlNodePtr cur;
   4514 
   4515     if (ret == NULL)
   4516         return(ret);
   4517     if (xmlXPathNodeSetIsEmpty(nodes1))
   4518 	return(ret);
   4519     if (xmlXPathNodeSetIsEmpty(nodes2))
   4520 	return(ret);
   4521 
   4522     l1 = xmlXPathNodeSetGetLength(nodes1);
   4523 
   4524     for (i = 0; i < l1; i++) {
   4525 	cur = xmlXPathNodeSetItem(nodes1, i);
   4526 	if (xmlXPathNodeSetContains(nodes2, cur)) {
   4527 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
   4528 	        break;
   4529 	}
   4530     }
   4531     return(ret);
   4532 }
   4533 
   4534 /**
   4535  * xmlXPathDistinctSorted:
   4536  * @nodes:  a node-set, sorted by document order
   4537  *
   4538  * Implements the EXSLT - Sets distinct() function:
   4539  *    node-set set:distinct (node-set)
   4540  *
   4541  * Returns a subset of the nodes contained in @nodes, or @nodes if
   4542  *         it is empty
   4543  */
   4544 xmlNodeSetPtr
   4545 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
   4546     xmlNodeSetPtr ret;
   4547     xmlHashTablePtr hash;
   4548     int i, l;
   4549     xmlChar * strval;
   4550     xmlNodePtr cur;
   4551 
   4552     if (xmlXPathNodeSetIsEmpty(nodes))
   4553 	return(nodes);
   4554 
   4555     ret = xmlXPathNodeSetCreate(NULL);
   4556     if (ret == NULL)
   4557         return(ret);
   4558     l = xmlXPathNodeSetGetLength(nodes);
   4559     hash = xmlHashCreate (l);
   4560     for (i = 0; i < l; i++) {
   4561 	cur = xmlXPathNodeSetItem(nodes, i);
   4562 	strval = xmlXPathCastNodeToString(cur);
   4563 	if (xmlHashLookup(hash, strval) == NULL) {
   4564 	    xmlHashAddEntry(hash, strval, strval);
   4565 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
   4566 	        break;
   4567 	} else {
   4568 	    xmlFree(strval);
   4569 	}
   4570     }
   4571     xmlHashFree(hash, xmlHashDefaultDeallocator);
   4572     return(ret);
   4573 }
   4574 
   4575 /**
   4576  * xmlXPathDistinct:
   4577  * @nodes:  a node-set
   4578  *
   4579  * Implements the EXSLT - Sets distinct() function:
   4580  *    node-set set:distinct (node-set)
   4581  * @nodes is sorted by document order, then #exslSetsDistinctSorted
   4582  * is called with the sorted node-set
   4583  *
   4584  * Returns a subset of the nodes contained in @nodes, or @nodes if
   4585  *         it is empty
   4586  */
   4587 xmlNodeSetPtr
   4588 xmlXPathDistinct (xmlNodeSetPtr nodes) {
   4589     if (xmlXPathNodeSetIsEmpty(nodes))
   4590 	return(nodes);
   4591 
   4592     xmlXPathNodeSetSort(nodes);
   4593     return(xmlXPathDistinctSorted(nodes));
   4594 }
   4595 
   4596 /**
   4597  * xmlXPathHasSameNodes:
   4598  * @nodes1:  a node-set
   4599  * @nodes2:  a node-set
   4600  *
   4601  * Implements the EXSLT - Sets has-same-nodes function:
   4602  *    boolean set:has-same-node(node-set, node-set)
   4603  *
   4604  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
   4605  *         otherwise
   4606  */
   4607 int
   4608 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4609     int i, l;
   4610     xmlNodePtr cur;
   4611 
   4612     if (xmlXPathNodeSetIsEmpty(nodes1) ||
   4613 	xmlXPathNodeSetIsEmpty(nodes2))
   4614 	return(0);
   4615 
   4616     l = xmlXPathNodeSetGetLength(nodes1);
   4617     for (i = 0; i < l; i++) {
   4618 	cur = xmlXPathNodeSetItem(nodes1, i);
   4619 	if (xmlXPathNodeSetContains(nodes2, cur))
   4620 	    return(1);
   4621     }
   4622     return(0);
   4623 }
   4624 
   4625 /**
   4626  * xmlXPathNodeLeadingSorted:
   4627  * @nodes: a node-set, sorted by document order
   4628  * @node: a node
   4629  *
   4630  * Implements the EXSLT - Sets leading() function:
   4631  *    node-set set:leading (node-set, node-set)
   4632  *
   4633  * Returns the nodes in @nodes that precede @node in document order,
   4634  *         @nodes if @node is NULL or an empty node-set if @nodes
   4635  *         doesn't contain @node
   4636  */
   4637 xmlNodeSetPtr
   4638 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4639     int i, l;
   4640     xmlNodePtr cur;
   4641     xmlNodeSetPtr ret;
   4642 
   4643     if (node == NULL)
   4644 	return(nodes);
   4645 
   4646     ret = xmlXPathNodeSetCreate(NULL);
   4647     if (ret == NULL)
   4648         return(ret);
   4649     if (xmlXPathNodeSetIsEmpty(nodes) ||
   4650 	(!xmlXPathNodeSetContains(nodes, node)))
   4651 	return(ret);
   4652 
   4653     l = xmlXPathNodeSetGetLength(nodes);
   4654     for (i = 0; i < l; i++) {
   4655 	cur = xmlXPathNodeSetItem(nodes, i);
   4656 	if (cur == node)
   4657 	    break;
   4658 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
   4659 	    break;
   4660     }
   4661     return(ret);
   4662 }
   4663 
   4664 /**
   4665  * xmlXPathNodeLeading:
   4666  * @nodes:  a node-set
   4667  * @node:  a node
   4668  *
   4669  * Implements the EXSLT - Sets leading() function:
   4670  *    node-set set:leading (node-set, node-set)
   4671  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
   4672  * is called.
   4673  *
   4674  * Returns the nodes in @nodes that precede @node in document order,
   4675  *         @nodes if @node is NULL or an empty node-set if @nodes
   4676  *         doesn't contain @node
   4677  */
   4678 xmlNodeSetPtr
   4679 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4680     xmlXPathNodeSetSort(nodes);
   4681     return(xmlXPathNodeLeadingSorted(nodes, node));
   4682 }
   4683 
   4684 /**
   4685  * xmlXPathLeadingSorted:
   4686  * @nodes1:  a node-set, sorted by document order
   4687  * @nodes2:  a node-set, sorted by document order
   4688  *
   4689  * Implements the EXSLT - Sets leading() function:
   4690  *    node-set set:leading (node-set, node-set)
   4691  *
   4692  * Returns the nodes in @nodes1 that precede the first node in @nodes2
   4693  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4694  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4695  */
   4696 xmlNodeSetPtr
   4697 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4698     if (xmlXPathNodeSetIsEmpty(nodes2))
   4699 	return(nodes1);
   4700     return(xmlXPathNodeLeadingSorted(nodes1,
   4701 				     xmlXPathNodeSetItem(nodes2, 1)));
   4702 }
   4703 
   4704 /**
   4705  * xmlXPathLeading:
   4706  * @nodes1:  a node-set
   4707  * @nodes2:  a node-set
   4708  *
   4709  * Implements the EXSLT - Sets leading() function:
   4710  *    node-set set:leading (node-set, node-set)
   4711  * @nodes1 and @nodes2 are sorted by document order, then
   4712  * #exslSetsLeadingSorted is called.
   4713  *
   4714  * Returns the nodes in @nodes1 that precede the first node in @nodes2
   4715  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4716  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4717  */
   4718 xmlNodeSetPtr
   4719 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4720     if (xmlXPathNodeSetIsEmpty(nodes2))
   4721 	return(nodes1);
   4722     if (xmlXPathNodeSetIsEmpty(nodes1))
   4723 	return(xmlXPathNodeSetCreate(NULL));
   4724     xmlXPathNodeSetSort(nodes1);
   4725     xmlXPathNodeSetSort(nodes2);
   4726     return(xmlXPathNodeLeadingSorted(nodes1,
   4727 				     xmlXPathNodeSetItem(nodes2, 1)));
   4728 }
   4729 
   4730 /**
   4731  * xmlXPathNodeTrailingSorted:
   4732  * @nodes: a node-set, sorted by document order
   4733  * @node: a node
   4734  *
   4735  * Implements the EXSLT - Sets trailing() function:
   4736  *    node-set set:trailing (node-set, node-set)
   4737  *
   4738  * Returns the nodes in @nodes that follow @node in document order,
   4739  *         @nodes if @node is NULL or an empty node-set if @nodes
   4740  *         doesn't contain @node
   4741  */
   4742 xmlNodeSetPtr
   4743 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4744     int i, l;
   4745     xmlNodePtr cur;
   4746     xmlNodeSetPtr ret;
   4747 
   4748     if (node == NULL)
   4749 	return(nodes);
   4750 
   4751     ret = xmlXPathNodeSetCreate(NULL);
   4752     if (ret == NULL)
   4753         return(ret);
   4754     if (xmlXPathNodeSetIsEmpty(nodes) ||
   4755 	(!xmlXPathNodeSetContains(nodes, node)))
   4756 	return(ret);
   4757 
   4758     l = xmlXPathNodeSetGetLength(nodes);
   4759     for (i = l - 1; i >= 0; i--) {
   4760 	cur = xmlXPathNodeSetItem(nodes, i);
   4761 	if (cur == node)
   4762 	    break;
   4763 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
   4764 	    break;
   4765     }
   4766     xmlXPathNodeSetSort(ret);	/* bug 413451 */
   4767     return(ret);
   4768 }
   4769 
   4770 /**
   4771  * xmlXPathNodeTrailing:
   4772  * @nodes:  a node-set
   4773  * @node:  a node
   4774  *
   4775  * Implements the EXSLT - Sets trailing() function:
   4776  *    node-set set:trailing (node-set, node-set)
   4777  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
   4778  * is called.
   4779  *
   4780  * Returns the nodes in @nodes that follow @node in document order,
   4781  *         @nodes if @node is NULL or an empty node-set if @nodes
   4782  *         doesn't contain @node
   4783  */
   4784 xmlNodeSetPtr
   4785 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4786     xmlXPathNodeSetSort(nodes);
   4787     return(xmlXPathNodeTrailingSorted(nodes, node));
   4788 }
   4789 
   4790 /**
   4791  * xmlXPathTrailingSorted:
   4792  * @nodes1:  a node-set, sorted by document order
   4793  * @nodes2:  a node-set, sorted by document order
   4794  *
   4795  * Implements the EXSLT - Sets trailing() function:
   4796  *    node-set set:trailing (node-set, node-set)
   4797  *
   4798  * Returns the nodes in @nodes1 that follow the first node in @nodes2
   4799  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4800  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4801  */
   4802 xmlNodeSetPtr
   4803 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4804     if (xmlXPathNodeSetIsEmpty(nodes2))
   4805 	return(nodes1);
   4806     return(xmlXPathNodeTrailingSorted(nodes1,
   4807 				      xmlXPathNodeSetItem(nodes2, 0)));
   4808 }
   4809 
   4810 /**
   4811  * xmlXPathTrailing:
   4812  * @nodes1:  a node-set
   4813  * @nodes2:  a node-set
   4814  *
   4815  * Implements the EXSLT - Sets trailing() function:
   4816  *    node-set set:trailing (node-set, node-set)
   4817  * @nodes1 and @nodes2 are sorted by document order, then
   4818  * #xmlXPathTrailingSorted is called.
   4819  *
   4820  * Returns the nodes in @nodes1 that follow the first node in @nodes2
   4821  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4822  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4823  */
   4824 xmlNodeSetPtr
   4825 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4826     if (xmlXPathNodeSetIsEmpty(nodes2))
   4827 	return(nodes1);
   4828     if (xmlXPathNodeSetIsEmpty(nodes1))
   4829 	return(xmlXPathNodeSetCreate(NULL));
   4830     xmlXPathNodeSetSort(nodes1);
   4831     xmlXPathNodeSetSort(nodes2);
   4832     return(xmlXPathNodeTrailingSorted(nodes1,
   4833 				      xmlXPathNodeSetItem(nodes2, 0)));
   4834 }
   4835 
   4836 /************************************************************************
   4837  *									*
   4838  *		Routines to handle extra functions			*
   4839  *									*
   4840  ************************************************************************/
   4841 
   4842 /**
   4843  * xmlXPathRegisterFunc:
   4844  * @ctxt:  the XPath context
   4845  * @name:  the function name
   4846  * @f:  the function implementation or NULL
   4847  *
   4848  * Register a new function. If @f is NULL it unregisters the function
   4849  *
   4850  * Returns 0 in case of success, -1 in case of error
   4851  */
   4852 int
   4853 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
   4854 		     xmlXPathFunction f) {
   4855     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
   4856 }
   4857 
   4858 /**
   4859  * xmlXPathRegisterFuncNS:
   4860  * @ctxt:  the XPath context
   4861  * @name:  the function name
   4862  * @ns_uri:  the function namespace URI
   4863  * @f:  the function implementation or NULL
   4864  *
   4865  * Register a new function. If @f is NULL it unregisters the function
   4866  *
   4867  * Returns 0 in case of success, -1 in case of error
   4868  */
   4869 int
   4870 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   4871 		       const xmlChar *ns_uri, xmlXPathFunction f) {
   4872     if (ctxt == NULL)
   4873 	return(-1);
   4874     if (name == NULL)
   4875 	return(-1);
   4876 
   4877     if (ctxt->funcHash == NULL)
   4878 	ctxt->funcHash = xmlHashCreate(0);
   4879     if (ctxt->funcHash == NULL)
   4880 	return(-1);
   4881     if (f == NULL)
   4882         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
   4883 XML_IGNORE_PEDANTIC_WARNINGS
   4884     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
   4885 XML_POP_WARNINGS
   4886 }
   4887 
   4888 /**
   4889  * xmlXPathRegisterFuncLookup:
   4890  * @ctxt:  the XPath context
   4891  * @f:  the lookup function
   4892  * @funcCtxt:  the lookup data
   4893  *
   4894  * Registers an external mechanism to do function lookup.
   4895  */
   4896 void
   4897 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
   4898 			    xmlXPathFuncLookupFunc f,
   4899 			    void *funcCtxt) {
   4900     if (ctxt == NULL)
   4901 	return;
   4902     ctxt->funcLookupFunc = f;
   4903     ctxt->funcLookupData = funcCtxt;
   4904 }
   4905 
   4906 /**
   4907  * xmlXPathFunctionLookup:
   4908  * @ctxt:  the XPath context
   4909  * @name:  the function name
   4910  *
   4911  * Search in the Function array of the context for the given
   4912  * function.
   4913  *
   4914  * Returns the xmlXPathFunction or NULL if not found
   4915  */
   4916 xmlXPathFunction
   4917 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
   4918     if (ctxt == NULL)
   4919 	return (NULL);
   4920 
   4921     if (ctxt->funcLookupFunc != NULL) {
   4922 	xmlXPathFunction ret;
   4923 	xmlXPathFuncLookupFunc f;
   4924 
   4925 	f = ctxt->funcLookupFunc;
   4926 	ret = f(ctxt->funcLookupData, name, NULL);
   4927 	if (ret != NULL)
   4928 	    return(ret);
   4929     }
   4930     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
   4931 }
   4932 
   4933 /**
   4934  * xmlXPathFunctionLookupNS:
   4935  * @ctxt:  the XPath context
   4936  * @name:  the function name
   4937  * @ns_uri:  the function namespace URI
   4938  *
   4939  * Search in the Function array of the context for the given
   4940  * function.
   4941  *
   4942  * Returns the xmlXPathFunction or NULL if not found
   4943  */
   4944 xmlXPathFunction
   4945 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   4946 			 const xmlChar *ns_uri) {
   4947     xmlXPathFunction ret;
   4948 
   4949     if (ctxt == NULL)
   4950 	return(NULL);
   4951     if (name == NULL)
   4952 	return(NULL);
   4953 
   4954     if (ctxt->funcLookupFunc != NULL) {
   4955 	xmlXPathFuncLookupFunc f;
   4956 
   4957 	f = ctxt->funcLookupFunc;
   4958 	ret = f(ctxt->funcLookupData, name, ns_uri);
   4959 	if (ret != NULL)
   4960 	    return(ret);
   4961     }
   4962 
   4963     if (ctxt->funcHash == NULL)
   4964 	return(NULL);
   4965 
   4966 XML_IGNORE_PEDANTIC_WARNINGS
   4967     ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
   4968 XML_POP_WARNINGS
   4969     return(ret);
   4970 }
   4971 
   4972 /**
   4973  * xmlXPathRegisteredFuncsCleanup:
   4974  * @ctxt:  the XPath context
   4975  *
   4976  * Cleanup the XPath context data associated to registered functions
   4977  */
   4978 void
   4979 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
   4980     if (ctxt == NULL)
   4981 	return;
   4982 
   4983     xmlHashFree(ctxt->funcHash, NULL);
   4984     ctxt->funcHash = NULL;
   4985 }
   4986 
   4987 /************************************************************************
   4988  *									*
   4989  *			Routines to handle Variables			*
   4990  *									*
   4991  ************************************************************************/
   4992 
   4993 /**
   4994  * xmlXPathRegisterVariable:
   4995  * @ctxt:  the XPath context
   4996  * @name:  the variable name
   4997  * @value:  the variable value or NULL
   4998  *
   4999  * Register a new variable value. If @value is NULL it unregisters
   5000  * the variable
   5001  *
   5002  * Returns 0 in case of success, -1 in case of error
   5003  */
   5004 int
   5005 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
   5006 			 xmlXPathObjectPtr value) {
   5007     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
   5008 }
   5009 
   5010 /**
   5011  * xmlXPathRegisterVariableNS:
   5012  * @ctxt:  the XPath context
   5013  * @name:  the variable name
   5014  * @ns_uri:  the variable namespace URI
   5015  * @value:  the variable value or NULL
   5016  *
   5017  * Register a new variable value. If @value is NULL it unregisters
   5018  * the variable
   5019  *
   5020  * Returns 0 in case of success, -1 in case of error
   5021  */
   5022 int
   5023 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   5024 			   const xmlChar *ns_uri,
   5025 			   xmlXPathObjectPtr value) {
   5026     if (ctxt == NULL)
   5027 	return(-1);
   5028     if (name == NULL)
   5029 	return(-1);
   5030 
   5031     if (ctxt->varHash == NULL)
   5032 	ctxt->varHash = xmlHashCreate(0);
   5033     if (ctxt->varHash == NULL)
   5034 	return(-1);
   5035     if (value == NULL)
   5036         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
   5037 	                           xmlXPathFreeObjectEntry));
   5038     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
   5039 			       (void *) value, xmlXPathFreeObjectEntry));
   5040 }
   5041 
   5042 /**
   5043  * xmlXPathRegisterVariableLookup:
   5044  * @ctxt:  the XPath context
   5045  * @f:  the lookup function
   5046  * @data:  the lookup data
   5047  *
   5048  * register an external mechanism to do variable lookup
   5049  */
   5050 void
   5051 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
   5052 	 xmlXPathVariableLookupFunc f, void *data) {
   5053     if (ctxt == NULL)
   5054 	return;
   5055     ctxt->varLookupFunc = f;
   5056     ctxt->varLookupData = data;
   5057 }
   5058 
   5059 /**
   5060  * xmlXPathVariableLookup:
   5061  * @ctxt:  the XPath context
   5062  * @name:  the variable name
   5063  *
   5064  * Search in the Variable array of the context for the given
   5065  * variable value.
   5066  *
   5067  * Returns a copy of the value or NULL if not found
   5068  */
   5069 xmlXPathObjectPtr
   5070 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
   5071     if (ctxt == NULL)
   5072 	return(NULL);
   5073 
   5074     if (ctxt->varLookupFunc != NULL) {
   5075 	xmlXPathObjectPtr ret;
   5076 
   5077 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
   5078 	        (ctxt->varLookupData, name, NULL);
   5079 	return(ret);
   5080     }
   5081     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
   5082 }
   5083 
   5084 /**
   5085  * xmlXPathVariableLookupNS:
   5086  * @ctxt:  the XPath context
   5087  * @name:  the variable name
   5088  * @ns_uri:  the variable namespace URI
   5089  *
   5090  * Search in the Variable array of the context for the given
   5091  * variable value.
   5092  *
   5093  * Returns the a copy of the value or NULL if not found
   5094  */
   5095 xmlXPathObjectPtr
   5096 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   5097 			 const xmlChar *ns_uri) {
   5098     if (ctxt == NULL)
   5099 	return(NULL);
   5100 
   5101     if (ctxt->varLookupFunc != NULL) {
   5102 	xmlXPathObjectPtr ret;
   5103 
   5104 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
   5105 	        (ctxt->varLookupData, name, ns_uri);
   5106 	if (ret != NULL) return(ret);
   5107     }
   5108 
   5109     if (ctxt->varHash == NULL)
   5110 	return(NULL);
   5111     if (name == NULL)
   5112 	return(NULL);
   5113 
   5114     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
   5115 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
   5116 }
   5117 
   5118 /**
   5119  * xmlXPathRegisteredVariablesCleanup:
   5120  * @ctxt:  the XPath context
   5121  *
   5122  * Cleanup the XPath context data associated to registered variables
   5123  */
   5124 void
   5125 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
   5126     if (ctxt == NULL)
   5127 	return;
   5128 
   5129     xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
   5130     ctxt->varHash = NULL;
   5131 }
   5132 
   5133 /**
   5134  * xmlXPathRegisterNs:
   5135  * @ctxt:  the XPath context
   5136  * @prefix:  the namespace prefix cannot be NULL or empty string
   5137  * @ns_uri:  the namespace name
   5138  *
   5139  * Register a new namespace. If @ns_uri is NULL it unregisters
   5140  * the namespace
   5141  *
   5142  * Returns 0 in case of success, -1 in case of error
   5143  */
   5144 int
   5145 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
   5146 			   const xmlChar *ns_uri) {
   5147     if (ctxt == NULL)
   5148 	return(-1);
   5149     if (prefix == NULL)
   5150 	return(-1);
   5151     if (prefix[0] == 0)
   5152 	return(-1);
   5153 
   5154     if (ctxt->nsHash == NULL)
   5155 	ctxt->nsHash = xmlHashCreate(10);
   5156     if (ctxt->nsHash == NULL)
   5157 	return(-1);
   5158     if (ns_uri == NULL)
   5159         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
   5160 	                          xmlHashDefaultDeallocator));
   5161     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
   5162 			      xmlHashDefaultDeallocator));
   5163 }
   5164 
   5165 /**
   5166  * xmlXPathNsLookup:
   5167  * @ctxt:  the XPath context
   5168  * @prefix:  the namespace prefix value
   5169  *
   5170  * Search in the namespace declaration array of the context for the given
   5171  * namespace name associated to the given prefix
   5172  *
   5173  * Returns the value or NULL if not found
   5174  */
   5175 const xmlChar *
   5176 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
   5177     if (ctxt == NULL)
   5178 	return(NULL);
   5179     if (prefix == NULL)
   5180 	return(NULL);
   5181 
   5182 #ifdef XML_XML_NAMESPACE
   5183     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
   5184 	return(XML_XML_NAMESPACE);
   5185 #endif
   5186 
   5187     if (ctxt->namespaces != NULL) {
   5188 	int i;
   5189 
   5190 	for (i = 0;i < ctxt->nsNr;i++) {
   5191 	    if ((ctxt->namespaces[i] != NULL) &&
   5192 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
   5193 		return(ctxt->namespaces[i]->href);
   5194 	}
   5195     }
   5196 
   5197     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
   5198 }
   5199 
   5200 /**
   5201  * xmlXPathRegisteredNsCleanup:
   5202  * @ctxt:  the XPath context
   5203  *
   5204  * Cleanup the XPath context data associated to registered variables
   5205  */
   5206 void
   5207 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
   5208     if (ctxt == NULL)
   5209 	return;
   5210 
   5211     xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
   5212     ctxt->nsHash = NULL;
   5213 }
   5214 
   5215 /************************************************************************
   5216  *									*
   5217  *			Routines to handle Values			*
   5218  *									*
   5219  ************************************************************************/
   5220 
   5221 /* Allocations are terrible, one needs to optimize all this !!! */
   5222 
   5223 /**
   5224  * xmlXPathNewFloat:
   5225  * @val:  the double value
   5226  *
   5227  * Create a new xmlXPathObjectPtr of type double and of value @val
   5228  *
   5229  * Returns the newly created object.
   5230  */
   5231 xmlXPathObjectPtr
   5232 xmlXPathNewFloat(double val) {
   5233     xmlXPathObjectPtr ret;
   5234 
   5235     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5236     if (ret == NULL) {
   5237         xmlXPathErrMemory(NULL, "creating float object\n");
   5238 	return(NULL);
   5239     }
   5240     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5241     ret->type = XPATH_NUMBER;
   5242     ret->floatval = val;
   5243 #ifdef XP_DEBUG_OBJ_USAGE
   5244     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
   5245 #endif
   5246     return(ret);
   5247 }
   5248 
   5249 /**
   5250  * xmlXPathNewBoolean:
   5251  * @val:  the boolean value
   5252  *
   5253  * Create a new xmlXPathObjectPtr of type boolean and of value @val
   5254  *
   5255  * Returns the newly created object.
   5256  */
   5257 xmlXPathObjectPtr
   5258 xmlXPathNewBoolean(int val) {
   5259     xmlXPathObjectPtr ret;
   5260 
   5261     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5262     if (ret == NULL) {
   5263         xmlXPathErrMemory(NULL, "creating boolean object\n");
   5264 	return(NULL);
   5265     }
   5266     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5267     ret->type = XPATH_BOOLEAN;
   5268     ret->boolval = (val != 0);
   5269 #ifdef XP_DEBUG_OBJ_USAGE
   5270     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
   5271 #endif
   5272     return(ret);
   5273 }
   5274 
   5275 /**
   5276  * xmlXPathNewString:
   5277  * @val:  the xmlChar * value
   5278  *
   5279  * Create a new xmlXPathObjectPtr of type string and of value @val
   5280  *
   5281  * Returns the newly created object.
   5282  */
   5283 xmlXPathObjectPtr
   5284 xmlXPathNewString(const xmlChar *val) {
   5285     xmlXPathObjectPtr ret;
   5286 
   5287     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5288     if (ret == NULL) {
   5289         xmlXPathErrMemory(NULL, "creating string object\n");
   5290 	return(NULL);
   5291     }
   5292     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5293     ret->type = XPATH_STRING;
   5294     if (val != NULL)
   5295 	ret->stringval = xmlStrdup(val);
   5296     else
   5297 	ret->stringval = xmlStrdup((const xmlChar *)"");
   5298 #ifdef XP_DEBUG_OBJ_USAGE
   5299     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5300 #endif
   5301     return(ret);
   5302 }
   5303 
   5304 /**
   5305  * xmlXPathWrapString:
   5306  * @val:  the xmlChar * value
   5307  *
   5308  * Wraps the @val string into an XPath object.
   5309  *
   5310  * Returns the newly created object.
   5311  */
   5312 xmlXPathObjectPtr
   5313 xmlXPathWrapString (xmlChar *val) {
   5314     xmlXPathObjectPtr ret;
   5315 
   5316     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5317     if (ret == NULL) {
   5318         xmlXPathErrMemory(NULL, "creating string object\n");
   5319 	return(NULL);
   5320     }
   5321     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5322     ret->type = XPATH_STRING;
   5323     ret->stringval = val;
   5324 #ifdef XP_DEBUG_OBJ_USAGE
   5325     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5326 #endif
   5327     return(ret);
   5328 }
   5329 
   5330 /**
   5331  * xmlXPathNewCString:
   5332  * @val:  the char * value
   5333  *
   5334  * Create a new xmlXPathObjectPtr of type string and of value @val
   5335  *
   5336  * Returns the newly created object.
   5337  */
   5338 xmlXPathObjectPtr
   5339 xmlXPathNewCString(const char *val) {
   5340     xmlXPathObjectPtr ret;
   5341 
   5342     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5343     if (ret == NULL) {
   5344         xmlXPathErrMemory(NULL, "creating string object\n");
   5345 	return(NULL);
   5346     }
   5347     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5348     ret->type = XPATH_STRING;
   5349     ret->stringval = xmlStrdup(BAD_CAST val);
   5350 #ifdef XP_DEBUG_OBJ_USAGE
   5351     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5352 #endif
   5353     return(ret);
   5354 }
   5355 
   5356 /**
   5357  * xmlXPathWrapCString:
   5358  * @val:  the char * value
   5359  *
   5360  * Wraps a string into an XPath object.
   5361  *
   5362  * Returns the newly created object.
   5363  */
   5364 xmlXPathObjectPtr
   5365 xmlXPathWrapCString (char * val) {
   5366     return(xmlXPathWrapString((xmlChar *)(val)));
   5367 }
   5368 
   5369 /**
   5370  * xmlXPathWrapExternal:
   5371  * @val:  the user data
   5372  *
   5373  * Wraps the @val data into an XPath object.
   5374  *
   5375  * Returns the newly created object.
   5376  */
   5377 xmlXPathObjectPtr
   5378 xmlXPathWrapExternal (void *val) {
   5379     xmlXPathObjectPtr ret;
   5380 
   5381     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5382     if (ret == NULL) {
   5383         xmlXPathErrMemory(NULL, "creating user object\n");
   5384 	return(NULL);
   5385     }
   5386     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5387     ret->type = XPATH_USERS;
   5388     ret->user = val;
   5389 #ifdef XP_DEBUG_OBJ_USAGE
   5390     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
   5391 #endif
   5392     return(ret);
   5393 }
   5394 
   5395 /**
   5396  * xmlXPathObjectCopy:
   5397  * @val:  the original object
   5398  *
   5399  * allocate a new copy of a given object
   5400  *
   5401  * Returns the newly created object.
   5402  */
   5403 xmlXPathObjectPtr
   5404 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
   5405     xmlXPathObjectPtr ret;
   5406 
   5407     if (val == NULL)
   5408 	return(NULL);
   5409 
   5410     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5411     if (ret == NULL) {
   5412         xmlXPathErrMemory(NULL, "copying object\n");
   5413 	return(NULL);
   5414     }
   5415     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
   5416 #ifdef XP_DEBUG_OBJ_USAGE
   5417     xmlXPathDebugObjUsageRequested(NULL, val->type);
   5418 #endif
   5419     switch (val->type) {
   5420 	case XPATH_BOOLEAN:
   5421 	case XPATH_NUMBER:
   5422 	case XPATH_POINT:
   5423 	case XPATH_RANGE:
   5424 	    break;
   5425 	case XPATH_STRING:
   5426 	    ret->stringval = xmlStrdup(val->stringval);
   5427 	    break;
   5428 	case XPATH_XSLT_TREE:
   5429 #if 0
   5430 /*
   5431   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
   5432   this previous handling is no longer correct, and can cause some serious
   5433   problems (ref. bug 145547)
   5434 */
   5435 	    if ((val->nodesetval != NULL) &&
   5436 		(val->nodesetval->nodeTab != NULL)) {
   5437 		xmlNodePtr cur, tmp;
   5438 		xmlDocPtr top;
   5439 
   5440 		ret->boolval = 1;
   5441 		top =  xmlNewDoc(NULL);
   5442 		top->name = (char *)
   5443 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
   5444 		ret->user = top;
   5445 		if (top != NULL) {
   5446 		    top->doc = top;
   5447 		    cur = val->nodesetval->nodeTab[0]->children;
   5448 		    while (cur != NULL) {
   5449 			tmp = xmlDocCopyNode(cur, top, 1);
   5450 			xmlAddChild((xmlNodePtr) top, tmp);
   5451 			cur = cur->next;
   5452 		    }
   5453 		}
   5454 
   5455 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
   5456 	    } else
   5457 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
   5458 	    /* Deallocate the copied tree value */
   5459 	    break;
   5460 #endif
   5461 	case XPATH_NODESET:
   5462 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
   5463 	    /* Do not deallocate the copied tree value */
   5464 	    ret->boolval = 0;
   5465 	    break;
   5466 	case XPATH_LOCATIONSET:
   5467 #ifdef LIBXML_XPTR_ENABLED
   5468 	{
   5469 	    xmlLocationSetPtr loc = val->user;
   5470 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
   5471 	    break;
   5472 	}
   5473 #endif
   5474         case XPATH_USERS:
   5475 	    ret->user = val->user;
   5476 	    break;
   5477         case XPATH_UNDEFINED:
   5478 	    xmlGenericError(xmlGenericErrorContext,
   5479 		    "xmlXPathObjectCopy: unsupported type %d\n",
   5480 		    val->type);
   5481 	    break;
   5482     }
   5483     return(ret);
   5484 }
   5485 
   5486 /**
   5487  * xmlXPathFreeObject:
   5488  * @obj:  the object to free
   5489  *
   5490  * Free up an xmlXPathObjectPtr object.
   5491  */
   5492 void
   5493 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
   5494     if (obj == NULL) return;
   5495     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
   5496 	if (obj->boolval) {
   5497 #if 0
   5498 	    if (obj->user != NULL) {
   5499                 xmlXPathFreeNodeSet(obj->nodesetval);
   5500 		xmlFreeNodeList((xmlNodePtr) obj->user);
   5501 	    } else
   5502 #endif
   5503 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
   5504 	    if (obj->nodesetval != NULL)
   5505 		xmlXPathFreeValueTree(obj->nodesetval);
   5506 	} else {
   5507 	    if (obj->nodesetval != NULL)
   5508 		xmlXPathFreeNodeSet(obj->nodesetval);
   5509 	}
   5510 #ifdef LIBXML_XPTR_ENABLED
   5511     } else if (obj->type == XPATH_LOCATIONSET) {
   5512 	if (obj->user != NULL)
   5513 	    xmlXPtrFreeLocationSet(obj->user);
   5514 #endif
   5515     } else if (obj->type == XPATH_STRING) {
   5516 	if (obj->stringval != NULL)
   5517 	    xmlFree(obj->stringval);
   5518     }
   5519 #ifdef XP_DEBUG_OBJ_USAGE
   5520     xmlXPathDebugObjUsageReleased(NULL, obj->type);
   5521 #endif
   5522     xmlFree(obj);
   5523 }
   5524 
   5525 static void
   5526 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
   5527     xmlXPathFreeObject((xmlXPathObjectPtr) obj);
   5528 }
   5529 
   5530 /**
   5531  * xmlXPathReleaseObject:
   5532  * @obj:  the xmlXPathObjectPtr to free or to cache
   5533  *
   5534  * Depending on the state of the cache this frees the given
   5535  * XPath object or stores it in the cache.
   5536  */
   5537 static void
   5538 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
   5539 {
   5540 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
   5541 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
   5542     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
   5543 
   5544 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
   5545 
   5546     if (obj == NULL)
   5547 	return;
   5548     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
   5549 	 xmlXPathFreeObject(obj);
   5550     } else {
   5551 	xmlXPathContextCachePtr cache =
   5552 	    (xmlXPathContextCachePtr) ctxt->cache;
   5553 
   5554 	switch (obj->type) {
   5555 	    case XPATH_NODESET:
   5556 	    case XPATH_XSLT_TREE:
   5557 		if (obj->nodesetval != NULL) {
   5558 		    if (obj->boolval) {
   5559 			/*
   5560 			* It looks like the @boolval is used for
   5561 			* evaluation if this an XSLT Result Tree Fragment.
   5562 			* TODO: Check if this assumption is correct.
   5563 			*/
   5564 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
   5565 			xmlXPathFreeValueTree(obj->nodesetval);
   5566 			obj->nodesetval = NULL;
   5567 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
   5568 			(XP_CACHE_WANTS(cache->nodesetObjs,
   5569 					cache->maxNodeset)))
   5570 		    {
   5571 			XP_CACHE_ADD(cache->nodesetObjs, obj);
   5572 			goto obj_cached;
   5573 		    } else {
   5574 			xmlXPathFreeNodeSet(obj->nodesetval);
   5575 			obj->nodesetval = NULL;
   5576 		    }
   5577 		}
   5578 		break;
   5579 	    case XPATH_STRING:
   5580 		if (obj->stringval != NULL)
   5581 		    xmlFree(obj->stringval);
   5582 
   5583 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
   5584 		    XP_CACHE_ADD(cache->stringObjs, obj);
   5585 		    goto obj_cached;
   5586 		}
   5587 		break;
   5588 	    case XPATH_BOOLEAN:
   5589 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
   5590 		    XP_CACHE_ADD(cache->booleanObjs, obj);
   5591 		    goto obj_cached;
   5592 		}
   5593 		break;
   5594 	    case XPATH_NUMBER:
   5595 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
   5596 		    XP_CACHE_ADD(cache->numberObjs, obj);
   5597 		    goto obj_cached;
   5598 		}
   5599 		break;
   5600 #ifdef LIBXML_XPTR_ENABLED
   5601 	    case XPATH_LOCATIONSET:
   5602 		if (obj->user != NULL) {
   5603 		    xmlXPtrFreeLocationSet(obj->user);
   5604 		}
   5605 		goto free_obj;
   5606 #endif
   5607 	    default:
   5608 		goto free_obj;
   5609 	}
   5610 
   5611 	/*
   5612 	* Fallback to adding to the misc-objects slot.
   5613 	*/
   5614 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
   5615 	    XP_CACHE_ADD(cache->miscObjs, obj);
   5616 	} else
   5617 	    goto free_obj;
   5618 
   5619 obj_cached:
   5620 
   5621 #ifdef XP_DEBUG_OBJ_USAGE
   5622 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
   5623 #endif
   5624 
   5625 	if (obj->nodesetval != NULL) {
   5626 	    xmlNodeSetPtr tmpset = obj->nodesetval;
   5627 
   5628 	    /*
   5629 	    * TODO: Due to those nasty ns-nodes, we need to traverse
   5630 	    *  the list and free the ns-nodes.
   5631 	    * URGENT TODO: Check if it's actually slowing things down.
   5632 	    *  Maybe we shouldn't try to preserve the list.
   5633 	    */
   5634 	    if (tmpset->nodeNr > 1) {
   5635 		int i;
   5636 		xmlNodePtr node;
   5637 
   5638 		for (i = 0; i < tmpset->nodeNr; i++) {
   5639 		    node = tmpset->nodeTab[i];
   5640 		    if ((node != NULL) &&
   5641 			(node->type == XML_NAMESPACE_DECL))
   5642 		    {
   5643 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   5644 		    }
   5645 		}
   5646 	    } else if (tmpset->nodeNr == 1) {
   5647 		if ((tmpset->nodeTab[0] != NULL) &&
   5648 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
   5649 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
   5650 	    }
   5651 	    tmpset->nodeNr = 0;
   5652 	    memset(obj, 0, sizeof(xmlXPathObject));
   5653 	    obj->nodesetval = tmpset;
   5654 	} else
   5655 	    memset(obj, 0, sizeof(xmlXPathObject));
   5656 
   5657 	return;
   5658 
   5659 free_obj:
   5660 	/*
   5661 	* Cache is full; free the object.
   5662 	*/
   5663 	if (obj->nodesetval != NULL)
   5664 	    xmlXPathFreeNodeSet(obj->nodesetval);
   5665 #ifdef XP_DEBUG_OBJ_USAGE
   5666 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
   5667 #endif
   5668 	xmlFree(obj);
   5669     }
   5670     return;
   5671 }
   5672 
   5673 
   5674 /************************************************************************
   5675  *									*
   5676  *			Type Casting Routines				*
   5677  *									*
   5678  ************************************************************************/
   5679 
   5680 /**
   5681  * xmlXPathCastBooleanToString:
   5682  * @val:  a boolean
   5683  *
   5684  * Converts a boolean to its string value.
   5685  *
   5686  * Returns a newly allocated string.
   5687  */
   5688 xmlChar *
   5689 xmlXPathCastBooleanToString (int val) {
   5690     xmlChar *ret;
   5691     if (val)
   5692 	ret = xmlStrdup((const xmlChar *) "true");
   5693     else
   5694 	ret = xmlStrdup((const xmlChar *) "false");
   5695     return(ret);
   5696 }
   5697 
   5698 /**
   5699  * xmlXPathCastNumberToString:
   5700  * @val:  a number
   5701  *
   5702  * Converts a number to its string value.
   5703  *
   5704  * Returns a newly allocated string.
   5705  */
   5706 xmlChar *
   5707 xmlXPathCastNumberToString (double val) {
   5708     xmlChar *ret;
   5709     switch (xmlXPathIsInf(val)) {
   5710     case 1:
   5711 	ret = xmlStrdup((const xmlChar *) "Infinity");
   5712 	break;
   5713     case -1:
   5714 	ret = xmlStrdup((const xmlChar *) "-Infinity");
   5715 	break;
   5716     default:
   5717 	if (xmlXPathIsNaN(val)) {
   5718 	    ret = xmlStrdup((const xmlChar *) "NaN");
   5719 	} else if (val == 0) {
   5720             /* Omit sign for negative zero. */
   5721 	    ret = xmlStrdup((const xmlChar *) "0");
   5722 	} else {
   5723 	    /* could be improved */
   5724 	    char buf[100];
   5725 	    xmlXPathFormatNumber(val, buf, 99);
   5726 	    buf[99] = 0;
   5727 	    ret = xmlStrdup((const xmlChar *) buf);
   5728 	}
   5729     }
   5730     return(ret);
   5731 }
   5732 
   5733 /**
   5734  * xmlXPathCastNodeToString:
   5735  * @node:  a node
   5736  *
   5737  * Converts a node to its string value.
   5738  *
   5739  * Returns a newly allocated string.
   5740  */
   5741 xmlChar *
   5742 xmlXPathCastNodeToString (xmlNodePtr node) {
   5743 xmlChar *ret;
   5744     if ((ret = xmlNodeGetContent(node)) == NULL)
   5745 	ret = xmlStrdup((const xmlChar *) "");
   5746     return(ret);
   5747 }
   5748 
   5749 /**
   5750  * xmlXPathCastNodeSetToString:
   5751  * @ns:  a node-set
   5752  *
   5753  * Converts a node-set to its string value.
   5754  *
   5755  * Returns a newly allocated string.
   5756  */
   5757 xmlChar *
   5758 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
   5759     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
   5760 	return(xmlStrdup((const xmlChar *) ""));
   5761 
   5762     if (ns->nodeNr > 1)
   5763 	xmlXPathNodeSetSort(ns);
   5764     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
   5765 }
   5766 
   5767 /**
   5768  * xmlXPathCastToString:
   5769  * @val:  an XPath object
   5770  *
   5771  * Converts an existing object to its string() equivalent
   5772  *
   5773  * Returns the allocated string value of the object, NULL in case of error.
   5774  *         It's up to the caller to free the string memory with xmlFree().
   5775  */
   5776 xmlChar *
   5777 xmlXPathCastToString(xmlXPathObjectPtr val) {
   5778     xmlChar *ret = NULL;
   5779 
   5780     if (val == NULL)
   5781 	return(xmlStrdup((const xmlChar *) ""));
   5782     switch (val->type) {
   5783 	case XPATH_UNDEFINED:
   5784 #ifdef DEBUG_EXPR
   5785 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
   5786 #endif
   5787 	    ret = xmlStrdup((const xmlChar *) "");
   5788 	    break;
   5789         case XPATH_NODESET:
   5790         case XPATH_XSLT_TREE:
   5791 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
   5792 	    break;
   5793 	case XPATH_STRING:
   5794 	    return(xmlStrdup(val->stringval));
   5795         case XPATH_BOOLEAN:
   5796 	    ret = xmlXPathCastBooleanToString(val->boolval);
   5797 	    break;
   5798 	case XPATH_NUMBER: {
   5799 	    ret = xmlXPathCastNumberToString(val->floatval);
   5800 	    break;
   5801 	}
   5802 	case XPATH_USERS:
   5803 	case XPATH_POINT:
   5804 	case XPATH_RANGE:
   5805 	case XPATH_LOCATIONSET:
   5806 	    TODO
   5807 	    ret = xmlStrdup((const xmlChar *) "");
   5808 	    break;
   5809     }
   5810     return(ret);
   5811 }
   5812 
   5813 /**
   5814  * xmlXPathConvertString:
   5815  * @val:  an XPath object
   5816  *
   5817  * Converts an existing object to its string() equivalent
   5818  *
   5819  * Returns the new object, the old one is freed (or the operation
   5820  *         is done directly on @val)
   5821  */
   5822 xmlXPathObjectPtr
   5823 xmlXPathConvertString(xmlXPathObjectPtr val) {
   5824     xmlChar *res = NULL;
   5825 
   5826     if (val == NULL)
   5827 	return(xmlXPathNewCString(""));
   5828 
   5829     switch (val->type) {
   5830     case XPATH_UNDEFINED:
   5831 #ifdef DEBUG_EXPR
   5832 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
   5833 #endif
   5834 	break;
   5835     case XPATH_NODESET:
   5836     case XPATH_XSLT_TREE:
   5837 	res = xmlXPathCastNodeSetToString(val->nodesetval);
   5838 	break;
   5839     case XPATH_STRING:
   5840 	return(val);
   5841     case XPATH_BOOLEAN:
   5842 	res = xmlXPathCastBooleanToString(val->boolval);
   5843 	break;
   5844     case XPATH_NUMBER:
   5845 	res = xmlXPathCastNumberToString(val->floatval);
   5846 	break;
   5847     case XPATH_USERS:
   5848     case XPATH_POINT:
   5849     case XPATH_RANGE:
   5850     case XPATH_LOCATIONSET:
   5851 	TODO;
   5852 	break;
   5853     }
   5854     xmlXPathFreeObject(val);
   5855     if (res == NULL)
   5856 	return(xmlXPathNewCString(""));
   5857     return(xmlXPathWrapString(res));
   5858 }
   5859 
   5860 /**
   5861  * xmlXPathCastBooleanToNumber:
   5862  * @val:  a boolean
   5863  *
   5864  * Converts a boolean to its number value
   5865  *
   5866  * Returns the number value
   5867  */
   5868 double
   5869 xmlXPathCastBooleanToNumber(int val) {
   5870     if (val)
   5871 	return(1.0);
   5872     return(0.0);
   5873 }
   5874 
   5875 /**
   5876  * xmlXPathCastStringToNumber:
   5877  * @val:  a string
   5878  *
   5879  * Converts a string to its number value
   5880  *
   5881  * Returns the number value
   5882  */
   5883 double
   5884 xmlXPathCastStringToNumber(const xmlChar * val) {
   5885     return(xmlXPathStringEvalNumber(val));
   5886 }
   5887 
   5888 /**
   5889  * xmlXPathCastNodeToNumber:
   5890  * @node:  a node
   5891  *
   5892  * Converts a node to its number value
   5893  *
   5894  * Returns the number value
   5895  */
   5896 double
   5897 xmlXPathCastNodeToNumber (xmlNodePtr node) {
   5898     xmlChar *strval;
   5899     double ret;
   5900 
   5901     if (node == NULL)
   5902 	return(NAN);
   5903     strval = xmlXPathCastNodeToString(node);
   5904     if (strval == NULL)
   5905 	return(NAN);
   5906     ret = xmlXPathCastStringToNumber(strval);
   5907     xmlFree(strval);
   5908 
   5909     return(ret);
   5910 }
   5911 
   5912 /**
   5913  * xmlXPathCastNodeSetToNumber:
   5914  * @ns:  a node-set
   5915  *
   5916  * Converts a node-set to its number value
   5917  *
   5918  * Returns the number value
   5919  */
   5920 double
   5921 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
   5922     xmlChar *str;
   5923     double ret;
   5924 
   5925     if (ns == NULL)
   5926 	return(NAN);
   5927     str = xmlXPathCastNodeSetToString(ns);
   5928     ret = xmlXPathCastStringToNumber(str);
   5929     xmlFree(str);
   5930     return(ret);
   5931 }
   5932 
   5933 /**
   5934  * xmlXPathCastToNumber:
   5935  * @val:  an XPath object
   5936  *
   5937  * Converts an XPath object to its number value
   5938  *
   5939  * Returns the number value
   5940  */
   5941 double
   5942 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
   5943     double ret = 0.0;
   5944 
   5945     if (val == NULL)
   5946 	return(NAN);
   5947     switch (val->type) {
   5948     case XPATH_UNDEFINED:
   5949 #ifdef DEGUB_EXPR
   5950 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
   5951 #endif
   5952 	ret = NAN;
   5953 	break;
   5954     case XPATH_NODESET:
   5955     case XPATH_XSLT_TREE:
   5956 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
   5957 	break;
   5958     case XPATH_STRING:
   5959 	ret = xmlXPathCastStringToNumber(val->stringval);
   5960 	break;
   5961     case XPATH_NUMBER:
   5962 	ret = val->floatval;
   5963 	break;
   5964     case XPATH_BOOLEAN:
   5965 	ret = xmlXPathCastBooleanToNumber(val->boolval);
   5966 	break;
   5967     case XPATH_USERS:
   5968     case XPATH_POINT:
   5969     case XPATH_RANGE:
   5970     case XPATH_LOCATIONSET:
   5971 	TODO;
   5972 	ret = NAN;
   5973 	break;
   5974     }
   5975     return(ret);
   5976 }
   5977 
   5978 /**
   5979  * xmlXPathConvertNumber:
   5980  * @val:  an XPath object
   5981  *
   5982  * Converts an existing object to its number() equivalent
   5983  *
   5984  * Returns the new object, the old one is freed (or the operation
   5985  *         is done directly on @val)
   5986  */
   5987 xmlXPathObjectPtr
   5988 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
   5989     xmlXPathObjectPtr ret;
   5990 
   5991     if (val == NULL)
   5992 	return(xmlXPathNewFloat(0.0));
   5993     if (val->type == XPATH_NUMBER)
   5994 	return(val);
   5995     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
   5996     xmlXPathFreeObject(val);
   5997     return(ret);
   5998 }
   5999 
   6000 /**
   6001  * xmlXPathCastNumberToBoolean:
   6002  * @val:  a number
   6003  *
   6004  * Converts a number to its boolean value
   6005  *
   6006  * Returns the boolean value
   6007  */
   6008 int
   6009 xmlXPathCastNumberToBoolean (double val) {
   6010      if (xmlXPathIsNaN(val) || (val == 0.0))
   6011 	 return(0);
   6012      return(1);
   6013 }
   6014 
   6015 /**
   6016  * xmlXPathCastStringToBoolean:
   6017  * @val:  a string
   6018  *
   6019  * Converts a string to its boolean value
   6020  *
   6021  * Returns the boolean value
   6022  */
   6023 int
   6024 xmlXPathCastStringToBoolean (const xmlChar *val) {
   6025     if ((val == NULL) || (xmlStrlen(val) == 0))
   6026 	return(0);
   6027     return(1);
   6028 }
   6029 
   6030 /**
   6031  * xmlXPathCastNodeSetToBoolean:
   6032  * @ns:  a node-set
   6033  *
   6034  * Converts a node-set to its boolean value
   6035  *
   6036  * Returns the boolean value
   6037  */
   6038 int
   6039 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
   6040     if ((ns == NULL) || (ns->nodeNr == 0))
   6041 	return(0);
   6042     return(1);
   6043 }
   6044 
   6045 /**
   6046  * xmlXPathCastToBoolean:
   6047  * @val:  an XPath object
   6048  *
   6049  * Converts an XPath object to its boolean value
   6050  *
   6051  * Returns the boolean value
   6052  */
   6053 int
   6054 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
   6055     int ret = 0;
   6056 
   6057     if (val == NULL)
   6058 	return(0);
   6059     switch (val->type) {
   6060     case XPATH_UNDEFINED:
   6061 #ifdef DEBUG_EXPR
   6062 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
   6063 #endif
   6064 	ret = 0;
   6065 	break;
   6066     case XPATH_NODESET:
   6067     case XPATH_XSLT_TREE:
   6068 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
   6069 	break;
   6070     case XPATH_STRING:
   6071 	ret = xmlXPathCastStringToBoolean(val->stringval);
   6072 	break;
   6073     case XPATH_NUMBER:
   6074 	ret = xmlXPathCastNumberToBoolean(val->floatval);
   6075 	break;
   6076     case XPATH_BOOLEAN:
   6077 	ret = val->boolval;
   6078 	break;
   6079     case XPATH_USERS:
   6080     case XPATH_POINT:
   6081     case XPATH_RANGE:
   6082     case XPATH_LOCATIONSET:
   6083 	TODO;
   6084 	ret = 0;
   6085 	break;
   6086     }
   6087     return(ret);
   6088 }
   6089 
   6090 
   6091 /**
   6092  * xmlXPathConvertBoolean:
   6093  * @val:  an XPath object
   6094  *
   6095  * Converts an existing object to its boolean() equivalent
   6096  *
   6097  * Returns the new object, the old one is freed (or the operation
   6098  *         is done directly on @val)
   6099  */
   6100 xmlXPathObjectPtr
   6101 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
   6102     xmlXPathObjectPtr ret;
   6103 
   6104     if (val == NULL)
   6105 	return(xmlXPathNewBoolean(0));
   6106     if (val->type == XPATH_BOOLEAN)
   6107 	return(val);
   6108     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
   6109     xmlXPathFreeObject(val);
   6110     return(ret);
   6111 }
   6112 
   6113 /************************************************************************
   6114  *									*
   6115  *		Routines to handle XPath contexts			*
   6116  *									*
   6117  ************************************************************************/
   6118 
   6119 /**
   6120  * xmlXPathNewContext:
   6121  * @doc:  the XML document
   6122  *
   6123  * Create a new xmlXPathContext
   6124  *
   6125  * Returns the xmlXPathContext just allocated. The caller will need to free it.
   6126  */
   6127 xmlXPathContextPtr
   6128 xmlXPathNewContext(xmlDocPtr doc) {
   6129     xmlXPathContextPtr ret;
   6130 
   6131     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
   6132     if (ret == NULL) {
   6133         xmlXPathErrMemory(NULL, "creating context\n");
   6134 	return(NULL);
   6135     }
   6136     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
   6137     ret->doc = doc;
   6138     ret->node = NULL;
   6139 
   6140     ret->varHash = NULL;
   6141 
   6142     ret->nb_types = 0;
   6143     ret->max_types = 0;
   6144     ret->types = NULL;
   6145 
   6146     ret->funcHash = xmlHashCreate(0);
   6147 
   6148     ret->nb_axis = 0;
   6149     ret->max_axis = 0;
   6150     ret->axis = NULL;
   6151 
   6152     ret->nsHash = NULL;
   6153     ret->user = NULL;
   6154 
   6155     ret->contextSize = -1;
   6156     ret->proximityPosition = -1;
   6157 
   6158 #ifdef XP_DEFAULT_CACHE_ON
   6159     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
   6160 	xmlXPathFreeContext(ret);
   6161 	return(NULL);
   6162     }
   6163 #endif
   6164 
   6165     xmlXPathRegisterAllFunctions(ret);
   6166 
   6167     return(ret);
   6168 }
   6169 
   6170 /**
   6171  * xmlXPathFreeContext:
   6172  * @ctxt:  the context to free
   6173  *
   6174  * Free up an xmlXPathContext
   6175  */
   6176 void
   6177 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
   6178     if (ctxt == NULL) return;
   6179 
   6180     if (ctxt->cache != NULL)
   6181 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
   6182     xmlXPathRegisteredNsCleanup(ctxt);
   6183     xmlXPathRegisteredFuncsCleanup(ctxt);
   6184     xmlXPathRegisteredVariablesCleanup(ctxt);
   6185     xmlResetError(&ctxt->lastError);
   6186     xmlFree(ctxt);
   6187 }
   6188 
   6189 /************************************************************************
   6190  *									*
   6191  *		Routines to handle XPath parser contexts		*
   6192  *									*
   6193  ************************************************************************/
   6194 
   6195 #define CHECK_CTXT(ctxt)						\
   6196     if (ctxt == NULL) {						\
   6197 	__xmlRaiseError(NULL, NULL, NULL,				\
   6198 		NULL, NULL, XML_FROM_XPATH,				\
   6199 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
   6200 		__FILE__, __LINE__,					\
   6201 		NULL, NULL, NULL, 0, 0,					\
   6202 		"NULL context pointer\n");				\
   6203 	return(NULL);							\
   6204     }									\
   6205 
   6206 #define CHECK_CTXT_NEG(ctxt)						\
   6207     if (ctxt == NULL) {						\
   6208 	__xmlRaiseError(NULL, NULL, NULL,				\
   6209 		NULL, NULL, XML_FROM_XPATH,				\
   6210 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
   6211 		__FILE__, __LINE__,					\
   6212 		NULL, NULL, NULL, 0, 0,					\
   6213 		"NULL context pointer\n");				\
   6214 	return(-1);							\
   6215     }									\
   6216 
   6217 
   6218 #define CHECK_CONTEXT(ctxt)						\
   6219     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
   6220         (ctxt->doc->children == NULL)) {				\
   6221 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
   6222 	return(NULL);							\
   6223     }
   6224 
   6225 
   6226 /**
   6227  * xmlXPathNewParserContext:
   6228  * @str:  the XPath expression
   6229  * @ctxt:  the XPath context
   6230  *
   6231  * Create a new xmlXPathParserContext
   6232  *
   6233  * Returns the xmlXPathParserContext just allocated.
   6234  */
   6235 xmlXPathParserContextPtr
   6236 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
   6237     xmlXPathParserContextPtr ret;
   6238 
   6239     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
   6240     if (ret == NULL) {
   6241         xmlXPathErrMemory(ctxt, "creating parser context\n");
   6242 	return(NULL);
   6243     }
   6244     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
   6245     ret->cur = ret->base = str;
   6246     ret->context = ctxt;
   6247 
   6248     ret->comp = xmlXPathNewCompExpr();
   6249     if (ret->comp == NULL) {
   6250 	xmlFree(ret->valueTab);
   6251 	xmlFree(ret);
   6252 	return(NULL);
   6253     }
   6254     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
   6255         ret->comp->dict = ctxt->dict;
   6256 	xmlDictReference(ret->comp->dict);
   6257     }
   6258 
   6259     return(ret);
   6260 }
   6261 
   6262 /**
   6263  * xmlXPathCompParserContext:
   6264  * @comp:  the XPath compiled expression
   6265  * @ctxt:  the XPath context
   6266  *
   6267  * Create a new xmlXPathParserContext when processing a compiled expression
   6268  *
   6269  * Returns the xmlXPathParserContext just allocated.
   6270  */
   6271 static xmlXPathParserContextPtr
   6272 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
   6273     xmlXPathParserContextPtr ret;
   6274 
   6275     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
   6276     if (ret == NULL) {
   6277         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
   6278 	return(NULL);
   6279     }
   6280     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
   6281 
   6282     /* Allocate the value stack */
   6283     ret->valueTab = (xmlXPathObjectPtr *)
   6284                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
   6285     if (ret->valueTab == NULL) {
   6286 	xmlFree(ret);
   6287 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
   6288 	return(NULL);
   6289     }
   6290     ret->valueNr = 0;
   6291     ret->valueMax = 10;
   6292     ret->value = NULL;
   6293     ret->valueFrame = 0;
   6294 
   6295     ret->context = ctxt;
   6296     ret->comp = comp;
   6297 
   6298     return(ret);
   6299 }
   6300 
   6301 /**
   6302  * xmlXPathFreeParserContext:
   6303  * @ctxt:  the context to free
   6304  *
   6305  * Free up an xmlXPathParserContext
   6306  */
   6307 void
   6308 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
   6309     int i;
   6310 
   6311     if (ctxt->valueTab != NULL) {
   6312         for (i = 0; i < ctxt->valueNr; i++) {
   6313             if (ctxt->context)
   6314                 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
   6315             else
   6316                 xmlXPathFreeObject(ctxt->valueTab[i]);
   6317         }
   6318         xmlFree(ctxt->valueTab);
   6319     }
   6320     if (ctxt->comp != NULL) {
   6321 #ifdef XPATH_STREAMING
   6322 	if (ctxt->comp->stream != NULL) {
   6323 	    xmlFreePatternList(ctxt->comp->stream);
   6324 	    ctxt->comp->stream = NULL;
   6325 	}
   6326 #endif
   6327 	xmlXPathFreeCompExpr(ctxt->comp);
   6328     }
   6329     xmlFree(ctxt);
   6330 }
   6331 
   6332 /************************************************************************
   6333  *									*
   6334  *		The implicit core function library			*
   6335  *									*
   6336  ************************************************************************/
   6337 
   6338 /**
   6339  * xmlXPathNodeValHash:
   6340  * @node:  a node pointer
   6341  *
   6342  * Function computing the beginning of the string value of the node,
   6343  * used to speed up comparisons
   6344  *
   6345  * Returns an int usable as a hash
   6346  */
   6347 static unsigned int
   6348 xmlXPathNodeValHash(xmlNodePtr node) {
   6349     int len = 2;
   6350     const xmlChar * string = NULL;
   6351     xmlNodePtr tmp = NULL;
   6352     unsigned int ret = 0;
   6353 
   6354     if (node == NULL)
   6355 	return(0);
   6356 
   6357     if (node->type == XML_DOCUMENT_NODE) {
   6358 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
   6359 	if (tmp == NULL)
   6360 	    node = node->children;
   6361 	else
   6362 	    node = tmp;
   6363 
   6364 	if (node == NULL)
   6365 	    return(0);
   6366     }
   6367 
   6368     switch (node->type) {
   6369 	case XML_COMMENT_NODE:
   6370 	case XML_PI_NODE:
   6371 	case XML_CDATA_SECTION_NODE:
   6372 	case XML_TEXT_NODE:
   6373 	    string = node->content;
   6374 	    if (string == NULL)
   6375 		return(0);
   6376 	    if (string[0] == 0)
   6377 		return(0);
   6378 	    return(((unsigned int) string[0]) +
   6379 		   (((unsigned int) string[1]) << 8));
   6380 	case XML_NAMESPACE_DECL:
   6381 	    string = ((xmlNsPtr)node)->href;
   6382 	    if (string == NULL)
   6383 		return(0);
   6384 	    if (string[0] == 0)
   6385 		return(0);
   6386 	    return(((unsigned int) string[0]) +
   6387 		   (((unsigned int) string[1]) << 8));
   6388 	case XML_ATTRIBUTE_NODE:
   6389 	    tmp = ((xmlAttrPtr) node)->children;
   6390 	    break;
   6391 	case XML_ELEMENT_NODE:
   6392 	    tmp = node->children;
   6393 	    break;
   6394 	default:
   6395 	    return(0);
   6396     }
   6397     while (tmp != NULL) {
   6398 	switch (tmp->type) {
   6399 	    case XML_CDATA_SECTION_NODE:
   6400 	    case XML_TEXT_NODE:
   6401 		string = tmp->content;
   6402 		break;
   6403 	    default:
   6404                 string = NULL;
   6405 		break;
   6406 	}
   6407 	if ((string != NULL) && (string[0] != 0)) {
   6408 	    if (len == 1) {
   6409 		return(ret + (((unsigned int) string[0]) << 8));
   6410 	    }
   6411 	    if (string[1] == 0) {
   6412 		len = 1;
   6413 		ret = (unsigned int) string[0];
   6414 	    } else {
   6415 		return(((unsigned int) string[0]) +
   6416 		       (((unsigned int) string[1]) << 8));
   6417 	    }
   6418 	}
   6419 	/*
   6420 	 * Skip to next node
   6421 	 */
   6422 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
   6423 	    if (tmp->children->type != XML_ENTITY_DECL) {
   6424 		tmp = tmp->children;
   6425 		continue;
   6426 	    }
   6427 	}
   6428 	if (tmp == node)
   6429 	    break;
   6430 
   6431 	if (tmp->next != NULL) {
   6432 	    tmp = tmp->next;
   6433 	    continue;
   6434 	}
   6435 
   6436 	do {
   6437 	    tmp = tmp->parent;
   6438 	    if (tmp == NULL)
   6439 		break;
   6440 	    if (tmp == node) {
   6441 		tmp = NULL;
   6442 		break;
   6443 	    }
   6444 	    if (tmp->next != NULL) {
   6445 		tmp = tmp->next;
   6446 		break;
   6447 	    }
   6448 	} while (tmp != NULL);
   6449     }
   6450     return(ret);
   6451 }
   6452 
   6453 /**
   6454  * xmlXPathStringHash:
   6455  * @string:  a string
   6456  *
   6457  * Function computing the beginning of the string value of the node,
   6458  * used to speed up comparisons
   6459  *
   6460  * Returns an int usable as a hash
   6461  */
   6462 static unsigned int
   6463 xmlXPathStringHash(const xmlChar * string) {
   6464     if (string == NULL)
   6465 	return((unsigned int) 0);
   6466     if (string[0] == 0)
   6467 	return(0);
   6468     return(((unsigned int) string[0]) +
   6469 	   (((unsigned int) string[1]) << 8));
   6470 }
   6471 
   6472 /**
   6473  * xmlXPathCompareNodeSetFloat:
   6474  * @ctxt:  the XPath Parser context
   6475  * @inf:  less than (1) or greater than (0)
   6476  * @strict:  is the comparison strict
   6477  * @arg:  the node set
   6478  * @f:  the value
   6479  *
   6480  * Implement the compare operation between a nodeset and a number
   6481  *     @ns < @val    (1, 1, ...
   6482  *     @ns <= @val   (1, 0, ...
   6483  *     @ns > @val    (0, 1, ...
   6484  *     @ns >= @val   (0, 0, ...
   6485  *
   6486  * If one object to be compared is a node-set and the other is a number,
   6487  * then the comparison will be true if and only if there is a node in the
   6488  * node-set such that the result of performing the comparison on the number
   6489  * to be compared and on the result of converting the string-value of that
   6490  * node to a number using the number function is true.
   6491  *
   6492  * Returns 0 or 1 depending on the results of the test.
   6493  */
   6494 static int
   6495 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6496 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
   6497     int i, ret = 0;
   6498     xmlNodeSetPtr ns;
   6499     xmlChar *str2;
   6500 
   6501     if ((f == NULL) || (arg == NULL) ||
   6502 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
   6503 	xmlXPathReleaseObject(ctxt->context, arg);
   6504 	xmlXPathReleaseObject(ctxt->context, f);
   6505         return(0);
   6506     }
   6507     ns = arg->nodesetval;
   6508     if (ns != NULL) {
   6509 	for (i = 0;i < ns->nodeNr;i++) {
   6510 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6511 	     if (str2 != NULL) {
   6512 		 valuePush(ctxt,
   6513 			   xmlXPathCacheNewString(ctxt->context, str2));
   6514 		 xmlFree(str2);
   6515 		 xmlXPathNumberFunction(ctxt, 1);
   6516 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
   6517 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
   6518 		 if (ret)
   6519 		     break;
   6520 	     }
   6521 	}
   6522     }
   6523     xmlXPathReleaseObject(ctxt->context, arg);
   6524     xmlXPathReleaseObject(ctxt->context, f);
   6525     return(ret);
   6526 }
   6527 
   6528 /**
   6529  * xmlXPathCompareNodeSetString:
   6530  * @ctxt:  the XPath Parser context
   6531  * @inf:  less than (1) or greater than (0)
   6532  * @strict:  is the comparison strict
   6533  * @arg:  the node set
   6534  * @s:  the value
   6535  *
   6536  * Implement the compare operation between a nodeset and a string
   6537  *     @ns < @val    (1, 1, ...
   6538  *     @ns <= @val   (1, 0, ...
   6539  *     @ns > @val    (0, 1, ...
   6540  *     @ns >= @val   (0, 0, ...
   6541  *
   6542  * If one object to be compared is a node-set and the other is a string,
   6543  * then the comparison will be true if and only if there is a node in
   6544  * the node-set such that the result of performing the comparison on the
   6545  * string-value of the node and the other string is true.
   6546  *
   6547  * Returns 0 or 1 depending on the results of the test.
   6548  */
   6549 static int
   6550 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6551 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
   6552     int i, ret = 0;
   6553     xmlNodeSetPtr ns;
   6554     xmlChar *str2;
   6555 
   6556     if ((s == NULL) || (arg == NULL) ||
   6557 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
   6558 	xmlXPathReleaseObject(ctxt->context, arg);
   6559 	xmlXPathReleaseObject(ctxt->context, s);
   6560         return(0);
   6561     }
   6562     ns = arg->nodesetval;
   6563     if (ns != NULL) {
   6564 	for (i = 0;i < ns->nodeNr;i++) {
   6565 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6566 	     if (str2 != NULL) {
   6567 		 valuePush(ctxt,
   6568 			   xmlXPathCacheNewString(ctxt->context, str2));
   6569 		 xmlFree(str2);
   6570 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
   6571 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
   6572 		 if (ret)
   6573 		     break;
   6574 	     }
   6575 	}
   6576     }
   6577     xmlXPathReleaseObject(ctxt->context, arg);
   6578     xmlXPathReleaseObject(ctxt->context, s);
   6579     return(ret);
   6580 }
   6581 
   6582 /**
   6583  * xmlXPathCompareNodeSets:
   6584  * @inf:  less than (1) or greater than (0)
   6585  * @strict:  is the comparison strict
   6586  * @arg1:  the first node set object
   6587  * @arg2:  the second node set object
   6588  *
   6589  * Implement the compare operation on nodesets:
   6590  *
   6591  * If both objects to be compared are node-sets, then the comparison
   6592  * will be true if and only if there is a node in the first node-set
   6593  * and a node in the second node-set such that the result of performing
   6594  * the comparison on the string-values of the two nodes is true.
   6595  * ....
   6596  * When neither object to be compared is a node-set and the operator
   6597  * is <=, <, >= or >, then the objects are compared by converting both
   6598  * objects to numbers and comparing the numbers according to IEEE 754.
   6599  * ....
   6600  * The number function converts its argument to a number as follows:
   6601  *  - a string that consists of optional whitespace followed by an
   6602  *    optional minus sign followed by a Number followed by whitespace
   6603  *    is converted to the IEEE 754 number that is nearest (according
   6604  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
   6605  *    represented by the string; any other string is converted to NaN
   6606  *
   6607  * Conclusion all nodes need to be converted first to their string value
   6608  * and then the comparison must be done when possible
   6609  */
   6610 static int
   6611 xmlXPathCompareNodeSets(int inf, int strict,
   6612 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
   6613     int i, j, init = 0;
   6614     double val1;
   6615     double *values2;
   6616     int ret = 0;
   6617     xmlNodeSetPtr ns1;
   6618     xmlNodeSetPtr ns2;
   6619 
   6620     if ((arg1 == NULL) ||
   6621 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
   6622 	xmlXPathFreeObject(arg2);
   6623         return(0);
   6624     }
   6625     if ((arg2 == NULL) ||
   6626 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
   6627 	xmlXPathFreeObject(arg1);
   6628 	xmlXPathFreeObject(arg2);
   6629         return(0);
   6630     }
   6631 
   6632     ns1 = arg1->nodesetval;
   6633     ns2 = arg2->nodesetval;
   6634 
   6635     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
   6636 	xmlXPathFreeObject(arg1);
   6637 	xmlXPathFreeObject(arg2);
   6638 	return(0);
   6639     }
   6640     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
   6641 	xmlXPathFreeObject(arg1);
   6642 	xmlXPathFreeObject(arg2);
   6643 	return(0);
   6644     }
   6645 
   6646     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
   6647     if (values2 == NULL) {
   6648         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6649 	xmlXPathFreeObject(arg1);
   6650 	xmlXPathFreeObject(arg2);
   6651 	return(0);
   6652     }
   6653     for (i = 0;i < ns1->nodeNr;i++) {
   6654 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
   6655 	if (xmlXPathIsNaN(val1))
   6656 	    continue;
   6657 	for (j = 0;j < ns2->nodeNr;j++) {
   6658 	    if (init == 0) {
   6659 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
   6660 	    }
   6661 	    if (xmlXPathIsNaN(values2[j]))
   6662 		continue;
   6663 	    if (inf && strict)
   6664 		ret = (val1 < values2[j]);
   6665 	    else if (inf && !strict)
   6666 		ret = (val1 <= values2[j]);
   6667 	    else if (!inf && strict)
   6668 		ret = (val1 > values2[j]);
   6669 	    else if (!inf && !strict)
   6670 		ret = (val1 >= values2[j]);
   6671 	    if (ret)
   6672 		break;
   6673 	}
   6674 	if (ret)
   6675 	    break;
   6676 	init = 1;
   6677     }
   6678     xmlFree(values2);
   6679     xmlXPathFreeObject(arg1);
   6680     xmlXPathFreeObject(arg2);
   6681     return(ret);
   6682 }
   6683 
   6684 /**
   6685  * xmlXPathCompareNodeSetValue:
   6686  * @ctxt:  the XPath Parser context
   6687  * @inf:  less than (1) or greater than (0)
   6688  * @strict:  is the comparison strict
   6689  * @arg:  the node set
   6690  * @val:  the value
   6691  *
   6692  * Implement the compare operation between a nodeset and a value
   6693  *     @ns < @val    (1, 1, ...
   6694  *     @ns <= @val   (1, 0, ...
   6695  *     @ns > @val    (0, 1, ...
   6696  *     @ns >= @val   (0, 0, ...
   6697  *
   6698  * If one object to be compared is a node-set and the other is a boolean,
   6699  * then the comparison will be true if and only if the result of performing
   6700  * the comparison on the boolean and on the result of converting
   6701  * the node-set to a boolean using the boolean function is true.
   6702  *
   6703  * Returns 0 or 1 depending on the results of the test.
   6704  */
   6705 static int
   6706 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6707 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
   6708     if ((val == NULL) || (arg == NULL) ||
   6709 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6710         return(0);
   6711 
   6712     switch(val->type) {
   6713         case XPATH_NUMBER:
   6714 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
   6715         case XPATH_NODESET:
   6716         case XPATH_XSLT_TREE:
   6717 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
   6718         case XPATH_STRING:
   6719 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
   6720         case XPATH_BOOLEAN:
   6721 	    valuePush(ctxt, arg);
   6722 	    xmlXPathBooleanFunction(ctxt, 1);
   6723 	    valuePush(ctxt, val);
   6724 	    return(xmlXPathCompareValues(ctxt, inf, strict));
   6725 	default:
   6726             xmlGenericError(xmlGenericErrorContext,
   6727                     "xmlXPathCompareNodeSetValue: Can't compare node set "
   6728                     "and object of type %d\n",
   6729                     val->type);
   6730             xmlXPathReleaseObject(ctxt->context, arg);
   6731             xmlXPathReleaseObject(ctxt->context, val);
   6732             XP_ERROR0(XPATH_INVALID_TYPE);
   6733     }
   6734     return(0);
   6735 }
   6736 
   6737 /**
   6738  * xmlXPathEqualNodeSetString:
   6739  * @arg:  the nodeset object argument
   6740  * @str:  the string to compare to.
   6741  * @neq:  flag to show whether for '=' (0) or '!=' (1)
   6742  *
   6743  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   6744  * If one object to be compared is a node-set and the other is a string,
   6745  * then the comparison will be true if and only if there is a node in
   6746  * the node-set such that the result of performing the comparison on the
   6747  * string-value of the node and the other string is true.
   6748  *
   6749  * Returns 0 or 1 depending on the results of the test.
   6750  */
   6751 static int
   6752 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
   6753 {
   6754     int i;
   6755     xmlNodeSetPtr ns;
   6756     xmlChar *str2;
   6757     unsigned int hash;
   6758 
   6759     if ((str == NULL) || (arg == NULL) ||
   6760         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6761         return (0);
   6762     ns = arg->nodesetval;
   6763     /*
   6764      * A NULL nodeset compared with a string is always false
   6765      * (since there is no node equal, and no node not equal)
   6766      */
   6767     if ((ns == NULL) || (ns->nodeNr <= 0) )
   6768         return (0);
   6769     hash = xmlXPathStringHash(str);
   6770     for (i = 0; i < ns->nodeNr; i++) {
   6771         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
   6772             str2 = xmlNodeGetContent(ns->nodeTab[i]);
   6773             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
   6774                 xmlFree(str2);
   6775 		if (neq)
   6776 		    continue;
   6777                 return (1);
   6778 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
   6779 		if (neq)
   6780 		    continue;
   6781                 return (1);
   6782             } else if (neq) {
   6783 		if (str2 != NULL)
   6784 		    xmlFree(str2);
   6785 		return (1);
   6786 	    }
   6787             if (str2 != NULL)
   6788                 xmlFree(str2);
   6789         } else if (neq)
   6790 	    return (1);
   6791     }
   6792     return (0);
   6793 }
   6794 
   6795 /**
   6796  * xmlXPathEqualNodeSetFloat:
   6797  * @arg:  the nodeset object argument
   6798  * @f:  the float to compare to
   6799  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
   6800  *
   6801  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   6802  * If one object to be compared is a node-set and the other is a number,
   6803  * then the comparison will be true if and only if there is a node in
   6804  * the node-set such that the result of performing the comparison on the
   6805  * number to be compared and on the result of converting the string-value
   6806  * of that node to a number using the number function is true.
   6807  *
   6808  * Returns 0 or 1 depending on the results of the test.
   6809  */
   6810 static int
   6811 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
   6812     xmlXPathObjectPtr arg, double f, int neq) {
   6813   int i, ret=0;
   6814   xmlNodeSetPtr ns;
   6815   xmlChar *str2;
   6816   xmlXPathObjectPtr val;
   6817   double v;
   6818 
   6819     if ((arg == NULL) ||
   6820 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6821         return(0);
   6822 
   6823     ns = arg->nodesetval;
   6824     if (ns != NULL) {
   6825 	for (i=0;i<ns->nodeNr;i++) {
   6826 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6827 	    if (str2 != NULL) {
   6828 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
   6829 		xmlFree(str2);
   6830 		xmlXPathNumberFunction(ctxt, 1);
   6831 		val = valuePop(ctxt);
   6832 		v = val->floatval;
   6833 		xmlXPathReleaseObject(ctxt->context, val);
   6834 		if (!xmlXPathIsNaN(v)) {
   6835 		    if ((!neq) && (v==f)) {
   6836 			ret = 1;
   6837 			break;
   6838 		    } else if ((neq) && (v!=f)) {
   6839 			ret = 1;
   6840 			break;
   6841 		    }
   6842 		} else {	/* NaN is unequal to any value */
   6843 		    if (neq)
   6844 			ret = 1;
   6845 		}
   6846 	    }
   6847 	}
   6848     }
   6849 
   6850     return(ret);
   6851 }
   6852 
   6853 
   6854 /**
   6855  * xmlXPathEqualNodeSets:
   6856  * @arg1:  first nodeset object argument
   6857  * @arg2:  second nodeset object argument
   6858  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
   6859  *
   6860  * Implement the equal / not equal operation on XPath nodesets:
   6861  * @arg1 == @arg2  or  @arg1 != @arg2
   6862  * If both objects to be compared are node-sets, then the comparison
   6863  * will be true if and only if there is a node in the first node-set and
   6864  * a node in the second node-set such that the result of performing the
   6865  * comparison on the string-values of the two nodes is true.
   6866  *
   6867  * (needless to say, this is a costly operation)
   6868  *
   6869  * Returns 0 or 1 depending on the results of the test.
   6870  */
   6871 static int
   6872 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
   6873     int i, j;
   6874     unsigned int *hashs1;
   6875     unsigned int *hashs2;
   6876     xmlChar **values1;
   6877     xmlChar **values2;
   6878     int ret = 0;
   6879     xmlNodeSetPtr ns1;
   6880     xmlNodeSetPtr ns2;
   6881 
   6882     if ((arg1 == NULL) ||
   6883 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
   6884         return(0);
   6885     if ((arg2 == NULL) ||
   6886 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
   6887         return(0);
   6888 
   6889     ns1 = arg1->nodesetval;
   6890     ns2 = arg2->nodesetval;
   6891 
   6892     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
   6893 	return(0);
   6894     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
   6895 	return(0);
   6896 
   6897     /*
   6898      * for equal, check if there is a node pertaining to both sets
   6899      */
   6900     if (neq == 0)
   6901 	for (i = 0;i < ns1->nodeNr;i++)
   6902 	    for (j = 0;j < ns2->nodeNr;j++)
   6903 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
   6904 		    return(1);
   6905 
   6906     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
   6907     if (values1 == NULL) {
   6908         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6909 	return(0);
   6910     }
   6911     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
   6912     if (hashs1 == NULL) {
   6913         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6914 	xmlFree(values1);
   6915 	return(0);
   6916     }
   6917     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
   6918     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
   6919     if (values2 == NULL) {
   6920         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6921 	xmlFree(hashs1);
   6922 	xmlFree(values1);
   6923 	return(0);
   6924     }
   6925     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
   6926     if (hashs2 == NULL) {
   6927         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6928 	xmlFree(hashs1);
   6929 	xmlFree(values1);
   6930 	xmlFree(values2);
   6931 	return(0);
   6932     }
   6933     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
   6934     for (i = 0;i < ns1->nodeNr;i++) {
   6935 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
   6936 	for (j = 0;j < ns2->nodeNr;j++) {
   6937 	    if (i == 0)
   6938 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
   6939 	    if (hashs1[i] != hashs2[j]) {
   6940 		if (neq) {
   6941 		    ret = 1;
   6942 		    break;
   6943 		}
   6944 	    }
   6945 	    else {
   6946 		if (values1[i] == NULL)
   6947 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
   6948 		if (values2[j] == NULL)
   6949 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
   6950 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
   6951 		if (ret)
   6952 		    break;
   6953 	    }
   6954 	}
   6955 	if (ret)
   6956 	    break;
   6957     }
   6958     for (i = 0;i < ns1->nodeNr;i++)
   6959 	if (values1[i] != NULL)
   6960 	    xmlFree(values1[i]);
   6961     for (j = 0;j < ns2->nodeNr;j++)
   6962 	if (values2[j] != NULL)
   6963 	    xmlFree(values2[j]);
   6964     xmlFree(values1);
   6965     xmlFree(values2);
   6966     xmlFree(hashs1);
   6967     xmlFree(hashs2);
   6968     return(ret);
   6969 }
   6970 
   6971 static int
   6972 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
   6973   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
   6974     int ret = 0;
   6975     /*
   6976      *At this point we are assured neither arg1 nor arg2
   6977      *is a nodeset, so we can just pick the appropriate routine.
   6978      */
   6979     switch (arg1->type) {
   6980         case XPATH_UNDEFINED:
   6981 #ifdef DEBUG_EXPR
   6982 	    xmlGenericError(xmlGenericErrorContext,
   6983 		    "Equal: undefined\n");
   6984 #endif
   6985 	    break;
   6986         case XPATH_BOOLEAN:
   6987 	    switch (arg2->type) {
   6988 	        case XPATH_UNDEFINED:
   6989 #ifdef DEBUG_EXPR
   6990 		    xmlGenericError(xmlGenericErrorContext,
   6991 			    "Equal: undefined\n");
   6992 #endif
   6993 		    break;
   6994 		case XPATH_BOOLEAN:
   6995 #ifdef DEBUG_EXPR
   6996 		    xmlGenericError(xmlGenericErrorContext,
   6997 			    "Equal: %d boolean %d \n",
   6998 			    arg1->boolval, arg2->boolval);
   6999 #endif
   7000 		    ret = (arg1->boolval == arg2->boolval);
   7001 		    break;
   7002 		case XPATH_NUMBER:
   7003 		    ret = (arg1->boolval ==
   7004 			   xmlXPathCastNumberToBoolean(arg2->floatval));
   7005 		    break;
   7006 		case XPATH_STRING:
   7007 		    if ((arg2->stringval == NULL) ||
   7008 			(arg2->stringval[0] == 0)) ret = 0;
   7009 		    else
   7010 			ret = 1;
   7011 		    ret = (arg1->boolval == ret);
   7012 		    break;
   7013 		case XPATH_USERS:
   7014 		case XPATH_POINT:
   7015 		case XPATH_RANGE:
   7016 		case XPATH_LOCATIONSET:
   7017 		    TODO
   7018 		    break;
   7019 		case XPATH_NODESET:
   7020 		case XPATH_XSLT_TREE:
   7021 		    break;
   7022 	    }
   7023 	    break;
   7024         case XPATH_NUMBER:
   7025 	    switch (arg2->type) {
   7026 	        case XPATH_UNDEFINED:
   7027 #ifdef DEBUG_EXPR
   7028 		    xmlGenericError(xmlGenericErrorContext,
   7029 			    "Equal: undefined\n");
   7030 #endif
   7031 		    break;
   7032 		case XPATH_BOOLEAN:
   7033 		    ret = (arg2->boolval==
   7034 			   xmlXPathCastNumberToBoolean(arg1->floatval));
   7035 		    break;
   7036 		case XPATH_STRING:
   7037 		    valuePush(ctxt, arg2);
   7038 		    xmlXPathNumberFunction(ctxt, 1);
   7039 		    arg2 = valuePop(ctxt);
   7040                     /* Falls through. */
   7041 		case XPATH_NUMBER:
   7042 		    /* Hand check NaN and Infinity equalities */
   7043 		    if (xmlXPathIsNaN(arg1->floatval) ||
   7044 			    xmlXPathIsNaN(arg2->floatval)) {
   7045 		        ret = 0;
   7046 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
   7047 		        if (xmlXPathIsInf(arg2->floatval) == 1)
   7048 			    ret = 1;
   7049 			else
   7050 			    ret = 0;
   7051 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
   7052 			if (xmlXPathIsInf(arg2->floatval) == -1)
   7053 			    ret = 1;
   7054 			else
   7055 			    ret = 0;
   7056 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
   7057 			if (xmlXPathIsInf(arg1->floatval) == 1)
   7058 			    ret = 1;
   7059 			else
   7060 			    ret = 0;
   7061 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
   7062 			if (xmlXPathIsInf(arg1->floatval) == -1)
   7063 			    ret = 1;
   7064 			else
   7065 			    ret = 0;
   7066 		    } else {
   7067 		        ret = (arg1->floatval == arg2->floatval);
   7068 		    }
   7069 		    break;
   7070 		case XPATH_USERS:
   7071 		case XPATH_POINT:
   7072 		case XPATH_RANGE:
   7073 		case XPATH_LOCATIONSET:
   7074 		    TODO
   7075 		    break;
   7076 		case XPATH_NODESET:
   7077 		case XPATH_XSLT_TREE:
   7078 		    break;
   7079 	    }
   7080 	    break;
   7081         case XPATH_STRING:
   7082 	    switch (arg2->type) {
   7083 	        case XPATH_UNDEFINED:
   7084 #ifdef DEBUG_EXPR
   7085 		    xmlGenericError(xmlGenericErrorContext,
   7086 			    "Equal: undefined\n");
   7087 #endif
   7088 		    break;
   7089 		case XPATH_BOOLEAN:
   7090 		    if ((arg1->stringval == NULL) ||
   7091 			(arg1->stringval[0] == 0)) ret = 0;
   7092 		    else
   7093 			ret = 1;
   7094 		    ret = (arg2->boolval == ret);
   7095 		    break;
   7096 		case XPATH_STRING:
   7097 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
   7098 		    break;
   7099 		case XPATH_NUMBER:
   7100 		    valuePush(ctxt, arg1);
   7101 		    xmlXPathNumberFunction(ctxt, 1);
   7102 		    arg1 = valuePop(ctxt);
   7103 		    /* Hand check NaN and Infinity equalities */
   7104 		    if (xmlXPathIsNaN(arg1->floatval) ||
   7105 			    xmlXPathIsNaN(arg2->floatval)) {
   7106 		        ret = 0;
   7107 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
   7108 			if (xmlXPathIsInf(arg2->floatval) == 1)
   7109 			    ret = 1;
   7110 			else
   7111 			    ret = 0;
   7112 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
   7113 			if (xmlXPathIsInf(arg2->floatval) == -1)
   7114 			    ret = 1;
   7115 			else
   7116 			    ret = 0;
   7117 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
   7118 			if (xmlXPathIsInf(arg1->floatval) == 1)
   7119 			    ret = 1;
   7120 			else
   7121 			    ret = 0;
   7122 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
   7123 			if (xmlXPathIsInf(arg1->floatval) == -1)
   7124 			    ret = 1;
   7125 			else
   7126 			    ret = 0;
   7127 		    } else {
   7128 		        ret = (arg1->floatval == arg2->floatval);
   7129 		    }
   7130 		    break;
   7131 		case XPATH_USERS:
   7132 		case XPATH_POINT:
   7133 		case XPATH_RANGE:
   7134 		case XPATH_LOCATIONSET:
   7135 		    TODO
   7136 		    break;
   7137 		case XPATH_NODESET:
   7138 		case XPATH_XSLT_TREE:
   7139 		    break;
   7140 	    }
   7141 	    break;
   7142         case XPATH_USERS:
   7143 	case XPATH_POINT:
   7144 	case XPATH_RANGE:
   7145 	case XPATH_LOCATIONSET:
   7146 	    TODO
   7147 	    break;
   7148 	case XPATH_NODESET:
   7149 	case XPATH_XSLT_TREE:
   7150 	    break;
   7151     }
   7152     xmlXPathReleaseObject(ctxt->context, arg1);
   7153     xmlXPathReleaseObject(ctxt->context, arg2);
   7154     return(ret);
   7155 }
   7156 
   7157 /**
   7158  * xmlXPathEqualValues:
   7159  * @ctxt:  the XPath Parser context
   7160  *
   7161  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   7162  *
   7163  * Returns 0 or 1 depending on the results of the test.
   7164  */
   7165 int
   7166 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
   7167     xmlXPathObjectPtr arg1, arg2, argtmp;
   7168     int ret = 0;
   7169 
   7170     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7171     arg2 = valuePop(ctxt);
   7172     arg1 = valuePop(ctxt);
   7173     if ((arg1 == NULL) || (arg2 == NULL)) {
   7174 	if (arg1 != NULL)
   7175 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7176 	else
   7177 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7178 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7179     }
   7180 
   7181     if (arg1 == arg2) {
   7182 #ifdef DEBUG_EXPR
   7183         xmlGenericError(xmlGenericErrorContext,
   7184 		"Equal: by pointer\n");
   7185 #endif
   7186 	xmlXPathFreeObject(arg1);
   7187         return(1);
   7188     }
   7189 
   7190     /*
   7191      *If either argument is a nodeset, it's a 'special case'
   7192      */
   7193     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7194       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7195 	/*
   7196 	 *Hack it to assure arg1 is the nodeset
   7197 	 */
   7198 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
   7199 		argtmp = arg2;
   7200 		arg2 = arg1;
   7201 		arg1 = argtmp;
   7202 	}
   7203 	switch (arg2->type) {
   7204 	    case XPATH_UNDEFINED:
   7205 #ifdef DEBUG_EXPR
   7206 		xmlGenericError(xmlGenericErrorContext,
   7207 			"Equal: undefined\n");
   7208 #endif
   7209 		break;
   7210 	    case XPATH_NODESET:
   7211 	    case XPATH_XSLT_TREE:
   7212 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
   7213 		break;
   7214 	    case XPATH_BOOLEAN:
   7215 		if ((arg1->nodesetval == NULL) ||
   7216 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
   7217 		else
   7218 		    ret = 1;
   7219 		ret = (ret == arg2->boolval);
   7220 		break;
   7221 	    case XPATH_NUMBER:
   7222 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
   7223 		break;
   7224 	    case XPATH_STRING:
   7225 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
   7226 		break;
   7227 	    case XPATH_USERS:
   7228 	    case XPATH_POINT:
   7229 	    case XPATH_RANGE:
   7230 	    case XPATH_LOCATIONSET:
   7231 		TODO
   7232 		break;
   7233 	}
   7234 	xmlXPathReleaseObject(ctxt->context, arg1);
   7235 	xmlXPathReleaseObject(ctxt->context, arg2);
   7236 	return(ret);
   7237     }
   7238 
   7239     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
   7240 }
   7241 
   7242 /**
   7243  * xmlXPathNotEqualValues:
   7244  * @ctxt:  the XPath Parser context
   7245  *
   7246  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   7247  *
   7248  * Returns 0 or 1 depending on the results of the test.
   7249  */
   7250 int
   7251 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
   7252     xmlXPathObjectPtr arg1, arg2, argtmp;
   7253     int ret = 0;
   7254 
   7255     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7256     arg2 = valuePop(ctxt);
   7257     arg1 = valuePop(ctxt);
   7258     if ((arg1 == NULL) || (arg2 == NULL)) {
   7259 	if (arg1 != NULL)
   7260 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7261 	else
   7262 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7263 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7264     }
   7265 
   7266     if (arg1 == arg2) {
   7267 #ifdef DEBUG_EXPR
   7268         xmlGenericError(xmlGenericErrorContext,
   7269 		"NotEqual: by pointer\n");
   7270 #endif
   7271 	xmlXPathReleaseObject(ctxt->context, arg1);
   7272         return(0);
   7273     }
   7274 
   7275     /*
   7276      *If either argument is a nodeset, it's a 'special case'
   7277      */
   7278     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7279       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7280 	/*
   7281 	 *Hack it to assure arg1 is the nodeset
   7282 	 */
   7283 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
   7284 		argtmp = arg2;
   7285 		arg2 = arg1;
   7286 		arg1 = argtmp;
   7287 	}
   7288 	switch (arg2->type) {
   7289 	    case XPATH_UNDEFINED:
   7290 #ifdef DEBUG_EXPR
   7291 		xmlGenericError(xmlGenericErrorContext,
   7292 			"NotEqual: undefined\n");
   7293 #endif
   7294 		break;
   7295 	    case XPATH_NODESET:
   7296 	    case XPATH_XSLT_TREE:
   7297 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
   7298 		break;
   7299 	    case XPATH_BOOLEAN:
   7300 		if ((arg1->nodesetval == NULL) ||
   7301 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
   7302 		else
   7303 		    ret = 1;
   7304 		ret = (ret != arg2->boolval);
   7305 		break;
   7306 	    case XPATH_NUMBER:
   7307 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
   7308 		break;
   7309 	    case XPATH_STRING:
   7310 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
   7311 		break;
   7312 	    case XPATH_USERS:
   7313 	    case XPATH_POINT:
   7314 	    case XPATH_RANGE:
   7315 	    case XPATH_LOCATIONSET:
   7316 		TODO
   7317 		break;
   7318 	}
   7319 	xmlXPathReleaseObject(ctxt->context, arg1);
   7320 	xmlXPathReleaseObject(ctxt->context, arg2);
   7321 	return(ret);
   7322     }
   7323 
   7324     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
   7325 }
   7326 
   7327 /**
   7328  * xmlXPathCompareValues:
   7329  * @ctxt:  the XPath Parser context
   7330  * @inf:  less than (1) or greater than (0)
   7331  * @strict:  is the comparison strict
   7332  *
   7333  * Implement the compare operation on XPath objects:
   7334  *     @arg1 < @arg2    (1, 1, ...
   7335  *     @arg1 <= @arg2   (1, 0, ...
   7336  *     @arg1 > @arg2    (0, 1, ...
   7337  *     @arg1 >= @arg2   (0, 0, ...
   7338  *
   7339  * When neither object to be compared is a node-set and the operator is
   7340  * <=, <, >=, >, then the objects are compared by converted both objects
   7341  * to numbers and comparing the numbers according to IEEE 754. The <
   7342  * comparison will be true if and only if the first number is less than the
   7343  * second number. The <= comparison will be true if and only if the first
   7344  * number is less than or equal to the second number. The > comparison
   7345  * will be true if and only if the first number is greater than the second
   7346  * number. The >= comparison will be true if and only if the first number
   7347  * is greater than or equal to the second number.
   7348  *
   7349  * Returns 1 if the comparison succeeded, 0 if it failed
   7350  */
   7351 int
   7352 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
   7353     int ret = 0, arg1i = 0, arg2i = 0;
   7354     xmlXPathObjectPtr arg1, arg2;
   7355 
   7356     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7357     arg2 = valuePop(ctxt);
   7358     arg1 = valuePop(ctxt);
   7359     if ((arg1 == NULL) || (arg2 == NULL)) {
   7360 	if (arg1 != NULL)
   7361 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7362 	else
   7363 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7364 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7365     }
   7366 
   7367     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7368       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7369 	/*
   7370 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
   7371 	 * are not freed from within this routine; they will be freed from the
   7372 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
   7373 	 */
   7374 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
   7375 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
   7376 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
   7377 	} else {
   7378 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7379 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
   7380 			                          arg1, arg2);
   7381 	    } else {
   7382 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
   7383 			                          arg2, arg1);
   7384 	    }
   7385 	}
   7386 	return(ret);
   7387     }
   7388 
   7389     if (arg1->type != XPATH_NUMBER) {
   7390 	valuePush(ctxt, arg1);
   7391 	xmlXPathNumberFunction(ctxt, 1);
   7392 	arg1 = valuePop(ctxt);
   7393     }
   7394     if (arg1->type != XPATH_NUMBER) {
   7395 	xmlXPathFreeObject(arg1);
   7396 	xmlXPathFreeObject(arg2);
   7397 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7398     }
   7399     if (arg2->type != XPATH_NUMBER) {
   7400 	valuePush(ctxt, arg2);
   7401 	xmlXPathNumberFunction(ctxt, 1);
   7402 	arg2 = valuePop(ctxt);
   7403     }
   7404     if (arg2->type != XPATH_NUMBER) {
   7405 	xmlXPathReleaseObject(ctxt->context, arg1);
   7406 	xmlXPathReleaseObject(ctxt->context, arg2);
   7407 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7408     }
   7409     /*
   7410      * Add tests for infinity and nan
   7411      * => feedback on 3.4 for Inf and NaN
   7412      */
   7413     /* Hand check NaN and Infinity comparisons */
   7414     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
   7415 	ret=0;
   7416     } else {
   7417 	arg1i=xmlXPathIsInf(arg1->floatval);
   7418 	arg2i=xmlXPathIsInf(arg2->floatval);
   7419 	if (inf && strict) {
   7420 	    if ((arg1i == -1 && arg2i != -1) ||
   7421 		(arg2i == 1 && arg1i != 1)) {
   7422 		ret = 1;
   7423 	    } else if (arg1i == 0 && arg2i == 0) {
   7424 		ret = (arg1->floatval < arg2->floatval);
   7425 	    } else {
   7426 		ret = 0;
   7427 	    }
   7428 	}
   7429 	else if (inf && !strict) {
   7430 	    if (arg1i == -1 || arg2i == 1) {
   7431 		ret = 1;
   7432 	    } else if (arg1i == 0 && arg2i == 0) {
   7433 		ret = (arg1->floatval <= arg2->floatval);
   7434 	    } else {
   7435 		ret = 0;
   7436 	    }
   7437 	}
   7438 	else if (!inf && strict) {
   7439 	    if ((arg1i == 1 && arg2i != 1) ||
   7440 		(arg2i == -1 && arg1i != -1)) {
   7441 		ret = 1;
   7442 	    } else if (arg1i == 0 && arg2i == 0) {
   7443 		ret = (arg1->floatval > arg2->floatval);
   7444 	    } else {
   7445 		ret = 0;
   7446 	    }
   7447 	}
   7448 	else if (!inf && !strict) {
   7449 	    if (arg1i == 1 || arg2i == -1) {
   7450 		ret = 1;
   7451 	    } else if (arg1i == 0 && arg2i == 0) {
   7452 		ret = (arg1->floatval >= arg2->floatval);
   7453 	    } else {
   7454 		ret = 0;
   7455 	    }
   7456 	}
   7457     }
   7458     xmlXPathReleaseObject(ctxt->context, arg1);
   7459     xmlXPathReleaseObject(ctxt->context, arg2);
   7460     return(ret);
   7461 }
   7462 
   7463 /**
   7464  * xmlXPathValueFlipSign:
   7465  * @ctxt:  the XPath Parser context
   7466  *
   7467  * Implement the unary - operation on an XPath object
   7468  * The numeric operators convert their operands to numbers as if
   7469  * by calling the number function.
   7470  */
   7471 void
   7472 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
   7473     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
   7474     CAST_TO_NUMBER;
   7475     CHECK_TYPE(XPATH_NUMBER);
   7476     ctxt->value->floatval = -ctxt->value->floatval;
   7477 }
   7478 
   7479 /**
   7480  * xmlXPathAddValues:
   7481  * @ctxt:  the XPath Parser context
   7482  *
   7483  * Implement the add operation on XPath objects:
   7484  * The numeric operators convert their operands to numbers as if
   7485  * by calling the number function.
   7486  */
   7487 void
   7488 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
   7489     xmlXPathObjectPtr arg;
   7490     double val;
   7491 
   7492     arg = valuePop(ctxt);
   7493     if (arg == NULL)
   7494 	XP_ERROR(XPATH_INVALID_OPERAND);
   7495     val = xmlXPathCastToNumber(arg);
   7496     xmlXPathReleaseObject(ctxt->context, arg);
   7497     CAST_TO_NUMBER;
   7498     CHECK_TYPE(XPATH_NUMBER);
   7499     ctxt->value->floatval += val;
   7500 }
   7501 
   7502 /**
   7503  * xmlXPathSubValues:
   7504  * @ctxt:  the XPath Parser context
   7505  *
   7506  * Implement the subtraction operation on XPath objects:
   7507  * The numeric operators convert their operands to numbers as if
   7508  * by calling the number function.
   7509  */
   7510 void
   7511 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
   7512     xmlXPathObjectPtr arg;
   7513     double val;
   7514 
   7515     arg = valuePop(ctxt);
   7516     if (arg == NULL)
   7517 	XP_ERROR(XPATH_INVALID_OPERAND);
   7518     val = xmlXPathCastToNumber(arg);
   7519     xmlXPathReleaseObject(ctxt->context, arg);
   7520     CAST_TO_NUMBER;
   7521     CHECK_TYPE(XPATH_NUMBER);
   7522     ctxt->value->floatval -= val;
   7523 }
   7524 
   7525 /**
   7526  * xmlXPathMultValues:
   7527  * @ctxt:  the XPath Parser context
   7528  *
   7529  * Implement the multiply operation on XPath objects:
   7530  * The numeric operators convert their operands to numbers as if
   7531  * by calling the number function.
   7532  */
   7533 void
   7534 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
   7535     xmlXPathObjectPtr arg;
   7536     double val;
   7537 
   7538     arg = valuePop(ctxt);
   7539     if (arg == NULL)
   7540 	XP_ERROR(XPATH_INVALID_OPERAND);
   7541     val = xmlXPathCastToNumber(arg);
   7542     xmlXPathReleaseObject(ctxt->context, arg);
   7543     CAST_TO_NUMBER;
   7544     CHECK_TYPE(XPATH_NUMBER);
   7545     ctxt->value->floatval *= val;
   7546 }
   7547 
   7548 /**
   7549  * xmlXPathDivValues:
   7550  * @ctxt:  the XPath Parser context
   7551  *
   7552  * Implement the div operation on XPath objects @arg1 / @arg2:
   7553  * The numeric operators convert their operands to numbers as if
   7554  * by calling the number function.
   7555  */
   7556 void
   7557 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
   7558     xmlXPathObjectPtr arg;
   7559     double val;
   7560 
   7561     arg = valuePop(ctxt);
   7562     if (arg == NULL)
   7563 	XP_ERROR(XPATH_INVALID_OPERAND);
   7564     val = xmlXPathCastToNumber(arg);
   7565     xmlXPathReleaseObject(ctxt->context, arg);
   7566     CAST_TO_NUMBER;
   7567     CHECK_TYPE(XPATH_NUMBER);
   7568     ctxt->value->floatval /= val;
   7569 }
   7570 
   7571 /**
   7572  * xmlXPathModValues:
   7573  * @ctxt:  the XPath Parser context
   7574  *
   7575  * Implement the mod operation on XPath objects: @arg1 / @arg2
   7576  * The numeric operators convert their operands to numbers as if
   7577  * by calling the number function.
   7578  */
   7579 void
   7580 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
   7581     xmlXPathObjectPtr arg;
   7582     double arg1, arg2;
   7583 
   7584     arg = valuePop(ctxt);
   7585     if (arg == NULL)
   7586 	XP_ERROR(XPATH_INVALID_OPERAND);
   7587     arg2 = xmlXPathCastToNumber(arg);
   7588     xmlXPathReleaseObject(ctxt->context, arg);
   7589     CAST_TO_NUMBER;
   7590     CHECK_TYPE(XPATH_NUMBER);
   7591     arg1 = ctxt->value->floatval;
   7592     if (arg2 == 0)
   7593 	ctxt->value->floatval = NAN;
   7594     else {
   7595 	ctxt->value->floatval = fmod(arg1, arg2);
   7596     }
   7597 }
   7598 
   7599 /************************************************************************
   7600  *									*
   7601  *		The traversal functions					*
   7602  *									*
   7603  ************************************************************************/
   7604 
   7605 /*
   7606  * A traversal function enumerates nodes along an axis.
   7607  * Initially it must be called with NULL, and it indicates
   7608  * termination on the axis by returning NULL.
   7609  */
   7610 typedef xmlNodePtr (*xmlXPathTraversalFunction)
   7611                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
   7612 
   7613 /*
   7614  * xmlXPathTraversalFunctionExt:
   7615  * A traversal function enumerates nodes along an axis.
   7616  * Initially it must be called with NULL, and it indicates
   7617  * termination on the axis by returning NULL.
   7618  * The context node of the traversal is specified via @contextNode.
   7619  */
   7620 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
   7621                     (xmlNodePtr cur, xmlNodePtr contextNode);
   7622 
   7623 /*
   7624  * xmlXPathNodeSetMergeFunction:
   7625  * Used for merging node sets in xmlXPathCollectAndTest().
   7626  */
   7627 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
   7628 		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
   7629 
   7630 
   7631 /**
   7632  * xmlXPathNextSelf:
   7633  * @ctxt:  the XPath Parser context
   7634  * @cur:  the current node in the traversal
   7635  *
   7636  * Traversal function for the "self" direction
   7637  * The self axis contains just the context node itself
   7638  *
   7639  * Returns the next element following that axis
   7640  */
   7641 xmlNodePtr
   7642 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7643     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7644     if (cur == NULL)
   7645         return(ctxt->context->node);
   7646     return(NULL);
   7647 }
   7648 
   7649 /**
   7650  * xmlXPathNextChild:
   7651  * @ctxt:  the XPath Parser context
   7652  * @cur:  the current node in the traversal
   7653  *
   7654  * Traversal function for the "child" direction
   7655  * The child axis contains the children of the context node in document order.
   7656  *
   7657  * Returns the next element following that axis
   7658  */
   7659 xmlNodePtr
   7660 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7661     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7662     if (cur == NULL) {
   7663 	if (ctxt->context->node == NULL) return(NULL);
   7664 	switch (ctxt->context->node->type) {
   7665             case XML_ELEMENT_NODE:
   7666             case XML_TEXT_NODE:
   7667             case XML_CDATA_SECTION_NODE:
   7668             case XML_ENTITY_REF_NODE:
   7669             case XML_ENTITY_NODE:
   7670             case XML_PI_NODE:
   7671             case XML_COMMENT_NODE:
   7672             case XML_NOTATION_NODE:
   7673             case XML_DTD_NODE:
   7674 		return(ctxt->context->node->children);
   7675             case XML_DOCUMENT_NODE:
   7676             case XML_DOCUMENT_TYPE_NODE:
   7677             case XML_DOCUMENT_FRAG_NODE:
   7678             case XML_HTML_DOCUMENT_NODE:
   7679 #ifdef LIBXML_DOCB_ENABLED
   7680 	    case XML_DOCB_DOCUMENT_NODE:
   7681 #endif
   7682 		return(((xmlDocPtr) ctxt->context->node)->children);
   7683 	    case XML_ELEMENT_DECL:
   7684 	    case XML_ATTRIBUTE_DECL:
   7685 	    case XML_ENTITY_DECL:
   7686             case XML_ATTRIBUTE_NODE:
   7687 	    case XML_NAMESPACE_DECL:
   7688 	    case XML_XINCLUDE_START:
   7689 	    case XML_XINCLUDE_END:
   7690 		return(NULL);
   7691 	}
   7692 	return(NULL);
   7693     }
   7694     if ((cur->type == XML_DOCUMENT_NODE) ||
   7695         (cur->type == XML_HTML_DOCUMENT_NODE))
   7696 	return(NULL);
   7697     return(cur->next);
   7698 }
   7699 
   7700 /**
   7701  * xmlXPathNextChildElement:
   7702  * @ctxt:  the XPath Parser context
   7703  * @cur:  the current node in the traversal
   7704  *
   7705  * Traversal function for the "child" direction and nodes of type element.
   7706  * The child axis contains the children of the context node in document order.
   7707  *
   7708  * Returns the next element following that axis
   7709  */
   7710 static xmlNodePtr
   7711 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7712     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7713     if (cur == NULL) {
   7714 	cur = ctxt->context->node;
   7715 	if (cur == NULL) return(NULL);
   7716 	/*
   7717 	* Get the first element child.
   7718 	*/
   7719 	switch (cur->type) {
   7720             case XML_ELEMENT_NODE:
   7721 	    case XML_DOCUMENT_FRAG_NODE:
   7722 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
   7723             case XML_ENTITY_NODE:
   7724 		cur = cur->children;
   7725 		if (cur != NULL) {
   7726 		    if (cur->type == XML_ELEMENT_NODE)
   7727 			return(cur);
   7728 		    do {
   7729 			cur = cur->next;
   7730 		    } while ((cur != NULL) &&
   7731 			(cur->type != XML_ELEMENT_NODE));
   7732 		    return(cur);
   7733 		}
   7734 		return(NULL);
   7735             case XML_DOCUMENT_NODE:
   7736             case XML_HTML_DOCUMENT_NODE:
   7737 #ifdef LIBXML_DOCB_ENABLED
   7738 	    case XML_DOCB_DOCUMENT_NODE:
   7739 #endif
   7740 		return(xmlDocGetRootElement((xmlDocPtr) cur));
   7741 	    default:
   7742 		return(NULL);
   7743 	}
   7744 	return(NULL);
   7745     }
   7746     /*
   7747     * Get the next sibling element node.
   7748     */
   7749     switch (cur->type) {
   7750 	case XML_ELEMENT_NODE:
   7751 	case XML_TEXT_NODE:
   7752 	case XML_ENTITY_REF_NODE:
   7753 	case XML_ENTITY_NODE:
   7754 	case XML_CDATA_SECTION_NODE:
   7755 	case XML_PI_NODE:
   7756 	case XML_COMMENT_NODE:
   7757 	case XML_XINCLUDE_END:
   7758 	    break;
   7759 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
   7760 	default:
   7761 	    return(NULL);
   7762     }
   7763     if (cur->next != NULL) {
   7764 	if (cur->next->type == XML_ELEMENT_NODE)
   7765 	    return(cur->next);
   7766 	cur = cur->next;
   7767 	do {
   7768 	    cur = cur->next;
   7769 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
   7770 	return(cur);
   7771     }
   7772     return(NULL);
   7773 }
   7774 
   7775 #if 0
   7776 /**
   7777  * xmlXPathNextDescendantOrSelfElemParent:
   7778  * @ctxt:  the XPath Parser context
   7779  * @cur:  the current node in the traversal
   7780  *
   7781  * Traversal function for the "descendant-or-self" axis.
   7782  * Additionally it returns only nodes which can be parents of
   7783  * element nodes.
   7784  *
   7785  *
   7786  * Returns the next element following that axis
   7787  */
   7788 static xmlNodePtr
   7789 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
   7790 				       xmlNodePtr contextNode)
   7791 {
   7792     if (cur == NULL) {
   7793 	if (contextNode == NULL)
   7794 	    return(NULL);
   7795 	switch (contextNode->type) {
   7796 	    case XML_ELEMENT_NODE:
   7797 	    case XML_XINCLUDE_START:
   7798 	    case XML_DOCUMENT_FRAG_NODE:
   7799 	    case XML_DOCUMENT_NODE:
   7800 #ifdef LIBXML_DOCB_ENABLED
   7801 	    case XML_DOCB_DOCUMENT_NODE:
   7802 #endif
   7803 	    case XML_HTML_DOCUMENT_NODE:
   7804 		return(contextNode);
   7805 	    default:
   7806 		return(NULL);
   7807 	}
   7808 	return(NULL);
   7809     } else {
   7810 	xmlNodePtr start = cur;
   7811 
   7812 	while (cur != NULL) {
   7813 	    switch (cur->type) {
   7814 		case XML_ELEMENT_NODE:
   7815 		/* TODO: OK to have XInclude here? */
   7816 		case XML_XINCLUDE_START:
   7817 		case XML_DOCUMENT_FRAG_NODE:
   7818 		    if (cur != start)
   7819 			return(cur);
   7820 		    if (cur->children != NULL) {
   7821 			cur = cur->children;
   7822 			continue;
   7823 		    }
   7824 		    break;
   7825 		/* Not sure if we need those here. */
   7826 		case XML_DOCUMENT_NODE:
   7827 #ifdef LIBXML_DOCB_ENABLED
   7828 		case XML_DOCB_DOCUMENT_NODE:
   7829 #endif
   7830 		case XML_HTML_DOCUMENT_NODE:
   7831 		    if (cur != start)
   7832 			return(cur);
   7833 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
   7834 		default:
   7835 		    break;
   7836 	    }
   7837 
   7838 next_sibling:
   7839 	    if ((cur == NULL) || (cur == contextNode))
   7840 		return(NULL);
   7841 	    if (cur->next != NULL) {
   7842 		cur = cur->next;
   7843 	    } else {
   7844 		cur = cur->parent;
   7845 		goto next_sibling;
   7846 	    }
   7847 	}
   7848     }
   7849     return(NULL);
   7850 }
   7851 #endif
   7852 
   7853 /**
   7854  * xmlXPathNextDescendant:
   7855  * @ctxt:  the XPath Parser context
   7856  * @cur:  the current node in the traversal
   7857  *
   7858  * Traversal function for the "descendant" direction
   7859  * the descendant axis contains the descendants of the context node in document
   7860  * order; a descendant is a child or a child of a child and so on.
   7861  *
   7862  * Returns the next element following that axis
   7863  */
   7864 xmlNodePtr
   7865 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7866     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7867     if (cur == NULL) {
   7868 	if (ctxt->context->node == NULL)
   7869 	    return(NULL);
   7870 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   7871 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
   7872 	    return(NULL);
   7873 
   7874         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
   7875 	    return(ctxt->context->doc->children);
   7876         return(ctxt->context->node->children);
   7877     }
   7878 
   7879     if (cur->type == XML_NAMESPACE_DECL)
   7880         return(NULL);
   7881     if (cur->children != NULL) {
   7882 	/*
   7883 	 * Do not descend on entities declarations
   7884 	 */
   7885 	if (cur->children->type != XML_ENTITY_DECL) {
   7886 	    cur = cur->children;
   7887 	    /*
   7888 	     * Skip DTDs
   7889 	     */
   7890 	    if (cur->type != XML_DTD_NODE)
   7891 		return(cur);
   7892 	}
   7893     }
   7894 
   7895     if (cur == ctxt->context->node) return(NULL);
   7896 
   7897     while (cur->next != NULL) {
   7898 	cur = cur->next;
   7899 	if ((cur->type != XML_ENTITY_DECL) &&
   7900 	    (cur->type != XML_DTD_NODE))
   7901 	    return(cur);
   7902     }
   7903 
   7904     do {
   7905         cur = cur->parent;
   7906 	if (cur == NULL) break;
   7907 	if (cur == ctxt->context->node) return(NULL);
   7908 	if (cur->next != NULL) {
   7909 	    cur = cur->next;
   7910 	    return(cur);
   7911 	}
   7912     } while (cur != NULL);
   7913     return(cur);
   7914 }
   7915 
   7916 /**
   7917  * xmlXPathNextDescendantOrSelf:
   7918  * @ctxt:  the XPath Parser context
   7919  * @cur:  the current node in the traversal
   7920  *
   7921  * Traversal function for the "descendant-or-self" direction
   7922  * the descendant-or-self axis contains the context node and the descendants
   7923  * of the context node in document order; thus the context node is the first
   7924  * node on the axis, and the first child of the context node is the second node
   7925  * on the axis
   7926  *
   7927  * Returns the next element following that axis
   7928  */
   7929 xmlNodePtr
   7930 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7931     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7932     if (cur == NULL)
   7933         return(ctxt->context->node);
   7934 
   7935     if (ctxt->context->node == NULL)
   7936         return(NULL);
   7937     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   7938         (ctxt->context->node->type == XML_NAMESPACE_DECL))
   7939         return(NULL);
   7940 
   7941     return(xmlXPathNextDescendant(ctxt, cur));
   7942 }
   7943 
   7944 /**
   7945  * xmlXPathNextParent:
   7946  * @ctxt:  the XPath Parser context
   7947  * @cur:  the current node in the traversal
   7948  *
   7949  * Traversal function for the "parent" direction
   7950  * The parent axis contains the parent of the context node, if there is one.
   7951  *
   7952  * Returns the next element following that axis
   7953  */
   7954 xmlNodePtr
   7955 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7956     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7957     /*
   7958      * the parent of an attribute or namespace node is the element
   7959      * to which the attribute or namespace node is attached
   7960      * Namespace handling !!!
   7961      */
   7962     if (cur == NULL) {
   7963 	if (ctxt->context->node == NULL) return(NULL);
   7964 	switch (ctxt->context->node->type) {
   7965             case XML_ELEMENT_NODE:
   7966             case XML_TEXT_NODE:
   7967             case XML_CDATA_SECTION_NODE:
   7968             case XML_ENTITY_REF_NODE:
   7969             case XML_ENTITY_NODE:
   7970             case XML_PI_NODE:
   7971             case XML_COMMENT_NODE:
   7972             case XML_NOTATION_NODE:
   7973             case XML_DTD_NODE:
   7974 	    case XML_ELEMENT_DECL:
   7975 	    case XML_ATTRIBUTE_DECL:
   7976 	    case XML_XINCLUDE_START:
   7977 	    case XML_XINCLUDE_END:
   7978 	    case XML_ENTITY_DECL:
   7979 		if (ctxt->context->node->parent == NULL)
   7980 		    return((xmlNodePtr) ctxt->context->doc);
   7981 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
   7982 		    ((ctxt->context->node->parent->name[0] == ' ') ||
   7983 		     (xmlStrEqual(ctxt->context->node->parent->name,
   7984 				 BAD_CAST "fake node libxslt"))))
   7985 		    return(NULL);
   7986 		return(ctxt->context->node->parent);
   7987             case XML_ATTRIBUTE_NODE: {
   7988 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
   7989 
   7990 		return(att->parent);
   7991 	    }
   7992             case XML_DOCUMENT_NODE:
   7993             case XML_DOCUMENT_TYPE_NODE:
   7994             case XML_DOCUMENT_FRAG_NODE:
   7995             case XML_HTML_DOCUMENT_NODE:
   7996 #ifdef LIBXML_DOCB_ENABLED
   7997 	    case XML_DOCB_DOCUMENT_NODE:
   7998 #endif
   7999                 return(NULL);
   8000 	    case XML_NAMESPACE_DECL: {
   8001 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
   8002 
   8003 		if ((ns->next != NULL) &&
   8004 		    (ns->next->type != XML_NAMESPACE_DECL))
   8005 		    return((xmlNodePtr) ns->next);
   8006                 return(NULL);
   8007 	    }
   8008 	}
   8009     }
   8010     return(NULL);
   8011 }
   8012 
   8013 /**
   8014  * xmlXPathNextAncestor:
   8015  * @ctxt:  the XPath Parser context
   8016  * @cur:  the current node in the traversal
   8017  *
   8018  * Traversal function for the "ancestor" direction
   8019  * the ancestor axis contains the ancestors of the context node; the ancestors
   8020  * of the context node consist of the parent of context node and the parent's
   8021  * parent and so on; the nodes are ordered in reverse document order; thus the
   8022  * parent is the first node on the axis, and the parent's parent is the second
   8023  * node on the axis
   8024  *
   8025  * Returns the next element following that axis
   8026  */
   8027 xmlNodePtr
   8028 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8029     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8030     /*
   8031      * the parent of an attribute or namespace node is the element
   8032      * to which the attribute or namespace node is attached
   8033      * !!!!!!!!!!!!!
   8034      */
   8035     if (cur == NULL) {
   8036 	if (ctxt->context->node == NULL) return(NULL);
   8037 	switch (ctxt->context->node->type) {
   8038             case XML_ELEMENT_NODE:
   8039             case XML_TEXT_NODE:
   8040             case XML_CDATA_SECTION_NODE:
   8041             case XML_ENTITY_REF_NODE:
   8042             case XML_ENTITY_NODE:
   8043             case XML_PI_NODE:
   8044             case XML_COMMENT_NODE:
   8045 	    case XML_DTD_NODE:
   8046 	    case XML_ELEMENT_DECL:
   8047 	    case XML_ATTRIBUTE_DECL:
   8048 	    case XML_ENTITY_DECL:
   8049             case XML_NOTATION_NODE:
   8050 	    case XML_XINCLUDE_START:
   8051 	    case XML_XINCLUDE_END:
   8052 		if (ctxt->context->node->parent == NULL)
   8053 		    return((xmlNodePtr) ctxt->context->doc);
   8054 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
   8055 		    ((ctxt->context->node->parent->name[0] == ' ') ||
   8056 		     (xmlStrEqual(ctxt->context->node->parent->name,
   8057 				 BAD_CAST "fake node libxslt"))))
   8058 		    return(NULL);
   8059 		return(ctxt->context->node->parent);
   8060             case XML_ATTRIBUTE_NODE: {
   8061 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
   8062 
   8063 		return(tmp->parent);
   8064 	    }
   8065             case XML_DOCUMENT_NODE:
   8066             case XML_DOCUMENT_TYPE_NODE:
   8067             case XML_DOCUMENT_FRAG_NODE:
   8068             case XML_HTML_DOCUMENT_NODE:
   8069 #ifdef LIBXML_DOCB_ENABLED
   8070 	    case XML_DOCB_DOCUMENT_NODE:
   8071 #endif
   8072                 return(NULL);
   8073 	    case XML_NAMESPACE_DECL: {
   8074 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
   8075 
   8076 		if ((ns->next != NULL) &&
   8077 		    (ns->next->type != XML_NAMESPACE_DECL))
   8078 		    return((xmlNodePtr) ns->next);
   8079 		/* Bad, how did that namespace end up here ? */
   8080                 return(NULL);
   8081 	    }
   8082 	}
   8083 	return(NULL);
   8084     }
   8085     if (cur == ctxt->context->doc->children)
   8086 	return((xmlNodePtr) ctxt->context->doc);
   8087     if (cur == (xmlNodePtr) ctxt->context->doc)
   8088 	return(NULL);
   8089     switch (cur->type) {
   8090 	case XML_ELEMENT_NODE:
   8091 	case XML_TEXT_NODE:
   8092 	case XML_CDATA_SECTION_NODE:
   8093 	case XML_ENTITY_REF_NODE:
   8094 	case XML_ENTITY_NODE:
   8095 	case XML_PI_NODE:
   8096 	case XML_COMMENT_NODE:
   8097 	case XML_NOTATION_NODE:
   8098 	case XML_DTD_NODE:
   8099         case XML_ELEMENT_DECL:
   8100         case XML_ATTRIBUTE_DECL:
   8101         case XML_ENTITY_DECL:
   8102 	case XML_XINCLUDE_START:
   8103 	case XML_XINCLUDE_END:
   8104 	    if (cur->parent == NULL)
   8105 		return(NULL);
   8106 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
   8107 		((cur->parent->name[0] == ' ') ||
   8108 		 (xmlStrEqual(cur->parent->name,
   8109 			      BAD_CAST "fake node libxslt"))))
   8110 		return(NULL);
   8111 	    return(cur->parent);
   8112 	case XML_ATTRIBUTE_NODE: {
   8113 	    xmlAttrPtr att = (xmlAttrPtr) cur;
   8114 
   8115 	    return(att->parent);
   8116 	}
   8117 	case XML_NAMESPACE_DECL: {
   8118 	    xmlNsPtr ns = (xmlNsPtr) cur;
   8119 
   8120 	    if ((ns->next != NULL) &&
   8121 	        (ns->next->type != XML_NAMESPACE_DECL))
   8122 	        return((xmlNodePtr) ns->next);
   8123 	    /* Bad, how did that namespace end up here ? */
   8124             return(NULL);
   8125 	}
   8126 	case XML_DOCUMENT_NODE:
   8127 	case XML_DOCUMENT_TYPE_NODE:
   8128 	case XML_DOCUMENT_FRAG_NODE:
   8129 	case XML_HTML_DOCUMENT_NODE:
   8130 #ifdef LIBXML_DOCB_ENABLED
   8131 	case XML_DOCB_DOCUMENT_NODE:
   8132 #endif
   8133 	    return(NULL);
   8134     }
   8135     return(NULL);
   8136 }
   8137 
   8138 /**
   8139  * xmlXPathNextAncestorOrSelf:
   8140  * @ctxt:  the XPath Parser context
   8141  * @cur:  the current node in the traversal
   8142  *
   8143  * Traversal function for the "ancestor-or-self" direction
   8144  * he ancestor-or-self axis contains the context node and ancestors of
   8145  * the context node in reverse document order; thus the context node is
   8146  * the first node on the axis, and the context node's parent the second;
   8147  * parent here is defined the same as with the parent axis.
   8148  *
   8149  * Returns the next element following that axis
   8150  */
   8151 xmlNodePtr
   8152 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8153     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8154     if (cur == NULL)
   8155         return(ctxt->context->node);
   8156     return(xmlXPathNextAncestor(ctxt, cur));
   8157 }
   8158 
   8159 /**
   8160  * xmlXPathNextFollowingSibling:
   8161  * @ctxt:  the XPath Parser context
   8162  * @cur:  the current node in the traversal
   8163  *
   8164  * Traversal function for the "following-sibling" direction
   8165  * The following-sibling axis contains the following siblings of the context
   8166  * node in document order.
   8167  *
   8168  * Returns the next element following that axis
   8169  */
   8170 xmlNodePtr
   8171 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8172     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8173     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   8174 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
   8175 	return(NULL);
   8176     if (cur == (xmlNodePtr) ctxt->context->doc)
   8177         return(NULL);
   8178     if (cur == NULL)
   8179         return(ctxt->context->node->next);
   8180     return(cur->next);
   8181 }
   8182 
   8183 /**
   8184  * xmlXPathNextPrecedingSibling:
   8185  * @ctxt:  the XPath Parser context
   8186  * @cur:  the current node in the traversal
   8187  *
   8188  * Traversal function for the "preceding-sibling" direction
   8189  * The preceding-sibling axis contains the preceding siblings of the context
   8190  * node in reverse document order; the first preceding sibling is first on the
   8191  * axis; the sibling preceding that node is the second on the axis and so on.
   8192  *
   8193  * Returns the next element following that axis
   8194  */
   8195 xmlNodePtr
   8196 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8197     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8198     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   8199 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
   8200 	return(NULL);
   8201     if (cur == (xmlNodePtr) ctxt->context->doc)
   8202         return(NULL);
   8203     if (cur == NULL)
   8204         return(ctxt->context->node->prev);
   8205     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
   8206 	cur = cur->prev;
   8207 	if (cur == NULL)
   8208 	    return(ctxt->context->node->prev);
   8209     }
   8210     return(cur->prev);
   8211 }
   8212 
   8213 /**
   8214  * xmlXPathNextFollowing:
   8215  * @ctxt:  the XPath Parser context
   8216  * @cur:  the current node in the traversal
   8217  *
   8218  * Traversal function for the "following" direction
   8219  * The following axis contains all nodes in the same document as the context
   8220  * node that are after the context node in document order, excluding any
   8221  * descendants and excluding attribute nodes and namespace nodes; the nodes
   8222  * are ordered in document order
   8223  *
   8224  * Returns the next element following that axis
   8225  */
   8226 xmlNodePtr
   8227 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8228     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8229     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
   8230         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
   8231         return(cur->children);
   8232 
   8233     if (cur == NULL) {
   8234         cur = ctxt->context->node;
   8235         if (cur->type == XML_ATTRIBUTE_NODE) {
   8236             cur = cur->parent;
   8237         } else if (cur->type == XML_NAMESPACE_DECL) {
   8238             xmlNsPtr ns = (xmlNsPtr) cur;
   8239 
   8240             if ((ns->next == NULL) ||
   8241                 (ns->next->type == XML_NAMESPACE_DECL))
   8242                 return (NULL);
   8243             cur = (xmlNodePtr) ns->next;
   8244         }
   8245     }
   8246     if (cur == NULL) return(NULL) ; /* ERROR */
   8247     if (cur->next != NULL) return(cur->next) ;
   8248     do {
   8249         cur = cur->parent;
   8250         if (cur == NULL) break;
   8251         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
   8252         if (cur->next != NULL) return(cur->next);
   8253     } while (cur != NULL);
   8254     return(cur);
   8255 }
   8256 
   8257 /*
   8258  * xmlXPathIsAncestor:
   8259  * @ancestor:  the ancestor node
   8260  * @node:  the current node
   8261  *
   8262  * Check that @ancestor is a @node's ancestor
   8263  *
   8264  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
   8265  */
   8266 static int
   8267 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
   8268     if ((ancestor == NULL) || (node == NULL)) return(0);
   8269     if (node->type == XML_NAMESPACE_DECL)
   8270         return(0);
   8271     if (ancestor->type == XML_NAMESPACE_DECL)
   8272         return(0);
   8273     /* nodes need to be in the same document */
   8274     if (ancestor->doc != node->doc) return(0);
   8275     /* avoid searching if ancestor or node is the root node */
   8276     if (ancestor == (xmlNodePtr) node->doc) return(1);
   8277     if (node == (xmlNodePtr) ancestor->doc) return(0);
   8278     while (node->parent != NULL) {
   8279         if (node->parent == ancestor)
   8280             return(1);
   8281 	node = node->parent;
   8282     }
   8283     return(0);
   8284 }
   8285 
   8286 /**
   8287  * xmlXPathNextPreceding:
   8288  * @ctxt:  the XPath Parser context
   8289  * @cur:  the current node in the traversal
   8290  *
   8291  * Traversal function for the "preceding" direction
   8292  * the preceding axis contains all nodes in the same document as the context
   8293  * node that are before the context node in document order, excluding any
   8294  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
   8295  * ordered in reverse document order
   8296  *
   8297  * Returns the next element following that axis
   8298  */
   8299 xmlNodePtr
   8300 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
   8301 {
   8302     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8303     if (cur == NULL) {
   8304         cur = ctxt->context->node;
   8305         if (cur->type == XML_ATTRIBUTE_NODE) {
   8306             cur = cur->parent;
   8307         } else if (cur->type == XML_NAMESPACE_DECL) {
   8308             xmlNsPtr ns = (xmlNsPtr) cur;
   8309 
   8310             if ((ns->next == NULL) ||
   8311                 (ns->next->type == XML_NAMESPACE_DECL))
   8312                 return (NULL);
   8313             cur = (xmlNodePtr) ns->next;
   8314         }
   8315     }
   8316     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
   8317 	return (NULL);
   8318     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
   8319 	cur = cur->prev;
   8320     do {
   8321         if (cur->prev != NULL) {
   8322             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
   8323             return (cur);
   8324         }
   8325 
   8326         cur = cur->parent;
   8327         if (cur == NULL)
   8328             return (NULL);
   8329         if (cur == ctxt->context->doc->children)
   8330             return (NULL);
   8331     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
   8332     return (cur);
   8333 }
   8334 
   8335 /**
   8336  * xmlXPathNextPrecedingInternal:
   8337  * @ctxt:  the XPath Parser context
   8338  * @cur:  the current node in the traversal
   8339  *
   8340  * Traversal function for the "preceding" direction
   8341  * the preceding axis contains all nodes in the same document as the context
   8342  * node that are before the context node in document order, excluding any
   8343  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
   8344  * ordered in reverse document order
   8345  * This is a faster implementation but internal only since it requires a
   8346  * state kept in the parser context: ctxt->ancestor.
   8347  *
   8348  * Returns the next element following that axis
   8349  */
   8350 static xmlNodePtr
   8351 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
   8352                               xmlNodePtr cur)
   8353 {
   8354     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8355     if (cur == NULL) {
   8356         cur = ctxt->context->node;
   8357         if (cur == NULL)
   8358             return (NULL);
   8359         if (cur->type == XML_ATTRIBUTE_NODE) {
   8360             cur = cur->parent;
   8361         } else if (cur->type == XML_NAMESPACE_DECL) {
   8362             xmlNsPtr ns = (xmlNsPtr) cur;
   8363 
   8364             if ((ns->next == NULL) ||
   8365                 (ns->next->type == XML_NAMESPACE_DECL))
   8366                 return (NULL);
   8367             cur = (xmlNodePtr) ns->next;
   8368         }
   8369         ctxt->ancestor = cur->parent;
   8370     }
   8371     if (cur->type == XML_NAMESPACE_DECL)
   8372         return(NULL);
   8373     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
   8374 	cur = cur->prev;
   8375     while (cur->prev == NULL) {
   8376         cur = cur->parent;
   8377         if (cur == NULL)
   8378             return (NULL);
   8379         if (cur == ctxt->context->doc->children)
   8380             return (NULL);
   8381         if (cur != ctxt->ancestor)
   8382             return (cur);
   8383         ctxt->ancestor = cur->parent;
   8384     }
   8385     cur = cur->prev;
   8386     while (cur->last != NULL)
   8387         cur = cur->last;
   8388     return (cur);
   8389 }
   8390 
   8391 /**
   8392  * xmlXPathNextNamespace:
   8393  * @ctxt:  the XPath Parser context
   8394  * @cur:  the current attribute in the traversal
   8395  *
   8396  * Traversal function for the "namespace" direction
   8397  * the namespace axis contains the namespace nodes of the context node;
   8398  * the order of nodes on this axis is implementation-defined; the axis will
   8399  * be empty unless the context node is an element
   8400  *
   8401  * We keep the XML namespace node at the end of the list.
   8402  *
   8403  * Returns the next element following that axis
   8404  */
   8405 xmlNodePtr
   8406 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8407     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8408     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
   8409     if (cur == NULL) {
   8410         if (ctxt->context->tmpNsList != NULL)
   8411 	    xmlFree(ctxt->context->tmpNsList);
   8412 	ctxt->context->tmpNsList =
   8413 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
   8414 	ctxt->context->tmpNsNr = 0;
   8415 	if (ctxt->context->tmpNsList != NULL) {
   8416 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
   8417 		ctxt->context->tmpNsNr++;
   8418 	    }
   8419 	}
   8420 	return((xmlNodePtr) xmlXPathXMLNamespace);
   8421     }
   8422     if (ctxt->context->tmpNsNr > 0) {
   8423 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
   8424     } else {
   8425 	if (ctxt->context->tmpNsList != NULL)
   8426 	    xmlFree(ctxt->context->tmpNsList);
   8427 	ctxt->context->tmpNsList = NULL;
   8428 	return(NULL);
   8429     }
   8430 }
   8431 
   8432 /**
   8433  * xmlXPathNextAttribute:
   8434  * @ctxt:  the XPath Parser context
   8435  * @cur:  the current attribute in the traversal
   8436  *
   8437  * Traversal function for the "attribute" direction
   8438  * TODO: support DTD inherited default attributes
   8439  *
   8440  * Returns the next element following that axis
   8441  */
   8442 xmlNodePtr
   8443 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8444     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8445     if (ctxt->context->node == NULL)
   8446 	return(NULL);
   8447     if (ctxt->context->node->type != XML_ELEMENT_NODE)
   8448 	return(NULL);
   8449     if (cur == NULL) {
   8450         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
   8451 	    return(NULL);
   8452         return((xmlNodePtr)ctxt->context->node->properties);
   8453     }
   8454     return((xmlNodePtr)cur->next);
   8455 }
   8456 
   8457 /************************************************************************
   8458  *									*
   8459  *		NodeTest Functions					*
   8460  *									*
   8461  ************************************************************************/
   8462 
   8463 #define IS_FUNCTION			200
   8464 
   8465 
   8466 /************************************************************************
   8467  *									*
   8468  *		Implicit tree core function library			*
   8469  *									*
   8470  ************************************************************************/
   8471 
   8472 /**
   8473  * xmlXPathRoot:
   8474  * @ctxt:  the XPath Parser context
   8475  *
   8476  * Initialize the context to the root of the document
   8477  */
   8478 void
   8479 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
   8480     if ((ctxt == NULL) || (ctxt->context == NULL))
   8481 	return;
   8482     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
   8483     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8484 	ctxt->context->node));
   8485 }
   8486 
   8487 /************************************************************************
   8488  *									*
   8489  *		The explicit core function library			*
   8490  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
   8491  *									*
   8492  ************************************************************************/
   8493 
   8494 
   8495 /**
   8496  * xmlXPathLastFunction:
   8497  * @ctxt:  the XPath Parser context
   8498  * @nargs:  the number of arguments
   8499  *
   8500  * Implement the last() XPath function
   8501  *    number last()
   8502  * The last function returns the number of nodes in the context node list.
   8503  */
   8504 void
   8505 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8506     CHECK_ARITY(0);
   8507     if (ctxt->context->contextSize >= 0) {
   8508 	valuePush(ctxt,
   8509 	    xmlXPathCacheNewFloat(ctxt->context,
   8510 		(double) ctxt->context->contextSize));
   8511 #ifdef DEBUG_EXPR
   8512 	xmlGenericError(xmlGenericErrorContext,
   8513 		"last() : %d\n", ctxt->context->contextSize);
   8514 #endif
   8515     } else {
   8516 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
   8517     }
   8518 }
   8519 
   8520 /**
   8521  * xmlXPathPositionFunction:
   8522  * @ctxt:  the XPath Parser context
   8523  * @nargs:  the number of arguments
   8524  *
   8525  * Implement the position() XPath function
   8526  *    number position()
   8527  * The position function returns the position of the context node in the
   8528  * context node list. The first position is 1, and so the last position
   8529  * will be equal to last().
   8530  */
   8531 void
   8532 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8533     CHECK_ARITY(0);
   8534     if (ctxt->context->proximityPosition >= 0) {
   8535 	valuePush(ctxt,
   8536 	      xmlXPathCacheNewFloat(ctxt->context,
   8537 		(double) ctxt->context->proximityPosition));
   8538 #ifdef DEBUG_EXPR
   8539 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
   8540 		ctxt->context->proximityPosition);
   8541 #endif
   8542     } else {
   8543 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
   8544     }
   8545 }
   8546 
   8547 /**
   8548  * xmlXPathCountFunction:
   8549  * @ctxt:  the XPath Parser context
   8550  * @nargs:  the number of arguments
   8551  *
   8552  * Implement the count() XPath function
   8553  *    number count(node-set)
   8554  */
   8555 void
   8556 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8557     xmlXPathObjectPtr cur;
   8558 
   8559     CHECK_ARITY(1);
   8560     if ((ctxt->value == NULL) ||
   8561 	((ctxt->value->type != XPATH_NODESET) &&
   8562 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8563 	XP_ERROR(XPATH_INVALID_TYPE);
   8564     cur = valuePop(ctxt);
   8565 
   8566     if ((cur == NULL) || (cur->nodesetval == NULL))
   8567 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
   8568     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
   8569 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8570 	    (double) cur->nodesetval->nodeNr));
   8571     } else {
   8572 	if ((cur->nodesetval->nodeNr != 1) ||
   8573 	    (cur->nodesetval->nodeTab == NULL)) {
   8574 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
   8575 	} else {
   8576 	    xmlNodePtr tmp;
   8577 	    int i = 0;
   8578 
   8579 	    tmp = cur->nodesetval->nodeTab[0];
   8580 	    if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
   8581 		tmp = tmp->children;
   8582 		while (tmp != NULL) {
   8583 		    tmp = tmp->next;
   8584 		    i++;
   8585 		}
   8586 	    }
   8587 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
   8588 	}
   8589     }
   8590     xmlXPathReleaseObject(ctxt->context, cur);
   8591 }
   8592 
   8593 /**
   8594  * xmlXPathGetElementsByIds:
   8595  * @doc:  the document
   8596  * @ids:  a whitespace separated list of IDs
   8597  *
   8598  * Selects elements by their unique ID.
   8599  *
   8600  * Returns a node-set of selected elements.
   8601  */
   8602 static xmlNodeSetPtr
   8603 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
   8604     xmlNodeSetPtr ret;
   8605     const xmlChar *cur = ids;
   8606     xmlChar *ID;
   8607     xmlAttrPtr attr;
   8608     xmlNodePtr elem = NULL;
   8609 
   8610     if (ids == NULL) return(NULL);
   8611 
   8612     ret = xmlXPathNodeSetCreate(NULL);
   8613     if (ret == NULL)
   8614         return(ret);
   8615 
   8616     while (IS_BLANK_CH(*cur)) cur++;
   8617     while (*cur != 0) {
   8618 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
   8619 	    cur++;
   8620 
   8621         ID = xmlStrndup(ids, cur - ids);
   8622 	if (ID != NULL) {
   8623 	    /*
   8624 	     * We used to check the fact that the value passed
   8625 	     * was an NCName, but this generated much troubles for
   8626 	     * me and Aleksey Sanin, people blatantly violated that
   8627 	     * constaint, like Visa3D spec.
   8628 	     * if (xmlValidateNCName(ID, 1) == 0)
   8629 	     */
   8630 	    attr = xmlGetID(doc, ID);
   8631 	    if (attr != NULL) {
   8632 		if (attr->type == XML_ATTRIBUTE_NODE)
   8633 		    elem = attr->parent;
   8634 		else if (attr->type == XML_ELEMENT_NODE)
   8635 		    elem = (xmlNodePtr) attr;
   8636 		else
   8637 		    elem = NULL;
   8638 		if (elem != NULL)
   8639 		    xmlXPathNodeSetAdd(ret, elem);
   8640 	    }
   8641 	    xmlFree(ID);
   8642 	}
   8643 
   8644 	while (IS_BLANK_CH(*cur)) cur++;
   8645 	ids = cur;
   8646     }
   8647     return(ret);
   8648 }
   8649 
   8650 /**
   8651  * xmlXPathIdFunction:
   8652  * @ctxt:  the XPath Parser context
   8653  * @nargs:  the number of arguments
   8654  *
   8655  * Implement the id() XPath function
   8656  *    node-set id(object)
   8657  * The id function selects elements by their unique ID
   8658  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
   8659  * then the result is the union of the result of applying id to the
   8660  * string value of each of the nodes in the argument node-set. When the
   8661  * argument to id is of any other type, the argument is converted to a
   8662  * string as if by a call to the string function; the string is split
   8663  * into a whitespace-separated list of tokens (whitespace is any sequence
   8664  * of characters matching the production S); the result is a node-set
   8665  * containing the elements in the same document as the context node that
   8666  * have a unique ID equal to any of the tokens in the list.
   8667  */
   8668 void
   8669 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8670     xmlChar *tokens;
   8671     xmlNodeSetPtr ret;
   8672     xmlXPathObjectPtr obj;
   8673 
   8674     CHECK_ARITY(1);
   8675     obj = valuePop(ctxt);
   8676     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   8677     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
   8678 	xmlNodeSetPtr ns;
   8679 	int i;
   8680 
   8681 	ret = xmlXPathNodeSetCreate(NULL);
   8682         /*
   8683          * FIXME -- in an out-of-memory condition this will behave badly.
   8684          * The solution is not clear -- we already popped an item from
   8685          * ctxt, so the object is in a corrupt state.
   8686          */
   8687 
   8688 	if (obj->nodesetval != NULL) {
   8689 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
   8690 		tokens =
   8691 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
   8692 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
   8693 		ret = xmlXPathNodeSetMerge(ret, ns);
   8694 		xmlXPathFreeNodeSet(ns);
   8695 		if (tokens != NULL)
   8696 		    xmlFree(tokens);
   8697 	    }
   8698 	}
   8699 	xmlXPathReleaseObject(ctxt->context, obj);
   8700 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
   8701 	return;
   8702     }
   8703     obj = xmlXPathCacheConvertString(ctxt->context, obj);
   8704     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
   8705     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
   8706     xmlXPathReleaseObject(ctxt->context, obj);
   8707     return;
   8708 }
   8709 
   8710 /**
   8711  * xmlXPathLocalNameFunction:
   8712  * @ctxt:  the XPath Parser context
   8713  * @nargs:  the number of arguments
   8714  *
   8715  * Implement the local-name() XPath function
   8716  *    string local-name(node-set?)
   8717  * The local-name function returns a string containing the local part
   8718  * of the name of the node in the argument node-set that is first in
   8719  * document order. If the node-set is empty or the first node has no
   8720  * name, an empty string is returned. If the argument is omitted it
   8721  * defaults to the context node.
   8722  */
   8723 void
   8724 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8725     xmlXPathObjectPtr cur;
   8726 
   8727     if (ctxt == NULL) return;
   8728 
   8729     if (nargs == 0) {
   8730 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8731 	    ctxt->context->node));
   8732 	nargs = 1;
   8733     }
   8734 
   8735     CHECK_ARITY(1);
   8736     if ((ctxt->value == NULL) ||
   8737 	((ctxt->value->type != XPATH_NODESET) &&
   8738 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8739 	XP_ERROR(XPATH_INVALID_TYPE);
   8740     cur = valuePop(ctxt);
   8741 
   8742     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
   8743 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8744     } else {
   8745 	int i = 0; /* Should be first in document order !!!!! */
   8746 	switch (cur->nodesetval->nodeTab[i]->type) {
   8747 	case XML_ELEMENT_NODE:
   8748 	case XML_ATTRIBUTE_NODE:
   8749 	case XML_PI_NODE:
   8750 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
   8751 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8752 	    else
   8753 		valuePush(ctxt,
   8754 		      xmlXPathCacheNewString(ctxt->context,
   8755 			cur->nodesetval->nodeTab[i]->name));
   8756 	    break;
   8757 	case XML_NAMESPACE_DECL:
   8758 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   8759 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
   8760 	    break;
   8761 	default:
   8762 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8763 	}
   8764     }
   8765     xmlXPathReleaseObject(ctxt->context, cur);
   8766 }
   8767 
   8768 /**
   8769  * xmlXPathNamespaceURIFunction:
   8770  * @ctxt:  the XPath Parser context
   8771  * @nargs:  the number of arguments
   8772  *
   8773  * Implement the namespace-uri() XPath function
   8774  *    string namespace-uri(node-set?)
   8775  * The namespace-uri function returns a string containing the
   8776  * namespace URI of the expanded name of the node in the argument
   8777  * node-set that is first in document order. If the node-set is empty,
   8778  * the first node has no name, or the expanded name has no namespace
   8779  * URI, an empty string is returned. If the argument is omitted it
   8780  * defaults to the context node.
   8781  */
   8782 void
   8783 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8784     xmlXPathObjectPtr cur;
   8785 
   8786     if (ctxt == NULL) return;
   8787 
   8788     if (nargs == 0) {
   8789 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8790 	    ctxt->context->node));
   8791 	nargs = 1;
   8792     }
   8793     CHECK_ARITY(1);
   8794     if ((ctxt->value == NULL) ||
   8795 	((ctxt->value->type != XPATH_NODESET) &&
   8796 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8797 	XP_ERROR(XPATH_INVALID_TYPE);
   8798     cur = valuePop(ctxt);
   8799 
   8800     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
   8801 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8802     } else {
   8803 	int i = 0; /* Should be first in document order !!!!! */
   8804 	switch (cur->nodesetval->nodeTab[i]->type) {
   8805 	case XML_ELEMENT_NODE:
   8806 	case XML_ATTRIBUTE_NODE:
   8807 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
   8808 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8809 	    else
   8810 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   8811 			  cur->nodesetval->nodeTab[i]->ns->href));
   8812 	    break;
   8813 	default:
   8814 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8815 	}
   8816     }
   8817     xmlXPathReleaseObject(ctxt->context, cur);
   8818 }
   8819 
   8820 /**
   8821  * xmlXPathNameFunction:
   8822  * @ctxt:  the XPath Parser context
   8823  * @nargs:  the number of arguments
   8824  *
   8825  * Implement the name() XPath function
   8826  *    string name(node-set?)
   8827  * The name function returns a string containing a QName representing
   8828  * the name of the node in the argument node-set that is first in document
   8829  * order. The QName must represent the name with respect to the namespace
   8830  * declarations in effect on the node whose name is being represented.
   8831  * Typically, this will be the form in which the name occurred in the XML
   8832  * source. This need not be the case if there are namespace declarations
   8833  * in effect on the node that associate multiple prefixes with the same
   8834  * namespace. However, an implementation may include information about
   8835  * the original prefix in its representation of nodes; in this case, an
   8836  * implementation can ensure that the returned string is always the same
   8837  * as the QName used in the XML source. If the argument it omitted it
   8838  * defaults to the context node.
   8839  * Libxml keep the original prefix so the "real qualified name" used is
   8840  * returned.
   8841  */
   8842 static void
   8843 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
   8844 {
   8845     xmlXPathObjectPtr cur;
   8846 
   8847     if (nargs == 0) {
   8848 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8849 	    ctxt->context->node));
   8850         nargs = 1;
   8851     }
   8852 
   8853     CHECK_ARITY(1);
   8854     if ((ctxt->value == NULL) ||
   8855         ((ctxt->value->type != XPATH_NODESET) &&
   8856          (ctxt->value->type != XPATH_XSLT_TREE)))
   8857         XP_ERROR(XPATH_INVALID_TYPE);
   8858     cur = valuePop(ctxt);
   8859 
   8860     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
   8861         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8862     } else {
   8863         int i = 0;              /* Should be first in document order !!!!! */
   8864 
   8865         switch (cur->nodesetval->nodeTab[i]->type) {
   8866             case XML_ELEMENT_NODE:
   8867             case XML_ATTRIBUTE_NODE:
   8868 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
   8869 		    valuePush(ctxt,
   8870 			xmlXPathCacheNewCString(ctxt->context, ""));
   8871 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
   8872                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
   8873 		    valuePush(ctxt,
   8874 		        xmlXPathCacheNewString(ctxt->context,
   8875 			    cur->nodesetval->nodeTab[i]->name));
   8876 		} else {
   8877 		    xmlChar *fullname;
   8878 
   8879 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
   8880 				     cur->nodesetval->nodeTab[i]->ns->prefix,
   8881 				     NULL, 0);
   8882 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
   8883 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
   8884 		    if (fullname == NULL) {
   8885 			XP_ERROR(XPATH_MEMORY_ERROR);
   8886 		    }
   8887 		    valuePush(ctxt, xmlXPathCacheWrapString(
   8888 			ctxt->context, fullname));
   8889                 }
   8890                 break;
   8891             default:
   8892 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8893 		    cur->nodesetval->nodeTab[i]));
   8894                 xmlXPathLocalNameFunction(ctxt, 1);
   8895         }
   8896     }
   8897     xmlXPathReleaseObject(ctxt->context, cur);
   8898 }
   8899 
   8900 
   8901 /**
   8902  * xmlXPathStringFunction:
   8903  * @ctxt:  the XPath Parser context
   8904  * @nargs:  the number of arguments
   8905  *
   8906  * Implement the string() XPath function
   8907  *    string string(object?)
   8908  * The string function converts an object to a string as follows:
   8909  *    - A node-set is converted to a string by returning the value of
   8910  *      the node in the node-set that is first in document order.
   8911  *      If the node-set is empty, an empty string is returned.
   8912  *    - A number is converted to a string as follows
   8913  *      + NaN is converted to the string NaN
   8914  *      + positive zero is converted to the string 0
   8915  *      + negative zero is converted to the string 0
   8916  *      + positive infinity is converted to the string Infinity
   8917  *      + negative infinity is converted to the string -Infinity
   8918  *      + if the number is an integer, the number is represented in
   8919  *        decimal form as a Number with no decimal point and no leading
   8920  *        zeros, preceded by a minus sign (-) if the number is negative
   8921  *      + otherwise, the number is represented in decimal form as a
   8922  *        Number including a decimal point with at least one digit
   8923  *        before the decimal point and at least one digit after the
   8924  *        decimal point, preceded by a minus sign (-) if the number
   8925  *        is negative; there must be no leading zeros before the decimal
   8926  *        point apart possibly from the one required digit immediately
   8927  *        before the decimal point; beyond the one required digit
   8928  *        after the decimal point there must be as many, but only as
   8929  *        many, more digits as are needed to uniquely distinguish the
   8930  *        number from all other IEEE 754 numeric values.
   8931  *    - The boolean false value is converted to the string false.
   8932  *      The boolean true value is converted to the string true.
   8933  *
   8934  * If the argument is omitted, it defaults to a node-set with the
   8935  * context node as its only member.
   8936  */
   8937 void
   8938 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8939     xmlXPathObjectPtr cur;
   8940 
   8941     if (ctxt == NULL) return;
   8942     if (nargs == 0) {
   8943     valuePush(ctxt,
   8944 	xmlXPathCacheWrapString(ctxt->context,
   8945 	    xmlXPathCastNodeToString(ctxt->context->node)));
   8946 	return;
   8947     }
   8948 
   8949     CHECK_ARITY(1);
   8950     cur = valuePop(ctxt);
   8951     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   8952     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
   8953 }
   8954 
   8955 /**
   8956  * xmlXPathStringLengthFunction:
   8957  * @ctxt:  the XPath Parser context
   8958  * @nargs:  the number of arguments
   8959  *
   8960  * Implement the string-length() XPath function
   8961  *    number string-length(string?)
   8962  * The string-length returns the number of characters in the string
   8963  * (see [3.6 Strings]). If the argument is omitted, it defaults to
   8964  * the context node converted to a string, in other words the value
   8965  * of the context node.
   8966  */
   8967 void
   8968 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8969     xmlXPathObjectPtr cur;
   8970 
   8971     if (nargs == 0) {
   8972         if ((ctxt == NULL) || (ctxt->context == NULL))
   8973 	    return;
   8974 	if (ctxt->context->node == NULL) {
   8975 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
   8976 	} else {
   8977 	    xmlChar *content;
   8978 
   8979 	    content = xmlXPathCastNodeToString(ctxt->context->node);
   8980 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8981 		xmlUTF8Strlen(content)));
   8982 	    xmlFree(content);
   8983 	}
   8984 	return;
   8985     }
   8986     CHECK_ARITY(1);
   8987     CAST_TO_STRING;
   8988     CHECK_TYPE(XPATH_STRING);
   8989     cur = valuePop(ctxt);
   8990     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8991 	xmlUTF8Strlen(cur->stringval)));
   8992     xmlXPathReleaseObject(ctxt->context, cur);
   8993 }
   8994 
   8995 /**
   8996  * xmlXPathConcatFunction:
   8997  * @ctxt:  the XPath Parser context
   8998  * @nargs:  the number of arguments
   8999  *
   9000  * Implement the concat() XPath function
   9001  *    string concat(string, string, string*)
   9002  * The concat function returns the concatenation of its arguments.
   9003  */
   9004 void
   9005 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9006     xmlXPathObjectPtr cur, newobj;
   9007     xmlChar *tmp;
   9008 
   9009     if (ctxt == NULL) return;
   9010     if (nargs < 2) {
   9011 	CHECK_ARITY(2);
   9012     }
   9013 
   9014     CAST_TO_STRING;
   9015     cur = valuePop(ctxt);
   9016     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
   9017 	xmlXPathReleaseObject(ctxt->context, cur);
   9018 	return;
   9019     }
   9020     nargs--;
   9021 
   9022     while (nargs > 0) {
   9023 	CAST_TO_STRING;
   9024 	newobj = valuePop(ctxt);
   9025 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
   9026 	    xmlXPathReleaseObject(ctxt->context, newobj);
   9027 	    xmlXPathReleaseObject(ctxt->context, cur);
   9028 	    XP_ERROR(XPATH_INVALID_TYPE);
   9029 	}
   9030 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
   9031 	newobj->stringval = cur->stringval;
   9032 	cur->stringval = tmp;
   9033 	xmlXPathReleaseObject(ctxt->context, newobj);
   9034 	nargs--;
   9035     }
   9036     valuePush(ctxt, cur);
   9037 }
   9038 
   9039 /**
   9040  * xmlXPathContainsFunction:
   9041  * @ctxt:  the XPath Parser context
   9042  * @nargs:  the number of arguments
   9043  *
   9044  * Implement the contains() XPath function
   9045  *    boolean contains(string, string)
   9046  * The contains function returns true if the first argument string
   9047  * contains the second argument string, and otherwise returns false.
   9048  */
   9049 void
   9050 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9051     xmlXPathObjectPtr hay, needle;
   9052 
   9053     CHECK_ARITY(2);
   9054     CAST_TO_STRING;
   9055     CHECK_TYPE(XPATH_STRING);
   9056     needle = valuePop(ctxt);
   9057     CAST_TO_STRING;
   9058     hay = valuePop(ctxt);
   9059 
   9060     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
   9061 	xmlXPathReleaseObject(ctxt->context, hay);
   9062 	xmlXPathReleaseObject(ctxt->context, needle);
   9063 	XP_ERROR(XPATH_INVALID_TYPE);
   9064     }
   9065     if (xmlStrstr(hay->stringval, needle->stringval))
   9066 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   9067     else
   9068 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   9069     xmlXPathReleaseObject(ctxt->context, hay);
   9070     xmlXPathReleaseObject(ctxt->context, needle);
   9071 }
   9072 
   9073 /**
   9074  * xmlXPathStartsWithFunction:
   9075  * @ctxt:  the XPath Parser context
   9076  * @nargs:  the number of arguments
   9077  *
   9078  * Implement the starts-with() XPath function
   9079  *    boolean starts-with(string, string)
   9080  * The starts-with function returns true if the first argument string
   9081  * starts with the second argument string, and otherwise returns false.
   9082  */
   9083 void
   9084 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9085     xmlXPathObjectPtr hay, needle;
   9086     int n;
   9087 
   9088     CHECK_ARITY(2);
   9089     CAST_TO_STRING;
   9090     CHECK_TYPE(XPATH_STRING);
   9091     needle = valuePop(ctxt);
   9092     CAST_TO_STRING;
   9093     hay = valuePop(ctxt);
   9094 
   9095     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
   9096 	xmlXPathReleaseObject(ctxt->context, hay);
   9097 	xmlXPathReleaseObject(ctxt->context, needle);
   9098 	XP_ERROR(XPATH_INVALID_TYPE);
   9099     }
   9100     n = xmlStrlen(needle->stringval);
   9101     if (xmlStrncmp(hay->stringval, needle->stringval, n))
   9102         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   9103     else
   9104         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   9105     xmlXPathReleaseObject(ctxt->context, hay);
   9106     xmlXPathReleaseObject(ctxt->context, needle);
   9107 }
   9108 
   9109 /**
   9110  * xmlXPathSubstringFunction:
   9111  * @ctxt:  the XPath Parser context
   9112  * @nargs:  the number of arguments
   9113  *
   9114  * Implement the substring() XPath function
   9115  *    string substring(string, number, number?)
   9116  * The substring function returns the substring of the first argument
   9117  * starting at the position specified in the second argument with
   9118  * length specified in the third argument. For example,
   9119  * substring("12345",2,3) returns "234". If the third argument is not
   9120  * specified, it returns the substring starting at the position specified
   9121  * in the second argument and continuing to the end of the string. For
   9122  * example, substring("12345",2) returns "2345".  More precisely, each
   9123  * character in the string (see [3.6 Strings]) is considered to have a
   9124  * numeric position: the position of the first character is 1, the position
   9125  * of the second character is 2 and so on. The returned substring contains
   9126  * those characters for which the position of the character is greater than
   9127  * or equal to the second argument and, if the third argument is specified,
   9128  * less than the sum of the second and third arguments; the comparisons
   9129  * and addition used for the above follow the standard IEEE 754 rules. Thus:
   9130  *  - substring("12345", 1.5, 2.6) returns "234"
   9131  *  - substring("12345", 0, 3) returns "12"
   9132  *  - substring("12345", 0 div 0, 3) returns ""
   9133  *  - substring("12345", 1, 0 div 0) returns ""
   9134  *  - substring("12345", -42, 1 div 0) returns "12345"
   9135  *  - substring("12345", -1 div 0, 1 div 0) returns ""
   9136  */
   9137 void
   9138 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9139     xmlXPathObjectPtr str, start, len;
   9140     double le=0, in;
   9141     int i, l, m;
   9142     xmlChar *ret;
   9143 
   9144     if (nargs < 2) {
   9145 	CHECK_ARITY(2);
   9146     }
   9147     if (nargs > 3) {
   9148 	CHECK_ARITY(3);
   9149     }
   9150     /*
   9151      * take care of possible last (position) argument
   9152     */
   9153     if (nargs == 3) {
   9154 	CAST_TO_NUMBER;
   9155 	CHECK_TYPE(XPATH_NUMBER);
   9156 	len = valuePop(ctxt);
   9157 	le = len->floatval;
   9158 	xmlXPathReleaseObject(ctxt->context, len);
   9159     }
   9160 
   9161     CAST_TO_NUMBER;
   9162     CHECK_TYPE(XPATH_NUMBER);
   9163     start = valuePop(ctxt);
   9164     in = start->floatval;
   9165     xmlXPathReleaseObject(ctxt->context, start);
   9166     CAST_TO_STRING;
   9167     CHECK_TYPE(XPATH_STRING);
   9168     str = valuePop(ctxt);
   9169     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
   9170 
   9171     /*
   9172      * If last pos not present, calculate last position
   9173     */
   9174     if (nargs != 3) {
   9175 	le = (double)m;
   9176 	if (in < 1.0)
   9177 	    in = 1.0;
   9178     }
   9179 
   9180     /* Need to check for the special cases where either
   9181      * the index is NaN, the length is NaN, or both
   9182      * arguments are infinity (relying on Inf + -Inf = NaN)
   9183      */
   9184     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
   9185         /*
   9186          * To meet the requirements of the spec, the arguments
   9187 	 * must be converted to integer format before
   9188 	 * initial index calculations are done
   9189          *
   9190          * First we go to integer form, rounding up
   9191 	 * and checking for special cases
   9192          */
   9193         i = (int) in;
   9194         if (((double)i)+0.5 <= in) i++;
   9195 
   9196 	if (xmlXPathIsInf(le) == 1) {
   9197 	    l = m;
   9198 	    if (i < 1)
   9199 		i = 1;
   9200 	}
   9201 	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
   9202 	    l = 0;
   9203 	else {
   9204 	    l = (int) le;
   9205 	    if (((double)l)+0.5 <= le) l++;
   9206 	}
   9207 
   9208 	/* Now we normalize inidices */
   9209         i -= 1;
   9210         l += i;
   9211         if (i < 0)
   9212             i = 0;
   9213         if (l > m)
   9214             l = m;
   9215 
   9216         /* number of chars to copy */
   9217         l -= i;
   9218 
   9219         ret = xmlUTF8Strsub(str->stringval, i, l);
   9220     }
   9221     else {
   9222         ret = NULL;
   9223     }
   9224     if (ret == NULL)
   9225 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   9226     else {
   9227 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
   9228 	xmlFree(ret);
   9229     }
   9230     xmlXPathReleaseObject(ctxt->context, str);
   9231 }
   9232 
   9233 /**
   9234  * xmlXPathSubstringBeforeFunction:
   9235  * @ctxt:  the XPath Parser context
   9236  * @nargs:  the number of arguments
   9237  *
   9238  * Implement the substring-before() XPath function
   9239  *    string substring-before(string, string)
   9240  * The substring-before function returns the substring of the first
   9241  * argument string that precedes the first occurrence of the second
   9242  * argument string in the first argument string, or the empty string
   9243  * if the first argument string does not contain the second argument
   9244  * string. For example, substring-before("1999/04/01","/") returns 1999.
   9245  */
   9246 void
   9247 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9248   xmlXPathObjectPtr str;
   9249   xmlXPathObjectPtr find;
   9250   xmlBufPtr target;
   9251   const xmlChar *point;
   9252   int offset;
   9253 
   9254   CHECK_ARITY(2);
   9255   CAST_TO_STRING;
   9256   find = valuePop(ctxt);
   9257   CAST_TO_STRING;
   9258   str = valuePop(ctxt);
   9259 
   9260   target = xmlBufCreate();
   9261   if (target) {
   9262     point = xmlStrstr(str->stringval, find->stringval);
   9263     if (point) {
   9264       offset = (int)(point - str->stringval);
   9265       xmlBufAdd(target, str->stringval, offset);
   9266     }
   9267     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9268 	xmlBufContent(target)));
   9269     xmlBufFree(target);
   9270   }
   9271   xmlXPathReleaseObject(ctxt->context, str);
   9272   xmlXPathReleaseObject(ctxt->context, find);
   9273 }
   9274 
   9275 /**
   9276  * xmlXPathSubstringAfterFunction:
   9277  * @ctxt:  the XPath Parser context
   9278  * @nargs:  the number of arguments
   9279  *
   9280  * Implement the substring-after() XPath function
   9281  *    string substring-after(string, string)
   9282  * The substring-after function returns the substring of the first
   9283  * argument string that follows the first occurrence of the second
   9284  * argument string in the first argument string, or the empty stringi
   9285  * if the first argument string does not contain the second argument
   9286  * string. For example, substring-after("1999/04/01","/") returns 04/01,
   9287  * and substring-after("1999/04/01","19") returns 99/04/01.
   9288  */
   9289 void
   9290 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9291   xmlXPathObjectPtr str;
   9292   xmlXPathObjectPtr find;
   9293   xmlBufPtr target;
   9294   const xmlChar *point;
   9295   int offset;
   9296 
   9297   CHECK_ARITY(2);
   9298   CAST_TO_STRING;
   9299   find = valuePop(ctxt);
   9300   CAST_TO_STRING;
   9301   str = valuePop(ctxt);
   9302 
   9303   target = xmlBufCreate();
   9304   if (target) {
   9305     point = xmlStrstr(str->stringval, find->stringval);
   9306     if (point) {
   9307       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
   9308       xmlBufAdd(target, &str->stringval[offset],
   9309 		   xmlStrlen(str->stringval) - offset);
   9310     }
   9311     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9312 	xmlBufContent(target)));
   9313     xmlBufFree(target);
   9314   }
   9315   xmlXPathReleaseObject(ctxt->context, str);
   9316   xmlXPathReleaseObject(ctxt->context, find);
   9317 }
   9318 
   9319 /**
   9320  * xmlXPathNormalizeFunction:
   9321  * @ctxt:  the XPath Parser context
   9322  * @nargs:  the number of arguments
   9323  *
   9324  * Implement the normalize-space() XPath function
   9325  *    string normalize-space(string?)
   9326  * The normalize-space function returns the argument string with white
   9327  * space normalized by stripping leading and trailing whitespace
   9328  * and replacing sequences of whitespace characters by a single
   9329  * space. Whitespace characters are the same allowed by the S production
   9330  * in XML. If the argument is omitted, it defaults to the context
   9331  * node converted to a string, in other words the value of the context node.
   9332  */
   9333 void
   9334 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9335   xmlXPathObjectPtr obj = NULL;
   9336   xmlChar *source = NULL;
   9337   xmlBufPtr target;
   9338   xmlChar blank;
   9339 
   9340   if (ctxt == NULL) return;
   9341   if (nargs == 0) {
   9342     /* Use current context node */
   9343       valuePush(ctxt,
   9344 	  xmlXPathCacheWrapString(ctxt->context,
   9345 	    xmlXPathCastNodeToString(ctxt->context->node)));
   9346     nargs = 1;
   9347   }
   9348 
   9349   CHECK_ARITY(1);
   9350   CAST_TO_STRING;
   9351   CHECK_TYPE(XPATH_STRING);
   9352   obj = valuePop(ctxt);
   9353   source = obj->stringval;
   9354 
   9355   target = xmlBufCreate();
   9356   if (target && source) {
   9357 
   9358     /* Skip leading whitespaces */
   9359     while (IS_BLANK_CH(*source))
   9360       source++;
   9361 
   9362     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
   9363     blank = 0;
   9364     while (*source) {
   9365       if (IS_BLANK_CH(*source)) {
   9366 	blank = 0x20;
   9367       } else {
   9368 	if (blank) {
   9369 	  xmlBufAdd(target, &blank, 1);
   9370 	  blank = 0;
   9371 	}
   9372 	xmlBufAdd(target, source, 1);
   9373       }
   9374       source++;
   9375     }
   9376     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9377 	xmlBufContent(target)));
   9378     xmlBufFree(target);
   9379   }
   9380   xmlXPathReleaseObject(ctxt->context, obj);
   9381 }
   9382 
   9383 /**
   9384  * xmlXPathTranslateFunction:
   9385  * @ctxt:  the XPath Parser context
   9386  * @nargs:  the number of arguments
   9387  *
   9388  * Implement the translate() XPath function
   9389  *    string translate(string, string, string)
   9390  * The translate function returns the first argument string with
   9391  * occurrences of characters in the second argument string replaced
   9392  * by the character at the corresponding position in the third argument
   9393  * string. For example, translate("bar","abc","ABC") returns the string
   9394  * BAr. If there is a character in the second argument string with no
   9395  * character at a corresponding position in the third argument string
   9396  * (because the second argument string is longer than the third argument
   9397  * string), then occurrences of that character in the first argument
   9398  * string are removed. For example, translate("--aaa--","abc-","ABC")
   9399  * returns "AAA". If a character occurs more than once in second
   9400  * argument string, then the first occurrence determines the replacement
   9401  * character. If the third argument string is longer than the second
   9402  * argument string, then excess characters are ignored.
   9403  */
   9404 void
   9405 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9406     xmlXPathObjectPtr str;
   9407     xmlXPathObjectPtr from;
   9408     xmlXPathObjectPtr to;
   9409     xmlBufPtr target;
   9410     int offset, max;
   9411     xmlChar ch;
   9412     const xmlChar *point;
   9413     xmlChar *cptr;
   9414 
   9415     CHECK_ARITY(3);
   9416 
   9417     CAST_TO_STRING;
   9418     to = valuePop(ctxt);
   9419     CAST_TO_STRING;
   9420     from = valuePop(ctxt);
   9421     CAST_TO_STRING;
   9422     str = valuePop(ctxt);
   9423 
   9424     target = xmlBufCreate();
   9425     if (target) {
   9426 	max = xmlUTF8Strlen(to->stringval);
   9427 	for (cptr = str->stringval; (ch=*cptr); ) {
   9428 	    offset = xmlUTF8Strloc(from->stringval, cptr);
   9429 	    if (offset >= 0) {
   9430 		if (offset < max) {
   9431 		    point = xmlUTF8Strpos(to->stringval, offset);
   9432 		    if (point)
   9433 			xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
   9434 		}
   9435 	    } else
   9436 		xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
   9437 
   9438 	    /* Step to next character in input */
   9439 	    cptr++;
   9440 	    if ( ch & 0x80 ) {
   9441 		/* if not simple ascii, verify proper format */
   9442 		if ( (ch & 0xc0) != 0xc0 ) {
   9443 		    xmlGenericError(xmlGenericErrorContext,
   9444 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
   9445                     /* not asserting an XPath error is probably better */
   9446 		    break;
   9447 		}
   9448 		/* then skip over remaining bytes for this char */
   9449 		while ( (ch <<= 1) & 0x80 )
   9450 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
   9451 			xmlGenericError(xmlGenericErrorContext,
   9452 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
   9453                         /* not asserting an XPath error is probably better */
   9454 			break;
   9455 		    }
   9456 		if (ch & 0x80) /* must have had error encountered */
   9457 		    break;
   9458 	    }
   9459 	}
   9460     }
   9461     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9462 	xmlBufContent(target)));
   9463     xmlBufFree(target);
   9464     xmlXPathReleaseObject(ctxt->context, str);
   9465     xmlXPathReleaseObject(ctxt->context, from);
   9466     xmlXPathReleaseObject(ctxt->context, to);
   9467 }
   9468 
   9469 /**
   9470  * xmlXPathBooleanFunction:
   9471  * @ctxt:  the XPath Parser context
   9472  * @nargs:  the number of arguments
   9473  *
   9474  * Implement the boolean() XPath function
   9475  *    boolean boolean(object)
   9476  * The boolean function converts its argument to a boolean as follows:
   9477  *    - a number is true if and only if it is neither positive or
   9478  *      negative zero nor NaN
   9479  *    - a node-set is true if and only if it is non-empty
   9480  *    - a string is true if and only if its length is non-zero
   9481  */
   9482 void
   9483 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9484     xmlXPathObjectPtr cur;
   9485 
   9486     CHECK_ARITY(1);
   9487     cur = valuePop(ctxt);
   9488     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   9489     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
   9490     valuePush(ctxt, cur);
   9491 }
   9492 
   9493 /**
   9494  * xmlXPathNotFunction:
   9495  * @ctxt:  the XPath Parser context
   9496  * @nargs:  the number of arguments
   9497  *
   9498  * Implement the not() XPath function
   9499  *    boolean not(boolean)
   9500  * The not function returns true if its argument is false,
   9501  * and false otherwise.
   9502  */
   9503 void
   9504 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9505     CHECK_ARITY(1);
   9506     CAST_TO_BOOLEAN;
   9507     CHECK_TYPE(XPATH_BOOLEAN);
   9508     ctxt->value->boolval = ! ctxt->value->boolval;
   9509 }
   9510 
   9511 /**
   9512  * xmlXPathTrueFunction:
   9513  * @ctxt:  the XPath Parser context
   9514  * @nargs:  the number of arguments
   9515  *
   9516  * Implement the true() XPath function
   9517  *    boolean true()
   9518  */
   9519 void
   9520 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9521     CHECK_ARITY(0);
   9522     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   9523 }
   9524 
   9525 /**
   9526  * xmlXPathFalseFunction:
   9527  * @ctxt:  the XPath Parser context
   9528  * @nargs:  the number of arguments
   9529  *
   9530  * Implement the false() XPath function
   9531  *    boolean false()
   9532  */
   9533 void
   9534 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9535     CHECK_ARITY(0);
   9536     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   9537 }
   9538 
   9539 /**
   9540  * xmlXPathLangFunction:
   9541  * @ctxt:  the XPath Parser context
   9542  * @nargs:  the number of arguments
   9543  *
   9544  * Implement the lang() XPath function
   9545  *    boolean lang(string)
   9546  * The lang function returns true or false depending on whether the
   9547  * language of the context node as specified by xml:lang attributes
   9548  * is the same as or is a sublanguage of the language specified by
   9549  * the argument string. The language of the context node is determined
   9550  * by the value of the xml:lang attribute on the context node, or, if
   9551  * the context node has no xml:lang attribute, by the value of the
   9552  * xml:lang attribute on the nearest ancestor of the context node that
   9553  * has an xml:lang attribute. If there is no such attribute, then lang
   9554  * returns false. If there is such an attribute, then lang returns
   9555  * true if the attribute value is equal to the argument ignoring case,
   9556  * or if there is some suffix starting with - such that the attribute
   9557  * value is equal to the argument ignoring that suffix of the attribute
   9558  * value and ignoring case.
   9559  */
   9560 void
   9561 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9562     xmlXPathObjectPtr val = NULL;
   9563     const xmlChar *theLang = NULL;
   9564     const xmlChar *lang;
   9565     int ret = 0;
   9566     int i;
   9567 
   9568     CHECK_ARITY(1);
   9569     CAST_TO_STRING;
   9570     CHECK_TYPE(XPATH_STRING);
   9571     val = valuePop(ctxt);
   9572     lang = val->stringval;
   9573     theLang = xmlNodeGetLang(ctxt->context->node);
   9574     if ((theLang != NULL) && (lang != NULL)) {
   9575         for (i = 0;lang[i] != 0;i++)
   9576 	    if (toupper(lang[i]) != toupper(theLang[i]))
   9577 	        goto not_equal;
   9578 	if ((theLang[i] == 0) || (theLang[i] == '-'))
   9579 	    ret = 1;
   9580     }
   9581 not_equal:
   9582     if (theLang != NULL)
   9583 	xmlFree((void *)theLang);
   9584 
   9585     xmlXPathReleaseObject(ctxt->context, val);
   9586     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
   9587 }
   9588 
   9589 /**
   9590  * xmlXPathNumberFunction:
   9591  * @ctxt:  the XPath Parser context
   9592  * @nargs:  the number of arguments
   9593  *
   9594  * Implement the number() XPath function
   9595  *    number number(object?)
   9596  */
   9597 void
   9598 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9599     xmlXPathObjectPtr cur;
   9600     double res;
   9601 
   9602     if (ctxt == NULL) return;
   9603     if (nargs == 0) {
   9604 	if (ctxt->context->node == NULL) {
   9605 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
   9606 	} else {
   9607 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
   9608 
   9609 	    res = xmlXPathStringEvalNumber(content);
   9610 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
   9611 	    xmlFree(content);
   9612 	}
   9613 	return;
   9614     }
   9615 
   9616     CHECK_ARITY(1);
   9617     cur = valuePop(ctxt);
   9618     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
   9619 }
   9620 
   9621 /**
   9622  * xmlXPathSumFunction:
   9623  * @ctxt:  the XPath Parser context
   9624  * @nargs:  the number of arguments
   9625  *
   9626  * Implement the sum() XPath function
   9627  *    number sum(node-set)
   9628  * The sum function returns the sum of the values of the nodes in
   9629  * the argument node-set.
   9630  */
   9631 void
   9632 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9633     xmlXPathObjectPtr cur;
   9634     int i;
   9635     double res = 0.0;
   9636 
   9637     CHECK_ARITY(1);
   9638     if ((ctxt->value == NULL) ||
   9639 	((ctxt->value->type != XPATH_NODESET) &&
   9640 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   9641 	XP_ERROR(XPATH_INVALID_TYPE);
   9642     cur = valuePop(ctxt);
   9643 
   9644     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
   9645 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
   9646 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
   9647 	}
   9648     }
   9649     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
   9650     xmlXPathReleaseObject(ctxt->context, cur);
   9651 }
   9652 
   9653 /**
   9654  * xmlXPathFloorFunction:
   9655  * @ctxt:  the XPath Parser context
   9656  * @nargs:  the number of arguments
   9657  *
   9658  * Implement the floor() XPath function
   9659  *    number floor(number)
   9660  * The floor function returns the largest (closest to positive infinity)
   9661  * number that is not greater than the argument and that is an integer.
   9662  */
   9663 void
   9664 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9665     CHECK_ARITY(1);
   9666     CAST_TO_NUMBER;
   9667     CHECK_TYPE(XPATH_NUMBER);
   9668 
   9669     ctxt->value->floatval = floor(ctxt->value->floatval);
   9670 }
   9671 
   9672 /**
   9673  * xmlXPathCeilingFunction:
   9674  * @ctxt:  the XPath Parser context
   9675  * @nargs:  the number of arguments
   9676  *
   9677  * Implement the ceiling() XPath function
   9678  *    number ceiling(number)
   9679  * The ceiling function returns the smallest (closest to negative infinity)
   9680  * number that is not less than the argument and that is an integer.
   9681  */
   9682 void
   9683 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9684     CHECK_ARITY(1);
   9685     CAST_TO_NUMBER;
   9686     CHECK_TYPE(XPATH_NUMBER);
   9687 
   9688     ctxt->value->floatval = ceil(ctxt->value->floatval);
   9689 }
   9690 
   9691 /**
   9692  * xmlXPathRoundFunction:
   9693  * @ctxt:  the XPath Parser context
   9694  * @nargs:  the number of arguments
   9695  *
   9696  * Implement the round() XPath function
   9697  *    number round(number)
   9698  * The round function returns the number that is closest to the
   9699  * argument and that is an integer. If there are two such numbers,
   9700  * then the one that is closest to positive infinity is returned.
   9701  */
   9702 void
   9703 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9704     double f;
   9705 
   9706     CHECK_ARITY(1);
   9707     CAST_TO_NUMBER;
   9708     CHECK_TYPE(XPATH_NUMBER);
   9709 
   9710     f = ctxt->value->floatval;
   9711 
   9712     if ((f >= -0.5) && (f < 0.5)) {
   9713         /* Handles negative zero. */
   9714         ctxt->value->floatval *= 0.0;
   9715     }
   9716     else {
   9717         double rounded = floor(f);
   9718         if (f - rounded >= 0.5)
   9719             rounded += 1.0;
   9720         ctxt->value->floatval = rounded;
   9721     }
   9722 }
   9723 
   9724 /************************************************************************
   9725  *									*
   9726  *			The Parser					*
   9727  *									*
   9728  ************************************************************************/
   9729 
   9730 /*
   9731  * a few forward declarations since we use a recursive call based
   9732  * implementation.
   9733  */
   9734 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
   9735 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
   9736 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
   9737 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
   9738 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
   9739 	                                  int qualified);
   9740 
   9741 /**
   9742  * xmlXPathCurrentChar:
   9743  * @ctxt:  the XPath parser context
   9744  * @cur:  pointer to the beginning of the char
   9745  * @len:  pointer to the length of the char read
   9746  *
   9747  * The current char value, if using UTF-8 this may actually span multiple
   9748  * bytes in the input buffer.
   9749  *
   9750  * Returns the current char value and its length
   9751  */
   9752 
   9753 static int
   9754 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
   9755     unsigned char c;
   9756     unsigned int val;
   9757     const xmlChar *cur;
   9758 
   9759     if (ctxt == NULL)
   9760 	return(0);
   9761     cur = ctxt->cur;
   9762 
   9763     /*
   9764      * We are supposed to handle UTF8, check it's valid
   9765      * From rfc2044: encoding of the Unicode values on UTF-8:
   9766      *
   9767      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
   9768      * 0000 0000-0000 007F   0xxxxxxx
   9769      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
   9770      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
   9771      *
   9772      * Check for the 0x110000 limit too
   9773      */
   9774     c = *cur;
   9775     if (c & 0x80) {
   9776 	if ((cur[1] & 0xc0) != 0x80)
   9777 	    goto encoding_error;
   9778 	if ((c & 0xe0) == 0xe0) {
   9779 
   9780 	    if ((cur[2] & 0xc0) != 0x80)
   9781 		goto encoding_error;
   9782 	    if ((c & 0xf0) == 0xf0) {
   9783 		if (((c & 0xf8) != 0xf0) ||
   9784 		    ((cur[3] & 0xc0) != 0x80))
   9785 		    goto encoding_error;
   9786 		/* 4-byte code */
   9787 		*len = 4;
   9788 		val = (cur[0] & 0x7) << 18;
   9789 		val |= (cur[1] & 0x3f) << 12;
   9790 		val |= (cur[2] & 0x3f) << 6;
   9791 		val |= cur[3] & 0x3f;
   9792 	    } else {
   9793 	      /* 3-byte code */
   9794 		*len = 3;
   9795 		val = (cur[0] & 0xf) << 12;
   9796 		val |= (cur[1] & 0x3f) << 6;
   9797 		val |= cur[2] & 0x3f;
   9798 	    }
   9799 	} else {
   9800 	  /* 2-byte code */
   9801 	    *len = 2;
   9802 	    val = (cur[0] & 0x1f) << 6;
   9803 	    val |= cur[1] & 0x3f;
   9804 	}
   9805 	if (!IS_CHAR(val)) {
   9806 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
   9807 	}
   9808 	return(val);
   9809     } else {
   9810 	/* 1-byte code */
   9811 	*len = 1;
   9812 	return((int) *cur);
   9813     }
   9814 encoding_error:
   9815     /*
   9816      * If we detect an UTF8 error that probably means that the
   9817      * input encoding didn't get properly advertised in the
   9818      * declaration header. Report the error and switch the encoding
   9819      * to ISO-Latin-1 (if you don't like this policy, just declare the
   9820      * encoding !)
   9821      */
   9822     *len = 0;
   9823     XP_ERROR0(XPATH_ENCODING_ERROR);
   9824 }
   9825 
   9826 /**
   9827  * xmlXPathParseNCName:
   9828  * @ctxt:  the XPath Parser context
   9829  *
   9830  * parse an XML namespace non qualified name.
   9831  *
   9832  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
   9833  *
   9834  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
   9835  *                       CombiningChar | Extender
   9836  *
   9837  * Returns the namespace name or NULL
   9838  */
   9839 
   9840 xmlChar *
   9841 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
   9842     const xmlChar *in;
   9843     xmlChar *ret;
   9844     int count = 0;
   9845 
   9846     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
   9847     /*
   9848      * Accelerator for simple ASCII names
   9849      */
   9850     in = ctxt->cur;
   9851     if (((*in >= 0x61) && (*in <= 0x7A)) ||
   9852 	((*in >= 0x41) && (*in <= 0x5A)) ||
   9853 	(*in == '_')) {
   9854 	in++;
   9855 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
   9856 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
   9857 	       ((*in >= 0x30) && (*in <= 0x39)) ||
   9858 	       (*in == '_') || (*in == '.') ||
   9859 	       (*in == '-'))
   9860 	    in++;
   9861 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
   9862             (*in == '[') || (*in == ']') || (*in == ':') ||
   9863             (*in == '@') || (*in == '*')) {
   9864 	    count = in - ctxt->cur;
   9865 	    if (count == 0)
   9866 		return(NULL);
   9867 	    ret = xmlStrndup(ctxt->cur, count);
   9868 	    ctxt->cur = in;
   9869 	    return(ret);
   9870 	}
   9871     }
   9872     return(xmlXPathParseNameComplex(ctxt, 0));
   9873 }
   9874 
   9875 
   9876 /**
   9877  * xmlXPathParseQName:
   9878  * @ctxt:  the XPath Parser context
   9879  * @prefix:  a xmlChar **
   9880  *
   9881  * parse an XML qualified name
   9882  *
   9883  * [NS 5] QName ::= (Prefix ':')? LocalPart
   9884  *
   9885  * [NS 6] Prefix ::= NCName
   9886  *
   9887  * [NS 7] LocalPart ::= NCName
   9888  *
   9889  * Returns the function returns the local part, and prefix is updated
   9890  *   to get the Prefix if any.
   9891  */
   9892 
   9893 static xmlChar *
   9894 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
   9895     xmlChar *ret = NULL;
   9896 
   9897     *prefix = NULL;
   9898     ret = xmlXPathParseNCName(ctxt);
   9899     if (ret && CUR == ':') {
   9900         *prefix = ret;
   9901 	NEXT;
   9902 	ret = xmlXPathParseNCName(ctxt);
   9903     }
   9904     return(ret);
   9905 }
   9906 
   9907 /**
   9908  * xmlXPathParseName:
   9909  * @ctxt:  the XPath Parser context
   9910  *
   9911  * parse an XML name
   9912  *
   9913  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
   9914  *                  CombiningChar | Extender
   9915  *
   9916  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
   9917  *
   9918  * Returns the namespace name or NULL
   9919  */
   9920 
   9921 xmlChar *
   9922 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
   9923     const xmlChar *in;
   9924     xmlChar *ret;
   9925     size_t count = 0;
   9926 
   9927     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
   9928     /*
   9929      * Accelerator for simple ASCII names
   9930      */
   9931     in = ctxt->cur;
   9932     if (((*in >= 0x61) && (*in <= 0x7A)) ||
   9933 	((*in >= 0x41) && (*in <= 0x5A)) ||
   9934 	(*in == '_') || (*in == ':')) {
   9935 	in++;
   9936 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
   9937 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
   9938 	       ((*in >= 0x30) && (*in <= 0x39)) ||
   9939 	       (*in == '_') || (*in == '-') ||
   9940 	       (*in == ':') || (*in == '.'))
   9941 	    in++;
   9942 	if ((*in > 0) && (*in < 0x80)) {
   9943 	    count = in - ctxt->cur;
   9944             if (count > XML_MAX_NAME_LENGTH) {
   9945                 ctxt->cur = in;
   9946                 XP_ERRORNULL(XPATH_EXPR_ERROR);
   9947             }
   9948 	    ret = xmlStrndup(ctxt->cur, count);
   9949 	    ctxt->cur = in;
   9950 	    return(ret);
   9951 	}
   9952     }
   9953     return(xmlXPathParseNameComplex(ctxt, 1));
   9954 }
   9955 
   9956 static xmlChar *
   9957 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
   9958     xmlChar buf[XML_MAX_NAMELEN + 5];
   9959     int len = 0, l;
   9960     int c;
   9961 
   9962     /*
   9963      * Handler for more complex cases
   9964      */
   9965     c = CUR_CHAR(l);
   9966     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
   9967         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
   9968         (c == '*') || /* accelerators */
   9969 	(!IS_LETTER(c) && (c != '_') &&
   9970          ((!qualified) || (c != ':')))) {
   9971 	return(NULL);
   9972     }
   9973 
   9974     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
   9975 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
   9976             (c == '.') || (c == '-') ||
   9977 	    (c == '_') || ((qualified) && (c == ':')) ||
   9978 	    (IS_COMBINING(c)) ||
   9979 	    (IS_EXTENDER(c)))) {
   9980 	COPY_BUF(l,buf,len,c);
   9981 	NEXTL(l);
   9982 	c = CUR_CHAR(l);
   9983 	if (len >= XML_MAX_NAMELEN) {
   9984 	    /*
   9985 	     * Okay someone managed to make a huge name, so he's ready to pay
   9986 	     * for the processing speed.
   9987 	     */
   9988 	    xmlChar *buffer;
   9989 	    int max = len * 2;
   9990 
   9991             if (len > XML_MAX_NAME_LENGTH) {
   9992                 XP_ERRORNULL(XPATH_EXPR_ERROR);
   9993             }
   9994 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
   9995 	    if (buffer == NULL) {
   9996 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
   9997 	    }
   9998 	    memcpy(buffer, buf, len);
   9999 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
   10000 		   (c == '.') || (c == '-') ||
   10001 		   (c == '_') || ((qualified) && (c == ':')) ||
   10002 		   (IS_COMBINING(c)) ||
   10003 		   (IS_EXTENDER(c))) {
   10004 		if (len + 10 > max) {
   10005                     if (max > XML_MAX_NAME_LENGTH) {
   10006                         XP_ERRORNULL(XPATH_EXPR_ERROR);
   10007                     }
   10008 		    max *= 2;
   10009 		    buffer = (xmlChar *) xmlRealloc(buffer,
   10010 			                            max * sizeof(xmlChar));
   10011 		    if (buffer == NULL) {
   10012 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
   10013 		    }
   10014 		}
   10015 		COPY_BUF(l,buffer,len,c);
   10016 		NEXTL(l);
   10017 		c = CUR_CHAR(l);
   10018 	    }
   10019 	    buffer[len] = 0;
   10020 	    return(buffer);
   10021 	}
   10022     }
   10023     if (len == 0)
   10024 	return(NULL);
   10025     return(xmlStrndup(buf, len));
   10026 }
   10027 
   10028 #define MAX_FRAC 20
   10029 
   10030 /**
   10031  * xmlXPathStringEvalNumber:
   10032  * @str:  A string to scan
   10033  *
   10034  *  [30a]  Float  ::= Number ('e' Digits?)?
   10035  *
   10036  *  [30]   Number ::=   Digits ('.' Digits?)?
   10037  *                    | '.' Digits
   10038  *  [31]   Digits ::=   [0-9]+
   10039  *
   10040  * Compile a Number in the string
   10041  * In complement of the Number expression, this function also handles
   10042  * negative values : '-' Number.
   10043  *
   10044  * Returns the double value.
   10045  */
   10046 double
   10047 xmlXPathStringEvalNumber(const xmlChar *str) {
   10048     const xmlChar *cur = str;
   10049     double ret;
   10050     int ok = 0;
   10051     int isneg = 0;
   10052     int exponent = 0;
   10053     int is_exponent_negative = 0;
   10054 #ifdef __GNUC__
   10055     unsigned long tmp = 0;
   10056     double temp;
   10057 #endif
   10058     if (cur == NULL) return(0);
   10059     while (IS_BLANK_CH(*cur)) cur++;
   10060     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
   10061         return(NAN);
   10062     }
   10063     if (*cur == '-') {
   10064 	isneg = 1;
   10065 	cur++;
   10066     }
   10067 
   10068 #ifdef __GNUC__
   10069     /*
   10070      * tmp/temp is a workaround against a gcc compiler bug
   10071      * http://veillard.com/gcc.bug
   10072      */
   10073     ret = 0;
   10074     while ((*cur >= '0') && (*cur <= '9')) {
   10075 	ret = ret * 10;
   10076 	tmp = (*cur - '0');
   10077 	ok = 1;
   10078 	cur++;
   10079 	temp = (double) tmp;
   10080 	ret = ret + temp;
   10081     }
   10082 #else
   10083     ret = 0;
   10084     while ((*cur >= '0') && (*cur <= '9')) {
   10085 	ret = ret * 10 + (*cur - '0');
   10086 	ok = 1;
   10087 	cur++;
   10088     }
   10089 #endif
   10090 
   10091     if (*cur == '.') {
   10092 	int v, frac = 0, max;
   10093 	double fraction = 0;
   10094 
   10095         cur++;
   10096 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
   10097 	    return(NAN);
   10098 	}
   10099         while (*cur == '0') {
   10100 	    frac = frac + 1;
   10101 	    cur++;
   10102         }
   10103         max = frac + MAX_FRAC;
   10104 	while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
   10105 	    v = (*cur - '0');
   10106 	    fraction = fraction * 10 + v;
   10107 	    frac = frac + 1;
   10108 	    cur++;
   10109 	}
   10110 	fraction /= pow(10.0, frac);
   10111 	ret = ret + fraction;
   10112 	while ((*cur >= '0') && (*cur <= '9'))
   10113 	    cur++;
   10114     }
   10115     if ((*cur == 'e') || (*cur == 'E')) {
   10116       cur++;
   10117       if (*cur == '-') {
   10118 	is_exponent_negative = 1;
   10119 	cur++;
   10120       } else if (*cur == '+') {
   10121         cur++;
   10122       }
   10123       while ((*cur >= '0') && (*cur <= '9')) {
   10124         if (exponent < 1000000)
   10125 	  exponent = exponent * 10 + (*cur - '0');
   10126 	cur++;
   10127       }
   10128     }
   10129     while (IS_BLANK_CH(*cur)) cur++;
   10130     if (*cur != 0) return(NAN);
   10131     if (isneg) ret = -ret;
   10132     if (is_exponent_negative) exponent = -exponent;
   10133     ret *= pow(10.0, (double)exponent);
   10134     return(ret);
   10135 }
   10136 
   10137 /**
   10138  * xmlXPathCompNumber:
   10139  * @ctxt:  the XPath Parser context
   10140  *
   10141  *  [30]   Number ::=   Digits ('.' Digits?)?
   10142  *                    | '.' Digits
   10143  *  [31]   Digits ::=   [0-9]+
   10144  *
   10145  * Compile a Number, then push it on the stack
   10146  *
   10147  */
   10148 static void
   10149 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
   10150 {
   10151     double ret = 0.0;
   10152     int ok = 0;
   10153     int exponent = 0;
   10154     int is_exponent_negative = 0;
   10155 #ifdef __GNUC__
   10156     unsigned long tmp = 0;
   10157     double temp;
   10158 #endif
   10159 
   10160     CHECK_ERROR;
   10161     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
   10162         XP_ERROR(XPATH_NUMBER_ERROR);
   10163     }
   10164 #ifdef __GNUC__
   10165     /*
   10166      * tmp/temp is a workaround against a gcc compiler bug
   10167      * http://veillard.com/gcc.bug
   10168      */
   10169     ret = 0;
   10170     while ((CUR >= '0') && (CUR <= '9')) {
   10171 	ret = ret * 10;
   10172 	tmp = (CUR - '0');
   10173         ok = 1;
   10174         NEXT;
   10175 	temp = (double) tmp;
   10176 	ret = ret + temp;
   10177     }
   10178 #else
   10179     ret = 0;
   10180     while ((CUR >= '0') && (CUR <= '9')) {
   10181 	ret = ret * 10 + (CUR - '0');
   10182 	ok = 1;
   10183 	NEXT;
   10184     }
   10185 #endif
   10186     if (CUR == '.') {
   10187 	int v, frac = 0, max;
   10188 	double fraction = 0;
   10189 
   10190         NEXT;
   10191         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
   10192             XP_ERROR(XPATH_NUMBER_ERROR);
   10193         }
   10194         while (CUR == '0') {
   10195             frac = frac + 1;
   10196             NEXT;
   10197         }
   10198         max = frac + MAX_FRAC;
   10199         while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
   10200 	    v = (CUR - '0');
   10201 	    fraction = fraction * 10 + v;
   10202 	    frac = frac + 1;
   10203             NEXT;
   10204         }
   10205         fraction /= pow(10.0, frac);
   10206         ret = ret + fraction;
   10207         while ((CUR >= '0') && (CUR <= '9'))
   10208             NEXT;
   10209     }
   10210     if ((CUR == 'e') || (CUR == 'E')) {
   10211         NEXT;
   10212         if (CUR == '-') {
   10213             is_exponent_negative = 1;
   10214             NEXT;
   10215         } else if (CUR == '+') {
   10216 	    NEXT;
   10217 	}
   10218         while ((CUR >= '0') && (CUR <= '9')) {
   10219             if (exponent < 1000000)
   10220                 exponent = exponent * 10 + (CUR - '0');
   10221             NEXT;
   10222         }
   10223         if (is_exponent_negative)
   10224             exponent = -exponent;
   10225         ret *= pow(10.0, (double) exponent);
   10226     }
   10227     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
   10228                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
   10229 }
   10230 
   10231 /**
   10232  * xmlXPathParseLiteral:
   10233  * @ctxt:  the XPath Parser context
   10234  *
   10235  * Parse a Literal
   10236  *
   10237  *  [29]   Literal ::=   '"' [^"]* '"'
   10238  *                    | "'" [^']* "'"
   10239  *
   10240  * Returns the value found or NULL in case of error
   10241  */
   10242 static xmlChar *
   10243 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
   10244     const xmlChar *q;
   10245     xmlChar *ret = NULL;
   10246 
   10247     if (CUR == '"') {
   10248         NEXT;
   10249 	q = CUR_PTR;
   10250 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
   10251 	    NEXT;
   10252 	if (!IS_CHAR_CH(CUR)) {
   10253 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
   10254 	} else {
   10255 	    ret = xmlStrndup(q, CUR_PTR - q);
   10256 	    NEXT;
   10257         }
   10258     } else if (CUR == '\'') {
   10259         NEXT;
   10260 	q = CUR_PTR;
   10261 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
   10262 	    NEXT;
   10263 	if (!IS_CHAR_CH(CUR)) {
   10264 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
   10265 	} else {
   10266 	    ret = xmlStrndup(q, CUR_PTR - q);
   10267 	    NEXT;
   10268         }
   10269     } else {
   10270 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
   10271     }
   10272     return(ret);
   10273 }
   10274 
   10275 /**
   10276  * xmlXPathCompLiteral:
   10277  * @ctxt:  the XPath Parser context
   10278  *
   10279  * Parse a Literal and push it on the stack.
   10280  *
   10281  *  [29]   Literal ::=   '"' [^"]* '"'
   10282  *                    | "'" [^']* "'"
   10283  *
   10284  * TODO: xmlXPathCompLiteral memory allocation could be improved.
   10285  */
   10286 static void
   10287 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
   10288     const xmlChar *q;
   10289     xmlChar *ret = NULL;
   10290 
   10291     if (CUR == '"') {
   10292         NEXT;
   10293 	q = CUR_PTR;
   10294 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
   10295 	    NEXT;
   10296 	if (!IS_CHAR_CH(CUR)) {
   10297 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
   10298 	} else {
   10299 	    ret = xmlStrndup(q, CUR_PTR - q);
   10300 	    NEXT;
   10301         }
   10302     } else if (CUR == '\'') {
   10303         NEXT;
   10304 	q = CUR_PTR;
   10305 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
   10306 	    NEXT;
   10307 	if (!IS_CHAR_CH(CUR)) {
   10308 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
   10309 	} else {
   10310 	    ret = xmlStrndup(q, CUR_PTR - q);
   10311 	    NEXT;
   10312         }
   10313     } else {
   10314 	XP_ERROR(XPATH_START_LITERAL_ERROR);
   10315     }
   10316     if (ret == NULL) return;
   10317     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
   10318 	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
   10319     xmlFree(ret);
   10320 }
   10321 
   10322 /**
   10323  * xmlXPathCompVariableReference:
   10324  * @ctxt:  the XPath Parser context
   10325  *
   10326  * Parse a VariableReference, evaluate it and push it on the stack.
   10327  *
   10328  * The variable bindings consist of a mapping from variable names
   10329  * to variable values. The value of a variable is an object, which can be
   10330  * of any of the types that are possible for the value of an expression,
   10331  * and may also be of additional types not specified here.
   10332  *
   10333  * Early evaluation is possible since:
   10334  * The variable bindings [...] used to evaluate a subexpression are
   10335  * always the same as those used to evaluate the containing expression.
   10336  *
   10337  *  [36]   VariableReference ::=   '$' QName
   10338  */
   10339 static void
   10340 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
   10341     xmlChar *name;
   10342     xmlChar *prefix;
   10343 
   10344     SKIP_BLANKS;
   10345     if (CUR != '$') {
   10346 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
   10347     }
   10348     NEXT;
   10349     name = xmlXPathParseQName(ctxt, &prefix);
   10350     if (name == NULL) {
   10351         xmlFree(prefix);
   10352 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
   10353     }
   10354     ctxt->comp->last = -1;
   10355     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
   10356 	           name, prefix);
   10357     SKIP_BLANKS;
   10358     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
   10359 	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
   10360     }
   10361 }
   10362 
   10363 /**
   10364  * xmlXPathIsNodeType:
   10365  * @name:  a name string
   10366  *
   10367  * Is the name given a NodeType one.
   10368  *
   10369  *  [38]   NodeType ::=   'comment'
   10370  *                    | 'text'
   10371  *                    | 'processing-instruction'
   10372  *                    | 'node'
   10373  *
   10374  * Returns 1 if true 0 otherwise
   10375  */
   10376 int
   10377 xmlXPathIsNodeType(const xmlChar *name) {
   10378     if (name == NULL)
   10379 	return(0);
   10380 
   10381     if (xmlStrEqual(name, BAD_CAST "node"))
   10382 	return(1);
   10383     if (xmlStrEqual(name, BAD_CAST "text"))
   10384 	return(1);
   10385     if (xmlStrEqual(name, BAD_CAST "comment"))
   10386 	return(1);
   10387     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
   10388 	return(1);
   10389     return(0);
   10390 }
   10391 
   10392 /**
   10393  * xmlXPathCompFunctionCall:
   10394  * @ctxt:  the XPath Parser context
   10395  *
   10396  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
   10397  *  [17]   Argument ::=   Expr
   10398  *
   10399  * Compile a function call, the evaluation of all arguments are
   10400  * pushed on the stack
   10401  */
   10402 static void
   10403 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
   10404     xmlChar *name;
   10405     xmlChar *prefix;
   10406     int nbargs = 0;
   10407     int sort = 1;
   10408 
   10409     name = xmlXPathParseQName(ctxt, &prefix);
   10410     if (name == NULL) {
   10411 	xmlFree(prefix);
   10412 	XP_ERROR(XPATH_EXPR_ERROR);
   10413     }
   10414     SKIP_BLANKS;
   10415 #ifdef DEBUG_EXPR
   10416     if (prefix == NULL)
   10417 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
   10418 			name);
   10419     else
   10420 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
   10421 			prefix, name);
   10422 #endif
   10423 
   10424     if (CUR != '(') {
   10425 	xmlFree(name);
   10426 	xmlFree(prefix);
   10427 	XP_ERROR(XPATH_EXPR_ERROR);
   10428     }
   10429     NEXT;
   10430     SKIP_BLANKS;
   10431 
   10432     /*
   10433     * Optimization for count(): we don't need the node-set to be sorted.
   10434     */
   10435     if ((prefix == NULL) && (name[0] == 'c') &&
   10436 	xmlStrEqual(name, BAD_CAST "count"))
   10437     {
   10438 	sort = 0;
   10439     }
   10440     ctxt->comp->last = -1;
   10441     if (CUR != ')') {
   10442 	while (CUR != 0) {
   10443 	    int op1 = ctxt->comp->last;
   10444 	    ctxt->comp->last = -1;
   10445 	    xmlXPathCompileExpr(ctxt, sort);
   10446 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   10447 		xmlFree(name);
   10448 		xmlFree(prefix);
   10449 		return;
   10450 	    }
   10451 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
   10452 	    nbargs++;
   10453 	    if (CUR == ')') break;
   10454 	    if (CUR != ',') {
   10455 		xmlFree(name);
   10456 		xmlFree(prefix);
   10457 		XP_ERROR(XPATH_EXPR_ERROR);
   10458 	    }
   10459 	    NEXT;
   10460 	    SKIP_BLANKS;
   10461 	}
   10462     }
   10463     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
   10464 	           name, prefix);
   10465     NEXT;
   10466     SKIP_BLANKS;
   10467 }
   10468 
   10469 /**
   10470  * xmlXPathCompPrimaryExpr:
   10471  * @ctxt:  the XPath Parser context
   10472  *
   10473  *  [15]   PrimaryExpr ::=   VariableReference
   10474  *                | '(' Expr ')'
   10475  *                | Literal
   10476  *                | Number
   10477  *                | FunctionCall
   10478  *
   10479  * Compile a primary expression.
   10480  */
   10481 static void
   10482 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
   10483     SKIP_BLANKS;
   10484     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
   10485     else if (CUR == '(') {
   10486 	NEXT;
   10487 	SKIP_BLANKS;
   10488 	xmlXPathCompileExpr(ctxt, 1);
   10489 	CHECK_ERROR;
   10490 	if (CUR != ')') {
   10491 	    XP_ERROR(XPATH_EXPR_ERROR);
   10492 	}
   10493 	NEXT;
   10494 	SKIP_BLANKS;
   10495     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
   10496 	xmlXPathCompNumber(ctxt);
   10497     } else if ((CUR == '\'') || (CUR == '"')) {
   10498 	xmlXPathCompLiteral(ctxt);
   10499     } else {
   10500 	xmlXPathCompFunctionCall(ctxt);
   10501     }
   10502     SKIP_BLANKS;
   10503 }
   10504 
   10505 /**
   10506  * xmlXPathCompFilterExpr:
   10507  * @ctxt:  the XPath Parser context
   10508  *
   10509  *  [20]   FilterExpr ::=   PrimaryExpr
   10510  *               | FilterExpr Predicate
   10511  *
   10512  * Compile a filter expression.
   10513  * Square brackets are used to filter expressions in the same way that
   10514  * they are used in location paths. It is an error if the expression to
   10515  * be filtered does not evaluate to a node-set. The context node list
   10516  * used for evaluating the expression in square brackets is the node-set
   10517  * to be filtered listed in document order.
   10518  */
   10519 
   10520 static void
   10521 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
   10522     xmlXPathCompPrimaryExpr(ctxt);
   10523     CHECK_ERROR;
   10524     SKIP_BLANKS;
   10525 
   10526     while (CUR == '[') {
   10527 	xmlXPathCompPredicate(ctxt, 1);
   10528 	SKIP_BLANKS;
   10529     }
   10530 
   10531 
   10532 }
   10533 
   10534 /**
   10535  * xmlXPathScanName:
   10536  * @ctxt:  the XPath Parser context
   10537  *
   10538  * Trickery: parse an XML name but without consuming the input flow
   10539  * Needed to avoid insanity in the parser state.
   10540  *
   10541  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
   10542  *                  CombiningChar | Extender
   10543  *
   10544  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
   10545  *
   10546  * [6] Names ::= Name (S Name)*
   10547  *
   10548  * Returns the Name parsed or NULL
   10549  */
   10550 
   10551 static xmlChar *
   10552 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
   10553     int len = 0, l;
   10554     int c;
   10555     const xmlChar *cur;
   10556     xmlChar *ret;
   10557 
   10558     cur = ctxt->cur;
   10559 
   10560     c = CUR_CHAR(l);
   10561     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
   10562 	(!IS_LETTER(c) && (c != '_') &&
   10563          (c != ':'))) {
   10564 	return(NULL);
   10565     }
   10566 
   10567     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
   10568 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
   10569             (c == '.') || (c == '-') ||
   10570 	    (c == '_') || (c == ':') ||
   10571 	    (IS_COMBINING(c)) ||
   10572 	    (IS_EXTENDER(c)))) {
   10573 	len += l;
   10574 	NEXTL(l);
   10575 	c = CUR_CHAR(l);
   10576     }
   10577     ret = xmlStrndup(cur, ctxt->cur - cur);
   10578     ctxt->cur = cur;
   10579     return(ret);
   10580 }
   10581 
   10582 /**
   10583  * xmlXPathCompPathExpr:
   10584  * @ctxt:  the XPath Parser context
   10585  *
   10586  *  [19]   PathExpr ::=   LocationPath
   10587  *               | FilterExpr
   10588  *               | FilterExpr '/' RelativeLocationPath
   10589  *               | FilterExpr '//' RelativeLocationPath
   10590  *
   10591  * Compile a path expression.
   10592  * The / operator and // operators combine an arbitrary expression
   10593  * and a relative location path. It is an error if the expression
   10594  * does not evaluate to a node-set.
   10595  * The / operator does composition in the same way as when / is
   10596  * used in a location path. As in location paths, // is short for
   10597  * /descendant-or-self::node()/.
   10598  */
   10599 
   10600 static void
   10601 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
   10602     int lc = 1;           /* Should we branch to LocationPath ?         */
   10603     xmlChar *name = NULL; /* we may have to preparse a name to find out */
   10604 
   10605     SKIP_BLANKS;
   10606     if ((CUR == '$') || (CUR == '(') ||
   10607 	(IS_ASCII_DIGIT(CUR)) ||
   10608         (CUR == '\'') || (CUR == '"') ||
   10609 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
   10610 	lc = 0;
   10611     } else if (CUR == '*') {
   10612 	/* relative or absolute location path */
   10613 	lc = 1;
   10614     } else if (CUR == '/') {
   10615 	/* relative or absolute location path */
   10616 	lc = 1;
   10617     } else if (CUR == '@') {
   10618 	/* relative abbreviated attribute location path */
   10619 	lc = 1;
   10620     } else if (CUR == '.') {
   10621 	/* relative abbreviated attribute location path */
   10622 	lc = 1;
   10623     } else {
   10624 	/*
   10625 	 * Problem is finding if we have a name here whether it's:
   10626 	 *   - a nodetype
   10627 	 *   - a function call in which case it's followed by '('
   10628 	 *   - an axis in which case it's followed by ':'
   10629 	 *   - a element name
   10630 	 * We do an a priori analysis here rather than having to
   10631 	 * maintain parsed token content through the recursive function
   10632 	 * calls. This looks uglier but makes the code easier to
   10633 	 * read/write/debug.
   10634 	 */
   10635 	SKIP_BLANKS;
   10636 	name = xmlXPathScanName(ctxt);
   10637 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
   10638 #ifdef DEBUG_STEP
   10639 	    xmlGenericError(xmlGenericErrorContext,
   10640 		    "PathExpr: Axis\n");
   10641 #endif
   10642 	    lc = 1;
   10643 	    xmlFree(name);
   10644 	} else if (name != NULL) {
   10645 	    int len =xmlStrlen(name);
   10646 
   10647 
   10648 	    while (NXT(len) != 0) {
   10649 		if (NXT(len) == '/') {
   10650 		    /* element name */
   10651 #ifdef DEBUG_STEP
   10652 		    xmlGenericError(xmlGenericErrorContext,
   10653 			    "PathExpr: AbbrRelLocation\n");
   10654 #endif
   10655 		    lc = 1;
   10656 		    break;
   10657 		} else if (IS_BLANK_CH(NXT(len))) {
   10658 		    /* ignore blanks */
   10659 		    ;
   10660 		} else if (NXT(len) == ':') {
   10661 #ifdef DEBUG_STEP
   10662 		    xmlGenericError(xmlGenericErrorContext,
   10663 			    "PathExpr: AbbrRelLocation\n");
   10664 #endif
   10665 		    lc = 1;
   10666 		    break;
   10667 		} else if ((NXT(len) == '(')) {
   10668 		    /* Node Type or Function */
   10669 		    if (xmlXPathIsNodeType(name)) {
   10670 #ifdef DEBUG_STEP
   10671 		        xmlGenericError(xmlGenericErrorContext,
   10672 				"PathExpr: Type search\n");
   10673 #endif
   10674 			lc = 1;
   10675 #ifdef LIBXML_XPTR_ENABLED
   10676                     } else if (ctxt->xptr &&
   10677                                xmlStrEqual(name, BAD_CAST "range-to")) {
   10678                         lc = 1;
   10679 #endif
   10680 		    } else {
   10681 #ifdef DEBUG_STEP
   10682 		        xmlGenericError(xmlGenericErrorContext,
   10683 				"PathExpr: function call\n");
   10684 #endif
   10685 			lc = 0;
   10686 		    }
   10687                     break;
   10688 		} else if ((NXT(len) == '[')) {
   10689 		    /* element name */
   10690 #ifdef DEBUG_STEP
   10691 		    xmlGenericError(xmlGenericErrorContext,
   10692 			    "PathExpr: AbbrRelLocation\n");
   10693 #endif
   10694 		    lc = 1;
   10695 		    break;
   10696 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
   10697 			   (NXT(len) == '=')) {
   10698 		    lc = 1;
   10699 		    break;
   10700 		} else {
   10701 		    lc = 1;
   10702 		    break;
   10703 		}
   10704 		len++;
   10705 	    }
   10706 	    if (NXT(len) == 0) {
   10707 #ifdef DEBUG_STEP
   10708 		xmlGenericError(xmlGenericErrorContext,
   10709 			"PathExpr: AbbrRelLocation\n");
   10710 #endif
   10711 		/* element name */
   10712 		lc = 1;
   10713 	    }
   10714 	    xmlFree(name);
   10715 	} else {
   10716 	    /* make sure all cases are covered explicitly */
   10717 	    XP_ERROR(XPATH_EXPR_ERROR);
   10718 	}
   10719     }
   10720 
   10721     if (lc) {
   10722 	if (CUR == '/') {
   10723 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
   10724 	} else {
   10725 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
   10726 	}
   10727 	xmlXPathCompLocationPath(ctxt);
   10728     } else {
   10729 	xmlXPathCompFilterExpr(ctxt);
   10730 	CHECK_ERROR;
   10731 	if ((CUR == '/') && (NXT(1) == '/')) {
   10732 	    SKIP(2);
   10733 	    SKIP_BLANKS;
   10734 
   10735 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   10736 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   10737 	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
   10738 
   10739 	    xmlXPathCompRelativeLocationPath(ctxt);
   10740 	} else if (CUR == '/') {
   10741 	    xmlXPathCompRelativeLocationPath(ctxt);
   10742 	}
   10743     }
   10744     SKIP_BLANKS;
   10745 }
   10746 
   10747 /**
   10748  * xmlXPathCompUnionExpr:
   10749  * @ctxt:  the XPath Parser context
   10750  *
   10751  *  [18]   UnionExpr ::=   PathExpr
   10752  *               | UnionExpr '|' PathExpr
   10753  *
   10754  * Compile an union expression.
   10755  */
   10756 
   10757 static void
   10758 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
   10759     xmlXPathCompPathExpr(ctxt);
   10760     CHECK_ERROR;
   10761     SKIP_BLANKS;
   10762     while (CUR == '|') {
   10763 	int op1 = ctxt->comp->last;
   10764 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
   10765 
   10766 	NEXT;
   10767 	SKIP_BLANKS;
   10768 	xmlXPathCompPathExpr(ctxt);
   10769 
   10770 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
   10771 
   10772 	SKIP_BLANKS;
   10773     }
   10774 }
   10775 
   10776 /**
   10777  * xmlXPathCompUnaryExpr:
   10778  * @ctxt:  the XPath Parser context
   10779  *
   10780  *  [27]   UnaryExpr ::=   UnionExpr
   10781  *                   | '-' UnaryExpr
   10782  *
   10783  * Compile an unary expression.
   10784  */
   10785 
   10786 static void
   10787 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
   10788     int minus = 0;
   10789     int found = 0;
   10790 
   10791     SKIP_BLANKS;
   10792     while (CUR == '-') {
   10793         minus = 1 - minus;
   10794 	found = 1;
   10795 	NEXT;
   10796 	SKIP_BLANKS;
   10797     }
   10798 
   10799     xmlXPathCompUnionExpr(ctxt);
   10800     CHECK_ERROR;
   10801     if (found) {
   10802 	if (minus)
   10803 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
   10804 	else
   10805 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
   10806     }
   10807 }
   10808 
   10809 /**
   10810  * xmlXPathCompMultiplicativeExpr:
   10811  * @ctxt:  the XPath Parser context
   10812  *
   10813  *  [26]   MultiplicativeExpr ::=   UnaryExpr
   10814  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
   10815  *                   | MultiplicativeExpr 'div' UnaryExpr
   10816  *                   | MultiplicativeExpr 'mod' UnaryExpr
   10817  *  [34]   MultiplyOperator ::=   '*'
   10818  *
   10819  * Compile an Additive expression.
   10820  */
   10821 
   10822 static void
   10823 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
   10824     xmlXPathCompUnaryExpr(ctxt);
   10825     CHECK_ERROR;
   10826     SKIP_BLANKS;
   10827     while ((CUR == '*') ||
   10828            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
   10829            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
   10830 	int op = -1;
   10831 	int op1 = ctxt->comp->last;
   10832 
   10833         if (CUR == '*') {
   10834 	    op = 0;
   10835 	    NEXT;
   10836 	} else if (CUR == 'd') {
   10837 	    op = 1;
   10838 	    SKIP(3);
   10839 	} else if (CUR == 'm') {
   10840 	    op = 2;
   10841 	    SKIP(3);
   10842 	}
   10843 	SKIP_BLANKS;
   10844         xmlXPathCompUnaryExpr(ctxt);
   10845 	CHECK_ERROR;
   10846 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
   10847 	SKIP_BLANKS;
   10848     }
   10849 }
   10850 
   10851 /**
   10852  * xmlXPathCompAdditiveExpr:
   10853  * @ctxt:  the XPath Parser context
   10854  *
   10855  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
   10856  *                   | AdditiveExpr '+' MultiplicativeExpr
   10857  *                   | AdditiveExpr '-' MultiplicativeExpr
   10858  *
   10859  * Compile an Additive expression.
   10860  */
   10861 
   10862 static void
   10863 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
   10864 
   10865     xmlXPathCompMultiplicativeExpr(ctxt);
   10866     CHECK_ERROR;
   10867     SKIP_BLANKS;
   10868     while ((CUR == '+') || (CUR == '-')) {
   10869 	int plus;
   10870 	int op1 = ctxt->comp->last;
   10871 
   10872         if (CUR == '+') plus = 1;
   10873 	else plus = 0;
   10874 	NEXT;
   10875 	SKIP_BLANKS;
   10876         xmlXPathCompMultiplicativeExpr(ctxt);
   10877 	CHECK_ERROR;
   10878 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
   10879 	SKIP_BLANKS;
   10880     }
   10881 }
   10882 
   10883 /**
   10884  * xmlXPathCompRelationalExpr:
   10885  * @ctxt:  the XPath Parser context
   10886  *
   10887  *  [24]   RelationalExpr ::=   AdditiveExpr
   10888  *                 | RelationalExpr '<' AdditiveExpr
   10889  *                 | RelationalExpr '>' AdditiveExpr
   10890  *                 | RelationalExpr '<=' AdditiveExpr
   10891  *                 | RelationalExpr '>=' AdditiveExpr
   10892  *
   10893  *  A <= B > C is allowed ? Answer from James, yes with
   10894  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
   10895  *  which is basically what got implemented.
   10896  *
   10897  * Compile a Relational expression, then push the result
   10898  * on the stack
   10899  */
   10900 
   10901 static void
   10902 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
   10903     xmlXPathCompAdditiveExpr(ctxt);
   10904     CHECK_ERROR;
   10905     SKIP_BLANKS;
   10906     while ((CUR == '<') ||
   10907            (CUR == '>') ||
   10908            ((CUR == '<') && (NXT(1) == '=')) ||
   10909            ((CUR == '>') && (NXT(1) == '='))) {
   10910 	int inf, strict;
   10911 	int op1 = ctxt->comp->last;
   10912 
   10913         if (CUR == '<') inf = 1;
   10914 	else inf = 0;
   10915 	if (NXT(1) == '=') strict = 0;
   10916 	else strict = 1;
   10917 	NEXT;
   10918 	if (!strict) NEXT;
   10919 	SKIP_BLANKS;
   10920         xmlXPathCompAdditiveExpr(ctxt);
   10921 	CHECK_ERROR;
   10922 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
   10923 	SKIP_BLANKS;
   10924     }
   10925 }
   10926 
   10927 /**
   10928  * xmlXPathCompEqualityExpr:
   10929  * @ctxt:  the XPath Parser context
   10930  *
   10931  *  [23]   EqualityExpr ::=   RelationalExpr
   10932  *                 | EqualityExpr '=' RelationalExpr
   10933  *                 | EqualityExpr '!=' RelationalExpr
   10934  *
   10935  *  A != B != C is allowed ? Answer from James, yes with
   10936  *  (RelationalExpr = RelationalExpr) = RelationalExpr
   10937  *  (RelationalExpr != RelationalExpr) != RelationalExpr
   10938  *  which is basically what got implemented.
   10939  *
   10940  * Compile an Equality expression.
   10941  *
   10942  */
   10943 static void
   10944 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
   10945     xmlXPathCompRelationalExpr(ctxt);
   10946     CHECK_ERROR;
   10947     SKIP_BLANKS;
   10948     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
   10949 	int eq;
   10950 	int op1 = ctxt->comp->last;
   10951 
   10952         if (CUR == '=') eq = 1;
   10953 	else eq = 0;
   10954 	NEXT;
   10955 	if (!eq) NEXT;
   10956 	SKIP_BLANKS;
   10957         xmlXPathCompRelationalExpr(ctxt);
   10958 	CHECK_ERROR;
   10959 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
   10960 	SKIP_BLANKS;
   10961     }
   10962 }
   10963 
   10964 /**
   10965  * xmlXPathCompAndExpr:
   10966  * @ctxt:  the XPath Parser context
   10967  *
   10968  *  [22]   AndExpr ::=   EqualityExpr
   10969  *                 | AndExpr 'and' EqualityExpr
   10970  *
   10971  * Compile an AND expression.
   10972  *
   10973  */
   10974 static void
   10975 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
   10976     xmlXPathCompEqualityExpr(ctxt);
   10977     CHECK_ERROR;
   10978     SKIP_BLANKS;
   10979     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
   10980 	int op1 = ctxt->comp->last;
   10981         SKIP(3);
   10982 	SKIP_BLANKS;
   10983         xmlXPathCompEqualityExpr(ctxt);
   10984 	CHECK_ERROR;
   10985 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
   10986 	SKIP_BLANKS;
   10987     }
   10988 }
   10989 
   10990 /**
   10991  * xmlXPathCompileExpr:
   10992  * @ctxt:  the XPath Parser context
   10993  *
   10994  *  [14]   Expr ::=   OrExpr
   10995  *  [21]   OrExpr ::=   AndExpr
   10996  *                 | OrExpr 'or' AndExpr
   10997  *
   10998  * Parse and compile an expression
   10999  */
   11000 static void
   11001 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
   11002     xmlXPathCompAndExpr(ctxt);
   11003     CHECK_ERROR;
   11004     SKIP_BLANKS;
   11005     while ((CUR == 'o') && (NXT(1) == 'r')) {
   11006 	int op1 = ctxt->comp->last;
   11007         SKIP(2);
   11008 	SKIP_BLANKS;
   11009         xmlXPathCompAndExpr(ctxt);
   11010 	CHECK_ERROR;
   11011 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
   11012 	SKIP_BLANKS;
   11013     }
   11014     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
   11015 	/* more ops could be optimized too */
   11016 	/*
   11017 	* This is the main place to eliminate sorting for
   11018 	* operations which don't require a sorted node-set.
   11019 	* E.g. count().
   11020 	*/
   11021 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
   11022     }
   11023 }
   11024 
   11025 /**
   11026  * xmlXPathCompPredicate:
   11027  * @ctxt:  the XPath Parser context
   11028  * @filter:  act as a filter
   11029  *
   11030  *  [8]   Predicate ::=   '[' PredicateExpr ']'
   11031  *  [9]   PredicateExpr ::=   Expr
   11032  *
   11033  * Compile a predicate expression
   11034  */
   11035 static void
   11036 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
   11037     int op1 = ctxt->comp->last;
   11038 
   11039     SKIP_BLANKS;
   11040     if (CUR != '[') {
   11041 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
   11042     }
   11043     NEXT;
   11044     SKIP_BLANKS;
   11045 
   11046     ctxt->comp->last = -1;
   11047     /*
   11048     * This call to xmlXPathCompileExpr() will deactivate sorting
   11049     * of the predicate result.
   11050     * TODO: Sorting is still activated for filters, since I'm not
   11051     *  sure if needed. Normally sorting should not be needed, since
   11052     *  a filter can only diminish the number of items in a sequence,
   11053     *  but won't change its order; so if the initial sequence is sorted,
   11054     *  subsequent sorting is not needed.
   11055     */
   11056     if (! filter)
   11057 	xmlXPathCompileExpr(ctxt, 0);
   11058     else
   11059 	xmlXPathCompileExpr(ctxt, 1);
   11060     CHECK_ERROR;
   11061 
   11062     if (CUR != ']') {
   11063 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
   11064     }
   11065 
   11066     if (filter)
   11067 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
   11068     else
   11069 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
   11070 
   11071     NEXT;
   11072     SKIP_BLANKS;
   11073 }
   11074 
   11075 /**
   11076  * xmlXPathCompNodeTest:
   11077  * @ctxt:  the XPath Parser context
   11078  * @test:  pointer to a xmlXPathTestVal
   11079  * @type:  pointer to a xmlXPathTypeVal
   11080  * @prefix:  placeholder for a possible name prefix
   11081  *
   11082  * [7] NodeTest ::=   NameTest
   11083  *		    | NodeType '(' ')'
   11084  *		    | 'processing-instruction' '(' Literal ')'
   11085  *
   11086  * [37] NameTest ::=  '*'
   11087  *		    | NCName ':' '*'
   11088  *		    | QName
   11089  * [38] NodeType ::= 'comment'
   11090  *		   | 'text'
   11091  *		   | 'processing-instruction'
   11092  *		   | 'node'
   11093  *
   11094  * Returns the name found and updates @test, @type and @prefix appropriately
   11095  */
   11096 static xmlChar *
   11097 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
   11098 	             xmlXPathTypeVal *type, const xmlChar **prefix,
   11099 		     xmlChar *name) {
   11100     int blanks;
   11101 
   11102     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
   11103 	STRANGE;
   11104 	return(NULL);
   11105     }
   11106     *type = (xmlXPathTypeVal) 0;
   11107     *test = (xmlXPathTestVal) 0;
   11108     *prefix = NULL;
   11109     SKIP_BLANKS;
   11110 
   11111     if ((name == NULL) && (CUR == '*')) {
   11112 	/*
   11113 	 * All elements
   11114 	 */
   11115 	NEXT;
   11116 	*test = NODE_TEST_ALL;
   11117 	return(NULL);
   11118     }
   11119 
   11120     if (name == NULL)
   11121 	name = xmlXPathParseNCName(ctxt);
   11122     if (name == NULL) {
   11123 	XP_ERRORNULL(XPATH_EXPR_ERROR);
   11124     }
   11125 
   11126     blanks = IS_BLANK_CH(CUR);
   11127     SKIP_BLANKS;
   11128     if (CUR == '(') {
   11129 	NEXT;
   11130 	/*
   11131 	 * NodeType or PI search
   11132 	 */
   11133 	if (xmlStrEqual(name, BAD_CAST "comment"))
   11134 	    *type = NODE_TYPE_COMMENT;
   11135 	else if (xmlStrEqual(name, BAD_CAST "node"))
   11136 	    *type = NODE_TYPE_NODE;
   11137 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
   11138 	    *type = NODE_TYPE_PI;
   11139 	else if (xmlStrEqual(name, BAD_CAST "text"))
   11140 	    *type = NODE_TYPE_TEXT;
   11141 	else {
   11142 	    if (name != NULL)
   11143 		xmlFree(name);
   11144 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
   11145 	}
   11146 
   11147 	*test = NODE_TEST_TYPE;
   11148 
   11149 	SKIP_BLANKS;
   11150 	if (*type == NODE_TYPE_PI) {
   11151 	    /*
   11152 	     * Specific case: search a PI by name.
   11153 	     */
   11154 	    if (name != NULL)
   11155 		xmlFree(name);
   11156 	    name = NULL;
   11157 	    if (CUR != ')') {
   11158 		name = xmlXPathParseLiteral(ctxt);
   11159 		CHECK_ERROR NULL;
   11160 		*test = NODE_TEST_PI;
   11161 		SKIP_BLANKS;
   11162 	    }
   11163 	}
   11164 	if (CUR != ')') {
   11165 	    if (name != NULL)
   11166 		xmlFree(name);
   11167 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
   11168 	}
   11169 	NEXT;
   11170 	return(name);
   11171     }
   11172     *test = NODE_TEST_NAME;
   11173     if ((!blanks) && (CUR == ':')) {
   11174 	NEXT;
   11175 
   11176 	/*
   11177 	 * Since currently the parser context don't have a
   11178 	 * namespace list associated:
   11179 	 * The namespace name for this prefix can be computed
   11180 	 * only at evaluation time. The compilation is done
   11181 	 * outside of any context.
   11182 	 */
   11183 #if 0
   11184 	*prefix = xmlXPathNsLookup(ctxt->context, name);
   11185 	if (name != NULL)
   11186 	    xmlFree(name);
   11187 	if (*prefix == NULL) {
   11188 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
   11189 	}
   11190 #else
   11191 	*prefix = name;
   11192 #endif
   11193 
   11194 	if (CUR == '*') {
   11195 	    /*
   11196 	     * All elements
   11197 	     */
   11198 	    NEXT;
   11199 	    *test = NODE_TEST_ALL;
   11200 	    return(NULL);
   11201 	}
   11202 
   11203 	name = xmlXPathParseNCName(ctxt);
   11204 	if (name == NULL) {
   11205 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
   11206 	}
   11207     }
   11208     return(name);
   11209 }
   11210 
   11211 /**
   11212  * xmlXPathIsAxisName:
   11213  * @name:  a preparsed name token
   11214  *
   11215  * [6] AxisName ::=   'ancestor'
   11216  *                  | 'ancestor-or-self'
   11217  *                  | 'attribute'
   11218  *                  | 'child'
   11219  *                  | 'descendant'
   11220  *                  | 'descendant-or-self'
   11221  *                  | 'following'
   11222  *                  | 'following-sibling'
   11223  *                  | 'namespace'
   11224  *                  | 'parent'
   11225  *                  | 'preceding'
   11226  *                  | 'preceding-sibling'
   11227  *                  | 'self'
   11228  *
   11229  * Returns the axis or 0
   11230  */
   11231 static xmlXPathAxisVal
   11232 xmlXPathIsAxisName(const xmlChar *name) {
   11233     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
   11234     switch (name[0]) {
   11235 	case 'a':
   11236 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
   11237 		ret = AXIS_ANCESTOR;
   11238 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
   11239 		ret = AXIS_ANCESTOR_OR_SELF;
   11240 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
   11241 		ret = AXIS_ATTRIBUTE;
   11242 	    break;
   11243 	case 'c':
   11244 	    if (xmlStrEqual(name, BAD_CAST "child"))
   11245 		ret = AXIS_CHILD;
   11246 	    break;
   11247 	case 'd':
   11248 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
   11249 		ret = AXIS_DESCENDANT;
   11250 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
   11251 		ret = AXIS_DESCENDANT_OR_SELF;
   11252 	    break;
   11253 	case 'f':
   11254 	    if (xmlStrEqual(name, BAD_CAST "following"))
   11255 		ret = AXIS_FOLLOWING;
   11256 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
   11257 		ret = AXIS_FOLLOWING_SIBLING;
   11258 	    break;
   11259 	case 'n':
   11260 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
   11261 		ret = AXIS_NAMESPACE;
   11262 	    break;
   11263 	case 'p':
   11264 	    if (xmlStrEqual(name, BAD_CAST "parent"))
   11265 		ret = AXIS_PARENT;
   11266 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
   11267 		ret = AXIS_PRECEDING;
   11268 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
   11269 		ret = AXIS_PRECEDING_SIBLING;
   11270 	    break;
   11271 	case 's':
   11272 	    if (xmlStrEqual(name, BAD_CAST "self"))
   11273 		ret = AXIS_SELF;
   11274 	    break;
   11275     }
   11276     return(ret);
   11277 }
   11278 
   11279 /**
   11280  * xmlXPathCompStep:
   11281  * @ctxt:  the XPath Parser context
   11282  *
   11283  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
   11284  *                  | AbbreviatedStep
   11285  *
   11286  * [12] AbbreviatedStep ::=   '.' | '..'
   11287  *
   11288  * [5] AxisSpecifier ::= AxisName '::'
   11289  *                  | AbbreviatedAxisSpecifier
   11290  *
   11291  * [13] AbbreviatedAxisSpecifier ::= '@'?
   11292  *
   11293  * Modified for XPtr range support as:
   11294  *
   11295  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
   11296  *                     | AbbreviatedStep
   11297  *                     | 'range-to' '(' Expr ')' Predicate*
   11298  *
   11299  * Compile one step in a Location Path
   11300  * A location step of . is short for self::node(). This is
   11301  * particularly useful in conjunction with //. For example, the
   11302  * location path .//para is short for
   11303  * self::node()/descendant-or-self::node()/child::para
   11304  * and so will select all para descendant elements of the context
   11305  * node.
   11306  * Similarly, a location step of .. is short for parent::node().
   11307  * For example, ../title is short for parent::node()/child::title
   11308  * and so will select the title children of the parent of the context
   11309  * node.
   11310  */
   11311 static void
   11312 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
   11313 #ifdef LIBXML_XPTR_ENABLED
   11314     int rangeto = 0;
   11315     int op2 = -1;
   11316 #endif
   11317 
   11318     SKIP_BLANKS;
   11319     if ((CUR == '.') && (NXT(1) == '.')) {
   11320 	SKIP(2);
   11321 	SKIP_BLANKS;
   11322 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
   11323 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11324     } else if (CUR == '.') {
   11325 	NEXT;
   11326 	SKIP_BLANKS;
   11327     } else {
   11328 	xmlChar *name = NULL;
   11329 	const xmlChar *prefix = NULL;
   11330 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
   11331 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
   11332 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
   11333 	int op1;
   11334 
   11335 	/*
   11336 	 * The modification needed for XPointer change to the production
   11337 	 */
   11338 #ifdef LIBXML_XPTR_ENABLED
   11339 	if (ctxt->xptr) {
   11340 	    name = xmlXPathParseNCName(ctxt);
   11341 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
   11342                 op2 = ctxt->comp->last;
   11343 		xmlFree(name);
   11344 		SKIP_BLANKS;
   11345 		if (CUR != '(') {
   11346 		    XP_ERROR(XPATH_EXPR_ERROR);
   11347 		}
   11348 		NEXT;
   11349 		SKIP_BLANKS;
   11350 
   11351 		xmlXPathCompileExpr(ctxt, 1);
   11352 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
   11353 		CHECK_ERROR;
   11354 
   11355 		SKIP_BLANKS;
   11356 		if (CUR != ')') {
   11357 		    XP_ERROR(XPATH_EXPR_ERROR);
   11358 		}
   11359 		NEXT;
   11360 		rangeto = 1;
   11361 		goto eval_predicates;
   11362 	    }
   11363 	}
   11364 #endif
   11365 	if (CUR == '*') {
   11366 	    axis = AXIS_CHILD;
   11367 	} else {
   11368 	    if (name == NULL)
   11369 		name = xmlXPathParseNCName(ctxt);
   11370 	    if (name != NULL) {
   11371 		axis = xmlXPathIsAxisName(name);
   11372 		if (axis != 0) {
   11373 		    SKIP_BLANKS;
   11374 		    if ((CUR == ':') && (NXT(1) == ':')) {
   11375 			SKIP(2);
   11376 			xmlFree(name);
   11377 			name = NULL;
   11378 		    } else {
   11379 			/* an element name can conflict with an axis one :-\ */
   11380 			axis = AXIS_CHILD;
   11381 		    }
   11382 		} else {
   11383 		    axis = AXIS_CHILD;
   11384 		}
   11385 	    } else if (CUR == '@') {
   11386 		NEXT;
   11387 		axis = AXIS_ATTRIBUTE;
   11388 	    } else {
   11389 		axis = AXIS_CHILD;
   11390 	    }
   11391 	}
   11392 
   11393         if (ctxt->error != XPATH_EXPRESSION_OK) {
   11394             xmlFree(name);
   11395             return;
   11396         }
   11397 
   11398 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
   11399 	if (test == 0)
   11400 	    return;
   11401 
   11402         if ((prefix != NULL) && (ctxt->context != NULL) &&
   11403 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
   11404 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
   11405 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
   11406 	    }
   11407 	}
   11408 #ifdef DEBUG_STEP
   11409 	xmlGenericError(xmlGenericErrorContext,
   11410 		"Basis : computing new set\n");
   11411 #endif
   11412 
   11413 #ifdef DEBUG_STEP
   11414 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
   11415 	if (ctxt->value == NULL)
   11416 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
   11417 	else if (ctxt->value->nodesetval == NULL)
   11418 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
   11419 	else
   11420 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
   11421 #endif
   11422 
   11423 #ifdef LIBXML_XPTR_ENABLED
   11424 eval_predicates:
   11425 #endif
   11426 	op1 = ctxt->comp->last;
   11427 	ctxt->comp->last = -1;
   11428 
   11429 	SKIP_BLANKS;
   11430 	while (CUR == '[') {
   11431 	    xmlXPathCompPredicate(ctxt, 0);
   11432 	}
   11433 
   11434 #ifdef LIBXML_XPTR_ENABLED
   11435 	if (rangeto) {
   11436 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
   11437 	} else
   11438 #endif
   11439 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
   11440 			   test, type, (void *)prefix, (void *)name);
   11441 
   11442     }
   11443 #ifdef DEBUG_STEP
   11444     xmlGenericError(xmlGenericErrorContext, "Step : ");
   11445     if (ctxt->value == NULL)
   11446 	xmlGenericError(xmlGenericErrorContext, "no value\n");
   11447     else if (ctxt->value->nodesetval == NULL)
   11448 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
   11449     else
   11450 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
   11451 		ctxt->value->nodesetval);
   11452 #endif
   11453 }
   11454 
   11455 /**
   11456  * xmlXPathCompRelativeLocationPath:
   11457  * @ctxt:  the XPath Parser context
   11458  *
   11459  *  [3]   RelativeLocationPath ::=   Step
   11460  *                     | RelativeLocationPath '/' Step
   11461  *                     | AbbreviatedRelativeLocationPath
   11462  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
   11463  *
   11464  * Compile a relative location path.
   11465  */
   11466 static void
   11467 xmlXPathCompRelativeLocationPath
   11468 (xmlXPathParserContextPtr ctxt) {
   11469     SKIP_BLANKS;
   11470     if ((CUR == '/') && (NXT(1) == '/')) {
   11471 	SKIP(2);
   11472 	SKIP_BLANKS;
   11473 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11474 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11475     } else if (CUR == '/') {
   11476 	    NEXT;
   11477 	SKIP_BLANKS;
   11478     }
   11479     xmlXPathCompStep(ctxt);
   11480     CHECK_ERROR;
   11481     SKIP_BLANKS;
   11482     while (CUR == '/') {
   11483 	if ((CUR == '/') && (NXT(1) == '/')) {
   11484 	    SKIP(2);
   11485 	    SKIP_BLANKS;
   11486 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11487 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11488 	    xmlXPathCompStep(ctxt);
   11489 	} else if (CUR == '/') {
   11490 	    NEXT;
   11491 	    SKIP_BLANKS;
   11492 	    xmlXPathCompStep(ctxt);
   11493 	}
   11494 	SKIP_BLANKS;
   11495     }
   11496 }
   11497 
   11498 /**
   11499  * xmlXPathCompLocationPath:
   11500  * @ctxt:  the XPath Parser context
   11501  *
   11502  *  [1]   LocationPath ::=   RelativeLocationPath
   11503  *                     | AbsoluteLocationPath
   11504  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
   11505  *                     | AbbreviatedAbsoluteLocationPath
   11506  *  [10]   AbbreviatedAbsoluteLocationPath ::=
   11507  *                           '//' RelativeLocationPath
   11508  *
   11509  * Compile a location path
   11510  *
   11511  * // is short for /descendant-or-self::node()/. For example,
   11512  * //para is short for /descendant-or-self::node()/child::para and
   11513  * so will select any para element in the document (even a para element
   11514  * that is a document element will be selected by //para since the
   11515  * document element node is a child of the root node); div//para is
   11516  * short for div/descendant-or-self::node()/child::para and so will
   11517  * select all para descendants of div children.
   11518  */
   11519 static void
   11520 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
   11521     SKIP_BLANKS;
   11522     if (CUR != '/') {
   11523         xmlXPathCompRelativeLocationPath(ctxt);
   11524     } else {
   11525 	while (CUR == '/') {
   11526 	    if ((CUR == '/') && (NXT(1) == '/')) {
   11527 		SKIP(2);
   11528 		SKIP_BLANKS;
   11529 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11530 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11531 		xmlXPathCompRelativeLocationPath(ctxt);
   11532 	    } else if (CUR == '/') {
   11533 		NEXT;
   11534 		SKIP_BLANKS;
   11535 		if ((CUR != 0 ) &&
   11536 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
   11537 		     (CUR == '@') || (CUR == '*')))
   11538 		    xmlXPathCompRelativeLocationPath(ctxt);
   11539 	    }
   11540 	    CHECK_ERROR;
   11541 	}
   11542     }
   11543 }
   11544 
   11545 /************************************************************************
   11546  *									*
   11547  *		XPath precompiled expression evaluation			*
   11548  *									*
   11549  ************************************************************************/
   11550 
   11551 static int
   11552 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
   11553 
   11554 #ifdef DEBUG_STEP
   11555 static void
   11556 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
   11557 			  int nbNodes)
   11558 {
   11559     xmlGenericError(xmlGenericErrorContext, "new step : ");
   11560     switch (op->value) {
   11561         case AXIS_ANCESTOR:
   11562             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
   11563             break;
   11564         case AXIS_ANCESTOR_OR_SELF:
   11565             xmlGenericError(xmlGenericErrorContext,
   11566                             "axis 'ancestors-or-self' ");
   11567             break;
   11568         case AXIS_ATTRIBUTE:
   11569             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
   11570             break;
   11571         case AXIS_CHILD:
   11572             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
   11573             break;
   11574         case AXIS_DESCENDANT:
   11575             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
   11576             break;
   11577         case AXIS_DESCENDANT_OR_SELF:
   11578             xmlGenericError(xmlGenericErrorContext,
   11579                             "axis 'descendant-or-self' ");
   11580             break;
   11581         case AXIS_FOLLOWING:
   11582             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
   11583             break;
   11584         case AXIS_FOLLOWING_SIBLING:
   11585             xmlGenericError(xmlGenericErrorContext,
   11586                             "axis 'following-siblings' ");
   11587             break;
   11588         case AXIS_NAMESPACE:
   11589             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
   11590             break;
   11591         case AXIS_PARENT:
   11592             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
   11593             break;
   11594         case AXIS_PRECEDING:
   11595             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
   11596             break;
   11597         case AXIS_PRECEDING_SIBLING:
   11598             xmlGenericError(xmlGenericErrorContext,
   11599                             "axis 'preceding-sibling' ");
   11600             break;
   11601         case AXIS_SELF:
   11602             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
   11603             break;
   11604     }
   11605     xmlGenericError(xmlGenericErrorContext,
   11606 	" context contains %d nodes\n", nbNodes);
   11607     switch (op->value2) {
   11608         case NODE_TEST_NONE:
   11609             xmlGenericError(xmlGenericErrorContext,
   11610                             "           searching for none !!!\n");
   11611             break;
   11612         case NODE_TEST_TYPE:
   11613             xmlGenericError(xmlGenericErrorContext,
   11614                             "           searching for type %d\n", op->value3);
   11615             break;
   11616         case NODE_TEST_PI:
   11617             xmlGenericError(xmlGenericErrorContext,
   11618                             "           searching for PI !!!\n");
   11619             break;
   11620         case NODE_TEST_ALL:
   11621             xmlGenericError(xmlGenericErrorContext,
   11622                             "           searching for *\n");
   11623             break;
   11624         case NODE_TEST_NS:
   11625             xmlGenericError(xmlGenericErrorContext,
   11626                             "           searching for namespace %s\n",
   11627                             op->value5);
   11628             break;
   11629         case NODE_TEST_NAME:
   11630             xmlGenericError(xmlGenericErrorContext,
   11631                             "           searching for name %s\n", op->value5);
   11632             if (op->value4)
   11633                 xmlGenericError(xmlGenericErrorContext,
   11634                                 "           with namespace %s\n", op->value4);
   11635             break;
   11636     }
   11637     xmlGenericError(xmlGenericErrorContext, "Testing : ");
   11638 }
   11639 #endif /* DEBUG_STEP */
   11640 
   11641 static int
   11642 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
   11643 			    xmlXPathStepOpPtr op,
   11644 			    xmlNodeSetPtr set,
   11645 			    int contextSize,
   11646 			    int hasNsNodes)
   11647 {
   11648     if (op->ch1 != -1) {
   11649 	xmlXPathCompExprPtr comp = ctxt->comp;
   11650 	/*
   11651 	* Process inner predicates first.
   11652 	*/
   11653 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
   11654 	    /*
   11655 	    * TODO: raise an internal error.
   11656 	    */
   11657 	}
   11658 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
   11659 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
   11660 	CHECK_ERROR0;
   11661 	if (contextSize <= 0)
   11662 	    return(0);
   11663     }
   11664     if (op->ch2 != -1) {
   11665 	xmlXPathContextPtr xpctxt = ctxt->context;
   11666 	xmlNodePtr contextNode, oldContextNode;
   11667 	xmlDocPtr oldContextDoc;
   11668 	int i, res, contextPos = 0, newContextSize;
   11669 	xmlXPathStepOpPtr exprOp;
   11670 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
   11671 
   11672 #ifdef LIBXML_XPTR_ENABLED
   11673 	/*
   11674 	* URGENT TODO: Check the following:
   11675 	*  We don't expect location sets if evaluating prediates, right?
   11676 	*  Only filters should expect location sets, right?
   11677 	*/
   11678 #endif
   11679 	/*
   11680 	* SPEC XPath 1.0:
   11681 	*  "For each node in the node-set to be filtered, the
   11682 	*  PredicateExpr is evaluated with that node as the
   11683 	*  context node, with the number of nodes in the
   11684 	*  node-set as the context size, and with the proximity
   11685 	*  position of the node in the node-set with respect to
   11686 	*  the axis as the context position;"
   11687 	* @oldset is the node-set" to be filtered.
   11688 	*
   11689 	* SPEC XPath 1.0:
   11690 	*  "only predicates change the context position and
   11691 	*  context size (see [2.4 Predicates])."
   11692 	* Example:
   11693 	*   node-set  context pos
   11694 	*    nA         1
   11695 	*    nB         2
   11696 	*    nC         3
   11697 	*   After applying predicate [position() > 1] :
   11698 	*   node-set  context pos
   11699 	*    nB         1
   11700 	*    nC         2
   11701 	*/
   11702 	oldContextNode = xpctxt->node;
   11703 	oldContextDoc = xpctxt->doc;
   11704 	/*
   11705 	* Get the expression of this predicate.
   11706 	*/
   11707 	exprOp = &ctxt->comp->steps[op->ch2];
   11708 	newContextSize = 0;
   11709 	for (i = 0; i < set->nodeNr; i++) {
   11710 	    if (set->nodeTab[i] == NULL)
   11711 		continue;
   11712 
   11713 	    contextNode = set->nodeTab[i];
   11714 	    xpctxt->node = contextNode;
   11715 	    xpctxt->contextSize = contextSize;
   11716 	    xpctxt->proximityPosition = ++contextPos;
   11717 
   11718 	    /*
   11719 	    * Also set the xpath document in case things like
   11720 	    * key() are evaluated in the predicate.
   11721 	    */
   11722 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
   11723 		(contextNode->doc != NULL))
   11724 		xpctxt->doc = contextNode->doc;
   11725 	    /*
   11726 	    * Evaluate the predicate expression with 1 context node
   11727 	    * at a time; this node is packaged into a node set; this
   11728 	    * node set is handed over to the evaluation mechanism.
   11729 	    */
   11730 	    if (contextObj == NULL)
   11731 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
   11732 	    else {
   11733 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
   11734 		    contextNode) < 0) {
   11735 		    ctxt->error = XPATH_MEMORY_ERROR;
   11736 		    goto evaluation_exit;
   11737 		}
   11738 	    }
   11739 
   11740 	    valuePush(ctxt, contextObj);
   11741 
   11742 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
   11743 
   11744 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
   11745 		xmlXPathNodeSetClear(set, hasNsNodes);
   11746 		newContextSize = 0;
   11747 		goto evaluation_exit;
   11748 	    }
   11749 
   11750 	    if (res != 0) {
   11751 		newContextSize++;
   11752 	    } else {
   11753 		/*
   11754 		* Remove the entry from the initial node set.
   11755 		*/
   11756 		set->nodeTab[i] = NULL;
   11757 		if (contextNode->type == XML_NAMESPACE_DECL)
   11758 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
   11759 	    }
   11760 	    if (ctxt->value == contextObj) {
   11761 		/*
   11762 		* Don't free the temporary XPath object holding the
   11763 		* context node, in order to avoid massive recreation
   11764 		* inside this loop.
   11765 		*/
   11766 		valuePop(ctxt);
   11767 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
   11768 	    } else {
   11769 		/*
   11770 		* TODO: The object was lost in the evaluation machinery.
   11771 		*  Can this happen? Maybe in internal-error cases.
   11772 		*/
   11773 		contextObj = NULL;
   11774 	    }
   11775 	}
   11776 
   11777 	if (contextObj != NULL) {
   11778 	    if (ctxt->value == contextObj)
   11779 		valuePop(ctxt);
   11780 	    xmlXPathReleaseObject(xpctxt, contextObj);
   11781 	}
   11782 evaluation_exit:
   11783 	if (exprRes != NULL)
   11784 	    xmlXPathReleaseObject(ctxt->context, exprRes);
   11785 	/*
   11786 	* Reset/invalidate the context.
   11787 	*/
   11788 	xpctxt->node = oldContextNode;
   11789 	xpctxt->doc = oldContextDoc;
   11790 	xpctxt->contextSize = -1;
   11791 	xpctxt->proximityPosition = -1;
   11792 	return(newContextSize);
   11793     }
   11794     return(contextSize);
   11795 }
   11796 
   11797 static int
   11798 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
   11799 				      xmlXPathStepOpPtr op,
   11800 				      xmlNodeSetPtr set,
   11801 				      int contextSize,
   11802 				      int minPos,
   11803 				      int maxPos,
   11804 				      int hasNsNodes)
   11805 {
   11806     if (op->ch1 != -1) {
   11807 	xmlXPathCompExprPtr comp = ctxt->comp;
   11808 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
   11809 	    /*
   11810 	    * TODO: raise an internal error.
   11811 	    */
   11812 	}
   11813 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
   11814 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
   11815 	CHECK_ERROR0;
   11816 	if (contextSize <= 0)
   11817 	    return(0);
   11818     }
   11819     /*
   11820     * Check if the node set contains a sufficient number of nodes for
   11821     * the requested range.
   11822     */
   11823     if (contextSize < minPos) {
   11824 	xmlXPathNodeSetClear(set, hasNsNodes);
   11825 	return(0);
   11826     }
   11827     if (op->ch2 == -1) {
   11828 	/*
   11829 	* TODO: Can this ever happen?
   11830 	*/
   11831 	return (contextSize);
   11832     } else {
   11833 	xmlDocPtr oldContextDoc;
   11834 	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
   11835 	xmlXPathStepOpPtr exprOp;
   11836 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
   11837 	xmlNodePtr oldContextNode, contextNode = NULL;
   11838 	xmlXPathContextPtr xpctxt = ctxt->context;
   11839         int frame;
   11840 
   11841 #ifdef LIBXML_XPTR_ENABLED
   11842 	    /*
   11843 	    * URGENT TODO: Check the following:
   11844 	    *  We don't expect location sets if evaluating prediates, right?
   11845 	    *  Only filters should expect location sets, right?
   11846 	*/
   11847 #endif /* LIBXML_XPTR_ENABLED */
   11848 
   11849 	/*
   11850 	* Save old context.
   11851 	*/
   11852 	oldContextNode = xpctxt->node;
   11853 	oldContextDoc = xpctxt->doc;
   11854 	/*
   11855 	* Get the expression of this predicate.
   11856 	*/
   11857 	exprOp = &ctxt->comp->steps[op->ch2];
   11858 	for (i = 0; i < set->nodeNr; i++) {
   11859             xmlXPathObjectPtr tmp;
   11860 
   11861 	    if (set->nodeTab[i] == NULL)
   11862 		continue;
   11863 
   11864 	    contextNode = set->nodeTab[i];
   11865 	    xpctxt->node = contextNode;
   11866 	    xpctxt->contextSize = contextSize;
   11867 	    xpctxt->proximityPosition = ++contextPos;
   11868 
   11869 	    /*
   11870 	    * Initialize the new set.
   11871 	    * Also set the xpath document in case things like
   11872 	    * key() evaluation are attempted on the predicate
   11873 	    */
   11874 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
   11875 		(contextNode->doc != NULL))
   11876 		xpctxt->doc = contextNode->doc;
   11877 	    /*
   11878 	    * Evaluate the predicate expression with 1 context node
   11879 	    * at a time; this node is packaged into a node set; this
   11880 	    * node set is handed over to the evaluation mechanism.
   11881 	    */
   11882 	    if (contextObj == NULL)
   11883 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
   11884 	    else {
   11885 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
   11886 		    contextNode) < 0) {
   11887 		    ctxt->error = XPATH_MEMORY_ERROR;
   11888 		    goto evaluation_exit;
   11889 		}
   11890 	    }
   11891 
   11892 	    valuePush(ctxt, contextObj);
   11893             frame = xmlXPathSetFrame(ctxt);
   11894 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
   11895             xmlXPathPopFrame(ctxt, frame);
   11896             tmp = valuePop(ctxt);
   11897 
   11898 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
   11899                 while (tmp != contextObj) {
   11900                     /*
   11901                      * Free up the result
   11902                      * then pop off contextObj, which will be freed later
   11903                      */
   11904                     xmlXPathReleaseObject(xpctxt, tmp);
   11905                     tmp = valuePop(ctxt);
   11906                 }
   11907 		goto evaluation_error;
   11908 	    }
   11909             /* push the result back onto the stack */
   11910             valuePush(ctxt, tmp);
   11911 
   11912 	    if (res)
   11913 		pos++;
   11914 
   11915 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
   11916 		/*
   11917 		* Fits in the requested range.
   11918 		*/
   11919 		newContextSize++;
   11920 		if (minPos == maxPos) {
   11921 		    /*
   11922 		    * Only 1 node was requested.
   11923 		    */
   11924 		    if (contextNode->type == XML_NAMESPACE_DECL) {
   11925 			/*
   11926 			* As always: take care of those nasty
   11927 			* namespace nodes.
   11928 			*/
   11929 			set->nodeTab[i] = NULL;
   11930 		    }
   11931 		    xmlXPathNodeSetClear(set, hasNsNodes);
   11932 		    set->nodeNr = 1;
   11933 		    set->nodeTab[0] = contextNode;
   11934 		    goto evaluation_exit;
   11935 		}
   11936 		if (pos == maxPos) {
   11937 		    /*
   11938 		    * We are done.
   11939 		    */
   11940 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
   11941 		    goto evaluation_exit;
   11942 		}
   11943 	    } else {
   11944 		/*
   11945 		* Remove the entry from the initial node set.
   11946 		*/
   11947 		set->nodeTab[i] = NULL;
   11948 		if (contextNode->type == XML_NAMESPACE_DECL)
   11949 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
   11950 	    }
   11951 	    if (exprRes != NULL) {
   11952 		xmlXPathReleaseObject(ctxt->context, exprRes);
   11953 		exprRes = NULL;
   11954 	    }
   11955 	    if (ctxt->value == contextObj) {
   11956 		/*
   11957 		* Don't free the temporary XPath object holding the
   11958 		* context node, in order to avoid massive recreation
   11959 		* inside this loop.
   11960 		*/
   11961 		valuePop(ctxt);
   11962 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
   11963 	    } else {
   11964 		/*
   11965 		* The object was lost in the evaluation machinery.
   11966 		* Can this happen? Maybe in case of internal-errors.
   11967 		*/
   11968 		contextObj = NULL;
   11969 	    }
   11970 	}
   11971 	goto evaluation_exit;
   11972 
   11973 evaluation_error:
   11974 	xmlXPathNodeSetClear(set, hasNsNodes);
   11975 	newContextSize = 0;
   11976 
   11977 evaluation_exit:
   11978 	if (contextObj != NULL) {
   11979 	    if (ctxt->value == contextObj)
   11980 		valuePop(ctxt);
   11981 	    xmlXPathReleaseObject(xpctxt, contextObj);
   11982 	}
   11983 	if (exprRes != NULL)
   11984 	    xmlXPathReleaseObject(ctxt->context, exprRes);
   11985 	/*
   11986 	* Reset/invalidate the context.
   11987 	*/
   11988 	xpctxt->node = oldContextNode;
   11989 	xpctxt->doc = oldContextDoc;
   11990 	xpctxt->contextSize = -1;
   11991 	xpctxt->proximityPosition = -1;
   11992 	return(newContextSize);
   11993     }
   11994     return(contextSize);
   11995 }
   11996 
   11997 static int
   11998 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
   11999 			    xmlXPathStepOpPtr op,
   12000 			    int *maxPos)
   12001 {
   12002 
   12003     xmlXPathStepOpPtr exprOp;
   12004 
   12005     /*
   12006     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
   12007     */
   12008 
   12009     /*
   12010     * If not -1, then ch1 will point to:
   12011     * 1) For predicates (XPATH_OP_PREDICATE):
   12012     *    - an inner predicate operator
   12013     * 2) For filters (XPATH_OP_FILTER):
   12014     *    - an inner filter operater OR
   12015     *    - an expression selecting the node set.
   12016     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
   12017     */
   12018     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
   12019 	return(0);
   12020 
   12021     if (op->ch2 != -1) {
   12022 	exprOp = &ctxt->comp->steps[op->ch2];
   12023     } else
   12024 	return(0);
   12025 
   12026     if ((exprOp != NULL) &&
   12027 	(exprOp->op == XPATH_OP_VALUE) &&
   12028 	(exprOp->value4 != NULL) &&
   12029 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
   12030     {
   12031         double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
   12032 
   12033 	/*
   12034 	* We have a "[n]" predicate here.
   12035 	* TODO: Unfortunately this simplistic test here is not
   12036 	* able to detect a position() predicate in compound
   12037 	* expressions like "[@attr = 'a" and position() = 1],
   12038 	* and even not the usage of position() in
   12039 	* "[position() = 1]"; thus - obviously - a position-range,
   12040 	* like it "[position() < 5]", is also not detected.
   12041 	* Maybe we could rewrite the AST to ease the optimization.
   12042 	*/
   12043 
   12044         if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
   12045 	    *maxPos = (int) floatval;
   12046             if (floatval == (double) *maxPos)
   12047                 return(1);
   12048         }
   12049     }
   12050     return(0);
   12051 }
   12052 
   12053 static int
   12054 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
   12055                            xmlXPathStepOpPtr op,
   12056 			   xmlNodePtr * first, xmlNodePtr * last,
   12057 			   int toBool)
   12058 {
   12059 
   12060 #define XP_TEST_HIT \
   12061     if (hasAxisRange != 0) { \
   12062 	if (++pos == maxPos) { \
   12063 	    if (addNode(seq, cur) < 0) \
   12064 	        ctxt->error = XPATH_MEMORY_ERROR; \
   12065 	    goto axis_range_end; } \
   12066     } else { \
   12067 	if (addNode(seq, cur) < 0) \
   12068 	    ctxt->error = XPATH_MEMORY_ERROR; \
   12069 	if (breakOnFirstHit) goto first_hit; }
   12070 
   12071 #define XP_TEST_HIT_NS \
   12072     if (hasAxisRange != 0) { \
   12073 	if (++pos == maxPos) { \
   12074 	    hasNsNodes = 1; \
   12075 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
   12076 	        ctxt->error = XPATH_MEMORY_ERROR; \
   12077 	goto axis_range_end; } \
   12078     } else { \
   12079 	hasNsNodes = 1; \
   12080 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
   12081 	    ctxt->error = XPATH_MEMORY_ERROR; \
   12082 	if (breakOnFirstHit) goto first_hit; }
   12083 
   12084     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
   12085     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
   12086     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
   12087     const xmlChar *prefix = op->value4;
   12088     const xmlChar *name = op->value5;
   12089     const xmlChar *URI = NULL;
   12090 
   12091 #ifdef DEBUG_STEP
   12092     int nbMatches = 0, prevMatches = 0;
   12093 #endif
   12094     int total = 0, hasNsNodes = 0;
   12095     /* The popped object holding the context nodes */
   12096     xmlXPathObjectPtr obj;
   12097     /* The set of context nodes for the node tests */
   12098     xmlNodeSetPtr contextSeq;
   12099     int contextIdx;
   12100     xmlNodePtr contextNode;
   12101     /* The final resulting node set wrt to all context nodes */
   12102     xmlNodeSetPtr outSeq;
   12103     /*
   12104     * The temporary resulting node set wrt 1 context node.
   12105     * Used to feed predicate evaluation.
   12106     */
   12107     xmlNodeSetPtr seq;
   12108     xmlNodePtr cur;
   12109     /* First predicate operator */
   12110     xmlXPathStepOpPtr predOp;
   12111     int maxPos; /* The requested position() (when a "[n]" predicate) */
   12112     int hasPredicateRange, hasAxisRange, pos, size, newSize;
   12113     int breakOnFirstHit;
   12114 
   12115     xmlXPathTraversalFunction next = NULL;
   12116     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
   12117     xmlXPathNodeSetMergeFunction mergeAndClear;
   12118     xmlNodePtr oldContextNode;
   12119     xmlXPathContextPtr xpctxt = ctxt->context;
   12120 
   12121 
   12122     CHECK_TYPE0(XPATH_NODESET);
   12123     obj = valuePop(ctxt);
   12124     /*
   12125     * Setup namespaces.
   12126     */
   12127     if (prefix != NULL) {
   12128         URI = xmlXPathNsLookup(xpctxt, prefix);
   12129         if (URI == NULL) {
   12130 	    xmlXPathReleaseObject(xpctxt, obj);
   12131             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
   12132 	}
   12133     }
   12134     /*
   12135     * Setup axis.
   12136     *
   12137     * MAYBE FUTURE TODO: merging optimizations:
   12138     * - If the nodes to be traversed wrt to the initial nodes and
   12139     *   the current axis cannot overlap, then we could avoid searching
   12140     *   for duplicates during the merge.
   12141     *   But the question is how/when to evaluate if they cannot overlap.
   12142     *   Example: if we know that for two initial nodes, the one is
   12143     *   not in the ancestor-or-self axis of the other, then we could safely
   12144     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
   12145     *   the descendant-or-self axis.
   12146     */
   12147     mergeAndClear = xmlXPathNodeSetMergeAndClear;
   12148     switch (axis) {
   12149         case AXIS_ANCESTOR:
   12150             first = NULL;
   12151             next = xmlXPathNextAncestor;
   12152             break;
   12153         case AXIS_ANCESTOR_OR_SELF:
   12154             first = NULL;
   12155             next = xmlXPathNextAncestorOrSelf;
   12156             break;
   12157         case AXIS_ATTRIBUTE:
   12158             first = NULL;
   12159 	    last = NULL;
   12160             next = xmlXPathNextAttribute;
   12161 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12162             break;
   12163         case AXIS_CHILD:
   12164 	    last = NULL;
   12165 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
   12166 		(type == NODE_TYPE_NODE))
   12167 	    {
   12168 		/*
   12169 		* Optimization if an element node type is 'element'.
   12170 		*/
   12171 		next = xmlXPathNextChildElement;
   12172 	    } else
   12173 		next = xmlXPathNextChild;
   12174 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12175             break;
   12176         case AXIS_DESCENDANT:
   12177 	    last = NULL;
   12178             next = xmlXPathNextDescendant;
   12179             break;
   12180         case AXIS_DESCENDANT_OR_SELF:
   12181 	    last = NULL;
   12182             next = xmlXPathNextDescendantOrSelf;
   12183             break;
   12184         case AXIS_FOLLOWING:
   12185 	    last = NULL;
   12186             next = xmlXPathNextFollowing;
   12187             break;
   12188         case AXIS_FOLLOWING_SIBLING:
   12189 	    last = NULL;
   12190             next = xmlXPathNextFollowingSibling;
   12191             break;
   12192         case AXIS_NAMESPACE:
   12193             first = NULL;
   12194 	    last = NULL;
   12195             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
   12196 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12197             break;
   12198         case AXIS_PARENT:
   12199             first = NULL;
   12200             next = xmlXPathNextParent;
   12201             break;
   12202         case AXIS_PRECEDING:
   12203             first = NULL;
   12204             next = xmlXPathNextPrecedingInternal;
   12205             break;
   12206         case AXIS_PRECEDING_SIBLING:
   12207             first = NULL;
   12208             next = xmlXPathNextPrecedingSibling;
   12209             break;
   12210         case AXIS_SELF:
   12211             first = NULL;
   12212 	    last = NULL;
   12213             next = xmlXPathNextSelf;
   12214 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12215             break;
   12216     }
   12217 
   12218 #ifdef DEBUG_STEP
   12219     xmlXPathDebugDumpStepAxis(op,
   12220 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
   12221 #endif
   12222 
   12223     if (next == NULL) {
   12224 	xmlXPathReleaseObject(xpctxt, obj);
   12225         return(0);
   12226     }
   12227     contextSeq = obj->nodesetval;
   12228     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
   12229 	xmlXPathReleaseObject(xpctxt, obj);
   12230         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
   12231         return(0);
   12232     }
   12233     /*
   12234     * Predicate optimization ---------------------------------------------
   12235     * If this step has a last predicate, which contains a position(),
   12236     * then we'll optimize (although not exactly "position()", but only
   12237     * the  short-hand form, i.e., "[n]".
   12238     *
   12239     * Example - expression "/foo[parent::bar][1]":
   12240     *
   12241     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
   12242     *   ROOT                               -- op->ch1
   12243     *   PREDICATE                          -- op->ch2 (predOp)
   12244     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
   12245     *       SORT
   12246     *         COLLECT  'parent' 'name' 'node' bar
   12247     *           NODE
   12248     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
   12249     *
   12250     */
   12251     maxPos = 0;
   12252     predOp = NULL;
   12253     hasPredicateRange = 0;
   12254     hasAxisRange = 0;
   12255     if (op->ch2 != -1) {
   12256 	/*
   12257 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
   12258 	*/
   12259 	predOp = &ctxt->comp->steps[op->ch2];
   12260 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
   12261 	    if (predOp->ch1 != -1) {
   12262 		/*
   12263 		* Use the next inner predicate operator.
   12264 		*/
   12265 		predOp = &ctxt->comp->steps[predOp->ch1];
   12266 		hasPredicateRange = 1;
   12267 	    } else {
   12268 		/*
   12269 		* There's no other predicate than the [n] predicate.
   12270 		*/
   12271 		predOp = NULL;
   12272 		hasAxisRange = 1;
   12273 	    }
   12274 	}
   12275     }
   12276     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
   12277     /*
   12278     * Axis traversal -----------------------------------------------------
   12279     */
   12280     /*
   12281      * 2.3 Node Tests
   12282      *  - For the attribute axis, the principal node type is attribute.
   12283      *  - For the namespace axis, the principal node type is namespace.
   12284      *  - For other axes, the principal node type is element.
   12285      *
   12286      * A node test * is true for any node of the
   12287      * principal node type. For example, child::* will
   12288      * select all element children of the context node
   12289      */
   12290     oldContextNode = xpctxt->node;
   12291     addNode = xmlXPathNodeSetAddUnique;
   12292     outSeq = NULL;
   12293     seq = NULL;
   12294     contextNode = NULL;
   12295     contextIdx = 0;
   12296 
   12297 
   12298     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
   12299            (ctxt->error == XPATH_EXPRESSION_OK)) {
   12300 	xpctxt->node = contextSeq->nodeTab[contextIdx++];
   12301 
   12302 	if (seq == NULL) {
   12303 	    seq = xmlXPathNodeSetCreate(NULL);
   12304 	    if (seq == NULL) {
   12305 		total = 0;
   12306 		goto error;
   12307 	    }
   12308 	}
   12309 	/*
   12310 	* Traverse the axis and test the nodes.
   12311 	*/
   12312 	pos = 0;
   12313 	cur = NULL;
   12314 	hasNsNodes = 0;
   12315         do {
   12316             cur = next(ctxt, cur);
   12317             if (cur == NULL)
   12318                 break;
   12319 
   12320 	    /*
   12321 	    * QUESTION TODO: What does the "first" and "last" stuff do?
   12322 	    */
   12323             if ((first != NULL) && (*first != NULL)) {
   12324 		if (*first == cur)
   12325 		    break;
   12326 		if (((total % 256) == 0) &&
   12327 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   12328 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
   12329 #else
   12330 		    (xmlXPathCmpNodes(*first, cur) >= 0))
   12331 #endif
   12332 		{
   12333 		    break;
   12334 		}
   12335 	    }
   12336 	    if ((last != NULL) && (*last != NULL)) {
   12337 		if (*last == cur)
   12338 		    break;
   12339 		if (((total % 256) == 0) &&
   12340 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   12341 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
   12342 #else
   12343 		    (xmlXPathCmpNodes(cur, *last) >= 0))
   12344 #endif
   12345 		{
   12346 		    break;
   12347 		}
   12348 	    }
   12349 
   12350             total++;
   12351 
   12352 #ifdef DEBUG_STEP
   12353             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
   12354 #endif
   12355 
   12356 	    switch (test) {
   12357                 case NODE_TEST_NONE:
   12358 		    total = 0;
   12359                     STRANGE
   12360 		    goto error;
   12361                 case NODE_TEST_TYPE:
   12362 		    if (type == NODE_TYPE_NODE) {
   12363 			switch (cur->type) {
   12364 			    case XML_DOCUMENT_NODE:
   12365 			    case XML_HTML_DOCUMENT_NODE:
   12366 #ifdef LIBXML_DOCB_ENABLED
   12367 			    case XML_DOCB_DOCUMENT_NODE:
   12368 #endif
   12369 			    case XML_ELEMENT_NODE:
   12370 			    case XML_ATTRIBUTE_NODE:
   12371 			    case XML_PI_NODE:
   12372 			    case XML_COMMENT_NODE:
   12373 			    case XML_CDATA_SECTION_NODE:
   12374 			    case XML_TEXT_NODE:
   12375 				XP_TEST_HIT
   12376 				break;
   12377 			    case XML_NAMESPACE_DECL: {
   12378 				if (axis == AXIS_NAMESPACE) {
   12379 				    XP_TEST_HIT_NS
   12380 				} else {
   12381 	                            hasNsNodes = 1;
   12382 				    XP_TEST_HIT
   12383 				}
   12384 				break;
   12385                             }
   12386 			    default:
   12387 				break;
   12388 			}
   12389 		    } else if (cur->type == (xmlElementType) type) {
   12390 			if (cur->type == XML_NAMESPACE_DECL)
   12391 			    XP_TEST_HIT_NS
   12392 			else
   12393 			    XP_TEST_HIT
   12394 		    } else if ((type == NODE_TYPE_TEXT) &&
   12395 			 (cur->type == XML_CDATA_SECTION_NODE))
   12396 		    {
   12397 			XP_TEST_HIT
   12398 		    }
   12399 		    break;
   12400                 case NODE_TEST_PI:
   12401                     if ((cur->type == XML_PI_NODE) &&
   12402                         ((name == NULL) || xmlStrEqual(name, cur->name)))
   12403 		    {
   12404 			XP_TEST_HIT
   12405                     }
   12406                     break;
   12407                 case NODE_TEST_ALL:
   12408                     if (axis == AXIS_ATTRIBUTE) {
   12409                         if (cur->type == XML_ATTRIBUTE_NODE)
   12410 			{
   12411                             if (prefix == NULL)
   12412 			    {
   12413 				XP_TEST_HIT
   12414                             } else if ((cur->ns != NULL) &&
   12415 				(xmlStrEqual(URI, cur->ns->href)))
   12416 			    {
   12417 				XP_TEST_HIT
   12418                             }
   12419                         }
   12420                     } else if (axis == AXIS_NAMESPACE) {
   12421                         if (cur->type == XML_NAMESPACE_DECL)
   12422 			{
   12423 			    XP_TEST_HIT_NS
   12424                         }
   12425                     } else {
   12426                         if (cur->type == XML_ELEMENT_NODE) {
   12427                             if (prefix == NULL)
   12428 			    {
   12429 				XP_TEST_HIT
   12430 
   12431                             } else if ((cur->ns != NULL) &&
   12432 				(xmlStrEqual(URI, cur->ns->href)))
   12433 			    {
   12434 				XP_TEST_HIT
   12435                             }
   12436                         }
   12437                     }
   12438                     break;
   12439                 case NODE_TEST_NS:{
   12440                         TODO;
   12441                         break;
   12442                     }
   12443                 case NODE_TEST_NAME:
   12444                     if (axis == AXIS_ATTRIBUTE) {
   12445                         if (cur->type != XML_ATTRIBUTE_NODE)
   12446 			    break;
   12447 		    } else if (axis == AXIS_NAMESPACE) {
   12448                         if (cur->type != XML_NAMESPACE_DECL)
   12449 			    break;
   12450 		    } else {
   12451 		        if (cur->type != XML_ELEMENT_NODE)
   12452 			    break;
   12453 		    }
   12454                     switch (cur->type) {
   12455                         case XML_ELEMENT_NODE:
   12456                             if (xmlStrEqual(name, cur->name)) {
   12457                                 if (prefix == NULL) {
   12458                                     if (cur->ns == NULL)
   12459 				    {
   12460 					XP_TEST_HIT
   12461                                     }
   12462                                 } else {
   12463                                     if ((cur->ns != NULL) &&
   12464                                         (xmlStrEqual(URI, cur->ns->href)))
   12465 				    {
   12466 					XP_TEST_HIT
   12467                                     }
   12468                                 }
   12469                             }
   12470                             break;
   12471                         case XML_ATTRIBUTE_NODE:{
   12472                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
   12473 
   12474                                 if (xmlStrEqual(name, attr->name)) {
   12475                                     if (prefix == NULL) {
   12476                                         if ((attr->ns == NULL) ||
   12477                                             (attr->ns->prefix == NULL))
   12478 					{
   12479 					    XP_TEST_HIT
   12480                                         }
   12481                                     } else {
   12482                                         if ((attr->ns != NULL) &&
   12483                                             (xmlStrEqual(URI,
   12484 					      attr->ns->href)))
   12485 					{
   12486 					    XP_TEST_HIT
   12487                                         }
   12488                                     }
   12489                                 }
   12490                                 break;
   12491                             }
   12492                         case XML_NAMESPACE_DECL:
   12493                             if (cur->type == XML_NAMESPACE_DECL) {
   12494                                 xmlNsPtr ns = (xmlNsPtr) cur;
   12495 
   12496                                 if ((ns->prefix != NULL) && (name != NULL)
   12497                                     && (xmlStrEqual(ns->prefix, name)))
   12498 				{
   12499 				    XP_TEST_HIT_NS
   12500                                 }
   12501                             }
   12502                             break;
   12503                         default:
   12504                             break;
   12505                     }
   12506                     break;
   12507 	    } /* switch(test) */
   12508         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
   12509 
   12510 	goto apply_predicates;
   12511 
   12512 axis_range_end: /* ----------------------------------------------------- */
   12513 	/*
   12514 	* We have a "/foo[n]", and position() = n was reached.
   12515 	* Note that we can have as well "/foo/::parent::foo[1]", so
   12516 	* a duplicate-aware merge is still needed.
   12517 	* Merge with the result.
   12518 	*/
   12519 	if (outSeq == NULL) {
   12520 	    outSeq = seq;
   12521 	    seq = NULL;
   12522 	} else
   12523 	    outSeq = mergeAndClear(outSeq, seq, 0);
   12524 	/*
   12525 	* Break if only a true/false result was requested.
   12526 	*/
   12527 	if (toBool)
   12528 	    break;
   12529 	continue;
   12530 
   12531 first_hit: /* ---------------------------------------------------------- */
   12532 	/*
   12533 	* Break if only a true/false result was requested and
   12534 	* no predicates existed and a node test succeeded.
   12535 	*/
   12536 	if (outSeq == NULL) {
   12537 	    outSeq = seq;
   12538 	    seq = NULL;
   12539 	} else
   12540 	    outSeq = mergeAndClear(outSeq, seq, 0);
   12541 	break;
   12542 
   12543 #ifdef DEBUG_STEP
   12544 	if (seq != NULL)
   12545 	    nbMatches += seq->nodeNr;
   12546 #endif
   12547 
   12548 apply_predicates: /* --------------------------------------------------- */
   12549         if (ctxt->error != XPATH_EXPRESSION_OK)
   12550 	    goto error;
   12551 
   12552         /*
   12553 	* Apply predicates.
   12554 	*/
   12555         if ((predOp != NULL) && (seq->nodeNr > 0)) {
   12556 	    /*
   12557 	    * E.g. when we have a "/foo[some expression][n]".
   12558 	    */
   12559 	    /*
   12560 	    * QUESTION TODO: The old predicate evaluation took into
   12561 	    *  account location-sets.
   12562 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
   12563 	    *  Do we expect such a set here?
   12564 	    *  All what I learned now from the evaluation semantics
   12565 	    *  does not indicate that a location-set will be processed
   12566 	    *  here, so this looks OK.
   12567 	    */
   12568 	    /*
   12569 	    * Iterate over all predicates, starting with the outermost
   12570 	    * predicate.
   12571 	    * TODO: Problem: we cannot execute the inner predicates first
   12572 	    *  since we cannot go back *up* the operator tree!
   12573 	    *  Options we have:
   12574 	    *  1) Use of recursive functions (like is it currently done
   12575 	    *     via xmlXPathCompOpEval())
   12576 	    *  2) Add a predicate evaluation information stack to the
   12577 	    *     context struct
   12578 	    *  3) Change the way the operators are linked; we need a
   12579 	    *     "parent" field on xmlXPathStepOp
   12580 	    *
   12581 	    * For the moment, I'll try to solve this with a recursive
   12582 	    * function: xmlXPathCompOpEvalPredicate().
   12583 	    */
   12584 	    size = seq->nodeNr;
   12585 	    if (hasPredicateRange != 0)
   12586 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
   12587 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
   12588 	    else
   12589 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
   12590 		    predOp, seq, size, hasNsNodes);
   12591 
   12592 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   12593 		total = 0;
   12594 		goto error;
   12595 	    }
   12596 	    /*
   12597 	    * Add the filtered set of nodes to the result node set.
   12598 	    */
   12599 	    if (newSize == 0) {
   12600 		/*
   12601 		* The predicates filtered all nodes out.
   12602 		*/
   12603 		xmlXPathNodeSetClear(seq, hasNsNodes);
   12604 	    } else if (seq->nodeNr > 0) {
   12605 		/*
   12606 		* Add to result set.
   12607 		*/
   12608 		if (outSeq == NULL) {
   12609 		    if (size != newSize) {
   12610 			/*
   12611 			* We need to merge and clear here, since
   12612 			* the sequence will contained NULLed entries.
   12613 			*/
   12614 			outSeq = mergeAndClear(NULL, seq, 1);
   12615 		    } else {
   12616 			outSeq = seq;
   12617 			seq = NULL;
   12618 		    }
   12619 		} else
   12620 		    outSeq = mergeAndClear(outSeq, seq,
   12621 			(size != newSize) ? 1: 0);
   12622 		/*
   12623 		* Break if only a true/false result was requested.
   12624 		*/
   12625 		if (toBool)
   12626 		    break;
   12627 	    }
   12628         } else if (seq->nodeNr > 0) {
   12629 	    /*
   12630 	    * Add to result set.
   12631 	    */
   12632 	    if (outSeq == NULL) {
   12633 		outSeq = seq;
   12634 		seq = NULL;
   12635 	    } else {
   12636 		outSeq = mergeAndClear(outSeq, seq, 0);
   12637 	    }
   12638 	}
   12639     }
   12640 
   12641 error:
   12642     if ((obj->boolval) && (obj->user != NULL)) {
   12643 	/*
   12644 	* QUESTION TODO: What does this do and why?
   12645 	* TODO: Do we have to do this also for the "error"
   12646 	* cleanup further down?
   12647 	*/
   12648 	ctxt->value->boolval = 1;
   12649 	ctxt->value->user = obj->user;
   12650 	obj->user = NULL;
   12651 	obj->boolval = 0;
   12652     }
   12653     xmlXPathReleaseObject(xpctxt, obj);
   12654 
   12655     /*
   12656     * Ensure we return at least an emtpy set.
   12657     */
   12658     if (outSeq == NULL) {
   12659 	if ((seq != NULL) && (seq->nodeNr == 0))
   12660 	    outSeq = seq;
   12661 	else
   12662 	    outSeq = xmlXPathNodeSetCreate(NULL);
   12663         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
   12664     }
   12665     if ((seq != NULL) && (seq != outSeq)) {
   12666 	 xmlXPathFreeNodeSet(seq);
   12667     }
   12668     /*
   12669     * Hand over the result. Better to push the set also in
   12670     * case of errors.
   12671     */
   12672     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
   12673     /*
   12674     * Reset the context node.
   12675     */
   12676     xpctxt->node = oldContextNode;
   12677     /*
   12678     * When traversing the namespace axis in "toBool" mode, it's
   12679     * possible that tmpNsList wasn't freed.
   12680     */
   12681     if (xpctxt->tmpNsList != NULL) {
   12682         xmlFree(xpctxt->tmpNsList);
   12683         xpctxt->tmpNsList = NULL;
   12684     }
   12685 
   12686 #ifdef DEBUG_STEP
   12687     xmlGenericError(xmlGenericErrorContext,
   12688 	"\nExamined %d nodes, found %d nodes at that step\n",
   12689 	total, nbMatches);
   12690 #endif
   12691 
   12692     return(total);
   12693 }
   12694 
   12695 static int
   12696 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
   12697 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
   12698 
   12699 /**
   12700  * xmlXPathCompOpEvalFirst:
   12701  * @ctxt:  the XPath parser context with the compiled expression
   12702  * @op:  an XPath compiled operation
   12703  * @first:  the first elem found so far
   12704  *
   12705  * Evaluate the Precompiled XPath operation searching only the first
   12706  * element in document order
   12707  *
   12708  * Returns the number of examined objects.
   12709  */
   12710 static int
   12711 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
   12712                         xmlXPathStepOpPtr op, xmlNodePtr * first)
   12713 {
   12714     int total = 0, cur;
   12715     xmlXPathCompExprPtr comp;
   12716     xmlXPathObjectPtr arg1, arg2;
   12717 
   12718     CHECK_ERROR0;
   12719     comp = ctxt->comp;
   12720     switch (op->op) {
   12721         case XPATH_OP_END:
   12722             return (0);
   12723         case XPATH_OP_UNION:
   12724             total =
   12725                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
   12726                                         first);
   12727 	    CHECK_ERROR0;
   12728             if ((ctxt->value != NULL)
   12729                 && (ctxt->value->type == XPATH_NODESET)
   12730                 && (ctxt->value->nodesetval != NULL)
   12731                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
   12732                 /*
   12733                  * limit tree traversing to first node in the result
   12734                  */
   12735 		/*
   12736 		* OPTIMIZE TODO: This implicitely sorts
   12737 		*  the result, even if not needed. E.g. if the argument
   12738 		*  of the count() function, no sorting is needed.
   12739 		* OPTIMIZE TODO: How do we know if the node-list wasn't
   12740 		*  aready sorted?
   12741 		*/
   12742 		if (ctxt->value->nodesetval->nodeNr > 1)
   12743 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12744                 *first = ctxt->value->nodesetval->nodeTab[0];
   12745             }
   12746             cur =
   12747                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
   12748                                         first);
   12749 	    CHECK_ERROR0;
   12750 
   12751             arg2 = valuePop(ctxt);
   12752             arg1 = valuePop(ctxt);
   12753             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
   12754                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
   12755 	        xmlXPathReleaseObject(ctxt->context, arg1);
   12756 	        xmlXPathReleaseObject(ctxt->context, arg2);
   12757                 XP_ERROR0(XPATH_INVALID_TYPE);
   12758             }
   12759 
   12760             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   12761                                                     arg2->nodesetval);
   12762             valuePush(ctxt, arg1);
   12763 	    xmlXPathReleaseObject(ctxt->context, arg2);
   12764             /* optimizer */
   12765 	    if (total > cur)
   12766 		xmlXPathCompSwap(op);
   12767             return (total + cur);
   12768         case XPATH_OP_ROOT:
   12769             xmlXPathRoot(ctxt);
   12770             return (0);
   12771         case XPATH_OP_NODE:
   12772             if (op->ch1 != -1)
   12773                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12774 	    CHECK_ERROR0;
   12775             if (op->ch2 != -1)
   12776                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12777 	    CHECK_ERROR0;
   12778 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   12779 		ctxt->context->node));
   12780             return (total);
   12781         case XPATH_OP_RESET:
   12782             if (op->ch1 != -1)
   12783                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12784 	    CHECK_ERROR0;
   12785             if (op->ch2 != -1)
   12786                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12787 	    CHECK_ERROR0;
   12788             ctxt->context->node = NULL;
   12789             return (total);
   12790         case XPATH_OP_COLLECT:{
   12791                 if (op->ch1 == -1)
   12792                     return (total);
   12793 
   12794                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12795 		CHECK_ERROR0;
   12796 
   12797                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
   12798                 return (total);
   12799             }
   12800         case XPATH_OP_VALUE:
   12801             valuePush(ctxt,
   12802                       xmlXPathCacheObjectCopy(ctxt->context,
   12803 			(xmlXPathObjectPtr) op->value4));
   12804             return (0);
   12805         case XPATH_OP_SORT:
   12806             if (op->ch1 != -1)
   12807                 total +=
   12808                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
   12809                                             first);
   12810 	    CHECK_ERROR0;
   12811             if ((ctxt->value != NULL)
   12812                 && (ctxt->value->type == XPATH_NODESET)
   12813                 && (ctxt->value->nodesetval != NULL)
   12814 		&& (ctxt->value->nodesetval->nodeNr > 1))
   12815                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12816             return (total);
   12817 #ifdef XP_OPTIMIZED_FILTER_FIRST
   12818 	case XPATH_OP_FILTER:
   12819                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
   12820             return (total);
   12821 #endif
   12822         default:
   12823             return (xmlXPathCompOpEval(ctxt, op));
   12824     }
   12825 }
   12826 
   12827 /**
   12828  * xmlXPathCompOpEvalLast:
   12829  * @ctxt:  the XPath parser context with the compiled expression
   12830  * @op:  an XPath compiled operation
   12831  * @last:  the last elem found so far
   12832  *
   12833  * Evaluate the Precompiled XPath operation searching only the last
   12834  * element in document order
   12835  *
   12836  * Returns the number of nodes traversed
   12837  */
   12838 static int
   12839 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
   12840                        xmlNodePtr * last)
   12841 {
   12842     int total = 0, cur;
   12843     xmlXPathCompExprPtr comp;
   12844     xmlXPathObjectPtr arg1, arg2;
   12845     xmlNodePtr bak;
   12846     xmlDocPtr bakd;
   12847     int pp;
   12848     int cs;
   12849 
   12850     CHECK_ERROR0;
   12851     comp = ctxt->comp;
   12852     switch (op->op) {
   12853         case XPATH_OP_END:
   12854             return (0);
   12855         case XPATH_OP_UNION:
   12856 	    bakd = ctxt->context->doc;
   12857 	    bak = ctxt->context->node;
   12858 	    pp = ctxt->context->proximityPosition;
   12859 	    cs = ctxt->context->contextSize;
   12860             total =
   12861                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
   12862 	    CHECK_ERROR0;
   12863             if ((ctxt->value != NULL)
   12864                 && (ctxt->value->type == XPATH_NODESET)
   12865                 && (ctxt->value->nodesetval != NULL)
   12866                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
   12867                 /*
   12868                  * limit tree traversing to first node in the result
   12869                  */
   12870 		if (ctxt->value->nodesetval->nodeNr > 1)
   12871 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12872                 *last =
   12873                     ctxt->value->nodesetval->nodeTab[ctxt->value->
   12874                                                      nodesetval->nodeNr -
   12875                                                      1];
   12876             }
   12877 	    ctxt->context->doc = bakd;
   12878 	    ctxt->context->node = bak;
   12879 	    ctxt->context->proximityPosition = pp;
   12880 	    ctxt->context->contextSize = cs;
   12881             cur =
   12882                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
   12883 	    CHECK_ERROR0;
   12884             if ((ctxt->value != NULL)
   12885                 && (ctxt->value->type == XPATH_NODESET)
   12886                 && (ctxt->value->nodesetval != NULL)
   12887                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
   12888             }
   12889 
   12890             arg2 = valuePop(ctxt);
   12891             arg1 = valuePop(ctxt);
   12892             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
   12893                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
   12894 	        xmlXPathReleaseObject(ctxt->context, arg1);
   12895 	        xmlXPathReleaseObject(ctxt->context, arg2);
   12896                 XP_ERROR0(XPATH_INVALID_TYPE);
   12897             }
   12898 
   12899             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   12900                                                     arg2->nodesetval);
   12901             valuePush(ctxt, arg1);
   12902 	    xmlXPathReleaseObject(ctxt->context, arg2);
   12903             /* optimizer */
   12904 	    if (total > cur)
   12905 		xmlXPathCompSwap(op);
   12906             return (total + cur);
   12907         case XPATH_OP_ROOT:
   12908             xmlXPathRoot(ctxt);
   12909             return (0);
   12910         case XPATH_OP_NODE:
   12911             if (op->ch1 != -1)
   12912                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12913 	    CHECK_ERROR0;
   12914             if (op->ch2 != -1)
   12915                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12916 	    CHECK_ERROR0;
   12917 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   12918 		ctxt->context->node));
   12919             return (total);
   12920         case XPATH_OP_RESET:
   12921             if (op->ch1 != -1)
   12922                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12923 	    CHECK_ERROR0;
   12924             if (op->ch2 != -1)
   12925                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12926 	    CHECK_ERROR0;
   12927             ctxt->context->node = NULL;
   12928             return (total);
   12929         case XPATH_OP_COLLECT:{
   12930                 if (op->ch1 == -1)
   12931                     return (0);
   12932 
   12933                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12934 		CHECK_ERROR0;
   12935 
   12936                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
   12937                 return (total);
   12938             }
   12939         case XPATH_OP_VALUE:
   12940             valuePush(ctxt,
   12941                       xmlXPathCacheObjectCopy(ctxt->context,
   12942 			(xmlXPathObjectPtr) op->value4));
   12943             return (0);
   12944         case XPATH_OP_SORT:
   12945             if (op->ch1 != -1)
   12946                 total +=
   12947                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
   12948                                            last);
   12949 	    CHECK_ERROR0;
   12950             if ((ctxt->value != NULL)
   12951                 && (ctxt->value->type == XPATH_NODESET)
   12952                 && (ctxt->value->nodesetval != NULL)
   12953 		&& (ctxt->value->nodesetval->nodeNr > 1))
   12954                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12955             return (total);
   12956         default:
   12957             return (xmlXPathCompOpEval(ctxt, op));
   12958     }
   12959 }
   12960 
   12961 #ifdef XP_OPTIMIZED_FILTER_FIRST
   12962 static int
   12963 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
   12964 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
   12965 {
   12966     int total = 0;
   12967     xmlXPathCompExprPtr comp;
   12968     xmlXPathObjectPtr res;
   12969     xmlXPathObjectPtr obj;
   12970     xmlNodeSetPtr oldset;
   12971     xmlNodePtr oldnode;
   12972     xmlDocPtr oldDoc;
   12973     int i;
   12974 
   12975     CHECK_ERROR0;
   12976     comp = ctxt->comp;
   12977     /*
   12978     * Optimization for ()[last()] selection i.e. the last elem
   12979     */
   12980     if ((op->ch1 != -1) && (op->ch2 != -1) &&
   12981 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   12982 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
   12983 	int f = comp->steps[op->ch2].ch1;
   12984 
   12985 	if ((f != -1) &&
   12986 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
   12987 	    (comp->steps[f].value5 == NULL) &&
   12988 	    (comp->steps[f].value == 0) &&
   12989 	    (comp->steps[f].value4 != NULL) &&
   12990 	    (xmlStrEqual
   12991 	    (comp->steps[f].value4, BAD_CAST "last"))) {
   12992 	    xmlNodePtr last = NULL;
   12993 
   12994 	    total +=
   12995 		xmlXPathCompOpEvalLast(ctxt,
   12996 		    &comp->steps[op->ch1],
   12997 		    &last);
   12998 	    CHECK_ERROR0;
   12999 	    /*
   13000 	    * The nodeset should be in document order,
   13001 	    * Keep only the last value
   13002 	    */
   13003 	    if ((ctxt->value != NULL) &&
   13004 		(ctxt->value->type == XPATH_NODESET) &&
   13005 		(ctxt->value->nodesetval != NULL) &&
   13006 		(ctxt->value->nodesetval->nodeTab != NULL) &&
   13007 		(ctxt->value->nodesetval->nodeNr > 1)) {
   13008                 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
   13009 		*first = *(ctxt->value->nodesetval->nodeTab);
   13010 	    }
   13011 	    return (total);
   13012 	}
   13013     }
   13014 
   13015     if (op->ch1 != -1)
   13016 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13017     CHECK_ERROR0;
   13018     if (op->ch2 == -1)
   13019 	return (total);
   13020     if (ctxt->value == NULL)
   13021 	return (total);
   13022 
   13023 #ifdef LIBXML_XPTR_ENABLED
   13024     oldnode = ctxt->context->node;
   13025     /*
   13026     * Hum are we filtering the result of an XPointer expression
   13027     */
   13028     if (ctxt->value->type == XPATH_LOCATIONSET) {
   13029 	xmlXPathObjectPtr tmp = NULL;
   13030 	xmlLocationSetPtr newlocset = NULL;
   13031 	xmlLocationSetPtr oldlocset;
   13032 
   13033 	/*
   13034 	* Extract the old locset, and then evaluate the result of the
   13035 	* expression for all the element in the locset. use it to grow
   13036 	* up a new locset.
   13037 	*/
   13038 	CHECK_TYPE0(XPATH_LOCATIONSET);
   13039 	obj = valuePop(ctxt);
   13040 	oldlocset = obj->user;
   13041 	ctxt->context->node = NULL;
   13042 
   13043 	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   13044 	    ctxt->context->contextSize = 0;
   13045 	    ctxt->context->proximityPosition = 0;
   13046 	    if (op->ch2 != -1)
   13047 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13048 	    res = valuePop(ctxt);
   13049 	    if (res != NULL) {
   13050 		xmlXPathReleaseObject(ctxt->context, res);
   13051 	    }
   13052 	    valuePush(ctxt, obj);
   13053 	    CHECK_ERROR0;
   13054 	    return (total);
   13055 	}
   13056 	newlocset = xmlXPtrLocationSetCreate(NULL);
   13057 
   13058 	for (i = 0; i < oldlocset->locNr; i++) {
   13059 	    /*
   13060 	    * Run the evaluation with a node list made of a
   13061 	    * single item in the nodelocset.
   13062 	    */
   13063 	    ctxt->context->node = oldlocset->locTab[i]->user;
   13064 	    ctxt->context->contextSize = oldlocset->locNr;
   13065 	    ctxt->context->proximityPosition = i + 1;
   13066 	    if (tmp == NULL) {
   13067 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13068 		    ctxt->context->node);
   13069 	    } else {
   13070 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13071 		                             ctxt->context->node) < 0) {
   13072 		    ctxt->error = XPATH_MEMORY_ERROR;
   13073 		}
   13074 	    }
   13075 	    valuePush(ctxt, tmp);
   13076 	    if (op->ch2 != -1)
   13077 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13078 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   13079 		xmlXPathFreeObject(obj);
   13080 		return(0);
   13081 	    }
   13082 	    /*
   13083 	    * The result of the evaluation need to be tested to
   13084 	    * decided whether the filter succeeded or not
   13085 	    */
   13086 	    res = valuePop(ctxt);
   13087 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13088 		xmlXPtrLocationSetAdd(newlocset,
   13089 		    xmlXPathCacheObjectCopy(ctxt->context,
   13090 			oldlocset->locTab[i]));
   13091 	    }
   13092 	    /*
   13093 	    * Cleanup
   13094 	    */
   13095 	    if (res != NULL) {
   13096 		xmlXPathReleaseObject(ctxt->context, res);
   13097 	    }
   13098 	    if (ctxt->value == tmp) {
   13099 		valuePop(ctxt);
   13100 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13101 		/*
   13102 		* REVISIT TODO: Don't create a temporary nodeset
   13103 		* for everly iteration.
   13104 		*/
   13105 		/* OLD: xmlXPathFreeObject(res); */
   13106 	    } else
   13107 		tmp = NULL;
   13108 	    ctxt->context->node = NULL;
   13109 	    /*
   13110 	    * Only put the first node in the result, then leave.
   13111 	    */
   13112 	    if (newlocset->locNr > 0) {
   13113 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
   13114 		break;
   13115 	    }
   13116 	}
   13117 	if (tmp != NULL) {
   13118 	    xmlXPathReleaseObject(ctxt->context, tmp);
   13119 	}
   13120 	/*
   13121 	* The result is used as the new evaluation locset.
   13122 	*/
   13123 	xmlXPathReleaseObject(ctxt->context, obj);
   13124 	ctxt->context->node = NULL;
   13125 	ctxt->context->contextSize = -1;
   13126 	ctxt->context->proximityPosition = -1;
   13127 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   13128 	ctxt->context->node = oldnode;
   13129 	return (total);
   13130     }
   13131 #endif /* LIBXML_XPTR_ENABLED */
   13132 
   13133     /*
   13134     * Extract the old set, and then evaluate the result of the
   13135     * expression for all the element in the set. use it to grow
   13136     * up a new set.
   13137     */
   13138     CHECK_TYPE0(XPATH_NODESET);
   13139     obj = valuePop(ctxt);
   13140     oldset = obj->nodesetval;
   13141 
   13142     oldnode = ctxt->context->node;
   13143     oldDoc = ctxt->context->doc;
   13144     ctxt->context->node = NULL;
   13145 
   13146     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
   13147 	ctxt->context->contextSize = 0;
   13148 	ctxt->context->proximityPosition = 0;
   13149 	/* QUESTION TODO: Why was this code commented out?
   13150 	    if (op->ch2 != -1)
   13151 		total +=
   13152 		    xmlXPathCompOpEval(ctxt,
   13153 			&comp->steps[op->ch2]);
   13154 	    CHECK_ERROR0;
   13155 	    res = valuePop(ctxt);
   13156 	    if (res != NULL)
   13157 		xmlXPathFreeObject(res);
   13158 	*/
   13159 	valuePush(ctxt, obj);
   13160 	ctxt->context->node = oldnode;
   13161 	CHECK_ERROR0;
   13162     } else {
   13163 	xmlNodeSetPtr newset;
   13164 	xmlXPathObjectPtr tmp = NULL;
   13165 	/*
   13166 	* Initialize the new set.
   13167 	* Also set the xpath document in case things like
   13168 	* key() evaluation are attempted on the predicate
   13169 	*/
   13170 	newset = xmlXPathNodeSetCreate(NULL);
   13171         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
   13172 
   13173 	for (i = 0; i < oldset->nodeNr; i++) {
   13174 	    /*
   13175 	    * Run the evaluation with a node list made of
   13176 	    * a single item in the nodeset.
   13177 	    */
   13178 	    ctxt->context->node = oldset->nodeTab[i];
   13179 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
   13180 		(oldset->nodeTab[i]->doc != NULL))
   13181 		ctxt->context->doc = oldset->nodeTab[i]->doc;
   13182 	    if (tmp == NULL) {
   13183 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13184 		    ctxt->context->node);
   13185 	    } else {
   13186 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13187 		                             ctxt->context->node) < 0) {
   13188 		    ctxt->error = XPATH_MEMORY_ERROR;
   13189 		}
   13190 	    }
   13191 	    valuePush(ctxt, tmp);
   13192 	    ctxt->context->contextSize = oldset->nodeNr;
   13193 	    ctxt->context->proximityPosition = i + 1;
   13194 	    if (op->ch2 != -1)
   13195 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13196 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   13197 		xmlXPathFreeNodeSet(newset);
   13198 		xmlXPathFreeObject(obj);
   13199 		return(0);
   13200 	    }
   13201 	    /*
   13202 	    * The result of the evaluation needs to be tested to
   13203 	    * decide whether the filter succeeded or not
   13204 	    */
   13205 	    res = valuePop(ctxt);
   13206 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13207 		if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
   13208 		    ctxt->error = XPATH_MEMORY_ERROR;
   13209 	    }
   13210 	    /*
   13211 	    * Cleanup
   13212 	    */
   13213 	    if (res != NULL) {
   13214 		xmlXPathReleaseObject(ctxt->context, res);
   13215 	    }
   13216 	    if (ctxt->value == tmp) {
   13217 		valuePop(ctxt);
   13218 		/*
   13219 		* Don't free the temporary nodeset
   13220 		* in order to avoid massive recreation inside this
   13221 		* loop.
   13222 		*/
   13223 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13224 	    } else
   13225 		tmp = NULL;
   13226 	    ctxt->context->node = NULL;
   13227 	    /*
   13228 	    * Only put the first node in the result, then leave.
   13229 	    */
   13230 	    if (newset->nodeNr > 0) {
   13231 		*first = *(newset->nodeTab);
   13232 		break;
   13233 	    }
   13234 	}
   13235 	if (tmp != NULL) {
   13236 	    xmlXPathReleaseObject(ctxt->context, tmp);
   13237 	}
   13238 	/*
   13239 	* The result is used as the new evaluation set.
   13240 	*/
   13241 	xmlXPathReleaseObject(ctxt->context, obj);
   13242 	ctxt->context->node = NULL;
   13243 	ctxt->context->contextSize = -1;
   13244 	ctxt->context->proximityPosition = -1;
   13245 	/* may want to move this past the '}' later */
   13246 	ctxt->context->doc = oldDoc;
   13247 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
   13248     }
   13249     ctxt->context->node = oldnode;
   13250     return(total);
   13251 }
   13252 #endif /* XP_OPTIMIZED_FILTER_FIRST */
   13253 
   13254 /**
   13255  * xmlXPathCompOpEval:
   13256  * @ctxt:  the XPath parser context with the compiled expression
   13257  * @op:  an XPath compiled operation
   13258  *
   13259  * Evaluate the Precompiled XPath operation
   13260  * Returns the number of nodes traversed
   13261  */
   13262 static int
   13263 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
   13264 {
   13265     int total = 0;
   13266     int equal, ret;
   13267     xmlXPathCompExprPtr comp;
   13268     xmlXPathObjectPtr arg1, arg2;
   13269     xmlNodePtr bak;
   13270     xmlDocPtr bakd;
   13271     int pp;
   13272     int cs;
   13273 
   13274     CHECK_ERROR0;
   13275     comp = ctxt->comp;
   13276     switch (op->op) {
   13277         case XPATH_OP_END:
   13278             return (0);
   13279         case XPATH_OP_AND:
   13280 	    bakd = ctxt->context->doc;
   13281 	    bak = ctxt->context->node;
   13282 	    pp = ctxt->context->proximityPosition;
   13283 	    cs = ctxt->context->contextSize;
   13284             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13285 	    CHECK_ERROR0;
   13286             xmlXPathBooleanFunction(ctxt, 1);
   13287             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
   13288                 return (total);
   13289             arg2 = valuePop(ctxt);
   13290 	    ctxt->context->doc = bakd;
   13291 	    ctxt->context->node = bak;
   13292 	    ctxt->context->proximityPosition = pp;
   13293 	    ctxt->context->contextSize = cs;
   13294             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13295 	    if (ctxt->error) {
   13296 		xmlXPathFreeObject(arg2);
   13297 		return(0);
   13298 	    }
   13299             xmlXPathBooleanFunction(ctxt, 1);
   13300             arg1 = valuePop(ctxt);
   13301             arg1->boolval &= arg2->boolval;
   13302             valuePush(ctxt, arg1);
   13303 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13304             return (total);
   13305         case XPATH_OP_OR:
   13306 	    bakd = ctxt->context->doc;
   13307 	    bak = ctxt->context->node;
   13308 	    pp = ctxt->context->proximityPosition;
   13309 	    cs = ctxt->context->contextSize;
   13310             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13311 	    CHECK_ERROR0;
   13312             xmlXPathBooleanFunction(ctxt, 1);
   13313             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
   13314                 return (total);
   13315             arg2 = valuePop(ctxt);
   13316 	    ctxt->context->doc = bakd;
   13317 	    ctxt->context->node = bak;
   13318 	    ctxt->context->proximityPosition = pp;
   13319 	    ctxt->context->contextSize = cs;
   13320             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13321 	    if (ctxt->error) {
   13322 		xmlXPathFreeObject(arg2);
   13323 		return(0);
   13324 	    }
   13325             xmlXPathBooleanFunction(ctxt, 1);
   13326             arg1 = valuePop(ctxt);
   13327             arg1->boolval |= arg2->boolval;
   13328             valuePush(ctxt, arg1);
   13329 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13330             return (total);
   13331         case XPATH_OP_EQUAL:
   13332 	    bakd = ctxt->context->doc;
   13333 	    bak = ctxt->context->node;
   13334 	    pp = ctxt->context->proximityPosition;
   13335 	    cs = ctxt->context->contextSize;
   13336             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13337 	    CHECK_ERROR0;
   13338 	    ctxt->context->doc = bakd;
   13339 	    ctxt->context->node = bak;
   13340 	    ctxt->context->proximityPosition = pp;
   13341 	    ctxt->context->contextSize = cs;
   13342             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13343 	    CHECK_ERROR0;
   13344 	    if (op->value)
   13345 		equal = xmlXPathEqualValues(ctxt);
   13346 	    else
   13347 		equal = xmlXPathNotEqualValues(ctxt);
   13348 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
   13349             return (total);
   13350         case XPATH_OP_CMP:
   13351 	    bakd = ctxt->context->doc;
   13352 	    bak = ctxt->context->node;
   13353 	    pp = ctxt->context->proximityPosition;
   13354 	    cs = ctxt->context->contextSize;
   13355             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13356 	    CHECK_ERROR0;
   13357 	    ctxt->context->doc = bakd;
   13358 	    ctxt->context->node = bak;
   13359 	    ctxt->context->proximityPosition = pp;
   13360 	    ctxt->context->contextSize = cs;
   13361             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13362 	    CHECK_ERROR0;
   13363             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
   13364 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
   13365             return (total);
   13366         case XPATH_OP_PLUS:
   13367 	    bakd = ctxt->context->doc;
   13368 	    bak = ctxt->context->node;
   13369 	    pp = ctxt->context->proximityPosition;
   13370 	    cs = ctxt->context->contextSize;
   13371             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13372 	    CHECK_ERROR0;
   13373             if (op->ch2 != -1) {
   13374 		ctxt->context->doc = bakd;
   13375 		ctxt->context->node = bak;
   13376 		ctxt->context->proximityPosition = pp;
   13377 		ctxt->context->contextSize = cs;
   13378                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13379 	    }
   13380 	    CHECK_ERROR0;
   13381             if (op->value == 0)
   13382                 xmlXPathSubValues(ctxt);
   13383             else if (op->value == 1)
   13384                 xmlXPathAddValues(ctxt);
   13385             else if (op->value == 2)
   13386                 xmlXPathValueFlipSign(ctxt);
   13387             else if (op->value == 3) {
   13388                 CAST_TO_NUMBER;
   13389                 CHECK_TYPE0(XPATH_NUMBER);
   13390             }
   13391             return (total);
   13392         case XPATH_OP_MULT:
   13393 	    bakd = ctxt->context->doc;
   13394 	    bak = ctxt->context->node;
   13395 	    pp = ctxt->context->proximityPosition;
   13396 	    cs = ctxt->context->contextSize;
   13397             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13398 	    CHECK_ERROR0;
   13399 	    ctxt->context->doc = bakd;
   13400 	    ctxt->context->node = bak;
   13401 	    ctxt->context->proximityPosition = pp;
   13402 	    ctxt->context->contextSize = cs;
   13403             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13404 	    CHECK_ERROR0;
   13405             if (op->value == 0)
   13406                 xmlXPathMultValues(ctxt);
   13407             else if (op->value == 1)
   13408                 xmlXPathDivValues(ctxt);
   13409             else if (op->value == 2)
   13410                 xmlXPathModValues(ctxt);
   13411             return (total);
   13412         case XPATH_OP_UNION:
   13413 	    bakd = ctxt->context->doc;
   13414 	    bak = ctxt->context->node;
   13415 	    pp = ctxt->context->proximityPosition;
   13416 	    cs = ctxt->context->contextSize;
   13417             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13418 	    CHECK_ERROR0;
   13419 	    ctxt->context->doc = bakd;
   13420 	    ctxt->context->node = bak;
   13421 	    ctxt->context->proximityPosition = pp;
   13422 	    ctxt->context->contextSize = cs;
   13423             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13424 	    CHECK_ERROR0;
   13425 
   13426             arg2 = valuePop(ctxt);
   13427             arg1 = valuePop(ctxt);
   13428             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
   13429                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
   13430 	        xmlXPathReleaseObject(ctxt->context, arg1);
   13431 	        xmlXPathReleaseObject(ctxt->context, arg2);
   13432                 XP_ERROR0(XPATH_INVALID_TYPE);
   13433             }
   13434 
   13435 	    if ((arg1->nodesetval == NULL) ||
   13436 		((arg2->nodesetval != NULL) &&
   13437 		 (arg2->nodesetval->nodeNr != 0)))
   13438 	    {
   13439 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   13440 							arg2->nodesetval);
   13441 	    }
   13442 
   13443             valuePush(ctxt, arg1);
   13444 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13445             return (total);
   13446         case XPATH_OP_ROOT:
   13447             xmlXPathRoot(ctxt);
   13448             return (total);
   13449         case XPATH_OP_NODE:
   13450             if (op->ch1 != -1)
   13451                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13452 	    CHECK_ERROR0;
   13453             if (op->ch2 != -1)
   13454                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13455 	    CHECK_ERROR0;
   13456 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   13457 		ctxt->context->node));
   13458             return (total);
   13459         case XPATH_OP_RESET:
   13460             if (op->ch1 != -1)
   13461                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13462 	    CHECK_ERROR0;
   13463             if (op->ch2 != -1)
   13464                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13465 	    CHECK_ERROR0;
   13466             ctxt->context->node = NULL;
   13467             return (total);
   13468         case XPATH_OP_COLLECT:{
   13469                 if (op->ch1 == -1)
   13470                     return (total);
   13471 
   13472                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13473 		CHECK_ERROR0;
   13474 
   13475                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
   13476                 return (total);
   13477             }
   13478         case XPATH_OP_VALUE:
   13479             valuePush(ctxt,
   13480                       xmlXPathCacheObjectCopy(ctxt->context,
   13481 			(xmlXPathObjectPtr) op->value4));
   13482             return (total);
   13483         case XPATH_OP_VARIABLE:{
   13484 		xmlXPathObjectPtr val;
   13485 
   13486                 if (op->ch1 != -1)
   13487                     total +=
   13488                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13489                 if (op->value5 == NULL) {
   13490 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
   13491 		    if (val == NULL)
   13492 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
   13493                     valuePush(ctxt, val);
   13494 		} else {
   13495                     const xmlChar *URI;
   13496 
   13497                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
   13498                     if (URI == NULL) {
   13499                         xmlGenericError(xmlGenericErrorContext,
   13500             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
   13501                                     (char *) op->value4, (char *)op->value5);
   13502                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
   13503                         return (total);
   13504                     }
   13505 		    val = xmlXPathVariableLookupNS(ctxt->context,
   13506                                                        op->value4, URI);
   13507 		    if (val == NULL)
   13508 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
   13509                     valuePush(ctxt, val);
   13510                 }
   13511                 return (total);
   13512             }
   13513         case XPATH_OP_FUNCTION:{
   13514                 xmlXPathFunction func;
   13515                 const xmlChar *oldFunc, *oldFuncURI;
   13516 		int i;
   13517                 int frame;
   13518 
   13519                 frame = xmlXPathSetFrame(ctxt);
   13520                 if (op->ch1 != -1) {
   13521                     total +=
   13522                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13523                     if (ctxt->error != XPATH_EXPRESSION_OK) {
   13524                         xmlXPathPopFrame(ctxt, frame);
   13525                         return (total);
   13526                     }
   13527                 }
   13528 		if (ctxt->valueNr < ctxt->valueFrame + op->value) {
   13529 		    xmlGenericError(xmlGenericErrorContext,
   13530 			    "xmlXPathCompOpEval: parameter error\n");
   13531 		    ctxt->error = XPATH_INVALID_OPERAND;
   13532                     xmlXPathPopFrame(ctxt, frame);
   13533 		    return (total);
   13534 		}
   13535 		for (i = 0; i < op->value; i++) {
   13536 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
   13537 			xmlGenericError(xmlGenericErrorContext,
   13538 				"xmlXPathCompOpEval: parameter error\n");
   13539 			ctxt->error = XPATH_INVALID_OPERAND;
   13540                         xmlXPathPopFrame(ctxt, frame);
   13541 			return (total);
   13542 		    }
   13543                 }
   13544                 if (op->cache != NULL)
   13545                     func = op->cache;
   13546                 else {
   13547                     const xmlChar *URI = NULL;
   13548 
   13549                     if (op->value5 == NULL)
   13550                         func =
   13551                             xmlXPathFunctionLookup(ctxt->context,
   13552                                                    op->value4);
   13553                     else {
   13554                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
   13555                         if (URI == NULL) {
   13556                             xmlGenericError(xmlGenericErrorContext,
   13557             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
   13558                                     (char *)op->value4, (char *)op->value5);
   13559                             xmlXPathPopFrame(ctxt, frame);
   13560                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
   13561                             return (total);
   13562                         }
   13563                         func = xmlXPathFunctionLookupNS(ctxt->context,
   13564                                                         op->value4, URI);
   13565                     }
   13566                     if (func == NULL) {
   13567                         xmlGenericError(xmlGenericErrorContext,
   13568                                 "xmlXPathCompOpEval: function %s not found\n",
   13569                                         (char *)op->value4);
   13570                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
   13571                     }
   13572                     op->cache = func;
   13573                     op->cacheURI = (void *) URI;
   13574                 }
   13575                 oldFunc = ctxt->context->function;
   13576                 oldFuncURI = ctxt->context->functionURI;
   13577                 ctxt->context->function = op->value4;
   13578                 ctxt->context->functionURI = op->cacheURI;
   13579                 func(ctxt, op->value);
   13580                 ctxt->context->function = oldFunc;
   13581                 ctxt->context->functionURI = oldFuncURI;
   13582                 xmlXPathPopFrame(ctxt, frame);
   13583                 return (total);
   13584             }
   13585         case XPATH_OP_ARG:
   13586 	    bakd = ctxt->context->doc;
   13587 	    bak = ctxt->context->node;
   13588 	    pp = ctxt->context->proximityPosition;
   13589 	    cs = ctxt->context->contextSize;
   13590             if (op->ch1 != -1) {
   13591                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13592                 ctxt->context->contextSize = cs;
   13593                 ctxt->context->proximityPosition = pp;
   13594                 ctxt->context->node = bak;
   13595                 ctxt->context->doc = bakd;
   13596 	        CHECK_ERROR0;
   13597             }
   13598             if (op->ch2 != -1) {
   13599                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13600                 ctxt->context->contextSize = cs;
   13601                 ctxt->context->proximityPosition = pp;
   13602                 ctxt->context->node = bak;
   13603                 ctxt->context->doc = bakd;
   13604 	        CHECK_ERROR0;
   13605 	    }
   13606             return (total);
   13607         case XPATH_OP_PREDICATE:
   13608         case XPATH_OP_FILTER:{
   13609                 xmlXPathObjectPtr res;
   13610                 xmlXPathObjectPtr obj, tmp;
   13611                 xmlNodeSetPtr newset = NULL;
   13612                 xmlNodeSetPtr oldset;
   13613                 xmlNodePtr oldnode;
   13614 		xmlDocPtr oldDoc;
   13615                 int i;
   13616 
   13617                 /*
   13618                  * Optimization for ()[1] selection i.e. the first elem
   13619                  */
   13620                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
   13621 #ifdef XP_OPTIMIZED_FILTER_FIRST
   13622 		    /*
   13623 		    * FILTER TODO: Can we assume that the inner processing
   13624 		    *  will result in an ordered list if we have an
   13625 		    *  XPATH_OP_FILTER?
   13626 		    *  What about an additional field or flag on
   13627 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
   13628 		    *  to assume anything, so it would be more robust and
   13629 		    *  easier to optimize.
   13630 		    */
   13631                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
   13632 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
   13633 #else
   13634 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   13635 #endif
   13636                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
   13637                     xmlXPathObjectPtr val;
   13638 
   13639                     val = comp->steps[op->ch2].value4;
   13640                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
   13641                         (val->floatval == 1.0)) {
   13642                         xmlNodePtr first = NULL;
   13643 
   13644                         total +=
   13645                             xmlXPathCompOpEvalFirst(ctxt,
   13646                                                     &comp->steps[op->ch1],
   13647                                                     &first);
   13648 			CHECK_ERROR0;
   13649                         /*
   13650                          * The nodeset should be in document order,
   13651                          * Keep only the first value
   13652                          */
   13653                         if ((ctxt->value != NULL) &&
   13654                             (ctxt->value->type == XPATH_NODESET) &&
   13655                             (ctxt->value->nodesetval != NULL) &&
   13656                             (ctxt->value->nodesetval->nodeNr > 1))
   13657                             xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
   13658                                                         1, 1);
   13659                         return (total);
   13660                     }
   13661                 }
   13662                 /*
   13663                  * Optimization for ()[last()] selection i.e. the last elem
   13664                  */
   13665                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
   13666                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   13667                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
   13668                     int f = comp->steps[op->ch2].ch1;
   13669 
   13670                     if ((f != -1) &&
   13671                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
   13672                         (comp->steps[f].value5 == NULL) &&
   13673                         (comp->steps[f].value == 0) &&
   13674                         (comp->steps[f].value4 != NULL) &&
   13675                         (xmlStrEqual
   13676                          (comp->steps[f].value4, BAD_CAST "last"))) {
   13677                         xmlNodePtr last = NULL;
   13678 
   13679                         total +=
   13680                             xmlXPathCompOpEvalLast(ctxt,
   13681                                                    &comp->steps[op->ch1],
   13682                                                    &last);
   13683 			CHECK_ERROR0;
   13684                         /*
   13685                          * The nodeset should be in document order,
   13686                          * Keep only the last value
   13687                          */
   13688                         if ((ctxt->value != NULL) &&
   13689                             (ctxt->value->type == XPATH_NODESET) &&
   13690                             (ctxt->value->nodesetval != NULL) &&
   13691                             (ctxt->value->nodesetval->nodeTab != NULL) &&
   13692                             (ctxt->value->nodesetval->nodeNr > 1))
   13693                             xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
   13694                         return (total);
   13695                     }
   13696                 }
   13697 		/*
   13698 		* Process inner predicates first.
   13699 		* Example "index[parent::book][1]":
   13700 		* ...
   13701 		*   PREDICATE   <-- we are here "[1]"
   13702 		*     PREDICATE <-- process "[parent::book]" first
   13703 		*       SORT
   13704 		*         COLLECT  'parent' 'name' 'node' book
   13705 		*           NODE
   13706 		*     ELEM Object is a number : 1
   13707 		*/
   13708                 if (op->ch1 != -1)
   13709                     total +=
   13710                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13711 		CHECK_ERROR0;
   13712                 if (op->ch2 == -1)
   13713                     return (total);
   13714                 if (ctxt->value == NULL)
   13715                     return (total);
   13716 
   13717                 oldnode = ctxt->context->node;
   13718 
   13719 #ifdef LIBXML_XPTR_ENABLED
   13720                 /*
   13721                  * Hum are we filtering the result of an XPointer expression
   13722                  */
   13723                 if (ctxt->value->type == XPATH_LOCATIONSET) {
   13724                     xmlLocationSetPtr newlocset = NULL;
   13725                     xmlLocationSetPtr oldlocset;
   13726 
   13727                     /*
   13728                      * Extract the old locset, and then evaluate the result of the
   13729                      * expression for all the element in the locset. use it to grow
   13730                      * up a new locset.
   13731                      */
   13732                     CHECK_TYPE0(XPATH_LOCATIONSET);
   13733                     obj = valuePop(ctxt);
   13734                     oldlocset = obj->user;
   13735                     ctxt->context->node = NULL;
   13736 
   13737                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   13738                         ctxt->context->contextSize = 0;
   13739                         ctxt->context->proximityPosition = 0;
   13740                         if (op->ch2 != -1)
   13741                             total +=
   13742                                 xmlXPathCompOpEval(ctxt,
   13743                                                    &comp->steps[op->ch2]);
   13744                         res = valuePop(ctxt);
   13745                         if (res != NULL) {
   13746 			    xmlXPathReleaseObject(ctxt->context, res);
   13747 			}
   13748                         valuePush(ctxt, obj);
   13749                         CHECK_ERROR0;
   13750                         return (total);
   13751                     }
   13752                     newlocset = xmlXPtrLocationSetCreate(NULL);
   13753 
   13754                     for (i = 0; i < oldlocset->locNr; i++) {
   13755                         /*
   13756                          * Run the evaluation with a node list made of a
   13757                          * single item in the nodelocset.
   13758                          */
   13759                         ctxt->context->node = oldlocset->locTab[i]->user;
   13760                         ctxt->context->contextSize = oldlocset->locNr;
   13761                         ctxt->context->proximityPosition = i + 1;
   13762 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13763 			    ctxt->context->node);
   13764                         valuePush(ctxt, tmp);
   13765 
   13766                         if (op->ch2 != -1)
   13767                             total +=
   13768                                 xmlXPathCompOpEval(ctxt,
   13769                                                    &comp->steps[op->ch2]);
   13770 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13771 			    xmlXPathFreeObject(obj);
   13772 			    return(0);
   13773 			}
   13774 
   13775                         /*
   13776                          * The result of the evaluation need to be tested to
   13777                          * decided whether the filter succeeded or not
   13778                          */
   13779                         res = valuePop(ctxt);
   13780                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13781                             xmlXPtrLocationSetAdd(newlocset,
   13782                                                   xmlXPathObjectCopy
   13783                                                   (oldlocset->locTab[i]));
   13784                         }
   13785 
   13786                         /*
   13787                          * Cleanup
   13788                          */
   13789                         if (res != NULL) {
   13790 			    xmlXPathReleaseObject(ctxt->context, res);
   13791 			}
   13792                         if (ctxt->value == tmp) {
   13793                             res = valuePop(ctxt);
   13794 			    xmlXPathReleaseObject(ctxt->context, res);
   13795                         }
   13796 
   13797                         ctxt->context->node = NULL;
   13798                     }
   13799 
   13800                     /*
   13801                      * The result is used as the new evaluation locset.
   13802                      */
   13803 		    xmlXPathReleaseObject(ctxt->context, obj);
   13804                     ctxt->context->node = NULL;
   13805                     ctxt->context->contextSize = -1;
   13806                     ctxt->context->proximityPosition = -1;
   13807                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   13808                     ctxt->context->node = oldnode;
   13809                     return (total);
   13810                 }
   13811 #endif /* LIBXML_XPTR_ENABLED */
   13812 
   13813                 /*
   13814                  * Extract the old set, and then evaluate the result of the
   13815                  * expression for all the element in the set. use it to grow
   13816                  * up a new set.
   13817                  */
   13818                 CHECK_TYPE0(XPATH_NODESET);
   13819                 obj = valuePop(ctxt);
   13820                 oldset = obj->nodesetval;
   13821 
   13822                 oldnode = ctxt->context->node;
   13823 		oldDoc = ctxt->context->doc;
   13824                 ctxt->context->node = NULL;
   13825 
   13826                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
   13827                     ctxt->context->contextSize = 0;
   13828                     ctxt->context->proximityPosition = 0;
   13829 /*
   13830                     if (op->ch2 != -1)
   13831                         total +=
   13832                             xmlXPathCompOpEval(ctxt,
   13833                                                &comp->steps[op->ch2]);
   13834 		    CHECK_ERROR0;
   13835                     res = valuePop(ctxt);
   13836                     if (res != NULL)
   13837                         xmlXPathFreeObject(res);
   13838 */
   13839                     valuePush(ctxt, obj);
   13840                     ctxt->context->node = oldnode;
   13841                     CHECK_ERROR0;
   13842                 } else {
   13843 		    tmp = NULL;
   13844                     /*
   13845                      * Initialize the new set.
   13846 		     * Also set the xpath document in case things like
   13847 		     * key() evaluation are attempted on the predicate
   13848                      */
   13849                     newset = xmlXPathNodeSetCreate(NULL);
   13850 		    /*
   13851 		    * SPEC XPath 1.0:
   13852 		    *  "For each node in the node-set to be filtered, the
   13853 		    *  PredicateExpr is evaluated with that node as the
   13854 		    *  context node, with the number of nodes in the
   13855 		    *  node-set as the context size, and with the proximity
   13856 		    *  position of the node in the node-set with respect to
   13857 		    *  the axis as the context position;"
   13858 		    * @oldset is the node-set" to be filtered.
   13859 		    *
   13860 		    * SPEC XPath 1.0:
   13861 		    *  "only predicates change the context position and
   13862 		    *  context size (see [2.4 Predicates])."
   13863 		    * Example:
   13864 		    *   node-set  context pos
   13865 		    *    nA         1
   13866 		    *    nB         2
   13867 		    *    nC         3
   13868 		    *   After applying predicate [position() > 1] :
   13869 		    *   node-set  context pos
   13870 		    *    nB         1
   13871 		    *    nC         2
   13872 		    *
   13873 		    * removed the first node in the node-set, then
   13874 		    * the context position of the
   13875 		    */
   13876                     for (i = 0; i < oldset->nodeNr; i++) {
   13877                         /*
   13878                          * Run the evaluation with a node list made of
   13879                          * a single item in the nodeset.
   13880                          */
   13881                         ctxt->context->node = oldset->nodeTab[i];
   13882 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
   13883 			    (oldset->nodeTab[i]->doc != NULL))
   13884 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
   13885 			if (tmp == NULL) {
   13886 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13887 				ctxt->context->node);
   13888 			} else {
   13889 			    if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13890 				               ctxt->context->node) < 0) {
   13891 				ctxt->error = XPATH_MEMORY_ERROR;
   13892 			    }
   13893 			}
   13894                         valuePush(ctxt, tmp);
   13895                         ctxt->context->contextSize = oldset->nodeNr;
   13896                         ctxt->context->proximityPosition = i + 1;
   13897 			/*
   13898 			* Evaluate the predicate against the context node.
   13899 			* Can/should we optimize position() predicates
   13900 			* here (e.g. "[1]")?
   13901 			*/
   13902                         if (op->ch2 != -1)
   13903                             total +=
   13904                                 xmlXPathCompOpEval(ctxt,
   13905                                                    &comp->steps[op->ch2]);
   13906 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13907 			    xmlXPathFreeNodeSet(newset);
   13908 			    xmlXPathFreeObject(obj);
   13909 			    return(0);
   13910 			}
   13911 
   13912                         /*
   13913                          * The result of the evaluation needs to be tested to
   13914                          * decide whether the filter succeeded or not
   13915                          */
   13916 			/*
   13917 			* OPTIMIZE TODO: Can we use
   13918 			* xmlXPathNodeSetAdd*Unique()* instead?
   13919 			*/
   13920                         res = valuePop(ctxt);
   13921                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13922                             if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
   13923 			        < 0)
   13924 				ctxt->error = XPATH_MEMORY_ERROR;
   13925                         }
   13926 
   13927                         /*
   13928                          * Cleanup
   13929                          */
   13930                         if (res != NULL) {
   13931 			    xmlXPathReleaseObject(ctxt->context, res);
   13932 			}
   13933                         if (ctxt->value == tmp) {
   13934                             valuePop(ctxt);
   13935 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13936 			    /*
   13937 			    * Don't free the temporary nodeset
   13938 			    * in order to avoid massive recreation inside this
   13939 			    * loop.
   13940 			    */
   13941                         } else
   13942 			    tmp = NULL;
   13943                         ctxt->context->node = NULL;
   13944                     }
   13945 		    if (tmp != NULL)
   13946 			xmlXPathReleaseObject(ctxt->context, tmp);
   13947                     /*
   13948                      * The result is used as the new evaluation set.
   13949                      */
   13950 		    xmlXPathReleaseObject(ctxt->context, obj);
   13951                     ctxt->context->node = NULL;
   13952                     ctxt->context->contextSize = -1;
   13953                     ctxt->context->proximityPosition = -1;
   13954 		    /* may want to move this past the '}' later */
   13955 		    ctxt->context->doc = oldDoc;
   13956 		    valuePush(ctxt,
   13957 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
   13958                 }
   13959                 ctxt->context->node = oldnode;
   13960                 return (total);
   13961             }
   13962         case XPATH_OP_SORT:
   13963             if (op->ch1 != -1)
   13964                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13965 	    CHECK_ERROR0;
   13966             if ((ctxt->value != NULL) &&
   13967                 (ctxt->value->type == XPATH_NODESET) &&
   13968                 (ctxt->value->nodesetval != NULL) &&
   13969 		(ctxt->value->nodesetval->nodeNr > 1))
   13970 	    {
   13971                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   13972 	    }
   13973             return (total);
   13974 #ifdef LIBXML_XPTR_ENABLED
   13975         case XPATH_OP_RANGETO:{
   13976                 xmlXPathObjectPtr range;
   13977                 xmlXPathObjectPtr res, obj;
   13978                 xmlXPathObjectPtr tmp;
   13979                 xmlLocationSetPtr newlocset = NULL;
   13980 		    xmlLocationSetPtr oldlocset;
   13981                 xmlNodeSetPtr oldset;
   13982                 int i, j;
   13983 
   13984                 if (op->ch1 != -1) {
   13985                     total +=
   13986                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13987                     CHECK_ERROR0;
   13988                 }
   13989                 if (ctxt->value == NULL) {
   13990                     XP_ERROR0(XPATH_INVALID_OPERAND);
   13991                 }
   13992                 if (op->ch2 == -1)
   13993                     return (total);
   13994 
   13995                 if (ctxt->value->type == XPATH_LOCATIONSET) {
   13996                     /*
   13997                      * Extract the old locset, and then evaluate the result of the
   13998                      * expression for all the element in the locset. use it to grow
   13999                      * up a new locset.
   14000                      */
   14001                     CHECK_TYPE0(XPATH_LOCATIONSET);
   14002                     obj = valuePop(ctxt);
   14003                     oldlocset = obj->user;
   14004 
   14005                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
   14006 		        ctxt->context->node = NULL;
   14007                         ctxt->context->contextSize = 0;
   14008                         ctxt->context->proximityPosition = 0;
   14009                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
   14010                         res = valuePop(ctxt);
   14011                         if (res != NULL) {
   14012 			    xmlXPathReleaseObject(ctxt->context, res);
   14013 			}
   14014                         valuePush(ctxt, obj);
   14015                         CHECK_ERROR0;
   14016                         return (total);
   14017                     }
   14018                     newlocset = xmlXPtrLocationSetCreate(NULL);
   14019 
   14020                     for (i = 0; i < oldlocset->locNr; i++) {
   14021                         /*
   14022                          * Run the evaluation with a node list made of a
   14023                          * single item in the nodelocset.
   14024                          */
   14025                         ctxt->context->node = oldlocset->locTab[i]->user;
   14026                         ctxt->context->contextSize = oldlocset->locNr;
   14027                         ctxt->context->proximityPosition = i + 1;
   14028 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   14029 			    ctxt->context->node);
   14030                         valuePush(ctxt, tmp);
   14031 
   14032                         if (op->ch2 != -1)
   14033                             total +=
   14034                                 xmlXPathCompOpEval(ctxt,
   14035                                                    &comp->steps[op->ch2]);
   14036 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   14037 			    xmlXPathFreeObject(obj);
   14038 			    return(0);
   14039 			}
   14040 
   14041                         res = valuePop(ctxt);
   14042 			if (res->type == XPATH_LOCATIONSET) {
   14043 			    xmlLocationSetPtr rloc =
   14044 			        (xmlLocationSetPtr)res->user;
   14045 			    for (j=0; j<rloc->locNr; j++) {
   14046 			        range = xmlXPtrNewRange(
   14047 				  oldlocset->locTab[i]->user,
   14048 				  oldlocset->locTab[i]->index,
   14049 				  rloc->locTab[j]->user2,
   14050 				  rloc->locTab[j]->index2);
   14051 				if (range != NULL) {
   14052 				    xmlXPtrLocationSetAdd(newlocset, range);
   14053 				}
   14054 			    }
   14055 			} else {
   14056 			    range = xmlXPtrNewRangeNodeObject(
   14057 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
   14058                             if (range != NULL) {
   14059                                 xmlXPtrLocationSetAdd(newlocset,range);
   14060 			    }
   14061                         }
   14062 
   14063                         /*
   14064                          * Cleanup
   14065                          */
   14066                         if (res != NULL) {
   14067 			    xmlXPathReleaseObject(ctxt->context, res);
   14068 			}
   14069                         if (ctxt->value == tmp) {
   14070                             res = valuePop(ctxt);
   14071 			    xmlXPathReleaseObject(ctxt->context, res);
   14072                         }
   14073 
   14074                         ctxt->context->node = NULL;
   14075                     }
   14076 		} else {	/* Not a location set */
   14077                     CHECK_TYPE0(XPATH_NODESET);
   14078                     obj = valuePop(ctxt);
   14079                     oldset = obj->nodesetval;
   14080                     ctxt->context->node = NULL;
   14081 
   14082                     newlocset = xmlXPtrLocationSetCreate(NULL);
   14083 
   14084                     if (oldset != NULL) {
   14085                         for (i = 0; i < oldset->nodeNr; i++) {
   14086                             /*
   14087                              * Run the evaluation with a node list made of a single item
   14088                              * in the nodeset.
   14089                              */
   14090                             ctxt->context->node = oldset->nodeTab[i];
   14091 			    /*
   14092 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
   14093 			    */
   14094 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   14095 				ctxt->context->node);
   14096                             valuePush(ctxt, tmp);
   14097 
   14098                             if (op->ch2 != -1)
   14099                                 total +=
   14100                                     xmlXPathCompOpEval(ctxt,
   14101                                                    &comp->steps[op->ch2]);
   14102 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
   14103 				xmlXPathFreeObject(obj);
   14104 				return(0);
   14105 			    }
   14106 
   14107                             res = valuePop(ctxt);
   14108                             range =
   14109                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
   14110                                                       res);
   14111                             if (range != NULL) {
   14112                                 xmlXPtrLocationSetAdd(newlocset, range);
   14113                             }
   14114 
   14115                             /*
   14116                              * Cleanup
   14117                              */
   14118                             if (res != NULL) {
   14119 				xmlXPathReleaseObject(ctxt->context, res);
   14120 			    }
   14121                             if (ctxt->value == tmp) {
   14122                                 res = valuePop(ctxt);
   14123 				xmlXPathReleaseObject(ctxt->context, res);
   14124                             }
   14125 
   14126                             ctxt->context->node = NULL;
   14127                         }
   14128                     }
   14129                 }
   14130 
   14131                 /*
   14132                  * The result is used as the new evaluation set.
   14133                  */
   14134 		xmlXPathReleaseObject(ctxt->context, obj);
   14135                 ctxt->context->node = NULL;
   14136                 ctxt->context->contextSize = -1;
   14137                 ctxt->context->proximityPosition = -1;
   14138                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   14139                 return (total);
   14140             }
   14141 #endif /* LIBXML_XPTR_ENABLED */
   14142     }
   14143     xmlGenericError(xmlGenericErrorContext,
   14144                     "XPath: unknown precompiled operation %d\n", op->op);
   14145     ctxt->error = XPATH_INVALID_OPERAND;
   14146     return (total);
   14147 }
   14148 
   14149 /**
   14150  * xmlXPathCompOpEvalToBoolean:
   14151  * @ctxt:  the XPath parser context
   14152  *
   14153  * Evaluates if the expression evaluates to true.
   14154  *
   14155  * Returns 1 if true, 0 if false and -1 on API or internal errors.
   14156  */
   14157 static int
   14158 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
   14159 			    xmlXPathStepOpPtr op,
   14160 			    int isPredicate)
   14161 {
   14162     xmlXPathObjectPtr resObj = NULL;
   14163 
   14164 start:
   14165     /* comp = ctxt->comp; */
   14166     switch (op->op) {
   14167         case XPATH_OP_END:
   14168             return (0);
   14169 	case XPATH_OP_VALUE:
   14170 	    resObj = (xmlXPathObjectPtr) op->value4;
   14171 	    if (isPredicate)
   14172 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
   14173 	    return(xmlXPathCastToBoolean(resObj));
   14174 	case XPATH_OP_SORT:
   14175 	    /*
   14176 	    * We don't need sorting for boolean results. Skip this one.
   14177 	    */
   14178             if (op->ch1 != -1) {
   14179 		op = &ctxt->comp->steps[op->ch1];
   14180 		goto start;
   14181 	    }
   14182 	    return(0);
   14183 	case XPATH_OP_COLLECT:
   14184 	    if (op->ch1 == -1)
   14185 		return(0);
   14186 
   14187             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
   14188 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14189 		return(-1);
   14190 
   14191             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
   14192 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14193 		return(-1);
   14194 
   14195 	    resObj = valuePop(ctxt);
   14196 	    if (resObj == NULL)
   14197 		return(-1);
   14198 	    break;
   14199 	default:
   14200 	    /*
   14201 	    * Fallback to call xmlXPathCompOpEval().
   14202 	    */
   14203 	    xmlXPathCompOpEval(ctxt, op);
   14204 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14205 		return(-1);
   14206 
   14207 	    resObj = valuePop(ctxt);
   14208 	    if (resObj == NULL)
   14209 		return(-1);
   14210 	    break;
   14211     }
   14212 
   14213     if (resObj) {
   14214 	int res;
   14215 
   14216 	if (resObj->type == XPATH_BOOLEAN) {
   14217 	    res = resObj->boolval;
   14218 	} else if (isPredicate) {
   14219 	    /*
   14220 	    * For predicates a result of type "number" is handled
   14221 	    * differently:
   14222 	    * SPEC XPath 1.0:
   14223 	    * "If the result is a number, the result will be converted
   14224 	    *  to true if the number is equal to the context position
   14225 	    *  and will be converted to false otherwise;"
   14226 	    */
   14227 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
   14228 	} else {
   14229 	    res = xmlXPathCastToBoolean(resObj);
   14230 	}
   14231 	xmlXPathReleaseObject(ctxt->context, resObj);
   14232 	return(res);
   14233     }
   14234 
   14235     return(0);
   14236 }
   14237 
   14238 #ifdef XPATH_STREAMING
   14239 /**
   14240  * xmlXPathRunStreamEval:
   14241  * @ctxt:  the XPath parser context with the compiled expression
   14242  *
   14243  * Evaluate the Precompiled Streamable XPath expression in the given context.
   14244  */
   14245 static int
   14246 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
   14247 		      xmlXPathObjectPtr *resultSeq, int toBool)
   14248 {
   14249     int max_depth, min_depth;
   14250     int from_root;
   14251     int ret, depth;
   14252     int eval_all_nodes;
   14253     xmlNodePtr cur = NULL, limit = NULL;
   14254     xmlStreamCtxtPtr patstream = NULL;
   14255 
   14256     int nb_nodes = 0;
   14257 
   14258     if ((ctxt == NULL) || (comp == NULL))
   14259         return(-1);
   14260     max_depth = xmlPatternMaxDepth(comp);
   14261     if (max_depth == -1)
   14262         return(-1);
   14263     if (max_depth == -2)
   14264         max_depth = 10000;
   14265     min_depth = xmlPatternMinDepth(comp);
   14266     if (min_depth == -1)
   14267         return(-1);
   14268     from_root = xmlPatternFromRoot(comp);
   14269     if (from_root < 0)
   14270         return(-1);
   14271 #if 0
   14272     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
   14273 #endif
   14274 
   14275     if (! toBool) {
   14276 	if (resultSeq == NULL)
   14277 	    return(-1);
   14278 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
   14279 	if (*resultSeq == NULL)
   14280 	    return(-1);
   14281     }
   14282 
   14283     /*
   14284      * handle the special cases of "/" amd "." being matched
   14285      */
   14286     if (min_depth == 0) {
   14287 	if (from_root) {
   14288 	    /* Select "/" */
   14289 	    if (toBool)
   14290 		return(1);
   14291 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
   14292 		                     (xmlNodePtr) ctxt->doc);
   14293 	} else {
   14294 	    /* Select "self::node()" */
   14295 	    if (toBool)
   14296 		return(1);
   14297 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
   14298 	}
   14299     }
   14300     if (max_depth == 0) {
   14301 	return(0);
   14302     }
   14303 
   14304     if (from_root) {
   14305         cur = (xmlNodePtr)ctxt->doc;
   14306     } else if (ctxt->node != NULL) {
   14307         switch (ctxt->node->type) {
   14308             case XML_ELEMENT_NODE:
   14309             case XML_DOCUMENT_NODE:
   14310             case XML_DOCUMENT_FRAG_NODE:
   14311             case XML_HTML_DOCUMENT_NODE:
   14312 #ifdef LIBXML_DOCB_ENABLED
   14313             case XML_DOCB_DOCUMENT_NODE:
   14314 #endif
   14315 	        cur = ctxt->node;
   14316 		break;
   14317             case XML_ATTRIBUTE_NODE:
   14318             case XML_TEXT_NODE:
   14319             case XML_CDATA_SECTION_NODE:
   14320             case XML_ENTITY_REF_NODE:
   14321             case XML_ENTITY_NODE:
   14322             case XML_PI_NODE:
   14323             case XML_COMMENT_NODE:
   14324             case XML_NOTATION_NODE:
   14325             case XML_DTD_NODE:
   14326             case XML_DOCUMENT_TYPE_NODE:
   14327             case XML_ELEMENT_DECL:
   14328             case XML_ATTRIBUTE_DECL:
   14329             case XML_ENTITY_DECL:
   14330             case XML_NAMESPACE_DECL:
   14331             case XML_XINCLUDE_START:
   14332             case XML_XINCLUDE_END:
   14333 		break;
   14334 	}
   14335 	limit = cur;
   14336     }
   14337     if (cur == NULL) {
   14338         return(0);
   14339     }
   14340 
   14341     patstream = xmlPatternGetStreamCtxt(comp);
   14342     if (patstream == NULL) {
   14343 	/*
   14344 	* QUESTION TODO: Is this an error?
   14345 	*/
   14346 	return(0);
   14347     }
   14348 
   14349     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
   14350 
   14351     if (from_root) {
   14352 	ret = xmlStreamPush(patstream, NULL, NULL);
   14353 	if (ret < 0) {
   14354 	} else if (ret == 1) {
   14355 	    if (toBool)
   14356 		goto return_1;
   14357 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
   14358 	}
   14359     }
   14360     depth = 0;
   14361     goto scan_children;
   14362 next_node:
   14363     do {
   14364         nb_nodes++;
   14365 
   14366 	switch (cur->type) {
   14367 	    case XML_ELEMENT_NODE:
   14368 	    case XML_TEXT_NODE:
   14369 	    case XML_CDATA_SECTION_NODE:
   14370 	    case XML_COMMENT_NODE:
   14371 	    case XML_PI_NODE:
   14372 		if (cur->type == XML_ELEMENT_NODE) {
   14373 		    ret = xmlStreamPush(patstream, cur->name,
   14374 				(cur->ns ? cur->ns->href : NULL));
   14375 		} else if (eval_all_nodes)
   14376 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
   14377 		else
   14378 		    break;
   14379 
   14380 		if (ret < 0) {
   14381 		    /* NOP. */
   14382 		} else if (ret == 1) {
   14383 		    if (toBool)
   14384 			goto return_1;
   14385 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
   14386 		        < 0) {
   14387 			ctxt->lastError.domain = XML_FROM_XPATH;
   14388 			ctxt->lastError.code = XML_ERR_NO_MEMORY;
   14389 		    }
   14390 		}
   14391 		if ((cur->children == NULL) || (depth >= max_depth)) {
   14392 		    ret = xmlStreamPop(patstream);
   14393 		    while (cur->next != NULL) {
   14394 			cur = cur->next;
   14395 			if ((cur->type != XML_ENTITY_DECL) &&
   14396 			    (cur->type != XML_DTD_NODE))
   14397 			    goto next_node;
   14398 		    }
   14399 		}
   14400 	    default:
   14401 		break;
   14402 	}
   14403 
   14404 scan_children:
   14405 	if (cur->type == XML_NAMESPACE_DECL) break;
   14406 	if ((cur->children != NULL) && (depth < max_depth)) {
   14407 	    /*
   14408 	     * Do not descend on entities declarations
   14409 	     */
   14410 	    if (cur->children->type != XML_ENTITY_DECL) {
   14411 		cur = cur->children;
   14412 		depth++;
   14413 		/*
   14414 		 * Skip DTDs
   14415 		 */
   14416 		if (cur->type != XML_DTD_NODE)
   14417 		    continue;
   14418 	    }
   14419 	}
   14420 
   14421 	if (cur == limit)
   14422 	    break;
   14423 
   14424 	while (cur->next != NULL) {
   14425 	    cur = cur->next;
   14426 	    if ((cur->type != XML_ENTITY_DECL) &&
   14427 		(cur->type != XML_DTD_NODE))
   14428 		goto next_node;
   14429 	}
   14430 
   14431 	do {
   14432 	    cur = cur->parent;
   14433 	    depth--;
   14434 	    if ((cur == NULL) || (cur == limit))
   14435 	        goto done;
   14436 	    if (cur->type == XML_ELEMENT_NODE) {
   14437 		ret = xmlStreamPop(patstream);
   14438 	    } else if ((eval_all_nodes) &&
   14439 		((cur->type == XML_TEXT_NODE) ||
   14440 		 (cur->type == XML_CDATA_SECTION_NODE) ||
   14441 		 (cur->type == XML_COMMENT_NODE) ||
   14442 		 (cur->type == XML_PI_NODE)))
   14443 	    {
   14444 		ret = xmlStreamPop(patstream);
   14445 	    }
   14446 	    if (cur->next != NULL) {
   14447 		cur = cur->next;
   14448 		break;
   14449 	    }
   14450 	} while (cur != NULL);
   14451 
   14452     } while ((cur != NULL) && (depth >= 0));
   14453 
   14454 done:
   14455 
   14456 #if 0
   14457     printf("stream eval: checked %d nodes selected %d\n",
   14458            nb_nodes, retObj->nodesetval->nodeNr);
   14459 #endif
   14460 
   14461     if (patstream)
   14462 	xmlFreeStreamCtxt(patstream);
   14463     return(0);
   14464 
   14465 return_1:
   14466     if (patstream)
   14467 	xmlFreeStreamCtxt(patstream);
   14468     return(1);
   14469 }
   14470 #endif /* XPATH_STREAMING */
   14471 
   14472 /**
   14473  * xmlXPathRunEval:
   14474  * @ctxt:  the XPath parser context with the compiled expression
   14475  * @toBool:  evaluate to a boolean result
   14476  *
   14477  * Evaluate the Precompiled XPath expression in the given context.
   14478  */
   14479 static int
   14480 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
   14481 {
   14482     xmlXPathCompExprPtr comp;
   14483 
   14484     if ((ctxt == NULL) || (ctxt->comp == NULL))
   14485 	return(-1);
   14486 
   14487     if (ctxt->valueTab == NULL) {
   14488 	/* Allocate the value stack */
   14489 	ctxt->valueTab = (xmlXPathObjectPtr *)
   14490 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
   14491 	if (ctxt->valueTab == NULL) {
   14492 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
   14493 	    xmlFree(ctxt);
   14494 	}
   14495 	ctxt->valueNr = 0;
   14496 	ctxt->valueMax = 10;
   14497 	ctxt->value = NULL;
   14498         ctxt->valueFrame = 0;
   14499     }
   14500 #ifdef XPATH_STREAMING
   14501     if (ctxt->comp->stream) {
   14502 	int res;
   14503 
   14504 	if (toBool) {
   14505 	    /*
   14506 	    * Evaluation to boolean result.
   14507 	    */
   14508 	    res = xmlXPathRunStreamEval(ctxt->context,
   14509 		ctxt->comp->stream, NULL, 1);
   14510 	    if (res != -1)
   14511 		return(res);
   14512 	} else {
   14513 	    xmlXPathObjectPtr resObj = NULL;
   14514 
   14515 	    /*
   14516 	    * Evaluation to a sequence.
   14517 	    */
   14518 	    res = xmlXPathRunStreamEval(ctxt->context,
   14519 		ctxt->comp->stream, &resObj, 0);
   14520 
   14521 	    if ((res != -1) && (resObj != NULL)) {
   14522 		valuePush(ctxt, resObj);
   14523 		return(0);
   14524 	    }
   14525 	    if (resObj != NULL)
   14526 		xmlXPathReleaseObject(ctxt->context, resObj);
   14527 	}
   14528 	/*
   14529 	* QUESTION TODO: This falls back to normal XPath evaluation
   14530 	* if res == -1. Is this intended?
   14531 	*/
   14532     }
   14533 #endif
   14534     comp = ctxt->comp;
   14535     if (comp->last < 0) {
   14536 	xmlGenericError(xmlGenericErrorContext,
   14537 	    "xmlXPathRunEval: last is less than zero\n");
   14538 	return(-1);
   14539     }
   14540     if (toBool)
   14541 	return(xmlXPathCompOpEvalToBoolean(ctxt,
   14542 	    &comp->steps[comp->last], 0));
   14543     else
   14544 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
   14545 
   14546     return(0);
   14547 }
   14548 
   14549 /************************************************************************
   14550  *									*
   14551  *			Public interfaces				*
   14552  *									*
   14553  ************************************************************************/
   14554 
   14555 /**
   14556  * xmlXPathEvalPredicate:
   14557  * @ctxt:  the XPath context
   14558  * @res:  the Predicate Expression evaluation result
   14559  *
   14560  * Evaluate a predicate result for the current node.
   14561  * A PredicateExpr is evaluated by evaluating the Expr and converting
   14562  * the result to a boolean. If the result is a number, the result will
   14563  * be converted to true if the number is equal to the position of the
   14564  * context node in the context node list (as returned by the position
   14565  * function) and will be converted to false otherwise; if the result
   14566  * is not a number, then the result will be converted as if by a call
   14567  * to the boolean function.
   14568  *
   14569  * Returns 1 if predicate is true, 0 otherwise
   14570  */
   14571 int
   14572 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
   14573     if ((ctxt == NULL) || (res == NULL)) return(0);
   14574     switch (res->type) {
   14575         case XPATH_BOOLEAN:
   14576 	    return(res->boolval);
   14577         case XPATH_NUMBER:
   14578 	    return(res->floatval == ctxt->proximityPosition);
   14579         case XPATH_NODESET:
   14580         case XPATH_XSLT_TREE:
   14581 	    if (res->nodesetval == NULL)
   14582 		return(0);
   14583 	    return(res->nodesetval->nodeNr != 0);
   14584         case XPATH_STRING:
   14585 	    return((res->stringval != NULL) &&
   14586 	           (xmlStrlen(res->stringval) != 0));
   14587         default:
   14588 	    STRANGE
   14589     }
   14590     return(0);
   14591 }
   14592 
   14593 /**
   14594  * xmlXPathEvaluatePredicateResult:
   14595  * @ctxt:  the XPath Parser context
   14596  * @res:  the Predicate Expression evaluation result
   14597  *
   14598  * Evaluate a predicate result for the current node.
   14599  * A PredicateExpr is evaluated by evaluating the Expr and converting
   14600  * the result to a boolean. If the result is a number, the result will
   14601  * be converted to true if the number is equal to the position of the
   14602  * context node in the context node list (as returned by the position
   14603  * function) and will be converted to false otherwise; if the result
   14604  * is not a number, then the result will be converted as if by a call
   14605  * to the boolean function.
   14606  *
   14607  * Returns 1 if predicate is true, 0 otherwise
   14608  */
   14609 int
   14610 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
   14611                                 xmlXPathObjectPtr res) {
   14612     if ((ctxt == NULL) || (res == NULL)) return(0);
   14613     switch (res->type) {
   14614         case XPATH_BOOLEAN:
   14615 	    return(res->boolval);
   14616         case XPATH_NUMBER:
   14617 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
   14618 	    return((res->floatval == ctxt->context->proximityPosition) &&
   14619 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
   14620 #else
   14621 	    return(res->floatval == ctxt->context->proximityPosition);
   14622 #endif
   14623         case XPATH_NODESET:
   14624         case XPATH_XSLT_TREE:
   14625 	    if (res->nodesetval == NULL)
   14626 		return(0);
   14627 	    return(res->nodesetval->nodeNr != 0);
   14628         case XPATH_STRING:
   14629 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
   14630 #ifdef LIBXML_XPTR_ENABLED
   14631 	case XPATH_LOCATIONSET:{
   14632 	    xmlLocationSetPtr ptr = res->user;
   14633 	    if (ptr == NULL)
   14634 	        return(0);
   14635 	    return (ptr->locNr != 0);
   14636 	    }
   14637 #endif
   14638         default:
   14639 	    STRANGE
   14640     }
   14641     return(0);
   14642 }
   14643 
   14644 #ifdef XPATH_STREAMING
   14645 /**
   14646  * xmlXPathTryStreamCompile:
   14647  * @ctxt: an XPath context
   14648  * @str:  the XPath expression
   14649  *
   14650  * Try to compile the XPath expression as a streamable subset.
   14651  *
   14652  * Returns the compiled expression or NULL if failed to compile.
   14653  */
   14654 static xmlXPathCompExprPtr
   14655 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
   14656     /*
   14657      * Optimization: use streaming patterns when the XPath expression can
   14658      * be compiled to a stream lookup
   14659      */
   14660     xmlPatternPtr stream;
   14661     xmlXPathCompExprPtr comp;
   14662     xmlDictPtr dict = NULL;
   14663     const xmlChar **namespaces = NULL;
   14664     xmlNsPtr ns;
   14665     int i, j;
   14666 
   14667     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
   14668         (!xmlStrchr(str, '@'))) {
   14669 	const xmlChar *tmp;
   14670 
   14671 	/*
   14672 	 * We don't try to handle expressions using the verbose axis
   14673 	 * specifiers ("::"), just the simplied form at this point.
   14674 	 * Additionally, if there is no list of namespaces available and
   14675 	 *  there's a ":" in the expression, indicating a prefixed QName,
   14676 	 *  then we won't try to compile either. xmlPatterncompile() needs
   14677 	 *  to have a list of namespaces at compilation time in order to
   14678 	 *  compile prefixed name tests.
   14679 	 */
   14680 	tmp = xmlStrchr(str, ':');
   14681 	if ((tmp != NULL) &&
   14682 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
   14683 	    return(NULL);
   14684 
   14685 	if (ctxt != NULL) {
   14686 	    dict = ctxt->dict;
   14687 	    if (ctxt->nsNr > 0) {
   14688 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
   14689 		if (namespaces == NULL) {
   14690 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
   14691 		    return(NULL);
   14692 		}
   14693 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
   14694 		    ns = ctxt->namespaces[j];
   14695 		    namespaces[i++] = ns->href;
   14696 		    namespaces[i++] = ns->prefix;
   14697 		}
   14698 		namespaces[i++] = NULL;
   14699 		namespaces[i] = NULL;
   14700 	    }
   14701 	}
   14702 
   14703 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
   14704 			&namespaces[0]);
   14705 	if (namespaces != NULL) {
   14706 	    xmlFree((xmlChar **)namespaces);
   14707 	}
   14708 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
   14709 	    comp = xmlXPathNewCompExpr();
   14710 	    if (comp == NULL) {
   14711 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
   14712 		return(NULL);
   14713 	    }
   14714 	    comp->stream = stream;
   14715 	    comp->dict = dict;
   14716 	    if (comp->dict)
   14717 		xmlDictReference(comp->dict);
   14718 	    return(comp);
   14719 	}
   14720 	xmlFreePattern(stream);
   14721     }
   14722     return(NULL);
   14723 }
   14724 #endif /* XPATH_STREAMING */
   14725 
   14726 static void
   14727 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
   14728 {
   14729     /*
   14730     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
   14731     * internal representation.
   14732     */
   14733 
   14734     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
   14735         (op->ch1 != -1) &&
   14736         (op->ch2 == -1 /* no predicate */))
   14737     {
   14738         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
   14739 
   14740         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
   14741             ((xmlXPathAxisVal) prevop->value ==
   14742                 AXIS_DESCENDANT_OR_SELF) &&
   14743             (prevop->ch2 == -1) &&
   14744             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
   14745             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
   14746         {
   14747             /*
   14748             * This is a "descendant-or-self::node()" without predicates.
   14749             * Try to eliminate it.
   14750             */
   14751 
   14752             switch ((xmlXPathAxisVal) op->value) {
   14753                 case AXIS_CHILD:
   14754                 case AXIS_DESCENDANT:
   14755                     /*
   14756                     * Convert "descendant-or-self::node()/child::" or
   14757                     * "descendant-or-self::node()/descendant::" to
   14758                     * "descendant::"
   14759                     */
   14760                     op->ch1   = prevop->ch1;
   14761                     op->value = AXIS_DESCENDANT;
   14762                     break;
   14763                 case AXIS_SELF:
   14764                 case AXIS_DESCENDANT_OR_SELF:
   14765                     /*
   14766                     * Convert "descendant-or-self::node()/self::" or
   14767                     * "descendant-or-self::node()/descendant-or-self::" to
   14768                     * to "descendant-or-self::"
   14769                     */
   14770                     op->ch1   = prevop->ch1;
   14771                     op->value = AXIS_DESCENDANT_OR_SELF;
   14772                     break;
   14773                 default:
   14774                     break;
   14775             }
   14776 	}
   14777     }
   14778 
   14779     /* OP_VALUE has invalid ch1. */
   14780     if (op->op == XPATH_OP_VALUE)
   14781         return;
   14782 
   14783     /* Recurse */
   14784     if (op->ch1 != -1)
   14785         xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
   14786     if (op->ch2 != -1)
   14787 	xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
   14788 }
   14789 
   14790 /**
   14791  * xmlXPathCtxtCompile:
   14792  * @ctxt: an XPath context
   14793  * @str:  the XPath expression
   14794  *
   14795  * Compile an XPath expression
   14796  *
   14797  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
   14798  *         the caller has to free the object.
   14799  */
   14800 xmlXPathCompExprPtr
   14801 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
   14802     xmlXPathParserContextPtr pctxt;
   14803     xmlXPathCompExprPtr comp;
   14804 
   14805 #ifdef XPATH_STREAMING
   14806     comp = xmlXPathTryStreamCompile(ctxt, str);
   14807     if (comp != NULL)
   14808         return(comp);
   14809 #endif
   14810 
   14811     xmlXPathInit();
   14812 
   14813     pctxt = xmlXPathNewParserContext(str, ctxt);
   14814     if (pctxt == NULL)
   14815         return NULL;
   14816     xmlXPathCompileExpr(pctxt, 1);
   14817 
   14818     if( pctxt->error != XPATH_EXPRESSION_OK )
   14819     {
   14820         xmlXPathFreeParserContext(pctxt);
   14821         return(NULL);
   14822     }
   14823 
   14824     if (*pctxt->cur != 0) {
   14825 	/*
   14826 	 * aleksey: in some cases this line prints *second* error message
   14827 	 * (see bug #78858) and probably this should be fixed.
   14828 	 * However, we are not sure that all error messages are printed
   14829 	 * out in other places. It's not critical so we leave it as-is for now
   14830 	 */
   14831 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   14832 	comp = NULL;
   14833     } else {
   14834 	comp = pctxt->comp;
   14835 	pctxt->comp = NULL;
   14836     }
   14837     xmlXPathFreeParserContext(pctxt);
   14838 
   14839     if (comp != NULL) {
   14840 	comp->expr = xmlStrdup(str);
   14841 #ifdef DEBUG_EVAL_COUNTS
   14842 	comp->string = xmlStrdup(str);
   14843 	comp->nb = 0;
   14844 #endif
   14845 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
   14846 	    xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
   14847 	}
   14848     }
   14849     return(comp);
   14850 }
   14851 
   14852 /**
   14853  * xmlXPathCompile:
   14854  * @str:  the XPath expression
   14855  *
   14856  * Compile an XPath expression
   14857  *
   14858  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
   14859  *         the caller has to free the object.
   14860  */
   14861 xmlXPathCompExprPtr
   14862 xmlXPathCompile(const xmlChar *str) {
   14863     return(xmlXPathCtxtCompile(NULL, str));
   14864 }
   14865 
   14866 /**
   14867  * xmlXPathCompiledEvalInternal:
   14868  * @comp:  the compiled XPath expression
   14869  * @ctxt:  the XPath context
   14870  * @resObj: the resulting XPath object or NULL
   14871  * @toBool: 1 if only a boolean result is requested
   14872  *
   14873  * Evaluate the Precompiled XPath expression in the given context.
   14874  * The caller has to free @resObj.
   14875  *
   14876  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14877  *         the caller has to free the object.
   14878  */
   14879 static int
   14880 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
   14881 			     xmlXPathContextPtr ctxt,
   14882 			     xmlXPathObjectPtr *resObjPtr,
   14883 			     int toBool)
   14884 {
   14885     xmlXPathParserContextPtr pctxt;
   14886     xmlXPathObjectPtr resObj;
   14887 #ifndef LIBXML_THREAD_ENABLED
   14888     static int reentance = 0;
   14889 #endif
   14890     int res;
   14891 
   14892     CHECK_CTXT_NEG(ctxt)
   14893 
   14894     if (comp == NULL)
   14895 	return(-1);
   14896     xmlXPathInit();
   14897 
   14898 #ifndef LIBXML_THREAD_ENABLED
   14899     reentance++;
   14900     if (reentance > 1)
   14901 	xmlXPathDisableOptimizer = 1;
   14902 #endif
   14903 
   14904 #ifdef DEBUG_EVAL_COUNTS
   14905     comp->nb++;
   14906     if ((comp->string != NULL) && (comp->nb > 100)) {
   14907 	fprintf(stderr, "100 x %s\n", comp->string);
   14908 	comp->nb = 0;
   14909     }
   14910 #endif
   14911     pctxt = xmlXPathCompParserContext(comp, ctxt);
   14912     res = xmlXPathRunEval(pctxt, toBool);
   14913 
   14914     if (pctxt->error != XPATH_EXPRESSION_OK) {
   14915         resObj = NULL;
   14916     } else {
   14917         resObj = valuePop(pctxt);
   14918         if (resObj == NULL) {
   14919             if (!toBool)
   14920                 xmlGenericError(xmlGenericErrorContext,
   14921                     "xmlXPathCompiledEval: No result on the stack.\n");
   14922         } else if (pctxt->valueNr > 0) {
   14923             xmlGenericError(xmlGenericErrorContext,
   14924                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
   14925                 pctxt->valueNr);
   14926         }
   14927     }
   14928 
   14929     if (resObjPtr)
   14930         *resObjPtr = resObj;
   14931     else
   14932         xmlXPathReleaseObject(ctxt, resObj);
   14933 
   14934     pctxt->comp = NULL;
   14935     xmlXPathFreeParserContext(pctxt);
   14936 #ifndef LIBXML_THREAD_ENABLED
   14937     reentance--;
   14938 #endif
   14939 
   14940     return(res);
   14941 }
   14942 
   14943 /**
   14944  * xmlXPathCompiledEval:
   14945  * @comp:  the compiled XPath expression
   14946  * @ctx:  the XPath context
   14947  *
   14948  * Evaluate the Precompiled XPath expression in the given context.
   14949  *
   14950  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14951  *         the caller has to free the object.
   14952  */
   14953 xmlXPathObjectPtr
   14954 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
   14955 {
   14956     xmlXPathObjectPtr res = NULL;
   14957 
   14958     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
   14959     return(res);
   14960 }
   14961 
   14962 /**
   14963  * xmlXPathCompiledEvalToBoolean:
   14964  * @comp:  the compiled XPath expression
   14965  * @ctxt:  the XPath context
   14966  *
   14967  * Applies the XPath boolean() function on the result of the given
   14968  * compiled expression.
   14969  *
   14970  * Returns 1 if the expression evaluated to true, 0 if to false and
   14971  *         -1 in API and internal errors.
   14972  */
   14973 int
   14974 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
   14975 			      xmlXPathContextPtr ctxt)
   14976 {
   14977     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
   14978 }
   14979 
   14980 /**
   14981  * xmlXPathEvalExpr:
   14982  * @ctxt:  the XPath Parser context
   14983  *
   14984  * Parse and evaluate an XPath expression in the given context,
   14985  * then push the result on the context stack
   14986  */
   14987 void
   14988 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
   14989 #ifdef XPATH_STREAMING
   14990     xmlXPathCompExprPtr comp;
   14991 #endif
   14992 
   14993     if (ctxt == NULL) return;
   14994 
   14995 #ifdef XPATH_STREAMING
   14996     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
   14997     if (comp != NULL) {
   14998         if (ctxt->comp != NULL)
   14999 	    xmlXPathFreeCompExpr(ctxt->comp);
   15000         ctxt->comp = comp;
   15001     } else
   15002 #endif
   15003     {
   15004 	xmlXPathCompileExpr(ctxt, 1);
   15005         CHECK_ERROR;
   15006 
   15007         /* Check for trailing characters. */
   15008         if (*ctxt->cur != 0)
   15009             XP_ERROR(XPATH_EXPR_ERROR);
   15010 
   15011 	if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
   15012 	    xmlXPathOptimizeExpression(ctxt->comp,
   15013 		&ctxt->comp->steps[ctxt->comp->last]);
   15014     }
   15015 
   15016     xmlXPathRunEval(ctxt, 0);
   15017 }
   15018 
   15019 /**
   15020  * xmlXPathEval:
   15021  * @str:  the XPath expression
   15022  * @ctx:  the XPath context
   15023  *
   15024  * Evaluate the XPath Location Path in the given context.
   15025  *
   15026  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   15027  *         the caller has to free the object.
   15028  */
   15029 xmlXPathObjectPtr
   15030 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
   15031     xmlXPathParserContextPtr ctxt;
   15032     xmlXPathObjectPtr res;
   15033 
   15034     CHECK_CTXT(ctx)
   15035 
   15036     xmlXPathInit();
   15037 
   15038     ctxt = xmlXPathNewParserContext(str, ctx);
   15039     if (ctxt == NULL)
   15040         return NULL;
   15041     xmlXPathEvalExpr(ctxt);
   15042 
   15043     if (ctxt->error != XPATH_EXPRESSION_OK) {
   15044 	res = NULL;
   15045     } else {
   15046 	res = valuePop(ctxt);
   15047         if (res == NULL) {
   15048             xmlGenericError(xmlGenericErrorContext,
   15049                 "xmlXPathCompiledEval: No result on the stack.\n");
   15050         } else if (ctxt->valueNr > 0) {
   15051             xmlGenericError(xmlGenericErrorContext,
   15052                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
   15053                 ctxt->valueNr);
   15054         }
   15055     }
   15056 
   15057     xmlXPathFreeParserContext(ctxt);
   15058     return(res);
   15059 }
   15060 
   15061 /**
   15062  * xmlXPathSetContextNode:
   15063  * @node: the node to to use as the context node
   15064  * @ctx:  the XPath context
   15065  *
   15066  * Sets 'node' as the context node. The node must be in the same
   15067  * document as that associated with the context.
   15068  *
   15069  * Returns -1 in case of error or 0 if successful
   15070  */
   15071 int
   15072 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
   15073     if ((node == NULL) || (ctx == NULL))
   15074         return(-1);
   15075 
   15076     if (node->doc == ctx->doc) {
   15077         ctx->node = node;
   15078 	return(0);
   15079     }
   15080     return(-1);
   15081 }
   15082 
   15083 /**
   15084  * xmlXPathNodeEval:
   15085  * @node: the node to to use as the context node
   15086  * @str:  the XPath expression
   15087  * @ctx:  the XPath context
   15088  *
   15089  * Evaluate the XPath Location Path in the given context. The node 'node'
   15090  * is set as the context node. The context node is not restored.
   15091  *
   15092  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   15093  *         the caller has to free the object.
   15094  */
   15095 xmlXPathObjectPtr
   15096 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
   15097     if (str == NULL)
   15098         return(NULL);
   15099     if (xmlXPathSetContextNode(node, ctx) < 0)
   15100         return(NULL);
   15101     return(xmlXPathEval(str, ctx));
   15102 }
   15103 
   15104 /**
   15105  * xmlXPathEvalExpression:
   15106  * @str:  the XPath expression
   15107  * @ctxt:  the XPath context
   15108  *
   15109  * Alias for xmlXPathEval().
   15110  *
   15111  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   15112  *         the caller has to free the object.
   15113  */
   15114 xmlXPathObjectPtr
   15115 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
   15116     return(xmlXPathEval(str, ctxt));
   15117 }
   15118 
   15119 /************************************************************************
   15120  *									*
   15121  *	Extra functions not pertaining to the XPath spec		*
   15122  *									*
   15123  ************************************************************************/
   15124 /**
   15125  * xmlXPathEscapeUriFunction:
   15126  * @ctxt:  the XPath Parser context
   15127  * @nargs:  the number of arguments
   15128  *
   15129  * Implement the escape-uri() XPath function
   15130  *    string escape-uri(string $str, bool $escape-reserved)
   15131  *
   15132  * This function applies the URI escaping rules defined in section 2 of [RFC
   15133  * 2396] to the string supplied as $uri-part, which typically represents all
   15134  * or part of a URI. The effect of the function is to replace any special
   15135  * character in the string by an escape sequence of the form %xx%yy...,
   15136  * where xxyy... is the hexadecimal representation of the octets used to
   15137  * represent the character in UTF-8.
   15138  *
   15139  * The set of characters that are escaped depends on the setting of the
   15140  * boolean argument $escape-reserved.
   15141  *
   15142  * If $escape-reserved is true, all characters are escaped other than lower
   15143  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
   15144  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
   15145  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
   15146  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
   15147  * A-F).
   15148  *
   15149  * If $escape-reserved is false, the behavior differs in that characters
   15150  * referred to in [RFC 2396] as reserved characters are not escaped. These
   15151  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
   15152  *
   15153  * [RFC 2396] does not define whether escaped URIs should use lower case or
   15154  * upper case for hexadecimal digits. To ensure that escaped URIs can be
   15155  * compared using string comparison functions, this function must always use
   15156  * the upper-case letters A-F.
   15157  *
   15158  * Generally, $escape-reserved should be set to true when escaping a string
   15159  * that is to form a single part of a URI, and to false when escaping an
   15160  * entire URI or URI reference.
   15161  *
   15162  * In the case of non-ascii characters, the string is encoded according to
   15163  * utf-8 and then converted according to RFC 2396.
   15164  *
   15165  * Examples
   15166  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
   15167  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
   15168  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
   15169  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
   15170  *
   15171  */
   15172 static void
   15173 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   15174     xmlXPathObjectPtr str;
   15175     int escape_reserved;
   15176     xmlBufPtr target;
   15177     xmlChar *cptr;
   15178     xmlChar escape[4];
   15179 
   15180     CHECK_ARITY(2);
   15181 
   15182     escape_reserved = xmlXPathPopBoolean(ctxt);
   15183 
   15184     CAST_TO_STRING;
   15185     str = valuePop(ctxt);
   15186 
   15187     target = xmlBufCreate();
   15188 
   15189     escape[0] = '%';
   15190     escape[3] = 0;
   15191 
   15192     if (target) {
   15193 	for (cptr = str->stringval; *cptr; cptr++) {
   15194 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
   15195 		(*cptr >= 'a' && *cptr <= 'z') ||
   15196 		(*cptr >= '0' && *cptr <= '9') ||
   15197 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
   15198 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
   15199 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
   15200 		(*cptr == '%' &&
   15201 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
   15202 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
   15203 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
   15204 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
   15205 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
   15206 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
   15207 		(!escape_reserved &&
   15208 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
   15209 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
   15210 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
   15211 		  *cptr == ','))) {
   15212 		xmlBufAdd(target, cptr, 1);
   15213 	    } else {
   15214 		if ((*cptr >> 4) < 10)
   15215 		    escape[1] = '0' + (*cptr >> 4);
   15216 		else
   15217 		    escape[1] = 'A' - 10 + (*cptr >> 4);
   15218 		if ((*cptr & 0xF) < 10)
   15219 		    escape[2] = '0' + (*cptr & 0xF);
   15220 		else
   15221 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
   15222 
   15223 		xmlBufAdd(target, &escape[0], 3);
   15224 	    }
   15225 	}
   15226     }
   15227     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   15228 	xmlBufContent(target)));
   15229     xmlBufFree(target);
   15230     xmlXPathReleaseObject(ctxt->context, str);
   15231 }
   15232 
   15233 /**
   15234  * xmlXPathRegisterAllFunctions:
   15235  * @ctxt:  the XPath context
   15236  *
   15237  * Registers all default XPath functions in this context
   15238  */
   15239 void
   15240 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
   15241 {
   15242     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
   15243                          xmlXPathBooleanFunction);
   15244     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
   15245                          xmlXPathCeilingFunction);
   15246     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
   15247                          xmlXPathCountFunction);
   15248     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
   15249                          xmlXPathConcatFunction);
   15250     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
   15251                          xmlXPathContainsFunction);
   15252     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
   15253                          xmlXPathIdFunction);
   15254     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
   15255                          xmlXPathFalseFunction);
   15256     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
   15257                          xmlXPathFloorFunction);
   15258     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
   15259                          xmlXPathLastFunction);
   15260     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
   15261                          xmlXPathLangFunction);
   15262     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
   15263                          xmlXPathLocalNameFunction);
   15264     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
   15265                          xmlXPathNotFunction);
   15266     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
   15267                          xmlXPathNameFunction);
   15268     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
   15269                          xmlXPathNamespaceURIFunction);
   15270     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
   15271                          xmlXPathNormalizeFunction);
   15272     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
   15273                          xmlXPathNumberFunction);
   15274     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
   15275                          xmlXPathPositionFunction);
   15276     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
   15277                          xmlXPathRoundFunction);
   15278     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
   15279                          xmlXPathStringFunction);
   15280     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
   15281                          xmlXPathStringLengthFunction);
   15282     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
   15283                          xmlXPathStartsWithFunction);
   15284     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
   15285                          xmlXPathSubstringFunction);
   15286     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
   15287                          xmlXPathSubstringBeforeFunction);
   15288     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
   15289                          xmlXPathSubstringAfterFunction);
   15290     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
   15291                          xmlXPathSumFunction);
   15292     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
   15293                          xmlXPathTrueFunction);
   15294     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
   15295                          xmlXPathTranslateFunction);
   15296 
   15297     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
   15298 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
   15299                          xmlXPathEscapeUriFunction);
   15300 }
   15301 
   15302 #endif /* LIBXML_XPATH_ENABLED */
   15303 #define bottom_xpath
   15304 #include "elfgcchack.h"
   15305