xref: /reactos/sdk/lib/3rdparty/libxml2/xpath.c (revision 682f85ad)
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@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 available.
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 available.
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 algorithm 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     "Operation limit exceeded\n",
614     "Recursion limit exceeded\n",
615     "?? Unknown error ??\n"	/* Must be last in the list! */
616 };
617 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
618 		   sizeof(xmlXPathErrorMessages[0])) - 1)
619 /**
620  * xmlXPathErrMemory:
621  * @ctxt:  an XPath context
622  * @extra:  extra informations
623  *
624  * Handle a redefinition of attribute error
625  */
626 static void
627 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
628 {
629     if (ctxt != NULL) {
630         xmlResetError(&ctxt->lastError);
631         if (extra) {
632             xmlChar buf[200];
633 
634             xmlStrPrintf(buf, 200,
635                          "Memory allocation failed : %s\n",
636                          extra);
637             ctxt->lastError.message = (char *) xmlStrdup(buf);
638         } else {
639             ctxt->lastError.message = (char *)
640 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
641         }
642         ctxt->lastError.domain = XML_FROM_XPATH;
643         ctxt->lastError.code = XML_ERR_NO_MEMORY;
644 	if (ctxt->error != NULL)
645 	    ctxt->error(ctxt->userData, &ctxt->lastError);
646     } else {
647         if (extra)
648             __xmlRaiseError(NULL, NULL, NULL,
649                             NULL, NULL, XML_FROM_XPATH,
650                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
651                             extra, NULL, NULL, 0, 0,
652                             "Memory allocation failed : %s\n", extra);
653         else
654             __xmlRaiseError(NULL, NULL, NULL,
655                             NULL, NULL, XML_FROM_XPATH,
656                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
657                             NULL, NULL, NULL, 0, 0,
658                             "Memory allocation failed\n");
659     }
660 }
661 
662 /**
663  * xmlXPathPErrMemory:
664  * @ctxt:  an XPath parser context
665  * @extra:  extra informations
666  *
667  * Handle a redefinition of attribute error
668  */
669 static void
670 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
671 {
672     if (ctxt == NULL)
673 	xmlXPathErrMemory(NULL, extra);
674     else {
675 	ctxt->error = XPATH_MEMORY_ERROR;
676 	xmlXPathErrMemory(ctxt->context, extra);
677     }
678 }
679 
680 /**
681  * xmlXPathErr:
682  * @ctxt:  a XPath parser context
683  * @error:  the error code
684  *
685  * Handle an XPath error
686  */
687 void
688 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
689 {
690     if ((error < 0) || (error > MAXERRNO))
691 	error = MAXERRNO;
692     if (ctxt == NULL) {
693 	__xmlRaiseError(NULL, NULL, NULL,
694 			NULL, NULL, XML_FROM_XPATH,
695 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
696 			XML_ERR_ERROR, NULL, 0,
697 			NULL, NULL, NULL, 0, 0,
698 			"%s", xmlXPathErrorMessages[error]);
699 	return;
700     }
701     ctxt->error = error;
702     if (ctxt->context == NULL) {
703 	__xmlRaiseError(NULL, NULL, NULL,
704 			NULL, NULL, XML_FROM_XPATH,
705 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
706 			XML_ERR_ERROR, NULL, 0,
707 			(const char *) ctxt->base, NULL, NULL,
708 			ctxt->cur - ctxt->base, 0,
709 			"%s", xmlXPathErrorMessages[error]);
710 	return;
711     }
712 
713     /* cleanup current last error */
714     xmlResetError(&ctxt->context->lastError);
715 
716     ctxt->context->lastError.domain = XML_FROM_XPATH;
717     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
718                            XPATH_EXPRESSION_OK;
719     ctxt->context->lastError.level = XML_ERR_ERROR;
720     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
721     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
722     ctxt->context->lastError.node = ctxt->context->debugNode;
723     if (ctxt->context->error != NULL) {
724 	ctxt->context->error(ctxt->context->userData,
725 	                     &ctxt->context->lastError);
726     } else {
727 	__xmlRaiseError(NULL, NULL, NULL,
728 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
729 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
730 			XML_ERR_ERROR, NULL, 0,
731 			(const char *) ctxt->base, NULL, NULL,
732 			ctxt->cur - ctxt->base, 0,
733 			"%s", xmlXPathErrorMessages[error]);
734     }
735 
736 }
737 
738 /**
739  * xmlXPatherror:
740  * @ctxt:  the XPath Parser context
741  * @file:  the file name
742  * @line:  the line number
743  * @no:  the error number
744  *
745  * Formats an error message.
746  */
747 void
748 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
749               int line ATTRIBUTE_UNUSED, int no) {
750     xmlXPathErr(ctxt, no);
751 }
752 
753 /**
754  * xmlXPathCheckOpLimit:
755  * @ctxt:  the XPath Parser context
756  * @opCount:  the number of operations to be added
757  *
758  * Adds opCount to the running total of operations and returns -1 if the
759  * operation limit is exceeded. Returns 0 otherwise.
760  */
761 static int
762 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
763     xmlXPathContextPtr xpctxt = ctxt->context;
764 
765     if ((opCount > xpctxt->opLimit) ||
766         (xpctxt->opCount > xpctxt->opLimit - opCount)) {
767         xpctxt->opCount = xpctxt->opLimit;
768         xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
769         return(-1);
770     }
771 
772     xpctxt->opCount += opCount;
773     return(0);
774 }
775 
776 #define OP_LIMIT_EXCEEDED(ctxt, n) \
777     ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
778 
779 /************************************************************************
780  *									*
781  *			Utilities					*
782  *									*
783  ************************************************************************/
784 
785 /**
786  * xsltPointerList:
787  *
788  * Pointer-list for various purposes.
789  */
790 typedef struct _xmlPointerList xmlPointerList;
791 typedef xmlPointerList *xmlPointerListPtr;
792 struct _xmlPointerList {
793     void **items;
794     int number;
795     int size;
796 };
797 /*
798 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
799 * and here, we should make the functions public.
800 */
801 static int
802 xmlPointerListAddSize(xmlPointerListPtr list,
803 		       void *item,
804 		       int initialSize)
805 {
806     if (list->items == NULL) {
807 	if (initialSize <= 0)
808 	    initialSize = 1;
809 	list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
810 	if (list->items == NULL) {
811 	    xmlXPathErrMemory(NULL,
812 		"xmlPointerListCreate: allocating item\n");
813 	    return(-1);
814 	}
815 	list->number = 0;
816 	list->size = initialSize;
817     } else if (list->size <= list->number) {
818         if (list->size > 50000000) {
819 	    xmlXPathErrMemory(NULL,
820 		"xmlPointerListAddSize: re-allocating item\n");
821             return(-1);
822         }
823 	list->size *= 2;
824 	list->items = (void **) xmlRealloc(list->items,
825 	    list->size * sizeof(void *));
826 	if (list->items == NULL) {
827 	    xmlXPathErrMemory(NULL,
828 		"xmlPointerListAddSize: re-allocating item\n");
829 	    list->size = 0;
830 	    return(-1);
831 	}
832     }
833     list->items[list->number++] = item;
834     return(0);
835 }
836 
837 /**
838  * xsltPointerListCreate:
839  *
840  * Creates an xsltPointerList structure.
841  *
842  * Returns a xsltPointerList structure or NULL in case of an error.
843  */
844 static xmlPointerListPtr
845 xmlPointerListCreate(int initialSize)
846 {
847     xmlPointerListPtr ret;
848 
849     ret = xmlMalloc(sizeof(xmlPointerList));
850     if (ret == NULL) {
851 	xmlXPathErrMemory(NULL,
852 	    "xmlPointerListCreate: allocating item\n");
853 	return (NULL);
854     }
855     memset(ret, 0, sizeof(xmlPointerList));
856     if (initialSize > 0) {
857 	xmlPointerListAddSize(ret, NULL, initialSize);
858 	ret->number = 0;
859     }
860     return (ret);
861 }
862 
863 /**
864  * xsltPointerListFree:
865  *
866  * Frees the xsltPointerList structure. This does not free
867  * the content of the list.
868  */
869 static void
870 xmlPointerListFree(xmlPointerListPtr list)
871 {
872     if (list == NULL)
873 	return;
874     if (list->items != NULL)
875 	xmlFree(list->items);
876     xmlFree(list);
877 }
878 
879 /************************************************************************
880  *									*
881  *			Parser Types					*
882  *									*
883  ************************************************************************/
884 
885 /*
886  * Types are private:
887  */
888 
889 typedef enum {
890     XPATH_OP_END=0,
891     XPATH_OP_AND,
892     XPATH_OP_OR,
893     XPATH_OP_EQUAL,
894     XPATH_OP_CMP,
895     XPATH_OP_PLUS,
896     XPATH_OP_MULT,
897     XPATH_OP_UNION,
898     XPATH_OP_ROOT,
899     XPATH_OP_NODE,
900     XPATH_OP_COLLECT,
901     XPATH_OP_VALUE, /* 11 */
902     XPATH_OP_VARIABLE,
903     XPATH_OP_FUNCTION,
904     XPATH_OP_ARG,
905     XPATH_OP_PREDICATE,
906     XPATH_OP_FILTER, /* 16 */
907     XPATH_OP_SORT /* 17 */
908 #ifdef LIBXML_XPTR_ENABLED
909     ,XPATH_OP_RANGETO
910 #endif
911 } xmlXPathOp;
912 
913 typedef enum {
914     AXIS_ANCESTOR = 1,
915     AXIS_ANCESTOR_OR_SELF,
916     AXIS_ATTRIBUTE,
917     AXIS_CHILD,
918     AXIS_DESCENDANT,
919     AXIS_DESCENDANT_OR_SELF,
920     AXIS_FOLLOWING,
921     AXIS_FOLLOWING_SIBLING,
922     AXIS_NAMESPACE,
923     AXIS_PARENT,
924     AXIS_PRECEDING,
925     AXIS_PRECEDING_SIBLING,
926     AXIS_SELF
927 } xmlXPathAxisVal;
928 
929 typedef enum {
930     NODE_TEST_NONE = 0,
931     NODE_TEST_TYPE = 1,
932     NODE_TEST_PI = 2,
933     NODE_TEST_ALL = 3,
934     NODE_TEST_NS = 4,
935     NODE_TEST_NAME = 5
936 } xmlXPathTestVal;
937 
938 typedef enum {
939     NODE_TYPE_NODE = 0,
940     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
941     NODE_TYPE_TEXT = XML_TEXT_NODE,
942     NODE_TYPE_PI = XML_PI_NODE
943 } xmlXPathTypeVal;
944 
945 typedef struct _xmlXPathStepOp xmlXPathStepOp;
946 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
947 struct _xmlXPathStepOp {
948     xmlXPathOp op;		/* The identifier of the operation */
949     int ch1;			/* First child */
950     int ch2;			/* Second child */
951     int value;
952     int value2;
953     int value3;
954     void *value4;
955     void *value5;
956     xmlXPathFunction cache;
957     void *cacheURI;
958 };
959 
960 struct _xmlXPathCompExpr {
961     int nbStep;			/* Number of steps in this expression */
962     int maxStep;		/* Maximum number of steps allocated */
963     xmlXPathStepOp *steps;	/* ops for computation of this expression */
964     int last;			/* index of last step in expression */
965     xmlChar *expr;		/* the expression being computed */
966     xmlDictPtr dict;		/* the dictionary to use if any */
967 #ifdef DEBUG_EVAL_COUNTS
968     int nb;
969     xmlChar *string;
970 #endif
971 #ifdef XPATH_STREAMING
972     xmlPatternPtr stream;
973 #endif
974 };
975 
976 /************************************************************************
977  *									*
978  *			Forward declarations				*
979  *									*
980  ************************************************************************/
981 static void
982 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
983 static void
984 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
985 static int
986 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
987                         xmlXPathStepOpPtr op, xmlNodePtr *first);
988 static int
989 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
990 			    xmlXPathStepOpPtr op,
991 			    int isPredicate);
992 static void
993 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
994 
995 /************************************************************************
996  *									*
997  *			Parser Type functions				*
998  *									*
999  ************************************************************************/
1000 
1001 /**
1002  * xmlXPathNewCompExpr:
1003  *
1004  * Create a new Xpath component
1005  *
1006  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1007  */
1008 static xmlXPathCompExprPtr
1009 xmlXPathNewCompExpr(void) {
1010     xmlXPathCompExprPtr cur;
1011 
1012     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1013     if (cur == NULL) {
1014         xmlXPathErrMemory(NULL, "allocating component\n");
1015 	return(NULL);
1016     }
1017     memset(cur, 0, sizeof(xmlXPathCompExpr));
1018     cur->maxStep = 10;
1019     cur->nbStep = 0;
1020     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1021 	                                   sizeof(xmlXPathStepOp));
1022     if (cur->steps == NULL) {
1023         xmlXPathErrMemory(NULL, "allocating steps\n");
1024 	xmlFree(cur);
1025 	return(NULL);
1026     }
1027     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1028     cur->last = -1;
1029 #ifdef DEBUG_EVAL_COUNTS
1030     cur->nb = 0;
1031 #endif
1032     return(cur);
1033 }
1034 
1035 /**
1036  * xmlXPathFreeCompExpr:
1037  * @comp:  an XPATH comp
1038  *
1039  * Free up the memory allocated by @comp
1040  */
1041 void
1042 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1043 {
1044     xmlXPathStepOpPtr op;
1045     int i;
1046 
1047     if (comp == NULL)
1048         return;
1049     if (comp->dict == NULL) {
1050 	for (i = 0; i < comp->nbStep; i++) {
1051 	    op = &comp->steps[i];
1052 	    if (op->value4 != NULL) {
1053 		if (op->op == XPATH_OP_VALUE)
1054 		    xmlXPathFreeObject(op->value4);
1055 		else
1056 		    xmlFree(op->value4);
1057 	    }
1058 	    if (op->value5 != NULL)
1059 		xmlFree(op->value5);
1060 	}
1061     } else {
1062 	for (i = 0; i < comp->nbStep; i++) {
1063 	    op = &comp->steps[i];
1064 	    if (op->value4 != NULL) {
1065 		if (op->op == XPATH_OP_VALUE)
1066 		    xmlXPathFreeObject(op->value4);
1067 	    }
1068 	}
1069         xmlDictFree(comp->dict);
1070     }
1071     if (comp->steps != NULL) {
1072         xmlFree(comp->steps);
1073     }
1074 #ifdef DEBUG_EVAL_COUNTS
1075     if (comp->string != NULL) {
1076         xmlFree(comp->string);
1077     }
1078 #endif
1079 #ifdef XPATH_STREAMING
1080     if (comp->stream != NULL) {
1081         xmlFreePatternList(comp->stream);
1082     }
1083 #endif
1084     if (comp->expr != NULL) {
1085         xmlFree(comp->expr);
1086     }
1087 
1088     xmlFree(comp);
1089 }
1090 
1091 /**
1092  * xmlXPathCompExprAdd:
1093  * @comp:  the compiled expression
1094  * @ch1: first child index
1095  * @ch2: second child index
1096  * @op:  an op
1097  * @value:  the first int value
1098  * @value2:  the second int value
1099  * @value3:  the third int value
1100  * @value4:  the first string value
1101  * @value5:  the second string value
1102  *
1103  * Add a step to an XPath Compiled Expression
1104  *
1105  * Returns -1 in case of failure, the index otherwise
1106  */
1107 static int
1108 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1109    xmlXPathOp op, int value,
1110    int value2, int value3, void *value4, void *value5) {
1111     xmlXPathCompExprPtr comp = ctxt->comp;
1112     if (comp->nbStep >= comp->maxStep) {
1113 	xmlXPathStepOp *real;
1114 
1115         if (comp->maxStep >= XPATH_MAX_STEPS) {
1116 	    xmlXPathPErrMemory(ctxt, "adding step\n");
1117 	    return(-1);
1118         }
1119 	comp->maxStep *= 2;
1120 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1121 		                      comp->maxStep * sizeof(xmlXPathStepOp));
1122 	if (real == NULL) {
1123 	    comp->maxStep /= 2;
1124 	    xmlXPathPErrMemory(ctxt, "adding step\n");
1125 	    return(-1);
1126 	}
1127 	comp->steps = real;
1128     }
1129     comp->last = comp->nbStep;
1130     comp->steps[comp->nbStep].ch1 = ch1;
1131     comp->steps[comp->nbStep].ch2 = ch2;
1132     comp->steps[comp->nbStep].op = op;
1133     comp->steps[comp->nbStep].value = value;
1134     comp->steps[comp->nbStep].value2 = value2;
1135     comp->steps[comp->nbStep].value3 = value3;
1136     if ((comp->dict != NULL) &&
1137         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1138 	 (op == XPATH_OP_COLLECT))) {
1139         if (value4 != NULL) {
1140 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
1141 	        (void *)xmlDictLookup(comp->dict, value4, -1);
1142 	    xmlFree(value4);
1143 	} else
1144 	    comp->steps[comp->nbStep].value4 = NULL;
1145         if (value5 != NULL) {
1146 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
1147 	        (void *)xmlDictLookup(comp->dict, value5, -1);
1148 	    xmlFree(value5);
1149 	} else
1150 	    comp->steps[comp->nbStep].value5 = NULL;
1151     } else {
1152 	comp->steps[comp->nbStep].value4 = value4;
1153 	comp->steps[comp->nbStep].value5 = value5;
1154     }
1155     comp->steps[comp->nbStep].cache = NULL;
1156     return(comp->nbStep++);
1157 }
1158 
1159 /**
1160  * xmlXPathCompSwap:
1161  * @comp:  the compiled expression
1162  * @op: operation index
1163  *
1164  * Swaps 2 operations in the compiled expression
1165  */
1166 static void
1167 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1168     int tmp;
1169 
1170 #ifndef LIBXML_THREAD_ENABLED
1171     /*
1172      * Since this manipulates possibly shared variables, this is
1173      * disabled if one detects that the library is used in a multithreaded
1174      * application
1175      */
1176     if (xmlXPathDisableOptimizer)
1177 	return;
1178 #endif
1179 
1180     tmp = op->ch1;
1181     op->ch1 = op->ch2;
1182     op->ch2 = tmp;
1183 }
1184 
1185 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
1186     xmlXPathCompExprAdd(ctxt, (op1), (op2),			\
1187 	                (op), (val), (val2), (val3), (val4), (val5))
1188 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
1189     xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,		\
1190 	                (op), (val), (val2), (val3), (val4), (val5))
1191 
1192 #define PUSH_LEAVE_EXPR(op, val, val2)					\
1193 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1194 
1195 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
1196 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1197 
1198 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
1199 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),			\
1200 			(val), (val2), 0 ,NULL ,NULL)
1201 
1202 /************************************************************************
1203  *									*
1204  *		XPath object cache structures				*
1205  *									*
1206  ************************************************************************/
1207 
1208 /* #define XP_DEFAULT_CACHE_ON */
1209 
1210 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1211 
1212 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1213 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1214 struct _xmlXPathContextCache {
1215     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1216     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1217     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1218     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1219     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1220     int maxNodeset;
1221     int maxString;
1222     int maxBoolean;
1223     int maxNumber;
1224     int maxMisc;
1225 #ifdef XP_DEBUG_OBJ_USAGE
1226     int dbgCachedAll;
1227     int dbgCachedNodeset;
1228     int dbgCachedString;
1229     int dbgCachedBool;
1230     int dbgCachedNumber;
1231     int dbgCachedPoint;
1232     int dbgCachedRange;
1233     int dbgCachedLocset;
1234     int dbgCachedUsers;
1235     int dbgCachedXSLTTree;
1236     int dbgCachedUndefined;
1237 
1238 
1239     int dbgReusedAll;
1240     int dbgReusedNodeset;
1241     int dbgReusedString;
1242     int dbgReusedBool;
1243     int dbgReusedNumber;
1244     int dbgReusedPoint;
1245     int dbgReusedRange;
1246     int dbgReusedLocset;
1247     int dbgReusedUsers;
1248     int dbgReusedXSLTTree;
1249     int dbgReusedUndefined;
1250 
1251 #endif
1252 };
1253 
1254 /************************************************************************
1255  *									*
1256  *		Debugging related functions				*
1257  *									*
1258  ************************************************************************/
1259 
1260 #define STRANGE							\
1261     xmlGenericError(xmlGenericErrorContext,				\
1262 	    "Internal error at %s:%d\n",				\
1263             __FILE__, __LINE__);
1264 
1265 #ifdef LIBXML_DEBUG_ENABLED
1266 static void
1267 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1268     int i;
1269     char shift[100];
1270 
1271     for (i = 0;((i < depth) && (i < 25));i++)
1272         shift[2 * i] = shift[2 * i + 1] = ' ';
1273     shift[2 * i] = shift[2 * i + 1] = 0;
1274     if (cur == NULL) {
1275 	fprintf(output, "%s", shift);
1276 	fprintf(output, "Node is NULL !\n");
1277 	return;
1278 
1279     }
1280 
1281     if ((cur->type == XML_DOCUMENT_NODE) ||
1282 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
1283 	fprintf(output, "%s", shift);
1284 	fprintf(output, " /\n");
1285     } else if (cur->type == XML_ATTRIBUTE_NODE)
1286 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1287     else
1288 	xmlDebugDumpOneNode(output, cur, depth);
1289 }
1290 static void
1291 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1292     xmlNodePtr tmp;
1293     int i;
1294     char shift[100];
1295 
1296     for (i = 0;((i < depth) && (i < 25));i++)
1297         shift[2 * i] = shift[2 * i + 1] = ' ';
1298     shift[2 * i] = shift[2 * i + 1] = 0;
1299     if (cur == NULL) {
1300 	fprintf(output, "%s", shift);
1301 	fprintf(output, "Node is NULL !\n");
1302 	return;
1303 
1304     }
1305 
1306     while (cur != NULL) {
1307 	tmp = cur;
1308 	cur = cur->next;
1309 	xmlDebugDumpOneNode(output, tmp, depth);
1310     }
1311 }
1312 
1313 static void
1314 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1315     int i;
1316     char shift[100];
1317 
1318     for (i = 0;((i < depth) && (i < 25));i++)
1319         shift[2 * i] = shift[2 * i + 1] = ' ';
1320     shift[2 * i] = shift[2 * i + 1] = 0;
1321 
1322     if (cur == NULL) {
1323 	fprintf(output, "%s", shift);
1324 	fprintf(output, "NodeSet is NULL !\n");
1325 	return;
1326 
1327     }
1328 
1329     if (cur != NULL) {
1330 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1331 	for (i = 0;i < cur->nodeNr;i++) {
1332 	    fprintf(output, "%s", shift);
1333 	    fprintf(output, "%d", i + 1);
1334 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1335 	}
1336     }
1337 }
1338 
1339 static void
1340 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1341     int i;
1342     char shift[100];
1343 
1344     for (i = 0;((i < depth) && (i < 25));i++)
1345         shift[2 * i] = shift[2 * i + 1] = ' ';
1346     shift[2 * i] = shift[2 * i + 1] = 0;
1347 
1348     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1349 	fprintf(output, "%s", shift);
1350 	fprintf(output, "Value Tree is NULL !\n");
1351 	return;
1352 
1353     }
1354 
1355     fprintf(output, "%s", shift);
1356     fprintf(output, "%d", i + 1);
1357     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1358 }
1359 #if defined(LIBXML_XPTR_ENABLED)
1360 static void
1361 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1362     int i;
1363     char shift[100];
1364 
1365     for (i = 0;((i < depth) && (i < 25));i++)
1366         shift[2 * i] = shift[2 * i + 1] = ' ';
1367     shift[2 * i] = shift[2 * i + 1] = 0;
1368 
1369     if (cur == NULL) {
1370 	fprintf(output, "%s", shift);
1371 	fprintf(output, "LocationSet is NULL !\n");
1372 	return;
1373 
1374     }
1375 
1376     for (i = 0;i < cur->locNr;i++) {
1377 	fprintf(output, "%s", shift);
1378         fprintf(output, "%d : ", i + 1);
1379 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1380     }
1381 }
1382 #endif /* LIBXML_XPTR_ENABLED */
1383 
1384 /**
1385  * xmlXPathDebugDumpObject:
1386  * @output:  the FILE * to dump the output
1387  * @cur:  the object to inspect
1388  * @depth:  indentation level
1389  *
1390  * Dump the content of the object for debugging purposes
1391  */
1392 void
1393 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1394     int i;
1395     char shift[100];
1396 
1397     if (output == NULL) return;
1398 
1399     for (i = 0;((i < depth) && (i < 25));i++)
1400         shift[2 * i] = shift[2 * i + 1] = ' ';
1401     shift[2 * i] = shift[2 * i + 1] = 0;
1402 
1403 
1404     fprintf(output, "%s", shift);
1405 
1406     if (cur == NULL) {
1407         fprintf(output, "Object is empty (NULL)\n");
1408 	return;
1409     }
1410     switch(cur->type) {
1411         case XPATH_UNDEFINED:
1412 	    fprintf(output, "Object is uninitialized\n");
1413 	    break;
1414         case XPATH_NODESET:
1415 	    fprintf(output, "Object is a Node Set :\n");
1416 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1417 	    break;
1418 	case XPATH_XSLT_TREE:
1419 	    fprintf(output, "Object is an XSLT value tree :\n");
1420 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1421 	    break;
1422         case XPATH_BOOLEAN:
1423 	    fprintf(output, "Object is a Boolean : ");
1424 	    if (cur->boolval) fprintf(output, "true\n");
1425 	    else fprintf(output, "false\n");
1426 	    break;
1427         case XPATH_NUMBER:
1428 	    switch (xmlXPathIsInf(cur->floatval)) {
1429 	    case 1:
1430 		fprintf(output, "Object is a number : Infinity\n");
1431 		break;
1432 	    case -1:
1433 		fprintf(output, "Object is a number : -Infinity\n");
1434 		break;
1435 	    default:
1436 		if (xmlXPathIsNaN(cur->floatval)) {
1437 		    fprintf(output, "Object is a number : NaN\n");
1438 		} else if (cur->floatval == 0) {
1439                     /* Omit sign for negative zero. */
1440 		    fprintf(output, "Object is a number : 0\n");
1441 		} else {
1442 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1443 		}
1444 	    }
1445 	    break;
1446         case XPATH_STRING:
1447 	    fprintf(output, "Object is a string : ");
1448 	    xmlDebugDumpString(output, cur->stringval);
1449 	    fprintf(output, "\n");
1450 	    break;
1451 	case XPATH_POINT:
1452 	    fprintf(output, "Object is a point : index %d in node", cur->index);
1453 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1454 	    fprintf(output, "\n");
1455 	    break;
1456 	case XPATH_RANGE:
1457 	    if ((cur->user2 == NULL) ||
1458 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1459 		fprintf(output, "Object is a collapsed range :\n");
1460 		fprintf(output, "%s", shift);
1461 		if (cur->index >= 0)
1462 		    fprintf(output, "index %d in ", cur->index);
1463 		fprintf(output, "node\n");
1464 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1465 			              depth + 1);
1466 	    } else  {
1467 		fprintf(output, "Object is a range :\n");
1468 		fprintf(output, "%s", shift);
1469 		fprintf(output, "From ");
1470 		if (cur->index >= 0)
1471 		    fprintf(output, "index %d in ", cur->index);
1472 		fprintf(output, "node\n");
1473 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1474 			              depth + 1);
1475 		fprintf(output, "%s", shift);
1476 		fprintf(output, "To ");
1477 		if (cur->index2 >= 0)
1478 		    fprintf(output, "index %d in ", cur->index2);
1479 		fprintf(output, "node\n");
1480 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1481 			              depth + 1);
1482 		fprintf(output, "\n");
1483 	    }
1484 	    break;
1485 	case XPATH_LOCATIONSET:
1486 #if defined(LIBXML_XPTR_ENABLED)
1487 	    fprintf(output, "Object is a Location Set:\n");
1488 	    xmlXPathDebugDumpLocationSet(output,
1489 		    (xmlLocationSetPtr) cur->user, depth);
1490 #endif
1491 	    break;
1492 	case XPATH_USERS:
1493 	    fprintf(output, "Object is user defined\n");
1494 	    break;
1495     }
1496 }
1497 
1498 static void
1499 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1500 	                     xmlXPathStepOpPtr op, int depth) {
1501     int i;
1502     char shift[100];
1503 
1504     for (i = 0;((i < depth) && (i < 25));i++)
1505         shift[2 * i] = shift[2 * i + 1] = ' ';
1506     shift[2 * i] = shift[2 * i + 1] = 0;
1507 
1508     fprintf(output, "%s", shift);
1509     if (op == NULL) {
1510 	fprintf(output, "Step is NULL\n");
1511 	return;
1512     }
1513     switch (op->op) {
1514         case XPATH_OP_END:
1515 	    fprintf(output, "END"); break;
1516         case XPATH_OP_AND:
1517 	    fprintf(output, "AND"); break;
1518         case XPATH_OP_OR:
1519 	    fprintf(output, "OR"); break;
1520         case XPATH_OP_EQUAL:
1521 	     if (op->value)
1522 		 fprintf(output, "EQUAL =");
1523 	     else
1524 		 fprintf(output, "EQUAL !=");
1525 	     break;
1526         case XPATH_OP_CMP:
1527 	     if (op->value)
1528 		 fprintf(output, "CMP <");
1529 	     else
1530 		 fprintf(output, "CMP >");
1531 	     if (!op->value2)
1532 		 fprintf(output, "=");
1533 	     break;
1534         case XPATH_OP_PLUS:
1535 	     if (op->value == 0)
1536 		 fprintf(output, "PLUS -");
1537 	     else if (op->value == 1)
1538 		 fprintf(output, "PLUS +");
1539 	     else if (op->value == 2)
1540 		 fprintf(output, "PLUS unary -");
1541 	     else if (op->value == 3)
1542 		 fprintf(output, "PLUS unary - -");
1543 	     break;
1544         case XPATH_OP_MULT:
1545 	     if (op->value == 0)
1546 		 fprintf(output, "MULT *");
1547 	     else if (op->value == 1)
1548 		 fprintf(output, "MULT div");
1549 	     else
1550 		 fprintf(output, "MULT mod");
1551 	     break;
1552         case XPATH_OP_UNION:
1553 	     fprintf(output, "UNION"); break;
1554         case XPATH_OP_ROOT:
1555 	     fprintf(output, "ROOT"); break;
1556         case XPATH_OP_NODE:
1557 	     fprintf(output, "NODE"); break;
1558         case XPATH_OP_SORT:
1559 	     fprintf(output, "SORT"); break;
1560         case XPATH_OP_COLLECT: {
1561 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1562 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1563 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1564 	    const xmlChar *prefix = op->value4;
1565 	    const xmlChar *name = op->value5;
1566 
1567 	    fprintf(output, "COLLECT ");
1568 	    switch (axis) {
1569 		case AXIS_ANCESTOR:
1570 		    fprintf(output, " 'ancestors' "); break;
1571 		case AXIS_ANCESTOR_OR_SELF:
1572 		    fprintf(output, " 'ancestors-or-self' "); break;
1573 		case AXIS_ATTRIBUTE:
1574 		    fprintf(output, " 'attributes' "); break;
1575 		case AXIS_CHILD:
1576 		    fprintf(output, " 'child' "); break;
1577 		case AXIS_DESCENDANT:
1578 		    fprintf(output, " 'descendant' "); break;
1579 		case AXIS_DESCENDANT_OR_SELF:
1580 		    fprintf(output, " 'descendant-or-self' "); break;
1581 		case AXIS_FOLLOWING:
1582 		    fprintf(output, " 'following' "); break;
1583 		case AXIS_FOLLOWING_SIBLING:
1584 		    fprintf(output, " 'following-siblings' "); break;
1585 		case AXIS_NAMESPACE:
1586 		    fprintf(output, " 'namespace' "); break;
1587 		case AXIS_PARENT:
1588 		    fprintf(output, " 'parent' "); break;
1589 		case AXIS_PRECEDING:
1590 		    fprintf(output, " 'preceding' "); break;
1591 		case AXIS_PRECEDING_SIBLING:
1592 		    fprintf(output, " 'preceding-sibling' "); break;
1593 		case AXIS_SELF:
1594 		    fprintf(output, " 'self' "); break;
1595 	    }
1596 	    switch (test) {
1597                 case NODE_TEST_NONE:
1598 		    fprintf(output, "'none' "); break;
1599                 case NODE_TEST_TYPE:
1600 		    fprintf(output, "'type' "); break;
1601                 case NODE_TEST_PI:
1602 		    fprintf(output, "'PI' "); break;
1603                 case NODE_TEST_ALL:
1604 		    fprintf(output, "'all' "); break;
1605                 case NODE_TEST_NS:
1606 		    fprintf(output, "'namespace' "); break;
1607                 case NODE_TEST_NAME:
1608 		    fprintf(output, "'name' "); break;
1609 	    }
1610 	    switch (type) {
1611                 case NODE_TYPE_NODE:
1612 		    fprintf(output, "'node' "); break;
1613                 case NODE_TYPE_COMMENT:
1614 		    fprintf(output, "'comment' "); break;
1615                 case NODE_TYPE_TEXT:
1616 		    fprintf(output, "'text' "); break;
1617                 case NODE_TYPE_PI:
1618 		    fprintf(output, "'PI' "); break;
1619 	    }
1620 	    if (prefix != NULL)
1621 		fprintf(output, "%s:", prefix);
1622 	    if (name != NULL)
1623 		fprintf(output, "%s", (const char *) name);
1624 	    break;
1625 
1626         }
1627 	case XPATH_OP_VALUE: {
1628 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1629 
1630 	    fprintf(output, "ELEM ");
1631 	    xmlXPathDebugDumpObject(output, object, 0);
1632 	    goto finish;
1633 	}
1634 	case XPATH_OP_VARIABLE: {
1635 	    const xmlChar *prefix = op->value5;
1636 	    const xmlChar *name = op->value4;
1637 
1638 	    if (prefix != NULL)
1639 		fprintf(output, "VARIABLE %s:%s", prefix, name);
1640 	    else
1641 		fprintf(output, "VARIABLE %s", name);
1642 	    break;
1643 	}
1644 	case XPATH_OP_FUNCTION: {
1645 	    int nbargs = op->value;
1646 	    const xmlChar *prefix = op->value5;
1647 	    const xmlChar *name = op->value4;
1648 
1649 	    if (prefix != NULL)
1650 		fprintf(output, "FUNCTION %s:%s(%d args)",
1651 			prefix, name, nbargs);
1652 	    else
1653 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1654 	    break;
1655 	}
1656         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1657         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1658         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1659 #ifdef LIBXML_XPTR_ENABLED
1660         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1661 #endif
1662 	default:
1663         fprintf(output, "UNKNOWN %d\n", op->op); return;
1664     }
1665     fprintf(output, "\n");
1666 finish:
1667     if (op->ch1 >= 0)
1668 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1669     if (op->ch2 >= 0)
1670 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1671 }
1672 
1673 /**
1674  * xmlXPathDebugDumpCompExpr:
1675  * @output:  the FILE * for the output
1676  * @comp:  the precompiled XPath expression
1677  * @depth:  the indentation level.
1678  *
1679  * Dumps the tree of the compiled XPath expression.
1680  */
1681 void
1682 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1683 	                  int depth) {
1684     int i;
1685     char shift[100];
1686 
1687     if ((output == NULL) || (comp == NULL)) return;
1688 
1689     for (i = 0;((i < depth) && (i < 25));i++)
1690         shift[2 * i] = shift[2 * i + 1] = ' ';
1691     shift[2 * i] = shift[2 * i + 1] = 0;
1692 
1693     fprintf(output, "%s", shift);
1694 
1695 #ifdef XPATH_STREAMING
1696     if (comp->stream) {
1697         fprintf(output, "Streaming Expression\n");
1698     } else
1699 #endif
1700     {
1701         fprintf(output, "Compiled Expression : %d elements\n",
1702                 comp->nbStep);
1703         i = comp->last;
1704         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1705     }
1706 }
1707 
1708 #ifdef XP_DEBUG_OBJ_USAGE
1709 
1710 /*
1711 * XPath object usage related debugging variables.
1712 */
1713 static int xmlXPathDebugObjCounterUndefined = 0;
1714 static int xmlXPathDebugObjCounterNodeset = 0;
1715 static int xmlXPathDebugObjCounterBool = 0;
1716 static int xmlXPathDebugObjCounterNumber = 0;
1717 static int xmlXPathDebugObjCounterString = 0;
1718 static int xmlXPathDebugObjCounterPoint = 0;
1719 static int xmlXPathDebugObjCounterRange = 0;
1720 static int xmlXPathDebugObjCounterLocset = 0;
1721 static int xmlXPathDebugObjCounterUsers = 0;
1722 static int xmlXPathDebugObjCounterXSLTTree = 0;
1723 static int xmlXPathDebugObjCounterAll = 0;
1724 
1725 static int xmlXPathDebugObjTotalUndefined = 0;
1726 static int xmlXPathDebugObjTotalNodeset = 0;
1727 static int xmlXPathDebugObjTotalBool = 0;
1728 static int xmlXPathDebugObjTotalNumber = 0;
1729 static int xmlXPathDebugObjTotalString = 0;
1730 static int xmlXPathDebugObjTotalPoint = 0;
1731 static int xmlXPathDebugObjTotalRange = 0;
1732 static int xmlXPathDebugObjTotalLocset = 0;
1733 static int xmlXPathDebugObjTotalUsers = 0;
1734 static int xmlXPathDebugObjTotalXSLTTree = 0;
1735 static int xmlXPathDebugObjTotalAll = 0;
1736 
1737 static int xmlXPathDebugObjMaxUndefined = 0;
1738 static int xmlXPathDebugObjMaxNodeset = 0;
1739 static int xmlXPathDebugObjMaxBool = 0;
1740 static int xmlXPathDebugObjMaxNumber = 0;
1741 static int xmlXPathDebugObjMaxString = 0;
1742 static int xmlXPathDebugObjMaxPoint = 0;
1743 static int xmlXPathDebugObjMaxRange = 0;
1744 static int xmlXPathDebugObjMaxLocset = 0;
1745 static int xmlXPathDebugObjMaxUsers = 0;
1746 static int xmlXPathDebugObjMaxXSLTTree = 0;
1747 static int xmlXPathDebugObjMaxAll = 0;
1748 
1749 /* REVISIT TODO: Make this static when committing */
1750 static void
1751 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1752 {
1753     if (ctxt != NULL) {
1754 	if (ctxt->cache != NULL) {
1755 	    xmlXPathContextCachePtr cache =
1756 		(xmlXPathContextCachePtr) ctxt->cache;
1757 
1758 	    cache->dbgCachedAll = 0;
1759 	    cache->dbgCachedNodeset = 0;
1760 	    cache->dbgCachedString = 0;
1761 	    cache->dbgCachedBool = 0;
1762 	    cache->dbgCachedNumber = 0;
1763 	    cache->dbgCachedPoint = 0;
1764 	    cache->dbgCachedRange = 0;
1765 	    cache->dbgCachedLocset = 0;
1766 	    cache->dbgCachedUsers = 0;
1767 	    cache->dbgCachedXSLTTree = 0;
1768 	    cache->dbgCachedUndefined = 0;
1769 
1770 	    cache->dbgReusedAll = 0;
1771 	    cache->dbgReusedNodeset = 0;
1772 	    cache->dbgReusedString = 0;
1773 	    cache->dbgReusedBool = 0;
1774 	    cache->dbgReusedNumber = 0;
1775 	    cache->dbgReusedPoint = 0;
1776 	    cache->dbgReusedRange = 0;
1777 	    cache->dbgReusedLocset = 0;
1778 	    cache->dbgReusedUsers = 0;
1779 	    cache->dbgReusedXSLTTree = 0;
1780 	    cache->dbgReusedUndefined = 0;
1781 	}
1782     }
1783 
1784     xmlXPathDebugObjCounterUndefined = 0;
1785     xmlXPathDebugObjCounterNodeset = 0;
1786     xmlXPathDebugObjCounterBool = 0;
1787     xmlXPathDebugObjCounterNumber = 0;
1788     xmlXPathDebugObjCounterString = 0;
1789     xmlXPathDebugObjCounterPoint = 0;
1790     xmlXPathDebugObjCounterRange = 0;
1791     xmlXPathDebugObjCounterLocset = 0;
1792     xmlXPathDebugObjCounterUsers = 0;
1793     xmlXPathDebugObjCounterXSLTTree = 0;
1794     xmlXPathDebugObjCounterAll = 0;
1795 
1796     xmlXPathDebugObjTotalUndefined = 0;
1797     xmlXPathDebugObjTotalNodeset = 0;
1798     xmlXPathDebugObjTotalBool = 0;
1799     xmlXPathDebugObjTotalNumber = 0;
1800     xmlXPathDebugObjTotalString = 0;
1801     xmlXPathDebugObjTotalPoint = 0;
1802     xmlXPathDebugObjTotalRange = 0;
1803     xmlXPathDebugObjTotalLocset = 0;
1804     xmlXPathDebugObjTotalUsers = 0;
1805     xmlXPathDebugObjTotalXSLTTree = 0;
1806     xmlXPathDebugObjTotalAll = 0;
1807 
1808     xmlXPathDebugObjMaxUndefined = 0;
1809     xmlXPathDebugObjMaxNodeset = 0;
1810     xmlXPathDebugObjMaxBool = 0;
1811     xmlXPathDebugObjMaxNumber = 0;
1812     xmlXPathDebugObjMaxString = 0;
1813     xmlXPathDebugObjMaxPoint = 0;
1814     xmlXPathDebugObjMaxRange = 0;
1815     xmlXPathDebugObjMaxLocset = 0;
1816     xmlXPathDebugObjMaxUsers = 0;
1817     xmlXPathDebugObjMaxXSLTTree = 0;
1818     xmlXPathDebugObjMaxAll = 0;
1819 
1820 }
1821 
1822 static void
1823 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1824 			      xmlXPathObjectType objType)
1825 {
1826     int isCached = 0;
1827 
1828     if (ctxt != NULL) {
1829 	if (ctxt->cache != NULL) {
1830 	    xmlXPathContextCachePtr cache =
1831 		(xmlXPathContextCachePtr) ctxt->cache;
1832 
1833 	    isCached = 1;
1834 
1835 	    cache->dbgReusedAll++;
1836 	    switch (objType) {
1837 		case XPATH_UNDEFINED:
1838 		    cache->dbgReusedUndefined++;
1839 		    break;
1840 		case XPATH_NODESET:
1841 		    cache->dbgReusedNodeset++;
1842 		    break;
1843 		case XPATH_BOOLEAN:
1844 		    cache->dbgReusedBool++;
1845 		    break;
1846 		case XPATH_NUMBER:
1847 		    cache->dbgReusedNumber++;
1848 		    break;
1849 		case XPATH_STRING:
1850 		    cache->dbgReusedString++;
1851 		    break;
1852 		case XPATH_POINT:
1853 		    cache->dbgReusedPoint++;
1854 		    break;
1855 		case XPATH_RANGE:
1856 		    cache->dbgReusedRange++;
1857 		    break;
1858 		case XPATH_LOCATIONSET:
1859 		    cache->dbgReusedLocset++;
1860 		    break;
1861 		case XPATH_USERS:
1862 		    cache->dbgReusedUsers++;
1863 		    break;
1864 		case XPATH_XSLT_TREE:
1865 		    cache->dbgReusedXSLTTree++;
1866 		    break;
1867 		default:
1868 		    break;
1869 	    }
1870 	}
1871     }
1872 
1873     switch (objType) {
1874 	case XPATH_UNDEFINED:
1875 	    if (! isCached)
1876 		xmlXPathDebugObjTotalUndefined++;
1877 	    xmlXPathDebugObjCounterUndefined++;
1878 	    if (xmlXPathDebugObjCounterUndefined >
1879 		xmlXPathDebugObjMaxUndefined)
1880 		xmlXPathDebugObjMaxUndefined =
1881 		    xmlXPathDebugObjCounterUndefined;
1882 	    break;
1883 	case XPATH_NODESET:
1884 	    if (! isCached)
1885 		xmlXPathDebugObjTotalNodeset++;
1886 	    xmlXPathDebugObjCounterNodeset++;
1887 	    if (xmlXPathDebugObjCounterNodeset >
1888 		xmlXPathDebugObjMaxNodeset)
1889 		xmlXPathDebugObjMaxNodeset =
1890 		    xmlXPathDebugObjCounterNodeset;
1891 	    break;
1892 	case XPATH_BOOLEAN:
1893 	    if (! isCached)
1894 		xmlXPathDebugObjTotalBool++;
1895 	    xmlXPathDebugObjCounterBool++;
1896 	    if (xmlXPathDebugObjCounterBool >
1897 		xmlXPathDebugObjMaxBool)
1898 		xmlXPathDebugObjMaxBool =
1899 		    xmlXPathDebugObjCounterBool;
1900 	    break;
1901 	case XPATH_NUMBER:
1902 	    if (! isCached)
1903 		xmlXPathDebugObjTotalNumber++;
1904 	    xmlXPathDebugObjCounterNumber++;
1905 	    if (xmlXPathDebugObjCounterNumber >
1906 		xmlXPathDebugObjMaxNumber)
1907 		xmlXPathDebugObjMaxNumber =
1908 		    xmlXPathDebugObjCounterNumber;
1909 	    break;
1910 	case XPATH_STRING:
1911 	    if (! isCached)
1912 		xmlXPathDebugObjTotalString++;
1913 	    xmlXPathDebugObjCounterString++;
1914 	    if (xmlXPathDebugObjCounterString >
1915 		xmlXPathDebugObjMaxString)
1916 		xmlXPathDebugObjMaxString =
1917 		    xmlXPathDebugObjCounterString;
1918 	    break;
1919 	case XPATH_POINT:
1920 	    if (! isCached)
1921 		xmlXPathDebugObjTotalPoint++;
1922 	    xmlXPathDebugObjCounterPoint++;
1923 	    if (xmlXPathDebugObjCounterPoint >
1924 		xmlXPathDebugObjMaxPoint)
1925 		xmlXPathDebugObjMaxPoint =
1926 		    xmlXPathDebugObjCounterPoint;
1927 	    break;
1928 	case XPATH_RANGE:
1929 	    if (! isCached)
1930 		xmlXPathDebugObjTotalRange++;
1931 	    xmlXPathDebugObjCounterRange++;
1932 	    if (xmlXPathDebugObjCounterRange >
1933 		xmlXPathDebugObjMaxRange)
1934 		xmlXPathDebugObjMaxRange =
1935 		    xmlXPathDebugObjCounterRange;
1936 	    break;
1937 	case XPATH_LOCATIONSET:
1938 	    if (! isCached)
1939 		xmlXPathDebugObjTotalLocset++;
1940 	    xmlXPathDebugObjCounterLocset++;
1941 	    if (xmlXPathDebugObjCounterLocset >
1942 		xmlXPathDebugObjMaxLocset)
1943 		xmlXPathDebugObjMaxLocset =
1944 		    xmlXPathDebugObjCounterLocset;
1945 	    break;
1946 	case XPATH_USERS:
1947 	    if (! isCached)
1948 		xmlXPathDebugObjTotalUsers++;
1949 	    xmlXPathDebugObjCounterUsers++;
1950 	    if (xmlXPathDebugObjCounterUsers >
1951 		xmlXPathDebugObjMaxUsers)
1952 		xmlXPathDebugObjMaxUsers =
1953 		    xmlXPathDebugObjCounterUsers;
1954 	    break;
1955 	case XPATH_XSLT_TREE:
1956 	    if (! isCached)
1957 		xmlXPathDebugObjTotalXSLTTree++;
1958 	    xmlXPathDebugObjCounterXSLTTree++;
1959 	    if (xmlXPathDebugObjCounterXSLTTree >
1960 		xmlXPathDebugObjMaxXSLTTree)
1961 		xmlXPathDebugObjMaxXSLTTree =
1962 		    xmlXPathDebugObjCounterXSLTTree;
1963 	    break;
1964 	default:
1965 	    break;
1966     }
1967     if (! isCached)
1968 	xmlXPathDebugObjTotalAll++;
1969     xmlXPathDebugObjCounterAll++;
1970     if (xmlXPathDebugObjCounterAll >
1971 	xmlXPathDebugObjMaxAll)
1972 	xmlXPathDebugObjMaxAll =
1973 	    xmlXPathDebugObjCounterAll;
1974 }
1975 
1976 static void
1977 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1978 			      xmlXPathObjectType objType)
1979 {
1980     int isCached = 0;
1981 
1982     if (ctxt != NULL) {
1983 	if (ctxt->cache != NULL) {
1984 	    xmlXPathContextCachePtr cache =
1985 		(xmlXPathContextCachePtr) ctxt->cache;
1986 
1987 	    isCached = 1;
1988 
1989 	    cache->dbgCachedAll++;
1990 	    switch (objType) {
1991 		case XPATH_UNDEFINED:
1992 		    cache->dbgCachedUndefined++;
1993 		    break;
1994 		case XPATH_NODESET:
1995 		    cache->dbgCachedNodeset++;
1996 		    break;
1997 		case XPATH_BOOLEAN:
1998 		    cache->dbgCachedBool++;
1999 		    break;
2000 		case XPATH_NUMBER:
2001 		    cache->dbgCachedNumber++;
2002 		    break;
2003 		case XPATH_STRING:
2004 		    cache->dbgCachedString++;
2005 		    break;
2006 		case XPATH_POINT:
2007 		    cache->dbgCachedPoint++;
2008 		    break;
2009 		case XPATH_RANGE:
2010 		    cache->dbgCachedRange++;
2011 		    break;
2012 		case XPATH_LOCATIONSET:
2013 		    cache->dbgCachedLocset++;
2014 		    break;
2015 		case XPATH_USERS:
2016 		    cache->dbgCachedUsers++;
2017 		    break;
2018 		case XPATH_XSLT_TREE:
2019 		    cache->dbgCachedXSLTTree++;
2020 		    break;
2021 		default:
2022 		    break;
2023 	    }
2024 
2025 	}
2026     }
2027     switch (objType) {
2028 	case XPATH_UNDEFINED:
2029 	    xmlXPathDebugObjCounterUndefined--;
2030 	    break;
2031 	case XPATH_NODESET:
2032 	    xmlXPathDebugObjCounterNodeset--;
2033 	    break;
2034 	case XPATH_BOOLEAN:
2035 	    xmlXPathDebugObjCounterBool--;
2036 	    break;
2037 	case XPATH_NUMBER:
2038 	    xmlXPathDebugObjCounterNumber--;
2039 	    break;
2040 	case XPATH_STRING:
2041 	    xmlXPathDebugObjCounterString--;
2042 	    break;
2043 	case XPATH_POINT:
2044 	    xmlXPathDebugObjCounterPoint--;
2045 	    break;
2046 	case XPATH_RANGE:
2047 	    xmlXPathDebugObjCounterRange--;
2048 	    break;
2049 	case XPATH_LOCATIONSET:
2050 	    xmlXPathDebugObjCounterLocset--;
2051 	    break;
2052 	case XPATH_USERS:
2053 	    xmlXPathDebugObjCounterUsers--;
2054 	    break;
2055 	case XPATH_XSLT_TREE:
2056 	    xmlXPathDebugObjCounterXSLTTree--;
2057 	    break;
2058 	default:
2059 	    break;
2060     }
2061     xmlXPathDebugObjCounterAll--;
2062 }
2063 
2064 /* REVISIT TODO: Make this static when committing */
2065 static void
2066 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2067 {
2068     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2069 	reqXSLTTree, reqUndefined;
2070     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2071 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2072     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2073 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2074     int leftObjs = xmlXPathDebugObjCounterAll;
2075 
2076     reqAll = xmlXPathDebugObjTotalAll;
2077     reqNodeset = xmlXPathDebugObjTotalNodeset;
2078     reqString = xmlXPathDebugObjTotalString;
2079     reqBool = xmlXPathDebugObjTotalBool;
2080     reqNumber = xmlXPathDebugObjTotalNumber;
2081     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2082     reqUndefined = xmlXPathDebugObjTotalUndefined;
2083 
2084     printf("# XPath object usage:\n");
2085 
2086     if (ctxt != NULL) {
2087 	if (ctxt->cache != NULL) {
2088 	    xmlXPathContextCachePtr cache =
2089 		(xmlXPathContextCachePtr) ctxt->cache;
2090 
2091 	    reAll = cache->dbgReusedAll;
2092 	    reqAll += reAll;
2093 	    reNodeset = cache->dbgReusedNodeset;
2094 	    reqNodeset += reNodeset;
2095 	    reString = cache->dbgReusedString;
2096 	    reqString += reString;
2097 	    reBool = cache->dbgReusedBool;
2098 	    reqBool += reBool;
2099 	    reNumber = cache->dbgReusedNumber;
2100 	    reqNumber += reNumber;
2101 	    reXSLTTree = cache->dbgReusedXSLTTree;
2102 	    reqXSLTTree += reXSLTTree;
2103 	    reUndefined = cache->dbgReusedUndefined;
2104 	    reqUndefined += reUndefined;
2105 
2106 	    caAll = cache->dbgCachedAll;
2107 	    caBool = cache->dbgCachedBool;
2108 	    caNodeset = cache->dbgCachedNodeset;
2109 	    caString = cache->dbgCachedString;
2110 	    caNumber = cache->dbgCachedNumber;
2111 	    caXSLTTree = cache->dbgCachedXSLTTree;
2112 	    caUndefined = cache->dbgCachedUndefined;
2113 
2114 	    if (cache->nodesetObjs)
2115 		leftObjs -= cache->nodesetObjs->number;
2116 	    if (cache->stringObjs)
2117 		leftObjs -= cache->stringObjs->number;
2118 	    if (cache->booleanObjs)
2119 		leftObjs -= cache->booleanObjs->number;
2120 	    if (cache->numberObjs)
2121 		leftObjs -= cache->numberObjs->number;
2122 	    if (cache->miscObjs)
2123 		leftObjs -= cache->miscObjs->number;
2124 	}
2125     }
2126 
2127     printf("# all\n");
2128     printf("#   total  : %d\n", reqAll);
2129     printf("#   left  : %d\n", leftObjs);
2130     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2131     printf("#   reused : %d\n", reAll);
2132     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2133 
2134     printf("# node-sets\n");
2135     printf("#   total  : %d\n", reqNodeset);
2136     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2137     printf("#   reused : %d\n", reNodeset);
2138     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2139 
2140     printf("# strings\n");
2141     printf("#   total  : %d\n", reqString);
2142     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2143     printf("#   reused : %d\n", reString);
2144     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2145 
2146     printf("# booleans\n");
2147     printf("#   total  : %d\n", reqBool);
2148     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2149     printf("#   reused : %d\n", reBool);
2150     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2151 
2152     printf("# numbers\n");
2153     printf("#   total  : %d\n", reqNumber);
2154     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2155     printf("#   reused : %d\n", reNumber);
2156     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2157 
2158     printf("# XSLT result tree fragments\n");
2159     printf("#   total  : %d\n", reqXSLTTree);
2160     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2161     printf("#   reused : %d\n", reXSLTTree);
2162     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2163 
2164     printf("# undefined\n");
2165     printf("#   total  : %d\n", reqUndefined);
2166     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2167     printf("#   reused : %d\n", reUndefined);
2168     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2169 
2170 }
2171 
2172 #endif /* XP_DEBUG_OBJ_USAGE */
2173 
2174 #endif /* LIBXML_DEBUG_ENABLED */
2175 
2176 /************************************************************************
2177  *									*
2178  *			XPath object caching				*
2179  *									*
2180  ************************************************************************/
2181 
2182 /**
2183  * xmlXPathNewCache:
2184  *
2185  * Create a new object cache
2186  *
2187  * Returns the xmlXPathCache just allocated.
2188  */
2189 static xmlXPathContextCachePtr
2190 xmlXPathNewCache(void)
2191 {
2192     xmlXPathContextCachePtr ret;
2193 
2194     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2195     if (ret == NULL) {
2196         xmlXPathErrMemory(NULL, "creating object cache\n");
2197 	return(NULL);
2198     }
2199     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2200     ret->maxNodeset = 100;
2201     ret->maxString = 100;
2202     ret->maxBoolean = 100;
2203     ret->maxNumber = 100;
2204     ret->maxMisc = 100;
2205     return(ret);
2206 }
2207 
2208 static void
2209 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2210 {
2211     int i;
2212     xmlXPathObjectPtr obj;
2213 
2214     if (list == NULL)
2215 	return;
2216 
2217     for (i = 0; i < list->number; i++) {
2218 	obj = list->items[i];
2219 	/*
2220 	* Note that it is already assured that we don't need to
2221 	* look out for namespace nodes in the node-set.
2222 	*/
2223 	if (obj->nodesetval != NULL) {
2224 	    if (obj->nodesetval->nodeTab != NULL)
2225 		xmlFree(obj->nodesetval->nodeTab);
2226 	    xmlFree(obj->nodesetval);
2227 	}
2228 	xmlFree(obj);
2229 #ifdef XP_DEBUG_OBJ_USAGE
2230 	xmlXPathDebugObjCounterAll--;
2231 #endif
2232     }
2233     xmlPointerListFree(list);
2234 }
2235 
2236 static void
2237 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2238 {
2239     if (cache == NULL)
2240 	return;
2241     if (cache->nodesetObjs)
2242 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2243     if (cache->stringObjs)
2244 	xmlXPathCacheFreeObjectList(cache->stringObjs);
2245     if (cache->booleanObjs)
2246 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
2247     if (cache->numberObjs)
2248 	xmlXPathCacheFreeObjectList(cache->numberObjs);
2249     if (cache->miscObjs)
2250 	xmlXPathCacheFreeObjectList(cache->miscObjs);
2251     xmlFree(cache);
2252 }
2253 
2254 /**
2255  * xmlXPathContextSetCache:
2256  *
2257  * @ctxt:  the XPath context
2258  * @active: enables/disables (creates/frees) the cache
2259  * @value: a value with semantics dependent on @options
2260  * @options: options (currently only the value 0 is used)
2261  *
2262  * Creates/frees an object cache on the XPath context.
2263  * If activates XPath objects (xmlXPathObject) will be cached internally
2264  * to be reused.
2265  * @options:
2266  *   0: This will set the XPath object caching:
2267  *      @value:
2268  *        This will set the maximum number of XPath objects
2269  *        to be cached per slot
2270  *        There are 5 slots for: node-set, string, number, boolean, and
2271  *        misc objects. Use <0 for the default number (100).
2272  *   Other values for @options have currently no effect.
2273  *
2274  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2275  */
2276 int
2277 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2278 			int active,
2279 			int value,
2280 			int options)
2281 {
2282     if (ctxt == NULL)
2283 	return(-1);
2284     if (active) {
2285 	xmlXPathContextCachePtr cache;
2286 
2287 	if (ctxt->cache == NULL) {
2288 	    ctxt->cache = xmlXPathNewCache();
2289 	    if (ctxt->cache == NULL)
2290 		return(-1);
2291 	}
2292 	cache = (xmlXPathContextCachePtr) ctxt->cache;
2293 	if (options == 0) {
2294 	    if (value < 0)
2295 		value = 100;
2296 	    cache->maxNodeset = value;
2297 	    cache->maxString = value;
2298 	    cache->maxNumber = value;
2299 	    cache->maxBoolean = value;
2300 	    cache->maxMisc = value;
2301 	}
2302     } else if (ctxt->cache != NULL) {
2303 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2304 	ctxt->cache = NULL;
2305     }
2306     return(0);
2307 }
2308 
2309 /**
2310  * xmlXPathCacheWrapNodeSet:
2311  * @ctxt: the XPath context
2312  * @val:  the NodePtr value
2313  *
2314  * This is the cached version of xmlXPathWrapNodeSet().
2315  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2316  *
2317  * Returns the created or reused object.
2318  */
2319 static xmlXPathObjectPtr
2320 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2321 {
2322     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2323 	xmlXPathContextCachePtr cache =
2324 	    (xmlXPathContextCachePtr) ctxt->cache;
2325 
2326 	if ((cache->miscObjs != NULL) &&
2327 	    (cache->miscObjs->number != 0))
2328 	{
2329 	    xmlXPathObjectPtr ret;
2330 
2331 	    ret = (xmlXPathObjectPtr)
2332 		cache->miscObjs->items[--cache->miscObjs->number];
2333 	    ret->type = XPATH_NODESET;
2334 	    ret->nodesetval = val;
2335 #ifdef XP_DEBUG_OBJ_USAGE
2336 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2337 #endif
2338 	    return(ret);
2339 	}
2340     }
2341 
2342     return(xmlXPathWrapNodeSet(val));
2343 
2344 }
2345 
2346 /**
2347  * xmlXPathCacheWrapString:
2348  * @ctxt: the XPath context
2349  * @val:  the xmlChar * value
2350  *
2351  * This is the cached version of xmlXPathWrapString().
2352  * Wraps the @val string into an XPath object.
2353  *
2354  * Returns the created or reused object.
2355  */
2356 static xmlXPathObjectPtr
2357 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2358 {
2359     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2360 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2361 
2362 	if ((cache->stringObjs != NULL) &&
2363 	    (cache->stringObjs->number != 0))
2364 	{
2365 
2366 	    xmlXPathObjectPtr ret;
2367 
2368 	    ret = (xmlXPathObjectPtr)
2369 		cache->stringObjs->items[--cache->stringObjs->number];
2370 	    ret->type = XPATH_STRING;
2371 	    ret->stringval = val;
2372 #ifdef XP_DEBUG_OBJ_USAGE
2373 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2374 #endif
2375 	    return(ret);
2376 	} else if ((cache->miscObjs != NULL) &&
2377 	    (cache->miscObjs->number != 0))
2378 	{
2379 	    xmlXPathObjectPtr ret;
2380 	    /*
2381 	    * Fallback to misc-cache.
2382 	    */
2383 	    ret = (xmlXPathObjectPtr)
2384 		cache->miscObjs->items[--cache->miscObjs->number];
2385 
2386 	    ret->type = XPATH_STRING;
2387 	    ret->stringval = val;
2388 #ifdef XP_DEBUG_OBJ_USAGE
2389 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2390 #endif
2391 	    return(ret);
2392 	}
2393     }
2394     return(xmlXPathWrapString(val));
2395 }
2396 
2397 /**
2398  * xmlXPathCacheNewNodeSet:
2399  * @ctxt: the XPath context
2400  * @val:  the NodePtr value
2401  *
2402  * This is the cached version of xmlXPathNewNodeSet().
2403  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2404  * it with the single Node @val
2405  *
2406  * Returns the created or reused object.
2407  */
2408 static xmlXPathObjectPtr
2409 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2410 {
2411     if ((ctxt != NULL) && (ctxt->cache)) {
2412 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2413 
2414 	if ((cache->nodesetObjs != NULL) &&
2415 	    (cache->nodesetObjs->number != 0))
2416 	{
2417 	    xmlXPathObjectPtr ret;
2418 	    /*
2419 	    * Use the nodeset-cache.
2420 	    */
2421 	    ret = (xmlXPathObjectPtr)
2422 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
2423 	    ret->type = XPATH_NODESET;
2424 	    ret->boolval = 0;
2425 	    if (val) {
2426 		if ((ret->nodesetval->nodeMax == 0) ||
2427 		    (val->type == XML_NAMESPACE_DECL))
2428 		{
2429                     /* TODO: Check memory error. */
2430 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2431 		} else {
2432 		    ret->nodesetval->nodeTab[0] = val;
2433 		    ret->nodesetval->nodeNr = 1;
2434 		}
2435 	    }
2436 #ifdef XP_DEBUG_OBJ_USAGE
2437 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2438 #endif
2439 	    return(ret);
2440 	} else if ((cache->miscObjs != NULL) &&
2441 	    (cache->miscObjs->number != 0))
2442 	{
2443 	    xmlXPathObjectPtr ret;
2444 	    /*
2445 	    * Fallback to misc-cache.
2446 	    */
2447 
2448 	    ret = (xmlXPathObjectPtr)
2449 		cache->miscObjs->items[--cache->miscObjs->number];
2450 
2451 	    ret->type = XPATH_NODESET;
2452 	    ret->boolval = 0;
2453 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
2454 	    if (ret->nodesetval == NULL) {
2455 		ctxt->lastError.domain = XML_FROM_XPATH;
2456 		ctxt->lastError.code = XML_ERR_NO_MEMORY;
2457 		return(NULL);
2458 	    }
2459 #ifdef XP_DEBUG_OBJ_USAGE
2460 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2461 #endif
2462 	    return(ret);
2463 	}
2464     }
2465     return(xmlXPathNewNodeSet(val));
2466 }
2467 
2468 /**
2469  * xmlXPathCacheNewCString:
2470  * @ctxt: the XPath context
2471  * @val:  the char * value
2472  *
2473  * This is the cached version of xmlXPathNewCString().
2474  * Acquire an xmlXPathObjectPtr of type string and of value @val
2475  *
2476  * Returns the created or reused object.
2477  */
2478 static xmlXPathObjectPtr
2479 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2480 {
2481     if ((ctxt != NULL) && (ctxt->cache)) {
2482 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2483 
2484 	if ((cache->stringObjs != NULL) &&
2485 	    (cache->stringObjs->number != 0))
2486 	{
2487 	    xmlXPathObjectPtr ret;
2488 
2489 	    ret = (xmlXPathObjectPtr)
2490 		cache->stringObjs->items[--cache->stringObjs->number];
2491 
2492 	    ret->type = XPATH_STRING;
2493 	    ret->stringval = xmlStrdup(BAD_CAST val);
2494 #ifdef XP_DEBUG_OBJ_USAGE
2495 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2496 #endif
2497 	    return(ret);
2498 	} else if ((cache->miscObjs != NULL) &&
2499 	    (cache->miscObjs->number != 0))
2500 	{
2501 	    xmlXPathObjectPtr ret;
2502 
2503 	    ret = (xmlXPathObjectPtr)
2504 		cache->miscObjs->items[--cache->miscObjs->number];
2505 
2506 	    ret->type = XPATH_STRING;
2507 	    ret->stringval = xmlStrdup(BAD_CAST val);
2508 #ifdef XP_DEBUG_OBJ_USAGE
2509 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2510 #endif
2511 	    return(ret);
2512 	}
2513     }
2514     return(xmlXPathNewCString(val));
2515 }
2516 
2517 /**
2518  * xmlXPathCacheNewString:
2519  * @ctxt: the XPath context
2520  * @val:  the xmlChar * value
2521  *
2522  * This is the cached version of xmlXPathNewString().
2523  * Acquire an xmlXPathObjectPtr of type string and of value @val
2524  *
2525  * Returns the created or reused object.
2526  */
2527 static xmlXPathObjectPtr
2528 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2529 {
2530     if ((ctxt != NULL) && (ctxt->cache)) {
2531 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2532 
2533 	if ((cache->stringObjs != NULL) &&
2534 	    (cache->stringObjs->number != 0))
2535 	{
2536 	    xmlXPathObjectPtr ret;
2537 
2538 	    ret = (xmlXPathObjectPtr)
2539 		cache->stringObjs->items[--cache->stringObjs->number];
2540 	    ret->type = XPATH_STRING;
2541 	    if (val != NULL)
2542 		ret->stringval = xmlStrdup(val);
2543 	    else
2544 		ret->stringval = xmlStrdup((const xmlChar *)"");
2545 #ifdef XP_DEBUG_OBJ_USAGE
2546 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2547 #endif
2548 	    return(ret);
2549 	} else if ((cache->miscObjs != NULL) &&
2550 	    (cache->miscObjs->number != 0))
2551 	{
2552 	    xmlXPathObjectPtr ret;
2553 
2554 	    ret = (xmlXPathObjectPtr)
2555 		cache->miscObjs->items[--cache->miscObjs->number];
2556 
2557 	    ret->type = XPATH_STRING;
2558 	    if (val != NULL)
2559 		ret->stringval = xmlStrdup(val);
2560 	    else
2561 		ret->stringval = xmlStrdup((const xmlChar *)"");
2562 #ifdef XP_DEBUG_OBJ_USAGE
2563 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2564 #endif
2565 	    return(ret);
2566 	}
2567     }
2568     return(xmlXPathNewString(val));
2569 }
2570 
2571 /**
2572  * xmlXPathCacheNewBoolean:
2573  * @ctxt: the XPath context
2574  * @val:  the boolean value
2575  *
2576  * This is the cached version of xmlXPathNewBoolean().
2577  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2578  *
2579  * Returns the created or reused object.
2580  */
2581 static xmlXPathObjectPtr
2582 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2583 {
2584     if ((ctxt != NULL) && (ctxt->cache)) {
2585 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2586 
2587 	if ((cache->booleanObjs != NULL) &&
2588 	    (cache->booleanObjs->number != 0))
2589 	{
2590 	    xmlXPathObjectPtr ret;
2591 
2592 	    ret = (xmlXPathObjectPtr)
2593 		cache->booleanObjs->items[--cache->booleanObjs->number];
2594 	    ret->type = XPATH_BOOLEAN;
2595 	    ret->boolval = (val != 0);
2596 #ifdef XP_DEBUG_OBJ_USAGE
2597 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2598 #endif
2599 	    return(ret);
2600 	} else if ((cache->miscObjs != NULL) &&
2601 	    (cache->miscObjs->number != 0))
2602 	{
2603 	    xmlXPathObjectPtr ret;
2604 
2605 	    ret = (xmlXPathObjectPtr)
2606 		cache->miscObjs->items[--cache->miscObjs->number];
2607 
2608 	    ret->type = XPATH_BOOLEAN;
2609 	    ret->boolval = (val != 0);
2610 #ifdef XP_DEBUG_OBJ_USAGE
2611 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2612 #endif
2613 	    return(ret);
2614 	}
2615     }
2616     return(xmlXPathNewBoolean(val));
2617 }
2618 
2619 /**
2620  * xmlXPathCacheNewFloat:
2621  * @ctxt: the XPath context
2622  * @val:  the double value
2623  *
2624  * This is the cached version of xmlXPathNewFloat().
2625  * Acquires an xmlXPathObjectPtr of type double and of value @val
2626  *
2627  * Returns the created or reused object.
2628  */
2629 static xmlXPathObjectPtr
2630 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2631 {
2632      if ((ctxt != NULL) && (ctxt->cache)) {
2633 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2634 
2635 	if ((cache->numberObjs != NULL) &&
2636 	    (cache->numberObjs->number != 0))
2637 	{
2638 	    xmlXPathObjectPtr ret;
2639 
2640 	    ret = (xmlXPathObjectPtr)
2641 		cache->numberObjs->items[--cache->numberObjs->number];
2642 	    ret->type = XPATH_NUMBER;
2643 	    ret->floatval = val;
2644 #ifdef XP_DEBUG_OBJ_USAGE
2645 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2646 #endif
2647 	    return(ret);
2648 	} else if ((cache->miscObjs != NULL) &&
2649 	    (cache->miscObjs->number != 0))
2650 	{
2651 	    xmlXPathObjectPtr ret;
2652 
2653 	    ret = (xmlXPathObjectPtr)
2654 		cache->miscObjs->items[--cache->miscObjs->number];
2655 
2656 	    ret->type = XPATH_NUMBER;
2657 	    ret->floatval = val;
2658 #ifdef XP_DEBUG_OBJ_USAGE
2659 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2660 #endif
2661 	    return(ret);
2662 	}
2663     }
2664     return(xmlXPathNewFloat(val));
2665 }
2666 
2667 /**
2668  * xmlXPathCacheConvertString:
2669  * @ctxt: the XPath context
2670  * @val:  an XPath object
2671  *
2672  * This is the cached version of xmlXPathConvertString().
2673  * Converts an existing object to its string() equivalent
2674  *
2675  * Returns a created or reused object, the old one is freed (cached)
2676  *         (or the operation is done directly on @val)
2677  */
2678 
2679 static xmlXPathObjectPtr
2680 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2681     xmlChar *res = NULL;
2682 
2683     if (val == NULL)
2684 	return(xmlXPathCacheNewCString(ctxt, ""));
2685 
2686     switch (val->type) {
2687     case XPATH_UNDEFINED:
2688 #ifdef DEBUG_EXPR
2689 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2690 #endif
2691 	break;
2692     case XPATH_NODESET:
2693     case XPATH_XSLT_TREE:
2694 	res = xmlXPathCastNodeSetToString(val->nodesetval);
2695 	break;
2696     case XPATH_STRING:
2697 	return(val);
2698     case XPATH_BOOLEAN:
2699 	res = xmlXPathCastBooleanToString(val->boolval);
2700 	break;
2701     case XPATH_NUMBER:
2702 	res = xmlXPathCastNumberToString(val->floatval);
2703 	break;
2704     case XPATH_USERS:
2705     case XPATH_POINT:
2706     case XPATH_RANGE:
2707     case XPATH_LOCATIONSET:
2708 	TODO;
2709 	break;
2710     }
2711     xmlXPathReleaseObject(ctxt, val);
2712     if (res == NULL)
2713 	return(xmlXPathCacheNewCString(ctxt, ""));
2714     return(xmlXPathCacheWrapString(ctxt, res));
2715 }
2716 
2717 /**
2718  * xmlXPathCacheObjectCopy:
2719  * @ctxt: the XPath context
2720  * @val:  the original object
2721  *
2722  * This is the cached version of xmlXPathObjectCopy().
2723  * Acquire a copy of a given object
2724  *
2725  * Returns a created or reused created object.
2726  */
2727 static xmlXPathObjectPtr
2728 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2729 {
2730     if (val == NULL)
2731 	return(NULL);
2732 
2733     if (XP_HAS_CACHE(ctxt)) {
2734 	switch (val->type) {
2735 	    case XPATH_NODESET:
2736 		return(xmlXPathCacheWrapNodeSet(ctxt,
2737 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2738 	    case XPATH_STRING:
2739 		return(xmlXPathCacheNewString(ctxt, val->stringval));
2740 	    case XPATH_BOOLEAN:
2741 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2742 	    case XPATH_NUMBER:
2743 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2744 	    default:
2745 		break;
2746 	}
2747     }
2748     return(xmlXPathObjectCopy(val));
2749 }
2750 
2751 /**
2752  * xmlXPathCacheConvertBoolean:
2753  * @ctxt: the XPath context
2754  * @val:  an XPath object
2755  *
2756  * This is the cached version of xmlXPathConvertBoolean().
2757  * Converts an existing object to its boolean() equivalent
2758  *
2759  * Returns a created or reused object, the old one is freed (or the operation
2760  *         is done directly on @val)
2761  */
2762 static xmlXPathObjectPtr
2763 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2764     xmlXPathObjectPtr ret;
2765 
2766     if (val == NULL)
2767 	return(xmlXPathCacheNewBoolean(ctxt, 0));
2768     if (val->type == XPATH_BOOLEAN)
2769 	return(val);
2770     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2771     xmlXPathReleaseObject(ctxt, val);
2772     return(ret);
2773 }
2774 
2775 /**
2776  * xmlXPathCacheConvertNumber:
2777  * @ctxt: the XPath context
2778  * @val:  an XPath object
2779  *
2780  * This is the cached version of xmlXPathConvertNumber().
2781  * Converts an existing object to its number() equivalent
2782  *
2783  * Returns a created or reused object, the old one is freed (or the operation
2784  *         is done directly on @val)
2785  */
2786 static xmlXPathObjectPtr
2787 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2788     xmlXPathObjectPtr ret;
2789 
2790     if (val == NULL)
2791 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
2792     if (val->type == XPATH_NUMBER)
2793 	return(val);
2794     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2795     xmlXPathReleaseObject(ctxt, val);
2796     return(ret);
2797 }
2798 
2799 /************************************************************************
2800  *									*
2801  *		Parser stacks related functions and macros		*
2802  *									*
2803  ************************************************************************/
2804 
2805 /**
2806  * xmlXPathSetFrame:
2807  * @ctxt: an XPath parser context
2808  *
2809  * Set the callee evaluation frame
2810  *
2811  * Returns the previous frame value to be restored once done
2812  */
2813 static int
2814 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2815     int ret;
2816 
2817     if (ctxt == NULL)
2818         return(0);
2819     ret = ctxt->valueFrame;
2820     ctxt->valueFrame = ctxt->valueNr;
2821     return(ret);
2822 }
2823 
2824 /**
2825  * xmlXPathPopFrame:
2826  * @ctxt: an XPath parser context
2827  * @frame: the previous frame value
2828  *
2829  * Remove the callee evaluation frame
2830  */
2831 static void
2832 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2833     if (ctxt == NULL)
2834         return;
2835     if (ctxt->valueNr < ctxt->valueFrame) {
2836         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2837     }
2838     ctxt->valueFrame = frame;
2839 }
2840 
2841 /**
2842  * valuePop:
2843  * @ctxt: an XPath evaluation context
2844  *
2845  * Pops the top XPath object from the value stack
2846  *
2847  * Returns the XPath object just removed
2848  */
2849 xmlXPathObjectPtr
2850 valuePop(xmlXPathParserContextPtr ctxt)
2851 {
2852     xmlXPathObjectPtr ret;
2853 
2854     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2855         return (NULL);
2856 
2857     if (ctxt->valueNr <= ctxt->valueFrame) {
2858         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2859         return (NULL);
2860     }
2861 
2862     ctxt->valueNr--;
2863     if (ctxt->valueNr > 0)
2864         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2865     else
2866         ctxt->value = NULL;
2867     ret = ctxt->valueTab[ctxt->valueNr];
2868     ctxt->valueTab[ctxt->valueNr] = NULL;
2869     return (ret);
2870 }
2871 /**
2872  * valuePush:
2873  * @ctxt:  an XPath evaluation context
2874  * @value:  the XPath object
2875  *
2876  * Pushes a new XPath object on top of the value stack. If value is NULL,
2877  * a memory error is recorded in the parser context.
2878  *
2879  * Returns the number of items on the value stack, or -1 in case of error.
2880  */
2881 int
2882 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2883 {
2884     if (ctxt == NULL) return(-1);
2885     if (value == NULL) {
2886         /*
2887          * A NULL value typically indicates that a memory allocation failed,
2888          * so we set ctxt->error here to propagate the error.
2889          */
2890 	ctxt->error = XPATH_MEMORY_ERROR;
2891         return(-1);
2892     }
2893     if (ctxt->valueNr >= ctxt->valueMax) {
2894         xmlXPathObjectPtr *tmp;
2895 
2896         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2897             xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2898             return (-1);
2899         }
2900         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2901                                              2 * ctxt->valueMax *
2902                                              sizeof(ctxt->valueTab[0]));
2903         if (tmp == NULL) {
2904             xmlXPathPErrMemory(ctxt, "pushing value\n");
2905             return (-1);
2906         }
2907         ctxt->valueMax *= 2;
2908 	ctxt->valueTab = tmp;
2909     }
2910     ctxt->valueTab[ctxt->valueNr] = value;
2911     ctxt->value = value;
2912     return (ctxt->valueNr++);
2913 }
2914 
2915 /**
2916  * xmlXPathPopBoolean:
2917  * @ctxt:  an XPath parser context
2918  *
2919  * Pops a boolean from the stack, handling conversion if needed.
2920  * Check error with #xmlXPathCheckError.
2921  *
2922  * Returns the boolean
2923  */
2924 int
2925 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2926     xmlXPathObjectPtr obj;
2927     int ret;
2928 
2929     obj = valuePop(ctxt);
2930     if (obj == NULL) {
2931 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2932 	return(0);
2933     }
2934     if (obj->type != XPATH_BOOLEAN)
2935 	ret = xmlXPathCastToBoolean(obj);
2936     else
2937         ret = obj->boolval;
2938     xmlXPathReleaseObject(ctxt->context, obj);
2939     return(ret);
2940 }
2941 
2942 /**
2943  * xmlXPathPopNumber:
2944  * @ctxt:  an XPath parser context
2945  *
2946  * Pops a number from the stack, handling conversion if needed.
2947  * Check error with #xmlXPathCheckError.
2948  *
2949  * Returns the number
2950  */
2951 double
2952 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2953     xmlXPathObjectPtr obj;
2954     double ret;
2955 
2956     obj = valuePop(ctxt);
2957     if (obj == NULL) {
2958 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2959 	return(0);
2960     }
2961     if (obj->type != XPATH_NUMBER)
2962 	ret = xmlXPathCastToNumber(obj);
2963     else
2964         ret = obj->floatval;
2965     xmlXPathReleaseObject(ctxt->context, obj);
2966     return(ret);
2967 }
2968 
2969 /**
2970  * xmlXPathPopString:
2971  * @ctxt:  an XPath parser context
2972  *
2973  * Pops a string from the stack, handling conversion if needed.
2974  * Check error with #xmlXPathCheckError.
2975  *
2976  * Returns the string
2977  */
2978 xmlChar *
2979 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2980     xmlXPathObjectPtr obj;
2981     xmlChar * ret;
2982 
2983     obj = valuePop(ctxt);
2984     if (obj == NULL) {
2985 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2986 	return(NULL);
2987     }
2988     ret = xmlXPathCastToString(obj);	/* this does required strdup */
2989     /* TODO: needs refactoring somewhere else */
2990     if (obj->stringval == ret)
2991 	obj->stringval = NULL;
2992     xmlXPathReleaseObject(ctxt->context, obj);
2993     return(ret);
2994 }
2995 
2996 /**
2997  * xmlXPathPopNodeSet:
2998  * @ctxt:  an XPath parser context
2999  *
3000  * Pops a node-set from the stack, handling conversion if needed.
3001  * Check error with #xmlXPathCheckError.
3002  *
3003  * Returns the node-set
3004  */
3005 xmlNodeSetPtr
3006 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3007     xmlXPathObjectPtr obj;
3008     xmlNodeSetPtr ret;
3009 
3010     if (ctxt == NULL) return(NULL);
3011     if (ctxt->value == NULL) {
3012 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3013 	return(NULL);
3014     }
3015     if (!xmlXPathStackIsNodeSet(ctxt)) {
3016 	xmlXPathSetTypeError(ctxt);
3017 	return(NULL);
3018     }
3019     obj = valuePop(ctxt);
3020     ret = obj->nodesetval;
3021 #if 0
3022     /* to fix memory leak of not clearing obj->user */
3023     if (obj->boolval && obj->user != NULL)
3024         xmlFreeNodeList((xmlNodePtr) obj->user);
3025 #endif
3026     obj->nodesetval = NULL;
3027     xmlXPathReleaseObject(ctxt->context, obj);
3028     return(ret);
3029 }
3030 
3031 /**
3032  * xmlXPathPopExternal:
3033  * @ctxt:  an XPath parser context
3034  *
3035  * Pops an external object from the stack, handling conversion if needed.
3036  * Check error with #xmlXPathCheckError.
3037  *
3038  * Returns the object
3039  */
3040 void *
3041 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3042     xmlXPathObjectPtr obj;
3043     void * ret;
3044 
3045     if ((ctxt == NULL) || (ctxt->value == NULL)) {
3046 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3047 	return(NULL);
3048     }
3049     if (ctxt->value->type != XPATH_USERS) {
3050 	xmlXPathSetTypeError(ctxt);
3051 	return(NULL);
3052     }
3053     obj = valuePop(ctxt);
3054     ret = obj->user;
3055     obj->user = NULL;
3056     xmlXPathReleaseObject(ctxt->context, obj);
3057     return(ret);
3058 }
3059 
3060 /*
3061  * Macros for accessing the content. Those should be used only by the parser,
3062  * and not exported.
3063  *
3064  * Dirty macros, i.e. one need to make assumption on the context to use them
3065  *
3066  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3067  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3068  *           in ISO-Latin or UTF-8.
3069  *           This should be used internally by the parser
3070  *           only to compare to ASCII values otherwise it would break when
3071  *           running with UTF-8 encoding.
3072  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3073  *           to compare on ASCII based substring.
3074  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3075  *           strings within the parser.
3076  *   CURRENT Returns the current char value, with the full decoding of
3077  *           UTF-8 if we are using this mode. It returns an int.
3078  *   NEXT    Skip to the next character, this does the proper decoding
3079  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3080  *           It returns the pointer to the current xmlChar.
3081  */
3082 
3083 #define CUR (*ctxt->cur)
3084 #define SKIP(val) ctxt->cur += (val)
3085 #define NXT(val) ctxt->cur[(val)]
3086 #define CUR_PTR ctxt->cur
3087 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3088 
3089 #define COPY_BUF(l,b,i,v)                                              \
3090     if (l == 1) b[i++] = (xmlChar) v;                                  \
3091     else i += xmlCopyChar(l,&b[i],v)
3092 
3093 #define NEXTL(l)  ctxt->cur += l
3094 
3095 #define SKIP_BLANKS							\
3096     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3097 
3098 #define CURRENT (*ctxt->cur)
3099 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3100 
3101 
3102 #ifndef DBL_DIG
3103 #define DBL_DIG 16
3104 #endif
3105 #ifndef DBL_EPSILON
3106 #define DBL_EPSILON 1E-9
3107 #endif
3108 
3109 #define UPPER_DOUBLE 1E9
3110 #define LOWER_DOUBLE 1E-5
3111 #define	LOWER_DOUBLE_EXP 5
3112 
3113 #define INTEGER_DIGITS DBL_DIG
3114 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3115 #define EXPONENT_DIGITS (3 + 2)
3116 
3117 /**
3118  * xmlXPathFormatNumber:
3119  * @number:     number to format
3120  * @buffer:     output buffer
3121  * @buffersize: size of output buffer
3122  *
3123  * Convert the number into a string representation.
3124  */
3125 static void
3126 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3127 {
3128     switch (xmlXPathIsInf(number)) {
3129     case 1:
3130 	if (buffersize > (int)sizeof("Infinity"))
3131 	    snprintf(buffer, buffersize, "Infinity");
3132 	break;
3133     case -1:
3134 	if (buffersize > (int)sizeof("-Infinity"))
3135 	    snprintf(buffer, buffersize, "-Infinity");
3136 	break;
3137     default:
3138 	if (xmlXPathIsNaN(number)) {
3139 	    if (buffersize > (int)sizeof("NaN"))
3140 		snprintf(buffer, buffersize, "NaN");
3141 	} else if (number == 0) {
3142             /* Omit sign for negative zero. */
3143 	    snprintf(buffer, buffersize, "0");
3144 	} else if ((number > INT_MIN) && (number < INT_MAX) &&
3145                    (number == (int) number)) {
3146 	    char work[30];
3147 	    char *ptr, *cur;
3148 	    int value = (int) number;
3149 
3150             ptr = &buffer[0];
3151 	    if (value == 0) {
3152 		*ptr++ = '0';
3153 	    } else {
3154 		snprintf(work, 29, "%d", value);
3155 		cur = &work[0];
3156 		while ((*cur) && (ptr - buffer < buffersize)) {
3157 		    *ptr++ = *cur++;
3158 		}
3159 	    }
3160 	    if (ptr - buffer < buffersize) {
3161 		*ptr = 0;
3162 	    } else if (buffersize > 0) {
3163 		ptr--;
3164 		*ptr = 0;
3165 	    }
3166 	} else {
3167 	    /*
3168 	      For the dimension of work,
3169 	          DBL_DIG is number of significant digits
3170 		  EXPONENT is only needed for "scientific notation"
3171 	          3 is sign, decimal point, and terminating zero
3172 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3173 	      Note that this dimension is slightly (a few characters)
3174 	      larger than actually necessary.
3175 	    */
3176 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3177 	    int integer_place, fraction_place;
3178 	    char *ptr;
3179 	    char *after_fraction;
3180 	    double absolute_value;
3181 	    int size;
3182 
3183 	    absolute_value = fabs(number);
3184 
3185 	    /*
3186 	     * First choose format - scientific or regular floating point.
3187 	     * In either case, result is in work, and after_fraction points
3188 	     * just past the fractional part.
3189 	    */
3190 	    if ( ((absolute_value > UPPER_DOUBLE) ||
3191 		  (absolute_value < LOWER_DOUBLE)) &&
3192 		 (absolute_value != 0.0) ) {
3193 		/* Use scientific notation */
3194 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3195 		fraction_place = DBL_DIG - 1;
3196 		size = snprintf(work, sizeof(work),"%*.*e",
3197 			 integer_place, fraction_place, number);
3198 		while ((size > 0) && (work[size] != 'e')) size--;
3199 
3200 	    }
3201 	    else {
3202 		/* Use regular notation */
3203 		if (absolute_value > 0.0) {
3204 		    integer_place = (int)log10(absolute_value);
3205 		    if (integer_place > 0)
3206 		        fraction_place = DBL_DIG - integer_place - 1;
3207 		    else
3208 		        fraction_place = DBL_DIG - integer_place;
3209 		} else {
3210 		    fraction_place = 1;
3211 		}
3212 		size = snprintf(work, sizeof(work), "%0.*f",
3213 				fraction_place, number);
3214 	    }
3215 
3216 	    /* Remove leading spaces sometimes inserted by snprintf */
3217 	    while (work[0] == ' ') {
3218 	        for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3219 		size--;
3220 	    }
3221 
3222 	    /* Remove fractional trailing zeroes */
3223 	    after_fraction = work + size;
3224 	    ptr = after_fraction;
3225 	    while (*(--ptr) == '0')
3226 		;
3227 	    if (*ptr != '.')
3228 	        ptr++;
3229 	    while ((*ptr++ = *after_fraction++) != 0);
3230 
3231 	    /* Finally copy result back to caller */
3232 	    size = strlen(work) + 1;
3233 	    if (size > buffersize) {
3234 		work[buffersize - 1] = 0;
3235 		size = buffersize;
3236 	    }
3237 	    memmove(buffer, work, size);
3238 	}
3239 	break;
3240     }
3241 }
3242 
3243 
3244 /************************************************************************
3245  *									*
3246  *			Routines to handle NodeSets			*
3247  *									*
3248  ************************************************************************/
3249 
3250 /**
3251  * xmlXPathOrderDocElems:
3252  * @doc:  an input document
3253  *
3254  * Call this routine to speed up XPath computation on static documents.
3255  * This stamps all the element nodes with the document order
3256  * Like for line information, the order is kept in the element->content
3257  * field, the value stored is actually - the node number (starting at -1)
3258  * to be able to differentiate from line numbers.
3259  *
3260  * Returns the number of elements found in the document or -1 in case
3261  *    of error.
3262  */
3263 long
3264 xmlXPathOrderDocElems(xmlDocPtr doc) {
3265     ptrdiff_t count = 0;
3266     xmlNodePtr cur;
3267 
3268     if (doc == NULL)
3269 	return(-1);
3270     cur = doc->children;
3271     while (cur != NULL) {
3272 	if (cur->type == XML_ELEMENT_NODE) {
3273 	    cur->content = (void *) (-(++count));
3274 	    if (cur->children != NULL) {
3275 		cur = cur->children;
3276 		continue;
3277 	    }
3278 	}
3279 	if (cur->next != NULL) {
3280 	    cur = cur->next;
3281 	    continue;
3282 	}
3283 	do {
3284 	    cur = cur->parent;
3285 	    if (cur == NULL)
3286 		break;
3287 	    if (cur == (xmlNodePtr) doc) {
3288 		cur = NULL;
3289 		break;
3290 	    }
3291 	    if (cur->next != NULL) {
3292 		cur = cur->next;
3293 		break;
3294 	    }
3295 	} while (cur != NULL);
3296     }
3297     return((long) count);
3298 }
3299 
3300 /**
3301  * xmlXPathCmpNodes:
3302  * @node1:  the first node
3303  * @node2:  the second node
3304  *
3305  * Compare two nodes w.r.t document order
3306  *
3307  * Returns -2 in case of error 1 if first point < second point, 0 if
3308  *         it's the same node, -1 otherwise
3309  */
3310 int
3311 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3312     int depth1, depth2;
3313     int attr1 = 0, attr2 = 0;
3314     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3315     xmlNodePtr cur, root;
3316 
3317     if ((node1 == NULL) || (node2 == NULL))
3318 	return(-2);
3319     /*
3320      * a couple of optimizations which will avoid computations in most cases
3321      */
3322     if (node1 == node2)		/* trivial case */
3323 	return(0);
3324     if (node1->type == XML_ATTRIBUTE_NODE) {
3325 	attr1 = 1;
3326 	attrNode1 = node1;
3327 	node1 = node1->parent;
3328     }
3329     if (node2->type == XML_ATTRIBUTE_NODE) {
3330 	attr2 = 1;
3331 	attrNode2 = node2;
3332 	node2 = node2->parent;
3333     }
3334     if (node1 == node2) {
3335 	if (attr1 == attr2) {
3336 	    /* not required, but we keep attributes in order */
3337 	    if (attr1 != 0) {
3338 	        cur = attrNode2->prev;
3339 		while (cur != NULL) {
3340 		    if (cur == attrNode1)
3341 		        return (1);
3342 		    cur = cur->prev;
3343 		}
3344 		return (-1);
3345 	    }
3346 	    return(0);
3347 	}
3348 	if (attr2 == 1)
3349 	    return(1);
3350 	return(-1);
3351     }
3352     if ((node1->type == XML_NAMESPACE_DECL) ||
3353         (node2->type == XML_NAMESPACE_DECL))
3354 	return(1);
3355     if (node1 == node2->prev)
3356 	return(1);
3357     if (node1 == node2->next)
3358 	return(-1);
3359 
3360     /*
3361      * Speedup using document order if available.
3362      */
3363     if ((node1->type == XML_ELEMENT_NODE) &&
3364 	(node2->type == XML_ELEMENT_NODE) &&
3365 	(0 > (ptrdiff_t) node1->content) &&
3366 	(0 > (ptrdiff_t) node2->content) &&
3367 	(node1->doc == node2->doc)) {
3368 	ptrdiff_t l1, l2;
3369 
3370 	l1 = -((ptrdiff_t) node1->content);
3371 	l2 = -((ptrdiff_t) node2->content);
3372 	if (l1 < l2)
3373 	    return(1);
3374 	if (l1 > l2)
3375 	    return(-1);
3376     }
3377 
3378     /*
3379      * compute depth to root
3380      */
3381     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3382 	if (cur->parent == node1)
3383 	    return(1);
3384 	depth2++;
3385     }
3386     root = cur;
3387     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3388 	if (cur->parent == node2)
3389 	    return(-1);
3390 	depth1++;
3391     }
3392     /*
3393      * Distinct document (or distinct entities :-( ) case.
3394      */
3395     if (root != cur) {
3396 	return(-2);
3397     }
3398     /*
3399      * get the nearest common ancestor.
3400      */
3401     while (depth1 > depth2) {
3402 	depth1--;
3403 	node1 = node1->parent;
3404     }
3405     while (depth2 > depth1) {
3406 	depth2--;
3407 	node2 = node2->parent;
3408     }
3409     while (node1->parent != node2->parent) {
3410 	node1 = node1->parent;
3411 	node2 = node2->parent;
3412 	/* should not happen but just in case ... */
3413 	if ((node1 == NULL) || (node2 == NULL))
3414 	    return(-2);
3415     }
3416     /*
3417      * Find who's first.
3418      */
3419     if (node1 == node2->prev)
3420 	return(1);
3421     if (node1 == node2->next)
3422 	return(-1);
3423     /*
3424      * Speedup using document order if available.
3425      */
3426     if ((node1->type == XML_ELEMENT_NODE) &&
3427 	(node2->type == XML_ELEMENT_NODE) &&
3428 	(0 > (ptrdiff_t) node1->content) &&
3429 	(0 > (ptrdiff_t) node2->content) &&
3430 	(node1->doc == node2->doc)) {
3431 	ptrdiff_t l1, l2;
3432 
3433 	l1 = -((ptrdiff_t) node1->content);
3434 	l2 = -((ptrdiff_t) node2->content);
3435 	if (l1 < l2)
3436 	    return(1);
3437 	if (l1 > l2)
3438 	    return(-1);
3439     }
3440 
3441     for (cur = node1->next;cur != NULL;cur = cur->next)
3442 	if (cur == node2)
3443 	    return(1);
3444     return(-1); /* assume there is no sibling list corruption */
3445 }
3446 
3447 /**
3448  * xmlXPathNodeSetSort:
3449  * @set:  the node set
3450  *
3451  * Sort the node set in document order
3452  */
3453 void
3454 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3455 #ifndef WITH_TIM_SORT
3456     int i, j, incr, len;
3457     xmlNodePtr tmp;
3458 #endif
3459 
3460     if (set == NULL)
3461 	return;
3462 
3463 #ifndef WITH_TIM_SORT
3464     /*
3465      * Use the old Shell's sort implementation to sort the node-set
3466      * Timsort ought to be quite faster
3467      */
3468     len = set->nodeNr;
3469     for (incr = len / 2; incr > 0; incr /= 2) {
3470 	for (i = incr; i < len; i++) {
3471 	    j = i - incr;
3472 	    while (j >= 0) {
3473 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3474 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
3475 			set->nodeTab[j + incr]) == -1)
3476 #else
3477 		if (xmlXPathCmpNodes(set->nodeTab[j],
3478 			set->nodeTab[j + incr]) == -1)
3479 #endif
3480 		{
3481 		    tmp = set->nodeTab[j];
3482 		    set->nodeTab[j] = set->nodeTab[j + incr];
3483 		    set->nodeTab[j + incr] = tmp;
3484 		    j -= incr;
3485 		} else
3486 		    break;
3487 	    }
3488 	}
3489     }
3490 #else /* WITH_TIM_SORT */
3491     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3492 #endif /* WITH_TIM_SORT */
3493 }
3494 
3495 #define XML_NODESET_DEFAULT	10
3496 /**
3497  * xmlXPathNodeSetDupNs:
3498  * @node:  the parent node of the namespace XPath node
3499  * @ns:  the libxml namespace declaration node.
3500  *
3501  * Namespace node in libxml don't match the XPath semantic. In a node set
3502  * the namespace nodes are duplicated and the next pointer is set to the
3503  * parent node in the XPath semantic.
3504  *
3505  * Returns the newly created object.
3506  */
3507 static xmlNodePtr
3508 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3509     xmlNsPtr cur;
3510 
3511     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3512 	return(NULL);
3513     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3514 	return((xmlNodePtr) ns);
3515 
3516     /*
3517      * Allocate a new Namespace and fill the fields.
3518      */
3519     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3520     if (cur == NULL) {
3521         xmlXPathErrMemory(NULL, "duplicating namespace\n");
3522 	return(NULL);
3523     }
3524     memset(cur, 0, sizeof(xmlNs));
3525     cur->type = XML_NAMESPACE_DECL;
3526     if (ns->href != NULL)
3527 	cur->href = xmlStrdup(ns->href);
3528     if (ns->prefix != NULL)
3529 	cur->prefix = xmlStrdup(ns->prefix);
3530     cur->next = (xmlNsPtr) node;
3531     return((xmlNodePtr) cur);
3532 }
3533 
3534 /**
3535  * xmlXPathNodeSetFreeNs:
3536  * @ns:  the XPath namespace node found in a nodeset.
3537  *
3538  * Namespace nodes in libxml don't match the XPath semantic. In a node set
3539  * the namespace nodes are duplicated and the next pointer is set to the
3540  * parent node in the XPath semantic. Check if such a node needs to be freed
3541  */
3542 void
3543 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3544     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3545 	return;
3546 
3547     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3548 	if (ns->href != NULL)
3549 	    xmlFree((xmlChar *)ns->href);
3550 	if (ns->prefix != NULL)
3551 	    xmlFree((xmlChar *)ns->prefix);
3552 	xmlFree(ns);
3553     }
3554 }
3555 
3556 /**
3557  * xmlXPathNodeSetCreate:
3558  * @val:  an initial xmlNodePtr, or NULL
3559  *
3560  * Create a new xmlNodeSetPtr of type double and of value @val
3561  *
3562  * Returns the newly created object.
3563  */
3564 xmlNodeSetPtr
3565 xmlXPathNodeSetCreate(xmlNodePtr val) {
3566     xmlNodeSetPtr ret;
3567 
3568     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3569     if (ret == NULL) {
3570         xmlXPathErrMemory(NULL, "creating nodeset\n");
3571 	return(NULL);
3572     }
3573     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3574     if (val != NULL) {
3575         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3576 					     sizeof(xmlNodePtr));
3577 	if (ret->nodeTab == NULL) {
3578 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
3579 	    xmlFree(ret);
3580 	    return(NULL);
3581 	}
3582 	memset(ret->nodeTab, 0 ,
3583 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3584         ret->nodeMax = XML_NODESET_DEFAULT;
3585 	if (val->type == XML_NAMESPACE_DECL) {
3586 	    xmlNsPtr ns = (xmlNsPtr) val;
3587 
3588             /* TODO: Check memory error. */
3589 	    ret->nodeTab[ret->nodeNr++] =
3590 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3591 	} else
3592 	    ret->nodeTab[ret->nodeNr++] = val;
3593     }
3594     return(ret);
3595 }
3596 
3597 /**
3598  * xmlXPathNodeSetContains:
3599  * @cur:  the node-set
3600  * @val:  the node
3601  *
3602  * checks whether @cur contains @val
3603  *
3604  * Returns true (1) if @cur contains @val, false (0) otherwise
3605  */
3606 int
3607 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3608     int i;
3609 
3610     if ((cur == NULL) || (val == NULL)) return(0);
3611     if (val->type == XML_NAMESPACE_DECL) {
3612 	for (i = 0; i < cur->nodeNr; i++) {
3613 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3614 		xmlNsPtr ns1, ns2;
3615 
3616 		ns1 = (xmlNsPtr) val;
3617 		ns2 = (xmlNsPtr) cur->nodeTab[i];
3618 		if (ns1 == ns2)
3619 		    return(1);
3620 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3621 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
3622 		    return(1);
3623 	    }
3624 	}
3625     } else {
3626 	for (i = 0; i < cur->nodeNr; i++) {
3627 	    if (cur->nodeTab[i] == val)
3628 		return(1);
3629 	}
3630     }
3631     return(0);
3632 }
3633 
3634 /**
3635  * xmlXPathNodeSetAddNs:
3636  * @cur:  the initial node set
3637  * @node:  the hosting node
3638  * @ns:  a the namespace node
3639  *
3640  * add a new namespace node to an existing NodeSet
3641  *
3642  * Returns 0 in case of success and -1 in case of error
3643  */
3644 int
3645 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3646     int i;
3647 
3648 
3649     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3650         (ns->type != XML_NAMESPACE_DECL) ||
3651 	(node->type != XML_ELEMENT_NODE))
3652 	return(-1);
3653 
3654     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3655     /*
3656      * prevent duplicates
3657      */
3658     for (i = 0;i < cur->nodeNr;i++) {
3659         if ((cur->nodeTab[i] != NULL) &&
3660 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3661 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3662 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3663 	    return(0);
3664     }
3665 
3666     /*
3667      * grow the nodeTab if needed
3668      */
3669     if (cur->nodeMax == 0) {
3670         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3671 					     sizeof(xmlNodePtr));
3672 	if (cur->nodeTab == NULL) {
3673 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3674 	    return(-1);
3675 	}
3676 	memset(cur->nodeTab, 0 ,
3677 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3678         cur->nodeMax = XML_NODESET_DEFAULT;
3679     } else if (cur->nodeNr == cur->nodeMax) {
3680         xmlNodePtr *temp;
3681 
3682         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3683             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3684             return(-1);
3685         }
3686 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3687 				      sizeof(xmlNodePtr));
3688 	if (temp == NULL) {
3689 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3690 	    return(-1);
3691 	}
3692         cur->nodeMax *= 2;
3693 	cur->nodeTab = temp;
3694     }
3695     /* TODO: Check memory error. */
3696     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3697     return(0);
3698 }
3699 
3700 /**
3701  * xmlXPathNodeSetAdd:
3702  * @cur:  the initial node set
3703  * @val:  a new xmlNodePtr
3704  *
3705  * add a new xmlNodePtr to an existing NodeSet
3706  *
3707  * Returns 0 in case of success, and -1 in case of error
3708  */
3709 int
3710 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3711     int i;
3712 
3713     if ((cur == NULL) || (val == NULL)) return(-1);
3714 
3715     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3716     /*
3717      * prevent duplicates
3718      */
3719     for (i = 0;i < cur->nodeNr;i++)
3720         if (cur->nodeTab[i] == val) return(0);
3721 
3722     /*
3723      * grow the nodeTab if needed
3724      */
3725     if (cur->nodeMax == 0) {
3726         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3727 					     sizeof(xmlNodePtr));
3728 	if (cur->nodeTab == NULL) {
3729 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3730 	    return(-1);
3731 	}
3732 	memset(cur->nodeTab, 0 ,
3733 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3734         cur->nodeMax = XML_NODESET_DEFAULT;
3735     } else if (cur->nodeNr == cur->nodeMax) {
3736         xmlNodePtr *temp;
3737 
3738         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3739             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3740             return(-1);
3741         }
3742 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3743 				      sizeof(xmlNodePtr));
3744 	if (temp == NULL) {
3745 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3746 	    return(-1);
3747 	}
3748         cur->nodeMax *= 2;
3749 	cur->nodeTab = temp;
3750     }
3751     if (val->type == XML_NAMESPACE_DECL) {
3752 	xmlNsPtr ns = (xmlNsPtr) val;
3753 
3754         /* TODO: Check memory error. */
3755 	cur->nodeTab[cur->nodeNr++] =
3756 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3757     } else
3758 	cur->nodeTab[cur->nodeNr++] = val;
3759     return(0);
3760 }
3761 
3762 /**
3763  * xmlXPathNodeSetAddUnique:
3764  * @cur:  the initial node set
3765  * @val:  a new xmlNodePtr
3766  *
3767  * add a new xmlNodePtr to an existing NodeSet, optimized version
3768  * when we are sure the node is not already in the set.
3769  *
3770  * Returns 0 in case of success and -1 in case of failure
3771  */
3772 int
3773 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3774     if ((cur == NULL) || (val == NULL)) return(-1);
3775 
3776     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3777     /*
3778      * grow the nodeTab if needed
3779      */
3780     if (cur->nodeMax == 0) {
3781         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3782 					     sizeof(xmlNodePtr));
3783 	if (cur->nodeTab == NULL) {
3784 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3785 	    return(-1);
3786 	}
3787 	memset(cur->nodeTab, 0 ,
3788 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3789         cur->nodeMax = XML_NODESET_DEFAULT;
3790     } else if (cur->nodeNr == cur->nodeMax) {
3791         xmlNodePtr *temp;
3792 
3793         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3794             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3795             return(-1);
3796         }
3797 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3798 				      sizeof(xmlNodePtr));
3799 	if (temp == NULL) {
3800 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3801 	    return(-1);
3802 	}
3803 	cur->nodeTab = temp;
3804         cur->nodeMax *= 2;
3805     }
3806     if (val->type == XML_NAMESPACE_DECL) {
3807 	xmlNsPtr ns = (xmlNsPtr) val;
3808 
3809         /* TODO: Check memory error. */
3810 	cur->nodeTab[cur->nodeNr++] =
3811 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3812     } else
3813 	cur->nodeTab[cur->nodeNr++] = val;
3814     return(0);
3815 }
3816 
3817 /**
3818  * xmlXPathNodeSetMerge:
3819  * @val1:  the first NodeSet or NULL
3820  * @val2:  the second NodeSet
3821  *
3822  * Merges two nodesets, all nodes from @val2 are added to @val1
3823  * if @val1 is NULL, a new set is created and copied from @val2
3824  *
3825  * Returns @val1 once extended or NULL in case of error.
3826  */
3827 xmlNodeSetPtr
3828 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3829     int i, j, initNr, skip;
3830     xmlNodePtr n1, n2;
3831 
3832     if (val2 == NULL) return(val1);
3833     if (val1 == NULL) {
3834 	val1 = xmlXPathNodeSetCreate(NULL);
3835     if (val1 == NULL)
3836         return (NULL);
3837 #if 0
3838 	/*
3839 	* TODO: The optimization won't work in every case, since
3840 	*  those nasty namespace nodes need to be added with
3841 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
3842 	*  memcpy is not possible.
3843 	*  If there was a flag on the nodesetval, indicating that
3844 	*  some temporary nodes are in, that would be helpful.
3845 	*/
3846 	/*
3847 	* Optimization: Create an equally sized node-set
3848 	* and memcpy the content.
3849 	*/
3850 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3851 	if (val1 == NULL)
3852 	    return(NULL);
3853 	if (val2->nodeNr != 0) {
3854 	    if (val2->nodeNr == 1)
3855 		*(val1->nodeTab) = *(val2->nodeTab);
3856 	    else {
3857 		memcpy(val1->nodeTab, val2->nodeTab,
3858 		    val2->nodeNr * sizeof(xmlNodePtr));
3859 	    }
3860 	    val1->nodeNr = val2->nodeNr;
3861 	}
3862 	return(val1);
3863 #endif
3864     }
3865 
3866     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3867     initNr = val1->nodeNr;
3868 
3869     for (i = 0;i < val2->nodeNr;i++) {
3870 	n2 = val2->nodeTab[i];
3871 	/*
3872 	 * check against duplicates
3873 	 */
3874 	skip = 0;
3875 	for (j = 0; j < initNr; j++) {
3876 	    n1 = val1->nodeTab[j];
3877 	    if (n1 == n2) {
3878 		skip = 1;
3879 		break;
3880 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3881 		       (n2->type == XML_NAMESPACE_DECL)) {
3882 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3883 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3884 			((xmlNsPtr) n2)->prefix)))
3885 		{
3886 		    skip = 1;
3887 		    break;
3888 		}
3889 	    }
3890 	}
3891 	if (skip)
3892 	    continue;
3893 
3894 	/*
3895 	 * grow the nodeTab if needed
3896 	 */
3897 	if (val1->nodeMax == 0) {
3898 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3899 						    sizeof(xmlNodePtr));
3900 	    if (val1->nodeTab == NULL) {
3901 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3902 		return(NULL);
3903 	    }
3904 	    memset(val1->nodeTab, 0 ,
3905 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3906 	    val1->nodeMax = XML_NODESET_DEFAULT;
3907 	} else if (val1->nodeNr == val1->nodeMax) {
3908 	    xmlNodePtr *temp;
3909 
3910             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3911                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3912                 return(NULL);
3913             }
3914 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3915 					     sizeof(xmlNodePtr));
3916 	    if (temp == NULL) {
3917 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3918 		return(NULL);
3919 	    }
3920 	    val1->nodeTab = temp;
3921 	    val1->nodeMax *= 2;
3922 	}
3923 	if (n2->type == XML_NAMESPACE_DECL) {
3924 	    xmlNsPtr ns = (xmlNsPtr) n2;
3925 
3926             /* TODO: Check memory error. */
3927 	    val1->nodeTab[val1->nodeNr++] =
3928 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3929 	} else
3930 	    val1->nodeTab[val1->nodeNr++] = n2;
3931     }
3932 
3933     return(val1);
3934 }
3935 
3936 
3937 /**
3938  * xmlXPathNodeSetMergeAndClear:
3939  * @set1:  the first NodeSet or NULL
3940  * @set2:  the second NodeSet
3941  *
3942  * Merges two nodesets, all nodes from @set2 are added to @set1.
3943  * Checks for duplicate nodes. Clears set2.
3944  *
3945  * Returns @set1 once extended or NULL in case of error.
3946  */
3947 static xmlNodeSetPtr
3948 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3949 {
3950     {
3951 	int i, j, initNbSet1;
3952 	xmlNodePtr n1, n2;
3953 
3954 	initNbSet1 = set1->nodeNr;
3955 	for (i = 0;i < set2->nodeNr;i++) {
3956 	    n2 = set2->nodeTab[i];
3957 	    /*
3958 	    * Skip duplicates.
3959 	    */
3960 	    for (j = 0; j < initNbSet1; j++) {
3961 		n1 = set1->nodeTab[j];
3962 		if (n1 == n2) {
3963 		    goto skip_node;
3964 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3965 		    (n2->type == XML_NAMESPACE_DECL))
3966 		{
3967 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3968 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3969 			((xmlNsPtr) n2)->prefix)))
3970 		    {
3971 			/*
3972 			* Free the namespace node.
3973 			*/
3974 			set2->nodeTab[i] = NULL;
3975 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3976 			goto skip_node;
3977 		    }
3978 		}
3979 	    }
3980 	    /*
3981 	    * grow the nodeTab if needed
3982 	    */
3983 	    if (set1->nodeMax == 0) {
3984 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3985 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3986 		if (set1->nodeTab == NULL) {
3987 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3988 		    return(NULL);
3989 		}
3990 		memset(set1->nodeTab, 0,
3991 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3992 		set1->nodeMax = XML_NODESET_DEFAULT;
3993 	    } else if (set1->nodeNr >= set1->nodeMax) {
3994 		xmlNodePtr *temp;
3995 
3996                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3997                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3998                     return(NULL);
3999                 }
4000 		temp = (xmlNodePtr *) xmlRealloc(
4001 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4002 		if (temp == NULL) {
4003 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4004 		    return(NULL);
4005 		}
4006 		set1->nodeTab = temp;
4007 		set1->nodeMax *= 2;
4008 	    }
4009 	    set1->nodeTab[set1->nodeNr++] = n2;
4010 skip_node:
4011 	    {}
4012 	}
4013     }
4014     set2->nodeNr = 0;
4015     return(set1);
4016 }
4017 
4018 /**
4019  * xmlXPathNodeSetMergeAndClearNoDupls:
4020  * @set1:  the first NodeSet or NULL
4021  * @set2:  the second NodeSet
4022  *
4023  * Merges two nodesets, all nodes from @set2 are added to @set1.
4024  * Doesn't check for duplicate nodes. Clears set2.
4025  *
4026  * Returns @set1 once extended or NULL in case of error.
4027  */
4028 static xmlNodeSetPtr
4029 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
4030 {
4031     {
4032 	int i;
4033 	xmlNodePtr n2;
4034 
4035 	for (i = 0;i < set2->nodeNr;i++) {
4036 	    n2 = set2->nodeTab[i];
4037 	    if (set1->nodeMax == 0) {
4038 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4039 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4040 		if (set1->nodeTab == NULL) {
4041 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4042 		    return(NULL);
4043 		}
4044 		memset(set1->nodeTab, 0,
4045 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4046 		set1->nodeMax = XML_NODESET_DEFAULT;
4047 	    } else if (set1->nodeNr >= set1->nodeMax) {
4048 		xmlNodePtr *temp;
4049 
4050                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4051                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4052                     return(NULL);
4053                 }
4054 		temp = (xmlNodePtr *) xmlRealloc(
4055 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4056 		if (temp == NULL) {
4057 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4058 		    return(NULL);
4059 		}
4060 		set1->nodeTab = temp;
4061 		set1->nodeMax *= 2;
4062 	    }
4063 	    set1->nodeTab[set1->nodeNr++] = n2;
4064 	}
4065     }
4066     set2->nodeNr = 0;
4067     return(set1);
4068 }
4069 
4070 /**
4071  * xmlXPathNodeSetDel:
4072  * @cur:  the initial node set
4073  * @val:  an xmlNodePtr
4074  *
4075  * Removes an xmlNodePtr from an existing NodeSet
4076  */
4077 void
4078 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4079     int i;
4080 
4081     if (cur == NULL) return;
4082     if (val == NULL) return;
4083 
4084     /*
4085      * find node in nodeTab
4086      */
4087     for (i = 0;i < cur->nodeNr;i++)
4088         if (cur->nodeTab[i] == val) break;
4089 
4090     if (i >= cur->nodeNr) {	/* not found */
4091 #ifdef DEBUG
4092         xmlGenericError(xmlGenericErrorContext,
4093 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4094 		val->name);
4095 #endif
4096         return;
4097     }
4098     if ((cur->nodeTab[i] != NULL) &&
4099 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4100 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4101     cur->nodeNr--;
4102     for (;i < cur->nodeNr;i++)
4103         cur->nodeTab[i] = cur->nodeTab[i + 1];
4104     cur->nodeTab[cur->nodeNr] = NULL;
4105 }
4106 
4107 /**
4108  * xmlXPathNodeSetRemove:
4109  * @cur:  the initial node set
4110  * @val:  the index to remove
4111  *
4112  * Removes an entry from an existing NodeSet list.
4113  */
4114 void
4115 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4116     if (cur == NULL) return;
4117     if (val >= cur->nodeNr) return;
4118     if ((cur->nodeTab[val] != NULL) &&
4119 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4120 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4121     cur->nodeNr--;
4122     for (;val < cur->nodeNr;val++)
4123         cur->nodeTab[val] = cur->nodeTab[val + 1];
4124     cur->nodeTab[cur->nodeNr] = NULL;
4125 }
4126 
4127 /**
4128  * xmlXPathFreeNodeSet:
4129  * @obj:  the xmlNodeSetPtr to free
4130  *
4131  * Free the NodeSet compound (not the actual nodes !).
4132  */
4133 void
4134 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4135     if (obj == NULL) return;
4136     if (obj->nodeTab != NULL) {
4137 	int i;
4138 
4139 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
4140 	for (i = 0;i < obj->nodeNr;i++)
4141 	    if ((obj->nodeTab[i] != NULL) &&
4142 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4143 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4144 	xmlFree(obj->nodeTab);
4145     }
4146     xmlFree(obj);
4147 }
4148 
4149 /**
4150  * xmlXPathNodeSetClearFromPos:
4151  * @set: the node set to be cleared
4152  * @pos: the start position to clear from
4153  *
4154  * Clears the list from temporary XPath objects (e.g. namespace nodes
4155  * are feed) starting with the entry at @pos, but does *not* free the list
4156  * itself. Sets the length of the list to @pos.
4157  */
4158 static void
4159 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4160 {
4161     if ((set == NULL) || (pos >= set->nodeNr))
4162 	return;
4163     else if ((hasNsNodes)) {
4164 	int i;
4165 	xmlNodePtr node;
4166 
4167 	for (i = pos; i < set->nodeNr; i++) {
4168 	    node = set->nodeTab[i];
4169 	    if ((node != NULL) &&
4170 		(node->type == XML_NAMESPACE_DECL))
4171 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4172 	}
4173     }
4174     set->nodeNr = pos;
4175 }
4176 
4177 /**
4178  * xmlXPathNodeSetClear:
4179  * @set:  the node set to clear
4180  *
4181  * Clears the list from all temporary XPath objects (e.g. namespace nodes
4182  * are feed), but does *not* free the list itself. Sets the length of the
4183  * list to 0.
4184  */
4185 static void
4186 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4187 {
4188     xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4189 }
4190 
4191 /**
4192  * xmlXPathNodeSetKeepLast:
4193  * @set: the node set to be cleared
4194  *
4195  * Move the last node to the first position and clear temporary XPath objects
4196  * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4197  * to 1.
4198  */
4199 static void
4200 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4201 {
4202     int i;
4203     xmlNodePtr node;
4204 
4205     if ((set == NULL) || (set->nodeNr <= 1))
4206 	return;
4207     for (i = 0; i < set->nodeNr - 1; i++) {
4208         node = set->nodeTab[i];
4209         if ((node != NULL) &&
4210             (node->type == XML_NAMESPACE_DECL))
4211             xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4212     }
4213     set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4214     set->nodeNr = 1;
4215 }
4216 
4217 /**
4218  * xmlXPathFreeValueTree:
4219  * @obj:  the xmlNodeSetPtr to free
4220  *
4221  * Free the NodeSet compound and the actual tree, this is different
4222  * from xmlXPathFreeNodeSet()
4223  */
4224 static void
4225 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4226     int i;
4227 
4228     if (obj == NULL) return;
4229 
4230     if (obj->nodeTab != NULL) {
4231 	for (i = 0;i < obj->nodeNr;i++) {
4232 	    if (obj->nodeTab[i] != NULL) {
4233 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4234 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4235 		} else {
4236 		    xmlFreeNodeList(obj->nodeTab[i]);
4237 		}
4238 	    }
4239 	}
4240 	xmlFree(obj->nodeTab);
4241     }
4242     xmlFree(obj);
4243 }
4244 
4245 #if defined(DEBUG) || defined(DEBUG_STEP)
4246 /**
4247  * xmlGenericErrorContextNodeSet:
4248  * @output:  a FILE * for the output
4249  * @obj:  the xmlNodeSetPtr to display
4250  *
4251  * Quick display of a NodeSet
4252  */
4253 void
4254 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4255     int i;
4256 
4257     if (output == NULL) output = xmlGenericErrorContext;
4258     if (obj == NULL)  {
4259         fprintf(output, "NodeSet == NULL !\n");
4260 	return;
4261     }
4262     if (obj->nodeNr == 0) {
4263         fprintf(output, "NodeSet is empty\n");
4264 	return;
4265     }
4266     if (obj->nodeTab == NULL) {
4267 	fprintf(output, " nodeTab == NULL !\n");
4268 	return;
4269     }
4270     for (i = 0; i < obj->nodeNr; i++) {
4271         if (obj->nodeTab[i] == NULL) {
4272 	    fprintf(output, " NULL !\n");
4273 	    return;
4274         }
4275 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4276 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4277 	    fprintf(output, " /");
4278 	else if (obj->nodeTab[i]->name == NULL)
4279 	    fprintf(output, " noname!");
4280 	else fprintf(output, " %s", obj->nodeTab[i]->name);
4281     }
4282     fprintf(output, "\n");
4283 }
4284 #endif
4285 
4286 /**
4287  * xmlXPathNewNodeSet:
4288  * @val:  the NodePtr value
4289  *
4290  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4291  * it with the single Node @val
4292  *
4293  * Returns the newly created object.
4294  */
4295 xmlXPathObjectPtr
4296 xmlXPathNewNodeSet(xmlNodePtr val) {
4297     xmlXPathObjectPtr ret;
4298 
4299     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4300     if (ret == NULL) {
4301         xmlXPathErrMemory(NULL, "creating nodeset\n");
4302 	return(NULL);
4303     }
4304     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4305     ret->type = XPATH_NODESET;
4306     ret->boolval = 0;
4307     /* TODO: Check memory error. */
4308     ret->nodesetval = xmlXPathNodeSetCreate(val);
4309     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4310 #ifdef XP_DEBUG_OBJ_USAGE
4311     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4312 #endif
4313     return(ret);
4314 }
4315 
4316 /**
4317  * xmlXPathNewValueTree:
4318  * @val:  the NodePtr value
4319  *
4320  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4321  * it with the tree root @val
4322  *
4323  * Returns the newly created object.
4324  */
4325 xmlXPathObjectPtr
4326 xmlXPathNewValueTree(xmlNodePtr val) {
4327     xmlXPathObjectPtr ret;
4328 
4329     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4330     if (ret == NULL) {
4331         xmlXPathErrMemory(NULL, "creating result value tree\n");
4332 	return(NULL);
4333     }
4334     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4335     ret->type = XPATH_XSLT_TREE;
4336     ret->boolval = 1;
4337     ret->user = (void *) val;
4338     ret->nodesetval = xmlXPathNodeSetCreate(val);
4339 #ifdef XP_DEBUG_OBJ_USAGE
4340     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4341 #endif
4342     return(ret);
4343 }
4344 
4345 /**
4346  * xmlXPathNewNodeSetList:
4347  * @val:  an existing NodeSet
4348  *
4349  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4350  * it with the Nodeset @val
4351  *
4352  * Returns the newly created object.
4353  */
4354 xmlXPathObjectPtr
4355 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4356 {
4357     xmlXPathObjectPtr ret;
4358     int i;
4359 
4360     if (val == NULL)
4361         ret = NULL;
4362     else if (val->nodeTab == NULL)
4363         ret = xmlXPathNewNodeSet(NULL);
4364     else {
4365         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4366         if (ret) {
4367             for (i = 1; i < val->nodeNr; ++i) {
4368                 /* TODO: Propagate memory error. */
4369                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4370 		    < 0) break;
4371 	    }
4372 	}
4373     }
4374 
4375     return (ret);
4376 }
4377 
4378 /**
4379  * xmlXPathWrapNodeSet:
4380  * @val:  the NodePtr value
4381  *
4382  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4383  *
4384  * Returns the newly created object.
4385  */
4386 xmlXPathObjectPtr
4387 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4388     xmlXPathObjectPtr ret;
4389 
4390     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4391     if (ret == NULL) {
4392         xmlXPathErrMemory(NULL, "creating node set object\n");
4393 	return(NULL);
4394     }
4395     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4396     ret->type = XPATH_NODESET;
4397     ret->nodesetval = val;
4398 #ifdef XP_DEBUG_OBJ_USAGE
4399     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4400 #endif
4401     return(ret);
4402 }
4403 
4404 /**
4405  * xmlXPathFreeNodeSetList:
4406  * @obj:  an existing NodeSetList object
4407  *
4408  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4409  * the list contrary to xmlXPathFreeObject().
4410  */
4411 void
4412 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4413     if (obj == NULL) return;
4414 #ifdef XP_DEBUG_OBJ_USAGE
4415     xmlXPathDebugObjUsageReleased(NULL, obj->type);
4416 #endif
4417     xmlFree(obj);
4418 }
4419 
4420 /**
4421  * xmlXPathDifference:
4422  * @nodes1:  a node-set
4423  * @nodes2:  a node-set
4424  *
4425  * Implements the EXSLT - Sets difference() function:
4426  *    node-set set:difference (node-set, node-set)
4427  *
4428  * Returns the difference between the two node sets, or nodes1 if
4429  *         nodes2 is empty
4430  */
4431 xmlNodeSetPtr
4432 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4433     xmlNodeSetPtr ret;
4434     int i, l1;
4435     xmlNodePtr cur;
4436 
4437     if (xmlXPathNodeSetIsEmpty(nodes2))
4438 	return(nodes1);
4439 
4440     /* TODO: Check memory error. */
4441     ret = xmlXPathNodeSetCreate(NULL);
4442     if (xmlXPathNodeSetIsEmpty(nodes1))
4443 	return(ret);
4444 
4445     l1 = xmlXPathNodeSetGetLength(nodes1);
4446 
4447     for (i = 0; i < l1; i++) {
4448 	cur = xmlXPathNodeSetItem(nodes1, i);
4449 	if (!xmlXPathNodeSetContains(nodes2, cur)) {
4450             /* TODO: Propagate memory error. */
4451 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4452 	        break;
4453 	}
4454     }
4455     return(ret);
4456 }
4457 
4458 /**
4459  * xmlXPathIntersection:
4460  * @nodes1:  a node-set
4461  * @nodes2:  a node-set
4462  *
4463  * Implements the EXSLT - Sets intersection() function:
4464  *    node-set set:intersection (node-set, node-set)
4465  *
4466  * Returns a node set comprising the nodes that are within both the
4467  *         node sets passed as arguments
4468  */
4469 xmlNodeSetPtr
4470 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4471     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4472     int i, l1;
4473     xmlNodePtr cur;
4474 
4475     if (ret == NULL)
4476         return(ret);
4477     if (xmlXPathNodeSetIsEmpty(nodes1))
4478 	return(ret);
4479     if (xmlXPathNodeSetIsEmpty(nodes2))
4480 	return(ret);
4481 
4482     l1 = xmlXPathNodeSetGetLength(nodes1);
4483 
4484     for (i = 0; i < l1; i++) {
4485 	cur = xmlXPathNodeSetItem(nodes1, i);
4486 	if (xmlXPathNodeSetContains(nodes2, cur)) {
4487             /* TODO: Propagate memory error. */
4488 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4489 	        break;
4490 	}
4491     }
4492     return(ret);
4493 }
4494 
4495 /**
4496  * xmlXPathDistinctSorted:
4497  * @nodes:  a node-set, sorted by document order
4498  *
4499  * Implements the EXSLT - Sets distinct() function:
4500  *    node-set set:distinct (node-set)
4501  *
4502  * Returns a subset of the nodes contained in @nodes, or @nodes if
4503  *         it is empty
4504  */
4505 xmlNodeSetPtr
4506 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4507     xmlNodeSetPtr ret;
4508     xmlHashTablePtr hash;
4509     int i, l;
4510     xmlChar * strval;
4511     xmlNodePtr cur;
4512 
4513     if (xmlXPathNodeSetIsEmpty(nodes))
4514 	return(nodes);
4515 
4516     ret = xmlXPathNodeSetCreate(NULL);
4517     if (ret == NULL)
4518         return(ret);
4519     l = xmlXPathNodeSetGetLength(nodes);
4520     hash = xmlHashCreate (l);
4521     for (i = 0; i < l; i++) {
4522 	cur = xmlXPathNodeSetItem(nodes, i);
4523 	strval = xmlXPathCastNodeToString(cur);
4524 	if (xmlHashLookup(hash, strval) == NULL) {
4525 	    xmlHashAddEntry(hash, strval, strval);
4526             /* TODO: Propagate memory error. */
4527 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4528 	        break;
4529 	} else {
4530 	    xmlFree(strval);
4531 	}
4532     }
4533     xmlHashFree(hash, xmlHashDefaultDeallocator);
4534     return(ret);
4535 }
4536 
4537 /**
4538  * xmlXPathDistinct:
4539  * @nodes:  a node-set
4540  *
4541  * Implements the EXSLT - Sets distinct() function:
4542  *    node-set set:distinct (node-set)
4543  * @nodes is sorted by document order, then #exslSetsDistinctSorted
4544  * is called with the sorted node-set
4545  *
4546  * Returns a subset of the nodes contained in @nodes, or @nodes if
4547  *         it is empty
4548  */
4549 xmlNodeSetPtr
4550 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4551     if (xmlXPathNodeSetIsEmpty(nodes))
4552 	return(nodes);
4553 
4554     xmlXPathNodeSetSort(nodes);
4555     return(xmlXPathDistinctSorted(nodes));
4556 }
4557 
4558 /**
4559  * xmlXPathHasSameNodes:
4560  * @nodes1:  a node-set
4561  * @nodes2:  a node-set
4562  *
4563  * Implements the EXSLT - Sets has-same-nodes function:
4564  *    boolean set:has-same-node(node-set, node-set)
4565  *
4566  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4567  *         otherwise
4568  */
4569 int
4570 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4571     int i, l;
4572     xmlNodePtr cur;
4573 
4574     if (xmlXPathNodeSetIsEmpty(nodes1) ||
4575 	xmlXPathNodeSetIsEmpty(nodes2))
4576 	return(0);
4577 
4578     l = xmlXPathNodeSetGetLength(nodes1);
4579     for (i = 0; i < l; i++) {
4580 	cur = xmlXPathNodeSetItem(nodes1, i);
4581 	if (xmlXPathNodeSetContains(nodes2, cur))
4582 	    return(1);
4583     }
4584     return(0);
4585 }
4586 
4587 /**
4588  * xmlXPathNodeLeadingSorted:
4589  * @nodes: a node-set, sorted by document order
4590  * @node: a node
4591  *
4592  * Implements the EXSLT - Sets leading() function:
4593  *    node-set set:leading (node-set, node-set)
4594  *
4595  * Returns the nodes in @nodes that precede @node in document order,
4596  *         @nodes if @node is NULL or an empty node-set if @nodes
4597  *         doesn't contain @node
4598  */
4599 xmlNodeSetPtr
4600 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4601     int i, l;
4602     xmlNodePtr cur;
4603     xmlNodeSetPtr ret;
4604 
4605     if (node == NULL)
4606 	return(nodes);
4607 
4608     ret = xmlXPathNodeSetCreate(NULL);
4609     if (ret == NULL)
4610         return(ret);
4611     if (xmlXPathNodeSetIsEmpty(nodes) ||
4612 	(!xmlXPathNodeSetContains(nodes, node)))
4613 	return(ret);
4614 
4615     l = xmlXPathNodeSetGetLength(nodes);
4616     for (i = 0; i < l; i++) {
4617 	cur = xmlXPathNodeSetItem(nodes, i);
4618 	if (cur == node)
4619 	    break;
4620         /* TODO: Propagate memory error. */
4621 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4622 	    break;
4623     }
4624     return(ret);
4625 }
4626 
4627 /**
4628  * xmlXPathNodeLeading:
4629  * @nodes:  a node-set
4630  * @node:  a node
4631  *
4632  * Implements the EXSLT - Sets leading() function:
4633  *    node-set set:leading (node-set, node-set)
4634  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4635  * is called.
4636  *
4637  * Returns the nodes in @nodes that precede @node in document order,
4638  *         @nodes if @node is NULL or an empty node-set if @nodes
4639  *         doesn't contain @node
4640  */
4641 xmlNodeSetPtr
4642 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4643     xmlXPathNodeSetSort(nodes);
4644     return(xmlXPathNodeLeadingSorted(nodes, node));
4645 }
4646 
4647 /**
4648  * xmlXPathLeadingSorted:
4649  * @nodes1:  a node-set, sorted by document order
4650  * @nodes2:  a node-set, sorted by document order
4651  *
4652  * Implements the EXSLT - Sets leading() function:
4653  *    node-set set:leading (node-set, node-set)
4654  *
4655  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4656  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4657  *         an empty node-set if @nodes1 doesn't contain @nodes2
4658  */
4659 xmlNodeSetPtr
4660 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4661     if (xmlXPathNodeSetIsEmpty(nodes2))
4662 	return(nodes1);
4663     return(xmlXPathNodeLeadingSorted(nodes1,
4664 				     xmlXPathNodeSetItem(nodes2, 1)));
4665 }
4666 
4667 /**
4668  * xmlXPathLeading:
4669  * @nodes1:  a node-set
4670  * @nodes2:  a node-set
4671  *
4672  * Implements the EXSLT - Sets leading() function:
4673  *    node-set set:leading (node-set, node-set)
4674  * @nodes1 and @nodes2 are sorted by document order, then
4675  * #exslSetsLeadingSorted is called.
4676  *
4677  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4678  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4679  *         an empty node-set if @nodes1 doesn't contain @nodes2
4680  */
4681 xmlNodeSetPtr
4682 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4683     if (xmlXPathNodeSetIsEmpty(nodes2))
4684 	return(nodes1);
4685     if (xmlXPathNodeSetIsEmpty(nodes1))
4686 	return(xmlXPathNodeSetCreate(NULL));
4687     xmlXPathNodeSetSort(nodes1);
4688     xmlXPathNodeSetSort(nodes2);
4689     return(xmlXPathNodeLeadingSorted(nodes1,
4690 				     xmlXPathNodeSetItem(nodes2, 1)));
4691 }
4692 
4693 /**
4694  * xmlXPathNodeTrailingSorted:
4695  * @nodes: a node-set, sorted by document order
4696  * @node: a node
4697  *
4698  * Implements the EXSLT - Sets trailing() function:
4699  *    node-set set:trailing (node-set, node-set)
4700  *
4701  * Returns the nodes in @nodes that follow @node in document order,
4702  *         @nodes if @node is NULL or an empty node-set if @nodes
4703  *         doesn't contain @node
4704  */
4705 xmlNodeSetPtr
4706 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4707     int i, l;
4708     xmlNodePtr cur;
4709     xmlNodeSetPtr ret;
4710 
4711     if (node == NULL)
4712 	return(nodes);
4713 
4714     ret = xmlXPathNodeSetCreate(NULL);
4715     if (ret == NULL)
4716         return(ret);
4717     if (xmlXPathNodeSetIsEmpty(nodes) ||
4718 	(!xmlXPathNodeSetContains(nodes, node)))
4719 	return(ret);
4720 
4721     l = xmlXPathNodeSetGetLength(nodes);
4722     for (i = l - 1; i >= 0; i--) {
4723 	cur = xmlXPathNodeSetItem(nodes, i);
4724 	if (cur == node)
4725 	    break;
4726         /* TODO: Propagate memory error. */
4727 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4728 	    break;
4729     }
4730     xmlXPathNodeSetSort(ret);	/* bug 413451 */
4731     return(ret);
4732 }
4733 
4734 /**
4735  * xmlXPathNodeTrailing:
4736  * @nodes:  a node-set
4737  * @node:  a node
4738  *
4739  * Implements the EXSLT - Sets trailing() function:
4740  *    node-set set:trailing (node-set, node-set)
4741  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4742  * is called.
4743  *
4744  * Returns the nodes in @nodes that follow @node in document order,
4745  *         @nodes if @node is NULL or an empty node-set if @nodes
4746  *         doesn't contain @node
4747  */
4748 xmlNodeSetPtr
4749 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4750     xmlXPathNodeSetSort(nodes);
4751     return(xmlXPathNodeTrailingSorted(nodes, node));
4752 }
4753 
4754 /**
4755  * xmlXPathTrailingSorted:
4756  * @nodes1:  a node-set, sorted by document order
4757  * @nodes2:  a node-set, sorted by document order
4758  *
4759  * Implements the EXSLT - Sets trailing() function:
4760  *    node-set set:trailing (node-set, node-set)
4761  *
4762  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4763  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4764  *         an empty node-set if @nodes1 doesn't contain @nodes2
4765  */
4766 xmlNodeSetPtr
4767 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4768     if (xmlXPathNodeSetIsEmpty(nodes2))
4769 	return(nodes1);
4770     return(xmlXPathNodeTrailingSorted(nodes1,
4771 				      xmlXPathNodeSetItem(nodes2, 0)));
4772 }
4773 
4774 /**
4775  * xmlXPathTrailing:
4776  * @nodes1:  a node-set
4777  * @nodes2:  a node-set
4778  *
4779  * Implements the EXSLT - Sets trailing() function:
4780  *    node-set set:trailing (node-set, node-set)
4781  * @nodes1 and @nodes2 are sorted by document order, then
4782  * #xmlXPathTrailingSorted is called.
4783  *
4784  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4785  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4786  *         an empty node-set if @nodes1 doesn't contain @nodes2
4787  */
4788 xmlNodeSetPtr
4789 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4790     if (xmlXPathNodeSetIsEmpty(nodes2))
4791 	return(nodes1);
4792     if (xmlXPathNodeSetIsEmpty(nodes1))
4793 	return(xmlXPathNodeSetCreate(NULL));
4794     xmlXPathNodeSetSort(nodes1);
4795     xmlXPathNodeSetSort(nodes2);
4796     return(xmlXPathNodeTrailingSorted(nodes1,
4797 				      xmlXPathNodeSetItem(nodes2, 0)));
4798 }
4799 
4800 /************************************************************************
4801  *									*
4802  *		Routines to handle extra functions			*
4803  *									*
4804  ************************************************************************/
4805 
4806 /**
4807  * xmlXPathRegisterFunc:
4808  * @ctxt:  the XPath context
4809  * @name:  the function name
4810  * @f:  the function implementation or NULL
4811  *
4812  * Register a new function. If @f is NULL it unregisters the function
4813  *
4814  * Returns 0 in case of success, -1 in case of error
4815  */
4816 int
4817 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4818 		     xmlXPathFunction f) {
4819     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4820 }
4821 
4822 /**
4823  * xmlXPathRegisterFuncNS:
4824  * @ctxt:  the XPath context
4825  * @name:  the function name
4826  * @ns_uri:  the function namespace URI
4827  * @f:  the function implementation or NULL
4828  *
4829  * Register a new function. If @f is NULL it unregisters the function
4830  *
4831  * Returns 0 in case of success, -1 in case of error
4832  */
4833 int
4834 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4835 		       const xmlChar *ns_uri, xmlXPathFunction f) {
4836     if (ctxt == NULL)
4837 	return(-1);
4838     if (name == NULL)
4839 	return(-1);
4840 
4841     if (ctxt->funcHash == NULL)
4842 	ctxt->funcHash = xmlHashCreate(0);
4843     if (ctxt->funcHash == NULL)
4844 	return(-1);
4845     if (f == NULL)
4846         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4847 XML_IGNORE_PEDANTIC_WARNINGS
4848     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4849 XML_POP_WARNINGS
4850 }
4851 
4852 /**
4853  * xmlXPathRegisterFuncLookup:
4854  * @ctxt:  the XPath context
4855  * @f:  the lookup function
4856  * @funcCtxt:  the lookup data
4857  *
4858  * Registers an external mechanism to do function lookup.
4859  */
4860 void
4861 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4862 			    xmlXPathFuncLookupFunc f,
4863 			    void *funcCtxt) {
4864     if (ctxt == NULL)
4865 	return;
4866     ctxt->funcLookupFunc = f;
4867     ctxt->funcLookupData = funcCtxt;
4868 }
4869 
4870 /**
4871  * xmlXPathFunctionLookup:
4872  * @ctxt:  the XPath context
4873  * @name:  the function name
4874  *
4875  * Search in the Function array of the context for the given
4876  * function.
4877  *
4878  * Returns the xmlXPathFunction or NULL if not found
4879  */
4880 xmlXPathFunction
4881 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4882     if (ctxt == NULL)
4883 	return (NULL);
4884 
4885     if (ctxt->funcLookupFunc != NULL) {
4886 	xmlXPathFunction ret;
4887 	xmlXPathFuncLookupFunc f;
4888 
4889 	f = ctxt->funcLookupFunc;
4890 	ret = f(ctxt->funcLookupData, name, NULL);
4891 	if (ret != NULL)
4892 	    return(ret);
4893     }
4894     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4895 }
4896 
4897 /**
4898  * xmlXPathFunctionLookupNS:
4899  * @ctxt:  the XPath context
4900  * @name:  the function name
4901  * @ns_uri:  the function namespace URI
4902  *
4903  * Search in the Function array of the context for the given
4904  * function.
4905  *
4906  * Returns the xmlXPathFunction or NULL if not found
4907  */
4908 xmlXPathFunction
4909 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4910 			 const xmlChar *ns_uri) {
4911     xmlXPathFunction ret;
4912 
4913     if (ctxt == NULL)
4914 	return(NULL);
4915     if (name == NULL)
4916 	return(NULL);
4917 
4918     if (ctxt->funcLookupFunc != NULL) {
4919 	xmlXPathFuncLookupFunc f;
4920 
4921 	f = ctxt->funcLookupFunc;
4922 	ret = f(ctxt->funcLookupData, name, ns_uri);
4923 	if (ret != NULL)
4924 	    return(ret);
4925     }
4926 
4927     if (ctxt->funcHash == NULL)
4928 	return(NULL);
4929 
4930 XML_IGNORE_PEDANTIC_WARNINGS
4931     ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4932 XML_POP_WARNINGS
4933     return(ret);
4934 }
4935 
4936 /**
4937  * xmlXPathRegisteredFuncsCleanup:
4938  * @ctxt:  the XPath context
4939  *
4940  * Cleanup the XPath context data associated to registered functions
4941  */
4942 void
4943 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4944     if (ctxt == NULL)
4945 	return;
4946 
4947     xmlHashFree(ctxt->funcHash, NULL);
4948     ctxt->funcHash = NULL;
4949 }
4950 
4951 /************************************************************************
4952  *									*
4953  *			Routines to handle Variables			*
4954  *									*
4955  ************************************************************************/
4956 
4957 /**
4958  * xmlXPathRegisterVariable:
4959  * @ctxt:  the XPath context
4960  * @name:  the variable name
4961  * @value:  the variable value or NULL
4962  *
4963  * Register a new variable value. If @value is NULL it unregisters
4964  * the variable
4965  *
4966  * Returns 0 in case of success, -1 in case of error
4967  */
4968 int
4969 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4970 			 xmlXPathObjectPtr value) {
4971     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4972 }
4973 
4974 /**
4975  * xmlXPathRegisterVariableNS:
4976  * @ctxt:  the XPath context
4977  * @name:  the variable name
4978  * @ns_uri:  the variable namespace URI
4979  * @value:  the variable value or NULL
4980  *
4981  * Register a new variable value. If @value is NULL it unregisters
4982  * the variable
4983  *
4984  * Returns 0 in case of success, -1 in case of error
4985  */
4986 int
4987 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4988 			   const xmlChar *ns_uri,
4989 			   xmlXPathObjectPtr value) {
4990     if (ctxt == NULL)
4991 	return(-1);
4992     if (name == NULL)
4993 	return(-1);
4994 
4995     if (ctxt->varHash == NULL)
4996 	ctxt->varHash = xmlHashCreate(0);
4997     if (ctxt->varHash == NULL)
4998 	return(-1);
4999     if (value == NULL)
5000         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5001 	                           xmlXPathFreeObjectEntry));
5002     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5003 			       (void *) value, xmlXPathFreeObjectEntry));
5004 }
5005 
5006 /**
5007  * xmlXPathRegisterVariableLookup:
5008  * @ctxt:  the XPath context
5009  * @f:  the lookup function
5010  * @data:  the lookup data
5011  *
5012  * register an external mechanism to do variable lookup
5013  */
5014 void
5015 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5016 	 xmlXPathVariableLookupFunc f, void *data) {
5017     if (ctxt == NULL)
5018 	return;
5019     ctxt->varLookupFunc = f;
5020     ctxt->varLookupData = data;
5021 }
5022 
5023 /**
5024  * xmlXPathVariableLookup:
5025  * @ctxt:  the XPath context
5026  * @name:  the variable name
5027  *
5028  * Search in the Variable array of the context for the given
5029  * variable value.
5030  *
5031  * Returns a copy of the value or NULL if not found
5032  */
5033 xmlXPathObjectPtr
5034 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5035     if (ctxt == NULL)
5036 	return(NULL);
5037 
5038     if (ctxt->varLookupFunc != NULL) {
5039 	xmlXPathObjectPtr ret;
5040 
5041 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5042 	        (ctxt->varLookupData, name, NULL);
5043 	return(ret);
5044     }
5045     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5046 }
5047 
5048 /**
5049  * xmlXPathVariableLookupNS:
5050  * @ctxt:  the XPath context
5051  * @name:  the variable name
5052  * @ns_uri:  the variable namespace URI
5053  *
5054  * Search in the Variable array of the context for the given
5055  * variable value.
5056  *
5057  * Returns the a copy of the value or NULL if not found
5058  */
5059 xmlXPathObjectPtr
5060 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5061 			 const xmlChar *ns_uri) {
5062     if (ctxt == NULL)
5063 	return(NULL);
5064 
5065     if (ctxt->varLookupFunc != NULL) {
5066 	xmlXPathObjectPtr ret;
5067 
5068 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5069 	        (ctxt->varLookupData, name, ns_uri);
5070 	if (ret != NULL) return(ret);
5071     }
5072 
5073     if (ctxt->varHash == NULL)
5074 	return(NULL);
5075     if (name == NULL)
5076 	return(NULL);
5077 
5078     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5079 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5080 }
5081 
5082 /**
5083  * xmlXPathRegisteredVariablesCleanup:
5084  * @ctxt:  the XPath context
5085  *
5086  * Cleanup the XPath context data associated to registered variables
5087  */
5088 void
5089 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5090     if (ctxt == NULL)
5091 	return;
5092 
5093     xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5094     ctxt->varHash = NULL;
5095 }
5096 
5097 /**
5098  * xmlXPathRegisterNs:
5099  * @ctxt:  the XPath context
5100  * @prefix:  the namespace prefix cannot be NULL or empty string
5101  * @ns_uri:  the namespace name
5102  *
5103  * Register a new namespace. If @ns_uri is NULL it unregisters
5104  * the namespace
5105  *
5106  * Returns 0 in case of success, -1 in case of error
5107  */
5108 int
5109 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5110 			   const xmlChar *ns_uri) {
5111     if (ctxt == NULL)
5112 	return(-1);
5113     if (prefix == NULL)
5114 	return(-1);
5115     if (prefix[0] == 0)
5116 	return(-1);
5117 
5118     if (ctxt->nsHash == NULL)
5119 	ctxt->nsHash = xmlHashCreate(10);
5120     if (ctxt->nsHash == NULL)
5121 	return(-1);
5122     if (ns_uri == NULL)
5123         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5124 	                          xmlHashDefaultDeallocator));
5125     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5126 			      xmlHashDefaultDeallocator));
5127 }
5128 
5129 /**
5130  * xmlXPathNsLookup:
5131  * @ctxt:  the XPath context
5132  * @prefix:  the namespace prefix value
5133  *
5134  * Search in the namespace declaration array of the context for the given
5135  * namespace name associated to the given prefix
5136  *
5137  * Returns the value or NULL if not found
5138  */
5139 const xmlChar *
5140 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5141     if (ctxt == NULL)
5142 	return(NULL);
5143     if (prefix == NULL)
5144 	return(NULL);
5145 
5146 #ifdef XML_XML_NAMESPACE
5147     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5148 	return(XML_XML_NAMESPACE);
5149 #endif
5150 
5151     if (ctxt->namespaces != NULL) {
5152 	int i;
5153 
5154 	for (i = 0;i < ctxt->nsNr;i++) {
5155 	    if ((ctxt->namespaces[i] != NULL) &&
5156 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5157 		return(ctxt->namespaces[i]->href);
5158 	}
5159     }
5160 
5161     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5162 }
5163 
5164 /**
5165  * xmlXPathRegisteredNsCleanup:
5166  * @ctxt:  the XPath context
5167  *
5168  * Cleanup the XPath context data associated to registered variables
5169  */
5170 void
5171 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5172     if (ctxt == NULL)
5173 	return;
5174 
5175     xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5176     ctxt->nsHash = NULL;
5177 }
5178 
5179 /************************************************************************
5180  *									*
5181  *			Routines to handle Values			*
5182  *									*
5183  ************************************************************************/
5184 
5185 /* Allocations are terrible, one needs to optimize all this !!! */
5186 
5187 /**
5188  * xmlXPathNewFloat:
5189  * @val:  the double value
5190  *
5191  * Create a new xmlXPathObjectPtr of type double and of value @val
5192  *
5193  * Returns the newly created object.
5194  */
5195 xmlXPathObjectPtr
5196 xmlXPathNewFloat(double val) {
5197     xmlXPathObjectPtr ret;
5198 
5199     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5200     if (ret == NULL) {
5201         xmlXPathErrMemory(NULL, "creating float object\n");
5202 	return(NULL);
5203     }
5204     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5205     ret->type = XPATH_NUMBER;
5206     ret->floatval = val;
5207 #ifdef XP_DEBUG_OBJ_USAGE
5208     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5209 #endif
5210     return(ret);
5211 }
5212 
5213 /**
5214  * xmlXPathNewBoolean:
5215  * @val:  the boolean value
5216  *
5217  * Create a new xmlXPathObjectPtr of type boolean and of value @val
5218  *
5219  * Returns the newly created object.
5220  */
5221 xmlXPathObjectPtr
5222 xmlXPathNewBoolean(int val) {
5223     xmlXPathObjectPtr ret;
5224 
5225     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5226     if (ret == NULL) {
5227         xmlXPathErrMemory(NULL, "creating boolean object\n");
5228 	return(NULL);
5229     }
5230     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5231     ret->type = XPATH_BOOLEAN;
5232     ret->boolval = (val != 0);
5233 #ifdef XP_DEBUG_OBJ_USAGE
5234     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5235 #endif
5236     return(ret);
5237 }
5238 
5239 /**
5240  * xmlXPathNewString:
5241  * @val:  the xmlChar * value
5242  *
5243  * Create a new xmlXPathObjectPtr of type string and of value @val
5244  *
5245  * Returns the newly created object.
5246  */
5247 xmlXPathObjectPtr
5248 xmlXPathNewString(const xmlChar *val) {
5249     xmlXPathObjectPtr ret;
5250 
5251     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5252     if (ret == NULL) {
5253         xmlXPathErrMemory(NULL, "creating string object\n");
5254 	return(NULL);
5255     }
5256     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5257     ret->type = XPATH_STRING;
5258     if (val != NULL)
5259 	ret->stringval = xmlStrdup(val);
5260     else
5261 	ret->stringval = xmlStrdup((const xmlChar *)"");
5262 #ifdef XP_DEBUG_OBJ_USAGE
5263     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5264 #endif
5265     return(ret);
5266 }
5267 
5268 /**
5269  * xmlXPathWrapString:
5270  * @val:  the xmlChar * value
5271  *
5272  * Wraps the @val string into an XPath object.
5273  *
5274  * Returns the newly created object.
5275  */
5276 xmlXPathObjectPtr
5277 xmlXPathWrapString (xmlChar *val) {
5278     xmlXPathObjectPtr ret;
5279 
5280     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5281     if (ret == NULL) {
5282         xmlXPathErrMemory(NULL, "creating string object\n");
5283 	return(NULL);
5284     }
5285     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5286     ret->type = XPATH_STRING;
5287     ret->stringval = val;
5288 #ifdef XP_DEBUG_OBJ_USAGE
5289     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5290 #endif
5291     return(ret);
5292 }
5293 
5294 /**
5295  * xmlXPathNewCString:
5296  * @val:  the char * value
5297  *
5298  * Create a new xmlXPathObjectPtr of type string and of value @val
5299  *
5300  * Returns the newly created object.
5301  */
5302 xmlXPathObjectPtr
5303 xmlXPathNewCString(const char *val) {
5304     xmlXPathObjectPtr ret;
5305 
5306     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5307     if (ret == NULL) {
5308         xmlXPathErrMemory(NULL, "creating string object\n");
5309 	return(NULL);
5310     }
5311     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5312     ret->type = XPATH_STRING;
5313     ret->stringval = xmlStrdup(BAD_CAST val);
5314 #ifdef XP_DEBUG_OBJ_USAGE
5315     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5316 #endif
5317     return(ret);
5318 }
5319 
5320 /**
5321  * xmlXPathWrapCString:
5322  * @val:  the char * value
5323  *
5324  * Wraps a string into an XPath object.
5325  *
5326  * Returns the newly created object.
5327  */
5328 xmlXPathObjectPtr
5329 xmlXPathWrapCString (char * val) {
5330     return(xmlXPathWrapString((xmlChar *)(val)));
5331 }
5332 
5333 /**
5334  * xmlXPathWrapExternal:
5335  * @val:  the user data
5336  *
5337  * Wraps the @val data into an XPath object.
5338  *
5339  * Returns the newly created object.
5340  */
5341 xmlXPathObjectPtr
5342 xmlXPathWrapExternal (void *val) {
5343     xmlXPathObjectPtr ret;
5344 
5345     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5346     if (ret == NULL) {
5347         xmlXPathErrMemory(NULL, "creating user object\n");
5348 	return(NULL);
5349     }
5350     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5351     ret->type = XPATH_USERS;
5352     ret->user = val;
5353 #ifdef XP_DEBUG_OBJ_USAGE
5354     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5355 #endif
5356     return(ret);
5357 }
5358 
5359 /**
5360  * xmlXPathObjectCopy:
5361  * @val:  the original object
5362  *
5363  * allocate a new copy of a given object
5364  *
5365  * Returns the newly created object.
5366  */
5367 xmlXPathObjectPtr
5368 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5369     xmlXPathObjectPtr ret;
5370 
5371     if (val == NULL)
5372 	return(NULL);
5373 
5374     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5375     if (ret == NULL) {
5376         xmlXPathErrMemory(NULL, "copying object\n");
5377 	return(NULL);
5378     }
5379     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5380 #ifdef XP_DEBUG_OBJ_USAGE
5381     xmlXPathDebugObjUsageRequested(NULL, val->type);
5382 #endif
5383     switch (val->type) {
5384 	case XPATH_BOOLEAN:
5385 	case XPATH_NUMBER:
5386 	case XPATH_POINT:
5387 	case XPATH_RANGE:
5388 	    break;
5389 	case XPATH_STRING:
5390 	    ret->stringval = xmlStrdup(val->stringval);
5391 	    break;
5392 	case XPATH_XSLT_TREE:
5393 #if 0
5394 /*
5395   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5396   this previous handling is no longer correct, and can cause some serious
5397   problems (ref. bug 145547)
5398 */
5399 	    if ((val->nodesetval != NULL) &&
5400 		(val->nodesetval->nodeTab != NULL)) {
5401 		xmlNodePtr cur, tmp;
5402 		xmlDocPtr top;
5403 
5404 		ret->boolval = 1;
5405 		top =  xmlNewDoc(NULL);
5406 		top->name = (char *)
5407 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5408 		ret->user = top;
5409 		if (top != NULL) {
5410 		    top->doc = top;
5411 		    cur = val->nodesetval->nodeTab[0]->children;
5412 		    while (cur != NULL) {
5413 			tmp = xmlDocCopyNode(cur, top, 1);
5414 			xmlAddChild((xmlNodePtr) top, tmp);
5415 			cur = cur->next;
5416 		    }
5417 		}
5418 
5419 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5420 	    } else
5421 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5422 	    /* Deallocate the copied tree value */
5423 	    break;
5424 #endif
5425 	case XPATH_NODESET:
5426             /* TODO: Check memory error. */
5427 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5428 	    /* Do not deallocate the copied tree value */
5429 	    ret->boolval = 0;
5430 	    break;
5431 	case XPATH_LOCATIONSET:
5432 #ifdef LIBXML_XPTR_ENABLED
5433 	{
5434 	    xmlLocationSetPtr loc = val->user;
5435 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5436 	    break;
5437 	}
5438 #endif
5439         case XPATH_USERS:
5440 	    ret->user = val->user;
5441 	    break;
5442         case XPATH_UNDEFINED:
5443 	    xmlGenericError(xmlGenericErrorContext,
5444 		    "xmlXPathObjectCopy: unsupported type %d\n",
5445 		    val->type);
5446 	    break;
5447     }
5448     return(ret);
5449 }
5450 
5451 /**
5452  * xmlXPathFreeObject:
5453  * @obj:  the object to free
5454  *
5455  * Free up an xmlXPathObjectPtr object.
5456  */
5457 void
5458 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5459     if (obj == NULL) return;
5460     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5461 	if (obj->boolval) {
5462 #if 0
5463 	    if (obj->user != NULL) {
5464                 xmlXPathFreeNodeSet(obj->nodesetval);
5465 		xmlFreeNodeList((xmlNodePtr) obj->user);
5466 	    } else
5467 #endif
5468 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5469 	    if (obj->nodesetval != NULL)
5470 		xmlXPathFreeValueTree(obj->nodesetval);
5471 	} else {
5472 	    if (obj->nodesetval != NULL)
5473 		xmlXPathFreeNodeSet(obj->nodesetval);
5474 	}
5475 #ifdef LIBXML_XPTR_ENABLED
5476     } else if (obj->type == XPATH_LOCATIONSET) {
5477 	if (obj->user != NULL)
5478 	    xmlXPtrFreeLocationSet(obj->user);
5479 #endif
5480     } else if (obj->type == XPATH_STRING) {
5481 	if (obj->stringval != NULL)
5482 	    xmlFree(obj->stringval);
5483     }
5484 #ifdef XP_DEBUG_OBJ_USAGE
5485     xmlXPathDebugObjUsageReleased(NULL, obj->type);
5486 #endif
5487     xmlFree(obj);
5488 }
5489 
5490 static void
5491 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5492     xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5493 }
5494 
5495 /**
5496  * xmlXPathReleaseObject:
5497  * @obj:  the xmlXPathObjectPtr to free or to cache
5498  *
5499  * Depending on the state of the cache this frees the given
5500  * XPath object or stores it in the cache.
5501  */
5502 static void
5503 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5504 {
5505 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5506 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5507     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5508 
5509 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5510 
5511     if (obj == NULL)
5512 	return;
5513     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5514 	 xmlXPathFreeObject(obj);
5515     } else {
5516 	xmlXPathContextCachePtr cache =
5517 	    (xmlXPathContextCachePtr) ctxt->cache;
5518 
5519 	switch (obj->type) {
5520 	    case XPATH_NODESET:
5521 	    case XPATH_XSLT_TREE:
5522 		if (obj->nodesetval != NULL) {
5523 		    if (obj->boolval) {
5524 			/*
5525 			* It looks like the @boolval is used for
5526 			* evaluation if this an XSLT Result Tree Fragment.
5527 			* TODO: Check if this assumption is correct.
5528 			*/
5529 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
5530 			xmlXPathFreeValueTree(obj->nodesetval);
5531 			obj->nodesetval = NULL;
5532 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
5533 			(XP_CACHE_WANTS(cache->nodesetObjs,
5534 					cache->maxNodeset)))
5535 		    {
5536 			XP_CACHE_ADD(cache->nodesetObjs, obj);
5537 			goto obj_cached;
5538 		    } else {
5539 			xmlXPathFreeNodeSet(obj->nodesetval);
5540 			obj->nodesetval = NULL;
5541 		    }
5542 		}
5543 		break;
5544 	    case XPATH_STRING:
5545 		if (obj->stringval != NULL)
5546 		    xmlFree(obj->stringval);
5547 
5548 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5549 		    XP_CACHE_ADD(cache->stringObjs, obj);
5550 		    goto obj_cached;
5551 		}
5552 		break;
5553 	    case XPATH_BOOLEAN:
5554 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5555 		    XP_CACHE_ADD(cache->booleanObjs, obj);
5556 		    goto obj_cached;
5557 		}
5558 		break;
5559 	    case XPATH_NUMBER:
5560 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5561 		    XP_CACHE_ADD(cache->numberObjs, obj);
5562 		    goto obj_cached;
5563 		}
5564 		break;
5565 #ifdef LIBXML_XPTR_ENABLED
5566 	    case XPATH_LOCATIONSET:
5567 		if (obj->user != NULL) {
5568 		    xmlXPtrFreeLocationSet(obj->user);
5569 		}
5570 		goto free_obj;
5571 #endif
5572 	    default:
5573 		goto free_obj;
5574 	}
5575 
5576 	/*
5577 	* Fallback to adding to the misc-objects slot.
5578 	*/
5579 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5580 	    XP_CACHE_ADD(cache->miscObjs, obj);
5581 	} else
5582 	    goto free_obj;
5583 
5584 obj_cached:
5585 
5586 #ifdef XP_DEBUG_OBJ_USAGE
5587 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5588 #endif
5589 
5590 	if (obj->nodesetval != NULL) {
5591 	    xmlNodeSetPtr tmpset = obj->nodesetval;
5592 
5593 	    /*
5594 	    * TODO: Due to those nasty ns-nodes, we need to traverse
5595 	    *  the list and free the ns-nodes.
5596 	    * URGENT TODO: Check if it's actually slowing things down.
5597 	    *  Maybe we shouldn't try to preserve the list.
5598 	    */
5599 	    if (tmpset->nodeNr > 1) {
5600 		int i;
5601 		xmlNodePtr node;
5602 
5603 		for (i = 0; i < tmpset->nodeNr; i++) {
5604 		    node = tmpset->nodeTab[i];
5605 		    if ((node != NULL) &&
5606 			(node->type == XML_NAMESPACE_DECL))
5607 		    {
5608 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5609 		    }
5610 		}
5611 	    } else if (tmpset->nodeNr == 1) {
5612 		if ((tmpset->nodeTab[0] != NULL) &&
5613 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5614 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5615 	    }
5616 	    tmpset->nodeNr = 0;
5617 	    memset(obj, 0, sizeof(xmlXPathObject));
5618 	    obj->nodesetval = tmpset;
5619 	} else
5620 	    memset(obj, 0, sizeof(xmlXPathObject));
5621 
5622 	return;
5623 
5624 free_obj:
5625 	/*
5626 	* Cache is full; free the object.
5627 	*/
5628 	if (obj->nodesetval != NULL)
5629 	    xmlXPathFreeNodeSet(obj->nodesetval);
5630 #ifdef XP_DEBUG_OBJ_USAGE
5631 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
5632 #endif
5633 	xmlFree(obj);
5634     }
5635     return;
5636 }
5637 
5638 
5639 /************************************************************************
5640  *									*
5641  *			Type Casting Routines				*
5642  *									*
5643  ************************************************************************/
5644 
5645 /**
5646  * xmlXPathCastBooleanToString:
5647  * @val:  a boolean
5648  *
5649  * Converts a boolean to its string value.
5650  *
5651  * Returns a newly allocated string.
5652  */
5653 xmlChar *
5654 xmlXPathCastBooleanToString (int val) {
5655     xmlChar *ret;
5656     if (val)
5657 	ret = xmlStrdup((const xmlChar *) "true");
5658     else
5659 	ret = xmlStrdup((const xmlChar *) "false");
5660     return(ret);
5661 }
5662 
5663 /**
5664  * xmlXPathCastNumberToString:
5665  * @val:  a number
5666  *
5667  * Converts a number to its string value.
5668  *
5669  * Returns a newly allocated string.
5670  */
5671 xmlChar *
5672 xmlXPathCastNumberToString (double val) {
5673     xmlChar *ret;
5674     switch (xmlXPathIsInf(val)) {
5675     case 1:
5676 	ret = xmlStrdup((const xmlChar *) "Infinity");
5677 	break;
5678     case -1:
5679 	ret = xmlStrdup((const xmlChar *) "-Infinity");
5680 	break;
5681     default:
5682 	if (xmlXPathIsNaN(val)) {
5683 	    ret = xmlStrdup((const xmlChar *) "NaN");
5684 	} else if (val == 0) {
5685             /* Omit sign for negative zero. */
5686 	    ret = xmlStrdup((const xmlChar *) "0");
5687 	} else {
5688 	    /* could be improved */
5689 	    char buf[100];
5690 	    xmlXPathFormatNumber(val, buf, 99);
5691 	    buf[99] = 0;
5692 	    ret = xmlStrdup((const xmlChar *) buf);
5693 	}
5694     }
5695     return(ret);
5696 }
5697 
5698 /**
5699  * xmlXPathCastNodeToString:
5700  * @node:  a node
5701  *
5702  * Converts a node to its string value.
5703  *
5704  * Returns a newly allocated string.
5705  */
5706 xmlChar *
5707 xmlXPathCastNodeToString (xmlNodePtr node) {
5708 xmlChar *ret;
5709     if ((ret = xmlNodeGetContent(node)) == NULL)
5710 	ret = xmlStrdup((const xmlChar *) "");
5711     return(ret);
5712 }
5713 
5714 /**
5715  * xmlXPathCastNodeSetToString:
5716  * @ns:  a node-set
5717  *
5718  * Converts a node-set to its string value.
5719  *
5720  * Returns a newly allocated string.
5721  */
5722 xmlChar *
5723 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5724     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5725 	return(xmlStrdup((const xmlChar *) ""));
5726 
5727     if (ns->nodeNr > 1)
5728 	xmlXPathNodeSetSort(ns);
5729     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5730 }
5731 
5732 /**
5733  * xmlXPathCastToString:
5734  * @val:  an XPath object
5735  *
5736  * Converts an existing object to its string() equivalent
5737  *
5738  * Returns the allocated string value of the object, NULL in case of error.
5739  *         It's up to the caller to free the string memory with xmlFree().
5740  */
5741 xmlChar *
5742 xmlXPathCastToString(xmlXPathObjectPtr val) {
5743     xmlChar *ret = NULL;
5744 
5745     if (val == NULL)
5746 	return(xmlStrdup((const xmlChar *) ""));
5747     switch (val->type) {
5748 	case XPATH_UNDEFINED:
5749 #ifdef DEBUG_EXPR
5750 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5751 #endif
5752 	    ret = xmlStrdup((const xmlChar *) "");
5753 	    break;
5754         case XPATH_NODESET:
5755         case XPATH_XSLT_TREE:
5756 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5757 	    break;
5758 	case XPATH_STRING:
5759 	    return(xmlStrdup(val->stringval));
5760         case XPATH_BOOLEAN:
5761 	    ret = xmlXPathCastBooleanToString(val->boolval);
5762 	    break;
5763 	case XPATH_NUMBER: {
5764 	    ret = xmlXPathCastNumberToString(val->floatval);
5765 	    break;
5766 	}
5767 	case XPATH_USERS:
5768 	case XPATH_POINT:
5769 	case XPATH_RANGE:
5770 	case XPATH_LOCATIONSET:
5771 	    TODO
5772 	    ret = xmlStrdup((const xmlChar *) "");
5773 	    break;
5774     }
5775     return(ret);
5776 }
5777 
5778 /**
5779  * xmlXPathConvertString:
5780  * @val:  an XPath object
5781  *
5782  * Converts an existing object to its string() equivalent
5783  *
5784  * Returns the new object, the old one is freed (or the operation
5785  *         is done directly on @val)
5786  */
5787 xmlXPathObjectPtr
5788 xmlXPathConvertString(xmlXPathObjectPtr val) {
5789     xmlChar *res = NULL;
5790 
5791     if (val == NULL)
5792 	return(xmlXPathNewCString(""));
5793 
5794     switch (val->type) {
5795     case XPATH_UNDEFINED:
5796 #ifdef DEBUG_EXPR
5797 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5798 #endif
5799 	break;
5800     case XPATH_NODESET:
5801     case XPATH_XSLT_TREE:
5802 	res = xmlXPathCastNodeSetToString(val->nodesetval);
5803 	break;
5804     case XPATH_STRING:
5805 	return(val);
5806     case XPATH_BOOLEAN:
5807 	res = xmlXPathCastBooleanToString(val->boolval);
5808 	break;
5809     case XPATH_NUMBER:
5810 	res = xmlXPathCastNumberToString(val->floatval);
5811 	break;
5812     case XPATH_USERS:
5813     case XPATH_POINT:
5814     case XPATH_RANGE:
5815     case XPATH_LOCATIONSET:
5816 	TODO;
5817 	break;
5818     }
5819     xmlXPathFreeObject(val);
5820     if (res == NULL)
5821 	return(xmlXPathNewCString(""));
5822     return(xmlXPathWrapString(res));
5823 }
5824 
5825 /**
5826  * xmlXPathCastBooleanToNumber:
5827  * @val:  a boolean
5828  *
5829  * Converts a boolean to its number value
5830  *
5831  * Returns the number value
5832  */
5833 double
5834 xmlXPathCastBooleanToNumber(int val) {
5835     if (val)
5836 	return(1.0);
5837     return(0.0);
5838 }
5839 
5840 /**
5841  * xmlXPathCastStringToNumber:
5842  * @val:  a string
5843  *
5844  * Converts a string to its number value
5845  *
5846  * Returns the number value
5847  */
5848 double
5849 xmlXPathCastStringToNumber(const xmlChar * val) {
5850     return(xmlXPathStringEvalNumber(val));
5851 }
5852 
5853 /**
5854  * xmlXPathCastNodeToNumber:
5855  * @node:  a node
5856  *
5857  * Converts a node to its number value
5858  *
5859  * Returns the number value
5860  */
5861 double
5862 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5863     xmlChar *strval;
5864     double ret;
5865 
5866     if (node == NULL)
5867 	return(NAN);
5868     strval = xmlXPathCastNodeToString(node);
5869     if (strval == NULL)
5870 	return(NAN);
5871     ret = xmlXPathCastStringToNumber(strval);
5872     xmlFree(strval);
5873 
5874     return(ret);
5875 }
5876 
5877 /**
5878  * xmlXPathCastNodeSetToNumber:
5879  * @ns:  a node-set
5880  *
5881  * Converts a node-set to its number value
5882  *
5883  * Returns the number value
5884  */
5885 double
5886 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5887     xmlChar *str;
5888     double ret;
5889 
5890     if (ns == NULL)
5891 	return(NAN);
5892     str = xmlXPathCastNodeSetToString(ns);
5893     ret = xmlXPathCastStringToNumber(str);
5894     xmlFree(str);
5895     return(ret);
5896 }
5897 
5898 /**
5899  * xmlXPathCastToNumber:
5900  * @val:  an XPath object
5901  *
5902  * Converts an XPath object to its number value
5903  *
5904  * Returns the number value
5905  */
5906 double
5907 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5908     double ret = 0.0;
5909 
5910     if (val == NULL)
5911 	return(NAN);
5912     switch (val->type) {
5913     case XPATH_UNDEFINED:
5914 #ifdef DEBUG_EXPR
5915 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5916 #endif
5917 	ret = NAN;
5918 	break;
5919     case XPATH_NODESET:
5920     case XPATH_XSLT_TREE:
5921 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5922 	break;
5923     case XPATH_STRING:
5924 	ret = xmlXPathCastStringToNumber(val->stringval);
5925 	break;
5926     case XPATH_NUMBER:
5927 	ret = val->floatval;
5928 	break;
5929     case XPATH_BOOLEAN:
5930 	ret = xmlXPathCastBooleanToNumber(val->boolval);
5931 	break;
5932     case XPATH_USERS:
5933     case XPATH_POINT:
5934     case XPATH_RANGE:
5935     case XPATH_LOCATIONSET:
5936 	TODO;
5937 	ret = NAN;
5938 	break;
5939     }
5940     return(ret);
5941 }
5942 
5943 /**
5944  * xmlXPathConvertNumber:
5945  * @val:  an XPath object
5946  *
5947  * Converts an existing object to its number() equivalent
5948  *
5949  * Returns the new object, the old one is freed (or the operation
5950  *         is done directly on @val)
5951  */
5952 xmlXPathObjectPtr
5953 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5954     xmlXPathObjectPtr ret;
5955 
5956     if (val == NULL)
5957 	return(xmlXPathNewFloat(0.0));
5958     if (val->type == XPATH_NUMBER)
5959 	return(val);
5960     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5961     xmlXPathFreeObject(val);
5962     return(ret);
5963 }
5964 
5965 /**
5966  * xmlXPathCastNumberToBoolean:
5967  * @val:  a number
5968  *
5969  * Converts a number to its boolean value
5970  *
5971  * Returns the boolean value
5972  */
5973 int
5974 xmlXPathCastNumberToBoolean (double val) {
5975      if (xmlXPathIsNaN(val) || (val == 0.0))
5976 	 return(0);
5977      return(1);
5978 }
5979 
5980 /**
5981  * xmlXPathCastStringToBoolean:
5982  * @val:  a string
5983  *
5984  * Converts a string to its boolean value
5985  *
5986  * Returns the boolean value
5987  */
5988 int
5989 xmlXPathCastStringToBoolean (const xmlChar *val) {
5990     if ((val == NULL) || (xmlStrlen(val) == 0))
5991 	return(0);
5992     return(1);
5993 }
5994 
5995 /**
5996  * xmlXPathCastNodeSetToBoolean:
5997  * @ns:  a node-set
5998  *
5999  * Converts a node-set to its boolean value
6000  *
6001  * Returns the boolean value
6002  */
6003 int
6004 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6005     if ((ns == NULL) || (ns->nodeNr == 0))
6006 	return(0);
6007     return(1);
6008 }
6009 
6010 /**
6011  * xmlXPathCastToBoolean:
6012  * @val:  an XPath object
6013  *
6014  * Converts an XPath object to its boolean value
6015  *
6016  * Returns the boolean value
6017  */
6018 int
6019 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6020     int ret = 0;
6021 
6022     if (val == NULL)
6023 	return(0);
6024     switch (val->type) {
6025     case XPATH_UNDEFINED:
6026 #ifdef DEBUG_EXPR
6027 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6028 #endif
6029 	ret = 0;
6030 	break;
6031     case XPATH_NODESET:
6032     case XPATH_XSLT_TREE:
6033 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6034 	break;
6035     case XPATH_STRING:
6036 	ret = xmlXPathCastStringToBoolean(val->stringval);
6037 	break;
6038     case XPATH_NUMBER:
6039 	ret = xmlXPathCastNumberToBoolean(val->floatval);
6040 	break;
6041     case XPATH_BOOLEAN:
6042 	ret = val->boolval;
6043 	break;
6044     case XPATH_USERS:
6045     case XPATH_POINT:
6046     case XPATH_RANGE:
6047     case XPATH_LOCATIONSET:
6048 	TODO;
6049 	ret = 0;
6050 	break;
6051     }
6052     return(ret);
6053 }
6054 
6055 
6056 /**
6057  * xmlXPathConvertBoolean:
6058  * @val:  an XPath object
6059  *
6060  * Converts an existing object to its boolean() equivalent
6061  *
6062  * Returns the new object, the old one is freed (or the operation
6063  *         is done directly on @val)
6064  */
6065 xmlXPathObjectPtr
6066 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6067     xmlXPathObjectPtr ret;
6068 
6069     if (val == NULL)
6070 	return(xmlXPathNewBoolean(0));
6071     if (val->type == XPATH_BOOLEAN)
6072 	return(val);
6073     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6074     xmlXPathFreeObject(val);
6075     return(ret);
6076 }
6077 
6078 /************************************************************************
6079  *									*
6080  *		Routines to handle XPath contexts			*
6081  *									*
6082  ************************************************************************/
6083 
6084 /**
6085  * xmlXPathNewContext:
6086  * @doc:  the XML document
6087  *
6088  * Create a new xmlXPathContext
6089  *
6090  * Returns the xmlXPathContext just allocated. The caller will need to free it.
6091  */
6092 xmlXPathContextPtr
6093 xmlXPathNewContext(xmlDocPtr doc) {
6094     xmlXPathContextPtr ret;
6095 
6096     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6097     if (ret == NULL) {
6098         xmlXPathErrMemory(NULL, "creating context\n");
6099 	return(NULL);
6100     }
6101     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6102     ret->doc = doc;
6103     ret->node = NULL;
6104 
6105     ret->varHash = NULL;
6106 
6107     ret->nb_types = 0;
6108     ret->max_types = 0;
6109     ret->types = NULL;
6110 
6111     ret->funcHash = xmlHashCreate(0);
6112 
6113     ret->nb_axis = 0;
6114     ret->max_axis = 0;
6115     ret->axis = NULL;
6116 
6117     ret->nsHash = NULL;
6118     ret->user = NULL;
6119 
6120     ret->contextSize = -1;
6121     ret->proximityPosition = -1;
6122 
6123     ret->maxDepth = INT_MAX;
6124     ret->maxParserDepth = INT_MAX;
6125 
6126 #ifdef XP_DEFAULT_CACHE_ON
6127     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6128 	xmlXPathFreeContext(ret);
6129 	return(NULL);
6130     }
6131 #endif
6132 
6133     xmlXPathRegisterAllFunctions(ret);
6134 
6135     return(ret);
6136 }
6137 
6138 /**
6139  * xmlXPathFreeContext:
6140  * @ctxt:  the context to free
6141  *
6142  * Free up an xmlXPathContext
6143  */
6144 void
6145 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6146     if (ctxt == NULL) return;
6147 
6148     if (ctxt->cache != NULL)
6149 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6150     xmlXPathRegisteredNsCleanup(ctxt);
6151     xmlXPathRegisteredFuncsCleanup(ctxt);
6152     xmlXPathRegisteredVariablesCleanup(ctxt);
6153     xmlResetError(&ctxt->lastError);
6154     xmlFree(ctxt);
6155 }
6156 
6157 /************************************************************************
6158  *									*
6159  *		Routines to handle XPath parser contexts		*
6160  *									*
6161  ************************************************************************/
6162 
6163 #define CHECK_CTXT(ctxt)						\
6164     if (ctxt == NULL) {						\
6165 	__xmlRaiseError(NULL, NULL, NULL,				\
6166 		NULL, NULL, XML_FROM_XPATH,				\
6167 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6168 		__FILE__, __LINE__,					\
6169 		NULL, NULL, NULL, 0, 0,					\
6170 		"NULL context pointer\n");				\
6171 	return(NULL);							\
6172     }									\
6173 
6174 #define CHECK_CTXT_NEG(ctxt)						\
6175     if (ctxt == NULL) {						\
6176 	__xmlRaiseError(NULL, NULL, NULL,				\
6177 		NULL, NULL, XML_FROM_XPATH,				\
6178 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6179 		__FILE__, __LINE__,					\
6180 		NULL, NULL, NULL, 0, 0,					\
6181 		"NULL context pointer\n");				\
6182 	return(-1);							\
6183     }									\
6184 
6185 
6186 #define CHECK_CONTEXT(ctxt)						\
6187     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
6188         (ctxt->doc->children == NULL)) {				\
6189 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
6190 	return(NULL);							\
6191     }
6192 
6193 
6194 /**
6195  * xmlXPathNewParserContext:
6196  * @str:  the XPath expression
6197  * @ctxt:  the XPath context
6198  *
6199  * Create a new xmlXPathParserContext
6200  *
6201  * Returns the xmlXPathParserContext just allocated.
6202  */
6203 xmlXPathParserContextPtr
6204 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6205     xmlXPathParserContextPtr ret;
6206 
6207     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6208     if (ret == NULL) {
6209         xmlXPathErrMemory(ctxt, "creating parser context\n");
6210 	return(NULL);
6211     }
6212     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6213     ret->cur = ret->base = str;
6214     ret->context = ctxt;
6215 
6216     ret->comp = xmlXPathNewCompExpr();
6217     if (ret->comp == NULL) {
6218 	xmlFree(ret->valueTab);
6219 	xmlFree(ret);
6220 	return(NULL);
6221     }
6222     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6223         ret->comp->dict = ctxt->dict;
6224 	xmlDictReference(ret->comp->dict);
6225     }
6226 
6227     return(ret);
6228 }
6229 
6230 /**
6231  * xmlXPathCompParserContext:
6232  * @comp:  the XPath compiled expression
6233  * @ctxt:  the XPath context
6234  *
6235  * Create a new xmlXPathParserContext when processing a compiled expression
6236  *
6237  * Returns the xmlXPathParserContext just allocated.
6238  */
6239 static xmlXPathParserContextPtr
6240 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6241     xmlXPathParserContextPtr ret;
6242 
6243     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6244     if (ret == NULL) {
6245         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6246 	return(NULL);
6247     }
6248     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6249 
6250     /* Allocate the value stack */
6251     ret->valueTab = (xmlXPathObjectPtr *)
6252                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6253     if (ret->valueTab == NULL) {
6254 	xmlFree(ret);
6255 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6256 	return(NULL);
6257     }
6258     ret->valueNr = 0;
6259     ret->valueMax = 10;
6260     ret->value = NULL;
6261     ret->valueFrame = 0;
6262 
6263     ret->context = ctxt;
6264     ret->comp = comp;
6265 
6266     return(ret);
6267 }
6268 
6269 /**
6270  * xmlXPathFreeParserContext:
6271  * @ctxt:  the context to free
6272  *
6273  * Free up an xmlXPathParserContext
6274  */
6275 void
6276 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6277     int i;
6278 
6279     if (ctxt->valueTab != NULL) {
6280         for (i = 0; i < ctxt->valueNr; i++) {
6281             if (ctxt->context)
6282                 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6283             else
6284                 xmlXPathFreeObject(ctxt->valueTab[i]);
6285         }
6286         xmlFree(ctxt->valueTab);
6287     }
6288     if (ctxt->comp != NULL) {
6289 #ifdef XPATH_STREAMING
6290 	if (ctxt->comp->stream != NULL) {
6291 	    xmlFreePatternList(ctxt->comp->stream);
6292 	    ctxt->comp->stream = NULL;
6293 	}
6294 #endif
6295 	xmlXPathFreeCompExpr(ctxt->comp);
6296     }
6297     xmlFree(ctxt);
6298 }
6299 
6300 /************************************************************************
6301  *									*
6302  *		The implicit core function library			*
6303  *									*
6304  ************************************************************************/
6305 
6306 /**
6307  * xmlXPathNodeValHash:
6308  * @node:  a node pointer
6309  *
6310  * Function computing the beginning of the string value of the node,
6311  * used to speed up comparisons
6312  *
6313  * Returns an int usable as a hash
6314  */
6315 static unsigned int
6316 xmlXPathNodeValHash(xmlNodePtr node) {
6317     int len = 2;
6318     const xmlChar * string = NULL;
6319     xmlNodePtr tmp = NULL;
6320     unsigned int ret = 0;
6321 
6322     if (node == NULL)
6323 	return(0);
6324 
6325     if (node->type == XML_DOCUMENT_NODE) {
6326 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
6327 	if (tmp == NULL)
6328 	    node = node->children;
6329 	else
6330 	    node = tmp;
6331 
6332 	if (node == NULL)
6333 	    return(0);
6334     }
6335 
6336     switch (node->type) {
6337 	case XML_COMMENT_NODE:
6338 	case XML_PI_NODE:
6339 	case XML_CDATA_SECTION_NODE:
6340 	case XML_TEXT_NODE:
6341 	    string = node->content;
6342 	    if (string == NULL)
6343 		return(0);
6344 	    if (string[0] == 0)
6345 		return(0);
6346 	    return(((unsigned int) string[0]) +
6347 		   (((unsigned int) string[1]) << 8));
6348 	case XML_NAMESPACE_DECL:
6349 	    string = ((xmlNsPtr)node)->href;
6350 	    if (string == NULL)
6351 		return(0);
6352 	    if (string[0] == 0)
6353 		return(0);
6354 	    return(((unsigned int) string[0]) +
6355 		   (((unsigned int) string[1]) << 8));
6356 	case XML_ATTRIBUTE_NODE:
6357 	    tmp = ((xmlAttrPtr) node)->children;
6358 	    break;
6359 	case XML_ELEMENT_NODE:
6360 	    tmp = node->children;
6361 	    break;
6362 	default:
6363 	    return(0);
6364     }
6365     while (tmp != NULL) {
6366 	switch (tmp->type) {
6367 	    case XML_CDATA_SECTION_NODE:
6368 	    case XML_TEXT_NODE:
6369 		string = tmp->content;
6370 		break;
6371 	    default:
6372                 string = NULL;
6373 		break;
6374 	}
6375 	if ((string != NULL) && (string[0] != 0)) {
6376 	    if (len == 1) {
6377 		return(ret + (((unsigned int) string[0]) << 8));
6378 	    }
6379 	    if (string[1] == 0) {
6380 		len = 1;
6381 		ret = (unsigned int) string[0];
6382 	    } else {
6383 		return(((unsigned int) string[0]) +
6384 		       (((unsigned int) string[1]) << 8));
6385 	    }
6386 	}
6387 	/*
6388 	 * Skip to next node
6389 	 */
6390 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6391 	    if (tmp->children->type != XML_ENTITY_DECL) {
6392 		tmp = tmp->children;
6393 		continue;
6394 	    }
6395 	}
6396 	if (tmp == node)
6397 	    break;
6398 
6399 	if (tmp->next != NULL) {
6400 	    tmp = tmp->next;
6401 	    continue;
6402 	}
6403 
6404 	do {
6405 	    tmp = tmp->parent;
6406 	    if (tmp == NULL)
6407 		break;
6408 	    if (tmp == node) {
6409 		tmp = NULL;
6410 		break;
6411 	    }
6412 	    if (tmp->next != NULL) {
6413 		tmp = tmp->next;
6414 		break;
6415 	    }
6416 	} while (tmp != NULL);
6417     }
6418     return(ret);
6419 }
6420 
6421 /**
6422  * xmlXPathStringHash:
6423  * @string:  a string
6424  *
6425  * Function computing the beginning of the string value of the node,
6426  * used to speed up comparisons
6427  *
6428  * Returns an int usable as a hash
6429  */
6430 static unsigned int
6431 xmlXPathStringHash(const xmlChar * string) {
6432     if (string == NULL)
6433 	return((unsigned int) 0);
6434     if (string[0] == 0)
6435 	return(0);
6436     return(((unsigned int) string[0]) +
6437 	   (((unsigned int) string[1]) << 8));
6438 }
6439 
6440 /**
6441  * xmlXPathCompareNodeSetFloat:
6442  * @ctxt:  the XPath Parser context
6443  * @inf:  less than (1) or greater than (0)
6444  * @strict:  is the comparison strict
6445  * @arg:  the node set
6446  * @f:  the value
6447  *
6448  * Implement the compare operation between a nodeset and a number
6449  *     @ns < @val    (1, 1, ...
6450  *     @ns <= @val   (1, 0, ...
6451  *     @ns > @val    (0, 1, ...
6452  *     @ns >= @val   (0, 0, ...
6453  *
6454  * If one object to be compared is a node-set and the other is a number,
6455  * then the comparison will be true if and only if there is a node in the
6456  * node-set such that the result of performing the comparison on the number
6457  * to be compared and on the result of converting the string-value of that
6458  * node to a number using the number function is true.
6459  *
6460  * Returns 0 or 1 depending on the results of the test.
6461  */
6462 static int
6463 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6464 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6465     int i, ret = 0;
6466     xmlNodeSetPtr ns;
6467     xmlChar *str2;
6468 
6469     if ((f == NULL) || (arg == NULL) ||
6470 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6471 	xmlXPathReleaseObject(ctxt->context, arg);
6472 	xmlXPathReleaseObject(ctxt->context, f);
6473         return(0);
6474     }
6475     ns = arg->nodesetval;
6476     if (ns != NULL) {
6477 	for (i = 0;i < ns->nodeNr;i++) {
6478 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6479 	     if (str2 != NULL) {
6480 		 valuePush(ctxt,
6481 			   xmlXPathCacheNewString(ctxt->context, str2));
6482 		 xmlFree(str2);
6483 		 xmlXPathNumberFunction(ctxt, 1);
6484 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6485 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6486 		 if (ret)
6487 		     break;
6488 	     }
6489 	}
6490     }
6491     xmlXPathReleaseObject(ctxt->context, arg);
6492     xmlXPathReleaseObject(ctxt->context, f);
6493     return(ret);
6494 }
6495 
6496 /**
6497  * xmlXPathCompareNodeSetString:
6498  * @ctxt:  the XPath Parser context
6499  * @inf:  less than (1) or greater than (0)
6500  * @strict:  is the comparison strict
6501  * @arg:  the node set
6502  * @s:  the value
6503  *
6504  * Implement the compare operation between a nodeset and a string
6505  *     @ns < @val    (1, 1, ...
6506  *     @ns <= @val   (1, 0, ...
6507  *     @ns > @val    (0, 1, ...
6508  *     @ns >= @val   (0, 0, ...
6509  *
6510  * If one object to be compared is a node-set and the other is a string,
6511  * then the comparison will be true if and only if there is a node in
6512  * the node-set such that the result of performing the comparison on the
6513  * string-value of the node and the other string is true.
6514  *
6515  * Returns 0 or 1 depending on the results of the test.
6516  */
6517 static int
6518 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6519 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6520     int i, ret = 0;
6521     xmlNodeSetPtr ns;
6522     xmlChar *str2;
6523 
6524     if ((s == NULL) || (arg == NULL) ||
6525 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6526 	xmlXPathReleaseObject(ctxt->context, arg);
6527 	xmlXPathReleaseObject(ctxt->context, s);
6528         return(0);
6529     }
6530     ns = arg->nodesetval;
6531     if (ns != NULL) {
6532 	for (i = 0;i < ns->nodeNr;i++) {
6533 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6534 	     if (str2 != NULL) {
6535 		 valuePush(ctxt,
6536 			   xmlXPathCacheNewString(ctxt->context, str2));
6537 		 xmlFree(str2);
6538 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6539 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6540 		 if (ret)
6541 		     break;
6542 	     }
6543 	}
6544     }
6545     xmlXPathReleaseObject(ctxt->context, arg);
6546     xmlXPathReleaseObject(ctxt->context, s);
6547     return(ret);
6548 }
6549 
6550 /**
6551  * xmlXPathCompareNodeSets:
6552  * @inf:  less than (1) or greater than (0)
6553  * @strict:  is the comparison strict
6554  * @arg1:  the first node set object
6555  * @arg2:  the second node set object
6556  *
6557  * Implement the compare operation on nodesets:
6558  *
6559  * If both objects to be compared are node-sets, then the comparison
6560  * will be true if and only if there is a node in the first node-set
6561  * and a node in the second node-set such that the result of performing
6562  * the comparison on the string-values of the two nodes is true.
6563  * ....
6564  * When neither object to be compared is a node-set and the operator
6565  * is <=, <, >= or >, then the objects are compared by converting both
6566  * objects to numbers and comparing the numbers according to IEEE 754.
6567  * ....
6568  * The number function converts its argument to a number as follows:
6569  *  - a string that consists of optional whitespace followed by an
6570  *    optional minus sign followed by a Number followed by whitespace
6571  *    is converted to the IEEE 754 number that is nearest (according
6572  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6573  *    represented by the string; any other string is converted to NaN
6574  *
6575  * Conclusion all nodes need to be converted first to their string value
6576  * and then the comparison must be done when possible
6577  */
6578 static int
6579 xmlXPathCompareNodeSets(int inf, int strict,
6580 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6581     int i, j, init = 0;
6582     double val1;
6583     double *values2;
6584     int ret = 0;
6585     xmlNodeSetPtr ns1;
6586     xmlNodeSetPtr ns2;
6587 
6588     if ((arg1 == NULL) ||
6589 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6590 	xmlXPathFreeObject(arg2);
6591         return(0);
6592     }
6593     if ((arg2 == NULL) ||
6594 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6595 	xmlXPathFreeObject(arg1);
6596 	xmlXPathFreeObject(arg2);
6597         return(0);
6598     }
6599 
6600     ns1 = arg1->nodesetval;
6601     ns2 = arg2->nodesetval;
6602 
6603     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6604 	xmlXPathFreeObject(arg1);
6605 	xmlXPathFreeObject(arg2);
6606 	return(0);
6607     }
6608     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6609 	xmlXPathFreeObject(arg1);
6610 	xmlXPathFreeObject(arg2);
6611 	return(0);
6612     }
6613 
6614     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6615     if (values2 == NULL) {
6616         /* TODO: Propagate memory error. */
6617         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6618 	xmlXPathFreeObject(arg1);
6619 	xmlXPathFreeObject(arg2);
6620 	return(0);
6621     }
6622     for (i = 0;i < ns1->nodeNr;i++) {
6623 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6624 	if (xmlXPathIsNaN(val1))
6625 	    continue;
6626 	for (j = 0;j < ns2->nodeNr;j++) {
6627 	    if (init == 0) {
6628 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6629 	    }
6630 	    if (xmlXPathIsNaN(values2[j]))
6631 		continue;
6632 	    if (inf && strict)
6633 		ret = (val1 < values2[j]);
6634 	    else if (inf && !strict)
6635 		ret = (val1 <= values2[j]);
6636 	    else if (!inf && strict)
6637 		ret = (val1 > values2[j]);
6638 	    else if (!inf && !strict)
6639 		ret = (val1 >= values2[j]);
6640 	    if (ret)
6641 		break;
6642 	}
6643 	if (ret)
6644 	    break;
6645 	init = 1;
6646     }
6647     xmlFree(values2);
6648     xmlXPathFreeObject(arg1);
6649     xmlXPathFreeObject(arg2);
6650     return(ret);
6651 }
6652 
6653 /**
6654  * xmlXPathCompareNodeSetValue:
6655  * @ctxt:  the XPath Parser context
6656  * @inf:  less than (1) or greater than (0)
6657  * @strict:  is the comparison strict
6658  * @arg:  the node set
6659  * @val:  the value
6660  *
6661  * Implement the compare operation between a nodeset and a value
6662  *     @ns < @val    (1, 1, ...
6663  *     @ns <= @val   (1, 0, ...
6664  *     @ns > @val    (0, 1, ...
6665  *     @ns >= @val   (0, 0, ...
6666  *
6667  * If one object to be compared is a node-set and the other is a boolean,
6668  * then the comparison will be true if and only if the result of performing
6669  * the comparison on the boolean and on the result of converting
6670  * the node-set to a boolean using the boolean function is true.
6671  *
6672  * Returns 0 or 1 depending on the results of the test.
6673  */
6674 static int
6675 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6676 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6677     if ((val == NULL) || (arg == NULL) ||
6678 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6679         return(0);
6680 
6681     switch(val->type) {
6682         case XPATH_NUMBER:
6683 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6684         case XPATH_NODESET:
6685         case XPATH_XSLT_TREE:
6686 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6687         case XPATH_STRING:
6688 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6689         case XPATH_BOOLEAN:
6690 	    valuePush(ctxt, arg);
6691 	    xmlXPathBooleanFunction(ctxt, 1);
6692 	    valuePush(ctxt, val);
6693 	    return(xmlXPathCompareValues(ctxt, inf, strict));
6694 	default:
6695             xmlGenericError(xmlGenericErrorContext,
6696                     "xmlXPathCompareNodeSetValue: Can't compare node set "
6697                     "and object of type %d\n",
6698                     val->type);
6699             xmlXPathReleaseObject(ctxt->context, arg);
6700             xmlXPathReleaseObject(ctxt->context, val);
6701             XP_ERROR0(XPATH_INVALID_TYPE);
6702     }
6703     return(0);
6704 }
6705 
6706 /**
6707  * xmlXPathEqualNodeSetString:
6708  * @arg:  the nodeset object argument
6709  * @str:  the string to compare to.
6710  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6711  *
6712  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6713  * If one object to be compared is a node-set and the other is a string,
6714  * then the comparison will be true if and only if there is a node in
6715  * the node-set such that the result of performing the comparison on the
6716  * string-value of the node and the other string is true.
6717  *
6718  * Returns 0 or 1 depending on the results of the test.
6719  */
6720 static int
6721 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6722 {
6723     int i;
6724     xmlNodeSetPtr ns;
6725     xmlChar *str2;
6726     unsigned int hash;
6727 
6728     if ((str == NULL) || (arg == NULL) ||
6729         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6730         return (0);
6731     ns = arg->nodesetval;
6732     /*
6733      * A NULL nodeset compared with a string is always false
6734      * (since there is no node equal, and no node not equal)
6735      */
6736     if ((ns == NULL) || (ns->nodeNr <= 0) )
6737         return (0);
6738     hash = xmlXPathStringHash(str);
6739     for (i = 0; i < ns->nodeNr; i++) {
6740         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6741             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6742             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6743                 xmlFree(str2);
6744 		if (neq)
6745 		    continue;
6746                 return (1);
6747 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6748 		if (neq)
6749 		    continue;
6750                 return (1);
6751             } else if (neq) {
6752 		if (str2 != NULL)
6753 		    xmlFree(str2);
6754 		return (1);
6755 	    }
6756             if (str2 != NULL)
6757                 xmlFree(str2);
6758         } else if (neq)
6759 	    return (1);
6760     }
6761     return (0);
6762 }
6763 
6764 /**
6765  * xmlXPathEqualNodeSetFloat:
6766  * @arg:  the nodeset object argument
6767  * @f:  the float to compare to
6768  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6769  *
6770  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6771  * If one object to be compared is a node-set and the other is a number,
6772  * then the comparison will be true if and only if there is a node in
6773  * the node-set such that the result of performing the comparison on the
6774  * number to be compared and on the result of converting the string-value
6775  * of that node to a number using the number function is true.
6776  *
6777  * Returns 0 or 1 depending on the results of the test.
6778  */
6779 static int
6780 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6781     xmlXPathObjectPtr arg, double f, int neq) {
6782   int i, ret=0;
6783   xmlNodeSetPtr ns;
6784   xmlChar *str2;
6785   xmlXPathObjectPtr val;
6786   double v;
6787 
6788     if ((arg == NULL) ||
6789 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6790         return(0);
6791 
6792     ns = arg->nodesetval;
6793     if (ns != NULL) {
6794 	for (i=0;i<ns->nodeNr;i++) {
6795 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6796 	    if (str2 != NULL) {
6797 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6798 		xmlFree(str2);
6799 		xmlXPathNumberFunction(ctxt, 1);
6800 		val = valuePop(ctxt);
6801 		v = val->floatval;
6802 		xmlXPathReleaseObject(ctxt->context, val);
6803 		if (!xmlXPathIsNaN(v)) {
6804 		    if ((!neq) && (v==f)) {
6805 			ret = 1;
6806 			break;
6807 		    } else if ((neq) && (v!=f)) {
6808 			ret = 1;
6809 			break;
6810 		    }
6811 		} else {	/* NaN is unequal to any value */
6812 		    if (neq)
6813 			ret = 1;
6814 		}
6815 	    }
6816 	}
6817     }
6818 
6819     return(ret);
6820 }
6821 
6822 
6823 /**
6824  * xmlXPathEqualNodeSets:
6825  * @arg1:  first nodeset object argument
6826  * @arg2:  second nodeset object argument
6827  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6828  *
6829  * Implement the equal / not equal operation on XPath nodesets:
6830  * @arg1 == @arg2  or  @arg1 != @arg2
6831  * If both objects to be compared are node-sets, then the comparison
6832  * will be true if and only if there is a node in the first node-set and
6833  * a node in the second node-set such that the result of performing the
6834  * comparison on the string-values of the two nodes is true.
6835  *
6836  * (needless to say, this is a costly operation)
6837  *
6838  * Returns 0 or 1 depending on the results of the test.
6839  */
6840 static int
6841 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6842     int i, j;
6843     unsigned int *hashs1;
6844     unsigned int *hashs2;
6845     xmlChar **values1;
6846     xmlChar **values2;
6847     int ret = 0;
6848     xmlNodeSetPtr ns1;
6849     xmlNodeSetPtr ns2;
6850 
6851     if ((arg1 == NULL) ||
6852 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6853         return(0);
6854     if ((arg2 == NULL) ||
6855 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6856         return(0);
6857 
6858     ns1 = arg1->nodesetval;
6859     ns2 = arg2->nodesetval;
6860 
6861     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6862 	return(0);
6863     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6864 	return(0);
6865 
6866     /*
6867      * for equal, check if there is a node pertaining to both sets
6868      */
6869     if (neq == 0)
6870 	for (i = 0;i < ns1->nodeNr;i++)
6871 	    for (j = 0;j < ns2->nodeNr;j++)
6872 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6873 		    return(1);
6874 
6875     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6876     if (values1 == NULL) {
6877         /* TODO: Propagate memory error. */
6878         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6879 	return(0);
6880     }
6881     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6882     if (hashs1 == NULL) {
6883         /* TODO: Propagate memory error. */
6884         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6885 	xmlFree(values1);
6886 	return(0);
6887     }
6888     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6889     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6890     if (values2 == NULL) {
6891         /* TODO: Propagate memory error. */
6892         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6893 	xmlFree(hashs1);
6894 	xmlFree(values1);
6895 	return(0);
6896     }
6897     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6898     if (hashs2 == NULL) {
6899         /* TODO: Propagate memory error. */
6900         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6901 	xmlFree(hashs1);
6902 	xmlFree(values1);
6903 	xmlFree(values2);
6904 	return(0);
6905     }
6906     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6907     for (i = 0;i < ns1->nodeNr;i++) {
6908 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6909 	for (j = 0;j < ns2->nodeNr;j++) {
6910 	    if (i == 0)
6911 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6912 	    if (hashs1[i] != hashs2[j]) {
6913 		if (neq) {
6914 		    ret = 1;
6915 		    break;
6916 		}
6917 	    }
6918 	    else {
6919 		if (values1[i] == NULL)
6920 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6921 		if (values2[j] == NULL)
6922 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6923 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6924 		if (ret)
6925 		    break;
6926 	    }
6927 	}
6928 	if (ret)
6929 	    break;
6930     }
6931     for (i = 0;i < ns1->nodeNr;i++)
6932 	if (values1[i] != NULL)
6933 	    xmlFree(values1[i]);
6934     for (j = 0;j < ns2->nodeNr;j++)
6935 	if (values2[j] != NULL)
6936 	    xmlFree(values2[j]);
6937     xmlFree(values1);
6938     xmlFree(values2);
6939     xmlFree(hashs1);
6940     xmlFree(hashs2);
6941     return(ret);
6942 }
6943 
6944 static int
6945 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6946   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6947     int ret = 0;
6948     /*
6949      *At this point we are assured neither arg1 nor arg2
6950      *is a nodeset, so we can just pick the appropriate routine.
6951      */
6952     switch (arg1->type) {
6953         case XPATH_UNDEFINED:
6954 #ifdef DEBUG_EXPR
6955 	    xmlGenericError(xmlGenericErrorContext,
6956 		    "Equal: undefined\n");
6957 #endif
6958 	    break;
6959         case XPATH_BOOLEAN:
6960 	    switch (arg2->type) {
6961 	        case XPATH_UNDEFINED:
6962 #ifdef DEBUG_EXPR
6963 		    xmlGenericError(xmlGenericErrorContext,
6964 			    "Equal: undefined\n");
6965 #endif
6966 		    break;
6967 		case XPATH_BOOLEAN:
6968 #ifdef DEBUG_EXPR
6969 		    xmlGenericError(xmlGenericErrorContext,
6970 			    "Equal: %d boolean %d \n",
6971 			    arg1->boolval, arg2->boolval);
6972 #endif
6973 		    ret = (arg1->boolval == arg2->boolval);
6974 		    break;
6975 		case XPATH_NUMBER:
6976 		    ret = (arg1->boolval ==
6977 			   xmlXPathCastNumberToBoolean(arg2->floatval));
6978 		    break;
6979 		case XPATH_STRING:
6980 		    if ((arg2->stringval == NULL) ||
6981 			(arg2->stringval[0] == 0)) ret = 0;
6982 		    else
6983 			ret = 1;
6984 		    ret = (arg1->boolval == ret);
6985 		    break;
6986 		case XPATH_USERS:
6987 		case XPATH_POINT:
6988 		case XPATH_RANGE:
6989 		case XPATH_LOCATIONSET:
6990 		    TODO
6991 		    break;
6992 		case XPATH_NODESET:
6993 		case XPATH_XSLT_TREE:
6994 		    break;
6995 	    }
6996 	    break;
6997         case XPATH_NUMBER:
6998 	    switch (arg2->type) {
6999 	        case XPATH_UNDEFINED:
7000 #ifdef DEBUG_EXPR
7001 		    xmlGenericError(xmlGenericErrorContext,
7002 			    "Equal: undefined\n");
7003 #endif
7004 		    break;
7005 		case XPATH_BOOLEAN:
7006 		    ret = (arg2->boolval==
7007 			   xmlXPathCastNumberToBoolean(arg1->floatval));
7008 		    break;
7009 		case XPATH_STRING:
7010 		    valuePush(ctxt, arg2);
7011 		    xmlXPathNumberFunction(ctxt, 1);
7012 		    arg2 = valuePop(ctxt);
7013                     /* Falls through. */
7014 		case XPATH_NUMBER:
7015 		    /* Hand check NaN and Infinity equalities */
7016 		    if (xmlXPathIsNaN(arg1->floatval) ||
7017 			    xmlXPathIsNaN(arg2->floatval)) {
7018 		        ret = 0;
7019 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7020 		        if (xmlXPathIsInf(arg2->floatval) == 1)
7021 			    ret = 1;
7022 			else
7023 			    ret = 0;
7024 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7025 			if (xmlXPathIsInf(arg2->floatval) == -1)
7026 			    ret = 1;
7027 			else
7028 			    ret = 0;
7029 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7030 			if (xmlXPathIsInf(arg1->floatval) == 1)
7031 			    ret = 1;
7032 			else
7033 			    ret = 0;
7034 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7035 			if (xmlXPathIsInf(arg1->floatval) == -1)
7036 			    ret = 1;
7037 			else
7038 			    ret = 0;
7039 		    } else {
7040 		        ret = (arg1->floatval == arg2->floatval);
7041 		    }
7042 		    break;
7043 		case XPATH_USERS:
7044 		case XPATH_POINT:
7045 		case XPATH_RANGE:
7046 		case XPATH_LOCATIONSET:
7047 		    TODO
7048 		    break;
7049 		case XPATH_NODESET:
7050 		case XPATH_XSLT_TREE:
7051 		    break;
7052 	    }
7053 	    break;
7054         case XPATH_STRING:
7055 	    switch (arg2->type) {
7056 	        case XPATH_UNDEFINED:
7057 #ifdef DEBUG_EXPR
7058 		    xmlGenericError(xmlGenericErrorContext,
7059 			    "Equal: undefined\n");
7060 #endif
7061 		    break;
7062 		case XPATH_BOOLEAN:
7063 		    if ((arg1->stringval == NULL) ||
7064 			(arg1->stringval[0] == 0)) ret = 0;
7065 		    else
7066 			ret = 1;
7067 		    ret = (arg2->boolval == ret);
7068 		    break;
7069 		case XPATH_STRING:
7070 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7071 		    break;
7072 		case XPATH_NUMBER:
7073 		    valuePush(ctxt, arg1);
7074 		    xmlXPathNumberFunction(ctxt, 1);
7075 		    arg1 = valuePop(ctxt);
7076 		    /* Hand check NaN and Infinity equalities */
7077 		    if (xmlXPathIsNaN(arg1->floatval) ||
7078 			    xmlXPathIsNaN(arg2->floatval)) {
7079 		        ret = 0;
7080 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7081 			if (xmlXPathIsInf(arg2->floatval) == 1)
7082 			    ret = 1;
7083 			else
7084 			    ret = 0;
7085 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7086 			if (xmlXPathIsInf(arg2->floatval) == -1)
7087 			    ret = 1;
7088 			else
7089 			    ret = 0;
7090 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7091 			if (xmlXPathIsInf(arg1->floatval) == 1)
7092 			    ret = 1;
7093 			else
7094 			    ret = 0;
7095 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7096 			if (xmlXPathIsInf(arg1->floatval) == -1)
7097 			    ret = 1;
7098 			else
7099 			    ret = 0;
7100 		    } else {
7101 		        ret = (arg1->floatval == arg2->floatval);
7102 		    }
7103 		    break;
7104 		case XPATH_USERS:
7105 		case XPATH_POINT:
7106 		case XPATH_RANGE:
7107 		case XPATH_LOCATIONSET:
7108 		    TODO
7109 		    break;
7110 		case XPATH_NODESET:
7111 		case XPATH_XSLT_TREE:
7112 		    break;
7113 	    }
7114 	    break;
7115         case XPATH_USERS:
7116 	case XPATH_POINT:
7117 	case XPATH_RANGE:
7118 	case XPATH_LOCATIONSET:
7119 	    TODO
7120 	    break;
7121 	case XPATH_NODESET:
7122 	case XPATH_XSLT_TREE:
7123 	    break;
7124     }
7125     xmlXPathReleaseObject(ctxt->context, arg1);
7126     xmlXPathReleaseObject(ctxt->context, arg2);
7127     return(ret);
7128 }
7129 
7130 /**
7131  * xmlXPathEqualValues:
7132  * @ctxt:  the XPath Parser context
7133  *
7134  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7135  *
7136  * Returns 0 or 1 depending on the results of the test.
7137  */
7138 int
7139 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7140     xmlXPathObjectPtr arg1, arg2, argtmp;
7141     int ret = 0;
7142 
7143     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7144     arg2 = valuePop(ctxt);
7145     arg1 = valuePop(ctxt);
7146     if ((arg1 == NULL) || (arg2 == NULL)) {
7147 	if (arg1 != NULL)
7148 	    xmlXPathReleaseObject(ctxt->context, arg1);
7149 	else
7150 	    xmlXPathReleaseObject(ctxt->context, arg2);
7151 	XP_ERROR0(XPATH_INVALID_OPERAND);
7152     }
7153 
7154     if (arg1 == arg2) {
7155 #ifdef DEBUG_EXPR
7156         xmlGenericError(xmlGenericErrorContext,
7157 		"Equal: by pointer\n");
7158 #endif
7159 	xmlXPathFreeObject(arg1);
7160         return(1);
7161     }
7162 
7163     /*
7164      *If either argument is a nodeset, it's a 'special case'
7165      */
7166     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7167       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7168 	/*
7169 	 *Hack it to assure arg1 is the nodeset
7170 	 */
7171 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7172 		argtmp = arg2;
7173 		arg2 = arg1;
7174 		arg1 = argtmp;
7175 	}
7176 	switch (arg2->type) {
7177 	    case XPATH_UNDEFINED:
7178 #ifdef DEBUG_EXPR
7179 		xmlGenericError(xmlGenericErrorContext,
7180 			"Equal: undefined\n");
7181 #endif
7182 		break;
7183 	    case XPATH_NODESET:
7184 	    case XPATH_XSLT_TREE:
7185 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7186 		break;
7187 	    case XPATH_BOOLEAN:
7188 		if ((arg1->nodesetval == NULL) ||
7189 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7190 		else
7191 		    ret = 1;
7192 		ret = (ret == arg2->boolval);
7193 		break;
7194 	    case XPATH_NUMBER:
7195 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7196 		break;
7197 	    case XPATH_STRING:
7198 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7199 		break;
7200 	    case XPATH_USERS:
7201 	    case XPATH_POINT:
7202 	    case XPATH_RANGE:
7203 	    case XPATH_LOCATIONSET:
7204 		TODO
7205 		break;
7206 	}
7207 	xmlXPathReleaseObject(ctxt->context, arg1);
7208 	xmlXPathReleaseObject(ctxt->context, arg2);
7209 	return(ret);
7210     }
7211 
7212     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7213 }
7214 
7215 /**
7216  * xmlXPathNotEqualValues:
7217  * @ctxt:  the XPath Parser context
7218  *
7219  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7220  *
7221  * Returns 0 or 1 depending on the results of the test.
7222  */
7223 int
7224 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7225     xmlXPathObjectPtr arg1, arg2, argtmp;
7226     int ret = 0;
7227 
7228     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7229     arg2 = valuePop(ctxt);
7230     arg1 = valuePop(ctxt);
7231     if ((arg1 == NULL) || (arg2 == NULL)) {
7232 	if (arg1 != NULL)
7233 	    xmlXPathReleaseObject(ctxt->context, arg1);
7234 	else
7235 	    xmlXPathReleaseObject(ctxt->context, arg2);
7236 	XP_ERROR0(XPATH_INVALID_OPERAND);
7237     }
7238 
7239     if (arg1 == arg2) {
7240 #ifdef DEBUG_EXPR
7241         xmlGenericError(xmlGenericErrorContext,
7242 		"NotEqual: by pointer\n");
7243 #endif
7244 	xmlXPathReleaseObject(ctxt->context, arg1);
7245         return(0);
7246     }
7247 
7248     /*
7249      *If either argument is a nodeset, it's a 'special case'
7250      */
7251     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7252       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7253 	/*
7254 	 *Hack it to assure arg1 is the nodeset
7255 	 */
7256 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7257 		argtmp = arg2;
7258 		arg2 = arg1;
7259 		arg1 = argtmp;
7260 	}
7261 	switch (arg2->type) {
7262 	    case XPATH_UNDEFINED:
7263 #ifdef DEBUG_EXPR
7264 		xmlGenericError(xmlGenericErrorContext,
7265 			"NotEqual: undefined\n");
7266 #endif
7267 		break;
7268 	    case XPATH_NODESET:
7269 	    case XPATH_XSLT_TREE:
7270 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7271 		break;
7272 	    case XPATH_BOOLEAN:
7273 		if ((arg1->nodesetval == NULL) ||
7274 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7275 		else
7276 		    ret = 1;
7277 		ret = (ret != arg2->boolval);
7278 		break;
7279 	    case XPATH_NUMBER:
7280 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7281 		break;
7282 	    case XPATH_STRING:
7283 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7284 		break;
7285 	    case XPATH_USERS:
7286 	    case XPATH_POINT:
7287 	    case XPATH_RANGE:
7288 	    case XPATH_LOCATIONSET:
7289 		TODO
7290 		break;
7291 	}
7292 	xmlXPathReleaseObject(ctxt->context, arg1);
7293 	xmlXPathReleaseObject(ctxt->context, arg2);
7294 	return(ret);
7295     }
7296 
7297     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7298 }
7299 
7300 /**
7301  * xmlXPathCompareValues:
7302  * @ctxt:  the XPath Parser context
7303  * @inf:  less than (1) or greater than (0)
7304  * @strict:  is the comparison strict
7305  *
7306  * Implement the compare operation on XPath objects:
7307  *     @arg1 < @arg2    (1, 1, ...
7308  *     @arg1 <= @arg2   (1, 0, ...
7309  *     @arg1 > @arg2    (0, 1, ...
7310  *     @arg1 >= @arg2   (0, 0, ...
7311  *
7312  * When neither object to be compared is a node-set and the operator is
7313  * <=, <, >=, >, then the objects are compared by converted both objects
7314  * to numbers and comparing the numbers according to IEEE 754. The <
7315  * comparison will be true if and only if the first number is less than the
7316  * second number. The <= comparison will be true if and only if the first
7317  * number is less than or equal to the second number. The > comparison
7318  * will be true if and only if the first number is greater than the second
7319  * number. The >= comparison will be true if and only if the first number
7320  * is greater than or equal to the second number.
7321  *
7322  * Returns 1 if the comparison succeeded, 0 if it failed
7323  */
7324 int
7325 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7326     int ret = 0, arg1i = 0, arg2i = 0;
7327     xmlXPathObjectPtr arg1, arg2;
7328 
7329     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7330     arg2 = valuePop(ctxt);
7331     arg1 = valuePop(ctxt);
7332     if ((arg1 == NULL) || (arg2 == NULL)) {
7333 	if (arg1 != NULL)
7334 	    xmlXPathReleaseObject(ctxt->context, arg1);
7335 	else
7336 	    xmlXPathReleaseObject(ctxt->context, arg2);
7337 	XP_ERROR0(XPATH_INVALID_OPERAND);
7338     }
7339 
7340     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7341       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7342 	/*
7343 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7344 	 * are not freed from within this routine; they will be freed from the
7345 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7346 	 */
7347 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7348 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7349 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7350 	} else {
7351 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7352 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7353 			                          arg1, arg2);
7354 	    } else {
7355 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7356 			                          arg2, arg1);
7357 	    }
7358 	}
7359 	return(ret);
7360     }
7361 
7362     if (arg1->type != XPATH_NUMBER) {
7363 	valuePush(ctxt, arg1);
7364 	xmlXPathNumberFunction(ctxt, 1);
7365 	arg1 = valuePop(ctxt);
7366     }
7367     if (arg1->type != XPATH_NUMBER) {
7368 	xmlXPathFreeObject(arg1);
7369 	xmlXPathFreeObject(arg2);
7370 	XP_ERROR0(XPATH_INVALID_OPERAND);
7371     }
7372     if (arg2->type != XPATH_NUMBER) {
7373 	valuePush(ctxt, arg2);
7374 	xmlXPathNumberFunction(ctxt, 1);
7375 	arg2 = valuePop(ctxt);
7376     }
7377     if (arg2->type != XPATH_NUMBER) {
7378 	xmlXPathReleaseObject(ctxt->context, arg1);
7379 	xmlXPathReleaseObject(ctxt->context, arg2);
7380 	XP_ERROR0(XPATH_INVALID_OPERAND);
7381     }
7382     /*
7383      * Add tests for infinity and nan
7384      * => feedback on 3.4 for Inf and NaN
7385      */
7386     /* Hand check NaN and Infinity comparisons */
7387     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7388 	ret=0;
7389     } else {
7390 	arg1i=xmlXPathIsInf(arg1->floatval);
7391 	arg2i=xmlXPathIsInf(arg2->floatval);
7392 	if (inf && strict) {
7393 	    if ((arg1i == -1 && arg2i != -1) ||
7394 		(arg2i == 1 && arg1i != 1)) {
7395 		ret = 1;
7396 	    } else if (arg1i == 0 && arg2i == 0) {
7397 		ret = (arg1->floatval < arg2->floatval);
7398 	    } else {
7399 		ret = 0;
7400 	    }
7401 	}
7402 	else if (inf && !strict) {
7403 	    if (arg1i == -1 || arg2i == 1) {
7404 		ret = 1;
7405 	    } else if (arg1i == 0 && arg2i == 0) {
7406 		ret = (arg1->floatval <= arg2->floatval);
7407 	    } else {
7408 		ret = 0;
7409 	    }
7410 	}
7411 	else if (!inf && strict) {
7412 	    if ((arg1i == 1 && arg2i != 1) ||
7413 		(arg2i == -1 && arg1i != -1)) {
7414 		ret = 1;
7415 	    } else if (arg1i == 0 && arg2i == 0) {
7416 		ret = (arg1->floatval > arg2->floatval);
7417 	    } else {
7418 		ret = 0;
7419 	    }
7420 	}
7421 	else if (!inf && !strict) {
7422 	    if (arg1i == 1 || arg2i == -1) {
7423 		ret = 1;
7424 	    } else if (arg1i == 0 && arg2i == 0) {
7425 		ret = (arg1->floatval >= arg2->floatval);
7426 	    } else {
7427 		ret = 0;
7428 	    }
7429 	}
7430     }
7431     xmlXPathReleaseObject(ctxt->context, arg1);
7432     xmlXPathReleaseObject(ctxt->context, arg2);
7433     return(ret);
7434 }
7435 
7436 /**
7437  * xmlXPathValueFlipSign:
7438  * @ctxt:  the XPath Parser context
7439  *
7440  * Implement the unary - operation on an XPath object
7441  * The numeric operators convert their operands to numbers as if
7442  * by calling the number function.
7443  */
7444 void
7445 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7446     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7447     CAST_TO_NUMBER;
7448     CHECK_TYPE(XPATH_NUMBER);
7449     ctxt->value->floatval = -ctxt->value->floatval;
7450 }
7451 
7452 /**
7453  * xmlXPathAddValues:
7454  * @ctxt:  the XPath Parser context
7455  *
7456  * Implement the add operation on XPath objects:
7457  * The numeric operators convert their operands to numbers as if
7458  * by calling the number function.
7459  */
7460 void
7461 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7462     xmlXPathObjectPtr arg;
7463     double val;
7464 
7465     arg = valuePop(ctxt);
7466     if (arg == NULL)
7467 	XP_ERROR(XPATH_INVALID_OPERAND);
7468     val = xmlXPathCastToNumber(arg);
7469     xmlXPathReleaseObject(ctxt->context, arg);
7470     CAST_TO_NUMBER;
7471     CHECK_TYPE(XPATH_NUMBER);
7472     ctxt->value->floatval += val;
7473 }
7474 
7475 /**
7476  * xmlXPathSubValues:
7477  * @ctxt:  the XPath Parser context
7478  *
7479  * Implement the subtraction operation on XPath objects:
7480  * The numeric operators convert their operands to numbers as if
7481  * by calling the number function.
7482  */
7483 void
7484 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7485     xmlXPathObjectPtr arg;
7486     double val;
7487 
7488     arg = valuePop(ctxt);
7489     if (arg == NULL)
7490 	XP_ERROR(XPATH_INVALID_OPERAND);
7491     val = xmlXPathCastToNumber(arg);
7492     xmlXPathReleaseObject(ctxt->context, arg);
7493     CAST_TO_NUMBER;
7494     CHECK_TYPE(XPATH_NUMBER);
7495     ctxt->value->floatval -= val;
7496 }
7497 
7498 /**
7499  * xmlXPathMultValues:
7500  * @ctxt:  the XPath Parser context
7501  *
7502  * Implement the multiply operation on XPath objects:
7503  * The numeric operators convert their operands to numbers as if
7504  * by calling the number function.
7505  */
7506 void
7507 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7508     xmlXPathObjectPtr arg;
7509     double val;
7510 
7511     arg = valuePop(ctxt);
7512     if (arg == NULL)
7513 	XP_ERROR(XPATH_INVALID_OPERAND);
7514     val = xmlXPathCastToNumber(arg);
7515     xmlXPathReleaseObject(ctxt->context, arg);
7516     CAST_TO_NUMBER;
7517     CHECK_TYPE(XPATH_NUMBER);
7518     ctxt->value->floatval *= val;
7519 }
7520 
7521 /**
7522  * xmlXPathDivValues:
7523  * @ctxt:  the XPath Parser context
7524  *
7525  * Implement the div operation on XPath objects @arg1 / @arg2:
7526  * The numeric operators convert their operands to numbers as if
7527  * by calling the number function.
7528  */
7529 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7530 void
7531 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7532     xmlXPathObjectPtr arg;
7533     double val;
7534 
7535     arg = valuePop(ctxt);
7536     if (arg == NULL)
7537 	XP_ERROR(XPATH_INVALID_OPERAND);
7538     val = xmlXPathCastToNumber(arg);
7539     xmlXPathReleaseObject(ctxt->context, arg);
7540     CAST_TO_NUMBER;
7541     CHECK_TYPE(XPATH_NUMBER);
7542     ctxt->value->floatval /= val;
7543 }
7544 
7545 /**
7546  * xmlXPathModValues:
7547  * @ctxt:  the XPath Parser context
7548  *
7549  * Implement the mod operation on XPath objects: @arg1 / @arg2
7550  * The numeric operators convert their operands to numbers as if
7551  * by calling the number function.
7552  */
7553 void
7554 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7555     xmlXPathObjectPtr arg;
7556     double arg1, arg2;
7557 
7558     arg = valuePop(ctxt);
7559     if (arg == NULL)
7560 	XP_ERROR(XPATH_INVALID_OPERAND);
7561     arg2 = xmlXPathCastToNumber(arg);
7562     xmlXPathReleaseObject(ctxt->context, arg);
7563     CAST_TO_NUMBER;
7564     CHECK_TYPE(XPATH_NUMBER);
7565     arg1 = ctxt->value->floatval;
7566     if (arg2 == 0)
7567 	ctxt->value->floatval = NAN;
7568     else {
7569 	ctxt->value->floatval = fmod(arg1, arg2);
7570     }
7571 }
7572 
7573 /************************************************************************
7574  *									*
7575  *		The traversal functions					*
7576  *									*
7577  ************************************************************************/
7578 
7579 /*
7580  * A traversal function enumerates nodes along an axis.
7581  * Initially it must be called with NULL, and it indicates
7582  * termination on the axis by returning NULL.
7583  */
7584 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7585                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7586 
7587 /*
7588  * xmlXPathTraversalFunctionExt:
7589  * A traversal function enumerates nodes along an axis.
7590  * Initially it must be called with NULL, and it indicates
7591  * termination on the axis by returning NULL.
7592  * The context node of the traversal is specified via @contextNode.
7593  */
7594 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7595                     (xmlNodePtr cur, xmlNodePtr contextNode);
7596 
7597 /*
7598  * xmlXPathNodeSetMergeFunction:
7599  * Used for merging node sets in xmlXPathCollectAndTest().
7600  */
7601 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7602 		    (xmlNodeSetPtr, xmlNodeSetPtr);
7603 
7604 
7605 /**
7606  * xmlXPathNextSelf:
7607  * @ctxt:  the XPath Parser context
7608  * @cur:  the current node in the traversal
7609  *
7610  * Traversal function for the "self" direction
7611  * The self axis contains just the context node itself
7612  *
7613  * Returns the next element following that axis
7614  */
7615 xmlNodePtr
7616 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7617     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7618     if (cur == NULL)
7619         return(ctxt->context->node);
7620     return(NULL);
7621 }
7622 
7623 /**
7624  * xmlXPathNextChild:
7625  * @ctxt:  the XPath Parser context
7626  * @cur:  the current node in the traversal
7627  *
7628  * Traversal function for the "child" direction
7629  * The child axis contains the children of the context node in document order.
7630  *
7631  * Returns the next element following that axis
7632  */
7633 xmlNodePtr
7634 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7635     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7636     if (cur == NULL) {
7637 	if (ctxt->context->node == NULL) return(NULL);
7638 	switch (ctxt->context->node->type) {
7639             case XML_ELEMENT_NODE:
7640             case XML_TEXT_NODE:
7641             case XML_CDATA_SECTION_NODE:
7642             case XML_ENTITY_REF_NODE:
7643             case XML_ENTITY_NODE:
7644             case XML_PI_NODE:
7645             case XML_COMMENT_NODE:
7646             case XML_NOTATION_NODE:
7647             case XML_DTD_NODE:
7648 		return(ctxt->context->node->children);
7649             case XML_DOCUMENT_NODE:
7650             case XML_DOCUMENT_TYPE_NODE:
7651             case XML_DOCUMENT_FRAG_NODE:
7652             case XML_HTML_DOCUMENT_NODE:
7653 #ifdef LIBXML_DOCB_ENABLED
7654 	    case XML_DOCB_DOCUMENT_NODE:
7655 #endif
7656 		return(((xmlDocPtr) ctxt->context->node)->children);
7657 	    case XML_ELEMENT_DECL:
7658 	    case XML_ATTRIBUTE_DECL:
7659 	    case XML_ENTITY_DECL:
7660             case XML_ATTRIBUTE_NODE:
7661 	    case XML_NAMESPACE_DECL:
7662 	    case XML_XINCLUDE_START:
7663 	    case XML_XINCLUDE_END:
7664 		return(NULL);
7665 	}
7666 	return(NULL);
7667     }
7668     if ((cur->type == XML_DOCUMENT_NODE) ||
7669         (cur->type == XML_HTML_DOCUMENT_NODE))
7670 	return(NULL);
7671     return(cur->next);
7672 }
7673 
7674 /**
7675  * xmlXPathNextChildElement:
7676  * @ctxt:  the XPath Parser context
7677  * @cur:  the current node in the traversal
7678  *
7679  * Traversal function for the "child" direction and nodes of type element.
7680  * The child axis contains the children of the context node in document order.
7681  *
7682  * Returns the next element following that axis
7683  */
7684 static xmlNodePtr
7685 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7686     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7687     if (cur == NULL) {
7688 	cur = ctxt->context->node;
7689 	if (cur == NULL) return(NULL);
7690 	/*
7691 	* Get the first element child.
7692 	*/
7693 	switch (cur->type) {
7694             case XML_ELEMENT_NODE:
7695 	    case XML_DOCUMENT_FRAG_NODE:
7696 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7697             case XML_ENTITY_NODE:
7698 		cur = cur->children;
7699 		if (cur != NULL) {
7700 		    if (cur->type == XML_ELEMENT_NODE)
7701 			return(cur);
7702 		    do {
7703 			cur = cur->next;
7704 		    } while ((cur != NULL) &&
7705 			(cur->type != XML_ELEMENT_NODE));
7706 		    return(cur);
7707 		}
7708 		return(NULL);
7709             case XML_DOCUMENT_NODE:
7710             case XML_HTML_DOCUMENT_NODE:
7711 #ifdef LIBXML_DOCB_ENABLED
7712 	    case XML_DOCB_DOCUMENT_NODE:
7713 #endif
7714 		return(xmlDocGetRootElement((xmlDocPtr) cur));
7715 	    default:
7716 		return(NULL);
7717 	}
7718 	return(NULL);
7719     }
7720     /*
7721     * Get the next sibling element node.
7722     */
7723     switch (cur->type) {
7724 	case XML_ELEMENT_NODE:
7725 	case XML_TEXT_NODE:
7726 	case XML_ENTITY_REF_NODE:
7727 	case XML_ENTITY_NODE:
7728 	case XML_CDATA_SECTION_NODE:
7729 	case XML_PI_NODE:
7730 	case XML_COMMENT_NODE:
7731 	case XML_XINCLUDE_END:
7732 	    break;
7733 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7734 	default:
7735 	    return(NULL);
7736     }
7737     if (cur->next != NULL) {
7738 	if (cur->next->type == XML_ELEMENT_NODE)
7739 	    return(cur->next);
7740 	cur = cur->next;
7741 	do {
7742 	    cur = cur->next;
7743 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7744 	return(cur);
7745     }
7746     return(NULL);
7747 }
7748 
7749 #if 0
7750 /**
7751  * xmlXPathNextDescendantOrSelfElemParent:
7752  * @ctxt:  the XPath Parser context
7753  * @cur:  the current node in the traversal
7754  *
7755  * Traversal function for the "descendant-or-self" axis.
7756  * Additionally it returns only nodes which can be parents of
7757  * element nodes.
7758  *
7759  *
7760  * Returns the next element following that axis
7761  */
7762 static xmlNodePtr
7763 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7764 				       xmlNodePtr contextNode)
7765 {
7766     if (cur == NULL) {
7767 	if (contextNode == NULL)
7768 	    return(NULL);
7769 	switch (contextNode->type) {
7770 	    case XML_ELEMENT_NODE:
7771 	    case XML_XINCLUDE_START:
7772 	    case XML_DOCUMENT_FRAG_NODE:
7773 	    case XML_DOCUMENT_NODE:
7774 #ifdef LIBXML_DOCB_ENABLED
7775 	    case XML_DOCB_DOCUMENT_NODE:
7776 #endif
7777 	    case XML_HTML_DOCUMENT_NODE:
7778 		return(contextNode);
7779 	    default:
7780 		return(NULL);
7781 	}
7782 	return(NULL);
7783     } else {
7784 	xmlNodePtr start = cur;
7785 
7786 	while (cur != NULL) {
7787 	    switch (cur->type) {
7788 		case XML_ELEMENT_NODE:
7789 		/* TODO: OK to have XInclude here? */
7790 		case XML_XINCLUDE_START:
7791 		case XML_DOCUMENT_FRAG_NODE:
7792 		    if (cur != start)
7793 			return(cur);
7794 		    if (cur->children != NULL) {
7795 			cur = cur->children;
7796 			continue;
7797 		    }
7798 		    break;
7799 		/* Not sure if we need those here. */
7800 		case XML_DOCUMENT_NODE:
7801 #ifdef LIBXML_DOCB_ENABLED
7802 		case XML_DOCB_DOCUMENT_NODE:
7803 #endif
7804 		case XML_HTML_DOCUMENT_NODE:
7805 		    if (cur != start)
7806 			return(cur);
7807 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7808 		default:
7809 		    break;
7810 	    }
7811 
7812 next_sibling:
7813 	    if ((cur == NULL) || (cur == contextNode))
7814 		return(NULL);
7815 	    if (cur->next != NULL) {
7816 		cur = cur->next;
7817 	    } else {
7818 		cur = cur->parent;
7819 		goto next_sibling;
7820 	    }
7821 	}
7822     }
7823     return(NULL);
7824 }
7825 #endif
7826 
7827 /**
7828  * xmlXPathNextDescendant:
7829  * @ctxt:  the XPath Parser context
7830  * @cur:  the current node in the traversal
7831  *
7832  * Traversal function for the "descendant" direction
7833  * the descendant axis contains the descendants of the context node in document
7834  * order; a descendant is a child or a child of a child and so on.
7835  *
7836  * Returns the next element following that axis
7837  */
7838 xmlNodePtr
7839 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7840     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7841     if (cur == NULL) {
7842 	if (ctxt->context->node == NULL)
7843 	    return(NULL);
7844 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7845 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7846 	    return(NULL);
7847 
7848         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7849 	    return(ctxt->context->doc->children);
7850         return(ctxt->context->node->children);
7851     }
7852 
7853     if (cur->type == XML_NAMESPACE_DECL)
7854         return(NULL);
7855     if (cur->children != NULL) {
7856 	/*
7857 	 * Do not descend on entities declarations
7858 	 */
7859 	if (cur->children->type != XML_ENTITY_DECL) {
7860 	    cur = cur->children;
7861 	    /*
7862 	     * Skip DTDs
7863 	     */
7864 	    if (cur->type != XML_DTD_NODE)
7865 		return(cur);
7866 	}
7867     }
7868 
7869     if (cur == ctxt->context->node) return(NULL);
7870 
7871     while (cur->next != NULL) {
7872 	cur = cur->next;
7873 	if ((cur->type != XML_ENTITY_DECL) &&
7874 	    (cur->type != XML_DTD_NODE))
7875 	    return(cur);
7876     }
7877 
7878     do {
7879         cur = cur->parent;
7880 	if (cur == NULL) break;
7881 	if (cur == ctxt->context->node) return(NULL);
7882 	if (cur->next != NULL) {
7883 	    cur = cur->next;
7884 	    return(cur);
7885 	}
7886     } while (cur != NULL);
7887     return(cur);
7888 }
7889 
7890 /**
7891  * xmlXPathNextDescendantOrSelf:
7892  * @ctxt:  the XPath Parser context
7893  * @cur:  the current node in the traversal
7894  *
7895  * Traversal function for the "descendant-or-self" direction
7896  * the descendant-or-self axis contains the context node and the descendants
7897  * of the context node in document order; thus the context node is the first
7898  * node on the axis, and the first child of the context node is the second node
7899  * on the axis
7900  *
7901  * Returns the next element following that axis
7902  */
7903 xmlNodePtr
7904 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7905     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7906     if (cur == NULL)
7907         return(ctxt->context->node);
7908 
7909     if (ctxt->context->node == NULL)
7910         return(NULL);
7911     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7912         (ctxt->context->node->type == XML_NAMESPACE_DECL))
7913         return(NULL);
7914 
7915     return(xmlXPathNextDescendant(ctxt, cur));
7916 }
7917 
7918 /**
7919  * xmlXPathNextParent:
7920  * @ctxt:  the XPath Parser context
7921  * @cur:  the current node in the traversal
7922  *
7923  * Traversal function for the "parent" direction
7924  * The parent axis contains the parent of the context node, if there is one.
7925  *
7926  * Returns the next element following that axis
7927  */
7928 xmlNodePtr
7929 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7930     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7931     /*
7932      * the parent of an attribute or namespace node is the element
7933      * to which the attribute or namespace node is attached
7934      * Namespace handling !!!
7935      */
7936     if (cur == NULL) {
7937 	if (ctxt->context->node == NULL) return(NULL);
7938 	switch (ctxt->context->node->type) {
7939             case XML_ELEMENT_NODE:
7940             case XML_TEXT_NODE:
7941             case XML_CDATA_SECTION_NODE:
7942             case XML_ENTITY_REF_NODE:
7943             case XML_ENTITY_NODE:
7944             case XML_PI_NODE:
7945             case XML_COMMENT_NODE:
7946             case XML_NOTATION_NODE:
7947             case XML_DTD_NODE:
7948 	    case XML_ELEMENT_DECL:
7949 	    case XML_ATTRIBUTE_DECL:
7950 	    case XML_XINCLUDE_START:
7951 	    case XML_XINCLUDE_END:
7952 	    case XML_ENTITY_DECL:
7953 		if (ctxt->context->node->parent == NULL)
7954 		    return((xmlNodePtr) ctxt->context->doc);
7955 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7956 		    ((ctxt->context->node->parent->name[0] == ' ') ||
7957 		     (xmlStrEqual(ctxt->context->node->parent->name,
7958 				 BAD_CAST "fake node libxslt"))))
7959 		    return(NULL);
7960 		return(ctxt->context->node->parent);
7961             case XML_ATTRIBUTE_NODE: {
7962 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7963 
7964 		return(att->parent);
7965 	    }
7966             case XML_DOCUMENT_NODE:
7967             case XML_DOCUMENT_TYPE_NODE:
7968             case XML_DOCUMENT_FRAG_NODE:
7969             case XML_HTML_DOCUMENT_NODE:
7970 #ifdef LIBXML_DOCB_ENABLED
7971 	    case XML_DOCB_DOCUMENT_NODE:
7972 #endif
7973                 return(NULL);
7974 	    case XML_NAMESPACE_DECL: {
7975 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7976 
7977 		if ((ns->next != NULL) &&
7978 		    (ns->next->type != XML_NAMESPACE_DECL))
7979 		    return((xmlNodePtr) ns->next);
7980                 return(NULL);
7981 	    }
7982 	}
7983     }
7984     return(NULL);
7985 }
7986 
7987 /**
7988  * xmlXPathNextAncestor:
7989  * @ctxt:  the XPath Parser context
7990  * @cur:  the current node in the traversal
7991  *
7992  * Traversal function for the "ancestor" direction
7993  * the ancestor axis contains the ancestors of the context node; the ancestors
7994  * of the context node consist of the parent of context node and the parent's
7995  * parent and so on; the nodes are ordered in reverse document order; thus the
7996  * parent is the first node on the axis, and the parent's parent is the second
7997  * node on the axis
7998  *
7999  * Returns the next element following that axis
8000  */
8001 xmlNodePtr
8002 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8003     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8004     /*
8005      * the parent of an attribute or namespace node is the element
8006      * to which the attribute or namespace node is attached
8007      * !!!!!!!!!!!!!
8008      */
8009     if (cur == NULL) {
8010 	if (ctxt->context->node == NULL) return(NULL);
8011 	switch (ctxt->context->node->type) {
8012             case XML_ELEMENT_NODE:
8013             case XML_TEXT_NODE:
8014             case XML_CDATA_SECTION_NODE:
8015             case XML_ENTITY_REF_NODE:
8016             case XML_ENTITY_NODE:
8017             case XML_PI_NODE:
8018             case XML_COMMENT_NODE:
8019 	    case XML_DTD_NODE:
8020 	    case XML_ELEMENT_DECL:
8021 	    case XML_ATTRIBUTE_DECL:
8022 	    case XML_ENTITY_DECL:
8023             case XML_NOTATION_NODE:
8024 	    case XML_XINCLUDE_START:
8025 	    case XML_XINCLUDE_END:
8026 		if (ctxt->context->node->parent == NULL)
8027 		    return((xmlNodePtr) ctxt->context->doc);
8028 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8029 		    ((ctxt->context->node->parent->name[0] == ' ') ||
8030 		     (xmlStrEqual(ctxt->context->node->parent->name,
8031 				 BAD_CAST "fake node libxslt"))))
8032 		    return(NULL);
8033 		return(ctxt->context->node->parent);
8034             case XML_ATTRIBUTE_NODE: {
8035 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8036 
8037 		return(tmp->parent);
8038 	    }
8039             case XML_DOCUMENT_NODE:
8040             case XML_DOCUMENT_TYPE_NODE:
8041             case XML_DOCUMENT_FRAG_NODE:
8042             case XML_HTML_DOCUMENT_NODE:
8043 #ifdef LIBXML_DOCB_ENABLED
8044 	    case XML_DOCB_DOCUMENT_NODE:
8045 #endif
8046                 return(NULL);
8047 	    case XML_NAMESPACE_DECL: {
8048 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8049 
8050 		if ((ns->next != NULL) &&
8051 		    (ns->next->type != XML_NAMESPACE_DECL))
8052 		    return((xmlNodePtr) ns->next);
8053 		/* Bad, how did that namespace end up here ? */
8054                 return(NULL);
8055 	    }
8056 	}
8057 	return(NULL);
8058     }
8059     if (cur == ctxt->context->doc->children)
8060 	return((xmlNodePtr) ctxt->context->doc);
8061     if (cur == (xmlNodePtr) ctxt->context->doc)
8062 	return(NULL);
8063     switch (cur->type) {
8064 	case XML_ELEMENT_NODE:
8065 	case XML_TEXT_NODE:
8066 	case XML_CDATA_SECTION_NODE:
8067 	case XML_ENTITY_REF_NODE:
8068 	case XML_ENTITY_NODE:
8069 	case XML_PI_NODE:
8070 	case XML_COMMENT_NODE:
8071 	case XML_NOTATION_NODE:
8072 	case XML_DTD_NODE:
8073         case XML_ELEMENT_DECL:
8074         case XML_ATTRIBUTE_DECL:
8075         case XML_ENTITY_DECL:
8076 	case XML_XINCLUDE_START:
8077 	case XML_XINCLUDE_END:
8078 	    if (cur->parent == NULL)
8079 		return(NULL);
8080 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
8081 		((cur->parent->name[0] == ' ') ||
8082 		 (xmlStrEqual(cur->parent->name,
8083 			      BAD_CAST "fake node libxslt"))))
8084 		return(NULL);
8085 	    return(cur->parent);
8086 	case XML_ATTRIBUTE_NODE: {
8087 	    xmlAttrPtr att = (xmlAttrPtr) cur;
8088 
8089 	    return(att->parent);
8090 	}
8091 	case XML_NAMESPACE_DECL: {
8092 	    xmlNsPtr ns = (xmlNsPtr) cur;
8093 
8094 	    if ((ns->next != NULL) &&
8095 	        (ns->next->type != XML_NAMESPACE_DECL))
8096 	        return((xmlNodePtr) ns->next);
8097 	    /* Bad, how did that namespace end up here ? */
8098             return(NULL);
8099 	}
8100 	case XML_DOCUMENT_NODE:
8101 	case XML_DOCUMENT_TYPE_NODE:
8102 	case XML_DOCUMENT_FRAG_NODE:
8103 	case XML_HTML_DOCUMENT_NODE:
8104 #ifdef LIBXML_DOCB_ENABLED
8105 	case XML_DOCB_DOCUMENT_NODE:
8106 #endif
8107 	    return(NULL);
8108     }
8109     return(NULL);
8110 }
8111 
8112 /**
8113  * xmlXPathNextAncestorOrSelf:
8114  * @ctxt:  the XPath Parser context
8115  * @cur:  the current node in the traversal
8116  *
8117  * Traversal function for the "ancestor-or-self" direction
8118  * he ancestor-or-self axis contains the context node and ancestors of
8119  * the context node in reverse document order; thus the context node is
8120  * the first node on the axis, and the context node's parent the second;
8121  * parent here is defined the same as with the parent axis.
8122  *
8123  * Returns the next element following that axis
8124  */
8125 xmlNodePtr
8126 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8127     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8128     if (cur == NULL)
8129         return(ctxt->context->node);
8130     return(xmlXPathNextAncestor(ctxt, cur));
8131 }
8132 
8133 /**
8134  * xmlXPathNextFollowingSibling:
8135  * @ctxt:  the XPath Parser context
8136  * @cur:  the current node in the traversal
8137  *
8138  * Traversal function for the "following-sibling" direction
8139  * The following-sibling axis contains the following siblings of the context
8140  * node in document order.
8141  *
8142  * Returns the next element following that axis
8143  */
8144 xmlNodePtr
8145 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8146     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8147     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8148 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8149 	return(NULL);
8150     if (cur == (xmlNodePtr) ctxt->context->doc)
8151         return(NULL);
8152     if (cur == NULL)
8153         return(ctxt->context->node->next);
8154     return(cur->next);
8155 }
8156 
8157 /**
8158  * xmlXPathNextPrecedingSibling:
8159  * @ctxt:  the XPath Parser context
8160  * @cur:  the current node in the traversal
8161  *
8162  * Traversal function for the "preceding-sibling" direction
8163  * The preceding-sibling axis contains the preceding siblings of the context
8164  * node in reverse document order; the first preceding sibling is first on the
8165  * axis; the sibling preceding that node is the second on the axis and so on.
8166  *
8167  * Returns the next element following that axis
8168  */
8169 xmlNodePtr
8170 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8171     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8172     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8173 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8174 	return(NULL);
8175     if (cur == (xmlNodePtr) ctxt->context->doc)
8176         return(NULL);
8177     if (cur == NULL)
8178         return(ctxt->context->node->prev);
8179     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8180 	cur = cur->prev;
8181 	if (cur == NULL)
8182 	    return(ctxt->context->node->prev);
8183     }
8184     return(cur->prev);
8185 }
8186 
8187 /**
8188  * xmlXPathNextFollowing:
8189  * @ctxt:  the XPath Parser context
8190  * @cur:  the current node in the traversal
8191  *
8192  * Traversal function for the "following" direction
8193  * The following axis contains all nodes in the same document as the context
8194  * node that are after the context node in document order, excluding any
8195  * descendants and excluding attribute nodes and namespace nodes; the nodes
8196  * are ordered in document order
8197  *
8198  * Returns the next element following that axis
8199  */
8200 xmlNodePtr
8201 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8202     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8203     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8204         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8205         return(cur->children);
8206 
8207     if (cur == NULL) {
8208         cur = ctxt->context->node;
8209         if (cur->type == XML_ATTRIBUTE_NODE) {
8210             cur = cur->parent;
8211         } else if (cur->type == XML_NAMESPACE_DECL) {
8212             xmlNsPtr ns = (xmlNsPtr) cur;
8213 
8214             if ((ns->next == NULL) ||
8215                 (ns->next->type == XML_NAMESPACE_DECL))
8216                 return (NULL);
8217             cur = (xmlNodePtr) ns->next;
8218         }
8219     }
8220     if (cur == NULL) return(NULL) ; /* ERROR */
8221     if (cur->next != NULL) return(cur->next) ;
8222     do {
8223         cur = cur->parent;
8224         if (cur == NULL) break;
8225         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8226         if (cur->next != NULL) return(cur->next);
8227     } while (cur != NULL);
8228     return(cur);
8229 }
8230 
8231 /*
8232  * xmlXPathIsAncestor:
8233  * @ancestor:  the ancestor node
8234  * @node:  the current node
8235  *
8236  * Check that @ancestor is a @node's ancestor
8237  *
8238  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8239  */
8240 static int
8241 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8242     if ((ancestor == NULL) || (node == NULL)) return(0);
8243     if (node->type == XML_NAMESPACE_DECL)
8244         return(0);
8245     if (ancestor->type == XML_NAMESPACE_DECL)
8246         return(0);
8247     /* nodes need to be in the same document */
8248     if (ancestor->doc != node->doc) return(0);
8249     /* avoid searching if ancestor or node is the root node */
8250     if (ancestor == (xmlNodePtr) node->doc) return(1);
8251     if (node == (xmlNodePtr) ancestor->doc) return(0);
8252     while (node->parent != NULL) {
8253         if (node->parent == ancestor)
8254             return(1);
8255 	node = node->parent;
8256     }
8257     return(0);
8258 }
8259 
8260 /**
8261  * xmlXPathNextPreceding:
8262  * @ctxt:  the XPath Parser context
8263  * @cur:  the current node in the traversal
8264  *
8265  * Traversal function for the "preceding" direction
8266  * the preceding axis contains all nodes in the same document as the context
8267  * node that are before the context node in document order, excluding any
8268  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8269  * ordered in reverse document order
8270  *
8271  * Returns the next element following that axis
8272  */
8273 xmlNodePtr
8274 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8275 {
8276     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8277     if (cur == NULL) {
8278         cur = ctxt->context->node;
8279         if (cur->type == XML_ATTRIBUTE_NODE) {
8280             cur = cur->parent;
8281         } else if (cur->type == XML_NAMESPACE_DECL) {
8282             xmlNsPtr ns = (xmlNsPtr) cur;
8283 
8284             if ((ns->next == NULL) ||
8285                 (ns->next->type == XML_NAMESPACE_DECL))
8286                 return (NULL);
8287             cur = (xmlNodePtr) ns->next;
8288         }
8289     }
8290     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8291 	return (NULL);
8292     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8293 	cur = cur->prev;
8294     do {
8295         if (cur->prev != NULL) {
8296             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8297             return (cur);
8298         }
8299 
8300         cur = cur->parent;
8301         if (cur == NULL)
8302             return (NULL);
8303         if (cur == ctxt->context->doc->children)
8304             return (NULL);
8305     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8306     return (cur);
8307 }
8308 
8309 /**
8310  * xmlXPathNextPrecedingInternal:
8311  * @ctxt:  the XPath Parser context
8312  * @cur:  the current node in the traversal
8313  *
8314  * Traversal function for the "preceding" direction
8315  * the preceding axis contains all nodes in the same document as the context
8316  * node that are before the context node in document order, excluding any
8317  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8318  * ordered in reverse document order
8319  * This is a faster implementation but internal only since it requires a
8320  * state kept in the parser context: ctxt->ancestor.
8321  *
8322  * Returns the next element following that axis
8323  */
8324 static xmlNodePtr
8325 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8326                               xmlNodePtr cur)
8327 {
8328     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8329     if (cur == NULL) {
8330         cur = ctxt->context->node;
8331         if (cur == NULL)
8332             return (NULL);
8333         if (cur->type == XML_ATTRIBUTE_NODE) {
8334             cur = cur->parent;
8335         } else if (cur->type == XML_NAMESPACE_DECL) {
8336             xmlNsPtr ns = (xmlNsPtr) cur;
8337 
8338             if ((ns->next == NULL) ||
8339                 (ns->next->type == XML_NAMESPACE_DECL))
8340                 return (NULL);
8341             cur = (xmlNodePtr) ns->next;
8342         }
8343         ctxt->ancestor = cur->parent;
8344     }
8345     if (cur->type == XML_NAMESPACE_DECL)
8346         return(NULL);
8347     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8348 	cur = cur->prev;
8349     while (cur->prev == NULL) {
8350         cur = cur->parent;
8351         if (cur == NULL)
8352             return (NULL);
8353         if (cur == ctxt->context->doc->children)
8354             return (NULL);
8355         if (cur != ctxt->ancestor)
8356             return (cur);
8357         ctxt->ancestor = cur->parent;
8358     }
8359     cur = cur->prev;
8360     while (cur->last != NULL)
8361         cur = cur->last;
8362     return (cur);
8363 }
8364 
8365 /**
8366  * xmlXPathNextNamespace:
8367  * @ctxt:  the XPath Parser context
8368  * @cur:  the current attribute in the traversal
8369  *
8370  * Traversal function for the "namespace" direction
8371  * the namespace axis contains the namespace nodes of the context node;
8372  * the order of nodes on this axis is implementation-defined; the axis will
8373  * be empty unless the context node is an element
8374  *
8375  * We keep the XML namespace node at the end of the list.
8376  *
8377  * Returns the next element following that axis
8378  */
8379 xmlNodePtr
8380 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8381     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8382     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8383     if (cur == NULL) {
8384         if (ctxt->context->tmpNsList != NULL)
8385 	    xmlFree(ctxt->context->tmpNsList);
8386 	ctxt->context->tmpNsList =
8387 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8388 	ctxt->context->tmpNsNr = 0;
8389 	if (ctxt->context->tmpNsList != NULL) {
8390 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8391 		ctxt->context->tmpNsNr++;
8392 	    }
8393 	}
8394 	return((xmlNodePtr) xmlXPathXMLNamespace);
8395     }
8396     if (ctxt->context->tmpNsNr > 0) {
8397 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8398     } else {
8399 	if (ctxt->context->tmpNsList != NULL)
8400 	    xmlFree(ctxt->context->tmpNsList);
8401 	ctxt->context->tmpNsList = NULL;
8402 	return(NULL);
8403     }
8404 }
8405 
8406 /**
8407  * xmlXPathNextAttribute:
8408  * @ctxt:  the XPath Parser context
8409  * @cur:  the current attribute in the traversal
8410  *
8411  * Traversal function for the "attribute" direction
8412  * TODO: support DTD inherited default attributes
8413  *
8414  * Returns the next element following that axis
8415  */
8416 xmlNodePtr
8417 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8418     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8419     if (ctxt->context->node == NULL)
8420 	return(NULL);
8421     if (ctxt->context->node->type != XML_ELEMENT_NODE)
8422 	return(NULL);
8423     if (cur == NULL) {
8424         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8425 	    return(NULL);
8426         return((xmlNodePtr)ctxt->context->node->properties);
8427     }
8428     return((xmlNodePtr)cur->next);
8429 }
8430 
8431 /************************************************************************
8432  *									*
8433  *		NodeTest Functions					*
8434  *									*
8435  ************************************************************************/
8436 
8437 #define IS_FUNCTION			200
8438 
8439 
8440 /************************************************************************
8441  *									*
8442  *		Implicit tree core function library			*
8443  *									*
8444  ************************************************************************/
8445 
8446 /**
8447  * xmlXPathRoot:
8448  * @ctxt:  the XPath Parser context
8449  *
8450  * Initialize the context to the root of the document
8451  */
8452 void
8453 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8454     if ((ctxt == NULL) || (ctxt->context == NULL))
8455 	return;
8456     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8457 	(xmlNodePtr) ctxt->context->doc));
8458 }
8459 
8460 /************************************************************************
8461  *									*
8462  *		The explicit core function library			*
8463  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8464  *									*
8465  ************************************************************************/
8466 
8467 
8468 /**
8469  * xmlXPathLastFunction:
8470  * @ctxt:  the XPath Parser context
8471  * @nargs:  the number of arguments
8472  *
8473  * Implement the last() XPath function
8474  *    number last()
8475  * The last function returns the number of nodes in the context node list.
8476  */
8477 void
8478 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8479     CHECK_ARITY(0);
8480     if (ctxt->context->contextSize >= 0) {
8481 	valuePush(ctxt,
8482 	    xmlXPathCacheNewFloat(ctxt->context,
8483 		(double) ctxt->context->contextSize));
8484 #ifdef DEBUG_EXPR
8485 	xmlGenericError(xmlGenericErrorContext,
8486 		"last() : %d\n", ctxt->context->contextSize);
8487 #endif
8488     } else {
8489 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8490     }
8491 }
8492 
8493 /**
8494  * xmlXPathPositionFunction:
8495  * @ctxt:  the XPath Parser context
8496  * @nargs:  the number of arguments
8497  *
8498  * Implement the position() XPath function
8499  *    number position()
8500  * The position function returns the position of the context node in the
8501  * context node list. The first position is 1, and so the last position
8502  * will be equal to last().
8503  */
8504 void
8505 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8506     CHECK_ARITY(0);
8507     if (ctxt->context->proximityPosition >= 0) {
8508 	valuePush(ctxt,
8509 	      xmlXPathCacheNewFloat(ctxt->context,
8510 		(double) ctxt->context->proximityPosition));
8511 #ifdef DEBUG_EXPR
8512 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8513 		ctxt->context->proximityPosition);
8514 #endif
8515     } else {
8516 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8517     }
8518 }
8519 
8520 /**
8521  * xmlXPathCountFunction:
8522  * @ctxt:  the XPath Parser context
8523  * @nargs:  the number of arguments
8524  *
8525  * Implement the count() XPath function
8526  *    number count(node-set)
8527  */
8528 void
8529 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8530     xmlXPathObjectPtr cur;
8531 
8532     CHECK_ARITY(1);
8533     if ((ctxt->value == NULL) ||
8534 	((ctxt->value->type != XPATH_NODESET) &&
8535 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8536 	XP_ERROR(XPATH_INVALID_TYPE);
8537     cur = valuePop(ctxt);
8538 
8539     if ((cur == NULL) || (cur->nodesetval == NULL))
8540 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8541     else
8542 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8543 	    (double) cur->nodesetval->nodeNr));
8544     xmlXPathReleaseObject(ctxt->context, cur);
8545 }
8546 
8547 /**
8548  * xmlXPathGetElementsByIds:
8549  * @doc:  the document
8550  * @ids:  a whitespace separated list of IDs
8551  *
8552  * Selects elements by their unique ID.
8553  *
8554  * Returns a node-set of selected elements.
8555  */
8556 static xmlNodeSetPtr
8557 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8558     xmlNodeSetPtr ret;
8559     const xmlChar *cur = ids;
8560     xmlChar *ID;
8561     xmlAttrPtr attr;
8562     xmlNodePtr elem = NULL;
8563 
8564     if (ids == NULL) return(NULL);
8565 
8566     ret = xmlXPathNodeSetCreate(NULL);
8567     if (ret == NULL)
8568         return(ret);
8569 
8570     while (IS_BLANK_CH(*cur)) cur++;
8571     while (*cur != 0) {
8572 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8573 	    cur++;
8574 
8575         ID = xmlStrndup(ids, cur - ids);
8576 	if (ID != NULL) {
8577 	    /*
8578 	     * We used to check the fact that the value passed
8579 	     * was an NCName, but this generated much troubles for
8580 	     * me and Aleksey Sanin, people blatantly violated that
8581 	     * constraint, like Visa3D spec.
8582 	     * if (xmlValidateNCName(ID, 1) == 0)
8583 	     */
8584 	    attr = xmlGetID(doc, ID);
8585 	    if (attr != NULL) {
8586 		if (attr->type == XML_ATTRIBUTE_NODE)
8587 		    elem = attr->parent;
8588 		else if (attr->type == XML_ELEMENT_NODE)
8589 		    elem = (xmlNodePtr) attr;
8590 		else
8591 		    elem = NULL;
8592                 /* TODO: Check memory error. */
8593 		if (elem != NULL)
8594 		    xmlXPathNodeSetAdd(ret, elem);
8595 	    }
8596 	    xmlFree(ID);
8597 	}
8598 
8599 	while (IS_BLANK_CH(*cur)) cur++;
8600 	ids = cur;
8601     }
8602     return(ret);
8603 }
8604 
8605 /**
8606  * xmlXPathIdFunction:
8607  * @ctxt:  the XPath Parser context
8608  * @nargs:  the number of arguments
8609  *
8610  * Implement the id() XPath function
8611  *    node-set id(object)
8612  * The id function selects elements by their unique ID
8613  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8614  * then the result is the union of the result of applying id to the
8615  * string value of each of the nodes in the argument node-set. When the
8616  * argument to id is of any other type, the argument is converted to a
8617  * string as if by a call to the string function; the string is split
8618  * into a whitespace-separated list of tokens (whitespace is any sequence
8619  * of characters matching the production S); the result is a node-set
8620  * containing the elements in the same document as the context node that
8621  * have a unique ID equal to any of the tokens in the list.
8622  */
8623 void
8624 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8625     xmlChar *tokens;
8626     xmlNodeSetPtr ret;
8627     xmlXPathObjectPtr obj;
8628 
8629     CHECK_ARITY(1);
8630     obj = valuePop(ctxt);
8631     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8632     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8633 	xmlNodeSetPtr ns;
8634 	int i;
8635 
8636         /* TODO: Check memory error. */
8637 	ret = xmlXPathNodeSetCreate(NULL);
8638 
8639 	if (obj->nodesetval != NULL) {
8640 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8641 		tokens =
8642 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8643 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8644                 /* TODO: Check memory error. */
8645 		ret = xmlXPathNodeSetMerge(ret, ns);
8646 		xmlXPathFreeNodeSet(ns);
8647 		if (tokens != NULL)
8648 		    xmlFree(tokens);
8649 	    }
8650 	}
8651 	xmlXPathReleaseObject(ctxt->context, obj);
8652 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8653 	return;
8654     }
8655     obj = xmlXPathCacheConvertString(ctxt->context, obj);
8656     if (obj == NULL) return;
8657     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8658     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8659     xmlXPathReleaseObject(ctxt->context, obj);
8660     return;
8661 }
8662 
8663 /**
8664  * xmlXPathLocalNameFunction:
8665  * @ctxt:  the XPath Parser context
8666  * @nargs:  the number of arguments
8667  *
8668  * Implement the local-name() XPath function
8669  *    string local-name(node-set?)
8670  * The local-name function returns a string containing the local part
8671  * of the name of the node in the argument node-set that is first in
8672  * document order. If the node-set is empty or the first node has no
8673  * name, an empty string is returned. If the argument is omitted it
8674  * defaults to the context node.
8675  */
8676 void
8677 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8678     xmlXPathObjectPtr cur;
8679 
8680     if (ctxt == NULL) return;
8681 
8682     if (nargs == 0) {
8683 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8684 	    ctxt->context->node));
8685 	nargs = 1;
8686     }
8687 
8688     CHECK_ARITY(1);
8689     if ((ctxt->value == NULL) ||
8690 	((ctxt->value->type != XPATH_NODESET) &&
8691 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8692 	XP_ERROR(XPATH_INVALID_TYPE);
8693     cur = valuePop(ctxt);
8694 
8695     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8696 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8697     } else {
8698 	int i = 0; /* Should be first in document order !!!!! */
8699 	switch (cur->nodesetval->nodeTab[i]->type) {
8700 	case XML_ELEMENT_NODE:
8701 	case XML_ATTRIBUTE_NODE:
8702 	case XML_PI_NODE:
8703 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8704 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8705 	    else
8706 		valuePush(ctxt,
8707 		      xmlXPathCacheNewString(ctxt->context,
8708 			cur->nodesetval->nodeTab[i]->name));
8709 	    break;
8710 	case XML_NAMESPACE_DECL:
8711 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8712 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8713 	    break;
8714 	default:
8715 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8716 	}
8717     }
8718     xmlXPathReleaseObject(ctxt->context, cur);
8719 }
8720 
8721 /**
8722  * xmlXPathNamespaceURIFunction:
8723  * @ctxt:  the XPath Parser context
8724  * @nargs:  the number of arguments
8725  *
8726  * Implement the namespace-uri() XPath function
8727  *    string namespace-uri(node-set?)
8728  * The namespace-uri function returns a string containing the
8729  * namespace URI of the expanded name of the node in the argument
8730  * node-set that is first in document order. If the node-set is empty,
8731  * the first node has no name, or the expanded name has no namespace
8732  * URI, an empty string is returned. If the argument is omitted it
8733  * defaults to the context node.
8734  */
8735 void
8736 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8737     xmlXPathObjectPtr cur;
8738 
8739     if (ctxt == NULL) return;
8740 
8741     if (nargs == 0) {
8742 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8743 	    ctxt->context->node));
8744 	nargs = 1;
8745     }
8746     CHECK_ARITY(1);
8747     if ((ctxt->value == NULL) ||
8748 	((ctxt->value->type != XPATH_NODESET) &&
8749 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8750 	XP_ERROR(XPATH_INVALID_TYPE);
8751     cur = valuePop(ctxt);
8752 
8753     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8754 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8755     } else {
8756 	int i = 0; /* Should be first in document order !!!!! */
8757 	switch (cur->nodesetval->nodeTab[i]->type) {
8758 	case XML_ELEMENT_NODE:
8759 	case XML_ATTRIBUTE_NODE:
8760 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8761 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8762 	    else
8763 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8764 			  cur->nodesetval->nodeTab[i]->ns->href));
8765 	    break;
8766 	default:
8767 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8768 	}
8769     }
8770     xmlXPathReleaseObject(ctxt->context, cur);
8771 }
8772 
8773 /**
8774  * xmlXPathNameFunction:
8775  * @ctxt:  the XPath Parser context
8776  * @nargs:  the number of arguments
8777  *
8778  * Implement the name() XPath function
8779  *    string name(node-set?)
8780  * The name function returns a string containing a QName representing
8781  * the name of the node in the argument node-set that is first in document
8782  * order. The QName must represent the name with respect to the namespace
8783  * declarations in effect on the node whose name is being represented.
8784  * Typically, this will be the form in which the name occurred in the XML
8785  * source. This need not be the case if there are namespace declarations
8786  * in effect on the node that associate multiple prefixes with the same
8787  * namespace. However, an implementation may include information about
8788  * the original prefix in its representation of nodes; in this case, an
8789  * implementation can ensure that the returned string is always the same
8790  * as the QName used in the XML source. If the argument it omitted it
8791  * defaults to the context node.
8792  * Libxml keep the original prefix so the "real qualified name" used is
8793  * returned.
8794  */
8795 static void
8796 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8797 {
8798     xmlXPathObjectPtr cur;
8799 
8800     if (nargs == 0) {
8801 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8802 	    ctxt->context->node));
8803         nargs = 1;
8804     }
8805 
8806     CHECK_ARITY(1);
8807     if ((ctxt->value == NULL) ||
8808         ((ctxt->value->type != XPATH_NODESET) &&
8809          (ctxt->value->type != XPATH_XSLT_TREE)))
8810         XP_ERROR(XPATH_INVALID_TYPE);
8811     cur = valuePop(ctxt);
8812 
8813     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8814         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8815     } else {
8816         int i = 0;              /* Should be first in document order !!!!! */
8817 
8818         switch (cur->nodesetval->nodeTab[i]->type) {
8819             case XML_ELEMENT_NODE:
8820             case XML_ATTRIBUTE_NODE:
8821 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8822 		    valuePush(ctxt,
8823 			xmlXPathCacheNewCString(ctxt->context, ""));
8824 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8825                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8826 		    valuePush(ctxt,
8827 		        xmlXPathCacheNewString(ctxt->context,
8828 			    cur->nodesetval->nodeTab[i]->name));
8829 		} else {
8830 		    xmlChar *fullname;
8831 
8832 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8833 				     cur->nodesetval->nodeTab[i]->ns->prefix,
8834 				     NULL, 0);
8835 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8836 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8837 		    if (fullname == NULL) {
8838 			XP_ERROR(XPATH_MEMORY_ERROR);
8839 		    }
8840 		    valuePush(ctxt, xmlXPathCacheWrapString(
8841 			ctxt->context, fullname));
8842                 }
8843                 break;
8844             default:
8845 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8846 		    cur->nodesetval->nodeTab[i]));
8847                 xmlXPathLocalNameFunction(ctxt, 1);
8848         }
8849     }
8850     xmlXPathReleaseObject(ctxt->context, cur);
8851 }
8852 
8853 
8854 /**
8855  * xmlXPathStringFunction:
8856  * @ctxt:  the XPath Parser context
8857  * @nargs:  the number of arguments
8858  *
8859  * Implement the string() XPath function
8860  *    string string(object?)
8861  * The string function converts an object to a string as follows:
8862  *    - A node-set is converted to a string by returning the value of
8863  *      the node in the node-set that is first in document order.
8864  *      If the node-set is empty, an empty string is returned.
8865  *    - A number is converted to a string as follows
8866  *      + NaN is converted to the string NaN
8867  *      + positive zero is converted to the string 0
8868  *      + negative zero is converted to the string 0
8869  *      + positive infinity is converted to the string Infinity
8870  *      + negative infinity is converted to the string -Infinity
8871  *      + if the number is an integer, the number is represented in
8872  *        decimal form as a Number with no decimal point and no leading
8873  *        zeros, preceded by a minus sign (-) if the number is negative
8874  *      + otherwise, the number is represented in decimal form as a
8875  *        Number including a decimal point with at least one digit
8876  *        before the decimal point and at least one digit after the
8877  *        decimal point, preceded by a minus sign (-) if the number
8878  *        is negative; there must be no leading zeros before the decimal
8879  *        point apart possibly from the one required digit immediately
8880  *        before the decimal point; beyond the one required digit
8881  *        after the decimal point there must be as many, but only as
8882  *        many, more digits as are needed to uniquely distinguish the
8883  *        number from all other IEEE 754 numeric values.
8884  *    - The boolean false value is converted to the string false.
8885  *      The boolean true value is converted to the string true.
8886  *
8887  * If the argument is omitted, it defaults to a node-set with the
8888  * context node as its only member.
8889  */
8890 void
8891 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8892     xmlXPathObjectPtr cur;
8893 
8894     if (ctxt == NULL) return;
8895     if (nargs == 0) {
8896     valuePush(ctxt,
8897 	xmlXPathCacheWrapString(ctxt->context,
8898 	    xmlXPathCastNodeToString(ctxt->context->node)));
8899 	return;
8900     }
8901 
8902     CHECK_ARITY(1);
8903     cur = valuePop(ctxt);
8904     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8905     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8906 }
8907 
8908 /**
8909  * xmlXPathStringLengthFunction:
8910  * @ctxt:  the XPath Parser context
8911  * @nargs:  the number of arguments
8912  *
8913  * Implement the string-length() XPath function
8914  *    number string-length(string?)
8915  * The string-length returns the number of characters in the string
8916  * (see [3.6 Strings]). If the argument is omitted, it defaults to
8917  * the context node converted to a string, in other words the value
8918  * of the context node.
8919  */
8920 void
8921 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8922     xmlXPathObjectPtr cur;
8923 
8924     if (nargs == 0) {
8925         if ((ctxt == NULL) || (ctxt->context == NULL))
8926 	    return;
8927 	if (ctxt->context->node == NULL) {
8928 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8929 	} else {
8930 	    xmlChar *content;
8931 
8932 	    content = xmlXPathCastNodeToString(ctxt->context->node);
8933 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8934 		xmlUTF8Strlen(content)));
8935 	    xmlFree(content);
8936 	}
8937 	return;
8938     }
8939     CHECK_ARITY(1);
8940     CAST_TO_STRING;
8941     CHECK_TYPE(XPATH_STRING);
8942     cur = valuePop(ctxt);
8943     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8944 	xmlUTF8Strlen(cur->stringval)));
8945     xmlXPathReleaseObject(ctxt->context, cur);
8946 }
8947 
8948 /**
8949  * xmlXPathConcatFunction:
8950  * @ctxt:  the XPath Parser context
8951  * @nargs:  the number of arguments
8952  *
8953  * Implement the concat() XPath function
8954  *    string concat(string, string, string*)
8955  * The concat function returns the concatenation of its arguments.
8956  */
8957 void
8958 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8959     xmlXPathObjectPtr cur, newobj;
8960     xmlChar *tmp;
8961 
8962     if (ctxt == NULL) return;
8963     if (nargs < 2) {
8964 	CHECK_ARITY(2);
8965     }
8966 
8967     CAST_TO_STRING;
8968     cur = valuePop(ctxt);
8969     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8970 	xmlXPathReleaseObject(ctxt->context, cur);
8971 	return;
8972     }
8973     nargs--;
8974 
8975     while (nargs > 0) {
8976 	CAST_TO_STRING;
8977 	newobj = valuePop(ctxt);
8978 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8979 	    xmlXPathReleaseObject(ctxt->context, newobj);
8980 	    xmlXPathReleaseObject(ctxt->context, cur);
8981 	    XP_ERROR(XPATH_INVALID_TYPE);
8982 	}
8983 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
8984 	newobj->stringval = cur->stringval;
8985 	cur->stringval = tmp;
8986 	xmlXPathReleaseObject(ctxt->context, newobj);
8987 	nargs--;
8988     }
8989     valuePush(ctxt, cur);
8990 }
8991 
8992 /**
8993  * xmlXPathContainsFunction:
8994  * @ctxt:  the XPath Parser context
8995  * @nargs:  the number of arguments
8996  *
8997  * Implement the contains() XPath function
8998  *    boolean contains(string, string)
8999  * The contains function returns true if the first argument string
9000  * contains the second argument string, and otherwise returns false.
9001  */
9002 void
9003 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9004     xmlXPathObjectPtr hay, needle;
9005 
9006     CHECK_ARITY(2);
9007     CAST_TO_STRING;
9008     CHECK_TYPE(XPATH_STRING);
9009     needle = valuePop(ctxt);
9010     CAST_TO_STRING;
9011     hay = valuePop(ctxt);
9012 
9013     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9014 	xmlXPathReleaseObject(ctxt->context, hay);
9015 	xmlXPathReleaseObject(ctxt->context, needle);
9016 	XP_ERROR(XPATH_INVALID_TYPE);
9017     }
9018     if (xmlStrstr(hay->stringval, needle->stringval))
9019 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9020     else
9021 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9022     xmlXPathReleaseObject(ctxt->context, hay);
9023     xmlXPathReleaseObject(ctxt->context, needle);
9024 }
9025 
9026 /**
9027  * xmlXPathStartsWithFunction:
9028  * @ctxt:  the XPath Parser context
9029  * @nargs:  the number of arguments
9030  *
9031  * Implement the starts-with() XPath function
9032  *    boolean starts-with(string, string)
9033  * The starts-with function returns true if the first argument string
9034  * starts with the second argument string, and otherwise returns false.
9035  */
9036 void
9037 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9038     xmlXPathObjectPtr hay, needle;
9039     int n;
9040 
9041     CHECK_ARITY(2);
9042     CAST_TO_STRING;
9043     CHECK_TYPE(XPATH_STRING);
9044     needle = valuePop(ctxt);
9045     CAST_TO_STRING;
9046     hay = valuePop(ctxt);
9047 
9048     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9049 	xmlXPathReleaseObject(ctxt->context, hay);
9050 	xmlXPathReleaseObject(ctxt->context, needle);
9051 	XP_ERROR(XPATH_INVALID_TYPE);
9052     }
9053     n = xmlStrlen(needle->stringval);
9054     if (xmlStrncmp(hay->stringval, needle->stringval, n))
9055         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9056     else
9057         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9058     xmlXPathReleaseObject(ctxt->context, hay);
9059     xmlXPathReleaseObject(ctxt->context, needle);
9060 }
9061 
9062 /**
9063  * xmlXPathSubstringFunction:
9064  * @ctxt:  the XPath Parser context
9065  * @nargs:  the number of arguments
9066  *
9067  * Implement the substring() XPath function
9068  *    string substring(string, number, number?)
9069  * The substring function returns the substring of the first argument
9070  * starting at the position specified in the second argument with
9071  * length specified in the third argument. For example,
9072  * substring("12345",2,3) returns "234". If the third argument is not
9073  * specified, it returns the substring starting at the position specified
9074  * in the second argument and continuing to the end of the string. For
9075  * example, substring("12345",2) returns "2345".  More precisely, each
9076  * character in the string (see [3.6 Strings]) is considered to have a
9077  * numeric position: the position of the first character is 1, the position
9078  * of the second character is 2 and so on. The returned substring contains
9079  * those characters for which the position of the character is greater than
9080  * or equal to the second argument and, if the third argument is specified,
9081  * less than the sum of the second and third arguments; the comparisons
9082  * and addition used for the above follow the standard IEEE 754 rules. Thus:
9083  *  - substring("12345", 1.5, 2.6) returns "234"
9084  *  - substring("12345", 0, 3) returns "12"
9085  *  - substring("12345", 0 div 0, 3) returns ""
9086  *  - substring("12345", 1, 0 div 0) returns ""
9087  *  - substring("12345", -42, 1 div 0) returns "12345"
9088  *  - substring("12345", -1 div 0, 1 div 0) returns ""
9089  */
9090 void
9091 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9092     xmlXPathObjectPtr str, start, len;
9093     double le=0, in;
9094     int i = 1, j = INT_MAX;
9095 
9096     if (nargs < 2) {
9097 	CHECK_ARITY(2);
9098     }
9099     if (nargs > 3) {
9100 	CHECK_ARITY(3);
9101     }
9102     /*
9103      * take care of possible last (position) argument
9104     */
9105     if (nargs == 3) {
9106 	CAST_TO_NUMBER;
9107 	CHECK_TYPE(XPATH_NUMBER);
9108 	len = valuePop(ctxt);
9109 	le = len->floatval;
9110 	xmlXPathReleaseObject(ctxt->context, len);
9111     }
9112 
9113     CAST_TO_NUMBER;
9114     CHECK_TYPE(XPATH_NUMBER);
9115     start = valuePop(ctxt);
9116     in = start->floatval;
9117     xmlXPathReleaseObject(ctxt->context, start);
9118     CAST_TO_STRING;
9119     CHECK_TYPE(XPATH_STRING);
9120     str = valuePop(ctxt);
9121 
9122     if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9123         i = INT_MAX;
9124     } else if (in >= 1.0) {
9125         i = (int)in;
9126         if (in - floor(in) >= 0.5)
9127             i += 1;
9128     }
9129 
9130     if (nargs == 3) {
9131         double rin, rle, end;
9132 
9133         rin = floor(in);
9134         if (in - rin >= 0.5)
9135             rin += 1.0;
9136 
9137         rle = floor(le);
9138         if (le - rle >= 0.5)
9139             rle += 1.0;
9140 
9141         end = rin + rle;
9142         if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9143             j = 1;
9144         } else if (end < INT_MAX) {
9145             j = (int)end;
9146         }
9147     }
9148 
9149     if (i < j) {
9150         xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9151 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9152 	xmlFree(ret);
9153     } else {
9154 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9155     }
9156 
9157     xmlXPathReleaseObject(ctxt->context, str);
9158 }
9159 
9160 /**
9161  * xmlXPathSubstringBeforeFunction:
9162  * @ctxt:  the XPath Parser context
9163  * @nargs:  the number of arguments
9164  *
9165  * Implement the substring-before() XPath function
9166  *    string substring-before(string, string)
9167  * The substring-before function returns the substring of the first
9168  * argument string that precedes the first occurrence of the second
9169  * argument string in the first argument string, or the empty string
9170  * if the first argument string does not contain the second argument
9171  * string. For example, substring-before("1999/04/01","/") returns 1999.
9172  */
9173 void
9174 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9175   xmlXPathObjectPtr str;
9176   xmlXPathObjectPtr find;
9177   xmlBufPtr target;
9178   const xmlChar *point;
9179   int offset;
9180 
9181   CHECK_ARITY(2);
9182   CAST_TO_STRING;
9183   find = valuePop(ctxt);
9184   CAST_TO_STRING;
9185   str = valuePop(ctxt);
9186 
9187   target = xmlBufCreate();
9188   if (target) {
9189     point = xmlStrstr(str->stringval, find->stringval);
9190     if (point) {
9191       offset = (int)(point - str->stringval);
9192       xmlBufAdd(target, str->stringval, offset);
9193     }
9194     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9195 	xmlBufContent(target)));
9196     xmlBufFree(target);
9197   }
9198   xmlXPathReleaseObject(ctxt->context, str);
9199   xmlXPathReleaseObject(ctxt->context, find);
9200 }
9201 
9202 /**
9203  * xmlXPathSubstringAfterFunction:
9204  * @ctxt:  the XPath Parser context
9205  * @nargs:  the number of arguments
9206  *
9207  * Implement the substring-after() XPath function
9208  *    string substring-after(string, string)
9209  * The substring-after function returns the substring of the first
9210  * argument string that follows the first occurrence of the second
9211  * argument string in the first argument string, or the empty stringi
9212  * if the first argument string does not contain the second argument
9213  * string. For example, substring-after("1999/04/01","/") returns 04/01,
9214  * and substring-after("1999/04/01","19") returns 99/04/01.
9215  */
9216 void
9217 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9218   xmlXPathObjectPtr str;
9219   xmlXPathObjectPtr find;
9220   xmlBufPtr target;
9221   const xmlChar *point;
9222   int offset;
9223 
9224   CHECK_ARITY(2);
9225   CAST_TO_STRING;
9226   find = valuePop(ctxt);
9227   CAST_TO_STRING;
9228   str = valuePop(ctxt);
9229 
9230   target = xmlBufCreate();
9231   if (target) {
9232     point = xmlStrstr(str->stringval, find->stringval);
9233     if (point) {
9234       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9235       xmlBufAdd(target, &str->stringval[offset],
9236 		   xmlStrlen(str->stringval) - offset);
9237     }
9238     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9239 	xmlBufContent(target)));
9240     xmlBufFree(target);
9241   }
9242   xmlXPathReleaseObject(ctxt->context, str);
9243   xmlXPathReleaseObject(ctxt->context, find);
9244 }
9245 
9246 /**
9247  * xmlXPathNormalizeFunction:
9248  * @ctxt:  the XPath Parser context
9249  * @nargs:  the number of arguments
9250  *
9251  * Implement the normalize-space() XPath function
9252  *    string normalize-space(string?)
9253  * The normalize-space function returns the argument string with white
9254  * space normalized by stripping leading and trailing whitespace
9255  * and replacing sequences of whitespace characters by a single
9256  * space. Whitespace characters are the same allowed by the S production
9257  * in XML. If the argument is omitted, it defaults to the context
9258  * node converted to a string, in other words the value of the context node.
9259  */
9260 void
9261 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9262   xmlXPathObjectPtr obj = NULL;
9263   xmlChar *source = NULL;
9264   xmlBufPtr target;
9265   xmlChar blank;
9266 
9267   if (ctxt == NULL) return;
9268   if (nargs == 0) {
9269     /* Use current context node */
9270       valuePush(ctxt,
9271 	  xmlXPathCacheWrapString(ctxt->context,
9272 	    xmlXPathCastNodeToString(ctxt->context->node)));
9273     nargs = 1;
9274   }
9275 
9276   CHECK_ARITY(1);
9277   CAST_TO_STRING;
9278   CHECK_TYPE(XPATH_STRING);
9279   obj = valuePop(ctxt);
9280   source = obj->stringval;
9281 
9282   target = xmlBufCreate();
9283   if (target && source) {
9284 
9285     /* Skip leading whitespaces */
9286     while (IS_BLANK_CH(*source))
9287       source++;
9288 
9289     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9290     blank = 0;
9291     while (*source) {
9292       if (IS_BLANK_CH(*source)) {
9293 	blank = 0x20;
9294       } else {
9295 	if (blank) {
9296 	  xmlBufAdd(target, &blank, 1);
9297 	  blank = 0;
9298 	}
9299 	xmlBufAdd(target, source, 1);
9300       }
9301       source++;
9302     }
9303     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9304 	xmlBufContent(target)));
9305     xmlBufFree(target);
9306   }
9307   xmlXPathReleaseObject(ctxt->context, obj);
9308 }
9309 
9310 /**
9311  * xmlXPathTranslateFunction:
9312  * @ctxt:  the XPath Parser context
9313  * @nargs:  the number of arguments
9314  *
9315  * Implement the translate() XPath function
9316  *    string translate(string, string, string)
9317  * The translate function returns the first argument string with
9318  * occurrences of characters in the second argument string replaced
9319  * by the character at the corresponding position in the third argument
9320  * string. For example, translate("bar","abc","ABC") returns the string
9321  * BAr. If there is a character in the second argument string with no
9322  * character at a corresponding position in the third argument string
9323  * (because the second argument string is longer than the third argument
9324  * string), then occurrences of that character in the first argument
9325  * string are removed. For example, translate("--aaa--","abc-","ABC")
9326  * returns "AAA". If a character occurs more than once in second
9327  * argument string, then the first occurrence determines the replacement
9328  * character. If the third argument string is longer than the second
9329  * argument string, then excess characters are ignored.
9330  */
9331 void
9332 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9333     xmlXPathObjectPtr str;
9334     xmlXPathObjectPtr from;
9335     xmlXPathObjectPtr to;
9336     xmlBufPtr target;
9337     int offset, max;
9338     xmlChar ch;
9339     const xmlChar *point;
9340     xmlChar *cptr;
9341 
9342     CHECK_ARITY(3);
9343 
9344     CAST_TO_STRING;
9345     to = valuePop(ctxt);
9346     CAST_TO_STRING;
9347     from = valuePop(ctxt);
9348     CAST_TO_STRING;
9349     str = valuePop(ctxt);
9350 
9351     target = xmlBufCreate();
9352     if (target) {
9353 	max = xmlUTF8Strlen(to->stringval);
9354 	for (cptr = str->stringval; (ch=*cptr); ) {
9355 	    offset = xmlUTF8Strloc(from->stringval, cptr);
9356 	    if (offset >= 0) {
9357 		if (offset < max) {
9358 		    point = xmlUTF8Strpos(to->stringval, offset);
9359 		    if (point)
9360 			xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9361 		}
9362 	    } else
9363 		xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9364 
9365 	    /* Step to next character in input */
9366 	    cptr++;
9367 	    if ( ch & 0x80 ) {
9368 		/* if not simple ascii, verify proper format */
9369 		if ( (ch & 0xc0) != 0xc0 ) {
9370 		    xmlGenericError(xmlGenericErrorContext,
9371 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
9372                     /* not asserting an XPath error is probably better */
9373 		    break;
9374 		}
9375 		/* then skip over remaining bytes for this char */
9376 		while ( (ch <<= 1) & 0x80 )
9377 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
9378 			xmlGenericError(xmlGenericErrorContext,
9379 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9380                         /* not asserting an XPath error is probably better */
9381 			break;
9382 		    }
9383 		if (ch & 0x80) /* must have had error encountered */
9384 		    break;
9385 	    }
9386 	}
9387     }
9388     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9389 	xmlBufContent(target)));
9390     xmlBufFree(target);
9391     xmlXPathReleaseObject(ctxt->context, str);
9392     xmlXPathReleaseObject(ctxt->context, from);
9393     xmlXPathReleaseObject(ctxt->context, to);
9394 }
9395 
9396 /**
9397  * xmlXPathBooleanFunction:
9398  * @ctxt:  the XPath Parser context
9399  * @nargs:  the number of arguments
9400  *
9401  * Implement the boolean() XPath function
9402  *    boolean boolean(object)
9403  * The boolean function converts its argument to a boolean as follows:
9404  *    - a number is true if and only if it is neither positive or
9405  *      negative zero nor NaN
9406  *    - a node-set is true if and only if it is non-empty
9407  *    - a string is true if and only if its length is non-zero
9408  */
9409 void
9410 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9411     xmlXPathObjectPtr cur;
9412 
9413     CHECK_ARITY(1);
9414     cur = valuePop(ctxt);
9415     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9416     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9417     valuePush(ctxt, cur);
9418 }
9419 
9420 /**
9421  * xmlXPathNotFunction:
9422  * @ctxt:  the XPath Parser context
9423  * @nargs:  the number of arguments
9424  *
9425  * Implement the not() XPath function
9426  *    boolean not(boolean)
9427  * The not function returns true if its argument is false,
9428  * and false otherwise.
9429  */
9430 void
9431 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9432     CHECK_ARITY(1);
9433     CAST_TO_BOOLEAN;
9434     CHECK_TYPE(XPATH_BOOLEAN);
9435     ctxt->value->boolval = ! ctxt->value->boolval;
9436 }
9437 
9438 /**
9439  * xmlXPathTrueFunction:
9440  * @ctxt:  the XPath Parser context
9441  * @nargs:  the number of arguments
9442  *
9443  * Implement the true() XPath function
9444  *    boolean true()
9445  */
9446 void
9447 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9448     CHECK_ARITY(0);
9449     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9450 }
9451 
9452 /**
9453  * xmlXPathFalseFunction:
9454  * @ctxt:  the XPath Parser context
9455  * @nargs:  the number of arguments
9456  *
9457  * Implement the false() XPath function
9458  *    boolean false()
9459  */
9460 void
9461 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9462     CHECK_ARITY(0);
9463     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9464 }
9465 
9466 /**
9467  * xmlXPathLangFunction:
9468  * @ctxt:  the XPath Parser context
9469  * @nargs:  the number of arguments
9470  *
9471  * Implement the lang() XPath function
9472  *    boolean lang(string)
9473  * The lang function returns true or false depending on whether the
9474  * language of the context node as specified by xml:lang attributes
9475  * is the same as or is a sublanguage of the language specified by
9476  * the argument string. The language of the context node is determined
9477  * by the value of the xml:lang attribute on the context node, or, if
9478  * the context node has no xml:lang attribute, by the value of the
9479  * xml:lang attribute on the nearest ancestor of the context node that
9480  * has an xml:lang attribute. If there is no such attribute, then lang
9481  * returns false. If there is such an attribute, then lang returns
9482  * true if the attribute value is equal to the argument ignoring case,
9483  * or if there is some suffix starting with - such that the attribute
9484  * value is equal to the argument ignoring that suffix of the attribute
9485  * value and ignoring case.
9486  */
9487 void
9488 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9489     xmlXPathObjectPtr val = NULL;
9490     const xmlChar *theLang = NULL;
9491     const xmlChar *lang;
9492     int ret = 0;
9493     int i;
9494 
9495     CHECK_ARITY(1);
9496     CAST_TO_STRING;
9497     CHECK_TYPE(XPATH_STRING);
9498     val = valuePop(ctxt);
9499     lang = val->stringval;
9500     theLang = xmlNodeGetLang(ctxt->context->node);
9501     if ((theLang != NULL) && (lang != NULL)) {
9502         for (i = 0;lang[i] != 0;i++)
9503 	    if (toupper(lang[i]) != toupper(theLang[i]))
9504 	        goto not_equal;
9505 	if ((theLang[i] == 0) || (theLang[i] == '-'))
9506 	    ret = 1;
9507     }
9508 not_equal:
9509     if (theLang != NULL)
9510 	xmlFree((void *)theLang);
9511 
9512     xmlXPathReleaseObject(ctxt->context, val);
9513     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9514 }
9515 
9516 /**
9517  * xmlXPathNumberFunction:
9518  * @ctxt:  the XPath Parser context
9519  * @nargs:  the number of arguments
9520  *
9521  * Implement the number() XPath function
9522  *    number number(object?)
9523  */
9524 void
9525 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9526     xmlXPathObjectPtr cur;
9527     double res;
9528 
9529     if (ctxt == NULL) return;
9530     if (nargs == 0) {
9531 	if (ctxt->context->node == NULL) {
9532 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9533 	} else {
9534 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9535 
9536 	    res = xmlXPathStringEvalNumber(content);
9537 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9538 	    xmlFree(content);
9539 	}
9540 	return;
9541     }
9542 
9543     CHECK_ARITY(1);
9544     cur = valuePop(ctxt);
9545     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9546 }
9547 
9548 /**
9549  * xmlXPathSumFunction:
9550  * @ctxt:  the XPath Parser context
9551  * @nargs:  the number of arguments
9552  *
9553  * Implement the sum() XPath function
9554  *    number sum(node-set)
9555  * The sum function returns the sum of the values of the nodes in
9556  * the argument node-set.
9557  */
9558 void
9559 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9560     xmlXPathObjectPtr cur;
9561     int i;
9562     double res = 0.0;
9563 
9564     CHECK_ARITY(1);
9565     if ((ctxt->value == NULL) ||
9566 	((ctxt->value->type != XPATH_NODESET) &&
9567 	 (ctxt->value->type != XPATH_XSLT_TREE)))
9568 	XP_ERROR(XPATH_INVALID_TYPE);
9569     cur = valuePop(ctxt);
9570 
9571     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9572 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9573 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9574 	}
9575     }
9576     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9577     xmlXPathReleaseObject(ctxt->context, cur);
9578 }
9579 
9580 /**
9581  * xmlXPathFloorFunction:
9582  * @ctxt:  the XPath Parser context
9583  * @nargs:  the number of arguments
9584  *
9585  * Implement the floor() XPath function
9586  *    number floor(number)
9587  * The floor function returns the largest (closest to positive infinity)
9588  * number that is not greater than the argument and that is an integer.
9589  */
9590 void
9591 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9592     CHECK_ARITY(1);
9593     CAST_TO_NUMBER;
9594     CHECK_TYPE(XPATH_NUMBER);
9595 
9596     ctxt->value->floatval = floor(ctxt->value->floatval);
9597 }
9598 
9599 /**
9600  * xmlXPathCeilingFunction:
9601  * @ctxt:  the XPath Parser context
9602  * @nargs:  the number of arguments
9603  *
9604  * Implement the ceiling() XPath function
9605  *    number ceiling(number)
9606  * The ceiling function returns the smallest (closest to negative infinity)
9607  * number that is not less than the argument and that is an integer.
9608  */
9609 void
9610 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9611     CHECK_ARITY(1);
9612     CAST_TO_NUMBER;
9613     CHECK_TYPE(XPATH_NUMBER);
9614 
9615 #ifdef _AIX
9616     /* Work around buggy ceil() function on AIX */
9617     ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9618 #else
9619     ctxt->value->floatval = ceil(ctxt->value->floatval);
9620 #endif
9621 }
9622 
9623 /**
9624  * xmlXPathRoundFunction:
9625  * @ctxt:  the XPath Parser context
9626  * @nargs:  the number of arguments
9627  *
9628  * Implement the round() XPath function
9629  *    number round(number)
9630  * The round function returns the number that is closest to the
9631  * argument and that is an integer. If there are two such numbers,
9632  * then the one that is closest to positive infinity is returned.
9633  */
9634 void
9635 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9636     double f;
9637 
9638     CHECK_ARITY(1);
9639     CAST_TO_NUMBER;
9640     CHECK_TYPE(XPATH_NUMBER);
9641 
9642     f = ctxt->value->floatval;
9643 
9644     if ((f >= -0.5) && (f < 0.5)) {
9645         /* Handles negative zero. */
9646         ctxt->value->floatval *= 0.0;
9647     }
9648     else {
9649         double rounded = floor(f);
9650         if (f - rounded >= 0.5)
9651             rounded += 1.0;
9652         ctxt->value->floatval = rounded;
9653     }
9654 }
9655 
9656 /************************************************************************
9657  *									*
9658  *			The Parser					*
9659  *									*
9660  ************************************************************************/
9661 
9662 /*
9663  * a few forward declarations since we use a recursive call based
9664  * implementation.
9665  */
9666 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9667 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9668 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9669 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9670 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9671 	                                  int qualified);
9672 
9673 /**
9674  * xmlXPathCurrentChar:
9675  * @ctxt:  the XPath parser context
9676  * @cur:  pointer to the beginning of the char
9677  * @len:  pointer to the length of the char read
9678  *
9679  * The current char value, if using UTF-8 this may actually span multiple
9680  * bytes in the input buffer.
9681  *
9682  * Returns the current char value and its length
9683  */
9684 
9685 static int
9686 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9687     unsigned char c;
9688     unsigned int val;
9689     const xmlChar *cur;
9690 
9691     if (ctxt == NULL)
9692 	return(0);
9693     cur = ctxt->cur;
9694 
9695     /*
9696      * We are supposed to handle UTF8, check it's valid
9697      * From rfc2044: encoding of the Unicode values on UTF-8:
9698      *
9699      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9700      * 0000 0000-0000 007F   0xxxxxxx
9701      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9702      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9703      *
9704      * Check for the 0x110000 limit too
9705      */
9706     c = *cur;
9707     if (c & 0x80) {
9708 	if ((cur[1] & 0xc0) != 0x80)
9709 	    goto encoding_error;
9710 	if ((c & 0xe0) == 0xe0) {
9711 
9712 	    if ((cur[2] & 0xc0) != 0x80)
9713 		goto encoding_error;
9714 	    if ((c & 0xf0) == 0xf0) {
9715 		if (((c & 0xf8) != 0xf0) ||
9716 		    ((cur[3] & 0xc0) != 0x80))
9717 		    goto encoding_error;
9718 		/* 4-byte code */
9719 		*len = 4;
9720 		val = (cur[0] & 0x7) << 18;
9721 		val |= (cur[1] & 0x3f) << 12;
9722 		val |= (cur[2] & 0x3f) << 6;
9723 		val |= cur[3] & 0x3f;
9724 	    } else {
9725 	      /* 3-byte code */
9726 		*len = 3;
9727 		val = (cur[0] & 0xf) << 12;
9728 		val |= (cur[1] & 0x3f) << 6;
9729 		val |= cur[2] & 0x3f;
9730 	    }
9731 	} else {
9732 	  /* 2-byte code */
9733 	    *len = 2;
9734 	    val = (cur[0] & 0x1f) << 6;
9735 	    val |= cur[1] & 0x3f;
9736 	}
9737 	if (!IS_CHAR(val)) {
9738 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9739 	}
9740 	return(val);
9741     } else {
9742 	/* 1-byte code */
9743 	*len = 1;
9744 	return((int) *cur);
9745     }
9746 encoding_error:
9747     /*
9748      * If we detect an UTF8 error that probably means that the
9749      * input encoding didn't get properly advertised in the
9750      * declaration header. Report the error and switch the encoding
9751      * to ISO-Latin-1 (if you don't like this policy, just declare the
9752      * encoding !)
9753      */
9754     *len = 0;
9755     XP_ERROR0(XPATH_ENCODING_ERROR);
9756 }
9757 
9758 /**
9759  * xmlXPathParseNCName:
9760  * @ctxt:  the XPath Parser context
9761  *
9762  * parse an XML namespace non qualified name.
9763  *
9764  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9765  *
9766  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9767  *                       CombiningChar | Extender
9768  *
9769  * Returns the namespace name or NULL
9770  */
9771 
9772 xmlChar *
9773 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9774     const xmlChar *in;
9775     xmlChar *ret;
9776     int count = 0;
9777 
9778     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9779     /*
9780      * Accelerator for simple ASCII names
9781      */
9782     in = ctxt->cur;
9783     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9784 	((*in >= 0x41) && (*in <= 0x5A)) ||
9785 	(*in == '_')) {
9786 	in++;
9787 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9788 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9789 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9790 	       (*in == '_') || (*in == '.') ||
9791 	       (*in == '-'))
9792 	    in++;
9793 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9794             (*in == '[') || (*in == ']') || (*in == ':') ||
9795             (*in == '@') || (*in == '*')) {
9796 	    count = in - ctxt->cur;
9797 	    if (count == 0)
9798 		return(NULL);
9799 	    ret = xmlStrndup(ctxt->cur, count);
9800 	    ctxt->cur = in;
9801 	    return(ret);
9802 	}
9803     }
9804     return(xmlXPathParseNameComplex(ctxt, 0));
9805 }
9806 
9807 
9808 /**
9809  * xmlXPathParseQName:
9810  * @ctxt:  the XPath Parser context
9811  * @prefix:  a xmlChar **
9812  *
9813  * parse an XML qualified name
9814  *
9815  * [NS 5] QName ::= (Prefix ':')? LocalPart
9816  *
9817  * [NS 6] Prefix ::= NCName
9818  *
9819  * [NS 7] LocalPart ::= NCName
9820  *
9821  * Returns the function returns the local part, and prefix is updated
9822  *   to get the Prefix if any.
9823  */
9824 
9825 static xmlChar *
9826 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9827     xmlChar *ret = NULL;
9828 
9829     *prefix = NULL;
9830     ret = xmlXPathParseNCName(ctxt);
9831     if (ret && CUR == ':') {
9832         *prefix = ret;
9833 	NEXT;
9834 	ret = xmlXPathParseNCName(ctxt);
9835     }
9836     return(ret);
9837 }
9838 
9839 /**
9840  * xmlXPathParseName:
9841  * @ctxt:  the XPath Parser context
9842  *
9843  * parse an XML name
9844  *
9845  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9846  *                  CombiningChar | Extender
9847  *
9848  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9849  *
9850  * Returns the namespace name or NULL
9851  */
9852 
9853 xmlChar *
9854 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9855     const xmlChar *in;
9856     xmlChar *ret;
9857     size_t count = 0;
9858 
9859     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9860     /*
9861      * Accelerator for simple ASCII names
9862      */
9863     in = ctxt->cur;
9864     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9865 	((*in >= 0x41) && (*in <= 0x5A)) ||
9866 	(*in == '_') || (*in == ':')) {
9867 	in++;
9868 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9869 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9870 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9871 	       (*in == '_') || (*in == '-') ||
9872 	       (*in == ':') || (*in == '.'))
9873 	    in++;
9874 	if ((*in > 0) && (*in < 0x80)) {
9875 	    count = in - ctxt->cur;
9876             if (count > XML_MAX_NAME_LENGTH) {
9877                 ctxt->cur = in;
9878                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9879             }
9880 	    ret = xmlStrndup(ctxt->cur, count);
9881 	    ctxt->cur = in;
9882 	    return(ret);
9883 	}
9884     }
9885     return(xmlXPathParseNameComplex(ctxt, 1));
9886 }
9887 
9888 static xmlChar *
9889 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9890     xmlChar buf[XML_MAX_NAMELEN + 5];
9891     int len = 0, l;
9892     int c;
9893 
9894     /*
9895      * Handler for more complex cases
9896      */
9897     c = CUR_CHAR(l);
9898     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9899         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9900         (c == '*') || /* accelerators */
9901 	(!IS_LETTER(c) && (c != '_') &&
9902          ((!qualified) || (c != ':')))) {
9903 	return(NULL);
9904     }
9905 
9906     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9907 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9908             (c == '.') || (c == '-') ||
9909 	    (c == '_') || ((qualified) && (c == ':')) ||
9910 	    (IS_COMBINING(c)) ||
9911 	    (IS_EXTENDER(c)))) {
9912 	COPY_BUF(l,buf,len,c);
9913 	NEXTL(l);
9914 	c = CUR_CHAR(l);
9915 	if (len >= XML_MAX_NAMELEN) {
9916 	    /*
9917 	     * Okay someone managed to make a huge name, so he's ready to pay
9918 	     * for the processing speed.
9919 	     */
9920 	    xmlChar *buffer;
9921 	    int max = len * 2;
9922 
9923             if (len > XML_MAX_NAME_LENGTH) {
9924                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9925             }
9926 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9927 	    if (buffer == NULL) {
9928 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
9929 	    }
9930 	    memcpy(buffer, buf, len);
9931 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9932 		   (c == '.') || (c == '-') ||
9933 		   (c == '_') || ((qualified) && (c == ':')) ||
9934 		   (IS_COMBINING(c)) ||
9935 		   (IS_EXTENDER(c))) {
9936 		if (len + 10 > max) {
9937                     xmlChar *tmp;
9938                     if (max > XML_MAX_NAME_LENGTH) {
9939                         xmlFree(buffer);
9940                         XP_ERRORNULL(XPATH_EXPR_ERROR);
9941                     }
9942 		    max *= 2;
9943 		    tmp = (xmlChar *) xmlRealloc(buffer,
9944 			                         max * sizeof(xmlChar));
9945 		    if (tmp == NULL) {
9946                         xmlFree(buffer);
9947 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
9948 		    }
9949                     buffer = tmp;
9950 		}
9951 		COPY_BUF(l,buffer,len,c);
9952 		NEXTL(l);
9953 		c = CUR_CHAR(l);
9954 	    }
9955 	    buffer[len] = 0;
9956 	    return(buffer);
9957 	}
9958     }
9959     if (len == 0)
9960 	return(NULL);
9961     return(xmlStrndup(buf, len));
9962 }
9963 
9964 #define MAX_FRAC 20
9965 
9966 /**
9967  * xmlXPathStringEvalNumber:
9968  * @str:  A string to scan
9969  *
9970  *  [30a]  Float  ::= Number ('e' Digits?)?
9971  *
9972  *  [30]   Number ::=   Digits ('.' Digits?)?
9973  *                    | '.' Digits
9974  *  [31]   Digits ::=   [0-9]+
9975  *
9976  * Compile a Number in the string
9977  * In complement of the Number expression, this function also handles
9978  * negative values : '-' Number.
9979  *
9980  * Returns the double value.
9981  */
9982 double
9983 xmlXPathStringEvalNumber(const xmlChar *str) {
9984     const xmlChar *cur = str;
9985     double ret;
9986     int ok = 0;
9987     int isneg = 0;
9988     int exponent = 0;
9989     int is_exponent_negative = 0;
9990 #ifdef __GNUC__
9991     unsigned long tmp = 0;
9992     double temp;
9993 #endif
9994     if (cur == NULL) return(0);
9995     while (IS_BLANK_CH(*cur)) cur++;
9996     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9997         return(NAN);
9998     }
9999     if (*cur == '-') {
10000 	isneg = 1;
10001 	cur++;
10002     }
10003 
10004 #ifdef __GNUC__
10005     /*
10006      * tmp/temp is a workaround against a gcc compiler bug
10007      * http://veillard.com/gcc.bug
10008      */
10009     ret = 0;
10010     while ((*cur >= '0') && (*cur <= '9')) {
10011 	ret = ret * 10;
10012 	tmp = (*cur - '0');
10013 	ok = 1;
10014 	cur++;
10015 	temp = (double) tmp;
10016 	ret = ret + temp;
10017     }
10018 #else
10019     ret = 0;
10020     while ((*cur >= '0') && (*cur <= '9')) {
10021 	ret = ret * 10 + (*cur - '0');
10022 	ok = 1;
10023 	cur++;
10024     }
10025 #endif
10026 
10027     if (*cur == '.') {
10028 	int v, frac = 0, max;
10029 	double fraction = 0;
10030 
10031         cur++;
10032 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10033 	    return(NAN);
10034 	}
10035         while (*cur == '0') {
10036 	    frac = frac + 1;
10037 	    cur++;
10038         }
10039         max = frac + MAX_FRAC;
10040 	while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10041 	    v = (*cur - '0');
10042 	    fraction = fraction * 10 + v;
10043 	    frac = frac + 1;
10044 	    cur++;
10045 	}
10046 	fraction /= pow(10.0, frac);
10047 	ret = ret + fraction;
10048 	while ((*cur >= '0') && (*cur <= '9'))
10049 	    cur++;
10050     }
10051     if ((*cur == 'e') || (*cur == 'E')) {
10052       cur++;
10053       if (*cur == '-') {
10054 	is_exponent_negative = 1;
10055 	cur++;
10056       } else if (*cur == '+') {
10057         cur++;
10058       }
10059       while ((*cur >= '0') && (*cur <= '9')) {
10060         if (exponent < 1000000)
10061 	  exponent = exponent * 10 + (*cur - '0');
10062 	cur++;
10063       }
10064     }
10065     while (IS_BLANK_CH(*cur)) cur++;
10066     if (*cur != 0) return(NAN);
10067     if (isneg) ret = -ret;
10068     if (is_exponent_negative) exponent = -exponent;
10069     ret *= pow(10.0, (double)exponent);
10070     return(ret);
10071 }
10072 
10073 /**
10074  * xmlXPathCompNumber:
10075  * @ctxt:  the XPath Parser context
10076  *
10077  *  [30]   Number ::=   Digits ('.' Digits?)?
10078  *                    | '.' Digits
10079  *  [31]   Digits ::=   [0-9]+
10080  *
10081  * Compile a Number, then push it on the stack
10082  *
10083  */
10084 static void
10085 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10086 {
10087     double ret = 0.0;
10088     int ok = 0;
10089     int exponent = 0;
10090     int is_exponent_negative = 0;
10091 #ifdef __GNUC__
10092     unsigned long tmp = 0;
10093     double temp;
10094 #endif
10095 
10096     CHECK_ERROR;
10097     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10098         XP_ERROR(XPATH_NUMBER_ERROR);
10099     }
10100 #ifdef __GNUC__
10101     /*
10102      * tmp/temp is a workaround against a gcc compiler bug
10103      * http://veillard.com/gcc.bug
10104      */
10105     ret = 0;
10106     while ((CUR >= '0') && (CUR <= '9')) {
10107 	ret = ret * 10;
10108 	tmp = (CUR - '0');
10109         ok = 1;
10110         NEXT;
10111 	temp = (double) tmp;
10112 	ret = ret + temp;
10113     }
10114 #else
10115     ret = 0;
10116     while ((CUR >= '0') && (CUR <= '9')) {
10117 	ret = ret * 10 + (CUR - '0');
10118 	ok = 1;
10119 	NEXT;
10120     }
10121 #endif
10122     if (CUR == '.') {
10123 	int v, frac = 0, max;
10124 	double fraction = 0;
10125 
10126         NEXT;
10127         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10128             XP_ERROR(XPATH_NUMBER_ERROR);
10129         }
10130         while (CUR == '0') {
10131             frac = frac + 1;
10132             NEXT;
10133         }
10134         max = frac + MAX_FRAC;
10135         while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10136 	    v = (CUR - '0');
10137 	    fraction = fraction * 10 + v;
10138 	    frac = frac + 1;
10139             NEXT;
10140         }
10141         fraction /= pow(10.0, frac);
10142         ret = ret + fraction;
10143         while ((CUR >= '0') && (CUR <= '9'))
10144             NEXT;
10145     }
10146     if ((CUR == 'e') || (CUR == 'E')) {
10147         NEXT;
10148         if (CUR == '-') {
10149             is_exponent_negative = 1;
10150             NEXT;
10151         } else if (CUR == '+') {
10152 	    NEXT;
10153 	}
10154         while ((CUR >= '0') && (CUR <= '9')) {
10155             if (exponent < 1000000)
10156                 exponent = exponent * 10 + (CUR - '0');
10157             NEXT;
10158         }
10159         if (is_exponent_negative)
10160             exponent = -exponent;
10161         ret *= pow(10.0, (double) exponent);
10162     }
10163     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10164                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10165 }
10166 
10167 /**
10168  * xmlXPathParseLiteral:
10169  * @ctxt:  the XPath Parser context
10170  *
10171  * Parse a Literal
10172  *
10173  *  [29]   Literal ::=   '"' [^"]* '"'
10174  *                    | "'" [^']* "'"
10175  *
10176  * Returns the value found or NULL in case of error
10177  */
10178 static xmlChar *
10179 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10180     const xmlChar *q;
10181     xmlChar *ret = NULL;
10182 
10183     if (CUR == '"') {
10184         NEXT;
10185 	q = CUR_PTR;
10186 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10187 	    NEXT;
10188 	if (!IS_CHAR_CH(CUR)) {
10189 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10190 	} else {
10191 	    ret = xmlStrndup(q, CUR_PTR - q);
10192 	    NEXT;
10193         }
10194     } else if (CUR == '\'') {
10195         NEXT;
10196 	q = CUR_PTR;
10197 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10198 	    NEXT;
10199 	if (!IS_CHAR_CH(CUR)) {
10200 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10201 	} else {
10202 	    ret = xmlStrndup(q, CUR_PTR - q);
10203 	    NEXT;
10204         }
10205     } else {
10206 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10207     }
10208     return(ret);
10209 }
10210 
10211 /**
10212  * xmlXPathCompLiteral:
10213  * @ctxt:  the XPath Parser context
10214  *
10215  * Parse a Literal and push it on the stack.
10216  *
10217  *  [29]   Literal ::=   '"' [^"]* '"'
10218  *                    | "'" [^']* "'"
10219  *
10220  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10221  */
10222 static void
10223 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10224     const xmlChar *q;
10225     xmlChar *ret = NULL;
10226 
10227     if (CUR == '"') {
10228         NEXT;
10229 	q = CUR_PTR;
10230 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10231 	    NEXT;
10232 	if (!IS_CHAR_CH(CUR)) {
10233 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10234 	} else {
10235 	    ret = xmlStrndup(q, CUR_PTR - q);
10236 	    NEXT;
10237         }
10238     } else if (CUR == '\'') {
10239         NEXT;
10240 	q = CUR_PTR;
10241 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10242 	    NEXT;
10243 	if (!IS_CHAR_CH(CUR)) {
10244 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10245 	} else {
10246 	    ret = xmlStrndup(q, CUR_PTR - q);
10247 	    NEXT;
10248         }
10249     } else {
10250 	XP_ERROR(XPATH_START_LITERAL_ERROR);
10251     }
10252     if (ret == NULL) return;
10253     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10254 	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
10255     xmlFree(ret);
10256 }
10257 
10258 /**
10259  * xmlXPathCompVariableReference:
10260  * @ctxt:  the XPath Parser context
10261  *
10262  * Parse a VariableReference, evaluate it and push it on the stack.
10263  *
10264  * The variable bindings consist of a mapping from variable names
10265  * to variable values. The value of a variable is an object, which can be
10266  * of any of the types that are possible for the value of an expression,
10267  * and may also be of additional types not specified here.
10268  *
10269  * Early evaluation is possible since:
10270  * The variable bindings [...] used to evaluate a subexpression are
10271  * always the same as those used to evaluate the containing expression.
10272  *
10273  *  [36]   VariableReference ::=   '$' QName
10274  */
10275 static void
10276 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10277     xmlChar *name;
10278     xmlChar *prefix;
10279 
10280     SKIP_BLANKS;
10281     if (CUR != '$') {
10282 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10283     }
10284     NEXT;
10285     name = xmlXPathParseQName(ctxt, &prefix);
10286     if (name == NULL) {
10287         xmlFree(prefix);
10288 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10289     }
10290     ctxt->comp->last = -1;
10291     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10292 	           name, prefix);
10293     SKIP_BLANKS;
10294     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10295 	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10296     }
10297 }
10298 
10299 /**
10300  * xmlXPathIsNodeType:
10301  * @name:  a name string
10302  *
10303  * Is the name given a NodeType one.
10304  *
10305  *  [38]   NodeType ::=   'comment'
10306  *                    | 'text'
10307  *                    | 'processing-instruction'
10308  *                    | 'node'
10309  *
10310  * Returns 1 if true 0 otherwise
10311  */
10312 int
10313 xmlXPathIsNodeType(const xmlChar *name) {
10314     if (name == NULL)
10315 	return(0);
10316 
10317     if (xmlStrEqual(name, BAD_CAST "node"))
10318 	return(1);
10319     if (xmlStrEqual(name, BAD_CAST "text"))
10320 	return(1);
10321     if (xmlStrEqual(name, BAD_CAST "comment"))
10322 	return(1);
10323     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10324 	return(1);
10325     return(0);
10326 }
10327 
10328 /**
10329  * xmlXPathCompFunctionCall:
10330  * @ctxt:  the XPath Parser context
10331  *
10332  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10333  *  [17]   Argument ::=   Expr
10334  *
10335  * Compile a function call, the evaluation of all arguments are
10336  * pushed on the stack
10337  */
10338 static void
10339 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10340     xmlChar *name;
10341     xmlChar *prefix;
10342     int nbargs = 0;
10343     int sort = 1;
10344 
10345     name = xmlXPathParseQName(ctxt, &prefix);
10346     if (name == NULL) {
10347 	xmlFree(prefix);
10348 	XP_ERROR(XPATH_EXPR_ERROR);
10349     }
10350     SKIP_BLANKS;
10351 #ifdef DEBUG_EXPR
10352     if (prefix == NULL)
10353 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10354 			name);
10355     else
10356 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10357 			prefix, name);
10358 #endif
10359 
10360     if (CUR != '(') {
10361 	xmlFree(name);
10362 	xmlFree(prefix);
10363 	XP_ERROR(XPATH_EXPR_ERROR);
10364     }
10365     NEXT;
10366     SKIP_BLANKS;
10367 
10368     /*
10369     * Optimization for count(): we don't need the node-set to be sorted.
10370     */
10371     if ((prefix == NULL) && (name[0] == 'c') &&
10372 	xmlStrEqual(name, BAD_CAST "count"))
10373     {
10374 	sort = 0;
10375     }
10376     ctxt->comp->last = -1;
10377     if (CUR != ')') {
10378 	while (CUR != 0) {
10379 	    int op1 = ctxt->comp->last;
10380 	    ctxt->comp->last = -1;
10381 	    xmlXPathCompileExpr(ctxt, sort);
10382 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10383 		xmlFree(name);
10384 		xmlFree(prefix);
10385 		return;
10386 	    }
10387 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10388 	    nbargs++;
10389 	    if (CUR == ')') break;
10390 	    if (CUR != ',') {
10391 		xmlFree(name);
10392 		xmlFree(prefix);
10393 		XP_ERROR(XPATH_EXPR_ERROR);
10394 	    }
10395 	    NEXT;
10396 	    SKIP_BLANKS;
10397 	}
10398     }
10399     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10400 	           name, prefix);
10401     NEXT;
10402     SKIP_BLANKS;
10403 }
10404 
10405 /**
10406  * xmlXPathCompPrimaryExpr:
10407  * @ctxt:  the XPath Parser context
10408  *
10409  *  [15]   PrimaryExpr ::=   VariableReference
10410  *                | '(' Expr ')'
10411  *                | Literal
10412  *                | Number
10413  *                | FunctionCall
10414  *
10415  * Compile a primary expression.
10416  */
10417 static void
10418 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10419     SKIP_BLANKS;
10420     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10421     else if (CUR == '(') {
10422 	NEXT;
10423 	SKIP_BLANKS;
10424 	xmlXPathCompileExpr(ctxt, 1);
10425 	CHECK_ERROR;
10426 	if (CUR != ')') {
10427 	    XP_ERROR(XPATH_EXPR_ERROR);
10428 	}
10429 	NEXT;
10430 	SKIP_BLANKS;
10431     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10432 	xmlXPathCompNumber(ctxt);
10433     } else if ((CUR == '\'') || (CUR == '"')) {
10434 	xmlXPathCompLiteral(ctxt);
10435     } else {
10436 	xmlXPathCompFunctionCall(ctxt);
10437     }
10438     SKIP_BLANKS;
10439 }
10440 
10441 /**
10442  * xmlXPathCompFilterExpr:
10443  * @ctxt:  the XPath Parser context
10444  *
10445  *  [20]   FilterExpr ::=   PrimaryExpr
10446  *               | FilterExpr Predicate
10447  *
10448  * Compile a filter expression.
10449  * Square brackets are used to filter expressions in the same way that
10450  * they are used in location paths. It is an error if the expression to
10451  * be filtered does not evaluate to a node-set. The context node list
10452  * used for evaluating the expression in square brackets is the node-set
10453  * to be filtered listed in document order.
10454  */
10455 
10456 static void
10457 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10458     xmlXPathCompPrimaryExpr(ctxt);
10459     CHECK_ERROR;
10460     SKIP_BLANKS;
10461 
10462     while (CUR == '[') {
10463 	xmlXPathCompPredicate(ctxt, 1);
10464 	SKIP_BLANKS;
10465     }
10466 
10467 
10468 }
10469 
10470 /**
10471  * xmlXPathScanName:
10472  * @ctxt:  the XPath Parser context
10473  *
10474  * Trickery: parse an XML name but without consuming the input flow
10475  * Needed to avoid insanity in the parser state.
10476  *
10477  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10478  *                  CombiningChar | Extender
10479  *
10480  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10481  *
10482  * [6] Names ::= Name (S Name)*
10483  *
10484  * Returns the Name parsed or NULL
10485  */
10486 
10487 static xmlChar *
10488 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10489     int len = 0, l;
10490     int c;
10491     const xmlChar *cur;
10492     xmlChar *ret;
10493 
10494     cur = ctxt->cur;
10495 
10496     c = CUR_CHAR(l);
10497     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10498 	(!IS_LETTER(c) && (c != '_') &&
10499          (c != ':'))) {
10500 	return(NULL);
10501     }
10502 
10503     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10504 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10505             (c == '.') || (c == '-') ||
10506 	    (c == '_') || (c == ':') ||
10507 	    (IS_COMBINING(c)) ||
10508 	    (IS_EXTENDER(c)))) {
10509 	len += l;
10510 	NEXTL(l);
10511 	c = CUR_CHAR(l);
10512     }
10513     ret = xmlStrndup(cur, ctxt->cur - cur);
10514     ctxt->cur = cur;
10515     return(ret);
10516 }
10517 
10518 /**
10519  * xmlXPathCompPathExpr:
10520  * @ctxt:  the XPath Parser context
10521  *
10522  *  [19]   PathExpr ::=   LocationPath
10523  *               | FilterExpr
10524  *               | FilterExpr '/' RelativeLocationPath
10525  *               | FilterExpr '//' RelativeLocationPath
10526  *
10527  * Compile a path expression.
10528  * The / operator and // operators combine an arbitrary expression
10529  * and a relative location path. It is an error if the expression
10530  * does not evaluate to a node-set.
10531  * The / operator does composition in the same way as when / is
10532  * used in a location path. As in location paths, // is short for
10533  * /descendant-or-self::node()/.
10534  */
10535 
10536 static void
10537 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10538     int lc = 1;           /* Should we branch to LocationPath ?         */
10539     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10540 
10541     SKIP_BLANKS;
10542     if ((CUR == '$') || (CUR == '(') ||
10543 	(IS_ASCII_DIGIT(CUR)) ||
10544         (CUR == '\'') || (CUR == '"') ||
10545 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10546 	lc = 0;
10547     } else if (CUR == '*') {
10548 	/* relative or absolute location path */
10549 	lc = 1;
10550     } else if (CUR == '/') {
10551 	/* relative or absolute location path */
10552 	lc = 1;
10553     } else if (CUR == '@') {
10554 	/* relative abbreviated attribute location path */
10555 	lc = 1;
10556     } else if (CUR == '.') {
10557 	/* relative abbreviated attribute location path */
10558 	lc = 1;
10559     } else {
10560 	/*
10561 	 * Problem is finding if we have a name here whether it's:
10562 	 *   - a nodetype
10563 	 *   - a function call in which case it's followed by '('
10564 	 *   - an axis in which case it's followed by ':'
10565 	 *   - a element name
10566 	 * We do an a priori analysis here rather than having to
10567 	 * maintain parsed token content through the recursive function
10568 	 * calls. This looks uglier but makes the code easier to
10569 	 * read/write/debug.
10570 	 */
10571 	SKIP_BLANKS;
10572 	name = xmlXPathScanName(ctxt);
10573 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10574 #ifdef DEBUG_STEP
10575 	    xmlGenericError(xmlGenericErrorContext,
10576 		    "PathExpr: Axis\n");
10577 #endif
10578 	    lc = 1;
10579 	    xmlFree(name);
10580 	} else if (name != NULL) {
10581 	    int len =xmlStrlen(name);
10582 
10583 
10584 	    while (NXT(len) != 0) {
10585 		if (NXT(len) == '/') {
10586 		    /* element name */
10587 #ifdef DEBUG_STEP
10588 		    xmlGenericError(xmlGenericErrorContext,
10589 			    "PathExpr: AbbrRelLocation\n");
10590 #endif
10591 		    lc = 1;
10592 		    break;
10593 		} else if (IS_BLANK_CH(NXT(len))) {
10594 		    /* ignore blanks */
10595 		    ;
10596 		} else if (NXT(len) == ':') {
10597 #ifdef DEBUG_STEP
10598 		    xmlGenericError(xmlGenericErrorContext,
10599 			    "PathExpr: AbbrRelLocation\n");
10600 #endif
10601 		    lc = 1;
10602 		    break;
10603 		} else if ((NXT(len) == '(')) {
10604 		    /* Node Type or Function */
10605 		    if (xmlXPathIsNodeType(name)) {
10606 #ifdef DEBUG_STEP
10607 		        xmlGenericError(xmlGenericErrorContext,
10608 				"PathExpr: Type search\n");
10609 #endif
10610 			lc = 1;
10611 #ifdef LIBXML_XPTR_ENABLED
10612                     } else if (ctxt->xptr &&
10613                                xmlStrEqual(name, BAD_CAST "range-to")) {
10614                         lc = 1;
10615 #endif
10616 		    } else {
10617 #ifdef DEBUG_STEP
10618 		        xmlGenericError(xmlGenericErrorContext,
10619 				"PathExpr: function call\n");
10620 #endif
10621 			lc = 0;
10622 		    }
10623                     break;
10624 		} else if ((NXT(len) == '[')) {
10625 		    /* element name */
10626 #ifdef DEBUG_STEP
10627 		    xmlGenericError(xmlGenericErrorContext,
10628 			    "PathExpr: AbbrRelLocation\n");
10629 #endif
10630 		    lc = 1;
10631 		    break;
10632 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10633 			   (NXT(len) == '=')) {
10634 		    lc = 1;
10635 		    break;
10636 		} else {
10637 		    lc = 1;
10638 		    break;
10639 		}
10640 		len++;
10641 	    }
10642 	    if (NXT(len) == 0) {
10643 #ifdef DEBUG_STEP
10644 		xmlGenericError(xmlGenericErrorContext,
10645 			"PathExpr: AbbrRelLocation\n");
10646 #endif
10647 		/* element name */
10648 		lc = 1;
10649 	    }
10650 	    xmlFree(name);
10651 	} else {
10652 	    /* make sure all cases are covered explicitly */
10653 	    XP_ERROR(XPATH_EXPR_ERROR);
10654 	}
10655     }
10656 
10657     if (lc) {
10658 	if (CUR == '/') {
10659 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10660 	} else {
10661 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10662 	}
10663 	xmlXPathCompLocationPath(ctxt);
10664     } else {
10665 	xmlXPathCompFilterExpr(ctxt);
10666 	CHECK_ERROR;
10667 	if ((CUR == '/') && (NXT(1) == '/')) {
10668 	    SKIP(2);
10669 	    SKIP_BLANKS;
10670 
10671 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10672 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10673 
10674 	    xmlXPathCompRelativeLocationPath(ctxt);
10675 	} else if (CUR == '/') {
10676 	    xmlXPathCompRelativeLocationPath(ctxt);
10677 	}
10678     }
10679     SKIP_BLANKS;
10680 }
10681 
10682 /**
10683  * xmlXPathCompUnionExpr:
10684  * @ctxt:  the XPath Parser context
10685  *
10686  *  [18]   UnionExpr ::=   PathExpr
10687  *               | UnionExpr '|' PathExpr
10688  *
10689  * Compile an union expression.
10690  */
10691 
10692 static void
10693 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10694     xmlXPathCompPathExpr(ctxt);
10695     CHECK_ERROR;
10696     SKIP_BLANKS;
10697     while (CUR == '|') {
10698 	int op1 = ctxt->comp->last;
10699 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10700 
10701 	NEXT;
10702 	SKIP_BLANKS;
10703 	xmlXPathCompPathExpr(ctxt);
10704 
10705 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10706 
10707 	SKIP_BLANKS;
10708     }
10709 }
10710 
10711 /**
10712  * xmlXPathCompUnaryExpr:
10713  * @ctxt:  the XPath Parser context
10714  *
10715  *  [27]   UnaryExpr ::=   UnionExpr
10716  *                   | '-' UnaryExpr
10717  *
10718  * Compile an unary expression.
10719  */
10720 
10721 static void
10722 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10723     int minus = 0;
10724     int found = 0;
10725 
10726     SKIP_BLANKS;
10727     while (CUR == '-') {
10728         minus = 1 - minus;
10729 	found = 1;
10730 	NEXT;
10731 	SKIP_BLANKS;
10732     }
10733 
10734     xmlXPathCompUnionExpr(ctxt);
10735     CHECK_ERROR;
10736     if (found) {
10737 	if (minus)
10738 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10739 	else
10740 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10741     }
10742 }
10743 
10744 /**
10745  * xmlXPathCompMultiplicativeExpr:
10746  * @ctxt:  the XPath Parser context
10747  *
10748  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10749  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10750  *                   | MultiplicativeExpr 'div' UnaryExpr
10751  *                   | MultiplicativeExpr 'mod' UnaryExpr
10752  *  [34]   MultiplyOperator ::=   '*'
10753  *
10754  * Compile an Additive expression.
10755  */
10756 
10757 static void
10758 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10759     xmlXPathCompUnaryExpr(ctxt);
10760     CHECK_ERROR;
10761     SKIP_BLANKS;
10762     while ((CUR == '*') ||
10763            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10764            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10765 	int op = -1;
10766 	int op1 = ctxt->comp->last;
10767 
10768         if (CUR == '*') {
10769 	    op = 0;
10770 	    NEXT;
10771 	} else if (CUR == 'd') {
10772 	    op = 1;
10773 	    SKIP(3);
10774 	} else if (CUR == 'm') {
10775 	    op = 2;
10776 	    SKIP(3);
10777 	}
10778 	SKIP_BLANKS;
10779         xmlXPathCompUnaryExpr(ctxt);
10780 	CHECK_ERROR;
10781 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10782 	SKIP_BLANKS;
10783     }
10784 }
10785 
10786 /**
10787  * xmlXPathCompAdditiveExpr:
10788  * @ctxt:  the XPath Parser context
10789  *
10790  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10791  *                   | AdditiveExpr '+' MultiplicativeExpr
10792  *                   | AdditiveExpr '-' MultiplicativeExpr
10793  *
10794  * Compile an Additive expression.
10795  */
10796 
10797 static void
10798 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10799 
10800     xmlXPathCompMultiplicativeExpr(ctxt);
10801     CHECK_ERROR;
10802     SKIP_BLANKS;
10803     while ((CUR == '+') || (CUR == '-')) {
10804 	int plus;
10805 	int op1 = ctxt->comp->last;
10806 
10807         if (CUR == '+') plus = 1;
10808 	else plus = 0;
10809 	NEXT;
10810 	SKIP_BLANKS;
10811         xmlXPathCompMultiplicativeExpr(ctxt);
10812 	CHECK_ERROR;
10813 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10814 	SKIP_BLANKS;
10815     }
10816 }
10817 
10818 /**
10819  * xmlXPathCompRelationalExpr:
10820  * @ctxt:  the XPath Parser context
10821  *
10822  *  [24]   RelationalExpr ::=   AdditiveExpr
10823  *                 | RelationalExpr '<' AdditiveExpr
10824  *                 | RelationalExpr '>' AdditiveExpr
10825  *                 | RelationalExpr '<=' AdditiveExpr
10826  *                 | RelationalExpr '>=' AdditiveExpr
10827  *
10828  *  A <= B > C is allowed ? Answer from James, yes with
10829  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10830  *  which is basically what got implemented.
10831  *
10832  * Compile a Relational expression, then push the result
10833  * on the stack
10834  */
10835 
10836 static void
10837 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10838     xmlXPathCompAdditiveExpr(ctxt);
10839     CHECK_ERROR;
10840     SKIP_BLANKS;
10841     while ((CUR == '<') || (CUR == '>')) {
10842 	int inf, strict;
10843 	int op1 = ctxt->comp->last;
10844 
10845         if (CUR == '<') inf = 1;
10846 	else inf = 0;
10847 	if (NXT(1) == '=') strict = 0;
10848 	else strict = 1;
10849 	NEXT;
10850 	if (!strict) NEXT;
10851 	SKIP_BLANKS;
10852         xmlXPathCompAdditiveExpr(ctxt);
10853 	CHECK_ERROR;
10854 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10855 	SKIP_BLANKS;
10856     }
10857 }
10858 
10859 /**
10860  * xmlXPathCompEqualityExpr:
10861  * @ctxt:  the XPath Parser context
10862  *
10863  *  [23]   EqualityExpr ::=   RelationalExpr
10864  *                 | EqualityExpr '=' RelationalExpr
10865  *                 | EqualityExpr '!=' RelationalExpr
10866  *
10867  *  A != B != C is allowed ? Answer from James, yes with
10868  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10869  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10870  *  which is basically what got implemented.
10871  *
10872  * Compile an Equality expression.
10873  *
10874  */
10875 static void
10876 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10877     xmlXPathCompRelationalExpr(ctxt);
10878     CHECK_ERROR;
10879     SKIP_BLANKS;
10880     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10881 	int eq;
10882 	int op1 = ctxt->comp->last;
10883 
10884         if (CUR == '=') eq = 1;
10885 	else eq = 0;
10886 	NEXT;
10887 	if (!eq) NEXT;
10888 	SKIP_BLANKS;
10889         xmlXPathCompRelationalExpr(ctxt);
10890 	CHECK_ERROR;
10891 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10892 	SKIP_BLANKS;
10893     }
10894 }
10895 
10896 /**
10897  * xmlXPathCompAndExpr:
10898  * @ctxt:  the XPath Parser context
10899  *
10900  *  [22]   AndExpr ::=   EqualityExpr
10901  *                 | AndExpr 'and' EqualityExpr
10902  *
10903  * Compile an AND expression.
10904  *
10905  */
10906 static void
10907 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10908     xmlXPathCompEqualityExpr(ctxt);
10909     CHECK_ERROR;
10910     SKIP_BLANKS;
10911     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10912 	int op1 = ctxt->comp->last;
10913         SKIP(3);
10914 	SKIP_BLANKS;
10915         xmlXPathCompEqualityExpr(ctxt);
10916 	CHECK_ERROR;
10917 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10918 	SKIP_BLANKS;
10919     }
10920 }
10921 
10922 /**
10923  * xmlXPathCompileExpr:
10924  * @ctxt:  the XPath Parser context
10925  *
10926  *  [14]   Expr ::=   OrExpr
10927  *  [21]   OrExpr ::=   AndExpr
10928  *                 | OrExpr 'or' AndExpr
10929  *
10930  * Parse and compile an expression
10931  */
10932 static void
10933 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10934     xmlXPathContextPtr xpctxt = ctxt->context;
10935 
10936     if (xpctxt != NULL) {
10937         if (xpctxt->depth >= xpctxt->maxParserDepth)
10938             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10939         xpctxt->depth += 1;
10940     }
10941 
10942     xmlXPathCompAndExpr(ctxt);
10943     CHECK_ERROR;
10944     SKIP_BLANKS;
10945     while ((CUR == 'o') && (NXT(1) == 'r')) {
10946 	int op1 = ctxt->comp->last;
10947         SKIP(2);
10948 	SKIP_BLANKS;
10949         xmlXPathCompAndExpr(ctxt);
10950 	CHECK_ERROR;
10951 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10952 	SKIP_BLANKS;
10953     }
10954     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10955 	/* more ops could be optimized too */
10956 	/*
10957 	* This is the main place to eliminate sorting for
10958 	* operations which don't require a sorted node-set.
10959 	* E.g. count().
10960 	*/
10961 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10962     }
10963 
10964     if (xpctxt != NULL)
10965         xpctxt->depth -= 1;
10966 }
10967 
10968 /**
10969  * xmlXPathCompPredicate:
10970  * @ctxt:  the XPath Parser context
10971  * @filter:  act as a filter
10972  *
10973  *  [8]   Predicate ::=   '[' PredicateExpr ']'
10974  *  [9]   PredicateExpr ::=   Expr
10975  *
10976  * Compile a predicate expression
10977  */
10978 static void
10979 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10980     int op1 = ctxt->comp->last;
10981 
10982     SKIP_BLANKS;
10983     if (CUR != '[') {
10984 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10985     }
10986     NEXT;
10987     SKIP_BLANKS;
10988 
10989     ctxt->comp->last = -1;
10990     /*
10991     * This call to xmlXPathCompileExpr() will deactivate sorting
10992     * of the predicate result.
10993     * TODO: Sorting is still activated for filters, since I'm not
10994     *  sure if needed. Normally sorting should not be needed, since
10995     *  a filter can only diminish the number of items in a sequence,
10996     *  but won't change its order; so if the initial sequence is sorted,
10997     *  subsequent sorting is not needed.
10998     */
10999     if (! filter)
11000 	xmlXPathCompileExpr(ctxt, 0);
11001     else
11002 	xmlXPathCompileExpr(ctxt, 1);
11003     CHECK_ERROR;
11004 
11005     if (CUR != ']') {
11006 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11007     }
11008 
11009     if (filter)
11010 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11011     else
11012 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11013 
11014     NEXT;
11015     SKIP_BLANKS;
11016 }
11017 
11018 /**
11019  * xmlXPathCompNodeTest:
11020  * @ctxt:  the XPath Parser context
11021  * @test:  pointer to a xmlXPathTestVal
11022  * @type:  pointer to a xmlXPathTypeVal
11023  * @prefix:  placeholder for a possible name prefix
11024  *
11025  * [7] NodeTest ::=   NameTest
11026  *		    | NodeType '(' ')'
11027  *		    | 'processing-instruction' '(' Literal ')'
11028  *
11029  * [37] NameTest ::=  '*'
11030  *		    | NCName ':' '*'
11031  *		    | QName
11032  * [38] NodeType ::= 'comment'
11033  *		   | 'text'
11034  *		   | 'processing-instruction'
11035  *		   | 'node'
11036  *
11037  * Returns the name found and updates @test, @type and @prefix appropriately
11038  */
11039 static xmlChar *
11040 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11041 	             xmlXPathTypeVal *type, const xmlChar **prefix,
11042 		     xmlChar *name) {
11043     int blanks;
11044 
11045     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11046 	STRANGE;
11047 	return(NULL);
11048     }
11049     *type = (xmlXPathTypeVal) 0;
11050     *test = (xmlXPathTestVal) 0;
11051     *prefix = NULL;
11052     SKIP_BLANKS;
11053 
11054     if ((name == NULL) && (CUR == '*')) {
11055 	/*
11056 	 * All elements
11057 	 */
11058 	NEXT;
11059 	*test = NODE_TEST_ALL;
11060 	return(NULL);
11061     }
11062 
11063     if (name == NULL)
11064 	name = xmlXPathParseNCName(ctxt);
11065     if (name == NULL) {
11066 	XP_ERRORNULL(XPATH_EXPR_ERROR);
11067     }
11068 
11069     blanks = IS_BLANK_CH(CUR);
11070     SKIP_BLANKS;
11071     if (CUR == '(') {
11072 	NEXT;
11073 	/*
11074 	 * NodeType or PI search
11075 	 */
11076 	if (xmlStrEqual(name, BAD_CAST "comment"))
11077 	    *type = NODE_TYPE_COMMENT;
11078 	else if (xmlStrEqual(name, BAD_CAST "node"))
11079 	    *type = NODE_TYPE_NODE;
11080 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11081 	    *type = NODE_TYPE_PI;
11082 	else if (xmlStrEqual(name, BAD_CAST "text"))
11083 	    *type = NODE_TYPE_TEXT;
11084 	else {
11085 	    if (name != NULL)
11086 		xmlFree(name);
11087 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11088 	}
11089 
11090 	*test = NODE_TEST_TYPE;
11091 
11092 	SKIP_BLANKS;
11093 	if (*type == NODE_TYPE_PI) {
11094 	    /*
11095 	     * Specific case: search a PI by name.
11096 	     */
11097 	    if (name != NULL)
11098 		xmlFree(name);
11099 	    name = NULL;
11100 	    if (CUR != ')') {
11101 		name = xmlXPathParseLiteral(ctxt);
11102 		CHECK_ERROR NULL;
11103 		*test = NODE_TEST_PI;
11104 		SKIP_BLANKS;
11105 	    }
11106 	}
11107 	if (CUR != ')') {
11108 	    if (name != NULL)
11109 		xmlFree(name);
11110 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11111 	}
11112 	NEXT;
11113 	return(name);
11114     }
11115     *test = NODE_TEST_NAME;
11116     if ((!blanks) && (CUR == ':')) {
11117 	NEXT;
11118 
11119 	/*
11120 	 * Since currently the parser context don't have a
11121 	 * namespace list associated:
11122 	 * The namespace name for this prefix can be computed
11123 	 * only at evaluation time. The compilation is done
11124 	 * outside of any context.
11125 	 */
11126 #if 0
11127 	*prefix = xmlXPathNsLookup(ctxt->context, name);
11128 	if (name != NULL)
11129 	    xmlFree(name);
11130 	if (*prefix == NULL) {
11131 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11132 	}
11133 #else
11134 	*prefix = name;
11135 #endif
11136 
11137 	if (CUR == '*') {
11138 	    /*
11139 	     * All elements
11140 	     */
11141 	    NEXT;
11142 	    *test = NODE_TEST_ALL;
11143 	    return(NULL);
11144 	}
11145 
11146 	name = xmlXPathParseNCName(ctxt);
11147 	if (name == NULL) {
11148 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11149 	}
11150     }
11151     return(name);
11152 }
11153 
11154 /**
11155  * xmlXPathIsAxisName:
11156  * @name:  a preparsed name token
11157  *
11158  * [6] AxisName ::=   'ancestor'
11159  *                  | 'ancestor-or-self'
11160  *                  | 'attribute'
11161  *                  | 'child'
11162  *                  | 'descendant'
11163  *                  | 'descendant-or-self'
11164  *                  | 'following'
11165  *                  | 'following-sibling'
11166  *                  | 'namespace'
11167  *                  | 'parent'
11168  *                  | 'preceding'
11169  *                  | 'preceding-sibling'
11170  *                  | 'self'
11171  *
11172  * Returns the axis or 0
11173  */
11174 static xmlXPathAxisVal
11175 xmlXPathIsAxisName(const xmlChar *name) {
11176     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11177     switch (name[0]) {
11178 	case 'a':
11179 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11180 		ret = AXIS_ANCESTOR;
11181 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11182 		ret = AXIS_ANCESTOR_OR_SELF;
11183 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11184 		ret = AXIS_ATTRIBUTE;
11185 	    break;
11186 	case 'c':
11187 	    if (xmlStrEqual(name, BAD_CAST "child"))
11188 		ret = AXIS_CHILD;
11189 	    break;
11190 	case 'd':
11191 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11192 		ret = AXIS_DESCENDANT;
11193 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11194 		ret = AXIS_DESCENDANT_OR_SELF;
11195 	    break;
11196 	case 'f':
11197 	    if (xmlStrEqual(name, BAD_CAST "following"))
11198 		ret = AXIS_FOLLOWING;
11199 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11200 		ret = AXIS_FOLLOWING_SIBLING;
11201 	    break;
11202 	case 'n':
11203 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11204 		ret = AXIS_NAMESPACE;
11205 	    break;
11206 	case 'p':
11207 	    if (xmlStrEqual(name, BAD_CAST "parent"))
11208 		ret = AXIS_PARENT;
11209 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11210 		ret = AXIS_PRECEDING;
11211 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11212 		ret = AXIS_PRECEDING_SIBLING;
11213 	    break;
11214 	case 's':
11215 	    if (xmlStrEqual(name, BAD_CAST "self"))
11216 		ret = AXIS_SELF;
11217 	    break;
11218     }
11219     return(ret);
11220 }
11221 
11222 /**
11223  * xmlXPathCompStep:
11224  * @ctxt:  the XPath Parser context
11225  *
11226  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11227  *                  | AbbreviatedStep
11228  *
11229  * [12] AbbreviatedStep ::=   '.' | '..'
11230  *
11231  * [5] AxisSpecifier ::= AxisName '::'
11232  *                  | AbbreviatedAxisSpecifier
11233  *
11234  * [13] AbbreviatedAxisSpecifier ::= '@'?
11235  *
11236  * Modified for XPtr range support as:
11237  *
11238  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11239  *                     | AbbreviatedStep
11240  *                     | 'range-to' '(' Expr ')' Predicate*
11241  *
11242  * Compile one step in a Location Path
11243  * A location step of . is short for self::node(). This is
11244  * particularly useful in conjunction with //. For example, the
11245  * location path .//para is short for
11246  * self::node()/descendant-or-self::node()/child::para
11247  * and so will select all para descendant elements of the context
11248  * node.
11249  * Similarly, a location step of .. is short for parent::node().
11250  * For example, ../title is short for parent::node()/child::title
11251  * and so will select the title children of the parent of the context
11252  * node.
11253  */
11254 static void
11255 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11256 #ifdef LIBXML_XPTR_ENABLED
11257     int rangeto = 0;
11258     int op2 = -1;
11259 #endif
11260 
11261     SKIP_BLANKS;
11262     if ((CUR == '.') && (NXT(1) == '.')) {
11263 	SKIP(2);
11264 	SKIP_BLANKS;
11265 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11266 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11267     } else if (CUR == '.') {
11268 	NEXT;
11269 	SKIP_BLANKS;
11270     } else {
11271 	xmlChar *name = NULL;
11272 	const xmlChar *prefix = NULL;
11273 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11274 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11275 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11276 	int op1;
11277 
11278 	/*
11279 	 * The modification needed for XPointer change to the production
11280 	 */
11281 #ifdef LIBXML_XPTR_ENABLED
11282 	if (ctxt->xptr) {
11283 	    name = xmlXPathParseNCName(ctxt);
11284 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11285                 op2 = ctxt->comp->last;
11286 		xmlFree(name);
11287 		SKIP_BLANKS;
11288 		if (CUR != '(') {
11289 		    XP_ERROR(XPATH_EXPR_ERROR);
11290 		}
11291 		NEXT;
11292 		SKIP_BLANKS;
11293 
11294 		xmlXPathCompileExpr(ctxt, 1);
11295 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11296 		CHECK_ERROR;
11297 
11298 		SKIP_BLANKS;
11299 		if (CUR != ')') {
11300 		    XP_ERROR(XPATH_EXPR_ERROR);
11301 		}
11302 		NEXT;
11303 		rangeto = 1;
11304 		goto eval_predicates;
11305 	    }
11306 	}
11307 #endif
11308 	if (CUR == '*') {
11309 	    axis = AXIS_CHILD;
11310 	} else {
11311 	    if (name == NULL)
11312 		name = xmlXPathParseNCName(ctxt);
11313 	    if (name != NULL) {
11314 		axis = xmlXPathIsAxisName(name);
11315 		if (axis != 0) {
11316 		    SKIP_BLANKS;
11317 		    if ((CUR == ':') && (NXT(1) == ':')) {
11318 			SKIP(2);
11319 			xmlFree(name);
11320 			name = NULL;
11321 		    } else {
11322 			/* an element name can conflict with an axis one :-\ */
11323 			axis = AXIS_CHILD;
11324 		    }
11325 		} else {
11326 		    axis = AXIS_CHILD;
11327 		}
11328 	    } else if (CUR == '@') {
11329 		NEXT;
11330 		axis = AXIS_ATTRIBUTE;
11331 	    } else {
11332 		axis = AXIS_CHILD;
11333 	    }
11334 	}
11335 
11336         if (ctxt->error != XPATH_EXPRESSION_OK) {
11337             xmlFree(name);
11338             return;
11339         }
11340 
11341 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11342 	if (test == 0)
11343 	    return;
11344 
11345         if ((prefix != NULL) && (ctxt->context != NULL) &&
11346 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11347 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11348 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11349 	    }
11350 	}
11351 #ifdef DEBUG_STEP
11352 	xmlGenericError(xmlGenericErrorContext,
11353 		"Basis : computing new set\n");
11354 #endif
11355 
11356 #ifdef DEBUG_STEP
11357 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11358 	if (ctxt->value == NULL)
11359 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11360 	else if (ctxt->value->nodesetval == NULL)
11361 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11362 	else
11363 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11364 #endif
11365 
11366 #ifdef LIBXML_XPTR_ENABLED
11367 eval_predicates:
11368 #endif
11369 	op1 = ctxt->comp->last;
11370 	ctxt->comp->last = -1;
11371 
11372 	SKIP_BLANKS;
11373 	while (CUR == '[') {
11374 	    xmlXPathCompPredicate(ctxt, 0);
11375 	}
11376 
11377 #ifdef LIBXML_XPTR_ENABLED
11378 	if (rangeto) {
11379 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11380 	} else
11381 #endif
11382 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11383 			   test, type, (void *)prefix, (void *)name);
11384 
11385     }
11386 #ifdef DEBUG_STEP
11387     xmlGenericError(xmlGenericErrorContext, "Step : ");
11388     if (ctxt->value == NULL)
11389 	xmlGenericError(xmlGenericErrorContext, "no value\n");
11390     else if (ctxt->value->nodesetval == NULL)
11391 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11392     else
11393 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11394 		ctxt->value->nodesetval);
11395 #endif
11396 }
11397 
11398 /**
11399  * xmlXPathCompRelativeLocationPath:
11400  * @ctxt:  the XPath Parser context
11401  *
11402  *  [3]   RelativeLocationPath ::=   Step
11403  *                     | RelativeLocationPath '/' Step
11404  *                     | AbbreviatedRelativeLocationPath
11405  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11406  *
11407  * Compile a relative location path.
11408  */
11409 static void
11410 xmlXPathCompRelativeLocationPath
11411 (xmlXPathParserContextPtr ctxt) {
11412     SKIP_BLANKS;
11413     if ((CUR == '/') && (NXT(1) == '/')) {
11414 	SKIP(2);
11415 	SKIP_BLANKS;
11416 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11417 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11418     } else if (CUR == '/') {
11419 	    NEXT;
11420 	SKIP_BLANKS;
11421     }
11422     xmlXPathCompStep(ctxt);
11423     CHECK_ERROR;
11424     SKIP_BLANKS;
11425     while (CUR == '/') {
11426 	if ((CUR == '/') && (NXT(1) == '/')) {
11427 	    SKIP(2);
11428 	    SKIP_BLANKS;
11429 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11430 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11431 	    xmlXPathCompStep(ctxt);
11432 	} else if (CUR == '/') {
11433 	    NEXT;
11434 	    SKIP_BLANKS;
11435 	    xmlXPathCompStep(ctxt);
11436 	}
11437 	SKIP_BLANKS;
11438     }
11439 }
11440 
11441 /**
11442  * xmlXPathCompLocationPath:
11443  * @ctxt:  the XPath Parser context
11444  *
11445  *  [1]   LocationPath ::=   RelativeLocationPath
11446  *                     | AbsoluteLocationPath
11447  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11448  *                     | AbbreviatedAbsoluteLocationPath
11449  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11450  *                           '//' RelativeLocationPath
11451  *
11452  * Compile a location path
11453  *
11454  * // is short for /descendant-or-self::node()/. For example,
11455  * //para is short for /descendant-or-self::node()/child::para and
11456  * so will select any para element in the document (even a para element
11457  * that is a document element will be selected by //para since the
11458  * document element node is a child of the root node); div//para is
11459  * short for div/descendant-or-self::node()/child::para and so will
11460  * select all para descendants of div children.
11461  */
11462 static void
11463 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11464     SKIP_BLANKS;
11465     if (CUR != '/') {
11466         xmlXPathCompRelativeLocationPath(ctxt);
11467     } else {
11468 	while (CUR == '/') {
11469 	    if ((CUR == '/') && (NXT(1) == '/')) {
11470 		SKIP(2);
11471 		SKIP_BLANKS;
11472 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11473 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11474 		xmlXPathCompRelativeLocationPath(ctxt);
11475 	    } else if (CUR == '/') {
11476 		NEXT;
11477 		SKIP_BLANKS;
11478 		if ((CUR != 0 ) &&
11479 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11480 		     (CUR == '@') || (CUR == '*')))
11481 		    xmlXPathCompRelativeLocationPath(ctxt);
11482 	    }
11483 	    CHECK_ERROR;
11484 	}
11485     }
11486 }
11487 
11488 /************************************************************************
11489  *									*
11490  *		XPath precompiled expression evaluation			*
11491  *									*
11492  ************************************************************************/
11493 
11494 static int
11495 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11496 
11497 #ifdef DEBUG_STEP
11498 static void
11499 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11500 			  int nbNodes)
11501 {
11502     xmlGenericError(xmlGenericErrorContext, "new step : ");
11503     switch (op->value) {
11504         case AXIS_ANCESTOR:
11505             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11506             break;
11507         case AXIS_ANCESTOR_OR_SELF:
11508             xmlGenericError(xmlGenericErrorContext,
11509                             "axis 'ancestors-or-self' ");
11510             break;
11511         case AXIS_ATTRIBUTE:
11512             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11513             break;
11514         case AXIS_CHILD:
11515             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11516             break;
11517         case AXIS_DESCENDANT:
11518             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11519             break;
11520         case AXIS_DESCENDANT_OR_SELF:
11521             xmlGenericError(xmlGenericErrorContext,
11522                             "axis 'descendant-or-self' ");
11523             break;
11524         case AXIS_FOLLOWING:
11525             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11526             break;
11527         case AXIS_FOLLOWING_SIBLING:
11528             xmlGenericError(xmlGenericErrorContext,
11529                             "axis 'following-siblings' ");
11530             break;
11531         case AXIS_NAMESPACE:
11532             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11533             break;
11534         case AXIS_PARENT:
11535             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11536             break;
11537         case AXIS_PRECEDING:
11538             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11539             break;
11540         case AXIS_PRECEDING_SIBLING:
11541             xmlGenericError(xmlGenericErrorContext,
11542                             "axis 'preceding-sibling' ");
11543             break;
11544         case AXIS_SELF:
11545             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11546             break;
11547     }
11548     xmlGenericError(xmlGenericErrorContext,
11549 	" context contains %d nodes\n", nbNodes);
11550     switch (op->value2) {
11551         case NODE_TEST_NONE:
11552             xmlGenericError(xmlGenericErrorContext,
11553                             "           searching for none !!!\n");
11554             break;
11555         case NODE_TEST_TYPE:
11556             xmlGenericError(xmlGenericErrorContext,
11557                             "           searching for type %d\n", op->value3);
11558             break;
11559         case NODE_TEST_PI:
11560             xmlGenericError(xmlGenericErrorContext,
11561                             "           searching for PI !!!\n");
11562             break;
11563         case NODE_TEST_ALL:
11564             xmlGenericError(xmlGenericErrorContext,
11565                             "           searching for *\n");
11566             break;
11567         case NODE_TEST_NS:
11568             xmlGenericError(xmlGenericErrorContext,
11569                             "           searching for namespace %s\n",
11570                             op->value5);
11571             break;
11572         case NODE_TEST_NAME:
11573             xmlGenericError(xmlGenericErrorContext,
11574                             "           searching for name %s\n", op->value5);
11575             if (op->value4)
11576                 xmlGenericError(xmlGenericErrorContext,
11577                                 "           with namespace %s\n", op->value4);
11578             break;
11579     }
11580     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11581 }
11582 #endif /* DEBUG_STEP */
11583 
11584 /**
11585  * xmlXPathNodeSetFilter:
11586  * @ctxt:  the XPath Parser context
11587  * @set: the node set to filter
11588  * @filterOpIndex: the index of the predicate/filter op
11589  * @minPos: minimum position in the filtered set (1-based)
11590  * @maxPos: maximum position in the filtered set (1-based)
11591  * @hasNsNodes: true if the node set may contain namespace nodes
11592  *
11593  * Filter a node set, keeping only nodes for which the predicate expression
11594  * matches. Afterwards, keep only nodes between minPos and maxPos in the
11595  * filtered result.
11596  */
11597 static void
11598 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11599 		      xmlNodeSetPtr set,
11600 		      int filterOpIndex,
11601                       int minPos, int maxPos,
11602 		      int hasNsNodes)
11603 {
11604     xmlXPathContextPtr xpctxt;
11605     xmlNodePtr oldnode;
11606     xmlDocPtr olddoc;
11607     xmlXPathStepOpPtr filterOp;
11608     int oldcs, oldpp;
11609     int i, j, pos;
11610 
11611     if ((set == NULL) || (set->nodeNr == 0))
11612         return;
11613 
11614     /*
11615     * Check if the node set contains a sufficient number of nodes for
11616     * the requested range.
11617     */
11618     if (set->nodeNr < minPos) {
11619         xmlXPathNodeSetClear(set, hasNsNodes);
11620         return;
11621     }
11622 
11623     xpctxt = ctxt->context;
11624     oldnode = xpctxt->node;
11625     olddoc = xpctxt->doc;
11626     oldcs = xpctxt->contextSize;
11627     oldpp = xpctxt->proximityPosition;
11628     filterOp = &ctxt->comp->steps[filterOpIndex];
11629 
11630     xpctxt->contextSize = set->nodeNr;
11631 
11632     for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11633         xmlNodePtr node = set->nodeTab[i];
11634         int res;
11635 
11636         xpctxt->node = node;
11637         xpctxt->proximityPosition = i + 1;
11638 
11639         /*
11640         * Also set the xpath document in case things like
11641         * key() are evaluated in the predicate.
11642         *
11643         * TODO: Get real doc for namespace nodes.
11644         */
11645         if ((node->type != XML_NAMESPACE_DECL) &&
11646             (node->doc != NULL))
11647             xpctxt->doc = node->doc;
11648 
11649         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11650 
11651         if (ctxt->error != XPATH_EXPRESSION_OK)
11652             goto exit;
11653         if (res < 0) {
11654             /* Shouldn't happen */
11655             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11656             goto exit;
11657         }
11658 
11659         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11660             if (i != j) {
11661                 set->nodeTab[j] = node;
11662                 set->nodeTab[i] = NULL;
11663             }
11664 
11665             j += 1;
11666         } else {
11667             /* Remove the entry from the initial node set. */
11668             set->nodeTab[i] = NULL;
11669             if (node->type == XML_NAMESPACE_DECL)
11670                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11671         }
11672 
11673         if (res != 0) {
11674             if (pos == maxPos) {
11675                 /* Clear remaining nodes and exit loop. */
11676                 if (hasNsNodes) {
11677                     for (i++; i < set->nodeNr; i++) {
11678                         node = set->nodeTab[i];
11679                         if ((node != NULL) &&
11680                             (node->type == XML_NAMESPACE_DECL))
11681                             xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11682                     }
11683                 }
11684                 break;
11685             }
11686 
11687             pos += 1;
11688         }
11689     }
11690 
11691     set->nodeNr = j;
11692 
11693     /* If too many elements were removed, shrink table to preserve memory. */
11694     if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11695         (set->nodeNr < set->nodeMax / 2)) {
11696         xmlNodePtr *tmp;
11697         int nodeMax = set->nodeNr;
11698 
11699         if (nodeMax < XML_NODESET_DEFAULT)
11700             nodeMax = XML_NODESET_DEFAULT;
11701         tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11702                 nodeMax * sizeof(xmlNodePtr));
11703         if (tmp == NULL) {
11704             xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11705         } else {
11706             set->nodeTab = tmp;
11707             set->nodeMax = nodeMax;
11708         }
11709     }
11710 
11711 exit:
11712     xpctxt->node = oldnode;
11713     xpctxt->doc = olddoc;
11714     xpctxt->contextSize = oldcs;
11715     xpctxt->proximityPosition = oldpp;
11716 }
11717 
11718 #ifdef LIBXML_XPTR_ENABLED
11719 /**
11720  * xmlXPathLocationSetFilter:
11721  * @ctxt:  the XPath Parser context
11722  * @locset: the location set to filter
11723  * @filterOpIndex: the index of the predicate/filter op
11724  * @minPos: minimum position in the filtered set (1-based)
11725  * @maxPos: maximum position in the filtered set (1-based)
11726  *
11727  * Filter a location set, keeping only nodes for which the predicate
11728  * expression matches. Afterwards, keep only nodes between minPos and maxPos
11729  * in the filtered result.
11730  */
11731 static void
11732 xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11733 		          xmlLocationSetPtr locset,
11734 		          int filterOpIndex,
11735                           int minPos, int maxPos)
11736 {
11737     xmlXPathContextPtr xpctxt;
11738     xmlNodePtr oldnode;
11739     xmlDocPtr olddoc;
11740     xmlXPathStepOpPtr filterOp;
11741     int oldcs, oldpp;
11742     int i, j, pos;
11743 
11744     if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11745         return;
11746 
11747     xpctxt = ctxt->context;
11748     oldnode = xpctxt->node;
11749     olddoc = xpctxt->doc;
11750     oldcs = xpctxt->contextSize;
11751     oldpp = xpctxt->proximityPosition;
11752     filterOp = &ctxt->comp->steps[filterOpIndex];
11753 
11754     xpctxt->contextSize = locset->locNr;
11755 
11756     for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11757         xmlNodePtr contextNode = locset->locTab[i]->user;
11758         int res;
11759 
11760         xpctxt->node = contextNode;
11761         xpctxt->proximityPosition = i + 1;
11762 
11763         /*
11764         * Also set the xpath document in case things like
11765         * key() are evaluated in the predicate.
11766         *
11767         * TODO: Get real doc for namespace nodes.
11768         */
11769         if ((contextNode->type != XML_NAMESPACE_DECL) &&
11770             (contextNode->doc != NULL))
11771             xpctxt->doc = contextNode->doc;
11772 
11773         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11774 
11775         if (ctxt->error != XPATH_EXPRESSION_OK)
11776             goto exit;
11777         if (res < 0) {
11778             /* Shouldn't happen */
11779             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11780             goto exit;
11781         }
11782 
11783         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11784             if (i != j) {
11785                 locset->locTab[j] = locset->locTab[i];
11786                 locset->locTab[i] = NULL;
11787             }
11788 
11789             j += 1;
11790         } else {
11791             /* Remove the entry from the initial location set. */
11792             xmlXPathFreeObject(locset->locTab[i]);
11793             locset->locTab[i] = NULL;
11794         }
11795 
11796         if (res != 0) {
11797             if (pos == maxPos) {
11798                 /* Clear remaining nodes and exit loop. */
11799                 for (i++; i < locset->locNr; i++) {
11800                     xmlXPathFreeObject(locset->locTab[i]);
11801                 }
11802                 break;
11803             }
11804 
11805             pos += 1;
11806         }
11807     }
11808 
11809     locset->locNr = j;
11810 
11811     /* If too many elements were removed, shrink table to preserve memory. */
11812     if ((locset->locMax > XML_NODESET_DEFAULT) &&
11813         (locset->locNr < locset->locMax / 2)) {
11814         xmlXPathObjectPtr *tmp;
11815         int locMax = locset->locNr;
11816 
11817         if (locMax < XML_NODESET_DEFAULT)
11818             locMax = XML_NODESET_DEFAULT;
11819         tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11820                 locMax * sizeof(xmlXPathObjectPtr));
11821         if (tmp == NULL) {
11822             xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11823         } else {
11824             locset->locTab = tmp;
11825             locset->locMax = locMax;
11826         }
11827     }
11828 
11829 exit:
11830     xpctxt->node = oldnode;
11831     xpctxt->doc = olddoc;
11832     xpctxt->contextSize = oldcs;
11833     xpctxt->proximityPosition = oldpp;
11834 }
11835 #endif /* LIBXML_XPTR_ENABLED */
11836 
11837 /**
11838  * xmlXPathCompOpEvalPredicate:
11839  * @ctxt:  the XPath Parser context
11840  * @op: the predicate op
11841  * @set: the node set to filter
11842  * @minPos: minimum position in the filtered set (1-based)
11843  * @maxPos: maximum position in the filtered set (1-based)
11844  * @hasNsNodes: true if the node set may contain namespace nodes
11845  *
11846  * Filter a node set, keeping only nodes for which the sequence of predicate
11847  * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11848  * in the filtered result.
11849  */
11850 static void
11851 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11852 			    xmlXPathStepOpPtr op,
11853 			    xmlNodeSetPtr set,
11854                             int minPos, int maxPos,
11855 			    int hasNsNodes)
11856 {
11857     if (op->ch1 != -1) {
11858 	xmlXPathCompExprPtr comp = ctxt->comp;
11859 	/*
11860 	* Process inner predicates first.
11861 	*/
11862 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11863             xmlGenericError(xmlGenericErrorContext,
11864                 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11865             XP_ERROR(XPATH_INVALID_OPERAND);
11866 	}
11867         if (ctxt->context->depth >= ctxt->context->maxDepth)
11868             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11869         ctxt->context->depth += 1;
11870 	xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11871                                     1, set->nodeNr, hasNsNodes);
11872         ctxt->context->depth -= 1;
11873 	CHECK_ERROR;
11874     }
11875 
11876     if (op->ch2 != -1)
11877         xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11878 }
11879 
11880 static int
11881 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11882 			    xmlXPathStepOpPtr op,
11883 			    int *maxPos)
11884 {
11885 
11886     xmlXPathStepOpPtr exprOp;
11887 
11888     /*
11889     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11890     */
11891 
11892     /*
11893     * If not -1, then ch1 will point to:
11894     * 1) For predicates (XPATH_OP_PREDICATE):
11895     *    - an inner predicate operator
11896     * 2) For filters (XPATH_OP_FILTER):
11897     *    - an inner filter operator OR
11898     *    - an expression selecting the node set.
11899     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11900     */
11901     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11902 	return(0);
11903 
11904     if (op->ch2 != -1) {
11905 	exprOp = &ctxt->comp->steps[op->ch2];
11906     } else
11907 	return(0);
11908 
11909     if ((exprOp != NULL) &&
11910 	(exprOp->op == XPATH_OP_VALUE) &&
11911 	(exprOp->value4 != NULL) &&
11912 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11913     {
11914         double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11915 
11916 	/*
11917 	* We have a "[n]" predicate here.
11918 	* TODO: Unfortunately this simplistic test here is not
11919 	* able to detect a position() predicate in compound
11920 	* expressions like "[@attr = 'a" and position() = 1],
11921 	* and even not the usage of position() in
11922 	* "[position() = 1]"; thus - obviously - a position-range,
11923 	* like it "[position() < 5]", is also not detected.
11924 	* Maybe we could rewrite the AST to ease the optimization.
11925 	*/
11926 
11927         if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11928 	    *maxPos = (int) floatval;
11929             if (floatval == (double) *maxPos)
11930                 return(1);
11931         }
11932     }
11933     return(0);
11934 }
11935 
11936 static int
11937 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11938                            xmlXPathStepOpPtr op,
11939 			   xmlNodePtr * first, xmlNodePtr * last,
11940 			   int toBool)
11941 {
11942 
11943 #define XP_TEST_HIT \
11944     if (hasAxisRange != 0) { \
11945 	if (++pos == maxPos) { \
11946 	    if (addNode(seq, cur) < 0) \
11947 	        ctxt->error = XPATH_MEMORY_ERROR; \
11948 	    goto axis_range_end; } \
11949     } else { \
11950 	if (addNode(seq, cur) < 0) \
11951 	    ctxt->error = XPATH_MEMORY_ERROR; \
11952 	if (breakOnFirstHit) goto first_hit; }
11953 
11954 #define XP_TEST_HIT_NS \
11955     if (hasAxisRange != 0) { \
11956 	if (++pos == maxPos) { \
11957 	    hasNsNodes = 1; \
11958 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11959 	        ctxt->error = XPATH_MEMORY_ERROR; \
11960 	goto axis_range_end; } \
11961     } else { \
11962 	hasNsNodes = 1; \
11963 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11964 	    ctxt->error = XPATH_MEMORY_ERROR; \
11965 	if (breakOnFirstHit) goto first_hit; }
11966 
11967     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11968     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11969     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11970     const xmlChar *prefix = op->value4;
11971     const xmlChar *name = op->value5;
11972     const xmlChar *URI = NULL;
11973 
11974 #ifdef DEBUG_STEP
11975     int nbMatches = 0, prevMatches = 0;
11976 #endif
11977     int total = 0, hasNsNodes = 0;
11978     /* The popped object holding the context nodes */
11979     xmlXPathObjectPtr obj;
11980     /* The set of context nodes for the node tests */
11981     xmlNodeSetPtr contextSeq;
11982     int contextIdx;
11983     xmlNodePtr contextNode;
11984     /* The final resulting node set wrt to all context nodes */
11985     xmlNodeSetPtr outSeq;
11986     /*
11987     * The temporary resulting node set wrt 1 context node.
11988     * Used to feed predicate evaluation.
11989     */
11990     xmlNodeSetPtr seq;
11991     xmlNodePtr cur;
11992     /* First predicate operator */
11993     xmlXPathStepOpPtr predOp;
11994     int maxPos; /* The requested position() (when a "[n]" predicate) */
11995     int hasPredicateRange, hasAxisRange, pos;
11996     int breakOnFirstHit;
11997 
11998     xmlXPathTraversalFunction next = NULL;
11999     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12000     xmlXPathNodeSetMergeFunction mergeAndClear;
12001     xmlNodePtr oldContextNode;
12002     xmlXPathContextPtr xpctxt = ctxt->context;
12003 
12004 
12005     CHECK_TYPE0(XPATH_NODESET);
12006     obj = valuePop(ctxt);
12007     /*
12008     * Setup namespaces.
12009     */
12010     if (prefix != NULL) {
12011         URI = xmlXPathNsLookup(xpctxt, prefix);
12012         if (URI == NULL) {
12013 	    xmlXPathReleaseObject(xpctxt, obj);
12014             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12015 	}
12016     }
12017     /*
12018     * Setup axis.
12019     *
12020     * MAYBE FUTURE TODO: merging optimizations:
12021     * - If the nodes to be traversed wrt to the initial nodes and
12022     *   the current axis cannot overlap, then we could avoid searching
12023     *   for duplicates during the merge.
12024     *   But the question is how/when to evaluate if they cannot overlap.
12025     *   Example: if we know that for two initial nodes, the one is
12026     *   not in the ancestor-or-self axis of the other, then we could safely
12027     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12028     *   the descendant-or-self axis.
12029     */
12030     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12031     switch (axis) {
12032         case AXIS_ANCESTOR:
12033             first = NULL;
12034             next = xmlXPathNextAncestor;
12035             break;
12036         case AXIS_ANCESTOR_OR_SELF:
12037             first = NULL;
12038             next = xmlXPathNextAncestorOrSelf;
12039             break;
12040         case AXIS_ATTRIBUTE:
12041             first = NULL;
12042 	    last = NULL;
12043             next = xmlXPathNextAttribute;
12044 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12045             break;
12046         case AXIS_CHILD:
12047 	    last = NULL;
12048 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12049 		(type == NODE_TYPE_NODE))
12050 	    {
12051 		/*
12052 		* Optimization if an element node type is 'element'.
12053 		*/
12054 		next = xmlXPathNextChildElement;
12055 	    } else
12056 		next = xmlXPathNextChild;
12057 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12058             break;
12059         case AXIS_DESCENDANT:
12060 	    last = NULL;
12061             next = xmlXPathNextDescendant;
12062             break;
12063         case AXIS_DESCENDANT_OR_SELF:
12064 	    last = NULL;
12065             next = xmlXPathNextDescendantOrSelf;
12066             break;
12067         case AXIS_FOLLOWING:
12068 	    last = NULL;
12069             next = xmlXPathNextFollowing;
12070             break;
12071         case AXIS_FOLLOWING_SIBLING:
12072 	    last = NULL;
12073             next = xmlXPathNextFollowingSibling;
12074             break;
12075         case AXIS_NAMESPACE:
12076             first = NULL;
12077 	    last = NULL;
12078             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12079 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12080             break;
12081         case AXIS_PARENT:
12082             first = NULL;
12083             next = xmlXPathNextParent;
12084             break;
12085         case AXIS_PRECEDING:
12086             first = NULL;
12087             next = xmlXPathNextPrecedingInternal;
12088             break;
12089         case AXIS_PRECEDING_SIBLING:
12090             first = NULL;
12091             next = xmlXPathNextPrecedingSibling;
12092             break;
12093         case AXIS_SELF:
12094             first = NULL;
12095 	    last = NULL;
12096             next = xmlXPathNextSelf;
12097 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12098             break;
12099     }
12100 
12101 #ifdef DEBUG_STEP
12102     xmlXPathDebugDumpStepAxis(op,
12103 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12104 #endif
12105 
12106     if (next == NULL) {
12107 	xmlXPathReleaseObject(xpctxt, obj);
12108         return(0);
12109     }
12110     contextSeq = obj->nodesetval;
12111     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12112 	xmlXPathReleaseObject(xpctxt, obj);
12113         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12114         return(0);
12115     }
12116     /*
12117     * Predicate optimization ---------------------------------------------
12118     * If this step has a last predicate, which contains a position(),
12119     * then we'll optimize (although not exactly "position()", but only
12120     * the  short-hand form, i.e., "[n]".
12121     *
12122     * Example - expression "/foo[parent::bar][1]":
12123     *
12124     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12125     *   ROOT                               -- op->ch1
12126     *   PREDICATE                          -- op->ch2 (predOp)
12127     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12128     *       SORT
12129     *         COLLECT  'parent' 'name' 'node' bar
12130     *           NODE
12131     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12132     *
12133     */
12134     maxPos = 0;
12135     predOp = NULL;
12136     hasPredicateRange = 0;
12137     hasAxisRange = 0;
12138     if (op->ch2 != -1) {
12139 	/*
12140 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12141 	*/
12142 	predOp = &ctxt->comp->steps[op->ch2];
12143 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12144 	    if (predOp->ch1 != -1) {
12145 		/*
12146 		* Use the next inner predicate operator.
12147 		*/
12148 		predOp = &ctxt->comp->steps[predOp->ch1];
12149 		hasPredicateRange = 1;
12150 	    } else {
12151 		/*
12152 		* There's no other predicate than the [n] predicate.
12153 		*/
12154 		predOp = NULL;
12155 		hasAxisRange = 1;
12156 	    }
12157 	}
12158     }
12159     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12160     /*
12161     * Axis traversal -----------------------------------------------------
12162     */
12163     /*
12164      * 2.3 Node Tests
12165      *  - For the attribute axis, the principal node type is attribute.
12166      *  - For the namespace axis, the principal node type is namespace.
12167      *  - For other axes, the principal node type is element.
12168      *
12169      * A node test * is true for any node of the
12170      * principal node type. For example, child::* will
12171      * select all element children of the context node
12172      */
12173     oldContextNode = xpctxt->node;
12174     addNode = xmlXPathNodeSetAddUnique;
12175     outSeq = NULL;
12176     seq = NULL;
12177     contextNode = NULL;
12178     contextIdx = 0;
12179 
12180 
12181     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12182            (ctxt->error == XPATH_EXPRESSION_OK)) {
12183 	xpctxt->node = contextSeq->nodeTab[contextIdx++];
12184 
12185 	if (seq == NULL) {
12186 	    seq = xmlXPathNodeSetCreate(NULL);
12187 	    if (seq == NULL) {
12188                 /* TODO: Propagate memory error. */
12189 		total = 0;
12190 		goto error;
12191 	    }
12192 	}
12193 	/*
12194 	* Traverse the axis and test the nodes.
12195 	*/
12196 	pos = 0;
12197 	cur = NULL;
12198 	hasNsNodes = 0;
12199         do {
12200             if (OP_LIMIT_EXCEEDED(ctxt, 1))
12201                 goto error;
12202 
12203             cur = next(ctxt, cur);
12204             if (cur == NULL)
12205                 break;
12206 
12207 	    /*
12208 	    * QUESTION TODO: What does the "first" and "last" stuff do?
12209 	    */
12210             if ((first != NULL) && (*first != NULL)) {
12211 		if (*first == cur)
12212 		    break;
12213 		if (((total % 256) == 0) &&
12214 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12215 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12216 #else
12217 		    (xmlXPathCmpNodes(*first, cur) >= 0))
12218 #endif
12219 		{
12220 		    break;
12221 		}
12222 	    }
12223 	    if ((last != NULL) && (*last != NULL)) {
12224 		if (*last == cur)
12225 		    break;
12226 		if (((total % 256) == 0) &&
12227 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12228 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12229 #else
12230 		    (xmlXPathCmpNodes(cur, *last) >= 0))
12231 #endif
12232 		{
12233 		    break;
12234 		}
12235 	    }
12236 
12237             total++;
12238 
12239 #ifdef DEBUG_STEP
12240             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12241 #endif
12242 
12243 	    switch (test) {
12244                 case NODE_TEST_NONE:
12245 		    total = 0;
12246                     STRANGE
12247 		    goto error;
12248                 case NODE_TEST_TYPE:
12249 		    if (type == NODE_TYPE_NODE) {
12250 			switch (cur->type) {
12251 			    case XML_DOCUMENT_NODE:
12252 			    case XML_HTML_DOCUMENT_NODE:
12253 #ifdef LIBXML_DOCB_ENABLED
12254 			    case XML_DOCB_DOCUMENT_NODE:
12255 #endif
12256 			    case XML_ELEMENT_NODE:
12257 			    case XML_ATTRIBUTE_NODE:
12258 			    case XML_PI_NODE:
12259 			    case XML_COMMENT_NODE:
12260 			    case XML_CDATA_SECTION_NODE:
12261 			    case XML_TEXT_NODE:
12262 				XP_TEST_HIT
12263 				break;
12264 			    case XML_NAMESPACE_DECL: {
12265 				if (axis == AXIS_NAMESPACE) {
12266 				    XP_TEST_HIT_NS
12267 				} else {
12268 	                            hasNsNodes = 1;
12269 				    XP_TEST_HIT
12270 				}
12271 				break;
12272                             }
12273 			    default:
12274 				break;
12275 			}
12276 		    } else if (cur->type == (xmlElementType) type) {
12277 			if (cur->type == XML_NAMESPACE_DECL)
12278 			    XP_TEST_HIT_NS
12279 			else
12280 			    XP_TEST_HIT
12281 		    } else if ((type == NODE_TYPE_TEXT) &&
12282 			 (cur->type == XML_CDATA_SECTION_NODE))
12283 		    {
12284 			XP_TEST_HIT
12285 		    }
12286 		    break;
12287                 case NODE_TEST_PI:
12288                     if ((cur->type == XML_PI_NODE) &&
12289                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12290 		    {
12291 			XP_TEST_HIT
12292                     }
12293                     break;
12294                 case NODE_TEST_ALL:
12295                     if (axis == AXIS_ATTRIBUTE) {
12296                         if (cur->type == XML_ATTRIBUTE_NODE)
12297 			{
12298                             if (prefix == NULL)
12299 			    {
12300 				XP_TEST_HIT
12301                             } else if ((cur->ns != NULL) &&
12302 				(xmlStrEqual(URI, cur->ns->href)))
12303 			    {
12304 				XP_TEST_HIT
12305                             }
12306                         }
12307                     } else if (axis == AXIS_NAMESPACE) {
12308                         if (cur->type == XML_NAMESPACE_DECL)
12309 			{
12310 			    XP_TEST_HIT_NS
12311                         }
12312                     } else {
12313                         if (cur->type == XML_ELEMENT_NODE) {
12314                             if (prefix == NULL)
12315 			    {
12316 				XP_TEST_HIT
12317 
12318                             } else if ((cur->ns != NULL) &&
12319 				(xmlStrEqual(URI, cur->ns->href)))
12320 			    {
12321 				XP_TEST_HIT
12322                             }
12323                         }
12324                     }
12325                     break;
12326                 case NODE_TEST_NS:{
12327                         TODO;
12328                         break;
12329                     }
12330                 case NODE_TEST_NAME:
12331                     if (axis == AXIS_ATTRIBUTE) {
12332                         if (cur->type != XML_ATTRIBUTE_NODE)
12333 			    break;
12334 		    } else if (axis == AXIS_NAMESPACE) {
12335                         if (cur->type != XML_NAMESPACE_DECL)
12336 			    break;
12337 		    } else {
12338 		        if (cur->type != XML_ELEMENT_NODE)
12339 			    break;
12340 		    }
12341                     switch (cur->type) {
12342                         case XML_ELEMENT_NODE:
12343                             if (xmlStrEqual(name, cur->name)) {
12344                                 if (prefix == NULL) {
12345                                     if (cur->ns == NULL)
12346 				    {
12347 					XP_TEST_HIT
12348                                     }
12349                                 } else {
12350                                     if ((cur->ns != NULL) &&
12351                                         (xmlStrEqual(URI, cur->ns->href)))
12352 				    {
12353 					XP_TEST_HIT
12354                                     }
12355                                 }
12356                             }
12357                             break;
12358                         case XML_ATTRIBUTE_NODE:{
12359                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12360 
12361                                 if (xmlStrEqual(name, attr->name)) {
12362                                     if (prefix == NULL) {
12363                                         if ((attr->ns == NULL) ||
12364                                             (attr->ns->prefix == NULL))
12365 					{
12366 					    XP_TEST_HIT
12367                                         }
12368                                     } else {
12369                                         if ((attr->ns != NULL) &&
12370                                             (xmlStrEqual(URI,
12371 					      attr->ns->href)))
12372 					{
12373 					    XP_TEST_HIT
12374                                         }
12375                                     }
12376                                 }
12377                                 break;
12378                             }
12379                         case XML_NAMESPACE_DECL:
12380                             if (cur->type == XML_NAMESPACE_DECL) {
12381                                 xmlNsPtr ns = (xmlNsPtr) cur;
12382 
12383                                 if ((ns->prefix != NULL) && (name != NULL)
12384                                     && (xmlStrEqual(ns->prefix, name)))
12385 				{
12386 				    XP_TEST_HIT_NS
12387                                 }
12388                             }
12389                             break;
12390                         default:
12391                             break;
12392                     }
12393                     break;
12394 	    } /* switch(test) */
12395         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12396 
12397 	goto apply_predicates;
12398 
12399 axis_range_end: /* ----------------------------------------------------- */
12400 	/*
12401 	* We have a "/foo[n]", and position() = n was reached.
12402 	* Note that we can have as well "/foo/::parent::foo[1]", so
12403 	* a duplicate-aware merge is still needed.
12404 	* Merge with the result.
12405 	*/
12406 	if (outSeq == NULL) {
12407 	    outSeq = seq;
12408 	    seq = NULL;
12409 	} else
12410             /* TODO: Check memory error. */
12411 	    outSeq = mergeAndClear(outSeq, seq);
12412 	/*
12413 	* Break if only a true/false result was requested.
12414 	*/
12415 	if (toBool)
12416 	    break;
12417 	continue;
12418 
12419 first_hit: /* ---------------------------------------------------------- */
12420 	/*
12421 	* Break if only a true/false result was requested and
12422 	* no predicates existed and a node test succeeded.
12423 	*/
12424 	if (outSeq == NULL) {
12425 	    outSeq = seq;
12426 	    seq = NULL;
12427 	} else
12428             /* TODO: Check memory error. */
12429 	    outSeq = mergeAndClear(outSeq, seq);
12430 	break;
12431 
12432 #ifdef DEBUG_STEP
12433 	if (seq != NULL)
12434 	    nbMatches += seq->nodeNr;
12435 #endif
12436 
12437 apply_predicates: /* --------------------------------------------------- */
12438         if (ctxt->error != XPATH_EXPRESSION_OK)
12439 	    goto error;
12440 
12441         /*
12442 	* Apply predicates.
12443 	*/
12444         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12445 	    /*
12446 	    * E.g. when we have a "/foo[some expression][n]".
12447 	    */
12448 	    /*
12449 	    * QUESTION TODO: The old predicate evaluation took into
12450 	    *  account location-sets.
12451 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12452 	    *  Do we expect such a set here?
12453 	    *  All what I learned now from the evaluation semantics
12454 	    *  does not indicate that a location-set will be processed
12455 	    *  here, so this looks OK.
12456 	    */
12457 	    /*
12458 	    * Iterate over all predicates, starting with the outermost
12459 	    * predicate.
12460 	    * TODO: Problem: we cannot execute the inner predicates first
12461 	    *  since we cannot go back *up* the operator tree!
12462 	    *  Options we have:
12463 	    *  1) Use of recursive functions (like is it currently done
12464 	    *     via xmlXPathCompOpEval())
12465 	    *  2) Add a predicate evaluation information stack to the
12466 	    *     context struct
12467 	    *  3) Change the way the operators are linked; we need a
12468 	    *     "parent" field on xmlXPathStepOp
12469 	    *
12470 	    * For the moment, I'll try to solve this with a recursive
12471 	    * function: xmlXPathCompOpEvalPredicate().
12472 	    */
12473 	    if (hasPredicateRange != 0)
12474 		xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12475 					    hasNsNodes);
12476 	    else
12477 		xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12478 					    hasNsNodes);
12479 
12480 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12481 		total = 0;
12482 		goto error;
12483 	    }
12484         }
12485 
12486         if (seq->nodeNr > 0) {
12487 	    /*
12488 	    * Add to result set.
12489 	    */
12490 	    if (outSeq == NULL) {
12491 		outSeq = seq;
12492 		seq = NULL;
12493 	    } else {
12494                 /* TODO: Check memory error. */
12495 		outSeq = mergeAndClear(outSeq, seq);
12496 	    }
12497 
12498             if (toBool)
12499                 break;
12500 	}
12501     }
12502 
12503 error:
12504     if ((obj->boolval) && (obj->user != NULL)) {
12505 	/*
12506 	* QUESTION TODO: What does this do and why?
12507 	* TODO: Do we have to do this also for the "error"
12508 	* cleanup further down?
12509 	*/
12510 	ctxt->value->boolval = 1;
12511 	ctxt->value->user = obj->user;
12512 	obj->user = NULL;
12513 	obj->boolval = 0;
12514     }
12515     xmlXPathReleaseObject(xpctxt, obj);
12516 
12517     /*
12518     * Ensure we return at least an empty set.
12519     */
12520     if (outSeq == NULL) {
12521 	if ((seq != NULL) && (seq->nodeNr == 0))
12522 	    outSeq = seq;
12523 	else
12524             /* TODO: Check memory error. */
12525 	    outSeq = xmlXPathNodeSetCreate(NULL);
12526     }
12527     if ((seq != NULL) && (seq != outSeq)) {
12528 	 xmlXPathFreeNodeSet(seq);
12529     }
12530     /*
12531     * Hand over the result. Better to push the set also in
12532     * case of errors.
12533     */
12534     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12535     /*
12536     * Reset the context node.
12537     */
12538     xpctxt->node = oldContextNode;
12539     /*
12540     * When traversing the namespace axis in "toBool" mode, it's
12541     * possible that tmpNsList wasn't freed.
12542     */
12543     if (xpctxt->tmpNsList != NULL) {
12544         xmlFree(xpctxt->tmpNsList);
12545         xpctxt->tmpNsList = NULL;
12546     }
12547 
12548 #ifdef DEBUG_STEP
12549     xmlGenericError(xmlGenericErrorContext,
12550 	"\nExamined %d nodes, found %d nodes at that step\n",
12551 	total, nbMatches);
12552 #endif
12553 
12554     return(total);
12555 }
12556 
12557 static int
12558 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12559 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12560 
12561 /**
12562  * xmlXPathCompOpEvalFirst:
12563  * @ctxt:  the XPath parser context with the compiled expression
12564  * @op:  an XPath compiled operation
12565  * @first:  the first elem found so far
12566  *
12567  * Evaluate the Precompiled XPath operation searching only the first
12568  * element in document order
12569  *
12570  * Returns the number of examined objects.
12571  */
12572 static int
12573 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12574                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12575 {
12576     int total = 0, cur;
12577     xmlXPathCompExprPtr comp;
12578     xmlXPathObjectPtr arg1, arg2;
12579 
12580     CHECK_ERROR0;
12581     if (OP_LIMIT_EXCEEDED(ctxt, 1))
12582         return(0);
12583     if (ctxt->context->depth >= ctxt->context->maxDepth)
12584         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12585     ctxt->context->depth += 1;
12586     comp = ctxt->comp;
12587     switch (op->op) {
12588         case XPATH_OP_END:
12589             break;
12590         case XPATH_OP_UNION:
12591             total =
12592                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12593                                         first);
12594 	    CHECK_ERROR0;
12595             if ((ctxt->value != NULL)
12596                 && (ctxt->value->type == XPATH_NODESET)
12597                 && (ctxt->value->nodesetval != NULL)
12598                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12599                 /*
12600                  * limit tree traversing to first node in the result
12601                  */
12602 		/*
12603 		* OPTIMIZE TODO: This implicitly sorts
12604 		*  the result, even if not needed. E.g. if the argument
12605 		*  of the count() function, no sorting is needed.
12606 		* OPTIMIZE TODO: How do we know if the node-list wasn't
12607 		*  already sorted?
12608 		*/
12609 		if (ctxt->value->nodesetval->nodeNr > 1)
12610 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12611                 *first = ctxt->value->nodesetval->nodeTab[0];
12612             }
12613             cur =
12614                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12615                                         first);
12616 	    CHECK_ERROR0;
12617 
12618             arg2 = valuePop(ctxt);
12619             arg1 = valuePop(ctxt);
12620             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12621                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12622 	        xmlXPathReleaseObject(ctxt->context, arg1);
12623 	        xmlXPathReleaseObject(ctxt->context, arg2);
12624                 XP_ERROR0(XPATH_INVALID_TYPE);
12625             }
12626             if ((ctxt->context->opLimit != 0) &&
12627                 (((arg1->nodesetval != NULL) &&
12628                   (xmlXPathCheckOpLimit(ctxt,
12629                                         arg1->nodesetval->nodeNr) < 0)) ||
12630                  ((arg2->nodesetval != NULL) &&
12631                   (xmlXPathCheckOpLimit(ctxt,
12632                                         arg2->nodesetval->nodeNr) < 0)))) {
12633 	        xmlXPathReleaseObject(ctxt->context, arg1);
12634 	        xmlXPathReleaseObject(ctxt->context, arg2);
12635                 break;
12636             }
12637 
12638             /* TODO: Check memory error. */
12639             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12640                                                     arg2->nodesetval);
12641             valuePush(ctxt, arg1);
12642 	    xmlXPathReleaseObject(ctxt->context, arg2);
12643             /* optimizer */
12644 	    if (total > cur)
12645 		xmlXPathCompSwap(op);
12646             total += cur;
12647             break;
12648         case XPATH_OP_ROOT:
12649             xmlXPathRoot(ctxt);
12650             break;
12651         case XPATH_OP_NODE:
12652             if (op->ch1 != -1)
12653                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12654 	    CHECK_ERROR0;
12655             if (op->ch2 != -1)
12656                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12657 	    CHECK_ERROR0;
12658 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12659 		ctxt->context->node));
12660             break;
12661         case XPATH_OP_COLLECT:{
12662                 if (op->ch1 == -1)
12663                     break;
12664 
12665                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12666 		CHECK_ERROR0;
12667 
12668                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12669                 break;
12670             }
12671         case XPATH_OP_VALUE:
12672             valuePush(ctxt,
12673                       xmlXPathCacheObjectCopy(ctxt->context,
12674 			(xmlXPathObjectPtr) op->value4));
12675             break;
12676         case XPATH_OP_SORT:
12677             if (op->ch1 != -1)
12678                 total +=
12679                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12680                                             first);
12681 	    CHECK_ERROR0;
12682             if ((ctxt->value != NULL)
12683                 && (ctxt->value->type == XPATH_NODESET)
12684                 && (ctxt->value->nodesetval != NULL)
12685 		&& (ctxt->value->nodesetval->nodeNr > 1))
12686                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12687             break;
12688 #ifdef XP_OPTIMIZED_FILTER_FIRST
12689 	case XPATH_OP_FILTER:
12690                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12691             break;
12692 #endif
12693         default:
12694             total += xmlXPathCompOpEval(ctxt, op);
12695             break;
12696     }
12697 
12698     ctxt->context->depth -= 1;
12699     return(total);
12700 }
12701 
12702 /**
12703  * xmlXPathCompOpEvalLast:
12704  * @ctxt:  the XPath parser context with the compiled expression
12705  * @op:  an XPath compiled operation
12706  * @last:  the last elem found so far
12707  *
12708  * Evaluate the Precompiled XPath operation searching only the last
12709  * element in document order
12710  *
12711  * Returns the number of nodes traversed
12712  */
12713 static int
12714 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12715                        xmlNodePtr * last)
12716 {
12717     int total = 0, cur;
12718     xmlXPathCompExprPtr comp;
12719     xmlXPathObjectPtr arg1, arg2;
12720 
12721     CHECK_ERROR0;
12722     if (OP_LIMIT_EXCEEDED(ctxt, 1))
12723         return(0);
12724     if (ctxt->context->depth >= ctxt->context->maxDepth)
12725         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12726     ctxt->context->depth += 1;
12727     comp = ctxt->comp;
12728     switch (op->op) {
12729         case XPATH_OP_END:
12730             break;
12731         case XPATH_OP_UNION:
12732             total =
12733                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12734 	    CHECK_ERROR0;
12735             if ((ctxt->value != NULL)
12736                 && (ctxt->value->type == XPATH_NODESET)
12737                 && (ctxt->value->nodesetval != NULL)
12738                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12739                 /*
12740                  * limit tree traversing to first node in the result
12741                  */
12742 		if (ctxt->value->nodesetval->nodeNr > 1)
12743 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12744                 *last =
12745                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12746                                                      nodesetval->nodeNr -
12747                                                      1];
12748             }
12749             cur =
12750                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12751 	    CHECK_ERROR0;
12752             if ((ctxt->value != NULL)
12753                 && (ctxt->value->type == XPATH_NODESET)
12754                 && (ctxt->value->nodesetval != NULL)
12755                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12756             }
12757 
12758             arg2 = valuePop(ctxt);
12759             arg1 = valuePop(ctxt);
12760             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12761                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12762 	        xmlXPathReleaseObject(ctxt->context, arg1);
12763 	        xmlXPathReleaseObject(ctxt->context, arg2);
12764                 XP_ERROR0(XPATH_INVALID_TYPE);
12765             }
12766             if ((ctxt->context->opLimit != 0) &&
12767                 (((arg1->nodesetval != NULL) &&
12768                   (xmlXPathCheckOpLimit(ctxt,
12769                                         arg1->nodesetval->nodeNr) < 0)) ||
12770                  ((arg2->nodesetval != NULL) &&
12771                   (xmlXPathCheckOpLimit(ctxt,
12772                                         arg2->nodesetval->nodeNr) < 0)))) {
12773 	        xmlXPathReleaseObject(ctxt->context, arg1);
12774 	        xmlXPathReleaseObject(ctxt->context, arg2);
12775                 break;
12776             }
12777 
12778             /* TODO: Check memory error. */
12779             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12780                                                     arg2->nodesetval);
12781             valuePush(ctxt, arg1);
12782 	    xmlXPathReleaseObject(ctxt->context, arg2);
12783             /* optimizer */
12784 	    if (total > cur)
12785 		xmlXPathCompSwap(op);
12786             total += cur;
12787             break;
12788         case XPATH_OP_ROOT:
12789             xmlXPathRoot(ctxt);
12790             break;
12791         case XPATH_OP_NODE:
12792             if (op->ch1 != -1)
12793                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12794 	    CHECK_ERROR0;
12795             if (op->ch2 != -1)
12796                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12797 	    CHECK_ERROR0;
12798 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12799 		ctxt->context->node));
12800             break;
12801         case XPATH_OP_COLLECT:{
12802                 if (op->ch1 == -1)
12803                     break;
12804 
12805                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12806 		CHECK_ERROR0;
12807 
12808                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12809                 break;
12810             }
12811         case XPATH_OP_VALUE:
12812             valuePush(ctxt,
12813                       xmlXPathCacheObjectCopy(ctxt->context,
12814 			(xmlXPathObjectPtr) op->value4));
12815             break;
12816         case XPATH_OP_SORT:
12817             if (op->ch1 != -1)
12818                 total +=
12819                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12820                                            last);
12821 	    CHECK_ERROR0;
12822             if ((ctxt->value != NULL)
12823                 && (ctxt->value->type == XPATH_NODESET)
12824                 && (ctxt->value->nodesetval != NULL)
12825 		&& (ctxt->value->nodesetval->nodeNr > 1))
12826                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12827             break;
12828         default:
12829             total += xmlXPathCompOpEval(ctxt, op);
12830             break;
12831     }
12832 
12833     ctxt->context->depth -= 1;
12834     return (total);
12835 }
12836 
12837 #ifdef XP_OPTIMIZED_FILTER_FIRST
12838 static int
12839 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12840 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12841 {
12842     int total = 0;
12843     xmlXPathCompExprPtr comp;
12844     xmlNodeSetPtr set;
12845 
12846     CHECK_ERROR0;
12847     comp = ctxt->comp;
12848     /*
12849     * Optimization for ()[last()] selection i.e. the last elem
12850     */
12851     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12852 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12853 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12854 	int f = comp->steps[op->ch2].ch1;
12855 
12856 	if ((f != -1) &&
12857 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12858 	    (comp->steps[f].value5 == NULL) &&
12859 	    (comp->steps[f].value == 0) &&
12860 	    (comp->steps[f].value4 != NULL) &&
12861 	    (xmlStrEqual
12862 	    (comp->steps[f].value4, BAD_CAST "last"))) {
12863 	    xmlNodePtr last = NULL;
12864 
12865 	    total +=
12866 		xmlXPathCompOpEvalLast(ctxt,
12867 		    &comp->steps[op->ch1],
12868 		    &last);
12869 	    CHECK_ERROR0;
12870 	    /*
12871 	    * The nodeset should be in document order,
12872 	    * Keep only the last value
12873 	    */
12874 	    if ((ctxt->value != NULL) &&
12875 		(ctxt->value->type == XPATH_NODESET) &&
12876 		(ctxt->value->nodesetval != NULL) &&
12877 		(ctxt->value->nodesetval->nodeTab != NULL) &&
12878 		(ctxt->value->nodesetval->nodeNr > 1)) {
12879                 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12880 		*first = *(ctxt->value->nodesetval->nodeTab);
12881 	    }
12882 	    return (total);
12883 	}
12884     }
12885 
12886     if (op->ch1 != -1)
12887 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12888     CHECK_ERROR0;
12889     if (op->ch2 == -1)
12890 	return (total);
12891     if (ctxt->value == NULL)
12892 	return (total);
12893 
12894 #ifdef LIBXML_XPTR_ENABLED
12895     /*
12896     * Hum are we filtering the result of an XPointer expression
12897     */
12898     if (ctxt->value->type == XPATH_LOCATIONSET) {
12899         xmlLocationSetPtr locset = ctxt->value->user;
12900 
12901         if (locset != NULL) {
12902             xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12903             if (locset->locNr > 0)
12904                 *first = (xmlNodePtr) locset->locTab[0]->user;
12905         }
12906 
12907 	return (total);
12908     }
12909 #endif /* LIBXML_XPTR_ENABLED */
12910 
12911     CHECK_TYPE0(XPATH_NODESET);
12912     set = ctxt->value->nodesetval;
12913     if (set != NULL) {
12914         xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12915         if (set->nodeNr > 0)
12916             *first = set->nodeTab[0];
12917     }
12918 
12919     return (total);
12920 }
12921 #endif /* XP_OPTIMIZED_FILTER_FIRST */
12922 
12923 /**
12924  * xmlXPathCompOpEval:
12925  * @ctxt:  the XPath parser context with the compiled expression
12926  * @op:  an XPath compiled operation
12927  *
12928  * Evaluate the Precompiled XPath operation
12929  * Returns the number of nodes traversed
12930  */
12931 static int
12932 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12933 {
12934     int total = 0;
12935     int equal, ret;
12936     xmlXPathCompExprPtr comp;
12937     xmlXPathObjectPtr arg1, arg2;
12938 
12939     CHECK_ERROR0;
12940     if (OP_LIMIT_EXCEEDED(ctxt, 1))
12941         return(0);
12942     if (ctxt->context->depth >= ctxt->context->maxDepth)
12943         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12944     ctxt->context->depth += 1;
12945     comp = ctxt->comp;
12946     switch (op->op) {
12947         case XPATH_OP_END:
12948             break;
12949         case XPATH_OP_AND:
12950             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12951 	    CHECK_ERROR0;
12952             xmlXPathBooleanFunction(ctxt, 1);
12953             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12954                 break;
12955             arg2 = valuePop(ctxt);
12956             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12957 	    if (ctxt->error) {
12958 		xmlXPathFreeObject(arg2);
12959 		break;
12960 	    }
12961             xmlXPathBooleanFunction(ctxt, 1);
12962             if (ctxt->value != NULL)
12963                 ctxt->value->boolval &= arg2->boolval;
12964 	    xmlXPathReleaseObject(ctxt->context, arg2);
12965             break;
12966         case XPATH_OP_OR:
12967             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12968 	    CHECK_ERROR0;
12969             xmlXPathBooleanFunction(ctxt, 1);
12970             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12971                 break;
12972             arg2 = valuePop(ctxt);
12973             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12974 	    if (ctxt->error) {
12975 		xmlXPathFreeObject(arg2);
12976 		break;
12977 	    }
12978             xmlXPathBooleanFunction(ctxt, 1);
12979             if (ctxt->value != NULL)
12980                 ctxt->value->boolval |= arg2->boolval;
12981 	    xmlXPathReleaseObject(ctxt->context, arg2);
12982             break;
12983         case XPATH_OP_EQUAL:
12984             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12985 	    CHECK_ERROR0;
12986             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12987 	    CHECK_ERROR0;
12988 	    if (op->value)
12989 		equal = xmlXPathEqualValues(ctxt);
12990 	    else
12991 		equal = xmlXPathNotEqualValues(ctxt);
12992 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
12993             break;
12994         case XPATH_OP_CMP:
12995             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12996 	    CHECK_ERROR0;
12997             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12998 	    CHECK_ERROR0;
12999             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13000 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13001             break;
13002         case XPATH_OP_PLUS:
13003             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13004 	    CHECK_ERROR0;
13005             if (op->ch2 != -1) {
13006                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13007 	    }
13008 	    CHECK_ERROR0;
13009             if (op->value == 0)
13010                 xmlXPathSubValues(ctxt);
13011             else if (op->value == 1)
13012                 xmlXPathAddValues(ctxt);
13013             else if (op->value == 2)
13014                 xmlXPathValueFlipSign(ctxt);
13015             else if (op->value == 3) {
13016                 CAST_TO_NUMBER;
13017                 CHECK_TYPE0(XPATH_NUMBER);
13018             }
13019             break;
13020         case XPATH_OP_MULT:
13021             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13022 	    CHECK_ERROR0;
13023             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13024 	    CHECK_ERROR0;
13025             if (op->value == 0)
13026                 xmlXPathMultValues(ctxt);
13027             else if (op->value == 1)
13028                 xmlXPathDivValues(ctxt);
13029             else if (op->value == 2)
13030                 xmlXPathModValues(ctxt);
13031             break;
13032         case XPATH_OP_UNION:
13033             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13034 	    CHECK_ERROR0;
13035             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13036 	    CHECK_ERROR0;
13037 
13038             arg2 = valuePop(ctxt);
13039             arg1 = valuePop(ctxt);
13040             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13041                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13042 	        xmlXPathReleaseObject(ctxt->context, arg1);
13043 	        xmlXPathReleaseObject(ctxt->context, arg2);
13044                 XP_ERROR0(XPATH_INVALID_TYPE);
13045             }
13046             if ((ctxt->context->opLimit != 0) &&
13047                 (((arg1->nodesetval != NULL) &&
13048                   (xmlXPathCheckOpLimit(ctxt,
13049                                         arg1->nodesetval->nodeNr) < 0)) ||
13050                  ((arg2->nodesetval != NULL) &&
13051                   (xmlXPathCheckOpLimit(ctxt,
13052                                         arg2->nodesetval->nodeNr) < 0)))) {
13053 	        xmlXPathReleaseObject(ctxt->context, arg1);
13054 	        xmlXPathReleaseObject(ctxt->context, arg2);
13055                 break;
13056             }
13057 
13058 	    if ((arg1->nodesetval == NULL) ||
13059 		((arg2->nodesetval != NULL) &&
13060 		 (arg2->nodesetval->nodeNr != 0)))
13061 	    {
13062                 /* TODO: Check memory error. */
13063 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13064 							arg2->nodesetval);
13065 	    }
13066 
13067             valuePush(ctxt, arg1);
13068 	    xmlXPathReleaseObject(ctxt->context, arg2);
13069             break;
13070         case XPATH_OP_ROOT:
13071             xmlXPathRoot(ctxt);
13072             break;
13073         case XPATH_OP_NODE:
13074             if (op->ch1 != -1)
13075                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13076 	    CHECK_ERROR0;
13077             if (op->ch2 != -1)
13078                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13079 	    CHECK_ERROR0;
13080 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13081 		ctxt->context->node));
13082             break;
13083         case XPATH_OP_COLLECT:{
13084                 if (op->ch1 == -1)
13085                     break;
13086 
13087                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13088 		CHECK_ERROR0;
13089 
13090                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13091                 break;
13092             }
13093         case XPATH_OP_VALUE:
13094             valuePush(ctxt,
13095                       xmlXPathCacheObjectCopy(ctxt->context,
13096 			(xmlXPathObjectPtr) op->value4));
13097             break;
13098         case XPATH_OP_VARIABLE:{
13099 		xmlXPathObjectPtr val;
13100 
13101                 if (op->ch1 != -1)
13102                     total +=
13103                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13104                 if (op->value5 == NULL) {
13105 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13106 		    if (val == NULL)
13107 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13108                     valuePush(ctxt, val);
13109 		} else {
13110                     const xmlChar *URI;
13111 
13112                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13113                     if (URI == NULL) {
13114                         xmlGenericError(xmlGenericErrorContext,
13115             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13116                                     (char *) op->value4, (char *)op->value5);
13117                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13118                         break;
13119                     }
13120 		    val = xmlXPathVariableLookupNS(ctxt->context,
13121                                                        op->value4, URI);
13122 		    if (val == NULL)
13123 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13124                     valuePush(ctxt, val);
13125                 }
13126                 break;
13127             }
13128         case XPATH_OP_FUNCTION:{
13129                 xmlXPathFunction func;
13130                 const xmlChar *oldFunc, *oldFuncURI;
13131 		int i;
13132                 int frame;
13133 
13134                 frame = xmlXPathSetFrame(ctxt);
13135                 if (op->ch1 != -1) {
13136                     total +=
13137                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13138                     if (ctxt->error != XPATH_EXPRESSION_OK) {
13139                         xmlXPathPopFrame(ctxt, frame);
13140                         break;
13141                     }
13142                 }
13143 		if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13144 		    xmlGenericError(xmlGenericErrorContext,
13145 			    "xmlXPathCompOpEval: parameter error\n");
13146 		    ctxt->error = XPATH_INVALID_OPERAND;
13147                     xmlXPathPopFrame(ctxt, frame);
13148 		    break;
13149 		}
13150 		for (i = 0; i < op->value; i++) {
13151 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13152 			xmlGenericError(xmlGenericErrorContext,
13153 				"xmlXPathCompOpEval: parameter error\n");
13154 			ctxt->error = XPATH_INVALID_OPERAND;
13155                         xmlXPathPopFrame(ctxt, frame);
13156 			break;
13157 		    }
13158                 }
13159                 if (op->cache != NULL)
13160                     func = op->cache;
13161                 else {
13162                     const xmlChar *URI = NULL;
13163 
13164                     if (op->value5 == NULL)
13165                         func =
13166                             xmlXPathFunctionLookup(ctxt->context,
13167                                                    op->value4);
13168                     else {
13169                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13170                         if (URI == NULL) {
13171                             xmlGenericError(xmlGenericErrorContext,
13172             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13173                                     (char *)op->value4, (char *)op->value5);
13174                             xmlXPathPopFrame(ctxt, frame);
13175                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13176                             break;
13177                         }
13178                         func = xmlXPathFunctionLookupNS(ctxt->context,
13179                                                         op->value4, URI);
13180                     }
13181                     if (func == NULL) {
13182                         xmlGenericError(xmlGenericErrorContext,
13183                                 "xmlXPathCompOpEval: function %s not found\n",
13184                                         (char *)op->value4);
13185                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13186                     }
13187                     op->cache = func;
13188                     op->cacheURI = (void *) URI;
13189                 }
13190                 oldFunc = ctxt->context->function;
13191                 oldFuncURI = ctxt->context->functionURI;
13192                 ctxt->context->function = op->value4;
13193                 ctxt->context->functionURI = op->cacheURI;
13194                 func(ctxt, op->value);
13195                 ctxt->context->function = oldFunc;
13196                 ctxt->context->functionURI = oldFuncURI;
13197                 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13198                     (ctxt->valueNr != ctxt->valueFrame + 1))
13199                     XP_ERROR0(XPATH_STACK_ERROR);
13200                 xmlXPathPopFrame(ctxt, frame);
13201                 break;
13202             }
13203         case XPATH_OP_ARG:
13204             if (op->ch1 != -1) {
13205                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13206 	        CHECK_ERROR0;
13207             }
13208             if (op->ch2 != -1) {
13209                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13210 	        CHECK_ERROR0;
13211 	    }
13212             break;
13213         case XPATH_OP_PREDICATE:
13214         case XPATH_OP_FILTER:{
13215                 xmlNodeSetPtr set;
13216 
13217                 /*
13218                  * Optimization for ()[1] selection i.e. the first elem
13219                  */
13220                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13221 #ifdef XP_OPTIMIZED_FILTER_FIRST
13222 		    /*
13223 		    * FILTER TODO: Can we assume that the inner processing
13224 		    *  will result in an ordered list if we have an
13225 		    *  XPATH_OP_FILTER?
13226 		    *  What about an additional field or flag on
13227 		    *  xmlXPathObject like @sorted ? This way we wouldn't need
13228 		    *  to assume anything, so it would be more robust and
13229 		    *  easier to optimize.
13230 		    */
13231                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13232 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13233 #else
13234 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13235 #endif
13236                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13237                     xmlXPathObjectPtr val;
13238 
13239                     val = comp->steps[op->ch2].value4;
13240                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13241                         (val->floatval == 1.0)) {
13242                         xmlNodePtr first = NULL;
13243 
13244                         total +=
13245                             xmlXPathCompOpEvalFirst(ctxt,
13246                                                     &comp->steps[op->ch1],
13247                                                     &first);
13248 			CHECK_ERROR0;
13249                         /*
13250                          * The nodeset should be in document order,
13251                          * Keep only the first value
13252                          */
13253                         if ((ctxt->value != NULL) &&
13254                             (ctxt->value->type == XPATH_NODESET) &&
13255                             (ctxt->value->nodesetval != NULL) &&
13256                             (ctxt->value->nodesetval->nodeNr > 1))
13257                             xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13258                                                         1, 1);
13259                         break;
13260                     }
13261                 }
13262                 /*
13263                  * Optimization for ()[last()] selection i.e. the last elem
13264                  */
13265                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13266                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13267                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13268                     int f = comp->steps[op->ch2].ch1;
13269 
13270                     if ((f != -1) &&
13271                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13272                         (comp->steps[f].value5 == NULL) &&
13273                         (comp->steps[f].value == 0) &&
13274                         (comp->steps[f].value4 != NULL) &&
13275                         (xmlStrEqual
13276                          (comp->steps[f].value4, BAD_CAST "last"))) {
13277                         xmlNodePtr last = NULL;
13278 
13279                         total +=
13280                             xmlXPathCompOpEvalLast(ctxt,
13281                                                    &comp->steps[op->ch1],
13282                                                    &last);
13283 			CHECK_ERROR0;
13284                         /*
13285                          * The nodeset should be in document order,
13286                          * Keep only the last value
13287                          */
13288                         if ((ctxt->value != NULL) &&
13289                             (ctxt->value->type == XPATH_NODESET) &&
13290                             (ctxt->value->nodesetval != NULL) &&
13291                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13292                             (ctxt->value->nodesetval->nodeNr > 1))
13293                             xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13294                         break;
13295                     }
13296                 }
13297 		/*
13298 		* Process inner predicates first.
13299 		* Example "index[parent::book][1]":
13300 		* ...
13301 		*   PREDICATE   <-- we are here "[1]"
13302 		*     PREDICATE <-- process "[parent::book]" first
13303 		*       SORT
13304 		*         COLLECT  'parent' 'name' 'node' book
13305 		*           NODE
13306 		*     ELEM Object is a number : 1
13307 		*/
13308                 if (op->ch1 != -1)
13309                     total +=
13310                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13311 		CHECK_ERROR0;
13312                 if (op->ch2 == -1)
13313                     break;
13314                 if (ctxt->value == NULL)
13315                     break;
13316 
13317 #ifdef LIBXML_XPTR_ENABLED
13318                 /*
13319                  * Hum are we filtering the result of an XPointer expression
13320                  */
13321                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13322                     xmlLocationSetPtr locset = ctxt->value->user;
13323                     xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13324                                               1, locset->locNr);
13325                     break;
13326                 }
13327 #endif /* LIBXML_XPTR_ENABLED */
13328 
13329                 CHECK_TYPE0(XPATH_NODESET);
13330                 set = ctxt->value->nodesetval;
13331                 if (set != NULL)
13332                     xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13333                                           1, set->nodeNr, 1);
13334                 break;
13335             }
13336         case XPATH_OP_SORT:
13337             if (op->ch1 != -1)
13338                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13339 	    CHECK_ERROR0;
13340             if ((ctxt->value != NULL) &&
13341                 (ctxt->value->type == XPATH_NODESET) &&
13342                 (ctxt->value->nodesetval != NULL) &&
13343 		(ctxt->value->nodesetval->nodeNr > 1))
13344 	    {
13345                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13346 	    }
13347             break;
13348 #ifdef LIBXML_XPTR_ENABLED
13349         case XPATH_OP_RANGETO:{
13350                 xmlXPathObjectPtr range;
13351                 xmlXPathObjectPtr res, obj;
13352                 xmlXPathObjectPtr tmp;
13353                 xmlLocationSetPtr newlocset = NULL;
13354 		    xmlLocationSetPtr oldlocset;
13355                 xmlNodeSetPtr oldset;
13356                 xmlNodePtr oldnode = ctxt->context->node;
13357                 int oldcs = ctxt->context->contextSize;
13358                 int oldpp = ctxt->context->proximityPosition;
13359                 int i, j;
13360 
13361                 if (op->ch1 != -1) {
13362                     total +=
13363                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13364                     CHECK_ERROR0;
13365                 }
13366                 if (ctxt->value == NULL) {
13367                     XP_ERROR0(XPATH_INVALID_OPERAND);
13368                 }
13369                 if (op->ch2 == -1)
13370                     break;
13371 
13372                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13373                     /*
13374                      * Extract the old locset, and then evaluate the result of the
13375                      * expression for all the element in the locset. use it to grow
13376                      * up a new locset.
13377                      */
13378                     CHECK_TYPE0(XPATH_LOCATIONSET);
13379 
13380                     if ((ctxt->value->user == NULL) ||
13381                         (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13382                         break;
13383 
13384                     obj = valuePop(ctxt);
13385                     oldlocset = obj->user;
13386 
13387                     newlocset = xmlXPtrLocationSetCreate(NULL);
13388 
13389                     for (i = 0; i < oldlocset->locNr; i++) {
13390                         /*
13391                          * Run the evaluation with a node list made of a
13392                          * single item in the nodelocset.
13393                          */
13394                         ctxt->context->node = oldlocset->locTab[i]->user;
13395                         ctxt->context->contextSize = oldlocset->locNr;
13396                         ctxt->context->proximityPosition = i + 1;
13397 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13398 			    ctxt->context->node);
13399                         valuePush(ctxt, tmp);
13400 
13401                         if (op->ch2 != -1)
13402                             total +=
13403                                 xmlXPathCompOpEval(ctxt,
13404                                                    &comp->steps[op->ch2]);
13405 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13406                             xmlXPtrFreeLocationSet(newlocset);
13407                             goto rangeto_error;
13408 			}
13409 
13410                         res = valuePop(ctxt);
13411 			if (res->type == XPATH_LOCATIONSET) {
13412 			    xmlLocationSetPtr rloc =
13413 			        (xmlLocationSetPtr)res->user;
13414 			    for (j=0; j<rloc->locNr; j++) {
13415 			        range = xmlXPtrNewRange(
13416 				  oldlocset->locTab[i]->user,
13417 				  oldlocset->locTab[i]->index,
13418 				  rloc->locTab[j]->user2,
13419 				  rloc->locTab[j]->index2);
13420 				if (range != NULL) {
13421 				    xmlXPtrLocationSetAdd(newlocset, range);
13422 				}
13423 			    }
13424 			} else {
13425 			    range = xmlXPtrNewRangeNodeObject(
13426 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
13427                             if (range != NULL) {
13428                                 xmlXPtrLocationSetAdd(newlocset,range);
13429 			    }
13430                         }
13431 
13432                         /*
13433                          * Cleanup
13434                          */
13435                         if (res != NULL) {
13436 			    xmlXPathReleaseObject(ctxt->context, res);
13437 			}
13438                         if (ctxt->value == tmp) {
13439                             res = valuePop(ctxt);
13440 			    xmlXPathReleaseObject(ctxt->context, res);
13441                         }
13442                     }
13443 		} else {	/* Not a location set */
13444                     CHECK_TYPE0(XPATH_NODESET);
13445                     obj = valuePop(ctxt);
13446                     oldset = obj->nodesetval;
13447 
13448                     newlocset = xmlXPtrLocationSetCreate(NULL);
13449 
13450                     if (oldset != NULL) {
13451                         for (i = 0; i < oldset->nodeNr; i++) {
13452                             /*
13453                              * Run the evaluation with a node list made of a single item
13454                              * in the nodeset.
13455                              */
13456                             ctxt->context->node = oldset->nodeTab[i];
13457 			    /*
13458 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
13459 			    */
13460 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13461 				ctxt->context->node);
13462                             valuePush(ctxt, tmp);
13463 
13464                             if (op->ch2 != -1)
13465                                 total +=
13466                                     xmlXPathCompOpEval(ctxt,
13467                                                    &comp->steps[op->ch2]);
13468 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
13469                                 xmlXPtrFreeLocationSet(newlocset);
13470                                 goto rangeto_error;
13471 			    }
13472 
13473                             res = valuePop(ctxt);
13474                             range =
13475                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13476                                                       res);
13477                             if (range != NULL) {
13478                                 xmlXPtrLocationSetAdd(newlocset, range);
13479                             }
13480 
13481                             /*
13482                              * Cleanup
13483                              */
13484                             if (res != NULL) {
13485 				xmlXPathReleaseObject(ctxt->context, res);
13486 			    }
13487                             if (ctxt->value == tmp) {
13488                                 res = valuePop(ctxt);
13489 				xmlXPathReleaseObject(ctxt->context, res);
13490                             }
13491                         }
13492                     }
13493                 }
13494 
13495                 /*
13496                  * The result is used as the new evaluation set.
13497                  */
13498                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13499 rangeto_error:
13500 		xmlXPathReleaseObject(ctxt->context, obj);
13501                 ctxt->context->node = oldnode;
13502                 ctxt->context->contextSize = oldcs;
13503                 ctxt->context->proximityPosition = oldpp;
13504                 break;
13505             }
13506 #endif /* LIBXML_XPTR_ENABLED */
13507         default:
13508             xmlGenericError(xmlGenericErrorContext,
13509                             "XPath: unknown precompiled operation %d\n", op->op);
13510             ctxt->error = XPATH_INVALID_OPERAND;
13511             break;
13512     }
13513 
13514     ctxt->context->depth -= 1;
13515     return (total);
13516 }
13517 
13518 /**
13519  * xmlXPathCompOpEvalToBoolean:
13520  * @ctxt:  the XPath parser context
13521  *
13522  * Evaluates if the expression evaluates to true.
13523  *
13524  * Returns 1 if true, 0 if false and -1 on API or internal errors.
13525  */
13526 static int
13527 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13528 			    xmlXPathStepOpPtr op,
13529 			    int isPredicate)
13530 {
13531     xmlXPathObjectPtr resObj = NULL;
13532 
13533 start:
13534     if (OP_LIMIT_EXCEEDED(ctxt, 1))
13535         return(0);
13536     /* comp = ctxt->comp; */
13537     switch (op->op) {
13538         case XPATH_OP_END:
13539             return (0);
13540 	case XPATH_OP_VALUE:
13541 	    resObj = (xmlXPathObjectPtr) op->value4;
13542 	    if (isPredicate)
13543 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13544 	    return(xmlXPathCastToBoolean(resObj));
13545 	case XPATH_OP_SORT:
13546 	    /*
13547 	    * We don't need sorting for boolean results. Skip this one.
13548 	    */
13549             if (op->ch1 != -1) {
13550 		op = &ctxt->comp->steps[op->ch1];
13551 		goto start;
13552 	    }
13553 	    return(0);
13554 	case XPATH_OP_COLLECT:
13555 	    if (op->ch1 == -1)
13556 		return(0);
13557 
13558             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13559 	    if (ctxt->error != XPATH_EXPRESSION_OK)
13560 		return(-1);
13561 
13562             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13563 	    if (ctxt->error != XPATH_EXPRESSION_OK)
13564 		return(-1);
13565 
13566 	    resObj = valuePop(ctxt);
13567 	    if (resObj == NULL)
13568 		return(-1);
13569 	    break;
13570 	default:
13571 	    /*
13572 	    * Fallback to call xmlXPathCompOpEval().
13573 	    */
13574 	    xmlXPathCompOpEval(ctxt, op);
13575 	    if (ctxt->error != XPATH_EXPRESSION_OK)
13576 		return(-1);
13577 
13578 	    resObj = valuePop(ctxt);
13579 	    if (resObj == NULL)
13580 		return(-1);
13581 	    break;
13582     }
13583 
13584     if (resObj) {
13585 	int res;
13586 
13587 	if (resObj->type == XPATH_BOOLEAN) {
13588 	    res = resObj->boolval;
13589 	} else if (isPredicate) {
13590 	    /*
13591 	    * For predicates a result of type "number" is handled
13592 	    * differently:
13593 	    * SPEC XPath 1.0:
13594 	    * "If the result is a number, the result will be converted
13595 	    *  to true if the number is equal to the context position
13596 	    *  and will be converted to false otherwise;"
13597 	    */
13598 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13599 	} else {
13600 	    res = xmlXPathCastToBoolean(resObj);
13601 	}
13602 	xmlXPathReleaseObject(ctxt->context, resObj);
13603 	return(res);
13604     }
13605 
13606     return(0);
13607 }
13608 
13609 #ifdef XPATH_STREAMING
13610 /**
13611  * xmlXPathRunStreamEval:
13612  * @ctxt:  the XPath parser context with the compiled expression
13613  *
13614  * Evaluate the Precompiled Streamable XPath expression in the given context.
13615  */
13616 static int
13617 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13618 		      xmlXPathObjectPtr *resultSeq, int toBool)
13619 {
13620     int max_depth, min_depth;
13621     int from_root;
13622     int ret, depth;
13623     int eval_all_nodes;
13624     xmlNodePtr cur = NULL, limit = NULL;
13625     xmlStreamCtxtPtr patstream = NULL;
13626 
13627     int nb_nodes = 0;
13628 
13629     if ((ctxt == NULL) || (comp == NULL))
13630         return(-1);
13631     max_depth = xmlPatternMaxDepth(comp);
13632     if (max_depth == -1)
13633         return(-1);
13634     if (max_depth == -2)
13635         max_depth = 10000;
13636     min_depth = xmlPatternMinDepth(comp);
13637     if (min_depth == -1)
13638         return(-1);
13639     from_root = xmlPatternFromRoot(comp);
13640     if (from_root < 0)
13641         return(-1);
13642 #if 0
13643     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13644 #endif
13645 
13646     if (! toBool) {
13647 	if (resultSeq == NULL)
13648 	    return(-1);
13649 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13650 	if (*resultSeq == NULL)
13651 	    return(-1);
13652     }
13653 
13654     /*
13655      * handle the special cases of "/" amd "." being matched
13656      */
13657     if (min_depth == 0) {
13658 	if (from_root) {
13659 	    /* Select "/" */
13660 	    if (toBool)
13661 		return(1);
13662             /* TODO: Check memory error. */
13663 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13664 		                     (xmlNodePtr) ctxt->doc);
13665 	} else {
13666 	    /* Select "self::node()" */
13667 	    if (toBool)
13668 		return(1);
13669             /* TODO: Check memory error. */
13670 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13671 	}
13672     }
13673     if (max_depth == 0) {
13674 	return(0);
13675     }
13676 
13677     if (from_root) {
13678         cur = (xmlNodePtr)ctxt->doc;
13679     } else if (ctxt->node != NULL) {
13680         switch (ctxt->node->type) {
13681             case XML_ELEMENT_NODE:
13682             case XML_DOCUMENT_NODE:
13683             case XML_DOCUMENT_FRAG_NODE:
13684             case XML_HTML_DOCUMENT_NODE:
13685 #ifdef LIBXML_DOCB_ENABLED
13686             case XML_DOCB_DOCUMENT_NODE:
13687 #endif
13688 	        cur = ctxt->node;
13689 		break;
13690             case XML_ATTRIBUTE_NODE:
13691             case XML_TEXT_NODE:
13692             case XML_CDATA_SECTION_NODE:
13693             case XML_ENTITY_REF_NODE:
13694             case XML_ENTITY_NODE:
13695             case XML_PI_NODE:
13696             case XML_COMMENT_NODE:
13697             case XML_NOTATION_NODE:
13698             case XML_DTD_NODE:
13699             case XML_DOCUMENT_TYPE_NODE:
13700             case XML_ELEMENT_DECL:
13701             case XML_ATTRIBUTE_DECL:
13702             case XML_ENTITY_DECL:
13703             case XML_NAMESPACE_DECL:
13704             case XML_XINCLUDE_START:
13705             case XML_XINCLUDE_END:
13706 		break;
13707 	}
13708 	limit = cur;
13709     }
13710     if (cur == NULL) {
13711         return(0);
13712     }
13713 
13714     patstream = xmlPatternGetStreamCtxt(comp);
13715     if (patstream == NULL) {
13716 	/*
13717 	* QUESTION TODO: Is this an error?
13718 	*/
13719 	return(0);
13720     }
13721 
13722     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13723 
13724     if (from_root) {
13725 	ret = xmlStreamPush(patstream, NULL, NULL);
13726 	if (ret < 0) {
13727 	} else if (ret == 1) {
13728 	    if (toBool)
13729 		goto return_1;
13730             /* TODO: Check memory error. */
13731 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13732 	}
13733     }
13734     depth = 0;
13735     goto scan_children;
13736 next_node:
13737     do {
13738         if (ctxt->opLimit != 0) {
13739             if (ctxt->opCount >= ctxt->opLimit) {
13740                 xmlGenericError(xmlGenericErrorContext,
13741                         "XPath operation limit exceeded\n");
13742                 xmlFreeStreamCtxt(patstream);
13743                 return(-1);
13744             }
13745             ctxt->opCount++;
13746         }
13747 
13748         nb_nodes++;
13749 
13750 	switch (cur->type) {
13751 	    case XML_ELEMENT_NODE:
13752 	    case XML_TEXT_NODE:
13753 	    case XML_CDATA_SECTION_NODE:
13754 	    case XML_COMMENT_NODE:
13755 	    case XML_PI_NODE:
13756 		if (cur->type == XML_ELEMENT_NODE) {
13757 		    ret = xmlStreamPush(patstream, cur->name,
13758 				(cur->ns ? cur->ns->href : NULL));
13759 		} else if (eval_all_nodes)
13760 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13761 		else
13762 		    break;
13763 
13764 		if (ret < 0) {
13765 		    /* NOP. */
13766 		} else if (ret == 1) {
13767 		    if (toBool)
13768 			goto return_1;
13769 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13770 		        < 0) {
13771 			ctxt->lastError.domain = XML_FROM_XPATH;
13772 			ctxt->lastError.code = XML_ERR_NO_MEMORY;
13773 		    }
13774 		}
13775 		if ((cur->children == NULL) || (depth >= max_depth)) {
13776 		    ret = xmlStreamPop(patstream);
13777 		    while (cur->next != NULL) {
13778 			cur = cur->next;
13779 			if ((cur->type != XML_ENTITY_DECL) &&
13780 			    (cur->type != XML_DTD_NODE))
13781 			    goto next_node;
13782 		    }
13783 		}
13784 	    default:
13785 		break;
13786 	}
13787 
13788 scan_children:
13789 	if (cur->type == XML_NAMESPACE_DECL) break;
13790 	if ((cur->children != NULL) && (depth < max_depth)) {
13791 	    /*
13792 	     * Do not descend on entities declarations
13793 	     */
13794 	    if (cur->children->type != XML_ENTITY_DECL) {
13795 		cur = cur->children;
13796 		depth++;
13797 		/*
13798 		 * Skip DTDs
13799 		 */
13800 		if (cur->type != XML_DTD_NODE)
13801 		    continue;
13802 	    }
13803 	}
13804 
13805 	if (cur == limit)
13806 	    break;
13807 
13808 	while (cur->next != NULL) {
13809 	    cur = cur->next;
13810 	    if ((cur->type != XML_ENTITY_DECL) &&
13811 		(cur->type != XML_DTD_NODE))
13812 		goto next_node;
13813 	}
13814 
13815 	do {
13816 	    cur = cur->parent;
13817 	    depth--;
13818 	    if ((cur == NULL) || (cur == limit))
13819 	        goto done;
13820 	    if (cur->type == XML_ELEMENT_NODE) {
13821 		ret = xmlStreamPop(patstream);
13822 	    } else if ((eval_all_nodes) &&
13823 		((cur->type == XML_TEXT_NODE) ||
13824 		 (cur->type == XML_CDATA_SECTION_NODE) ||
13825 		 (cur->type == XML_COMMENT_NODE) ||
13826 		 (cur->type == XML_PI_NODE)))
13827 	    {
13828 		ret = xmlStreamPop(patstream);
13829 	    }
13830 	    if (cur->next != NULL) {
13831 		cur = cur->next;
13832 		break;
13833 	    }
13834 	} while (cur != NULL);
13835 
13836     } while ((cur != NULL) && (depth >= 0));
13837 
13838 done:
13839 
13840 #if 0
13841     printf("stream eval: checked %d nodes selected %d\n",
13842            nb_nodes, retObj->nodesetval->nodeNr);
13843 #endif
13844 
13845     if (patstream)
13846 	xmlFreeStreamCtxt(patstream);
13847     return(0);
13848 
13849 return_1:
13850     if (patstream)
13851 	xmlFreeStreamCtxt(patstream);
13852     return(1);
13853 }
13854 #endif /* XPATH_STREAMING */
13855 
13856 /**
13857  * xmlXPathRunEval:
13858  * @ctxt:  the XPath parser context with the compiled expression
13859  * @toBool:  evaluate to a boolean result
13860  *
13861  * Evaluate the Precompiled XPath expression in the given context.
13862  */
13863 static int
13864 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13865 {
13866     xmlXPathCompExprPtr comp;
13867 
13868     if ((ctxt == NULL) || (ctxt->comp == NULL))
13869 	return(-1);
13870 
13871     ctxt->context->depth = 0;
13872 
13873     if (ctxt->valueTab == NULL) {
13874 	/* Allocate the value stack */
13875 	ctxt->valueTab = (xmlXPathObjectPtr *)
13876 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13877 	if (ctxt->valueTab == NULL) {
13878 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13879 	    xmlFree(ctxt);
13880 	}
13881 	ctxt->valueNr = 0;
13882 	ctxt->valueMax = 10;
13883 	ctxt->value = NULL;
13884         ctxt->valueFrame = 0;
13885     }
13886 #ifdef XPATH_STREAMING
13887     if (ctxt->comp->stream) {
13888 	int res;
13889 
13890 	if (toBool) {
13891 	    /*
13892 	    * Evaluation to boolean result.
13893 	    */
13894 	    res = xmlXPathRunStreamEval(ctxt->context,
13895 		ctxt->comp->stream, NULL, 1);
13896 	    if (res != -1)
13897 		return(res);
13898 	} else {
13899 	    xmlXPathObjectPtr resObj = NULL;
13900 
13901 	    /*
13902 	    * Evaluation to a sequence.
13903 	    */
13904 	    res = xmlXPathRunStreamEval(ctxt->context,
13905 		ctxt->comp->stream, &resObj, 0);
13906 
13907 	    if ((res != -1) && (resObj != NULL)) {
13908 		valuePush(ctxt, resObj);
13909 		return(0);
13910 	    }
13911 	    if (resObj != NULL)
13912 		xmlXPathReleaseObject(ctxt->context, resObj);
13913 	}
13914 	/*
13915 	* QUESTION TODO: This falls back to normal XPath evaluation
13916 	* if res == -1. Is this intended?
13917 	*/
13918     }
13919 #endif
13920     comp = ctxt->comp;
13921     if (comp->last < 0) {
13922 	xmlGenericError(xmlGenericErrorContext,
13923 	    "xmlXPathRunEval: last is less than zero\n");
13924 	return(-1);
13925     }
13926     if (toBool)
13927 	return(xmlXPathCompOpEvalToBoolean(ctxt,
13928 	    &comp->steps[comp->last], 0));
13929     else
13930 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13931 
13932     return(0);
13933 }
13934 
13935 /************************************************************************
13936  *									*
13937  *			Public interfaces				*
13938  *									*
13939  ************************************************************************/
13940 
13941 /**
13942  * xmlXPathEvalPredicate:
13943  * @ctxt:  the XPath context
13944  * @res:  the Predicate Expression evaluation result
13945  *
13946  * Evaluate a predicate result for the current node.
13947  * A PredicateExpr is evaluated by evaluating the Expr and converting
13948  * the result to a boolean. If the result is a number, the result will
13949  * be converted to true if the number is equal to the position of the
13950  * context node in the context node list (as returned by the position
13951  * function) and will be converted to false otherwise; if the result
13952  * is not a number, then the result will be converted as if by a call
13953  * to the boolean function.
13954  *
13955  * Returns 1 if predicate is true, 0 otherwise
13956  */
13957 int
13958 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13959     if ((ctxt == NULL) || (res == NULL)) return(0);
13960     switch (res->type) {
13961         case XPATH_BOOLEAN:
13962 	    return(res->boolval);
13963         case XPATH_NUMBER:
13964 	    return(res->floatval == ctxt->proximityPosition);
13965         case XPATH_NODESET:
13966         case XPATH_XSLT_TREE:
13967 	    if (res->nodesetval == NULL)
13968 		return(0);
13969 	    return(res->nodesetval->nodeNr != 0);
13970         case XPATH_STRING:
13971 	    return((res->stringval != NULL) &&
13972 	           (xmlStrlen(res->stringval) != 0));
13973         default:
13974 	    STRANGE
13975     }
13976     return(0);
13977 }
13978 
13979 /**
13980  * xmlXPathEvaluatePredicateResult:
13981  * @ctxt:  the XPath Parser context
13982  * @res:  the Predicate Expression evaluation result
13983  *
13984  * Evaluate a predicate result for the current node.
13985  * A PredicateExpr is evaluated by evaluating the Expr and converting
13986  * the result to a boolean. If the result is a number, the result will
13987  * be converted to true if the number is equal to the position of the
13988  * context node in the context node list (as returned by the position
13989  * function) and will be converted to false otherwise; if the result
13990  * is not a number, then the result will be converted as if by a call
13991  * to the boolean function.
13992  *
13993  * Returns 1 if predicate is true, 0 otherwise
13994  */
13995 int
13996 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
13997                                 xmlXPathObjectPtr res) {
13998     if ((ctxt == NULL) || (res == NULL)) return(0);
13999     switch (res->type) {
14000         case XPATH_BOOLEAN:
14001 	    return(res->boolval);
14002         case XPATH_NUMBER:
14003 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14004 	    return((res->floatval == ctxt->context->proximityPosition) &&
14005 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14006 #else
14007 	    return(res->floatval == ctxt->context->proximityPosition);
14008 #endif
14009         case XPATH_NODESET:
14010         case XPATH_XSLT_TREE:
14011 	    if (res->nodesetval == NULL)
14012 		return(0);
14013 	    return(res->nodesetval->nodeNr != 0);
14014         case XPATH_STRING:
14015 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14016 #ifdef LIBXML_XPTR_ENABLED
14017 	case XPATH_LOCATIONSET:{
14018 	    xmlLocationSetPtr ptr = res->user;
14019 	    if (ptr == NULL)
14020 	        return(0);
14021 	    return (ptr->locNr != 0);
14022 	    }
14023 #endif
14024         default:
14025 	    STRANGE
14026     }
14027     return(0);
14028 }
14029 
14030 #ifdef XPATH_STREAMING
14031 /**
14032  * xmlXPathTryStreamCompile:
14033  * @ctxt: an XPath context
14034  * @str:  the XPath expression
14035  *
14036  * Try to compile the XPath expression as a streamable subset.
14037  *
14038  * Returns the compiled expression or NULL if failed to compile.
14039  */
14040 static xmlXPathCompExprPtr
14041 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14042     /*
14043      * Optimization: use streaming patterns when the XPath expression can
14044      * be compiled to a stream lookup
14045      */
14046     xmlPatternPtr stream;
14047     xmlXPathCompExprPtr comp;
14048     xmlDictPtr dict = NULL;
14049     const xmlChar **namespaces = NULL;
14050     xmlNsPtr ns;
14051     int i, j;
14052 
14053     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14054         (!xmlStrchr(str, '@'))) {
14055 	const xmlChar *tmp;
14056 
14057 	/*
14058 	 * We don't try to handle expressions using the verbose axis
14059 	 * specifiers ("::"), just the simplified form at this point.
14060 	 * Additionally, if there is no list of namespaces available and
14061 	 *  there's a ":" in the expression, indicating a prefixed QName,
14062 	 *  then we won't try to compile either. xmlPatterncompile() needs
14063 	 *  to have a list of namespaces at compilation time in order to
14064 	 *  compile prefixed name tests.
14065 	 */
14066 	tmp = xmlStrchr(str, ':');
14067 	if ((tmp != NULL) &&
14068 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14069 	    return(NULL);
14070 
14071 	if (ctxt != NULL) {
14072 	    dict = ctxt->dict;
14073 	    if (ctxt->nsNr > 0) {
14074 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14075 		if (namespaces == NULL) {
14076 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14077 		    return(NULL);
14078 		}
14079 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14080 		    ns = ctxt->namespaces[j];
14081 		    namespaces[i++] = ns->href;
14082 		    namespaces[i++] = ns->prefix;
14083 		}
14084 		namespaces[i++] = NULL;
14085 		namespaces[i] = NULL;
14086 	    }
14087 	}
14088 
14089 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14090 			&namespaces[0]);
14091 	if (namespaces != NULL) {
14092 	    xmlFree((xmlChar **)namespaces);
14093 	}
14094 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14095 	    comp = xmlXPathNewCompExpr();
14096 	    if (comp == NULL) {
14097 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14098 		return(NULL);
14099 	    }
14100 	    comp->stream = stream;
14101 	    comp->dict = dict;
14102 	    if (comp->dict)
14103 		xmlDictReference(comp->dict);
14104 	    return(comp);
14105 	}
14106 	xmlFreePattern(stream);
14107     }
14108     return(NULL);
14109 }
14110 #endif /* XPATH_STREAMING */
14111 
14112 static void
14113 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14114                            xmlXPathStepOpPtr op)
14115 {
14116     xmlXPathCompExprPtr comp = pctxt->comp;
14117     xmlXPathContextPtr ctxt;
14118 
14119     /*
14120     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14121     * internal representation.
14122     */
14123 
14124     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14125         (op->ch1 != -1) &&
14126         (op->ch2 == -1 /* no predicate */))
14127     {
14128         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14129 
14130         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14131             ((xmlXPathAxisVal) prevop->value ==
14132                 AXIS_DESCENDANT_OR_SELF) &&
14133             (prevop->ch2 == -1) &&
14134             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14135             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14136         {
14137             /*
14138             * This is a "descendant-or-self::node()" without predicates.
14139             * Try to eliminate it.
14140             */
14141 
14142             switch ((xmlXPathAxisVal) op->value) {
14143                 case AXIS_CHILD:
14144                 case AXIS_DESCENDANT:
14145                     /*
14146                     * Convert "descendant-or-self::node()/child::" or
14147                     * "descendant-or-self::node()/descendant::" to
14148                     * "descendant::"
14149                     */
14150                     op->ch1   = prevop->ch1;
14151                     op->value = AXIS_DESCENDANT;
14152                     break;
14153                 case AXIS_SELF:
14154                 case AXIS_DESCENDANT_OR_SELF:
14155                     /*
14156                     * Convert "descendant-or-self::node()/self::" or
14157                     * "descendant-or-self::node()/descendant-or-self::" to
14158                     * to "descendant-or-self::"
14159                     */
14160                     op->ch1   = prevop->ch1;
14161                     op->value = AXIS_DESCENDANT_OR_SELF;
14162                     break;
14163                 default:
14164                     break;
14165             }
14166 	}
14167     }
14168 
14169     /* OP_VALUE has invalid ch1. */
14170     if (op->op == XPATH_OP_VALUE)
14171         return;
14172 
14173     /* Recurse */
14174     ctxt = pctxt->context;
14175     if (ctxt != NULL) {
14176         if (ctxt->depth >= ctxt->maxDepth)
14177             return;
14178         ctxt->depth += 1;
14179     }
14180     if (op->ch1 != -1)
14181         xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14182     if (op->ch2 != -1)
14183 	xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14184     if (ctxt != NULL)
14185         ctxt->depth -= 1;
14186 }
14187 
14188 /**
14189  * xmlXPathCtxtCompile:
14190  * @ctxt: an XPath context
14191  * @str:  the XPath expression
14192  *
14193  * Compile an XPath expression
14194  *
14195  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14196  *         the caller has to free the object.
14197  */
14198 xmlXPathCompExprPtr
14199 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14200     xmlXPathParserContextPtr pctxt;
14201     xmlXPathCompExprPtr comp;
14202 
14203 #ifdef XPATH_STREAMING
14204     comp = xmlXPathTryStreamCompile(ctxt, str);
14205     if (comp != NULL)
14206         return(comp);
14207 #endif
14208 
14209     xmlXPathInit();
14210 
14211     pctxt = xmlXPathNewParserContext(str, ctxt);
14212     if (pctxt == NULL)
14213         return NULL;
14214     if (ctxt != NULL)
14215         ctxt->depth = 0;
14216     xmlXPathCompileExpr(pctxt, 1);
14217 
14218     if( pctxt->error != XPATH_EXPRESSION_OK )
14219     {
14220         xmlXPathFreeParserContext(pctxt);
14221         return(NULL);
14222     }
14223 
14224     if (*pctxt->cur != 0) {
14225 	/*
14226 	 * aleksey: in some cases this line prints *second* error message
14227 	 * (see bug #78858) and probably this should be fixed.
14228 	 * However, we are not sure that all error messages are printed
14229 	 * out in other places. It's not critical so we leave it as-is for now
14230 	 */
14231 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14232 	comp = NULL;
14233     } else {
14234 	comp = pctxt->comp;
14235 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
14236             if (ctxt != NULL)
14237                 ctxt->depth = 0;
14238 	    xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14239 	}
14240 	pctxt->comp = NULL;
14241     }
14242     xmlXPathFreeParserContext(pctxt);
14243 
14244     if (comp != NULL) {
14245 	comp->expr = xmlStrdup(str);
14246 #ifdef DEBUG_EVAL_COUNTS
14247 	comp->string = xmlStrdup(str);
14248 	comp->nb = 0;
14249 #endif
14250     }
14251     return(comp);
14252 }
14253 
14254 /**
14255  * xmlXPathCompile:
14256  * @str:  the XPath expression
14257  *
14258  * Compile an XPath expression
14259  *
14260  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14261  *         the caller has to free the object.
14262  */
14263 xmlXPathCompExprPtr
14264 xmlXPathCompile(const xmlChar *str) {
14265     return(xmlXPathCtxtCompile(NULL, str));
14266 }
14267 
14268 /**
14269  * xmlXPathCompiledEvalInternal:
14270  * @comp:  the compiled XPath expression
14271  * @ctxt:  the XPath context
14272  * @resObj: the resulting XPath object or NULL
14273  * @toBool: 1 if only a boolean result is requested
14274  *
14275  * Evaluate the Precompiled XPath expression in the given context.
14276  * The caller has to free @resObj.
14277  *
14278  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14279  *         the caller has to free the object.
14280  */
14281 static int
14282 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14283 			     xmlXPathContextPtr ctxt,
14284 			     xmlXPathObjectPtr *resObjPtr,
14285 			     int toBool)
14286 {
14287     xmlXPathParserContextPtr pctxt;
14288     xmlXPathObjectPtr resObj;
14289 #ifndef LIBXML_THREAD_ENABLED
14290     static int reentance = 0;
14291 #endif
14292     int res;
14293 
14294     CHECK_CTXT_NEG(ctxt)
14295 
14296     if (comp == NULL)
14297 	return(-1);
14298     xmlXPathInit();
14299 
14300 #ifndef LIBXML_THREAD_ENABLED
14301     reentance++;
14302     if (reentance > 1)
14303 	xmlXPathDisableOptimizer = 1;
14304 #endif
14305 
14306 #ifdef DEBUG_EVAL_COUNTS
14307     comp->nb++;
14308     if ((comp->string != NULL) && (comp->nb > 100)) {
14309 	fprintf(stderr, "100 x %s\n", comp->string);
14310 	comp->nb = 0;
14311     }
14312 #endif
14313     pctxt = xmlXPathCompParserContext(comp, ctxt);
14314     res = xmlXPathRunEval(pctxt, toBool);
14315 
14316     if (pctxt->error != XPATH_EXPRESSION_OK) {
14317         resObj = NULL;
14318     } else {
14319         resObj = valuePop(pctxt);
14320         if (resObj == NULL) {
14321             if (!toBool)
14322                 xmlGenericError(xmlGenericErrorContext,
14323                     "xmlXPathCompiledEval: No result on the stack.\n");
14324         } else if (pctxt->valueNr > 0) {
14325             xmlGenericError(xmlGenericErrorContext,
14326                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14327                 pctxt->valueNr);
14328         }
14329     }
14330 
14331     if (resObjPtr)
14332         *resObjPtr = resObj;
14333     else
14334         xmlXPathReleaseObject(ctxt, resObj);
14335 
14336     pctxt->comp = NULL;
14337     xmlXPathFreeParserContext(pctxt);
14338 #ifndef LIBXML_THREAD_ENABLED
14339     reentance--;
14340 #endif
14341 
14342     return(res);
14343 }
14344 
14345 /**
14346  * xmlXPathCompiledEval:
14347  * @comp:  the compiled XPath expression
14348  * @ctx:  the XPath context
14349  *
14350  * Evaluate the Precompiled XPath expression in the given context.
14351  *
14352  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14353  *         the caller has to free the object.
14354  */
14355 xmlXPathObjectPtr
14356 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14357 {
14358     xmlXPathObjectPtr res = NULL;
14359 
14360     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14361     return(res);
14362 }
14363 
14364 /**
14365  * xmlXPathCompiledEvalToBoolean:
14366  * @comp:  the compiled XPath expression
14367  * @ctxt:  the XPath context
14368  *
14369  * Applies the XPath boolean() function on the result of the given
14370  * compiled expression.
14371  *
14372  * Returns 1 if the expression evaluated to true, 0 if to false and
14373  *         -1 in API and internal errors.
14374  */
14375 int
14376 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14377 			      xmlXPathContextPtr ctxt)
14378 {
14379     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14380 }
14381 
14382 /**
14383  * xmlXPathEvalExpr:
14384  * @ctxt:  the XPath Parser context
14385  *
14386  * Parse and evaluate an XPath expression in the given context,
14387  * then push the result on the context stack
14388  */
14389 void
14390 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14391 #ifdef XPATH_STREAMING
14392     xmlXPathCompExprPtr comp;
14393 #endif
14394 
14395     if (ctxt == NULL) return;
14396 
14397 #ifdef XPATH_STREAMING
14398     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14399     if (comp != NULL) {
14400         if (ctxt->comp != NULL)
14401 	    xmlXPathFreeCompExpr(ctxt->comp);
14402         ctxt->comp = comp;
14403     } else
14404 #endif
14405     {
14406         if (ctxt->context != NULL)
14407             ctxt->context->depth = 0;
14408 	xmlXPathCompileExpr(ctxt, 1);
14409         CHECK_ERROR;
14410 
14411         /* Check for trailing characters. */
14412         if (*ctxt->cur != 0)
14413             XP_ERROR(XPATH_EXPR_ERROR);
14414 
14415 	if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14416             if (ctxt->context != NULL)
14417                 ctxt->context->depth = 0;
14418 	    xmlXPathOptimizeExpression(ctxt,
14419 		&ctxt->comp->steps[ctxt->comp->last]);
14420         }
14421     }
14422 
14423     xmlXPathRunEval(ctxt, 0);
14424 }
14425 
14426 /**
14427  * xmlXPathEval:
14428  * @str:  the XPath expression
14429  * @ctx:  the XPath context
14430  *
14431  * Evaluate the XPath Location Path in the given context.
14432  *
14433  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14434  *         the caller has to free the object.
14435  */
14436 xmlXPathObjectPtr
14437 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14438     xmlXPathParserContextPtr ctxt;
14439     xmlXPathObjectPtr res;
14440 
14441     CHECK_CTXT(ctx)
14442 
14443     xmlXPathInit();
14444 
14445     ctxt = xmlXPathNewParserContext(str, ctx);
14446     if (ctxt == NULL)
14447         return NULL;
14448     xmlXPathEvalExpr(ctxt);
14449 
14450     if (ctxt->error != XPATH_EXPRESSION_OK) {
14451 	res = NULL;
14452     } else {
14453 	res = valuePop(ctxt);
14454         if (res == NULL) {
14455             xmlGenericError(xmlGenericErrorContext,
14456                 "xmlXPathCompiledEval: No result on the stack.\n");
14457         } else if (ctxt->valueNr > 0) {
14458             xmlGenericError(xmlGenericErrorContext,
14459                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14460                 ctxt->valueNr);
14461         }
14462     }
14463 
14464     xmlXPathFreeParserContext(ctxt);
14465     return(res);
14466 }
14467 
14468 /**
14469  * xmlXPathSetContextNode:
14470  * @node: the node to to use as the context node
14471  * @ctx:  the XPath context
14472  *
14473  * Sets 'node' as the context node. The node must be in the same
14474  * document as that associated with the context.
14475  *
14476  * Returns -1 in case of error or 0 if successful
14477  */
14478 int
14479 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14480     if ((node == NULL) || (ctx == NULL))
14481         return(-1);
14482 
14483     if (node->doc == ctx->doc) {
14484         ctx->node = node;
14485 	return(0);
14486     }
14487     return(-1);
14488 }
14489 
14490 /**
14491  * xmlXPathNodeEval:
14492  * @node: the node to to use as the context node
14493  * @str:  the XPath expression
14494  * @ctx:  the XPath context
14495  *
14496  * Evaluate the XPath Location Path in the given context. The node 'node'
14497  * is set as the context node. The context node is not restored.
14498  *
14499  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14500  *         the caller has to free the object.
14501  */
14502 xmlXPathObjectPtr
14503 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14504     if (str == NULL)
14505         return(NULL);
14506     if (xmlXPathSetContextNode(node, ctx) < 0)
14507         return(NULL);
14508     return(xmlXPathEval(str, ctx));
14509 }
14510 
14511 /**
14512  * xmlXPathEvalExpression:
14513  * @str:  the XPath expression
14514  * @ctxt:  the XPath context
14515  *
14516  * Alias for xmlXPathEval().
14517  *
14518  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14519  *         the caller has to free the object.
14520  */
14521 xmlXPathObjectPtr
14522 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14523     return(xmlXPathEval(str, ctxt));
14524 }
14525 
14526 /************************************************************************
14527  *									*
14528  *	Extra functions not pertaining to the XPath spec		*
14529  *									*
14530  ************************************************************************/
14531 /**
14532  * xmlXPathEscapeUriFunction:
14533  * @ctxt:  the XPath Parser context
14534  * @nargs:  the number of arguments
14535  *
14536  * Implement the escape-uri() XPath function
14537  *    string escape-uri(string $str, bool $escape-reserved)
14538  *
14539  * This function applies the URI escaping rules defined in section 2 of [RFC
14540  * 2396] to the string supplied as $uri-part, which typically represents all
14541  * or part of a URI. The effect of the function is to replace any special
14542  * character in the string by an escape sequence of the form %xx%yy...,
14543  * where xxyy... is the hexadecimal representation of the octets used to
14544  * represent the character in UTF-8.
14545  *
14546  * The set of characters that are escaped depends on the setting of the
14547  * boolean argument $escape-reserved.
14548  *
14549  * If $escape-reserved is true, all characters are escaped other than lower
14550  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14551  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14552  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14553  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14554  * A-F).
14555  *
14556  * If $escape-reserved is false, the behavior differs in that characters
14557  * referred to in [RFC 2396] as reserved characters are not escaped. These
14558  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14559  *
14560  * [RFC 2396] does not define whether escaped URIs should use lower case or
14561  * upper case for hexadecimal digits. To ensure that escaped URIs can be
14562  * compared using string comparison functions, this function must always use
14563  * the upper-case letters A-F.
14564  *
14565  * Generally, $escape-reserved should be set to true when escaping a string
14566  * that is to form a single part of a URI, and to false when escaping an
14567  * entire URI or URI reference.
14568  *
14569  * In the case of non-ascii characters, the string is encoded according to
14570  * utf-8 and then converted according to RFC 2396.
14571  *
14572  * Examples
14573  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14574  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14575  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14576  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14577  *
14578  */
14579 static void
14580 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14581     xmlXPathObjectPtr str;
14582     int escape_reserved;
14583     xmlBufPtr target;
14584     xmlChar *cptr;
14585     xmlChar escape[4];
14586 
14587     CHECK_ARITY(2);
14588 
14589     escape_reserved = xmlXPathPopBoolean(ctxt);
14590 
14591     CAST_TO_STRING;
14592     str = valuePop(ctxt);
14593 
14594     target = xmlBufCreate();
14595 
14596     escape[0] = '%';
14597     escape[3] = 0;
14598 
14599     if (target) {
14600 	for (cptr = str->stringval; *cptr; cptr++) {
14601 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
14602 		(*cptr >= 'a' && *cptr <= 'z') ||
14603 		(*cptr >= '0' && *cptr <= '9') ||
14604 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
14605 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
14606 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14607 		(*cptr == '%' &&
14608 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14609 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14610 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
14611 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14612 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14613 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14614 		(!escape_reserved &&
14615 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14616 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14617 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14618 		  *cptr == ','))) {
14619 		xmlBufAdd(target, cptr, 1);
14620 	    } else {
14621 		if ((*cptr >> 4) < 10)
14622 		    escape[1] = '0' + (*cptr >> 4);
14623 		else
14624 		    escape[1] = 'A' - 10 + (*cptr >> 4);
14625 		if ((*cptr & 0xF) < 10)
14626 		    escape[2] = '0' + (*cptr & 0xF);
14627 		else
14628 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
14629 
14630 		xmlBufAdd(target, &escape[0], 3);
14631 	    }
14632 	}
14633     }
14634     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14635 	xmlBufContent(target)));
14636     xmlBufFree(target);
14637     xmlXPathReleaseObject(ctxt->context, str);
14638 }
14639 
14640 /**
14641  * xmlXPathRegisterAllFunctions:
14642  * @ctxt:  the XPath context
14643  *
14644  * Registers all default XPath functions in this context
14645  */
14646 void
14647 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14648 {
14649     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14650                          xmlXPathBooleanFunction);
14651     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14652                          xmlXPathCeilingFunction);
14653     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14654                          xmlXPathCountFunction);
14655     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14656                          xmlXPathConcatFunction);
14657     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14658                          xmlXPathContainsFunction);
14659     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14660                          xmlXPathIdFunction);
14661     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14662                          xmlXPathFalseFunction);
14663     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14664                          xmlXPathFloorFunction);
14665     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14666                          xmlXPathLastFunction);
14667     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14668                          xmlXPathLangFunction);
14669     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14670                          xmlXPathLocalNameFunction);
14671     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14672                          xmlXPathNotFunction);
14673     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14674                          xmlXPathNameFunction);
14675     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14676                          xmlXPathNamespaceURIFunction);
14677     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14678                          xmlXPathNormalizeFunction);
14679     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14680                          xmlXPathNumberFunction);
14681     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14682                          xmlXPathPositionFunction);
14683     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14684                          xmlXPathRoundFunction);
14685     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14686                          xmlXPathStringFunction);
14687     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14688                          xmlXPathStringLengthFunction);
14689     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14690                          xmlXPathStartsWithFunction);
14691     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14692                          xmlXPathSubstringFunction);
14693     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14694                          xmlXPathSubstringBeforeFunction);
14695     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14696                          xmlXPathSubstringAfterFunction);
14697     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14698                          xmlXPathSumFunction);
14699     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14700                          xmlXPathTrueFunction);
14701     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14702                          xmlXPathTranslateFunction);
14703 
14704     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14705 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14706                          xmlXPathEscapeUriFunction);
14707 }
14708 
14709 #endif /* LIBXML_XPATH_ENABLED */
14710 #define bottom_xpath
14711 #include "elfgcchack.h"
14712