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  *
      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 INFINITY
    481 #define INFINITY (DBL_MAX * DBL_MAX)
    482 #endif
    483 
    484 #ifndef NAN
    485 #define NAN (INFINITY / INFINITY)
    486 #endif
    487 
    488 double xmlXPathNAN;
    489 double xmlXPathPINF;
    490 double xmlXPathNINF;
    491 
    492 /**
    493  * xmlXPathInit:
    494  *
    495  * Initialize the XPath environment
    496  */
    497 void
    498 xmlXPathInit(void) {
    499     xmlXPathNAN = NAN;
    500     xmlXPathPINF = INFINITY;
    501     xmlXPathNINF = -INFINITY;
    502 }
    503 
    504 /**
    505  * xmlXPathIsNaN:
    506  * @val:  a double value
    507  *
    508  * Returns 1 if the value is a NaN, 0 otherwise
    509  */
    510 int
    511 xmlXPathIsNaN(double val) {
    512 #ifdef isnan
    513     return isnan(val);
    514 #else
    515     return !(val == val);
    516 #endif
    517 }
    518 
    519 /**
    520  * xmlXPathIsInf:
    521  * @val:  a double value
    522  *
    523  * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
    524  */
    525 int
    526 xmlXPathIsInf(double val) {
    527 #ifdef isinf
    528     return isinf(val) ? (val > 0 ? 1 : -1) : 0;
    529 #else
    530     if (val >= INFINITY)
    531         return 1;
    532     if (val <= -INFINITY)
    533         return -1;
    534     return 0;
    535 #endif
    536 }
    537 
    538 #endif /* SCHEMAS or XPATH */
    539 
    540 #ifdef LIBXML_XPATH_ENABLED
    541 
    542 /*
    543  * TODO: when compatibility allows remove all "fake node libxslt" strings
    544  *       the test should just be name[0] = ' '
    545  */
    546 #ifdef DEBUG_XPATH_EXPRESSION
    547 #define DEBUG_STEP
    548 #define DEBUG_EXPR
    549 #define DEBUG_EVAL_COUNTS
    550 #endif
    551 
    552 static xmlNs xmlXPathXMLNamespaceStruct = {
    553     NULL,
    554     XML_NAMESPACE_DECL,
    555     XML_XML_NAMESPACE,
    556     BAD_CAST "xml",
    557     NULL,
    558     NULL
    559 };
    560 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
    561 #ifndef LIBXML_THREAD_ENABLED
    562 /*
    563  * Optimizer is disabled only when threaded apps are detected while
    564  * the library ain't compiled for thread safety.
    565  */
    566 static int xmlXPathDisableOptimizer = 0;
    567 #endif
    568 
    569 /************************************************************************
    570  *									*
    571  *			Error handling routines				*
    572  *									*
    573  ************************************************************************/
    574 
    575 /**
    576  * XP_ERRORNULL:
    577  * @X:  the error code
    578  *
    579  * Macro to raise an XPath error and return NULL.
    580  */
    581 #define XP_ERRORNULL(X)							\
    582     { xmlXPathErr(ctxt, X); return(NULL); }
    583 
    584 /*
    585  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
    586  */
    587 static const char *xmlXPathErrorMessages[] = {
    588     "Ok\n",
    589     "Number encoding\n",
    590     "Unfinished literal\n",
    591     "Start of literal\n",
    592     "Expected $ for variable reference\n",
    593     "Undefined variable\n",
    594     "Invalid predicate\n",
    595     "Invalid expression\n",
    596     "Missing closing curly brace\n",
    597     "Unregistered function\n",
    598     "Invalid operand\n",
    599     "Invalid type\n",
    600     "Invalid number of arguments\n",
    601     "Invalid context size\n",
    602     "Invalid context position\n",
    603     "Memory allocation error\n",
    604     "Syntax error\n",
    605     "Resource error\n",
    606     "Sub resource error\n",
    607     "Undefined namespace prefix\n",
    608     "Encoding error\n",
    609     "Char out of XML range\n",
    610     "Invalid or incomplete context\n",
    611     "Stack usage error\n",
    612     "Forbidden variable\n",
    613     "?? Unknown error ??\n"	/* Must be last in the list! */
    614 };
    615 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
    616 		   sizeof(xmlXPathErrorMessages[0])) - 1)
    617 /**
    618  * xmlXPathErrMemory:
    619  * @ctxt:  an XPath context
    620  * @extra:  extra informations
    621  *
    622  * Handle a redefinition of attribute error
    623  */
    624 static void
    625 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
    626 {
    627     if (ctxt != NULL) {
    628         if (extra) {
    629             xmlChar buf[200];
    630 
    631             xmlStrPrintf(buf, 200,
    632                          "Memory allocation failed : %s\n",
    633                          extra);
    634             ctxt->lastError.message = (char *) xmlStrdup(buf);
    635         } else {
    636             ctxt->lastError.message = (char *)
    637 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
    638         }
    639         ctxt->lastError.domain = XML_FROM_XPATH;
    640         ctxt->lastError.code = XML_ERR_NO_MEMORY;
    641 	if (ctxt->error != NULL)
    642 	    ctxt->error(ctxt->userData, &ctxt->lastError);
    643     } else {
    644         if (extra)
    645             __xmlRaiseError(NULL, NULL, NULL,
    646                             NULL, NULL, XML_FROM_XPATH,
    647                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
    648                             extra, NULL, NULL, 0, 0,
    649                             "Memory allocation failed : %s\n", extra);
    650         else
    651             __xmlRaiseError(NULL, NULL, NULL,
    652                             NULL, NULL, XML_FROM_XPATH,
    653                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
    654                             NULL, NULL, NULL, 0, 0,
    655                             "Memory allocation failed\n");
    656     }
    657 }
    658 
    659 /**
    660  * xmlXPathPErrMemory:
    661  * @ctxt:  an XPath parser context
    662  * @extra:  extra informations
    663  *
    664  * Handle a redefinition of attribute error
    665  */
    666 static void
    667 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
    668 {
    669     if (ctxt == NULL)
    670 	xmlXPathErrMemory(NULL, extra);
    671     else {
    672 	ctxt->error = XPATH_MEMORY_ERROR;
    673 	xmlXPathErrMemory(ctxt->context, extra);
    674     }
    675 }
    676 
    677 /**
    678  * xmlXPathErr:
    679  * @ctxt:  a XPath parser context
    680  * @error:  the error code
    681  *
    682  * Handle an XPath error
    683  */
    684 void
    685 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
    686 {
    687     if ((error < 0) || (error > MAXERRNO))
    688 	error = MAXERRNO;
    689     if (ctxt == NULL) {
    690 	__xmlRaiseError(NULL, NULL, NULL,
    691 			NULL, NULL, XML_FROM_XPATH,
    692 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    693 			XML_ERR_ERROR, NULL, 0,
    694 			NULL, NULL, NULL, 0, 0,
    695 			"%s", xmlXPathErrorMessages[error]);
    696 	return;
    697     }
    698     ctxt->error = error;
    699     if (ctxt->context == NULL) {
    700 	__xmlRaiseError(NULL, NULL, NULL,
    701 			NULL, NULL, XML_FROM_XPATH,
    702 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    703 			XML_ERR_ERROR, NULL, 0,
    704 			(const char *) ctxt->base, NULL, NULL,
    705 			ctxt->cur - ctxt->base, 0,
    706 			"%s", xmlXPathErrorMessages[error]);
    707 	return;
    708     }
    709 
    710     /* cleanup current last error */
    711     xmlResetError(&ctxt->context->lastError);
    712 
    713     ctxt->context->lastError.domain = XML_FROM_XPATH;
    714     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
    715                            XPATH_EXPRESSION_OK;
    716     ctxt->context->lastError.level = XML_ERR_ERROR;
    717     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
    718     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
    719     ctxt->context->lastError.node = ctxt->context->debugNode;
    720     if (ctxt->context->error != NULL) {
    721 	ctxt->context->error(ctxt->context->userData,
    722 	                     &ctxt->context->lastError);
    723     } else {
    724 	__xmlRaiseError(NULL, NULL, NULL,
    725 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
    726 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
    727 			XML_ERR_ERROR, NULL, 0,
    728 			(const char *) ctxt->base, NULL, NULL,
    729 			ctxt->cur - ctxt->base, 0,
    730 			"%s", xmlXPathErrorMessages[error]);
    731     }
    732 
    733 }
    734 
    735 /**
    736  * xmlXPatherror:
    737  * @ctxt:  the XPath Parser context
    738  * @file:  the file name
    739  * @line:  the line number
    740  * @no:  the error number
    741  *
    742  * Formats an error message.
    743  */
    744 void
    745 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
    746               int line ATTRIBUTE_UNUSED, int no) {
    747     xmlXPathErr(ctxt, no);
    748 }
    749 
    750 /************************************************************************
    751  *									*
    752  *			Utilities					*
    753  *									*
    754  ************************************************************************/
    755 
    756 /**
    757  * xsltPointerList:
    758  *
    759  * Pointer-list for various purposes.
    760  */
    761 typedef struct _xmlPointerList xmlPointerList;
    762 typedef xmlPointerList *xmlPointerListPtr;
    763 struct _xmlPointerList {
    764     void **items;
    765     int number;
    766     int size;
    767 };
    768 /*
    769 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
    770 * and here, we should make the functions public.
    771 */
    772 static int
    773 xmlPointerListAddSize(xmlPointerListPtr list,
    774 		       void *item,
    775 		       int initialSize)
    776 {
    777     if (list->items == NULL) {
    778 	if (initialSize <= 0)
    779 	    initialSize = 1;
    780 	list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
    781 	if (list->items == NULL) {
    782 	    xmlXPathErrMemory(NULL,
    783 		"xmlPointerListCreate: allocating item\n");
    784 	    return(-1);
    785 	}
    786 	list->number = 0;
    787 	list->size = initialSize;
    788     } else if (list->size <= list->number) {
    789         if (list->size > 50000000) {
    790 	    xmlXPathErrMemory(NULL,
    791 		"xmlPointerListAddSize: re-allocating item\n");
    792             return(-1);
    793         }
    794 	list->size *= 2;
    795 	list->items = (void **) xmlRealloc(list->items,
    796 	    list->size * sizeof(void *));
    797 	if (list->items == NULL) {
    798 	    xmlXPathErrMemory(NULL,
    799 		"xmlPointerListAddSize: re-allocating item\n");
    800 	    list->size = 0;
    801 	    return(-1);
    802 	}
    803     }
    804     list->items[list->number++] = item;
    805     return(0);
    806 }
    807 
    808 /**
    809  * xsltPointerListCreate:
    810  *
    811  * Creates an xsltPointerList structure.
    812  *
    813  * Returns a xsltPointerList structure or NULL in case of an error.
    814  */
    815 static xmlPointerListPtr
    816 xmlPointerListCreate(int initialSize)
    817 {
    818     xmlPointerListPtr ret;
    819 
    820     ret = xmlMalloc(sizeof(xmlPointerList));
    821     if (ret == NULL) {
    822 	xmlXPathErrMemory(NULL,
    823 	    "xmlPointerListCreate: allocating item\n");
    824 	return (NULL);
    825     }
    826     memset(ret, 0, sizeof(xmlPointerList));
    827     if (initialSize > 0) {
    828 	xmlPointerListAddSize(ret, NULL, initialSize);
    829 	ret->number = 0;
    830     }
    831     return (ret);
    832 }
    833 
    834 /**
    835  * xsltPointerListFree:
    836  *
    837  * Frees the xsltPointerList structure. This does not free
    838  * the content of the list.
    839  */
    840 static void
    841 xmlPointerListFree(xmlPointerListPtr list)
    842 {
    843     if (list == NULL)
    844 	return;
    845     if (list->items != NULL)
    846 	xmlFree(list->items);
    847     xmlFree(list);
    848 }
    849 
    850 /************************************************************************
    851  *									*
    852  *			Parser Types					*
    853  *									*
    854  ************************************************************************/
    855 
    856 /*
    857  * Types are private:
    858  */
    859 
    860 typedef enum {
    861     XPATH_OP_END=0,
    862     XPATH_OP_AND,
    863     XPATH_OP_OR,
    864     XPATH_OP_EQUAL,
    865     XPATH_OP_CMP,
    866     XPATH_OP_PLUS,
    867     XPATH_OP_MULT,
    868     XPATH_OP_UNION,
    869     XPATH_OP_ROOT,
    870     XPATH_OP_NODE,
    871     XPATH_OP_COLLECT,
    872     XPATH_OP_VALUE, /* 11 */
    873     XPATH_OP_VARIABLE,
    874     XPATH_OP_FUNCTION,
    875     XPATH_OP_ARG,
    876     XPATH_OP_PREDICATE,
    877     XPATH_OP_FILTER, /* 16 */
    878     XPATH_OP_SORT /* 17 */
    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_SORT:
   1529 	     fprintf(output, "SORT"); break;
   1530         case XPATH_OP_COLLECT: {
   1531 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
   1532 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
   1533 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
   1534 	    const xmlChar *prefix = op->value4;
   1535 	    const xmlChar *name = op->value5;
   1536 
   1537 	    fprintf(output, "COLLECT ");
   1538 	    switch (axis) {
   1539 		case AXIS_ANCESTOR:
   1540 		    fprintf(output, " 'ancestors' "); break;
   1541 		case AXIS_ANCESTOR_OR_SELF:
   1542 		    fprintf(output, " 'ancestors-or-self' "); break;
   1543 		case AXIS_ATTRIBUTE:
   1544 		    fprintf(output, " 'attributes' "); break;
   1545 		case AXIS_CHILD:
   1546 		    fprintf(output, " 'child' "); break;
   1547 		case AXIS_DESCENDANT:
   1548 		    fprintf(output, " 'descendant' "); break;
   1549 		case AXIS_DESCENDANT_OR_SELF:
   1550 		    fprintf(output, " 'descendant-or-self' "); break;
   1551 		case AXIS_FOLLOWING:
   1552 		    fprintf(output, " 'following' "); break;
   1553 		case AXIS_FOLLOWING_SIBLING:
   1554 		    fprintf(output, " 'following-siblings' "); break;
   1555 		case AXIS_NAMESPACE:
   1556 		    fprintf(output, " 'namespace' "); break;
   1557 		case AXIS_PARENT:
   1558 		    fprintf(output, " 'parent' "); break;
   1559 		case AXIS_PRECEDING:
   1560 		    fprintf(output, " 'preceding' "); break;
   1561 		case AXIS_PRECEDING_SIBLING:
   1562 		    fprintf(output, " 'preceding-sibling' "); break;
   1563 		case AXIS_SELF:
   1564 		    fprintf(output, " 'self' "); break;
   1565 	    }
   1566 	    switch (test) {
   1567                 case NODE_TEST_NONE:
   1568 		    fprintf(output, "'none' "); break;
   1569                 case NODE_TEST_TYPE:
   1570 		    fprintf(output, "'type' "); break;
   1571                 case NODE_TEST_PI:
   1572 		    fprintf(output, "'PI' "); break;
   1573                 case NODE_TEST_ALL:
   1574 		    fprintf(output, "'all' "); break;
   1575                 case NODE_TEST_NS:
   1576 		    fprintf(output, "'namespace' "); break;
   1577                 case NODE_TEST_NAME:
   1578 		    fprintf(output, "'name' "); break;
   1579 	    }
   1580 	    switch (type) {
   1581                 case NODE_TYPE_NODE:
   1582 		    fprintf(output, "'node' "); break;
   1583                 case NODE_TYPE_COMMENT:
   1584 		    fprintf(output, "'comment' "); break;
   1585                 case NODE_TYPE_TEXT:
   1586 		    fprintf(output, "'text' "); break;
   1587                 case NODE_TYPE_PI:
   1588 		    fprintf(output, "'PI' "); break;
   1589 	    }
   1590 	    if (prefix != NULL)
   1591 		fprintf(output, "%s:", prefix);
   1592 	    if (name != NULL)
   1593 		fprintf(output, "%s", (const char *) name);
   1594 	    break;
   1595 
   1596         }
   1597 	case XPATH_OP_VALUE: {
   1598 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
   1599 
   1600 	    fprintf(output, "ELEM ");
   1601 	    xmlXPathDebugDumpObject(output, object, 0);
   1602 	    goto finish;
   1603 	}
   1604 	case XPATH_OP_VARIABLE: {
   1605 	    const xmlChar *prefix = op->value5;
   1606 	    const xmlChar *name = op->value4;
   1607 
   1608 	    if (prefix != NULL)
   1609 		fprintf(output, "VARIABLE %s:%s", prefix, name);
   1610 	    else
   1611 		fprintf(output, "VARIABLE %s", name);
   1612 	    break;
   1613 	}
   1614 	case XPATH_OP_FUNCTION: {
   1615 	    int nbargs = op->value;
   1616 	    const xmlChar *prefix = op->value5;
   1617 	    const xmlChar *name = op->value4;
   1618 
   1619 	    if (prefix != NULL)
   1620 		fprintf(output, "FUNCTION %s:%s(%d args)",
   1621 			prefix, name, nbargs);
   1622 	    else
   1623 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
   1624 	    break;
   1625 	}
   1626         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
   1627         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
   1628         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
   1629 #ifdef LIBXML_XPTR_ENABLED
   1630         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
   1631 #endif
   1632 	default:
   1633         fprintf(output, "UNKNOWN %d\n", op->op); return;
   1634     }
   1635     fprintf(output, "\n");
   1636 finish:
   1637     if (op->ch1 >= 0)
   1638 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
   1639     if (op->ch2 >= 0)
   1640 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
   1641 }
   1642 
   1643 /**
   1644  * xmlXPathDebugDumpCompExpr:
   1645  * @output:  the FILE * for the output
   1646  * @comp:  the precompiled XPath expression
   1647  * @depth:  the indentation level.
   1648  *
   1649  * Dumps the tree of the compiled XPath expression.
   1650  */
   1651 void
   1652 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
   1653 	                  int depth) {
   1654     int i;
   1655     char shift[100];
   1656 
   1657     if ((output == NULL) || (comp == NULL)) return;
   1658 
   1659     for (i = 0;((i < depth) && (i < 25));i++)
   1660         shift[2 * i] = shift[2 * i + 1] = ' ';
   1661     shift[2 * i] = shift[2 * i + 1] = 0;
   1662 
   1663     fprintf(output, "%s", shift);
   1664 
   1665 #ifdef XPATH_STREAMING
   1666     if (comp->stream) {
   1667         fprintf(output, "Streaming Expression\n");
   1668     } else
   1669 #endif
   1670     {
   1671         fprintf(output, "Compiled Expression : %d elements\n",
   1672                 comp->nbStep);
   1673         i = comp->last;
   1674         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
   1675     }
   1676 }
   1677 
   1678 #ifdef XP_DEBUG_OBJ_USAGE
   1679 
   1680 /*
   1681 * XPath object usage related debugging variables.
   1682 */
   1683 static int xmlXPathDebugObjCounterUndefined = 0;
   1684 static int xmlXPathDebugObjCounterNodeset = 0;
   1685 static int xmlXPathDebugObjCounterBool = 0;
   1686 static int xmlXPathDebugObjCounterNumber = 0;
   1687 static int xmlXPathDebugObjCounterString = 0;
   1688 static int xmlXPathDebugObjCounterPoint = 0;
   1689 static int xmlXPathDebugObjCounterRange = 0;
   1690 static int xmlXPathDebugObjCounterLocset = 0;
   1691 static int xmlXPathDebugObjCounterUsers = 0;
   1692 static int xmlXPathDebugObjCounterXSLTTree = 0;
   1693 static int xmlXPathDebugObjCounterAll = 0;
   1694 
   1695 static int xmlXPathDebugObjTotalUndefined = 0;
   1696 static int xmlXPathDebugObjTotalNodeset = 0;
   1697 static int xmlXPathDebugObjTotalBool = 0;
   1698 static int xmlXPathDebugObjTotalNumber = 0;
   1699 static int xmlXPathDebugObjTotalString = 0;
   1700 static int xmlXPathDebugObjTotalPoint = 0;
   1701 static int xmlXPathDebugObjTotalRange = 0;
   1702 static int xmlXPathDebugObjTotalLocset = 0;
   1703 static int xmlXPathDebugObjTotalUsers = 0;
   1704 static int xmlXPathDebugObjTotalXSLTTree = 0;
   1705 static int xmlXPathDebugObjTotalAll = 0;
   1706 
   1707 static int xmlXPathDebugObjMaxUndefined = 0;
   1708 static int xmlXPathDebugObjMaxNodeset = 0;
   1709 static int xmlXPathDebugObjMaxBool = 0;
   1710 static int xmlXPathDebugObjMaxNumber = 0;
   1711 static int xmlXPathDebugObjMaxString = 0;
   1712 static int xmlXPathDebugObjMaxPoint = 0;
   1713 static int xmlXPathDebugObjMaxRange = 0;
   1714 static int xmlXPathDebugObjMaxLocset = 0;
   1715 static int xmlXPathDebugObjMaxUsers = 0;
   1716 static int xmlXPathDebugObjMaxXSLTTree = 0;
   1717 static int xmlXPathDebugObjMaxAll = 0;
   1718 
   1719 /* REVISIT TODO: Make this static when committing */
   1720 static void
   1721 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
   1722 {
   1723     if (ctxt != NULL) {
   1724 	if (ctxt->cache != NULL) {
   1725 	    xmlXPathContextCachePtr cache =
   1726 		(xmlXPathContextCachePtr) ctxt->cache;
   1727 
   1728 	    cache->dbgCachedAll = 0;
   1729 	    cache->dbgCachedNodeset = 0;
   1730 	    cache->dbgCachedString = 0;
   1731 	    cache->dbgCachedBool = 0;
   1732 	    cache->dbgCachedNumber = 0;
   1733 	    cache->dbgCachedPoint = 0;
   1734 	    cache->dbgCachedRange = 0;
   1735 	    cache->dbgCachedLocset = 0;
   1736 	    cache->dbgCachedUsers = 0;
   1737 	    cache->dbgCachedXSLTTree = 0;
   1738 	    cache->dbgCachedUndefined = 0;
   1739 
   1740 	    cache->dbgReusedAll = 0;
   1741 	    cache->dbgReusedNodeset = 0;
   1742 	    cache->dbgReusedString = 0;
   1743 	    cache->dbgReusedBool = 0;
   1744 	    cache->dbgReusedNumber = 0;
   1745 	    cache->dbgReusedPoint = 0;
   1746 	    cache->dbgReusedRange = 0;
   1747 	    cache->dbgReusedLocset = 0;
   1748 	    cache->dbgReusedUsers = 0;
   1749 	    cache->dbgReusedXSLTTree = 0;
   1750 	    cache->dbgReusedUndefined = 0;
   1751 	}
   1752     }
   1753 
   1754     xmlXPathDebugObjCounterUndefined = 0;
   1755     xmlXPathDebugObjCounterNodeset = 0;
   1756     xmlXPathDebugObjCounterBool = 0;
   1757     xmlXPathDebugObjCounterNumber = 0;
   1758     xmlXPathDebugObjCounterString = 0;
   1759     xmlXPathDebugObjCounterPoint = 0;
   1760     xmlXPathDebugObjCounterRange = 0;
   1761     xmlXPathDebugObjCounterLocset = 0;
   1762     xmlXPathDebugObjCounterUsers = 0;
   1763     xmlXPathDebugObjCounterXSLTTree = 0;
   1764     xmlXPathDebugObjCounterAll = 0;
   1765 
   1766     xmlXPathDebugObjTotalUndefined = 0;
   1767     xmlXPathDebugObjTotalNodeset = 0;
   1768     xmlXPathDebugObjTotalBool = 0;
   1769     xmlXPathDebugObjTotalNumber = 0;
   1770     xmlXPathDebugObjTotalString = 0;
   1771     xmlXPathDebugObjTotalPoint = 0;
   1772     xmlXPathDebugObjTotalRange = 0;
   1773     xmlXPathDebugObjTotalLocset = 0;
   1774     xmlXPathDebugObjTotalUsers = 0;
   1775     xmlXPathDebugObjTotalXSLTTree = 0;
   1776     xmlXPathDebugObjTotalAll = 0;
   1777 
   1778     xmlXPathDebugObjMaxUndefined = 0;
   1779     xmlXPathDebugObjMaxNodeset = 0;
   1780     xmlXPathDebugObjMaxBool = 0;
   1781     xmlXPathDebugObjMaxNumber = 0;
   1782     xmlXPathDebugObjMaxString = 0;
   1783     xmlXPathDebugObjMaxPoint = 0;
   1784     xmlXPathDebugObjMaxRange = 0;
   1785     xmlXPathDebugObjMaxLocset = 0;
   1786     xmlXPathDebugObjMaxUsers = 0;
   1787     xmlXPathDebugObjMaxXSLTTree = 0;
   1788     xmlXPathDebugObjMaxAll = 0;
   1789 
   1790 }
   1791 
   1792 static void
   1793 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
   1794 			      xmlXPathObjectType objType)
   1795 {
   1796     int isCached = 0;
   1797 
   1798     if (ctxt != NULL) {
   1799 	if (ctxt->cache != NULL) {
   1800 	    xmlXPathContextCachePtr cache =
   1801 		(xmlXPathContextCachePtr) ctxt->cache;
   1802 
   1803 	    isCached = 1;
   1804 
   1805 	    cache->dbgReusedAll++;
   1806 	    switch (objType) {
   1807 		case XPATH_UNDEFINED:
   1808 		    cache->dbgReusedUndefined++;
   1809 		    break;
   1810 		case XPATH_NODESET:
   1811 		    cache->dbgReusedNodeset++;
   1812 		    break;
   1813 		case XPATH_BOOLEAN:
   1814 		    cache->dbgReusedBool++;
   1815 		    break;
   1816 		case XPATH_NUMBER:
   1817 		    cache->dbgReusedNumber++;
   1818 		    break;
   1819 		case XPATH_STRING:
   1820 		    cache->dbgReusedString++;
   1821 		    break;
   1822 		case XPATH_POINT:
   1823 		    cache->dbgReusedPoint++;
   1824 		    break;
   1825 		case XPATH_RANGE:
   1826 		    cache->dbgReusedRange++;
   1827 		    break;
   1828 		case XPATH_LOCATIONSET:
   1829 		    cache->dbgReusedLocset++;
   1830 		    break;
   1831 		case XPATH_USERS:
   1832 		    cache->dbgReusedUsers++;
   1833 		    break;
   1834 		case XPATH_XSLT_TREE:
   1835 		    cache->dbgReusedXSLTTree++;
   1836 		    break;
   1837 		default:
   1838 		    break;
   1839 	    }
   1840 	}
   1841     }
   1842 
   1843     switch (objType) {
   1844 	case XPATH_UNDEFINED:
   1845 	    if (! isCached)
   1846 		xmlXPathDebugObjTotalUndefined++;
   1847 	    xmlXPathDebugObjCounterUndefined++;
   1848 	    if (xmlXPathDebugObjCounterUndefined >
   1849 		xmlXPathDebugObjMaxUndefined)
   1850 		xmlXPathDebugObjMaxUndefined =
   1851 		    xmlXPathDebugObjCounterUndefined;
   1852 	    break;
   1853 	case XPATH_NODESET:
   1854 	    if (! isCached)
   1855 		xmlXPathDebugObjTotalNodeset++;
   1856 	    xmlXPathDebugObjCounterNodeset++;
   1857 	    if (xmlXPathDebugObjCounterNodeset >
   1858 		xmlXPathDebugObjMaxNodeset)
   1859 		xmlXPathDebugObjMaxNodeset =
   1860 		    xmlXPathDebugObjCounterNodeset;
   1861 	    break;
   1862 	case XPATH_BOOLEAN:
   1863 	    if (! isCached)
   1864 		xmlXPathDebugObjTotalBool++;
   1865 	    xmlXPathDebugObjCounterBool++;
   1866 	    if (xmlXPathDebugObjCounterBool >
   1867 		xmlXPathDebugObjMaxBool)
   1868 		xmlXPathDebugObjMaxBool =
   1869 		    xmlXPathDebugObjCounterBool;
   1870 	    break;
   1871 	case XPATH_NUMBER:
   1872 	    if (! isCached)
   1873 		xmlXPathDebugObjTotalNumber++;
   1874 	    xmlXPathDebugObjCounterNumber++;
   1875 	    if (xmlXPathDebugObjCounterNumber >
   1876 		xmlXPathDebugObjMaxNumber)
   1877 		xmlXPathDebugObjMaxNumber =
   1878 		    xmlXPathDebugObjCounterNumber;
   1879 	    break;
   1880 	case XPATH_STRING:
   1881 	    if (! isCached)
   1882 		xmlXPathDebugObjTotalString++;
   1883 	    xmlXPathDebugObjCounterString++;
   1884 	    if (xmlXPathDebugObjCounterString >
   1885 		xmlXPathDebugObjMaxString)
   1886 		xmlXPathDebugObjMaxString =
   1887 		    xmlXPathDebugObjCounterString;
   1888 	    break;
   1889 	case XPATH_POINT:
   1890 	    if (! isCached)
   1891 		xmlXPathDebugObjTotalPoint++;
   1892 	    xmlXPathDebugObjCounterPoint++;
   1893 	    if (xmlXPathDebugObjCounterPoint >
   1894 		xmlXPathDebugObjMaxPoint)
   1895 		xmlXPathDebugObjMaxPoint =
   1896 		    xmlXPathDebugObjCounterPoint;
   1897 	    break;
   1898 	case XPATH_RANGE:
   1899 	    if (! isCached)
   1900 		xmlXPathDebugObjTotalRange++;
   1901 	    xmlXPathDebugObjCounterRange++;
   1902 	    if (xmlXPathDebugObjCounterRange >
   1903 		xmlXPathDebugObjMaxRange)
   1904 		xmlXPathDebugObjMaxRange =
   1905 		    xmlXPathDebugObjCounterRange;
   1906 	    break;
   1907 	case XPATH_LOCATIONSET:
   1908 	    if (! isCached)
   1909 		xmlXPathDebugObjTotalLocset++;
   1910 	    xmlXPathDebugObjCounterLocset++;
   1911 	    if (xmlXPathDebugObjCounterLocset >
   1912 		xmlXPathDebugObjMaxLocset)
   1913 		xmlXPathDebugObjMaxLocset =
   1914 		    xmlXPathDebugObjCounterLocset;
   1915 	    break;
   1916 	case XPATH_USERS:
   1917 	    if (! isCached)
   1918 		xmlXPathDebugObjTotalUsers++;
   1919 	    xmlXPathDebugObjCounterUsers++;
   1920 	    if (xmlXPathDebugObjCounterUsers >
   1921 		xmlXPathDebugObjMaxUsers)
   1922 		xmlXPathDebugObjMaxUsers =
   1923 		    xmlXPathDebugObjCounterUsers;
   1924 	    break;
   1925 	case XPATH_XSLT_TREE:
   1926 	    if (! isCached)
   1927 		xmlXPathDebugObjTotalXSLTTree++;
   1928 	    xmlXPathDebugObjCounterXSLTTree++;
   1929 	    if (xmlXPathDebugObjCounterXSLTTree >
   1930 		xmlXPathDebugObjMaxXSLTTree)
   1931 		xmlXPathDebugObjMaxXSLTTree =
   1932 		    xmlXPathDebugObjCounterXSLTTree;
   1933 	    break;
   1934 	default:
   1935 	    break;
   1936     }
   1937     if (! isCached)
   1938 	xmlXPathDebugObjTotalAll++;
   1939     xmlXPathDebugObjCounterAll++;
   1940     if (xmlXPathDebugObjCounterAll >
   1941 	xmlXPathDebugObjMaxAll)
   1942 	xmlXPathDebugObjMaxAll =
   1943 	    xmlXPathDebugObjCounterAll;
   1944 }
   1945 
   1946 static void
   1947 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
   1948 			      xmlXPathObjectType objType)
   1949 {
   1950     int isCached = 0;
   1951 
   1952     if (ctxt != NULL) {
   1953 	if (ctxt->cache != NULL) {
   1954 	    xmlXPathContextCachePtr cache =
   1955 		(xmlXPathContextCachePtr) ctxt->cache;
   1956 
   1957 	    isCached = 1;
   1958 
   1959 	    cache->dbgCachedAll++;
   1960 	    switch (objType) {
   1961 		case XPATH_UNDEFINED:
   1962 		    cache->dbgCachedUndefined++;
   1963 		    break;
   1964 		case XPATH_NODESET:
   1965 		    cache->dbgCachedNodeset++;
   1966 		    break;
   1967 		case XPATH_BOOLEAN:
   1968 		    cache->dbgCachedBool++;
   1969 		    break;
   1970 		case XPATH_NUMBER:
   1971 		    cache->dbgCachedNumber++;
   1972 		    break;
   1973 		case XPATH_STRING:
   1974 		    cache->dbgCachedString++;
   1975 		    break;
   1976 		case XPATH_POINT:
   1977 		    cache->dbgCachedPoint++;
   1978 		    break;
   1979 		case XPATH_RANGE:
   1980 		    cache->dbgCachedRange++;
   1981 		    break;
   1982 		case XPATH_LOCATIONSET:
   1983 		    cache->dbgCachedLocset++;
   1984 		    break;
   1985 		case XPATH_USERS:
   1986 		    cache->dbgCachedUsers++;
   1987 		    break;
   1988 		case XPATH_XSLT_TREE:
   1989 		    cache->dbgCachedXSLTTree++;
   1990 		    break;
   1991 		default:
   1992 		    break;
   1993 	    }
   1994 
   1995 	}
   1996     }
   1997     switch (objType) {
   1998 	case XPATH_UNDEFINED:
   1999 	    xmlXPathDebugObjCounterUndefined--;
   2000 	    break;
   2001 	case XPATH_NODESET:
   2002 	    xmlXPathDebugObjCounterNodeset--;
   2003 	    break;
   2004 	case XPATH_BOOLEAN:
   2005 	    xmlXPathDebugObjCounterBool--;
   2006 	    break;
   2007 	case XPATH_NUMBER:
   2008 	    xmlXPathDebugObjCounterNumber--;
   2009 	    break;
   2010 	case XPATH_STRING:
   2011 	    xmlXPathDebugObjCounterString--;
   2012 	    break;
   2013 	case XPATH_POINT:
   2014 	    xmlXPathDebugObjCounterPoint--;
   2015 	    break;
   2016 	case XPATH_RANGE:
   2017 	    xmlXPathDebugObjCounterRange--;
   2018 	    break;
   2019 	case XPATH_LOCATIONSET:
   2020 	    xmlXPathDebugObjCounterLocset--;
   2021 	    break;
   2022 	case XPATH_USERS:
   2023 	    xmlXPathDebugObjCounterUsers--;
   2024 	    break;
   2025 	case XPATH_XSLT_TREE:
   2026 	    xmlXPathDebugObjCounterXSLTTree--;
   2027 	    break;
   2028 	default:
   2029 	    break;
   2030     }
   2031     xmlXPathDebugObjCounterAll--;
   2032 }
   2033 
   2034 /* REVISIT TODO: Make this static when committing */
   2035 static void
   2036 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
   2037 {
   2038     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
   2039 	reqXSLTTree, reqUndefined;
   2040     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
   2041 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
   2042     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
   2043 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
   2044     int leftObjs = xmlXPathDebugObjCounterAll;
   2045 
   2046     reqAll = xmlXPathDebugObjTotalAll;
   2047     reqNodeset = xmlXPathDebugObjTotalNodeset;
   2048     reqString = xmlXPathDebugObjTotalString;
   2049     reqBool = xmlXPathDebugObjTotalBool;
   2050     reqNumber = xmlXPathDebugObjTotalNumber;
   2051     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
   2052     reqUndefined = xmlXPathDebugObjTotalUndefined;
   2053 
   2054     printf("# XPath object usage:\n");
   2055 
   2056     if (ctxt != NULL) {
   2057 	if (ctxt->cache != NULL) {
   2058 	    xmlXPathContextCachePtr cache =
   2059 		(xmlXPathContextCachePtr) ctxt->cache;
   2060 
   2061 	    reAll = cache->dbgReusedAll;
   2062 	    reqAll += reAll;
   2063 	    reNodeset = cache->dbgReusedNodeset;
   2064 	    reqNodeset += reNodeset;
   2065 	    reString = cache->dbgReusedString;
   2066 	    reqString += reString;
   2067 	    reBool = cache->dbgReusedBool;
   2068 	    reqBool += reBool;
   2069 	    reNumber = cache->dbgReusedNumber;
   2070 	    reqNumber += reNumber;
   2071 	    reXSLTTree = cache->dbgReusedXSLTTree;
   2072 	    reqXSLTTree += reXSLTTree;
   2073 	    reUndefined = cache->dbgReusedUndefined;
   2074 	    reqUndefined += reUndefined;
   2075 
   2076 	    caAll = cache->dbgCachedAll;
   2077 	    caBool = cache->dbgCachedBool;
   2078 	    caNodeset = cache->dbgCachedNodeset;
   2079 	    caString = cache->dbgCachedString;
   2080 	    caNumber = cache->dbgCachedNumber;
   2081 	    caXSLTTree = cache->dbgCachedXSLTTree;
   2082 	    caUndefined = cache->dbgCachedUndefined;
   2083 
   2084 	    if (cache->nodesetObjs)
   2085 		leftObjs -= cache->nodesetObjs->number;
   2086 	    if (cache->stringObjs)
   2087 		leftObjs -= cache->stringObjs->number;
   2088 	    if (cache->booleanObjs)
   2089 		leftObjs -= cache->booleanObjs->number;
   2090 	    if (cache->numberObjs)
   2091 		leftObjs -= cache->numberObjs->number;
   2092 	    if (cache->miscObjs)
   2093 		leftObjs -= cache->miscObjs->number;
   2094 	}
   2095     }
   2096 
   2097     printf("# all\n");
   2098     printf("#   total  : %d\n", reqAll);
   2099     printf("#   left  : %d\n", leftObjs);
   2100     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
   2101     printf("#   reused : %d\n", reAll);
   2102     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
   2103 
   2104     printf("# node-sets\n");
   2105     printf("#   total  : %d\n", reqNodeset);
   2106     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
   2107     printf("#   reused : %d\n", reNodeset);
   2108     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
   2109 
   2110     printf("# strings\n");
   2111     printf("#   total  : %d\n", reqString);
   2112     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
   2113     printf("#   reused : %d\n", reString);
   2114     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
   2115 
   2116     printf("# booleans\n");
   2117     printf("#   total  : %d\n", reqBool);
   2118     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
   2119     printf("#   reused : %d\n", reBool);
   2120     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
   2121 
   2122     printf("# numbers\n");
   2123     printf("#   total  : %d\n", reqNumber);
   2124     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
   2125     printf("#   reused : %d\n", reNumber);
   2126     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
   2127 
   2128     printf("# XSLT result tree fragments\n");
   2129     printf("#   total  : %d\n", reqXSLTTree);
   2130     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
   2131     printf("#   reused : %d\n", reXSLTTree);
   2132     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
   2133 
   2134     printf("# undefined\n");
   2135     printf("#   total  : %d\n", reqUndefined);
   2136     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
   2137     printf("#   reused : %d\n", reUndefined);
   2138     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
   2139 
   2140 }
   2141 
   2142 #endif /* XP_DEBUG_OBJ_USAGE */
   2143 
   2144 #endif /* LIBXML_DEBUG_ENABLED */
   2145 
   2146 /************************************************************************
   2147  *									*
   2148  *			XPath object caching				*
   2149  *									*
   2150  ************************************************************************/
   2151 
   2152 /**
   2153  * xmlXPathNewCache:
   2154  *
   2155  * Create a new object cache
   2156  *
   2157  * Returns the xmlXPathCache just allocated.
   2158  */
   2159 static xmlXPathContextCachePtr
   2160 xmlXPathNewCache(void)
   2161 {
   2162     xmlXPathContextCachePtr ret;
   2163 
   2164     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
   2165     if (ret == NULL) {
   2166         xmlXPathErrMemory(NULL, "creating object cache\n");
   2167 	return(NULL);
   2168     }
   2169     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
   2170     ret->maxNodeset = 100;
   2171     ret->maxString = 100;
   2172     ret->maxBoolean = 100;
   2173     ret->maxNumber = 100;
   2174     ret->maxMisc = 100;
   2175     return(ret);
   2176 }
   2177 
   2178 static void
   2179 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
   2180 {
   2181     int i;
   2182     xmlXPathObjectPtr obj;
   2183 
   2184     if (list == NULL)
   2185 	return;
   2186 
   2187     for (i = 0; i < list->number; i++) {
   2188 	obj = list->items[i];
   2189 	/*
   2190 	* Note that it is already assured that we don't need to
   2191 	* look out for namespace nodes in the node-set.
   2192 	*/
   2193 	if (obj->nodesetval != NULL) {
   2194 	    if (obj->nodesetval->nodeTab != NULL)
   2195 		xmlFree(obj->nodesetval->nodeTab);
   2196 	    xmlFree(obj->nodesetval);
   2197 	}
   2198 	xmlFree(obj);
   2199 #ifdef XP_DEBUG_OBJ_USAGE
   2200 	xmlXPathDebugObjCounterAll--;
   2201 #endif
   2202     }
   2203     xmlPointerListFree(list);
   2204 }
   2205 
   2206 static void
   2207 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
   2208 {
   2209     if (cache == NULL)
   2210 	return;
   2211     if (cache->nodesetObjs)
   2212 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
   2213     if (cache->stringObjs)
   2214 	xmlXPathCacheFreeObjectList(cache->stringObjs);
   2215     if (cache->booleanObjs)
   2216 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
   2217     if (cache->numberObjs)
   2218 	xmlXPathCacheFreeObjectList(cache->numberObjs);
   2219     if (cache->miscObjs)
   2220 	xmlXPathCacheFreeObjectList(cache->miscObjs);
   2221     xmlFree(cache);
   2222 }
   2223 
   2224 /**
   2225  * xmlXPathContextSetCache:
   2226  *
   2227  * @ctxt:  the XPath context
   2228  * @active: enables/disables (creates/frees) the cache
   2229  * @value: a value with semantics dependant on @options
   2230  * @options: options (currently only the value 0 is used)
   2231  *
   2232  * Creates/frees an object cache on the XPath context.
   2233  * If activates XPath objects (xmlXPathObject) will be cached internally
   2234  * to be reused.
   2235  * @options:
   2236  *   0: This will set the XPath object caching:
   2237  *      @value:
   2238  *        This will set the maximum number of XPath objects
   2239  *        to be cached per slot
   2240  *        There are 5 slots for: node-set, string, number, boolean, and
   2241  *        misc objects. Use <0 for the default number (100).
   2242  *   Other values for @options have currently no effect.
   2243  *
   2244  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
   2245  */
   2246 int
   2247 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
   2248 			int active,
   2249 			int value,
   2250 			int options)
   2251 {
   2252     if (ctxt == NULL)
   2253 	return(-1);
   2254     if (active) {
   2255 	xmlXPathContextCachePtr cache;
   2256 
   2257 	if (ctxt->cache == NULL) {
   2258 	    ctxt->cache = xmlXPathNewCache();
   2259 	    if (ctxt->cache == NULL)
   2260 		return(-1);
   2261 	}
   2262 	cache = (xmlXPathContextCachePtr) ctxt->cache;
   2263 	if (options == 0) {
   2264 	    if (value < 0)
   2265 		value = 100;
   2266 	    cache->maxNodeset = value;
   2267 	    cache->maxString = value;
   2268 	    cache->maxNumber = value;
   2269 	    cache->maxBoolean = value;
   2270 	    cache->maxMisc = value;
   2271 	}
   2272     } else if (ctxt->cache != NULL) {
   2273 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
   2274 	ctxt->cache = NULL;
   2275     }
   2276     return(0);
   2277 }
   2278 
   2279 /**
   2280  * xmlXPathCacheWrapNodeSet:
   2281  * @ctxt: the XPath context
   2282  * @val:  the NodePtr value
   2283  *
   2284  * This is the cached version of xmlXPathWrapNodeSet().
   2285  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
   2286  *
   2287  * Returns the created or reused object.
   2288  */
   2289 static xmlXPathObjectPtr
   2290 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
   2291 {
   2292     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
   2293 	xmlXPathContextCachePtr cache =
   2294 	    (xmlXPathContextCachePtr) ctxt->cache;
   2295 
   2296 	if ((cache->miscObjs != NULL) &&
   2297 	    (cache->miscObjs->number != 0))
   2298 	{
   2299 	    xmlXPathObjectPtr ret;
   2300 
   2301 	    ret = (xmlXPathObjectPtr)
   2302 		cache->miscObjs->items[--cache->miscObjs->number];
   2303 	    ret->type = XPATH_NODESET;
   2304 	    ret->nodesetval = val;
   2305 #ifdef XP_DEBUG_OBJ_USAGE
   2306 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   2307 #endif
   2308 	    return(ret);
   2309 	}
   2310     }
   2311 
   2312     return(xmlXPathWrapNodeSet(val));
   2313 
   2314 }
   2315 
   2316 /**
   2317  * xmlXPathCacheWrapString:
   2318  * @ctxt: the XPath context
   2319  * @val:  the xmlChar * value
   2320  *
   2321  * This is the cached version of xmlXPathWrapString().
   2322  * Wraps the @val string into an XPath object.
   2323  *
   2324  * Returns the created or reused object.
   2325  */
   2326 static xmlXPathObjectPtr
   2327 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
   2328 {
   2329     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
   2330 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2331 
   2332 	if ((cache->stringObjs != NULL) &&
   2333 	    (cache->stringObjs->number != 0))
   2334 	{
   2335 
   2336 	    xmlXPathObjectPtr ret;
   2337 
   2338 	    ret = (xmlXPathObjectPtr)
   2339 		cache->stringObjs->items[--cache->stringObjs->number];
   2340 	    ret->type = XPATH_STRING;
   2341 	    ret->stringval = val;
   2342 #ifdef XP_DEBUG_OBJ_USAGE
   2343 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2344 #endif
   2345 	    return(ret);
   2346 	} else if ((cache->miscObjs != NULL) &&
   2347 	    (cache->miscObjs->number != 0))
   2348 	{
   2349 	    xmlXPathObjectPtr ret;
   2350 	    /*
   2351 	    * Fallback to misc-cache.
   2352 	    */
   2353 	    ret = (xmlXPathObjectPtr)
   2354 		cache->miscObjs->items[--cache->miscObjs->number];
   2355 
   2356 	    ret->type = XPATH_STRING;
   2357 	    ret->stringval = val;
   2358 #ifdef XP_DEBUG_OBJ_USAGE
   2359 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2360 #endif
   2361 	    return(ret);
   2362 	}
   2363     }
   2364     return(xmlXPathWrapString(val));
   2365 }
   2366 
   2367 /**
   2368  * xmlXPathCacheNewNodeSet:
   2369  * @ctxt: the XPath context
   2370  * @val:  the NodePtr value
   2371  *
   2372  * This is the cached version of xmlXPathNewNodeSet().
   2373  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
   2374  * it with the single Node @val
   2375  *
   2376  * Returns the created or reused object.
   2377  */
   2378 static xmlXPathObjectPtr
   2379 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
   2380 {
   2381     if ((ctxt != NULL) && (ctxt->cache)) {
   2382 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2383 
   2384 	if ((cache->nodesetObjs != NULL) &&
   2385 	    (cache->nodesetObjs->number != 0))
   2386 	{
   2387 	    xmlXPathObjectPtr ret;
   2388 	    /*
   2389 	    * Use the nodset-cache.
   2390 	    */
   2391 	    ret = (xmlXPathObjectPtr)
   2392 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
   2393 	    ret->type = XPATH_NODESET;
   2394 	    ret->boolval = 0;
   2395 	    if (val) {
   2396 		if ((ret->nodesetval->nodeMax == 0) ||
   2397 		    (val->type == XML_NAMESPACE_DECL))
   2398 		{
   2399 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
   2400 		} else {
   2401 		    ret->nodesetval->nodeTab[0] = val;
   2402 		    ret->nodesetval->nodeNr = 1;
   2403 		}
   2404 	    }
   2405 #ifdef XP_DEBUG_OBJ_USAGE
   2406 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   2407 #endif
   2408 	    return(ret);
   2409 	} else if ((cache->miscObjs != NULL) &&
   2410 	    (cache->miscObjs->number != 0))
   2411 	{
   2412 	    xmlXPathObjectPtr ret;
   2413 	    /*
   2414 	    * Fallback to misc-cache.
   2415 	    */
   2416 
   2417 	    ret = (xmlXPathObjectPtr)
   2418 		cache->miscObjs->items[--cache->miscObjs->number];
   2419 
   2420 	    ret->type = XPATH_NODESET;
   2421 	    ret->boolval = 0;
   2422 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
   2423 	    if (ret->nodesetval == NULL) {
   2424 		ctxt->lastError.domain = XML_FROM_XPATH;
   2425 		ctxt->lastError.code = XML_ERR_NO_MEMORY;
   2426 		return(NULL);
   2427 	    }
   2428 #ifdef XP_DEBUG_OBJ_USAGE
   2429 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
   2430 #endif
   2431 	    return(ret);
   2432 	}
   2433     }
   2434     return(xmlXPathNewNodeSet(val));
   2435 }
   2436 
   2437 /**
   2438  * xmlXPathCacheNewCString:
   2439  * @ctxt: the XPath context
   2440  * @val:  the char * value
   2441  *
   2442  * This is the cached version of xmlXPathNewCString().
   2443  * Acquire an xmlXPathObjectPtr of type string and of value @val
   2444  *
   2445  * Returns the created or reused object.
   2446  */
   2447 static xmlXPathObjectPtr
   2448 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
   2449 {
   2450     if ((ctxt != NULL) && (ctxt->cache)) {
   2451 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2452 
   2453 	if ((cache->stringObjs != NULL) &&
   2454 	    (cache->stringObjs->number != 0))
   2455 	{
   2456 	    xmlXPathObjectPtr ret;
   2457 
   2458 	    ret = (xmlXPathObjectPtr)
   2459 		cache->stringObjs->items[--cache->stringObjs->number];
   2460 
   2461 	    ret->type = XPATH_STRING;
   2462 	    ret->stringval = xmlStrdup(BAD_CAST val);
   2463 #ifdef XP_DEBUG_OBJ_USAGE
   2464 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2465 #endif
   2466 	    return(ret);
   2467 	} else if ((cache->miscObjs != NULL) &&
   2468 	    (cache->miscObjs->number != 0))
   2469 	{
   2470 	    xmlXPathObjectPtr ret;
   2471 
   2472 	    ret = (xmlXPathObjectPtr)
   2473 		cache->miscObjs->items[--cache->miscObjs->number];
   2474 
   2475 	    ret->type = XPATH_STRING;
   2476 	    ret->stringval = xmlStrdup(BAD_CAST val);
   2477 #ifdef XP_DEBUG_OBJ_USAGE
   2478 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2479 #endif
   2480 	    return(ret);
   2481 	}
   2482     }
   2483     return(xmlXPathNewCString(val));
   2484 }
   2485 
   2486 /**
   2487  * xmlXPathCacheNewString:
   2488  * @ctxt: the XPath context
   2489  * @val:  the xmlChar * value
   2490  *
   2491  * This is the cached version of xmlXPathNewString().
   2492  * Acquire an xmlXPathObjectPtr of type string and of value @val
   2493  *
   2494  * Returns the created or reused object.
   2495  */
   2496 static xmlXPathObjectPtr
   2497 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
   2498 {
   2499     if ((ctxt != NULL) && (ctxt->cache)) {
   2500 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2501 
   2502 	if ((cache->stringObjs != NULL) &&
   2503 	    (cache->stringObjs->number != 0))
   2504 	{
   2505 	    xmlXPathObjectPtr ret;
   2506 
   2507 	    ret = (xmlXPathObjectPtr)
   2508 		cache->stringObjs->items[--cache->stringObjs->number];
   2509 	    ret->type = XPATH_STRING;
   2510 	    if (val != NULL)
   2511 		ret->stringval = xmlStrdup(val);
   2512 	    else
   2513 		ret->stringval = xmlStrdup((const xmlChar *)"");
   2514 #ifdef XP_DEBUG_OBJ_USAGE
   2515 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2516 #endif
   2517 	    return(ret);
   2518 	} else if ((cache->miscObjs != NULL) &&
   2519 	    (cache->miscObjs->number != 0))
   2520 	{
   2521 	    xmlXPathObjectPtr ret;
   2522 
   2523 	    ret = (xmlXPathObjectPtr)
   2524 		cache->miscObjs->items[--cache->miscObjs->number];
   2525 
   2526 	    ret->type = XPATH_STRING;
   2527 	    if (val != NULL)
   2528 		ret->stringval = xmlStrdup(val);
   2529 	    else
   2530 		ret->stringval = xmlStrdup((const xmlChar *)"");
   2531 #ifdef XP_DEBUG_OBJ_USAGE
   2532 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
   2533 #endif
   2534 	    return(ret);
   2535 	}
   2536     }
   2537     return(xmlXPathNewString(val));
   2538 }
   2539 
   2540 /**
   2541  * xmlXPathCacheNewBoolean:
   2542  * @ctxt: the XPath context
   2543  * @val:  the boolean value
   2544  *
   2545  * This is the cached version of xmlXPathNewBoolean().
   2546  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
   2547  *
   2548  * Returns the created or reused object.
   2549  */
   2550 static xmlXPathObjectPtr
   2551 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
   2552 {
   2553     if ((ctxt != NULL) && (ctxt->cache)) {
   2554 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2555 
   2556 	if ((cache->booleanObjs != NULL) &&
   2557 	    (cache->booleanObjs->number != 0))
   2558 	{
   2559 	    xmlXPathObjectPtr ret;
   2560 
   2561 	    ret = (xmlXPathObjectPtr)
   2562 		cache->booleanObjs->items[--cache->booleanObjs->number];
   2563 	    ret->type = XPATH_BOOLEAN;
   2564 	    ret->boolval = (val != 0);
   2565 #ifdef XP_DEBUG_OBJ_USAGE
   2566 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
   2567 #endif
   2568 	    return(ret);
   2569 	} else if ((cache->miscObjs != NULL) &&
   2570 	    (cache->miscObjs->number != 0))
   2571 	{
   2572 	    xmlXPathObjectPtr ret;
   2573 
   2574 	    ret = (xmlXPathObjectPtr)
   2575 		cache->miscObjs->items[--cache->miscObjs->number];
   2576 
   2577 	    ret->type = XPATH_BOOLEAN;
   2578 	    ret->boolval = (val != 0);
   2579 #ifdef XP_DEBUG_OBJ_USAGE
   2580 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
   2581 #endif
   2582 	    return(ret);
   2583 	}
   2584     }
   2585     return(xmlXPathNewBoolean(val));
   2586 }
   2587 
   2588 /**
   2589  * xmlXPathCacheNewFloat:
   2590  * @ctxt: the XPath context
   2591  * @val:  the double value
   2592  *
   2593  * This is the cached version of xmlXPathNewFloat().
   2594  * Acquires an xmlXPathObjectPtr of type double and of value @val
   2595  *
   2596  * Returns the created or reused object.
   2597  */
   2598 static xmlXPathObjectPtr
   2599 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
   2600 {
   2601      if ((ctxt != NULL) && (ctxt->cache)) {
   2602 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
   2603 
   2604 	if ((cache->numberObjs != NULL) &&
   2605 	    (cache->numberObjs->number != 0))
   2606 	{
   2607 	    xmlXPathObjectPtr ret;
   2608 
   2609 	    ret = (xmlXPathObjectPtr)
   2610 		cache->numberObjs->items[--cache->numberObjs->number];
   2611 	    ret->type = XPATH_NUMBER;
   2612 	    ret->floatval = val;
   2613 #ifdef XP_DEBUG_OBJ_USAGE
   2614 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
   2615 #endif
   2616 	    return(ret);
   2617 	} else if ((cache->miscObjs != NULL) &&
   2618 	    (cache->miscObjs->number != 0))
   2619 	{
   2620 	    xmlXPathObjectPtr ret;
   2621 
   2622 	    ret = (xmlXPathObjectPtr)
   2623 		cache->miscObjs->items[--cache->miscObjs->number];
   2624 
   2625 	    ret->type = XPATH_NUMBER;
   2626 	    ret->floatval = val;
   2627 #ifdef XP_DEBUG_OBJ_USAGE
   2628 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
   2629 #endif
   2630 	    return(ret);
   2631 	}
   2632     }
   2633     return(xmlXPathNewFloat(val));
   2634 }
   2635 
   2636 /**
   2637  * xmlXPathCacheConvertString:
   2638  * @ctxt: the XPath context
   2639  * @val:  an XPath object
   2640  *
   2641  * This is the cached version of xmlXPathConvertString().
   2642  * Converts an existing object to its string() equivalent
   2643  *
   2644  * Returns a created or reused object, the old one is freed (cached)
   2645  *         (or the operation is done directly on @val)
   2646  */
   2647 
   2648 static xmlXPathObjectPtr
   2649 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2650     xmlChar *res = NULL;
   2651 
   2652     if (val == NULL)
   2653 	return(xmlXPathCacheNewCString(ctxt, ""));
   2654 
   2655     switch (val->type) {
   2656     case XPATH_UNDEFINED:
   2657 #ifdef DEBUG_EXPR
   2658 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
   2659 #endif
   2660 	break;
   2661     case XPATH_NODESET:
   2662     case XPATH_XSLT_TREE:
   2663 	res = xmlXPathCastNodeSetToString(val->nodesetval);
   2664 	break;
   2665     case XPATH_STRING:
   2666 	return(val);
   2667     case XPATH_BOOLEAN:
   2668 	res = xmlXPathCastBooleanToString(val->boolval);
   2669 	break;
   2670     case XPATH_NUMBER:
   2671 	res = xmlXPathCastNumberToString(val->floatval);
   2672 	break;
   2673     case XPATH_USERS:
   2674     case XPATH_POINT:
   2675     case XPATH_RANGE:
   2676     case XPATH_LOCATIONSET:
   2677 	TODO;
   2678 	break;
   2679     }
   2680     xmlXPathReleaseObject(ctxt, val);
   2681     if (res == NULL)
   2682 	return(xmlXPathCacheNewCString(ctxt, ""));
   2683     return(xmlXPathCacheWrapString(ctxt, res));
   2684 }
   2685 
   2686 /**
   2687  * xmlXPathCacheObjectCopy:
   2688  * @ctxt: the XPath context
   2689  * @val:  the original object
   2690  *
   2691  * This is the cached version of xmlXPathObjectCopy().
   2692  * Acquire a copy of a given object
   2693  *
   2694  * Returns a created or reused created object.
   2695  */
   2696 static xmlXPathObjectPtr
   2697 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
   2698 {
   2699     if (val == NULL)
   2700 	return(NULL);
   2701 
   2702     if (XP_HAS_CACHE(ctxt)) {
   2703 	switch (val->type) {
   2704 	    case XPATH_NODESET:
   2705 		return(xmlXPathCacheWrapNodeSet(ctxt,
   2706 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
   2707 	    case XPATH_STRING:
   2708 		return(xmlXPathCacheNewString(ctxt, val->stringval));
   2709 	    case XPATH_BOOLEAN:
   2710 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
   2711 	    case XPATH_NUMBER:
   2712 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
   2713 	    default:
   2714 		break;
   2715 	}
   2716     }
   2717     return(xmlXPathObjectCopy(val));
   2718 }
   2719 
   2720 /**
   2721  * xmlXPathCacheConvertBoolean:
   2722  * @ctxt: the XPath context
   2723  * @val:  an XPath object
   2724  *
   2725  * This is the cached version of xmlXPathConvertBoolean().
   2726  * Converts an existing object to its boolean() equivalent
   2727  *
   2728  * Returns a created or reused object, the old one is freed (or the operation
   2729  *         is done directly on @val)
   2730  */
   2731 static xmlXPathObjectPtr
   2732 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2733     xmlXPathObjectPtr ret;
   2734 
   2735     if (val == NULL)
   2736 	return(xmlXPathCacheNewBoolean(ctxt, 0));
   2737     if (val->type == XPATH_BOOLEAN)
   2738 	return(val);
   2739     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
   2740     xmlXPathReleaseObject(ctxt, val);
   2741     return(ret);
   2742 }
   2743 
   2744 /**
   2745  * xmlXPathCacheConvertNumber:
   2746  * @ctxt: the XPath context
   2747  * @val:  an XPath object
   2748  *
   2749  * This is the cached version of xmlXPathConvertNumber().
   2750  * Converts an existing object to its number() equivalent
   2751  *
   2752  * Returns a created or reused object, the old one is freed (or the operation
   2753  *         is done directly on @val)
   2754  */
   2755 static xmlXPathObjectPtr
   2756 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
   2757     xmlXPathObjectPtr ret;
   2758 
   2759     if (val == NULL)
   2760 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
   2761     if (val->type == XPATH_NUMBER)
   2762 	return(val);
   2763     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
   2764     xmlXPathReleaseObject(ctxt, val);
   2765     return(ret);
   2766 }
   2767 
   2768 /************************************************************************
   2769  *									*
   2770  *		Parser stacks related functions and macros		*
   2771  *									*
   2772  ************************************************************************/
   2773 
   2774 /**
   2775  * xmlXPathSetFrame:
   2776  * @ctxt: an XPath parser context
   2777  *
   2778  * Set the callee evaluation frame
   2779  *
   2780  * Returns the previous frame value to be restored once done
   2781  */
   2782 static int
   2783 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
   2784     int ret;
   2785 
   2786     if (ctxt == NULL)
   2787         return(0);
   2788     ret = ctxt->valueFrame;
   2789     ctxt->valueFrame = ctxt->valueNr;
   2790     return(ret);
   2791 }
   2792 
   2793 /**
   2794  * xmlXPathPopFrame:
   2795  * @ctxt: an XPath parser context
   2796  * @frame: the previous frame value
   2797  *
   2798  * Remove the callee evaluation frame
   2799  */
   2800 static void
   2801 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
   2802     if (ctxt == NULL)
   2803         return;
   2804     if (ctxt->valueNr < ctxt->valueFrame) {
   2805         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
   2806     }
   2807     ctxt->valueFrame = frame;
   2808 }
   2809 
   2810 /**
   2811  * valuePop:
   2812  * @ctxt: an XPath evaluation context
   2813  *
   2814  * Pops the top XPath object from the value stack
   2815  *
   2816  * Returns the XPath object just removed
   2817  */
   2818 xmlXPathObjectPtr
   2819 valuePop(xmlXPathParserContextPtr ctxt)
   2820 {
   2821     xmlXPathObjectPtr ret;
   2822 
   2823     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
   2824         return (NULL);
   2825 
   2826     if (ctxt->valueNr <= ctxt->valueFrame) {
   2827         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
   2828         return (NULL);
   2829     }
   2830 
   2831     ctxt->valueNr--;
   2832     if (ctxt->valueNr > 0)
   2833         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
   2834     else
   2835         ctxt->value = NULL;
   2836     ret = ctxt->valueTab[ctxt->valueNr];
   2837     ctxt->valueTab[ctxt->valueNr] = NULL;
   2838     return (ret);
   2839 }
   2840 /**
   2841  * valuePush:
   2842  * @ctxt:  an XPath evaluation context
   2843  * @value:  the XPath object
   2844  *
   2845  * Pushes a new XPath object on top of the value stack
   2846  *
   2847  * returns the number of items on the value stack
   2848  */
   2849 int
   2850 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
   2851 {
   2852     if ((ctxt == NULL) || (value == NULL)) return(-1);
   2853     if (ctxt->valueNr >= ctxt->valueMax) {
   2854         xmlXPathObjectPtr *tmp;
   2855 
   2856         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
   2857             xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
   2858             ctxt->error = XPATH_MEMORY_ERROR;
   2859             return (0);
   2860         }
   2861         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
   2862                                              2 * ctxt->valueMax *
   2863                                              sizeof(ctxt->valueTab[0]));
   2864         if (tmp == NULL) {
   2865             xmlXPathErrMemory(NULL, "pushing value\n");
   2866             ctxt->error = XPATH_MEMORY_ERROR;
   2867             return (0);
   2868         }
   2869         ctxt->valueMax *= 2;
   2870 	ctxt->valueTab = tmp;
   2871     }
   2872     ctxt->valueTab[ctxt->valueNr] = value;
   2873     ctxt->value = value;
   2874     return (ctxt->valueNr++);
   2875 }
   2876 
   2877 /**
   2878  * xmlXPathPopBoolean:
   2879  * @ctxt:  an XPath parser context
   2880  *
   2881  * Pops a boolean from the stack, handling conversion if needed.
   2882  * Check error with #xmlXPathCheckError.
   2883  *
   2884  * Returns the boolean
   2885  */
   2886 int
   2887 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
   2888     xmlXPathObjectPtr obj;
   2889     int ret;
   2890 
   2891     obj = valuePop(ctxt);
   2892     if (obj == NULL) {
   2893 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2894 	return(0);
   2895     }
   2896     if (obj->type != XPATH_BOOLEAN)
   2897 	ret = xmlXPathCastToBoolean(obj);
   2898     else
   2899         ret = obj->boolval;
   2900     xmlXPathReleaseObject(ctxt->context, obj);
   2901     return(ret);
   2902 }
   2903 
   2904 /**
   2905  * xmlXPathPopNumber:
   2906  * @ctxt:  an XPath parser context
   2907  *
   2908  * Pops a number from the stack, handling conversion if needed.
   2909  * Check error with #xmlXPathCheckError.
   2910  *
   2911  * Returns the number
   2912  */
   2913 double
   2914 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
   2915     xmlXPathObjectPtr obj;
   2916     double ret;
   2917 
   2918     obj = valuePop(ctxt);
   2919     if (obj == NULL) {
   2920 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2921 	return(0);
   2922     }
   2923     if (obj->type != XPATH_NUMBER)
   2924 	ret = xmlXPathCastToNumber(obj);
   2925     else
   2926         ret = obj->floatval;
   2927     xmlXPathReleaseObject(ctxt->context, obj);
   2928     return(ret);
   2929 }
   2930 
   2931 /**
   2932  * xmlXPathPopString:
   2933  * @ctxt:  an XPath parser context
   2934  *
   2935  * Pops a string from the stack, handling conversion if needed.
   2936  * Check error with #xmlXPathCheckError.
   2937  *
   2938  * Returns the string
   2939  */
   2940 xmlChar *
   2941 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
   2942     xmlXPathObjectPtr obj;
   2943     xmlChar * ret;
   2944 
   2945     obj = valuePop(ctxt);
   2946     if (obj == NULL) {
   2947 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2948 	return(NULL);
   2949     }
   2950     ret = xmlXPathCastToString(obj);	/* this does required strdup */
   2951     /* TODO: needs refactoring somewhere else */
   2952     if (obj->stringval == ret)
   2953 	obj->stringval = NULL;
   2954     xmlXPathReleaseObject(ctxt->context, obj);
   2955     return(ret);
   2956 }
   2957 
   2958 /**
   2959  * xmlXPathPopNodeSet:
   2960  * @ctxt:  an XPath parser context
   2961  *
   2962  * Pops a node-set from the stack, handling conversion if needed.
   2963  * Check error with #xmlXPathCheckError.
   2964  *
   2965  * Returns the node-set
   2966  */
   2967 xmlNodeSetPtr
   2968 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
   2969     xmlXPathObjectPtr obj;
   2970     xmlNodeSetPtr ret;
   2971 
   2972     if (ctxt == NULL) return(NULL);
   2973     if (ctxt->value == NULL) {
   2974 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   2975 	return(NULL);
   2976     }
   2977     if (!xmlXPathStackIsNodeSet(ctxt)) {
   2978 	xmlXPathSetTypeError(ctxt);
   2979 	return(NULL);
   2980     }
   2981     obj = valuePop(ctxt);
   2982     ret = obj->nodesetval;
   2983 #if 0
   2984     /* to fix memory leak of not clearing obj->user */
   2985     if (obj->boolval && obj->user != NULL)
   2986         xmlFreeNodeList((xmlNodePtr) obj->user);
   2987 #endif
   2988     obj->nodesetval = NULL;
   2989     xmlXPathReleaseObject(ctxt->context, obj);
   2990     return(ret);
   2991 }
   2992 
   2993 /**
   2994  * xmlXPathPopExternal:
   2995  * @ctxt:  an XPath parser context
   2996  *
   2997  * Pops an external object from the stack, handling conversion if needed.
   2998  * Check error with #xmlXPathCheckError.
   2999  *
   3000  * Returns the object
   3001  */
   3002 void *
   3003 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
   3004     xmlXPathObjectPtr obj;
   3005     void * ret;
   3006 
   3007     if ((ctxt == NULL) || (ctxt->value == NULL)) {
   3008 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
   3009 	return(NULL);
   3010     }
   3011     if (ctxt->value->type != XPATH_USERS) {
   3012 	xmlXPathSetTypeError(ctxt);
   3013 	return(NULL);
   3014     }
   3015     obj = valuePop(ctxt);
   3016     ret = obj->user;
   3017     obj->user = NULL;
   3018     xmlXPathReleaseObject(ctxt->context, obj);
   3019     return(ret);
   3020 }
   3021 
   3022 /*
   3023  * Macros for accessing the content. Those should be used only by the parser,
   3024  * and not exported.
   3025  *
   3026  * Dirty macros, i.e. one need to make assumption on the context to use them
   3027  *
   3028  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
   3029  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
   3030  *           in ISO-Latin or UTF-8.
   3031  *           This should be used internally by the parser
   3032  *           only to compare to ASCII values otherwise it would break when
   3033  *           running with UTF-8 encoding.
   3034  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
   3035  *           to compare on ASCII based substring.
   3036  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
   3037  *           strings within the parser.
   3038  *   CURRENT Returns the current char value, with the full decoding of
   3039  *           UTF-8 if we are using this mode. It returns an int.
   3040  *   NEXT    Skip to the next character, this does the proper decoding
   3041  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
   3042  *           It returns the pointer to the current xmlChar.
   3043  */
   3044 
   3045 #define CUR (*ctxt->cur)
   3046 #define SKIP(val) ctxt->cur += (val)
   3047 #define NXT(val) ctxt->cur[(val)]
   3048 #define CUR_PTR ctxt->cur
   3049 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
   3050 
   3051 #define COPY_BUF(l,b,i,v)                                              \
   3052     if (l == 1) b[i++] = (xmlChar) v;                                  \
   3053     else i += xmlCopyChar(l,&b[i],v)
   3054 
   3055 #define NEXTL(l)  ctxt->cur += l
   3056 
   3057 #define SKIP_BLANKS							\
   3058     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
   3059 
   3060 #define CURRENT (*ctxt->cur)
   3061 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
   3062 
   3063 
   3064 #ifndef DBL_DIG
   3065 #define DBL_DIG 16
   3066 #endif
   3067 #ifndef DBL_EPSILON
   3068 #define DBL_EPSILON 1E-9
   3069 #endif
   3070 
   3071 #define UPPER_DOUBLE 1E9
   3072 #define LOWER_DOUBLE 1E-5
   3073 #define	LOWER_DOUBLE_EXP 5
   3074 
   3075 #define INTEGER_DIGITS DBL_DIG
   3076 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
   3077 #define EXPONENT_DIGITS (3 + 2)
   3078 
   3079 /**
   3080  * xmlXPathFormatNumber:
   3081  * @number:     number to format
   3082  * @buffer:     output buffer
   3083  * @buffersize: size of output buffer
   3084  *
   3085  * Convert the number into a string representation.
   3086  */
   3087 static void
   3088 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
   3089 {
   3090     switch (xmlXPathIsInf(number)) {
   3091     case 1:
   3092 	if (buffersize > (int)sizeof("Infinity"))
   3093 	    snprintf(buffer, buffersize, "Infinity");
   3094 	break;
   3095     case -1:
   3096 	if (buffersize > (int)sizeof("-Infinity"))
   3097 	    snprintf(buffer, buffersize, "-Infinity");
   3098 	break;
   3099     default:
   3100 	if (xmlXPathIsNaN(number)) {
   3101 	    if (buffersize > (int)sizeof("NaN"))
   3102 		snprintf(buffer, buffersize, "NaN");
   3103 	} else if (number == 0) {
   3104             /* Omit sign for negative zero. */
   3105 	    snprintf(buffer, buffersize, "0");
   3106 	} else if ((number > INT_MIN) && (number < INT_MAX) &&
   3107                    (number == (int) number)) {
   3108 	    char work[30];
   3109 	    char *ptr, *cur;
   3110 	    int value = (int) number;
   3111 
   3112             ptr = &buffer[0];
   3113 	    if (value == 0) {
   3114 		*ptr++ = '0';
   3115 	    } else {
   3116 		snprintf(work, 29, "%d", value);
   3117 		cur = &work[0];
   3118 		while ((*cur) && (ptr - buffer < buffersize)) {
   3119 		    *ptr++ = *cur++;
   3120 		}
   3121 	    }
   3122 	    if (ptr - buffer < buffersize) {
   3123 		*ptr = 0;
   3124 	    } else if (buffersize > 0) {
   3125 		ptr--;
   3126 		*ptr = 0;
   3127 	    }
   3128 	} else {
   3129 	    /*
   3130 	      For the dimension of work,
   3131 	          DBL_DIG is number of significant digits
   3132 		  EXPONENT is only needed for "scientific notation"
   3133 	          3 is sign, decimal point, and terminating zero
   3134 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
   3135 	      Note that this dimension is slightly (a few characters)
   3136 	      larger than actually necessary.
   3137 	    */
   3138 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
   3139 	    int integer_place, fraction_place;
   3140 	    char *ptr;
   3141 	    char *after_fraction;
   3142 	    double absolute_value;
   3143 	    int size;
   3144 
   3145 	    absolute_value = fabs(number);
   3146 
   3147 	    /*
   3148 	     * First choose format - scientific or regular floating point.
   3149 	     * In either case, result is in work, and after_fraction points
   3150 	     * just past the fractional part.
   3151 	    */
   3152 	    if ( ((absolute_value > UPPER_DOUBLE) ||
   3153 		  (absolute_value < LOWER_DOUBLE)) &&
   3154 		 (absolute_value != 0.0) ) {
   3155 		/* Use scientific notation */
   3156 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
   3157 		fraction_place = DBL_DIG - 1;
   3158 		size = snprintf(work, sizeof(work),"%*.*e",
   3159 			 integer_place, fraction_place, number);
   3160 		while ((size > 0) && (work[size] != 'e')) size--;
   3161 
   3162 	    }
   3163 	    else {
   3164 		/* Use regular notation */
   3165 		if (absolute_value > 0.0) {
   3166 		    integer_place = (int)log10(absolute_value);
   3167 		    if (integer_place > 0)
   3168 		        fraction_place = DBL_DIG - integer_place - 1;
   3169 		    else
   3170 		        fraction_place = DBL_DIG - integer_place;
   3171 		} else {
   3172 		    fraction_place = 1;
   3173 		}
   3174 		size = snprintf(work, sizeof(work), "%0.*f",
   3175 				fraction_place, number);
   3176 	    }
   3177 
   3178 	    /* Remove leading spaces sometimes inserted by snprintf */
   3179 	    while (work[0] == ' ') {
   3180 	        for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
   3181 		size--;
   3182 	    }
   3183 
   3184 	    /* Remove fractional trailing zeroes */
   3185 	    after_fraction = work + size;
   3186 	    ptr = after_fraction;
   3187 	    while (*(--ptr) == '0')
   3188 		;
   3189 	    if (*ptr != '.')
   3190 	        ptr++;
   3191 	    while ((*ptr++ = *after_fraction++) != 0);
   3192 
   3193 	    /* Finally copy result back to caller */
   3194 	    size = strlen(work) + 1;
   3195 	    if (size > buffersize) {
   3196 		work[buffersize - 1] = 0;
   3197 		size = buffersize;
   3198 	    }
   3199 	    memmove(buffer, work, size);
   3200 	}
   3201 	break;
   3202     }
   3203 }
   3204 
   3205 
   3206 /************************************************************************
   3207  *									*
   3208  *			Routines to handle NodeSets			*
   3209  *									*
   3210  ************************************************************************/
   3211 
   3212 /**
   3213  * xmlXPathOrderDocElems:
   3214  * @doc:  an input document
   3215  *
   3216  * Call this routine to speed up XPath computation on static documents.
   3217  * This stamps all the element nodes with the document order
   3218  * Like for line information, the order is kept in the element->content
   3219  * field, the value stored is actually - the node number (starting at -1)
   3220  * to be able to differentiate from line numbers.
   3221  *
   3222  * Returns the number of elements found in the document or -1 in case
   3223  *    of error.
   3224  */
   3225 long
   3226 xmlXPathOrderDocElems(xmlDocPtr doc) {
   3227     ptrdiff_t count = 0;
   3228     xmlNodePtr cur;
   3229 
   3230     if (doc == NULL)
   3231 	return(-1);
   3232     cur = doc->children;
   3233     while (cur != NULL) {
   3234 	if (cur->type == XML_ELEMENT_NODE) {
   3235 	    cur->content = (void *) (-(++count));
   3236 	    if (cur->children != NULL) {
   3237 		cur = cur->children;
   3238 		continue;
   3239 	    }
   3240 	}
   3241 	if (cur->next != NULL) {
   3242 	    cur = cur->next;
   3243 	    continue;
   3244 	}
   3245 	do {
   3246 	    cur = cur->parent;
   3247 	    if (cur == NULL)
   3248 		break;
   3249 	    if (cur == (xmlNodePtr) doc) {
   3250 		cur = NULL;
   3251 		break;
   3252 	    }
   3253 	    if (cur->next != NULL) {
   3254 		cur = cur->next;
   3255 		break;
   3256 	    }
   3257 	} while (cur != NULL);
   3258     }
   3259     return((long) count);
   3260 }
   3261 
   3262 /**
   3263  * xmlXPathCmpNodes:
   3264  * @node1:  the first node
   3265  * @node2:  the second node
   3266  *
   3267  * Compare two nodes w.r.t document order
   3268  *
   3269  * Returns -2 in case of error 1 if first point < second point, 0 if
   3270  *         it's the same node, -1 otherwise
   3271  */
   3272 int
   3273 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
   3274     int depth1, depth2;
   3275     int attr1 = 0, attr2 = 0;
   3276     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
   3277     xmlNodePtr cur, root;
   3278 
   3279     if ((node1 == NULL) || (node2 == NULL))
   3280 	return(-2);
   3281     /*
   3282      * a couple of optimizations which will avoid computations in most cases
   3283      */
   3284     if (node1 == node2)		/* trivial case */
   3285 	return(0);
   3286     if (node1->type == XML_ATTRIBUTE_NODE) {
   3287 	attr1 = 1;
   3288 	attrNode1 = node1;
   3289 	node1 = node1->parent;
   3290     }
   3291     if (node2->type == XML_ATTRIBUTE_NODE) {
   3292 	attr2 = 1;
   3293 	attrNode2 = node2;
   3294 	node2 = node2->parent;
   3295     }
   3296     if (node1 == node2) {
   3297 	if (attr1 == attr2) {
   3298 	    /* not required, but we keep attributes in order */
   3299 	    if (attr1 != 0) {
   3300 	        cur = attrNode2->prev;
   3301 		while (cur != NULL) {
   3302 		    if (cur == attrNode1)
   3303 		        return (1);
   3304 		    cur = cur->prev;
   3305 		}
   3306 		return (-1);
   3307 	    }
   3308 	    return(0);
   3309 	}
   3310 	if (attr2 == 1)
   3311 	    return(1);
   3312 	return(-1);
   3313     }
   3314     if ((node1->type == XML_NAMESPACE_DECL) ||
   3315         (node2->type == XML_NAMESPACE_DECL))
   3316 	return(1);
   3317     if (node1 == node2->prev)
   3318 	return(1);
   3319     if (node1 == node2->next)
   3320 	return(-1);
   3321 
   3322     /*
   3323      * Speedup using document order if availble.
   3324      */
   3325     if ((node1->type == XML_ELEMENT_NODE) &&
   3326 	(node2->type == XML_ELEMENT_NODE) &&
   3327 	(0 > (ptrdiff_t) node1->content) &&
   3328 	(0 > (ptrdiff_t) node2->content) &&
   3329 	(node1->doc == node2->doc)) {
   3330 	ptrdiff_t l1, l2;
   3331 
   3332 	l1 = -((ptrdiff_t) node1->content);
   3333 	l2 = -((ptrdiff_t) node2->content);
   3334 	if (l1 < l2)
   3335 	    return(1);
   3336 	if (l1 > l2)
   3337 	    return(-1);
   3338     }
   3339 
   3340     /*
   3341      * compute depth to root
   3342      */
   3343     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
   3344 	if (cur->parent == node1)
   3345 	    return(1);
   3346 	depth2++;
   3347     }
   3348     root = cur;
   3349     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
   3350 	if (cur->parent == node2)
   3351 	    return(-1);
   3352 	depth1++;
   3353     }
   3354     /*
   3355      * Distinct document (or distinct entities :-( ) case.
   3356      */
   3357     if (root != cur) {
   3358 	return(-2);
   3359     }
   3360     /*
   3361      * get the nearest common ancestor.
   3362      */
   3363     while (depth1 > depth2) {
   3364 	depth1--;
   3365 	node1 = node1->parent;
   3366     }
   3367     while (depth2 > depth1) {
   3368 	depth2--;
   3369 	node2 = node2->parent;
   3370     }
   3371     while (node1->parent != node2->parent) {
   3372 	node1 = node1->parent;
   3373 	node2 = node2->parent;
   3374 	/* should not happen but just in case ... */
   3375 	if ((node1 == NULL) || (node2 == NULL))
   3376 	    return(-2);
   3377     }
   3378     /*
   3379      * Find who's first.
   3380      */
   3381     if (node1 == node2->prev)
   3382 	return(1);
   3383     if (node1 == node2->next)
   3384 	return(-1);
   3385     /*
   3386      * Speedup using document order if availble.
   3387      */
   3388     if ((node1->type == XML_ELEMENT_NODE) &&
   3389 	(node2->type == XML_ELEMENT_NODE) &&
   3390 	(0 > (ptrdiff_t) node1->content) &&
   3391 	(0 > (ptrdiff_t) node2->content) &&
   3392 	(node1->doc == node2->doc)) {
   3393 	ptrdiff_t l1, l2;
   3394 
   3395 	l1 = -((ptrdiff_t) node1->content);
   3396 	l2 = -((ptrdiff_t) node2->content);
   3397 	if (l1 < l2)
   3398 	    return(1);
   3399 	if (l1 > l2)
   3400 	    return(-1);
   3401     }
   3402 
   3403     for (cur = node1->next;cur != NULL;cur = cur->next)
   3404 	if (cur == node2)
   3405 	    return(1);
   3406     return(-1); /* assume there is no sibling list corruption */
   3407 }
   3408 
   3409 /**
   3410  * xmlXPathNodeSetSort:
   3411  * @set:  the node set
   3412  *
   3413  * Sort the node set in document order
   3414  */
   3415 void
   3416 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
   3417 #ifndef WITH_TIM_SORT
   3418     int i, j, incr, len;
   3419     xmlNodePtr tmp;
   3420 #endif
   3421 
   3422     if (set == NULL)
   3423 	return;
   3424 
   3425 #ifndef WITH_TIM_SORT
   3426     /*
   3427      * Use the old Shell's sort implementation to sort the node-set
   3428      * Timsort ought to be quite faster
   3429      */
   3430     len = set->nodeNr;
   3431     for (incr = len / 2; incr > 0; incr /= 2) {
   3432 	for (i = incr; i < len; i++) {
   3433 	    j = i - incr;
   3434 	    while (j >= 0) {
   3435 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   3436 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
   3437 			set->nodeTab[j + incr]) == -1)
   3438 #else
   3439 		if (xmlXPathCmpNodes(set->nodeTab[j],
   3440 			set->nodeTab[j + incr]) == -1)
   3441 #endif
   3442 		{
   3443 		    tmp = set->nodeTab[j];
   3444 		    set->nodeTab[j] = set->nodeTab[j + incr];
   3445 		    set->nodeTab[j + incr] = tmp;
   3446 		    j -= incr;
   3447 		} else
   3448 		    break;
   3449 	    }
   3450 	}
   3451     }
   3452 #else /* WITH_TIM_SORT */
   3453     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
   3454 #endif /* WITH_TIM_SORT */
   3455 }
   3456 
   3457 #define XML_NODESET_DEFAULT	10
   3458 /**
   3459  * xmlXPathNodeSetDupNs:
   3460  * @node:  the parent node of the namespace XPath node
   3461  * @ns:  the libxml namespace declaration node.
   3462  *
   3463  * Namespace node in libxml don't match the XPath semantic. In a node set
   3464  * the namespace nodes are duplicated and the next pointer is set to the
   3465  * parent node in the XPath semantic.
   3466  *
   3467  * Returns the newly created object.
   3468  */
   3469 static xmlNodePtr
   3470 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
   3471     xmlNsPtr cur;
   3472 
   3473     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
   3474 	return(NULL);
   3475     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
   3476 	return((xmlNodePtr) ns);
   3477 
   3478     /*
   3479      * Allocate a new Namespace and fill the fields.
   3480      */
   3481     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
   3482     if (cur == NULL) {
   3483         xmlXPathErrMemory(NULL, "duplicating namespace\n");
   3484 	return(NULL);
   3485     }
   3486     memset(cur, 0, sizeof(xmlNs));
   3487     cur->type = XML_NAMESPACE_DECL;
   3488     if (ns->href != NULL)
   3489 	cur->href = xmlStrdup(ns->href);
   3490     if (ns->prefix != NULL)
   3491 	cur->prefix = xmlStrdup(ns->prefix);
   3492     cur->next = (xmlNsPtr) node;
   3493     return((xmlNodePtr) cur);
   3494 }
   3495 
   3496 /**
   3497  * xmlXPathNodeSetFreeNs:
   3498  * @ns:  the XPath namespace node found in a nodeset.
   3499  *
   3500  * Namespace nodes in libxml don't match the XPath semantic. In a node set
   3501  * the namespace nodes are duplicated and the next pointer is set to the
   3502  * parent node in the XPath semantic. Check if such a node needs to be freed
   3503  */
   3504 void
   3505 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
   3506     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
   3507 	return;
   3508 
   3509     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
   3510 	if (ns->href != NULL)
   3511 	    xmlFree((xmlChar *)ns->href);
   3512 	if (ns->prefix != NULL)
   3513 	    xmlFree((xmlChar *)ns->prefix);
   3514 	xmlFree(ns);
   3515     }
   3516 }
   3517 
   3518 /**
   3519  * xmlXPathNodeSetCreate:
   3520  * @val:  an initial xmlNodePtr, or NULL
   3521  *
   3522  * Create a new xmlNodeSetPtr of type double and of value @val
   3523  *
   3524  * Returns the newly created object.
   3525  */
   3526 xmlNodeSetPtr
   3527 xmlXPathNodeSetCreate(xmlNodePtr val) {
   3528     xmlNodeSetPtr ret;
   3529 
   3530     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
   3531     if (ret == NULL) {
   3532         xmlXPathErrMemory(NULL, "creating nodeset\n");
   3533 	return(NULL);
   3534     }
   3535     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
   3536     if (val != NULL) {
   3537         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3538 					     sizeof(xmlNodePtr));
   3539 	if (ret->nodeTab == NULL) {
   3540 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
   3541 	    xmlFree(ret);
   3542 	    return(NULL);
   3543 	}
   3544 	memset(ret->nodeTab, 0 ,
   3545 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3546         ret->nodeMax = XML_NODESET_DEFAULT;
   3547 	if (val->type == XML_NAMESPACE_DECL) {
   3548 	    xmlNsPtr ns = (xmlNsPtr) val;
   3549 
   3550 	    ret->nodeTab[ret->nodeNr++] =
   3551 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3552 	} else
   3553 	    ret->nodeTab[ret->nodeNr++] = val;
   3554     }
   3555     return(ret);
   3556 }
   3557 
   3558 /**
   3559  * xmlXPathNodeSetCreateSize:
   3560  * @size:  the initial size of the set
   3561  *
   3562  * Create a new xmlNodeSetPtr of type double and of value @val
   3563  *
   3564  * Returns the newly created object.
   3565  */
   3566 static xmlNodeSetPtr
   3567 xmlXPathNodeSetCreateSize(int size) {
   3568     xmlNodeSetPtr ret;
   3569 
   3570     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
   3571     if (ret == NULL) {
   3572         xmlXPathErrMemory(NULL, "creating nodeset\n");
   3573 	return(NULL);
   3574     }
   3575     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
   3576     if (size < XML_NODESET_DEFAULT)
   3577 	size = XML_NODESET_DEFAULT;
   3578     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
   3579     if (ret->nodeTab == NULL) {
   3580 	xmlXPathErrMemory(NULL, "creating nodeset\n");
   3581 	xmlFree(ret);
   3582 	return(NULL);
   3583     }
   3584     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
   3585     ret->nodeMax = size;
   3586     return(ret);
   3587 }
   3588 
   3589 /**
   3590  * xmlXPathNodeSetContains:
   3591  * @cur:  the node-set
   3592  * @val:  the node
   3593  *
   3594  * checks whether @cur contains @val
   3595  *
   3596  * Returns true (1) if @cur contains @val, false (0) otherwise
   3597  */
   3598 int
   3599 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
   3600     int i;
   3601 
   3602     if ((cur == NULL) || (val == NULL)) return(0);
   3603     if (val->type == XML_NAMESPACE_DECL) {
   3604 	for (i = 0; i < cur->nodeNr; i++) {
   3605 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
   3606 		xmlNsPtr ns1, ns2;
   3607 
   3608 		ns1 = (xmlNsPtr) val;
   3609 		ns2 = (xmlNsPtr) cur->nodeTab[i];
   3610 		if (ns1 == ns2)
   3611 		    return(1);
   3612 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
   3613 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
   3614 		    return(1);
   3615 	    }
   3616 	}
   3617     } else {
   3618 	for (i = 0; i < cur->nodeNr; i++) {
   3619 	    if (cur->nodeTab[i] == val)
   3620 		return(1);
   3621 	}
   3622     }
   3623     return(0);
   3624 }
   3625 
   3626 /**
   3627  * xmlXPathNodeSetAddNs:
   3628  * @cur:  the initial node set
   3629  * @node:  the hosting node
   3630  * @ns:  a the namespace node
   3631  *
   3632  * add a new namespace node to an existing NodeSet
   3633  *
   3634  * Returns 0 in case of success and -1 in case of error
   3635  */
   3636 int
   3637 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
   3638     int i;
   3639 
   3640 
   3641     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
   3642         (ns->type != XML_NAMESPACE_DECL) ||
   3643 	(node->type != XML_ELEMENT_NODE))
   3644 	return(-1);
   3645 
   3646     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3647     /*
   3648      * prevent duplicates
   3649      */
   3650     for (i = 0;i < cur->nodeNr;i++) {
   3651         if ((cur->nodeTab[i] != NULL) &&
   3652 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
   3653 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
   3654 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
   3655 	    return(0);
   3656     }
   3657 
   3658     /*
   3659      * grow the nodeTab if needed
   3660      */
   3661     if (cur->nodeMax == 0) {
   3662         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3663 					     sizeof(xmlNodePtr));
   3664 	if (cur->nodeTab == NULL) {
   3665 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3666 	    return(-1);
   3667 	}
   3668 	memset(cur->nodeTab, 0 ,
   3669 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3670         cur->nodeMax = XML_NODESET_DEFAULT;
   3671     } else if (cur->nodeNr == cur->nodeMax) {
   3672         xmlNodePtr *temp;
   3673 
   3674         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   3675             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
   3676             return(-1);
   3677         }
   3678 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
   3679 				      sizeof(xmlNodePtr));
   3680 	if (temp == NULL) {
   3681 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3682 	    return(-1);
   3683 	}
   3684         cur->nodeMax *= 2;
   3685 	cur->nodeTab = temp;
   3686     }
   3687     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
   3688     return(0);
   3689 }
   3690 
   3691 /**
   3692  * xmlXPathNodeSetAdd:
   3693  * @cur:  the initial node set
   3694  * @val:  a new xmlNodePtr
   3695  *
   3696  * add a new xmlNodePtr to an existing NodeSet
   3697  *
   3698  * Returns 0 in case of success, and -1 in case of error
   3699  */
   3700 int
   3701 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
   3702     int i;
   3703 
   3704     if ((cur == NULL) || (val == NULL)) return(-1);
   3705 
   3706     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3707     /*
   3708      * prevent duplicates
   3709      */
   3710     for (i = 0;i < cur->nodeNr;i++)
   3711         if (cur->nodeTab[i] == val) return(0);
   3712 
   3713     /*
   3714      * grow the nodeTab if needed
   3715      */
   3716     if (cur->nodeMax == 0) {
   3717         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3718 					     sizeof(xmlNodePtr));
   3719 	if (cur->nodeTab == NULL) {
   3720 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3721 	    return(-1);
   3722 	}
   3723 	memset(cur->nodeTab, 0 ,
   3724 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3725         cur->nodeMax = XML_NODESET_DEFAULT;
   3726     } else if (cur->nodeNr == cur->nodeMax) {
   3727         xmlNodePtr *temp;
   3728 
   3729         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   3730             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
   3731             return(-1);
   3732         }
   3733 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
   3734 				      sizeof(xmlNodePtr));
   3735 	if (temp == NULL) {
   3736 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3737 	    return(-1);
   3738 	}
   3739         cur->nodeMax *= 2;
   3740 	cur->nodeTab = temp;
   3741     }
   3742     if (val->type == XML_NAMESPACE_DECL) {
   3743 	xmlNsPtr ns = (xmlNsPtr) val;
   3744 
   3745 	cur->nodeTab[cur->nodeNr++] =
   3746 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3747     } else
   3748 	cur->nodeTab[cur->nodeNr++] = val;
   3749     return(0);
   3750 }
   3751 
   3752 /**
   3753  * xmlXPathNodeSetAddUnique:
   3754  * @cur:  the initial node set
   3755  * @val:  a new xmlNodePtr
   3756  *
   3757  * add a new xmlNodePtr to an existing NodeSet, optimized version
   3758  * when we are sure the node is not already in the set.
   3759  *
   3760  * Returns 0 in case of success and -1 in case of failure
   3761  */
   3762 int
   3763 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
   3764     if ((cur == NULL) || (val == NULL)) return(-1);
   3765 
   3766     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3767     /*
   3768      * grow the nodeTab if needed
   3769      */
   3770     if (cur->nodeMax == 0) {
   3771         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3772 					     sizeof(xmlNodePtr));
   3773 	if (cur->nodeTab == NULL) {
   3774 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3775 	    return(-1);
   3776 	}
   3777 	memset(cur->nodeTab, 0 ,
   3778 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3779         cur->nodeMax = XML_NODESET_DEFAULT;
   3780     } else if (cur->nodeNr == cur->nodeMax) {
   3781         xmlNodePtr *temp;
   3782 
   3783         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   3784             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
   3785             return(-1);
   3786         }
   3787 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
   3788 				      sizeof(xmlNodePtr));
   3789 	if (temp == NULL) {
   3790 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
   3791 	    return(-1);
   3792 	}
   3793 	cur->nodeTab = temp;
   3794         cur->nodeMax *= 2;
   3795     }
   3796     if (val->type == XML_NAMESPACE_DECL) {
   3797 	xmlNsPtr ns = (xmlNsPtr) val;
   3798 
   3799 	cur->nodeTab[cur->nodeNr++] =
   3800 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3801     } else
   3802 	cur->nodeTab[cur->nodeNr++] = val;
   3803     return(0);
   3804 }
   3805 
   3806 /**
   3807  * xmlXPathNodeSetMerge:
   3808  * @val1:  the first NodeSet or NULL
   3809  * @val2:  the second NodeSet
   3810  *
   3811  * Merges two nodesets, all nodes from @val2 are added to @val1
   3812  * if @val1 is NULL, a new set is created and copied from @val2
   3813  *
   3814  * Returns @val1 once extended or NULL in case of error.
   3815  */
   3816 xmlNodeSetPtr
   3817 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
   3818     int i, j, initNr, skip;
   3819     xmlNodePtr n1, n2;
   3820 
   3821     if (val2 == NULL) return(val1);
   3822     if (val1 == NULL) {
   3823 	val1 = xmlXPathNodeSetCreate(NULL);
   3824     if (val1 == NULL)
   3825         return (NULL);
   3826 #if 0
   3827 	/*
   3828 	* TODO: The optimization won't work in every case, since
   3829 	*  those nasty namespace nodes need to be added with
   3830 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
   3831 	*  memcpy is not possible.
   3832 	*  If there was a flag on the nodesetval, indicating that
   3833 	*  some temporary nodes are in, that would be helpfull.
   3834 	*/
   3835 	/*
   3836 	* Optimization: Create an equally sized node-set
   3837 	* and memcpy the content.
   3838 	*/
   3839 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
   3840 	if (val1 == NULL)
   3841 	    return(NULL);
   3842 	if (val2->nodeNr != 0) {
   3843 	    if (val2->nodeNr == 1)
   3844 		*(val1->nodeTab) = *(val2->nodeTab);
   3845 	    else {
   3846 		memcpy(val1->nodeTab, val2->nodeTab,
   3847 		    val2->nodeNr * sizeof(xmlNodePtr));
   3848 	    }
   3849 	    val1->nodeNr = val2->nodeNr;
   3850 	}
   3851 	return(val1);
   3852 #endif
   3853     }
   3854 
   3855     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   3856     initNr = val1->nodeNr;
   3857 
   3858     for (i = 0;i < val2->nodeNr;i++) {
   3859 	n2 = val2->nodeTab[i];
   3860 	/*
   3861 	 * check against duplicates
   3862 	 */
   3863 	skip = 0;
   3864 	for (j = 0; j < initNr; j++) {
   3865 	    n1 = val1->nodeTab[j];
   3866 	    if (n1 == n2) {
   3867 		skip = 1;
   3868 		break;
   3869 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
   3870 		       (n2->type == XML_NAMESPACE_DECL)) {
   3871 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
   3872 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
   3873 			((xmlNsPtr) n2)->prefix)))
   3874 		{
   3875 		    skip = 1;
   3876 		    break;
   3877 		}
   3878 	    }
   3879 	}
   3880 	if (skip)
   3881 	    continue;
   3882 
   3883 	/*
   3884 	 * grow the nodeTab if needed
   3885 	 */
   3886 	if (val1->nodeMax == 0) {
   3887 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
   3888 						    sizeof(xmlNodePtr));
   3889 	    if (val1->nodeTab == NULL) {
   3890 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3891 		return(NULL);
   3892 	    }
   3893 	    memset(val1->nodeTab, 0 ,
   3894 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   3895 	    val1->nodeMax = XML_NODESET_DEFAULT;
   3896 	} else if (val1->nodeNr == val1->nodeMax) {
   3897 	    xmlNodePtr *temp;
   3898 
   3899             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   3900                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
   3901                 return(NULL);
   3902             }
   3903 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
   3904 					     sizeof(xmlNodePtr));
   3905 	    if (temp == NULL) {
   3906 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
   3907 		return(NULL);
   3908 	    }
   3909 	    val1->nodeTab = temp;
   3910 	    val1->nodeMax *= 2;
   3911 	}
   3912 	if (n2->type == XML_NAMESPACE_DECL) {
   3913 	    xmlNsPtr ns = (xmlNsPtr) n2;
   3914 
   3915 	    val1->nodeTab[val1->nodeNr++] =
   3916 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
   3917 	} else
   3918 	    val1->nodeTab[val1->nodeNr++] = n2;
   3919     }
   3920 
   3921     return(val1);
   3922 }
   3923 
   3924 
   3925 /**
   3926  * xmlXPathNodeSetMergeAndClear:
   3927  * @set1:  the first NodeSet or NULL
   3928  * @set2:  the second NodeSet
   3929  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
   3930  *
   3931  * Merges two nodesets, all nodes from @set2 are added to @set1
   3932  * if @set1 is NULL, a new set is created and copied from @set2.
   3933  * Checks for duplicate nodes. Clears set2.
   3934  *
   3935  * Returns @set1 once extended or NULL in case of error.
   3936  */
   3937 static xmlNodeSetPtr
   3938 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
   3939 			     int hasNullEntries)
   3940 {
   3941     if ((set1 == NULL) && (hasNullEntries == 0)) {
   3942 	/*
   3943 	* Note that doing a memcpy of the list, namespace nodes are
   3944 	* just assigned to set1, since set2 is cleared anyway.
   3945 	*/
   3946 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
   3947 	if (set1 == NULL)
   3948 	    return(NULL);
   3949 	if (set2->nodeNr != 0) {
   3950 	    memcpy(set1->nodeTab, set2->nodeTab,
   3951 		set2->nodeNr * sizeof(xmlNodePtr));
   3952 	    set1->nodeNr = set2->nodeNr;
   3953 	}
   3954     } else {
   3955 	int i, j, initNbSet1;
   3956 	xmlNodePtr n1, n2;
   3957 
   3958 	if (set1 == NULL)
   3959             set1 = xmlXPathNodeSetCreate(NULL);
   3960         if (set1 == NULL)
   3961             return (NULL);
   3962 
   3963 	initNbSet1 = set1->nodeNr;
   3964 	for (i = 0;i < set2->nodeNr;i++) {
   3965 	    n2 = set2->nodeTab[i];
   3966 	    /*
   3967 	    * Skip NULLed entries.
   3968 	    */
   3969 	    if (n2 == NULL)
   3970 		continue;
   3971 	    /*
   3972 	    * Skip duplicates.
   3973 	    */
   3974 	    for (j = 0; j < initNbSet1; j++) {
   3975 		n1 = set1->nodeTab[j];
   3976 		if (n1 == n2) {
   3977 		    goto skip_node;
   3978 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
   3979 		    (n2->type == XML_NAMESPACE_DECL))
   3980 		{
   3981 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
   3982 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
   3983 			((xmlNsPtr) n2)->prefix)))
   3984 		    {
   3985 			/*
   3986 			* Free the namespace node.
   3987 			*/
   3988 			set2->nodeTab[i] = NULL;
   3989 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
   3990 			goto skip_node;
   3991 		    }
   3992 		}
   3993 	    }
   3994 	    /*
   3995 	    * grow the nodeTab if needed
   3996 	    */
   3997 	    if (set1->nodeMax == 0) {
   3998 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
   3999 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
   4000 		if (set1->nodeTab == NULL) {
   4001 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   4002 		    return(NULL);
   4003 		}
   4004 		memset(set1->nodeTab, 0,
   4005 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   4006 		set1->nodeMax = XML_NODESET_DEFAULT;
   4007 	    } else if (set1->nodeNr >= set1->nodeMax) {
   4008 		xmlNodePtr *temp;
   4009 
   4010                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   4011                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
   4012                     return(NULL);
   4013                 }
   4014 		temp = (xmlNodePtr *) xmlRealloc(
   4015 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
   4016 		if (temp == NULL) {
   4017 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   4018 		    return(NULL);
   4019 		}
   4020 		set1->nodeTab = temp;
   4021 		set1->nodeMax *= 2;
   4022 	    }
   4023 	    set1->nodeTab[set1->nodeNr++] = n2;
   4024 skip_node:
   4025 	    {}
   4026 	}
   4027     }
   4028     set2->nodeNr = 0;
   4029     return(set1);
   4030 }
   4031 
   4032 /**
   4033  * xmlXPathNodeSetMergeAndClearNoDupls:
   4034  * @set1:  the first NodeSet or NULL
   4035  * @set2:  the second NodeSet
   4036  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
   4037  *
   4038  * Merges two nodesets, all nodes from @set2 are added to @set1
   4039  * if @set1 is NULL, a new set is created and copied from @set2.
   4040  * Doesn't chack for duplicate nodes. Clears set2.
   4041  *
   4042  * Returns @set1 once extended or NULL in case of error.
   4043  */
   4044 static xmlNodeSetPtr
   4045 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
   4046 				    int hasNullEntries)
   4047 {
   4048     if (set2 == NULL)
   4049 	return(set1);
   4050     if ((set1 == NULL) && (hasNullEntries == 0)) {
   4051 	/*
   4052 	* Note that doing a memcpy of the list, namespace nodes are
   4053 	* just assigned to set1, since set2 is cleared anyway.
   4054 	*/
   4055 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
   4056 	if (set1 == NULL)
   4057 	    return(NULL);
   4058 	if (set2->nodeNr != 0) {
   4059 	    memcpy(set1->nodeTab, set2->nodeTab,
   4060 		set2->nodeNr * sizeof(xmlNodePtr));
   4061 	    set1->nodeNr = set2->nodeNr;
   4062 	}
   4063     } else {
   4064 	int i;
   4065 	xmlNodePtr n2;
   4066 
   4067 	if (set1 == NULL)
   4068 	    set1 = xmlXPathNodeSetCreate(NULL);
   4069         if (set1 == NULL)
   4070             return (NULL);
   4071 
   4072 	for (i = 0;i < set2->nodeNr;i++) {
   4073 	    n2 = set2->nodeTab[i];
   4074 	    /*
   4075 	    * Skip NULLed entries.
   4076 	    */
   4077 	    if (n2 == NULL)
   4078 		continue;
   4079 	    if (set1->nodeMax == 0) {
   4080 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
   4081 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
   4082 		if (set1->nodeTab == NULL) {
   4083 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   4084 		    return(NULL);
   4085 		}
   4086 		memset(set1->nodeTab, 0,
   4087 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
   4088 		set1->nodeMax = XML_NODESET_DEFAULT;
   4089 	    } else if (set1->nodeNr >= set1->nodeMax) {
   4090 		xmlNodePtr *temp;
   4091 
   4092                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
   4093                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
   4094                     return(NULL);
   4095                 }
   4096 		temp = (xmlNodePtr *) xmlRealloc(
   4097 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
   4098 		if (temp == NULL) {
   4099 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
   4100 		    return(NULL);
   4101 		}
   4102 		set1->nodeTab = temp;
   4103 		set1->nodeMax *= 2;
   4104 	    }
   4105 	    set1->nodeTab[set1->nodeNr++] = n2;
   4106 	}
   4107     }
   4108     set2->nodeNr = 0;
   4109     return(set1);
   4110 }
   4111 
   4112 /**
   4113  * xmlXPathNodeSetDel:
   4114  * @cur:  the initial node set
   4115  * @val:  an xmlNodePtr
   4116  *
   4117  * Removes an xmlNodePtr from an existing NodeSet
   4118  */
   4119 void
   4120 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
   4121     int i;
   4122 
   4123     if (cur == NULL) return;
   4124     if (val == NULL) return;
   4125 
   4126     /*
   4127      * find node in nodeTab
   4128      */
   4129     for (i = 0;i < cur->nodeNr;i++)
   4130         if (cur->nodeTab[i] == val) break;
   4131 
   4132     if (i >= cur->nodeNr) {	/* not found */
   4133 #ifdef DEBUG
   4134         xmlGenericError(xmlGenericErrorContext,
   4135 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
   4136 		val->name);
   4137 #endif
   4138         return;
   4139     }
   4140     if ((cur->nodeTab[i] != NULL) &&
   4141 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
   4142 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
   4143     cur->nodeNr--;
   4144     for (;i < cur->nodeNr;i++)
   4145         cur->nodeTab[i] = cur->nodeTab[i + 1];
   4146     cur->nodeTab[cur->nodeNr] = NULL;
   4147 }
   4148 
   4149 /**
   4150  * xmlXPathNodeSetRemove:
   4151  * @cur:  the initial node set
   4152  * @val:  the index to remove
   4153  *
   4154  * Removes an entry from an existing NodeSet list.
   4155  */
   4156 void
   4157 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
   4158     if (cur == NULL) return;
   4159     if (val >= cur->nodeNr) return;
   4160     if ((cur->nodeTab[val] != NULL) &&
   4161 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
   4162 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
   4163     cur->nodeNr--;
   4164     for (;val < cur->nodeNr;val++)
   4165         cur->nodeTab[val] = cur->nodeTab[val + 1];
   4166     cur->nodeTab[cur->nodeNr] = NULL;
   4167 }
   4168 
   4169 /**
   4170  * xmlXPathFreeNodeSet:
   4171  * @obj:  the xmlNodeSetPtr to free
   4172  *
   4173  * Free the NodeSet compound (not the actual nodes !).
   4174  */
   4175 void
   4176 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
   4177     if (obj == NULL) return;
   4178     if (obj->nodeTab != NULL) {
   4179 	int i;
   4180 
   4181 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
   4182 	for (i = 0;i < obj->nodeNr;i++)
   4183 	    if ((obj->nodeTab[i] != NULL) &&
   4184 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
   4185 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
   4186 	xmlFree(obj->nodeTab);
   4187     }
   4188     xmlFree(obj);
   4189 }
   4190 
   4191 /**
   4192  * xmlXPathNodeSetClearFromPos:
   4193  * @set: the node set to be cleared
   4194  * @pos: the start position to clear from
   4195  *
   4196  * Clears the list from temporary XPath objects (e.g. namespace nodes
   4197  * are feed) starting with the entry at @pos, but does *not* free the list
   4198  * itself. Sets the length of the list to @pos.
   4199  */
   4200 static void
   4201 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
   4202 {
   4203     if ((set == NULL) || (pos >= set->nodeNr))
   4204 	return;
   4205     else if ((hasNsNodes)) {
   4206 	int i;
   4207 	xmlNodePtr node;
   4208 
   4209 	for (i = pos; i < set->nodeNr; i++) {
   4210 	    node = set->nodeTab[i];
   4211 	    if ((node != NULL) &&
   4212 		(node->type == XML_NAMESPACE_DECL))
   4213 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   4214 	}
   4215     }
   4216     set->nodeNr = pos;
   4217 }
   4218 
   4219 /**
   4220  * xmlXPathNodeSetClear:
   4221  * @set:  the node set to clear
   4222  *
   4223  * Clears the list from all temporary XPath objects (e.g. namespace nodes
   4224  * are feed), but does *not* free the list itself. Sets the length of the
   4225  * list to 0.
   4226  */
   4227 static void
   4228 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
   4229 {
   4230     xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
   4231 }
   4232 
   4233 /**
   4234  * xmlXPathNodeSetKeepLast:
   4235  * @set: the node set to be cleared
   4236  *
   4237  * Move the last node to the first position and clear temporary XPath objects
   4238  * (e.g. namespace nodes) from all other nodes. Sets the length of the list
   4239  * to 1.
   4240  */
   4241 static void
   4242 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
   4243 {
   4244     int i;
   4245     xmlNodePtr node;
   4246 
   4247     if ((set == NULL) || (set->nodeNr <= 1))
   4248 	return;
   4249     for (i = 0; i < set->nodeNr - 1; i++) {
   4250         node = set->nodeTab[i];
   4251         if ((node != NULL) &&
   4252             (node->type == XML_NAMESPACE_DECL))
   4253             xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   4254     }
   4255     set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
   4256     set->nodeNr = 1;
   4257 }
   4258 
   4259 /**
   4260  * xmlXPathFreeValueTree:
   4261  * @obj:  the xmlNodeSetPtr to free
   4262  *
   4263  * Free the NodeSet compound and the actual tree, this is different
   4264  * from xmlXPathFreeNodeSet()
   4265  */
   4266 static void
   4267 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
   4268     int i;
   4269 
   4270     if (obj == NULL) return;
   4271 
   4272     if (obj->nodeTab != NULL) {
   4273 	for (i = 0;i < obj->nodeNr;i++) {
   4274 	    if (obj->nodeTab[i] != NULL) {
   4275 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
   4276 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
   4277 		} else {
   4278 		    xmlFreeNodeList(obj->nodeTab[i]);
   4279 		}
   4280 	    }
   4281 	}
   4282 	xmlFree(obj->nodeTab);
   4283     }
   4284     xmlFree(obj);
   4285 }
   4286 
   4287 #if defined(DEBUG) || defined(DEBUG_STEP)
   4288 /**
   4289  * xmlGenericErrorContextNodeSet:
   4290  * @output:  a FILE * for the output
   4291  * @obj:  the xmlNodeSetPtr to display
   4292  *
   4293  * Quick display of a NodeSet
   4294  */
   4295 void
   4296 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
   4297     int i;
   4298 
   4299     if (output == NULL) output = xmlGenericErrorContext;
   4300     if (obj == NULL)  {
   4301         fprintf(output, "NodeSet == NULL !\n");
   4302 	return;
   4303     }
   4304     if (obj->nodeNr == 0) {
   4305         fprintf(output, "NodeSet is empty\n");
   4306 	return;
   4307     }
   4308     if (obj->nodeTab == NULL) {
   4309 	fprintf(output, " nodeTab == NULL !\n");
   4310 	return;
   4311     }
   4312     for (i = 0; i < obj->nodeNr; i++) {
   4313         if (obj->nodeTab[i] == NULL) {
   4314 	    fprintf(output, " NULL !\n");
   4315 	    return;
   4316         }
   4317 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
   4318 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
   4319 	    fprintf(output, " /");
   4320 	else if (obj->nodeTab[i]->name == NULL)
   4321 	    fprintf(output, " noname!");
   4322 	else fprintf(output, " %s", obj->nodeTab[i]->name);
   4323     }
   4324     fprintf(output, "\n");
   4325 }
   4326 #endif
   4327 
   4328 /**
   4329  * xmlXPathNewNodeSet:
   4330  * @val:  the NodePtr value
   4331  *
   4332  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
   4333  * it with the single Node @val
   4334  *
   4335  * Returns the newly created object.
   4336  */
   4337 xmlXPathObjectPtr
   4338 xmlXPathNewNodeSet(xmlNodePtr val) {
   4339     xmlXPathObjectPtr ret;
   4340 
   4341     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4342     if (ret == NULL) {
   4343         xmlXPathErrMemory(NULL, "creating nodeset\n");
   4344 	return(NULL);
   4345     }
   4346     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4347     ret->type = XPATH_NODESET;
   4348     ret->boolval = 0;
   4349     ret->nodesetval = xmlXPathNodeSetCreate(val);
   4350     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
   4351 #ifdef XP_DEBUG_OBJ_USAGE
   4352     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
   4353 #endif
   4354     return(ret);
   4355 }
   4356 
   4357 /**
   4358  * xmlXPathNewValueTree:
   4359  * @val:  the NodePtr value
   4360  *
   4361  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
   4362  * it with the tree root @val
   4363  *
   4364  * Returns the newly created object.
   4365  */
   4366 xmlXPathObjectPtr
   4367 xmlXPathNewValueTree(xmlNodePtr val) {
   4368     xmlXPathObjectPtr ret;
   4369 
   4370     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4371     if (ret == NULL) {
   4372         xmlXPathErrMemory(NULL, "creating result value tree\n");
   4373 	return(NULL);
   4374     }
   4375     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4376     ret->type = XPATH_XSLT_TREE;
   4377     ret->boolval = 1;
   4378     ret->user = (void *) val;
   4379     ret->nodesetval = xmlXPathNodeSetCreate(val);
   4380 #ifdef XP_DEBUG_OBJ_USAGE
   4381     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
   4382 #endif
   4383     return(ret);
   4384 }
   4385 
   4386 /**
   4387  * xmlXPathNewNodeSetList:
   4388  * @val:  an existing NodeSet
   4389  *
   4390  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
   4391  * it with the Nodeset @val
   4392  *
   4393  * Returns the newly created object.
   4394  */
   4395 xmlXPathObjectPtr
   4396 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
   4397 {
   4398     xmlXPathObjectPtr ret;
   4399     int i;
   4400 
   4401     if (val == NULL)
   4402         ret = NULL;
   4403     else if (val->nodeTab == NULL)
   4404         ret = xmlXPathNewNodeSet(NULL);
   4405     else {
   4406         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
   4407         if (ret) {
   4408             for (i = 1; i < val->nodeNr; ++i) {
   4409                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
   4410 		    < 0) break;
   4411 	    }
   4412 	}
   4413     }
   4414 
   4415     return (ret);
   4416 }
   4417 
   4418 /**
   4419  * xmlXPathWrapNodeSet:
   4420  * @val:  the NodePtr value
   4421  *
   4422  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
   4423  *
   4424  * Returns the newly created object.
   4425  */
   4426 xmlXPathObjectPtr
   4427 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
   4428     xmlXPathObjectPtr ret;
   4429 
   4430     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   4431     if (ret == NULL) {
   4432         xmlXPathErrMemory(NULL, "creating node set object\n");
   4433 	return(NULL);
   4434     }
   4435     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   4436     ret->type = XPATH_NODESET;
   4437     ret->nodesetval = val;
   4438 #ifdef XP_DEBUG_OBJ_USAGE
   4439     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
   4440 #endif
   4441     return(ret);
   4442 }
   4443 
   4444 /**
   4445  * xmlXPathFreeNodeSetList:
   4446  * @obj:  an existing NodeSetList object
   4447  *
   4448  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
   4449  * the list contrary to xmlXPathFreeObject().
   4450  */
   4451 void
   4452 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
   4453     if (obj == NULL) return;
   4454 #ifdef XP_DEBUG_OBJ_USAGE
   4455     xmlXPathDebugObjUsageReleased(NULL, obj->type);
   4456 #endif
   4457     xmlFree(obj);
   4458 }
   4459 
   4460 /**
   4461  * xmlXPathDifference:
   4462  * @nodes1:  a node-set
   4463  * @nodes2:  a node-set
   4464  *
   4465  * Implements the EXSLT - Sets difference() function:
   4466  *    node-set set:difference (node-set, node-set)
   4467  *
   4468  * Returns the difference between the two node sets, or nodes1 if
   4469  *         nodes2 is empty
   4470  */
   4471 xmlNodeSetPtr
   4472 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4473     xmlNodeSetPtr ret;
   4474     int i, l1;
   4475     xmlNodePtr cur;
   4476 
   4477     if (xmlXPathNodeSetIsEmpty(nodes2))
   4478 	return(nodes1);
   4479 
   4480     ret = xmlXPathNodeSetCreate(NULL);
   4481     if (xmlXPathNodeSetIsEmpty(nodes1))
   4482 	return(ret);
   4483 
   4484     l1 = xmlXPathNodeSetGetLength(nodes1);
   4485 
   4486     for (i = 0; i < l1; i++) {
   4487 	cur = xmlXPathNodeSetItem(nodes1, i);
   4488 	if (!xmlXPathNodeSetContains(nodes2, cur)) {
   4489 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
   4490 	        break;
   4491 	}
   4492     }
   4493     return(ret);
   4494 }
   4495 
   4496 /**
   4497  * xmlXPathIntersection:
   4498  * @nodes1:  a node-set
   4499  * @nodes2:  a node-set
   4500  *
   4501  * Implements the EXSLT - Sets intersection() function:
   4502  *    node-set set:intersection (node-set, node-set)
   4503  *
   4504  * Returns a node set comprising the nodes that are within both the
   4505  *         node sets passed as arguments
   4506  */
   4507 xmlNodeSetPtr
   4508 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4509     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
   4510     int i, l1;
   4511     xmlNodePtr cur;
   4512 
   4513     if (ret == NULL)
   4514         return(ret);
   4515     if (xmlXPathNodeSetIsEmpty(nodes1))
   4516 	return(ret);
   4517     if (xmlXPathNodeSetIsEmpty(nodes2))
   4518 	return(ret);
   4519 
   4520     l1 = xmlXPathNodeSetGetLength(nodes1);
   4521 
   4522     for (i = 0; i < l1; i++) {
   4523 	cur = xmlXPathNodeSetItem(nodes1, i);
   4524 	if (xmlXPathNodeSetContains(nodes2, cur)) {
   4525 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
   4526 	        break;
   4527 	}
   4528     }
   4529     return(ret);
   4530 }
   4531 
   4532 /**
   4533  * xmlXPathDistinctSorted:
   4534  * @nodes:  a node-set, sorted by document order
   4535  *
   4536  * Implements the EXSLT - Sets distinct() function:
   4537  *    node-set set:distinct (node-set)
   4538  *
   4539  * Returns a subset of the nodes contained in @nodes, or @nodes if
   4540  *         it is empty
   4541  */
   4542 xmlNodeSetPtr
   4543 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
   4544     xmlNodeSetPtr ret;
   4545     xmlHashTablePtr hash;
   4546     int i, l;
   4547     xmlChar * strval;
   4548     xmlNodePtr cur;
   4549 
   4550     if (xmlXPathNodeSetIsEmpty(nodes))
   4551 	return(nodes);
   4552 
   4553     ret = xmlXPathNodeSetCreate(NULL);
   4554     if (ret == NULL)
   4555         return(ret);
   4556     l = xmlXPathNodeSetGetLength(nodes);
   4557     hash = xmlHashCreate (l);
   4558     for (i = 0; i < l; i++) {
   4559 	cur = xmlXPathNodeSetItem(nodes, i);
   4560 	strval = xmlXPathCastNodeToString(cur);
   4561 	if (xmlHashLookup(hash, strval) == NULL) {
   4562 	    xmlHashAddEntry(hash, strval, strval);
   4563 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
   4564 	        break;
   4565 	} else {
   4566 	    xmlFree(strval);
   4567 	}
   4568     }
   4569     xmlHashFree(hash, xmlHashDefaultDeallocator);
   4570     return(ret);
   4571 }
   4572 
   4573 /**
   4574  * xmlXPathDistinct:
   4575  * @nodes:  a node-set
   4576  *
   4577  * Implements the EXSLT - Sets distinct() function:
   4578  *    node-set set:distinct (node-set)
   4579  * @nodes is sorted by document order, then #exslSetsDistinctSorted
   4580  * is called with the sorted node-set
   4581  *
   4582  * Returns a subset of the nodes contained in @nodes, or @nodes if
   4583  *         it is empty
   4584  */
   4585 xmlNodeSetPtr
   4586 xmlXPathDistinct (xmlNodeSetPtr nodes) {
   4587     if (xmlXPathNodeSetIsEmpty(nodes))
   4588 	return(nodes);
   4589 
   4590     xmlXPathNodeSetSort(nodes);
   4591     return(xmlXPathDistinctSorted(nodes));
   4592 }
   4593 
   4594 /**
   4595  * xmlXPathHasSameNodes:
   4596  * @nodes1:  a node-set
   4597  * @nodes2:  a node-set
   4598  *
   4599  * Implements the EXSLT - Sets has-same-nodes function:
   4600  *    boolean set:has-same-node(node-set, node-set)
   4601  *
   4602  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
   4603  *         otherwise
   4604  */
   4605 int
   4606 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4607     int i, l;
   4608     xmlNodePtr cur;
   4609 
   4610     if (xmlXPathNodeSetIsEmpty(nodes1) ||
   4611 	xmlXPathNodeSetIsEmpty(nodes2))
   4612 	return(0);
   4613 
   4614     l = xmlXPathNodeSetGetLength(nodes1);
   4615     for (i = 0; i < l; i++) {
   4616 	cur = xmlXPathNodeSetItem(nodes1, i);
   4617 	if (xmlXPathNodeSetContains(nodes2, cur))
   4618 	    return(1);
   4619     }
   4620     return(0);
   4621 }
   4622 
   4623 /**
   4624  * xmlXPathNodeLeadingSorted:
   4625  * @nodes: a node-set, sorted by document order
   4626  * @node: a node
   4627  *
   4628  * Implements the EXSLT - Sets leading() function:
   4629  *    node-set set:leading (node-set, node-set)
   4630  *
   4631  * Returns the nodes in @nodes that precede @node in document order,
   4632  *         @nodes if @node is NULL or an empty node-set if @nodes
   4633  *         doesn't contain @node
   4634  */
   4635 xmlNodeSetPtr
   4636 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4637     int i, l;
   4638     xmlNodePtr cur;
   4639     xmlNodeSetPtr ret;
   4640 
   4641     if (node == NULL)
   4642 	return(nodes);
   4643 
   4644     ret = xmlXPathNodeSetCreate(NULL);
   4645     if (ret == NULL)
   4646         return(ret);
   4647     if (xmlXPathNodeSetIsEmpty(nodes) ||
   4648 	(!xmlXPathNodeSetContains(nodes, node)))
   4649 	return(ret);
   4650 
   4651     l = xmlXPathNodeSetGetLength(nodes);
   4652     for (i = 0; i < l; i++) {
   4653 	cur = xmlXPathNodeSetItem(nodes, i);
   4654 	if (cur == node)
   4655 	    break;
   4656 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
   4657 	    break;
   4658     }
   4659     return(ret);
   4660 }
   4661 
   4662 /**
   4663  * xmlXPathNodeLeading:
   4664  * @nodes:  a node-set
   4665  * @node:  a node
   4666  *
   4667  * Implements the EXSLT - Sets leading() function:
   4668  *    node-set set:leading (node-set, node-set)
   4669  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
   4670  * is called.
   4671  *
   4672  * Returns the nodes in @nodes that precede @node in document order,
   4673  *         @nodes if @node is NULL or an empty node-set if @nodes
   4674  *         doesn't contain @node
   4675  */
   4676 xmlNodeSetPtr
   4677 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4678     xmlXPathNodeSetSort(nodes);
   4679     return(xmlXPathNodeLeadingSorted(nodes, node));
   4680 }
   4681 
   4682 /**
   4683  * xmlXPathLeadingSorted:
   4684  * @nodes1:  a node-set, sorted by document order
   4685  * @nodes2:  a node-set, sorted by document order
   4686  *
   4687  * Implements the EXSLT - Sets leading() function:
   4688  *    node-set set:leading (node-set, node-set)
   4689  *
   4690  * Returns the nodes in @nodes1 that precede the first node in @nodes2
   4691  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4692  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4693  */
   4694 xmlNodeSetPtr
   4695 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4696     if (xmlXPathNodeSetIsEmpty(nodes2))
   4697 	return(nodes1);
   4698     return(xmlXPathNodeLeadingSorted(nodes1,
   4699 				     xmlXPathNodeSetItem(nodes2, 1)));
   4700 }
   4701 
   4702 /**
   4703  * xmlXPathLeading:
   4704  * @nodes1:  a node-set
   4705  * @nodes2:  a node-set
   4706  *
   4707  * Implements the EXSLT - Sets leading() function:
   4708  *    node-set set:leading (node-set, node-set)
   4709  * @nodes1 and @nodes2 are sorted by document order, then
   4710  * #exslSetsLeadingSorted is called.
   4711  *
   4712  * Returns the nodes in @nodes1 that precede the first node in @nodes2
   4713  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4714  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4715  */
   4716 xmlNodeSetPtr
   4717 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4718     if (xmlXPathNodeSetIsEmpty(nodes2))
   4719 	return(nodes1);
   4720     if (xmlXPathNodeSetIsEmpty(nodes1))
   4721 	return(xmlXPathNodeSetCreate(NULL));
   4722     xmlXPathNodeSetSort(nodes1);
   4723     xmlXPathNodeSetSort(nodes2);
   4724     return(xmlXPathNodeLeadingSorted(nodes1,
   4725 				     xmlXPathNodeSetItem(nodes2, 1)));
   4726 }
   4727 
   4728 /**
   4729  * xmlXPathNodeTrailingSorted:
   4730  * @nodes: a node-set, sorted by document order
   4731  * @node: a node
   4732  *
   4733  * Implements the EXSLT - Sets trailing() function:
   4734  *    node-set set:trailing (node-set, node-set)
   4735  *
   4736  * Returns the nodes in @nodes that follow @node in document order,
   4737  *         @nodes if @node is NULL or an empty node-set if @nodes
   4738  *         doesn't contain @node
   4739  */
   4740 xmlNodeSetPtr
   4741 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4742     int i, l;
   4743     xmlNodePtr cur;
   4744     xmlNodeSetPtr ret;
   4745 
   4746     if (node == NULL)
   4747 	return(nodes);
   4748 
   4749     ret = xmlXPathNodeSetCreate(NULL);
   4750     if (ret == NULL)
   4751         return(ret);
   4752     if (xmlXPathNodeSetIsEmpty(nodes) ||
   4753 	(!xmlXPathNodeSetContains(nodes, node)))
   4754 	return(ret);
   4755 
   4756     l = xmlXPathNodeSetGetLength(nodes);
   4757     for (i = l - 1; i >= 0; i--) {
   4758 	cur = xmlXPathNodeSetItem(nodes, i);
   4759 	if (cur == node)
   4760 	    break;
   4761 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
   4762 	    break;
   4763     }
   4764     xmlXPathNodeSetSort(ret);	/* bug 413451 */
   4765     return(ret);
   4766 }
   4767 
   4768 /**
   4769  * xmlXPathNodeTrailing:
   4770  * @nodes:  a node-set
   4771  * @node:  a node
   4772  *
   4773  * Implements the EXSLT - Sets trailing() function:
   4774  *    node-set set:trailing (node-set, node-set)
   4775  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
   4776  * is called.
   4777  *
   4778  * Returns the nodes in @nodes that follow @node in document order,
   4779  *         @nodes if @node is NULL or an empty node-set if @nodes
   4780  *         doesn't contain @node
   4781  */
   4782 xmlNodeSetPtr
   4783 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
   4784     xmlXPathNodeSetSort(nodes);
   4785     return(xmlXPathNodeTrailingSorted(nodes, node));
   4786 }
   4787 
   4788 /**
   4789  * xmlXPathTrailingSorted:
   4790  * @nodes1:  a node-set, sorted by document order
   4791  * @nodes2:  a node-set, sorted by document order
   4792  *
   4793  * Implements the EXSLT - Sets trailing() function:
   4794  *    node-set set:trailing (node-set, node-set)
   4795  *
   4796  * Returns the nodes in @nodes1 that follow the first node in @nodes2
   4797  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4798  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4799  */
   4800 xmlNodeSetPtr
   4801 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4802     if (xmlXPathNodeSetIsEmpty(nodes2))
   4803 	return(nodes1);
   4804     return(xmlXPathNodeTrailingSorted(nodes1,
   4805 				      xmlXPathNodeSetItem(nodes2, 0)));
   4806 }
   4807 
   4808 /**
   4809  * xmlXPathTrailing:
   4810  * @nodes1:  a node-set
   4811  * @nodes2:  a node-set
   4812  *
   4813  * Implements the EXSLT - Sets trailing() function:
   4814  *    node-set set:trailing (node-set, node-set)
   4815  * @nodes1 and @nodes2 are sorted by document order, then
   4816  * #xmlXPathTrailingSorted is called.
   4817  *
   4818  * Returns the nodes in @nodes1 that follow the first node in @nodes2
   4819  *         in document order, @nodes1 if @nodes2 is NULL or empty or
   4820  *         an empty node-set if @nodes1 doesn't contain @nodes2
   4821  */
   4822 xmlNodeSetPtr
   4823 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
   4824     if (xmlXPathNodeSetIsEmpty(nodes2))
   4825 	return(nodes1);
   4826     if (xmlXPathNodeSetIsEmpty(nodes1))
   4827 	return(xmlXPathNodeSetCreate(NULL));
   4828     xmlXPathNodeSetSort(nodes1);
   4829     xmlXPathNodeSetSort(nodes2);
   4830     return(xmlXPathNodeTrailingSorted(nodes1,
   4831 				      xmlXPathNodeSetItem(nodes2, 0)));
   4832 }
   4833 
   4834 /************************************************************************
   4835  *									*
   4836  *		Routines to handle extra functions			*
   4837  *									*
   4838  ************************************************************************/
   4839 
   4840 /**
   4841  * xmlXPathRegisterFunc:
   4842  * @ctxt:  the XPath context
   4843  * @name:  the function name
   4844  * @f:  the function implementation or NULL
   4845  *
   4846  * Register a new function. If @f is NULL it unregisters the function
   4847  *
   4848  * Returns 0 in case of success, -1 in case of error
   4849  */
   4850 int
   4851 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
   4852 		     xmlXPathFunction f) {
   4853     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
   4854 }
   4855 
   4856 /**
   4857  * xmlXPathRegisterFuncNS:
   4858  * @ctxt:  the XPath context
   4859  * @name:  the function name
   4860  * @ns_uri:  the function namespace URI
   4861  * @f:  the function implementation or NULL
   4862  *
   4863  * Register a new function. If @f is NULL it unregisters the function
   4864  *
   4865  * Returns 0 in case of success, -1 in case of error
   4866  */
   4867 int
   4868 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   4869 		       const xmlChar *ns_uri, xmlXPathFunction f) {
   4870     if (ctxt == NULL)
   4871 	return(-1);
   4872     if (name == NULL)
   4873 	return(-1);
   4874 
   4875     if (ctxt->funcHash == NULL)
   4876 	ctxt->funcHash = xmlHashCreate(0);
   4877     if (ctxt->funcHash == NULL)
   4878 	return(-1);
   4879     if (f == NULL)
   4880         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
   4881 XML_IGNORE_PEDANTIC_WARNINGS
   4882     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
   4883 XML_POP_WARNINGS
   4884 }
   4885 
   4886 /**
   4887  * xmlXPathRegisterFuncLookup:
   4888  * @ctxt:  the XPath context
   4889  * @f:  the lookup function
   4890  * @funcCtxt:  the lookup data
   4891  *
   4892  * Registers an external mechanism to do function lookup.
   4893  */
   4894 void
   4895 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
   4896 			    xmlXPathFuncLookupFunc f,
   4897 			    void *funcCtxt) {
   4898     if (ctxt == NULL)
   4899 	return;
   4900     ctxt->funcLookupFunc = f;
   4901     ctxt->funcLookupData = funcCtxt;
   4902 }
   4903 
   4904 /**
   4905  * xmlXPathFunctionLookup:
   4906  * @ctxt:  the XPath context
   4907  * @name:  the function name
   4908  *
   4909  * Search in the Function array of the context for the given
   4910  * function.
   4911  *
   4912  * Returns the xmlXPathFunction or NULL if not found
   4913  */
   4914 xmlXPathFunction
   4915 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
   4916     if (ctxt == NULL)
   4917 	return (NULL);
   4918 
   4919     if (ctxt->funcLookupFunc != NULL) {
   4920 	xmlXPathFunction ret;
   4921 	xmlXPathFuncLookupFunc f;
   4922 
   4923 	f = ctxt->funcLookupFunc;
   4924 	ret = f(ctxt->funcLookupData, name, NULL);
   4925 	if (ret != NULL)
   4926 	    return(ret);
   4927     }
   4928     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
   4929 }
   4930 
   4931 /**
   4932  * xmlXPathFunctionLookupNS:
   4933  * @ctxt:  the XPath context
   4934  * @name:  the function name
   4935  * @ns_uri:  the function namespace URI
   4936  *
   4937  * Search in the Function array of the context for the given
   4938  * function.
   4939  *
   4940  * Returns the xmlXPathFunction or NULL if not found
   4941  */
   4942 xmlXPathFunction
   4943 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   4944 			 const xmlChar *ns_uri) {
   4945     xmlXPathFunction ret;
   4946 
   4947     if (ctxt == NULL)
   4948 	return(NULL);
   4949     if (name == NULL)
   4950 	return(NULL);
   4951 
   4952     if (ctxt->funcLookupFunc != NULL) {
   4953 	xmlXPathFuncLookupFunc f;
   4954 
   4955 	f = ctxt->funcLookupFunc;
   4956 	ret = f(ctxt->funcLookupData, name, ns_uri);
   4957 	if (ret != NULL)
   4958 	    return(ret);
   4959     }
   4960 
   4961     if (ctxt->funcHash == NULL)
   4962 	return(NULL);
   4963 
   4964 XML_IGNORE_PEDANTIC_WARNINGS
   4965     ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
   4966 XML_POP_WARNINGS
   4967     return(ret);
   4968 }
   4969 
   4970 /**
   4971  * xmlXPathRegisteredFuncsCleanup:
   4972  * @ctxt:  the XPath context
   4973  *
   4974  * Cleanup the XPath context data associated to registered functions
   4975  */
   4976 void
   4977 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
   4978     if (ctxt == NULL)
   4979 	return;
   4980 
   4981     xmlHashFree(ctxt->funcHash, NULL);
   4982     ctxt->funcHash = NULL;
   4983 }
   4984 
   4985 /************************************************************************
   4986  *									*
   4987  *			Routines to handle Variables			*
   4988  *									*
   4989  ************************************************************************/
   4990 
   4991 /**
   4992  * xmlXPathRegisterVariable:
   4993  * @ctxt:  the XPath context
   4994  * @name:  the variable name
   4995  * @value:  the variable value or NULL
   4996  *
   4997  * Register a new variable value. If @value is NULL it unregisters
   4998  * the variable
   4999  *
   5000  * Returns 0 in case of success, -1 in case of error
   5001  */
   5002 int
   5003 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
   5004 			 xmlXPathObjectPtr value) {
   5005     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
   5006 }
   5007 
   5008 /**
   5009  * xmlXPathRegisterVariableNS:
   5010  * @ctxt:  the XPath context
   5011  * @name:  the variable name
   5012  * @ns_uri:  the variable namespace URI
   5013  * @value:  the variable value or NULL
   5014  *
   5015  * Register a new variable value. If @value is NULL it unregisters
   5016  * the variable
   5017  *
   5018  * Returns 0 in case of success, -1 in case of error
   5019  */
   5020 int
   5021 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   5022 			   const xmlChar *ns_uri,
   5023 			   xmlXPathObjectPtr value) {
   5024     if (ctxt == NULL)
   5025 	return(-1);
   5026     if (name == NULL)
   5027 	return(-1);
   5028 
   5029     if (ctxt->varHash == NULL)
   5030 	ctxt->varHash = xmlHashCreate(0);
   5031     if (ctxt->varHash == NULL)
   5032 	return(-1);
   5033     if (value == NULL)
   5034         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
   5035 	                           xmlXPathFreeObjectEntry));
   5036     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
   5037 			       (void *) value, xmlXPathFreeObjectEntry));
   5038 }
   5039 
   5040 /**
   5041  * xmlXPathRegisterVariableLookup:
   5042  * @ctxt:  the XPath context
   5043  * @f:  the lookup function
   5044  * @data:  the lookup data
   5045  *
   5046  * register an external mechanism to do variable lookup
   5047  */
   5048 void
   5049 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
   5050 	 xmlXPathVariableLookupFunc f, void *data) {
   5051     if (ctxt == NULL)
   5052 	return;
   5053     ctxt->varLookupFunc = f;
   5054     ctxt->varLookupData = data;
   5055 }
   5056 
   5057 /**
   5058  * xmlXPathVariableLookup:
   5059  * @ctxt:  the XPath context
   5060  * @name:  the variable name
   5061  *
   5062  * Search in the Variable array of the context for the given
   5063  * variable value.
   5064  *
   5065  * Returns a copy of the value or NULL if not found
   5066  */
   5067 xmlXPathObjectPtr
   5068 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
   5069     if (ctxt == NULL)
   5070 	return(NULL);
   5071 
   5072     if (ctxt->varLookupFunc != NULL) {
   5073 	xmlXPathObjectPtr ret;
   5074 
   5075 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
   5076 	        (ctxt->varLookupData, name, NULL);
   5077 	return(ret);
   5078     }
   5079     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
   5080 }
   5081 
   5082 /**
   5083  * xmlXPathVariableLookupNS:
   5084  * @ctxt:  the XPath context
   5085  * @name:  the variable name
   5086  * @ns_uri:  the variable namespace URI
   5087  *
   5088  * Search in the Variable array of the context for the given
   5089  * variable value.
   5090  *
   5091  * Returns the a copy of the value or NULL if not found
   5092  */
   5093 xmlXPathObjectPtr
   5094 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
   5095 			 const xmlChar *ns_uri) {
   5096     if (ctxt == NULL)
   5097 	return(NULL);
   5098 
   5099     if (ctxt->varLookupFunc != NULL) {
   5100 	xmlXPathObjectPtr ret;
   5101 
   5102 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
   5103 	        (ctxt->varLookupData, name, ns_uri);
   5104 	if (ret != NULL) return(ret);
   5105     }
   5106 
   5107     if (ctxt->varHash == NULL)
   5108 	return(NULL);
   5109     if (name == NULL)
   5110 	return(NULL);
   5111 
   5112     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
   5113 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
   5114 }
   5115 
   5116 /**
   5117  * xmlXPathRegisteredVariablesCleanup:
   5118  * @ctxt:  the XPath context
   5119  *
   5120  * Cleanup the XPath context data associated to registered variables
   5121  */
   5122 void
   5123 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
   5124     if (ctxt == NULL)
   5125 	return;
   5126 
   5127     xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
   5128     ctxt->varHash = NULL;
   5129 }
   5130 
   5131 /**
   5132  * xmlXPathRegisterNs:
   5133  * @ctxt:  the XPath context
   5134  * @prefix:  the namespace prefix cannot be NULL or empty string
   5135  * @ns_uri:  the namespace name
   5136  *
   5137  * Register a new namespace. If @ns_uri is NULL it unregisters
   5138  * the namespace
   5139  *
   5140  * Returns 0 in case of success, -1 in case of error
   5141  */
   5142 int
   5143 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
   5144 			   const xmlChar *ns_uri) {
   5145     if (ctxt == NULL)
   5146 	return(-1);
   5147     if (prefix == NULL)
   5148 	return(-1);
   5149     if (prefix[0] == 0)
   5150 	return(-1);
   5151 
   5152     if (ctxt->nsHash == NULL)
   5153 	ctxt->nsHash = xmlHashCreate(10);
   5154     if (ctxt->nsHash == NULL)
   5155 	return(-1);
   5156     if (ns_uri == NULL)
   5157         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
   5158 	                          xmlHashDefaultDeallocator));
   5159     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
   5160 			      xmlHashDefaultDeallocator));
   5161 }
   5162 
   5163 /**
   5164  * xmlXPathNsLookup:
   5165  * @ctxt:  the XPath context
   5166  * @prefix:  the namespace prefix value
   5167  *
   5168  * Search in the namespace declaration array of the context for the given
   5169  * namespace name associated to the given prefix
   5170  *
   5171  * Returns the value or NULL if not found
   5172  */
   5173 const xmlChar *
   5174 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
   5175     if (ctxt == NULL)
   5176 	return(NULL);
   5177     if (prefix == NULL)
   5178 	return(NULL);
   5179 
   5180 #ifdef XML_XML_NAMESPACE
   5181     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
   5182 	return(XML_XML_NAMESPACE);
   5183 #endif
   5184 
   5185     if (ctxt->namespaces != NULL) {
   5186 	int i;
   5187 
   5188 	for (i = 0;i < ctxt->nsNr;i++) {
   5189 	    if ((ctxt->namespaces[i] != NULL) &&
   5190 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
   5191 		return(ctxt->namespaces[i]->href);
   5192 	}
   5193     }
   5194 
   5195     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
   5196 }
   5197 
   5198 /**
   5199  * xmlXPathRegisteredNsCleanup:
   5200  * @ctxt:  the XPath context
   5201  *
   5202  * Cleanup the XPath context data associated to registered variables
   5203  */
   5204 void
   5205 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
   5206     if (ctxt == NULL)
   5207 	return;
   5208 
   5209     xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
   5210     ctxt->nsHash = NULL;
   5211 }
   5212 
   5213 /************************************************************************
   5214  *									*
   5215  *			Routines to handle Values			*
   5216  *									*
   5217  ************************************************************************/
   5218 
   5219 /* Allocations are terrible, one needs to optimize all this !!! */
   5220 
   5221 /**
   5222  * xmlXPathNewFloat:
   5223  * @val:  the double value
   5224  *
   5225  * Create a new xmlXPathObjectPtr of type double and of value @val
   5226  *
   5227  * Returns the newly created object.
   5228  */
   5229 xmlXPathObjectPtr
   5230 xmlXPathNewFloat(double val) {
   5231     xmlXPathObjectPtr ret;
   5232 
   5233     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5234     if (ret == NULL) {
   5235         xmlXPathErrMemory(NULL, "creating float object\n");
   5236 	return(NULL);
   5237     }
   5238     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5239     ret->type = XPATH_NUMBER;
   5240     ret->floatval = val;
   5241 #ifdef XP_DEBUG_OBJ_USAGE
   5242     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
   5243 #endif
   5244     return(ret);
   5245 }
   5246 
   5247 /**
   5248  * xmlXPathNewBoolean:
   5249  * @val:  the boolean value
   5250  *
   5251  * Create a new xmlXPathObjectPtr of type boolean and of value @val
   5252  *
   5253  * Returns the newly created object.
   5254  */
   5255 xmlXPathObjectPtr
   5256 xmlXPathNewBoolean(int val) {
   5257     xmlXPathObjectPtr ret;
   5258 
   5259     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5260     if (ret == NULL) {
   5261         xmlXPathErrMemory(NULL, "creating boolean object\n");
   5262 	return(NULL);
   5263     }
   5264     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5265     ret->type = XPATH_BOOLEAN;
   5266     ret->boolval = (val != 0);
   5267 #ifdef XP_DEBUG_OBJ_USAGE
   5268     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
   5269 #endif
   5270     return(ret);
   5271 }
   5272 
   5273 /**
   5274  * xmlXPathNewString:
   5275  * @val:  the xmlChar * value
   5276  *
   5277  * Create a new xmlXPathObjectPtr of type string and of value @val
   5278  *
   5279  * Returns the newly created object.
   5280  */
   5281 xmlXPathObjectPtr
   5282 xmlXPathNewString(const xmlChar *val) {
   5283     xmlXPathObjectPtr ret;
   5284 
   5285     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5286     if (ret == NULL) {
   5287         xmlXPathErrMemory(NULL, "creating string object\n");
   5288 	return(NULL);
   5289     }
   5290     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5291     ret->type = XPATH_STRING;
   5292     if (val != NULL)
   5293 	ret->stringval = xmlStrdup(val);
   5294     else
   5295 	ret->stringval = xmlStrdup((const xmlChar *)"");
   5296 #ifdef XP_DEBUG_OBJ_USAGE
   5297     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5298 #endif
   5299     return(ret);
   5300 }
   5301 
   5302 /**
   5303  * xmlXPathWrapString:
   5304  * @val:  the xmlChar * value
   5305  *
   5306  * Wraps the @val string into an XPath object.
   5307  *
   5308  * Returns the newly created object.
   5309  */
   5310 xmlXPathObjectPtr
   5311 xmlXPathWrapString (xmlChar *val) {
   5312     xmlXPathObjectPtr ret;
   5313 
   5314     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5315     if (ret == NULL) {
   5316         xmlXPathErrMemory(NULL, "creating string object\n");
   5317 	return(NULL);
   5318     }
   5319     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5320     ret->type = XPATH_STRING;
   5321     ret->stringval = val;
   5322 #ifdef XP_DEBUG_OBJ_USAGE
   5323     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5324 #endif
   5325     return(ret);
   5326 }
   5327 
   5328 /**
   5329  * xmlXPathNewCString:
   5330  * @val:  the char * value
   5331  *
   5332  * Create a new xmlXPathObjectPtr of type string and of value @val
   5333  *
   5334  * Returns the newly created object.
   5335  */
   5336 xmlXPathObjectPtr
   5337 xmlXPathNewCString(const char *val) {
   5338     xmlXPathObjectPtr ret;
   5339 
   5340     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5341     if (ret == NULL) {
   5342         xmlXPathErrMemory(NULL, "creating string object\n");
   5343 	return(NULL);
   5344     }
   5345     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5346     ret->type = XPATH_STRING;
   5347     ret->stringval = xmlStrdup(BAD_CAST val);
   5348 #ifdef XP_DEBUG_OBJ_USAGE
   5349     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
   5350 #endif
   5351     return(ret);
   5352 }
   5353 
   5354 /**
   5355  * xmlXPathWrapCString:
   5356  * @val:  the char * value
   5357  *
   5358  * Wraps a string into an XPath object.
   5359  *
   5360  * Returns the newly created object.
   5361  */
   5362 xmlXPathObjectPtr
   5363 xmlXPathWrapCString (char * val) {
   5364     return(xmlXPathWrapString((xmlChar *)(val)));
   5365 }
   5366 
   5367 /**
   5368  * xmlXPathWrapExternal:
   5369  * @val:  the user data
   5370  *
   5371  * Wraps the @val data into an XPath object.
   5372  *
   5373  * Returns the newly created object.
   5374  */
   5375 xmlXPathObjectPtr
   5376 xmlXPathWrapExternal (void *val) {
   5377     xmlXPathObjectPtr ret;
   5378 
   5379     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5380     if (ret == NULL) {
   5381         xmlXPathErrMemory(NULL, "creating user object\n");
   5382 	return(NULL);
   5383     }
   5384     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
   5385     ret->type = XPATH_USERS;
   5386     ret->user = val;
   5387 #ifdef XP_DEBUG_OBJ_USAGE
   5388     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
   5389 #endif
   5390     return(ret);
   5391 }
   5392 
   5393 /**
   5394  * xmlXPathObjectCopy:
   5395  * @val:  the original object
   5396  *
   5397  * allocate a new copy of a given object
   5398  *
   5399  * Returns the newly created object.
   5400  */
   5401 xmlXPathObjectPtr
   5402 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
   5403     xmlXPathObjectPtr ret;
   5404 
   5405     if (val == NULL)
   5406 	return(NULL);
   5407 
   5408     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
   5409     if (ret == NULL) {
   5410         xmlXPathErrMemory(NULL, "copying object\n");
   5411 	return(NULL);
   5412     }
   5413     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
   5414 #ifdef XP_DEBUG_OBJ_USAGE
   5415     xmlXPathDebugObjUsageRequested(NULL, val->type);
   5416 #endif
   5417     switch (val->type) {
   5418 	case XPATH_BOOLEAN:
   5419 	case XPATH_NUMBER:
   5420 	case XPATH_POINT:
   5421 	case XPATH_RANGE:
   5422 	    break;
   5423 	case XPATH_STRING:
   5424 	    ret->stringval = xmlStrdup(val->stringval);
   5425 	    break;
   5426 	case XPATH_XSLT_TREE:
   5427 #if 0
   5428 /*
   5429   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
   5430   this previous handling is no longer correct, and can cause some serious
   5431   problems (ref. bug 145547)
   5432 */
   5433 	    if ((val->nodesetval != NULL) &&
   5434 		(val->nodesetval->nodeTab != NULL)) {
   5435 		xmlNodePtr cur, tmp;
   5436 		xmlDocPtr top;
   5437 
   5438 		ret->boolval = 1;
   5439 		top =  xmlNewDoc(NULL);
   5440 		top->name = (char *)
   5441 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
   5442 		ret->user = top;
   5443 		if (top != NULL) {
   5444 		    top->doc = top;
   5445 		    cur = val->nodesetval->nodeTab[0]->children;
   5446 		    while (cur != NULL) {
   5447 			tmp = xmlDocCopyNode(cur, top, 1);
   5448 			xmlAddChild((xmlNodePtr) top, tmp);
   5449 			cur = cur->next;
   5450 		    }
   5451 		}
   5452 
   5453 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
   5454 	    } else
   5455 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
   5456 	    /* Deallocate the copied tree value */
   5457 	    break;
   5458 #endif
   5459 	case XPATH_NODESET:
   5460 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
   5461 	    /* Do not deallocate the copied tree value */
   5462 	    ret->boolval = 0;
   5463 	    break;
   5464 	case XPATH_LOCATIONSET:
   5465 #ifdef LIBXML_XPTR_ENABLED
   5466 	{
   5467 	    xmlLocationSetPtr loc = val->user;
   5468 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
   5469 	    break;
   5470 	}
   5471 #endif
   5472         case XPATH_USERS:
   5473 	    ret->user = val->user;
   5474 	    break;
   5475         case XPATH_UNDEFINED:
   5476 	    xmlGenericError(xmlGenericErrorContext,
   5477 		    "xmlXPathObjectCopy: unsupported type %d\n",
   5478 		    val->type);
   5479 	    break;
   5480     }
   5481     return(ret);
   5482 }
   5483 
   5484 /**
   5485  * xmlXPathFreeObject:
   5486  * @obj:  the object to free
   5487  *
   5488  * Free up an xmlXPathObjectPtr object.
   5489  */
   5490 void
   5491 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
   5492     if (obj == NULL) return;
   5493     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
   5494 	if (obj->boolval) {
   5495 #if 0
   5496 	    if (obj->user != NULL) {
   5497                 xmlXPathFreeNodeSet(obj->nodesetval);
   5498 		xmlFreeNodeList((xmlNodePtr) obj->user);
   5499 	    } else
   5500 #endif
   5501 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
   5502 	    if (obj->nodesetval != NULL)
   5503 		xmlXPathFreeValueTree(obj->nodesetval);
   5504 	} else {
   5505 	    if (obj->nodesetval != NULL)
   5506 		xmlXPathFreeNodeSet(obj->nodesetval);
   5507 	}
   5508 #ifdef LIBXML_XPTR_ENABLED
   5509     } else if (obj->type == XPATH_LOCATIONSET) {
   5510 	if (obj->user != NULL)
   5511 	    xmlXPtrFreeLocationSet(obj->user);
   5512 #endif
   5513     } else if (obj->type == XPATH_STRING) {
   5514 	if (obj->stringval != NULL)
   5515 	    xmlFree(obj->stringval);
   5516     }
   5517 #ifdef XP_DEBUG_OBJ_USAGE
   5518     xmlXPathDebugObjUsageReleased(NULL, obj->type);
   5519 #endif
   5520     xmlFree(obj);
   5521 }
   5522 
   5523 static void
   5524 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
   5525     xmlXPathFreeObject((xmlXPathObjectPtr) obj);
   5526 }
   5527 
   5528 /**
   5529  * xmlXPathReleaseObject:
   5530  * @obj:  the xmlXPathObjectPtr to free or to cache
   5531  *
   5532  * Depending on the state of the cache this frees the given
   5533  * XPath object or stores it in the cache.
   5534  */
   5535 static void
   5536 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
   5537 {
   5538 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
   5539 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
   5540     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
   5541 
   5542 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
   5543 
   5544     if (obj == NULL)
   5545 	return;
   5546     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
   5547 	 xmlXPathFreeObject(obj);
   5548     } else {
   5549 	xmlXPathContextCachePtr cache =
   5550 	    (xmlXPathContextCachePtr) ctxt->cache;
   5551 
   5552 	switch (obj->type) {
   5553 	    case XPATH_NODESET:
   5554 	    case XPATH_XSLT_TREE:
   5555 		if (obj->nodesetval != NULL) {
   5556 		    if (obj->boolval) {
   5557 			/*
   5558 			* It looks like the @boolval is used for
   5559 			* evaluation if this an XSLT Result Tree Fragment.
   5560 			* TODO: Check if this assumption is correct.
   5561 			*/
   5562 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
   5563 			xmlXPathFreeValueTree(obj->nodesetval);
   5564 			obj->nodesetval = NULL;
   5565 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
   5566 			(XP_CACHE_WANTS(cache->nodesetObjs,
   5567 					cache->maxNodeset)))
   5568 		    {
   5569 			XP_CACHE_ADD(cache->nodesetObjs, obj);
   5570 			goto obj_cached;
   5571 		    } else {
   5572 			xmlXPathFreeNodeSet(obj->nodesetval);
   5573 			obj->nodesetval = NULL;
   5574 		    }
   5575 		}
   5576 		break;
   5577 	    case XPATH_STRING:
   5578 		if (obj->stringval != NULL)
   5579 		    xmlFree(obj->stringval);
   5580 
   5581 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
   5582 		    XP_CACHE_ADD(cache->stringObjs, obj);
   5583 		    goto obj_cached;
   5584 		}
   5585 		break;
   5586 	    case XPATH_BOOLEAN:
   5587 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
   5588 		    XP_CACHE_ADD(cache->booleanObjs, obj);
   5589 		    goto obj_cached;
   5590 		}
   5591 		break;
   5592 	    case XPATH_NUMBER:
   5593 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
   5594 		    XP_CACHE_ADD(cache->numberObjs, obj);
   5595 		    goto obj_cached;
   5596 		}
   5597 		break;
   5598 #ifdef LIBXML_XPTR_ENABLED
   5599 	    case XPATH_LOCATIONSET:
   5600 		if (obj->user != NULL) {
   5601 		    xmlXPtrFreeLocationSet(obj->user);
   5602 		}
   5603 		goto free_obj;
   5604 #endif
   5605 	    default:
   5606 		goto free_obj;
   5607 	}
   5608 
   5609 	/*
   5610 	* Fallback to adding to the misc-objects slot.
   5611 	*/
   5612 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
   5613 	    XP_CACHE_ADD(cache->miscObjs, obj);
   5614 	} else
   5615 	    goto free_obj;
   5616 
   5617 obj_cached:
   5618 
   5619 #ifdef XP_DEBUG_OBJ_USAGE
   5620 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
   5621 #endif
   5622 
   5623 	if (obj->nodesetval != NULL) {
   5624 	    xmlNodeSetPtr tmpset = obj->nodesetval;
   5625 
   5626 	    /*
   5627 	    * TODO: Due to those nasty ns-nodes, we need to traverse
   5628 	    *  the list and free the ns-nodes.
   5629 	    * URGENT TODO: Check if it's actually slowing things down.
   5630 	    *  Maybe we shouldn't try to preserve the list.
   5631 	    */
   5632 	    if (tmpset->nodeNr > 1) {
   5633 		int i;
   5634 		xmlNodePtr node;
   5635 
   5636 		for (i = 0; i < tmpset->nodeNr; i++) {
   5637 		    node = tmpset->nodeTab[i];
   5638 		    if ((node != NULL) &&
   5639 			(node->type == XML_NAMESPACE_DECL))
   5640 		    {
   5641 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
   5642 		    }
   5643 		}
   5644 	    } else if (tmpset->nodeNr == 1) {
   5645 		if ((tmpset->nodeTab[0] != NULL) &&
   5646 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
   5647 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
   5648 	    }
   5649 	    tmpset->nodeNr = 0;
   5650 	    memset(obj, 0, sizeof(xmlXPathObject));
   5651 	    obj->nodesetval = tmpset;
   5652 	} else
   5653 	    memset(obj, 0, sizeof(xmlXPathObject));
   5654 
   5655 	return;
   5656 
   5657 free_obj:
   5658 	/*
   5659 	* Cache is full; free the object.
   5660 	*/
   5661 	if (obj->nodesetval != NULL)
   5662 	    xmlXPathFreeNodeSet(obj->nodesetval);
   5663 #ifdef XP_DEBUG_OBJ_USAGE
   5664 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
   5665 #endif
   5666 	xmlFree(obj);
   5667     }
   5668     return;
   5669 }
   5670 
   5671 
   5672 /************************************************************************
   5673  *									*
   5674  *			Type Casting Routines				*
   5675  *									*
   5676  ************************************************************************/
   5677 
   5678 /**
   5679  * xmlXPathCastBooleanToString:
   5680  * @val:  a boolean
   5681  *
   5682  * Converts a boolean to its string value.
   5683  *
   5684  * Returns a newly allocated string.
   5685  */
   5686 xmlChar *
   5687 xmlXPathCastBooleanToString (int val) {
   5688     xmlChar *ret;
   5689     if (val)
   5690 	ret = xmlStrdup((const xmlChar *) "true");
   5691     else
   5692 	ret = xmlStrdup((const xmlChar *) "false");
   5693     return(ret);
   5694 }
   5695 
   5696 /**
   5697  * xmlXPathCastNumberToString:
   5698  * @val:  a number
   5699  *
   5700  * Converts a number to its string value.
   5701  *
   5702  * Returns a newly allocated string.
   5703  */
   5704 xmlChar *
   5705 xmlXPathCastNumberToString (double val) {
   5706     xmlChar *ret;
   5707     switch (xmlXPathIsInf(val)) {
   5708     case 1:
   5709 	ret = xmlStrdup((const xmlChar *) "Infinity");
   5710 	break;
   5711     case -1:
   5712 	ret = xmlStrdup((const xmlChar *) "-Infinity");
   5713 	break;
   5714     default:
   5715 	if (xmlXPathIsNaN(val)) {
   5716 	    ret = xmlStrdup((const xmlChar *) "NaN");
   5717 	} else if (val == 0) {
   5718             /* Omit sign for negative zero. */
   5719 	    ret = xmlStrdup((const xmlChar *) "0");
   5720 	} else {
   5721 	    /* could be improved */
   5722 	    char buf[100];
   5723 	    xmlXPathFormatNumber(val, buf, 99);
   5724 	    buf[99] = 0;
   5725 	    ret = xmlStrdup((const xmlChar *) buf);
   5726 	}
   5727     }
   5728     return(ret);
   5729 }
   5730 
   5731 /**
   5732  * xmlXPathCastNodeToString:
   5733  * @node:  a node
   5734  *
   5735  * Converts a node to its string value.
   5736  *
   5737  * Returns a newly allocated string.
   5738  */
   5739 xmlChar *
   5740 xmlXPathCastNodeToString (xmlNodePtr node) {
   5741 xmlChar *ret;
   5742     if ((ret = xmlNodeGetContent(node)) == NULL)
   5743 	ret = xmlStrdup((const xmlChar *) "");
   5744     return(ret);
   5745 }
   5746 
   5747 /**
   5748  * xmlXPathCastNodeSetToString:
   5749  * @ns:  a node-set
   5750  *
   5751  * Converts a node-set to its string value.
   5752  *
   5753  * Returns a newly allocated string.
   5754  */
   5755 xmlChar *
   5756 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
   5757     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
   5758 	return(xmlStrdup((const xmlChar *) ""));
   5759 
   5760     if (ns->nodeNr > 1)
   5761 	xmlXPathNodeSetSort(ns);
   5762     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
   5763 }
   5764 
   5765 /**
   5766  * xmlXPathCastToString:
   5767  * @val:  an XPath object
   5768  *
   5769  * Converts an existing object to its string() equivalent
   5770  *
   5771  * Returns the allocated string value of the object, NULL in case of error.
   5772  *         It's up to the caller to free the string memory with xmlFree().
   5773  */
   5774 xmlChar *
   5775 xmlXPathCastToString(xmlXPathObjectPtr val) {
   5776     xmlChar *ret = NULL;
   5777 
   5778     if (val == NULL)
   5779 	return(xmlStrdup((const xmlChar *) ""));
   5780     switch (val->type) {
   5781 	case XPATH_UNDEFINED:
   5782 #ifdef DEBUG_EXPR
   5783 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
   5784 #endif
   5785 	    ret = xmlStrdup((const xmlChar *) "");
   5786 	    break;
   5787         case XPATH_NODESET:
   5788         case XPATH_XSLT_TREE:
   5789 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
   5790 	    break;
   5791 	case XPATH_STRING:
   5792 	    return(xmlStrdup(val->stringval));
   5793         case XPATH_BOOLEAN:
   5794 	    ret = xmlXPathCastBooleanToString(val->boolval);
   5795 	    break;
   5796 	case XPATH_NUMBER: {
   5797 	    ret = xmlXPathCastNumberToString(val->floatval);
   5798 	    break;
   5799 	}
   5800 	case XPATH_USERS:
   5801 	case XPATH_POINT:
   5802 	case XPATH_RANGE:
   5803 	case XPATH_LOCATIONSET:
   5804 	    TODO
   5805 	    ret = xmlStrdup((const xmlChar *) "");
   5806 	    break;
   5807     }
   5808     return(ret);
   5809 }
   5810 
   5811 /**
   5812  * xmlXPathConvertString:
   5813  * @val:  an XPath object
   5814  *
   5815  * Converts an existing object to its string() equivalent
   5816  *
   5817  * Returns the new object, the old one is freed (or the operation
   5818  *         is done directly on @val)
   5819  */
   5820 xmlXPathObjectPtr
   5821 xmlXPathConvertString(xmlXPathObjectPtr val) {
   5822     xmlChar *res = NULL;
   5823 
   5824     if (val == NULL)
   5825 	return(xmlXPathNewCString(""));
   5826 
   5827     switch (val->type) {
   5828     case XPATH_UNDEFINED:
   5829 #ifdef DEBUG_EXPR
   5830 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
   5831 #endif
   5832 	break;
   5833     case XPATH_NODESET:
   5834     case XPATH_XSLT_TREE:
   5835 	res = xmlXPathCastNodeSetToString(val->nodesetval);
   5836 	break;
   5837     case XPATH_STRING:
   5838 	return(val);
   5839     case XPATH_BOOLEAN:
   5840 	res = xmlXPathCastBooleanToString(val->boolval);
   5841 	break;
   5842     case XPATH_NUMBER:
   5843 	res = xmlXPathCastNumberToString(val->floatval);
   5844 	break;
   5845     case XPATH_USERS:
   5846     case XPATH_POINT:
   5847     case XPATH_RANGE:
   5848     case XPATH_LOCATIONSET:
   5849 	TODO;
   5850 	break;
   5851     }
   5852     xmlXPathFreeObject(val);
   5853     if (res == NULL)
   5854 	return(xmlXPathNewCString(""));
   5855     return(xmlXPathWrapString(res));
   5856 }
   5857 
   5858 /**
   5859  * xmlXPathCastBooleanToNumber:
   5860  * @val:  a boolean
   5861  *
   5862  * Converts a boolean to its number value
   5863  *
   5864  * Returns the number value
   5865  */
   5866 double
   5867 xmlXPathCastBooleanToNumber(int val) {
   5868     if (val)
   5869 	return(1.0);
   5870     return(0.0);
   5871 }
   5872 
   5873 /**
   5874  * xmlXPathCastStringToNumber:
   5875  * @val:  a string
   5876  *
   5877  * Converts a string to its number value
   5878  *
   5879  * Returns the number value
   5880  */
   5881 double
   5882 xmlXPathCastStringToNumber(const xmlChar * val) {
   5883     return(xmlXPathStringEvalNumber(val));
   5884 }
   5885 
   5886 /**
   5887  * xmlXPathCastNodeToNumber:
   5888  * @node:  a node
   5889  *
   5890  * Converts a node to its number value
   5891  *
   5892  * Returns the number value
   5893  */
   5894 double
   5895 xmlXPathCastNodeToNumber (xmlNodePtr node) {
   5896     xmlChar *strval;
   5897     double ret;
   5898 
   5899     if (node == NULL)
   5900 	return(NAN);
   5901     strval = xmlXPathCastNodeToString(node);
   5902     if (strval == NULL)
   5903 	return(NAN);
   5904     ret = xmlXPathCastStringToNumber(strval);
   5905     xmlFree(strval);
   5906 
   5907     return(ret);
   5908 }
   5909 
   5910 /**
   5911  * xmlXPathCastNodeSetToNumber:
   5912  * @ns:  a node-set
   5913  *
   5914  * Converts a node-set to its number value
   5915  *
   5916  * Returns the number value
   5917  */
   5918 double
   5919 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
   5920     xmlChar *str;
   5921     double ret;
   5922 
   5923     if (ns == NULL)
   5924 	return(NAN);
   5925     str = xmlXPathCastNodeSetToString(ns);
   5926     ret = xmlXPathCastStringToNumber(str);
   5927     xmlFree(str);
   5928     return(ret);
   5929 }
   5930 
   5931 /**
   5932  * xmlXPathCastToNumber:
   5933  * @val:  an XPath object
   5934  *
   5935  * Converts an XPath object to its number value
   5936  *
   5937  * Returns the number value
   5938  */
   5939 double
   5940 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
   5941     double ret = 0.0;
   5942 
   5943     if (val == NULL)
   5944 	return(NAN);
   5945     switch (val->type) {
   5946     case XPATH_UNDEFINED:
   5947 #ifdef DEGUB_EXPR
   5948 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
   5949 #endif
   5950 	ret = NAN;
   5951 	break;
   5952     case XPATH_NODESET:
   5953     case XPATH_XSLT_TREE:
   5954 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
   5955 	break;
   5956     case XPATH_STRING:
   5957 	ret = xmlXPathCastStringToNumber(val->stringval);
   5958 	break;
   5959     case XPATH_NUMBER:
   5960 	ret = val->floatval;
   5961 	break;
   5962     case XPATH_BOOLEAN:
   5963 	ret = xmlXPathCastBooleanToNumber(val->boolval);
   5964 	break;
   5965     case XPATH_USERS:
   5966     case XPATH_POINT:
   5967     case XPATH_RANGE:
   5968     case XPATH_LOCATIONSET:
   5969 	TODO;
   5970 	ret = NAN;
   5971 	break;
   5972     }
   5973     return(ret);
   5974 }
   5975 
   5976 /**
   5977  * xmlXPathConvertNumber:
   5978  * @val:  an XPath object
   5979  *
   5980  * Converts an existing object to its number() equivalent
   5981  *
   5982  * Returns the new object, the old one is freed (or the operation
   5983  *         is done directly on @val)
   5984  */
   5985 xmlXPathObjectPtr
   5986 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
   5987     xmlXPathObjectPtr ret;
   5988 
   5989     if (val == NULL)
   5990 	return(xmlXPathNewFloat(0.0));
   5991     if (val->type == XPATH_NUMBER)
   5992 	return(val);
   5993     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
   5994     xmlXPathFreeObject(val);
   5995     return(ret);
   5996 }
   5997 
   5998 /**
   5999  * xmlXPathCastNumberToBoolean:
   6000  * @val:  a number
   6001  *
   6002  * Converts a number to its boolean value
   6003  *
   6004  * Returns the boolean value
   6005  */
   6006 int
   6007 xmlXPathCastNumberToBoolean (double val) {
   6008      if (xmlXPathIsNaN(val) || (val == 0.0))
   6009 	 return(0);
   6010      return(1);
   6011 }
   6012 
   6013 /**
   6014  * xmlXPathCastStringToBoolean:
   6015  * @val:  a string
   6016  *
   6017  * Converts a string to its boolean value
   6018  *
   6019  * Returns the boolean value
   6020  */
   6021 int
   6022 xmlXPathCastStringToBoolean (const xmlChar *val) {
   6023     if ((val == NULL) || (xmlStrlen(val) == 0))
   6024 	return(0);
   6025     return(1);
   6026 }
   6027 
   6028 /**
   6029  * xmlXPathCastNodeSetToBoolean:
   6030  * @ns:  a node-set
   6031  *
   6032  * Converts a node-set to its boolean value
   6033  *
   6034  * Returns the boolean value
   6035  */
   6036 int
   6037 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
   6038     if ((ns == NULL) || (ns->nodeNr == 0))
   6039 	return(0);
   6040     return(1);
   6041 }
   6042 
   6043 /**
   6044  * xmlXPathCastToBoolean:
   6045  * @val:  an XPath object
   6046  *
   6047  * Converts an XPath object to its boolean value
   6048  *
   6049  * Returns the boolean value
   6050  */
   6051 int
   6052 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
   6053     int ret = 0;
   6054 
   6055     if (val == NULL)
   6056 	return(0);
   6057     switch (val->type) {
   6058     case XPATH_UNDEFINED:
   6059 #ifdef DEBUG_EXPR
   6060 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
   6061 #endif
   6062 	ret = 0;
   6063 	break;
   6064     case XPATH_NODESET:
   6065     case XPATH_XSLT_TREE:
   6066 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
   6067 	break;
   6068     case XPATH_STRING:
   6069 	ret = xmlXPathCastStringToBoolean(val->stringval);
   6070 	break;
   6071     case XPATH_NUMBER:
   6072 	ret = xmlXPathCastNumberToBoolean(val->floatval);
   6073 	break;
   6074     case XPATH_BOOLEAN:
   6075 	ret = val->boolval;
   6076 	break;
   6077     case XPATH_USERS:
   6078     case XPATH_POINT:
   6079     case XPATH_RANGE:
   6080     case XPATH_LOCATIONSET:
   6081 	TODO;
   6082 	ret = 0;
   6083 	break;
   6084     }
   6085     return(ret);
   6086 }
   6087 
   6088 
   6089 /**
   6090  * xmlXPathConvertBoolean:
   6091  * @val:  an XPath object
   6092  *
   6093  * Converts an existing object to its boolean() equivalent
   6094  *
   6095  * Returns the new object, the old one is freed (or the operation
   6096  *         is done directly on @val)
   6097  */
   6098 xmlXPathObjectPtr
   6099 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
   6100     xmlXPathObjectPtr ret;
   6101 
   6102     if (val == NULL)
   6103 	return(xmlXPathNewBoolean(0));
   6104     if (val->type == XPATH_BOOLEAN)
   6105 	return(val);
   6106     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
   6107     xmlXPathFreeObject(val);
   6108     return(ret);
   6109 }
   6110 
   6111 /************************************************************************
   6112  *									*
   6113  *		Routines to handle XPath contexts			*
   6114  *									*
   6115  ************************************************************************/
   6116 
   6117 /**
   6118  * xmlXPathNewContext:
   6119  * @doc:  the XML document
   6120  *
   6121  * Create a new xmlXPathContext
   6122  *
   6123  * Returns the xmlXPathContext just allocated. The caller will need to free it.
   6124  */
   6125 xmlXPathContextPtr
   6126 xmlXPathNewContext(xmlDocPtr doc) {
   6127     xmlXPathContextPtr ret;
   6128 
   6129     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
   6130     if (ret == NULL) {
   6131         xmlXPathErrMemory(NULL, "creating context\n");
   6132 	return(NULL);
   6133     }
   6134     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
   6135     ret->doc = doc;
   6136     ret->node = NULL;
   6137 
   6138     ret->varHash = NULL;
   6139 
   6140     ret->nb_types = 0;
   6141     ret->max_types = 0;
   6142     ret->types = NULL;
   6143 
   6144     ret->funcHash = xmlHashCreate(0);
   6145 
   6146     ret->nb_axis = 0;
   6147     ret->max_axis = 0;
   6148     ret->axis = NULL;
   6149 
   6150     ret->nsHash = NULL;
   6151     ret->user = NULL;
   6152 
   6153     ret->contextSize = -1;
   6154     ret->proximityPosition = -1;
   6155 
   6156 #ifdef XP_DEFAULT_CACHE_ON
   6157     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
   6158 	xmlXPathFreeContext(ret);
   6159 	return(NULL);
   6160     }
   6161 #endif
   6162 
   6163     xmlXPathRegisterAllFunctions(ret);
   6164 
   6165     return(ret);
   6166 }
   6167 
   6168 /**
   6169  * xmlXPathFreeContext:
   6170  * @ctxt:  the context to free
   6171  *
   6172  * Free up an xmlXPathContext
   6173  */
   6174 void
   6175 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
   6176     if (ctxt == NULL) return;
   6177 
   6178     if (ctxt->cache != NULL)
   6179 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
   6180     xmlXPathRegisteredNsCleanup(ctxt);
   6181     xmlXPathRegisteredFuncsCleanup(ctxt);
   6182     xmlXPathRegisteredVariablesCleanup(ctxt);
   6183     xmlResetError(&ctxt->lastError);
   6184     xmlFree(ctxt);
   6185 }
   6186 
   6187 /************************************************************************
   6188  *									*
   6189  *		Routines to handle XPath parser contexts		*
   6190  *									*
   6191  ************************************************************************/
   6192 
   6193 #define CHECK_CTXT(ctxt)						\
   6194     if (ctxt == NULL) {						\
   6195 	__xmlRaiseError(NULL, NULL, NULL,				\
   6196 		NULL, NULL, XML_FROM_XPATH,				\
   6197 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
   6198 		__FILE__, __LINE__,					\
   6199 		NULL, NULL, NULL, 0, 0,					\
   6200 		"NULL context pointer\n");				\
   6201 	return(NULL);							\
   6202     }									\
   6203 
   6204 #define CHECK_CTXT_NEG(ctxt)						\
   6205     if (ctxt == NULL) {						\
   6206 	__xmlRaiseError(NULL, NULL, NULL,				\
   6207 		NULL, NULL, XML_FROM_XPATH,				\
   6208 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
   6209 		__FILE__, __LINE__,					\
   6210 		NULL, NULL, NULL, 0, 0,					\
   6211 		"NULL context pointer\n");				\
   6212 	return(-1);							\
   6213     }									\
   6214 
   6215 
   6216 #define CHECK_CONTEXT(ctxt)						\
   6217     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
   6218         (ctxt->doc->children == NULL)) {				\
   6219 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
   6220 	return(NULL);							\
   6221     }
   6222 
   6223 
   6224 /**
   6225  * xmlXPathNewParserContext:
   6226  * @str:  the XPath expression
   6227  * @ctxt:  the XPath context
   6228  *
   6229  * Create a new xmlXPathParserContext
   6230  *
   6231  * Returns the xmlXPathParserContext just allocated.
   6232  */
   6233 xmlXPathParserContextPtr
   6234 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
   6235     xmlXPathParserContextPtr ret;
   6236 
   6237     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
   6238     if (ret == NULL) {
   6239         xmlXPathErrMemory(ctxt, "creating parser context\n");
   6240 	return(NULL);
   6241     }
   6242     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
   6243     ret->cur = ret->base = str;
   6244     ret->context = ctxt;
   6245 
   6246     ret->comp = xmlXPathNewCompExpr();
   6247     if (ret->comp == NULL) {
   6248 	xmlFree(ret->valueTab);
   6249 	xmlFree(ret);
   6250 	return(NULL);
   6251     }
   6252     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
   6253         ret->comp->dict = ctxt->dict;
   6254 	xmlDictReference(ret->comp->dict);
   6255     }
   6256 
   6257     return(ret);
   6258 }
   6259 
   6260 /**
   6261  * xmlXPathCompParserContext:
   6262  * @comp:  the XPath compiled expression
   6263  * @ctxt:  the XPath context
   6264  *
   6265  * Create a new xmlXPathParserContext when processing a compiled expression
   6266  *
   6267  * Returns the xmlXPathParserContext just allocated.
   6268  */
   6269 static xmlXPathParserContextPtr
   6270 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
   6271     xmlXPathParserContextPtr ret;
   6272 
   6273     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
   6274     if (ret == NULL) {
   6275         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
   6276 	return(NULL);
   6277     }
   6278     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
   6279 
   6280     /* Allocate the value stack */
   6281     ret->valueTab = (xmlXPathObjectPtr *)
   6282                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
   6283     if (ret->valueTab == NULL) {
   6284 	xmlFree(ret);
   6285 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
   6286 	return(NULL);
   6287     }
   6288     ret->valueNr = 0;
   6289     ret->valueMax = 10;
   6290     ret->value = NULL;
   6291     ret->valueFrame = 0;
   6292 
   6293     ret->context = ctxt;
   6294     ret->comp = comp;
   6295 
   6296     return(ret);
   6297 }
   6298 
   6299 /**
   6300  * xmlXPathFreeParserContext:
   6301  * @ctxt:  the context to free
   6302  *
   6303  * Free up an xmlXPathParserContext
   6304  */
   6305 void
   6306 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
   6307     int i;
   6308 
   6309     if (ctxt->valueTab != NULL) {
   6310         for (i = 0; i < ctxt->valueNr; i++) {
   6311             if (ctxt->context)
   6312                 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
   6313             else
   6314                 xmlXPathFreeObject(ctxt->valueTab[i]);
   6315         }
   6316         xmlFree(ctxt->valueTab);
   6317     }
   6318     if (ctxt->comp != NULL) {
   6319 #ifdef XPATH_STREAMING
   6320 	if (ctxt->comp->stream != NULL) {
   6321 	    xmlFreePatternList(ctxt->comp->stream);
   6322 	    ctxt->comp->stream = NULL;
   6323 	}
   6324 #endif
   6325 	xmlXPathFreeCompExpr(ctxt->comp);
   6326     }
   6327     xmlFree(ctxt);
   6328 }
   6329 
   6330 /************************************************************************
   6331  *									*
   6332  *		The implicit core function library			*
   6333  *									*
   6334  ************************************************************************/
   6335 
   6336 /**
   6337  * xmlXPathNodeValHash:
   6338  * @node:  a node pointer
   6339  *
   6340  * Function computing the beginning of the string value of the node,
   6341  * used to speed up comparisons
   6342  *
   6343  * Returns an int usable as a hash
   6344  */
   6345 static unsigned int
   6346 xmlXPathNodeValHash(xmlNodePtr node) {
   6347     int len = 2;
   6348     const xmlChar * string = NULL;
   6349     xmlNodePtr tmp = NULL;
   6350     unsigned int ret = 0;
   6351 
   6352     if (node == NULL)
   6353 	return(0);
   6354 
   6355     if (node->type == XML_DOCUMENT_NODE) {
   6356 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
   6357 	if (tmp == NULL)
   6358 	    node = node->children;
   6359 	else
   6360 	    node = tmp;
   6361 
   6362 	if (node == NULL)
   6363 	    return(0);
   6364     }
   6365 
   6366     switch (node->type) {
   6367 	case XML_COMMENT_NODE:
   6368 	case XML_PI_NODE:
   6369 	case XML_CDATA_SECTION_NODE:
   6370 	case XML_TEXT_NODE:
   6371 	    string = node->content;
   6372 	    if (string == NULL)
   6373 		return(0);
   6374 	    if (string[0] == 0)
   6375 		return(0);
   6376 	    return(((unsigned int) string[0]) +
   6377 		   (((unsigned int) string[1]) << 8));
   6378 	case XML_NAMESPACE_DECL:
   6379 	    string = ((xmlNsPtr)node)->href;
   6380 	    if (string == NULL)
   6381 		return(0);
   6382 	    if (string[0] == 0)
   6383 		return(0);
   6384 	    return(((unsigned int) string[0]) +
   6385 		   (((unsigned int) string[1]) << 8));
   6386 	case XML_ATTRIBUTE_NODE:
   6387 	    tmp = ((xmlAttrPtr) node)->children;
   6388 	    break;
   6389 	case XML_ELEMENT_NODE:
   6390 	    tmp = node->children;
   6391 	    break;
   6392 	default:
   6393 	    return(0);
   6394     }
   6395     while (tmp != NULL) {
   6396 	switch (tmp->type) {
   6397 	    case XML_CDATA_SECTION_NODE:
   6398 	    case XML_TEXT_NODE:
   6399 		string = tmp->content;
   6400 		break;
   6401 	    default:
   6402                 string = NULL;
   6403 		break;
   6404 	}
   6405 	if ((string != NULL) && (string[0] != 0)) {
   6406 	    if (len == 1) {
   6407 		return(ret + (((unsigned int) string[0]) << 8));
   6408 	    }
   6409 	    if (string[1] == 0) {
   6410 		len = 1;
   6411 		ret = (unsigned int) string[0];
   6412 	    } else {
   6413 		return(((unsigned int) string[0]) +
   6414 		       (((unsigned int) string[1]) << 8));
   6415 	    }
   6416 	}
   6417 	/*
   6418 	 * Skip to next node
   6419 	 */
   6420 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
   6421 	    if (tmp->children->type != XML_ENTITY_DECL) {
   6422 		tmp = tmp->children;
   6423 		continue;
   6424 	    }
   6425 	}
   6426 	if (tmp == node)
   6427 	    break;
   6428 
   6429 	if (tmp->next != NULL) {
   6430 	    tmp = tmp->next;
   6431 	    continue;
   6432 	}
   6433 
   6434 	do {
   6435 	    tmp = tmp->parent;
   6436 	    if (tmp == NULL)
   6437 		break;
   6438 	    if (tmp == node) {
   6439 		tmp = NULL;
   6440 		break;
   6441 	    }
   6442 	    if (tmp->next != NULL) {
   6443 		tmp = tmp->next;
   6444 		break;
   6445 	    }
   6446 	} while (tmp != NULL);
   6447     }
   6448     return(ret);
   6449 }
   6450 
   6451 /**
   6452  * xmlXPathStringHash:
   6453  * @string:  a string
   6454  *
   6455  * Function computing the beginning of the string value of the node,
   6456  * used to speed up comparisons
   6457  *
   6458  * Returns an int usable as a hash
   6459  */
   6460 static unsigned int
   6461 xmlXPathStringHash(const xmlChar * string) {
   6462     if (string == NULL)
   6463 	return((unsigned int) 0);
   6464     if (string[0] == 0)
   6465 	return(0);
   6466     return(((unsigned int) string[0]) +
   6467 	   (((unsigned int) string[1]) << 8));
   6468 }
   6469 
   6470 /**
   6471  * xmlXPathCompareNodeSetFloat:
   6472  * @ctxt:  the XPath Parser context
   6473  * @inf:  less than (1) or greater than (0)
   6474  * @strict:  is the comparison strict
   6475  * @arg:  the node set
   6476  * @f:  the value
   6477  *
   6478  * Implement the compare operation between a nodeset and a number
   6479  *     @ns < @val    (1, 1, ...
   6480  *     @ns <= @val   (1, 0, ...
   6481  *     @ns > @val    (0, 1, ...
   6482  *     @ns >= @val   (0, 0, ...
   6483  *
   6484  * If one object to be compared is a node-set and the other is a number,
   6485  * then the comparison will be true if and only if there is a node in the
   6486  * node-set such that the result of performing the comparison on the number
   6487  * to be compared and on the result of converting the string-value of that
   6488  * node to a number using the number function is true.
   6489  *
   6490  * Returns 0 or 1 depending on the results of the test.
   6491  */
   6492 static int
   6493 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6494 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
   6495     int i, ret = 0;
   6496     xmlNodeSetPtr ns;
   6497     xmlChar *str2;
   6498 
   6499     if ((f == NULL) || (arg == NULL) ||
   6500 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
   6501 	xmlXPathReleaseObject(ctxt->context, arg);
   6502 	xmlXPathReleaseObject(ctxt->context, f);
   6503         return(0);
   6504     }
   6505     ns = arg->nodesetval;
   6506     if (ns != NULL) {
   6507 	for (i = 0;i < ns->nodeNr;i++) {
   6508 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6509 	     if (str2 != NULL) {
   6510 		 valuePush(ctxt,
   6511 			   xmlXPathCacheNewString(ctxt->context, str2));
   6512 		 xmlFree(str2);
   6513 		 xmlXPathNumberFunction(ctxt, 1);
   6514 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
   6515 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
   6516 		 if (ret)
   6517 		     break;
   6518 	     }
   6519 	}
   6520     }
   6521     xmlXPathReleaseObject(ctxt->context, arg);
   6522     xmlXPathReleaseObject(ctxt->context, f);
   6523     return(ret);
   6524 }
   6525 
   6526 /**
   6527  * xmlXPathCompareNodeSetString:
   6528  * @ctxt:  the XPath Parser context
   6529  * @inf:  less than (1) or greater than (0)
   6530  * @strict:  is the comparison strict
   6531  * @arg:  the node set
   6532  * @s:  the value
   6533  *
   6534  * Implement the compare operation between a nodeset and a string
   6535  *     @ns < @val    (1, 1, ...
   6536  *     @ns <= @val   (1, 0, ...
   6537  *     @ns > @val    (0, 1, ...
   6538  *     @ns >= @val   (0, 0, ...
   6539  *
   6540  * If one object to be compared is a node-set and the other is a string,
   6541  * then the comparison will be true if and only if there is a node in
   6542  * the node-set such that the result of performing the comparison on the
   6543  * string-value of the node and the other string is true.
   6544  *
   6545  * Returns 0 or 1 depending on the results of the test.
   6546  */
   6547 static int
   6548 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6549 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
   6550     int i, ret = 0;
   6551     xmlNodeSetPtr ns;
   6552     xmlChar *str2;
   6553 
   6554     if ((s == NULL) || (arg == NULL) ||
   6555 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
   6556 	xmlXPathReleaseObject(ctxt->context, arg);
   6557 	xmlXPathReleaseObject(ctxt->context, s);
   6558         return(0);
   6559     }
   6560     ns = arg->nodesetval;
   6561     if (ns != NULL) {
   6562 	for (i = 0;i < ns->nodeNr;i++) {
   6563 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6564 	     if (str2 != NULL) {
   6565 		 valuePush(ctxt,
   6566 			   xmlXPathCacheNewString(ctxt->context, str2));
   6567 		 xmlFree(str2);
   6568 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
   6569 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
   6570 		 if (ret)
   6571 		     break;
   6572 	     }
   6573 	}
   6574     }
   6575     xmlXPathReleaseObject(ctxt->context, arg);
   6576     xmlXPathReleaseObject(ctxt->context, s);
   6577     return(ret);
   6578 }
   6579 
   6580 /**
   6581  * xmlXPathCompareNodeSets:
   6582  * @inf:  less than (1) or greater than (0)
   6583  * @strict:  is the comparison strict
   6584  * @arg1:  the first node set object
   6585  * @arg2:  the second node set object
   6586  *
   6587  * Implement the compare operation on nodesets:
   6588  *
   6589  * If both objects to be compared are node-sets, then the comparison
   6590  * will be true if and only if there is a node in the first node-set
   6591  * and a node in the second node-set such that the result of performing
   6592  * the comparison on the string-values of the two nodes is true.
   6593  * ....
   6594  * When neither object to be compared is a node-set and the operator
   6595  * is <=, <, >= or >, then the objects are compared by converting both
   6596  * objects to numbers and comparing the numbers according to IEEE 754.
   6597  * ....
   6598  * The number function converts its argument to a number as follows:
   6599  *  - a string that consists of optional whitespace followed by an
   6600  *    optional minus sign followed by a Number followed by whitespace
   6601  *    is converted to the IEEE 754 number that is nearest (according
   6602  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
   6603  *    represented by the string; any other string is converted to NaN
   6604  *
   6605  * Conclusion all nodes need to be converted first to their string value
   6606  * and then the comparison must be done when possible
   6607  */
   6608 static int
   6609 xmlXPathCompareNodeSets(int inf, int strict,
   6610 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
   6611     int i, j, init = 0;
   6612     double val1;
   6613     double *values2;
   6614     int ret = 0;
   6615     xmlNodeSetPtr ns1;
   6616     xmlNodeSetPtr ns2;
   6617 
   6618     if ((arg1 == NULL) ||
   6619 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
   6620 	xmlXPathFreeObject(arg2);
   6621         return(0);
   6622     }
   6623     if ((arg2 == NULL) ||
   6624 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
   6625 	xmlXPathFreeObject(arg1);
   6626 	xmlXPathFreeObject(arg2);
   6627         return(0);
   6628     }
   6629 
   6630     ns1 = arg1->nodesetval;
   6631     ns2 = arg2->nodesetval;
   6632 
   6633     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
   6634 	xmlXPathFreeObject(arg1);
   6635 	xmlXPathFreeObject(arg2);
   6636 	return(0);
   6637     }
   6638     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
   6639 	xmlXPathFreeObject(arg1);
   6640 	xmlXPathFreeObject(arg2);
   6641 	return(0);
   6642     }
   6643 
   6644     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
   6645     if (values2 == NULL) {
   6646         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6647 	xmlXPathFreeObject(arg1);
   6648 	xmlXPathFreeObject(arg2);
   6649 	return(0);
   6650     }
   6651     for (i = 0;i < ns1->nodeNr;i++) {
   6652 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
   6653 	if (xmlXPathIsNaN(val1))
   6654 	    continue;
   6655 	for (j = 0;j < ns2->nodeNr;j++) {
   6656 	    if (init == 0) {
   6657 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
   6658 	    }
   6659 	    if (xmlXPathIsNaN(values2[j]))
   6660 		continue;
   6661 	    if (inf && strict)
   6662 		ret = (val1 < values2[j]);
   6663 	    else 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 	    if (ret)
   6670 		break;
   6671 	}
   6672 	if (ret)
   6673 	    break;
   6674 	init = 1;
   6675     }
   6676     xmlFree(values2);
   6677     xmlXPathFreeObject(arg1);
   6678     xmlXPathFreeObject(arg2);
   6679     return(ret);
   6680 }
   6681 
   6682 /**
   6683  * xmlXPathCompareNodeSetValue:
   6684  * @ctxt:  the XPath Parser context
   6685  * @inf:  less than (1) or greater than (0)
   6686  * @strict:  is the comparison strict
   6687  * @arg:  the node set
   6688  * @val:  the value
   6689  *
   6690  * Implement the compare operation between a nodeset and a value
   6691  *     @ns < @val    (1, 1, ...
   6692  *     @ns <= @val   (1, 0, ...
   6693  *     @ns > @val    (0, 1, ...
   6694  *     @ns >= @val   (0, 0, ...
   6695  *
   6696  * If one object to be compared is a node-set and the other is a boolean,
   6697  * then the comparison will be true if and only if the result of performing
   6698  * the comparison on the boolean and on the result of converting
   6699  * the node-set to a boolean using the boolean function is true.
   6700  *
   6701  * Returns 0 or 1 depending on the results of the test.
   6702  */
   6703 static int
   6704 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
   6705 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
   6706     if ((val == NULL) || (arg == NULL) ||
   6707 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6708         return(0);
   6709 
   6710     switch(val->type) {
   6711         case XPATH_NUMBER:
   6712 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
   6713         case XPATH_NODESET:
   6714         case XPATH_XSLT_TREE:
   6715 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
   6716         case XPATH_STRING:
   6717 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
   6718         case XPATH_BOOLEAN:
   6719 	    valuePush(ctxt, arg);
   6720 	    xmlXPathBooleanFunction(ctxt, 1);
   6721 	    valuePush(ctxt, val);
   6722 	    return(xmlXPathCompareValues(ctxt, inf, strict));
   6723 	default:
   6724             xmlGenericError(xmlGenericErrorContext,
   6725                     "xmlXPathCompareNodeSetValue: Can't compare node set "
   6726                     "and object of type %d\n",
   6727                     val->type);
   6728             xmlXPathReleaseObject(ctxt->context, arg);
   6729             xmlXPathReleaseObject(ctxt->context, val);
   6730             XP_ERROR0(XPATH_INVALID_TYPE);
   6731     }
   6732     return(0);
   6733 }
   6734 
   6735 /**
   6736  * xmlXPathEqualNodeSetString:
   6737  * @arg:  the nodeset object argument
   6738  * @str:  the string to compare to.
   6739  * @neq:  flag to show whether for '=' (0) or '!=' (1)
   6740  *
   6741  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   6742  * If one object to be compared is a node-set and the other is a string,
   6743  * then the comparison will be true if and only if there is a node in
   6744  * the node-set such that the result of performing the comparison on the
   6745  * string-value of the node and the other string is true.
   6746  *
   6747  * Returns 0 or 1 depending on the results of the test.
   6748  */
   6749 static int
   6750 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
   6751 {
   6752     int i;
   6753     xmlNodeSetPtr ns;
   6754     xmlChar *str2;
   6755     unsigned int hash;
   6756 
   6757     if ((str == NULL) || (arg == NULL) ||
   6758         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6759         return (0);
   6760     ns = arg->nodesetval;
   6761     /*
   6762      * A NULL nodeset compared with a string is always false
   6763      * (since there is no node equal, and no node not equal)
   6764      */
   6765     if ((ns == NULL) || (ns->nodeNr <= 0) )
   6766         return (0);
   6767     hash = xmlXPathStringHash(str);
   6768     for (i = 0; i < ns->nodeNr; i++) {
   6769         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
   6770             str2 = xmlNodeGetContent(ns->nodeTab[i]);
   6771             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
   6772                 xmlFree(str2);
   6773 		if (neq)
   6774 		    continue;
   6775                 return (1);
   6776 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
   6777 		if (neq)
   6778 		    continue;
   6779                 return (1);
   6780             } else if (neq) {
   6781 		if (str2 != NULL)
   6782 		    xmlFree(str2);
   6783 		return (1);
   6784 	    }
   6785             if (str2 != NULL)
   6786                 xmlFree(str2);
   6787         } else if (neq)
   6788 	    return (1);
   6789     }
   6790     return (0);
   6791 }
   6792 
   6793 /**
   6794  * xmlXPathEqualNodeSetFloat:
   6795  * @arg:  the nodeset object argument
   6796  * @f:  the float to compare to
   6797  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
   6798  *
   6799  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   6800  * If one object to be compared is a node-set and the other is a number,
   6801  * then the comparison will be true if and only if there is a node in
   6802  * the node-set such that the result of performing the comparison on the
   6803  * number to be compared and on the result of converting the string-value
   6804  * of that node to a number using the number function is true.
   6805  *
   6806  * Returns 0 or 1 depending on the results of the test.
   6807  */
   6808 static int
   6809 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
   6810     xmlXPathObjectPtr arg, double f, int neq) {
   6811   int i, ret=0;
   6812   xmlNodeSetPtr ns;
   6813   xmlChar *str2;
   6814   xmlXPathObjectPtr val;
   6815   double v;
   6816 
   6817     if ((arg == NULL) ||
   6818 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
   6819         return(0);
   6820 
   6821     ns = arg->nodesetval;
   6822     if (ns != NULL) {
   6823 	for (i=0;i<ns->nodeNr;i++) {
   6824 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
   6825 	    if (str2 != NULL) {
   6826 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
   6827 		xmlFree(str2);
   6828 		xmlXPathNumberFunction(ctxt, 1);
   6829 		val = valuePop(ctxt);
   6830 		v = val->floatval;
   6831 		xmlXPathReleaseObject(ctxt->context, val);
   6832 		if (!xmlXPathIsNaN(v)) {
   6833 		    if ((!neq) && (v==f)) {
   6834 			ret = 1;
   6835 			break;
   6836 		    } else if ((neq) && (v!=f)) {
   6837 			ret = 1;
   6838 			break;
   6839 		    }
   6840 		} else {	/* NaN is unequal to any value */
   6841 		    if (neq)
   6842 			ret = 1;
   6843 		}
   6844 	    }
   6845 	}
   6846     }
   6847 
   6848     return(ret);
   6849 }
   6850 
   6851 
   6852 /**
   6853  * xmlXPathEqualNodeSets:
   6854  * @arg1:  first nodeset object argument
   6855  * @arg2:  second nodeset object argument
   6856  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
   6857  *
   6858  * Implement the equal / not equal operation on XPath nodesets:
   6859  * @arg1 == @arg2  or  @arg1 != @arg2
   6860  * If both objects to be compared are node-sets, then the comparison
   6861  * will be true if and only if there is a node in the first node-set and
   6862  * a node in the second node-set such that the result of performing the
   6863  * comparison on the string-values of the two nodes is true.
   6864  *
   6865  * (needless to say, this is a costly operation)
   6866  *
   6867  * Returns 0 or 1 depending on the results of the test.
   6868  */
   6869 static int
   6870 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
   6871     int i, j;
   6872     unsigned int *hashs1;
   6873     unsigned int *hashs2;
   6874     xmlChar **values1;
   6875     xmlChar **values2;
   6876     int ret = 0;
   6877     xmlNodeSetPtr ns1;
   6878     xmlNodeSetPtr ns2;
   6879 
   6880     if ((arg1 == NULL) ||
   6881 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
   6882         return(0);
   6883     if ((arg2 == NULL) ||
   6884 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
   6885         return(0);
   6886 
   6887     ns1 = arg1->nodesetval;
   6888     ns2 = arg2->nodesetval;
   6889 
   6890     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
   6891 	return(0);
   6892     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
   6893 	return(0);
   6894 
   6895     /*
   6896      * for equal, check if there is a node pertaining to both sets
   6897      */
   6898     if (neq == 0)
   6899 	for (i = 0;i < ns1->nodeNr;i++)
   6900 	    for (j = 0;j < ns2->nodeNr;j++)
   6901 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
   6902 		    return(1);
   6903 
   6904     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
   6905     if (values1 == NULL) {
   6906         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6907 	return(0);
   6908     }
   6909     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
   6910     if (hashs1 == NULL) {
   6911         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6912 	xmlFree(values1);
   6913 	return(0);
   6914     }
   6915     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
   6916     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
   6917     if (values2 == NULL) {
   6918         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6919 	xmlFree(hashs1);
   6920 	xmlFree(values1);
   6921 	return(0);
   6922     }
   6923     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
   6924     if (hashs2 == NULL) {
   6925         xmlXPathErrMemory(NULL, "comparing nodesets\n");
   6926 	xmlFree(hashs1);
   6927 	xmlFree(values1);
   6928 	xmlFree(values2);
   6929 	return(0);
   6930     }
   6931     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
   6932     for (i = 0;i < ns1->nodeNr;i++) {
   6933 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
   6934 	for (j = 0;j < ns2->nodeNr;j++) {
   6935 	    if (i == 0)
   6936 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
   6937 	    if (hashs1[i] != hashs2[j]) {
   6938 		if (neq) {
   6939 		    ret = 1;
   6940 		    break;
   6941 		}
   6942 	    }
   6943 	    else {
   6944 		if (values1[i] == NULL)
   6945 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
   6946 		if (values2[j] == NULL)
   6947 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
   6948 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
   6949 		if (ret)
   6950 		    break;
   6951 	    }
   6952 	}
   6953 	if (ret)
   6954 	    break;
   6955     }
   6956     for (i = 0;i < ns1->nodeNr;i++)
   6957 	if (values1[i] != NULL)
   6958 	    xmlFree(values1[i]);
   6959     for (j = 0;j < ns2->nodeNr;j++)
   6960 	if (values2[j] != NULL)
   6961 	    xmlFree(values2[j]);
   6962     xmlFree(values1);
   6963     xmlFree(values2);
   6964     xmlFree(hashs1);
   6965     xmlFree(hashs2);
   6966     return(ret);
   6967 }
   6968 
   6969 static int
   6970 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
   6971   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
   6972     int ret = 0;
   6973     /*
   6974      *At this point we are assured neither arg1 nor arg2
   6975      *is a nodeset, so we can just pick the appropriate routine.
   6976      */
   6977     switch (arg1->type) {
   6978         case XPATH_UNDEFINED:
   6979 #ifdef DEBUG_EXPR
   6980 	    xmlGenericError(xmlGenericErrorContext,
   6981 		    "Equal: undefined\n");
   6982 #endif
   6983 	    break;
   6984         case XPATH_BOOLEAN:
   6985 	    switch (arg2->type) {
   6986 	        case XPATH_UNDEFINED:
   6987 #ifdef DEBUG_EXPR
   6988 		    xmlGenericError(xmlGenericErrorContext,
   6989 			    "Equal: undefined\n");
   6990 #endif
   6991 		    break;
   6992 		case XPATH_BOOLEAN:
   6993 #ifdef DEBUG_EXPR
   6994 		    xmlGenericError(xmlGenericErrorContext,
   6995 			    "Equal: %d boolean %d \n",
   6996 			    arg1->boolval, arg2->boolval);
   6997 #endif
   6998 		    ret = (arg1->boolval == arg2->boolval);
   6999 		    break;
   7000 		case XPATH_NUMBER:
   7001 		    ret = (arg1->boolval ==
   7002 			   xmlXPathCastNumberToBoolean(arg2->floatval));
   7003 		    break;
   7004 		case XPATH_STRING:
   7005 		    if ((arg2->stringval == NULL) ||
   7006 			(arg2->stringval[0] == 0)) ret = 0;
   7007 		    else
   7008 			ret = 1;
   7009 		    ret = (arg1->boolval == ret);
   7010 		    break;
   7011 		case XPATH_USERS:
   7012 		case XPATH_POINT:
   7013 		case XPATH_RANGE:
   7014 		case XPATH_LOCATIONSET:
   7015 		    TODO
   7016 		    break;
   7017 		case XPATH_NODESET:
   7018 		case XPATH_XSLT_TREE:
   7019 		    break;
   7020 	    }
   7021 	    break;
   7022         case XPATH_NUMBER:
   7023 	    switch (arg2->type) {
   7024 	        case XPATH_UNDEFINED:
   7025 #ifdef DEBUG_EXPR
   7026 		    xmlGenericError(xmlGenericErrorContext,
   7027 			    "Equal: undefined\n");
   7028 #endif
   7029 		    break;
   7030 		case XPATH_BOOLEAN:
   7031 		    ret = (arg2->boolval==
   7032 			   xmlXPathCastNumberToBoolean(arg1->floatval));
   7033 		    break;
   7034 		case XPATH_STRING:
   7035 		    valuePush(ctxt, arg2);
   7036 		    xmlXPathNumberFunction(ctxt, 1);
   7037 		    arg2 = valuePop(ctxt);
   7038                     /* Falls through. */
   7039 		case XPATH_NUMBER:
   7040 		    /* Hand check NaN and Infinity equalities */
   7041 		    if (xmlXPathIsNaN(arg1->floatval) ||
   7042 			    xmlXPathIsNaN(arg2->floatval)) {
   7043 		        ret = 0;
   7044 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
   7045 		        if (xmlXPathIsInf(arg2->floatval) == 1)
   7046 			    ret = 1;
   7047 			else
   7048 			    ret = 0;
   7049 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
   7050 			if (xmlXPathIsInf(arg2->floatval) == -1)
   7051 			    ret = 1;
   7052 			else
   7053 			    ret = 0;
   7054 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
   7055 			if (xmlXPathIsInf(arg1->floatval) == 1)
   7056 			    ret = 1;
   7057 			else
   7058 			    ret = 0;
   7059 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
   7060 			if (xmlXPathIsInf(arg1->floatval) == -1)
   7061 			    ret = 1;
   7062 			else
   7063 			    ret = 0;
   7064 		    } else {
   7065 		        ret = (arg1->floatval == arg2->floatval);
   7066 		    }
   7067 		    break;
   7068 		case XPATH_USERS:
   7069 		case XPATH_POINT:
   7070 		case XPATH_RANGE:
   7071 		case XPATH_LOCATIONSET:
   7072 		    TODO
   7073 		    break;
   7074 		case XPATH_NODESET:
   7075 		case XPATH_XSLT_TREE:
   7076 		    break;
   7077 	    }
   7078 	    break;
   7079         case XPATH_STRING:
   7080 	    switch (arg2->type) {
   7081 	        case XPATH_UNDEFINED:
   7082 #ifdef DEBUG_EXPR
   7083 		    xmlGenericError(xmlGenericErrorContext,
   7084 			    "Equal: undefined\n");
   7085 #endif
   7086 		    break;
   7087 		case XPATH_BOOLEAN:
   7088 		    if ((arg1->stringval == NULL) ||
   7089 			(arg1->stringval[0] == 0)) ret = 0;
   7090 		    else
   7091 			ret = 1;
   7092 		    ret = (arg2->boolval == ret);
   7093 		    break;
   7094 		case XPATH_STRING:
   7095 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
   7096 		    break;
   7097 		case XPATH_NUMBER:
   7098 		    valuePush(ctxt, arg1);
   7099 		    xmlXPathNumberFunction(ctxt, 1);
   7100 		    arg1 = valuePop(ctxt);
   7101 		    /* Hand check NaN and Infinity equalities */
   7102 		    if (xmlXPathIsNaN(arg1->floatval) ||
   7103 			    xmlXPathIsNaN(arg2->floatval)) {
   7104 		        ret = 0;
   7105 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
   7106 			if (xmlXPathIsInf(arg2->floatval) == 1)
   7107 			    ret = 1;
   7108 			else
   7109 			    ret = 0;
   7110 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
   7111 			if (xmlXPathIsInf(arg2->floatval) == -1)
   7112 			    ret = 1;
   7113 			else
   7114 			    ret = 0;
   7115 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
   7116 			if (xmlXPathIsInf(arg1->floatval) == 1)
   7117 			    ret = 1;
   7118 			else
   7119 			    ret = 0;
   7120 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
   7121 			if (xmlXPathIsInf(arg1->floatval) == -1)
   7122 			    ret = 1;
   7123 			else
   7124 			    ret = 0;
   7125 		    } else {
   7126 		        ret = (arg1->floatval == arg2->floatval);
   7127 		    }
   7128 		    break;
   7129 		case XPATH_USERS:
   7130 		case XPATH_POINT:
   7131 		case XPATH_RANGE:
   7132 		case XPATH_LOCATIONSET:
   7133 		    TODO
   7134 		    break;
   7135 		case XPATH_NODESET:
   7136 		case XPATH_XSLT_TREE:
   7137 		    break;
   7138 	    }
   7139 	    break;
   7140         case XPATH_USERS:
   7141 	case XPATH_POINT:
   7142 	case XPATH_RANGE:
   7143 	case XPATH_LOCATIONSET:
   7144 	    TODO
   7145 	    break;
   7146 	case XPATH_NODESET:
   7147 	case XPATH_XSLT_TREE:
   7148 	    break;
   7149     }
   7150     xmlXPathReleaseObject(ctxt->context, arg1);
   7151     xmlXPathReleaseObject(ctxt->context, arg2);
   7152     return(ret);
   7153 }
   7154 
   7155 /**
   7156  * xmlXPathEqualValues:
   7157  * @ctxt:  the XPath Parser context
   7158  *
   7159  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   7160  *
   7161  * Returns 0 or 1 depending on the results of the test.
   7162  */
   7163 int
   7164 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
   7165     xmlXPathObjectPtr arg1, arg2, argtmp;
   7166     int ret = 0;
   7167 
   7168     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7169     arg2 = valuePop(ctxt);
   7170     arg1 = valuePop(ctxt);
   7171     if ((arg1 == NULL) || (arg2 == NULL)) {
   7172 	if (arg1 != NULL)
   7173 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7174 	else
   7175 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7176 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7177     }
   7178 
   7179     if (arg1 == arg2) {
   7180 #ifdef DEBUG_EXPR
   7181         xmlGenericError(xmlGenericErrorContext,
   7182 		"Equal: by pointer\n");
   7183 #endif
   7184 	xmlXPathFreeObject(arg1);
   7185         return(1);
   7186     }
   7187 
   7188     /*
   7189      *If either argument is a nodeset, it's a 'special case'
   7190      */
   7191     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7192       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7193 	/*
   7194 	 *Hack it to assure arg1 is the nodeset
   7195 	 */
   7196 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
   7197 		argtmp = arg2;
   7198 		arg2 = arg1;
   7199 		arg1 = argtmp;
   7200 	}
   7201 	switch (arg2->type) {
   7202 	    case XPATH_UNDEFINED:
   7203 #ifdef DEBUG_EXPR
   7204 		xmlGenericError(xmlGenericErrorContext,
   7205 			"Equal: undefined\n");
   7206 #endif
   7207 		break;
   7208 	    case XPATH_NODESET:
   7209 	    case XPATH_XSLT_TREE:
   7210 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
   7211 		break;
   7212 	    case XPATH_BOOLEAN:
   7213 		if ((arg1->nodesetval == NULL) ||
   7214 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
   7215 		else
   7216 		    ret = 1;
   7217 		ret = (ret == arg2->boolval);
   7218 		break;
   7219 	    case XPATH_NUMBER:
   7220 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
   7221 		break;
   7222 	    case XPATH_STRING:
   7223 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
   7224 		break;
   7225 	    case XPATH_USERS:
   7226 	    case XPATH_POINT:
   7227 	    case XPATH_RANGE:
   7228 	    case XPATH_LOCATIONSET:
   7229 		TODO
   7230 		break;
   7231 	}
   7232 	xmlXPathReleaseObject(ctxt->context, arg1);
   7233 	xmlXPathReleaseObject(ctxt->context, arg2);
   7234 	return(ret);
   7235     }
   7236 
   7237     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
   7238 }
   7239 
   7240 /**
   7241  * xmlXPathNotEqualValues:
   7242  * @ctxt:  the XPath Parser context
   7243  *
   7244  * Implement the equal operation on XPath objects content: @arg1 == @arg2
   7245  *
   7246  * Returns 0 or 1 depending on the results of the test.
   7247  */
   7248 int
   7249 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
   7250     xmlXPathObjectPtr arg1, arg2, argtmp;
   7251     int ret = 0;
   7252 
   7253     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7254     arg2 = valuePop(ctxt);
   7255     arg1 = valuePop(ctxt);
   7256     if ((arg1 == NULL) || (arg2 == NULL)) {
   7257 	if (arg1 != NULL)
   7258 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7259 	else
   7260 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7261 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7262     }
   7263 
   7264     if (arg1 == arg2) {
   7265 #ifdef DEBUG_EXPR
   7266         xmlGenericError(xmlGenericErrorContext,
   7267 		"NotEqual: by pointer\n");
   7268 #endif
   7269 	xmlXPathReleaseObject(ctxt->context, arg1);
   7270         return(0);
   7271     }
   7272 
   7273     /*
   7274      *If either argument is a nodeset, it's a 'special case'
   7275      */
   7276     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7277       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7278 	/*
   7279 	 *Hack it to assure arg1 is the nodeset
   7280 	 */
   7281 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
   7282 		argtmp = arg2;
   7283 		arg2 = arg1;
   7284 		arg1 = argtmp;
   7285 	}
   7286 	switch (arg2->type) {
   7287 	    case XPATH_UNDEFINED:
   7288 #ifdef DEBUG_EXPR
   7289 		xmlGenericError(xmlGenericErrorContext,
   7290 			"NotEqual: undefined\n");
   7291 #endif
   7292 		break;
   7293 	    case XPATH_NODESET:
   7294 	    case XPATH_XSLT_TREE:
   7295 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
   7296 		break;
   7297 	    case XPATH_BOOLEAN:
   7298 		if ((arg1->nodesetval == NULL) ||
   7299 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
   7300 		else
   7301 		    ret = 1;
   7302 		ret = (ret != arg2->boolval);
   7303 		break;
   7304 	    case XPATH_NUMBER:
   7305 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
   7306 		break;
   7307 	    case XPATH_STRING:
   7308 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
   7309 		break;
   7310 	    case XPATH_USERS:
   7311 	    case XPATH_POINT:
   7312 	    case XPATH_RANGE:
   7313 	    case XPATH_LOCATIONSET:
   7314 		TODO
   7315 		break;
   7316 	}
   7317 	xmlXPathReleaseObject(ctxt->context, arg1);
   7318 	xmlXPathReleaseObject(ctxt->context, arg2);
   7319 	return(ret);
   7320     }
   7321 
   7322     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
   7323 }
   7324 
   7325 /**
   7326  * xmlXPathCompareValues:
   7327  * @ctxt:  the XPath Parser context
   7328  * @inf:  less than (1) or greater than (0)
   7329  * @strict:  is the comparison strict
   7330  *
   7331  * Implement the compare operation on XPath objects:
   7332  *     @arg1 < @arg2    (1, 1, ...
   7333  *     @arg1 <= @arg2   (1, 0, ...
   7334  *     @arg1 > @arg2    (0, 1, ...
   7335  *     @arg1 >= @arg2   (0, 0, ...
   7336  *
   7337  * When neither object to be compared is a node-set and the operator is
   7338  * <=, <, >=, >, then the objects are compared by converted both objects
   7339  * to numbers and comparing the numbers according to IEEE 754. The <
   7340  * comparison will be true if and only if the first number is less than the
   7341  * second number. The <= comparison will be true if and only if the first
   7342  * number is less than or equal to the second number. The > comparison
   7343  * will be true if and only if the first number is greater than the second
   7344  * number. The >= comparison will be true if and only if the first number
   7345  * is greater than or equal to the second number.
   7346  *
   7347  * Returns 1 if the comparison succeeded, 0 if it failed
   7348  */
   7349 int
   7350 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
   7351     int ret = 0, arg1i = 0, arg2i = 0;
   7352     xmlXPathObjectPtr arg1, arg2;
   7353 
   7354     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
   7355     arg2 = valuePop(ctxt);
   7356     arg1 = valuePop(ctxt);
   7357     if ((arg1 == NULL) || (arg2 == NULL)) {
   7358 	if (arg1 != NULL)
   7359 	    xmlXPathReleaseObject(ctxt->context, arg1);
   7360 	else
   7361 	    xmlXPathReleaseObject(ctxt->context, arg2);
   7362 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7363     }
   7364 
   7365     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
   7366       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7367 	/*
   7368 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
   7369 	 * are not freed from within this routine; they will be freed from the
   7370 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
   7371 	 */
   7372 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
   7373 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
   7374 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
   7375 	} else {
   7376 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
   7377 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
   7378 			                          arg1, arg2);
   7379 	    } else {
   7380 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
   7381 			                          arg2, arg1);
   7382 	    }
   7383 	}
   7384 	return(ret);
   7385     }
   7386 
   7387     if (arg1->type != XPATH_NUMBER) {
   7388 	valuePush(ctxt, arg1);
   7389 	xmlXPathNumberFunction(ctxt, 1);
   7390 	arg1 = valuePop(ctxt);
   7391     }
   7392     if (arg1->type != XPATH_NUMBER) {
   7393 	xmlXPathFreeObject(arg1);
   7394 	xmlXPathFreeObject(arg2);
   7395 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7396     }
   7397     if (arg2->type != XPATH_NUMBER) {
   7398 	valuePush(ctxt, arg2);
   7399 	xmlXPathNumberFunction(ctxt, 1);
   7400 	arg2 = valuePop(ctxt);
   7401     }
   7402     if (arg2->type != XPATH_NUMBER) {
   7403 	xmlXPathReleaseObject(ctxt->context, arg1);
   7404 	xmlXPathReleaseObject(ctxt->context, arg2);
   7405 	XP_ERROR0(XPATH_INVALID_OPERAND);
   7406     }
   7407     /*
   7408      * Add tests for infinity and nan
   7409      * => feedback on 3.4 for Inf and NaN
   7410      */
   7411     /* Hand check NaN and Infinity comparisons */
   7412     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
   7413 	ret=0;
   7414     } else {
   7415 	arg1i=xmlXPathIsInf(arg1->floatval);
   7416 	arg2i=xmlXPathIsInf(arg2->floatval);
   7417 	if (inf && strict) {
   7418 	    if ((arg1i == -1 && arg2i != -1) ||
   7419 		(arg2i == 1 && arg1i != 1)) {
   7420 		ret = 1;
   7421 	    } else if (arg1i == 0 && arg2i == 0) {
   7422 		ret = (arg1->floatval < arg2->floatval);
   7423 	    } else {
   7424 		ret = 0;
   7425 	    }
   7426 	}
   7427 	else if (inf && !strict) {
   7428 	    if (arg1i == -1 || arg2i == 1) {
   7429 		ret = 1;
   7430 	    } else if (arg1i == 0 && arg2i == 0) {
   7431 		ret = (arg1->floatval <= arg2->floatval);
   7432 	    } else {
   7433 		ret = 0;
   7434 	    }
   7435 	}
   7436 	else if (!inf && strict) {
   7437 	    if ((arg1i == 1 && arg2i != 1) ||
   7438 		(arg2i == -1 && arg1i != -1)) {
   7439 		ret = 1;
   7440 	    } else if (arg1i == 0 && arg2i == 0) {
   7441 		ret = (arg1->floatval > arg2->floatval);
   7442 	    } else {
   7443 		ret = 0;
   7444 	    }
   7445 	}
   7446 	else if (!inf && !strict) {
   7447 	    if (arg1i == 1 || arg2i == -1) {
   7448 		ret = 1;
   7449 	    } else if (arg1i == 0 && arg2i == 0) {
   7450 		ret = (arg1->floatval >= arg2->floatval);
   7451 	    } else {
   7452 		ret = 0;
   7453 	    }
   7454 	}
   7455     }
   7456     xmlXPathReleaseObject(ctxt->context, arg1);
   7457     xmlXPathReleaseObject(ctxt->context, arg2);
   7458     return(ret);
   7459 }
   7460 
   7461 /**
   7462  * xmlXPathValueFlipSign:
   7463  * @ctxt:  the XPath Parser context
   7464  *
   7465  * Implement the unary - operation on an XPath object
   7466  * The numeric operators convert their operands to numbers as if
   7467  * by calling the number function.
   7468  */
   7469 void
   7470 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
   7471     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
   7472     CAST_TO_NUMBER;
   7473     CHECK_TYPE(XPATH_NUMBER);
   7474     ctxt->value->floatval = -ctxt->value->floatval;
   7475 }
   7476 
   7477 /**
   7478  * xmlXPathAddValues:
   7479  * @ctxt:  the XPath Parser context
   7480  *
   7481  * Implement the add operation on XPath objects:
   7482  * The numeric operators convert their operands to numbers as if
   7483  * by calling the number function.
   7484  */
   7485 void
   7486 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
   7487     xmlXPathObjectPtr arg;
   7488     double val;
   7489 
   7490     arg = valuePop(ctxt);
   7491     if (arg == NULL)
   7492 	XP_ERROR(XPATH_INVALID_OPERAND);
   7493     val = xmlXPathCastToNumber(arg);
   7494     xmlXPathReleaseObject(ctxt->context, arg);
   7495     CAST_TO_NUMBER;
   7496     CHECK_TYPE(XPATH_NUMBER);
   7497     ctxt->value->floatval += val;
   7498 }
   7499 
   7500 /**
   7501  * xmlXPathSubValues:
   7502  * @ctxt:  the XPath Parser context
   7503  *
   7504  * Implement the subtraction operation on XPath objects:
   7505  * The numeric operators convert their operands to numbers as if
   7506  * by calling the number function.
   7507  */
   7508 void
   7509 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
   7510     xmlXPathObjectPtr arg;
   7511     double val;
   7512 
   7513     arg = valuePop(ctxt);
   7514     if (arg == NULL)
   7515 	XP_ERROR(XPATH_INVALID_OPERAND);
   7516     val = xmlXPathCastToNumber(arg);
   7517     xmlXPathReleaseObject(ctxt->context, arg);
   7518     CAST_TO_NUMBER;
   7519     CHECK_TYPE(XPATH_NUMBER);
   7520     ctxt->value->floatval -= val;
   7521 }
   7522 
   7523 /**
   7524  * xmlXPathMultValues:
   7525  * @ctxt:  the XPath Parser context
   7526  *
   7527  * Implement the multiply operation on XPath objects:
   7528  * The numeric operators convert their operands to numbers as if
   7529  * by calling the number function.
   7530  */
   7531 void
   7532 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
   7533     xmlXPathObjectPtr arg;
   7534     double val;
   7535 
   7536     arg = valuePop(ctxt);
   7537     if (arg == NULL)
   7538 	XP_ERROR(XPATH_INVALID_OPERAND);
   7539     val = xmlXPathCastToNumber(arg);
   7540     xmlXPathReleaseObject(ctxt->context, arg);
   7541     CAST_TO_NUMBER;
   7542     CHECK_TYPE(XPATH_NUMBER);
   7543     ctxt->value->floatval *= val;
   7544 }
   7545 
   7546 /**
   7547  * xmlXPathDivValues:
   7548  * @ctxt:  the XPath Parser context
   7549  *
   7550  * Implement the div operation on XPath objects @arg1 / @arg2:
   7551  * The numeric operators convert their operands to numbers as if
   7552  * by calling the number function.
   7553  */
   7554 void
   7555 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
   7556     xmlXPathObjectPtr arg;
   7557     double val;
   7558 
   7559     arg = valuePop(ctxt);
   7560     if (arg == NULL)
   7561 	XP_ERROR(XPATH_INVALID_OPERAND);
   7562     val = xmlXPathCastToNumber(arg);
   7563     xmlXPathReleaseObject(ctxt->context, arg);
   7564     CAST_TO_NUMBER;
   7565     CHECK_TYPE(XPATH_NUMBER);
   7566     ctxt->value->floatval /= val;
   7567 }
   7568 
   7569 /**
   7570  * xmlXPathModValues:
   7571  * @ctxt:  the XPath Parser context
   7572  *
   7573  * Implement the mod operation on XPath objects: @arg1 / @arg2
   7574  * The numeric operators convert their operands to numbers as if
   7575  * by calling the number function.
   7576  */
   7577 void
   7578 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
   7579     xmlXPathObjectPtr arg;
   7580     double arg1, arg2;
   7581 
   7582     arg = valuePop(ctxt);
   7583     if (arg == NULL)
   7584 	XP_ERROR(XPATH_INVALID_OPERAND);
   7585     arg2 = xmlXPathCastToNumber(arg);
   7586     xmlXPathReleaseObject(ctxt->context, arg);
   7587     CAST_TO_NUMBER;
   7588     CHECK_TYPE(XPATH_NUMBER);
   7589     arg1 = ctxt->value->floatval;
   7590     if (arg2 == 0)
   7591 	ctxt->value->floatval = NAN;
   7592     else {
   7593 	ctxt->value->floatval = fmod(arg1, arg2);
   7594     }
   7595 }
   7596 
   7597 /************************************************************************
   7598  *									*
   7599  *		The traversal functions					*
   7600  *									*
   7601  ************************************************************************/
   7602 
   7603 /*
   7604  * A traversal function enumerates nodes along an axis.
   7605  * Initially it must be called with NULL, and it indicates
   7606  * termination on the axis by returning NULL.
   7607  */
   7608 typedef xmlNodePtr (*xmlXPathTraversalFunction)
   7609                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
   7610 
   7611 /*
   7612  * xmlXPathTraversalFunctionExt:
   7613  * A traversal function enumerates nodes along an axis.
   7614  * Initially it must be called with NULL, and it indicates
   7615  * termination on the axis by returning NULL.
   7616  * The context node of the traversal is specified via @contextNode.
   7617  */
   7618 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
   7619                     (xmlNodePtr cur, xmlNodePtr contextNode);
   7620 
   7621 /*
   7622  * xmlXPathNodeSetMergeFunction:
   7623  * Used for merging node sets in xmlXPathCollectAndTest().
   7624  */
   7625 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
   7626 		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
   7627 
   7628 
   7629 /**
   7630  * xmlXPathNextSelf:
   7631  * @ctxt:  the XPath Parser context
   7632  * @cur:  the current node in the traversal
   7633  *
   7634  * Traversal function for the "self" direction
   7635  * The self axis contains just the context node itself
   7636  *
   7637  * Returns the next element following that axis
   7638  */
   7639 xmlNodePtr
   7640 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7641     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7642     if (cur == NULL)
   7643         return(ctxt->context->node);
   7644     return(NULL);
   7645 }
   7646 
   7647 /**
   7648  * xmlXPathNextChild:
   7649  * @ctxt:  the XPath Parser context
   7650  * @cur:  the current node in the traversal
   7651  *
   7652  * Traversal function for the "child" direction
   7653  * The child axis contains the children of the context node in document order.
   7654  *
   7655  * Returns the next element following that axis
   7656  */
   7657 xmlNodePtr
   7658 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7659     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7660     if (cur == NULL) {
   7661 	if (ctxt->context->node == NULL) return(NULL);
   7662 	switch (ctxt->context->node->type) {
   7663             case XML_ELEMENT_NODE:
   7664             case XML_TEXT_NODE:
   7665             case XML_CDATA_SECTION_NODE:
   7666             case XML_ENTITY_REF_NODE:
   7667             case XML_ENTITY_NODE:
   7668             case XML_PI_NODE:
   7669             case XML_COMMENT_NODE:
   7670             case XML_NOTATION_NODE:
   7671             case XML_DTD_NODE:
   7672 		return(ctxt->context->node->children);
   7673             case XML_DOCUMENT_NODE:
   7674             case XML_DOCUMENT_TYPE_NODE:
   7675             case XML_DOCUMENT_FRAG_NODE:
   7676             case XML_HTML_DOCUMENT_NODE:
   7677 #ifdef LIBXML_DOCB_ENABLED
   7678 	    case XML_DOCB_DOCUMENT_NODE:
   7679 #endif
   7680 		return(((xmlDocPtr) ctxt->context->node)->children);
   7681 	    case XML_ELEMENT_DECL:
   7682 	    case XML_ATTRIBUTE_DECL:
   7683 	    case XML_ENTITY_DECL:
   7684             case XML_ATTRIBUTE_NODE:
   7685 	    case XML_NAMESPACE_DECL:
   7686 	    case XML_XINCLUDE_START:
   7687 	    case XML_XINCLUDE_END:
   7688 		return(NULL);
   7689 	}
   7690 	return(NULL);
   7691     }
   7692     if ((cur->type == XML_DOCUMENT_NODE) ||
   7693         (cur->type == XML_HTML_DOCUMENT_NODE))
   7694 	return(NULL);
   7695     return(cur->next);
   7696 }
   7697 
   7698 /**
   7699  * xmlXPathNextChildElement:
   7700  * @ctxt:  the XPath Parser context
   7701  * @cur:  the current node in the traversal
   7702  *
   7703  * Traversal function for the "child" direction and nodes of type element.
   7704  * The child axis contains the children of the context node in document order.
   7705  *
   7706  * Returns the next element following that axis
   7707  */
   7708 static xmlNodePtr
   7709 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7710     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7711     if (cur == NULL) {
   7712 	cur = ctxt->context->node;
   7713 	if (cur == NULL) return(NULL);
   7714 	/*
   7715 	* Get the first element child.
   7716 	*/
   7717 	switch (cur->type) {
   7718             case XML_ELEMENT_NODE:
   7719 	    case XML_DOCUMENT_FRAG_NODE:
   7720 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
   7721             case XML_ENTITY_NODE:
   7722 		cur = cur->children;
   7723 		if (cur != NULL) {
   7724 		    if (cur->type == XML_ELEMENT_NODE)
   7725 			return(cur);
   7726 		    do {
   7727 			cur = cur->next;
   7728 		    } while ((cur != NULL) &&
   7729 			(cur->type != XML_ELEMENT_NODE));
   7730 		    return(cur);
   7731 		}
   7732 		return(NULL);
   7733             case XML_DOCUMENT_NODE:
   7734             case XML_HTML_DOCUMENT_NODE:
   7735 #ifdef LIBXML_DOCB_ENABLED
   7736 	    case XML_DOCB_DOCUMENT_NODE:
   7737 #endif
   7738 		return(xmlDocGetRootElement((xmlDocPtr) cur));
   7739 	    default:
   7740 		return(NULL);
   7741 	}
   7742 	return(NULL);
   7743     }
   7744     /*
   7745     * Get the next sibling element node.
   7746     */
   7747     switch (cur->type) {
   7748 	case XML_ELEMENT_NODE:
   7749 	case XML_TEXT_NODE:
   7750 	case XML_ENTITY_REF_NODE:
   7751 	case XML_ENTITY_NODE:
   7752 	case XML_CDATA_SECTION_NODE:
   7753 	case XML_PI_NODE:
   7754 	case XML_COMMENT_NODE:
   7755 	case XML_XINCLUDE_END:
   7756 	    break;
   7757 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
   7758 	default:
   7759 	    return(NULL);
   7760     }
   7761     if (cur->next != NULL) {
   7762 	if (cur->next->type == XML_ELEMENT_NODE)
   7763 	    return(cur->next);
   7764 	cur = cur->next;
   7765 	do {
   7766 	    cur = cur->next;
   7767 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
   7768 	return(cur);
   7769     }
   7770     return(NULL);
   7771 }
   7772 
   7773 #if 0
   7774 /**
   7775  * xmlXPathNextDescendantOrSelfElemParent:
   7776  * @ctxt:  the XPath Parser context
   7777  * @cur:  the current node in the traversal
   7778  *
   7779  * Traversal function for the "descendant-or-self" axis.
   7780  * Additionally it returns only nodes which can be parents of
   7781  * element nodes.
   7782  *
   7783  *
   7784  * Returns the next element following that axis
   7785  */
   7786 static xmlNodePtr
   7787 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
   7788 				       xmlNodePtr contextNode)
   7789 {
   7790     if (cur == NULL) {
   7791 	if (contextNode == NULL)
   7792 	    return(NULL);
   7793 	switch (contextNode->type) {
   7794 	    case XML_ELEMENT_NODE:
   7795 	    case XML_XINCLUDE_START:
   7796 	    case XML_DOCUMENT_FRAG_NODE:
   7797 	    case XML_DOCUMENT_NODE:
   7798 #ifdef LIBXML_DOCB_ENABLED
   7799 	    case XML_DOCB_DOCUMENT_NODE:
   7800 #endif
   7801 	    case XML_HTML_DOCUMENT_NODE:
   7802 		return(contextNode);
   7803 	    default:
   7804 		return(NULL);
   7805 	}
   7806 	return(NULL);
   7807     } else {
   7808 	xmlNodePtr start = cur;
   7809 
   7810 	while (cur != NULL) {
   7811 	    switch (cur->type) {
   7812 		case XML_ELEMENT_NODE:
   7813 		/* TODO: OK to have XInclude here? */
   7814 		case XML_XINCLUDE_START:
   7815 		case XML_DOCUMENT_FRAG_NODE:
   7816 		    if (cur != start)
   7817 			return(cur);
   7818 		    if (cur->children != NULL) {
   7819 			cur = cur->children;
   7820 			continue;
   7821 		    }
   7822 		    break;
   7823 		/* Not sure if we need those here. */
   7824 		case XML_DOCUMENT_NODE:
   7825 #ifdef LIBXML_DOCB_ENABLED
   7826 		case XML_DOCB_DOCUMENT_NODE:
   7827 #endif
   7828 		case XML_HTML_DOCUMENT_NODE:
   7829 		    if (cur != start)
   7830 			return(cur);
   7831 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
   7832 		default:
   7833 		    break;
   7834 	    }
   7835 
   7836 next_sibling:
   7837 	    if ((cur == NULL) || (cur == contextNode))
   7838 		return(NULL);
   7839 	    if (cur->next != NULL) {
   7840 		cur = cur->next;
   7841 	    } else {
   7842 		cur = cur->parent;
   7843 		goto next_sibling;
   7844 	    }
   7845 	}
   7846     }
   7847     return(NULL);
   7848 }
   7849 #endif
   7850 
   7851 /**
   7852  * xmlXPathNextDescendant:
   7853  * @ctxt:  the XPath Parser context
   7854  * @cur:  the current node in the traversal
   7855  *
   7856  * Traversal function for the "descendant" direction
   7857  * the descendant axis contains the descendants of the context node in document
   7858  * order; a descendant is a child or a child of a child and so on.
   7859  *
   7860  * Returns the next element following that axis
   7861  */
   7862 xmlNodePtr
   7863 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7864     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7865     if (cur == NULL) {
   7866 	if (ctxt->context->node == NULL)
   7867 	    return(NULL);
   7868 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   7869 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
   7870 	    return(NULL);
   7871 
   7872         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
   7873 	    return(ctxt->context->doc->children);
   7874         return(ctxt->context->node->children);
   7875     }
   7876 
   7877     if (cur->type == XML_NAMESPACE_DECL)
   7878         return(NULL);
   7879     if (cur->children != NULL) {
   7880 	/*
   7881 	 * Do not descend on entities declarations
   7882 	 */
   7883 	if (cur->children->type != XML_ENTITY_DECL) {
   7884 	    cur = cur->children;
   7885 	    /*
   7886 	     * Skip DTDs
   7887 	     */
   7888 	    if (cur->type != XML_DTD_NODE)
   7889 		return(cur);
   7890 	}
   7891     }
   7892 
   7893     if (cur == ctxt->context->node) return(NULL);
   7894 
   7895     while (cur->next != NULL) {
   7896 	cur = cur->next;
   7897 	if ((cur->type != XML_ENTITY_DECL) &&
   7898 	    (cur->type != XML_DTD_NODE))
   7899 	    return(cur);
   7900     }
   7901 
   7902     do {
   7903         cur = cur->parent;
   7904 	if (cur == NULL) break;
   7905 	if (cur == ctxt->context->node) return(NULL);
   7906 	if (cur->next != NULL) {
   7907 	    cur = cur->next;
   7908 	    return(cur);
   7909 	}
   7910     } while (cur != NULL);
   7911     return(cur);
   7912 }
   7913 
   7914 /**
   7915  * xmlXPathNextDescendantOrSelf:
   7916  * @ctxt:  the XPath Parser context
   7917  * @cur:  the current node in the traversal
   7918  *
   7919  * Traversal function for the "descendant-or-self" direction
   7920  * the descendant-or-self axis contains the context node and the descendants
   7921  * of the context node in document order; thus the context node is the first
   7922  * node on the axis, and the first child of the context node is the second node
   7923  * on the axis
   7924  *
   7925  * Returns the next element following that axis
   7926  */
   7927 xmlNodePtr
   7928 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7929     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7930     if (cur == NULL)
   7931         return(ctxt->context->node);
   7932 
   7933     if (ctxt->context->node == NULL)
   7934         return(NULL);
   7935     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   7936         (ctxt->context->node->type == XML_NAMESPACE_DECL))
   7937         return(NULL);
   7938 
   7939     return(xmlXPathNextDescendant(ctxt, cur));
   7940 }
   7941 
   7942 /**
   7943  * xmlXPathNextParent:
   7944  * @ctxt:  the XPath Parser context
   7945  * @cur:  the current node in the traversal
   7946  *
   7947  * Traversal function for the "parent" direction
   7948  * The parent axis contains the parent of the context node, if there is one.
   7949  *
   7950  * Returns the next element following that axis
   7951  */
   7952 xmlNodePtr
   7953 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   7954     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   7955     /*
   7956      * the parent of an attribute or namespace node is the element
   7957      * to which the attribute or namespace node is attached
   7958      * Namespace handling !!!
   7959      */
   7960     if (cur == NULL) {
   7961 	if (ctxt->context->node == NULL) return(NULL);
   7962 	switch (ctxt->context->node->type) {
   7963             case XML_ELEMENT_NODE:
   7964             case XML_TEXT_NODE:
   7965             case XML_CDATA_SECTION_NODE:
   7966             case XML_ENTITY_REF_NODE:
   7967             case XML_ENTITY_NODE:
   7968             case XML_PI_NODE:
   7969             case XML_COMMENT_NODE:
   7970             case XML_NOTATION_NODE:
   7971             case XML_DTD_NODE:
   7972 	    case XML_ELEMENT_DECL:
   7973 	    case XML_ATTRIBUTE_DECL:
   7974 	    case XML_XINCLUDE_START:
   7975 	    case XML_XINCLUDE_END:
   7976 	    case XML_ENTITY_DECL:
   7977 		if (ctxt->context->node->parent == NULL)
   7978 		    return((xmlNodePtr) ctxt->context->doc);
   7979 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
   7980 		    ((ctxt->context->node->parent->name[0] == ' ') ||
   7981 		     (xmlStrEqual(ctxt->context->node->parent->name,
   7982 				 BAD_CAST "fake node libxslt"))))
   7983 		    return(NULL);
   7984 		return(ctxt->context->node->parent);
   7985             case XML_ATTRIBUTE_NODE: {
   7986 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
   7987 
   7988 		return(att->parent);
   7989 	    }
   7990             case XML_DOCUMENT_NODE:
   7991             case XML_DOCUMENT_TYPE_NODE:
   7992             case XML_DOCUMENT_FRAG_NODE:
   7993             case XML_HTML_DOCUMENT_NODE:
   7994 #ifdef LIBXML_DOCB_ENABLED
   7995 	    case XML_DOCB_DOCUMENT_NODE:
   7996 #endif
   7997                 return(NULL);
   7998 	    case XML_NAMESPACE_DECL: {
   7999 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
   8000 
   8001 		if ((ns->next != NULL) &&
   8002 		    (ns->next->type != XML_NAMESPACE_DECL))
   8003 		    return((xmlNodePtr) ns->next);
   8004                 return(NULL);
   8005 	    }
   8006 	}
   8007     }
   8008     return(NULL);
   8009 }
   8010 
   8011 /**
   8012  * xmlXPathNextAncestor:
   8013  * @ctxt:  the XPath Parser context
   8014  * @cur:  the current node in the traversal
   8015  *
   8016  * Traversal function for the "ancestor" direction
   8017  * the ancestor axis contains the ancestors of the context node; the ancestors
   8018  * of the context node consist of the parent of context node and the parent's
   8019  * parent and so on; the nodes are ordered in reverse document order; thus the
   8020  * parent is the first node on the axis, and the parent's parent is the second
   8021  * node on the axis
   8022  *
   8023  * Returns the next element following that axis
   8024  */
   8025 xmlNodePtr
   8026 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8027     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8028     /*
   8029      * the parent of an attribute or namespace node is the element
   8030      * to which the attribute or namespace node is attached
   8031      * !!!!!!!!!!!!!
   8032      */
   8033     if (cur == NULL) {
   8034 	if (ctxt->context->node == NULL) return(NULL);
   8035 	switch (ctxt->context->node->type) {
   8036             case XML_ELEMENT_NODE:
   8037             case XML_TEXT_NODE:
   8038             case XML_CDATA_SECTION_NODE:
   8039             case XML_ENTITY_REF_NODE:
   8040             case XML_ENTITY_NODE:
   8041             case XML_PI_NODE:
   8042             case XML_COMMENT_NODE:
   8043 	    case XML_DTD_NODE:
   8044 	    case XML_ELEMENT_DECL:
   8045 	    case XML_ATTRIBUTE_DECL:
   8046 	    case XML_ENTITY_DECL:
   8047             case XML_NOTATION_NODE:
   8048 	    case XML_XINCLUDE_START:
   8049 	    case XML_XINCLUDE_END:
   8050 		if (ctxt->context->node->parent == NULL)
   8051 		    return((xmlNodePtr) ctxt->context->doc);
   8052 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
   8053 		    ((ctxt->context->node->parent->name[0] == ' ') ||
   8054 		     (xmlStrEqual(ctxt->context->node->parent->name,
   8055 				 BAD_CAST "fake node libxslt"))))
   8056 		    return(NULL);
   8057 		return(ctxt->context->node->parent);
   8058             case XML_ATTRIBUTE_NODE: {
   8059 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
   8060 
   8061 		return(tmp->parent);
   8062 	    }
   8063             case XML_DOCUMENT_NODE:
   8064             case XML_DOCUMENT_TYPE_NODE:
   8065             case XML_DOCUMENT_FRAG_NODE:
   8066             case XML_HTML_DOCUMENT_NODE:
   8067 #ifdef LIBXML_DOCB_ENABLED
   8068 	    case XML_DOCB_DOCUMENT_NODE:
   8069 #endif
   8070                 return(NULL);
   8071 	    case XML_NAMESPACE_DECL: {
   8072 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
   8073 
   8074 		if ((ns->next != NULL) &&
   8075 		    (ns->next->type != XML_NAMESPACE_DECL))
   8076 		    return((xmlNodePtr) ns->next);
   8077 		/* Bad, how did that namespace end up here ? */
   8078                 return(NULL);
   8079 	    }
   8080 	}
   8081 	return(NULL);
   8082     }
   8083     if (cur == ctxt->context->doc->children)
   8084 	return((xmlNodePtr) ctxt->context->doc);
   8085     if (cur == (xmlNodePtr) ctxt->context->doc)
   8086 	return(NULL);
   8087     switch (cur->type) {
   8088 	case XML_ELEMENT_NODE:
   8089 	case XML_TEXT_NODE:
   8090 	case XML_CDATA_SECTION_NODE:
   8091 	case XML_ENTITY_REF_NODE:
   8092 	case XML_ENTITY_NODE:
   8093 	case XML_PI_NODE:
   8094 	case XML_COMMENT_NODE:
   8095 	case XML_NOTATION_NODE:
   8096 	case XML_DTD_NODE:
   8097         case XML_ELEMENT_DECL:
   8098         case XML_ATTRIBUTE_DECL:
   8099         case XML_ENTITY_DECL:
   8100 	case XML_XINCLUDE_START:
   8101 	case XML_XINCLUDE_END:
   8102 	    if (cur->parent == NULL)
   8103 		return(NULL);
   8104 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
   8105 		((cur->parent->name[0] == ' ') ||
   8106 		 (xmlStrEqual(cur->parent->name,
   8107 			      BAD_CAST "fake node libxslt"))))
   8108 		return(NULL);
   8109 	    return(cur->parent);
   8110 	case XML_ATTRIBUTE_NODE: {
   8111 	    xmlAttrPtr att = (xmlAttrPtr) cur;
   8112 
   8113 	    return(att->parent);
   8114 	}
   8115 	case XML_NAMESPACE_DECL: {
   8116 	    xmlNsPtr ns = (xmlNsPtr) cur;
   8117 
   8118 	    if ((ns->next != NULL) &&
   8119 	        (ns->next->type != XML_NAMESPACE_DECL))
   8120 	        return((xmlNodePtr) ns->next);
   8121 	    /* Bad, how did that namespace end up here ? */
   8122             return(NULL);
   8123 	}
   8124 	case XML_DOCUMENT_NODE:
   8125 	case XML_DOCUMENT_TYPE_NODE:
   8126 	case XML_DOCUMENT_FRAG_NODE:
   8127 	case XML_HTML_DOCUMENT_NODE:
   8128 #ifdef LIBXML_DOCB_ENABLED
   8129 	case XML_DOCB_DOCUMENT_NODE:
   8130 #endif
   8131 	    return(NULL);
   8132     }
   8133     return(NULL);
   8134 }
   8135 
   8136 /**
   8137  * xmlXPathNextAncestorOrSelf:
   8138  * @ctxt:  the XPath Parser context
   8139  * @cur:  the current node in the traversal
   8140  *
   8141  * Traversal function for the "ancestor-or-self" direction
   8142  * he ancestor-or-self axis contains the context node and ancestors of
   8143  * the context node in reverse document order; thus the context node is
   8144  * the first node on the axis, and the context node's parent the second;
   8145  * parent here is defined the same as with the parent axis.
   8146  *
   8147  * Returns the next element following that axis
   8148  */
   8149 xmlNodePtr
   8150 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8151     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8152     if (cur == NULL)
   8153         return(ctxt->context->node);
   8154     return(xmlXPathNextAncestor(ctxt, cur));
   8155 }
   8156 
   8157 /**
   8158  * xmlXPathNextFollowingSibling:
   8159  * @ctxt:  the XPath Parser context
   8160  * @cur:  the current node in the traversal
   8161  *
   8162  * Traversal function for the "following-sibling" direction
   8163  * The following-sibling axis contains the following siblings of the context
   8164  * node in document order.
   8165  *
   8166  * Returns the next element following that axis
   8167  */
   8168 xmlNodePtr
   8169 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8170     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8171     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   8172 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
   8173 	return(NULL);
   8174     if (cur == (xmlNodePtr) ctxt->context->doc)
   8175         return(NULL);
   8176     if (cur == NULL)
   8177         return(ctxt->context->node->next);
   8178     return(cur->next);
   8179 }
   8180 
   8181 /**
   8182  * xmlXPathNextPrecedingSibling:
   8183  * @ctxt:  the XPath Parser context
   8184  * @cur:  the current node in the traversal
   8185  *
   8186  * Traversal function for the "preceding-sibling" direction
   8187  * The preceding-sibling axis contains the preceding siblings of the context
   8188  * node in reverse document order; the first preceding sibling is first on the
   8189  * axis; the sibling preceding that node is the second on the axis and so on.
   8190  *
   8191  * Returns the next element following that axis
   8192  */
   8193 xmlNodePtr
   8194 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8195     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8196     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
   8197 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
   8198 	return(NULL);
   8199     if (cur == (xmlNodePtr) ctxt->context->doc)
   8200         return(NULL);
   8201     if (cur == NULL)
   8202         return(ctxt->context->node->prev);
   8203     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
   8204 	cur = cur->prev;
   8205 	if (cur == NULL)
   8206 	    return(ctxt->context->node->prev);
   8207     }
   8208     return(cur->prev);
   8209 }
   8210 
   8211 /**
   8212  * xmlXPathNextFollowing:
   8213  * @ctxt:  the XPath Parser context
   8214  * @cur:  the current node in the traversal
   8215  *
   8216  * Traversal function for the "following" direction
   8217  * The following axis contains all nodes in the same document as the context
   8218  * node that are after the context node in document order, excluding any
   8219  * descendants and excluding attribute nodes and namespace nodes; the nodes
   8220  * are ordered in document order
   8221  *
   8222  * Returns the next element following that axis
   8223  */
   8224 xmlNodePtr
   8225 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8226     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8227     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
   8228         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
   8229         return(cur->children);
   8230 
   8231     if (cur == NULL) {
   8232         cur = ctxt->context->node;
   8233         if (cur->type == XML_ATTRIBUTE_NODE) {
   8234             cur = cur->parent;
   8235         } else if (cur->type == XML_NAMESPACE_DECL) {
   8236             xmlNsPtr ns = (xmlNsPtr) cur;
   8237 
   8238             if ((ns->next == NULL) ||
   8239                 (ns->next->type == XML_NAMESPACE_DECL))
   8240                 return (NULL);
   8241             cur = (xmlNodePtr) ns->next;
   8242         }
   8243     }
   8244     if (cur == NULL) return(NULL) ; /* ERROR */
   8245     if (cur->next != NULL) return(cur->next) ;
   8246     do {
   8247         cur = cur->parent;
   8248         if (cur == NULL) break;
   8249         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
   8250         if (cur->next != NULL) return(cur->next);
   8251     } while (cur != NULL);
   8252     return(cur);
   8253 }
   8254 
   8255 /*
   8256  * xmlXPathIsAncestor:
   8257  * @ancestor:  the ancestor node
   8258  * @node:  the current node
   8259  *
   8260  * Check that @ancestor is a @node's ancestor
   8261  *
   8262  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
   8263  */
   8264 static int
   8265 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
   8266     if ((ancestor == NULL) || (node == NULL)) return(0);
   8267     if (node->type == XML_NAMESPACE_DECL)
   8268         return(0);
   8269     if (ancestor->type == XML_NAMESPACE_DECL)
   8270         return(0);
   8271     /* nodes need to be in the same document */
   8272     if (ancestor->doc != node->doc) return(0);
   8273     /* avoid searching if ancestor or node is the root node */
   8274     if (ancestor == (xmlNodePtr) node->doc) return(1);
   8275     if (node == (xmlNodePtr) ancestor->doc) return(0);
   8276     while (node->parent != NULL) {
   8277         if (node->parent == ancestor)
   8278             return(1);
   8279 	node = node->parent;
   8280     }
   8281     return(0);
   8282 }
   8283 
   8284 /**
   8285  * xmlXPathNextPreceding:
   8286  * @ctxt:  the XPath Parser context
   8287  * @cur:  the current node in the traversal
   8288  *
   8289  * Traversal function for the "preceding" direction
   8290  * the preceding axis contains all nodes in the same document as the context
   8291  * node that are before the context node in document order, excluding any
   8292  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
   8293  * ordered in reverse document order
   8294  *
   8295  * Returns the next element following that axis
   8296  */
   8297 xmlNodePtr
   8298 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
   8299 {
   8300     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8301     if (cur == NULL) {
   8302         cur = ctxt->context->node;
   8303         if (cur->type == XML_ATTRIBUTE_NODE) {
   8304             cur = cur->parent;
   8305         } else if (cur->type == XML_NAMESPACE_DECL) {
   8306             xmlNsPtr ns = (xmlNsPtr) cur;
   8307 
   8308             if ((ns->next == NULL) ||
   8309                 (ns->next->type == XML_NAMESPACE_DECL))
   8310                 return (NULL);
   8311             cur = (xmlNodePtr) ns->next;
   8312         }
   8313     }
   8314     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
   8315 	return (NULL);
   8316     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
   8317 	cur = cur->prev;
   8318     do {
   8319         if (cur->prev != NULL) {
   8320             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
   8321             return (cur);
   8322         }
   8323 
   8324         cur = cur->parent;
   8325         if (cur == NULL)
   8326             return (NULL);
   8327         if (cur == ctxt->context->doc->children)
   8328             return (NULL);
   8329     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
   8330     return (cur);
   8331 }
   8332 
   8333 /**
   8334  * xmlXPathNextPrecedingInternal:
   8335  * @ctxt:  the XPath Parser context
   8336  * @cur:  the current node in the traversal
   8337  *
   8338  * Traversal function for the "preceding" direction
   8339  * the preceding axis contains all nodes in the same document as the context
   8340  * node that are before the context node in document order, excluding any
   8341  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
   8342  * ordered in reverse document order
   8343  * This is a faster implementation but internal only since it requires a
   8344  * state kept in the parser context: ctxt->ancestor.
   8345  *
   8346  * Returns the next element following that axis
   8347  */
   8348 static xmlNodePtr
   8349 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
   8350                               xmlNodePtr cur)
   8351 {
   8352     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8353     if (cur == NULL) {
   8354         cur = ctxt->context->node;
   8355         if (cur == NULL)
   8356             return (NULL);
   8357         if (cur->type == XML_ATTRIBUTE_NODE) {
   8358             cur = cur->parent;
   8359         } else if (cur->type == XML_NAMESPACE_DECL) {
   8360             xmlNsPtr ns = (xmlNsPtr) cur;
   8361 
   8362             if ((ns->next == NULL) ||
   8363                 (ns->next->type == XML_NAMESPACE_DECL))
   8364                 return (NULL);
   8365             cur = (xmlNodePtr) ns->next;
   8366         }
   8367         ctxt->ancestor = cur->parent;
   8368     }
   8369     if (cur->type == XML_NAMESPACE_DECL)
   8370         return(NULL);
   8371     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
   8372 	cur = cur->prev;
   8373     while (cur->prev == NULL) {
   8374         cur = cur->parent;
   8375         if (cur == NULL)
   8376             return (NULL);
   8377         if (cur == ctxt->context->doc->children)
   8378             return (NULL);
   8379         if (cur != ctxt->ancestor)
   8380             return (cur);
   8381         ctxt->ancestor = cur->parent;
   8382     }
   8383     cur = cur->prev;
   8384     while (cur->last != NULL)
   8385         cur = cur->last;
   8386     return (cur);
   8387 }
   8388 
   8389 /**
   8390  * xmlXPathNextNamespace:
   8391  * @ctxt:  the XPath Parser context
   8392  * @cur:  the current attribute in the traversal
   8393  *
   8394  * Traversal function for the "namespace" direction
   8395  * the namespace axis contains the namespace nodes of the context node;
   8396  * the order of nodes on this axis is implementation-defined; the axis will
   8397  * be empty unless the context node is an element
   8398  *
   8399  * We keep the XML namespace node at the end of the list.
   8400  *
   8401  * Returns the next element following that axis
   8402  */
   8403 xmlNodePtr
   8404 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8405     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8406     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
   8407     if (cur == NULL) {
   8408         if (ctxt->context->tmpNsList != NULL)
   8409 	    xmlFree(ctxt->context->tmpNsList);
   8410 	ctxt->context->tmpNsList =
   8411 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
   8412 	ctxt->context->tmpNsNr = 0;
   8413 	if (ctxt->context->tmpNsList != NULL) {
   8414 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
   8415 		ctxt->context->tmpNsNr++;
   8416 	    }
   8417 	}
   8418 	return((xmlNodePtr) xmlXPathXMLNamespace);
   8419     }
   8420     if (ctxt->context->tmpNsNr > 0) {
   8421 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
   8422     } else {
   8423 	if (ctxt->context->tmpNsList != NULL)
   8424 	    xmlFree(ctxt->context->tmpNsList);
   8425 	ctxt->context->tmpNsList = NULL;
   8426 	return(NULL);
   8427     }
   8428 }
   8429 
   8430 /**
   8431  * xmlXPathNextAttribute:
   8432  * @ctxt:  the XPath Parser context
   8433  * @cur:  the current attribute in the traversal
   8434  *
   8435  * Traversal function for the "attribute" direction
   8436  * TODO: support DTD inherited default attributes
   8437  *
   8438  * Returns the next element following that axis
   8439  */
   8440 xmlNodePtr
   8441 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
   8442     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
   8443     if (ctxt->context->node == NULL)
   8444 	return(NULL);
   8445     if (ctxt->context->node->type != XML_ELEMENT_NODE)
   8446 	return(NULL);
   8447     if (cur == NULL) {
   8448         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
   8449 	    return(NULL);
   8450         return((xmlNodePtr)ctxt->context->node->properties);
   8451     }
   8452     return((xmlNodePtr)cur->next);
   8453 }
   8454 
   8455 /************************************************************************
   8456  *									*
   8457  *		NodeTest Functions					*
   8458  *									*
   8459  ************************************************************************/
   8460 
   8461 #define IS_FUNCTION			200
   8462 
   8463 
   8464 /************************************************************************
   8465  *									*
   8466  *		Implicit tree core function library			*
   8467  *									*
   8468  ************************************************************************/
   8469 
   8470 /**
   8471  * xmlXPathRoot:
   8472  * @ctxt:  the XPath Parser context
   8473  *
   8474  * Initialize the context to the root of the document
   8475  */
   8476 void
   8477 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
   8478     if ((ctxt == NULL) || (ctxt->context == NULL))
   8479 	return;
   8480     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8481 	(xmlNodePtr) ctxt->context->doc));
   8482 }
   8483 
   8484 /************************************************************************
   8485  *									*
   8486  *		The explicit core function library			*
   8487  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
   8488  *									*
   8489  ************************************************************************/
   8490 
   8491 
   8492 /**
   8493  * xmlXPathLastFunction:
   8494  * @ctxt:  the XPath Parser context
   8495  * @nargs:  the number of arguments
   8496  *
   8497  * Implement the last() XPath function
   8498  *    number last()
   8499  * The last function returns the number of nodes in the context node list.
   8500  */
   8501 void
   8502 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8503     CHECK_ARITY(0);
   8504     if (ctxt->context->contextSize >= 0) {
   8505 	valuePush(ctxt,
   8506 	    xmlXPathCacheNewFloat(ctxt->context,
   8507 		(double) ctxt->context->contextSize));
   8508 #ifdef DEBUG_EXPR
   8509 	xmlGenericError(xmlGenericErrorContext,
   8510 		"last() : %d\n", ctxt->context->contextSize);
   8511 #endif
   8512     } else {
   8513 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
   8514     }
   8515 }
   8516 
   8517 /**
   8518  * xmlXPathPositionFunction:
   8519  * @ctxt:  the XPath Parser context
   8520  * @nargs:  the number of arguments
   8521  *
   8522  * Implement the position() XPath function
   8523  *    number position()
   8524  * The position function returns the position of the context node in the
   8525  * context node list. The first position is 1, and so the last position
   8526  * will be equal to last().
   8527  */
   8528 void
   8529 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8530     CHECK_ARITY(0);
   8531     if (ctxt->context->proximityPosition >= 0) {
   8532 	valuePush(ctxt,
   8533 	      xmlXPathCacheNewFloat(ctxt->context,
   8534 		(double) ctxt->context->proximityPosition));
   8535 #ifdef DEBUG_EXPR
   8536 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
   8537 		ctxt->context->proximityPosition);
   8538 #endif
   8539     } else {
   8540 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
   8541     }
   8542 }
   8543 
   8544 /**
   8545  * xmlXPathCountFunction:
   8546  * @ctxt:  the XPath Parser context
   8547  * @nargs:  the number of arguments
   8548  *
   8549  * Implement the count() XPath function
   8550  *    number count(node-set)
   8551  */
   8552 void
   8553 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8554     xmlXPathObjectPtr cur;
   8555 
   8556     CHECK_ARITY(1);
   8557     if ((ctxt->value == NULL) ||
   8558 	((ctxt->value->type != XPATH_NODESET) &&
   8559 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8560 	XP_ERROR(XPATH_INVALID_TYPE);
   8561     cur = valuePop(ctxt);
   8562 
   8563     if ((cur == NULL) || (cur->nodesetval == NULL))
   8564 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
   8565     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
   8566 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8567 	    (double) cur->nodesetval->nodeNr));
   8568     } else {
   8569 	if ((cur->nodesetval->nodeNr != 1) ||
   8570 	    (cur->nodesetval->nodeTab == NULL)) {
   8571 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
   8572 	} else {
   8573 	    xmlNodePtr tmp;
   8574 	    int i = 0;
   8575 
   8576 	    tmp = cur->nodesetval->nodeTab[0];
   8577 	    if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
   8578 		tmp = tmp->children;
   8579 		while (tmp != NULL) {
   8580 		    tmp = tmp->next;
   8581 		    i++;
   8582 		}
   8583 	    }
   8584 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
   8585 	}
   8586     }
   8587     xmlXPathReleaseObject(ctxt->context, cur);
   8588 }
   8589 
   8590 /**
   8591  * xmlXPathGetElementsByIds:
   8592  * @doc:  the document
   8593  * @ids:  a whitespace separated list of IDs
   8594  *
   8595  * Selects elements by their unique ID.
   8596  *
   8597  * Returns a node-set of selected elements.
   8598  */
   8599 static xmlNodeSetPtr
   8600 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
   8601     xmlNodeSetPtr ret;
   8602     const xmlChar *cur = ids;
   8603     xmlChar *ID;
   8604     xmlAttrPtr attr;
   8605     xmlNodePtr elem = NULL;
   8606 
   8607     if (ids == NULL) return(NULL);
   8608 
   8609     ret = xmlXPathNodeSetCreate(NULL);
   8610     if (ret == NULL)
   8611         return(ret);
   8612 
   8613     while (IS_BLANK_CH(*cur)) cur++;
   8614     while (*cur != 0) {
   8615 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
   8616 	    cur++;
   8617 
   8618         ID = xmlStrndup(ids, cur - ids);
   8619 	if (ID != NULL) {
   8620 	    /*
   8621 	     * We used to check the fact that the value passed
   8622 	     * was an NCName, but this generated much troubles for
   8623 	     * me and Aleksey Sanin, people blatantly violated that
   8624 	     * constaint, like Visa3D spec.
   8625 	     * if (xmlValidateNCName(ID, 1) == 0)
   8626 	     */
   8627 	    attr = xmlGetID(doc, ID);
   8628 	    if (attr != NULL) {
   8629 		if (attr->type == XML_ATTRIBUTE_NODE)
   8630 		    elem = attr->parent;
   8631 		else if (attr->type == XML_ELEMENT_NODE)
   8632 		    elem = (xmlNodePtr) attr;
   8633 		else
   8634 		    elem = NULL;
   8635 		if (elem != NULL)
   8636 		    xmlXPathNodeSetAdd(ret, elem);
   8637 	    }
   8638 	    xmlFree(ID);
   8639 	}
   8640 
   8641 	while (IS_BLANK_CH(*cur)) cur++;
   8642 	ids = cur;
   8643     }
   8644     return(ret);
   8645 }
   8646 
   8647 /**
   8648  * xmlXPathIdFunction:
   8649  * @ctxt:  the XPath Parser context
   8650  * @nargs:  the number of arguments
   8651  *
   8652  * Implement the id() XPath function
   8653  *    node-set id(object)
   8654  * The id function selects elements by their unique ID
   8655  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
   8656  * then the result is the union of the result of applying id to the
   8657  * string value of each of the nodes in the argument node-set. When the
   8658  * argument to id is of any other type, the argument is converted to a
   8659  * string as if by a call to the string function; the string is split
   8660  * into a whitespace-separated list of tokens (whitespace is any sequence
   8661  * of characters matching the production S); the result is a node-set
   8662  * containing the elements in the same document as the context node that
   8663  * have a unique ID equal to any of the tokens in the list.
   8664  */
   8665 void
   8666 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8667     xmlChar *tokens;
   8668     xmlNodeSetPtr ret;
   8669     xmlXPathObjectPtr obj;
   8670 
   8671     CHECK_ARITY(1);
   8672     obj = valuePop(ctxt);
   8673     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   8674     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
   8675 	xmlNodeSetPtr ns;
   8676 	int i;
   8677 
   8678 	ret = xmlXPathNodeSetCreate(NULL);
   8679         /*
   8680          * FIXME -- in an out-of-memory condition this will behave badly.
   8681          * The solution is not clear -- we already popped an item from
   8682          * ctxt, so the object is in a corrupt state.
   8683          */
   8684 
   8685 	if (obj->nodesetval != NULL) {
   8686 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
   8687 		tokens =
   8688 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
   8689 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
   8690 		ret = xmlXPathNodeSetMerge(ret, ns);
   8691 		xmlXPathFreeNodeSet(ns);
   8692 		if (tokens != NULL)
   8693 		    xmlFree(tokens);
   8694 	    }
   8695 	}
   8696 	xmlXPathReleaseObject(ctxt->context, obj);
   8697 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
   8698 	return;
   8699     }
   8700     obj = xmlXPathCacheConvertString(ctxt->context, obj);
   8701     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
   8702     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
   8703     xmlXPathReleaseObject(ctxt->context, obj);
   8704     return;
   8705 }
   8706 
   8707 /**
   8708  * xmlXPathLocalNameFunction:
   8709  * @ctxt:  the XPath Parser context
   8710  * @nargs:  the number of arguments
   8711  *
   8712  * Implement the local-name() XPath function
   8713  *    string local-name(node-set?)
   8714  * The local-name function returns a string containing the local part
   8715  * of the name of the node in the argument node-set that is first in
   8716  * document order. If the node-set is empty or the first node has no
   8717  * name, an empty string is returned. If the argument is omitted it
   8718  * defaults to the context node.
   8719  */
   8720 void
   8721 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8722     xmlXPathObjectPtr cur;
   8723 
   8724     if (ctxt == NULL) return;
   8725 
   8726     if (nargs == 0) {
   8727 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8728 	    ctxt->context->node));
   8729 	nargs = 1;
   8730     }
   8731 
   8732     CHECK_ARITY(1);
   8733     if ((ctxt->value == NULL) ||
   8734 	((ctxt->value->type != XPATH_NODESET) &&
   8735 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8736 	XP_ERROR(XPATH_INVALID_TYPE);
   8737     cur = valuePop(ctxt);
   8738 
   8739     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
   8740 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8741     } else {
   8742 	int i = 0; /* Should be first in document order !!!!! */
   8743 	switch (cur->nodesetval->nodeTab[i]->type) {
   8744 	case XML_ELEMENT_NODE:
   8745 	case XML_ATTRIBUTE_NODE:
   8746 	case XML_PI_NODE:
   8747 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
   8748 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8749 	    else
   8750 		valuePush(ctxt,
   8751 		      xmlXPathCacheNewString(ctxt->context,
   8752 			cur->nodesetval->nodeTab[i]->name));
   8753 	    break;
   8754 	case XML_NAMESPACE_DECL:
   8755 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   8756 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
   8757 	    break;
   8758 	default:
   8759 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8760 	}
   8761     }
   8762     xmlXPathReleaseObject(ctxt->context, cur);
   8763 }
   8764 
   8765 /**
   8766  * xmlXPathNamespaceURIFunction:
   8767  * @ctxt:  the XPath Parser context
   8768  * @nargs:  the number of arguments
   8769  *
   8770  * Implement the namespace-uri() XPath function
   8771  *    string namespace-uri(node-set?)
   8772  * The namespace-uri function returns a string containing the
   8773  * namespace URI of the expanded name of the node in the argument
   8774  * node-set that is first in document order. If the node-set is empty,
   8775  * the first node has no name, or the expanded name has no namespace
   8776  * URI, an empty string is returned. If the argument is omitted it
   8777  * defaults to the context node.
   8778  */
   8779 void
   8780 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8781     xmlXPathObjectPtr cur;
   8782 
   8783     if (ctxt == NULL) return;
   8784 
   8785     if (nargs == 0) {
   8786 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8787 	    ctxt->context->node));
   8788 	nargs = 1;
   8789     }
   8790     CHECK_ARITY(1);
   8791     if ((ctxt->value == NULL) ||
   8792 	((ctxt->value->type != XPATH_NODESET) &&
   8793 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   8794 	XP_ERROR(XPATH_INVALID_TYPE);
   8795     cur = valuePop(ctxt);
   8796 
   8797     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
   8798 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8799     } else {
   8800 	int i = 0; /* Should be first in document order !!!!! */
   8801 	switch (cur->nodesetval->nodeTab[i]->type) {
   8802 	case XML_ELEMENT_NODE:
   8803 	case XML_ATTRIBUTE_NODE:
   8804 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
   8805 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8806 	    else
   8807 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   8808 			  cur->nodesetval->nodeTab[i]->ns->href));
   8809 	    break;
   8810 	default:
   8811 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8812 	}
   8813     }
   8814     xmlXPathReleaseObject(ctxt->context, cur);
   8815 }
   8816 
   8817 /**
   8818  * xmlXPathNameFunction:
   8819  * @ctxt:  the XPath Parser context
   8820  * @nargs:  the number of arguments
   8821  *
   8822  * Implement the name() XPath function
   8823  *    string name(node-set?)
   8824  * The name function returns a string containing a QName representing
   8825  * the name of the node in the argument node-set that is first in document
   8826  * order. The QName must represent the name with respect to the namespace
   8827  * declarations in effect on the node whose name is being represented.
   8828  * Typically, this will be the form in which the name occurred in the XML
   8829  * source. This need not be the case if there are namespace declarations
   8830  * in effect on the node that associate multiple prefixes with the same
   8831  * namespace. However, an implementation may include information about
   8832  * the original prefix in its representation of nodes; in this case, an
   8833  * implementation can ensure that the returned string is always the same
   8834  * as the QName used in the XML source. If the argument it omitted it
   8835  * defaults to the context node.
   8836  * Libxml keep the original prefix so the "real qualified name" used is
   8837  * returned.
   8838  */
   8839 static void
   8840 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
   8841 {
   8842     xmlXPathObjectPtr cur;
   8843 
   8844     if (nargs == 0) {
   8845 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8846 	    ctxt->context->node));
   8847         nargs = 1;
   8848     }
   8849 
   8850     CHECK_ARITY(1);
   8851     if ((ctxt->value == NULL) ||
   8852         ((ctxt->value->type != XPATH_NODESET) &&
   8853          (ctxt->value->type != XPATH_XSLT_TREE)))
   8854         XP_ERROR(XPATH_INVALID_TYPE);
   8855     cur = valuePop(ctxt);
   8856 
   8857     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
   8858         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   8859     } else {
   8860         int i = 0;              /* Should be first in document order !!!!! */
   8861 
   8862         switch (cur->nodesetval->nodeTab[i]->type) {
   8863             case XML_ELEMENT_NODE:
   8864             case XML_ATTRIBUTE_NODE:
   8865 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
   8866 		    valuePush(ctxt,
   8867 			xmlXPathCacheNewCString(ctxt->context, ""));
   8868 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
   8869                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
   8870 		    valuePush(ctxt,
   8871 		        xmlXPathCacheNewString(ctxt->context,
   8872 			    cur->nodesetval->nodeTab[i]->name));
   8873 		} else {
   8874 		    xmlChar *fullname;
   8875 
   8876 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
   8877 				     cur->nodesetval->nodeTab[i]->ns->prefix,
   8878 				     NULL, 0);
   8879 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
   8880 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
   8881 		    if (fullname == NULL) {
   8882 			XP_ERROR(XPATH_MEMORY_ERROR);
   8883 		    }
   8884 		    valuePush(ctxt, xmlXPathCacheWrapString(
   8885 			ctxt->context, fullname));
   8886                 }
   8887                 break;
   8888             default:
   8889 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   8890 		    cur->nodesetval->nodeTab[i]));
   8891                 xmlXPathLocalNameFunction(ctxt, 1);
   8892         }
   8893     }
   8894     xmlXPathReleaseObject(ctxt->context, cur);
   8895 }
   8896 
   8897 
   8898 /**
   8899  * xmlXPathStringFunction:
   8900  * @ctxt:  the XPath Parser context
   8901  * @nargs:  the number of arguments
   8902  *
   8903  * Implement the string() XPath function
   8904  *    string string(object?)
   8905  * The string function converts an object to a string as follows:
   8906  *    - A node-set is converted to a string by returning the value of
   8907  *      the node in the node-set that is first in document order.
   8908  *      If the node-set is empty, an empty string is returned.
   8909  *    - A number is converted to a string as follows
   8910  *      + NaN is converted to the string NaN
   8911  *      + positive zero is converted to the string 0
   8912  *      + negative zero is converted to the string 0
   8913  *      + positive infinity is converted to the string Infinity
   8914  *      + negative infinity is converted to the string -Infinity
   8915  *      + if the number is an integer, the number is represented in
   8916  *        decimal form as a Number with no decimal point and no leading
   8917  *        zeros, preceded by a minus sign (-) if the number is negative
   8918  *      + otherwise, the number is represented in decimal form as a
   8919  *        Number including a decimal point with at least one digit
   8920  *        before the decimal point and at least one digit after the
   8921  *        decimal point, preceded by a minus sign (-) if the number
   8922  *        is negative; there must be no leading zeros before the decimal
   8923  *        point apart possibly from the one required digit immediately
   8924  *        before the decimal point; beyond the one required digit
   8925  *        after the decimal point there must be as many, but only as
   8926  *        many, more digits as are needed to uniquely distinguish the
   8927  *        number from all other IEEE 754 numeric values.
   8928  *    - The boolean false value is converted to the string false.
   8929  *      The boolean true value is converted to the string true.
   8930  *
   8931  * If the argument is omitted, it defaults to a node-set with the
   8932  * context node as its only member.
   8933  */
   8934 void
   8935 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8936     xmlXPathObjectPtr cur;
   8937 
   8938     if (ctxt == NULL) return;
   8939     if (nargs == 0) {
   8940     valuePush(ctxt,
   8941 	xmlXPathCacheWrapString(ctxt->context,
   8942 	    xmlXPathCastNodeToString(ctxt->context->node)));
   8943 	return;
   8944     }
   8945 
   8946     CHECK_ARITY(1);
   8947     cur = valuePop(ctxt);
   8948     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   8949     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
   8950 }
   8951 
   8952 /**
   8953  * xmlXPathStringLengthFunction:
   8954  * @ctxt:  the XPath Parser context
   8955  * @nargs:  the number of arguments
   8956  *
   8957  * Implement the string-length() XPath function
   8958  *    number string-length(string?)
   8959  * The string-length returns the number of characters in the string
   8960  * (see [3.6 Strings]). If the argument is omitted, it defaults to
   8961  * the context node converted to a string, in other words the value
   8962  * of the context node.
   8963  */
   8964 void
   8965 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   8966     xmlXPathObjectPtr cur;
   8967 
   8968     if (nargs == 0) {
   8969         if ((ctxt == NULL) || (ctxt->context == NULL))
   8970 	    return;
   8971 	if (ctxt->context->node == NULL) {
   8972 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
   8973 	} else {
   8974 	    xmlChar *content;
   8975 
   8976 	    content = xmlXPathCastNodeToString(ctxt->context->node);
   8977 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8978 		xmlUTF8Strlen(content)));
   8979 	    xmlFree(content);
   8980 	}
   8981 	return;
   8982     }
   8983     CHECK_ARITY(1);
   8984     CAST_TO_STRING;
   8985     CHECK_TYPE(XPATH_STRING);
   8986     cur = valuePop(ctxt);
   8987     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
   8988 	xmlUTF8Strlen(cur->stringval)));
   8989     xmlXPathReleaseObject(ctxt->context, cur);
   8990 }
   8991 
   8992 /**
   8993  * xmlXPathConcatFunction:
   8994  * @ctxt:  the XPath Parser context
   8995  * @nargs:  the number of arguments
   8996  *
   8997  * Implement the concat() XPath function
   8998  *    string concat(string, string, string*)
   8999  * The concat function returns the concatenation of its arguments.
   9000  */
   9001 void
   9002 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9003     xmlXPathObjectPtr cur, newobj;
   9004     xmlChar *tmp;
   9005 
   9006     if (ctxt == NULL) return;
   9007     if (nargs < 2) {
   9008 	CHECK_ARITY(2);
   9009     }
   9010 
   9011     CAST_TO_STRING;
   9012     cur = valuePop(ctxt);
   9013     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
   9014 	xmlXPathReleaseObject(ctxt->context, cur);
   9015 	return;
   9016     }
   9017     nargs--;
   9018 
   9019     while (nargs > 0) {
   9020 	CAST_TO_STRING;
   9021 	newobj = valuePop(ctxt);
   9022 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
   9023 	    xmlXPathReleaseObject(ctxt->context, newobj);
   9024 	    xmlXPathReleaseObject(ctxt->context, cur);
   9025 	    XP_ERROR(XPATH_INVALID_TYPE);
   9026 	}
   9027 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
   9028 	newobj->stringval = cur->stringval;
   9029 	cur->stringval = tmp;
   9030 	xmlXPathReleaseObject(ctxt->context, newobj);
   9031 	nargs--;
   9032     }
   9033     valuePush(ctxt, cur);
   9034 }
   9035 
   9036 /**
   9037  * xmlXPathContainsFunction:
   9038  * @ctxt:  the XPath Parser context
   9039  * @nargs:  the number of arguments
   9040  *
   9041  * Implement the contains() XPath function
   9042  *    boolean contains(string, string)
   9043  * The contains function returns true if the first argument string
   9044  * contains the second argument string, and otherwise returns false.
   9045  */
   9046 void
   9047 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9048     xmlXPathObjectPtr hay, needle;
   9049 
   9050     CHECK_ARITY(2);
   9051     CAST_TO_STRING;
   9052     CHECK_TYPE(XPATH_STRING);
   9053     needle = valuePop(ctxt);
   9054     CAST_TO_STRING;
   9055     hay = valuePop(ctxt);
   9056 
   9057     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
   9058 	xmlXPathReleaseObject(ctxt->context, hay);
   9059 	xmlXPathReleaseObject(ctxt->context, needle);
   9060 	XP_ERROR(XPATH_INVALID_TYPE);
   9061     }
   9062     if (xmlStrstr(hay->stringval, needle->stringval))
   9063 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   9064     else
   9065 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   9066     xmlXPathReleaseObject(ctxt->context, hay);
   9067     xmlXPathReleaseObject(ctxt->context, needle);
   9068 }
   9069 
   9070 /**
   9071  * xmlXPathStartsWithFunction:
   9072  * @ctxt:  the XPath Parser context
   9073  * @nargs:  the number of arguments
   9074  *
   9075  * Implement the starts-with() XPath function
   9076  *    boolean starts-with(string, string)
   9077  * The starts-with function returns true if the first argument string
   9078  * starts with the second argument string, and otherwise returns false.
   9079  */
   9080 void
   9081 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9082     xmlXPathObjectPtr hay, needle;
   9083     int n;
   9084 
   9085     CHECK_ARITY(2);
   9086     CAST_TO_STRING;
   9087     CHECK_TYPE(XPATH_STRING);
   9088     needle = valuePop(ctxt);
   9089     CAST_TO_STRING;
   9090     hay = valuePop(ctxt);
   9091 
   9092     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
   9093 	xmlXPathReleaseObject(ctxt->context, hay);
   9094 	xmlXPathReleaseObject(ctxt->context, needle);
   9095 	XP_ERROR(XPATH_INVALID_TYPE);
   9096     }
   9097     n = xmlStrlen(needle->stringval);
   9098     if (xmlStrncmp(hay->stringval, needle->stringval, n))
   9099         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   9100     else
   9101         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   9102     xmlXPathReleaseObject(ctxt->context, hay);
   9103     xmlXPathReleaseObject(ctxt->context, needle);
   9104 }
   9105 
   9106 /**
   9107  * xmlXPathSubstringFunction:
   9108  * @ctxt:  the XPath Parser context
   9109  * @nargs:  the number of arguments
   9110  *
   9111  * Implement the substring() XPath function
   9112  *    string substring(string, number, number?)
   9113  * The substring function returns the substring of the first argument
   9114  * starting at the position specified in the second argument with
   9115  * length specified in the third argument. For example,
   9116  * substring("12345",2,3) returns "234". If the third argument is not
   9117  * specified, it returns the substring starting at the position specified
   9118  * in the second argument and continuing to the end of the string. For
   9119  * example, substring("12345",2) returns "2345".  More precisely, each
   9120  * character in the string (see [3.6 Strings]) is considered to have a
   9121  * numeric position: the position of the first character is 1, the position
   9122  * of the second character is 2 and so on. The returned substring contains
   9123  * those characters for which the position of the character is greater than
   9124  * or equal to the second argument and, if the third argument is specified,
   9125  * less than the sum of the second and third arguments; the comparisons
   9126  * and addition used for the above follow the standard IEEE 754 rules. Thus:
   9127  *  - substring("12345", 1.5, 2.6) returns "234"
   9128  *  - substring("12345", 0, 3) returns "12"
   9129  *  - substring("12345", 0 div 0, 3) returns ""
   9130  *  - substring("12345", 1, 0 div 0) returns ""
   9131  *  - substring("12345", -42, 1 div 0) returns "12345"
   9132  *  - substring("12345", -1 div 0, 1 div 0) returns ""
   9133  */
   9134 void
   9135 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9136     xmlXPathObjectPtr str, start, len;
   9137     double le=0, in;
   9138     int i, l, m;
   9139     xmlChar *ret;
   9140 
   9141     if (nargs < 2) {
   9142 	CHECK_ARITY(2);
   9143     }
   9144     if (nargs > 3) {
   9145 	CHECK_ARITY(3);
   9146     }
   9147     /*
   9148      * take care of possible last (position) argument
   9149     */
   9150     if (nargs == 3) {
   9151 	CAST_TO_NUMBER;
   9152 	CHECK_TYPE(XPATH_NUMBER);
   9153 	len = valuePop(ctxt);
   9154 	le = len->floatval;
   9155 	xmlXPathReleaseObject(ctxt->context, len);
   9156     }
   9157 
   9158     CAST_TO_NUMBER;
   9159     CHECK_TYPE(XPATH_NUMBER);
   9160     start = valuePop(ctxt);
   9161     in = start->floatval;
   9162     xmlXPathReleaseObject(ctxt->context, start);
   9163     CAST_TO_STRING;
   9164     CHECK_TYPE(XPATH_STRING);
   9165     str = valuePop(ctxt);
   9166     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
   9167 
   9168     /*
   9169      * If last pos not present, calculate last position
   9170     */
   9171     if (nargs != 3) {
   9172 	le = (double)m;
   9173 	if (in < 1.0)
   9174 	    in = 1.0;
   9175     }
   9176 
   9177     /* Need to check for the special cases where either
   9178      * the index is NaN, the length is NaN, or both
   9179      * arguments are infinity (relying on Inf + -Inf = NaN)
   9180      */
   9181     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
   9182         /*
   9183          * To meet the requirements of the spec, the arguments
   9184 	 * must be converted to integer format before
   9185 	 * initial index calculations are done
   9186          *
   9187          * First we go to integer form, rounding up
   9188 	 * and checking for special cases
   9189          */
   9190         i = (int) in;
   9191         if (((double)i)+0.5 <= in) i++;
   9192 
   9193 	if (xmlXPathIsInf(le) == 1) {
   9194 	    l = m;
   9195 	    if (i < 1)
   9196 		i = 1;
   9197 	}
   9198 	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
   9199 	    l = 0;
   9200 	else {
   9201 	    l = (int) le;
   9202 	    if (((double)l)+0.5 <= le) l++;
   9203 	}
   9204 
   9205 	/* Now we normalize inidices */
   9206         i -= 1;
   9207         l += i;
   9208         if (i < 0)
   9209             i = 0;
   9210         if (l > m)
   9211             l = m;
   9212 
   9213         /* number of chars to copy */
   9214         l -= i;
   9215 
   9216         ret = xmlUTF8Strsub(str->stringval, i, l);
   9217     }
   9218     else {
   9219         ret = NULL;
   9220     }
   9221     if (ret == NULL)
   9222 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
   9223     else {
   9224 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
   9225 	xmlFree(ret);
   9226     }
   9227     xmlXPathReleaseObject(ctxt->context, str);
   9228 }
   9229 
   9230 /**
   9231  * xmlXPathSubstringBeforeFunction:
   9232  * @ctxt:  the XPath Parser context
   9233  * @nargs:  the number of arguments
   9234  *
   9235  * Implement the substring-before() XPath function
   9236  *    string substring-before(string, string)
   9237  * The substring-before function returns the substring of the first
   9238  * argument string that precedes the first occurrence of the second
   9239  * argument string in the first argument string, or the empty string
   9240  * if the first argument string does not contain the second argument
   9241  * string. For example, substring-before("1999/04/01","/") returns 1999.
   9242  */
   9243 void
   9244 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9245   xmlXPathObjectPtr str;
   9246   xmlXPathObjectPtr find;
   9247   xmlBufPtr target;
   9248   const xmlChar *point;
   9249   int offset;
   9250 
   9251   CHECK_ARITY(2);
   9252   CAST_TO_STRING;
   9253   find = valuePop(ctxt);
   9254   CAST_TO_STRING;
   9255   str = valuePop(ctxt);
   9256 
   9257   target = xmlBufCreate();
   9258   if (target) {
   9259     point = xmlStrstr(str->stringval, find->stringval);
   9260     if (point) {
   9261       offset = (int)(point - str->stringval);
   9262       xmlBufAdd(target, str->stringval, offset);
   9263     }
   9264     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9265 	xmlBufContent(target)));
   9266     xmlBufFree(target);
   9267   }
   9268   xmlXPathReleaseObject(ctxt->context, str);
   9269   xmlXPathReleaseObject(ctxt->context, find);
   9270 }
   9271 
   9272 /**
   9273  * xmlXPathSubstringAfterFunction:
   9274  * @ctxt:  the XPath Parser context
   9275  * @nargs:  the number of arguments
   9276  *
   9277  * Implement the substring-after() XPath function
   9278  *    string substring-after(string, string)
   9279  * The substring-after function returns the substring of the first
   9280  * argument string that follows the first occurrence of the second
   9281  * argument string in the first argument string, or the empty stringi
   9282  * if the first argument string does not contain the second argument
   9283  * string. For example, substring-after("1999/04/01","/") returns 04/01,
   9284  * and substring-after("1999/04/01","19") returns 99/04/01.
   9285  */
   9286 void
   9287 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9288   xmlXPathObjectPtr str;
   9289   xmlXPathObjectPtr find;
   9290   xmlBufPtr target;
   9291   const xmlChar *point;
   9292   int offset;
   9293 
   9294   CHECK_ARITY(2);
   9295   CAST_TO_STRING;
   9296   find = valuePop(ctxt);
   9297   CAST_TO_STRING;
   9298   str = valuePop(ctxt);
   9299 
   9300   target = xmlBufCreate();
   9301   if (target) {
   9302     point = xmlStrstr(str->stringval, find->stringval);
   9303     if (point) {
   9304       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
   9305       xmlBufAdd(target, &str->stringval[offset],
   9306 		   xmlStrlen(str->stringval) - offset);
   9307     }
   9308     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9309 	xmlBufContent(target)));
   9310     xmlBufFree(target);
   9311   }
   9312   xmlXPathReleaseObject(ctxt->context, str);
   9313   xmlXPathReleaseObject(ctxt->context, find);
   9314 }
   9315 
   9316 /**
   9317  * xmlXPathNormalizeFunction:
   9318  * @ctxt:  the XPath Parser context
   9319  * @nargs:  the number of arguments
   9320  *
   9321  * Implement the normalize-space() XPath function
   9322  *    string normalize-space(string?)
   9323  * The normalize-space function returns the argument string with white
   9324  * space normalized by stripping leading and trailing whitespace
   9325  * and replacing sequences of whitespace characters by a single
   9326  * space. Whitespace characters are the same allowed by the S production
   9327  * in XML. If the argument is omitted, it defaults to the context
   9328  * node converted to a string, in other words the value of the context node.
   9329  */
   9330 void
   9331 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9332   xmlXPathObjectPtr obj = NULL;
   9333   xmlChar *source = NULL;
   9334   xmlBufPtr target;
   9335   xmlChar blank;
   9336 
   9337   if (ctxt == NULL) return;
   9338   if (nargs == 0) {
   9339     /* Use current context node */
   9340       valuePush(ctxt,
   9341 	  xmlXPathCacheWrapString(ctxt->context,
   9342 	    xmlXPathCastNodeToString(ctxt->context->node)));
   9343     nargs = 1;
   9344   }
   9345 
   9346   CHECK_ARITY(1);
   9347   CAST_TO_STRING;
   9348   CHECK_TYPE(XPATH_STRING);
   9349   obj = valuePop(ctxt);
   9350   source = obj->stringval;
   9351 
   9352   target = xmlBufCreate();
   9353   if (target && source) {
   9354 
   9355     /* Skip leading whitespaces */
   9356     while (IS_BLANK_CH(*source))
   9357       source++;
   9358 
   9359     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
   9360     blank = 0;
   9361     while (*source) {
   9362       if (IS_BLANK_CH(*source)) {
   9363 	blank = 0x20;
   9364       } else {
   9365 	if (blank) {
   9366 	  xmlBufAdd(target, &blank, 1);
   9367 	  blank = 0;
   9368 	}
   9369 	xmlBufAdd(target, source, 1);
   9370       }
   9371       source++;
   9372     }
   9373     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9374 	xmlBufContent(target)));
   9375     xmlBufFree(target);
   9376   }
   9377   xmlXPathReleaseObject(ctxt->context, obj);
   9378 }
   9379 
   9380 /**
   9381  * xmlXPathTranslateFunction:
   9382  * @ctxt:  the XPath Parser context
   9383  * @nargs:  the number of arguments
   9384  *
   9385  * Implement the translate() XPath function
   9386  *    string translate(string, string, string)
   9387  * The translate function returns the first argument string with
   9388  * occurrences of characters in the second argument string replaced
   9389  * by the character at the corresponding position in the third argument
   9390  * string. For example, translate("bar","abc","ABC") returns the string
   9391  * BAr. If there is a character in the second argument string with no
   9392  * character at a corresponding position in the third argument string
   9393  * (because the second argument string is longer than the third argument
   9394  * string), then occurrences of that character in the first argument
   9395  * string are removed. For example, translate("--aaa--","abc-","ABC")
   9396  * returns "AAA". If a character occurs more than once in second
   9397  * argument string, then the first occurrence determines the replacement
   9398  * character. If the third argument string is longer than the second
   9399  * argument string, then excess characters are ignored.
   9400  */
   9401 void
   9402 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9403     xmlXPathObjectPtr str;
   9404     xmlXPathObjectPtr from;
   9405     xmlXPathObjectPtr to;
   9406     xmlBufPtr target;
   9407     int offset, max;
   9408     xmlChar ch;
   9409     const xmlChar *point;
   9410     xmlChar *cptr;
   9411 
   9412     CHECK_ARITY(3);
   9413 
   9414     CAST_TO_STRING;
   9415     to = valuePop(ctxt);
   9416     CAST_TO_STRING;
   9417     from = valuePop(ctxt);
   9418     CAST_TO_STRING;
   9419     str = valuePop(ctxt);
   9420 
   9421     target = xmlBufCreate();
   9422     if (target) {
   9423 	max = xmlUTF8Strlen(to->stringval);
   9424 	for (cptr = str->stringval; (ch=*cptr); ) {
   9425 	    offset = xmlUTF8Strloc(from->stringval, cptr);
   9426 	    if (offset >= 0) {
   9427 		if (offset < max) {
   9428 		    point = xmlUTF8Strpos(to->stringval, offset);
   9429 		    if (point)
   9430 			xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
   9431 		}
   9432 	    } else
   9433 		xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
   9434 
   9435 	    /* Step to next character in input */
   9436 	    cptr++;
   9437 	    if ( ch & 0x80 ) {
   9438 		/* if not simple ascii, verify proper format */
   9439 		if ( (ch & 0xc0) != 0xc0 ) {
   9440 		    xmlGenericError(xmlGenericErrorContext,
   9441 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
   9442                     /* not asserting an XPath error is probably better */
   9443 		    break;
   9444 		}
   9445 		/* then skip over remaining bytes for this char */
   9446 		while ( (ch <<= 1) & 0x80 )
   9447 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
   9448 			xmlGenericError(xmlGenericErrorContext,
   9449 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
   9450                         /* not asserting an XPath error is probably better */
   9451 			break;
   9452 		    }
   9453 		if (ch & 0x80) /* must have had error encountered */
   9454 		    break;
   9455 	    }
   9456 	}
   9457     }
   9458     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   9459 	xmlBufContent(target)));
   9460     xmlBufFree(target);
   9461     xmlXPathReleaseObject(ctxt->context, str);
   9462     xmlXPathReleaseObject(ctxt->context, from);
   9463     xmlXPathReleaseObject(ctxt->context, to);
   9464 }
   9465 
   9466 /**
   9467  * xmlXPathBooleanFunction:
   9468  * @ctxt:  the XPath Parser context
   9469  * @nargs:  the number of arguments
   9470  *
   9471  * Implement the boolean() XPath function
   9472  *    boolean boolean(object)
   9473  * The boolean function converts its argument to a boolean as follows:
   9474  *    - a number is true if and only if it is neither positive or
   9475  *      negative zero nor NaN
   9476  *    - a node-set is true if and only if it is non-empty
   9477  *    - a string is true if and only if its length is non-zero
   9478  */
   9479 void
   9480 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9481     xmlXPathObjectPtr cur;
   9482 
   9483     CHECK_ARITY(1);
   9484     cur = valuePop(ctxt);
   9485     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
   9486     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
   9487     valuePush(ctxt, cur);
   9488 }
   9489 
   9490 /**
   9491  * xmlXPathNotFunction:
   9492  * @ctxt:  the XPath Parser context
   9493  * @nargs:  the number of arguments
   9494  *
   9495  * Implement the not() XPath function
   9496  *    boolean not(boolean)
   9497  * The not function returns true if its argument is false,
   9498  * and false otherwise.
   9499  */
   9500 void
   9501 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9502     CHECK_ARITY(1);
   9503     CAST_TO_BOOLEAN;
   9504     CHECK_TYPE(XPATH_BOOLEAN);
   9505     ctxt->value->boolval = ! ctxt->value->boolval;
   9506 }
   9507 
   9508 /**
   9509  * xmlXPathTrueFunction:
   9510  * @ctxt:  the XPath Parser context
   9511  * @nargs:  the number of arguments
   9512  *
   9513  * Implement the true() XPath function
   9514  *    boolean true()
   9515  */
   9516 void
   9517 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9518     CHECK_ARITY(0);
   9519     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
   9520 }
   9521 
   9522 /**
   9523  * xmlXPathFalseFunction:
   9524  * @ctxt:  the XPath Parser context
   9525  * @nargs:  the number of arguments
   9526  *
   9527  * Implement the false() XPath function
   9528  *    boolean false()
   9529  */
   9530 void
   9531 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9532     CHECK_ARITY(0);
   9533     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
   9534 }
   9535 
   9536 /**
   9537  * xmlXPathLangFunction:
   9538  * @ctxt:  the XPath Parser context
   9539  * @nargs:  the number of arguments
   9540  *
   9541  * Implement the lang() XPath function
   9542  *    boolean lang(string)
   9543  * The lang function returns true or false depending on whether the
   9544  * language of the context node as specified by xml:lang attributes
   9545  * is the same as or is a sublanguage of the language specified by
   9546  * the argument string. The language of the context node is determined
   9547  * by the value of the xml:lang attribute on the context node, or, if
   9548  * the context node has no xml:lang attribute, by the value of the
   9549  * xml:lang attribute on the nearest ancestor of the context node that
   9550  * has an xml:lang attribute. If there is no such attribute, then lang
   9551  * returns false. If there is such an attribute, then lang returns
   9552  * true if the attribute value is equal to the argument ignoring case,
   9553  * or if there is some suffix starting with - such that the attribute
   9554  * value is equal to the argument ignoring that suffix of the attribute
   9555  * value and ignoring case.
   9556  */
   9557 void
   9558 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9559     xmlXPathObjectPtr val = NULL;
   9560     const xmlChar *theLang = NULL;
   9561     const xmlChar *lang;
   9562     int ret = 0;
   9563     int i;
   9564 
   9565     CHECK_ARITY(1);
   9566     CAST_TO_STRING;
   9567     CHECK_TYPE(XPATH_STRING);
   9568     val = valuePop(ctxt);
   9569     lang = val->stringval;
   9570     theLang = xmlNodeGetLang(ctxt->context->node);
   9571     if ((theLang != NULL) && (lang != NULL)) {
   9572         for (i = 0;lang[i] != 0;i++)
   9573 	    if (toupper(lang[i]) != toupper(theLang[i]))
   9574 	        goto not_equal;
   9575 	if ((theLang[i] == 0) || (theLang[i] == '-'))
   9576 	    ret = 1;
   9577     }
   9578 not_equal:
   9579     if (theLang != NULL)
   9580 	xmlFree((void *)theLang);
   9581 
   9582     xmlXPathReleaseObject(ctxt->context, val);
   9583     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
   9584 }
   9585 
   9586 /**
   9587  * xmlXPathNumberFunction:
   9588  * @ctxt:  the XPath Parser context
   9589  * @nargs:  the number of arguments
   9590  *
   9591  * Implement the number() XPath function
   9592  *    number number(object?)
   9593  */
   9594 void
   9595 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9596     xmlXPathObjectPtr cur;
   9597     double res;
   9598 
   9599     if (ctxt == NULL) return;
   9600     if (nargs == 0) {
   9601 	if (ctxt->context->node == NULL) {
   9602 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
   9603 	} else {
   9604 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
   9605 
   9606 	    res = xmlXPathStringEvalNumber(content);
   9607 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
   9608 	    xmlFree(content);
   9609 	}
   9610 	return;
   9611     }
   9612 
   9613     CHECK_ARITY(1);
   9614     cur = valuePop(ctxt);
   9615     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
   9616 }
   9617 
   9618 /**
   9619  * xmlXPathSumFunction:
   9620  * @ctxt:  the XPath Parser context
   9621  * @nargs:  the number of arguments
   9622  *
   9623  * Implement the sum() XPath function
   9624  *    number sum(node-set)
   9625  * The sum function returns the sum of the values of the nodes in
   9626  * the argument node-set.
   9627  */
   9628 void
   9629 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9630     xmlXPathObjectPtr cur;
   9631     int i;
   9632     double res = 0.0;
   9633 
   9634     CHECK_ARITY(1);
   9635     if ((ctxt->value == NULL) ||
   9636 	((ctxt->value->type != XPATH_NODESET) &&
   9637 	 (ctxt->value->type != XPATH_XSLT_TREE)))
   9638 	XP_ERROR(XPATH_INVALID_TYPE);
   9639     cur = valuePop(ctxt);
   9640 
   9641     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
   9642 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
   9643 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
   9644 	}
   9645     }
   9646     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
   9647     xmlXPathReleaseObject(ctxt->context, cur);
   9648 }
   9649 
   9650 /**
   9651  * xmlXPathFloorFunction:
   9652  * @ctxt:  the XPath Parser context
   9653  * @nargs:  the number of arguments
   9654  *
   9655  * Implement the floor() XPath function
   9656  *    number floor(number)
   9657  * The floor function returns the largest (closest to positive infinity)
   9658  * number that is not greater than the argument and that is an integer.
   9659  */
   9660 void
   9661 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9662     CHECK_ARITY(1);
   9663     CAST_TO_NUMBER;
   9664     CHECK_TYPE(XPATH_NUMBER);
   9665 
   9666     ctxt->value->floatval = floor(ctxt->value->floatval);
   9667 }
   9668 
   9669 /**
   9670  * xmlXPathCeilingFunction:
   9671  * @ctxt:  the XPath Parser context
   9672  * @nargs:  the number of arguments
   9673  *
   9674  * Implement the ceiling() XPath function
   9675  *    number ceiling(number)
   9676  * The ceiling function returns the smallest (closest to negative infinity)
   9677  * number that is not less than the argument and that is an integer.
   9678  */
   9679 void
   9680 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9681     CHECK_ARITY(1);
   9682     CAST_TO_NUMBER;
   9683     CHECK_TYPE(XPATH_NUMBER);
   9684 
   9685     ctxt->value->floatval = ceil(ctxt->value->floatval);
   9686 }
   9687 
   9688 /**
   9689  * xmlXPathRoundFunction:
   9690  * @ctxt:  the XPath Parser context
   9691  * @nargs:  the number of arguments
   9692  *
   9693  * Implement the round() XPath function
   9694  *    number round(number)
   9695  * The round function returns the number that is closest to the
   9696  * argument and that is an integer. If there are two such numbers,
   9697  * then the one that is closest to positive infinity is returned.
   9698  */
   9699 void
   9700 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   9701     double f;
   9702 
   9703     CHECK_ARITY(1);
   9704     CAST_TO_NUMBER;
   9705     CHECK_TYPE(XPATH_NUMBER);
   9706 
   9707     f = ctxt->value->floatval;
   9708 
   9709     if ((f >= -0.5) && (f < 0.5)) {
   9710         /* Handles negative zero. */
   9711         ctxt->value->floatval *= 0.0;
   9712     }
   9713     else {
   9714         double rounded = floor(f);
   9715         if (f - rounded >= 0.5)
   9716             rounded += 1.0;
   9717         ctxt->value->floatval = rounded;
   9718     }
   9719 }
   9720 
   9721 /************************************************************************
   9722  *									*
   9723  *			The Parser					*
   9724  *									*
   9725  ************************************************************************/
   9726 
   9727 /*
   9728  * a few forward declarations since we use a recursive call based
   9729  * implementation.
   9730  */
   9731 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
   9732 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
   9733 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
   9734 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
   9735 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
   9736 	                                  int qualified);
   9737 
   9738 /**
   9739  * xmlXPathCurrentChar:
   9740  * @ctxt:  the XPath parser context
   9741  * @cur:  pointer to the beginning of the char
   9742  * @len:  pointer to the length of the char read
   9743  *
   9744  * The current char value, if using UTF-8 this may actually span multiple
   9745  * bytes in the input buffer.
   9746  *
   9747  * Returns the current char value and its length
   9748  */
   9749 
   9750 static int
   9751 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
   9752     unsigned char c;
   9753     unsigned int val;
   9754     const xmlChar *cur;
   9755 
   9756     if (ctxt == NULL)
   9757 	return(0);
   9758     cur = ctxt->cur;
   9759 
   9760     /*
   9761      * We are supposed to handle UTF8, check it's valid
   9762      * From rfc2044: encoding of the Unicode values on UTF-8:
   9763      *
   9764      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
   9765      * 0000 0000-0000 007F   0xxxxxxx
   9766      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
   9767      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
   9768      *
   9769      * Check for the 0x110000 limit too
   9770      */
   9771     c = *cur;
   9772     if (c & 0x80) {
   9773 	if ((cur[1] & 0xc0) != 0x80)
   9774 	    goto encoding_error;
   9775 	if ((c & 0xe0) == 0xe0) {
   9776 
   9777 	    if ((cur[2] & 0xc0) != 0x80)
   9778 		goto encoding_error;
   9779 	    if ((c & 0xf0) == 0xf0) {
   9780 		if (((c & 0xf8) != 0xf0) ||
   9781 		    ((cur[3] & 0xc0) != 0x80))
   9782 		    goto encoding_error;
   9783 		/* 4-byte code */
   9784 		*len = 4;
   9785 		val = (cur[0] & 0x7) << 18;
   9786 		val |= (cur[1] & 0x3f) << 12;
   9787 		val |= (cur[2] & 0x3f) << 6;
   9788 		val |= cur[3] & 0x3f;
   9789 	    } else {
   9790 	      /* 3-byte code */
   9791 		*len = 3;
   9792 		val = (cur[0] & 0xf) << 12;
   9793 		val |= (cur[1] & 0x3f) << 6;
   9794 		val |= cur[2] & 0x3f;
   9795 	    }
   9796 	} else {
   9797 	  /* 2-byte code */
   9798 	    *len = 2;
   9799 	    val = (cur[0] & 0x1f) << 6;
   9800 	    val |= cur[1] & 0x3f;
   9801 	}
   9802 	if (!IS_CHAR(val)) {
   9803 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
   9804 	}
   9805 	return(val);
   9806     } else {
   9807 	/* 1-byte code */
   9808 	*len = 1;
   9809 	return((int) *cur);
   9810     }
   9811 encoding_error:
   9812     /*
   9813      * If we detect an UTF8 error that probably means that the
   9814      * input encoding didn't get properly advertised in the
   9815      * declaration header. Report the error and switch the encoding
   9816      * to ISO-Latin-1 (if you don't like this policy, just declare the
   9817      * encoding !)
   9818      */
   9819     *len = 0;
   9820     XP_ERROR0(XPATH_ENCODING_ERROR);
   9821 }
   9822 
   9823 /**
   9824  * xmlXPathParseNCName:
   9825  * @ctxt:  the XPath Parser context
   9826  *
   9827  * parse an XML namespace non qualified name.
   9828  *
   9829  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
   9830  *
   9831  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
   9832  *                       CombiningChar | Extender
   9833  *
   9834  * Returns the namespace name or NULL
   9835  */
   9836 
   9837 xmlChar *
   9838 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
   9839     const xmlChar *in;
   9840     xmlChar *ret;
   9841     int count = 0;
   9842 
   9843     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
   9844     /*
   9845      * Accelerator for simple ASCII names
   9846      */
   9847     in = ctxt->cur;
   9848     if (((*in >= 0x61) && (*in <= 0x7A)) ||
   9849 	((*in >= 0x41) && (*in <= 0x5A)) ||
   9850 	(*in == '_')) {
   9851 	in++;
   9852 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
   9853 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
   9854 	       ((*in >= 0x30) && (*in <= 0x39)) ||
   9855 	       (*in == '_') || (*in == '.') ||
   9856 	       (*in == '-'))
   9857 	    in++;
   9858 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
   9859             (*in == '[') || (*in == ']') || (*in == ':') ||
   9860             (*in == '@') || (*in == '*')) {
   9861 	    count = in - ctxt->cur;
   9862 	    if (count == 0)
   9863 		return(NULL);
   9864 	    ret = xmlStrndup(ctxt->cur, count);
   9865 	    ctxt->cur = in;
   9866 	    return(ret);
   9867 	}
   9868     }
   9869     return(xmlXPathParseNameComplex(ctxt, 0));
   9870 }
   9871 
   9872 
   9873 /**
   9874  * xmlXPathParseQName:
   9875  * @ctxt:  the XPath Parser context
   9876  * @prefix:  a xmlChar **
   9877  *
   9878  * parse an XML qualified name
   9879  *
   9880  * [NS 5] QName ::= (Prefix ':')? LocalPart
   9881  *
   9882  * [NS 6] Prefix ::= NCName
   9883  *
   9884  * [NS 7] LocalPart ::= NCName
   9885  *
   9886  * Returns the function returns the local part, and prefix is updated
   9887  *   to get the Prefix if any.
   9888  */
   9889 
   9890 static xmlChar *
   9891 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
   9892     xmlChar *ret = NULL;
   9893 
   9894     *prefix = NULL;
   9895     ret = xmlXPathParseNCName(ctxt);
   9896     if (ret && CUR == ':') {
   9897         *prefix = ret;
   9898 	NEXT;
   9899 	ret = xmlXPathParseNCName(ctxt);
   9900     }
   9901     return(ret);
   9902 }
   9903 
   9904 /**
   9905  * xmlXPathParseName:
   9906  * @ctxt:  the XPath Parser context
   9907  *
   9908  * parse an XML name
   9909  *
   9910  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
   9911  *                  CombiningChar | Extender
   9912  *
   9913  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
   9914  *
   9915  * Returns the namespace name or NULL
   9916  */
   9917 
   9918 xmlChar *
   9919 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
   9920     const xmlChar *in;
   9921     xmlChar *ret;
   9922     size_t count = 0;
   9923 
   9924     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
   9925     /*
   9926      * Accelerator for simple ASCII names
   9927      */
   9928     in = ctxt->cur;
   9929     if (((*in >= 0x61) && (*in <= 0x7A)) ||
   9930 	((*in >= 0x41) && (*in <= 0x5A)) ||
   9931 	(*in == '_') || (*in == ':')) {
   9932 	in++;
   9933 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
   9934 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
   9935 	       ((*in >= 0x30) && (*in <= 0x39)) ||
   9936 	       (*in == '_') || (*in == '-') ||
   9937 	       (*in == ':') || (*in == '.'))
   9938 	    in++;
   9939 	if ((*in > 0) && (*in < 0x80)) {
   9940 	    count = in - ctxt->cur;
   9941             if (count > XML_MAX_NAME_LENGTH) {
   9942                 ctxt->cur = in;
   9943                 XP_ERRORNULL(XPATH_EXPR_ERROR);
   9944             }
   9945 	    ret = xmlStrndup(ctxt->cur, count);
   9946 	    ctxt->cur = in;
   9947 	    return(ret);
   9948 	}
   9949     }
   9950     return(xmlXPathParseNameComplex(ctxt, 1));
   9951 }
   9952 
   9953 static xmlChar *
   9954 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
   9955     xmlChar buf[XML_MAX_NAMELEN + 5];
   9956     int len = 0, l;
   9957     int c;
   9958 
   9959     /*
   9960      * Handler for more complex cases
   9961      */
   9962     c = CUR_CHAR(l);
   9963     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
   9964         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
   9965         (c == '*') || /* accelerators */
   9966 	(!IS_LETTER(c) && (c != '_') &&
   9967          ((!qualified) || (c != ':')))) {
   9968 	return(NULL);
   9969     }
   9970 
   9971     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
   9972 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
   9973             (c == '.') || (c == '-') ||
   9974 	    (c == '_') || ((qualified) && (c == ':')) ||
   9975 	    (IS_COMBINING(c)) ||
   9976 	    (IS_EXTENDER(c)))) {
   9977 	COPY_BUF(l,buf,len,c);
   9978 	NEXTL(l);
   9979 	c = CUR_CHAR(l);
   9980 	if (len >= XML_MAX_NAMELEN) {
   9981 	    /*
   9982 	     * Okay someone managed to make a huge name, so he's ready to pay
   9983 	     * for the processing speed.
   9984 	     */
   9985 	    xmlChar *buffer;
   9986 	    int max = len * 2;
   9987 
   9988             if (len > XML_MAX_NAME_LENGTH) {
   9989                 XP_ERRORNULL(XPATH_EXPR_ERROR);
   9990             }
   9991 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
   9992 	    if (buffer == NULL) {
   9993 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
   9994 	    }
   9995 	    memcpy(buffer, buf, len);
   9996 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
   9997 		   (c == '.') || (c == '-') ||
   9998 		   (c == '_') || ((qualified) && (c == ':')) ||
   9999 		   (IS_COMBINING(c)) ||
   10000 		   (IS_EXTENDER(c))) {
   10001 		if (len + 10 > max) {
   10002                     if (max > XML_MAX_NAME_LENGTH) {
   10003                         XP_ERRORNULL(XPATH_EXPR_ERROR);
   10004                     }
   10005 		    max *= 2;
   10006 		    buffer = (xmlChar *) xmlRealloc(buffer,
   10007 			                            max * sizeof(xmlChar));
   10008 		    if (buffer == NULL) {
   10009 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
   10010 		    }
   10011 		}
   10012 		COPY_BUF(l,buffer,len,c);
   10013 		NEXTL(l);
   10014 		c = CUR_CHAR(l);
   10015 	    }
   10016 	    buffer[len] = 0;
   10017 	    return(buffer);
   10018 	}
   10019     }
   10020     if (len == 0)
   10021 	return(NULL);
   10022     return(xmlStrndup(buf, len));
   10023 }
   10024 
   10025 #define MAX_FRAC 20
   10026 
   10027 /**
   10028  * xmlXPathStringEvalNumber:
   10029  * @str:  A string to scan
   10030  *
   10031  *  [30a]  Float  ::= Number ('e' Digits?)?
   10032  *
   10033  *  [30]   Number ::=   Digits ('.' Digits?)?
   10034  *                    | '.' Digits
   10035  *  [31]   Digits ::=   [0-9]+
   10036  *
   10037  * Compile a Number in the string
   10038  * In complement of the Number expression, this function also handles
   10039  * negative values : '-' Number.
   10040  *
   10041  * Returns the double value.
   10042  */
   10043 double
   10044 xmlXPathStringEvalNumber(const xmlChar *str) {
   10045     const xmlChar *cur = str;
   10046     double ret;
   10047     int ok = 0;
   10048     int isneg = 0;
   10049     int exponent = 0;
   10050     int is_exponent_negative = 0;
   10051 #ifdef __GNUC__
   10052     unsigned long tmp = 0;
   10053     double temp;
   10054 #endif
   10055     if (cur == NULL) return(0);
   10056     while (IS_BLANK_CH(*cur)) cur++;
   10057     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
   10058         return(NAN);
   10059     }
   10060     if (*cur == '-') {
   10061 	isneg = 1;
   10062 	cur++;
   10063     }
   10064 
   10065 #ifdef __GNUC__
   10066     /*
   10067      * tmp/temp is a workaround against a gcc compiler bug
   10068      * http://veillard.com/gcc.bug
   10069      */
   10070     ret = 0;
   10071     while ((*cur >= '0') && (*cur <= '9')) {
   10072 	ret = ret * 10;
   10073 	tmp = (*cur - '0');
   10074 	ok = 1;
   10075 	cur++;
   10076 	temp = (double) tmp;
   10077 	ret = ret + temp;
   10078     }
   10079 #else
   10080     ret = 0;
   10081     while ((*cur >= '0') && (*cur <= '9')) {
   10082 	ret = ret * 10 + (*cur - '0');
   10083 	ok = 1;
   10084 	cur++;
   10085     }
   10086 #endif
   10087 
   10088     if (*cur == '.') {
   10089 	int v, frac = 0, max;
   10090 	double fraction = 0;
   10091 
   10092         cur++;
   10093 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
   10094 	    return(NAN);
   10095 	}
   10096         while (*cur == '0') {
   10097 	    frac = frac + 1;
   10098 	    cur++;
   10099         }
   10100         max = frac + MAX_FRAC;
   10101 	while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
   10102 	    v = (*cur - '0');
   10103 	    fraction = fraction * 10 + v;
   10104 	    frac = frac + 1;
   10105 	    cur++;
   10106 	}
   10107 	fraction /= pow(10.0, frac);
   10108 	ret = ret + fraction;
   10109 	while ((*cur >= '0') && (*cur <= '9'))
   10110 	    cur++;
   10111     }
   10112     if ((*cur == 'e') || (*cur == 'E')) {
   10113       cur++;
   10114       if (*cur == '-') {
   10115 	is_exponent_negative = 1;
   10116 	cur++;
   10117       } else if (*cur == '+') {
   10118         cur++;
   10119       }
   10120       while ((*cur >= '0') && (*cur <= '9')) {
   10121         if (exponent < 1000000)
   10122 	  exponent = exponent * 10 + (*cur - '0');
   10123 	cur++;
   10124       }
   10125     }
   10126     while (IS_BLANK_CH(*cur)) cur++;
   10127     if (*cur != 0) return(NAN);
   10128     if (isneg) ret = -ret;
   10129     if (is_exponent_negative) exponent = -exponent;
   10130     ret *= pow(10.0, (double)exponent);
   10131     return(ret);
   10132 }
   10133 
   10134 /**
   10135  * xmlXPathCompNumber:
   10136  * @ctxt:  the XPath Parser context
   10137  *
   10138  *  [30]   Number ::=   Digits ('.' Digits?)?
   10139  *                    | '.' Digits
   10140  *  [31]   Digits ::=   [0-9]+
   10141  *
   10142  * Compile a Number, then push it on the stack
   10143  *
   10144  */
   10145 static void
   10146 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
   10147 {
   10148     double ret = 0.0;
   10149     int ok = 0;
   10150     int exponent = 0;
   10151     int is_exponent_negative = 0;
   10152 #ifdef __GNUC__
   10153     unsigned long tmp = 0;
   10154     double temp;
   10155 #endif
   10156 
   10157     CHECK_ERROR;
   10158     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
   10159         XP_ERROR(XPATH_NUMBER_ERROR);
   10160     }
   10161 #ifdef __GNUC__
   10162     /*
   10163      * tmp/temp is a workaround against a gcc compiler bug
   10164      * http://veillard.com/gcc.bug
   10165      */
   10166     ret = 0;
   10167     while ((CUR >= '0') && (CUR <= '9')) {
   10168 	ret = ret * 10;
   10169 	tmp = (CUR - '0');
   10170         ok = 1;
   10171         NEXT;
   10172 	temp = (double) tmp;
   10173 	ret = ret + temp;
   10174     }
   10175 #else
   10176     ret = 0;
   10177     while ((CUR >= '0') && (CUR <= '9')) {
   10178 	ret = ret * 10 + (CUR - '0');
   10179 	ok = 1;
   10180 	NEXT;
   10181     }
   10182 #endif
   10183     if (CUR == '.') {
   10184 	int v, frac = 0, max;
   10185 	double fraction = 0;
   10186 
   10187         NEXT;
   10188         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
   10189             XP_ERROR(XPATH_NUMBER_ERROR);
   10190         }
   10191         while (CUR == '0') {
   10192             frac = frac + 1;
   10193             NEXT;
   10194         }
   10195         max = frac + MAX_FRAC;
   10196         while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
   10197 	    v = (CUR - '0');
   10198 	    fraction = fraction * 10 + v;
   10199 	    frac = frac + 1;
   10200             NEXT;
   10201         }
   10202         fraction /= pow(10.0, frac);
   10203         ret = ret + fraction;
   10204         while ((CUR >= '0') && (CUR <= '9'))
   10205             NEXT;
   10206     }
   10207     if ((CUR == 'e') || (CUR == 'E')) {
   10208         NEXT;
   10209         if (CUR == '-') {
   10210             is_exponent_negative = 1;
   10211             NEXT;
   10212         } else if (CUR == '+') {
   10213 	    NEXT;
   10214 	}
   10215         while ((CUR >= '0') && (CUR <= '9')) {
   10216             if (exponent < 1000000)
   10217                 exponent = exponent * 10 + (CUR - '0');
   10218             NEXT;
   10219         }
   10220         if (is_exponent_negative)
   10221             exponent = -exponent;
   10222         ret *= pow(10.0, (double) exponent);
   10223     }
   10224     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
   10225                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
   10226 }
   10227 
   10228 /**
   10229  * xmlXPathParseLiteral:
   10230  * @ctxt:  the XPath Parser context
   10231  *
   10232  * Parse a Literal
   10233  *
   10234  *  [29]   Literal ::=   '"' [^"]* '"'
   10235  *                    | "'" [^']* "'"
   10236  *
   10237  * Returns the value found or NULL in case of error
   10238  */
   10239 static xmlChar *
   10240 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
   10241     const xmlChar *q;
   10242     xmlChar *ret = NULL;
   10243 
   10244     if (CUR == '"') {
   10245         NEXT;
   10246 	q = CUR_PTR;
   10247 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
   10248 	    NEXT;
   10249 	if (!IS_CHAR_CH(CUR)) {
   10250 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
   10251 	} else {
   10252 	    ret = xmlStrndup(q, CUR_PTR - q);
   10253 	    NEXT;
   10254         }
   10255     } else if (CUR == '\'') {
   10256         NEXT;
   10257 	q = CUR_PTR;
   10258 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
   10259 	    NEXT;
   10260 	if (!IS_CHAR_CH(CUR)) {
   10261 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
   10262 	} else {
   10263 	    ret = xmlStrndup(q, CUR_PTR - q);
   10264 	    NEXT;
   10265         }
   10266     } else {
   10267 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
   10268     }
   10269     return(ret);
   10270 }
   10271 
   10272 /**
   10273  * xmlXPathCompLiteral:
   10274  * @ctxt:  the XPath Parser context
   10275  *
   10276  * Parse a Literal and push it on the stack.
   10277  *
   10278  *  [29]   Literal ::=   '"' [^"]* '"'
   10279  *                    | "'" [^']* "'"
   10280  *
   10281  * TODO: xmlXPathCompLiteral memory allocation could be improved.
   10282  */
   10283 static void
   10284 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
   10285     const xmlChar *q;
   10286     xmlChar *ret = NULL;
   10287 
   10288     if (CUR == '"') {
   10289         NEXT;
   10290 	q = CUR_PTR;
   10291 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
   10292 	    NEXT;
   10293 	if (!IS_CHAR_CH(CUR)) {
   10294 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
   10295 	} else {
   10296 	    ret = xmlStrndup(q, CUR_PTR - q);
   10297 	    NEXT;
   10298         }
   10299     } else if (CUR == '\'') {
   10300         NEXT;
   10301 	q = CUR_PTR;
   10302 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
   10303 	    NEXT;
   10304 	if (!IS_CHAR_CH(CUR)) {
   10305 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
   10306 	} else {
   10307 	    ret = xmlStrndup(q, CUR_PTR - q);
   10308 	    NEXT;
   10309         }
   10310     } else {
   10311 	XP_ERROR(XPATH_START_LITERAL_ERROR);
   10312     }
   10313     if (ret == NULL) return;
   10314     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
   10315 	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
   10316     xmlFree(ret);
   10317 }
   10318 
   10319 /**
   10320  * xmlXPathCompVariableReference:
   10321  * @ctxt:  the XPath Parser context
   10322  *
   10323  * Parse a VariableReference, evaluate it and push it on the stack.
   10324  *
   10325  * The variable bindings consist of a mapping from variable names
   10326  * to variable values. The value of a variable is an object, which can be
   10327  * of any of the types that are possible for the value of an expression,
   10328  * and may also be of additional types not specified here.
   10329  *
   10330  * Early evaluation is possible since:
   10331  * The variable bindings [...] used to evaluate a subexpression are
   10332  * always the same as those used to evaluate the containing expression.
   10333  *
   10334  *  [36]   VariableReference ::=   '$' QName
   10335  */
   10336 static void
   10337 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
   10338     xmlChar *name;
   10339     xmlChar *prefix;
   10340 
   10341     SKIP_BLANKS;
   10342     if (CUR != '$') {
   10343 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
   10344     }
   10345     NEXT;
   10346     name = xmlXPathParseQName(ctxt, &prefix);
   10347     if (name == NULL) {
   10348         xmlFree(prefix);
   10349 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
   10350     }
   10351     ctxt->comp->last = -1;
   10352     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
   10353 	           name, prefix);
   10354     SKIP_BLANKS;
   10355     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
   10356 	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
   10357     }
   10358 }
   10359 
   10360 /**
   10361  * xmlXPathIsNodeType:
   10362  * @name:  a name string
   10363  *
   10364  * Is the name given a NodeType one.
   10365  *
   10366  *  [38]   NodeType ::=   'comment'
   10367  *                    | 'text'
   10368  *                    | 'processing-instruction'
   10369  *                    | 'node'
   10370  *
   10371  * Returns 1 if true 0 otherwise
   10372  */
   10373 int
   10374 xmlXPathIsNodeType(const xmlChar *name) {
   10375     if (name == NULL)
   10376 	return(0);
   10377 
   10378     if (xmlStrEqual(name, BAD_CAST "node"))
   10379 	return(1);
   10380     if (xmlStrEqual(name, BAD_CAST "text"))
   10381 	return(1);
   10382     if (xmlStrEqual(name, BAD_CAST "comment"))
   10383 	return(1);
   10384     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
   10385 	return(1);
   10386     return(0);
   10387 }
   10388 
   10389 /**
   10390  * xmlXPathCompFunctionCall:
   10391  * @ctxt:  the XPath Parser context
   10392  *
   10393  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
   10394  *  [17]   Argument ::=   Expr
   10395  *
   10396  * Compile a function call, the evaluation of all arguments are
   10397  * pushed on the stack
   10398  */
   10399 static void
   10400 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
   10401     xmlChar *name;
   10402     xmlChar *prefix;
   10403     int nbargs = 0;
   10404     int sort = 1;
   10405 
   10406     name = xmlXPathParseQName(ctxt, &prefix);
   10407     if (name == NULL) {
   10408 	xmlFree(prefix);
   10409 	XP_ERROR(XPATH_EXPR_ERROR);
   10410     }
   10411     SKIP_BLANKS;
   10412 #ifdef DEBUG_EXPR
   10413     if (prefix == NULL)
   10414 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
   10415 			name);
   10416     else
   10417 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
   10418 			prefix, name);
   10419 #endif
   10420 
   10421     if (CUR != '(') {
   10422 	xmlFree(name);
   10423 	xmlFree(prefix);
   10424 	XP_ERROR(XPATH_EXPR_ERROR);
   10425     }
   10426     NEXT;
   10427     SKIP_BLANKS;
   10428 
   10429     /*
   10430     * Optimization for count(): we don't need the node-set to be sorted.
   10431     */
   10432     if ((prefix == NULL) && (name[0] == 'c') &&
   10433 	xmlStrEqual(name, BAD_CAST "count"))
   10434     {
   10435 	sort = 0;
   10436     }
   10437     ctxt->comp->last = -1;
   10438     if (CUR != ')') {
   10439 	while (CUR != 0) {
   10440 	    int op1 = ctxt->comp->last;
   10441 	    ctxt->comp->last = -1;
   10442 	    xmlXPathCompileExpr(ctxt, sort);
   10443 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   10444 		xmlFree(name);
   10445 		xmlFree(prefix);
   10446 		return;
   10447 	    }
   10448 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
   10449 	    nbargs++;
   10450 	    if (CUR == ')') break;
   10451 	    if (CUR != ',') {
   10452 		xmlFree(name);
   10453 		xmlFree(prefix);
   10454 		XP_ERROR(XPATH_EXPR_ERROR);
   10455 	    }
   10456 	    NEXT;
   10457 	    SKIP_BLANKS;
   10458 	}
   10459     }
   10460     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
   10461 	           name, prefix);
   10462     NEXT;
   10463     SKIP_BLANKS;
   10464 }
   10465 
   10466 /**
   10467  * xmlXPathCompPrimaryExpr:
   10468  * @ctxt:  the XPath Parser context
   10469  *
   10470  *  [15]   PrimaryExpr ::=   VariableReference
   10471  *                | '(' Expr ')'
   10472  *                | Literal
   10473  *                | Number
   10474  *                | FunctionCall
   10475  *
   10476  * Compile a primary expression.
   10477  */
   10478 static void
   10479 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
   10480     SKIP_BLANKS;
   10481     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
   10482     else if (CUR == '(') {
   10483 	NEXT;
   10484 	SKIP_BLANKS;
   10485 	xmlXPathCompileExpr(ctxt, 1);
   10486 	CHECK_ERROR;
   10487 	if (CUR != ')') {
   10488 	    XP_ERROR(XPATH_EXPR_ERROR);
   10489 	}
   10490 	NEXT;
   10491 	SKIP_BLANKS;
   10492     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
   10493 	xmlXPathCompNumber(ctxt);
   10494     } else if ((CUR == '\'') || (CUR == '"')) {
   10495 	xmlXPathCompLiteral(ctxt);
   10496     } else {
   10497 	xmlXPathCompFunctionCall(ctxt);
   10498     }
   10499     SKIP_BLANKS;
   10500 }
   10501 
   10502 /**
   10503  * xmlXPathCompFilterExpr:
   10504  * @ctxt:  the XPath Parser context
   10505  *
   10506  *  [20]   FilterExpr ::=   PrimaryExpr
   10507  *               | FilterExpr Predicate
   10508  *
   10509  * Compile a filter expression.
   10510  * Square brackets are used to filter expressions in the same way that
   10511  * they are used in location paths. It is an error if the expression to
   10512  * be filtered does not evaluate to a node-set. The context node list
   10513  * used for evaluating the expression in square brackets is the node-set
   10514  * to be filtered listed in document order.
   10515  */
   10516 
   10517 static void
   10518 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
   10519     xmlXPathCompPrimaryExpr(ctxt);
   10520     CHECK_ERROR;
   10521     SKIP_BLANKS;
   10522 
   10523     while (CUR == '[') {
   10524 	xmlXPathCompPredicate(ctxt, 1);
   10525 	SKIP_BLANKS;
   10526     }
   10527 
   10528 
   10529 }
   10530 
   10531 /**
   10532  * xmlXPathScanName:
   10533  * @ctxt:  the XPath Parser context
   10534  *
   10535  * Trickery: parse an XML name but without consuming the input flow
   10536  * Needed to avoid insanity in the parser state.
   10537  *
   10538  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
   10539  *                  CombiningChar | Extender
   10540  *
   10541  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
   10542  *
   10543  * [6] Names ::= Name (S Name)*
   10544  *
   10545  * Returns the Name parsed or NULL
   10546  */
   10547 
   10548 static xmlChar *
   10549 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
   10550     int len = 0, l;
   10551     int c;
   10552     const xmlChar *cur;
   10553     xmlChar *ret;
   10554 
   10555     cur = ctxt->cur;
   10556 
   10557     c = CUR_CHAR(l);
   10558     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
   10559 	(!IS_LETTER(c) && (c != '_') &&
   10560          (c != ':'))) {
   10561 	return(NULL);
   10562     }
   10563 
   10564     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
   10565 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
   10566             (c == '.') || (c == '-') ||
   10567 	    (c == '_') || (c == ':') ||
   10568 	    (IS_COMBINING(c)) ||
   10569 	    (IS_EXTENDER(c)))) {
   10570 	len += l;
   10571 	NEXTL(l);
   10572 	c = CUR_CHAR(l);
   10573     }
   10574     ret = xmlStrndup(cur, ctxt->cur - cur);
   10575     ctxt->cur = cur;
   10576     return(ret);
   10577 }
   10578 
   10579 /**
   10580  * xmlXPathCompPathExpr:
   10581  * @ctxt:  the XPath Parser context
   10582  *
   10583  *  [19]   PathExpr ::=   LocationPath
   10584  *               | FilterExpr
   10585  *               | FilterExpr '/' RelativeLocationPath
   10586  *               | FilterExpr '//' RelativeLocationPath
   10587  *
   10588  * Compile a path expression.
   10589  * The / operator and // operators combine an arbitrary expression
   10590  * and a relative location path. It is an error if the expression
   10591  * does not evaluate to a node-set.
   10592  * The / operator does composition in the same way as when / is
   10593  * used in a location path. As in location paths, // is short for
   10594  * /descendant-or-self::node()/.
   10595  */
   10596 
   10597 static void
   10598 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
   10599     int lc = 1;           /* Should we branch to LocationPath ?         */
   10600     xmlChar *name = NULL; /* we may have to preparse a name to find out */
   10601 
   10602     SKIP_BLANKS;
   10603     if ((CUR == '$') || (CUR == '(') ||
   10604 	(IS_ASCII_DIGIT(CUR)) ||
   10605         (CUR == '\'') || (CUR == '"') ||
   10606 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
   10607 	lc = 0;
   10608     } else if (CUR == '*') {
   10609 	/* relative or absolute location path */
   10610 	lc = 1;
   10611     } else if (CUR == '/') {
   10612 	/* relative or absolute location path */
   10613 	lc = 1;
   10614     } else if (CUR == '@') {
   10615 	/* relative abbreviated attribute location path */
   10616 	lc = 1;
   10617     } else if (CUR == '.') {
   10618 	/* relative abbreviated attribute location path */
   10619 	lc = 1;
   10620     } else {
   10621 	/*
   10622 	 * Problem is finding if we have a name here whether it's:
   10623 	 *   - a nodetype
   10624 	 *   - a function call in which case it's followed by '('
   10625 	 *   - an axis in which case it's followed by ':'
   10626 	 *   - a element name
   10627 	 * We do an a priori analysis here rather than having to
   10628 	 * maintain parsed token content through the recursive function
   10629 	 * calls. This looks uglier but makes the code easier to
   10630 	 * read/write/debug.
   10631 	 */
   10632 	SKIP_BLANKS;
   10633 	name = xmlXPathScanName(ctxt);
   10634 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
   10635 #ifdef DEBUG_STEP
   10636 	    xmlGenericError(xmlGenericErrorContext,
   10637 		    "PathExpr: Axis\n");
   10638 #endif
   10639 	    lc = 1;
   10640 	    xmlFree(name);
   10641 	} else if (name != NULL) {
   10642 	    int len =xmlStrlen(name);
   10643 
   10644 
   10645 	    while (NXT(len) != 0) {
   10646 		if (NXT(len) == '/') {
   10647 		    /* element name */
   10648 #ifdef DEBUG_STEP
   10649 		    xmlGenericError(xmlGenericErrorContext,
   10650 			    "PathExpr: AbbrRelLocation\n");
   10651 #endif
   10652 		    lc = 1;
   10653 		    break;
   10654 		} else if (IS_BLANK_CH(NXT(len))) {
   10655 		    /* ignore blanks */
   10656 		    ;
   10657 		} else if (NXT(len) == ':') {
   10658 #ifdef DEBUG_STEP
   10659 		    xmlGenericError(xmlGenericErrorContext,
   10660 			    "PathExpr: AbbrRelLocation\n");
   10661 #endif
   10662 		    lc = 1;
   10663 		    break;
   10664 		} else if ((NXT(len) == '(')) {
   10665 		    /* Node Type or Function */
   10666 		    if (xmlXPathIsNodeType(name)) {
   10667 #ifdef DEBUG_STEP
   10668 		        xmlGenericError(xmlGenericErrorContext,
   10669 				"PathExpr: Type search\n");
   10670 #endif
   10671 			lc = 1;
   10672 #ifdef LIBXML_XPTR_ENABLED
   10673                     } else if (ctxt->xptr &&
   10674                                xmlStrEqual(name, BAD_CAST "range-to")) {
   10675                         lc = 1;
   10676 #endif
   10677 		    } else {
   10678 #ifdef DEBUG_STEP
   10679 		        xmlGenericError(xmlGenericErrorContext,
   10680 				"PathExpr: function call\n");
   10681 #endif
   10682 			lc = 0;
   10683 		    }
   10684                     break;
   10685 		} else if ((NXT(len) == '[')) {
   10686 		    /* element name */
   10687 #ifdef DEBUG_STEP
   10688 		    xmlGenericError(xmlGenericErrorContext,
   10689 			    "PathExpr: AbbrRelLocation\n");
   10690 #endif
   10691 		    lc = 1;
   10692 		    break;
   10693 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
   10694 			   (NXT(len) == '=')) {
   10695 		    lc = 1;
   10696 		    break;
   10697 		} else {
   10698 		    lc = 1;
   10699 		    break;
   10700 		}
   10701 		len++;
   10702 	    }
   10703 	    if (NXT(len) == 0) {
   10704 #ifdef DEBUG_STEP
   10705 		xmlGenericError(xmlGenericErrorContext,
   10706 			"PathExpr: AbbrRelLocation\n");
   10707 #endif
   10708 		/* element name */
   10709 		lc = 1;
   10710 	    }
   10711 	    xmlFree(name);
   10712 	} else {
   10713 	    /* make sure all cases are covered explicitly */
   10714 	    XP_ERROR(XPATH_EXPR_ERROR);
   10715 	}
   10716     }
   10717 
   10718     if (lc) {
   10719 	if (CUR == '/') {
   10720 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
   10721 	} else {
   10722 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
   10723 	}
   10724 	xmlXPathCompLocationPath(ctxt);
   10725     } else {
   10726 	xmlXPathCompFilterExpr(ctxt);
   10727 	CHECK_ERROR;
   10728 	if ((CUR == '/') && (NXT(1) == '/')) {
   10729 	    SKIP(2);
   10730 	    SKIP_BLANKS;
   10731 
   10732 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   10733 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   10734 
   10735 	    xmlXPathCompRelativeLocationPath(ctxt);
   10736 	} else if (CUR == '/') {
   10737 	    xmlXPathCompRelativeLocationPath(ctxt);
   10738 	}
   10739     }
   10740     SKIP_BLANKS;
   10741 }
   10742 
   10743 /**
   10744  * xmlXPathCompUnionExpr:
   10745  * @ctxt:  the XPath Parser context
   10746  *
   10747  *  [18]   UnionExpr ::=   PathExpr
   10748  *               | UnionExpr '|' PathExpr
   10749  *
   10750  * Compile an union expression.
   10751  */
   10752 
   10753 static void
   10754 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
   10755     xmlXPathCompPathExpr(ctxt);
   10756     CHECK_ERROR;
   10757     SKIP_BLANKS;
   10758     while (CUR == '|') {
   10759 	int op1 = ctxt->comp->last;
   10760 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
   10761 
   10762 	NEXT;
   10763 	SKIP_BLANKS;
   10764 	xmlXPathCompPathExpr(ctxt);
   10765 
   10766 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
   10767 
   10768 	SKIP_BLANKS;
   10769     }
   10770 }
   10771 
   10772 /**
   10773  * xmlXPathCompUnaryExpr:
   10774  * @ctxt:  the XPath Parser context
   10775  *
   10776  *  [27]   UnaryExpr ::=   UnionExpr
   10777  *                   | '-' UnaryExpr
   10778  *
   10779  * Compile an unary expression.
   10780  */
   10781 
   10782 static void
   10783 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
   10784     int minus = 0;
   10785     int found = 0;
   10786 
   10787     SKIP_BLANKS;
   10788     while (CUR == '-') {
   10789         minus = 1 - minus;
   10790 	found = 1;
   10791 	NEXT;
   10792 	SKIP_BLANKS;
   10793     }
   10794 
   10795     xmlXPathCompUnionExpr(ctxt);
   10796     CHECK_ERROR;
   10797     if (found) {
   10798 	if (minus)
   10799 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
   10800 	else
   10801 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
   10802     }
   10803 }
   10804 
   10805 /**
   10806  * xmlXPathCompMultiplicativeExpr:
   10807  * @ctxt:  the XPath Parser context
   10808  *
   10809  *  [26]   MultiplicativeExpr ::=   UnaryExpr
   10810  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
   10811  *                   | MultiplicativeExpr 'div' UnaryExpr
   10812  *                   | MultiplicativeExpr 'mod' UnaryExpr
   10813  *  [34]   MultiplyOperator ::=   '*'
   10814  *
   10815  * Compile an Additive expression.
   10816  */
   10817 
   10818 static void
   10819 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
   10820     xmlXPathCompUnaryExpr(ctxt);
   10821     CHECK_ERROR;
   10822     SKIP_BLANKS;
   10823     while ((CUR == '*') ||
   10824            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
   10825            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
   10826 	int op = -1;
   10827 	int op1 = ctxt->comp->last;
   10828 
   10829         if (CUR == '*') {
   10830 	    op = 0;
   10831 	    NEXT;
   10832 	} else if (CUR == 'd') {
   10833 	    op = 1;
   10834 	    SKIP(3);
   10835 	} else if (CUR == 'm') {
   10836 	    op = 2;
   10837 	    SKIP(3);
   10838 	}
   10839 	SKIP_BLANKS;
   10840         xmlXPathCompUnaryExpr(ctxt);
   10841 	CHECK_ERROR;
   10842 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
   10843 	SKIP_BLANKS;
   10844     }
   10845 }
   10846 
   10847 /**
   10848  * xmlXPathCompAdditiveExpr:
   10849  * @ctxt:  the XPath Parser context
   10850  *
   10851  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
   10852  *                   | AdditiveExpr '+' MultiplicativeExpr
   10853  *                   | AdditiveExpr '-' MultiplicativeExpr
   10854  *
   10855  * Compile an Additive expression.
   10856  */
   10857 
   10858 static void
   10859 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
   10860 
   10861     xmlXPathCompMultiplicativeExpr(ctxt);
   10862     CHECK_ERROR;
   10863     SKIP_BLANKS;
   10864     while ((CUR == '+') || (CUR == '-')) {
   10865 	int plus;
   10866 	int op1 = ctxt->comp->last;
   10867 
   10868         if (CUR == '+') plus = 1;
   10869 	else plus = 0;
   10870 	NEXT;
   10871 	SKIP_BLANKS;
   10872         xmlXPathCompMultiplicativeExpr(ctxt);
   10873 	CHECK_ERROR;
   10874 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
   10875 	SKIP_BLANKS;
   10876     }
   10877 }
   10878 
   10879 /**
   10880  * xmlXPathCompRelationalExpr:
   10881  * @ctxt:  the XPath Parser context
   10882  *
   10883  *  [24]   RelationalExpr ::=   AdditiveExpr
   10884  *                 | RelationalExpr '<' AdditiveExpr
   10885  *                 | RelationalExpr '>' AdditiveExpr
   10886  *                 | RelationalExpr '<=' AdditiveExpr
   10887  *                 | RelationalExpr '>=' AdditiveExpr
   10888  *
   10889  *  A <= B > C is allowed ? Answer from James, yes with
   10890  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
   10891  *  which is basically what got implemented.
   10892  *
   10893  * Compile a Relational expression, then push the result
   10894  * on the stack
   10895  */
   10896 
   10897 static void
   10898 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
   10899     xmlXPathCompAdditiveExpr(ctxt);
   10900     CHECK_ERROR;
   10901     SKIP_BLANKS;
   10902     while ((CUR == '<') ||
   10903            (CUR == '>') ||
   10904            ((CUR == '<') && (NXT(1) == '=')) ||
   10905            ((CUR == '>') && (NXT(1) == '='))) {
   10906 	int inf, strict;
   10907 	int op1 = ctxt->comp->last;
   10908 
   10909         if (CUR == '<') inf = 1;
   10910 	else inf = 0;
   10911 	if (NXT(1) == '=') strict = 0;
   10912 	else strict = 1;
   10913 	NEXT;
   10914 	if (!strict) NEXT;
   10915 	SKIP_BLANKS;
   10916         xmlXPathCompAdditiveExpr(ctxt);
   10917 	CHECK_ERROR;
   10918 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
   10919 	SKIP_BLANKS;
   10920     }
   10921 }
   10922 
   10923 /**
   10924  * xmlXPathCompEqualityExpr:
   10925  * @ctxt:  the XPath Parser context
   10926  *
   10927  *  [23]   EqualityExpr ::=   RelationalExpr
   10928  *                 | EqualityExpr '=' RelationalExpr
   10929  *                 | EqualityExpr '!=' RelationalExpr
   10930  *
   10931  *  A != B != C is allowed ? Answer from James, yes with
   10932  *  (RelationalExpr = RelationalExpr) = RelationalExpr
   10933  *  (RelationalExpr != RelationalExpr) != RelationalExpr
   10934  *  which is basically what got implemented.
   10935  *
   10936  * Compile an Equality expression.
   10937  *
   10938  */
   10939 static void
   10940 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
   10941     xmlXPathCompRelationalExpr(ctxt);
   10942     CHECK_ERROR;
   10943     SKIP_BLANKS;
   10944     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
   10945 	int eq;
   10946 	int op1 = ctxt->comp->last;
   10947 
   10948         if (CUR == '=') eq = 1;
   10949 	else eq = 0;
   10950 	NEXT;
   10951 	if (!eq) NEXT;
   10952 	SKIP_BLANKS;
   10953         xmlXPathCompRelationalExpr(ctxt);
   10954 	CHECK_ERROR;
   10955 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
   10956 	SKIP_BLANKS;
   10957     }
   10958 }
   10959 
   10960 /**
   10961  * xmlXPathCompAndExpr:
   10962  * @ctxt:  the XPath Parser context
   10963  *
   10964  *  [22]   AndExpr ::=   EqualityExpr
   10965  *                 | AndExpr 'and' EqualityExpr
   10966  *
   10967  * Compile an AND expression.
   10968  *
   10969  */
   10970 static void
   10971 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
   10972     xmlXPathCompEqualityExpr(ctxt);
   10973     CHECK_ERROR;
   10974     SKIP_BLANKS;
   10975     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
   10976 	int op1 = ctxt->comp->last;
   10977         SKIP(3);
   10978 	SKIP_BLANKS;
   10979         xmlXPathCompEqualityExpr(ctxt);
   10980 	CHECK_ERROR;
   10981 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
   10982 	SKIP_BLANKS;
   10983     }
   10984 }
   10985 
   10986 /**
   10987  * xmlXPathCompileExpr:
   10988  * @ctxt:  the XPath Parser context
   10989  *
   10990  *  [14]   Expr ::=   OrExpr
   10991  *  [21]   OrExpr ::=   AndExpr
   10992  *                 | OrExpr 'or' AndExpr
   10993  *
   10994  * Parse and compile an expression
   10995  */
   10996 static void
   10997 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
   10998     xmlXPathCompAndExpr(ctxt);
   10999     CHECK_ERROR;
   11000     SKIP_BLANKS;
   11001     while ((CUR == 'o') && (NXT(1) == 'r')) {
   11002 	int op1 = ctxt->comp->last;
   11003         SKIP(2);
   11004 	SKIP_BLANKS;
   11005         xmlXPathCompAndExpr(ctxt);
   11006 	CHECK_ERROR;
   11007 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
   11008 	SKIP_BLANKS;
   11009     }
   11010     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
   11011 	/* more ops could be optimized too */
   11012 	/*
   11013 	* This is the main place to eliminate sorting for
   11014 	* operations which don't require a sorted node-set.
   11015 	* E.g. count().
   11016 	*/
   11017 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
   11018     }
   11019 }
   11020 
   11021 /**
   11022  * xmlXPathCompPredicate:
   11023  * @ctxt:  the XPath Parser context
   11024  * @filter:  act as a filter
   11025  *
   11026  *  [8]   Predicate ::=   '[' PredicateExpr ']'
   11027  *  [9]   PredicateExpr ::=   Expr
   11028  *
   11029  * Compile a predicate expression
   11030  */
   11031 static void
   11032 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
   11033     int op1 = ctxt->comp->last;
   11034 
   11035     SKIP_BLANKS;
   11036     if (CUR != '[') {
   11037 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
   11038     }
   11039     NEXT;
   11040     SKIP_BLANKS;
   11041 
   11042     ctxt->comp->last = -1;
   11043     /*
   11044     * This call to xmlXPathCompileExpr() will deactivate sorting
   11045     * of the predicate result.
   11046     * TODO: Sorting is still activated for filters, since I'm not
   11047     *  sure if needed. Normally sorting should not be needed, since
   11048     *  a filter can only diminish the number of items in a sequence,
   11049     *  but won't change its order; so if the initial sequence is sorted,
   11050     *  subsequent sorting is not needed.
   11051     */
   11052     if (! filter)
   11053 	xmlXPathCompileExpr(ctxt, 0);
   11054     else
   11055 	xmlXPathCompileExpr(ctxt, 1);
   11056     CHECK_ERROR;
   11057 
   11058     if (CUR != ']') {
   11059 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
   11060     }
   11061 
   11062     if (filter)
   11063 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
   11064     else
   11065 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
   11066 
   11067     NEXT;
   11068     SKIP_BLANKS;
   11069 }
   11070 
   11071 /**
   11072  * xmlXPathCompNodeTest:
   11073  * @ctxt:  the XPath Parser context
   11074  * @test:  pointer to a xmlXPathTestVal
   11075  * @type:  pointer to a xmlXPathTypeVal
   11076  * @prefix:  placeholder for a possible name prefix
   11077  *
   11078  * [7] NodeTest ::=   NameTest
   11079  *		    | NodeType '(' ')'
   11080  *		    | 'processing-instruction' '(' Literal ')'
   11081  *
   11082  * [37] NameTest ::=  '*'
   11083  *		    | NCName ':' '*'
   11084  *		    | QName
   11085  * [38] NodeType ::= 'comment'
   11086  *		   | 'text'
   11087  *		   | 'processing-instruction'
   11088  *		   | 'node'
   11089  *
   11090  * Returns the name found and updates @test, @type and @prefix appropriately
   11091  */
   11092 static xmlChar *
   11093 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
   11094 	             xmlXPathTypeVal *type, const xmlChar **prefix,
   11095 		     xmlChar *name) {
   11096     int blanks;
   11097 
   11098     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
   11099 	STRANGE;
   11100 	return(NULL);
   11101     }
   11102     *type = (xmlXPathTypeVal) 0;
   11103     *test = (xmlXPathTestVal) 0;
   11104     *prefix = NULL;
   11105     SKIP_BLANKS;
   11106 
   11107     if ((name == NULL) && (CUR == '*')) {
   11108 	/*
   11109 	 * All elements
   11110 	 */
   11111 	NEXT;
   11112 	*test = NODE_TEST_ALL;
   11113 	return(NULL);
   11114     }
   11115 
   11116     if (name == NULL)
   11117 	name = xmlXPathParseNCName(ctxt);
   11118     if (name == NULL) {
   11119 	XP_ERRORNULL(XPATH_EXPR_ERROR);
   11120     }
   11121 
   11122     blanks = IS_BLANK_CH(CUR);
   11123     SKIP_BLANKS;
   11124     if (CUR == '(') {
   11125 	NEXT;
   11126 	/*
   11127 	 * NodeType or PI search
   11128 	 */
   11129 	if (xmlStrEqual(name, BAD_CAST "comment"))
   11130 	    *type = NODE_TYPE_COMMENT;
   11131 	else if (xmlStrEqual(name, BAD_CAST "node"))
   11132 	    *type = NODE_TYPE_NODE;
   11133 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
   11134 	    *type = NODE_TYPE_PI;
   11135 	else if (xmlStrEqual(name, BAD_CAST "text"))
   11136 	    *type = NODE_TYPE_TEXT;
   11137 	else {
   11138 	    if (name != NULL)
   11139 		xmlFree(name);
   11140 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
   11141 	}
   11142 
   11143 	*test = NODE_TEST_TYPE;
   11144 
   11145 	SKIP_BLANKS;
   11146 	if (*type == NODE_TYPE_PI) {
   11147 	    /*
   11148 	     * Specific case: search a PI by name.
   11149 	     */
   11150 	    if (name != NULL)
   11151 		xmlFree(name);
   11152 	    name = NULL;
   11153 	    if (CUR != ')') {
   11154 		name = xmlXPathParseLiteral(ctxt);
   11155 		CHECK_ERROR NULL;
   11156 		*test = NODE_TEST_PI;
   11157 		SKIP_BLANKS;
   11158 	    }
   11159 	}
   11160 	if (CUR != ')') {
   11161 	    if (name != NULL)
   11162 		xmlFree(name);
   11163 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
   11164 	}
   11165 	NEXT;
   11166 	return(name);
   11167     }
   11168     *test = NODE_TEST_NAME;
   11169     if ((!blanks) && (CUR == ':')) {
   11170 	NEXT;
   11171 
   11172 	/*
   11173 	 * Since currently the parser context don't have a
   11174 	 * namespace list associated:
   11175 	 * The namespace name for this prefix can be computed
   11176 	 * only at evaluation time. The compilation is done
   11177 	 * outside of any context.
   11178 	 */
   11179 #if 0
   11180 	*prefix = xmlXPathNsLookup(ctxt->context, name);
   11181 	if (name != NULL)
   11182 	    xmlFree(name);
   11183 	if (*prefix == NULL) {
   11184 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
   11185 	}
   11186 #else
   11187 	*prefix = name;
   11188 #endif
   11189 
   11190 	if (CUR == '*') {
   11191 	    /*
   11192 	     * All elements
   11193 	     */
   11194 	    NEXT;
   11195 	    *test = NODE_TEST_ALL;
   11196 	    return(NULL);
   11197 	}
   11198 
   11199 	name = xmlXPathParseNCName(ctxt);
   11200 	if (name == NULL) {
   11201 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
   11202 	}
   11203     }
   11204     return(name);
   11205 }
   11206 
   11207 /**
   11208  * xmlXPathIsAxisName:
   11209  * @name:  a preparsed name token
   11210  *
   11211  * [6] AxisName ::=   'ancestor'
   11212  *                  | 'ancestor-or-self'
   11213  *                  | 'attribute'
   11214  *                  | 'child'
   11215  *                  | 'descendant'
   11216  *                  | 'descendant-or-self'
   11217  *                  | 'following'
   11218  *                  | 'following-sibling'
   11219  *                  | 'namespace'
   11220  *                  | 'parent'
   11221  *                  | 'preceding'
   11222  *                  | 'preceding-sibling'
   11223  *                  | 'self'
   11224  *
   11225  * Returns the axis or 0
   11226  */
   11227 static xmlXPathAxisVal
   11228 xmlXPathIsAxisName(const xmlChar *name) {
   11229     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
   11230     switch (name[0]) {
   11231 	case 'a':
   11232 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
   11233 		ret = AXIS_ANCESTOR;
   11234 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
   11235 		ret = AXIS_ANCESTOR_OR_SELF;
   11236 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
   11237 		ret = AXIS_ATTRIBUTE;
   11238 	    break;
   11239 	case 'c':
   11240 	    if (xmlStrEqual(name, BAD_CAST "child"))
   11241 		ret = AXIS_CHILD;
   11242 	    break;
   11243 	case 'd':
   11244 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
   11245 		ret = AXIS_DESCENDANT;
   11246 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
   11247 		ret = AXIS_DESCENDANT_OR_SELF;
   11248 	    break;
   11249 	case 'f':
   11250 	    if (xmlStrEqual(name, BAD_CAST "following"))
   11251 		ret = AXIS_FOLLOWING;
   11252 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
   11253 		ret = AXIS_FOLLOWING_SIBLING;
   11254 	    break;
   11255 	case 'n':
   11256 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
   11257 		ret = AXIS_NAMESPACE;
   11258 	    break;
   11259 	case 'p':
   11260 	    if (xmlStrEqual(name, BAD_CAST "parent"))
   11261 		ret = AXIS_PARENT;
   11262 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
   11263 		ret = AXIS_PRECEDING;
   11264 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
   11265 		ret = AXIS_PRECEDING_SIBLING;
   11266 	    break;
   11267 	case 's':
   11268 	    if (xmlStrEqual(name, BAD_CAST "self"))
   11269 		ret = AXIS_SELF;
   11270 	    break;
   11271     }
   11272     return(ret);
   11273 }
   11274 
   11275 /**
   11276  * xmlXPathCompStep:
   11277  * @ctxt:  the XPath Parser context
   11278  *
   11279  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
   11280  *                  | AbbreviatedStep
   11281  *
   11282  * [12] AbbreviatedStep ::=   '.' | '..'
   11283  *
   11284  * [5] AxisSpecifier ::= AxisName '::'
   11285  *                  | AbbreviatedAxisSpecifier
   11286  *
   11287  * [13] AbbreviatedAxisSpecifier ::= '@'?
   11288  *
   11289  * Modified for XPtr range support as:
   11290  *
   11291  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
   11292  *                     | AbbreviatedStep
   11293  *                     | 'range-to' '(' Expr ')' Predicate*
   11294  *
   11295  * Compile one step in a Location Path
   11296  * A location step of . is short for self::node(). This is
   11297  * particularly useful in conjunction with //. For example, the
   11298  * location path .//para is short for
   11299  * self::node()/descendant-or-self::node()/child::para
   11300  * and so will select all para descendant elements of the context
   11301  * node.
   11302  * Similarly, a location step of .. is short for parent::node().
   11303  * For example, ../title is short for parent::node()/child::title
   11304  * and so will select the title children of the parent of the context
   11305  * node.
   11306  */
   11307 static void
   11308 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
   11309 #ifdef LIBXML_XPTR_ENABLED
   11310     int rangeto = 0;
   11311     int op2 = -1;
   11312 #endif
   11313 
   11314     SKIP_BLANKS;
   11315     if ((CUR == '.') && (NXT(1) == '.')) {
   11316 	SKIP(2);
   11317 	SKIP_BLANKS;
   11318 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
   11319 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11320     } else if (CUR == '.') {
   11321 	NEXT;
   11322 	SKIP_BLANKS;
   11323     } else {
   11324 	xmlChar *name = NULL;
   11325 	const xmlChar *prefix = NULL;
   11326 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
   11327 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
   11328 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
   11329 	int op1;
   11330 
   11331 	/*
   11332 	 * The modification needed for XPointer change to the production
   11333 	 */
   11334 #ifdef LIBXML_XPTR_ENABLED
   11335 	if (ctxt->xptr) {
   11336 	    name = xmlXPathParseNCName(ctxt);
   11337 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
   11338                 op2 = ctxt->comp->last;
   11339 		xmlFree(name);
   11340 		SKIP_BLANKS;
   11341 		if (CUR != '(') {
   11342 		    XP_ERROR(XPATH_EXPR_ERROR);
   11343 		}
   11344 		NEXT;
   11345 		SKIP_BLANKS;
   11346 
   11347 		xmlXPathCompileExpr(ctxt, 1);
   11348 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
   11349 		CHECK_ERROR;
   11350 
   11351 		SKIP_BLANKS;
   11352 		if (CUR != ')') {
   11353 		    XP_ERROR(XPATH_EXPR_ERROR);
   11354 		}
   11355 		NEXT;
   11356 		rangeto = 1;
   11357 		goto eval_predicates;
   11358 	    }
   11359 	}
   11360 #endif
   11361 	if (CUR == '*') {
   11362 	    axis = AXIS_CHILD;
   11363 	} else {
   11364 	    if (name == NULL)
   11365 		name = xmlXPathParseNCName(ctxt);
   11366 	    if (name != NULL) {
   11367 		axis = xmlXPathIsAxisName(name);
   11368 		if (axis != 0) {
   11369 		    SKIP_BLANKS;
   11370 		    if ((CUR == ':') && (NXT(1) == ':')) {
   11371 			SKIP(2);
   11372 			xmlFree(name);
   11373 			name = NULL;
   11374 		    } else {
   11375 			/* an element name can conflict with an axis one :-\ */
   11376 			axis = AXIS_CHILD;
   11377 		    }
   11378 		} else {
   11379 		    axis = AXIS_CHILD;
   11380 		}
   11381 	    } else if (CUR == '@') {
   11382 		NEXT;
   11383 		axis = AXIS_ATTRIBUTE;
   11384 	    } else {
   11385 		axis = AXIS_CHILD;
   11386 	    }
   11387 	}
   11388 
   11389         if (ctxt->error != XPATH_EXPRESSION_OK) {
   11390             xmlFree(name);
   11391             return;
   11392         }
   11393 
   11394 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
   11395 	if (test == 0)
   11396 	    return;
   11397 
   11398         if ((prefix != NULL) && (ctxt->context != NULL) &&
   11399 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
   11400 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
   11401 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
   11402 	    }
   11403 	}
   11404 #ifdef DEBUG_STEP
   11405 	xmlGenericError(xmlGenericErrorContext,
   11406 		"Basis : computing new set\n");
   11407 #endif
   11408 
   11409 #ifdef DEBUG_STEP
   11410 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
   11411 	if (ctxt->value == NULL)
   11412 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
   11413 	else if (ctxt->value->nodesetval == NULL)
   11414 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
   11415 	else
   11416 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
   11417 #endif
   11418 
   11419 #ifdef LIBXML_XPTR_ENABLED
   11420 eval_predicates:
   11421 #endif
   11422 	op1 = ctxt->comp->last;
   11423 	ctxt->comp->last = -1;
   11424 
   11425 	SKIP_BLANKS;
   11426 	while (CUR == '[') {
   11427 	    xmlXPathCompPredicate(ctxt, 0);
   11428 	}
   11429 
   11430 #ifdef LIBXML_XPTR_ENABLED
   11431 	if (rangeto) {
   11432 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
   11433 	} else
   11434 #endif
   11435 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
   11436 			   test, type, (void *)prefix, (void *)name);
   11437 
   11438     }
   11439 #ifdef DEBUG_STEP
   11440     xmlGenericError(xmlGenericErrorContext, "Step : ");
   11441     if (ctxt->value == NULL)
   11442 	xmlGenericError(xmlGenericErrorContext, "no value\n");
   11443     else if (ctxt->value->nodesetval == NULL)
   11444 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
   11445     else
   11446 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
   11447 		ctxt->value->nodesetval);
   11448 #endif
   11449 }
   11450 
   11451 /**
   11452  * xmlXPathCompRelativeLocationPath:
   11453  * @ctxt:  the XPath Parser context
   11454  *
   11455  *  [3]   RelativeLocationPath ::=   Step
   11456  *                     | RelativeLocationPath '/' Step
   11457  *                     | AbbreviatedRelativeLocationPath
   11458  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
   11459  *
   11460  * Compile a relative location path.
   11461  */
   11462 static void
   11463 xmlXPathCompRelativeLocationPath
   11464 (xmlXPathParserContextPtr ctxt) {
   11465     SKIP_BLANKS;
   11466     if ((CUR == '/') && (NXT(1) == '/')) {
   11467 	SKIP(2);
   11468 	SKIP_BLANKS;
   11469 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11470 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11471     } else if (CUR == '/') {
   11472 	    NEXT;
   11473 	SKIP_BLANKS;
   11474     }
   11475     xmlXPathCompStep(ctxt);
   11476     CHECK_ERROR;
   11477     SKIP_BLANKS;
   11478     while (CUR == '/') {
   11479 	if ((CUR == '/') && (NXT(1) == '/')) {
   11480 	    SKIP(2);
   11481 	    SKIP_BLANKS;
   11482 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11483 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11484 	    xmlXPathCompStep(ctxt);
   11485 	} else if (CUR == '/') {
   11486 	    NEXT;
   11487 	    SKIP_BLANKS;
   11488 	    xmlXPathCompStep(ctxt);
   11489 	}
   11490 	SKIP_BLANKS;
   11491     }
   11492 }
   11493 
   11494 /**
   11495  * xmlXPathCompLocationPath:
   11496  * @ctxt:  the XPath Parser context
   11497  *
   11498  *  [1]   LocationPath ::=   RelativeLocationPath
   11499  *                     | AbsoluteLocationPath
   11500  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
   11501  *                     | AbbreviatedAbsoluteLocationPath
   11502  *  [10]   AbbreviatedAbsoluteLocationPath ::=
   11503  *                           '//' RelativeLocationPath
   11504  *
   11505  * Compile a location path
   11506  *
   11507  * // is short for /descendant-or-self::node()/. For example,
   11508  * //para is short for /descendant-or-self::node()/child::para and
   11509  * so will select any para element in the document (even a para element
   11510  * that is a document element will be selected by //para since the
   11511  * document element node is a child of the root node); div//para is
   11512  * short for div/descendant-or-self::node()/child::para and so will
   11513  * select all para descendants of div children.
   11514  */
   11515 static void
   11516 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
   11517     SKIP_BLANKS;
   11518     if (CUR != '/') {
   11519         xmlXPathCompRelativeLocationPath(ctxt);
   11520     } else {
   11521 	while (CUR == '/') {
   11522 	    if ((CUR == '/') && (NXT(1) == '/')) {
   11523 		SKIP(2);
   11524 		SKIP_BLANKS;
   11525 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
   11526 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
   11527 		xmlXPathCompRelativeLocationPath(ctxt);
   11528 	    } else if (CUR == '/') {
   11529 		NEXT;
   11530 		SKIP_BLANKS;
   11531 		if ((CUR != 0 ) &&
   11532 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
   11533 		     (CUR == '@') || (CUR == '*')))
   11534 		    xmlXPathCompRelativeLocationPath(ctxt);
   11535 	    }
   11536 	    CHECK_ERROR;
   11537 	}
   11538     }
   11539 }
   11540 
   11541 /************************************************************************
   11542  *									*
   11543  *		XPath precompiled expression evaluation			*
   11544  *									*
   11545  ************************************************************************/
   11546 
   11547 static int
   11548 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
   11549 
   11550 #ifdef DEBUG_STEP
   11551 static void
   11552 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
   11553 			  int nbNodes)
   11554 {
   11555     xmlGenericError(xmlGenericErrorContext, "new step : ");
   11556     switch (op->value) {
   11557         case AXIS_ANCESTOR:
   11558             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
   11559             break;
   11560         case AXIS_ANCESTOR_OR_SELF:
   11561             xmlGenericError(xmlGenericErrorContext,
   11562                             "axis 'ancestors-or-self' ");
   11563             break;
   11564         case AXIS_ATTRIBUTE:
   11565             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
   11566             break;
   11567         case AXIS_CHILD:
   11568             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
   11569             break;
   11570         case AXIS_DESCENDANT:
   11571             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
   11572             break;
   11573         case AXIS_DESCENDANT_OR_SELF:
   11574             xmlGenericError(xmlGenericErrorContext,
   11575                             "axis 'descendant-or-self' ");
   11576             break;
   11577         case AXIS_FOLLOWING:
   11578             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
   11579             break;
   11580         case AXIS_FOLLOWING_SIBLING:
   11581             xmlGenericError(xmlGenericErrorContext,
   11582                             "axis 'following-siblings' ");
   11583             break;
   11584         case AXIS_NAMESPACE:
   11585             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
   11586             break;
   11587         case AXIS_PARENT:
   11588             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
   11589             break;
   11590         case AXIS_PRECEDING:
   11591             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
   11592             break;
   11593         case AXIS_PRECEDING_SIBLING:
   11594             xmlGenericError(xmlGenericErrorContext,
   11595                             "axis 'preceding-sibling' ");
   11596             break;
   11597         case AXIS_SELF:
   11598             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
   11599             break;
   11600     }
   11601     xmlGenericError(xmlGenericErrorContext,
   11602 	" context contains %d nodes\n", nbNodes);
   11603     switch (op->value2) {
   11604         case NODE_TEST_NONE:
   11605             xmlGenericError(xmlGenericErrorContext,
   11606                             "           searching for none !!!\n");
   11607             break;
   11608         case NODE_TEST_TYPE:
   11609             xmlGenericError(xmlGenericErrorContext,
   11610                             "           searching for type %d\n", op->value3);
   11611             break;
   11612         case NODE_TEST_PI:
   11613             xmlGenericError(xmlGenericErrorContext,
   11614                             "           searching for PI !!!\n");
   11615             break;
   11616         case NODE_TEST_ALL:
   11617             xmlGenericError(xmlGenericErrorContext,
   11618                             "           searching for *\n");
   11619             break;
   11620         case NODE_TEST_NS:
   11621             xmlGenericError(xmlGenericErrorContext,
   11622                             "           searching for namespace %s\n",
   11623                             op->value5);
   11624             break;
   11625         case NODE_TEST_NAME:
   11626             xmlGenericError(xmlGenericErrorContext,
   11627                             "           searching for name %s\n", op->value5);
   11628             if (op->value4)
   11629                 xmlGenericError(xmlGenericErrorContext,
   11630                                 "           with namespace %s\n", op->value4);
   11631             break;
   11632     }
   11633     xmlGenericError(xmlGenericErrorContext, "Testing : ");
   11634 }
   11635 #endif /* DEBUG_STEP */
   11636 
   11637 static int
   11638 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
   11639 			    xmlXPathStepOpPtr op,
   11640 			    xmlNodeSetPtr set,
   11641 			    int contextSize,
   11642 			    int hasNsNodes)
   11643 {
   11644     if (op->ch1 != -1) {
   11645 	xmlXPathCompExprPtr comp = ctxt->comp;
   11646 	/*
   11647 	* Process inner predicates first.
   11648 	*/
   11649 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
   11650 	    /*
   11651 	    * TODO: raise an internal error.
   11652 	    */
   11653 	}
   11654 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
   11655 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
   11656 	CHECK_ERROR0;
   11657 	if (contextSize <= 0)
   11658 	    return(0);
   11659     }
   11660     if (op->ch2 != -1) {
   11661 	xmlXPathContextPtr xpctxt = ctxt->context;
   11662 	xmlNodePtr contextNode, oldContextNode;
   11663 	xmlDocPtr oldContextDoc;
   11664         int oldcs, oldpp;
   11665 	int i, res, contextPos = 0, newContextSize;
   11666 	xmlXPathStepOpPtr exprOp;
   11667 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
   11668 
   11669 #ifdef LIBXML_XPTR_ENABLED
   11670 	/*
   11671 	* URGENT TODO: Check the following:
   11672 	*  We don't expect location sets if evaluating prediates, right?
   11673 	*  Only filters should expect location sets, right?
   11674 	*/
   11675 #endif
   11676 	/*
   11677 	* SPEC XPath 1.0:
   11678 	*  "For each node in the node-set to be filtered, the
   11679 	*  PredicateExpr is evaluated with that node as the
   11680 	*  context node, with the number of nodes in the
   11681 	*  node-set as the context size, and with the proximity
   11682 	*  position of the node in the node-set with respect to
   11683 	*  the axis as the context position;"
   11684 	* @oldset is the node-set" to be filtered.
   11685 	*
   11686 	* SPEC XPath 1.0:
   11687 	*  "only predicates change the context position and
   11688 	*  context size (see [2.4 Predicates])."
   11689 	* Example:
   11690 	*   node-set  context pos
   11691 	*    nA         1
   11692 	*    nB         2
   11693 	*    nC         3
   11694 	*   After applying predicate [position() > 1] :
   11695 	*   node-set  context pos
   11696 	*    nB         1
   11697 	*    nC         2
   11698 	*/
   11699 	oldContextNode = xpctxt->node;
   11700 	oldContextDoc = xpctxt->doc;
   11701         oldcs = xpctxt->contextSize;
   11702         oldpp = xpctxt->proximityPosition;
   11703 	/*
   11704 	* Get the expression of this predicate.
   11705 	*/
   11706 	exprOp = &ctxt->comp->steps[op->ch2];
   11707 	newContextSize = 0;
   11708 	for (i = 0; i < set->nodeNr; i++) {
   11709 	    if (set->nodeTab[i] == NULL)
   11710 		continue;
   11711 
   11712 	    contextNode = set->nodeTab[i];
   11713 	    xpctxt->node = contextNode;
   11714 	    xpctxt->contextSize = contextSize;
   11715 	    xpctxt->proximityPosition = ++contextPos;
   11716 
   11717 	    /*
   11718 	    * Also set the xpath document in case things like
   11719 	    * key() are evaluated in the predicate.
   11720 	    */
   11721 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
   11722 		(contextNode->doc != NULL))
   11723 		xpctxt->doc = contextNode->doc;
   11724 	    /*
   11725 	    * Evaluate the predicate expression with 1 context node
   11726 	    * at a time; this node is packaged into a node set; this
   11727 	    * node set is handed over to the evaluation mechanism.
   11728 	    */
   11729 	    if (contextObj == NULL)
   11730 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
   11731 	    else {
   11732 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
   11733 		    contextNode) < 0) {
   11734 		    ctxt->error = XPATH_MEMORY_ERROR;
   11735 		    goto evaluation_exit;
   11736 		}
   11737 	    }
   11738 
   11739 	    valuePush(ctxt, contextObj);
   11740 
   11741 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
   11742 
   11743 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
   11744 		xmlXPathNodeSetClear(set, hasNsNodes);
   11745 		newContextSize = 0;
   11746 		goto evaluation_exit;
   11747 	    }
   11748 
   11749 	    if (res != 0) {
   11750 		newContextSize++;
   11751 	    } else {
   11752 		/*
   11753 		* Remove the entry from the initial node set.
   11754 		*/
   11755 		set->nodeTab[i] = NULL;
   11756 		if (contextNode->type == XML_NAMESPACE_DECL)
   11757 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
   11758 	    }
   11759 	    if (ctxt->value == contextObj) {
   11760 		/*
   11761 		* Don't free the temporary XPath object holding the
   11762 		* context node, in order to avoid massive recreation
   11763 		* inside this loop.
   11764 		*/
   11765 		valuePop(ctxt);
   11766 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
   11767 	    } else {
   11768 		/*
   11769 		* TODO: The object was lost in the evaluation machinery.
   11770 		*  Can this happen? Maybe in internal-error cases.
   11771 		*/
   11772 		contextObj = NULL;
   11773 	    }
   11774 	}
   11775 
   11776 	if (contextObj != NULL) {
   11777 	    if (ctxt->value == contextObj)
   11778 		valuePop(ctxt);
   11779 	    xmlXPathReleaseObject(xpctxt, contextObj);
   11780 	}
   11781 evaluation_exit:
   11782 	if (exprRes != NULL)
   11783 	    xmlXPathReleaseObject(ctxt->context, exprRes);
   11784 	/*
   11785 	* Reset/invalidate the context.
   11786 	*/
   11787 	xpctxt->node = oldContextNode;
   11788 	xpctxt->doc = oldContextDoc;
   11789 	xpctxt->contextSize = oldcs;
   11790 	xpctxt->proximityPosition = oldpp;
   11791 	return(newContextSize);
   11792     }
   11793     return(contextSize);
   11794 }
   11795 
   11796 static int
   11797 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
   11798 				      xmlXPathStepOpPtr op,
   11799 				      xmlNodeSetPtr set,
   11800 				      int contextSize,
   11801 				      int minPos,
   11802 				      int maxPos,
   11803 				      int hasNsNodes)
   11804 {
   11805     if (op->ch1 != -1) {
   11806 	xmlXPathCompExprPtr comp = ctxt->comp;
   11807 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
   11808 	    /*
   11809 	    * TODO: raise an internal error.
   11810 	    */
   11811 	}
   11812 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
   11813 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
   11814 	CHECK_ERROR0;
   11815 	if (contextSize <= 0)
   11816 	    return(0);
   11817     }
   11818     /*
   11819     * Check if the node set contains a sufficient number of nodes for
   11820     * the requested range.
   11821     */
   11822     if (contextSize < minPos) {
   11823 	xmlXPathNodeSetClear(set, hasNsNodes);
   11824 	return(0);
   11825     }
   11826     if (op->ch2 == -1) {
   11827 	/*
   11828 	* TODO: Can this ever happen?
   11829 	*/
   11830 	return (contextSize);
   11831     } else {
   11832 	xmlDocPtr oldContextDoc;
   11833         int oldcs, oldpp;
   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         oldcs = xpctxt->contextSize;
   11855         oldpp = xpctxt->proximityPosition;
   11856 	/*
   11857 	* Get the expression of this predicate.
   11858 	*/
   11859 	exprOp = &ctxt->comp->steps[op->ch2];
   11860 	for (i = 0; i < set->nodeNr; i++) {
   11861             xmlXPathObjectPtr tmp;
   11862 
   11863 	    if (set->nodeTab[i] == NULL)
   11864 		continue;
   11865 
   11866 	    contextNode = set->nodeTab[i];
   11867 	    xpctxt->node = contextNode;
   11868 	    xpctxt->contextSize = contextSize;
   11869 	    xpctxt->proximityPosition = ++contextPos;
   11870 
   11871 	    /*
   11872 	    * Initialize the new set.
   11873 	    * Also set the xpath document in case things like
   11874 	    * key() evaluation are attempted on the predicate
   11875 	    */
   11876 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
   11877 		(contextNode->doc != NULL))
   11878 		xpctxt->doc = contextNode->doc;
   11879 	    /*
   11880 	    * Evaluate the predicate expression with 1 context node
   11881 	    * at a time; this node is packaged into a node set; this
   11882 	    * node set is handed over to the evaluation mechanism.
   11883 	    */
   11884 	    if (contextObj == NULL)
   11885 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
   11886 	    else {
   11887 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
   11888 		    contextNode) < 0) {
   11889 		    ctxt->error = XPATH_MEMORY_ERROR;
   11890 		    goto evaluation_exit;
   11891 		}
   11892 	    }
   11893 
   11894 	    valuePush(ctxt, contextObj);
   11895             frame = xmlXPathSetFrame(ctxt);
   11896 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
   11897             xmlXPathPopFrame(ctxt, frame);
   11898             tmp = valuePop(ctxt);
   11899 
   11900 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
   11901                 while (tmp != contextObj) {
   11902                     /*
   11903                      * Free up the result
   11904                      * then pop off contextObj, which will be freed later
   11905                      */
   11906                     xmlXPathReleaseObject(xpctxt, tmp);
   11907                     tmp = valuePop(ctxt);
   11908                 }
   11909 		goto evaluation_error;
   11910 	    }
   11911             /* push the result back onto the stack */
   11912             valuePush(ctxt, tmp);
   11913 
   11914 	    if (res)
   11915 		pos++;
   11916 
   11917 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
   11918 		/*
   11919 		* Fits in the requested range.
   11920 		*/
   11921 		newContextSize++;
   11922 		if (minPos == maxPos) {
   11923 		    /*
   11924 		    * Only 1 node was requested.
   11925 		    */
   11926 		    if (contextNode->type == XML_NAMESPACE_DECL) {
   11927 			/*
   11928 			* As always: take care of those nasty
   11929 			* namespace nodes.
   11930 			*/
   11931 			set->nodeTab[i] = NULL;
   11932 		    }
   11933 		    xmlXPathNodeSetClear(set, hasNsNodes);
   11934 		    set->nodeNr = 1;
   11935 		    set->nodeTab[0] = contextNode;
   11936 		    goto evaluation_exit;
   11937 		}
   11938 		if (pos == maxPos) {
   11939 		    /*
   11940 		    * We are done.
   11941 		    */
   11942 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
   11943 		    goto evaluation_exit;
   11944 		}
   11945 	    } else {
   11946 		/*
   11947 		* Remove the entry from the initial node set.
   11948 		*/
   11949 		set->nodeTab[i] = NULL;
   11950 		if (contextNode->type == XML_NAMESPACE_DECL)
   11951 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
   11952 	    }
   11953 	    if (exprRes != NULL) {
   11954 		xmlXPathReleaseObject(ctxt->context, exprRes);
   11955 		exprRes = NULL;
   11956 	    }
   11957 	    if (ctxt->value == contextObj) {
   11958 		/*
   11959 		* Don't free the temporary XPath object holding the
   11960 		* context node, in order to avoid massive recreation
   11961 		* inside this loop.
   11962 		*/
   11963 		valuePop(ctxt);
   11964 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
   11965 	    } else {
   11966 		/*
   11967 		* The object was lost in the evaluation machinery.
   11968 		* Can this happen? Maybe in case of internal-errors.
   11969 		*/
   11970 		contextObj = NULL;
   11971 	    }
   11972 	}
   11973 	goto evaluation_exit;
   11974 
   11975 evaluation_error:
   11976 	xmlXPathNodeSetClear(set, hasNsNodes);
   11977 	newContextSize = 0;
   11978 
   11979 evaluation_exit:
   11980 	if (contextObj != NULL) {
   11981 	    if (ctxt->value == contextObj)
   11982 		valuePop(ctxt);
   11983 	    xmlXPathReleaseObject(xpctxt, contextObj);
   11984 	}
   11985 	if (exprRes != NULL)
   11986 	    xmlXPathReleaseObject(ctxt->context, exprRes);
   11987 	/*
   11988 	* Reset/invalidate the context.
   11989 	*/
   11990 	xpctxt->node = oldContextNode;
   11991 	xpctxt->doc = oldContextDoc;
   11992 	xpctxt->contextSize = oldcs;
   11993 	xpctxt->proximityPosition = oldpp;
   11994 	return(newContextSize);
   11995     }
   11996     return(contextSize);
   11997 }
   11998 
   11999 static int
   12000 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
   12001 			    xmlXPathStepOpPtr op,
   12002 			    int *maxPos)
   12003 {
   12004 
   12005     xmlXPathStepOpPtr exprOp;
   12006 
   12007     /*
   12008     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
   12009     */
   12010 
   12011     /*
   12012     * If not -1, then ch1 will point to:
   12013     * 1) For predicates (XPATH_OP_PREDICATE):
   12014     *    - an inner predicate operator
   12015     * 2) For filters (XPATH_OP_FILTER):
   12016     *    - an inner filter operater OR
   12017     *    - an expression selecting the node set.
   12018     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
   12019     */
   12020     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
   12021 	return(0);
   12022 
   12023     if (op->ch2 != -1) {
   12024 	exprOp = &ctxt->comp->steps[op->ch2];
   12025     } else
   12026 	return(0);
   12027 
   12028     if ((exprOp != NULL) &&
   12029 	(exprOp->op == XPATH_OP_VALUE) &&
   12030 	(exprOp->value4 != NULL) &&
   12031 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
   12032     {
   12033         double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
   12034 
   12035 	/*
   12036 	* We have a "[n]" predicate here.
   12037 	* TODO: Unfortunately this simplistic test here is not
   12038 	* able to detect a position() predicate in compound
   12039 	* expressions like "[@attr = 'a" and position() = 1],
   12040 	* and even not the usage of position() in
   12041 	* "[position() = 1]"; thus - obviously - a position-range,
   12042 	* like it "[position() < 5]", is also not detected.
   12043 	* Maybe we could rewrite the AST to ease the optimization.
   12044 	*/
   12045 
   12046         if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
   12047 	    *maxPos = (int) floatval;
   12048             if (floatval == (double) *maxPos)
   12049                 return(1);
   12050         }
   12051     }
   12052     return(0);
   12053 }
   12054 
   12055 static int
   12056 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
   12057                            xmlXPathStepOpPtr op,
   12058 			   xmlNodePtr * first, xmlNodePtr * last,
   12059 			   int toBool)
   12060 {
   12061 
   12062 #define XP_TEST_HIT \
   12063     if (hasAxisRange != 0) { \
   12064 	if (++pos == maxPos) { \
   12065 	    if (addNode(seq, cur) < 0) \
   12066 	        ctxt->error = XPATH_MEMORY_ERROR; \
   12067 	    goto axis_range_end; } \
   12068     } else { \
   12069 	if (addNode(seq, cur) < 0) \
   12070 	    ctxt->error = XPATH_MEMORY_ERROR; \
   12071 	if (breakOnFirstHit) goto first_hit; }
   12072 
   12073 #define XP_TEST_HIT_NS \
   12074     if (hasAxisRange != 0) { \
   12075 	if (++pos == maxPos) { \
   12076 	    hasNsNodes = 1; \
   12077 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
   12078 	        ctxt->error = XPATH_MEMORY_ERROR; \
   12079 	goto axis_range_end; } \
   12080     } else { \
   12081 	hasNsNodes = 1; \
   12082 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
   12083 	    ctxt->error = XPATH_MEMORY_ERROR; \
   12084 	if (breakOnFirstHit) goto first_hit; }
   12085 
   12086     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
   12087     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
   12088     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
   12089     const xmlChar *prefix = op->value4;
   12090     const xmlChar *name = op->value5;
   12091     const xmlChar *URI = NULL;
   12092 
   12093 #ifdef DEBUG_STEP
   12094     int nbMatches = 0, prevMatches = 0;
   12095 #endif
   12096     int total = 0, hasNsNodes = 0;
   12097     /* The popped object holding the context nodes */
   12098     xmlXPathObjectPtr obj;
   12099     /* The set of context nodes for the node tests */
   12100     xmlNodeSetPtr contextSeq;
   12101     int contextIdx;
   12102     xmlNodePtr contextNode;
   12103     /* The final resulting node set wrt to all context nodes */
   12104     xmlNodeSetPtr outSeq;
   12105     /*
   12106     * The temporary resulting node set wrt 1 context node.
   12107     * Used to feed predicate evaluation.
   12108     */
   12109     xmlNodeSetPtr seq;
   12110     xmlNodePtr cur;
   12111     /* First predicate operator */
   12112     xmlXPathStepOpPtr predOp;
   12113     int maxPos; /* The requested position() (when a "[n]" predicate) */
   12114     int hasPredicateRange, hasAxisRange, pos, size, newSize;
   12115     int breakOnFirstHit;
   12116 
   12117     xmlXPathTraversalFunction next = NULL;
   12118     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
   12119     xmlXPathNodeSetMergeFunction mergeAndClear;
   12120     xmlNodePtr oldContextNode;
   12121     xmlXPathContextPtr xpctxt = ctxt->context;
   12122 
   12123 
   12124     CHECK_TYPE0(XPATH_NODESET);
   12125     obj = valuePop(ctxt);
   12126     /*
   12127     * Setup namespaces.
   12128     */
   12129     if (prefix != NULL) {
   12130         URI = xmlXPathNsLookup(xpctxt, prefix);
   12131         if (URI == NULL) {
   12132 	    xmlXPathReleaseObject(xpctxt, obj);
   12133             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
   12134 	}
   12135     }
   12136     /*
   12137     * Setup axis.
   12138     *
   12139     * MAYBE FUTURE TODO: merging optimizations:
   12140     * - If the nodes to be traversed wrt to the initial nodes and
   12141     *   the current axis cannot overlap, then we could avoid searching
   12142     *   for duplicates during the merge.
   12143     *   But the question is how/when to evaluate if they cannot overlap.
   12144     *   Example: if we know that for two initial nodes, the one is
   12145     *   not in the ancestor-or-self axis of the other, then we could safely
   12146     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
   12147     *   the descendant-or-self axis.
   12148     */
   12149     mergeAndClear = xmlXPathNodeSetMergeAndClear;
   12150     switch (axis) {
   12151         case AXIS_ANCESTOR:
   12152             first = NULL;
   12153             next = xmlXPathNextAncestor;
   12154             break;
   12155         case AXIS_ANCESTOR_OR_SELF:
   12156             first = NULL;
   12157             next = xmlXPathNextAncestorOrSelf;
   12158             break;
   12159         case AXIS_ATTRIBUTE:
   12160             first = NULL;
   12161 	    last = NULL;
   12162             next = xmlXPathNextAttribute;
   12163 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12164             break;
   12165         case AXIS_CHILD:
   12166 	    last = NULL;
   12167 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
   12168 		(type == NODE_TYPE_NODE))
   12169 	    {
   12170 		/*
   12171 		* Optimization if an element node type is 'element'.
   12172 		*/
   12173 		next = xmlXPathNextChildElement;
   12174 	    } else
   12175 		next = xmlXPathNextChild;
   12176 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12177             break;
   12178         case AXIS_DESCENDANT:
   12179 	    last = NULL;
   12180             next = xmlXPathNextDescendant;
   12181             break;
   12182         case AXIS_DESCENDANT_OR_SELF:
   12183 	    last = NULL;
   12184             next = xmlXPathNextDescendantOrSelf;
   12185             break;
   12186         case AXIS_FOLLOWING:
   12187 	    last = NULL;
   12188             next = xmlXPathNextFollowing;
   12189             break;
   12190         case AXIS_FOLLOWING_SIBLING:
   12191 	    last = NULL;
   12192             next = xmlXPathNextFollowingSibling;
   12193             break;
   12194         case AXIS_NAMESPACE:
   12195             first = NULL;
   12196 	    last = NULL;
   12197             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
   12198 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12199             break;
   12200         case AXIS_PARENT:
   12201             first = NULL;
   12202             next = xmlXPathNextParent;
   12203             break;
   12204         case AXIS_PRECEDING:
   12205             first = NULL;
   12206             next = xmlXPathNextPrecedingInternal;
   12207             break;
   12208         case AXIS_PRECEDING_SIBLING:
   12209             first = NULL;
   12210             next = xmlXPathNextPrecedingSibling;
   12211             break;
   12212         case AXIS_SELF:
   12213             first = NULL;
   12214 	    last = NULL;
   12215             next = xmlXPathNextSelf;
   12216 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
   12217             break;
   12218     }
   12219 
   12220 #ifdef DEBUG_STEP
   12221     xmlXPathDebugDumpStepAxis(op,
   12222 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
   12223 #endif
   12224 
   12225     if (next == NULL) {
   12226 	xmlXPathReleaseObject(xpctxt, obj);
   12227         return(0);
   12228     }
   12229     contextSeq = obj->nodesetval;
   12230     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
   12231 	xmlXPathReleaseObject(xpctxt, obj);
   12232         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
   12233         return(0);
   12234     }
   12235     /*
   12236     * Predicate optimization ---------------------------------------------
   12237     * If this step has a last predicate, which contains a position(),
   12238     * then we'll optimize (although not exactly "position()", but only
   12239     * the  short-hand form, i.e., "[n]".
   12240     *
   12241     * Example - expression "/foo[parent::bar][1]":
   12242     *
   12243     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
   12244     *   ROOT                               -- op->ch1
   12245     *   PREDICATE                          -- op->ch2 (predOp)
   12246     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
   12247     *       SORT
   12248     *         COLLECT  'parent' 'name' 'node' bar
   12249     *           NODE
   12250     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
   12251     *
   12252     */
   12253     maxPos = 0;
   12254     predOp = NULL;
   12255     hasPredicateRange = 0;
   12256     hasAxisRange = 0;
   12257     if (op->ch2 != -1) {
   12258 	/*
   12259 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
   12260 	*/
   12261 	predOp = &ctxt->comp->steps[op->ch2];
   12262 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
   12263 	    if (predOp->ch1 != -1) {
   12264 		/*
   12265 		* Use the next inner predicate operator.
   12266 		*/
   12267 		predOp = &ctxt->comp->steps[predOp->ch1];
   12268 		hasPredicateRange = 1;
   12269 	    } else {
   12270 		/*
   12271 		* There's no other predicate than the [n] predicate.
   12272 		*/
   12273 		predOp = NULL;
   12274 		hasAxisRange = 1;
   12275 	    }
   12276 	}
   12277     }
   12278     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
   12279     /*
   12280     * Axis traversal -----------------------------------------------------
   12281     */
   12282     /*
   12283      * 2.3 Node Tests
   12284      *  - For the attribute axis, the principal node type is attribute.
   12285      *  - For the namespace axis, the principal node type is namespace.
   12286      *  - For other axes, the principal node type is element.
   12287      *
   12288      * A node test * is true for any node of the
   12289      * principal node type. For example, child::* will
   12290      * select all element children of the context node
   12291      */
   12292     oldContextNode = xpctxt->node;
   12293     addNode = xmlXPathNodeSetAddUnique;
   12294     outSeq = NULL;
   12295     seq = NULL;
   12296     contextNode = NULL;
   12297     contextIdx = 0;
   12298 
   12299 
   12300     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
   12301            (ctxt->error == XPATH_EXPRESSION_OK)) {
   12302 	xpctxt->node = contextSeq->nodeTab[contextIdx++];
   12303 
   12304 	if (seq == NULL) {
   12305 	    seq = xmlXPathNodeSetCreate(NULL);
   12306 	    if (seq == NULL) {
   12307 		total = 0;
   12308 		goto error;
   12309 	    }
   12310 	}
   12311 	/*
   12312 	* Traverse the axis and test the nodes.
   12313 	*/
   12314 	pos = 0;
   12315 	cur = NULL;
   12316 	hasNsNodes = 0;
   12317         do {
   12318             cur = next(ctxt, cur);
   12319             if (cur == NULL)
   12320                 break;
   12321 
   12322 	    /*
   12323 	    * QUESTION TODO: What does the "first" and "last" stuff do?
   12324 	    */
   12325             if ((first != NULL) && (*first != NULL)) {
   12326 		if (*first == cur)
   12327 		    break;
   12328 		if (((total % 256) == 0) &&
   12329 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   12330 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
   12331 #else
   12332 		    (xmlXPathCmpNodes(*first, cur) >= 0))
   12333 #endif
   12334 		{
   12335 		    break;
   12336 		}
   12337 	    }
   12338 	    if ((last != NULL) && (*last != NULL)) {
   12339 		if (*last == cur)
   12340 		    break;
   12341 		if (((total % 256) == 0) &&
   12342 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
   12343 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
   12344 #else
   12345 		    (xmlXPathCmpNodes(cur, *last) >= 0))
   12346 #endif
   12347 		{
   12348 		    break;
   12349 		}
   12350 	    }
   12351 
   12352             total++;
   12353 
   12354 #ifdef DEBUG_STEP
   12355             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
   12356 #endif
   12357 
   12358 	    switch (test) {
   12359                 case NODE_TEST_NONE:
   12360 		    total = 0;
   12361                     STRANGE
   12362 		    goto error;
   12363                 case NODE_TEST_TYPE:
   12364 		    if (type == NODE_TYPE_NODE) {
   12365 			switch (cur->type) {
   12366 			    case XML_DOCUMENT_NODE:
   12367 			    case XML_HTML_DOCUMENT_NODE:
   12368 #ifdef LIBXML_DOCB_ENABLED
   12369 			    case XML_DOCB_DOCUMENT_NODE:
   12370 #endif
   12371 			    case XML_ELEMENT_NODE:
   12372 			    case XML_ATTRIBUTE_NODE:
   12373 			    case XML_PI_NODE:
   12374 			    case XML_COMMENT_NODE:
   12375 			    case XML_CDATA_SECTION_NODE:
   12376 			    case XML_TEXT_NODE:
   12377 				XP_TEST_HIT
   12378 				break;
   12379 			    case XML_NAMESPACE_DECL: {
   12380 				if (axis == AXIS_NAMESPACE) {
   12381 				    XP_TEST_HIT_NS
   12382 				} else {
   12383 	                            hasNsNodes = 1;
   12384 				    XP_TEST_HIT
   12385 				}
   12386 				break;
   12387                             }
   12388 			    default:
   12389 				break;
   12390 			}
   12391 		    } else if (cur->type == (xmlElementType) type) {
   12392 			if (cur->type == XML_NAMESPACE_DECL)
   12393 			    XP_TEST_HIT_NS
   12394 			else
   12395 			    XP_TEST_HIT
   12396 		    } else if ((type == NODE_TYPE_TEXT) &&
   12397 			 (cur->type == XML_CDATA_SECTION_NODE))
   12398 		    {
   12399 			XP_TEST_HIT
   12400 		    }
   12401 		    break;
   12402                 case NODE_TEST_PI:
   12403                     if ((cur->type == XML_PI_NODE) &&
   12404                         ((name == NULL) || xmlStrEqual(name, cur->name)))
   12405 		    {
   12406 			XP_TEST_HIT
   12407                     }
   12408                     break;
   12409                 case NODE_TEST_ALL:
   12410                     if (axis == AXIS_ATTRIBUTE) {
   12411                         if (cur->type == XML_ATTRIBUTE_NODE)
   12412 			{
   12413                             if (prefix == NULL)
   12414 			    {
   12415 				XP_TEST_HIT
   12416                             } else if ((cur->ns != NULL) &&
   12417 				(xmlStrEqual(URI, cur->ns->href)))
   12418 			    {
   12419 				XP_TEST_HIT
   12420                             }
   12421                         }
   12422                     } else if (axis == AXIS_NAMESPACE) {
   12423                         if (cur->type == XML_NAMESPACE_DECL)
   12424 			{
   12425 			    XP_TEST_HIT_NS
   12426                         }
   12427                     } else {
   12428                         if (cur->type == XML_ELEMENT_NODE) {
   12429                             if (prefix == NULL)
   12430 			    {
   12431 				XP_TEST_HIT
   12432 
   12433                             } else if ((cur->ns != NULL) &&
   12434 				(xmlStrEqual(URI, cur->ns->href)))
   12435 			    {
   12436 				XP_TEST_HIT
   12437                             }
   12438                         }
   12439                     }
   12440                     break;
   12441                 case NODE_TEST_NS:{
   12442                         TODO;
   12443                         break;
   12444                     }
   12445                 case NODE_TEST_NAME:
   12446                     if (axis == AXIS_ATTRIBUTE) {
   12447                         if (cur->type != XML_ATTRIBUTE_NODE)
   12448 			    break;
   12449 		    } else if (axis == AXIS_NAMESPACE) {
   12450                         if (cur->type != XML_NAMESPACE_DECL)
   12451 			    break;
   12452 		    } else {
   12453 		        if (cur->type != XML_ELEMENT_NODE)
   12454 			    break;
   12455 		    }
   12456                     switch (cur->type) {
   12457                         case XML_ELEMENT_NODE:
   12458                             if (xmlStrEqual(name, cur->name)) {
   12459                                 if (prefix == NULL) {
   12460                                     if (cur->ns == NULL)
   12461 				    {
   12462 					XP_TEST_HIT
   12463                                     }
   12464                                 } else {
   12465                                     if ((cur->ns != NULL) &&
   12466                                         (xmlStrEqual(URI, cur->ns->href)))
   12467 				    {
   12468 					XP_TEST_HIT
   12469                                     }
   12470                                 }
   12471                             }
   12472                             break;
   12473                         case XML_ATTRIBUTE_NODE:{
   12474                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
   12475 
   12476                                 if (xmlStrEqual(name, attr->name)) {
   12477                                     if (prefix == NULL) {
   12478                                         if ((attr->ns == NULL) ||
   12479                                             (attr->ns->prefix == NULL))
   12480 					{
   12481 					    XP_TEST_HIT
   12482                                         }
   12483                                     } else {
   12484                                         if ((attr->ns != NULL) &&
   12485                                             (xmlStrEqual(URI,
   12486 					      attr->ns->href)))
   12487 					{
   12488 					    XP_TEST_HIT
   12489                                         }
   12490                                     }
   12491                                 }
   12492                                 break;
   12493                             }
   12494                         case XML_NAMESPACE_DECL:
   12495                             if (cur->type == XML_NAMESPACE_DECL) {
   12496                                 xmlNsPtr ns = (xmlNsPtr) cur;
   12497 
   12498                                 if ((ns->prefix != NULL) && (name != NULL)
   12499                                     && (xmlStrEqual(ns->prefix, name)))
   12500 				{
   12501 				    XP_TEST_HIT_NS
   12502                                 }
   12503                             }
   12504                             break;
   12505                         default:
   12506                             break;
   12507                     }
   12508                     break;
   12509 	    } /* switch(test) */
   12510         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
   12511 
   12512 	goto apply_predicates;
   12513 
   12514 axis_range_end: /* ----------------------------------------------------- */
   12515 	/*
   12516 	* We have a "/foo[n]", and position() = n was reached.
   12517 	* Note that we can have as well "/foo/::parent::foo[1]", so
   12518 	* a duplicate-aware merge is still needed.
   12519 	* Merge with the result.
   12520 	*/
   12521 	if (outSeq == NULL) {
   12522 	    outSeq = seq;
   12523 	    seq = NULL;
   12524 	} else
   12525 	    outSeq = mergeAndClear(outSeq, seq, 0);
   12526 	/*
   12527 	* Break if only a true/false result was requested.
   12528 	*/
   12529 	if (toBool)
   12530 	    break;
   12531 	continue;
   12532 
   12533 first_hit: /* ---------------------------------------------------------- */
   12534 	/*
   12535 	* Break if only a true/false result was requested and
   12536 	* no predicates existed and a node test succeeded.
   12537 	*/
   12538 	if (outSeq == NULL) {
   12539 	    outSeq = seq;
   12540 	    seq = NULL;
   12541 	} else
   12542 	    outSeq = mergeAndClear(outSeq, seq, 0);
   12543 	break;
   12544 
   12545 #ifdef DEBUG_STEP
   12546 	if (seq != NULL)
   12547 	    nbMatches += seq->nodeNr;
   12548 #endif
   12549 
   12550 apply_predicates: /* --------------------------------------------------- */
   12551         if (ctxt->error != XPATH_EXPRESSION_OK)
   12552 	    goto error;
   12553 
   12554         /*
   12555 	* Apply predicates.
   12556 	*/
   12557         if ((predOp != NULL) && (seq->nodeNr > 0)) {
   12558 	    /*
   12559 	    * E.g. when we have a "/foo[some expression][n]".
   12560 	    */
   12561 	    /*
   12562 	    * QUESTION TODO: The old predicate evaluation took into
   12563 	    *  account location-sets.
   12564 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
   12565 	    *  Do we expect such a set here?
   12566 	    *  All what I learned now from the evaluation semantics
   12567 	    *  does not indicate that a location-set will be processed
   12568 	    *  here, so this looks OK.
   12569 	    */
   12570 	    /*
   12571 	    * Iterate over all predicates, starting with the outermost
   12572 	    * predicate.
   12573 	    * TODO: Problem: we cannot execute the inner predicates first
   12574 	    *  since we cannot go back *up* the operator tree!
   12575 	    *  Options we have:
   12576 	    *  1) Use of recursive functions (like is it currently done
   12577 	    *     via xmlXPathCompOpEval())
   12578 	    *  2) Add a predicate evaluation information stack to the
   12579 	    *     context struct
   12580 	    *  3) Change the way the operators are linked; we need a
   12581 	    *     "parent" field on xmlXPathStepOp
   12582 	    *
   12583 	    * For the moment, I'll try to solve this with a recursive
   12584 	    * function: xmlXPathCompOpEvalPredicate().
   12585 	    */
   12586 	    size = seq->nodeNr;
   12587 	    if (hasPredicateRange != 0)
   12588 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
   12589 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
   12590 	    else
   12591 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
   12592 		    predOp, seq, size, hasNsNodes);
   12593 
   12594 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   12595 		total = 0;
   12596 		goto error;
   12597 	    }
   12598 	    /*
   12599 	    * Add the filtered set of nodes to the result node set.
   12600 	    */
   12601 	    if (newSize == 0) {
   12602 		/*
   12603 		* The predicates filtered all nodes out.
   12604 		*/
   12605 		xmlXPathNodeSetClear(seq, hasNsNodes);
   12606 	    } else if (seq->nodeNr > 0) {
   12607 		/*
   12608 		* Add to result set.
   12609 		*/
   12610 		if (outSeq == NULL) {
   12611 		    if (size != newSize) {
   12612 			/*
   12613 			* We need to merge and clear here, since
   12614 			* the sequence will contained NULLed entries.
   12615 			*/
   12616 			outSeq = mergeAndClear(NULL, seq, 1);
   12617 		    } else {
   12618 			outSeq = seq;
   12619 			seq = NULL;
   12620 		    }
   12621 		} else
   12622 		    outSeq = mergeAndClear(outSeq, seq,
   12623 			(size != newSize) ? 1: 0);
   12624 		/*
   12625 		* Break if only a true/false result was requested.
   12626 		*/
   12627 		if (toBool)
   12628 		    break;
   12629 	    }
   12630         } else if (seq->nodeNr > 0) {
   12631 	    /*
   12632 	    * Add to result set.
   12633 	    */
   12634 	    if (outSeq == NULL) {
   12635 		outSeq = seq;
   12636 		seq = NULL;
   12637 	    } else {
   12638 		outSeq = mergeAndClear(outSeq, seq, 0);
   12639 	    }
   12640 	}
   12641     }
   12642 
   12643 error:
   12644     if ((obj->boolval) && (obj->user != NULL)) {
   12645 	/*
   12646 	* QUESTION TODO: What does this do and why?
   12647 	* TODO: Do we have to do this also for the "error"
   12648 	* cleanup further down?
   12649 	*/
   12650 	ctxt->value->boolval = 1;
   12651 	ctxt->value->user = obj->user;
   12652 	obj->user = NULL;
   12653 	obj->boolval = 0;
   12654     }
   12655     xmlXPathReleaseObject(xpctxt, obj);
   12656 
   12657     /*
   12658     * Ensure we return at least an emtpy set.
   12659     */
   12660     if (outSeq == NULL) {
   12661 	if ((seq != NULL) && (seq->nodeNr == 0))
   12662 	    outSeq = seq;
   12663 	else
   12664 	    outSeq = xmlXPathNodeSetCreate(NULL);
   12665         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
   12666     }
   12667     if ((seq != NULL) && (seq != outSeq)) {
   12668 	 xmlXPathFreeNodeSet(seq);
   12669     }
   12670     /*
   12671     * Hand over the result. Better to push the set also in
   12672     * case of errors.
   12673     */
   12674     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
   12675     /*
   12676     * Reset the context node.
   12677     */
   12678     xpctxt->node = oldContextNode;
   12679     /*
   12680     * When traversing the namespace axis in "toBool" mode, it's
   12681     * possible that tmpNsList wasn't freed.
   12682     */
   12683     if (xpctxt->tmpNsList != NULL) {
   12684         xmlFree(xpctxt->tmpNsList);
   12685         xpctxt->tmpNsList = NULL;
   12686     }
   12687 
   12688 #ifdef DEBUG_STEP
   12689     xmlGenericError(xmlGenericErrorContext,
   12690 	"\nExamined %d nodes, found %d nodes at that step\n",
   12691 	total, nbMatches);
   12692 #endif
   12693 
   12694     return(total);
   12695 }
   12696 
   12697 static int
   12698 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
   12699 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
   12700 
   12701 /**
   12702  * xmlXPathCompOpEvalFirst:
   12703  * @ctxt:  the XPath parser context with the compiled expression
   12704  * @op:  an XPath compiled operation
   12705  * @first:  the first elem found so far
   12706  *
   12707  * Evaluate the Precompiled XPath operation searching only the first
   12708  * element in document order
   12709  *
   12710  * Returns the number of examined objects.
   12711  */
   12712 static int
   12713 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
   12714                         xmlXPathStepOpPtr op, xmlNodePtr * first)
   12715 {
   12716     int total = 0, cur;
   12717     xmlXPathCompExprPtr comp;
   12718     xmlXPathObjectPtr arg1, arg2;
   12719 
   12720     CHECK_ERROR0;
   12721     comp = ctxt->comp;
   12722     switch (op->op) {
   12723         case XPATH_OP_END:
   12724             return (0);
   12725         case XPATH_OP_UNION:
   12726             total =
   12727                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
   12728                                         first);
   12729 	    CHECK_ERROR0;
   12730             if ((ctxt->value != NULL)
   12731                 && (ctxt->value->type == XPATH_NODESET)
   12732                 && (ctxt->value->nodesetval != NULL)
   12733                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
   12734                 /*
   12735                  * limit tree traversing to first node in the result
   12736                  */
   12737 		/*
   12738 		* OPTIMIZE TODO: This implicitely sorts
   12739 		*  the result, even if not needed. E.g. if the argument
   12740 		*  of the count() function, no sorting is needed.
   12741 		* OPTIMIZE TODO: How do we know if the node-list wasn't
   12742 		*  aready sorted?
   12743 		*/
   12744 		if (ctxt->value->nodesetval->nodeNr > 1)
   12745 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12746                 *first = ctxt->value->nodesetval->nodeTab[0];
   12747             }
   12748             cur =
   12749                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
   12750                                         first);
   12751 	    CHECK_ERROR0;
   12752 
   12753             arg2 = valuePop(ctxt);
   12754             arg1 = valuePop(ctxt);
   12755             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
   12756                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
   12757 	        xmlXPathReleaseObject(ctxt->context, arg1);
   12758 	        xmlXPathReleaseObject(ctxt->context, arg2);
   12759                 XP_ERROR0(XPATH_INVALID_TYPE);
   12760             }
   12761 
   12762             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   12763                                                     arg2->nodesetval);
   12764             valuePush(ctxt, arg1);
   12765 	    xmlXPathReleaseObject(ctxt->context, arg2);
   12766             /* optimizer */
   12767 	    if (total > cur)
   12768 		xmlXPathCompSwap(op);
   12769             return (total + cur);
   12770         case XPATH_OP_ROOT:
   12771             xmlXPathRoot(ctxt);
   12772             return (0);
   12773         case XPATH_OP_NODE:
   12774             if (op->ch1 != -1)
   12775                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12776 	    CHECK_ERROR0;
   12777             if (op->ch2 != -1)
   12778                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12779 	    CHECK_ERROR0;
   12780 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   12781 		ctxt->context->node));
   12782             return (total);
   12783         case XPATH_OP_COLLECT:{
   12784                 if (op->ch1 == -1)
   12785                     return (total);
   12786 
   12787                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12788 		CHECK_ERROR0;
   12789 
   12790                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
   12791                 return (total);
   12792             }
   12793         case XPATH_OP_VALUE:
   12794             valuePush(ctxt,
   12795                       xmlXPathCacheObjectCopy(ctxt->context,
   12796 			(xmlXPathObjectPtr) op->value4));
   12797             return (0);
   12798         case XPATH_OP_SORT:
   12799             if (op->ch1 != -1)
   12800                 total +=
   12801                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
   12802                                             first);
   12803 	    CHECK_ERROR0;
   12804             if ((ctxt->value != NULL)
   12805                 && (ctxt->value->type == XPATH_NODESET)
   12806                 && (ctxt->value->nodesetval != NULL)
   12807 		&& (ctxt->value->nodesetval->nodeNr > 1))
   12808                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12809             return (total);
   12810 #ifdef XP_OPTIMIZED_FILTER_FIRST
   12811 	case XPATH_OP_FILTER:
   12812                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
   12813             return (total);
   12814 #endif
   12815         default:
   12816             return (xmlXPathCompOpEval(ctxt, op));
   12817     }
   12818 }
   12819 
   12820 /**
   12821  * xmlXPathCompOpEvalLast:
   12822  * @ctxt:  the XPath parser context with the compiled expression
   12823  * @op:  an XPath compiled operation
   12824  * @last:  the last elem found so far
   12825  *
   12826  * Evaluate the Precompiled XPath operation searching only the last
   12827  * element in document order
   12828  *
   12829  * Returns the number of nodes traversed
   12830  */
   12831 static int
   12832 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
   12833                        xmlNodePtr * last)
   12834 {
   12835     int total = 0, cur;
   12836     xmlXPathCompExprPtr comp;
   12837     xmlXPathObjectPtr arg1, arg2;
   12838 
   12839     CHECK_ERROR0;
   12840     comp = ctxt->comp;
   12841     switch (op->op) {
   12842         case XPATH_OP_END:
   12843             return (0);
   12844         case XPATH_OP_UNION:
   12845             total =
   12846                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
   12847 	    CHECK_ERROR0;
   12848             if ((ctxt->value != NULL)
   12849                 && (ctxt->value->type == XPATH_NODESET)
   12850                 && (ctxt->value->nodesetval != NULL)
   12851                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
   12852                 /*
   12853                  * limit tree traversing to first node in the result
   12854                  */
   12855 		if (ctxt->value->nodesetval->nodeNr > 1)
   12856 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12857                 *last =
   12858                     ctxt->value->nodesetval->nodeTab[ctxt->value->
   12859                                                      nodesetval->nodeNr -
   12860                                                      1];
   12861             }
   12862             cur =
   12863                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
   12864 	    CHECK_ERROR0;
   12865             if ((ctxt->value != NULL)
   12866                 && (ctxt->value->type == XPATH_NODESET)
   12867                 && (ctxt->value->nodesetval != NULL)
   12868                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
   12869             }
   12870 
   12871             arg2 = valuePop(ctxt);
   12872             arg1 = valuePop(ctxt);
   12873             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
   12874                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
   12875 	        xmlXPathReleaseObject(ctxt->context, arg1);
   12876 	        xmlXPathReleaseObject(ctxt->context, arg2);
   12877                 XP_ERROR0(XPATH_INVALID_TYPE);
   12878             }
   12879 
   12880             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   12881                                                     arg2->nodesetval);
   12882             valuePush(ctxt, arg1);
   12883 	    xmlXPathReleaseObject(ctxt->context, arg2);
   12884             /* optimizer */
   12885 	    if (total > cur)
   12886 		xmlXPathCompSwap(op);
   12887             return (total + cur);
   12888         case XPATH_OP_ROOT:
   12889             xmlXPathRoot(ctxt);
   12890             return (0);
   12891         case XPATH_OP_NODE:
   12892             if (op->ch1 != -1)
   12893                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12894 	    CHECK_ERROR0;
   12895             if (op->ch2 != -1)
   12896                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   12897 	    CHECK_ERROR0;
   12898 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   12899 		ctxt->context->node));
   12900             return (total);
   12901         case XPATH_OP_COLLECT:{
   12902                 if (op->ch1 == -1)
   12903                     return (0);
   12904 
   12905                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12906 		CHECK_ERROR0;
   12907 
   12908                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
   12909                 return (total);
   12910             }
   12911         case XPATH_OP_VALUE:
   12912             valuePush(ctxt,
   12913                       xmlXPathCacheObjectCopy(ctxt->context,
   12914 			(xmlXPathObjectPtr) op->value4));
   12915             return (0);
   12916         case XPATH_OP_SORT:
   12917             if (op->ch1 != -1)
   12918                 total +=
   12919                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
   12920                                            last);
   12921 	    CHECK_ERROR0;
   12922             if ((ctxt->value != NULL)
   12923                 && (ctxt->value->type == XPATH_NODESET)
   12924                 && (ctxt->value->nodesetval != NULL)
   12925 		&& (ctxt->value->nodesetval->nodeNr > 1))
   12926                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   12927             return (total);
   12928         default:
   12929             return (xmlXPathCompOpEval(ctxt, op));
   12930     }
   12931 }
   12932 
   12933 #ifdef XP_OPTIMIZED_FILTER_FIRST
   12934 static int
   12935 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
   12936 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
   12937 {
   12938     int total = 0;
   12939     xmlXPathCompExprPtr comp;
   12940     xmlXPathObjectPtr res;
   12941     xmlXPathObjectPtr obj;
   12942     xmlNodeSetPtr oldset;
   12943     xmlNodePtr oldnode;
   12944     xmlDocPtr oldDoc;
   12945     int oldcs, oldpp;
   12946     int i;
   12947 
   12948     CHECK_ERROR0;
   12949     comp = ctxt->comp;
   12950     /*
   12951     * Optimization for ()[last()] selection i.e. the last elem
   12952     */
   12953     if ((op->ch1 != -1) && (op->ch2 != -1) &&
   12954 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   12955 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
   12956 	int f = comp->steps[op->ch2].ch1;
   12957 
   12958 	if ((f != -1) &&
   12959 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
   12960 	    (comp->steps[f].value5 == NULL) &&
   12961 	    (comp->steps[f].value == 0) &&
   12962 	    (comp->steps[f].value4 != NULL) &&
   12963 	    (xmlStrEqual
   12964 	    (comp->steps[f].value4, BAD_CAST "last"))) {
   12965 	    xmlNodePtr last = NULL;
   12966 
   12967 	    total +=
   12968 		xmlXPathCompOpEvalLast(ctxt,
   12969 		    &comp->steps[op->ch1],
   12970 		    &last);
   12971 	    CHECK_ERROR0;
   12972 	    /*
   12973 	    * The nodeset should be in document order,
   12974 	    * Keep only the last value
   12975 	    */
   12976 	    if ((ctxt->value != NULL) &&
   12977 		(ctxt->value->type == XPATH_NODESET) &&
   12978 		(ctxt->value->nodesetval != NULL) &&
   12979 		(ctxt->value->nodesetval->nodeTab != NULL) &&
   12980 		(ctxt->value->nodesetval->nodeNr > 1)) {
   12981                 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
   12982 		*first = *(ctxt->value->nodesetval->nodeTab);
   12983 	    }
   12984 	    return (total);
   12985 	}
   12986     }
   12987 
   12988     if (op->ch1 != -1)
   12989 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   12990     CHECK_ERROR0;
   12991     if (op->ch2 == -1)
   12992 	return (total);
   12993     if (ctxt->value == NULL)
   12994 	return (total);
   12995 
   12996 #ifdef LIBXML_XPTR_ENABLED
   12997     /*
   12998     * Hum are we filtering the result of an XPointer expression
   12999     */
   13000     if (ctxt->value->type == XPATH_LOCATIONSET) {
   13001 	xmlXPathObjectPtr tmp = NULL;
   13002 	xmlLocationSetPtr newlocset = NULL;
   13003 	xmlLocationSetPtr oldlocset;
   13004 
   13005 	/*
   13006 	* Extract the old locset, and then evaluate the result of the
   13007 	* expression for all the element in the locset. use it to grow
   13008 	* up a new locset.
   13009 	*/
   13010 	CHECK_TYPE0(XPATH_LOCATIONSET);
   13011 
   13012 	if ((ctxt->value->user == NULL) ||
   13013             (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
   13014 	    return (total);
   13015 
   13016 	obj = valuePop(ctxt);
   13017 	oldlocset = obj->user;
   13018         oldnode = ctxt->context->node;
   13019         oldcs = ctxt->context->contextSize;
   13020         oldpp = ctxt->context->proximityPosition;
   13021 
   13022 	newlocset = xmlXPtrLocationSetCreate(NULL);
   13023 
   13024 	for (i = 0; i < oldlocset->locNr; i++) {
   13025 	    /*
   13026 	    * Run the evaluation with a node list made of a
   13027 	    * single item in the nodelocset.
   13028 	    */
   13029 	    ctxt->context->node = oldlocset->locTab[i]->user;
   13030 	    ctxt->context->contextSize = oldlocset->locNr;
   13031 	    ctxt->context->proximityPosition = i + 1;
   13032 	    if (tmp == NULL) {
   13033 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13034 		    ctxt->context->node);
   13035 	    } else {
   13036 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13037 		                             ctxt->context->node) < 0) {
   13038 		    ctxt->error = XPATH_MEMORY_ERROR;
   13039 		}
   13040 	    }
   13041 	    valuePush(ctxt, tmp);
   13042 	    if (op->ch2 != -1)
   13043 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13044 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   13045                 xmlXPtrFreeLocationSet(newlocset);
   13046                 goto xptr_error;
   13047 	    }
   13048 	    /*
   13049 	    * The result of the evaluation need to be tested to
   13050 	    * decided whether the filter succeeded or not
   13051 	    */
   13052 	    res = valuePop(ctxt);
   13053 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13054 		xmlXPtrLocationSetAdd(newlocset,
   13055 		    xmlXPathCacheObjectCopy(ctxt->context,
   13056 			oldlocset->locTab[i]));
   13057 	    }
   13058 	    /*
   13059 	    * Cleanup
   13060 	    */
   13061 	    if (res != NULL) {
   13062 		xmlXPathReleaseObject(ctxt->context, res);
   13063 	    }
   13064 	    if (ctxt->value == tmp) {
   13065 		valuePop(ctxt);
   13066 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13067 		/*
   13068 		* REVISIT TODO: Don't create a temporary nodeset
   13069 		* for everly iteration.
   13070 		*/
   13071 		/* OLD: xmlXPathFreeObject(res); */
   13072 	    } else
   13073 		tmp = NULL;
   13074 	    /*
   13075 	    * Only put the first node in the result, then leave.
   13076 	    */
   13077 	    if (newlocset->locNr > 0) {
   13078 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
   13079 		break;
   13080 	    }
   13081 	}
   13082 	if (tmp != NULL) {
   13083 	    xmlXPathReleaseObject(ctxt->context, tmp);
   13084 	}
   13085 	/*
   13086 	* The result is used as the new evaluation locset.
   13087 	*/
   13088 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   13089 xptr_error:
   13090 	xmlXPathReleaseObject(ctxt->context, obj);
   13091 	ctxt->context->node = oldnode;
   13092 	ctxt->context->contextSize = oldcs;
   13093 	ctxt->context->proximityPosition = oldpp;
   13094 	return (total);
   13095     }
   13096 #endif /* LIBXML_XPTR_ENABLED */
   13097 
   13098     /*
   13099     * Extract the old set, and then evaluate the result of the
   13100     * expression for all the element in the set. use it to grow
   13101     * up a new set.
   13102     */
   13103     CHECK_TYPE0(XPATH_NODESET);
   13104 
   13105     if ((ctxt->value->nodesetval != NULL) &&
   13106         (ctxt->value->nodesetval->nodeNr != 0)) {
   13107 	xmlNodeSetPtr newset;
   13108 	xmlXPathObjectPtr tmp = NULL;
   13109 
   13110         obj = valuePop(ctxt);
   13111         oldset = obj->nodesetval;
   13112         oldnode = ctxt->context->node;
   13113         oldDoc = ctxt->context->doc;
   13114         oldcs = ctxt->context->contextSize;
   13115         oldpp = ctxt->context->proximityPosition;
   13116 
   13117 	/*
   13118 	* Initialize the new set.
   13119 	* Also set the xpath document in case things like
   13120 	* key() evaluation are attempted on the predicate
   13121 	*/
   13122 	newset = xmlXPathNodeSetCreate(NULL);
   13123         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
   13124 
   13125 	for (i = 0; i < oldset->nodeNr; i++) {
   13126 	    /*
   13127 	    * Run the evaluation with a node list made of
   13128 	    * a single item in the nodeset.
   13129 	    */
   13130 	    ctxt->context->node = oldset->nodeTab[i];
   13131 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
   13132 		(oldset->nodeTab[i]->doc != NULL))
   13133 		ctxt->context->doc = oldset->nodeTab[i]->doc;
   13134 	    if (tmp == NULL) {
   13135 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13136 		    ctxt->context->node);
   13137 	    } else {
   13138 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13139 		                             ctxt->context->node) < 0) {
   13140 		    ctxt->error = XPATH_MEMORY_ERROR;
   13141 		}
   13142 	    }
   13143 	    valuePush(ctxt, tmp);
   13144 	    ctxt->context->contextSize = oldset->nodeNr;
   13145 	    ctxt->context->proximityPosition = i + 1;
   13146 	    if (op->ch2 != -1)
   13147 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13148 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
   13149 		xmlXPathFreeNodeSet(newset);
   13150                 goto error;
   13151 	    }
   13152 	    /*
   13153 	    * The result of the evaluation needs to be tested to
   13154 	    * decide whether the filter succeeded or not
   13155 	    */
   13156 	    res = valuePop(ctxt);
   13157 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13158 		if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
   13159 		    ctxt->error = XPATH_MEMORY_ERROR;
   13160 	    }
   13161 	    /*
   13162 	    * Cleanup
   13163 	    */
   13164 	    if (res != NULL) {
   13165 		xmlXPathReleaseObject(ctxt->context, res);
   13166 	    }
   13167 	    if (ctxt->value == tmp) {
   13168 		valuePop(ctxt);
   13169 		/*
   13170 		* Don't free the temporary nodeset
   13171 		* in order to avoid massive recreation inside this
   13172 		* loop.
   13173 		*/
   13174 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13175 	    } else
   13176 		tmp = NULL;
   13177 	    /*
   13178 	    * Only put the first node in the result, then leave.
   13179 	    */
   13180 	    if (newset->nodeNr > 0) {
   13181 		*first = *(newset->nodeTab);
   13182 		break;
   13183 	    }
   13184 	}
   13185 	if (tmp != NULL) {
   13186 	    xmlXPathReleaseObject(ctxt->context, tmp);
   13187 	}
   13188 	/*
   13189 	* The result is used as the new evaluation set.
   13190 	*/
   13191 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
   13192 error:
   13193 	xmlXPathReleaseObject(ctxt->context, obj);
   13194 	ctxt->context->node = oldnode;
   13195 	ctxt->context->doc = oldDoc;
   13196 	ctxt->context->contextSize = oldcs;
   13197 	ctxt->context->proximityPosition = oldpp;
   13198     }
   13199     return(total);
   13200 }
   13201 #endif /* XP_OPTIMIZED_FILTER_FIRST */
   13202 
   13203 /**
   13204  * xmlXPathCompOpEval:
   13205  * @ctxt:  the XPath parser context with the compiled expression
   13206  * @op:  an XPath compiled operation
   13207  *
   13208  * Evaluate the Precompiled XPath operation
   13209  * Returns the number of nodes traversed
   13210  */
   13211 static int
   13212 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
   13213 {
   13214     int total = 0;
   13215     int equal, ret;
   13216     xmlXPathCompExprPtr comp;
   13217     xmlXPathObjectPtr arg1, arg2;
   13218 
   13219     CHECK_ERROR0;
   13220     comp = ctxt->comp;
   13221     switch (op->op) {
   13222         case XPATH_OP_END:
   13223             return (0);
   13224         case XPATH_OP_AND:
   13225             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13226 	    CHECK_ERROR0;
   13227             xmlXPathBooleanFunction(ctxt, 1);
   13228             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
   13229                 return (total);
   13230             arg2 = valuePop(ctxt);
   13231             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13232 	    if (ctxt->error) {
   13233 		xmlXPathFreeObject(arg2);
   13234 		return(0);
   13235 	    }
   13236             xmlXPathBooleanFunction(ctxt, 1);
   13237             if (ctxt->value != NULL)
   13238                 ctxt->value->boolval &= arg2->boolval;
   13239 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13240             return (total);
   13241         case XPATH_OP_OR:
   13242             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13243 	    CHECK_ERROR0;
   13244             xmlXPathBooleanFunction(ctxt, 1);
   13245             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
   13246                 return (total);
   13247             arg2 = valuePop(ctxt);
   13248             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13249 	    if (ctxt->error) {
   13250 		xmlXPathFreeObject(arg2);
   13251 		return(0);
   13252 	    }
   13253             xmlXPathBooleanFunction(ctxt, 1);
   13254             if (ctxt->value != NULL)
   13255                 ctxt->value->boolval |= arg2->boolval;
   13256 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13257             return (total);
   13258         case XPATH_OP_EQUAL:
   13259             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13260 	    CHECK_ERROR0;
   13261             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13262 	    CHECK_ERROR0;
   13263 	    if (op->value)
   13264 		equal = xmlXPathEqualValues(ctxt);
   13265 	    else
   13266 		equal = xmlXPathNotEqualValues(ctxt);
   13267 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
   13268             return (total);
   13269         case XPATH_OP_CMP:
   13270             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13271 	    CHECK_ERROR0;
   13272             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13273 	    CHECK_ERROR0;
   13274             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
   13275 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
   13276             return (total);
   13277         case XPATH_OP_PLUS:
   13278             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13279 	    CHECK_ERROR0;
   13280             if (op->ch2 != -1) {
   13281                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13282 	    }
   13283 	    CHECK_ERROR0;
   13284             if (op->value == 0)
   13285                 xmlXPathSubValues(ctxt);
   13286             else if (op->value == 1)
   13287                 xmlXPathAddValues(ctxt);
   13288             else if (op->value == 2)
   13289                 xmlXPathValueFlipSign(ctxt);
   13290             else if (op->value == 3) {
   13291                 CAST_TO_NUMBER;
   13292                 CHECK_TYPE0(XPATH_NUMBER);
   13293             }
   13294             return (total);
   13295         case XPATH_OP_MULT:
   13296             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13297 	    CHECK_ERROR0;
   13298             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13299 	    CHECK_ERROR0;
   13300             if (op->value == 0)
   13301                 xmlXPathMultValues(ctxt);
   13302             else if (op->value == 1)
   13303                 xmlXPathDivValues(ctxt);
   13304             else if (op->value == 2)
   13305                 xmlXPathModValues(ctxt);
   13306             return (total);
   13307         case XPATH_OP_UNION:
   13308             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13309 	    CHECK_ERROR0;
   13310             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13311 	    CHECK_ERROR0;
   13312 
   13313             arg2 = valuePop(ctxt);
   13314             arg1 = valuePop(ctxt);
   13315             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
   13316                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
   13317 	        xmlXPathReleaseObject(ctxt->context, arg1);
   13318 	        xmlXPathReleaseObject(ctxt->context, arg2);
   13319                 XP_ERROR0(XPATH_INVALID_TYPE);
   13320             }
   13321 
   13322 	    if ((arg1->nodesetval == NULL) ||
   13323 		((arg2->nodesetval != NULL) &&
   13324 		 (arg2->nodesetval->nodeNr != 0)))
   13325 	    {
   13326 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
   13327 							arg2->nodesetval);
   13328 	    }
   13329 
   13330             valuePush(ctxt, arg1);
   13331 	    xmlXPathReleaseObject(ctxt->context, arg2);
   13332             return (total);
   13333         case XPATH_OP_ROOT:
   13334             xmlXPathRoot(ctxt);
   13335             return (total);
   13336         case XPATH_OP_NODE:
   13337             if (op->ch1 != -1)
   13338                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13339 	    CHECK_ERROR0;
   13340             if (op->ch2 != -1)
   13341                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13342 	    CHECK_ERROR0;
   13343 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
   13344 		ctxt->context->node));
   13345             return (total);
   13346         case XPATH_OP_COLLECT:{
   13347                 if (op->ch1 == -1)
   13348                     return (total);
   13349 
   13350                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13351 		CHECK_ERROR0;
   13352 
   13353                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
   13354                 return (total);
   13355             }
   13356         case XPATH_OP_VALUE:
   13357             valuePush(ctxt,
   13358                       xmlXPathCacheObjectCopy(ctxt->context,
   13359 			(xmlXPathObjectPtr) op->value4));
   13360             return (total);
   13361         case XPATH_OP_VARIABLE:{
   13362 		xmlXPathObjectPtr val;
   13363 
   13364                 if (op->ch1 != -1)
   13365                     total +=
   13366                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13367                 if (op->value5 == NULL) {
   13368 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
   13369 		    if (val == NULL)
   13370 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
   13371                     valuePush(ctxt, val);
   13372 		} else {
   13373                     const xmlChar *URI;
   13374 
   13375                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
   13376                     if (URI == NULL) {
   13377                         xmlGenericError(xmlGenericErrorContext,
   13378             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
   13379                                     (char *) op->value4, (char *)op->value5);
   13380                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
   13381                         return (total);
   13382                     }
   13383 		    val = xmlXPathVariableLookupNS(ctxt->context,
   13384                                                        op->value4, URI);
   13385 		    if (val == NULL)
   13386 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
   13387                     valuePush(ctxt, val);
   13388                 }
   13389                 return (total);
   13390             }
   13391         case XPATH_OP_FUNCTION:{
   13392                 xmlXPathFunction func;
   13393                 const xmlChar *oldFunc, *oldFuncURI;
   13394 		int i;
   13395                 int frame;
   13396 
   13397                 frame = xmlXPathSetFrame(ctxt);
   13398                 if (op->ch1 != -1) {
   13399                     total +=
   13400                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13401                     if (ctxt->error != XPATH_EXPRESSION_OK) {
   13402                         xmlXPathPopFrame(ctxt, frame);
   13403                         return (total);
   13404                     }
   13405                 }
   13406 		if (ctxt->valueNr < ctxt->valueFrame + op->value) {
   13407 		    xmlGenericError(xmlGenericErrorContext,
   13408 			    "xmlXPathCompOpEval: parameter error\n");
   13409 		    ctxt->error = XPATH_INVALID_OPERAND;
   13410                     xmlXPathPopFrame(ctxt, frame);
   13411 		    return (total);
   13412 		}
   13413 		for (i = 0; i < op->value; i++) {
   13414 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
   13415 			xmlGenericError(xmlGenericErrorContext,
   13416 				"xmlXPathCompOpEval: parameter error\n");
   13417 			ctxt->error = XPATH_INVALID_OPERAND;
   13418                         xmlXPathPopFrame(ctxt, frame);
   13419 			return (total);
   13420 		    }
   13421                 }
   13422                 if (op->cache != NULL)
   13423                     func = op->cache;
   13424                 else {
   13425                     const xmlChar *URI = NULL;
   13426 
   13427                     if (op->value5 == NULL)
   13428                         func =
   13429                             xmlXPathFunctionLookup(ctxt->context,
   13430                                                    op->value4);
   13431                     else {
   13432                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
   13433                         if (URI == NULL) {
   13434                             xmlGenericError(xmlGenericErrorContext,
   13435             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
   13436                                     (char *)op->value4, (char *)op->value5);
   13437                             xmlXPathPopFrame(ctxt, frame);
   13438                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
   13439                             return (total);
   13440                         }
   13441                         func = xmlXPathFunctionLookupNS(ctxt->context,
   13442                                                         op->value4, URI);
   13443                     }
   13444                     if (func == NULL) {
   13445                         xmlGenericError(xmlGenericErrorContext,
   13446                                 "xmlXPathCompOpEval: function %s not found\n",
   13447                                         (char *)op->value4);
   13448                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
   13449                     }
   13450                     op->cache = func;
   13451                     op->cacheURI = (void *) URI;
   13452                 }
   13453                 oldFunc = ctxt->context->function;
   13454                 oldFuncURI = ctxt->context->functionURI;
   13455                 ctxt->context->function = op->value4;
   13456                 ctxt->context->functionURI = op->cacheURI;
   13457                 func(ctxt, op->value);
   13458                 ctxt->context->function = oldFunc;
   13459                 ctxt->context->functionURI = oldFuncURI;
   13460                 xmlXPathPopFrame(ctxt, frame);
   13461                 return (total);
   13462             }
   13463         case XPATH_OP_ARG:
   13464             if (op->ch1 != -1) {
   13465                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13466 	        CHECK_ERROR0;
   13467             }
   13468             if (op->ch2 != -1) {
   13469                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
   13470 	        CHECK_ERROR0;
   13471 	    }
   13472             return (total);
   13473         case XPATH_OP_PREDICATE:
   13474         case XPATH_OP_FILTER:{
   13475                 xmlXPathObjectPtr res;
   13476                 xmlXPathObjectPtr obj, tmp;
   13477                 xmlNodeSetPtr newset = NULL;
   13478                 xmlNodeSetPtr oldset;
   13479                 xmlNodePtr oldnode;
   13480 		xmlDocPtr oldDoc;
   13481                 int oldcs, oldpp;
   13482                 int i;
   13483 
   13484                 /*
   13485                  * Optimization for ()[1] selection i.e. the first elem
   13486                  */
   13487                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
   13488 #ifdef XP_OPTIMIZED_FILTER_FIRST
   13489 		    /*
   13490 		    * FILTER TODO: Can we assume that the inner processing
   13491 		    *  will result in an ordered list if we have an
   13492 		    *  XPATH_OP_FILTER?
   13493 		    *  What about an additional field or flag on
   13494 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
   13495 		    *  to assume anything, so it would be more robust and
   13496 		    *  easier to optimize.
   13497 		    */
   13498                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
   13499 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
   13500 #else
   13501 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   13502 #endif
   13503                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
   13504                     xmlXPathObjectPtr val;
   13505 
   13506                     val = comp->steps[op->ch2].value4;
   13507                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
   13508                         (val->floatval == 1.0)) {
   13509                         xmlNodePtr first = NULL;
   13510 
   13511                         total +=
   13512                             xmlXPathCompOpEvalFirst(ctxt,
   13513                                                     &comp->steps[op->ch1],
   13514                                                     &first);
   13515 			CHECK_ERROR0;
   13516                         /*
   13517                          * The nodeset should be in document order,
   13518                          * Keep only the first value
   13519                          */
   13520                         if ((ctxt->value != NULL) &&
   13521                             (ctxt->value->type == XPATH_NODESET) &&
   13522                             (ctxt->value->nodesetval != NULL) &&
   13523                             (ctxt->value->nodesetval->nodeNr > 1))
   13524                             xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
   13525                                                         1, 1);
   13526                         return (total);
   13527                     }
   13528                 }
   13529                 /*
   13530                  * Optimization for ()[last()] selection i.e. the last elem
   13531                  */
   13532                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
   13533                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
   13534                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
   13535                     int f = comp->steps[op->ch2].ch1;
   13536 
   13537                     if ((f != -1) &&
   13538                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
   13539                         (comp->steps[f].value5 == NULL) &&
   13540                         (comp->steps[f].value == 0) &&
   13541                         (comp->steps[f].value4 != NULL) &&
   13542                         (xmlStrEqual
   13543                          (comp->steps[f].value4, BAD_CAST "last"))) {
   13544                         xmlNodePtr last = NULL;
   13545 
   13546                         total +=
   13547                             xmlXPathCompOpEvalLast(ctxt,
   13548                                                    &comp->steps[op->ch1],
   13549                                                    &last);
   13550 			CHECK_ERROR0;
   13551                         /*
   13552                          * The nodeset should be in document order,
   13553                          * Keep only the last value
   13554                          */
   13555                         if ((ctxt->value != NULL) &&
   13556                             (ctxt->value->type == XPATH_NODESET) &&
   13557                             (ctxt->value->nodesetval != NULL) &&
   13558                             (ctxt->value->nodesetval->nodeTab != NULL) &&
   13559                             (ctxt->value->nodesetval->nodeNr > 1))
   13560                             xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
   13561                         return (total);
   13562                     }
   13563                 }
   13564 		/*
   13565 		* Process inner predicates first.
   13566 		* Example "index[parent::book][1]":
   13567 		* ...
   13568 		*   PREDICATE   <-- we are here "[1]"
   13569 		*     PREDICATE <-- process "[parent::book]" first
   13570 		*       SORT
   13571 		*         COLLECT  'parent' 'name' 'node' book
   13572 		*           NODE
   13573 		*     ELEM Object is a number : 1
   13574 		*/
   13575                 if (op->ch1 != -1)
   13576                     total +=
   13577                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13578 		CHECK_ERROR0;
   13579                 if (op->ch2 == -1)
   13580                     return (total);
   13581                 if (ctxt->value == NULL)
   13582                     return (total);
   13583 
   13584 #ifdef LIBXML_XPTR_ENABLED
   13585                 /*
   13586                  * Hum are we filtering the result of an XPointer expression
   13587                  */
   13588                 if (ctxt->value->type == XPATH_LOCATIONSET) {
   13589                     xmlLocationSetPtr newlocset = NULL;
   13590                     xmlLocationSetPtr oldlocset;
   13591 
   13592                     /*
   13593                      * Extract the old locset, and then evaluate the result of the
   13594                      * expression for all the element in the locset. use it to grow
   13595                      * up a new locset.
   13596                      */
   13597                     CHECK_TYPE0(XPATH_LOCATIONSET);
   13598 
   13599                     if ((ctxt->value->user == NULL) ||
   13600                         (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
   13601                         return (total);
   13602 
   13603                     obj = valuePop(ctxt);
   13604                     oldlocset = obj->user;
   13605                     oldnode = ctxt->context->node;
   13606                     oldcs = ctxt->context->contextSize;
   13607                     oldpp = ctxt->context->proximityPosition;
   13608 
   13609                     newlocset = xmlXPtrLocationSetCreate(NULL);
   13610 
   13611                     for (i = 0; i < oldlocset->locNr; i++) {
   13612                         /*
   13613                          * Run the evaluation with a node list made of a
   13614                          * single item in the nodelocset.
   13615                          */
   13616                         ctxt->context->node = oldlocset->locTab[i]->user;
   13617                         ctxt->context->contextSize = oldlocset->locNr;
   13618                         ctxt->context->proximityPosition = i + 1;
   13619 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13620 			    ctxt->context->node);
   13621                         valuePush(ctxt, tmp);
   13622 
   13623                         if (op->ch2 != -1)
   13624                             total +=
   13625                                 xmlXPathCompOpEval(ctxt,
   13626                                                    &comp->steps[op->ch2]);
   13627 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13628                             xmlXPtrFreeLocationSet(newlocset);
   13629                             goto filter_xptr_error;
   13630 			}
   13631 
   13632                         /*
   13633                          * The result of the evaluation need to be tested to
   13634                          * decided whether the filter succeeded or not
   13635                          */
   13636                         res = valuePop(ctxt);
   13637                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13638                             xmlXPtrLocationSetAdd(newlocset,
   13639                                                   xmlXPathObjectCopy
   13640                                                   (oldlocset->locTab[i]));
   13641                         }
   13642 
   13643                         /*
   13644                          * Cleanup
   13645                          */
   13646                         if (res != NULL) {
   13647 			    xmlXPathReleaseObject(ctxt->context, res);
   13648 			}
   13649                         if (ctxt->value == tmp) {
   13650                             res = valuePop(ctxt);
   13651 			    xmlXPathReleaseObject(ctxt->context, res);
   13652                         }
   13653                     }
   13654 
   13655                     /*
   13656                      * The result is used as the new evaluation locset.
   13657                      */
   13658                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   13659 filter_xptr_error:
   13660 		    xmlXPathReleaseObject(ctxt->context, obj);
   13661                     ctxt->context->node = oldnode;
   13662                     ctxt->context->contextSize = oldcs;
   13663                     ctxt->context->proximityPosition = oldpp;
   13664                     return (total);
   13665                 }
   13666 #endif /* LIBXML_XPTR_ENABLED */
   13667 
   13668                 /*
   13669                  * Extract the old set, and then evaluate the result of the
   13670                  * expression for all the element in the set. use it to grow
   13671                  * up a new set.
   13672                  */
   13673                 CHECK_TYPE0(XPATH_NODESET);
   13674 
   13675                 if ((ctxt->value->nodesetval != NULL) &&
   13676                     (ctxt->value->nodesetval->nodeNr != 0)) {
   13677                     obj = valuePop(ctxt);
   13678                     oldset = obj->nodesetval;
   13679                     oldnode = ctxt->context->node;
   13680                     oldDoc = ctxt->context->doc;
   13681                     oldcs = ctxt->context->contextSize;
   13682                     oldpp = ctxt->context->proximityPosition;
   13683 		    tmp = NULL;
   13684                     /*
   13685                      * Initialize the new set.
   13686 		     * Also set the xpath document in case things like
   13687 		     * key() evaluation are attempted on the predicate
   13688                      */
   13689                     newset = xmlXPathNodeSetCreate(NULL);
   13690 		    /*
   13691 		    * SPEC XPath 1.0:
   13692 		    *  "For each node in the node-set to be filtered, the
   13693 		    *  PredicateExpr is evaluated with that node as the
   13694 		    *  context node, with the number of nodes in the
   13695 		    *  node-set as the context size, and with the proximity
   13696 		    *  position of the node in the node-set with respect to
   13697 		    *  the axis as the context position;"
   13698 		    * @oldset is the node-set" to be filtered.
   13699 		    *
   13700 		    * SPEC XPath 1.0:
   13701 		    *  "only predicates change the context position and
   13702 		    *  context size (see [2.4 Predicates])."
   13703 		    * Example:
   13704 		    *   node-set  context pos
   13705 		    *    nA         1
   13706 		    *    nB         2
   13707 		    *    nC         3
   13708 		    *   After applying predicate [position() > 1] :
   13709 		    *   node-set  context pos
   13710 		    *    nB         1
   13711 		    *    nC         2
   13712 		    *
   13713 		    * removed the first node in the node-set, then
   13714 		    * the context position of the
   13715 		    */
   13716                     for (i = 0; i < oldset->nodeNr; i++) {
   13717                         /*
   13718                          * Run the evaluation with a node list made of
   13719                          * a single item in the nodeset.
   13720                          */
   13721                         ctxt->context->node = oldset->nodeTab[i];
   13722 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
   13723 			    (oldset->nodeTab[i]->doc != NULL))
   13724 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
   13725 			if (tmp == NULL) {
   13726 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13727 				ctxt->context->node);
   13728 			} else {
   13729 			    if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
   13730 				               ctxt->context->node) < 0) {
   13731 				ctxt->error = XPATH_MEMORY_ERROR;
   13732 			    }
   13733 			}
   13734                         valuePush(ctxt, tmp);
   13735                         ctxt->context->contextSize = oldset->nodeNr;
   13736                         ctxt->context->proximityPosition = i + 1;
   13737 			/*
   13738 			* Evaluate the predicate against the context node.
   13739 			* Can/should we optimize position() predicates
   13740 			* here (e.g. "[1]")?
   13741 			*/
   13742                         if (op->ch2 != -1)
   13743                             total +=
   13744                                 xmlXPathCompOpEval(ctxt,
   13745                                                    &comp->steps[op->ch2]);
   13746 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13747 			    xmlXPathFreeNodeSet(newset);
   13748                             goto filter_error;
   13749 			}
   13750 
   13751                         /*
   13752                          * The result of the evaluation needs to be tested to
   13753                          * decide whether the filter succeeded or not
   13754                          */
   13755 			/*
   13756 			* OPTIMIZE TODO: Can we use
   13757 			* xmlXPathNodeSetAdd*Unique()* instead?
   13758 			*/
   13759                         res = valuePop(ctxt);
   13760                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
   13761                             if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
   13762 			        < 0)
   13763 				ctxt->error = XPATH_MEMORY_ERROR;
   13764                         }
   13765 
   13766                         /*
   13767                          * Cleanup
   13768                          */
   13769                         if (res != NULL) {
   13770 			    xmlXPathReleaseObject(ctxt->context, res);
   13771 			}
   13772                         if (ctxt->value == tmp) {
   13773                             valuePop(ctxt);
   13774 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
   13775 			    /*
   13776 			    * Don't free the temporary nodeset
   13777 			    * in order to avoid massive recreation inside this
   13778 			    * loop.
   13779 			    */
   13780                         } else
   13781 			    tmp = NULL;
   13782                     }
   13783 		    if (tmp != NULL)
   13784 			xmlXPathReleaseObject(ctxt->context, tmp);
   13785                     /*
   13786                      * The result is used as the new evaluation set.
   13787                      */
   13788 		    valuePush(ctxt,
   13789 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
   13790 filter_error:
   13791 		    xmlXPathReleaseObject(ctxt->context, obj);
   13792 		    ctxt->context->node = oldnode;
   13793 		    ctxt->context->doc = oldDoc;
   13794                     ctxt->context->contextSize = oldcs;
   13795                     ctxt->context->proximityPosition = oldpp;
   13796                 }
   13797                 return (total);
   13798             }
   13799         case XPATH_OP_SORT:
   13800             if (op->ch1 != -1)
   13801                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13802 	    CHECK_ERROR0;
   13803             if ((ctxt->value != NULL) &&
   13804                 (ctxt->value->type == XPATH_NODESET) &&
   13805                 (ctxt->value->nodesetval != NULL) &&
   13806 		(ctxt->value->nodesetval->nodeNr > 1))
   13807 	    {
   13808                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
   13809 	    }
   13810             return (total);
   13811 #ifdef LIBXML_XPTR_ENABLED
   13812         case XPATH_OP_RANGETO:{
   13813                 xmlXPathObjectPtr range;
   13814                 xmlXPathObjectPtr res, obj;
   13815                 xmlXPathObjectPtr tmp;
   13816                 xmlLocationSetPtr newlocset = NULL;
   13817 		    xmlLocationSetPtr oldlocset;
   13818                 xmlNodeSetPtr oldset;
   13819                 xmlNodePtr oldnode = ctxt->context->node;
   13820                 int oldcs = ctxt->context->contextSize;
   13821                 int oldpp = ctxt->context->proximityPosition;
   13822                 int i, j;
   13823 
   13824                 if (op->ch1 != -1) {
   13825                     total +=
   13826                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
   13827                     CHECK_ERROR0;
   13828                 }
   13829                 if (ctxt->value == NULL) {
   13830                     XP_ERROR0(XPATH_INVALID_OPERAND);
   13831                 }
   13832                 if (op->ch2 == -1)
   13833                     return (total);
   13834 
   13835                 if (ctxt->value->type == XPATH_LOCATIONSET) {
   13836                     /*
   13837                      * Extract the old locset, and then evaluate the result of the
   13838                      * expression for all the element in the locset. use it to grow
   13839                      * up a new locset.
   13840                      */
   13841                     CHECK_TYPE0(XPATH_LOCATIONSET);
   13842 
   13843                     if ((ctxt->value->user == NULL) ||
   13844                         (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
   13845                         return (total);
   13846 
   13847                     obj = valuePop(ctxt);
   13848                     oldlocset = obj->user;
   13849 
   13850                     newlocset = xmlXPtrLocationSetCreate(NULL);
   13851 
   13852                     for (i = 0; i < oldlocset->locNr; i++) {
   13853                         /*
   13854                          * Run the evaluation with a node list made of a
   13855                          * single item in the nodelocset.
   13856                          */
   13857                         ctxt->context->node = oldlocset->locTab[i]->user;
   13858                         ctxt->context->contextSize = oldlocset->locNr;
   13859                         ctxt->context->proximityPosition = i + 1;
   13860 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13861 			    ctxt->context->node);
   13862                         valuePush(ctxt, tmp);
   13863 
   13864                         if (op->ch2 != -1)
   13865                             total +=
   13866                                 xmlXPathCompOpEval(ctxt,
   13867                                                    &comp->steps[op->ch2]);
   13868 			if (ctxt->error != XPATH_EXPRESSION_OK) {
   13869                             xmlXPtrFreeLocationSet(newlocset);
   13870                             goto rangeto_error;
   13871 			}
   13872 
   13873                         res = valuePop(ctxt);
   13874 			if (res->type == XPATH_LOCATIONSET) {
   13875 			    xmlLocationSetPtr rloc =
   13876 			        (xmlLocationSetPtr)res->user;
   13877 			    for (j=0; j<rloc->locNr; j++) {
   13878 			        range = xmlXPtrNewRange(
   13879 				  oldlocset->locTab[i]->user,
   13880 				  oldlocset->locTab[i]->index,
   13881 				  rloc->locTab[j]->user2,
   13882 				  rloc->locTab[j]->index2);
   13883 				if (range != NULL) {
   13884 				    xmlXPtrLocationSetAdd(newlocset, range);
   13885 				}
   13886 			    }
   13887 			} else {
   13888 			    range = xmlXPtrNewRangeNodeObject(
   13889 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
   13890                             if (range != NULL) {
   13891                                 xmlXPtrLocationSetAdd(newlocset,range);
   13892 			    }
   13893                         }
   13894 
   13895                         /*
   13896                          * Cleanup
   13897                          */
   13898                         if (res != NULL) {
   13899 			    xmlXPathReleaseObject(ctxt->context, res);
   13900 			}
   13901                         if (ctxt->value == tmp) {
   13902                             res = valuePop(ctxt);
   13903 			    xmlXPathReleaseObject(ctxt->context, res);
   13904                         }
   13905                     }
   13906 		} else {	/* Not a location set */
   13907                     CHECK_TYPE0(XPATH_NODESET);
   13908                     obj = valuePop(ctxt);
   13909                     oldset = obj->nodesetval;
   13910 
   13911                     newlocset = xmlXPtrLocationSetCreate(NULL);
   13912 
   13913                     if (oldset != NULL) {
   13914                         for (i = 0; i < oldset->nodeNr; i++) {
   13915                             /*
   13916                              * Run the evaluation with a node list made of a single item
   13917                              * in the nodeset.
   13918                              */
   13919                             ctxt->context->node = oldset->nodeTab[i];
   13920 			    /*
   13921 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
   13922 			    */
   13923 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
   13924 				ctxt->context->node);
   13925                             valuePush(ctxt, tmp);
   13926 
   13927                             if (op->ch2 != -1)
   13928                                 total +=
   13929                                     xmlXPathCompOpEval(ctxt,
   13930                                                    &comp->steps[op->ch2]);
   13931 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
   13932                                 xmlXPtrFreeLocationSet(newlocset);
   13933                                 goto rangeto_error;
   13934 			    }
   13935 
   13936                             res = valuePop(ctxt);
   13937                             range =
   13938                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
   13939                                                       res);
   13940                             if (range != NULL) {
   13941                                 xmlXPtrLocationSetAdd(newlocset, range);
   13942                             }
   13943 
   13944                             /*
   13945                              * Cleanup
   13946                              */
   13947                             if (res != NULL) {
   13948 				xmlXPathReleaseObject(ctxt->context, res);
   13949 			    }
   13950                             if (ctxt->value == tmp) {
   13951                                 res = valuePop(ctxt);
   13952 				xmlXPathReleaseObject(ctxt->context, res);
   13953                             }
   13954                         }
   13955                     }
   13956                 }
   13957 
   13958                 /*
   13959                  * The result is used as the new evaluation set.
   13960                  */
   13961                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
   13962 rangeto_error:
   13963 		xmlXPathReleaseObject(ctxt->context, obj);
   13964                 ctxt->context->node = oldnode;
   13965                 ctxt->context->contextSize = oldcs;
   13966                 ctxt->context->proximityPosition = oldpp;
   13967                 return (total);
   13968             }
   13969 #endif /* LIBXML_XPTR_ENABLED */
   13970     }
   13971     xmlGenericError(xmlGenericErrorContext,
   13972                     "XPath: unknown precompiled operation %d\n", op->op);
   13973     ctxt->error = XPATH_INVALID_OPERAND;
   13974     return (total);
   13975 }
   13976 
   13977 /**
   13978  * xmlXPathCompOpEvalToBoolean:
   13979  * @ctxt:  the XPath parser context
   13980  *
   13981  * Evaluates if the expression evaluates to true.
   13982  *
   13983  * Returns 1 if true, 0 if false and -1 on API or internal errors.
   13984  */
   13985 static int
   13986 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
   13987 			    xmlXPathStepOpPtr op,
   13988 			    int isPredicate)
   13989 {
   13990     xmlXPathObjectPtr resObj = NULL;
   13991 
   13992 start:
   13993     /* comp = ctxt->comp; */
   13994     switch (op->op) {
   13995         case XPATH_OP_END:
   13996             return (0);
   13997 	case XPATH_OP_VALUE:
   13998 	    resObj = (xmlXPathObjectPtr) op->value4;
   13999 	    if (isPredicate)
   14000 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
   14001 	    return(xmlXPathCastToBoolean(resObj));
   14002 	case XPATH_OP_SORT:
   14003 	    /*
   14004 	    * We don't need sorting for boolean results. Skip this one.
   14005 	    */
   14006             if (op->ch1 != -1) {
   14007 		op = &ctxt->comp->steps[op->ch1];
   14008 		goto start;
   14009 	    }
   14010 	    return(0);
   14011 	case XPATH_OP_COLLECT:
   14012 	    if (op->ch1 == -1)
   14013 		return(0);
   14014 
   14015             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
   14016 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14017 		return(-1);
   14018 
   14019             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
   14020 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14021 		return(-1);
   14022 
   14023 	    resObj = valuePop(ctxt);
   14024 	    if (resObj == NULL)
   14025 		return(-1);
   14026 	    break;
   14027 	default:
   14028 	    /*
   14029 	    * Fallback to call xmlXPathCompOpEval().
   14030 	    */
   14031 	    xmlXPathCompOpEval(ctxt, op);
   14032 	    if (ctxt->error != XPATH_EXPRESSION_OK)
   14033 		return(-1);
   14034 
   14035 	    resObj = valuePop(ctxt);
   14036 	    if (resObj == NULL)
   14037 		return(-1);
   14038 	    break;
   14039     }
   14040 
   14041     if (resObj) {
   14042 	int res;
   14043 
   14044 	if (resObj->type == XPATH_BOOLEAN) {
   14045 	    res = resObj->boolval;
   14046 	} else if (isPredicate) {
   14047 	    /*
   14048 	    * For predicates a result of type "number" is handled
   14049 	    * differently:
   14050 	    * SPEC XPath 1.0:
   14051 	    * "If the result is a number, the result will be converted
   14052 	    *  to true if the number is equal to the context position
   14053 	    *  and will be converted to false otherwise;"
   14054 	    */
   14055 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
   14056 	} else {
   14057 	    res = xmlXPathCastToBoolean(resObj);
   14058 	}
   14059 	xmlXPathReleaseObject(ctxt->context, resObj);
   14060 	return(res);
   14061     }
   14062 
   14063     return(0);
   14064 }
   14065 
   14066 #ifdef XPATH_STREAMING
   14067 /**
   14068  * xmlXPathRunStreamEval:
   14069  * @ctxt:  the XPath parser context with the compiled expression
   14070  *
   14071  * Evaluate the Precompiled Streamable XPath expression in the given context.
   14072  */
   14073 static int
   14074 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
   14075 		      xmlXPathObjectPtr *resultSeq, int toBool)
   14076 {
   14077     int max_depth, min_depth;
   14078     int from_root;
   14079     int ret, depth;
   14080     int eval_all_nodes;
   14081     xmlNodePtr cur = NULL, limit = NULL;
   14082     xmlStreamCtxtPtr patstream = NULL;
   14083 
   14084     int nb_nodes = 0;
   14085 
   14086     if ((ctxt == NULL) || (comp == NULL))
   14087         return(-1);
   14088     max_depth = xmlPatternMaxDepth(comp);
   14089     if (max_depth == -1)
   14090         return(-1);
   14091     if (max_depth == -2)
   14092         max_depth = 10000;
   14093     min_depth = xmlPatternMinDepth(comp);
   14094     if (min_depth == -1)
   14095         return(-1);
   14096     from_root = xmlPatternFromRoot(comp);
   14097     if (from_root < 0)
   14098         return(-1);
   14099 #if 0
   14100     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
   14101 #endif
   14102 
   14103     if (! toBool) {
   14104 	if (resultSeq == NULL)
   14105 	    return(-1);
   14106 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
   14107 	if (*resultSeq == NULL)
   14108 	    return(-1);
   14109     }
   14110 
   14111     /*
   14112      * handle the special cases of "/" amd "." being matched
   14113      */
   14114     if (min_depth == 0) {
   14115 	if (from_root) {
   14116 	    /* Select "/" */
   14117 	    if (toBool)
   14118 		return(1);
   14119 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
   14120 		                     (xmlNodePtr) ctxt->doc);
   14121 	} else {
   14122 	    /* Select "self::node()" */
   14123 	    if (toBool)
   14124 		return(1);
   14125 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
   14126 	}
   14127     }
   14128     if (max_depth == 0) {
   14129 	return(0);
   14130     }
   14131 
   14132     if (from_root) {
   14133         cur = (xmlNodePtr)ctxt->doc;
   14134     } else if (ctxt->node != NULL) {
   14135         switch (ctxt->node->type) {
   14136             case XML_ELEMENT_NODE:
   14137             case XML_DOCUMENT_NODE:
   14138             case XML_DOCUMENT_FRAG_NODE:
   14139             case XML_HTML_DOCUMENT_NODE:
   14140 #ifdef LIBXML_DOCB_ENABLED
   14141             case XML_DOCB_DOCUMENT_NODE:
   14142 #endif
   14143 	        cur = ctxt->node;
   14144 		break;
   14145             case XML_ATTRIBUTE_NODE:
   14146             case XML_TEXT_NODE:
   14147             case XML_CDATA_SECTION_NODE:
   14148             case XML_ENTITY_REF_NODE:
   14149             case XML_ENTITY_NODE:
   14150             case XML_PI_NODE:
   14151             case XML_COMMENT_NODE:
   14152             case XML_NOTATION_NODE:
   14153             case XML_DTD_NODE:
   14154             case XML_DOCUMENT_TYPE_NODE:
   14155             case XML_ELEMENT_DECL:
   14156             case XML_ATTRIBUTE_DECL:
   14157             case XML_ENTITY_DECL:
   14158             case XML_NAMESPACE_DECL:
   14159             case XML_XINCLUDE_START:
   14160             case XML_XINCLUDE_END:
   14161 		break;
   14162 	}
   14163 	limit = cur;
   14164     }
   14165     if (cur == NULL) {
   14166         return(0);
   14167     }
   14168 
   14169     patstream = xmlPatternGetStreamCtxt(comp);
   14170     if (patstream == NULL) {
   14171 	/*
   14172 	* QUESTION TODO: Is this an error?
   14173 	*/
   14174 	return(0);
   14175     }
   14176 
   14177     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
   14178 
   14179     if (from_root) {
   14180 	ret = xmlStreamPush(patstream, NULL, NULL);
   14181 	if (ret < 0) {
   14182 	} else if (ret == 1) {
   14183 	    if (toBool)
   14184 		goto return_1;
   14185 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
   14186 	}
   14187     }
   14188     depth = 0;
   14189     goto scan_children;
   14190 next_node:
   14191     do {
   14192         nb_nodes++;
   14193 
   14194 	switch (cur->type) {
   14195 	    case XML_ELEMENT_NODE:
   14196 	    case XML_TEXT_NODE:
   14197 	    case XML_CDATA_SECTION_NODE:
   14198 	    case XML_COMMENT_NODE:
   14199 	    case XML_PI_NODE:
   14200 		if (cur->type == XML_ELEMENT_NODE) {
   14201 		    ret = xmlStreamPush(patstream, cur->name,
   14202 				(cur->ns ? cur->ns->href : NULL));
   14203 		} else if (eval_all_nodes)
   14204 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
   14205 		else
   14206 		    break;
   14207 
   14208 		if (ret < 0) {
   14209 		    /* NOP. */
   14210 		} else if (ret == 1) {
   14211 		    if (toBool)
   14212 			goto return_1;
   14213 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
   14214 		        < 0) {
   14215 			ctxt->lastError.domain = XML_FROM_XPATH;
   14216 			ctxt->lastError.code = XML_ERR_NO_MEMORY;
   14217 		    }
   14218 		}
   14219 		if ((cur->children == NULL) || (depth >= max_depth)) {
   14220 		    ret = xmlStreamPop(patstream);
   14221 		    while (cur->next != NULL) {
   14222 			cur = cur->next;
   14223 			if ((cur->type != XML_ENTITY_DECL) &&
   14224 			    (cur->type != XML_DTD_NODE))
   14225 			    goto next_node;
   14226 		    }
   14227 		}
   14228 	    default:
   14229 		break;
   14230 	}
   14231 
   14232 scan_children:
   14233 	if (cur->type == XML_NAMESPACE_DECL) break;
   14234 	if ((cur->children != NULL) && (depth < max_depth)) {
   14235 	    /*
   14236 	     * Do not descend on entities declarations
   14237 	     */
   14238 	    if (cur->children->type != XML_ENTITY_DECL) {
   14239 		cur = cur->children;
   14240 		depth++;
   14241 		/*
   14242 		 * Skip DTDs
   14243 		 */
   14244 		if (cur->type != XML_DTD_NODE)
   14245 		    continue;
   14246 	    }
   14247 	}
   14248 
   14249 	if (cur == limit)
   14250 	    break;
   14251 
   14252 	while (cur->next != NULL) {
   14253 	    cur = cur->next;
   14254 	    if ((cur->type != XML_ENTITY_DECL) &&
   14255 		(cur->type != XML_DTD_NODE))
   14256 		goto next_node;
   14257 	}
   14258 
   14259 	do {
   14260 	    cur = cur->parent;
   14261 	    depth--;
   14262 	    if ((cur == NULL) || (cur == limit))
   14263 	        goto done;
   14264 	    if (cur->type == XML_ELEMENT_NODE) {
   14265 		ret = xmlStreamPop(patstream);
   14266 	    } else if ((eval_all_nodes) &&
   14267 		((cur->type == XML_TEXT_NODE) ||
   14268 		 (cur->type == XML_CDATA_SECTION_NODE) ||
   14269 		 (cur->type == XML_COMMENT_NODE) ||
   14270 		 (cur->type == XML_PI_NODE)))
   14271 	    {
   14272 		ret = xmlStreamPop(patstream);
   14273 	    }
   14274 	    if (cur->next != NULL) {
   14275 		cur = cur->next;
   14276 		break;
   14277 	    }
   14278 	} while (cur != NULL);
   14279 
   14280     } while ((cur != NULL) && (depth >= 0));
   14281 
   14282 done:
   14283 
   14284 #if 0
   14285     printf("stream eval: checked %d nodes selected %d\n",
   14286            nb_nodes, retObj->nodesetval->nodeNr);
   14287 #endif
   14288 
   14289     if (patstream)
   14290 	xmlFreeStreamCtxt(patstream);
   14291     return(0);
   14292 
   14293 return_1:
   14294     if (patstream)
   14295 	xmlFreeStreamCtxt(patstream);
   14296     return(1);
   14297 }
   14298 #endif /* XPATH_STREAMING */
   14299 
   14300 /**
   14301  * xmlXPathRunEval:
   14302  * @ctxt:  the XPath parser context with the compiled expression
   14303  * @toBool:  evaluate to a boolean result
   14304  *
   14305  * Evaluate the Precompiled XPath expression in the given context.
   14306  */
   14307 static int
   14308 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
   14309 {
   14310     xmlXPathCompExprPtr comp;
   14311 
   14312     if ((ctxt == NULL) || (ctxt->comp == NULL))
   14313 	return(-1);
   14314 
   14315     if (ctxt->valueTab == NULL) {
   14316 	/* Allocate the value stack */
   14317 	ctxt->valueTab = (xmlXPathObjectPtr *)
   14318 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
   14319 	if (ctxt->valueTab == NULL) {
   14320 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
   14321 	    xmlFree(ctxt);
   14322 	}
   14323 	ctxt->valueNr = 0;
   14324 	ctxt->valueMax = 10;
   14325 	ctxt->value = NULL;
   14326         ctxt->valueFrame = 0;
   14327     }
   14328 #ifdef XPATH_STREAMING
   14329     if (ctxt->comp->stream) {
   14330 	int res;
   14331 
   14332 	if (toBool) {
   14333 	    /*
   14334 	    * Evaluation to boolean result.
   14335 	    */
   14336 	    res = xmlXPathRunStreamEval(ctxt->context,
   14337 		ctxt->comp->stream, NULL, 1);
   14338 	    if (res != -1)
   14339 		return(res);
   14340 	} else {
   14341 	    xmlXPathObjectPtr resObj = NULL;
   14342 
   14343 	    /*
   14344 	    * Evaluation to a sequence.
   14345 	    */
   14346 	    res = xmlXPathRunStreamEval(ctxt->context,
   14347 		ctxt->comp->stream, &resObj, 0);
   14348 
   14349 	    if ((res != -1) && (resObj != NULL)) {
   14350 		valuePush(ctxt, resObj);
   14351 		return(0);
   14352 	    }
   14353 	    if (resObj != NULL)
   14354 		xmlXPathReleaseObject(ctxt->context, resObj);
   14355 	}
   14356 	/*
   14357 	* QUESTION TODO: This falls back to normal XPath evaluation
   14358 	* if res == -1. Is this intended?
   14359 	*/
   14360     }
   14361 #endif
   14362     comp = ctxt->comp;
   14363     if (comp->last < 0) {
   14364 	xmlGenericError(xmlGenericErrorContext,
   14365 	    "xmlXPathRunEval: last is less than zero\n");
   14366 	return(-1);
   14367     }
   14368     if (toBool)
   14369 	return(xmlXPathCompOpEvalToBoolean(ctxt,
   14370 	    &comp->steps[comp->last], 0));
   14371     else
   14372 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
   14373 
   14374     return(0);
   14375 }
   14376 
   14377 /************************************************************************
   14378  *									*
   14379  *			Public interfaces				*
   14380  *									*
   14381  ************************************************************************/
   14382 
   14383 /**
   14384  * xmlXPathEvalPredicate:
   14385  * @ctxt:  the XPath context
   14386  * @res:  the Predicate Expression evaluation result
   14387  *
   14388  * Evaluate a predicate result for the current node.
   14389  * A PredicateExpr is evaluated by evaluating the Expr and converting
   14390  * the result to a boolean. If the result is a number, the result will
   14391  * be converted to true if the number is equal to the position of the
   14392  * context node in the context node list (as returned by the position
   14393  * function) and will be converted to false otherwise; if the result
   14394  * is not a number, then the result will be converted as if by a call
   14395  * to the boolean function.
   14396  *
   14397  * Returns 1 if predicate is true, 0 otherwise
   14398  */
   14399 int
   14400 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
   14401     if ((ctxt == NULL) || (res == NULL)) return(0);
   14402     switch (res->type) {
   14403         case XPATH_BOOLEAN:
   14404 	    return(res->boolval);
   14405         case XPATH_NUMBER:
   14406 	    return(res->floatval == ctxt->proximityPosition);
   14407         case XPATH_NODESET:
   14408         case XPATH_XSLT_TREE:
   14409 	    if (res->nodesetval == NULL)
   14410 		return(0);
   14411 	    return(res->nodesetval->nodeNr != 0);
   14412         case XPATH_STRING:
   14413 	    return((res->stringval != NULL) &&
   14414 	           (xmlStrlen(res->stringval) != 0));
   14415         default:
   14416 	    STRANGE
   14417     }
   14418     return(0);
   14419 }
   14420 
   14421 /**
   14422  * xmlXPathEvaluatePredicateResult:
   14423  * @ctxt:  the XPath Parser context
   14424  * @res:  the Predicate Expression evaluation result
   14425  *
   14426  * Evaluate a predicate result for the current node.
   14427  * A PredicateExpr is evaluated by evaluating the Expr and converting
   14428  * the result to a boolean. If the result is a number, the result will
   14429  * be converted to true if the number is equal to the position of the
   14430  * context node in the context node list (as returned by the position
   14431  * function) and will be converted to false otherwise; if the result
   14432  * is not a number, then the result will be converted as if by a call
   14433  * to the boolean function.
   14434  *
   14435  * Returns 1 if predicate is true, 0 otherwise
   14436  */
   14437 int
   14438 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
   14439                                 xmlXPathObjectPtr res) {
   14440     if ((ctxt == NULL) || (res == NULL)) return(0);
   14441     switch (res->type) {
   14442         case XPATH_BOOLEAN:
   14443 	    return(res->boolval);
   14444         case XPATH_NUMBER:
   14445 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
   14446 	    return((res->floatval == ctxt->context->proximityPosition) &&
   14447 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
   14448 #else
   14449 	    return(res->floatval == ctxt->context->proximityPosition);
   14450 #endif
   14451         case XPATH_NODESET:
   14452         case XPATH_XSLT_TREE:
   14453 	    if (res->nodesetval == NULL)
   14454 		return(0);
   14455 	    return(res->nodesetval->nodeNr != 0);
   14456         case XPATH_STRING:
   14457 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
   14458 #ifdef LIBXML_XPTR_ENABLED
   14459 	case XPATH_LOCATIONSET:{
   14460 	    xmlLocationSetPtr ptr = res->user;
   14461 	    if (ptr == NULL)
   14462 	        return(0);
   14463 	    return (ptr->locNr != 0);
   14464 	    }
   14465 #endif
   14466         default:
   14467 	    STRANGE
   14468     }
   14469     return(0);
   14470 }
   14471 
   14472 #ifdef XPATH_STREAMING
   14473 /**
   14474  * xmlXPathTryStreamCompile:
   14475  * @ctxt: an XPath context
   14476  * @str:  the XPath expression
   14477  *
   14478  * Try to compile the XPath expression as a streamable subset.
   14479  *
   14480  * Returns the compiled expression or NULL if failed to compile.
   14481  */
   14482 static xmlXPathCompExprPtr
   14483 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
   14484     /*
   14485      * Optimization: use streaming patterns when the XPath expression can
   14486      * be compiled to a stream lookup
   14487      */
   14488     xmlPatternPtr stream;
   14489     xmlXPathCompExprPtr comp;
   14490     xmlDictPtr dict = NULL;
   14491     const xmlChar **namespaces = NULL;
   14492     xmlNsPtr ns;
   14493     int i, j;
   14494 
   14495     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
   14496         (!xmlStrchr(str, '@'))) {
   14497 	const xmlChar *tmp;
   14498 
   14499 	/*
   14500 	 * We don't try to handle expressions using the verbose axis
   14501 	 * specifiers ("::"), just the simplied form at this point.
   14502 	 * Additionally, if there is no list of namespaces available and
   14503 	 *  there's a ":" in the expression, indicating a prefixed QName,
   14504 	 *  then we won't try to compile either. xmlPatterncompile() needs
   14505 	 *  to have a list of namespaces at compilation time in order to
   14506 	 *  compile prefixed name tests.
   14507 	 */
   14508 	tmp = xmlStrchr(str, ':');
   14509 	if ((tmp != NULL) &&
   14510 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
   14511 	    return(NULL);
   14512 
   14513 	if (ctxt != NULL) {
   14514 	    dict = ctxt->dict;
   14515 	    if (ctxt->nsNr > 0) {
   14516 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
   14517 		if (namespaces == NULL) {
   14518 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
   14519 		    return(NULL);
   14520 		}
   14521 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
   14522 		    ns = ctxt->namespaces[j];
   14523 		    namespaces[i++] = ns->href;
   14524 		    namespaces[i++] = ns->prefix;
   14525 		}
   14526 		namespaces[i++] = NULL;
   14527 		namespaces[i] = NULL;
   14528 	    }
   14529 	}
   14530 
   14531 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
   14532 			&namespaces[0]);
   14533 	if (namespaces != NULL) {
   14534 	    xmlFree((xmlChar **)namespaces);
   14535 	}
   14536 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
   14537 	    comp = xmlXPathNewCompExpr();
   14538 	    if (comp == NULL) {
   14539 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
   14540 		return(NULL);
   14541 	    }
   14542 	    comp->stream = stream;
   14543 	    comp->dict = dict;
   14544 	    if (comp->dict)
   14545 		xmlDictReference(comp->dict);
   14546 	    return(comp);
   14547 	}
   14548 	xmlFreePattern(stream);
   14549     }
   14550     return(NULL);
   14551 }
   14552 #endif /* XPATH_STREAMING */
   14553 
   14554 static void
   14555 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
   14556 {
   14557     /*
   14558     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
   14559     * internal representation.
   14560     */
   14561 
   14562     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
   14563         (op->ch1 != -1) &&
   14564         (op->ch2 == -1 /* no predicate */))
   14565     {
   14566         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
   14567 
   14568         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
   14569             ((xmlXPathAxisVal) prevop->value ==
   14570                 AXIS_DESCENDANT_OR_SELF) &&
   14571             (prevop->ch2 == -1) &&
   14572             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
   14573             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
   14574         {
   14575             /*
   14576             * This is a "descendant-or-self::node()" without predicates.
   14577             * Try to eliminate it.
   14578             */
   14579 
   14580             switch ((xmlXPathAxisVal) op->value) {
   14581                 case AXIS_CHILD:
   14582                 case AXIS_DESCENDANT:
   14583                     /*
   14584                     * Convert "descendant-or-self::node()/child::" or
   14585                     * "descendant-or-self::node()/descendant::" to
   14586                     * "descendant::"
   14587                     */
   14588                     op->ch1   = prevop->ch1;
   14589                     op->value = AXIS_DESCENDANT;
   14590                     break;
   14591                 case AXIS_SELF:
   14592                 case AXIS_DESCENDANT_OR_SELF:
   14593                     /*
   14594                     * Convert "descendant-or-self::node()/self::" or
   14595                     * "descendant-or-self::node()/descendant-or-self::" to
   14596                     * to "descendant-or-self::"
   14597                     */
   14598                     op->ch1   = prevop->ch1;
   14599                     op->value = AXIS_DESCENDANT_OR_SELF;
   14600                     break;
   14601                 default:
   14602                     break;
   14603             }
   14604 	}
   14605     }
   14606 
   14607     /* OP_VALUE has invalid ch1. */
   14608     if (op->op == XPATH_OP_VALUE)
   14609         return;
   14610 
   14611     /* Recurse */
   14612     if (op->ch1 != -1)
   14613         xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
   14614     if (op->ch2 != -1)
   14615 	xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
   14616 }
   14617 
   14618 /**
   14619  * xmlXPathCtxtCompile:
   14620  * @ctxt: an XPath context
   14621  * @str:  the XPath expression
   14622  *
   14623  * Compile an XPath expression
   14624  *
   14625  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
   14626  *         the caller has to free the object.
   14627  */
   14628 xmlXPathCompExprPtr
   14629 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
   14630     xmlXPathParserContextPtr pctxt;
   14631     xmlXPathCompExprPtr comp;
   14632 
   14633 #ifdef XPATH_STREAMING
   14634     comp = xmlXPathTryStreamCompile(ctxt, str);
   14635     if (comp != NULL)
   14636         return(comp);
   14637 #endif
   14638 
   14639     xmlXPathInit();
   14640 
   14641     pctxt = xmlXPathNewParserContext(str, ctxt);
   14642     if (pctxt == NULL)
   14643         return NULL;
   14644     xmlXPathCompileExpr(pctxt, 1);
   14645 
   14646     if( pctxt->error != XPATH_EXPRESSION_OK )
   14647     {
   14648         xmlXPathFreeParserContext(pctxt);
   14649         return(NULL);
   14650     }
   14651 
   14652     if (*pctxt->cur != 0) {
   14653 	/*
   14654 	 * aleksey: in some cases this line prints *second* error message
   14655 	 * (see bug #78858) and probably this should be fixed.
   14656 	 * However, we are not sure that all error messages are printed
   14657 	 * out in other places. It's not critical so we leave it as-is for now
   14658 	 */
   14659 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
   14660 	comp = NULL;
   14661     } else {
   14662 	comp = pctxt->comp;
   14663 	pctxt->comp = NULL;
   14664     }
   14665     xmlXPathFreeParserContext(pctxt);
   14666 
   14667     if (comp != NULL) {
   14668 	comp->expr = xmlStrdup(str);
   14669 #ifdef DEBUG_EVAL_COUNTS
   14670 	comp->string = xmlStrdup(str);
   14671 	comp->nb = 0;
   14672 #endif
   14673 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
   14674 	    xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
   14675 	}
   14676     }
   14677     return(comp);
   14678 }
   14679 
   14680 /**
   14681  * xmlXPathCompile:
   14682  * @str:  the XPath expression
   14683  *
   14684  * Compile an XPath expression
   14685  *
   14686  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
   14687  *         the caller has to free the object.
   14688  */
   14689 xmlXPathCompExprPtr
   14690 xmlXPathCompile(const xmlChar *str) {
   14691     return(xmlXPathCtxtCompile(NULL, str));
   14692 }
   14693 
   14694 /**
   14695  * xmlXPathCompiledEvalInternal:
   14696  * @comp:  the compiled XPath expression
   14697  * @ctxt:  the XPath context
   14698  * @resObj: the resulting XPath object or NULL
   14699  * @toBool: 1 if only a boolean result is requested
   14700  *
   14701  * Evaluate the Precompiled XPath expression in the given context.
   14702  * The caller has to free @resObj.
   14703  *
   14704  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14705  *         the caller has to free the object.
   14706  */
   14707 static int
   14708 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
   14709 			     xmlXPathContextPtr ctxt,
   14710 			     xmlXPathObjectPtr *resObjPtr,
   14711 			     int toBool)
   14712 {
   14713     xmlXPathParserContextPtr pctxt;
   14714     xmlXPathObjectPtr resObj;
   14715 #ifndef LIBXML_THREAD_ENABLED
   14716     static int reentance = 0;
   14717 #endif
   14718     int res;
   14719 
   14720     CHECK_CTXT_NEG(ctxt)
   14721 
   14722     if (comp == NULL)
   14723 	return(-1);
   14724     xmlXPathInit();
   14725 
   14726 #ifndef LIBXML_THREAD_ENABLED
   14727     reentance++;
   14728     if (reentance > 1)
   14729 	xmlXPathDisableOptimizer = 1;
   14730 #endif
   14731 
   14732 #ifdef DEBUG_EVAL_COUNTS
   14733     comp->nb++;
   14734     if ((comp->string != NULL) && (comp->nb > 100)) {
   14735 	fprintf(stderr, "100 x %s\n", comp->string);
   14736 	comp->nb = 0;
   14737     }
   14738 #endif
   14739     pctxt = xmlXPathCompParserContext(comp, ctxt);
   14740     res = xmlXPathRunEval(pctxt, toBool);
   14741 
   14742     if (pctxt->error != XPATH_EXPRESSION_OK) {
   14743         resObj = NULL;
   14744     } else {
   14745         resObj = valuePop(pctxt);
   14746         if (resObj == NULL) {
   14747             if (!toBool)
   14748                 xmlGenericError(xmlGenericErrorContext,
   14749                     "xmlXPathCompiledEval: No result on the stack.\n");
   14750         } else if (pctxt->valueNr > 0) {
   14751             xmlGenericError(xmlGenericErrorContext,
   14752                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
   14753                 pctxt->valueNr);
   14754         }
   14755     }
   14756 
   14757     if (resObjPtr)
   14758         *resObjPtr = resObj;
   14759     else
   14760         xmlXPathReleaseObject(ctxt, resObj);
   14761 
   14762     pctxt->comp = NULL;
   14763     xmlXPathFreeParserContext(pctxt);
   14764 #ifndef LIBXML_THREAD_ENABLED
   14765     reentance--;
   14766 #endif
   14767 
   14768     return(res);
   14769 }
   14770 
   14771 /**
   14772  * xmlXPathCompiledEval:
   14773  * @comp:  the compiled XPath expression
   14774  * @ctx:  the XPath context
   14775  *
   14776  * Evaluate the Precompiled XPath expression in the given context.
   14777  *
   14778  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14779  *         the caller has to free the object.
   14780  */
   14781 xmlXPathObjectPtr
   14782 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
   14783 {
   14784     xmlXPathObjectPtr res = NULL;
   14785 
   14786     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
   14787     return(res);
   14788 }
   14789 
   14790 /**
   14791  * xmlXPathCompiledEvalToBoolean:
   14792  * @comp:  the compiled XPath expression
   14793  * @ctxt:  the XPath context
   14794  *
   14795  * Applies the XPath boolean() function on the result of the given
   14796  * compiled expression.
   14797  *
   14798  * Returns 1 if the expression evaluated to true, 0 if to false and
   14799  *         -1 in API and internal errors.
   14800  */
   14801 int
   14802 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
   14803 			      xmlXPathContextPtr ctxt)
   14804 {
   14805     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
   14806 }
   14807 
   14808 /**
   14809  * xmlXPathEvalExpr:
   14810  * @ctxt:  the XPath Parser context
   14811  *
   14812  * Parse and evaluate an XPath expression in the given context,
   14813  * then push the result on the context stack
   14814  */
   14815 void
   14816 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
   14817 #ifdef XPATH_STREAMING
   14818     xmlXPathCompExprPtr comp;
   14819 #endif
   14820 
   14821     if (ctxt == NULL) return;
   14822 
   14823 #ifdef XPATH_STREAMING
   14824     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
   14825     if (comp != NULL) {
   14826         if (ctxt->comp != NULL)
   14827 	    xmlXPathFreeCompExpr(ctxt->comp);
   14828         ctxt->comp = comp;
   14829     } else
   14830 #endif
   14831     {
   14832 	xmlXPathCompileExpr(ctxt, 1);
   14833         CHECK_ERROR;
   14834 
   14835         /* Check for trailing characters. */
   14836         if (*ctxt->cur != 0)
   14837             XP_ERROR(XPATH_EXPR_ERROR);
   14838 
   14839 	if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
   14840 	    xmlXPathOptimizeExpression(ctxt->comp,
   14841 		&ctxt->comp->steps[ctxt->comp->last]);
   14842     }
   14843 
   14844     xmlXPathRunEval(ctxt, 0);
   14845 }
   14846 
   14847 /**
   14848  * xmlXPathEval:
   14849  * @str:  the XPath expression
   14850  * @ctx:  the XPath context
   14851  *
   14852  * Evaluate the XPath Location Path in the given context.
   14853  *
   14854  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14855  *         the caller has to free the object.
   14856  */
   14857 xmlXPathObjectPtr
   14858 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
   14859     xmlXPathParserContextPtr ctxt;
   14860     xmlXPathObjectPtr res;
   14861 
   14862     CHECK_CTXT(ctx)
   14863 
   14864     xmlXPathInit();
   14865 
   14866     ctxt = xmlXPathNewParserContext(str, ctx);
   14867     if (ctxt == NULL)
   14868         return NULL;
   14869     xmlXPathEvalExpr(ctxt);
   14870 
   14871     if (ctxt->error != XPATH_EXPRESSION_OK) {
   14872 	res = NULL;
   14873     } else {
   14874 	res = valuePop(ctxt);
   14875         if (res == NULL) {
   14876             xmlGenericError(xmlGenericErrorContext,
   14877                 "xmlXPathCompiledEval: No result on the stack.\n");
   14878         } else if (ctxt->valueNr > 0) {
   14879             xmlGenericError(xmlGenericErrorContext,
   14880                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
   14881                 ctxt->valueNr);
   14882         }
   14883     }
   14884 
   14885     xmlXPathFreeParserContext(ctxt);
   14886     return(res);
   14887 }
   14888 
   14889 /**
   14890  * xmlXPathSetContextNode:
   14891  * @node: the node to to use as the context node
   14892  * @ctx:  the XPath context
   14893  *
   14894  * Sets 'node' as the context node. The node must be in the same
   14895  * document as that associated with the context.
   14896  *
   14897  * Returns -1 in case of error or 0 if successful
   14898  */
   14899 int
   14900 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
   14901     if ((node == NULL) || (ctx == NULL))
   14902         return(-1);
   14903 
   14904     if (node->doc == ctx->doc) {
   14905         ctx->node = node;
   14906 	return(0);
   14907     }
   14908     return(-1);
   14909 }
   14910 
   14911 /**
   14912  * xmlXPathNodeEval:
   14913  * @node: the node to to use as the context node
   14914  * @str:  the XPath expression
   14915  * @ctx:  the XPath context
   14916  *
   14917  * Evaluate the XPath Location Path in the given context. The node 'node'
   14918  * is set as the context node. The context node is not restored.
   14919  *
   14920  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14921  *         the caller has to free the object.
   14922  */
   14923 xmlXPathObjectPtr
   14924 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
   14925     if (str == NULL)
   14926         return(NULL);
   14927     if (xmlXPathSetContextNode(node, ctx) < 0)
   14928         return(NULL);
   14929     return(xmlXPathEval(str, ctx));
   14930 }
   14931 
   14932 /**
   14933  * xmlXPathEvalExpression:
   14934  * @str:  the XPath expression
   14935  * @ctxt:  the XPath context
   14936  *
   14937  * Alias for xmlXPathEval().
   14938  *
   14939  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
   14940  *         the caller has to free the object.
   14941  */
   14942 xmlXPathObjectPtr
   14943 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
   14944     return(xmlXPathEval(str, ctxt));
   14945 }
   14946 
   14947 /************************************************************************
   14948  *									*
   14949  *	Extra functions not pertaining to the XPath spec		*
   14950  *									*
   14951  ************************************************************************/
   14952 /**
   14953  * xmlXPathEscapeUriFunction:
   14954  * @ctxt:  the XPath Parser context
   14955  * @nargs:  the number of arguments
   14956  *
   14957  * Implement the escape-uri() XPath function
   14958  *    string escape-uri(string $str, bool $escape-reserved)
   14959  *
   14960  * This function applies the URI escaping rules defined in section 2 of [RFC
   14961  * 2396] to the string supplied as $uri-part, which typically represents all
   14962  * or part of a URI. The effect of the function is to replace any special
   14963  * character in the string by an escape sequence of the form %xx%yy...,
   14964  * where xxyy... is the hexadecimal representation of the octets used to
   14965  * represent the character in UTF-8.
   14966  *
   14967  * The set of characters that are escaped depends on the setting of the
   14968  * boolean argument $escape-reserved.
   14969  *
   14970  * If $escape-reserved is true, all characters are escaped other than lower
   14971  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
   14972  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
   14973  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
   14974  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
   14975  * A-F).
   14976  *
   14977  * If $escape-reserved is false, the behavior differs in that characters
   14978  * referred to in [RFC 2396] as reserved characters are not escaped. These
   14979  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
   14980  *
   14981  * [RFC 2396] does not define whether escaped URIs should use lower case or
   14982  * upper case for hexadecimal digits. To ensure that escaped URIs can be
   14983  * compared using string comparison functions, this function must always use
   14984  * the upper-case letters A-F.
   14985  *
   14986  * Generally, $escape-reserved should be set to true when escaping a string
   14987  * that is to form a single part of a URI, and to false when escaping an
   14988  * entire URI or URI reference.
   14989  *
   14990  * In the case of non-ascii characters, the string is encoded according to
   14991  * utf-8 and then converted according to RFC 2396.
   14992  *
   14993  * Examples
   14994  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
   14995  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
   14996  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
   14997  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
   14998  *
   14999  */
   15000 static void
   15001 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
   15002     xmlXPathObjectPtr str;
   15003     int escape_reserved;
   15004     xmlBufPtr target;
   15005     xmlChar *cptr;
   15006     xmlChar escape[4];
   15007 
   15008     CHECK_ARITY(2);
   15009 
   15010     escape_reserved = xmlXPathPopBoolean(ctxt);
   15011 
   15012     CAST_TO_STRING;
   15013     str = valuePop(ctxt);
   15014 
   15015     target = xmlBufCreate();
   15016 
   15017     escape[0] = '%';
   15018     escape[3] = 0;
   15019 
   15020     if (target) {
   15021 	for (cptr = str->stringval; *cptr; cptr++) {
   15022 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
   15023 		(*cptr >= 'a' && *cptr <= 'z') ||
   15024 		(*cptr >= '0' && *cptr <= '9') ||
   15025 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
   15026 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
   15027 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
   15028 		(*cptr == '%' &&
   15029 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
   15030 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
   15031 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
   15032 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
   15033 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
   15034 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
   15035 		(!escape_reserved &&
   15036 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
   15037 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
   15038 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
   15039 		  *cptr == ','))) {
   15040 		xmlBufAdd(target, cptr, 1);
   15041 	    } else {
   15042 		if ((*cptr >> 4) < 10)
   15043 		    escape[1] = '0' + (*cptr >> 4);
   15044 		else
   15045 		    escape[1] = 'A' - 10 + (*cptr >> 4);
   15046 		if ((*cptr & 0xF) < 10)
   15047 		    escape[2] = '0' + (*cptr & 0xF);
   15048 		else
   15049 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
   15050 
   15051 		xmlBufAdd(target, &escape[0], 3);
   15052 	    }
   15053 	}
   15054     }
   15055     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
   15056 	xmlBufContent(target)));
   15057     xmlBufFree(target);
   15058     xmlXPathReleaseObject(ctxt->context, str);
   15059 }
   15060 
   15061 /**
   15062  * xmlXPathRegisterAllFunctions:
   15063  * @ctxt:  the XPath context
   15064  *
   15065  * Registers all default XPath functions in this context
   15066  */
   15067 void
   15068 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
   15069 {
   15070     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
   15071                          xmlXPathBooleanFunction);
   15072     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
   15073                          xmlXPathCeilingFunction);
   15074     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
   15075                          xmlXPathCountFunction);
   15076     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
   15077                          xmlXPathConcatFunction);
   15078     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
   15079                          xmlXPathContainsFunction);
   15080     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
   15081                          xmlXPathIdFunction);
   15082     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
   15083                          xmlXPathFalseFunction);
   15084     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
   15085                          xmlXPathFloorFunction);
   15086     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
   15087                          xmlXPathLastFunction);
   15088     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
   15089                          xmlXPathLangFunction);
   15090     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
   15091                          xmlXPathLocalNameFunction);
   15092     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
   15093                          xmlXPathNotFunction);
   15094     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
   15095                          xmlXPathNameFunction);
   15096     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
   15097                          xmlXPathNamespaceURIFunction);
   15098     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
   15099                          xmlXPathNormalizeFunction);
   15100     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
   15101                          xmlXPathNumberFunction);
   15102     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
   15103                          xmlXPathPositionFunction);
   15104     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
   15105                          xmlXPathRoundFunction);
   15106     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
   15107                          xmlXPathStringFunction);
   15108     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
   15109                          xmlXPathStringLengthFunction);
   15110     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
   15111                          xmlXPathStartsWithFunction);
   15112     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
   15113                          xmlXPathSubstringFunction);
   15114     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
   15115                          xmlXPathSubstringBeforeFunction);
   15116     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
   15117                          xmlXPathSubstringAfterFunction);
   15118     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
   15119                          xmlXPathSumFunction);
   15120     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
   15121                          xmlXPathTrueFunction);
   15122     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
   15123                          xmlXPathTranslateFunction);
   15124 
   15125     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
   15126 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
   15127                          xmlXPathEscapeUriFunction);
   15128 }
   15129 
   15130 #endif /* LIBXML_XPATH_ENABLED */
   15131 #define bottom_xpath
   15132 #include "elfgcchack.h"
   15133