xref: /reactos/sdk/lib/3rdparty/libxml2/xpath.c (revision 595b846d)
1 /*
2  * xpath.c: XML Path Language implementation
3  *          XPath is a language for addressing parts of an XML document,
4  *          designed to be used by both XSLT and XPointer
5  *f
6  * Reference: W3C Recommendation 16 November 1999
7  *     http://www.w3.org/TR/1999/REC-xpath-19991116
8  * Public reference:
9  *     http://www.w3.org/TR/xpath
10  *
11  * See Copyright for the status of this software
12  *
13  * Author: daniel@veillard.com
14  *
15  */
16 
17 /* To avoid EBCDIC trouble when parsing on zOS */
18 #if defined(__MVS__)
19 #pragma convert("ISO8859-1")
20 #endif
21 
22 #define IN_LIBXML
23 #include "libxml.h"
24 
25 #include <limits.h>
26 #include <string.h>
27 #include <stddef.h>
28 
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32 #ifdef HAVE_MATH_H
33 #include <math.h>
34 #endif
35 #ifdef HAVE_FLOAT_H
36 #include <float.h>
37 #endif
38 #ifdef HAVE_CTYPE_H
39 #include <ctype.h>
40 #endif
41 #ifdef HAVE_SIGNAL_H
42 #include <signal.h>
43 #endif
44 
45 #include <libxml/xmlmemory.h>
46 #include <libxml/tree.h>
47 #include <libxml/valid.h>
48 #include <libxml/xpath.h>
49 #include <libxml/xpathInternals.h>
50 #include <libxml/parserInternals.h>
51 #include <libxml/hash.h>
52 #ifdef LIBXML_XPTR_ENABLED
53 #include <libxml/xpointer.h>
54 #endif
55 #ifdef LIBXML_DEBUG_ENABLED
56 #include <libxml/debugXML.h>
57 #endif
58 #include <libxml/xmlerror.h>
59 #include <libxml/threads.h>
60 #include <libxml/globals.h>
61 #ifdef LIBXML_PATTERN_ENABLED
62 #include <libxml/pattern.h>
63 #endif
64 
65 #include "buf.h"
66 
67 #ifdef LIBXML_PATTERN_ENABLED
68 #define XPATH_STREAMING
69 #endif
70 
71 #define TODO								\
72     xmlGenericError(xmlGenericErrorContext,				\
73 	    "Unimplemented block at %s:%d\n",				\
74             __FILE__, __LINE__);
75 
76 /**
77  * WITH_TIM_SORT:
78  *
79  * Use the Timsort algorithm provided in timsort.h to sort
80  * nodeset as this is a great improvement over the old Shell sort
81  * used in xmlXPathNodeSetSort()
82  */
83 #define WITH_TIM_SORT
84 
85 /*
86 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
87 * If defined, this will use xmlXPathCmpNodesExt() instead of
88 * xmlXPathCmpNodes(). The new function is optimized comparison of
89 * non-element nodes; actually it will speed up comparison only if
90 * xmlXPathOrderDocElems() was called in order to index the elements of
91 * a tree in document order; Libxslt does such an indexing, thus it will
92 * benefit from this optimization.
93 */
94 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
95 
96 /*
97 * XP_OPTIMIZED_FILTER_FIRST:
98 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
99 * in a way, that it stop evaluation at the first node.
100 */
101 #define XP_OPTIMIZED_FILTER_FIRST
102 
103 /*
104 * XP_DEBUG_OBJ_USAGE:
105 * Internal flag to enable tracking of how much XPath objects have been
106 * created.
107 */
108 /* #define XP_DEBUG_OBJ_USAGE */
109 
110 /*
111  * XPATH_MAX_STEPS:
112  * when compiling an XPath expression we arbitrary limit the maximum
113  * number of step operation in the compiled expression. 1000000 is
114  * an insanely large value which should never be reached under normal
115  * circumstances
116  */
117 #define XPATH_MAX_STEPS 1000000
118 
119 /*
120  * XPATH_MAX_STACK_DEPTH:
121  * when evaluating an XPath expression we arbitrary limit the maximum
122  * number of object allowed to be pushed on the stack. 1000000 is
123  * an insanely large value which should never be reached under normal
124  * circumstances
125  */
126 #define XPATH_MAX_STACK_DEPTH 1000000
127 
128 /*
129  * XPATH_MAX_NODESET_LENGTH:
130  * when evaluating an XPath expression nodesets are created and we
131  * arbitrary limit the maximum length of those node set. 10000000 is
132  * an insanely large value which should never be reached under normal
133  * circumstances, one would first need to construct an in memory tree
134  * with more than 10 millions nodes.
135  */
136 #define XPATH_MAX_NODESET_LENGTH 10000000
137 
138 /*
139  * TODO:
140  * There are a few spots where some tests are done which depend upon ascii
141  * data.  These should be enhanced for full UTF8 support (see particularly
142  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
143  */
144 
145 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
146 /**
147  * xmlXPathCmpNodesExt:
148  * @node1:  the first node
149  * @node2:  the second node
150  *
151  * Compare two nodes w.r.t document order.
152  * This one is optimized for handling of non-element nodes.
153  *
154  * Returns -2 in case of error 1 if first point < second point, 0 if
155  *         it's the same node, -1 otherwise
156  */
157 static int
158 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
159     int depth1, depth2;
160     int misc = 0, precedence1 = 0, precedence2 = 0;
161     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
162     xmlNodePtr cur, root;
163     ptrdiff_t l1, l2;
164 
165     if ((node1 == NULL) || (node2 == NULL))
166 	return(-2);
167 
168     if (node1 == node2)
169 	return(0);
170 
171     /*
172      * a couple of optimizations which will avoid computations in most cases
173      */
174     switch (node1->type) {
175 	case XML_ELEMENT_NODE:
176 	    if (node2->type == XML_ELEMENT_NODE) {
177 		if ((0 > (ptrdiff_t) node1->content) &&
178 		    (0 > (ptrdiff_t) node2->content) &&
179 		    (node1->doc == node2->doc))
180 		{
181 		    l1 = -((ptrdiff_t) node1->content);
182 		    l2 = -((ptrdiff_t) node2->content);
183 		    if (l1 < l2)
184 			return(1);
185 		    if (l1 > l2)
186 			return(-1);
187 		} else
188 		    goto turtle_comparison;
189 	    }
190 	    break;
191 	case XML_ATTRIBUTE_NODE:
192 	    precedence1 = 1; /* element is owner */
193 	    miscNode1 = node1;
194 	    node1 = node1->parent;
195 	    misc = 1;
196 	    break;
197 	case XML_TEXT_NODE:
198 	case XML_CDATA_SECTION_NODE:
199 	case XML_COMMENT_NODE:
200 	case XML_PI_NODE: {
201 	    miscNode1 = node1;
202 	    /*
203 	    * Find nearest element node.
204 	    */
205 	    if (node1->prev != NULL) {
206 		do {
207 		    node1 = node1->prev;
208 		    if (node1->type == XML_ELEMENT_NODE) {
209 			precedence1 = 3; /* element in prev-sibl axis */
210 			break;
211 		    }
212 		    if (node1->prev == NULL) {
213 			precedence1 = 2; /* element is parent */
214 			/*
215 			* URGENT TODO: Are there any cases, where the
216 			* parent of such a node is not an element node?
217 			*/
218 			node1 = node1->parent;
219 			break;
220 		    }
221 		} while (1);
222 	    } else {
223 		precedence1 = 2; /* element is parent */
224 		node1 = node1->parent;
225 	    }
226 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
227 		(0 <= (ptrdiff_t) node1->content)) {
228 		/*
229 		* Fallback for whatever case.
230 		*/
231 		node1 = miscNode1;
232 		precedence1 = 0;
233 	    } else
234 		misc = 1;
235 	}
236 	    break;
237 	case XML_NAMESPACE_DECL:
238 	    /*
239 	    * TODO: why do we return 1 for namespace nodes?
240 	    */
241 	    return(1);
242 	default:
243 	    break;
244     }
245     switch (node2->type) {
246 	case XML_ELEMENT_NODE:
247 	    break;
248 	case XML_ATTRIBUTE_NODE:
249 	    precedence2 = 1; /* element is owner */
250 	    miscNode2 = node2;
251 	    node2 = node2->parent;
252 	    misc = 1;
253 	    break;
254 	case XML_TEXT_NODE:
255 	case XML_CDATA_SECTION_NODE:
256 	case XML_COMMENT_NODE:
257 	case XML_PI_NODE: {
258 	    miscNode2 = node2;
259 	    if (node2->prev != NULL) {
260 		do {
261 		    node2 = node2->prev;
262 		    if (node2->type == XML_ELEMENT_NODE) {
263 			precedence2 = 3; /* element in prev-sibl axis */
264 			break;
265 		    }
266 		    if (node2->prev == NULL) {
267 			precedence2 = 2; /* element is parent */
268 			node2 = node2->parent;
269 			break;
270 		    }
271 		} while (1);
272 	    } else {
273 		precedence2 = 2; /* element is parent */
274 		node2 = node2->parent;
275 	    }
276 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
277 		(0 <= (ptrdiff_t) node2->content))
278 	    {
279 		node2 = miscNode2;
280 		precedence2 = 0;
281 	    } else
282 		misc = 1;
283 	}
284 	    break;
285 	case XML_NAMESPACE_DECL:
286 	    return(1);
287 	default:
288 	    break;
289     }
290     if (misc) {
291 	if (node1 == node2) {
292 	    if (precedence1 == precedence2) {
293 		/*
294 		* The ugly case; but normally there aren't many
295 		* adjacent non-element nodes around.
296 		*/
297 		cur = miscNode2->prev;
298 		while (cur != NULL) {
299 		    if (cur == miscNode1)
300 			return(1);
301 		    if (cur->type == XML_ELEMENT_NODE)
302 			return(-1);
303 		    cur = cur->prev;
304 		}
305 		return (-1);
306 	    } else {
307 		/*
308 		* Evaluate based on higher precedence wrt to the element.
309 		* TODO: This assumes attributes are sorted before content.
310 		*   Is this 100% correct?
311 		*/
312 		if (precedence1 < precedence2)
313 		    return(1);
314 		else
315 		    return(-1);
316 	    }
317 	}
318 	/*
319 	* Special case: One of the helper-elements is contained by the other.
320 	* <foo>
321 	*   <node2>
322 	*     <node1>Text-1(precedence1 == 2)</node1>
323 	*   </node2>
324 	*   Text-6(precedence2 == 3)
325 	* </foo>
326 	*/
327 	if ((precedence2 == 3) && (precedence1 > 1)) {
328 	    cur = node1->parent;
329 	    while (cur) {
330 		if (cur == node2)
331 		    return(1);
332 		cur = cur->parent;
333 	    }
334 	}
335 	if ((precedence1 == 3) && (precedence2 > 1)) {
336 	    cur = node2->parent;
337 	    while (cur) {
338 		if (cur == node1)
339 		    return(-1);
340 		cur = cur->parent;
341 	    }
342 	}
343     }
344 
345     /*
346      * Speedup using document order if availble.
347      */
348     if ((node1->type == XML_ELEMENT_NODE) &&
349 	(node2->type == XML_ELEMENT_NODE) &&
350 	(0 > (ptrdiff_t) node1->content) &&
351 	(0 > (ptrdiff_t) node2->content) &&
352 	(node1->doc == node2->doc)) {
353 
354 	l1 = -((ptrdiff_t) node1->content);
355 	l2 = -((ptrdiff_t) node2->content);
356 	if (l1 < l2)
357 	    return(1);
358 	if (l1 > l2)
359 	    return(-1);
360     }
361 
362 turtle_comparison:
363 
364     if (node1 == node2->prev)
365 	return(1);
366     if (node1 == node2->next)
367 	return(-1);
368     /*
369      * compute depth to root
370      */
371     for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
372 	if (cur->parent == node1)
373 	    return(1);
374 	depth2++;
375     }
376     root = cur;
377     for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
378 	if (cur->parent == node2)
379 	    return(-1);
380 	depth1++;
381     }
382     /*
383      * Distinct document (or distinct entities :-( ) case.
384      */
385     if (root != cur) {
386 	return(-2);
387     }
388     /*
389      * get the nearest common ancestor.
390      */
391     while (depth1 > depth2) {
392 	depth1--;
393 	node1 = node1->parent;
394     }
395     while (depth2 > depth1) {
396 	depth2--;
397 	node2 = node2->parent;
398     }
399     while (node1->parent != node2->parent) {
400 	node1 = node1->parent;
401 	node2 = node2->parent;
402 	/* should not happen but just in case ... */
403 	if ((node1 == NULL) || (node2 == NULL))
404 	    return(-2);
405     }
406     /*
407      * Find who's first.
408      */
409     if (node1 == node2->prev)
410 	return(1);
411     if (node1 == node2->next)
412 	return(-1);
413     /*
414      * Speedup using document order if availble.
415      */
416     if ((node1->type == XML_ELEMENT_NODE) &&
417 	(node2->type == XML_ELEMENT_NODE) &&
418 	(0 > (ptrdiff_t) node1->content) &&
419 	(0 > (ptrdiff_t) node2->content) &&
420 	(node1->doc == node2->doc)) {
421 
422 	l1 = -((ptrdiff_t) node1->content);
423 	l2 = -((ptrdiff_t) node2->content);
424 	if (l1 < l2)
425 	    return(1);
426 	if (l1 > l2)
427 	    return(-1);
428     }
429 
430     for (cur = node1->next;cur != NULL;cur = cur->next)
431 	if (cur == node2)
432 	    return(1);
433     return(-1); /* assume there is no sibling list corruption */
434 }
435 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
436 
437 /*
438  * Wrapper for the Timsort argorithm from timsort.h
439  */
440 #ifdef WITH_TIM_SORT
441 #define SORT_NAME libxml_domnode
442 #define SORT_TYPE xmlNodePtr
443 /**
444  * wrap_cmp:
445  * @x: a node
446  * @y: another node
447  *
448  * Comparison function for the Timsort implementation
449  *
450  * Returns -2 in case of error -1 if first point < second point, 0 if
451  *         it's the same node, +1 otherwise
452  */
453 static
454 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
455 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
456     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
457     {
458         int res = xmlXPathCmpNodesExt(x, y);
459         return res == -2 ? res : -res;
460     }
461 #else
462     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
463     {
464         int res = xmlXPathCmpNodes(x, y);
465         return res == -2 ? res : -res;
466     }
467 #endif
468 #define SORT_CMP(x, y)  (wrap_cmp(x, y))
469 #include "timsort.h"
470 #endif /* WITH_TIM_SORT */
471 
472 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
473 
474 /************************************************************************
475  *									*
476  *			Floating point stuff				*
477  *									*
478  ************************************************************************/
479 
480 #ifndef TRIO_REPLACE_STDIO
481 #define TRIO_PUBLIC static
482 #endif
483 #include "trionan.c"
484 
485 /*
486  * The lack of portability of this section of the libc is annoying !
487  */
488 double xmlXPathNAN = 0;
489 double xmlXPathPINF = 1;
490 double xmlXPathNINF = -1;
491 static double xmlXPathNZERO = 0; /* not exported from headers */
492 static int xmlXPathInitialized = 0;
493 
494 /**
495  * xmlXPathInit:
496  *
497  * Initialize the XPath environment
498  */
499 void
500 xmlXPathInit(void) {
501     if (xmlXPathInitialized) return;
502 
503     xmlXPathPINF = trio_pinf();
504     xmlXPathNINF = trio_ninf();
505     xmlXPathNAN = trio_nan();
506     xmlXPathNZERO = trio_nzero();
507 
508     xmlXPathInitialized = 1;
509 }
510 
511 /**
512  * xmlXPathIsNaN:
513  * @val:  a double value
514  *
515  * Provides a portable isnan() function to detect whether a double
516  * is a NotaNumber. Based on trio code
517  * http://sourceforge.net/projects/ctrio/
518  *
519  * Returns 1 if the value is a NaN, 0 otherwise
520  */
521 int
522 xmlXPathIsNaN(double val) {
523     return(trio_isnan(val));
524 }
525 
526 /**
527  * xmlXPathIsInf:
528  * @val:  a double value
529  *
530  * Provides a portable isinf() function to detect whether a double
531  * is a +Infinite or -Infinite. Based on trio code
532  * http://sourceforge.net/projects/ctrio/
533  *
534  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
535  */
536 int
537 xmlXPathIsInf(double val) {
538     return(trio_isinf(val));
539 }
540 
541 #endif /* SCHEMAS or XPATH */
542 #ifdef LIBXML_XPATH_ENABLED
543 /**
544  * xmlXPathGetSign:
545  * @val:  a double value
546  *
547  * Provides a portable function to detect the sign of a double
548  * Modified from trio code
549  * http://sourceforge.net/projects/ctrio/
550  *
551  * Returns 1 if the value is Negative, 0 if positive
552  */
553 static int
554 xmlXPathGetSign(double val) {
555     return(trio_signbit(val));
556 }
557 
558 
559 /*
560  * TODO: when compatibility allows remove all "fake node libxslt" strings
561  *       the test should just be name[0] = ' '
562  */
563 #ifdef DEBUG_XPATH_EXPRESSION
564 #define DEBUG_STEP
565 #define DEBUG_EXPR
566 #define DEBUG_EVAL_COUNTS
567 #endif
568 
569 static xmlNs xmlXPathXMLNamespaceStruct = {
570     NULL,
571     XML_NAMESPACE_DECL,
572     XML_XML_NAMESPACE,
573     BAD_CAST "xml",
574     NULL,
575     NULL
576 };
577 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
578 #ifndef LIBXML_THREAD_ENABLED
579 /*
580  * Optimizer is disabled only when threaded apps are detected while
581  * the library ain't compiled for thread safety.
582  */
583 static int xmlXPathDisableOptimizer = 0;
584 #endif
585 
586 /************************************************************************
587  *									*
588  *			Error handling routines				*
589  *									*
590  ************************************************************************/
591 
592 /**
593  * XP_ERRORNULL:
594  * @X:  the error code
595  *
596  * Macro to raise an XPath error and return NULL.
597  */
598 #define XP_ERRORNULL(X)							\
599     { xmlXPathErr(ctxt, X); return(NULL); }
600 
601 /*
602  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
603  */
604 static const char *xmlXPathErrorMessages[] = {
605     "Ok\n",
606     "Number encoding\n",
607     "Unfinished literal\n",
608     "Start of literal\n",
609     "Expected $ for variable reference\n",
610     "Undefined variable\n",
611     "Invalid predicate\n",
612     "Invalid expression\n",
613     "Missing closing curly brace\n",
614     "Unregistered function\n",
615     "Invalid operand\n",
616     "Invalid type\n",
617     "Invalid number of arguments\n",
618     "Invalid context size\n",
619     "Invalid context position\n",
620     "Memory allocation error\n",
621     "Syntax error\n",
622     "Resource error\n",
623     "Sub resource error\n",
624     "Undefined namespace prefix\n",
625     "Encoding error\n",
626     "Char out of XML range\n",
627     "Invalid or incomplete context\n",
628     "Stack usage error\n",
629     "Forbidden variable\n",
630     "?? Unknown error ??\n"	/* Must be last in the list! */
631 };
632 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
633 		   sizeof(xmlXPathErrorMessages[0])) - 1)
634 /**
635  * xmlXPathErrMemory:
636  * @ctxt:  an XPath context
637  * @extra:  extra informations
638  *
639  * Handle a redefinition of attribute error
640  */
641 static void
642 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
643 {
644     if (ctxt != NULL) {
645         if (extra) {
646             xmlChar buf[200];
647 
648             xmlStrPrintf(buf, 200,
649                          "Memory allocation failed : %s\n",
650                          extra);
651             ctxt->lastError.message = (char *) xmlStrdup(buf);
652         } else {
653             ctxt->lastError.message = (char *)
654 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
655         }
656         ctxt->lastError.domain = XML_FROM_XPATH;
657         ctxt->lastError.code = XML_ERR_NO_MEMORY;
658 	if (ctxt->error != NULL)
659 	    ctxt->error(ctxt->userData, &ctxt->lastError);
660     } else {
661         if (extra)
662             __xmlRaiseError(NULL, NULL, NULL,
663                             NULL, NULL, XML_FROM_XPATH,
664                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
665                             extra, NULL, NULL, 0, 0,
666                             "Memory allocation failed : %s\n", extra);
667         else
668             __xmlRaiseError(NULL, NULL, NULL,
669                             NULL, NULL, XML_FROM_XPATH,
670                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
671                             NULL, NULL, NULL, 0, 0,
672                             "Memory allocation failed\n");
673     }
674 }
675 
676 /**
677  * xmlXPathPErrMemory:
678  * @ctxt:  an XPath parser context
679  * @extra:  extra informations
680  *
681  * Handle a redefinition of attribute error
682  */
683 static void
684 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
685 {
686     if (ctxt == NULL)
687 	xmlXPathErrMemory(NULL, extra);
688     else {
689 	ctxt->error = XPATH_MEMORY_ERROR;
690 	xmlXPathErrMemory(ctxt->context, extra);
691     }
692 }
693 
694 /**
695  * xmlXPathErr:
696  * @ctxt:  a XPath parser context
697  * @error:  the error code
698  *
699  * Handle an XPath error
700  */
701 void
702 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
703 {
704     if ((error < 0) || (error > MAXERRNO))
705 	error = MAXERRNO;
706     if (ctxt == NULL) {
707 	__xmlRaiseError(NULL, NULL, NULL,
708 			NULL, NULL, XML_FROM_XPATH,
709 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
710 			XML_ERR_ERROR, NULL, 0,
711 			NULL, NULL, NULL, 0, 0,
712 			"%s", xmlXPathErrorMessages[error]);
713 	return;
714     }
715     ctxt->error = error;
716     if (ctxt->context == NULL) {
717 	__xmlRaiseError(NULL, NULL, NULL,
718 			NULL, NULL, XML_FROM_XPATH,
719 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
720 			XML_ERR_ERROR, NULL, 0,
721 			(const char *) ctxt->base, NULL, NULL,
722 			ctxt->cur - ctxt->base, 0,
723 			"%s", xmlXPathErrorMessages[error]);
724 	return;
725     }
726 
727     /* cleanup current last error */
728     xmlResetError(&ctxt->context->lastError);
729 
730     ctxt->context->lastError.domain = XML_FROM_XPATH;
731     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
732                            XPATH_EXPRESSION_OK;
733     ctxt->context->lastError.level = XML_ERR_ERROR;
734     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
735     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
736     ctxt->context->lastError.node = ctxt->context->debugNode;
737     if (ctxt->context->error != NULL) {
738 	ctxt->context->error(ctxt->context->userData,
739 	                     &ctxt->context->lastError);
740     } else {
741 	__xmlRaiseError(NULL, NULL, NULL,
742 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
743 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
744 			XML_ERR_ERROR, NULL, 0,
745 			(const char *) ctxt->base, NULL, NULL,
746 			ctxt->cur - ctxt->base, 0,
747 			"%s", xmlXPathErrorMessages[error]);
748     }
749 
750 }
751 
752 /**
753  * xmlXPatherror:
754  * @ctxt:  the XPath Parser context
755  * @file:  the file name
756  * @line:  the line number
757  * @no:  the error number
758  *
759  * Formats an error message.
760  */
761 void
762 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
763               int line ATTRIBUTE_UNUSED, int no) {
764     xmlXPathErr(ctxt, no);
765 }
766 
767 /************************************************************************
768  *									*
769  *			Utilities					*
770  *									*
771  ************************************************************************/
772 
773 /**
774  * xsltPointerList:
775  *
776  * Pointer-list for various purposes.
777  */
778 typedef struct _xmlPointerList xmlPointerList;
779 typedef xmlPointerList *xmlPointerListPtr;
780 struct _xmlPointerList {
781     void **items;
782     int number;
783     int size;
784 };
785 /*
786 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
787 * and here, we should make the functions public.
788 */
789 static int
790 xmlPointerListAddSize(xmlPointerListPtr list,
791 		       void *item,
792 		       int initialSize)
793 {
794     if (list->items == NULL) {
795 	if (initialSize <= 0)
796 	    initialSize = 1;
797 	list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
798 	if (list->items == NULL) {
799 	    xmlXPathErrMemory(NULL,
800 		"xmlPointerListCreate: allocating item\n");
801 	    return(-1);
802 	}
803 	list->number = 0;
804 	list->size = initialSize;
805     } else if (list->size <= list->number) {
806         if (list->size > 50000000) {
807 	    xmlXPathErrMemory(NULL,
808 		"xmlPointerListAddSize: re-allocating item\n");
809             return(-1);
810         }
811 	list->size *= 2;
812 	list->items = (void **) xmlRealloc(list->items,
813 	    list->size * sizeof(void *));
814 	if (list->items == NULL) {
815 	    xmlXPathErrMemory(NULL,
816 		"xmlPointerListAddSize: re-allocating item\n");
817 	    list->size = 0;
818 	    return(-1);
819 	}
820     }
821     list->items[list->number++] = item;
822     return(0);
823 }
824 
825 /**
826  * xsltPointerListCreate:
827  *
828  * Creates an xsltPointerList structure.
829  *
830  * Returns a xsltPointerList structure or NULL in case of an error.
831  */
832 static xmlPointerListPtr
833 xmlPointerListCreate(int initialSize)
834 {
835     xmlPointerListPtr ret;
836 
837     ret = xmlMalloc(sizeof(xmlPointerList));
838     if (ret == NULL) {
839 	xmlXPathErrMemory(NULL,
840 	    "xmlPointerListCreate: allocating item\n");
841 	return (NULL);
842     }
843     memset(ret, 0, sizeof(xmlPointerList));
844     if (initialSize > 0) {
845 	xmlPointerListAddSize(ret, NULL, initialSize);
846 	ret->number = 0;
847     }
848     return (ret);
849 }
850 
851 /**
852  * xsltPointerListFree:
853  *
854  * Frees the xsltPointerList structure. This does not free
855  * the content of the list.
856  */
857 static void
858 xmlPointerListFree(xmlPointerListPtr list)
859 {
860     if (list == NULL)
861 	return;
862     if (list->items != NULL)
863 	xmlFree(list->items);
864     xmlFree(list);
865 }
866 
867 /************************************************************************
868  *									*
869  *			Parser Types					*
870  *									*
871  ************************************************************************/
872 
873 /*
874  * Types are private:
875  */
876 
877 typedef enum {
878     XPATH_OP_END=0,
879     XPATH_OP_AND,
880     XPATH_OP_OR,
881     XPATH_OP_EQUAL,
882     XPATH_OP_CMP,
883     XPATH_OP_PLUS,
884     XPATH_OP_MULT,
885     XPATH_OP_UNION,
886     XPATH_OP_ROOT,
887     XPATH_OP_NODE,
888     XPATH_OP_RESET, /* 10 */
889     XPATH_OP_COLLECT,
890     XPATH_OP_VALUE, /* 12 */
891     XPATH_OP_VARIABLE,
892     XPATH_OP_FUNCTION,
893     XPATH_OP_ARG,
894     XPATH_OP_PREDICATE,
895     XPATH_OP_FILTER, /* 17 */
896     XPATH_OP_SORT /* 18 */
897 #ifdef LIBXML_XPTR_ENABLED
898     ,XPATH_OP_RANGETO
899 #endif
900 } xmlXPathOp;
901 
902 typedef enum {
903     AXIS_ANCESTOR = 1,
904     AXIS_ANCESTOR_OR_SELF,
905     AXIS_ATTRIBUTE,
906     AXIS_CHILD,
907     AXIS_DESCENDANT,
908     AXIS_DESCENDANT_OR_SELF,
909     AXIS_FOLLOWING,
910     AXIS_FOLLOWING_SIBLING,
911     AXIS_NAMESPACE,
912     AXIS_PARENT,
913     AXIS_PRECEDING,
914     AXIS_PRECEDING_SIBLING,
915     AXIS_SELF
916 } xmlXPathAxisVal;
917 
918 typedef enum {
919     NODE_TEST_NONE = 0,
920     NODE_TEST_TYPE = 1,
921     NODE_TEST_PI = 2,
922     NODE_TEST_ALL = 3,
923     NODE_TEST_NS = 4,
924     NODE_TEST_NAME = 5
925 } xmlXPathTestVal;
926 
927 typedef enum {
928     NODE_TYPE_NODE = 0,
929     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
930     NODE_TYPE_TEXT = XML_TEXT_NODE,
931     NODE_TYPE_PI = XML_PI_NODE
932 } xmlXPathTypeVal;
933 
934 typedef struct _xmlXPathStepOp xmlXPathStepOp;
935 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
936 struct _xmlXPathStepOp {
937     xmlXPathOp op;		/* The identifier of the operation */
938     int ch1;			/* First child */
939     int ch2;			/* Second child */
940     int value;
941     int value2;
942     int value3;
943     void *value4;
944     void *value5;
945     xmlXPathFunction cache;
946     void *cacheURI;
947 };
948 
949 struct _xmlXPathCompExpr {
950     int nbStep;			/* Number of steps in this expression */
951     int maxStep;		/* Maximum number of steps allocated */
952     xmlXPathStepOp *steps;	/* ops for computation of this expression */
953     int last;			/* index of last step in expression */
954     xmlChar *expr;		/* the expression being computed */
955     xmlDictPtr dict;		/* the dictionary to use if any */
956 #ifdef DEBUG_EVAL_COUNTS
957     int nb;
958     xmlChar *string;
959 #endif
960 #ifdef XPATH_STREAMING
961     xmlPatternPtr stream;
962 #endif
963 };
964 
965 /************************************************************************
966  *									*
967  *			Forward declarations				*
968  *									*
969  ************************************************************************/
970 static void
971 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
972 static void
973 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
974 static int
975 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
976                         xmlXPathStepOpPtr op, xmlNodePtr *first);
977 static int
978 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
979 			    xmlXPathStepOpPtr op,
980 			    int isPredicate);
981 
982 /************************************************************************
983  *									*
984  *			Parser Type functions				*
985  *									*
986  ************************************************************************/
987 
988 /**
989  * xmlXPathNewCompExpr:
990  *
991  * Create a new Xpath component
992  *
993  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
994  */
995 static xmlXPathCompExprPtr
996 xmlXPathNewCompExpr(void) {
997     xmlXPathCompExprPtr cur;
998 
999     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1000     if (cur == NULL) {
1001         xmlXPathErrMemory(NULL, "allocating component\n");
1002 	return(NULL);
1003     }
1004     memset(cur, 0, sizeof(xmlXPathCompExpr));
1005     cur->maxStep = 10;
1006     cur->nbStep = 0;
1007     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1008 	                                   sizeof(xmlXPathStepOp));
1009     if (cur->steps == NULL) {
1010         xmlXPathErrMemory(NULL, "allocating steps\n");
1011 	xmlFree(cur);
1012 	return(NULL);
1013     }
1014     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1015     cur->last = -1;
1016 #ifdef DEBUG_EVAL_COUNTS
1017     cur->nb = 0;
1018 #endif
1019     return(cur);
1020 }
1021 
1022 /**
1023  * xmlXPathFreeCompExpr:
1024  * @comp:  an XPATH comp
1025  *
1026  * Free up the memory allocated by @comp
1027  */
1028 void
1029 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1030 {
1031     xmlXPathStepOpPtr op;
1032     int i;
1033 
1034     if (comp == NULL)
1035         return;
1036     if (comp->dict == NULL) {
1037 	for (i = 0; i < comp->nbStep; i++) {
1038 	    op = &comp->steps[i];
1039 	    if (op->value4 != NULL) {
1040 		if (op->op == XPATH_OP_VALUE)
1041 		    xmlXPathFreeObject(op->value4);
1042 		else
1043 		    xmlFree(op->value4);
1044 	    }
1045 	    if (op->value5 != NULL)
1046 		xmlFree(op->value5);
1047 	}
1048     } else {
1049 	for (i = 0; i < comp->nbStep; i++) {
1050 	    op = &comp->steps[i];
1051 	    if (op->value4 != NULL) {
1052 		if (op->op == XPATH_OP_VALUE)
1053 		    xmlXPathFreeObject(op->value4);
1054 	    }
1055 	}
1056         xmlDictFree(comp->dict);
1057     }
1058     if (comp->steps != NULL) {
1059         xmlFree(comp->steps);
1060     }
1061 #ifdef DEBUG_EVAL_COUNTS
1062     if (comp->string != NULL) {
1063         xmlFree(comp->string);
1064     }
1065 #endif
1066 #ifdef XPATH_STREAMING
1067     if (comp->stream != NULL) {
1068         xmlFreePatternList(comp->stream);
1069     }
1070 #endif
1071     if (comp->expr != NULL) {
1072         xmlFree(comp->expr);
1073     }
1074 
1075     xmlFree(comp);
1076 }
1077 
1078 /**
1079  * xmlXPathCompExprAdd:
1080  * @comp:  the compiled expression
1081  * @ch1: first child index
1082  * @ch2: second child index
1083  * @op:  an op
1084  * @value:  the first int value
1085  * @value2:  the second int value
1086  * @value3:  the third int value
1087  * @value4:  the first string value
1088  * @value5:  the second string value
1089  *
1090  * Add a step to an XPath Compiled Expression
1091  *
1092  * Returns -1 in case of failure, the index otherwise
1093  */
1094 static int
1095 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1096    xmlXPathOp op, int value,
1097    int value2, int value3, void *value4, void *value5) {
1098     if (comp->nbStep >= comp->maxStep) {
1099 	xmlXPathStepOp *real;
1100 
1101         if (comp->maxStep >= XPATH_MAX_STEPS) {
1102 	    xmlXPathErrMemory(NULL, "adding step\n");
1103 	    return(-1);
1104         }
1105 	comp->maxStep *= 2;
1106 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1107 		                      comp->maxStep * sizeof(xmlXPathStepOp));
1108 	if (real == NULL) {
1109 	    comp->maxStep /= 2;
1110 	    xmlXPathErrMemory(NULL, "adding step\n");
1111 	    return(-1);
1112 	}
1113 	comp->steps = real;
1114     }
1115     comp->last = comp->nbStep;
1116     comp->steps[comp->nbStep].ch1 = ch1;
1117     comp->steps[comp->nbStep].ch2 = ch2;
1118     comp->steps[comp->nbStep].op = op;
1119     comp->steps[comp->nbStep].value = value;
1120     comp->steps[comp->nbStep].value2 = value2;
1121     comp->steps[comp->nbStep].value3 = value3;
1122     if ((comp->dict != NULL) &&
1123         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1124 	 (op == XPATH_OP_COLLECT))) {
1125         if (value4 != NULL) {
1126 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
1127 	        (void *)xmlDictLookup(comp->dict, value4, -1);
1128 	    xmlFree(value4);
1129 	} else
1130 	    comp->steps[comp->nbStep].value4 = NULL;
1131         if (value5 != NULL) {
1132 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
1133 	        (void *)xmlDictLookup(comp->dict, value5, -1);
1134 	    xmlFree(value5);
1135 	} else
1136 	    comp->steps[comp->nbStep].value5 = NULL;
1137     } else {
1138 	comp->steps[comp->nbStep].value4 = value4;
1139 	comp->steps[comp->nbStep].value5 = value5;
1140     }
1141     comp->steps[comp->nbStep].cache = NULL;
1142     return(comp->nbStep++);
1143 }
1144 
1145 /**
1146  * xmlXPathCompSwap:
1147  * @comp:  the compiled expression
1148  * @op: operation index
1149  *
1150  * Swaps 2 operations in the compiled expression
1151  */
1152 static void
1153 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1154     int tmp;
1155 
1156 #ifndef LIBXML_THREAD_ENABLED
1157     /*
1158      * Since this manipulates possibly shared variables, this is
1159      * disabled if one detects that the library is used in a multithreaded
1160      * application
1161      */
1162     if (xmlXPathDisableOptimizer)
1163 	return;
1164 #endif
1165 
1166     tmp = op->ch1;
1167     op->ch1 = op->ch2;
1168     op->ch2 = tmp;
1169 }
1170 
1171 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
1172     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
1173 	                (op), (val), (val2), (val3), (val4), (val5))
1174 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
1175     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
1176 	                (op), (val), (val2), (val3), (val4), (val5))
1177 
1178 #define PUSH_LEAVE_EXPR(op, val, val2)					\
1179 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1180 
1181 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
1182 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1183 
1184 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
1185 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
1186 			(val), (val2), 0 ,NULL ,NULL)
1187 
1188 /************************************************************************
1189  *									*
1190  *		XPath object cache structures				*
1191  *									*
1192  ************************************************************************/
1193 
1194 /* #define XP_DEFAULT_CACHE_ON */
1195 
1196 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1197 
1198 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1199 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1200 struct _xmlXPathContextCache {
1201     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1202     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1203     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1204     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1205     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1206     int maxNodeset;
1207     int maxString;
1208     int maxBoolean;
1209     int maxNumber;
1210     int maxMisc;
1211 #ifdef XP_DEBUG_OBJ_USAGE
1212     int dbgCachedAll;
1213     int dbgCachedNodeset;
1214     int dbgCachedString;
1215     int dbgCachedBool;
1216     int dbgCachedNumber;
1217     int dbgCachedPoint;
1218     int dbgCachedRange;
1219     int dbgCachedLocset;
1220     int dbgCachedUsers;
1221     int dbgCachedXSLTTree;
1222     int dbgCachedUndefined;
1223 
1224 
1225     int dbgReusedAll;
1226     int dbgReusedNodeset;
1227     int dbgReusedString;
1228     int dbgReusedBool;
1229     int dbgReusedNumber;
1230     int dbgReusedPoint;
1231     int dbgReusedRange;
1232     int dbgReusedLocset;
1233     int dbgReusedUsers;
1234     int dbgReusedXSLTTree;
1235     int dbgReusedUndefined;
1236 
1237 #endif
1238 };
1239 
1240 /************************************************************************
1241  *									*
1242  *		Debugging related functions				*
1243  *									*
1244  ************************************************************************/
1245 
1246 #define STRANGE							\
1247     xmlGenericError(xmlGenericErrorContext,				\
1248 	    "Internal error at %s:%d\n",				\
1249             __FILE__, __LINE__);
1250 
1251 #ifdef LIBXML_DEBUG_ENABLED
1252 static void
1253 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1254     int i;
1255     char shift[100];
1256 
1257     for (i = 0;((i < depth) && (i < 25));i++)
1258         shift[2 * i] = shift[2 * i + 1] = ' ';
1259     shift[2 * i] = shift[2 * i + 1] = 0;
1260     if (cur == NULL) {
1261 	fprintf(output, "%s", shift);
1262 	fprintf(output, "Node is NULL !\n");
1263 	return;
1264 
1265     }
1266 
1267     if ((cur->type == XML_DOCUMENT_NODE) ||
1268 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
1269 	fprintf(output, "%s", shift);
1270 	fprintf(output, " /\n");
1271     } else if (cur->type == XML_ATTRIBUTE_NODE)
1272 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1273     else
1274 	xmlDebugDumpOneNode(output, cur, depth);
1275 }
1276 static void
1277 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1278     xmlNodePtr tmp;
1279     int i;
1280     char shift[100];
1281 
1282     for (i = 0;((i < depth) && (i < 25));i++)
1283         shift[2 * i] = shift[2 * i + 1] = ' ';
1284     shift[2 * i] = shift[2 * i + 1] = 0;
1285     if (cur == NULL) {
1286 	fprintf(output, "%s", shift);
1287 	fprintf(output, "Node is NULL !\n");
1288 	return;
1289 
1290     }
1291 
1292     while (cur != NULL) {
1293 	tmp = cur;
1294 	cur = cur->next;
1295 	xmlDebugDumpOneNode(output, tmp, depth);
1296     }
1297 }
1298 
1299 static void
1300 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1301     int i;
1302     char shift[100];
1303 
1304     for (i = 0;((i < depth) && (i < 25));i++)
1305         shift[2 * i] = shift[2 * i + 1] = ' ';
1306     shift[2 * i] = shift[2 * i + 1] = 0;
1307 
1308     if (cur == NULL) {
1309 	fprintf(output, "%s", shift);
1310 	fprintf(output, "NodeSet is NULL !\n");
1311 	return;
1312 
1313     }
1314 
1315     if (cur != NULL) {
1316 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1317 	for (i = 0;i < cur->nodeNr;i++) {
1318 	    fprintf(output, "%s", shift);
1319 	    fprintf(output, "%d", i + 1);
1320 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1321 	}
1322     }
1323 }
1324 
1325 static void
1326 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1327     int i;
1328     char shift[100];
1329 
1330     for (i = 0;((i < depth) && (i < 25));i++)
1331         shift[2 * i] = shift[2 * i + 1] = ' ';
1332     shift[2 * i] = shift[2 * i + 1] = 0;
1333 
1334     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1335 	fprintf(output, "%s", shift);
1336 	fprintf(output, "Value Tree is NULL !\n");
1337 	return;
1338 
1339     }
1340 
1341     fprintf(output, "%s", shift);
1342     fprintf(output, "%d", i + 1);
1343     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1344 }
1345 #if defined(LIBXML_XPTR_ENABLED)
1346 static void
1347 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1348     int i;
1349     char shift[100];
1350 
1351     for (i = 0;((i < depth) && (i < 25));i++)
1352         shift[2 * i] = shift[2 * i + 1] = ' ';
1353     shift[2 * i] = shift[2 * i + 1] = 0;
1354 
1355     if (cur == NULL) {
1356 	fprintf(output, "%s", shift);
1357 	fprintf(output, "LocationSet is NULL !\n");
1358 	return;
1359 
1360     }
1361 
1362     for (i = 0;i < cur->locNr;i++) {
1363 	fprintf(output, "%s", shift);
1364         fprintf(output, "%d : ", i + 1);
1365 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1366     }
1367 }
1368 #endif /* LIBXML_XPTR_ENABLED */
1369 
1370 /**
1371  * xmlXPathDebugDumpObject:
1372  * @output:  the FILE * to dump the output
1373  * @cur:  the object to inspect
1374  * @depth:  indentation level
1375  *
1376  * Dump the content of the object for debugging purposes
1377  */
1378 void
1379 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1380     int i;
1381     char shift[100];
1382 
1383     if (output == NULL) return;
1384 
1385     for (i = 0;((i < depth) && (i < 25));i++)
1386         shift[2 * i] = shift[2 * i + 1] = ' ';
1387     shift[2 * i] = shift[2 * i + 1] = 0;
1388 
1389 
1390     fprintf(output, "%s", shift);
1391 
1392     if (cur == NULL) {
1393         fprintf(output, "Object is empty (NULL)\n");
1394 	return;
1395     }
1396     switch(cur->type) {
1397         case XPATH_UNDEFINED:
1398 	    fprintf(output, "Object is uninitialized\n");
1399 	    break;
1400         case XPATH_NODESET:
1401 	    fprintf(output, "Object is a Node Set :\n");
1402 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1403 	    break;
1404 	case XPATH_XSLT_TREE:
1405 	    fprintf(output, "Object is an XSLT value tree :\n");
1406 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1407 	    break;
1408         case XPATH_BOOLEAN:
1409 	    fprintf(output, "Object is a Boolean : ");
1410 	    if (cur->boolval) fprintf(output, "true\n");
1411 	    else fprintf(output, "false\n");
1412 	    break;
1413         case XPATH_NUMBER:
1414 	    switch (xmlXPathIsInf(cur->floatval)) {
1415 	    case 1:
1416 		fprintf(output, "Object is a number : Infinity\n");
1417 		break;
1418 	    case -1:
1419 		fprintf(output, "Object is a number : -Infinity\n");
1420 		break;
1421 	    default:
1422 		if (xmlXPathIsNaN(cur->floatval)) {
1423 		    fprintf(output, "Object is a number : NaN\n");
1424 		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1425 		    fprintf(output, "Object is a number : 0\n");
1426 		} else {
1427 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1428 		}
1429 	    }
1430 	    break;
1431         case XPATH_STRING:
1432 	    fprintf(output, "Object is a string : ");
1433 	    xmlDebugDumpString(output, cur->stringval);
1434 	    fprintf(output, "\n");
1435 	    break;
1436 	case XPATH_POINT:
1437 	    fprintf(output, "Object is a point : index %d in node", cur->index);
1438 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1439 	    fprintf(output, "\n");
1440 	    break;
1441 	case XPATH_RANGE:
1442 	    if ((cur->user2 == NULL) ||
1443 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1444 		fprintf(output, "Object is a collapsed range :\n");
1445 		fprintf(output, "%s", shift);
1446 		if (cur->index >= 0)
1447 		    fprintf(output, "index %d in ", cur->index);
1448 		fprintf(output, "node\n");
1449 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1450 			              depth + 1);
1451 	    } else  {
1452 		fprintf(output, "Object is a range :\n");
1453 		fprintf(output, "%s", shift);
1454 		fprintf(output, "From ");
1455 		if (cur->index >= 0)
1456 		    fprintf(output, "index %d in ", cur->index);
1457 		fprintf(output, "node\n");
1458 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1459 			              depth + 1);
1460 		fprintf(output, "%s", shift);
1461 		fprintf(output, "To ");
1462 		if (cur->index2 >= 0)
1463 		    fprintf(output, "index %d in ", cur->index2);
1464 		fprintf(output, "node\n");
1465 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1466 			              depth + 1);
1467 		fprintf(output, "\n");
1468 	    }
1469 	    break;
1470 	case XPATH_LOCATIONSET:
1471 #if defined(LIBXML_XPTR_ENABLED)
1472 	    fprintf(output, "Object is a Location Set:\n");
1473 	    xmlXPathDebugDumpLocationSet(output,
1474 		    (xmlLocationSetPtr) cur->user, depth);
1475 #endif
1476 	    break;
1477 	case XPATH_USERS:
1478 	    fprintf(output, "Object is user defined\n");
1479 	    break;
1480     }
1481 }
1482 
1483 static void
1484 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1485 	                     xmlXPathStepOpPtr op, int depth) {
1486     int i;
1487     char shift[100];
1488 
1489     for (i = 0;((i < depth) && (i < 25));i++)
1490         shift[2 * i] = shift[2 * i + 1] = ' ';
1491     shift[2 * i] = shift[2 * i + 1] = 0;
1492 
1493     fprintf(output, "%s", shift);
1494     if (op == NULL) {
1495 	fprintf(output, "Step is NULL\n");
1496 	return;
1497     }
1498     switch (op->op) {
1499         case XPATH_OP_END:
1500 	    fprintf(output, "END"); break;
1501         case XPATH_OP_AND:
1502 	    fprintf(output, "AND"); break;
1503         case XPATH_OP_OR:
1504 	    fprintf(output, "OR"); break;
1505         case XPATH_OP_EQUAL:
1506 	     if (op->value)
1507 		 fprintf(output, "EQUAL =");
1508 	     else
1509 		 fprintf(output, "EQUAL !=");
1510 	     break;
1511         case XPATH_OP_CMP:
1512 	     if (op->value)
1513 		 fprintf(output, "CMP <");
1514 	     else
1515 		 fprintf(output, "CMP >");
1516 	     if (!op->value2)
1517 		 fprintf(output, "=");
1518 	     break;
1519         case XPATH_OP_PLUS:
1520 	     if (op->value == 0)
1521 		 fprintf(output, "PLUS -");
1522 	     else if (op->value == 1)
1523 		 fprintf(output, "PLUS +");
1524 	     else if (op->value == 2)
1525 		 fprintf(output, "PLUS unary -");
1526 	     else if (op->value == 3)
1527 		 fprintf(output, "PLUS unary - -");
1528 	     break;
1529         case XPATH_OP_MULT:
1530 	     if (op->value == 0)
1531 		 fprintf(output, "MULT *");
1532 	     else if (op->value == 1)
1533 		 fprintf(output, "MULT div");
1534 	     else
1535 		 fprintf(output, "MULT mod");
1536 	     break;
1537         case XPATH_OP_UNION:
1538 	     fprintf(output, "UNION"); break;
1539         case XPATH_OP_ROOT:
1540 	     fprintf(output, "ROOT"); break;
1541         case XPATH_OP_NODE:
1542 	     fprintf(output, "NODE"); break;
1543         case XPATH_OP_RESET:
1544 	     fprintf(output, "RESET"); break;
1545         case XPATH_OP_SORT:
1546 	     fprintf(output, "SORT"); break;
1547         case XPATH_OP_COLLECT: {
1548 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1549 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1550 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1551 	    const xmlChar *prefix = op->value4;
1552 	    const xmlChar *name = op->value5;
1553 
1554 	    fprintf(output, "COLLECT ");
1555 	    switch (axis) {
1556 		case AXIS_ANCESTOR:
1557 		    fprintf(output, " 'ancestors' "); break;
1558 		case AXIS_ANCESTOR_OR_SELF:
1559 		    fprintf(output, " 'ancestors-or-self' "); break;
1560 		case AXIS_ATTRIBUTE:
1561 		    fprintf(output, " 'attributes' "); break;
1562 		case AXIS_CHILD:
1563 		    fprintf(output, " 'child' "); break;
1564 		case AXIS_DESCENDANT:
1565 		    fprintf(output, " 'descendant' "); break;
1566 		case AXIS_DESCENDANT_OR_SELF:
1567 		    fprintf(output, " 'descendant-or-self' "); break;
1568 		case AXIS_FOLLOWING:
1569 		    fprintf(output, " 'following' "); break;
1570 		case AXIS_FOLLOWING_SIBLING:
1571 		    fprintf(output, " 'following-siblings' "); break;
1572 		case AXIS_NAMESPACE:
1573 		    fprintf(output, " 'namespace' "); break;
1574 		case AXIS_PARENT:
1575 		    fprintf(output, " 'parent' "); break;
1576 		case AXIS_PRECEDING:
1577 		    fprintf(output, " 'preceding' "); break;
1578 		case AXIS_PRECEDING_SIBLING:
1579 		    fprintf(output, " 'preceding-sibling' "); break;
1580 		case AXIS_SELF:
1581 		    fprintf(output, " 'self' "); break;
1582 	    }
1583 	    switch (test) {
1584                 case NODE_TEST_NONE:
1585 		    fprintf(output, "'none' "); break;
1586                 case NODE_TEST_TYPE:
1587 		    fprintf(output, "'type' "); break;
1588                 case NODE_TEST_PI:
1589 		    fprintf(output, "'PI' "); break;
1590                 case NODE_TEST_ALL:
1591 		    fprintf(output, "'all' "); break;
1592                 case NODE_TEST_NS:
1593 		    fprintf(output, "'namespace' "); break;
1594                 case NODE_TEST_NAME:
1595 		    fprintf(output, "'name' "); break;
1596 	    }
1597 	    switch (type) {
1598                 case NODE_TYPE_NODE:
1599 		    fprintf(output, "'node' "); break;
1600                 case NODE_TYPE_COMMENT:
1601 		    fprintf(output, "'comment' "); break;
1602                 case NODE_TYPE_TEXT:
1603 		    fprintf(output, "'text' "); break;
1604                 case NODE_TYPE_PI:
1605 		    fprintf(output, "'PI' "); break;
1606 	    }
1607 	    if (prefix != NULL)
1608 		fprintf(output, "%s:", prefix);
1609 	    if (name != NULL)
1610 		fprintf(output, "%s", (const char *) name);
1611 	    break;
1612 
1613         }
1614 	case XPATH_OP_VALUE: {
1615 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1616 
1617 	    fprintf(output, "ELEM ");
1618 	    xmlXPathDebugDumpObject(output, object, 0);
1619 	    goto finish;
1620 	}
1621 	case XPATH_OP_VARIABLE: {
1622 	    const xmlChar *prefix = op->value5;
1623 	    const xmlChar *name = op->value4;
1624 
1625 	    if (prefix != NULL)
1626 		fprintf(output, "VARIABLE %s:%s", prefix, name);
1627 	    else
1628 		fprintf(output, "VARIABLE %s", name);
1629 	    break;
1630 	}
1631 	case XPATH_OP_FUNCTION: {
1632 	    int nbargs = op->value;
1633 	    const xmlChar *prefix = op->value5;
1634 	    const xmlChar *name = op->value4;
1635 
1636 	    if (prefix != NULL)
1637 		fprintf(output, "FUNCTION %s:%s(%d args)",
1638 			prefix, name, nbargs);
1639 	    else
1640 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1641 	    break;
1642 	}
1643         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1644         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1645         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1646 #ifdef LIBXML_XPTR_ENABLED
1647         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1648 #endif
1649 	default:
1650         fprintf(output, "UNKNOWN %d\n", op->op); return;
1651     }
1652     fprintf(output, "\n");
1653 finish:
1654     if (op->ch1 >= 0)
1655 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1656     if (op->ch2 >= 0)
1657 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1658 }
1659 
1660 /**
1661  * xmlXPathDebugDumpCompExpr:
1662  * @output:  the FILE * for the output
1663  * @comp:  the precompiled XPath expression
1664  * @depth:  the indentation level.
1665  *
1666  * Dumps the tree of the compiled XPath expression.
1667  */
1668 void
1669 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1670 	                  int depth) {
1671     int i;
1672     char shift[100];
1673 
1674     if ((output == NULL) || (comp == NULL)) return;
1675 
1676     for (i = 0;((i < depth) && (i < 25));i++)
1677         shift[2 * i] = shift[2 * i + 1] = ' ';
1678     shift[2 * i] = shift[2 * i + 1] = 0;
1679 
1680     fprintf(output, "%s", shift);
1681 
1682 #ifdef XPATH_STREAMING
1683     if (comp->stream) {
1684         fprintf(output, "Streaming Expression\n");
1685     } else
1686 #endif
1687     {
1688         fprintf(output, "Compiled Expression : %d elements\n",
1689                 comp->nbStep);
1690         i = comp->last;
1691         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1692     }
1693 }
1694 
1695 #ifdef XP_DEBUG_OBJ_USAGE
1696 
1697 /*
1698 * XPath object usage related debugging variables.
1699 */
1700 static int xmlXPathDebugObjCounterUndefined = 0;
1701 static int xmlXPathDebugObjCounterNodeset = 0;
1702 static int xmlXPathDebugObjCounterBool = 0;
1703 static int xmlXPathDebugObjCounterNumber = 0;
1704 static int xmlXPathDebugObjCounterString = 0;
1705 static int xmlXPathDebugObjCounterPoint = 0;
1706 static int xmlXPathDebugObjCounterRange = 0;
1707 static int xmlXPathDebugObjCounterLocset = 0;
1708 static int xmlXPathDebugObjCounterUsers = 0;
1709 static int xmlXPathDebugObjCounterXSLTTree = 0;
1710 static int xmlXPathDebugObjCounterAll = 0;
1711 
1712 static int xmlXPathDebugObjTotalUndefined = 0;
1713 static int xmlXPathDebugObjTotalNodeset = 0;
1714 static int xmlXPathDebugObjTotalBool = 0;
1715 static int xmlXPathDebugObjTotalNumber = 0;
1716 static int xmlXPathDebugObjTotalString = 0;
1717 static int xmlXPathDebugObjTotalPoint = 0;
1718 static int xmlXPathDebugObjTotalRange = 0;
1719 static int xmlXPathDebugObjTotalLocset = 0;
1720 static int xmlXPathDebugObjTotalUsers = 0;
1721 static int xmlXPathDebugObjTotalXSLTTree = 0;
1722 static int xmlXPathDebugObjTotalAll = 0;
1723 
1724 static int xmlXPathDebugObjMaxUndefined = 0;
1725 static int xmlXPathDebugObjMaxNodeset = 0;
1726 static int xmlXPathDebugObjMaxBool = 0;
1727 static int xmlXPathDebugObjMaxNumber = 0;
1728 static int xmlXPathDebugObjMaxString = 0;
1729 static int xmlXPathDebugObjMaxPoint = 0;
1730 static int xmlXPathDebugObjMaxRange = 0;
1731 static int xmlXPathDebugObjMaxLocset = 0;
1732 static int xmlXPathDebugObjMaxUsers = 0;
1733 static int xmlXPathDebugObjMaxXSLTTree = 0;
1734 static int xmlXPathDebugObjMaxAll = 0;
1735 
1736 /* REVISIT TODO: Make this static when committing */
1737 static void
1738 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1739 {
1740     if (ctxt != NULL) {
1741 	if (ctxt->cache != NULL) {
1742 	    xmlXPathContextCachePtr cache =
1743 		(xmlXPathContextCachePtr) ctxt->cache;
1744 
1745 	    cache->dbgCachedAll = 0;
1746 	    cache->dbgCachedNodeset = 0;
1747 	    cache->dbgCachedString = 0;
1748 	    cache->dbgCachedBool = 0;
1749 	    cache->dbgCachedNumber = 0;
1750 	    cache->dbgCachedPoint = 0;
1751 	    cache->dbgCachedRange = 0;
1752 	    cache->dbgCachedLocset = 0;
1753 	    cache->dbgCachedUsers = 0;
1754 	    cache->dbgCachedXSLTTree = 0;
1755 	    cache->dbgCachedUndefined = 0;
1756 
1757 	    cache->dbgReusedAll = 0;
1758 	    cache->dbgReusedNodeset = 0;
1759 	    cache->dbgReusedString = 0;
1760 	    cache->dbgReusedBool = 0;
1761 	    cache->dbgReusedNumber = 0;
1762 	    cache->dbgReusedPoint = 0;
1763 	    cache->dbgReusedRange = 0;
1764 	    cache->dbgReusedLocset = 0;
1765 	    cache->dbgReusedUsers = 0;
1766 	    cache->dbgReusedXSLTTree = 0;
1767 	    cache->dbgReusedUndefined = 0;
1768 	}
1769     }
1770 
1771     xmlXPathDebugObjCounterUndefined = 0;
1772     xmlXPathDebugObjCounterNodeset = 0;
1773     xmlXPathDebugObjCounterBool = 0;
1774     xmlXPathDebugObjCounterNumber = 0;
1775     xmlXPathDebugObjCounterString = 0;
1776     xmlXPathDebugObjCounterPoint = 0;
1777     xmlXPathDebugObjCounterRange = 0;
1778     xmlXPathDebugObjCounterLocset = 0;
1779     xmlXPathDebugObjCounterUsers = 0;
1780     xmlXPathDebugObjCounterXSLTTree = 0;
1781     xmlXPathDebugObjCounterAll = 0;
1782 
1783     xmlXPathDebugObjTotalUndefined = 0;
1784     xmlXPathDebugObjTotalNodeset = 0;
1785     xmlXPathDebugObjTotalBool = 0;
1786     xmlXPathDebugObjTotalNumber = 0;
1787     xmlXPathDebugObjTotalString = 0;
1788     xmlXPathDebugObjTotalPoint = 0;
1789     xmlXPathDebugObjTotalRange = 0;
1790     xmlXPathDebugObjTotalLocset = 0;
1791     xmlXPathDebugObjTotalUsers = 0;
1792     xmlXPathDebugObjTotalXSLTTree = 0;
1793     xmlXPathDebugObjTotalAll = 0;
1794 
1795     xmlXPathDebugObjMaxUndefined = 0;
1796     xmlXPathDebugObjMaxNodeset = 0;
1797     xmlXPathDebugObjMaxBool = 0;
1798     xmlXPathDebugObjMaxNumber = 0;
1799     xmlXPathDebugObjMaxString = 0;
1800     xmlXPathDebugObjMaxPoint = 0;
1801     xmlXPathDebugObjMaxRange = 0;
1802     xmlXPathDebugObjMaxLocset = 0;
1803     xmlXPathDebugObjMaxUsers = 0;
1804     xmlXPathDebugObjMaxXSLTTree = 0;
1805     xmlXPathDebugObjMaxAll = 0;
1806 
1807 }
1808 
1809 static void
1810 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1811 			      xmlXPathObjectType objType)
1812 {
1813     int isCached = 0;
1814 
1815     if (ctxt != NULL) {
1816 	if (ctxt->cache != NULL) {
1817 	    xmlXPathContextCachePtr cache =
1818 		(xmlXPathContextCachePtr) ctxt->cache;
1819 
1820 	    isCached = 1;
1821 
1822 	    cache->dbgReusedAll++;
1823 	    switch (objType) {
1824 		case XPATH_UNDEFINED:
1825 		    cache->dbgReusedUndefined++;
1826 		    break;
1827 		case XPATH_NODESET:
1828 		    cache->dbgReusedNodeset++;
1829 		    break;
1830 		case XPATH_BOOLEAN:
1831 		    cache->dbgReusedBool++;
1832 		    break;
1833 		case XPATH_NUMBER:
1834 		    cache->dbgReusedNumber++;
1835 		    break;
1836 		case XPATH_STRING:
1837 		    cache->dbgReusedString++;
1838 		    break;
1839 		case XPATH_POINT:
1840 		    cache->dbgReusedPoint++;
1841 		    break;
1842 		case XPATH_RANGE:
1843 		    cache->dbgReusedRange++;
1844 		    break;
1845 		case XPATH_LOCATIONSET:
1846 		    cache->dbgReusedLocset++;
1847 		    break;
1848 		case XPATH_USERS:
1849 		    cache->dbgReusedUsers++;
1850 		    break;
1851 		case XPATH_XSLT_TREE:
1852 		    cache->dbgReusedXSLTTree++;
1853 		    break;
1854 		default:
1855 		    break;
1856 	    }
1857 	}
1858     }
1859 
1860     switch (objType) {
1861 	case XPATH_UNDEFINED:
1862 	    if (! isCached)
1863 		xmlXPathDebugObjTotalUndefined++;
1864 	    xmlXPathDebugObjCounterUndefined++;
1865 	    if (xmlXPathDebugObjCounterUndefined >
1866 		xmlXPathDebugObjMaxUndefined)
1867 		xmlXPathDebugObjMaxUndefined =
1868 		    xmlXPathDebugObjCounterUndefined;
1869 	    break;
1870 	case XPATH_NODESET:
1871 	    if (! isCached)
1872 		xmlXPathDebugObjTotalNodeset++;
1873 	    xmlXPathDebugObjCounterNodeset++;
1874 	    if (xmlXPathDebugObjCounterNodeset >
1875 		xmlXPathDebugObjMaxNodeset)
1876 		xmlXPathDebugObjMaxNodeset =
1877 		    xmlXPathDebugObjCounterNodeset;
1878 	    break;
1879 	case XPATH_BOOLEAN:
1880 	    if (! isCached)
1881 		xmlXPathDebugObjTotalBool++;
1882 	    xmlXPathDebugObjCounterBool++;
1883 	    if (xmlXPathDebugObjCounterBool >
1884 		xmlXPathDebugObjMaxBool)
1885 		xmlXPathDebugObjMaxBool =
1886 		    xmlXPathDebugObjCounterBool;
1887 	    break;
1888 	case XPATH_NUMBER:
1889 	    if (! isCached)
1890 		xmlXPathDebugObjTotalNumber++;
1891 	    xmlXPathDebugObjCounterNumber++;
1892 	    if (xmlXPathDebugObjCounterNumber >
1893 		xmlXPathDebugObjMaxNumber)
1894 		xmlXPathDebugObjMaxNumber =
1895 		    xmlXPathDebugObjCounterNumber;
1896 	    break;
1897 	case XPATH_STRING:
1898 	    if (! isCached)
1899 		xmlXPathDebugObjTotalString++;
1900 	    xmlXPathDebugObjCounterString++;
1901 	    if (xmlXPathDebugObjCounterString >
1902 		xmlXPathDebugObjMaxString)
1903 		xmlXPathDebugObjMaxString =
1904 		    xmlXPathDebugObjCounterString;
1905 	    break;
1906 	case XPATH_POINT:
1907 	    if (! isCached)
1908 		xmlXPathDebugObjTotalPoint++;
1909 	    xmlXPathDebugObjCounterPoint++;
1910 	    if (xmlXPathDebugObjCounterPoint >
1911 		xmlXPathDebugObjMaxPoint)
1912 		xmlXPathDebugObjMaxPoint =
1913 		    xmlXPathDebugObjCounterPoint;
1914 	    break;
1915 	case XPATH_RANGE:
1916 	    if (! isCached)
1917 		xmlXPathDebugObjTotalRange++;
1918 	    xmlXPathDebugObjCounterRange++;
1919 	    if (xmlXPathDebugObjCounterRange >
1920 		xmlXPathDebugObjMaxRange)
1921 		xmlXPathDebugObjMaxRange =
1922 		    xmlXPathDebugObjCounterRange;
1923 	    break;
1924 	case XPATH_LOCATIONSET:
1925 	    if (! isCached)
1926 		xmlXPathDebugObjTotalLocset++;
1927 	    xmlXPathDebugObjCounterLocset++;
1928 	    if (xmlXPathDebugObjCounterLocset >
1929 		xmlXPathDebugObjMaxLocset)
1930 		xmlXPathDebugObjMaxLocset =
1931 		    xmlXPathDebugObjCounterLocset;
1932 	    break;
1933 	case XPATH_USERS:
1934 	    if (! isCached)
1935 		xmlXPathDebugObjTotalUsers++;
1936 	    xmlXPathDebugObjCounterUsers++;
1937 	    if (xmlXPathDebugObjCounterUsers >
1938 		xmlXPathDebugObjMaxUsers)
1939 		xmlXPathDebugObjMaxUsers =
1940 		    xmlXPathDebugObjCounterUsers;
1941 	    break;
1942 	case XPATH_XSLT_TREE:
1943 	    if (! isCached)
1944 		xmlXPathDebugObjTotalXSLTTree++;
1945 	    xmlXPathDebugObjCounterXSLTTree++;
1946 	    if (xmlXPathDebugObjCounterXSLTTree >
1947 		xmlXPathDebugObjMaxXSLTTree)
1948 		xmlXPathDebugObjMaxXSLTTree =
1949 		    xmlXPathDebugObjCounterXSLTTree;
1950 	    break;
1951 	default:
1952 	    break;
1953     }
1954     if (! isCached)
1955 	xmlXPathDebugObjTotalAll++;
1956     xmlXPathDebugObjCounterAll++;
1957     if (xmlXPathDebugObjCounterAll >
1958 	xmlXPathDebugObjMaxAll)
1959 	xmlXPathDebugObjMaxAll =
1960 	    xmlXPathDebugObjCounterAll;
1961 }
1962 
1963 static void
1964 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1965 			      xmlXPathObjectType objType)
1966 {
1967     int isCached = 0;
1968 
1969     if (ctxt != NULL) {
1970 	if (ctxt->cache != NULL) {
1971 	    xmlXPathContextCachePtr cache =
1972 		(xmlXPathContextCachePtr) ctxt->cache;
1973 
1974 	    isCached = 1;
1975 
1976 	    cache->dbgCachedAll++;
1977 	    switch (objType) {
1978 		case XPATH_UNDEFINED:
1979 		    cache->dbgCachedUndefined++;
1980 		    break;
1981 		case XPATH_NODESET:
1982 		    cache->dbgCachedNodeset++;
1983 		    break;
1984 		case XPATH_BOOLEAN:
1985 		    cache->dbgCachedBool++;
1986 		    break;
1987 		case XPATH_NUMBER:
1988 		    cache->dbgCachedNumber++;
1989 		    break;
1990 		case XPATH_STRING:
1991 		    cache->dbgCachedString++;
1992 		    break;
1993 		case XPATH_POINT:
1994 		    cache->dbgCachedPoint++;
1995 		    break;
1996 		case XPATH_RANGE:
1997 		    cache->dbgCachedRange++;
1998 		    break;
1999 		case XPATH_LOCATIONSET:
2000 		    cache->dbgCachedLocset++;
2001 		    break;
2002 		case XPATH_USERS:
2003 		    cache->dbgCachedUsers++;
2004 		    break;
2005 		case XPATH_XSLT_TREE:
2006 		    cache->dbgCachedXSLTTree++;
2007 		    break;
2008 		default:
2009 		    break;
2010 	    }
2011 
2012 	}
2013     }
2014     switch (objType) {
2015 	case XPATH_UNDEFINED:
2016 	    xmlXPathDebugObjCounterUndefined--;
2017 	    break;
2018 	case XPATH_NODESET:
2019 	    xmlXPathDebugObjCounterNodeset--;
2020 	    break;
2021 	case XPATH_BOOLEAN:
2022 	    xmlXPathDebugObjCounterBool--;
2023 	    break;
2024 	case XPATH_NUMBER:
2025 	    xmlXPathDebugObjCounterNumber--;
2026 	    break;
2027 	case XPATH_STRING:
2028 	    xmlXPathDebugObjCounterString--;
2029 	    break;
2030 	case XPATH_POINT:
2031 	    xmlXPathDebugObjCounterPoint--;
2032 	    break;
2033 	case XPATH_RANGE:
2034 	    xmlXPathDebugObjCounterRange--;
2035 	    break;
2036 	case XPATH_LOCATIONSET:
2037 	    xmlXPathDebugObjCounterLocset--;
2038 	    break;
2039 	case XPATH_USERS:
2040 	    xmlXPathDebugObjCounterUsers--;
2041 	    break;
2042 	case XPATH_XSLT_TREE:
2043 	    xmlXPathDebugObjCounterXSLTTree--;
2044 	    break;
2045 	default:
2046 	    break;
2047     }
2048     xmlXPathDebugObjCounterAll--;
2049 }
2050 
2051 /* REVISIT TODO: Make this static when committing */
2052 static void
2053 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2054 {
2055     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2056 	reqXSLTTree, reqUndefined;
2057     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2058 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2059     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2060 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2061     int leftObjs = xmlXPathDebugObjCounterAll;
2062 
2063     reqAll = xmlXPathDebugObjTotalAll;
2064     reqNodeset = xmlXPathDebugObjTotalNodeset;
2065     reqString = xmlXPathDebugObjTotalString;
2066     reqBool = xmlXPathDebugObjTotalBool;
2067     reqNumber = xmlXPathDebugObjTotalNumber;
2068     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2069     reqUndefined = xmlXPathDebugObjTotalUndefined;
2070 
2071     printf("# XPath object usage:\n");
2072 
2073     if (ctxt != NULL) {
2074 	if (ctxt->cache != NULL) {
2075 	    xmlXPathContextCachePtr cache =
2076 		(xmlXPathContextCachePtr) ctxt->cache;
2077 
2078 	    reAll = cache->dbgReusedAll;
2079 	    reqAll += reAll;
2080 	    reNodeset = cache->dbgReusedNodeset;
2081 	    reqNodeset += reNodeset;
2082 	    reString = cache->dbgReusedString;
2083 	    reqString += reString;
2084 	    reBool = cache->dbgReusedBool;
2085 	    reqBool += reBool;
2086 	    reNumber = cache->dbgReusedNumber;
2087 	    reqNumber += reNumber;
2088 	    reXSLTTree = cache->dbgReusedXSLTTree;
2089 	    reqXSLTTree += reXSLTTree;
2090 	    reUndefined = cache->dbgReusedUndefined;
2091 	    reqUndefined += reUndefined;
2092 
2093 	    caAll = cache->dbgCachedAll;
2094 	    caBool = cache->dbgCachedBool;
2095 	    caNodeset = cache->dbgCachedNodeset;
2096 	    caString = cache->dbgCachedString;
2097 	    caNumber = cache->dbgCachedNumber;
2098 	    caXSLTTree = cache->dbgCachedXSLTTree;
2099 	    caUndefined = cache->dbgCachedUndefined;
2100 
2101 	    if (cache->nodesetObjs)
2102 		leftObjs -= cache->nodesetObjs->number;
2103 	    if (cache->stringObjs)
2104 		leftObjs -= cache->stringObjs->number;
2105 	    if (cache->booleanObjs)
2106 		leftObjs -= cache->booleanObjs->number;
2107 	    if (cache->numberObjs)
2108 		leftObjs -= cache->numberObjs->number;
2109 	    if (cache->miscObjs)
2110 		leftObjs -= cache->miscObjs->number;
2111 	}
2112     }
2113 
2114     printf("# all\n");
2115     printf("#   total  : %d\n", reqAll);
2116     printf("#   left  : %d\n", leftObjs);
2117     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2118     printf("#   reused : %d\n", reAll);
2119     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2120 
2121     printf("# node-sets\n");
2122     printf("#   total  : %d\n", reqNodeset);
2123     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2124     printf("#   reused : %d\n", reNodeset);
2125     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2126 
2127     printf("# strings\n");
2128     printf("#   total  : %d\n", reqString);
2129     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2130     printf("#   reused : %d\n", reString);
2131     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2132 
2133     printf("# booleans\n");
2134     printf("#   total  : %d\n", reqBool);
2135     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2136     printf("#   reused : %d\n", reBool);
2137     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2138 
2139     printf("# numbers\n");
2140     printf("#   total  : %d\n", reqNumber);
2141     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2142     printf("#   reused : %d\n", reNumber);
2143     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2144 
2145     printf("# XSLT result tree fragments\n");
2146     printf("#   total  : %d\n", reqXSLTTree);
2147     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2148     printf("#   reused : %d\n", reXSLTTree);
2149     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2150 
2151     printf("# undefined\n");
2152     printf("#   total  : %d\n", reqUndefined);
2153     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2154     printf("#   reused : %d\n", reUndefined);
2155     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2156 
2157 }
2158 
2159 #endif /* XP_DEBUG_OBJ_USAGE */
2160 
2161 #endif /* LIBXML_DEBUG_ENABLED */
2162 
2163 /************************************************************************
2164  *									*
2165  *			XPath object caching				*
2166  *									*
2167  ************************************************************************/
2168 
2169 /**
2170  * xmlXPathNewCache:
2171  *
2172  * Create a new object cache
2173  *
2174  * Returns the xmlXPathCache just allocated.
2175  */
2176 static xmlXPathContextCachePtr
2177 xmlXPathNewCache(void)
2178 {
2179     xmlXPathContextCachePtr ret;
2180 
2181     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2182     if (ret == NULL) {
2183         xmlXPathErrMemory(NULL, "creating object cache\n");
2184 	return(NULL);
2185     }
2186     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2187     ret->maxNodeset = 100;
2188     ret->maxString = 100;
2189     ret->maxBoolean = 100;
2190     ret->maxNumber = 100;
2191     ret->maxMisc = 100;
2192     return(ret);
2193 }
2194 
2195 static void
2196 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2197 {
2198     int i;
2199     xmlXPathObjectPtr obj;
2200 
2201     if (list == NULL)
2202 	return;
2203 
2204     for (i = 0; i < list->number; i++) {
2205 	obj = list->items[i];
2206 	/*
2207 	* Note that it is already assured that we don't need to
2208 	* look out for namespace nodes in the node-set.
2209 	*/
2210 	if (obj->nodesetval != NULL) {
2211 	    if (obj->nodesetval->nodeTab != NULL)
2212 		xmlFree(obj->nodesetval->nodeTab);
2213 	    xmlFree(obj->nodesetval);
2214 	}
2215 	xmlFree(obj);
2216 #ifdef XP_DEBUG_OBJ_USAGE
2217 	xmlXPathDebugObjCounterAll--;
2218 #endif
2219     }
2220     xmlPointerListFree(list);
2221 }
2222 
2223 static void
2224 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2225 {
2226     if (cache == NULL)
2227 	return;
2228     if (cache->nodesetObjs)
2229 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2230     if (cache->stringObjs)
2231 	xmlXPathCacheFreeObjectList(cache->stringObjs);
2232     if (cache->booleanObjs)
2233 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
2234     if (cache->numberObjs)
2235 	xmlXPathCacheFreeObjectList(cache->numberObjs);
2236     if (cache->miscObjs)
2237 	xmlXPathCacheFreeObjectList(cache->miscObjs);
2238     xmlFree(cache);
2239 }
2240 
2241 /**
2242  * xmlXPathContextSetCache:
2243  *
2244  * @ctxt:  the XPath context
2245  * @active: enables/disables (creates/frees) the cache
2246  * @value: a value with semantics dependant on @options
2247  * @options: options (currently only the value 0 is used)
2248  *
2249  * Creates/frees an object cache on the XPath context.
2250  * If activates XPath objects (xmlXPathObject) will be cached internally
2251  * to be reused.
2252  * @options:
2253  *   0: This will set the XPath object caching:
2254  *      @value:
2255  *        This will set the maximum number of XPath objects
2256  *        to be cached per slot
2257  *        There are 5 slots for: node-set, string, number, boolean, and
2258  *        misc objects. Use <0 for the default number (100).
2259  *   Other values for @options have currently no effect.
2260  *
2261  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2262  */
2263 int
2264 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2265 			int active,
2266 			int value,
2267 			int options)
2268 {
2269     if (ctxt == NULL)
2270 	return(-1);
2271     if (active) {
2272 	xmlXPathContextCachePtr cache;
2273 
2274 	if (ctxt->cache == NULL) {
2275 	    ctxt->cache = xmlXPathNewCache();
2276 	    if (ctxt->cache == NULL)
2277 		return(-1);
2278 	}
2279 	cache = (xmlXPathContextCachePtr) ctxt->cache;
2280 	if (options == 0) {
2281 	    if (value < 0)
2282 		value = 100;
2283 	    cache->maxNodeset = value;
2284 	    cache->maxString = value;
2285 	    cache->maxNumber = value;
2286 	    cache->maxBoolean = value;
2287 	    cache->maxMisc = value;
2288 	}
2289     } else if (ctxt->cache != NULL) {
2290 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2291 	ctxt->cache = NULL;
2292     }
2293     return(0);
2294 }
2295 
2296 /**
2297  * xmlXPathCacheWrapNodeSet:
2298  * @ctxt: the XPath context
2299  * @val:  the NodePtr value
2300  *
2301  * This is the cached version of xmlXPathWrapNodeSet().
2302  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2303  *
2304  * Returns the created or reused object.
2305  */
2306 static xmlXPathObjectPtr
2307 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2308 {
2309     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2310 	xmlXPathContextCachePtr cache =
2311 	    (xmlXPathContextCachePtr) ctxt->cache;
2312 
2313 	if ((cache->miscObjs != NULL) &&
2314 	    (cache->miscObjs->number != 0))
2315 	{
2316 	    xmlXPathObjectPtr ret;
2317 
2318 	    ret = (xmlXPathObjectPtr)
2319 		cache->miscObjs->items[--cache->miscObjs->number];
2320 	    ret->type = XPATH_NODESET;
2321 	    ret->nodesetval = val;
2322 #ifdef XP_DEBUG_OBJ_USAGE
2323 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2324 #endif
2325 	    return(ret);
2326 	}
2327     }
2328 
2329     return(xmlXPathWrapNodeSet(val));
2330 
2331 }
2332 
2333 /**
2334  * xmlXPathCacheWrapString:
2335  * @ctxt: the XPath context
2336  * @val:  the xmlChar * value
2337  *
2338  * This is the cached version of xmlXPathWrapString().
2339  * Wraps the @val string into an XPath object.
2340  *
2341  * Returns the created or reused object.
2342  */
2343 static xmlXPathObjectPtr
2344 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2345 {
2346     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2347 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2348 
2349 	if ((cache->stringObjs != NULL) &&
2350 	    (cache->stringObjs->number != 0))
2351 	{
2352 
2353 	    xmlXPathObjectPtr ret;
2354 
2355 	    ret = (xmlXPathObjectPtr)
2356 		cache->stringObjs->items[--cache->stringObjs->number];
2357 	    ret->type = XPATH_STRING;
2358 	    ret->stringval = val;
2359 #ifdef XP_DEBUG_OBJ_USAGE
2360 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2361 #endif
2362 	    return(ret);
2363 	} else if ((cache->miscObjs != NULL) &&
2364 	    (cache->miscObjs->number != 0))
2365 	{
2366 	    xmlXPathObjectPtr ret;
2367 	    /*
2368 	    * Fallback to misc-cache.
2369 	    */
2370 	    ret = (xmlXPathObjectPtr)
2371 		cache->miscObjs->items[--cache->miscObjs->number];
2372 
2373 	    ret->type = XPATH_STRING;
2374 	    ret->stringval = val;
2375 #ifdef XP_DEBUG_OBJ_USAGE
2376 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2377 #endif
2378 	    return(ret);
2379 	}
2380     }
2381     return(xmlXPathWrapString(val));
2382 }
2383 
2384 /**
2385  * xmlXPathCacheNewNodeSet:
2386  * @ctxt: the XPath context
2387  * @val:  the NodePtr value
2388  *
2389  * This is the cached version of xmlXPathNewNodeSet().
2390  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2391  * it with the single Node @val
2392  *
2393  * Returns the created or reused object.
2394  */
2395 static xmlXPathObjectPtr
2396 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2397 {
2398     if ((ctxt != NULL) && (ctxt->cache)) {
2399 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2400 
2401 	if ((cache->nodesetObjs != NULL) &&
2402 	    (cache->nodesetObjs->number != 0))
2403 	{
2404 	    xmlXPathObjectPtr ret;
2405 	    /*
2406 	    * Use the nodset-cache.
2407 	    */
2408 	    ret = (xmlXPathObjectPtr)
2409 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
2410 	    ret->type = XPATH_NODESET;
2411 	    ret->boolval = 0;
2412 	    if (val) {
2413 		if ((ret->nodesetval->nodeMax == 0) ||
2414 		    (val->type == XML_NAMESPACE_DECL))
2415 		{
2416 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2417 		} else {
2418 		    ret->nodesetval->nodeTab[0] = val;
2419 		    ret->nodesetval->nodeNr = 1;
2420 		}
2421 	    }
2422 #ifdef XP_DEBUG_OBJ_USAGE
2423 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2424 #endif
2425 	    return(ret);
2426 	} else if ((cache->miscObjs != NULL) &&
2427 	    (cache->miscObjs->number != 0))
2428 	{
2429 	    xmlXPathObjectPtr ret;
2430 	    /*
2431 	    * Fallback to misc-cache.
2432 	    */
2433 
2434 	    ret = (xmlXPathObjectPtr)
2435 		cache->miscObjs->items[--cache->miscObjs->number];
2436 
2437 	    ret->type = XPATH_NODESET;
2438 	    ret->boolval = 0;
2439 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
2440 	    if (ret->nodesetval == NULL) {
2441 		ctxt->lastError.domain = XML_FROM_XPATH;
2442 		ctxt->lastError.code = XML_ERR_NO_MEMORY;
2443 		return(NULL);
2444 	    }
2445 #ifdef XP_DEBUG_OBJ_USAGE
2446 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2447 #endif
2448 	    return(ret);
2449 	}
2450     }
2451     return(xmlXPathNewNodeSet(val));
2452 }
2453 
2454 /**
2455  * xmlXPathCacheNewCString:
2456  * @ctxt: the XPath context
2457  * @val:  the char * value
2458  *
2459  * This is the cached version of xmlXPathNewCString().
2460  * Acquire an xmlXPathObjectPtr of type string and of value @val
2461  *
2462  * Returns the created or reused object.
2463  */
2464 static xmlXPathObjectPtr
2465 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2466 {
2467     if ((ctxt != NULL) && (ctxt->cache)) {
2468 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2469 
2470 	if ((cache->stringObjs != NULL) &&
2471 	    (cache->stringObjs->number != 0))
2472 	{
2473 	    xmlXPathObjectPtr ret;
2474 
2475 	    ret = (xmlXPathObjectPtr)
2476 		cache->stringObjs->items[--cache->stringObjs->number];
2477 
2478 	    ret->type = XPATH_STRING;
2479 	    ret->stringval = xmlStrdup(BAD_CAST val);
2480 #ifdef XP_DEBUG_OBJ_USAGE
2481 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2482 #endif
2483 	    return(ret);
2484 	} else if ((cache->miscObjs != NULL) &&
2485 	    (cache->miscObjs->number != 0))
2486 	{
2487 	    xmlXPathObjectPtr ret;
2488 
2489 	    ret = (xmlXPathObjectPtr)
2490 		cache->miscObjs->items[--cache->miscObjs->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 	}
2499     }
2500     return(xmlXPathNewCString(val));
2501 }
2502 
2503 /**
2504  * xmlXPathCacheNewString:
2505  * @ctxt: the XPath context
2506  * @val:  the xmlChar * value
2507  *
2508  * This is the cached version of xmlXPathNewString().
2509  * Acquire an xmlXPathObjectPtr of type string and of value @val
2510  *
2511  * Returns the created or reused object.
2512  */
2513 static xmlXPathObjectPtr
2514 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2515 {
2516     if ((ctxt != NULL) && (ctxt->cache)) {
2517 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2518 
2519 	if ((cache->stringObjs != NULL) &&
2520 	    (cache->stringObjs->number != 0))
2521 	{
2522 	    xmlXPathObjectPtr ret;
2523 
2524 	    ret = (xmlXPathObjectPtr)
2525 		cache->stringObjs->items[--cache->stringObjs->number];
2526 	    ret->type = XPATH_STRING;
2527 	    if (val != NULL)
2528 		ret->stringval = xmlStrdup(val);
2529 	    else
2530 		ret->stringval = xmlStrdup((const xmlChar *)"");
2531 #ifdef XP_DEBUG_OBJ_USAGE
2532 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2533 #endif
2534 	    return(ret);
2535 	} else if ((cache->miscObjs != NULL) &&
2536 	    (cache->miscObjs->number != 0))
2537 	{
2538 	    xmlXPathObjectPtr ret;
2539 
2540 	    ret = (xmlXPathObjectPtr)
2541 		cache->miscObjs->items[--cache->miscObjs->number];
2542 
2543 	    ret->type = XPATH_STRING;
2544 	    if (val != NULL)
2545 		ret->stringval = xmlStrdup(val);
2546 	    else
2547 		ret->stringval = xmlStrdup((const xmlChar *)"");
2548 #ifdef XP_DEBUG_OBJ_USAGE
2549 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2550 #endif
2551 	    return(ret);
2552 	}
2553     }
2554     return(xmlXPathNewString(val));
2555 }
2556 
2557 /**
2558  * xmlXPathCacheNewBoolean:
2559  * @ctxt: the XPath context
2560  * @val:  the boolean value
2561  *
2562  * This is the cached version of xmlXPathNewBoolean().
2563  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2564  *
2565  * Returns the created or reused object.
2566  */
2567 static xmlXPathObjectPtr
2568 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2569 {
2570     if ((ctxt != NULL) && (ctxt->cache)) {
2571 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2572 
2573 	if ((cache->booleanObjs != NULL) &&
2574 	    (cache->booleanObjs->number != 0))
2575 	{
2576 	    xmlXPathObjectPtr ret;
2577 
2578 	    ret = (xmlXPathObjectPtr)
2579 		cache->booleanObjs->items[--cache->booleanObjs->number];
2580 	    ret->type = XPATH_BOOLEAN;
2581 	    ret->boolval = (val != 0);
2582 #ifdef XP_DEBUG_OBJ_USAGE
2583 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2584 #endif
2585 	    return(ret);
2586 	} else if ((cache->miscObjs != NULL) &&
2587 	    (cache->miscObjs->number != 0))
2588 	{
2589 	    xmlXPathObjectPtr ret;
2590 
2591 	    ret = (xmlXPathObjectPtr)
2592 		cache->miscObjs->items[--cache->miscObjs->number];
2593 
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 	}
2601     }
2602     return(xmlXPathNewBoolean(val));
2603 }
2604 
2605 /**
2606  * xmlXPathCacheNewFloat:
2607  * @ctxt: the XPath context
2608  * @val:  the double value
2609  *
2610  * This is the cached version of xmlXPathNewFloat().
2611  * Acquires an xmlXPathObjectPtr of type double and of value @val
2612  *
2613  * Returns the created or reused object.
2614  */
2615 static xmlXPathObjectPtr
2616 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2617 {
2618      if ((ctxt != NULL) && (ctxt->cache)) {
2619 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2620 
2621 	if ((cache->numberObjs != NULL) &&
2622 	    (cache->numberObjs->number != 0))
2623 	{
2624 	    xmlXPathObjectPtr ret;
2625 
2626 	    ret = (xmlXPathObjectPtr)
2627 		cache->numberObjs->items[--cache->numberObjs->number];
2628 	    ret->type = XPATH_NUMBER;
2629 	    ret->floatval = val;
2630 #ifdef XP_DEBUG_OBJ_USAGE
2631 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2632 #endif
2633 	    return(ret);
2634 	} else if ((cache->miscObjs != NULL) &&
2635 	    (cache->miscObjs->number != 0))
2636 	{
2637 	    xmlXPathObjectPtr ret;
2638 
2639 	    ret = (xmlXPathObjectPtr)
2640 		cache->miscObjs->items[--cache->miscObjs->number];
2641 
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 	}
2649     }
2650     return(xmlXPathNewFloat(val));
2651 }
2652 
2653 /**
2654  * xmlXPathCacheConvertString:
2655  * @ctxt: the XPath context
2656  * @val:  an XPath object
2657  *
2658  * This is the cached version of xmlXPathConvertString().
2659  * Converts an existing object to its string() equivalent
2660  *
2661  * Returns a created or reused object, the old one is freed (cached)
2662  *         (or the operation is done directly on @val)
2663  */
2664 
2665 static xmlXPathObjectPtr
2666 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2667     xmlChar *res = NULL;
2668 
2669     if (val == NULL)
2670 	return(xmlXPathCacheNewCString(ctxt, ""));
2671 
2672     switch (val->type) {
2673     case XPATH_UNDEFINED:
2674 #ifdef DEBUG_EXPR
2675 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2676 #endif
2677 	break;
2678     case XPATH_NODESET:
2679     case XPATH_XSLT_TREE:
2680 	res = xmlXPathCastNodeSetToString(val->nodesetval);
2681 	break;
2682     case XPATH_STRING:
2683 	return(val);
2684     case XPATH_BOOLEAN:
2685 	res = xmlXPathCastBooleanToString(val->boolval);
2686 	break;
2687     case XPATH_NUMBER:
2688 	res = xmlXPathCastNumberToString(val->floatval);
2689 	break;
2690     case XPATH_USERS:
2691     case XPATH_POINT:
2692     case XPATH_RANGE:
2693     case XPATH_LOCATIONSET:
2694 	TODO;
2695 	break;
2696     }
2697     xmlXPathReleaseObject(ctxt, val);
2698     if (res == NULL)
2699 	return(xmlXPathCacheNewCString(ctxt, ""));
2700     return(xmlXPathCacheWrapString(ctxt, res));
2701 }
2702 
2703 /**
2704  * xmlXPathCacheObjectCopy:
2705  * @ctxt: the XPath context
2706  * @val:  the original object
2707  *
2708  * This is the cached version of xmlXPathObjectCopy().
2709  * Acquire a copy of a given object
2710  *
2711  * Returns a created or reused created object.
2712  */
2713 static xmlXPathObjectPtr
2714 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2715 {
2716     if (val == NULL)
2717 	return(NULL);
2718 
2719     if (XP_HAS_CACHE(ctxt)) {
2720 	switch (val->type) {
2721 	    case XPATH_NODESET:
2722 		return(xmlXPathCacheWrapNodeSet(ctxt,
2723 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2724 	    case XPATH_STRING:
2725 		return(xmlXPathCacheNewString(ctxt, val->stringval));
2726 	    case XPATH_BOOLEAN:
2727 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2728 	    case XPATH_NUMBER:
2729 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2730 	    default:
2731 		break;
2732 	}
2733     }
2734     return(xmlXPathObjectCopy(val));
2735 }
2736 
2737 /**
2738  * xmlXPathCacheConvertBoolean:
2739  * @ctxt: the XPath context
2740  * @val:  an XPath object
2741  *
2742  * This is the cached version of xmlXPathConvertBoolean().
2743  * Converts an existing object to its boolean() equivalent
2744  *
2745  * Returns a created or reused object, the old one is freed (or the operation
2746  *         is done directly on @val)
2747  */
2748 static xmlXPathObjectPtr
2749 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2750     xmlXPathObjectPtr ret;
2751 
2752     if (val == NULL)
2753 	return(xmlXPathCacheNewBoolean(ctxt, 0));
2754     if (val->type == XPATH_BOOLEAN)
2755 	return(val);
2756     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2757     xmlXPathReleaseObject(ctxt, val);
2758     return(ret);
2759 }
2760 
2761 /**
2762  * xmlXPathCacheConvertNumber:
2763  * @ctxt: the XPath context
2764  * @val:  an XPath object
2765  *
2766  * This is the cached version of xmlXPathConvertNumber().
2767  * Converts an existing object to its number() equivalent
2768  *
2769  * Returns a created or reused object, the old one is freed (or the operation
2770  *         is done directly on @val)
2771  */
2772 static xmlXPathObjectPtr
2773 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2774     xmlXPathObjectPtr ret;
2775 
2776     if (val == NULL)
2777 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
2778     if (val->type == XPATH_NUMBER)
2779 	return(val);
2780     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2781     xmlXPathReleaseObject(ctxt, val);
2782     return(ret);
2783 }
2784 
2785 /************************************************************************
2786  *									*
2787  *		Parser stacks related functions and macros		*
2788  *									*
2789  ************************************************************************/
2790 
2791 /**
2792  * xmlXPathSetFrame:
2793  * @ctxt: an XPath parser context
2794  *
2795  * Set the callee evaluation frame
2796  *
2797  * Returns the previous frame value to be restored once done
2798  */
2799 static int
2800 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2801     int ret;
2802 
2803     if (ctxt == NULL)
2804         return(0);
2805     ret = ctxt->valueFrame;
2806     ctxt->valueFrame = ctxt->valueNr;
2807     return(ret);
2808 }
2809 
2810 /**
2811  * xmlXPathPopFrame:
2812  * @ctxt: an XPath parser context
2813  * @frame: the previous frame value
2814  *
2815  * Remove the callee evaluation frame
2816  */
2817 static void
2818 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2819     if (ctxt == NULL)
2820         return;
2821     if (ctxt->valueNr < ctxt->valueFrame) {
2822         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2823     }
2824     ctxt->valueFrame = frame;
2825 }
2826 
2827 /**
2828  * valuePop:
2829  * @ctxt: an XPath evaluation context
2830  *
2831  * Pops the top XPath object from the value stack
2832  *
2833  * Returns the XPath object just removed
2834  */
2835 xmlXPathObjectPtr
2836 valuePop(xmlXPathParserContextPtr ctxt)
2837 {
2838     xmlXPathObjectPtr ret;
2839 
2840     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2841         return (NULL);
2842 
2843     if (ctxt->valueNr <= ctxt->valueFrame) {
2844         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2845         return (NULL);
2846     }
2847 
2848     ctxt->valueNr--;
2849     if (ctxt->valueNr > 0)
2850         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2851     else
2852         ctxt->value = NULL;
2853     ret = ctxt->valueTab[ctxt->valueNr];
2854     ctxt->valueTab[ctxt->valueNr] = NULL;
2855     return (ret);
2856 }
2857 /**
2858  * valuePush:
2859  * @ctxt:  an XPath evaluation context
2860  * @value:  the XPath object
2861  *
2862  * Pushes a new XPath object on top of the value stack
2863  *
2864  * returns the number of items on the value stack
2865  */
2866 int
2867 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2868 {
2869     if ((ctxt == NULL) || (value == NULL)) return(-1);
2870     if (ctxt->valueNr >= ctxt->valueMax) {
2871         xmlXPathObjectPtr *tmp;
2872 
2873         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2874             xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2875             ctxt->error = XPATH_MEMORY_ERROR;
2876             return (0);
2877         }
2878         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2879                                              2 * ctxt->valueMax *
2880                                              sizeof(ctxt->valueTab[0]));
2881         if (tmp == NULL) {
2882             xmlXPathErrMemory(NULL, "pushing value\n");
2883             ctxt->error = XPATH_MEMORY_ERROR;
2884             return (0);
2885         }
2886         ctxt->valueMax *= 2;
2887 	ctxt->valueTab = tmp;
2888     }
2889     ctxt->valueTab[ctxt->valueNr] = value;
2890     ctxt->value = value;
2891     return (ctxt->valueNr++);
2892 }
2893 
2894 /**
2895  * xmlXPathPopBoolean:
2896  * @ctxt:  an XPath parser context
2897  *
2898  * Pops a boolean from the stack, handling conversion if needed.
2899  * Check error with #xmlXPathCheckError.
2900  *
2901  * Returns the boolean
2902  */
2903 int
2904 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2905     xmlXPathObjectPtr obj;
2906     int ret;
2907 
2908     obj = valuePop(ctxt);
2909     if (obj == NULL) {
2910 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2911 	return(0);
2912     }
2913     if (obj->type != XPATH_BOOLEAN)
2914 	ret = xmlXPathCastToBoolean(obj);
2915     else
2916         ret = obj->boolval;
2917     xmlXPathReleaseObject(ctxt->context, obj);
2918     return(ret);
2919 }
2920 
2921 /**
2922  * xmlXPathPopNumber:
2923  * @ctxt:  an XPath parser context
2924  *
2925  * Pops a number from the stack, handling conversion if needed.
2926  * Check error with #xmlXPathCheckError.
2927  *
2928  * Returns the number
2929  */
2930 double
2931 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2932     xmlXPathObjectPtr obj;
2933     double ret;
2934 
2935     obj = valuePop(ctxt);
2936     if (obj == NULL) {
2937 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2938 	return(0);
2939     }
2940     if (obj->type != XPATH_NUMBER)
2941 	ret = xmlXPathCastToNumber(obj);
2942     else
2943         ret = obj->floatval;
2944     xmlXPathReleaseObject(ctxt->context, obj);
2945     return(ret);
2946 }
2947 
2948 /**
2949  * xmlXPathPopString:
2950  * @ctxt:  an XPath parser context
2951  *
2952  * Pops a string from the stack, handling conversion if needed.
2953  * Check error with #xmlXPathCheckError.
2954  *
2955  * Returns the string
2956  */
2957 xmlChar *
2958 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2959     xmlXPathObjectPtr obj;
2960     xmlChar * ret;
2961 
2962     obj = valuePop(ctxt);
2963     if (obj == NULL) {
2964 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2965 	return(NULL);
2966     }
2967     ret = xmlXPathCastToString(obj);	/* this does required strdup */
2968     /* TODO: needs refactoring somewhere else */
2969     if (obj->stringval == ret)
2970 	obj->stringval = NULL;
2971     xmlXPathReleaseObject(ctxt->context, obj);
2972     return(ret);
2973 }
2974 
2975 /**
2976  * xmlXPathPopNodeSet:
2977  * @ctxt:  an XPath parser context
2978  *
2979  * Pops a node-set from the stack, handling conversion if needed.
2980  * Check error with #xmlXPathCheckError.
2981  *
2982  * Returns the node-set
2983  */
2984 xmlNodeSetPtr
2985 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2986     xmlXPathObjectPtr obj;
2987     xmlNodeSetPtr ret;
2988 
2989     if (ctxt == NULL) return(NULL);
2990     if (ctxt->value == NULL) {
2991 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2992 	return(NULL);
2993     }
2994     if (!xmlXPathStackIsNodeSet(ctxt)) {
2995 	xmlXPathSetTypeError(ctxt);
2996 	return(NULL);
2997     }
2998     obj = valuePop(ctxt);
2999     ret = obj->nodesetval;
3000 #if 0
3001     /* to fix memory leak of not clearing obj->user */
3002     if (obj->boolval && obj->user != NULL)
3003         xmlFreeNodeList((xmlNodePtr) obj->user);
3004 #endif
3005     obj->nodesetval = NULL;
3006     xmlXPathReleaseObject(ctxt->context, obj);
3007     return(ret);
3008 }
3009 
3010 /**
3011  * xmlXPathPopExternal:
3012  * @ctxt:  an XPath parser context
3013  *
3014  * Pops an external object from the stack, handling conversion if needed.
3015  * Check error with #xmlXPathCheckError.
3016  *
3017  * Returns the object
3018  */
3019 void *
3020 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3021     xmlXPathObjectPtr obj;
3022     void * ret;
3023 
3024     if ((ctxt == NULL) || (ctxt->value == NULL)) {
3025 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3026 	return(NULL);
3027     }
3028     if (ctxt->value->type != XPATH_USERS) {
3029 	xmlXPathSetTypeError(ctxt);
3030 	return(NULL);
3031     }
3032     obj = valuePop(ctxt);
3033     ret = obj->user;
3034     obj->user = NULL;
3035     xmlXPathReleaseObject(ctxt->context, obj);
3036     return(ret);
3037 }
3038 
3039 /*
3040  * Macros for accessing the content. Those should be used only by the parser,
3041  * and not exported.
3042  *
3043  * Dirty macros, i.e. one need to make assumption on the context to use them
3044  *
3045  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3046  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3047  *           in ISO-Latin or UTF-8.
3048  *           This should be used internally by the parser
3049  *           only to compare to ASCII values otherwise it would break when
3050  *           running with UTF-8 encoding.
3051  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3052  *           to compare on ASCII based substring.
3053  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3054  *           strings within the parser.
3055  *   CURRENT Returns the current char value, with the full decoding of
3056  *           UTF-8 if we are using this mode. It returns an int.
3057  *   NEXT    Skip to the next character, this does the proper decoding
3058  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3059  *           It returns the pointer to the current xmlChar.
3060  */
3061 
3062 #define CUR (*ctxt->cur)
3063 #define SKIP(val) ctxt->cur += (val)
3064 #define NXT(val) ctxt->cur[(val)]
3065 #define CUR_PTR ctxt->cur
3066 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3067 
3068 #define COPY_BUF(l,b,i,v)                                              \
3069     if (l == 1) b[i++] = (xmlChar) v;                                  \
3070     else i += xmlCopyChar(l,&b[i],v)
3071 
3072 #define NEXTL(l)  ctxt->cur += l
3073 
3074 #define SKIP_BLANKS							\
3075     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3076 
3077 #define CURRENT (*ctxt->cur)
3078 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3079 
3080 
3081 #ifndef DBL_DIG
3082 #define DBL_DIG 16
3083 #endif
3084 #ifndef DBL_EPSILON
3085 #define DBL_EPSILON 1E-9
3086 #endif
3087 
3088 #define UPPER_DOUBLE 1E9
3089 #define LOWER_DOUBLE 1E-5
3090 #define	LOWER_DOUBLE_EXP 5
3091 
3092 #define INTEGER_DIGITS DBL_DIG
3093 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3094 #define EXPONENT_DIGITS (3 + 2)
3095 
3096 /**
3097  * xmlXPathFormatNumber:
3098  * @number:     number to format
3099  * @buffer:     output buffer
3100  * @buffersize: size of output buffer
3101  *
3102  * Convert the number into a string representation.
3103  */
3104 static void
3105 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3106 {
3107     switch (xmlXPathIsInf(number)) {
3108     case 1:
3109 	if (buffersize > (int)sizeof("Infinity"))
3110 	    snprintf(buffer, buffersize, "Infinity");
3111 	break;
3112     case -1:
3113 	if (buffersize > (int)sizeof("-Infinity"))
3114 	    snprintf(buffer, buffersize, "-Infinity");
3115 	break;
3116     default:
3117 	if (xmlXPathIsNaN(number)) {
3118 	    if (buffersize > (int)sizeof("NaN"))
3119 		snprintf(buffer, buffersize, "NaN");
3120 	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
3121 	    snprintf(buffer, buffersize, "0");
3122 	} else if ((number > INT_MIN) && (number < INT_MAX) &&
3123                    (number == (int) number)) {
3124 	    char work[30];
3125 	    char *ptr, *cur;
3126 	    int value = (int) number;
3127 
3128             ptr = &buffer[0];
3129 	    if (value == 0) {
3130 		*ptr++ = '0';
3131 	    } else {
3132 		snprintf(work, 29, "%d", value);
3133 		cur = &work[0];
3134 		while ((*cur) && (ptr - buffer < buffersize)) {
3135 		    *ptr++ = *cur++;
3136 		}
3137 	    }
3138 	    if (ptr - buffer < buffersize) {
3139 		*ptr = 0;
3140 	    } else if (buffersize > 0) {
3141 		ptr--;
3142 		*ptr = 0;
3143 	    }
3144 	} else {
3145 	    /*
3146 	      For the dimension of work,
3147 	          DBL_DIG is number of significant digits
3148 		  EXPONENT is only needed for "scientific notation"
3149 	          3 is sign, decimal point, and terminating zero
3150 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3151 	      Note that this dimension is slightly (a few characters)
3152 	      larger than actually necessary.
3153 	    */
3154 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3155 	    int integer_place, fraction_place;
3156 	    char *ptr;
3157 	    char *after_fraction;
3158 	    double absolute_value;
3159 	    int size;
3160 
3161 	    absolute_value = fabs(number);
3162 
3163 	    /*
3164 	     * First choose format - scientific or regular floating point.
3165 	     * In either case, result is in work, and after_fraction points
3166 	     * just past the fractional part.
3167 	    */
3168 	    if ( ((absolute_value > UPPER_DOUBLE) ||
3169 		  (absolute_value < LOWER_DOUBLE)) &&
3170 		 (absolute_value != 0.0) ) {
3171 		/* Use scientific notation */
3172 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3173 		fraction_place = DBL_DIG - 1;
3174 		size = snprintf(work, sizeof(work),"%*.*e",
3175 			 integer_place, fraction_place, number);
3176 		while ((size > 0) && (work[size] != 'e')) size--;
3177 
3178 	    }
3179 	    else {
3180 		/* Use regular notation */
3181 		if (absolute_value > 0.0) {
3182 		    integer_place = (int)log10(absolute_value);
3183 		    if (integer_place > 0)
3184 		        fraction_place = DBL_DIG - integer_place - 1;
3185 		    else
3186 		        fraction_place = DBL_DIG - integer_place;
3187 		} else {
3188 		    fraction_place = 1;
3189 		}
3190 		size = snprintf(work, sizeof(work), "%0.*f",
3191 				fraction_place, number);
3192 	    }
3193 
3194 	    /* Remove leading spaces sometimes inserted by snprintf */
3195 	    while (work[0] == ' ') {
3196 	        for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3197 		size--;
3198 	    }
3199 
3200 	    /* Remove fractional trailing zeroes */
3201 	    after_fraction = work + size;
3202 	    ptr = after_fraction;
3203 	    while (*(--ptr) == '0')
3204 		;
3205 	    if (*ptr != '.')
3206 	        ptr++;
3207 	    while ((*ptr++ = *after_fraction++) != 0);
3208 
3209 	    /* Finally copy result back to caller */
3210 	    size = strlen(work) + 1;
3211 	    if (size > buffersize) {
3212 		work[buffersize - 1] = 0;
3213 		size = buffersize;
3214 	    }
3215 	    memmove(buffer, work, size);
3216 	}
3217 	break;
3218     }
3219 }
3220 
3221 
3222 /************************************************************************
3223  *									*
3224  *			Routines to handle NodeSets			*
3225  *									*
3226  ************************************************************************/
3227 
3228 /**
3229  * xmlXPathOrderDocElems:
3230  * @doc:  an input document
3231  *
3232  * Call this routine to speed up XPath computation on static documents.
3233  * This stamps all the element nodes with the document order
3234  * Like for line information, the order is kept in the element->content
3235  * field, the value stored is actually - the node number (starting at -1)
3236  * to be able to differentiate from line numbers.
3237  *
3238  * Returns the number of elements found in the document or -1 in case
3239  *    of error.
3240  */
3241 long
3242 xmlXPathOrderDocElems(xmlDocPtr doc) {
3243     ptrdiff_t count = 0;
3244     xmlNodePtr cur;
3245 
3246     if (doc == NULL)
3247 	return(-1);
3248     cur = doc->children;
3249     while (cur != NULL) {
3250 	if (cur->type == XML_ELEMENT_NODE) {
3251 	    cur->content = (void *) (-(++count));
3252 	    if (cur->children != NULL) {
3253 		cur = cur->children;
3254 		continue;
3255 	    }
3256 	}
3257 	if (cur->next != NULL) {
3258 	    cur = cur->next;
3259 	    continue;
3260 	}
3261 	do {
3262 	    cur = cur->parent;
3263 	    if (cur == NULL)
3264 		break;
3265 	    if (cur == (xmlNodePtr) doc) {
3266 		cur = NULL;
3267 		break;
3268 	    }
3269 	    if (cur->next != NULL) {
3270 		cur = cur->next;
3271 		break;
3272 	    }
3273 	} while (cur != NULL);
3274     }
3275     return((long) count);
3276 }
3277 
3278 /**
3279  * xmlXPathCmpNodes:
3280  * @node1:  the first node
3281  * @node2:  the second node
3282  *
3283  * Compare two nodes w.r.t document order
3284  *
3285  * Returns -2 in case of error 1 if first point < second point, 0 if
3286  *         it's the same node, -1 otherwise
3287  */
3288 int
3289 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3290     int depth1, depth2;
3291     int attr1 = 0, attr2 = 0;
3292     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3293     xmlNodePtr cur, root;
3294 
3295     if ((node1 == NULL) || (node2 == NULL))
3296 	return(-2);
3297     /*
3298      * a couple of optimizations which will avoid computations in most cases
3299      */
3300     if (node1 == node2)		/* trivial case */
3301 	return(0);
3302     if (node1->type == XML_ATTRIBUTE_NODE) {
3303 	attr1 = 1;
3304 	attrNode1 = node1;
3305 	node1 = node1->parent;
3306     }
3307     if (node2->type == XML_ATTRIBUTE_NODE) {
3308 	attr2 = 1;
3309 	attrNode2 = node2;
3310 	node2 = node2->parent;
3311     }
3312     if (node1 == node2) {
3313 	if (attr1 == attr2) {
3314 	    /* not required, but we keep attributes in order */
3315 	    if (attr1 != 0) {
3316 	        cur = attrNode2->prev;
3317 		while (cur != NULL) {
3318 		    if (cur == attrNode1)
3319 		        return (1);
3320 		    cur = cur->prev;
3321 		}
3322 		return (-1);
3323 	    }
3324 	    return(0);
3325 	}
3326 	if (attr2 == 1)
3327 	    return(1);
3328 	return(-1);
3329     }
3330     if ((node1->type == XML_NAMESPACE_DECL) ||
3331         (node2->type == XML_NAMESPACE_DECL))
3332 	return(1);
3333     if (node1 == node2->prev)
3334 	return(1);
3335     if (node1 == node2->next)
3336 	return(-1);
3337 
3338     /*
3339      * Speedup using document order if availble.
3340      */
3341     if ((node1->type == XML_ELEMENT_NODE) &&
3342 	(node2->type == XML_ELEMENT_NODE) &&
3343 	(0 > (ptrdiff_t) node1->content) &&
3344 	(0 > (ptrdiff_t) node2->content) &&
3345 	(node1->doc == node2->doc)) {
3346 	ptrdiff_t l1, l2;
3347 
3348 	l1 = -((ptrdiff_t) node1->content);
3349 	l2 = -((ptrdiff_t) node2->content);
3350 	if (l1 < l2)
3351 	    return(1);
3352 	if (l1 > l2)
3353 	    return(-1);
3354     }
3355 
3356     /*
3357      * compute depth to root
3358      */
3359     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3360 	if (cur->parent == node1)
3361 	    return(1);
3362 	depth2++;
3363     }
3364     root = cur;
3365     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3366 	if (cur->parent == node2)
3367 	    return(-1);
3368 	depth1++;
3369     }
3370     /*
3371      * Distinct document (or distinct entities :-( ) case.
3372      */
3373     if (root != cur) {
3374 	return(-2);
3375     }
3376     /*
3377      * get the nearest common ancestor.
3378      */
3379     while (depth1 > depth2) {
3380 	depth1--;
3381 	node1 = node1->parent;
3382     }
3383     while (depth2 > depth1) {
3384 	depth2--;
3385 	node2 = node2->parent;
3386     }
3387     while (node1->parent != node2->parent) {
3388 	node1 = node1->parent;
3389 	node2 = node2->parent;
3390 	/* should not happen but just in case ... */
3391 	if ((node1 == NULL) || (node2 == NULL))
3392 	    return(-2);
3393     }
3394     /*
3395      * Find who's first.
3396      */
3397     if (node1 == node2->prev)
3398 	return(1);
3399     if (node1 == node2->next)
3400 	return(-1);
3401     /*
3402      * Speedup using document order if availble.
3403      */
3404     if ((node1->type == XML_ELEMENT_NODE) &&
3405 	(node2->type == XML_ELEMENT_NODE) &&
3406 	(0 > (ptrdiff_t) node1->content) &&
3407 	(0 > (ptrdiff_t) node2->content) &&
3408 	(node1->doc == node2->doc)) {
3409 	ptrdiff_t l1, l2;
3410 
3411 	l1 = -((ptrdiff_t) node1->content);
3412 	l2 = -((ptrdiff_t) node2->content);
3413 	if (l1 < l2)
3414 	    return(1);
3415 	if (l1 > l2)
3416 	    return(-1);
3417     }
3418 
3419     for (cur = node1->next;cur != NULL;cur = cur->next)
3420 	if (cur == node2)
3421 	    return(1);
3422     return(-1); /* assume there is no sibling list corruption */
3423 }
3424 
3425 /**
3426  * xmlXPathNodeSetSort:
3427  * @set:  the node set
3428  *
3429  * Sort the node set in document order
3430  */
3431 void
3432 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3433 #ifndef WITH_TIM_SORT
3434     int i, j, incr, len;
3435     xmlNodePtr tmp;
3436 #endif
3437 
3438     if (set == NULL)
3439 	return;
3440 
3441 #ifndef WITH_TIM_SORT
3442     /*
3443      * Use the old Shell's sort implementation to sort the node-set
3444      * Timsort ought to be quite faster
3445      */
3446     len = set->nodeNr;
3447     for (incr = len / 2; incr > 0; incr /= 2) {
3448 	for (i = incr; i < len; i++) {
3449 	    j = i - incr;
3450 	    while (j >= 0) {
3451 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3452 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
3453 			set->nodeTab[j + incr]) == -1)
3454 #else
3455 		if (xmlXPathCmpNodes(set->nodeTab[j],
3456 			set->nodeTab[j + incr]) == -1)
3457 #endif
3458 		{
3459 		    tmp = set->nodeTab[j];
3460 		    set->nodeTab[j] = set->nodeTab[j + incr];
3461 		    set->nodeTab[j + incr] = tmp;
3462 		    j -= incr;
3463 		} else
3464 		    break;
3465 	    }
3466 	}
3467     }
3468 #else /* WITH_TIM_SORT */
3469     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3470 #endif /* WITH_TIM_SORT */
3471 }
3472 
3473 #define XML_NODESET_DEFAULT	10
3474 /**
3475  * xmlXPathNodeSetDupNs:
3476  * @node:  the parent node of the namespace XPath node
3477  * @ns:  the libxml namespace declaration node.
3478  *
3479  * Namespace node in libxml don't match the XPath semantic. In a node set
3480  * the namespace nodes are duplicated and the next pointer is set to the
3481  * parent node in the XPath semantic.
3482  *
3483  * Returns the newly created object.
3484  */
3485 static xmlNodePtr
3486 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3487     xmlNsPtr cur;
3488 
3489     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3490 	return(NULL);
3491     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3492 	return((xmlNodePtr) ns);
3493 
3494     /*
3495      * Allocate a new Namespace and fill the fields.
3496      */
3497     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3498     if (cur == NULL) {
3499         xmlXPathErrMemory(NULL, "duplicating namespace\n");
3500 	return(NULL);
3501     }
3502     memset(cur, 0, sizeof(xmlNs));
3503     cur->type = XML_NAMESPACE_DECL;
3504     if (ns->href != NULL)
3505 	cur->href = xmlStrdup(ns->href);
3506     if (ns->prefix != NULL)
3507 	cur->prefix = xmlStrdup(ns->prefix);
3508     cur->next = (xmlNsPtr) node;
3509     return((xmlNodePtr) cur);
3510 }
3511 
3512 /**
3513  * xmlXPathNodeSetFreeNs:
3514  * @ns:  the XPath namespace node found in a nodeset.
3515  *
3516  * Namespace nodes in libxml don't match the XPath semantic. In a node set
3517  * the namespace nodes are duplicated and the next pointer is set to the
3518  * parent node in the XPath semantic. Check if such a node needs to be freed
3519  */
3520 void
3521 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3522     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3523 	return;
3524 
3525     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3526 	if (ns->href != NULL)
3527 	    xmlFree((xmlChar *)ns->href);
3528 	if (ns->prefix != NULL)
3529 	    xmlFree((xmlChar *)ns->prefix);
3530 	xmlFree(ns);
3531     }
3532 }
3533 
3534 /**
3535  * xmlXPathNodeSetCreate:
3536  * @val:  an initial xmlNodePtr, or NULL
3537  *
3538  * Create a new xmlNodeSetPtr of type double and of value @val
3539  *
3540  * Returns the newly created object.
3541  */
3542 xmlNodeSetPtr
3543 xmlXPathNodeSetCreate(xmlNodePtr val) {
3544     xmlNodeSetPtr ret;
3545 
3546     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3547     if (ret == NULL) {
3548         xmlXPathErrMemory(NULL, "creating nodeset\n");
3549 	return(NULL);
3550     }
3551     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3552     if (val != NULL) {
3553         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3554 					     sizeof(xmlNodePtr));
3555 	if (ret->nodeTab == NULL) {
3556 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
3557 	    xmlFree(ret);
3558 	    return(NULL);
3559 	}
3560 	memset(ret->nodeTab, 0 ,
3561 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3562         ret->nodeMax = XML_NODESET_DEFAULT;
3563 	if (val->type == XML_NAMESPACE_DECL) {
3564 	    xmlNsPtr ns = (xmlNsPtr) val;
3565 
3566 	    ret->nodeTab[ret->nodeNr++] =
3567 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3568 	} else
3569 	    ret->nodeTab[ret->nodeNr++] = val;
3570     }
3571     return(ret);
3572 }
3573 
3574 /**
3575  * xmlXPathNodeSetCreateSize:
3576  * @size:  the initial size of the set
3577  *
3578  * Create a new xmlNodeSetPtr of type double and of value @val
3579  *
3580  * Returns the newly created object.
3581  */
3582 static xmlNodeSetPtr
3583 xmlXPathNodeSetCreateSize(int size) {
3584     xmlNodeSetPtr ret;
3585 
3586     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3587     if (ret == NULL) {
3588         xmlXPathErrMemory(NULL, "creating nodeset\n");
3589 	return(NULL);
3590     }
3591     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3592     if (size < XML_NODESET_DEFAULT)
3593 	size = XML_NODESET_DEFAULT;
3594     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3595     if (ret->nodeTab == NULL) {
3596 	xmlXPathErrMemory(NULL, "creating nodeset\n");
3597 	xmlFree(ret);
3598 	return(NULL);
3599     }
3600     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3601     ret->nodeMax = size;
3602     return(ret);
3603 }
3604 
3605 /**
3606  * xmlXPathNodeSetContains:
3607  * @cur:  the node-set
3608  * @val:  the node
3609  *
3610  * checks whether @cur contains @val
3611  *
3612  * Returns true (1) if @cur contains @val, false (0) otherwise
3613  */
3614 int
3615 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3616     int i;
3617 
3618     if ((cur == NULL) || (val == NULL)) return(0);
3619     if (val->type == XML_NAMESPACE_DECL) {
3620 	for (i = 0; i < cur->nodeNr; i++) {
3621 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3622 		xmlNsPtr ns1, ns2;
3623 
3624 		ns1 = (xmlNsPtr) val;
3625 		ns2 = (xmlNsPtr) cur->nodeTab[i];
3626 		if (ns1 == ns2)
3627 		    return(1);
3628 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3629 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
3630 		    return(1);
3631 	    }
3632 	}
3633     } else {
3634 	for (i = 0; i < cur->nodeNr; i++) {
3635 	    if (cur->nodeTab[i] == val)
3636 		return(1);
3637 	}
3638     }
3639     return(0);
3640 }
3641 
3642 /**
3643  * xmlXPathNodeSetAddNs:
3644  * @cur:  the initial node set
3645  * @node:  the hosting node
3646  * @ns:  a the namespace node
3647  *
3648  * add a new namespace node to an existing NodeSet
3649  *
3650  * Returns 0 in case of success and -1 in case of error
3651  */
3652 int
3653 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3654     int i;
3655 
3656 
3657     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3658         (ns->type != XML_NAMESPACE_DECL) ||
3659 	(node->type != XML_ELEMENT_NODE))
3660 	return(-1);
3661 
3662     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3663     /*
3664      * prevent duplicates
3665      */
3666     for (i = 0;i < cur->nodeNr;i++) {
3667         if ((cur->nodeTab[i] != NULL) &&
3668 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3669 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3670 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3671 	    return(0);
3672     }
3673 
3674     /*
3675      * grow the nodeTab if needed
3676      */
3677     if (cur->nodeMax == 0) {
3678         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3679 					     sizeof(xmlNodePtr));
3680 	if (cur->nodeTab == NULL) {
3681 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3682 	    return(-1);
3683 	}
3684 	memset(cur->nodeTab, 0 ,
3685 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3686         cur->nodeMax = XML_NODESET_DEFAULT;
3687     } else if (cur->nodeNr == cur->nodeMax) {
3688         xmlNodePtr *temp;
3689 
3690         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3691             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3692             return(-1);
3693         }
3694 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3695 				      sizeof(xmlNodePtr));
3696 	if (temp == NULL) {
3697 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3698 	    return(-1);
3699 	}
3700         cur->nodeMax *= 2;
3701 	cur->nodeTab = temp;
3702     }
3703     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3704     return(0);
3705 }
3706 
3707 /**
3708  * xmlXPathNodeSetAdd:
3709  * @cur:  the initial node set
3710  * @val:  a new xmlNodePtr
3711  *
3712  * add a new xmlNodePtr to an existing NodeSet
3713  *
3714  * Returns 0 in case of success, and -1 in case of error
3715  */
3716 int
3717 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3718     int i;
3719 
3720     if ((cur == NULL) || (val == NULL)) return(-1);
3721 
3722     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3723     /*
3724      * prevent duplicates
3725      */
3726     for (i = 0;i < cur->nodeNr;i++)
3727         if (cur->nodeTab[i] == val) return(0);
3728 
3729     /*
3730      * grow the nodeTab if needed
3731      */
3732     if (cur->nodeMax == 0) {
3733         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3734 					     sizeof(xmlNodePtr));
3735 	if (cur->nodeTab == NULL) {
3736 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3737 	    return(-1);
3738 	}
3739 	memset(cur->nodeTab, 0 ,
3740 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3741         cur->nodeMax = XML_NODESET_DEFAULT;
3742     } else if (cur->nodeNr == cur->nodeMax) {
3743         xmlNodePtr *temp;
3744 
3745         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3746             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3747             return(-1);
3748         }
3749 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3750 				      sizeof(xmlNodePtr));
3751 	if (temp == NULL) {
3752 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3753 	    return(-1);
3754 	}
3755         cur->nodeMax *= 2;
3756 	cur->nodeTab = temp;
3757     }
3758     if (val->type == XML_NAMESPACE_DECL) {
3759 	xmlNsPtr ns = (xmlNsPtr) val;
3760 
3761 	cur->nodeTab[cur->nodeNr++] =
3762 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3763     } else
3764 	cur->nodeTab[cur->nodeNr++] = val;
3765     return(0);
3766 }
3767 
3768 /**
3769  * xmlXPathNodeSetAddUnique:
3770  * @cur:  the initial node set
3771  * @val:  a new xmlNodePtr
3772  *
3773  * add a new xmlNodePtr to an existing NodeSet, optimized version
3774  * when we are sure the node is not already in the set.
3775  *
3776  * Returns 0 in case of success and -1 in case of failure
3777  */
3778 int
3779 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3780     if ((cur == NULL) || (val == NULL)) return(-1);
3781 
3782     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3783     /*
3784      * grow the nodeTab if needed
3785      */
3786     if (cur->nodeMax == 0) {
3787         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3788 					     sizeof(xmlNodePtr));
3789 	if (cur->nodeTab == NULL) {
3790 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3791 	    return(-1);
3792 	}
3793 	memset(cur->nodeTab, 0 ,
3794 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3795         cur->nodeMax = XML_NODESET_DEFAULT;
3796     } else if (cur->nodeNr == cur->nodeMax) {
3797         xmlNodePtr *temp;
3798 
3799         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3800             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3801             return(-1);
3802         }
3803 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3804 				      sizeof(xmlNodePtr));
3805 	if (temp == NULL) {
3806 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3807 	    return(-1);
3808 	}
3809 	cur->nodeTab = temp;
3810         cur->nodeMax *= 2;
3811     }
3812     if (val->type == XML_NAMESPACE_DECL) {
3813 	xmlNsPtr ns = (xmlNsPtr) val;
3814 
3815 	cur->nodeTab[cur->nodeNr++] =
3816 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3817     } else
3818 	cur->nodeTab[cur->nodeNr++] = val;
3819     return(0);
3820 }
3821 
3822 /**
3823  * xmlXPathNodeSetMerge:
3824  * @val1:  the first NodeSet or NULL
3825  * @val2:  the second NodeSet
3826  *
3827  * Merges two nodesets, all nodes from @val2 are added to @val1
3828  * if @val1 is NULL, a new set is created and copied from @val2
3829  *
3830  * Returns @val1 once extended or NULL in case of error.
3831  */
3832 xmlNodeSetPtr
3833 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3834     int i, j, initNr, skip;
3835     xmlNodePtr n1, n2;
3836 
3837     if (val2 == NULL) return(val1);
3838     if (val1 == NULL) {
3839 	val1 = xmlXPathNodeSetCreate(NULL);
3840     if (val1 == NULL)
3841         return (NULL);
3842 #if 0
3843 	/*
3844 	* TODO: The optimization won't work in every case, since
3845 	*  those nasty namespace nodes need to be added with
3846 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
3847 	*  memcpy is not possible.
3848 	*  If there was a flag on the nodesetval, indicating that
3849 	*  some temporary nodes are in, that would be helpfull.
3850 	*/
3851 	/*
3852 	* Optimization: Create an equally sized node-set
3853 	* and memcpy the content.
3854 	*/
3855 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3856 	if (val1 == NULL)
3857 	    return(NULL);
3858 	if (val2->nodeNr != 0) {
3859 	    if (val2->nodeNr == 1)
3860 		*(val1->nodeTab) = *(val2->nodeTab);
3861 	    else {
3862 		memcpy(val1->nodeTab, val2->nodeTab,
3863 		    val2->nodeNr * sizeof(xmlNodePtr));
3864 	    }
3865 	    val1->nodeNr = val2->nodeNr;
3866 	}
3867 	return(val1);
3868 #endif
3869     }
3870 
3871     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3872     initNr = val1->nodeNr;
3873 
3874     for (i = 0;i < val2->nodeNr;i++) {
3875 	n2 = val2->nodeTab[i];
3876 	/*
3877 	 * check against duplicates
3878 	 */
3879 	skip = 0;
3880 	for (j = 0; j < initNr; j++) {
3881 	    n1 = val1->nodeTab[j];
3882 	    if (n1 == n2) {
3883 		skip = 1;
3884 		break;
3885 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3886 		       (n2->type == XML_NAMESPACE_DECL)) {
3887 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3888 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3889 			((xmlNsPtr) n2)->prefix)))
3890 		{
3891 		    skip = 1;
3892 		    break;
3893 		}
3894 	    }
3895 	}
3896 	if (skip)
3897 	    continue;
3898 
3899 	/*
3900 	 * grow the nodeTab if needed
3901 	 */
3902 	if (val1->nodeMax == 0) {
3903 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3904 						    sizeof(xmlNodePtr));
3905 	    if (val1->nodeTab == NULL) {
3906 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3907 		return(NULL);
3908 	    }
3909 	    memset(val1->nodeTab, 0 ,
3910 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3911 	    val1->nodeMax = XML_NODESET_DEFAULT;
3912 	} else if (val1->nodeNr == val1->nodeMax) {
3913 	    xmlNodePtr *temp;
3914 
3915             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3916                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3917                 return(NULL);
3918             }
3919 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3920 					     sizeof(xmlNodePtr));
3921 	    if (temp == NULL) {
3922 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3923 		return(NULL);
3924 	    }
3925 	    val1->nodeTab = temp;
3926 	    val1->nodeMax *= 2;
3927 	}
3928 	if (n2->type == XML_NAMESPACE_DECL) {
3929 	    xmlNsPtr ns = (xmlNsPtr) n2;
3930 
3931 	    val1->nodeTab[val1->nodeNr++] =
3932 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3933 	} else
3934 	    val1->nodeTab[val1->nodeNr++] = n2;
3935     }
3936 
3937     return(val1);
3938 }
3939 
3940 
3941 /**
3942  * xmlXPathNodeSetMergeAndClear:
3943  * @set1:  the first NodeSet or NULL
3944  * @set2:  the second NodeSet
3945  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3946  *
3947  * Merges two nodesets, all nodes from @set2 are added to @set1
3948  * if @set1 is NULL, a new set is created and copied from @set2.
3949  * Checks for duplicate nodes. Clears set2.
3950  *
3951  * Returns @set1 once extended or NULL in case of error.
3952  */
3953 static xmlNodeSetPtr
3954 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3955 			     int hasNullEntries)
3956 {
3957     if ((set1 == NULL) && (hasNullEntries == 0)) {
3958 	/*
3959 	* Note that doing a memcpy of the list, namespace nodes are
3960 	* just assigned to set1, since set2 is cleared anyway.
3961 	*/
3962 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3963 	if (set1 == NULL)
3964 	    return(NULL);
3965 	if (set2->nodeNr != 0) {
3966 	    memcpy(set1->nodeTab, set2->nodeTab,
3967 		set2->nodeNr * sizeof(xmlNodePtr));
3968 	    set1->nodeNr = set2->nodeNr;
3969 	}
3970     } else {
3971 	int i, j, initNbSet1;
3972 	xmlNodePtr n1, n2;
3973 
3974 	if (set1 == NULL)
3975             set1 = xmlXPathNodeSetCreate(NULL);
3976         if (set1 == NULL)
3977             return (NULL);
3978 
3979 	initNbSet1 = set1->nodeNr;
3980 	for (i = 0;i < set2->nodeNr;i++) {
3981 	    n2 = set2->nodeTab[i];
3982 	    /*
3983 	    * Skip NULLed entries.
3984 	    */
3985 	    if (n2 == NULL)
3986 		continue;
3987 	    /*
3988 	    * Skip duplicates.
3989 	    */
3990 	    for (j = 0; j < initNbSet1; j++) {
3991 		n1 = set1->nodeTab[j];
3992 		if (n1 == n2) {
3993 		    goto skip_node;
3994 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3995 		    (n2->type == XML_NAMESPACE_DECL))
3996 		{
3997 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3998 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3999 			((xmlNsPtr) n2)->prefix)))
4000 		    {
4001 			/*
4002 			* Free the namespace node.
4003 			*/
4004 			set2->nodeTab[i] = NULL;
4005 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
4006 			goto skip_node;
4007 		    }
4008 		}
4009 	    }
4010 	    /*
4011 	    * grow the nodeTab if needed
4012 	    */
4013 	    if (set1->nodeMax == 0) {
4014 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4015 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4016 		if (set1->nodeTab == NULL) {
4017 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4018 		    return(NULL);
4019 		}
4020 		memset(set1->nodeTab, 0,
4021 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4022 		set1->nodeMax = XML_NODESET_DEFAULT;
4023 	    } else if (set1->nodeNr >= set1->nodeMax) {
4024 		xmlNodePtr *temp;
4025 
4026                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4027                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4028                     return(NULL);
4029                 }
4030 		temp = (xmlNodePtr *) xmlRealloc(
4031 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4032 		if (temp == NULL) {
4033 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4034 		    return(NULL);
4035 		}
4036 		set1->nodeTab = temp;
4037 		set1->nodeMax *= 2;
4038 	    }
4039 	    set1->nodeTab[set1->nodeNr++] = n2;
4040 skip_node:
4041 	    {}
4042 	}
4043     }
4044     set2->nodeNr = 0;
4045     return(set1);
4046 }
4047 
4048 /**
4049  * xmlXPathNodeSetMergeAndClearNoDupls:
4050  * @set1:  the first NodeSet or NULL
4051  * @set2:  the second NodeSet
4052  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4053  *
4054  * Merges two nodesets, all nodes from @set2 are added to @set1
4055  * if @set1 is NULL, a new set is created and copied from @set2.
4056  * Doesn't chack for duplicate nodes. Clears set2.
4057  *
4058  * Returns @set1 once extended or NULL in case of error.
4059  */
4060 static xmlNodeSetPtr
4061 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4062 				    int hasNullEntries)
4063 {
4064     if (set2 == NULL)
4065 	return(set1);
4066     if ((set1 == NULL) && (hasNullEntries == 0)) {
4067 	/*
4068 	* Note that doing a memcpy of the list, namespace nodes are
4069 	* just assigned to set1, since set2 is cleared anyway.
4070 	*/
4071 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4072 	if (set1 == NULL)
4073 	    return(NULL);
4074 	if (set2->nodeNr != 0) {
4075 	    memcpy(set1->nodeTab, set2->nodeTab,
4076 		set2->nodeNr * sizeof(xmlNodePtr));
4077 	    set1->nodeNr = set2->nodeNr;
4078 	}
4079     } else {
4080 	int i;
4081 	xmlNodePtr n2;
4082 
4083 	if (set1 == NULL)
4084 	    set1 = xmlXPathNodeSetCreate(NULL);
4085         if (set1 == NULL)
4086             return (NULL);
4087 
4088 	for (i = 0;i < set2->nodeNr;i++) {
4089 	    n2 = set2->nodeTab[i];
4090 	    /*
4091 	    * Skip NULLed entries.
4092 	    */
4093 	    if (n2 == NULL)
4094 		continue;
4095 	    if (set1->nodeMax == 0) {
4096 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4097 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4098 		if (set1->nodeTab == NULL) {
4099 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4100 		    return(NULL);
4101 		}
4102 		memset(set1->nodeTab, 0,
4103 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4104 		set1->nodeMax = XML_NODESET_DEFAULT;
4105 	    } else if (set1->nodeNr >= set1->nodeMax) {
4106 		xmlNodePtr *temp;
4107 
4108                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4109                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4110                     return(NULL);
4111                 }
4112 		temp = (xmlNodePtr *) xmlRealloc(
4113 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4114 		if (temp == NULL) {
4115 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4116 		    return(NULL);
4117 		}
4118 		set1->nodeTab = temp;
4119 		set1->nodeMax *= 2;
4120 	    }
4121 	    set1->nodeTab[set1->nodeNr++] = n2;
4122 	}
4123     }
4124     set2->nodeNr = 0;
4125     return(set1);
4126 }
4127 
4128 /**
4129  * xmlXPathNodeSetDel:
4130  * @cur:  the initial node set
4131  * @val:  an xmlNodePtr
4132  *
4133  * Removes an xmlNodePtr from an existing NodeSet
4134  */
4135 void
4136 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4137     int i;
4138 
4139     if (cur == NULL) return;
4140     if (val == NULL) return;
4141 
4142     /*
4143      * find node in nodeTab
4144      */
4145     for (i = 0;i < cur->nodeNr;i++)
4146         if (cur->nodeTab[i] == val) break;
4147 
4148     if (i >= cur->nodeNr) {	/* not found */
4149 #ifdef DEBUG
4150         xmlGenericError(xmlGenericErrorContext,
4151 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4152 		val->name);
4153 #endif
4154         return;
4155     }
4156     if ((cur->nodeTab[i] != NULL) &&
4157 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4158 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4159     cur->nodeNr--;
4160     for (;i < cur->nodeNr;i++)
4161         cur->nodeTab[i] = cur->nodeTab[i + 1];
4162     cur->nodeTab[cur->nodeNr] = NULL;
4163 }
4164 
4165 /**
4166  * xmlXPathNodeSetRemove:
4167  * @cur:  the initial node set
4168  * @val:  the index to remove
4169  *
4170  * Removes an entry from an existing NodeSet list.
4171  */
4172 void
4173 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4174     if (cur == NULL) return;
4175     if (val >= cur->nodeNr) return;
4176     if ((cur->nodeTab[val] != NULL) &&
4177 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4178 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4179     cur->nodeNr--;
4180     for (;val < cur->nodeNr;val++)
4181         cur->nodeTab[val] = cur->nodeTab[val + 1];
4182     cur->nodeTab[cur->nodeNr] = NULL;
4183 }
4184 
4185 /**
4186  * xmlXPathFreeNodeSet:
4187  * @obj:  the xmlNodeSetPtr to free
4188  *
4189  * Free the NodeSet compound (not the actual nodes !).
4190  */
4191 void
4192 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4193     if (obj == NULL) return;
4194     if (obj->nodeTab != NULL) {
4195 	int i;
4196 
4197 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
4198 	for (i = 0;i < obj->nodeNr;i++)
4199 	    if ((obj->nodeTab[i] != NULL) &&
4200 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4201 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4202 	xmlFree(obj->nodeTab);
4203     }
4204     xmlFree(obj);
4205 }
4206 
4207 /**
4208  * xmlXPathNodeSetClearFromPos:
4209  * @set: the node set to be cleared
4210  * @pos: the start position to clear from
4211  *
4212  * Clears the list from temporary XPath objects (e.g. namespace nodes
4213  * are feed) starting with the entry at @pos, but does *not* free the list
4214  * itself. Sets the length of the list to @pos.
4215  */
4216 static void
4217 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4218 {
4219     if ((set == NULL) || (pos >= set->nodeNr))
4220 	return;
4221     else if ((hasNsNodes)) {
4222 	int i;
4223 	xmlNodePtr node;
4224 
4225 	for (i = pos; i < set->nodeNr; i++) {
4226 	    node = set->nodeTab[i];
4227 	    if ((node != NULL) &&
4228 		(node->type == XML_NAMESPACE_DECL))
4229 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4230 	}
4231     }
4232     set->nodeNr = pos;
4233 }
4234 
4235 /**
4236  * xmlXPathNodeSetClear:
4237  * @set:  the node set to clear
4238  *
4239  * Clears the list from all temporary XPath objects (e.g. namespace nodes
4240  * are feed), but does *not* free the list itself. Sets the length of the
4241  * list to 0.
4242  */
4243 static void
4244 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4245 {
4246     xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4247 }
4248 
4249 /**
4250  * xmlXPathNodeSetKeepLast:
4251  * @set: the node set to be cleared
4252  *
4253  * Move the last node to the first position and clear temporary XPath objects
4254  * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4255  * to 1.
4256  */
4257 static void
4258 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4259 {
4260     int i;
4261     xmlNodePtr node;
4262 
4263     if ((set == NULL) || (set->nodeNr <= 1))
4264 	return;
4265     for (i = 0; i < set->nodeNr - 1; i++) {
4266         node = set->nodeTab[i];
4267         if ((node != NULL) &&
4268             (node->type == XML_NAMESPACE_DECL))
4269             xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4270     }
4271     set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4272     set->nodeNr = 1;
4273 }
4274 
4275 /**
4276  * xmlXPathFreeValueTree:
4277  * @obj:  the xmlNodeSetPtr to free
4278  *
4279  * Free the NodeSet compound and the actual tree, this is different
4280  * from xmlXPathFreeNodeSet()
4281  */
4282 static void
4283 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4284     int i;
4285 
4286     if (obj == NULL) return;
4287 
4288     if (obj->nodeTab != NULL) {
4289 	for (i = 0;i < obj->nodeNr;i++) {
4290 	    if (obj->nodeTab[i] != NULL) {
4291 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4292 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4293 		} else {
4294 		    xmlFreeNodeList(obj->nodeTab[i]);
4295 		}
4296 	    }
4297 	}
4298 	xmlFree(obj->nodeTab);
4299     }
4300     xmlFree(obj);
4301 }
4302 
4303 #if defined(DEBUG) || defined(DEBUG_STEP)
4304 /**
4305  * xmlGenericErrorContextNodeSet:
4306  * @output:  a FILE * for the output
4307  * @obj:  the xmlNodeSetPtr to display
4308  *
4309  * Quick display of a NodeSet
4310  */
4311 void
4312 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4313     int i;
4314 
4315     if (output == NULL) output = xmlGenericErrorContext;
4316     if (obj == NULL)  {
4317         fprintf(output, "NodeSet == NULL !\n");
4318 	return;
4319     }
4320     if (obj->nodeNr == 0) {
4321         fprintf(output, "NodeSet is empty\n");
4322 	return;
4323     }
4324     if (obj->nodeTab == NULL) {
4325 	fprintf(output, " nodeTab == NULL !\n");
4326 	return;
4327     }
4328     for (i = 0; i < obj->nodeNr; i++) {
4329         if (obj->nodeTab[i] == NULL) {
4330 	    fprintf(output, " NULL !\n");
4331 	    return;
4332         }
4333 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4334 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4335 	    fprintf(output, " /");
4336 	else if (obj->nodeTab[i]->name == NULL)
4337 	    fprintf(output, " noname!");
4338 	else fprintf(output, " %s", obj->nodeTab[i]->name);
4339     }
4340     fprintf(output, "\n");
4341 }
4342 #endif
4343 
4344 /**
4345  * xmlXPathNewNodeSet:
4346  * @val:  the NodePtr value
4347  *
4348  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4349  * it with the single Node @val
4350  *
4351  * Returns the newly created object.
4352  */
4353 xmlXPathObjectPtr
4354 xmlXPathNewNodeSet(xmlNodePtr val) {
4355     xmlXPathObjectPtr ret;
4356 
4357     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4358     if (ret == NULL) {
4359         xmlXPathErrMemory(NULL, "creating nodeset\n");
4360 	return(NULL);
4361     }
4362     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4363     ret->type = XPATH_NODESET;
4364     ret->boolval = 0;
4365     ret->nodesetval = xmlXPathNodeSetCreate(val);
4366     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4367 #ifdef XP_DEBUG_OBJ_USAGE
4368     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4369 #endif
4370     return(ret);
4371 }
4372 
4373 /**
4374  * xmlXPathNewValueTree:
4375  * @val:  the NodePtr value
4376  *
4377  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4378  * it with the tree root @val
4379  *
4380  * Returns the newly created object.
4381  */
4382 xmlXPathObjectPtr
4383 xmlXPathNewValueTree(xmlNodePtr val) {
4384     xmlXPathObjectPtr ret;
4385 
4386     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4387     if (ret == NULL) {
4388         xmlXPathErrMemory(NULL, "creating result value tree\n");
4389 	return(NULL);
4390     }
4391     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4392     ret->type = XPATH_XSLT_TREE;
4393     ret->boolval = 1;
4394     ret->user = (void *) val;
4395     ret->nodesetval = xmlXPathNodeSetCreate(val);
4396 #ifdef XP_DEBUG_OBJ_USAGE
4397     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4398 #endif
4399     return(ret);
4400 }
4401 
4402 /**
4403  * xmlXPathNewNodeSetList:
4404  * @val:  an existing NodeSet
4405  *
4406  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4407  * it with the Nodeset @val
4408  *
4409  * Returns the newly created object.
4410  */
4411 xmlXPathObjectPtr
4412 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4413 {
4414     xmlXPathObjectPtr ret;
4415     int i;
4416 
4417     if (val == NULL)
4418         ret = NULL;
4419     else if (val->nodeTab == NULL)
4420         ret = xmlXPathNewNodeSet(NULL);
4421     else {
4422         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4423         if (ret) {
4424             for (i = 1; i < val->nodeNr; ++i) {
4425                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4426 		    < 0) break;
4427 	    }
4428 	}
4429     }
4430 
4431     return (ret);
4432 }
4433 
4434 /**
4435  * xmlXPathWrapNodeSet:
4436  * @val:  the NodePtr value
4437  *
4438  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4439  *
4440  * Returns the newly created object.
4441  */
4442 xmlXPathObjectPtr
4443 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4444     xmlXPathObjectPtr ret;
4445 
4446     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4447     if (ret == NULL) {
4448         xmlXPathErrMemory(NULL, "creating node set object\n");
4449 	return(NULL);
4450     }
4451     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4452     ret->type = XPATH_NODESET;
4453     ret->nodesetval = val;
4454 #ifdef XP_DEBUG_OBJ_USAGE
4455     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4456 #endif
4457     return(ret);
4458 }
4459 
4460 /**
4461  * xmlXPathFreeNodeSetList:
4462  * @obj:  an existing NodeSetList object
4463  *
4464  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4465  * the list contrary to xmlXPathFreeObject().
4466  */
4467 void
4468 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4469     if (obj == NULL) return;
4470 #ifdef XP_DEBUG_OBJ_USAGE
4471     xmlXPathDebugObjUsageReleased(NULL, obj->type);
4472 #endif
4473     xmlFree(obj);
4474 }
4475 
4476 /**
4477  * xmlXPathDifference:
4478  * @nodes1:  a node-set
4479  * @nodes2:  a node-set
4480  *
4481  * Implements the EXSLT - Sets difference() function:
4482  *    node-set set:difference (node-set, node-set)
4483  *
4484  * Returns the difference between the two node sets, or nodes1 if
4485  *         nodes2 is empty
4486  */
4487 xmlNodeSetPtr
4488 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4489     xmlNodeSetPtr ret;
4490     int i, l1;
4491     xmlNodePtr cur;
4492 
4493     if (xmlXPathNodeSetIsEmpty(nodes2))
4494 	return(nodes1);
4495 
4496     ret = xmlXPathNodeSetCreate(NULL);
4497     if (xmlXPathNodeSetIsEmpty(nodes1))
4498 	return(ret);
4499 
4500     l1 = xmlXPathNodeSetGetLength(nodes1);
4501 
4502     for (i = 0; i < l1; i++) {
4503 	cur = xmlXPathNodeSetItem(nodes1, i);
4504 	if (!xmlXPathNodeSetContains(nodes2, cur)) {
4505 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4506 	        break;
4507 	}
4508     }
4509     return(ret);
4510 }
4511 
4512 /**
4513  * xmlXPathIntersection:
4514  * @nodes1:  a node-set
4515  * @nodes2:  a node-set
4516  *
4517  * Implements the EXSLT - Sets intersection() function:
4518  *    node-set set:intersection (node-set, node-set)
4519  *
4520  * Returns a node set comprising the nodes that are within both the
4521  *         node sets passed as arguments
4522  */
4523 xmlNodeSetPtr
4524 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4525     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4526     int i, l1;
4527     xmlNodePtr cur;
4528 
4529     if (ret == NULL)
4530         return(ret);
4531     if (xmlXPathNodeSetIsEmpty(nodes1))
4532 	return(ret);
4533     if (xmlXPathNodeSetIsEmpty(nodes2))
4534 	return(ret);
4535 
4536     l1 = xmlXPathNodeSetGetLength(nodes1);
4537 
4538     for (i = 0; i < l1; i++) {
4539 	cur = xmlXPathNodeSetItem(nodes1, i);
4540 	if (xmlXPathNodeSetContains(nodes2, cur)) {
4541 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4542 	        break;
4543 	}
4544     }
4545     return(ret);
4546 }
4547 
4548 /**
4549  * xmlXPathDistinctSorted:
4550  * @nodes:  a node-set, sorted by document order
4551  *
4552  * Implements the EXSLT - Sets distinct() function:
4553  *    node-set set:distinct (node-set)
4554  *
4555  * Returns a subset of the nodes contained in @nodes, or @nodes if
4556  *         it is empty
4557  */
4558 xmlNodeSetPtr
4559 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4560     xmlNodeSetPtr ret;
4561     xmlHashTablePtr hash;
4562     int i, l;
4563     xmlChar * strval;
4564     xmlNodePtr cur;
4565 
4566     if (xmlXPathNodeSetIsEmpty(nodes))
4567 	return(nodes);
4568 
4569     ret = xmlXPathNodeSetCreate(NULL);
4570     if (ret == NULL)
4571         return(ret);
4572     l = xmlXPathNodeSetGetLength(nodes);
4573     hash = xmlHashCreate (l);
4574     for (i = 0; i < l; i++) {
4575 	cur = xmlXPathNodeSetItem(nodes, i);
4576 	strval = xmlXPathCastNodeToString(cur);
4577 	if (xmlHashLookup(hash, strval) == NULL) {
4578 	    xmlHashAddEntry(hash, strval, strval);
4579 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4580 	        break;
4581 	} else {
4582 	    xmlFree(strval);
4583 	}
4584     }
4585     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4586     return(ret);
4587 }
4588 
4589 /**
4590  * xmlXPathDistinct:
4591  * @nodes:  a node-set
4592  *
4593  * Implements the EXSLT - Sets distinct() function:
4594  *    node-set set:distinct (node-set)
4595  * @nodes is sorted by document order, then #exslSetsDistinctSorted
4596  * is called with the sorted node-set
4597  *
4598  * Returns a subset of the nodes contained in @nodes, or @nodes if
4599  *         it is empty
4600  */
4601 xmlNodeSetPtr
4602 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4603     if (xmlXPathNodeSetIsEmpty(nodes))
4604 	return(nodes);
4605 
4606     xmlXPathNodeSetSort(nodes);
4607     return(xmlXPathDistinctSorted(nodes));
4608 }
4609 
4610 /**
4611  * xmlXPathHasSameNodes:
4612  * @nodes1:  a node-set
4613  * @nodes2:  a node-set
4614  *
4615  * Implements the EXSLT - Sets has-same-nodes function:
4616  *    boolean set:has-same-node(node-set, node-set)
4617  *
4618  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4619  *         otherwise
4620  */
4621 int
4622 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4623     int i, l;
4624     xmlNodePtr cur;
4625 
4626     if (xmlXPathNodeSetIsEmpty(nodes1) ||
4627 	xmlXPathNodeSetIsEmpty(nodes2))
4628 	return(0);
4629 
4630     l = xmlXPathNodeSetGetLength(nodes1);
4631     for (i = 0; i < l; i++) {
4632 	cur = xmlXPathNodeSetItem(nodes1, i);
4633 	if (xmlXPathNodeSetContains(nodes2, cur))
4634 	    return(1);
4635     }
4636     return(0);
4637 }
4638 
4639 /**
4640  * xmlXPathNodeLeadingSorted:
4641  * @nodes: a node-set, sorted by document order
4642  * @node: a node
4643  *
4644  * Implements the EXSLT - Sets leading() function:
4645  *    node-set set:leading (node-set, node-set)
4646  *
4647  * Returns the nodes in @nodes that precede @node in document order,
4648  *         @nodes if @node is NULL or an empty node-set if @nodes
4649  *         doesn't contain @node
4650  */
4651 xmlNodeSetPtr
4652 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4653     int i, l;
4654     xmlNodePtr cur;
4655     xmlNodeSetPtr ret;
4656 
4657     if (node == NULL)
4658 	return(nodes);
4659 
4660     ret = xmlXPathNodeSetCreate(NULL);
4661     if (ret == NULL)
4662         return(ret);
4663     if (xmlXPathNodeSetIsEmpty(nodes) ||
4664 	(!xmlXPathNodeSetContains(nodes, node)))
4665 	return(ret);
4666 
4667     l = xmlXPathNodeSetGetLength(nodes);
4668     for (i = 0; i < l; i++) {
4669 	cur = xmlXPathNodeSetItem(nodes, i);
4670 	if (cur == node)
4671 	    break;
4672 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4673 	    break;
4674     }
4675     return(ret);
4676 }
4677 
4678 /**
4679  * xmlXPathNodeLeading:
4680  * @nodes:  a node-set
4681  * @node:  a node
4682  *
4683  * Implements the EXSLT - Sets leading() function:
4684  *    node-set set:leading (node-set, node-set)
4685  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4686  * is called.
4687  *
4688  * Returns the nodes in @nodes that precede @node in document order,
4689  *         @nodes if @node is NULL or an empty node-set if @nodes
4690  *         doesn't contain @node
4691  */
4692 xmlNodeSetPtr
4693 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4694     xmlXPathNodeSetSort(nodes);
4695     return(xmlXPathNodeLeadingSorted(nodes, node));
4696 }
4697 
4698 /**
4699  * xmlXPathLeadingSorted:
4700  * @nodes1:  a node-set, sorted by document order
4701  * @nodes2:  a node-set, sorted by document order
4702  *
4703  * Implements the EXSLT - Sets leading() function:
4704  *    node-set set:leading (node-set, node-set)
4705  *
4706  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4707  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4708  *         an empty node-set if @nodes1 doesn't contain @nodes2
4709  */
4710 xmlNodeSetPtr
4711 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4712     if (xmlXPathNodeSetIsEmpty(nodes2))
4713 	return(nodes1);
4714     return(xmlXPathNodeLeadingSorted(nodes1,
4715 				     xmlXPathNodeSetItem(nodes2, 1)));
4716 }
4717 
4718 /**
4719  * xmlXPathLeading:
4720  * @nodes1:  a node-set
4721  * @nodes2:  a node-set
4722  *
4723  * Implements the EXSLT - Sets leading() function:
4724  *    node-set set:leading (node-set, node-set)
4725  * @nodes1 and @nodes2 are sorted by document order, then
4726  * #exslSetsLeadingSorted is called.
4727  *
4728  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4729  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4730  *         an empty node-set if @nodes1 doesn't contain @nodes2
4731  */
4732 xmlNodeSetPtr
4733 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4734     if (xmlXPathNodeSetIsEmpty(nodes2))
4735 	return(nodes1);
4736     if (xmlXPathNodeSetIsEmpty(nodes1))
4737 	return(xmlXPathNodeSetCreate(NULL));
4738     xmlXPathNodeSetSort(nodes1);
4739     xmlXPathNodeSetSort(nodes2);
4740     return(xmlXPathNodeLeadingSorted(nodes1,
4741 				     xmlXPathNodeSetItem(nodes2, 1)));
4742 }
4743 
4744 /**
4745  * xmlXPathNodeTrailingSorted:
4746  * @nodes: a node-set, sorted by document order
4747  * @node: a node
4748  *
4749  * Implements the EXSLT - Sets trailing() function:
4750  *    node-set set:trailing (node-set, node-set)
4751  *
4752  * Returns the nodes in @nodes that follow @node in document order,
4753  *         @nodes if @node is NULL or an empty node-set if @nodes
4754  *         doesn't contain @node
4755  */
4756 xmlNodeSetPtr
4757 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4758     int i, l;
4759     xmlNodePtr cur;
4760     xmlNodeSetPtr ret;
4761 
4762     if (node == NULL)
4763 	return(nodes);
4764 
4765     ret = xmlXPathNodeSetCreate(NULL);
4766     if (ret == NULL)
4767         return(ret);
4768     if (xmlXPathNodeSetIsEmpty(nodes) ||
4769 	(!xmlXPathNodeSetContains(nodes, node)))
4770 	return(ret);
4771 
4772     l = xmlXPathNodeSetGetLength(nodes);
4773     for (i = l - 1; i >= 0; i--) {
4774 	cur = xmlXPathNodeSetItem(nodes, i);
4775 	if (cur == node)
4776 	    break;
4777 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4778 	    break;
4779     }
4780     xmlXPathNodeSetSort(ret);	/* bug 413451 */
4781     return(ret);
4782 }
4783 
4784 /**
4785  * xmlXPathNodeTrailing:
4786  * @nodes:  a node-set
4787  * @node:  a node
4788  *
4789  * Implements the EXSLT - Sets trailing() function:
4790  *    node-set set:trailing (node-set, node-set)
4791  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4792  * is called.
4793  *
4794  * Returns the nodes in @nodes that follow @node in document order,
4795  *         @nodes if @node is NULL or an empty node-set if @nodes
4796  *         doesn't contain @node
4797  */
4798 xmlNodeSetPtr
4799 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4800     xmlXPathNodeSetSort(nodes);
4801     return(xmlXPathNodeTrailingSorted(nodes, node));
4802 }
4803 
4804 /**
4805  * xmlXPathTrailingSorted:
4806  * @nodes1:  a node-set, sorted by document order
4807  * @nodes2:  a node-set, sorted by document order
4808  *
4809  * Implements the EXSLT - Sets trailing() function:
4810  *    node-set set:trailing (node-set, node-set)
4811  *
4812  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4813  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4814  *         an empty node-set if @nodes1 doesn't contain @nodes2
4815  */
4816 xmlNodeSetPtr
4817 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4818     if (xmlXPathNodeSetIsEmpty(nodes2))
4819 	return(nodes1);
4820     return(xmlXPathNodeTrailingSorted(nodes1,
4821 				      xmlXPathNodeSetItem(nodes2, 0)));
4822 }
4823 
4824 /**
4825  * xmlXPathTrailing:
4826  * @nodes1:  a node-set
4827  * @nodes2:  a node-set
4828  *
4829  * Implements the EXSLT - Sets trailing() function:
4830  *    node-set set:trailing (node-set, node-set)
4831  * @nodes1 and @nodes2 are sorted by document order, then
4832  * #xmlXPathTrailingSorted is called.
4833  *
4834  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4835  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4836  *         an empty node-set if @nodes1 doesn't contain @nodes2
4837  */
4838 xmlNodeSetPtr
4839 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4840     if (xmlXPathNodeSetIsEmpty(nodes2))
4841 	return(nodes1);
4842     if (xmlXPathNodeSetIsEmpty(nodes1))
4843 	return(xmlXPathNodeSetCreate(NULL));
4844     xmlXPathNodeSetSort(nodes1);
4845     xmlXPathNodeSetSort(nodes2);
4846     return(xmlXPathNodeTrailingSorted(nodes1,
4847 				      xmlXPathNodeSetItem(nodes2, 0)));
4848 }
4849 
4850 /************************************************************************
4851  *									*
4852  *		Routines to handle extra functions			*
4853  *									*
4854  ************************************************************************/
4855 
4856 /**
4857  * xmlXPathRegisterFunc:
4858  * @ctxt:  the XPath context
4859  * @name:  the function name
4860  * @f:  the function implementation or NULL
4861  *
4862  * Register a new function. If @f is NULL it unregisters the function
4863  *
4864  * Returns 0 in case of success, -1 in case of error
4865  */
4866 int
4867 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4868 		     xmlXPathFunction f) {
4869     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4870 }
4871 
4872 /**
4873  * xmlXPathRegisterFuncNS:
4874  * @ctxt:  the XPath context
4875  * @name:  the function name
4876  * @ns_uri:  the function namespace URI
4877  * @f:  the function implementation or NULL
4878  *
4879  * Register a new function. If @f is NULL it unregisters the function
4880  *
4881  * Returns 0 in case of success, -1 in case of error
4882  */
4883 int
4884 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4885 		       const xmlChar *ns_uri, xmlXPathFunction f) {
4886     if (ctxt == NULL)
4887 	return(-1);
4888     if (name == NULL)
4889 	return(-1);
4890 
4891     if (ctxt->funcHash == NULL)
4892 	ctxt->funcHash = xmlHashCreate(0);
4893     if (ctxt->funcHash == NULL)
4894 	return(-1);
4895     if (f == NULL)
4896         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4897     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4898 }
4899 
4900 /**
4901  * xmlXPathRegisterFuncLookup:
4902  * @ctxt:  the XPath context
4903  * @f:  the lookup function
4904  * @funcCtxt:  the lookup data
4905  *
4906  * Registers an external mechanism to do function lookup.
4907  */
4908 void
4909 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4910 			    xmlXPathFuncLookupFunc f,
4911 			    void *funcCtxt) {
4912     if (ctxt == NULL)
4913 	return;
4914     ctxt->funcLookupFunc = f;
4915     ctxt->funcLookupData = funcCtxt;
4916 }
4917 
4918 /**
4919  * xmlXPathFunctionLookup:
4920  * @ctxt:  the XPath context
4921  * @name:  the function name
4922  *
4923  * Search in the Function array of the context for the given
4924  * function.
4925  *
4926  * Returns the xmlXPathFunction or NULL if not found
4927  */
4928 xmlXPathFunction
4929 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4930     if (ctxt == NULL)
4931 	return (NULL);
4932 
4933     if (ctxt->funcLookupFunc != NULL) {
4934 	xmlXPathFunction ret;
4935 	xmlXPathFuncLookupFunc f;
4936 
4937 	f = ctxt->funcLookupFunc;
4938 	ret = f(ctxt->funcLookupData, name, NULL);
4939 	if (ret != NULL)
4940 	    return(ret);
4941     }
4942     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4943 }
4944 
4945 /**
4946  * xmlXPathFunctionLookupNS:
4947  * @ctxt:  the XPath context
4948  * @name:  the function name
4949  * @ns_uri:  the function namespace URI
4950  *
4951  * Search in the Function array of the context for the given
4952  * function.
4953  *
4954  * Returns the xmlXPathFunction or NULL if not found
4955  */
4956 xmlXPathFunction
4957 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4958 			 const xmlChar *ns_uri) {
4959     xmlXPathFunction ret;
4960 
4961     if (ctxt == NULL)
4962 	return(NULL);
4963     if (name == NULL)
4964 	return(NULL);
4965 
4966     if (ctxt->funcLookupFunc != NULL) {
4967 	xmlXPathFuncLookupFunc f;
4968 
4969 	f = ctxt->funcLookupFunc;
4970 	ret = f(ctxt->funcLookupData, name, ns_uri);
4971 	if (ret != NULL)
4972 	    return(ret);
4973     }
4974 
4975     if (ctxt->funcHash == NULL)
4976 	return(NULL);
4977 
4978     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4979     return(ret);
4980 }
4981 
4982 /**
4983  * xmlXPathRegisteredFuncsCleanup:
4984  * @ctxt:  the XPath context
4985  *
4986  * Cleanup the XPath context data associated to registered functions
4987  */
4988 void
4989 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4990     if (ctxt == NULL)
4991 	return;
4992 
4993     xmlHashFree(ctxt->funcHash, NULL);
4994     ctxt->funcHash = NULL;
4995 }
4996 
4997 /************************************************************************
4998  *									*
4999  *			Routines to handle Variables			*
5000  *									*
5001  ************************************************************************/
5002 
5003 /**
5004  * xmlXPathRegisterVariable:
5005  * @ctxt:  the XPath context
5006  * @name:  the variable name
5007  * @value:  the variable value or NULL
5008  *
5009  * Register a new variable value. If @value is NULL it unregisters
5010  * the variable
5011  *
5012  * Returns 0 in case of success, -1 in case of error
5013  */
5014 int
5015 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
5016 			 xmlXPathObjectPtr value) {
5017     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
5018 }
5019 
5020 /**
5021  * xmlXPathRegisterVariableNS:
5022  * @ctxt:  the XPath context
5023  * @name:  the variable name
5024  * @ns_uri:  the variable namespace URI
5025  * @value:  the variable value or NULL
5026  *
5027  * Register a new variable value. If @value is NULL it unregisters
5028  * the variable
5029  *
5030  * Returns 0 in case of success, -1 in case of error
5031  */
5032 int
5033 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5034 			   const xmlChar *ns_uri,
5035 			   xmlXPathObjectPtr value) {
5036     if (ctxt == NULL)
5037 	return(-1);
5038     if (name == NULL)
5039 	return(-1);
5040 
5041     if (ctxt->varHash == NULL)
5042 	ctxt->varHash = xmlHashCreate(0);
5043     if (ctxt->varHash == NULL)
5044 	return(-1);
5045     if (value == NULL)
5046         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5047 	                           (xmlHashDeallocator)xmlXPathFreeObject));
5048     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5049 			       (void *) value,
5050 			       (xmlHashDeallocator)xmlXPathFreeObject));
5051 }
5052 
5053 /**
5054  * xmlXPathRegisterVariableLookup:
5055  * @ctxt:  the XPath context
5056  * @f:  the lookup function
5057  * @data:  the lookup data
5058  *
5059  * register an external mechanism to do variable lookup
5060  */
5061 void
5062 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5063 	 xmlXPathVariableLookupFunc f, void *data) {
5064     if (ctxt == NULL)
5065 	return;
5066     ctxt->varLookupFunc = f;
5067     ctxt->varLookupData = data;
5068 }
5069 
5070 /**
5071  * xmlXPathVariableLookup:
5072  * @ctxt:  the XPath context
5073  * @name:  the variable name
5074  *
5075  * Search in the Variable array of the context for the given
5076  * variable value.
5077  *
5078  * Returns a copy of the value or NULL if not found
5079  */
5080 xmlXPathObjectPtr
5081 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5082     if (ctxt == NULL)
5083 	return(NULL);
5084 
5085     if (ctxt->varLookupFunc != NULL) {
5086 	xmlXPathObjectPtr ret;
5087 
5088 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5089 	        (ctxt->varLookupData, name, NULL);
5090 	return(ret);
5091     }
5092     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5093 }
5094 
5095 /**
5096  * xmlXPathVariableLookupNS:
5097  * @ctxt:  the XPath context
5098  * @name:  the variable name
5099  * @ns_uri:  the variable namespace URI
5100  *
5101  * Search in the Variable array of the context for the given
5102  * variable value.
5103  *
5104  * Returns the a copy of the value or NULL if not found
5105  */
5106 xmlXPathObjectPtr
5107 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5108 			 const xmlChar *ns_uri) {
5109     if (ctxt == NULL)
5110 	return(NULL);
5111 
5112     if (ctxt->varLookupFunc != NULL) {
5113 	xmlXPathObjectPtr ret;
5114 
5115 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5116 	        (ctxt->varLookupData, name, ns_uri);
5117 	if (ret != NULL) return(ret);
5118     }
5119 
5120     if (ctxt->varHash == NULL)
5121 	return(NULL);
5122     if (name == NULL)
5123 	return(NULL);
5124 
5125     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5126 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5127 }
5128 
5129 /**
5130  * xmlXPathRegisteredVariablesCleanup:
5131  * @ctxt:  the XPath context
5132  *
5133  * Cleanup the XPath context data associated to registered variables
5134  */
5135 void
5136 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5137     if (ctxt == NULL)
5138 	return;
5139 
5140     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5141     ctxt->varHash = NULL;
5142 }
5143 
5144 /**
5145  * xmlXPathRegisterNs:
5146  * @ctxt:  the XPath context
5147  * @prefix:  the namespace prefix cannot be NULL or empty string
5148  * @ns_uri:  the namespace name
5149  *
5150  * Register a new namespace. If @ns_uri is NULL it unregisters
5151  * the namespace
5152  *
5153  * Returns 0 in case of success, -1 in case of error
5154  */
5155 int
5156 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5157 			   const xmlChar *ns_uri) {
5158     if (ctxt == NULL)
5159 	return(-1);
5160     if (prefix == NULL)
5161 	return(-1);
5162     if (prefix[0] == 0)
5163 	return(-1);
5164 
5165     if (ctxt->nsHash == NULL)
5166 	ctxt->nsHash = xmlHashCreate(10);
5167     if (ctxt->nsHash == NULL)
5168 	return(-1);
5169     if (ns_uri == NULL)
5170         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5171 	                          (xmlHashDeallocator)xmlFree));
5172     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5173 			      (xmlHashDeallocator)xmlFree));
5174 }
5175 
5176 /**
5177  * xmlXPathNsLookup:
5178  * @ctxt:  the XPath context
5179  * @prefix:  the namespace prefix value
5180  *
5181  * Search in the namespace declaration array of the context for the given
5182  * namespace name associated to the given prefix
5183  *
5184  * Returns the value or NULL if not found
5185  */
5186 const xmlChar *
5187 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5188     if (ctxt == NULL)
5189 	return(NULL);
5190     if (prefix == NULL)
5191 	return(NULL);
5192 
5193 #ifdef XML_XML_NAMESPACE
5194     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5195 	return(XML_XML_NAMESPACE);
5196 #endif
5197 
5198     if (ctxt->namespaces != NULL) {
5199 	int i;
5200 
5201 	for (i = 0;i < ctxt->nsNr;i++) {
5202 	    if ((ctxt->namespaces[i] != NULL) &&
5203 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5204 		return(ctxt->namespaces[i]->href);
5205 	}
5206     }
5207 
5208     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5209 }
5210 
5211 /**
5212  * xmlXPathRegisteredNsCleanup:
5213  * @ctxt:  the XPath context
5214  *
5215  * Cleanup the XPath context data associated to registered variables
5216  */
5217 void
5218 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5219     if (ctxt == NULL)
5220 	return;
5221 
5222     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5223     ctxt->nsHash = NULL;
5224 }
5225 
5226 /************************************************************************
5227  *									*
5228  *			Routines to handle Values			*
5229  *									*
5230  ************************************************************************/
5231 
5232 /* Allocations are terrible, one needs to optimize all this !!! */
5233 
5234 /**
5235  * xmlXPathNewFloat:
5236  * @val:  the double value
5237  *
5238  * Create a new xmlXPathObjectPtr of type double and of value @val
5239  *
5240  * Returns the newly created object.
5241  */
5242 xmlXPathObjectPtr
5243 xmlXPathNewFloat(double val) {
5244     xmlXPathObjectPtr ret;
5245 
5246     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5247     if (ret == NULL) {
5248         xmlXPathErrMemory(NULL, "creating float object\n");
5249 	return(NULL);
5250     }
5251     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5252     ret->type = XPATH_NUMBER;
5253     ret->floatval = val;
5254 #ifdef XP_DEBUG_OBJ_USAGE
5255     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5256 #endif
5257     return(ret);
5258 }
5259 
5260 /**
5261  * xmlXPathNewBoolean:
5262  * @val:  the boolean value
5263  *
5264  * Create a new xmlXPathObjectPtr of type boolean and of value @val
5265  *
5266  * Returns the newly created object.
5267  */
5268 xmlXPathObjectPtr
5269 xmlXPathNewBoolean(int val) {
5270     xmlXPathObjectPtr ret;
5271 
5272     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5273     if (ret == NULL) {
5274         xmlXPathErrMemory(NULL, "creating boolean object\n");
5275 	return(NULL);
5276     }
5277     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5278     ret->type = XPATH_BOOLEAN;
5279     ret->boolval = (val != 0);
5280 #ifdef XP_DEBUG_OBJ_USAGE
5281     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5282 #endif
5283     return(ret);
5284 }
5285 
5286 /**
5287  * xmlXPathNewString:
5288  * @val:  the xmlChar * value
5289  *
5290  * Create a new xmlXPathObjectPtr of type string and of value @val
5291  *
5292  * Returns the newly created object.
5293  */
5294 xmlXPathObjectPtr
5295 xmlXPathNewString(const xmlChar *val) {
5296     xmlXPathObjectPtr ret;
5297 
5298     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5299     if (ret == NULL) {
5300         xmlXPathErrMemory(NULL, "creating string object\n");
5301 	return(NULL);
5302     }
5303     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5304     ret->type = XPATH_STRING;
5305     if (val != NULL)
5306 	ret->stringval = xmlStrdup(val);
5307     else
5308 	ret->stringval = xmlStrdup((const xmlChar *)"");
5309 #ifdef XP_DEBUG_OBJ_USAGE
5310     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5311 #endif
5312     return(ret);
5313 }
5314 
5315 /**
5316  * xmlXPathWrapString:
5317  * @val:  the xmlChar * value
5318  *
5319  * Wraps the @val string into an XPath object.
5320  *
5321  * Returns the newly created object.
5322  */
5323 xmlXPathObjectPtr
5324 xmlXPathWrapString (xmlChar *val) {
5325     xmlXPathObjectPtr ret;
5326 
5327     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5328     if (ret == NULL) {
5329         xmlXPathErrMemory(NULL, "creating string object\n");
5330 	return(NULL);
5331     }
5332     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5333     ret->type = XPATH_STRING;
5334     ret->stringval = val;
5335 #ifdef XP_DEBUG_OBJ_USAGE
5336     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5337 #endif
5338     return(ret);
5339 }
5340 
5341 /**
5342  * xmlXPathNewCString:
5343  * @val:  the char * value
5344  *
5345  * Create a new xmlXPathObjectPtr of type string and of value @val
5346  *
5347  * Returns the newly created object.
5348  */
5349 xmlXPathObjectPtr
5350 xmlXPathNewCString(const char *val) {
5351     xmlXPathObjectPtr ret;
5352 
5353     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5354     if (ret == NULL) {
5355         xmlXPathErrMemory(NULL, "creating string object\n");
5356 	return(NULL);
5357     }
5358     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5359     ret->type = XPATH_STRING;
5360     ret->stringval = xmlStrdup(BAD_CAST val);
5361 #ifdef XP_DEBUG_OBJ_USAGE
5362     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5363 #endif
5364     return(ret);
5365 }
5366 
5367 /**
5368  * xmlXPathWrapCString:
5369  * @val:  the char * value
5370  *
5371  * Wraps a string into an XPath object.
5372  *
5373  * Returns the newly created object.
5374  */
5375 xmlXPathObjectPtr
5376 xmlXPathWrapCString (char * val) {
5377     return(xmlXPathWrapString((xmlChar *)(val)));
5378 }
5379 
5380 /**
5381  * xmlXPathWrapExternal:
5382  * @val:  the user data
5383  *
5384  * Wraps the @val data into an XPath object.
5385  *
5386  * Returns the newly created object.
5387  */
5388 xmlXPathObjectPtr
5389 xmlXPathWrapExternal (void *val) {
5390     xmlXPathObjectPtr ret;
5391 
5392     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5393     if (ret == NULL) {
5394         xmlXPathErrMemory(NULL, "creating user object\n");
5395 	return(NULL);
5396     }
5397     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5398     ret->type = XPATH_USERS;
5399     ret->user = val;
5400 #ifdef XP_DEBUG_OBJ_USAGE
5401     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5402 #endif
5403     return(ret);
5404 }
5405 
5406 /**
5407  * xmlXPathObjectCopy:
5408  * @val:  the original object
5409  *
5410  * allocate a new copy of a given object
5411  *
5412  * Returns the newly created object.
5413  */
5414 xmlXPathObjectPtr
5415 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5416     xmlXPathObjectPtr ret;
5417 
5418     if (val == NULL)
5419 	return(NULL);
5420 
5421     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5422     if (ret == NULL) {
5423         xmlXPathErrMemory(NULL, "copying object\n");
5424 	return(NULL);
5425     }
5426     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5427 #ifdef XP_DEBUG_OBJ_USAGE
5428     xmlXPathDebugObjUsageRequested(NULL, val->type);
5429 #endif
5430     switch (val->type) {
5431 	case XPATH_BOOLEAN:
5432 	case XPATH_NUMBER:
5433 	case XPATH_POINT:
5434 	case XPATH_RANGE:
5435 	    break;
5436 	case XPATH_STRING:
5437 	    ret->stringval = xmlStrdup(val->stringval);
5438 	    break;
5439 	case XPATH_XSLT_TREE:
5440 #if 0
5441 /*
5442   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5443   this previous handling is no longer correct, and can cause some serious
5444   problems (ref. bug 145547)
5445 */
5446 	    if ((val->nodesetval != NULL) &&
5447 		(val->nodesetval->nodeTab != NULL)) {
5448 		xmlNodePtr cur, tmp;
5449 		xmlDocPtr top;
5450 
5451 		ret->boolval = 1;
5452 		top =  xmlNewDoc(NULL);
5453 		top->name = (char *)
5454 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5455 		ret->user = top;
5456 		if (top != NULL) {
5457 		    top->doc = top;
5458 		    cur = val->nodesetval->nodeTab[0]->children;
5459 		    while (cur != NULL) {
5460 			tmp = xmlDocCopyNode(cur, top, 1);
5461 			xmlAddChild((xmlNodePtr) top, tmp);
5462 			cur = cur->next;
5463 		    }
5464 		}
5465 
5466 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5467 	    } else
5468 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5469 	    /* Deallocate the copied tree value */
5470 	    break;
5471 #endif
5472 	case XPATH_NODESET:
5473 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5474 	    /* Do not deallocate the copied tree value */
5475 	    ret->boolval = 0;
5476 	    break;
5477 	case XPATH_LOCATIONSET:
5478 #ifdef LIBXML_XPTR_ENABLED
5479 	{
5480 	    xmlLocationSetPtr loc = val->user;
5481 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5482 	    break;
5483 	}
5484 #endif
5485         case XPATH_USERS:
5486 	    ret->user = val->user;
5487 	    break;
5488         case XPATH_UNDEFINED:
5489 	    xmlGenericError(xmlGenericErrorContext,
5490 		    "xmlXPathObjectCopy: unsupported type %d\n",
5491 		    val->type);
5492 	    break;
5493     }
5494     return(ret);
5495 }
5496 
5497 /**
5498  * xmlXPathFreeObject:
5499  * @obj:  the object to free
5500  *
5501  * Free up an xmlXPathObjectPtr object.
5502  */
5503 void
5504 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5505     if (obj == NULL) return;
5506     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5507 	if (obj->boolval) {
5508 #if 0
5509 	    if (obj->user != NULL) {
5510                 xmlXPathFreeNodeSet(obj->nodesetval);
5511 		xmlFreeNodeList((xmlNodePtr) obj->user);
5512 	    } else
5513 #endif
5514 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5515 	    if (obj->nodesetval != NULL)
5516 		xmlXPathFreeValueTree(obj->nodesetval);
5517 	} else {
5518 	    if (obj->nodesetval != NULL)
5519 		xmlXPathFreeNodeSet(obj->nodesetval);
5520 	}
5521 #ifdef LIBXML_XPTR_ENABLED
5522     } else if (obj->type == XPATH_LOCATIONSET) {
5523 	if (obj->user != NULL)
5524 	    xmlXPtrFreeLocationSet(obj->user);
5525 #endif
5526     } else if (obj->type == XPATH_STRING) {
5527 	if (obj->stringval != NULL)
5528 	    xmlFree(obj->stringval);
5529     }
5530 #ifdef XP_DEBUG_OBJ_USAGE
5531     xmlXPathDebugObjUsageReleased(NULL, obj->type);
5532 #endif
5533     xmlFree(obj);
5534 }
5535 
5536 /**
5537  * xmlXPathReleaseObject:
5538  * @obj:  the xmlXPathObjectPtr to free or to cache
5539  *
5540  * Depending on the state of the cache this frees the given
5541  * XPath object or stores it in the cache.
5542  */
5543 static void
5544 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5545 {
5546 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5547 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5548     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5549 
5550 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5551 
5552     if (obj == NULL)
5553 	return;
5554     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5555 	 xmlXPathFreeObject(obj);
5556     } else {
5557 	xmlXPathContextCachePtr cache =
5558 	    (xmlXPathContextCachePtr) ctxt->cache;
5559 
5560 	switch (obj->type) {
5561 	    case XPATH_NODESET:
5562 	    case XPATH_XSLT_TREE:
5563 		if (obj->nodesetval != NULL) {
5564 		    if (obj->boolval) {
5565 			/*
5566 			* It looks like the @boolval is used for
5567 			* evaluation if this an XSLT Result Tree Fragment.
5568 			* TODO: Check if this assumption is correct.
5569 			*/
5570 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
5571 			xmlXPathFreeValueTree(obj->nodesetval);
5572 			obj->nodesetval = NULL;
5573 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
5574 			(XP_CACHE_WANTS(cache->nodesetObjs,
5575 					cache->maxNodeset)))
5576 		    {
5577 			XP_CACHE_ADD(cache->nodesetObjs, obj);
5578 			goto obj_cached;
5579 		    } else {
5580 			xmlXPathFreeNodeSet(obj->nodesetval);
5581 			obj->nodesetval = NULL;
5582 		    }
5583 		}
5584 		break;
5585 	    case XPATH_STRING:
5586 		if (obj->stringval != NULL)
5587 		    xmlFree(obj->stringval);
5588 
5589 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5590 		    XP_CACHE_ADD(cache->stringObjs, obj);
5591 		    goto obj_cached;
5592 		}
5593 		break;
5594 	    case XPATH_BOOLEAN:
5595 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5596 		    XP_CACHE_ADD(cache->booleanObjs, obj);
5597 		    goto obj_cached;
5598 		}
5599 		break;
5600 	    case XPATH_NUMBER:
5601 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5602 		    XP_CACHE_ADD(cache->numberObjs, obj);
5603 		    goto obj_cached;
5604 		}
5605 		break;
5606 #ifdef LIBXML_XPTR_ENABLED
5607 	    case XPATH_LOCATIONSET:
5608 		if (obj->user != NULL) {
5609 		    xmlXPtrFreeLocationSet(obj->user);
5610 		}
5611 		goto free_obj;
5612 #endif
5613 	    default:
5614 		goto free_obj;
5615 	}
5616 
5617 	/*
5618 	* Fallback to adding to the misc-objects slot.
5619 	*/
5620 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5621 	    XP_CACHE_ADD(cache->miscObjs, obj);
5622 	} else
5623 	    goto free_obj;
5624 
5625 obj_cached:
5626 
5627 #ifdef XP_DEBUG_OBJ_USAGE
5628 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5629 #endif
5630 
5631 	if (obj->nodesetval != NULL) {
5632 	    xmlNodeSetPtr tmpset = obj->nodesetval;
5633 
5634 	    /*
5635 	    * TODO: Due to those nasty ns-nodes, we need to traverse
5636 	    *  the list and free the ns-nodes.
5637 	    * URGENT TODO: Check if it's actually slowing things down.
5638 	    *  Maybe we shouldn't try to preserve the list.
5639 	    */
5640 	    if (tmpset->nodeNr > 1) {
5641 		int i;
5642 		xmlNodePtr node;
5643 
5644 		for (i = 0; i < tmpset->nodeNr; i++) {
5645 		    node = tmpset->nodeTab[i];
5646 		    if ((node != NULL) &&
5647 			(node->type == XML_NAMESPACE_DECL))
5648 		    {
5649 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5650 		    }
5651 		}
5652 	    } else if (tmpset->nodeNr == 1) {
5653 		if ((tmpset->nodeTab[0] != NULL) &&
5654 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5655 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5656 	    }
5657 	    tmpset->nodeNr = 0;
5658 	    memset(obj, 0, sizeof(xmlXPathObject));
5659 	    obj->nodesetval = tmpset;
5660 	} else
5661 	    memset(obj, 0, sizeof(xmlXPathObject));
5662 
5663 	return;
5664 
5665 free_obj:
5666 	/*
5667 	* Cache is full; free the object.
5668 	*/
5669 	if (obj->nodesetval != NULL)
5670 	    xmlXPathFreeNodeSet(obj->nodesetval);
5671 #ifdef XP_DEBUG_OBJ_USAGE
5672 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
5673 #endif
5674 	xmlFree(obj);
5675     }
5676     return;
5677 }
5678 
5679 
5680 /************************************************************************
5681  *									*
5682  *			Type Casting Routines				*
5683  *									*
5684  ************************************************************************/
5685 
5686 /**
5687  * xmlXPathCastBooleanToString:
5688  * @val:  a boolean
5689  *
5690  * Converts a boolean to its string value.
5691  *
5692  * Returns a newly allocated string.
5693  */
5694 xmlChar *
5695 xmlXPathCastBooleanToString (int val) {
5696     xmlChar *ret;
5697     if (val)
5698 	ret = xmlStrdup((const xmlChar *) "true");
5699     else
5700 	ret = xmlStrdup((const xmlChar *) "false");
5701     return(ret);
5702 }
5703 
5704 /**
5705  * xmlXPathCastNumberToString:
5706  * @val:  a number
5707  *
5708  * Converts a number to its string value.
5709  *
5710  * Returns a newly allocated string.
5711  */
5712 xmlChar *
5713 xmlXPathCastNumberToString (double val) {
5714     xmlChar *ret;
5715     switch (xmlXPathIsInf(val)) {
5716     case 1:
5717 	ret = xmlStrdup((const xmlChar *) "Infinity");
5718 	break;
5719     case -1:
5720 	ret = xmlStrdup((const xmlChar *) "-Infinity");
5721 	break;
5722     default:
5723 	if (xmlXPathIsNaN(val)) {
5724 	    ret = xmlStrdup((const xmlChar *) "NaN");
5725 	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
5726 	    ret = xmlStrdup((const xmlChar *) "0");
5727 	} else {
5728 	    /* could be improved */
5729 	    char buf[100];
5730 	    xmlXPathFormatNumber(val, buf, 99);
5731 	    buf[99] = 0;
5732 	    ret = xmlStrdup((const xmlChar *) buf);
5733 	}
5734     }
5735     return(ret);
5736 }
5737 
5738 /**
5739  * xmlXPathCastNodeToString:
5740  * @node:  a node
5741  *
5742  * Converts a node to its string value.
5743  *
5744  * Returns a newly allocated string.
5745  */
5746 xmlChar *
5747 xmlXPathCastNodeToString (xmlNodePtr node) {
5748 xmlChar *ret;
5749     if ((ret = xmlNodeGetContent(node)) == NULL)
5750 	ret = xmlStrdup((const xmlChar *) "");
5751     return(ret);
5752 }
5753 
5754 /**
5755  * xmlXPathCastNodeSetToString:
5756  * @ns:  a node-set
5757  *
5758  * Converts a node-set to its string value.
5759  *
5760  * Returns a newly allocated string.
5761  */
5762 xmlChar *
5763 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5764     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5765 	return(xmlStrdup((const xmlChar *) ""));
5766 
5767     if (ns->nodeNr > 1)
5768 	xmlXPathNodeSetSort(ns);
5769     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5770 }
5771 
5772 /**
5773  * xmlXPathCastToString:
5774  * @val:  an XPath object
5775  *
5776  * Converts an existing object to its string() equivalent
5777  *
5778  * Returns the allocated string value of the object, NULL in case of error.
5779  *         It's up to the caller to free the string memory with xmlFree().
5780  */
5781 xmlChar *
5782 xmlXPathCastToString(xmlXPathObjectPtr val) {
5783     xmlChar *ret = NULL;
5784 
5785     if (val == NULL)
5786 	return(xmlStrdup((const xmlChar *) ""));
5787     switch (val->type) {
5788 	case XPATH_UNDEFINED:
5789 #ifdef DEBUG_EXPR
5790 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5791 #endif
5792 	    ret = xmlStrdup((const xmlChar *) "");
5793 	    break;
5794         case XPATH_NODESET:
5795         case XPATH_XSLT_TREE:
5796 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5797 	    break;
5798 	case XPATH_STRING:
5799 	    return(xmlStrdup(val->stringval));
5800         case XPATH_BOOLEAN:
5801 	    ret = xmlXPathCastBooleanToString(val->boolval);
5802 	    break;
5803 	case XPATH_NUMBER: {
5804 	    ret = xmlXPathCastNumberToString(val->floatval);
5805 	    break;
5806 	}
5807 	case XPATH_USERS:
5808 	case XPATH_POINT:
5809 	case XPATH_RANGE:
5810 	case XPATH_LOCATIONSET:
5811 	    TODO
5812 	    ret = xmlStrdup((const xmlChar *) "");
5813 	    break;
5814     }
5815     return(ret);
5816 }
5817 
5818 /**
5819  * xmlXPathConvertString:
5820  * @val:  an XPath object
5821  *
5822  * Converts an existing object to its string() equivalent
5823  *
5824  * Returns the new object, the old one is freed (or the operation
5825  *         is done directly on @val)
5826  */
5827 xmlXPathObjectPtr
5828 xmlXPathConvertString(xmlXPathObjectPtr val) {
5829     xmlChar *res = NULL;
5830 
5831     if (val == NULL)
5832 	return(xmlXPathNewCString(""));
5833 
5834     switch (val->type) {
5835     case XPATH_UNDEFINED:
5836 #ifdef DEBUG_EXPR
5837 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5838 #endif
5839 	break;
5840     case XPATH_NODESET:
5841     case XPATH_XSLT_TREE:
5842 	res = xmlXPathCastNodeSetToString(val->nodesetval);
5843 	break;
5844     case XPATH_STRING:
5845 	return(val);
5846     case XPATH_BOOLEAN:
5847 	res = xmlXPathCastBooleanToString(val->boolval);
5848 	break;
5849     case XPATH_NUMBER:
5850 	res = xmlXPathCastNumberToString(val->floatval);
5851 	break;
5852     case XPATH_USERS:
5853     case XPATH_POINT:
5854     case XPATH_RANGE:
5855     case XPATH_LOCATIONSET:
5856 	TODO;
5857 	break;
5858     }
5859     xmlXPathFreeObject(val);
5860     if (res == NULL)
5861 	return(xmlXPathNewCString(""));
5862     return(xmlXPathWrapString(res));
5863 }
5864 
5865 /**
5866  * xmlXPathCastBooleanToNumber:
5867  * @val:  a boolean
5868  *
5869  * Converts a boolean to its number value
5870  *
5871  * Returns the number value
5872  */
5873 double
5874 xmlXPathCastBooleanToNumber(int val) {
5875     if (val)
5876 	return(1.0);
5877     return(0.0);
5878 }
5879 
5880 /**
5881  * xmlXPathCastStringToNumber:
5882  * @val:  a string
5883  *
5884  * Converts a string to its number value
5885  *
5886  * Returns the number value
5887  */
5888 double
5889 xmlXPathCastStringToNumber(const xmlChar * val) {
5890     return(xmlXPathStringEvalNumber(val));
5891 }
5892 
5893 /**
5894  * xmlXPathCastNodeToNumber:
5895  * @node:  a node
5896  *
5897  * Converts a node to its number value
5898  *
5899  * Returns the number value
5900  */
5901 double
5902 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5903     xmlChar *strval;
5904     double ret;
5905 
5906     if (node == NULL)
5907 	return(xmlXPathNAN);
5908     strval = xmlXPathCastNodeToString(node);
5909     if (strval == NULL)
5910 	return(xmlXPathNAN);
5911     ret = xmlXPathCastStringToNumber(strval);
5912     xmlFree(strval);
5913 
5914     return(ret);
5915 }
5916 
5917 /**
5918  * xmlXPathCastNodeSetToNumber:
5919  * @ns:  a node-set
5920  *
5921  * Converts a node-set to its number value
5922  *
5923  * Returns the number value
5924  */
5925 double
5926 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5927     xmlChar *str;
5928     double ret;
5929 
5930     if (ns == NULL)
5931 	return(xmlXPathNAN);
5932     str = xmlXPathCastNodeSetToString(ns);
5933     ret = xmlXPathCastStringToNumber(str);
5934     xmlFree(str);
5935     return(ret);
5936 }
5937 
5938 /**
5939  * xmlXPathCastToNumber:
5940  * @val:  an XPath object
5941  *
5942  * Converts an XPath object to its number value
5943  *
5944  * Returns the number value
5945  */
5946 double
5947 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5948     double ret = 0.0;
5949 
5950     if (val == NULL)
5951 	return(xmlXPathNAN);
5952     switch (val->type) {
5953     case XPATH_UNDEFINED:
5954 #ifdef DEGUB_EXPR
5955 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5956 #endif
5957 	ret = xmlXPathNAN;
5958 	break;
5959     case XPATH_NODESET:
5960     case XPATH_XSLT_TREE:
5961 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5962 	break;
5963     case XPATH_STRING:
5964 	ret = xmlXPathCastStringToNumber(val->stringval);
5965 	break;
5966     case XPATH_NUMBER:
5967 	ret = val->floatval;
5968 	break;
5969     case XPATH_BOOLEAN:
5970 	ret = xmlXPathCastBooleanToNumber(val->boolval);
5971 	break;
5972     case XPATH_USERS:
5973     case XPATH_POINT:
5974     case XPATH_RANGE:
5975     case XPATH_LOCATIONSET:
5976 	TODO;
5977 	ret = xmlXPathNAN;
5978 	break;
5979     }
5980     return(ret);
5981 }
5982 
5983 /**
5984  * xmlXPathConvertNumber:
5985  * @val:  an XPath object
5986  *
5987  * Converts an existing object to its number() equivalent
5988  *
5989  * Returns the new object, the old one is freed (or the operation
5990  *         is done directly on @val)
5991  */
5992 xmlXPathObjectPtr
5993 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5994     xmlXPathObjectPtr ret;
5995 
5996     if (val == NULL)
5997 	return(xmlXPathNewFloat(0.0));
5998     if (val->type == XPATH_NUMBER)
5999 	return(val);
6000     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
6001     xmlXPathFreeObject(val);
6002     return(ret);
6003 }
6004 
6005 /**
6006  * xmlXPathCastNumberToBoolean:
6007  * @val:  a number
6008  *
6009  * Converts a number to its boolean value
6010  *
6011  * Returns the boolean value
6012  */
6013 int
6014 xmlXPathCastNumberToBoolean (double val) {
6015      if (xmlXPathIsNaN(val) || (val == 0.0))
6016 	 return(0);
6017      return(1);
6018 }
6019 
6020 /**
6021  * xmlXPathCastStringToBoolean:
6022  * @val:  a string
6023  *
6024  * Converts a string to its boolean value
6025  *
6026  * Returns the boolean value
6027  */
6028 int
6029 xmlXPathCastStringToBoolean (const xmlChar *val) {
6030     if ((val == NULL) || (xmlStrlen(val) == 0))
6031 	return(0);
6032     return(1);
6033 }
6034 
6035 /**
6036  * xmlXPathCastNodeSetToBoolean:
6037  * @ns:  a node-set
6038  *
6039  * Converts a node-set to its boolean value
6040  *
6041  * Returns the boolean value
6042  */
6043 int
6044 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6045     if ((ns == NULL) || (ns->nodeNr == 0))
6046 	return(0);
6047     return(1);
6048 }
6049 
6050 /**
6051  * xmlXPathCastToBoolean:
6052  * @val:  an XPath object
6053  *
6054  * Converts an XPath object to its boolean value
6055  *
6056  * Returns the boolean value
6057  */
6058 int
6059 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6060     int ret = 0;
6061 
6062     if (val == NULL)
6063 	return(0);
6064     switch (val->type) {
6065     case XPATH_UNDEFINED:
6066 #ifdef DEBUG_EXPR
6067 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6068 #endif
6069 	ret = 0;
6070 	break;
6071     case XPATH_NODESET:
6072     case XPATH_XSLT_TREE:
6073 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6074 	break;
6075     case XPATH_STRING:
6076 	ret = xmlXPathCastStringToBoolean(val->stringval);
6077 	break;
6078     case XPATH_NUMBER:
6079 	ret = xmlXPathCastNumberToBoolean(val->floatval);
6080 	break;
6081     case XPATH_BOOLEAN:
6082 	ret = val->boolval;
6083 	break;
6084     case XPATH_USERS:
6085     case XPATH_POINT:
6086     case XPATH_RANGE:
6087     case XPATH_LOCATIONSET:
6088 	TODO;
6089 	ret = 0;
6090 	break;
6091     }
6092     return(ret);
6093 }
6094 
6095 
6096 /**
6097  * xmlXPathConvertBoolean:
6098  * @val:  an XPath object
6099  *
6100  * Converts an existing object to its boolean() equivalent
6101  *
6102  * Returns the new object, the old one is freed (or the operation
6103  *         is done directly on @val)
6104  */
6105 xmlXPathObjectPtr
6106 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6107     xmlXPathObjectPtr ret;
6108 
6109     if (val == NULL)
6110 	return(xmlXPathNewBoolean(0));
6111     if (val->type == XPATH_BOOLEAN)
6112 	return(val);
6113     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6114     xmlXPathFreeObject(val);
6115     return(ret);
6116 }
6117 
6118 /************************************************************************
6119  *									*
6120  *		Routines to handle XPath contexts			*
6121  *									*
6122  ************************************************************************/
6123 
6124 /**
6125  * xmlXPathNewContext:
6126  * @doc:  the XML document
6127  *
6128  * Create a new xmlXPathContext
6129  *
6130  * Returns the xmlXPathContext just allocated. The caller will need to free it.
6131  */
6132 xmlXPathContextPtr
6133 xmlXPathNewContext(xmlDocPtr doc) {
6134     xmlXPathContextPtr ret;
6135 
6136     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6137     if (ret == NULL) {
6138         xmlXPathErrMemory(NULL, "creating context\n");
6139 	return(NULL);
6140     }
6141     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6142     ret->doc = doc;
6143     ret->node = NULL;
6144 
6145     ret->varHash = NULL;
6146 
6147     ret->nb_types = 0;
6148     ret->max_types = 0;
6149     ret->types = NULL;
6150 
6151     ret->funcHash = xmlHashCreate(0);
6152 
6153     ret->nb_axis = 0;
6154     ret->max_axis = 0;
6155     ret->axis = NULL;
6156 
6157     ret->nsHash = NULL;
6158     ret->user = NULL;
6159 
6160     ret->contextSize = -1;
6161     ret->proximityPosition = -1;
6162 
6163 #ifdef XP_DEFAULT_CACHE_ON
6164     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6165 	xmlXPathFreeContext(ret);
6166 	return(NULL);
6167     }
6168 #endif
6169 
6170     xmlXPathRegisterAllFunctions(ret);
6171 
6172     return(ret);
6173 }
6174 
6175 /**
6176  * xmlXPathFreeContext:
6177  * @ctxt:  the context to free
6178  *
6179  * Free up an xmlXPathContext
6180  */
6181 void
6182 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6183     if (ctxt == NULL) return;
6184 
6185     if (ctxt->cache != NULL)
6186 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6187     xmlXPathRegisteredNsCleanup(ctxt);
6188     xmlXPathRegisteredFuncsCleanup(ctxt);
6189     xmlXPathRegisteredVariablesCleanup(ctxt);
6190     xmlResetError(&ctxt->lastError);
6191     xmlFree(ctxt);
6192 }
6193 
6194 /************************************************************************
6195  *									*
6196  *		Routines to handle XPath parser contexts		*
6197  *									*
6198  ************************************************************************/
6199 
6200 #define CHECK_CTXT(ctxt)						\
6201     if (ctxt == NULL) {						\
6202 	__xmlRaiseError(NULL, NULL, NULL,				\
6203 		NULL, NULL, XML_FROM_XPATH,				\
6204 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6205 		__FILE__, __LINE__,					\
6206 		NULL, NULL, NULL, 0, 0,					\
6207 		"NULL context pointer\n");				\
6208 	return(NULL);							\
6209     }									\
6210 
6211 #define CHECK_CTXT_NEG(ctxt)						\
6212     if (ctxt == NULL) {						\
6213 	__xmlRaiseError(NULL, NULL, NULL,				\
6214 		NULL, NULL, XML_FROM_XPATH,				\
6215 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6216 		__FILE__, __LINE__,					\
6217 		NULL, NULL, NULL, 0, 0,					\
6218 		"NULL context pointer\n");				\
6219 	return(-1);							\
6220     }									\
6221 
6222 
6223 #define CHECK_CONTEXT(ctxt)						\
6224     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
6225         (ctxt->doc->children == NULL)) {				\
6226 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
6227 	return(NULL);							\
6228     }
6229 
6230 
6231 /**
6232  * xmlXPathNewParserContext:
6233  * @str:  the XPath expression
6234  * @ctxt:  the XPath context
6235  *
6236  * Create a new xmlXPathParserContext
6237  *
6238  * Returns the xmlXPathParserContext just allocated.
6239  */
6240 xmlXPathParserContextPtr
6241 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6242     xmlXPathParserContextPtr ret;
6243 
6244     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6245     if (ret == NULL) {
6246         xmlXPathErrMemory(ctxt, "creating parser context\n");
6247 	return(NULL);
6248     }
6249     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6250     ret->cur = ret->base = str;
6251     ret->context = ctxt;
6252 
6253     ret->comp = xmlXPathNewCompExpr();
6254     if (ret->comp == NULL) {
6255 	xmlFree(ret->valueTab);
6256 	xmlFree(ret);
6257 	return(NULL);
6258     }
6259     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6260         ret->comp->dict = ctxt->dict;
6261 	xmlDictReference(ret->comp->dict);
6262     }
6263 
6264     return(ret);
6265 }
6266 
6267 /**
6268  * xmlXPathCompParserContext:
6269  * @comp:  the XPath compiled expression
6270  * @ctxt:  the XPath context
6271  *
6272  * Create a new xmlXPathParserContext when processing a compiled expression
6273  *
6274  * Returns the xmlXPathParserContext just allocated.
6275  */
6276 static xmlXPathParserContextPtr
6277 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6278     xmlXPathParserContextPtr ret;
6279 
6280     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6281     if (ret == NULL) {
6282         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6283 	return(NULL);
6284     }
6285     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6286 
6287     /* Allocate the value stack */
6288     ret->valueTab = (xmlXPathObjectPtr *)
6289                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6290     if (ret->valueTab == NULL) {
6291 	xmlFree(ret);
6292 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6293 	return(NULL);
6294     }
6295     ret->valueNr = 0;
6296     ret->valueMax = 10;
6297     ret->value = NULL;
6298     ret->valueFrame = 0;
6299 
6300     ret->context = ctxt;
6301     ret->comp = comp;
6302 
6303     return(ret);
6304 }
6305 
6306 /**
6307  * xmlXPathFreeParserContext:
6308  * @ctxt:  the context to free
6309  *
6310  * Free up an xmlXPathParserContext
6311  */
6312 void
6313 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6314     int i;
6315 
6316     if (ctxt->valueTab != NULL) {
6317         for (i = 0; i < ctxt->valueNr; i++) {
6318             if (ctxt->context)
6319                 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6320             else
6321                 xmlXPathFreeObject(ctxt->valueTab[i]);
6322         }
6323         xmlFree(ctxt->valueTab);
6324     }
6325     if (ctxt->comp != NULL) {
6326 #ifdef XPATH_STREAMING
6327 	if (ctxt->comp->stream != NULL) {
6328 	    xmlFreePatternList(ctxt->comp->stream);
6329 	    ctxt->comp->stream = NULL;
6330 	}
6331 #endif
6332 	xmlXPathFreeCompExpr(ctxt->comp);
6333     }
6334     xmlFree(ctxt);
6335 }
6336 
6337 /************************************************************************
6338  *									*
6339  *		The implicit core function library			*
6340  *									*
6341  ************************************************************************/
6342 
6343 /**
6344  * xmlXPathNodeValHash:
6345  * @node:  a node pointer
6346  *
6347  * Function computing the beginning of the string value of the node,
6348  * used to speed up comparisons
6349  *
6350  * Returns an int usable as a hash
6351  */
6352 static unsigned int
6353 xmlXPathNodeValHash(xmlNodePtr node) {
6354     int len = 2;
6355     const xmlChar * string = NULL;
6356     xmlNodePtr tmp = NULL;
6357     unsigned int ret = 0;
6358 
6359     if (node == NULL)
6360 	return(0);
6361 
6362     if (node->type == XML_DOCUMENT_NODE) {
6363 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
6364 	if (tmp == NULL)
6365 	    node = node->children;
6366 	else
6367 	    node = tmp;
6368 
6369 	if (node == NULL)
6370 	    return(0);
6371     }
6372 
6373     switch (node->type) {
6374 	case XML_COMMENT_NODE:
6375 	case XML_PI_NODE:
6376 	case XML_CDATA_SECTION_NODE:
6377 	case XML_TEXT_NODE:
6378 	    string = node->content;
6379 	    if (string == NULL)
6380 		return(0);
6381 	    if (string[0] == 0)
6382 		return(0);
6383 	    return(((unsigned int) string[0]) +
6384 		   (((unsigned int) string[1]) << 8));
6385 	case XML_NAMESPACE_DECL:
6386 	    string = ((xmlNsPtr)node)->href;
6387 	    if (string == NULL)
6388 		return(0);
6389 	    if (string[0] == 0)
6390 		return(0);
6391 	    return(((unsigned int) string[0]) +
6392 		   (((unsigned int) string[1]) << 8));
6393 	case XML_ATTRIBUTE_NODE:
6394 	    tmp = ((xmlAttrPtr) node)->children;
6395 	    break;
6396 	case XML_ELEMENT_NODE:
6397 	    tmp = node->children;
6398 	    break;
6399 	default:
6400 	    return(0);
6401     }
6402     while (tmp != NULL) {
6403 	switch (tmp->type) {
6404 	    case XML_CDATA_SECTION_NODE:
6405 	    case XML_TEXT_NODE:
6406 		string = tmp->content;
6407 		break;
6408 	    default:
6409                 string = NULL;
6410 		break;
6411 	}
6412 	if ((string != NULL) && (string[0] != 0)) {
6413 	    if (len == 1) {
6414 		return(ret + (((unsigned int) string[0]) << 8));
6415 	    }
6416 	    if (string[1] == 0) {
6417 		len = 1;
6418 		ret = (unsigned int) string[0];
6419 	    } else {
6420 		return(((unsigned int) string[0]) +
6421 		       (((unsigned int) string[1]) << 8));
6422 	    }
6423 	}
6424 	/*
6425 	 * Skip to next node
6426 	 */
6427 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6428 	    if (tmp->children->type != XML_ENTITY_DECL) {
6429 		tmp = tmp->children;
6430 		continue;
6431 	    }
6432 	}
6433 	if (tmp == node)
6434 	    break;
6435 
6436 	if (tmp->next != NULL) {
6437 	    tmp = tmp->next;
6438 	    continue;
6439 	}
6440 
6441 	do {
6442 	    tmp = tmp->parent;
6443 	    if (tmp == NULL)
6444 		break;
6445 	    if (tmp == node) {
6446 		tmp = NULL;
6447 		break;
6448 	    }
6449 	    if (tmp->next != NULL) {
6450 		tmp = tmp->next;
6451 		break;
6452 	    }
6453 	} while (tmp != NULL);
6454     }
6455     return(ret);
6456 }
6457 
6458 /**
6459  * xmlXPathStringHash:
6460  * @string:  a string
6461  *
6462  * Function computing the beginning of the string value of the node,
6463  * used to speed up comparisons
6464  *
6465  * Returns an int usable as a hash
6466  */
6467 static unsigned int
6468 xmlXPathStringHash(const xmlChar * string) {
6469     if (string == NULL)
6470 	return((unsigned int) 0);
6471     if (string[0] == 0)
6472 	return(0);
6473     return(((unsigned int) string[0]) +
6474 	   (((unsigned int) string[1]) << 8));
6475 }
6476 
6477 /**
6478  * xmlXPathCompareNodeSetFloat:
6479  * @ctxt:  the XPath Parser context
6480  * @inf:  less than (1) or greater than (0)
6481  * @strict:  is the comparison strict
6482  * @arg:  the node set
6483  * @f:  the value
6484  *
6485  * Implement the compare operation between a nodeset and a number
6486  *     @ns < @val    (1, 1, ...
6487  *     @ns <= @val   (1, 0, ...
6488  *     @ns > @val    (0, 1, ...
6489  *     @ns >= @val   (0, 0, ...
6490  *
6491  * If one object to be compared is a node-set and the other is a number,
6492  * then the comparison will be true if and only if there is a node in the
6493  * node-set such that the result of performing the comparison on the number
6494  * to be compared and on the result of converting the string-value of that
6495  * node to a number using the number function is true.
6496  *
6497  * Returns 0 or 1 depending on the results of the test.
6498  */
6499 static int
6500 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6501 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6502     int i, ret = 0;
6503     xmlNodeSetPtr ns;
6504     xmlChar *str2;
6505 
6506     if ((f == NULL) || (arg == NULL) ||
6507 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6508 	xmlXPathReleaseObject(ctxt->context, arg);
6509 	xmlXPathReleaseObject(ctxt->context, f);
6510         return(0);
6511     }
6512     ns = arg->nodesetval;
6513     if (ns != NULL) {
6514 	for (i = 0;i < ns->nodeNr;i++) {
6515 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6516 	     if (str2 != NULL) {
6517 		 valuePush(ctxt,
6518 			   xmlXPathCacheNewString(ctxt->context, str2));
6519 		 xmlFree(str2);
6520 		 xmlXPathNumberFunction(ctxt, 1);
6521 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6522 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6523 		 if (ret)
6524 		     break;
6525 	     }
6526 	}
6527     }
6528     xmlXPathReleaseObject(ctxt->context, arg);
6529     xmlXPathReleaseObject(ctxt->context, f);
6530     return(ret);
6531 }
6532 
6533 /**
6534  * xmlXPathCompareNodeSetString:
6535  * @ctxt:  the XPath Parser context
6536  * @inf:  less than (1) or greater than (0)
6537  * @strict:  is the comparison strict
6538  * @arg:  the node set
6539  * @s:  the value
6540  *
6541  * Implement the compare operation between a nodeset and a string
6542  *     @ns < @val    (1, 1, ...
6543  *     @ns <= @val   (1, 0, ...
6544  *     @ns > @val    (0, 1, ...
6545  *     @ns >= @val   (0, 0, ...
6546  *
6547  * If one object to be compared is a node-set and the other is a string,
6548  * then the comparison will be true if and only if there is a node in
6549  * the node-set such that the result of performing the comparison on the
6550  * string-value of the node and the other string is true.
6551  *
6552  * Returns 0 or 1 depending on the results of the test.
6553  */
6554 static int
6555 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6556 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6557     int i, ret = 0;
6558     xmlNodeSetPtr ns;
6559     xmlChar *str2;
6560 
6561     if ((s == NULL) || (arg == NULL) ||
6562 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6563 	xmlXPathReleaseObject(ctxt->context, arg);
6564 	xmlXPathReleaseObject(ctxt->context, s);
6565         return(0);
6566     }
6567     ns = arg->nodesetval;
6568     if (ns != NULL) {
6569 	for (i = 0;i < ns->nodeNr;i++) {
6570 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6571 	     if (str2 != NULL) {
6572 		 valuePush(ctxt,
6573 			   xmlXPathCacheNewString(ctxt->context, str2));
6574 		 xmlFree(str2);
6575 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6576 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6577 		 if (ret)
6578 		     break;
6579 	     }
6580 	}
6581     }
6582     xmlXPathReleaseObject(ctxt->context, arg);
6583     xmlXPathReleaseObject(ctxt->context, s);
6584     return(ret);
6585 }
6586 
6587 /**
6588  * xmlXPathCompareNodeSets:
6589  * @inf:  less than (1) or greater than (0)
6590  * @strict:  is the comparison strict
6591  * @arg1:  the first node set object
6592  * @arg2:  the second node set object
6593  *
6594  * Implement the compare operation on nodesets:
6595  *
6596  * If both objects to be compared are node-sets, then the comparison
6597  * will be true if and only if there is a node in the first node-set
6598  * and a node in the second node-set such that the result of performing
6599  * the comparison on the string-values of the two nodes is true.
6600  * ....
6601  * When neither object to be compared is a node-set and the operator
6602  * is <=, <, >= or >, then the objects are compared by converting both
6603  * objects to numbers and comparing the numbers according to IEEE 754.
6604  * ....
6605  * The number function converts its argument to a number as follows:
6606  *  - a string that consists of optional whitespace followed by an
6607  *    optional minus sign followed by a Number followed by whitespace
6608  *    is converted to the IEEE 754 number that is nearest (according
6609  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6610  *    represented by the string; any other string is converted to NaN
6611  *
6612  * Conclusion all nodes need to be converted first to their string value
6613  * and then the comparison must be done when possible
6614  */
6615 static int
6616 xmlXPathCompareNodeSets(int inf, int strict,
6617 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6618     int i, j, init = 0;
6619     double val1;
6620     double *values2;
6621     int ret = 0;
6622     xmlNodeSetPtr ns1;
6623     xmlNodeSetPtr ns2;
6624 
6625     if ((arg1 == NULL) ||
6626 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6627 	xmlXPathFreeObject(arg2);
6628         return(0);
6629     }
6630     if ((arg2 == NULL) ||
6631 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6632 	xmlXPathFreeObject(arg1);
6633 	xmlXPathFreeObject(arg2);
6634         return(0);
6635     }
6636 
6637     ns1 = arg1->nodesetval;
6638     ns2 = arg2->nodesetval;
6639 
6640     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6641 	xmlXPathFreeObject(arg1);
6642 	xmlXPathFreeObject(arg2);
6643 	return(0);
6644     }
6645     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6646 	xmlXPathFreeObject(arg1);
6647 	xmlXPathFreeObject(arg2);
6648 	return(0);
6649     }
6650 
6651     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6652     if (values2 == NULL) {
6653         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6654 	xmlXPathFreeObject(arg1);
6655 	xmlXPathFreeObject(arg2);
6656 	return(0);
6657     }
6658     for (i = 0;i < ns1->nodeNr;i++) {
6659 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6660 	if (xmlXPathIsNaN(val1))
6661 	    continue;
6662 	for (j = 0;j < ns2->nodeNr;j++) {
6663 	    if (init == 0) {
6664 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6665 	    }
6666 	    if (xmlXPathIsNaN(values2[j]))
6667 		continue;
6668 	    if (inf && strict)
6669 		ret = (val1 < values2[j]);
6670 	    else if (inf && !strict)
6671 		ret = (val1 <= values2[j]);
6672 	    else if (!inf && strict)
6673 		ret = (val1 > values2[j]);
6674 	    else if (!inf && !strict)
6675 		ret = (val1 >= values2[j]);
6676 	    if (ret)
6677 		break;
6678 	}
6679 	if (ret)
6680 	    break;
6681 	init = 1;
6682     }
6683     xmlFree(values2);
6684     xmlXPathFreeObject(arg1);
6685     xmlXPathFreeObject(arg2);
6686     return(ret);
6687 }
6688 
6689 /**
6690  * xmlXPathCompareNodeSetValue:
6691  * @ctxt:  the XPath Parser context
6692  * @inf:  less than (1) or greater than (0)
6693  * @strict:  is the comparison strict
6694  * @arg:  the node set
6695  * @val:  the value
6696  *
6697  * Implement the compare operation between a nodeset and a value
6698  *     @ns < @val    (1, 1, ...
6699  *     @ns <= @val   (1, 0, ...
6700  *     @ns > @val    (0, 1, ...
6701  *     @ns >= @val   (0, 0, ...
6702  *
6703  * If one object to be compared is a node-set and the other is a boolean,
6704  * then the comparison will be true if and only if the result of performing
6705  * the comparison on the boolean and on the result of converting
6706  * the node-set to a boolean using the boolean function is true.
6707  *
6708  * Returns 0 or 1 depending on the results of the test.
6709  */
6710 static int
6711 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6712 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6713     if ((val == NULL) || (arg == NULL) ||
6714 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6715         return(0);
6716 
6717     switch(val->type) {
6718         case XPATH_NUMBER:
6719 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6720         case XPATH_NODESET:
6721         case XPATH_XSLT_TREE:
6722 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6723         case XPATH_STRING:
6724 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6725         case XPATH_BOOLEAN:
6726 	    valuePush(ctxt, arg);
6727 	    xmlXPathBooleanFunction(ctxt, 1);
6728 	    valuePush(ctxt, val);
6729 	    return(xmlXPathCompareValues(ctxt, inf, strict));
6730 	default:
6731             xmlGenericError(xmlGenericErrorContext,
6732                     "xmlXPathCompareNodeSetValue: Can't compare node set "
6733                     "and object of type %d\n",
6734                     val->type);
6735             xmlXPathReleaseObject(ctxt->context, arg);
6736             xmlXPathReleaseObject(ctxt->context, val);
6737             XP_ERROR0(XPATH_INVALID_TYPE);
6738     }
6739     return(0);
6740 }
6741 
6742 /**
6743  * xmlXPathEqualNodeSetString:
6744  * @arg:  the nodeset object argument
6745  * @str:  the string to compare to.
6746  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6747  *
6748  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6749  * If one object to be compared is a node-set and the other is a string,
6750  * then the comparison will be true if and only if there is a node in
6751  * the node-set such that the result of performing the comparison on the
6752  * string-value of the node and the other string is true.
6753  *
6754  * Returns 0 or 1 depending on the results of the test.
6755  */
6756 static int
6757 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6758 {
6759     int i;
6760     xmlNodeSetPtr ns;
6761     xmlChar *str2;
6762     unsigned int hash;
6763 
6764     if ((str == NULL) || (arg == NULL) ||
6765         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6766         return (0);
6767     ns = arg->nodesetval;
6768     /*
6769      * A NULL nodeset compared with a string is always false
6770      * (since there is no node equal, and no node not equal)
6771      */
6772     if ((ns == NULL) || (ns->nodeNr <= 0) )
6773         return (0);
6774     hash = xmlXPathStringHash(str);
6775     for (i = 0; i < ns->nodeNr; i++) {
6776         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6777             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6778             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6779                 xmlFree(str2);
6780 		if (neq)
6781 		    continue;
6782                 return (1);
6783 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6784 		if (neq)
6785 		    continue;
6786                 return (1);
6787             } else if (neq) {
6788 		if (str2 != NULL)
6789 		    xmlFree(str2);
6790 		return (1);
6791 	    }
6792             if (str2 != NULL)
6793                 xmlFree(str2);
6794         } else if (neq)
6795 	    return (1);
6796     }
6797     return (0);
6798 }
6799 
6800 /**
6801  * xmlXPathEqualNodeSetFloat:
6802  * @arg:  the nodeset object argument
6803  * @f:  the float to compare to
6804  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6805  *
6806  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6807  * If one object to be compared is a node-set and the other is a number,
6808  * then the comparison will be true if and only if there is a node in
6809  * the node-set such that the result of performing the comparison on the
6810  * number to be compared and on the result of converting the string-value
6811  * of that node to a number using the number function is true.
6812  *
6813  * Returns 0 or 1 depending on the results of the test.
6814  */
6815 static int
6816 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6817     xmlXPathObjectPtr arg, double f, int neq) {
6818   int i, ret=0;
6819   xmlNodeSetPtr ns;
6820   xmlChar *str2;
6821   xmlXPathObjectPtr val;
6822   double v;
6823 
6824     if ((arg == NULL) ||
6825 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6826         return(0);
6827 
6828     ns = arg->nodesetval;
6829     if (ns != NULL) {
6830 	for (i=0;i<ns->nodeNr;i++) {
6831 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6832 	    if (str2 != NULL) {
6833 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6834 		xmlFree(str2);
6835 		xmlXPathNumberFunction(ctxt, 1);
6836 		val = valuePop(ctxt);
6837 		v = val->floatval;
6838 		xmlXPathReleaseObject(ctxt->context, val);
6839 		if (!xmlXPathIsNaN(v)) {
6840 		    if ((!neq) && (v==f)) {
6841 			ret = 1;
6842 			break;
6843 		    } else if ((neq) && (v!=f)) {
6844 			ret = 1;
6845 			break;
6846 		    }
6847 		} else {	/* NaN is unequal to any value */
6848 		    if (neq)
6849 			ret = 1;
6850 		}
6851 	    }
6852 	}
6853     }
6854 
6855     return(ret);
6856 }
6857 
6858 
6859 /**
6860  * xmlXPathEqualNodeSets:
6861  * @arg1:  first nodeset object argument
6862  * @arg2:  second nodeset object argument
6863  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6864  *
6865  * Implement the equal / not equal operation on XPath nodesets:
6866  * @arg1 == @arg2  or  @arg1 != @arg2
6867  * If both objects to be compared are node-sets, then the comparison
6868  * will be true if and only if there is a node in the first node-set and
6869  * a node in the second node-set such that the result of performing the
6870  * comparison on the string-values of the two nodes is true.
6871  *
6872  * (needless to say, this is a costly operation)
6873  *
6874  * Returns 0 or 1 depending on the results of the test.
6875  */
6876 static int
6877 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6878     int i, j;
6879     unsigned int *hashs1;
6880     unsigned int *hashs2;
6881     xmlChar **values1;
6882     xmlChar **values2;
6883     int ret = 0;
6884     xmlNodeSetPtr ns1;
6885     xmlNodeSetPtr ns2;
6886 
6887     if ((arg1 == NULL) ||
6888 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6889         return(0);
6890     if ((arg2 == NULL) ||
6891 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6892         return(0);
6893 
6894     ns1 = arg1->nodesetval;
6895     ns2 = arg2->nodesetval;
6896 
6897     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6898 	return(0);
6899     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6900 	return(0);
6901 
6902     /*
6903      * for equal, check if there is a node pertaining to both sets
6904      */
6905     if (neq == 0)
6906 	for (i = 0;i < ns1->nodeNr;i++)
6907 	    for (j = 0;j < ns2->nodeNr;j++)
6908 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6909 		    return(1);
6910 
6911     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6912     if (values1 == NULL) {
6913         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6914 	return(0);
6915     }
6916     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6917     if (hashs1 == NULL) {
6918         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6919 	xmlFree(values1);
6920 	return(0);
6921     }
6922     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6923     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6924     if (values2 == NULL) {
6925         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6926 	xmlFree(hashs1);
6927 	xmlFree(values1);
6928 	return(0);
6929     }
6930     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6931     if (hashs2 == NULL) {
6932         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6933 	xmlFree(hashs1);
6934 	xmlFree(values1);
6935 	xmlFree(values2);
6936 	return(0);
6937     }
6938     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6939     for (i = 0;i < ns1->nodeNr;i++) {
6940 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6941 	for (j = 0;j < ns2->nodeNr;j++) {
6942 	    if (i == 0)
6943 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6944 	    if (hashs1[i] != hashs2[j]) {
6945 		if (neq) {
6946 		    ret = 1;
6947 		    break;
6948 		}
6949 	    }
6950 	    else {
6951 		if (values1[i] == NULL)
6952 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6953 		if (values2[j] == NULL)
6954 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6955 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6956 		if (ret)
6957 		    break;
6958 	    }
6959 	}
6960 	if (ret)
6961 	    break;
6962     }
6963     for (i = 0;i < ns1->nodeNr;i++)
6964 	if (values1[i] != NULL)
6965 	    xmlFree(values1[i]);
6966     for (j = 0;j < ns2->nodeNr;j++)
6967 	if (values2[j] != NULL)
6968 	    xmlFree(values2[j]);
6969     xmlFree(values1);
6970     xmlFree(values2);
6971     xmlFree(hashs1);
6972     xmlFree(hashs2);
6973     return(ret);
6974 }
6975 
6976 static int
6977 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6978   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6979     int ret = 0;
6980     /*
6981      *At this point we are assured neither arg1 nor arg2
6982      *is a nodeset, so we can just pick the appropriate routine.
6983      */
6984     switch (arg1->type) {
6985         case XPATH_UNDEFINED:
6986 #ifdef DEBUG_EXPR
6987 	    xmlGenericError(xmlGenericErrorContext,
6988 		    "Equal: undefined\n");
6989 #endif
6990 	    break;
6991         case XPATH_BOOLEAN:
6992 	    switch (arg2->type) {
6993 	        case XPATH_UNDEFINED:
6994 #ifdef DEBUG_EXPR
6995 		    xmlGenericError(xmlGenericErrorContext,
6996 			    "Equal: undefined\n");
6997 #endif
6998 		    break;
6999 		case XPATH_BOOLEAN:
7000 #ifdef DEBUG_EXPR
7001 		    xmlGenericError(xmlGenericErrorContext,
7002 			    "Equal: %d boolean %d \n",
7003 			    arg1->boolval, arg2->boolval);
7004 #endif
7005 		    ret = (arg1->boolval == arg2->boolval);
7006 		    break;
7007 		case XPATH_NUMBER:
7008 		    ret = (arg1->boolval ==
7009 			   xmlXPathCastNumberToBoolean(arg2->floatval));
7010 		    break;
7011 		case XPATH_STRING:
7012 		    if ((arg2->stringval == NULL) ||
7013 			(arg2->stringval[0] == 0)) ret = 0;
7014 		    else
7015 			ret = 1;
7016 		    ret = (arg1->boolval == ret);
7017 		    break;
7018 		case XPATH_USERS:
7019 		case XPATH_POINT:
7020 		case XPATH_RANGE:
7021 		case XPATH_LOCATIONSET:
7022 		    TODO
7023 		    break;
7024 		case XPATH_NODESET:
7025 		case XPATH_XSLT_TREE:
7026 		    break;
7027 	    }
7028 	    break;
7029         case XPATH_NUMBER:
7030 	    switch (arg2->type) {
7031 	        case XPATH_UNDEFINED:
7032 #ifdef DEBUG_EXPR
7033 		    xmlGenericError(xmlGenericErrorContext,
7034 			    "Equal: undefined\n");
7035 #endif
7036 		    break;
7037 		case XPATH_BOOLEAN:
7038 		    ret = (arg2->boolval==
7039 			   xmlXPathCastNumberToBoolean(arg1->floatval));
7040 		    break;
7041 		case XPATH_STRING:
7042 		    valuePush(ctxt, arg2);
7043 		    xmlXPathNumberFunction(ctxt, 1);
7044 		    arg2 = valuePop(ctxt);
7045                     /* Falls through. */
7046 		case XPATH_NUMBER:
7047 		    /* Hand check NaN and Infinity equalities */
7048 		    if (xmlXPathIsNaN(arg1->floatval) ||
7049 			    xmlXPathIsNaN(arg2->floatval)) {
7050 		        ret = 0;
7051 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7052 		        if (xmlXPathIsInf(arg2->floatval) == 1)
7053 			    ret = 1;
7054 			else
7055 			    ret = 0;
7056 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7057 			if (xmlXPathIsInf(arg2->floatval) == -1)
7058 			    ret = 1;
7059 			else
7060 			    ret = 0;
7061 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7062 			if (xmlXPathIsInf(arg1->floatval) == 1)
7063 			    ret = 1;
7064 			else
7065 			    ret = 0;
7066 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7067 			if (xmlXPathIsInf(arg1->floatval) == -1)
7068 			    ret = 1;
7069 			else
7070 			    ret = 0;
7071 		    } else {
7072 		        ret = (arg1->floatval == arg2->floatval);
7073 		    }
7074 		    break;
7075 		case XPATH_USERS:
7076 		case XPATH_POINT:
7077 		case XPATH_RANGE:
7078 		case XPATH_LOCATIONSET:
7079 		    TODO
7080 		    break;
7081 		case XPATH_NODESET:
7082 		case XPATH_XSLT_TREE:
7083 		    break;
7084 	    }
7085 	    break;
7086         case XPATH_STRING:
7087 	    switch (arg2->type) {
7088 	        case XPATH_UNDEFINED:
7089 #ifdef DEBUG_EXPR
7090 		    xmlGenericError(xmlGenericErrorContext,
7091 			    "Equal: undefined\n");
7092 #endif
7093 		    break;
7094 		case XPATH_BOOLEAN:
7095 		    if ((arg1->stringval == NULL) ||
7096 			(arg1->stringval[0] == 0)) ret = 0;
7097 		    else
7098 			ret = 1;
7099 		    ret = (arg2->boolval == ret);
7100 		    break;
7101 		case XPATH_STRING:
7102 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7103 		    break;
7104 		case XPATH_NUMBER:
7105 		    valuePush(ctxt, arg1);
7106 		    xmlXPathNumberFunction(ctxt, 1);
7107 		    arg1 = valuePop(ctxt);
7108 		    /* Hand check NaN and Infinity equalities */
7109 		    if (xmlXPathIsNaN(arg1->floatval) ||
7110 			    xmlXPathIsNaN(arg2->floatval)) {
7111 		        ret = 0;
7112 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7113 			if (xmlXPathIsInf(arg2->floatval) == 1)
7114 			    ret = 1;
7115 			else
7116 			    ret = 0;
7117 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7118 			if (xmlXPathIsInf(arg2->floatval) == -1)
7119 			    ret = 1;
7120 			else
7121 			    ret = 0;
7122 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7123 			if (xmlXPathIsInf(arg1->floatval) == 1)
7124 			    ret = 1;
7125 			else
7126 			    ret = 0;
7127 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7128 			if (xmlXPathIsInf(arg1->floatval) == -1)
7129 			    ret = 1;
7130 			else
7131 			    ret = 0;
7132 		    } else {
7133 		        ret = (arg1->floatval == arg2->floatval);
7134 		    }
7135 		    break;
7136 		case XPATH_USERS:
7137 		case XPATH_POINT:
7138 		case XPATH_RANGE:
7139 		case XPATH_LOCATIONSET:
7140 		    TODO
7141 		    break;
7142 		case XPATH_NODESET:
7143 		case XPATH_XSLT_TREE:
7144 		    break;
7145 	    }
7146 	    break;
7147         case XPATH_USERS:
7148 	case XPATH_POINT:
7149 	case XPATH_RANGE:
7150 	case XPATH_LOCATIONSET:
7151 	    TODO
7152 	    break;
7153 	case XPATH_NODESET:
7154 	case XPATH_XSLT_TREE:
7155 	    break;
7156     }
7157     xmlXPathReleaseObject(ctxt->context, arg1);
7158     xmlXPathReleaseObject(ctxt->context, arg2);
7159     return(ret);
7160 }
7161 
7162 /**
7163  * xmlXPathEqualValues:
7164  * @ctxt:  the XPath Parser context
7165  *
7166  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7167  *
7168  * Returns 0 or 1 depending on the results of the test.
7169  */
7170 int
7171 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7172     xmlXPathObjectPtr arg1, arg2, argtmp;
7173     int ret = 0;
7174 
7175     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7176     arg2 = valuePop(ctxt);
7177     arg1 = valuePop(ctxt);
7178     if ((arg1 == NULL) || (arg2 == NULL)) {
7179 	if (arg1 != NULL)
7180 	    xmlXPathReleaseObject(ctxt->context, arg1);
7181 	else
7182 	    xmlXPathReleaseObject(ctxt->context, arg2);
7183 	XP_ERROR0(XPATH_INVALID_OPERAND);
7184     }
7185 
7186     if (arg1 == arg2) {
7187 #ifdef DEBUG_EXPR
7188         xmlGenericError(xmlGenericErrorContext,
7189 		"Equal: by pointer\n");
7190 #endif
7191 	xmlXPathFreeObject(arg1);
7192         return(1);
7193     }
7194 
7195     /*
7196      *If either argument is a nodeset, it's a 'special case'
7197      */
7198     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7199       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7200 	/*
7201 	 *Hack it to assure arg1 is the nodeset
7202 	 */
7203 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7204 		argtmp = arg2;
7205 		arg2 = arg1;
7206 		arg1 = argtmp;
7207 	}
7208 	switch (arg2->type) {
7209 	    case XPATH_UNDEFINED:
7210 #ifdef DEBUG_EXPR
7211 		xmlGenericError(xmlGenericErrorContext,
7212 			"Equal: undefined\n");
7213 #endif
7214 		break;
7215 	    case XPATH_NODESET:
7216 	    case XPATH_XSLT_TREE:
7217 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7218 		break;
7219 	    case XPATH_BOOLEAN:
7220 		if ((arg1->nodesetval == NULL) ||
7221 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7222 		else
7223 		    ret = 1;
7224 		ret = (ret == arg2->boolval);
7225 		break;
7226 	    case XPATH_NUMBER:
7227 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7228 		break;
7229 	    case XPATH_STRING:
7230 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7231 		break;
7232 	    case XPATH_USERS:
7233 	    case XPATH_POINT:
7234 	    case XPATH_RANGE:
7235 	    case XPATH_LOCATIONSET:
7236 		TODO
7237 		break;
7238 	}
7239 	xmlXPathReleaseObject(ctxt->context, arg1);
7240 	xmlXPathReleaseObject(ctxt->context, arg2);
7241 	return(ret);
7242     }
7243 
7244     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7245 }
7246 
7247 /**
7248  * xmlXPathNotEqualValues:
7249  * @ctxt:  the XPath Parser context
7250  *
7251  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7252  *
7253  * Returns 0 or 1 depending on the results of the test.
7254  */
7255 int
7256 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7257     xmlXPathObjectPtr arg1, arg2, argtmp;
7258     int ret = 0;
7259 
7260     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7261     arg2 = valuePop(ctxt);
7262     arg1 = valuePop(ctxt);
7263     if ((arg1 == NULL) || (arg2 == NULL)) {
7264 	if (arg1 != NULL)
7265 	    xmlXPathReleaseObject(ctxt->context, arg1);
7266 	else
7267 	    xmlXPathReleaseObject(ctxt->context, arg2);
7268 	XP_ERROR0(XPATH_INVALID_OPERAND);
7269     }
7270 
7271     if (arg1 == arg2) {
7272 #ifdef DEBUG_EXPR
7273         xmlGenericError(xmlGenericErrorContext,
7274 		"NotEqual: by pointer\n");
7275 #endif
7276 	xmlXPathReleaseObject(ctxt->context, arg1);
7277         return(0);
7278     }
7279 
7280     /*
7281      *If either argument is a nodeset, it's a 'special case'
7282      */
7283     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7284       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7285 	/*
7286 	 *Hack it to assure arg1 is the nodeset
7287 	 */
7288 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7289 		argtmp = arg2;
7290 		arg2 = arg1;
7291 		arg1 = argtmp;
7292 	}
7293 	switch (arg2->type) {
7294 	    case XPATH_UNDEFINED:
7295 #ifdef DEBUG_EXPR
7296 		xmlGenericError(xmlGenericErrorContext,
7297 			"NotEqual: undefined\n");
7298 #endif
7299 		break;
7300 	    case XPATH_NODESET:
7301 	    case XPATH_XSLT_TREE:
7302 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7303 		break;
7304 	    case XPATH_BOOLEAN:
7305 		if ((arg1->nodesetval == NULL) ||
7306 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7307 		else
7308 		    ret = 1;
7309 		ret = (ret != arg2->boolval);
7310 		break;
7311 	    case XPATH_NUMBER:
7312 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7313 		break;
7314 	    case XPATH_STRING:
7315 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7316 		break;
7317 	    case XPATH_USERS:
7318 	    case XPATH_POINT:
7319 	    case XPATH_RANGE:
7320 	    case XPATH_LOCATIONSET:
7321 		TODO
7322 		break;
7323 	}
7324 	xmlXPathReleaseObject(ctxt->context, arg1);
7325 	xmlXPathReleaseObject(ctxt->context, arg2);
7326 	return(ret);
7327     }
7328 
7329     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7330 }
7331 
7332 /**
7333  * xmlXPathCompareValues:
7334  * @ctxt:  the XPath Parser context
7335  * @inf:  less than (1) or greater than (0)
7336  * @strict:  is the comparison strict
7337  *
7338  * Implement the compare operation on XPath objects:
7339  *     @arg1 < @arg2    (1, 1, ...
7340  *     @arg1 <= @arg2   (1, 0, ...
7341  *     @arg1 > @arg2    (0, 1, ...
7342  *     @arg1 >= @arg2   (0, 0, ...
7343  *
7344  * When neither object to be compared is a node-set and the operator is
7345  * <=, <, >=, >, then the objects are compared by converted both objects
7346  * to numbers and comparing the numbers according to IEEE 754. The <
7347  * comparison will be true if and only if the first number is less than the
7348  * second number. The <= comparison will be true if and only if the first
7349  * number is less than or equal to the second number. The > comparison
7350  * will be true if and only if the first number is greater than the second
7351  * number. The >= comparison will be true if and only if the first number
7352  * is greater than or equal to the second number.
7353  *
7354  * Returns 1 if the comparison succeeded, 0 if it failed
7355  */
7356 int
7357 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7358     int ret = 0, arg1i = 0, arg2i = 0;
7359     xmlXPathObjectPtr arg1, arg2;
7360 
7361     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7362     arg2 = valuePop(ctxt);
7363     arg1 = valuePop(ctxt);
7364     if ((arg1 == NULL) || (arg2 == NULL)) {
7365 	if (arg1 != NULL)
7366 	    xmlXPathReleaseObject(ctxt->context, arg1);
7367 	else
7368 	    xmlXPathReleaseObject(ctxt->context, arg2);
7369 	XP_ERROR0(XPATH_INVALID_OPERAND);
7370     }
7371 
7372     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7373       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7374 	/*
7375 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7376 	 * are not freed from within this routine; they will be freed from the
7377 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7378 	 */
7379 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7380 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7381 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7382 	} else {
7383 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7384 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7385 			                          arg1, arg2);
7386 	    } else {
7387 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7388 			                          arg2, arg1);
7389 	    }
7390 	}
7391 	return(ret);
7392     }
7393 
7394     if (arg1->type != XPATH_NUMBER) {
7395 	valuePush(ctxt, arg1);
7396 	xmlXPathNumberFunction(ctxt, 1);
7397 	arg1 = valuePop(ctxt);
7398     }
7399     if (arg1->type != XPATH_NUMBER) {
7400 	xmlXPathFreeObject(arg1);
7401 	xmlXPathFreeObject(arg2);
7402 	XP_ERROR0(XPATH_INVALID_OPERAND);
7403     }
7404     if (arg2->type != XPATH_NUMBER) {
7405 	valuePush(ctxt, arg2);
7406 	xmlXPathNumberFunction(ctxt, 1);
7407 	arg2 = valuePop(ctxt);
7408     }
7409     if (arg2->type != XPATH_NUMBER) {
7410 	xmlXPathReleaseObject(ctxt->context, arg1);
7411 	xmlXPathReleaseObject(ctxt->context, arg2);
7412 	XP_ERROR0(XPATH_INVALID_OPERAND);
7413     }
7414     /*
7415      * Add tests for infinity and nan
7416      * => feedback on 3.4 for Inf and NaN
7417      */
7418     /* Hand check NaN and Infinity comparisons */
7419     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7420 	ret=0;
7421     } else {
7422 	arg1i=xmlXPathIsInf(arg1->floatval);
7423 	arg2i=xmlXPathIsInf(arg2->floatval);
7424 	if (inf && strict) {
7425 	    if ((arg1i == -1 && arg2i != -1) ||
7426 		(arg2i == 1 && arg1i != 1)) {
7427 		ret = 1;
7428 	    } else if (arg1i == 0 && arg2i == 0) {
7429 		ret = (arg1->floatval < arg2->floatval);
7430 	    } else {
7431 		ret = 0;
7432 	    }
7433 	}
7434 	else if (inf && !strict) {
7435 	    if (arg1i == -1 || arg2i == 1) {
7436 		ret = 1;
7437 	    } else if (arg1i == 0 && arg2i == 0) {
7438 		ret = (arg1->floatval <= arg2->floatval);
7439 	    } else {
7440 		ret = 0;
7441 	    }
7442 	}
7443 	else if (!inf && strict) {
7444 	    if ((arg1i == 1 && arg2i != 1) ||
7445 		(arg2i == -1 && arg1i != -1)) {
7446 		ret = 1;
7447 	    } else if (arg1i == 0 && arg2i == 0) {
7448 		ret = (arg1->floatval > arg2->floatval);
7449 	    } else {
7450 		ret = 0;
7451 	    }
7452 	}
7453 	else if (!inf && !strict) {
7454 	    if (arg1i == 1 || arg2i == -1) {
7455 		ret = 1;
7456 	    } else if (arg1i == 0 && arg2i == 0) {
7457 		ret = (arg1->floatval >= arg2->floatval);
7458 	    } else {
7459 		ret = 0;
7460 	    }
7461 	}
7462     }
7463     xmlXPathReleaseObject(ctxt->context, arg1);
7464     xmlXPathReleaseObject(ctxt->context, arg2);
7465     return(ret);
7466 }
7467 
7468 /**
7469  * xmlXPathValueFlipSign:
7470  * @ctxt:  the XPath Parser context
7471  *
7472  * Implement the unary - operation on an XPath object
7473  * The numeric operators convert their operands to numbers as if
7474  * by calling the number function.
7475  */
7476 void
7477 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7478     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7479     CAST_TO_NUMBER;
7480     CHECK_TYPE(XPATH_NUMBER);
7481     if (xmlXPathIsNaN(ctxt->value->floatval))
7482         ctxt->value->floatval=xmlXPathNAN;
7483     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7484         ctxt->value->floatval=xmlXPathNINF;
7485     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7486         ctxt->value->floatval=xmlXPathPINF;
7487     else if (ctxt->value->floatval == 0) {
7488         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7489 	    ctxt->value->floatval = xmlXPathNZERO;
7490 	else
7491 	    ctxt->value->floatval = 0;
7492     }
7493     else
7494         ctxt->value->floatval = - ctxt->value->floatval;
7495 }
7496 
7497 /**
7498  * xmlXPathAddValues:
7499  * @ctxt:  the XPath Parser context
7500  *
7501  * Implement the add operation on XPath objects:
7502  * The numeric operators convert their operands to numbers as if
7503  * by calling the number function.
7504  */
7505 void
7506 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7507     xmlXPathObjectPtr arg;
7508     double val;
7509 
7510     arg = valuePop(ctxt);
7511     if (arg == NULL)
7512 	XP_ERROR(XPATH_INVALID_OPERAND);
7513     val = xmlXPathCastToNumber(arg);
7514     xmlXPathReleaseObject(ctxt->context, arg);
7515     CAST_TO_NUMBER;
7516     CHECK_TYPE(XPATH_NUMBER);
7517     ctxt->value->floatval += val;
7518 }
7519 
7520 /**
7521  * xmlXPathSubValues:
7522  * @ctxt:  the XPath Parser context
7523  *
7524  * Implement the subtraction operation on XPath objects:
7525  * The numeric operators convert their operands to numbers as if
7526  * by calling the number function.
7527  */
7528 void
7529 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7530     xmlXPathObjectPtr arg;
7531     double val;
7532 
7533     arg = valuePop(ctxt);
7534     if (arg == NULL)
7535 	XP_ERROR(XPATH_INVALID_OPERAND);
7536     val = xmlXPathCastToNumber(arg);
7537     xmlXPathReleaseObject(ctxt->context, arg);
7538     CAST_TO_NUMBER;
7539     CHECK_TYPE(XPATH_NUMBER);
7540     ctxt->value->floatval -= val;
7541 }
7542 
7543 /**
7544  * xmlXPathMultValues:
7545  * @ctxt:  the XPath Parser context
7546  *
7547  * Implement the multiply operation on XPath objects:
7548  * The numeric operators convert their operands to numbers as if
7549  * by calling the number function.
7550  */
7551 void
7552 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7553     xmlXPathObjectPtr arg;
7554     double val;
7555 
7556     arg = valuePop(ctxt);
7557     if (arg == NULL)
7558 	XP_ERROR(XPATH_INVALID_OPERAND);
7559     val = xmlXPathCastToNumber(arg);
7560     xmlXPathReleaseObject(ctxt->context, arg);
7561     CAST_TO_NUMBER;
7562     CHECK_TYPE(XPATH_NUMBER);
7563     ctxt->value->floatval *= val;
7564 }
7565 
7566 /**
7567  * xmlXPathDivValues:
7568  * @ctxt:  the XPath Parser context
7569  *
7570  * Implement the div operation on XPath objects @arg1 / @arg2:
7571  * The numeric operators convert their operands to numbers as if
7572  * by calling the number function.
7573  */
7574 void
7575 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7576     xmlXPathObjectPtr arg;
7577     double val;
7578 
7579     arg = valuePop(ctxt);
7580     if (arg == NULL)
7581 	XP_ERROR(XPATH_INVALID_OPERAND);
7582     val = xmlXPathCastToNumber(arg);
7583     xmlXPathReleaseObject(ctxt->context, arg);
7584     CAST_TO_NUMBER;
7585     CHECK_TYPE(XPATH_NUMBER);
7586     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7587 	ctxt->value->floatval = xmlXPathNAN;
7588     else if (val == 0 && xmlXPathGetSign(val) != 0) {
7589 	if (ctxt->value->floatval == 0)
7590 	    ctxt->value->floatval = xmlXPathNAN;
7591 	else if (ctxt->value->floatval > 0)
7592 	    ctxt->value->floatval = xmlXPathNINF;
7593 	else if (ctxt->value->floatval < 0)
7594 	    ctxt->value->floatval = xmlXPathPINF;
7595     }
7596     else if (val == 0) {
7597 	if (ctxt->value->floatval == 0)
7598 	    ctxt->value->floatval = xmlXPathNAN;
7599 	else if (ctxt->value->floatval > 0)
7600 	    ctxt->value->floatval = xmlXPathPINF;
7601 	else if (ctxt->value->floatval < 0)
7602 	    ctxt->value->floatval = xmlXPathNINF;
7603     } else
7604 	ctxt->value->floatval /= val;
7605 }
7606 
7607 /**
7608  * xmlXPathModValues:
7609  * @ctxt:  the XPath Parser context
7610  *
7611  * Implement the mod operation on XPath objects: @arg1 / @arg2
7612  * The numeric operators convert their operands to numbers as if
7613  * by calling the number function.
7614  */
7615 void
7616 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7617     xmlXPathObjectPtr arg;
7618     double arg1, arg2;
7619 
7620     arg = valuePop(ctxt);
7621     if (arg == NULL)
7622 	XP_ERROR(XPATH_INVALID_OPERAND);
7623     arg2 = xmlXPathCastToNumber(arg);
7624     xmlXPathReleaseObject(ctxt->context, arg);
7625     CAST_TO_NUMBER;
7626     CHECK_TYPE(XPATH_NUMBER);
7627     arg1 = ctxt->value->floatval;
7628     if (arg2 == 0)
7629 	ctxt->value->floatval = xmlXPathNAN;
7630     else {
7631 	ctxt->value->floatval = fmod(arg1, arg2);
7632     }
7633 }
7634 
7635 /************************************************************************
7636  *									*
7637  *		The traversal functions					*
7638  *									*
7639  ************************************************************************/
7640 
7641 /*
7642  * A traversal function enumerates nodes along an axis.
7643  * Initially it must be called with NULL, and it indicates
7644  * termination on the axis by returning NULL.
7645  */
7646 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7647                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7648 
7649 /*
7650  * xmlXPathTraversalFunctionExt:
7651  * A traversal function enumerates nodes along an axis.
7652  * Initially it must be called with NULL, and it indicates
7653  * termination on the axis by returning NULL.
7654  * The context node of the traversal is specified via @contextNode.
7655  */
7656 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7657                     (xmlNodePtr cur, xmlNodePtr contextNode);
7658 
7659 /*
7660  * xmlXPathNodeSetMergeFunction:
7661  * Used for merging node sets in xmlXPathCollectAndTest().
7662  */
7663 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7664 		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
7665 
7666 
7667 /**
7668  * xmlXPathNextSelf:
7669  * @ctxt:  the XPath Parser context
7670  * @cur:  the current node in the traversal
7671  *
7672  * Traversal function for the "self" direction
7673  * The self axis contains just the context node itself
7674  *
7675  * Returns the next element following that axis
7676  */
7677 xmlNodePtr
7678 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7679     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7680     if (cur == NULL)
7681         return(ctxt->context->node);
7682     return(NULL);
7683 }
7684 
7685 /**
7686  * xmlXPathNextChild:
7687  * @ctxt:  the XPath Parser context
7688  * @cur:  the current node in the traversal
7689  *
7690  * Traversal function for the "child" direction
7691  * The child axis contains the children of the context node in document order.
7692  *
7693  * Returns the next element following that axis
7694  */
7695 xmlNodePtr
7696 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7697     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7698     if (cur == NULL) {
7699 	if (ctxt->context->node == NULL) return(NULL);
7700 	switch (ctxt->context->node->type) {
7701             case XML_ELEMENT_NODE:
7702             case XML_TEXT_NODE:
7703             case XML_CDATA_SECTION_NODE:
7704             case XML_ENTITY_REF_NODE:
7705             case XML_ENTITY_NODE:
7706             case XML_PI_NODE:
7707             case XML_COMMENT_NODE:
7708             case XML_NOTATION_NODE:
7709             case XML_DTD_NODE:
7710 		return(ctxt->context->node->children);
7711             case XML_DOCUMENT_NODE:
7712             case XML_DOCUMENT_TYPE_NODE:
7713             case XML_DOCUMENT_FRAG_NODE:
7714             case XML_HTML_DOCUMENT_NODE:
7715 #ifdef LIBXML_DOCB_ENABLED
7716 	    case XML_DOCB_DOCUMENT_NODE:
7717 #endif
7718 		return(((xmlDocPtr) ctxt->context->node)->children);
7719 	    case XML_ELEMENT_DECL:
7720 	    case XML_ATTRIBUTE_DECL:
7721 	    case XML_ENTITY_DECL:
7722             case XML_ATTRIBUTE_NODE:
7723 	    case XML_NAMESPACE_DECL:
7724 	    case XML_XINCLUDE_START:
7725 	    case XML_XINCLUDE_END:
7726 		return(NULL);
7727 	}
7728 	return(NULL);
7729     }
7730     if ((cur->type == XML_DOCUMENT_NODE) ||
7731         (cur->type == XML_HTML_DOCUMENT_NODE))
7732 	return(NULL);
7733     return(cur->next);
7734 }
7735 
7736 /**
7737  * xmlXPathNextChildElement:
7738  * @ctxt:  the XPath Parser context
7739  * @cur:  the current node in the traversal
7740  *
7741  * Traversal function for the "child" direction and nodes of type element.
7742  * The child axis contains the children of the context node in document order.
7743  *
7744  * Returns the next element following that axis
7745  */
7746 static xmlNodePtr
7747 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7748     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7749     if (cur == NULL) {
7750 	cur = ctxt->context->node;
7751 	if (cur == NULL) return(NULL);
7752 	/*
7753 	* Get the first element child.
7754 	*/
7755 	switch (cur->type) {
7756             case XML_ELEMENT_NODE:
7757 	    case XML_DOCUMENT_FRAG_NODE:
7758 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7759             case XML_ENTITY_NODE:
7760 		cur = cur->children;
7761 		if (cur != NULL) {
7762 		    if (cur->type == XML_ELEMENT_NODE)
7763 			return(cur);
7764 		    do {
7765 			cur = cur->next;
7766 		    } while ((cur != NULL) &&
7767 			(cur->type != XML_ELEMENT_NODE));
7768 		    return(cur);
7769 		}
7770 		return(NULL);
7771             case XML_DOCUMENT_NODE:
7772             case XML_HTML_DOCUMENT_NODE:
7773 #ifdef LIBXML_DOCB_ENABLED
7774 	    case XML_DOCB_DOCUMENT_NODE:
7775 #endif
7776 		return(xmlDocGetRootElement((xmlDocPtr) cur));
7777 	    default:
7778 		return(NULL);
7779 	}
7780 	return(NULL);
7781     }
7782     /*
7783     * Get the next sibling element node.
7784     */
7785     switch (cur->type) {
7786 	case XML_ELEMENT_NODE:
7787 	case XML_TEXT_NODE:
7788 	case XML_ENTITY_REF_NODE:
7789 	case XML_ENTITY_NODE:
7790 	case XML_CDATA_SECTION_NODE:
7791 	case XML_PI_NODE:
7792 	case XML_COMMENT_NODE:
7793 	case XML_XINCLUDE_END:
7794 	    break;
7795 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7796 	default:
7797 	    return(NULL);
7798     }
7799     if (cur->next != NULL) {
7800 	if (cur->next->type == XML_ELEMENT_NODE)
7801 	    return(cur->next);
7802 	cur = cur->next;
7803 	do {
7804 	    cur = cur->next;
7805 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7806 	return(cur);
7807     }
7808     return(NULL);
7809 }
7810 
7811 #if 0
7812 /**
7813  * xmlXPathNextDescendantOrSelfElemParent:
7814  * @ctxt:  the XPath Parser context
7815  * @cur:  the current node in the traversal
7816  *
7817  * Traversal function for the "descendant-or-self" axis.
7818  * Additionally it returns only nodes which can be parents of
7819  * element nodes.
7820  *
7821  *
7822  * Returns the next element following that axis
7823  */
7824 static xmlNodePtr
7825 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7826 				       xmlNodePtr contextNode)
7827 {
7828     if (cur == NULL) {
7829 	if (contextNode == NULL)
7830 	    return(NULL);
7831 	switch (contextNode->type) {
7832 	    case XML_ELEMENT_NODE:
7833 	    case XML_XINCLUDE_START:
7834 	    case XML_DOCUMENT_FRAG_NODE:
7835 	    case XML_DOCUMENT_NODE:
7836 #ifdef LIBXML_DOCB_ENABLED
7837 	    case XML_DOCB_DOCUMENT_NODE:
7838 #endif
7839 	    case XML_HTML_DOCUMENT_NODE:
7840 		return(contextNode);
7841 	    default:
7842 		return(NULL);
7843 	}
7844 	return(NULL);
7845     } else {
7846 	xmlNodePtr start = cur;
7847 
7848 	while (cur != NULL) {
7849 	    switch (cur->type) {
7850 		case XML_ELEMENT_NODE:
7851 		/* TODO: OK to have XInclude here? */
7852 		case XML_XINCLUDE_START:
7853 		case XML_DOCUMENT_FRAG_NODE:
7854 		    if (cur != start)
7855 			return(cur);
7856 		    if (cur->children != NULL) {
7857 			cur = cur->children;
7858 			continue;
7859 		    }
7860 		    break;
7861 		/* Not sure if we need those here. */
7862 		case XML_DOCUMENT_NODE:
7863 #ifdef LIBXML_DOCB_ENABLED
7864 		case XML_DOCB_DOCUMENT_NODE:
7865 #endif
7866 		case XML_HTML_DOCUMENT_NODE:
7867 		    if (cur != start)
7868 			return(cur);
7869 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7870 		default:
7871 		    break;
7872 	    }
7873 
7874 next_sibling:
7875 	    if ((cur == NULL) || (cur == contextNode))
7876 		return(NULL);
7877 	    if (cur->next != NULL) {
7878 		cur = cur->next;
7879 	    } else {
7880 		cur = cur->parent;
7881 		goto next_sibling;
7882 	    }
7883 	}
7884     }
7885     return(NULL);
7886 }
7887 #endif
7888 
7889 /**
7890  * xmlXPathNextDescendant:
7891  * @ctxt:  the XPath Parser context
7892  * @cur:  the current node in the traversal
7893  *
7894  * Traversal function for the "descendant" direction
7895  * the descendant axis contains the descendants of the context node in document
7896  * order; a descendant is a child or a child of a child and so on.
7897  *
7898  * Returns the next element following that axis
7899  */
7900 xmlNodePtr
7901 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7902     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7903     if (cur == NULL) {
7904 	if (ctxt->context->node == NULL)
7905 	    return(NULL);
7906 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7907 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7908 	    return(NULL);
7909 
7910         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7911 	    return(ctxt->context->doc->children);
7912         return(ctxt->context->node->children);
7913     }
7914 
7915     if (cur->type == XML_NAMESPACE_DECL)
7916         return(NULL);
7917     if (cur->children != NULL) {
7918 	/*
7919 	 * Do not descend on entities declarations
7920 	 */
7921 	if (cur->children->type != XML_ENTITY_DECL) {
7922 	    cur = cur->children;
7923 	    /*
7924 	     * Skip DTDs
7925 	     */
7926 	    if (cur->type != XML_DTD_NODE)
7927 		return(cur);
7928 	}
7929     }
7930 
7931     if (cur == ctxt->context->node) return(NULL);
7932 
7933     while (cur->next != NULL) {
7934 	cur = cur->next;
7935 	if ((cur->type != XML_ENTITY_DECL) &&
7936 	    (cur->type != XML_DTD_NODE))
7937 	    return(cur);
7938     }
7939 
7940     do {
7941         cur = cur->parent;
7942 	if (cur == NULL) break;
7943 	if (cur == ctxt->context->node) return(NULL);
7944 	if (cur->next != NULL) {
7945 	    cur = cur->next;
7946 	    return(cur);
7947 	}
7948     } while (cur != NULL);
7949     return(cur);
7950 }
7951 
7952 /**
7953  * xmlXPathNextDescendantOrSelf:
7954  * @ctxt:  the XPath Parser context
7955  * @cur:  the current node in the traversal
7956  *
7957  * Traversal function for the "descendant-or-self" direction
7958  * the descendant-or-self axis contains the context node and the descendants
7959  * of the context node in document order; thus the context node is the first
7960  * node on the axis, and the first child of the context node is the second node
7961  * on the axis
7962  *
7963  * Returns the next element following that axis
7964  */
7965 xmlNodePtr
7966 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7967     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7968     if (cur == NULL)
7969         return(ctxt->context->node);
7970 
7971     if (ctxt->context->node == NULL)
7972         return(NULL);
7973     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7974         (ctxt->context->node->type == XML_NAMESPACE_DECL))
7975         return(NULL);
7976 
7977     return(xmlXPathNextDescendant(ctxt, cur));
7978 }
7979 
7980 /**
7981  * xmlXPathNextParent:
7982  * @ctxt:  the XPath Parser context
7983  * @cur:  the current node in the traversal
7984  *
7985  * Traversal function for the "parent" direction
7986  * The parent axis contains the parent of the context node, if there is one.
7987  *
7988  * Returns the next element following that axis
7989  */
7990 xmlNodePtr
7991 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7992     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7993     /*
7994      * the parent of an attribute or namespace node is the element
7995      * to which the attribute or namespace node is attached
7996      * Namespace handling !!!
7997      */
7998     if (cur == NULL) {
7999 	if (ctxt->context->node == NULL) return(NULL);
8000 	switch (ctxt->context->node->type) {
8001             case XML_ELEMENT_NODE:
8002             case XML_TEXT_NODE:
8003             case XML_CDATA_SECTION_NODE:
8004             case XML_ENTITY_REF_NODE:
8005             case XML_ENTITY_NODE:
8006             case XML_PI_NODE:
8007             case XML_COMMENT_NODE:
8008             case XML_NOTATION_NODE:
8009             case XML_DTD_NODE:
8010 	    case XML_ELEMENT_DECL:
8011 	    case XML_ATTRIBUTE_DECL:
8012 	    case XML_XINCLUDE_START:
8013 	    case XML_XINCLUDE_END:
8014 	    case XML_ENTITY_DECL:
8015 		if (ctxt->context->node->parent == NULL)
8016 		    return((xmlNodePtr) ctxt->context->doc);
8017 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8018 		    ((ctxt->context->node->parent->name[0] == ' ') ||
8019 		     (xmlStrEqual(ctxt->context->node->parent->name,
8020 				 BAD_CAST "fake node libxslt"))))
8021 		    return(NULL);
8022 		return(ctxt->context->node->parent);
8023             case XML_ATTRIBUTE_NODE: {
8024 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8025 
8026 		return(att->parent);
8027 	    }
8028             case XML_DOCUMENT_NODE:
8029             case XML_DOCUMENT_TYPE_NODE:
8030             case XML_DOCUMENT_FRAG_NODE:
8031             case XML_HTML_DOCUMENT_NODE:
8032 #ifdef LIBXML_DOCB_ENABLED
8033 	    case XML_DOCB_DOCUMENT_NODE:
8034 #endif
8035                 return(NULL);
8036 	    case XML_NAMESPACE_DECL: {
8037 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8038 
8039 		if ((ns->next != NULL) &&
8040 		    (ns->next->type != XML_NAMESPACE_DECL))
8041 		    return((xmlNodePtr) ns->next);
8042                 return(NULL);
8043 	    }
8044 	}
8045     }
8046     return(NULL);
8047 }
8048 
8049 /**
8050  * xmlXPathNextAncestor:
8051  * @ctxt:  the XPath Parser context
8052  * @cur:  the current node in the traversal
8053  *
8054  * Traversal function for the "ancestor" direction
8055  * the ancestor axis contains the ancestors of the context node; the ancestors
8056  * of the context node consist of the parent of context node and the parent's
8057  * parent and so on; the nodes are ordered in reverse document order; thus the
8058  * parent is the first node on the axis, and the parent's parent is the second
8059  * node on the axis
8060  *
8061  * Returns the next element following that axis
8062  */
8063 xmlNodePtr
8064 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8065     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8066     /*
8067      * the parent of an attribute or namespace node is the element
8068      * to which the attribute or namespace node is attached
8069      * !!!!!!!!!!!!!
8070      */
8071     if (cur == NULL) {
8072 	if (ctxt->context->node == NULL) return(NULL);
8073 	switch (ctxt->context->node->type) {
8074             case XML_ELEMENT_NODE:
8075             case XML_TEXT_NODE:
8076             case XML_CDATA_SECTION_NODE:
8077             case XML_ENTITY_REF_NODE:
8078             case XML_ENTITY_NODE:
8079             case XML_PI_NODE:
8080             case XML_COMMENT_NODE:
8081 	    case XML_DTD_NODE:
8082 	    case XML_ELEMENT_DECL:
8083 	    case XML_ATTRIBUTE_DECL:
8084 	    case XML_ENTITY_DECL:
8085             case XML_NOTATION_NODE:
8086 	    case XML_XINCLUDE_START:
8087 	    case XML_XINCLUDE_END:
8088 		if (ctxt->context->node->parent == NULL)
8089 		    return((xmlNodePtr) ctxt->context->doc);
8090 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8091 		    ((ctxt->context->node->parent->name[0] == ' ') ||
8092 		     (xmlStrEqual(ctxt->context->node->parent->name,
8093 				 BAD_CAST "fake node libxslt"))))
8094 		    return(NULL);
8095 		return(ctxt->context->node->parent);
8096             case XML_ATTRIBUTE_NODE: {
8097 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8098 
8099 		return(tmp->parent);
8100 	    }
8101             case XML_DOCUMENT_NODE:
8102             case XML_DOCUMENT_TYPE_NODE:
8103             case XML_DOCUMENT_FRAG_NODE:
8104             case XML_HTML_DOCUMENT_NODE:
8105 #ifdef LIBXML_DOCB_ENABLED
8106 	    case XML_DOCB_DOCUMENT_NODE:
8107 #endif
8108                 return(NULL);
8109 	    case XML_NAMESPACE_DECL: {
8110 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8111 
8112 		if ((ns->next != NULL) &&
8113 		    (ns->next->type != XML_NAMESPACE_DECL))
8114 		    return((xmlNodePtr) ns->next);
8115 		/* Bad, how did that namespace end up here ? */
8116                 return(NULL);
8117 	    }
8118 	}
8119 	return(NULL);
8120     }
8121     if (cur == ctxt->context->doc->children)
8122 	return((xmlNodePtr) ctxt->context->doc);
8123     if (cur == (xmlNodePtr) ctxt->context->doc)
8124 	return(NULL);
8125     switch (cur->type) {
8126 	case XML_ELEMENT_NODE:
8127 	case XML_TEXT_NODE:
8128 	case XML_CDATA_SECTION_NODE:
8129 	case XML_ENTITY_REF_NODE:
8130 	case XML_ENTITY_NODE:
8131 	case XML_PI_NODE:
8132 	case XML_COMMENT_NODE:
8133 	case XML_NOTATION_NODE:
8134 	case XML_DTD_NODE:
8135         case XML_ELEMENT_DECL:
8136         case XML_ATTRIBUTE_DECL:
8137         case XML_ENTITY_DECL:
8138 	case XML_XINCLUDE_START:
8139 	case XML_XINCLUDE_END:
8140 	    if (cur->parent == NULL)
8141 		return(NULL);
8142 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
8143 		((cur->parent->name[0] == ' ') ||
8144 		 (xmlStrEqual(cur->parent->name,
8145 			      BAD_CAST "fake node libxslt"))))
8146 		return(NULL);
8147 	    return(cur->parent);
8148 	case XML_ATTRIBUTE_NODE: {
8149 	    xmlAttrPtr att = (xmlAttrPtr) cur;
8150 
8151 	    return(att->parent);
8152 	}
8153 	case XML_NAMESPACE_DECL: {
8154 	    xmlNsPtr ns = (xmlNsPtr) cur;
8155 
8156 	    if ((ns->next != NULL) &&
8157 	        (ns->next->type != XML_NAMESPACE_DECL))
8158 	        return((xmlNodePtr) ns->next);
8159 	    /* Bad, how did that namespace end up here ? */
8160             return(NULL);
8161 	}
8162 	case XML_DOCUMENT_NODE:
8163 	case XML_DOCUMENT_TYPE_NODE:
8164 	case XML_DOCUMENT_FRAG_NODE:
8165 	case XML_HTML_DOCUMENT_NODE:
8166 #ifdef LIBXML_DOCB_ENABLED
8167 	case XML_DOCB_DOCUMENT_NODE:
8168 #endif
8169 	    return(NULL);
8170     }
8171     return(NULL);
8172 }
8173 
8174 /**
8175  * xmlXPathNextAncestorOrSelf:
8176  * @ctxt:  the XPath Parser context
8177  * @cur:  the current node in the traversal
8178  *
8179  * Traversal function for the "ancestor-or-self" direction
8180  * he ancestor-or-self axis contains the context node and ancestors of
8181  * the context node in reverse document order; thus the context node is
8182  * the first node on the axis, and the context node's parent the second;
8183  * parent here is defined the same as with the parent axis.
8184  *
8185  * Returns the next element following that axis
8186  */
8187 xmlNodePtr
8188 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8189     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8190     if (cur == NULL)
8191         return(ctxt->context->node);
8192     return(xmlXPathNextAncestor(ctxt, cur));
8193 }
8194 
8195 /**
8196  * xmlXPathNextFollowingSibling:
8197  * @ctxt:  the XPath Parser context
8198  * @cur:  the current node in the traversal
8199  *
8200  * Traversal function for the "following-sibling" direction
8201  * The following-sibling axis contains the following siblings of the context
8202  * node in document order.
8203  *
8204  * Returns the next element following that axis
8205  */
8206 xmlNodePtr
8207 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8208     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8209     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8210 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8211 	return(NULL);
8212     if (cur == (xmlNodePtr) ctxt->context->doc)
8213         return(NULL);
8214     if (cur == NULL)
8215         return(ctxt->context->node->next);
8216     return(cur->next);
8217 }
8218 
8219 /**
8220  * xmlXPathNextPrecedingSibling:
8221  * @ctxt:  the XPath Parser context
8222  * @cur:  the current node in the traversal
8223  *
8224  * Traversal function for the "preceding-sibling" direction
8225  * The preceding-sibling axis contains the preceding siblings of the context
8226  * node in reverse document order; the first preceding sibling is first on the
8227  * axis; the sibling preceding that node is the second on the axis and so on.
8228  *
8229  * Returns the next element following that axis
8230  */
8231 xmlNodePtr
8232 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8233     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8234     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8235 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8236 	return(NULL);
8237     if (cur == (xmlNodePtr) ctxt->context->doc)
8238         return(NULL);
8239     if (cur == NULL)
8240         return(ctxt->context->node->prev);
8241     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8242 	cur = cur->prev;
8243 	if (cur == NULL)
8244 	    return(ctxt->context->node->prev);
8245     }
8246     return(cur->prev);
8247 }
8248 
8249 /**
8250  * xmlXPathNextFollowing:
8251  * @ctxt:  the XPath Parser context
8252  * @cur:  the current node in the traversal
8253  *
8254  * Traversal function for the "following" direction
8255  * The following axis contains all nodes in the same document as the context
8256  * node that are after the context node in document order, excluding any
8257  * descendants and excluding attribute nodes and namespace nodes; the nodes
8258  * are ordered in document order
8259  *
8260  * Returns the next element following that axis
8261  */
8262 xmlNodePtr
8263 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8264     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8265     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8266         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8267         return(cur->children);
8268 
8269     if (cur == NULL) {
8270         cur = ctxt->context->node;
8271         if (cur->type == XML_ATTRIBUTE_NODE) {
8272             cur = cur->parent;
8273         } else if (cur->type == XML_NAMESPACE_DECL) {
8274             xmlNsPtr ns = (xmlNsPtr) cur;
8275 
8276             if ((ns->next == NULL) ||
8277                 (ns->next->type == XML_NAMESPACE_DECL))
8278                 return (NULL);
8279             cur = (xmlNodePtr) ns->next;
8280         }
8281     }
8282     if (cur == NULL) return(NULL) ; /* ERROR */
8283     if (cur->next != NULL) return(cur->next) ;
8284     do {
8285         cur = cur->parent;
8286         if (cur == NULL) break;
8287         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8288         if (cur->next != NULL) return(cur->next);
8289     } while (cur != NULL);
8290     return(cur);
8291 }
8292 
8293 /*
8294  * xmlXPathIsAncestor:
8295  * @ancestor:  the ancestor node
8296  * @node:  the current node
8297  *
8298  * Check that @ancestor is a @node's ancestor
8299  *
8300  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8301  */
8302 static int
8303 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8304     if ((ancestor == NULL) || (node == NULL)) return(0);
8305     if (node->type == XML_NAMESPACE_DECL)
8306         return(0);
8307     if (ancestor->type == XML_NAMESPACE_DECL)
8308         return(0);
8309     /* nodes need to be in the same document */
8310     if (ancestor->doc != node->doc) return(0);
8311     /* avoid searching if ancestor or node is the root node */
8312     if (ancestor == (xmlNodePtr) node->doc) return(1);
8313     if (node == (xmlNodePtr) ancestor->doc) return(0);
8314     while (node->parent != NULL) {
8315         if (node->parent == ancestor)
8316             return(1);
8317 	node = node->parent;
8318     }
8319     return(0);
8320 }
8321 
8322 /**
8323  * xmlXPathNextPreceding:
8324  * @ctxt:  the XPath Parser context
8325  * @cur:  the current node in the traversal
8326  *
8327  * Traversal function for the "preceding" direction
8328  * the preceding axis contains all nodes in the same document as the context
8329  * node that are before the context node in document order, excluding any
8330  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8331  * ordered in reverse document order
8332  *
8333  * Returns the next element following that axis
8334  */
8335 xmlNodePtr
8336 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8337 {
8338     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8339     if (cur == NULL) {
8340         cur = ctxt->context->node;
8341         if (cur->type == XML_ATTRIBUTE_NODE) {
8342             cur = cur->parent;
8343         } else if (cur->type == XML_NAMESPACE_DECL) {
8344             xmlNsPtr ns = (xmlNsPtr) cur;
8345 
8346             if ((ns->next == NULL) ||
8347                 (ns->next->type == XML_NAMESPACE_DECL))
8348                 return (NULL);
8349             cur = (xmlNodePtr) ns->next;
8350         }
8351     }
8352     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8353 	return (NULL);
8354     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8355 	cur = cur->prev;
8356     do {
8357         if (cur->prev != NULL) {
8358             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8359             return (cur);
8360         }
8361 
8362         cur = cur->parent;
8363         if (cur == NULL)
8364             return (NULL);
8365         if (cur == ctxt->context->doc->children)
8366             return (NULL);
8367     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8368     return (cur);
8369 }
8370 
8371 /**
8372  * xmlXPathNextPrecedingInternal:
8373  * @ctxt:  the XPath Parser context
8374  * @cur:  the current node in the traversal
8375  *
8376  * Traversal function for the "preceding" direction
8377  * the preceding axis contains all nodes in the same document as the context
8378  * node that are before the context node in document order, excluding any
8379  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8380  * ordered in reverse document order
8381  * This is a faster implementation but internal only since it requires a
8382  * state kept in the parser context: ctxt->ancestor.
8383  *
8384  * Returns the next element following that axis
8385  */
8386 static xmlNodePtr
8387 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8388                               xmlNodePtr cur)
8389 {
8390     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8391     if (cur == NULL) {
8392         cur = ctxt->context->node;
8393         if (cur == NULL)
8394             return (NULL);
8395         if (cur->type == XML_ATTRIBUTE_NODE) {
8396             cur = cur->parent;
8397         } else if (cur->type == XML_NAMESPACE_DECL) {
8398             xmlNsPtr ns = (xmlNsPtr) cur;
8399 
8400             if ((ns->next == NULL) ||
8401                 (ns->next->type == XML_NAMESPACE_DECL))
8402                 return (NULL);
8403             cur = (xmlNodePtr) ns->next;
8404         }
8405         ctxt->ancestor = cur->parent;
8406     }
8407     if (cur->type == XML_NAMESPACE_DECL)
8408         return(NULL);
8409     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8410 	cur = cur->prev;
8411     while (cur->prev == NULL) {
8412         cur = cur->parent;
8413         if (cur == NULL)
8414             return (NULL);
8415         if (cur == ctxt->context->doc->children)
8416             return (NULL);
8417         if (cur != ctxt->ancestor)
8418             return (cur);
8419         ctxt->ancestor = cur->parent;
8420     }
8421     cur = cur->prev;
8422     while (cur->last != NULL)
8423         cur = cur->last;
8424     return (cur);
8425 }
8426 
8427 /**
8428  * xmlXPathNextNamespace:
8429  * @ctxt:  the XPath Parser context
8430  * @cur:  the current attribute in the traversal
8431  *
8432  * Traversal function for the "namespace" direction
8433  * the namespace axis contains the namespace nodes of the context node;
8434  * the order of nodes on this axis is implementation-defined; the axis will
8435  * be empty unless the context node is an element
8436  *
8437  * We keep the XML namespace node at the end of the list.
8438  *
8439  * Returns the next element following that axis
8440  */
8441 xmlNodePtr
8442 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8443     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8444     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8445     if (cur == NULL) {
8446         if (ctxt->context->tmpNsList != NULL)
8447 	    xmlFree(ctxt->context->tmpNsList);
8448 	ctxt->context->tmpNsList =
8449 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8450 	ctxt->context->tmpNsNr = 0;
8451 	if (ctxt->context->tmpNsList != NULL) {
8452 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8453 		ctxt->context->tmpNsNr++;
8454 	    }
8455 	}
8456 	return((xmlNodePtr) xmlXPathXMLNamespace);
8457     }
8458     if (ctxt->context->tmpNsNr > 0) {
8459 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8460     } else {
8461 	if (ctxt->context->tmpNsList != NULL)
8462 	    xmlFree(ctxt->context->tmpNsList);
8463 	ctxt->context->tmpNsList = NULL;
8464 	return(NULL);
8465     }
8466 }
8467 
8468 /**
8469  * xmlXPathNextAttribute:
8470  * @ctxt:  the XPath Parser context
8471  * @cur:  the current attribute in the traversal
8472  *
8473  * Traversal function for the "attribute" direction
8474  * TODO: support DTD inherited default attributes
8475  *
8476  * Returns the next element following that axis
8477  */
8478 xmlNodePtr
8479 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8480     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8481     if (ctxt->context->node == NULL)
8482 	return(NULL);
8483     if (ctxt->context->node->type != XML_ELEMENT_NODE)
8484 	return(NULL);
8485     if (cur == NULL) {
8486         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8487 	    return(NULL);
8488         return((xmlNodePtr)ctxt->context->node->properties);
8489     }
8490     return((xmlNodePtr)cur->next);
8491 }
8492 
8493 /************************************************************************
8494  *									*
8495  *		NodeTest Functions					*
8496  *									*
8497  ************************************************************************/
8498 
8499 #define IS_FUNCTION			200
8500 
8501 
8502 /************************************************************************
8503  *									*
8504  *		Implicit tree core function library			*
8505  *									*
8506  ************************************************************************/
8507 
8508 /**
8509  * xmlXPathRoot:
8510  * @ctxt:  the XPath Parser context
8511  *
8512  * Initialize the context to the root of the document
8513  */
8514 void
8515 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8516     if ((ctxt == NULL) || (ctxt->context == NULL))
8517 	return;
8518     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8519     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8520 	ctxt->context->node));
8521 }
8522 
8523 /************************************************************************
8524  *									*
8525  *		The explicit core function library			*
8526  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8527  *									*
8528  ************************************************************************/
8529 
8530 
8531 /**
8532  * xmlXPathLastFunction:
8533  * @ctxt:  the XPath Parser context
8534  * @nargs:  the number of arguments
8535  *
8536  * Implement the last() XPath function
8537  *    number last()
8538  * The last function returns the number of nodes in the context node list.
8539  */
8540 void
8541 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8542     CHECK_ARITY(0);
8543     if (ctxt->context->contextSize >= 0) {
8544 	valuePush(ctxt,
8545 	    xmlXPathCacheNewFloat(ctxt->context,
8546 		(double) ctxt->context->contextSize));
8547 #ifdef DEBUG_EXPR
8548 	xmlGenericError(xmlGenericErrorContext,
8549 		"last() : %d\n", ctxt->context->contextSize);
8550 #endif
8551     } else {
8552 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8553     }
8554 }
8555 
8556 /**
8557  * xmlXPathPositionFunction:
8558  * @ctxt:  the XPath Parser context
8559  * @nargs:  the number of arguments
8560  *
8561  * Implement the position() XPath function
8562  *    number position()
8563  * The position function returns the position of the context node in the
8564  * context node list. The first position is 1, and so the last position
8565  * will be equal to last().
8566  */
8567 void
8568 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8569     CHECK_ARITY(0);
8570     if (ctxt->context->proximityPosition >= 0) {
8571 	valuePush(ctxt,
8572 	      xmlXPathCacheNewFloat(ctxt->context,
8573 		(double) ctxt->context->proximityPosition));
8574 #ifdef DEBUG_EXPR
8575 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8576 		ctxt->context->proximityPosition);
8577 #endif
8578     } else {
8579 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8580     }
8581 }
8582 
8583 /**
8584  * xmlXPathCountFunction:
8585  * @ctxt:  the XPath Parser context
8586  * @nargs:  the number of arguments
8587  *
8588  * Implement the count() XPath function
8589  *    number count(node-set)
8590  */
8591 void
8592 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8593     xmlXPathObjectPtr cur;
8594 
8595     CHECK_ARITY(1);
8596     if ((ctxt->value == NULL) ||
8597 	((ctxt->value->type != XPATH_NODESET) &&
8598 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8599 	XP_ERROR(XPATH_INVALID_TYPE);
8600     cur = valuePop(ctxt);
8601 
8602     if ((cur == NULL) || (cur->nodesetval == NULL))
8603 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8604     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8605 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8606 	    (double) cur->nodesetval->nodeNr));
8607     } else {
8608 	if ((cur->nodesetval->nodeNr != 1) ||
8609 	    (cur->nodesetval->nodeTab == NULL)) {
8610 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8611 	} else {
8612 	    xmlNodePtr tmp;
8613 	    int i = 0;
8614 
8615 	    tmp = cur->nodesetval->nodeTab[0];
8616 	    if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8617 		tmp = tmp->children;
8618 		while (tmp != NULL) {
8619 		    tmp = tmp->next;
8620 		    i++;
8621 		}
8622 	    }
8623 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8624 	}
8625     }
8626     xmlXPathReleaseObject(ctxt->context, cur);
8627 }
8628 
8629 /**
8630  * xmlXPathGetElementsByIds:
8631  * @doc:  the document
8632  * @ids:  a whitespace separated list of IDs
8633  *
8634  * Selects elements by their unique ID.
8635  *
8636  * Returns a node-set of selected elements.
8637  */
8638 static xmlNodeSetPtr
8639 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8640     xmlNodeSetPtr ret;
8641     const xmlChar *cur = ids;
8642     xmlChar *ID;
8643     xmlAttrPtr attr;
8644     xmlNodePtr elem = NULL;
8645 
8646     if (ids == NULL) return(NULL);
8647 
8648     ret = xmlXPathNodeSetCreate(NULL);
8649     if (ret == NULL)
8650         return(ret);
8651 
8652     while (IS_BLANK_CH(*cur)) cur++;
8653     while (*cur != 0) {
8654 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8655 	    cur++;
8656 
8657         ID = xmlStrndup(ids, cur - ids);
8658 	if (ID != NULL) {
8659 	    /*
8660 	     * We used to check the fact that the value passed
8661 	     * was an NCName, but this generated much troubles for
8662 	     * me and Aleksey Sanin, people blatantly violated that
8663 	     * constaint, like Visa3D spec.
8664 	     * if (xmlValidateNCName(ID, 1) == 0)
8665 	     */
8666 	    attr = xmlGetID(doc, ID);
8667 	    if (attr != NULL) {
8668 		if (attr->type == XML_ATTRIBUTE_NODE)
8669 		    elem = attr->parent;
8670 		else if (attr->type == XML_ELEMENT_NODE)
8671 		    elem = (xmlNodePtr) attr;
8672 		else
8673 		    elem = NULL;
8674 		if (elem != NULL)
8675 		    xmlXPathNodeSetAdd(ret, elem);
8676 	    }
8677 	    xmlFree(ID);
8678 	}
8679 
8680 	while (IS_BLANK_CH(*cur)) cur++;
8681 	ids = cur;
8682     }
8683     return(ret);
8684 }
8685 
8686 /**
8687  * xmlXPathIdFunction:
8688  * @ctxt:  the XPath Parser context
8689  * @nargs:  the number of arguments
8690  *
8691  * Implement the id() XPath function
8692  *    node-set id(object)
8693  * The id function selects elements by their unique ID
8694  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8695  * then the result is the union of the result of applying id to the
8696  * string value of each of the nodes in the argument node-set. When the
8697  * argument to id is of any other type, the argument is converted to a
8698  * string as if by a call to the string function; the string is split
8699  * into a whitespace-separated list of tokens (whitespace is any sequence
8700  * of characters matching the production S); the result is a node-set
8701  * containing the elements in the same document as the context node that
8702  * have a unique ID equal to any of the tokens in the list.
8703  */
8704 void
8705 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8706     xmlChar *tokens;
8707     xmlNodeSetPtr ret;
8708     xmlXPathObjectPtr obj;
8709 
8710     CHECK_ARITY(1);
8711     obj = valuePop(ctxt);
8712     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8713     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8714 	xmlNodeSetPtr ns;
8715 	int i;
8716 
8717 	ret = xmlXPathNodeSetCreate(NULL);
8718         /*
8719          * FIXME -- in an out-of-memory condition this will behave badly.
8720          * The solution is not clear -- we already popped an item from
8721          * ctxt, so the object is in a corrupt state.
8722          */
8723 
8724 	if (obj->nodesetval != NULL) {
8725 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8726 		tokens =
8727 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8728 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8729 		ret = xmlXPathNodeSetMerge(ret, ns);
8730 		xmlXPathFreeNodeSet(ns);
8731 		if (tokens != NULL)
8732 		    xmlFree(tokens);
8733 	    }
8734 	}
8735 	xmlXPathReleaseObject(ctxt->context, obj);
8736 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8737 	return;
8738     }
8739     obj = xmlXPathCacheConvertString(ctxt->context, obj);
8740     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8741     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8742     xmlXPathReleaseObject(ctxt->context, obj);
8743     return;
8744 }
8745 
8746 /**
8747  * xmlXPathLocalNameFunction:
8748  * @ctxt:  the XPath Parser context
8749  * @nargs:  the number of arguments
8750  *
8751  * Implement the local-name() XPath function
8752  *    string local-name(node-set?)
8753  * The local-name function returns a string containing the local part
8754  * of the name of the node in the argument node-set that is first in
8755  * document order. If the node-set is empty or the first node has no
8756  * name, an empty string is returned. If the argument is omitted it
8757  * defaults to the context node.
8758  */
8759 void
8760 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8761     xmlXPathObjectPtr cur;
8762 
8763     if (ctxt == NULL) return;
8764 
8765     if (nargs == 0) {
8766 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8767 	    ctxt->context->node));
8768 	nargs = 1;
8769     }
8770 
8771     CHECK_ARITY(1);
8772     if ((ctxt->value == NULL) ||
8773 	((ctxt->value->type != XPATH_NODESET) &&
8774 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8775 	XP_ERROR(XPATH_INVALID_TYPE);
8776     cur = valuePop(ctxt);
8777 
8778     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8779 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8780     } else {
8781 	int i = 0; /* Should be first in document order !!!!! */
8782 	switch (cur->nodesetval->nodeTab[i]->type) {
8783 	case XML_ELEMENT_NODE:
8784 	case XML_ATTRIBUTE_NODE:
8785 	case XML_PI_NODE:
8786 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8787 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8788 	    else
8789 		valuePush(ctxt,
8790 		      xmlXPathCacheNewString(ctxt->context,
8791 			cur->nodesetval->nodeTab[i]->name));
8792 	    break;
8793 	case XML_NAMESPACE_DECL:
8794 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8795 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8796 	    break;
8797 	default:
8798 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8799 	}
8800     }
8801     xmlXPathReleaseObject(ctxt->context, cur);
8802 }
8803 
8804 /**
8805  * xmlXPathNamespaceURIFunction:
8806  * @ctxt:  the XPath Parser context
8807  * @nargs:  the number of arguments
8808  *
8809  * Implement the namespace-uri() XPath function
8810  *    string namespace-uri(node-set?)
8811  * The namespace-uri function returns a string containing the
8812  * namespace URI of the expanded name of the node in the argument
8813  * node-set that is first in document order. If the node-set is empty,
8814  * the first node has no name, or the expanded name has no namespace
8815  * URI, an empty string is returned. If the argument is omitted it
8816  * defaults to the context node.
8817  */
8818 void
8819 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8820     xmlXPathObjectPtr cur;
8821 
8822     if (ctxt == NULL) return;
8823 
8824     if (nargs == 0) {
8825 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8826 	    ctxt->context->node));
8827 	nargs = 1;
8828     }
8829     CHECK_ARITY(1);
8830     if ((ctxt->value == NULL) ||
8831 	((ctxt->value->type != XPATH_NODESET) &&
8832 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8833 	XP_ERROR(XPATH_INVALID_TYPE);
8834     cur = valuePop(ctxt);
8835 
8836     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8837 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8838     } else {
8839 	int i = 0; /* Should be first in document order !!!!! */
8840 	switch (cur->nodesetval->nodeTab[i]->type) {
8841 	case XML_ELEMENT_NODE:
8842 	case XML_ATTRIBUTE_NODE:
8843 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8844 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8845 	    else
8846 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8847 			  cur->nodesetval->nodeTab[i]->ns->href));
8848 	    break;
8849 	default:
8850 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8851 	}
8852     }
8853     xmlXPathReleaseObject(ctxt->context, cur);
8854 }
8855 
8856 /**
8857  * xmlXPathNameFunction:
8858  * @ctxt:  the XPath Parser context
8859  * @nargs:  the number of arguments
8860  *
8861  * Implement the name() XPath function
8862  *    string name(node-set?)
8863  * The name function returns a string containing a QName representing
8864  * the name of the node in the argument node-set that is first in document
8865  * order. The QName must represent the name with respect to the namespace
8866  * declarations in effect on the node whose name is being represented.
8867  * Typically, this will be the form in which the name occurred in the XML
8868  * source. This need not be the case if there are namespace declarations
8869  * in effect on the node that associate multiple prefixes with the same
8870  * namespace. However, an implementation may include information about
8871  * the original prefix in its representation of nodes; in this case, an
8872  * implementation can ensure that the returned string is always the same
8873  * as the QName used in the XML source. If the argument it omitted it
8874  * defaults to the context node.
8875  * Libxml keep the original prefix so the "real qualified name" used is
8876  * returned.
8877  */
8878 static void
8879 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8880 {
8881     xmlXPathObjectPtr cur;
8882 
8883     if (nargs == 0) {
8884 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8885 	    ctxt->context->node));
8886         nargs = 1;
8887     }
8888 
8889     CHECK_ARITY(1);
8890     if ((ctxt->value == NULL) ||
8891         ((ctxt->value->type != XPATH_NODESET) &&
8892          (ctxt->value->type != XPATH_XSLT_TREE)))
8893         XP_ERROR(XPATH_INVALID_TYPE);
8894     cur = valuePop(ctxt);
8895 
8896     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8897         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8898     } else {
8899         int i = 0;              /* Should be first in document order !!!!! */
8900 
8901         switch (cur->nodesetval->nodeTab[i]->type) {
8902             case XML_ELEMENT_NODE:
8903             case XML_ATTRIBUTE_NODE:
8904 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8905 		    valuePush(ctxt,
8906 			xmlXPathCacheNewCString(ctxt->context, ""));
8907 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8908                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8909 		    valuePush(ctxt,
8910 		        xmlXPathCacheNewString(ctxt->context,
8911 			    cur->nodesetval->nodeTab[i]->name));
8912 		} else {
8913 		    xmlChar *fullname;
8914 
8915 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8916 				     cur->nodesetval->nodeTab[i]->ns->prefix,
8917 				     NULL, 0);
8918 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8919 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8920 		    if (fullname == NULL) {
8921 			XP_ERROR(XPATH_MEMORY_ERROR);
8922 		    }
8923 		    valuePush(ctxt, xmlXPathCacheWrapString(
8924 			ctxt->context, fullname));
8925                 }
8926                 break;
8927             default:
8928 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8929 		    cur->nodesetval->nodeTab[i]));
8930                 xmlXPathLocalNameFunction(ctxt, 1);
8931         }
8932     }
8933     xmlXPathReleaseObject(ctxt->context, cur);
8934 }
8935 
8936 
8937 /**
8938  * xmlXPathStringFunction:
8939  * @ctxt:  the XPath Parser context
8940  * @nargs:  the number of arguments
8941  *
8942  * Implement the string() XPath function
8943  *    string string(object?)
8944  * The string function converts an object to a string as follows:
8945  *    - A node-set is converted to a string by returning the value of
8946  *      the node in the node-set that is first in document order.
8947  *      If the node-set is empty, an empty string is returned.
8948  *    - A number is converted to a string as follows
8949  *      + NaN is converted to the string NaN
8950  *      + positive zero is converted to the string 0
8951  *      + negative zero is converted to the string 0
8952  *      + positive infinity is converted to the string Infinity
8953  *      + negative infinity is converted to the string -Infinity
8954  *      + if the number is an integer, the number is represented in
8955  *        decimal form as a Number with no decimal point and no leading
8956  *        zeros, preceded by a minus sign (-) if the number is negative
8957  *      + otherwise, the number is represented in decimal form as a
8958  *        Number including a decimal point with at least one digit
8959  *        before the decimal point and at least one digit after the
8960  *        decimal point, preceded by a minus sign (-) if the number
8961  *        is negative; there must be no leading zeros before the decimal
8962  *        point apart possibly from the one required digit immediately
8963  *        before the decimal point; beyond the one required digit
8964  *        after the decimal point there must be as many, but only as
8965  *        many, more digits as are needed to uniquely distinguish the
8966  *        number from all other IEEE 754 numeric values.
8967  *    - The boolean false value is converted to the string false.
8968  *      The boolean true value is converted to the string true.
8969  *
8970  * If the argument is omitted, it defaults to a node-set with the
8971  * context node as its only member.
8972  */
8973 void
8974 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8975     xmlXPathObjectPtr cur;
8976 
8977     if (ctxt == NULL) return;
8978     if (nargs == 0) {
8979     valuePush(ctxt,
8980 	xmlXPathCacheWrapString(ctxt->context,
8981 	    xmlXPathCastNodeToString(ctxt->context->node)));
8982 	return;
8983     }
8984 
8985     CHECK_ARITY(1);
8986     cur = valuePop(ctxt);
8987     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8988     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8989 }
8990 
8991 /**
8992  * xmlXPathStringLengthFunction:
8993  * @ctxt:  the XPath Parser context
8994  * @nargs:  the number of arguments
8995  *
8996  * Implement the string-length() XPath function
8997  *    number string-length(string?)
8998  * The string-length returns the number of characters in the string
8999  * (see [3.6 Strings]). If the argument is omitted, it defaults to
9000  * the context node converted to a string, in other words the value
9001  * of the context node.
9002  */
9003 void
9004 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9005     xmlXPathObjectPtr cur;
9006 
9007     if (nargs == 0) {
9008         if ((ctxt == NULL) || (ctxt->context == NULL))
9009 	    return;
9010 	if (ctxt->context->node == NULL) {
9011 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
9012 	} else {
9013 	    xmlChar *content;
9014 
9015 	    content = xmlXPathCastNodeToString(ctxt->context->node);
9016 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9017 		xmlUTF8Strlen(content)));
9018 	    xmlFree(content);
9019 	}
9020 	return;
9021     }
9022     CHECK_ARITY(1);
9023     CAST_TO_STRING;
9024     CHECK_TYPE(XPATH_STRING);
9025     cur = valuePop(ctxt);
9026     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9027 	xmlUTF8Strlen(cur->stringval)));
9028     xmlXPathReleaseObject(ctxt->context, cur);
9029 }
9030 
9031 /**
9032  * xmlXPathConcatFunction:
9033  * @ctxt:  the XPath Parser context
9034  * @nargs:  the number of arguments
9035  *
9036  * Implement the concat() XPath function
9037  *    string concat(string, string, string*)
9038  * The concat function returns the concatenation of its arguments.
9039  */
9040 void
9041 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9042     xmlXPathObjectPtr cur, newobj;
9043     xmlChar *tmp;
9044 
9045     if (ctxt == NULL) return;
9046     if (nargs < 2) {
9047 	CHECK_ARITY(2);
9048     }
9049 
9050     CAST_TO_STRING;
9051     cur = valuePop(ctxt);
9052     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
9053 	xmlXPathReleaseObject(ctxt->context, cur);
9054 	return;
9055     }
9056     nargs--;
9057 
9058     while (nargs > 0) {
9059 	CAST_TO_STRING;
9060 	newobj = valuePop(ctxt);
9061 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9062 	    xmlXPathReleaseObject(ctxt->context, newobj);
9063 	    xmlXPathReleaseObject(ctxt->context, cur);
9064 	    XP_ERROR(XPATH_INVALID_TYPE);
9065 	}
9066 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
9067 	newobj->stringval = cur->stringval;
9068 	cur->stringval = tmp;
9069 	xmlXPathReleaseObject(ctxt->context, newobj);
9070 	nargs--;
9071     }
9072     valuePush(ctxt, cur);
9073 }
9074 
9075 /**
9076  * xmlXPathContainsFunction:
9077  * @ctxt:  the XPath Parser context
9078  * @nargs:  the number of arguments
9079  *
9080  * Implement the contains() XPath function
9081  *    boolean contains(string, string)
9082  * The contains function returns true if the first argument string
9083  * contains the second argument string, and otherwise returns false.
9084  */
9085 void
9086 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9087     xmlXPathObjectPtr hay, needle;
9088 
9089     CHECK_ARITY(2);
9090     CAST_TO_STRING;
9091     CHECK_TYPE(XPATH_STRING);
9092     needle = valuePop(ctxt);
9093     CAST_TO_STRING;
9094     hay = valuePop(ctxt);
9095 
9096     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9097 	xmlXPathReleaseObject(ctxt->context, hay);
9098 	xmlXPathReleaseObject(ctxt->context, needle);
9099 	XP_ERROR(XPATH_INVALID_TYPE);
9100     }
9101     if (xmlStrstr(hay->stringval, needle->stringval))
9102 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9103     else
9104 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9105     xmlXPathReleaseObject(ctxt->context, hay);
9106     xmlXPathReleaseObject(ctxt->context, needle);
9107 }
9108 
9109 /**
9110  * xmlXPathStartsWithFunction:
9111  * @ctxt:  the XPath Parser context
9112  * @nargs:  the number of arguments
9113  *
9114  * Implement the starts-with() XPath function
9115  *    boolean starts-with(string, string)
9116  * The starts-with function returns true if the first argument string
9117  * starts with the second argument string, and otherwise returns false.
9118  */
9119 void
9120 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9121     xmlXPathObjectPtr hay, needle;
9122     int n;
9123 
9124     CHECK_ARITY(2);
9125     CAST_TO_STRING;
9126     CHECK_TYPE(XPATH_STRING);
9127     needle = valuePop(ctxt);
9128     CAST_TO_STRING;
9129     hay = valuePop(ctxt);
9130 
9131     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9132 	xmlXPathReleaseObject(ctxt->context, hay);
9133 	xmlXPathReleaseObject(ctxt->context, needle);
9134 	XP_ERROR(XPATH_INVALID_TYPE);
9135     }
9136     n = xmlStrlen(needle->stringval);
9137     if (xmlStrncmp(hay->stringval, needle->stringval, n))
9138         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9139     else
9140         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9141     xmlXPathReleaseObject(ctxt->context, hay);
9142     xmlXPathReleaseObject(ctxt->context, needle);
9143 }
9144 
9145 /**
9146  * xmlXPathSubstringFunction:
9147  * @ctxt:  the XPath Parser context
9148  * @nargs:  the number of arguments
9149  *
9150  * Implement the substring() XPath function
9151  *    string substring(string, number, number?)
9152  * The substring function returns the substring of the first argument
9153  * starting at the position specified in the second argument with
9154  * length specified in the third argument. For example,
9155  * substring("12345",2,3) returns "234". If the third argument is not
9156  * specified, it returns the substring starting at the position specified
9157  * in the second argument and continuing to the end of the string. For
9158  * example, substring("12345",2) returns "2345".  More precisely, each
9159  * character in the string (see [3.6 Strings]) is considered to have a
9160  * numeric position: the position of the first character is 1, the position
9161  * of the second character is 2 and so on. The returned substring contains
9162  * those characters for which the position of the character is greater than
9163  * or equal to the second argument and, if the third argument is specified,
9164  * less than the sum of the second and third arguments; the comparisons
9165  * and addition used for the above follow the standard IEEE 754 rules. Thus:
9166  *  - substring("12345", 1.5, 2.6) returns "234"
9167  *  - substring("12345", 0, 3) returns "12"
9168  *  - substring("12345", 0 div 0, 3) returns ""
9169  *  - substring("12345", 1, 0 div 0) returns ""
9170  *  - substring("12345", -42, 1 div 0) returns "12345"
9171  *  - substring("12345", -1 div 0, 1 div 0) returns ""
9172  */
9173 void
9174 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9175     xmlXPathObjectPtr str, start, len;
9176     double le=0, in;
9177     int i, l, m;
9178     xmlChar *ret;
9179 
9180     if (nargs < 2) {
9181 	CHECK_ARITY(2);
9182     }
9183     if (nargs > 3) {
9184 	CHECK_ARITY(3);
9185     }
9186     /*
9187      * take care of possible last (position) argument
9188     */
9189     if (nargs == 3) {
9190 	CAST_TO_NUMBER;
9191 	CHECK_TYPE(XPATH_NUMBER);
9192 	len = valuePop(ctxt);
9193 	le = len->floatval;
9194 	xmlXPathReleaseObject(ctxt->context, len);
9195     }
9196 
9197     CAST_TO_NUMBER;
9198     CHECK_TYPE(XPATH_NUMBER);
9199     start = valuePop(ctxt);
9200     in = start->floatval;
9201     xmlXPathReleaseObject(ctxt->context, start);
9202     CAST_TO_STRING;
9203     CHECK_TYPE(XPATH_STRING);
9204     str = valuePop(ctxt);
9205     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9206 
9207     /*
9208      * If last pos not present, calculate last position
9209     */
9210     if (nargs != 3) {
9211 	le = (double)m;
9212 	if (in < 1.0)
9213 	    in = 1.0;
9214     }
9215 
9216     /* Need to check for the special cases where either
9217      * the index is NaN, the length is NaN, or both
9218      * arguments are infinity (relying on Inf + -Inf = NaN)
9219      */
9220     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9221         /*
9222          * To meet the requirements of the spec, the arguments
9223 	 * must be converted to integer format before
9224 	 * initial index calculations are done
9225          *
9226          * First we go to integer form, rounding up
9227 	 * and checking for special cases
9228          */
9229         i = (int) in;
9230         if (((double)i)+0.5 <= in) i++;
9231 
9232 	if (xmlXPathIsInf(le) == 1) {
9233 	    l = m;
9234 	    if (i < 1)
9235 		i = 1;
9236 	}
9237 	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9238 	    l = 0;
9239 	else {
9240 	    l = (int) le;
9241 	    if (((double)l)+0.5 <= le) l++;
9242 	}
9243 
9244 	/* Now we normalize inidices */
9245         i -= 1;
9246         l += i;
9247         if (i < 0)
9248             i = 0;
9249         if (l > m)
9250             l = m;
9251 
9252         /* number of chars to copy */
9253         l -= i;
9254 
9255         ret = xmlUTF8Strsub(str->stringval, i, l);
9256     }
9257     else {
9258         ret = NULL;
9259     }
9260     if (ret == NULL)
9261 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9262     else {
9263 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9264 	xmlFree(ret);
9265     }
9266     xmlXPathReleaseObject(ctxt->context, str);
9267 }
9268 
9269 /**
9270  * xmlXPathSubstringBeforeFunction:
9271  * @ctxt:  the XPath Parser context
9272  * @nargs:  the number of arguments
9273  *
9274  * Implement the substring-before() XPath function
9275  *    string substring-before(string, string)
9276  * The substring-before function returns the substring of the first
9277  * argument string that precedes the first occurrence of the second
9278  * argument string in the first argument string, or the empty string
9279  * if the first argument string does not contain the second argument
9280  * string. For example, substring-before("1999/04/01","/") returns 1999.
9281  */
9282 void
9283 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9284   xmlXPathObjectPtr str;
9285   xmlXPathObjectPtr find;
9286   xmlBufPtr target;
9287   const xmlChar *point;
9288   int offset;
9289 
9290   CHECK_ARITY(2);
9291   CAST_TO_STRING;
9292   find = valuePop(ctxt);
9293   CAST_TO_STRING;
9294   str = valuePop(ctxt);
9295 
9296   target = xmlBufCreate();
9297   if (target) {
9298     point = xmlStrstr(str->stringval, find->stringval);
9299     if (point) {
9300       offset = (int)(point - str->stringval);
9301       xmlBufAdd(target, str->stringval, offset);
9302     }
9303     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9304 	xmlBufContent(target)));
9305     xmlBufFree(target);
9306   }
9307   xmlXPathReleaseObject(ctxt->context, str);
9308   xmlXPathReleaseObject(ctxt->context, find);
9309 }
9310 
9311 /**
9312  * xmlXPathSubstringAfterFunction:
9313  * @ctxt:  the XPath Parser context
9314  * @nargs:  the number of arguments
9315  *
9316  * Implement the substring-after() XPath function
9317  *    string substring-after(string, string)
9318  * The substring-after function returns the substring of the first
9319  * argument string that follows the first occurrence of the second
9320  * argument string in the first argument string, or the empty stringi
9321  * if the first argument string does not contain the second argument
9322  * string. For example, substring-after("1999/04/01","/") returns 04/01,
9323  * and substring-after("1999/04/01","19") returns 99/04/01.
9324  */
9325 void
9326 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9327   xmlXPathObjectPtr str;
9328   xmlXPathObjectPtr find;
9329   xmlBufPtr target;
9330   const xmlChar *point;
9331   int offset;
9332 
9333   CHECK_ARITY(2);
9334   CAST_TO_STRING;
9335   find = valuePop(ctxt);
9336   CAST_TO_STRING;
9337   str = valuePop(ctxt);
9338 
9339   target = xmlBufCreate();
9340   if (target) {
9341     point = xmlStrstr(str->stringval, find->stringval);
9342     if (point) {
9343       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9344       xmlBufAdd(target, &str->stringval[offset],
9345 		   xmlStrlen(str->stringval) - offset);
9346     }
9347     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9348 	xmlBufContent(target)));
9349     xmlBufFree(target);
9350   }
9351   xmlXPathReleaseObject(ctxt->context, str);
9352   xmlXPathReleaseObject(ctxt->context, find);
9353 }
9354 
9355 /**
9356  * xmlXPathNormalizeFunction:
9357  * @ctxt:  the XPath Parser context
9358  * @nargs:  the number of arguments
9359  *
9360  * Implement the normalize-space() XPath function
9361  *    string normalize-space(string?)
9362  * The normalize-space function returns the argument string with white
9363  * space normalized by stripping leading and trailing whitespace
9364  * and replacing sequences of whitespace characters by a single
9365  * space. Whitespace characters are the same allowed by the S production
9366  * in XML. If the argument is omitted, it defaults to the context
9367  * node converted to a string, in other words the value of the context node.
9368  */
9369 void
9370 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9371   xmlXPathObjectPtr obj = NULL;
9372   xmlChar *source = NULL;
9373   xmlBufPtr target;
9374   xmlChar blank;
9375 
9376   if (ctxt == NULL) return;
9377   if (nargs == 0) {
9378     /* Use current context node */
9379       valuePush(ctxt,
9380 	  xmlXPathCacheWrapString(ctxt->context,
9381 	    xmlXPathCastNodeToString(ctxt->context->node)));
9382     nargs = 1;
9383   }
9384 
9385   CHECK_ARITY(1);
9386   CAST_TO_STRING;
9387   CHECK_TYPE(XPATH_STRING);
9388   obj = valuePop(ctxt);
9389   source = obj->stringval;
9390 
9391   target = xmlBufCreate();
9392   if (target && source) {
9393 
9394     /* Skip leading whitespaces */
9395     while (IS_BLANK_CH(*source))
9396       source++;
9397 
9398     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9399     blank = 0;
9400     while (*source) {
9401       if (IS_BLANK_CH(*source)) {
9402 	blank = 0x20;
9403       } else {
9404 	if (blank) {
9405 	  xmlBufAdd(target, &blank, 1);
9406 	  blank = 0;
9407 	}
9408 	xmlBufAdd(target, source, 1);
9409       }
9410       source++;
9411     }
9412     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9413 	xmlBufContent(target)));
9414     xmlBufFree(target);
9415   }
9416   xmlXPathReleaseObject(ctxt->context, obj);
9417 }
9418 
9419 /**
9420  * xmlXPathTranslateFunction:
9421  * @ctxt:  the XPath Parser context
9422  * @nargs:  the number of arguments
9423  *
9424  * Implement the translate() XPath function
9425  *    string translate(string, string, string)
9426  * The translate function returns the first argument string with
9427  * occurrences of characters in the second argument string replaced
9428  * by the character at the corresponding position in the third argument
9429  * string. For example, translate("bar","abc","ABC") returns the string
9430  * BAr. If there is a character in the second argument string with no
9431  * character at a corresponding position in the third argument string
9432  * (because the second argument string is longer than the third argument
9433  * string), then occurrences of that character in the first argument
9434  * string are removed. For example, translate("--aaa--","abc-","ABC")
9435  * returns "AAA". If a character occurs more than once in second
9436  * argument string, then the first occurrence determines the replacement
9437  * character. If the third argument string is longer than the second
9438  * argument string, then excess characters are ignored.
9439  */
9440 void
9441 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9442     xmlXPathObjectPtr str;
9443     xmlXPathObjectPtr from;
9444     xmlXPathObjectPtr to;
9445     xmlBufPtr target;
9446     int offset, max;
9447     xmlChar ch;
9448     const xmlChar *point;
9449     xmlChar *cptr;
9450 
9451     CHECK_ARITY(3);
9452 
9453     CAST_TO_STRING;
9454     to = valuePop(ctxt);
9455     CAST_TO_STRING;
9456     from = valuePop(ctxt);
9457     CAST_TO_STRING;
9458     str = valuePop(ctxt);
9459 
9460     target = xmlBufCreate();
9461     if (target) {
9462 	max = xmlUTF8Strlen(to->stringval);
9463 	for (cptr = str->stringval; (ch=*cptr); ) {
9464 	    offset = xmlUTF8Strloc(from->stringval, cptr);
9465 	    if (offset >= 0) {
9466 		if (offset < max) {
9467 		    point = xmlUTF8Strpos(to->stringval, offset);
9468 		    if (point)
9469 			xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9470 		}
9471 	    } else
9472 		xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9473 
9474 	    /* Step to next character in input */
9475 	    cptr++;
9476 	    if ( ch & 0x80 ) {
9477 		/* if not simple ascii, verify proper format */
9478 		if ( (ch & 0xc0) != 0xc0 ) {
9479 		    xmlGenericError(xmlGenericErrorContext,
9480 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
9481                     /* not asserting an XPath error is probably better */
9482 		    break;
9483 		}
9484 		/* then skip over remaining bytes for this char */
9485 		while ( (ch <<= 1) & 0x80 )
9486 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
9487 			xmlGenericError(xmlGenericErrorContext,
9488 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9489                         /* not asserting an XPath error is probably better */
9490 			break;
9491 		    }
9492 		if (ch & 0x80) /* must have had error encountered */
9493 		    break;
9494 	    }
9495 	}
9496     }
9497     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9498 	xmlBufContent(target)));
9499     xmlBufFree(target);
9500     xmlXPathReleaseObject(ctxt->context, str);
9501     xmlXPathReleaseObject(ctxt->context, from);
9502     xmlXPathReleaseObject(ctxt->context, to);
9503 }
9504 
9505 /**
9506  * xmlXPathBooleanFunction:
9507  * @ctxt:  the XPath Parser context
9508  * @nargs:  the number of arguments
9509  *
9510  * Implement the boolean() XPath function
9511  *    boolean boolean(object)
9512  * The boolean function converts its argument to a boolean as follows:
9513  *    - a number is true if and only if it is neither positive or
9514  *      negative zero nor NaN
9515  *    - a node-set is true if and only if it is non-empty
9516  *    - a string is true if and only if its length is non-zero
9517  */
9518 void
9519 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9520     xmlXPathObjectPtr cur;
9521 
9522     CHECK_ARITY(1);
9523     cur = valuePop(ctxt);
9524     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9525     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9526     valuePush(ctxt, cur);
9527 }
9528 
9529 /**
9530  * xmlXPathNotFunction:
9531  * @ctxt:  the XPath Parser context
9532  * @nargs:  the number of arguments
9533  *
9534  * Implement the not() XPath function
9535  *    boolean not(boolean)
9536  * The not function returns true if its argument is false,
9537  * and false otherwise.
9538  */
9539 void
9540 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9541     CHECK_ARITY(1);
9542     CAST_TO_BOOLEAN;
9543     CHECK_TYPE(XPATH_BOOLEAN);
9544     ctxt->value->boolval = ! ctxt->value->boolval;
9545 }
9546 
9547 /**
9548  * xmlXPathTrueFunction:
9549  * @ctxt:  the XPath Parser context
9550  * @nargs:  the number of arguments
9551  *
9552  * Implement the true() XPath function
9553  *    boolean true()
9554  */
9555 void
9556 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9557     CHECK_ARITY(0);
9558     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9559 }
9560 
9561 /**
9562  * xmlXPathFalseFunction:
9563  * @ctxt:  the XPath Parser context
9564  * @nargs:  the number of arguments
9565  *
9566  * Implement the false() XPath function
9567  *    boolean false()
9568  */
9569 void
9570 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9571     CHECK_ARITY(0);
9572     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9573 }
9574 
9575 /**
9576  * xmlXPathLangFunction:
9577  * @ctxt:  the XPath Parser context
9578  * @nargs:  the number of arguments
9579  *
9580  * Implement the lang() XPath function
9581  *    boolean lang(string)
9582  * The lang function returns true or false depending on whether the
9583  * language of the context node as specified by xml:lang attributes
9584  * is the same as or is a sublanguage of the language specified by
9585  * the argument string. The language of the context node is determined
9586  * by the value of the xml:lang attribute on the context node, or, if
9587  * the context node has no xml:lang attribute, by the value of the
9588  * xml:lang attribute on the nearest ancestor of the context node that
9589  * has an xml:lang attribute. If there is no such attribute, then lang
9590  * returns false. If there is such an attribute, then lang returns
9591  * true if the attribute value is equal to the argument ignoring case,
9592  * or if there is some suffix starting with - such that the attribute
9593  * value is equal to the argument ignoring that suffix of the attribute
9594  * value and ignoring case.
9595  */
9596 void
9597 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9598     xmlXPathObjectPtr val = NULL;
9599     const xmlChar *theLang = NULL;
9600     const xmlChar *lang;
9601     int ret = 0;
9602     int i;
9603 
9604     CHECK_ARITY(1);
9605     CAST_TO_STRING;
9606     CHECK_TYPE(XPATH_STRING);
9607     val = valuePop(ctxt);
9608     lang = val->stringval;
9609     theLang = xmlNodeGetLang(ctxt->context->node);
9610     if ((theLang != NULL) && (lang != NULL)) {
9611         for (i = 0;lang[i] != 0;i++)
9612 	    if (toupper(lang[i]) != toupper(theLang[i]))
9613 	        goto not_equal;
9614 	if ((theLang[i] == 0) || (theLang[i] == '-'))
9615 	    ret = 1;
9616     }
9617 not_equal:
9618     if (theLang != NULL)
9619 	xmlFree((void *)theLang);
9620 
9621     xmlXPathReleaseObject(ctxt->context, val);
9622     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9623 }
9624 
9625 /**
9626  * xmlXPathNumberFunction:
9627  * @ctxt:  the XPath Parser context
9628  * @nargs:  the number of arguments
9629  *
9630  * Implement the number() XPath function
9631  *    number number(object?)
9632  */
9633 void
9634 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9635     xmlXPathObjectPtr cur;
9636     double res;
9637 
9638     if (ctxt == NULL) return;
9639     if (nargs == 0) {
9640 	if (ctxt->context->node == NULL) {
9641 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9642 	} else {
9643 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9644 
9645 	    res = xmlXPathStringEvalNumber(content);
9646 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9647 	    xmlFree(content);
9648 	}
9649 	return;
9650     }
9651 
9652     CHECK_ARITY(1);
9653     cur = valuePop(ctxt);
9654     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9655 }
9656 
9657 /**
9658  * xmlXPathSumFunction:
9659  * @ctxt:  the XPath Parser context
9660  * @nargs:  the number of arguments
9661  *
9662  * Implement the sum() XPath function
9663  *    number sum(node-set)
9664  * The sum function returns the sum of the values of the nodes in
9665  * the argument node-set.
9666  */
9667 void
9668 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9669     xmlXPathObjectPtr cur;
9670     int i;
9671     double res = 0.0;
9672 
9673     CHECK_ARITY(1);
9674     if ((ctxt->value == NULL) ||
9675 	((ctxt->value->type != XPATH_NODESET) &&
9676 	 (ctxt->value->type != XPATH_XSLT_TREE)))
9677 	XP_ERROR(XPATH_INVALID_TYPE);
9678     cur = valuePop(ctxt);
9679 
9680     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9681 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9682 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9683 	}
9684     }
9685     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9686     xmlXPathReleaseObject(ctxt->context, cur);
9687 }
9688 
9689 /**
9690  * xmlXPathFloorFunction:
9691  * @ctxt:  the XPath Parser context
9692  * @nargs:  the number of arguments
9693  *
9694  * Implement the floor() XPath function
9695  *    number floor(number)
9696  * The floor function returns the largest (closest to positive infinity)
9697  * number that is not greater than the argument and that is an integer.
9698  */
9699 void
9700 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9701     CHECK_ARITY(1);
9702     CAST_TO_NUMBER;
9703     CHECK_TYPE(XPATH_NUMBER);
9704 
9705     ctxt->value->floatval = floor(ctxt->value->floatval);
9706 }
9707 
9708 /**
9709  * xmlXPathCeilingFunction:
9710  * @ctxt:  the XPath Parser context
9711  * @nargs:  the number of arguments
9712  *
9713  * Implement the ceiling() XPath function
9714  *    number ceiling(number)
9715  * The ceiling function returns the smallest (closest to negative infinity)
9716  * number that is not less than the argument and that is an integer.
9717  */
9718 void
9719 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9720     CHECK_ARITY(1);
9721     CAST_TO_NUMBER;
9722     CHECK_TYPE(XPATH_NUMBER);
9723 
9724     ctxt->value->floatval = ceil(ctxt->value->floatval);
9725 }
9726 
9727 /**
9728  * xmlXPathRoundFunction:
9729  * @ctxt:  the XPath Parser context
9730  * @nargs:  the number of arguments
9731  *
9732  * Implement the round() XPath function
9733  *    number round(number)
9734  * The round function returns the number that is closest to the
9735  * argument and that is an integer. If there are two such numbers,
9736  * then the one that is closest to positive infinity is returned.
9737  */
9738 void
9739 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9740     double f;
9741 
9742     CHECK_ARITY(1);
9743     CAST_TO_NUMBER;
9744     CHECK_TYPE(XPATH_NUMBER);
9745 
9746     f = ctxt->value->floatval;
9747 
9748     /* Test for zero to keep negative zero unchanged. */
9749     if ((xmlXPathIsNaN(f)) || (f == 0.0))
9750 	return;
9751 
9752     if ((f >= -0.5) && (f < 0.0)) {
9753         /* Negative zero. */
9754         ctxt->value->floatval = xmlXPathNZERO;
9755     }
9756     else {
9757         double rounded = floor(f);
9758         if (f - rounded >= 0.5)
9759             rounded += 1.0;
9760         ctxt->value->floatval = rounded;
9761     }
9762 }
9763 
9764 /************************************************************************
9765  *									*
9766  *			The Parser					*
9767  *									*
9768  ************************************************************************/
9769 
9770 /*
9771  * a few forward declarations since we use a recursive call based
9772  * implementation.
9773  */
9774 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9775 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9776 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9777 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9778 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9779 	                                  int qualified);
9780 
9781 /**
9782  * xmlXPathCurrentChar:
9783  * @ctxt:  the XPath parser context
9784  * @cur:  pointer to the beginning of the char
9785  * @len:  pointer to the length of the char read
9786  *
9787  * The current char value, if using UTF-8 this may actually span multiple
9788  * bytes in the input buffer.
9789  *
9790  * Returns the current char value and its length
9791  */
9792 
9793 static int
9794 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9795     unsigned char c;
9796     unsigned int val;
9797     const xmlChar *cur;
9798 
9799     if (ctxt == NULL)
9800 	return(0);
9801     cur = ctxt->cur;
9802 
9803     /*
9804      * We are supposed to handle UTF8, check it's valid
9805      * From rfc2044: encoding of the Unicode values on UTF-8:
9806      *
9807      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9808      * 0000 0000-0000 007F   0xxxxxxx
9809      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9810      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9811      *
9812      * Check for the 0x110000 limit too
9813      */
9814     c = *cur;
9815     if (c & 0x80) {
9816 	if ((cur[1] & 0xc0) != 0x80)
9817 	    goto encoding_error;
9818 	if ((c & 0xe0) == 0xe0) {
9819 
9820 	    if ((cur[2] & 0xc0) != 0x80)
9821 		goto encoding_error;
9822 	    if ((c & 0xf0) == 0xf0) {
9823 		if (((c & 0xf8) != 0xf0) ||
9824 		    ((cur[3] & 0xc0) != 0x80))
9825 		    goto encoding_error;
9826 		/* 4-byte code */
9827 		*len = 4;
9828 		val = (cur[0] & 0x7) << 18;
9829 		val |= (cur[1] & 0x3f) << 12;
9830 		val |= (cur[2] & 0x3f) << 6;
9831 		val |= cur[3] & 0x3f;
9832 	    } else {
9833 	      /* 3-byte code */
9834 		*len = 3;
9835 		val = (cur[0] & 0xf) << 12;
9836 		val |= (cur[1] & 0x3f) << 6;
9837 		val |= cur[2] & 0x3f;
9838 	    }
9839 	} else {
9840 	  /* 2-byte code */
9841 	    *len = 2;
9842 	    val = (cur[0] & 0x1f) << 6;
9843 	    val |= cur[1] & 0x3f;
9844 	}
9845 	if (!IS_CHAR(val)) {
9846 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9847 	}
9848 	return(val);
9849     } else {
9850 	/* 1-byte code */
9851 	*len = 1;
9852 	return((int) *cur);
9853     }
9854 encoding_error:
9855     /*
9856      * If we detect an UTF8 error that probably means that the
9857      * input encoding didn't get properly advertised in the
9858      * declaration header. Report the error and switch the encoding
9859      * to ISO-Latin-1 (if you don't like this policy, just declare the
9860      * encoding !)
9861      */
9862     *len = 0;
9863     XP_ERROR0(XPATH_ENCODING_ERROR);
9864 }
9865 
9866 /**
9867  * xmlXPathParseNCName:
9868  * @ctxt:  the XPath Parser context
9869  *
9870  * parse an XML namespace non qualified name.
9871  *
9872  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9873  *
9874  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9875  *                       CombiningChar | Extender
9876  *
9877  * Returns the namespace name or NULL
9878  */
9879 
9880 xmlChar *
9881 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9882     const xmlChar *in;
9883     xmlChar *ret;
9884     int count = 0;
9885 
9886     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9887     /*
9888      * Accelerator for simple ASCII names
9889      */
9890     in = ctxt->cur;
9891     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9892 	((*in >= 0x41) && (*in <= 0x5A)) ||
9893 	(*in == '_')) {
9894 	in++;
9895 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9896 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9897 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9898 	       (*in == '_') || (*in == '.') ||
9899 	       (*in == '-'))
9900 	    in++;
9901 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9902             (*in == '[') || (*in == ']') || (*in == ':') ||
9903             (*in == '@') || (*in == '*')) {
9904 	    count = in - ctxt->cur;
9905 	    if (count == 0)
9906 		return(NULL);
9907 	    ret = xmlStrndup(ctxt->cur, count);
9908 	    ctxt->cur = in;
9909 	    return(ret);
9910 	}
9911     }
9912     return(xmlXPathParseNameComplex(ctxt, 0));
9913 }
9914 
9915 
9916 /**
9917  * xmlXPathParseQName:
9918  * @ctxt:  the XPath Parser context
9919  * @prefix:  a xmlChar **
9920  *
9921  * parse an XML qualified name
9922  *
9923  * [NS 5] QName ::= (Prefix ':')? LocalPart
9924  *
9925  * [NS 6] Prefix ::= NCName
9926  *
9927  * [NS 7] LocalPart ::= NCName
9928  *
9929  * Returns the function returns the local part, and prefix is updated
9930  *   to get the Prefix if any.
9931  */
9932 
9933 static xmlChar *
9934 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9935     xmlChar *ret = NULL;
9936 
9937     *prefix = NULL;
9938     ret = xmlXPathParseNCName(ctxt);
9939     if (ret && CUR == ':') {
9940         *prefix = ret;
9941 	NEXT;
9942 	ret = xmlXPathParseNCName(ctxt);
9943     }
9944     return(ret);
9945 }
9946 
9947 /**
9948  * xmlXPathParseName:
9949  * @ctxt:  the XPath Parser context
9950  *
9951  * parse an XML name
9952  *
9953  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9954  *                  CombiningChar | Extender
9955  *
9956  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9957  *
9958  * Returns the namespace name or NULL
9959  */
9960 
9961 xmlChar *
9962 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9963     const xmlChar *in;
9964     xmlChar *ret;
9965     size_t count = 0;
9966 
9967     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9968     /*
9969      * Accelerator for simple ASCII names
9970      */
9971     in = ctxt->cur;
9972     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9973 	((*in >= 0x41) && (*in <= 0x5A)) ||
9974 	(*in == '_') || (*in == ':')) {
9975 	in++;
9976 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9977 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9978 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9979 	       (*in == '_') || (*in == '-') ||
9980 	       (*in == ':') || (*in == '.'))
9981 	    in++;
9982 	if ((*in > 0) && (*in < 0x80)) {
9983 	    count = in - ctxt->cur;
9984             if (count > XML_MAX_NAME_LENGTH) {
9985                 ctxt->cur = in;
9986                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9987             }
9988 	    ret = xmlStrndup(ctxt->cur, count);
9989 	    ctxt->cur = in;
9990 	    return(ret);
9991 	}
9992     }
9993     return(xmlXPathParseNameComplex(ctxt, 1));
9994 }
9995 
9996 static xmlChar *
9997 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9998     xmlChar buf[XML_MAX_NAMELEN + 5];
9999     int len = 0, l;
10000     int c;
10001 
10002     /*
10003      * Handler for more complex cases
10004      */
10005     c = CUR_CHAR(l);
10006     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10007         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
10008         (c == '*') || /* accelerators */
10009 	(!IS_LETTER(c) && (c != '_') &&
10010          ((!qualified) || (c != ':')))) {
10011 	return(NULL);
10012     }
10013 
10014     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10015 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10016             (c == '.') || (c == '-') ||
10017 	    (c == '_') || ((qualified) && (c == ':')) ||
10018 	    (IS_COMBINING(c)) ||
10019 	    (IS_EXTENDER(c)))) {
10020 	COPY_BUF(l,buf,len,c);
10021 	NEXTL(l);
10022 	c = CUR_CHAR(l);
10023 	if (len >= XML_MAX_NAMELEN) {
10024 	    /*
10025 	     * Okay someone managed to make a huge name, so he's ready to pay
10026 	     * for the processing speed.
10027 	     */
10028 	    xmlChar *buffer;
10029 	    int max = len * 2;
10030 
10031             if (len > XML_MAX_NAME_LENGTH) {
10032                 XP_ERRORNULL(XPATH_EXPR_ERROR);
10033             }
10034 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
10035 	    if (buffer == NULL) {
10036 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
10037 	    }
10038 	    memcpy(buffer, buf, len);
10039 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10040 		   (c == '.') || (c == '-') ||
10041 		   (c == '_') || ((qualified) && (c == ':')) ||
10042 		   (IS_COMBINING(c)) ||
10043 		   (IS_EXTENDER(c))) {
10044 		if (len + 10 > max) {
10045                     if (max > XML_MAX_NAME_LENGTH) {
10046                         XP_ERRORNULL(XPATH_EXPR_ERROR);
10047                     }
10048 		    max *= 2;
10049 		    buffer = (xmlChar *) xmlRealloc(buffer,
10050 			                            max * sizeof(xmlChar));
10051 		    if (buffer == NULL) {
10052 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
10053 		    }
10054 		}
10055 		COPY_BUF(l,buffer,len,c);
10056 		NEXTL(l);
10057 		c = CUR_CHAR(l);
10058 	    }
10059 	    buffer[len] = 0;
10060 	    return(buffer);
10061 	}
10062     }
10063     if (len == 0)
10064 	return(NULL);
10065     return(xmlStrndup(buf, len));
10066 }
10067 
10068 #define MAX_FRAC 20
10069 
10070 /**
10071  * xmlXPathStringEvalNumber:
10072  * @str:  A string to scan
10073  *
10074  *  [30a]  Float  ::= Number ('e' Digits?)?
10075  *
10076  *  [30]   Number ::=   Digits ('.' Digits?)?
10077  *                    | '.' Digits
10078  *  [31]   Digits ::=   [0-9]+
10079  *
10080  * Compile a Number in the string
10081  * In complement of the Number expression, this function also handles
10082  * negative values : '-' Number.
10083  *
10084  * Returns the double value.
10085  */
10086 double
10087 xmlXPathStringEvalNumber(const xmlChar *str) {
10088     const xmlChar *cur = str;
10089     double ret;
10090     int ok = 0;
10091     int isneg = 0;
10092     int exponent = 0;
10093     int is_exponent_negative = 0;
10094 #ifdef __GNUC__
10095     unsigned long tmp = 0;
10096     double temp;
10097 #endif
10098     if (cur == NULL) return(0);
10099     while (IS_BLANK_CH(*cur)) cur++;
10100     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10101         return(xmlXPathNAN);
10102     }
10103     if (*cur == '-') {
10104 	isneg = 1;
10105 	cur++;
10106     }
10107 
10108 #ifdef __GNUC__
10109     /*
10110      * tmp/temp is a workaround against a gcc compiler bug
10111      * http://veillard.com/gcc.bug
10112      */
10113     ret = 0;
10114     while ((*cur >= '0') && (*cur <= '9')) {
10115 	ret = ret * 10;
10116 	tmp = (*cur - '0');
10117 	ok = 1;
10118 	cur++;
10119 	temp = (double) tmp;
10120 	ret = ret + temp;
10121     }
10122 #else
10123     ret = 0;
10124     while ((*cur >= '0') && (*cur <= '9')) {
10125 	ret = ret * 10 + (*cur - '0');
10126 	ok = 1;
10127 	cur++;
10128     }
10129 #endif
10130 
10131     if (*cur == '.') {
10132 	int v, frac = 0, max;
10133 	double fraction = 0;
10134 
10135         cur++;
10136 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10137 	    return(xmlXPathNAN);
10138 	}
10139         while (*cur == '0') {
10140 	    frac = frac + 1;
10141 	    cur++;
10142         }
10143         max = frac + MAX_FRAC;
10144 	while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10145 	    v = (*cur - '0');
10146 	    fraction = fraction * 10 + v;
10147 	    frac = frac + 1;
10148 	    cur++;
10149 	}
10150 	fraction /= pow(10.0, frac);
10151 	ret = ret + fraction;
10152 	while ((*cur >= '0') && (*cur <= '9'))
10153 	    cur++;
10154     }
10155     if ((*cur == 'e') || (*cur == 'E')) {
10156       cur++;
10157       if (*cur == '-') {
10158 	is_exponent_negative = 1;
10159 	cur++;
10160       } else if (*cur == '+') {
10161         cur++;
10162       }
10163       while ((*cur >= '0') && (*cur <= '9')) {
10164         if (exponent < 1000000)
10165 	  exponent = exponent * 10 + (*cur - '0');
10166 	cur++;
10167       }
10168     }
10169     while (IS_BLANK_CH(*cur)) cur++;
10170     if (*cur != 0) return(xmlXPathNAN);
10171     if (isneg) ret = -ret;
10172     if (is_exponent_negative) exponent = -exponent;
10173     ret *= pow(10.0, (double)exponent);
10174     return(ret);
10175 }
10176 
10177 /**
10178  * xmlXPathCompNumber:
10179  * @ctxt:  the XPath Parser context
10180  *
10181  *  [30]   Number ::=   Digits ('.' Digits?)?
10182  *                    | '.' Digits
10183  *  [31]   Digits ::=   [0-9]+
10184  *
10185  * Compile a Number, then push it on the stack
10186  *
10187  */
10188 static void
10189 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10190 {
10191     double ret = 0.0;
10192     int ok = 0;
10193     int exponent = 0;
10194     int is_exponent_negative = 0;
10195 #ifdef __GNUC__
10196     unsigned long tmp = 0;
10197     double temp;
10198 #endif
10199 
10200     CHECK_ERROR;
10201     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10202         XP_ERROR(XPATH_NUMBER_ERROR);
10203     }
10204 #ifdef __GNUC__
10205     /*
10206      * tmp/temp is a workaround against a gcc compiler bug
10207      * http://veillard.com/gcc.bug
10208      */
10209     ret = 0;
10210     while ((CUR >= '0') && (CUR <= '9')) {
10211 	ret = ret * 10;
10212 	tmp = (CUR - '0');
10213         ok = 1;
10214         NEXT;
10215 	temp = (double) tmp;
10216 	ret = ret + temp;
10217     }
10218 #else
10219     ret = 0;
10220     while ((CUR >= '0') && (CUR <= '9')) {
10221 	ret = ret * 10 + (CUR - '0');
10222 	ok = 1;
10223 	NEXT;
10224     }
10225 #endif
10226     if (CUR == '.') {
10227 	int v, frac = 0, max;
10228 	double fraction = 0;
10229 
10230         NEXT;
10231         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10232             XP_ERROR(XPATH_NUMBER_ERROR);
10233         }
10234         while (CUR == '0') {
10235             frac = frac + 1;
10236             NEXT;
10237         }
10238         max = frac + MAX_FRAC;
10239         while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10240 	    v = (CUR - '0');
10241 	    fraction = fraction * 10 + v;
10242 	    frac = frac + 1;
10243             NEXT;
10244         }
10245         fraction /= pow(10.0, frac);
10246         ret = ret + fraction;
10247         while ((CUR >= '0') && (CUR <= '9'))
10248             NEXT;
10249     }
10250     if ((CUR == 'e') || (CUR == 'E')) {
10251         NEXT;
10252         if (CUR == '-') {
10253             is_exponent_negative = 1;
10254             NEXT;
10255         } else if (CUR == '+') {
10256 	    NEXT;
10257 	}
10258         while ((CUR >= '0') && (CUR <= '9')) {
10259             if (exponent < 1000000)
10260                 exponent = exponent * 10 + (CUR - '0');
10261             NEXT;
10262         }
10263         if (is_exponent_negative)
10264             exponent = -exponent;
10265         ret *= pow(10.0, (double) exponent);
10266     }
10267     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10268                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10269 }
10270 
10271 /**
10272  * xmlXPathParseLiteral:
10273  * @ctxt:  the XPath Parser context
10274  *
10275  * Parse a Literal
10276  *
10277  *  [29]   Literal ::=   '"' [^"]* '"'
10278  *                    | "'" [^']* "'"
10279  *
10280  * Returns the value found or NULL in case of error
10281  */
10282 static xmlChar *
10283 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10284     const xmlChar *q;
10285     xmlChar *ret = NULL;
10286 
10287     if (CUR == '"') {
10288         NEXT;
10289 	q = CUR_PTR;
10290 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10291 	    NEXT;
10292 	if (!IS_CHAR_CH(CUR)) {
10293 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10294 	} else {
10295 	    ret = xmlStrndup(q, CUR_PTR - q);
10296 	    NEXT;
10297         }
10298     } else if (CUR == '\'') {
10299         NEXT;
10300 	q = CUR_PTR;
10301 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10302 	    NEXT;
10303 	if (!IS_CHAR_CH(CUR)) {
10304 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10305 	} else {
10306 	    ret = xmlStrndup(q, CUR_PTR - q);
10307 	    NEXT;
10308         }
10309     } else {
10310 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10311     }
10312     return(ret);
10313 }
10314 
10315 /**
10316  * xmlXPathCompLiteral:
10317  * @ctxt:  the XPath Parser context
10318  *
10319  * Parse a Literal and push it on the stack.
10320  *
10321  *  [29]   Literal ::=   '"' [^"]* '"'
10322  *                    | "'" [^']* "'"
10323  *
10324  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10325  */
10326 static void
10327 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10328     const xmlChar *q;
10329     xmlChar *ret = NULL;
10330 
10331     if (CUR == '"') {
10332         NEXT;
10333 	q = CUR_PTR;
10334 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10335 	    NEXT;
10336 	if (!IS_CHAR_CH(CUR)) {
10337 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10338 	} else {
10339 	    ret = xmlStrndup(q, CUR_PTR - q);
10340 	    NEXT;
10341         }
10342     } else if (CUR == '\'') {
10343         NEXT;
10344 	q = CUR_PTR;
10345 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10346 	    NEXT;
10347 	if (!IS_CHAR_CH(CUR)) {
10348 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10349 	} else {
10350 	    ret = xmlStrndup(q, CUR_PTR - q);
10351 	    NEXT;
10352         }
10353     } else {
10354 	XP_ERROR(XPATH_START_LITERAL_ERROR);
10355     }
10356     if (ret == NULL) return;
10357     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10358 	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
10359     xmlFree(ret);
10360 }
10361 
10362 /**
10363  * xmlXPathCompVariableReference:
10364  * @ctxt:  the XPath Parser context
10365  *
10366  * Parse a VariableReference, evaluate it and push it on the stack.
10367  *
10368  * The variable bindings consist of a mapping from variable names
10369  * to variable values. The value of a variable is an object, which can be
10370  * of any of the types that are possible for the value of an expression,
10371  * and may also be of additional types not specified here.
10372  *
10373  * Early evaluation is possible since:
10374  * The variable bindings [...] used to evaluate a subexpression are
10375  * always the same as those used to evaluate the containing expression.
10376  *
10377  *  [36]   VariableReference ::=   '$' QName
10378  */
10379 static void
10380 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10381     xmlChar *name;
10382     xmlChar *prefix;
10383 
10384     SKIP_BLANKS;
10385     if (CUR != '$') {
10386 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10387     }
10388     NEXT;
10389     name = xmlXPathParseQName(ctxt, &prefix);
10390     if (name == NULL) {
10391         xmlFree(prefix);
10392 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10393     }
10394     ctxt->comp->last = -1;
10395     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10396 	           name, prefix);
10397     SKIP_BLANKS;
10398     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10399 	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10400     }
10401 }
10402 
10403 /**
10404  * xmlXPathIsNodeType:
10405  * @name:  a name string
10406  *
10407  * Is the name given a NodeType one.
10408  *
10409  *  [38]   NodeType ::=   'comment'
10410  *                    | 'text'
10411  *                    | 'processing-instruction'
10412  *                    | 'node'
10413  *
10414  * Returns 1 if true 0 otherwise
10415  */
10416 int
10417 xmlXPathIsNodeType(const xmlChar *name) {
10418     if (name == NULL)
10419 	return(0);
10420 
10421     if (xmlStrEqual(name, BAD_CAST "node"))
10422 	return(1);
10423     if (xmlStrEqual(name, BAD_CAST "text"))
10424 	return(1);
10425     if (xmlStrEqual(name, BAD_CAST "comment"))
10426 	return(1);
10427     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10428 	return(1);
10429     return(0);
10430 }
10431 
10432 /**
10433  * xmlXPathCompFunctionCall:
10434  * @ctxt:  the XPath Parser context
10435  *
10436  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10437  *  [17]   Argument ::=   Expr
10438  *
10439  * Compile a function call, the evaluation of all arguments are
10440  * pushed on the stack
10441  */
10442 static void
10443 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10444     xmlChar *name;
10445     xmlChar *prefix;
10446     int nbargs = 0;
10447     int sort = 1;
10448 
10449     name = xmlXPathParseQName(ctxt, &prefix);
10450     if (name == NULL) {
10451 	xmlFree(prefix);
10452 	XP_ERROR(XPATH_EXPR_ERROR);
10453     }
10454     SKIP_BLANKS;
10455 #ifdef DEBUG_EXPR
10456     if (prefix == NULL)
10457 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10458 			name);
10459     else
10460 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10461 			prefix, name);
10462 #endif
10463 
10464     if (CUR != '(') {
10465 	xmlFree(name);
10466 	xmlFree(prefix);
10467 	XP_ERROR(XPATH_EXPR_ERROR);
10468     }
10469     NEXT;
10470     SKIP_BLANKS;
10471 
10472     /*
10473     * Optimization for count(): we don't need the node-set to be sorted.
10474     */
10475     if ((prefix == NULL) && (name[0] == 'c') &&
10476 	xmlStrEqual(name, BAD_CAST "count"))
10477     {
10478 	sort = 0;
10479     }
10480     ctxt->comp->last = -1;
10481     if (CUR != ')') {
10482 	while (CUR != 0) {
10483 	    int op1 = ctxt->comp->last;
10484 	    ctxt->comp->last = -1;
10485 	    xmlXPathCompileExpr(ctxt, sort);
10486 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10487 		xmlFree(name);
10488 		xmlFree(prefix);
10489 		return;
10490 	    }
10491 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10492 	    nbargs++;
10493 	    if (CUR == ')') break;
10494 	    if (CUR != ',') {
10495 		xmlFree(name);
10496 		xmlFree(prefix);
10497 		XP_ERROR(XPATH_EXPR_ERROR);
10498 	    }
10499 	    NEXT;
10500 	    SKIP_BLANKS;
10501 	}
10502     }
10503     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10504 	           name, prefix);
10505     NEXT;
10506     SKIP_BLANKS;
10507 }
10508 
10509 /**
10510  * xmlXPathCompPrimaryExpr:
10511  * @ctxt:  the XPath Parser context
10512  *
10513  *  [15]   PrimaryExpr ::=   VariableReference
10514  *                | '(' Expr ')'
10515  *                | Literal
10516  *                | Number
10517  *                | FunctionCall
10518  *
10519  * Compile a primary expression.
10520  */
10521 static void
10522 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10523     SKIP_BLANKS;
10524     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10525     else if (CUR == '(') {
10526 	NEXT;
10527 	SKIP_BLANKS;
10528 	xmlXPathCompileExpr(ctxt, 1);
10529 	CHECK_ERROR;
10530 	if (CUR != ')') {
10531 	    XP_ERROR(XPATH_EXPR_ERROR);
10532 	}
10533 	NEXT;
10534 	SKIP_BLANKS;
10535     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10536 	xmlXPathCompNumber(ctxt);
10537     } else if ((CUR == '\'') || (CUR == '"')) {
10538 	xmlXPathCompLiteral(ctxt);
10539     } else {
10540 	xmlXPathCompFunctionCall(ctxt);
10541     }
10542     SKIP_BLANKS;
10543 }
10544 
10545 /**
10546  * xmlXPathCompFilterExpr:
10547  * @ctxt:  the XPath Parser context
10548  *
10549  *  [20]   FilterExpr ::=   PrimaryExpr
10550  *               | FilterExpr Predicate
10551  *
10552  * Compile a filter expression.
10553  * Square brackets are used to filter expressions in the same way that
10554  * they are used in location paths. It is an error if the expression to
10555  * be filtered does not evaluate to a node-set. The context node list
10556  * used for evaluating the expression in square brackets is the node-set
10557  * to be filtered listed in document order.
10558  */
10559 
10560 static void
10561 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10562     xmlXPathCompPrimaryExpr(ctxt);
10563     CHECK_ERROR;
10564     SKIP_BLANKS;
10565 
10566     while (CUR == '[') {
10567 	xmlXPathCompPredicate(ctxt, 1);
10568 	SKIP_BLANKS;
10569     }
10570 
10571 
10572 }
10573 
10574 /**
10575  * xmlXPathScanName:
10576  * @ctxt:  the XPath Parser context
10577  *
10578  * Trickery: parse an XML name but without consuming the input flow
10579  * Needed to avoid insanity in the parser state.
10580  *
10581  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10582  *                  CombiningChar | Extender
10583  *
10584  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10585  *
10586  * [6] Names ::= Name (S Name)*
10587  *
10588  * Returns the Name parsed or NULL
10589  */
10590 
10591 static xmlChar *
10592 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10593     int len = 0, l;
10594     int c;
10595     const xmlChar *cur;
10596     xmlChar *ret;
10597 
10598     cur = ctxt->cur;
10599 
10600     c = CUR_CHAR(l);
10601     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10602 	(!IS_LETTER(c) && (c != '_') &&
10603          (c != ':'))) {
10604 	return(NULL);
10605     }
10606 
10607     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10608 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10609             (c == '.') || (c == '-') ||
10610 	    (c == '_') || (c == ':') ||
10611 	    (IS_COMBINING(c)) ||
10612 	    (IS_EXTENDER(c)))) {
10613 	len += l;
10614 	NEXTL(l);
10615 	c = CUR_CHAR(l);
10616     }
10617     ret = xmlStrndup(cur, ctxt->cur - cur);
10618     ctxt->cur = cur;
10619     return(ret);
10620 }
10621 
10622 /**
10623  * xmlXPathCompPathExpr:
10624  * @ctxt:  the XPath Parser context
10625  *
10626  *  [19]   PathExpr ::=   LocationPath
10627  *               | FilterExpr
10628  *               | FilterExpr '/' RelativeLocationPath
10629  *               | FilterExpr '//' RelativeLocationPath
10630  *
10631  * Compile a path expression.
10632  * The / operator and // operators combine an arbitrary expression
10633  * and a relative location path. It is an error if the expression
10634  * does not evaluate to a node-set.
10635  * The / operator does composition in the same way as when / is
10636  * used in a location path. As in location paths, // is short for
10637  * /descendant-or-self::node()/.
10638  */
10639 
10640 static void
10641 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10642     int lc = 1;           /* Should we branch to LocationPath ?         */
10643     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10644 
10645     SKIP_BLANKS;
10646     if ((CUR == '$') || (CUR == '(') ||
10647 	(IS_ASCII_DIGIT(CUR)) ||
10648         (CUR == '\'') || (CUR == '"') ||
10649 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10650 	lc = 0;
10651     } else if (CUR == '*') {
10652 	/* relative or absolute location path */
10653 	lc = 1;
10654     } else if (CUR == '/') {
10655 	/* relative or absolute location path */
10656 	lc = 1;
10657     } else if (CUR == '@') {
10658 	/* relative abbreviated attribute location path */
10659 	lc = 1;
10660     } else if (CUR == '.') {
10661 	/* relative abbreviated attribute location path */
10662 	lc = 1;
10663     } else {
10664 	/*
10665 	 * Problem is finding if we have a name here whether it's:
10666 	 *   - a nodetype
10667 	 *   - a function call in which case it's followed by '('
10668 	 *   - an axis in which case it's followed by ':'
10669 	 *   - a element name
10670 	 * We do an a priori analysis here rather than having to
10671 	 * maintain parsed token content through the recursive function
10672 	 * calls. This looks uglier but makes the code easier to
10673 	 * read/write/debug.
10674 	 */
10675 	SKIP_BLANKS;
10676 	name = xmlXPathScanName(ctxt);
10677 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10678 #ifdef DEBUG_STEP
10679 	    xmlGenericError(xmlGenericErrorContext,
10680 		    "PathExpr: Axis\n");
10681 #endif
10682 	    lc = 1;
10683 	    xmlFree(name);
10684 	} else if (name != NULL) {
10685 	    int len =xmlStrlen(name);
10686 
10687 
10688 	    while (NXT(len) != 0) {
10689 		if (NXT(len) == '/') {
10690 		    /* element name */
10691 #ifdef DEBUG_STEP
10692 		    xmlGenericError(xmlGenericErrorContext,
10693 			    "PathExpr: AbbrRelLocation\n");
10694 #endif
10695 		    lc = 1;
10696 		    break;
10697 		} else if (IS_BLANK_CH(NXT(len))) {
10698 		    /* ignore blanks */
10699 		    ;
10700 		} else if (NXT(len) == ':') {
10701 #ifdef DEBUG_STEP
10702 		    xmlGenericError(xmlGenericErrorContext,
10703 			    "PathExpr: AbbrRelLocation\n");
10704 #endif
10705 		    lc = 1;
10706 		    break;
10707 		} else if ((NXT(len) == '(')) {
10708 		    /* Node Type or Function */
10709 		    if (xmlXPathIsNodeType(name)) {
10710 #ifdef DEBUG_STEP
10711 		        xmlGenericError(xmlGenericErrorContext,
10712 				"PathExpr: Type search\n");
10713 #endif
10714 			lc = 1;
10715 #ifdef LIBXML_XPTR_ENABLED
10716                     } else if (ctxt->xptr &&
10717                                xmlStrEqual(name, BAD_CAST "range-to")) {
10718                         lc = 1;
10719 #endif
10720 		    } else {
10721 #ifdef DEBUG_STEP
10722 		        xmlGenericError(xmlGenericErrorContext,
10723 				"PathExpr: function call\n");
10724 #endif
10725 			lc = 0;
10726 		    }
10727                     break;
10728 		} else if ((NXT(len) == '[')) {
10729 		    /* element name */
10730 #ifdef DEBUG_STEP
10731 		    xmlGenericError(xmlGenericErrorContext,
10732 			    "PathExpr: AbbrRelLocation\n");
10733 #endif
10734 		    lc = 1;
10735 		    break;
10736 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10737 			   (NXT(len) == '=')) {
10738 		    lc = 1;
10739 		    break;
10740 		} else {
10741 		    lc = 1;
10742 		    break;
10743 		}
10744 		len++;
10745 	    }
10746 	    if (NXT(len) == 0) {
10747 #ifdef DEBUG_STEP
10748 		xmlGenericError(xmlGenericErrorContext,
10749 			"PathExpr: AbbrRelLocation\n");
10750 #endif
10751 		/* element name */
10752 		lc = 1;
10753 	    }
10754 	    xmlFree(name);
10755 	} else {
10756 	    /* make sure all cases are covered explicitly */
10757 	    XP_ERROR(XPATH_EXPR_ERROR);
10758 	}
10759     }
10760 
10761     if (lc) {
10762 	if (CUR == '/') {
10763 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10764 	} else {
10765 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10766 	}
10767 	xmlXPathCompLocationPath(ctxt);
10768     } else {
10769 	xmlXPathCompFilterExpr(ctxt);
10770 	CHECK_ERROR;
10771 	if ((CUR == '/') && (NXT(1) == '/')) {
10772 	    SKIP(2);
10773 	    SKIP_BLANKS;
10774 
10775 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10776 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10777 	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10778 
10779 	    xmlXPathCompRelativeLocationPath(ctxt);
10780 	} else if (CUR == '/') {
10781 	    xmlXPathCompRelativeLocationPath(ctxt);
10782 	}
10783     }
10784     SKIP_BLANKS;
10785 }
10786 
10787 /**
10788  * xmlXPathCompUnionExpr:
10789  * @ctxt:  the XPath Parser context
10790  *
10791  *  [18]   UnionExpr ::=   PathExpr
10792  *               | UnionExpr '|' PathExpr
10793  *
10794  * Compile an union expression.
10795  */
10796 
10797 static void
10798 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10799     xmlXPathCompPathExpr(ctxt);
10800     CHECK_ERROR;
10801     SKIP_BLANKS;
10802     while (CUR == '|') {
10803 	int op1 = ctxt->comp->last;
10804 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10805 
10806 	NEXT;
10807 	SKIP_BLANKS;
10808 	xmlXPathCompPathExpr(ctxt);
10809 
10810 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10811 
10812 	SKIP_BLANKS;
10813     }
10814 }
10815 
10816 /**
10817  * xmlXPathCompUnaryExpr:
10818  * @ctxt:  the XPath Parser context
10819  *
10820  *  [27]   UnaryExpr ::=   UnionExpr
10821  *                   | '-' UnaryExpr
10822  *
10823  * Compile an unary expression.
10824  */
10825 
10826 static void
10827 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10828     int minus = 0;
10829     int found = 0;
10830 
10831     SKIP_BLANKS;
10832     while (CUR == '-') {
10833         minus = 1 - minus;
10834 	found = 1;
10835 	NEXT;
10836 	SKIP_BLANKS;
10837     }
10838 
10839     xmlXPathCompUnionExpr(ctxt);
10840     CHECK_ERROR;
10841     if (found) {
10842 	if (minus)
10843 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10844 	else
10845 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10846     }
10847 }
10848 
10849 /**
10850  * xmlXPathCompMultiplicativeExpr:
10851  * @ctxt:  the XPath Parser context
10852  *
10853  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10854  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10855  *                   | MultiplicativeExpr 'div' UnaryExpr
10856  *                   | MultiplicativeExpr 'mod' UnaryExpr
10857  *  [34]   MultiplyOperator ::=   '*'
10858  *
10859  * Compile an Additive expression.
10860  */
10861 
10862 static void
10863 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10864     xmlXPathCompUnaryExpr(ctxt);
10865     CHECK_ERROR;
10866     SKIP_BLANKS;
10867     while ((CUR == '*') ||
10868            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10869            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10870 	int op = -1;
10871 	int op1 = ctxt->comp->last;
10872 
10873         if (CUR == '*') {
10874 	    op = 0;
10875 	    NEXT;
10876 	} else if (CUR == 'd') {
10877 	    op = 1;
10878 	    SKIP(3);
10879 	} else if (CUR == 'm') {
10880 	    op = 2;
10881 	    SKIP(3);
10882 	}
10883 	SKIP_BLANKS;
10884         xmlXPathCompUnaryExpr(ctxt);
10885 	CHECK_ERROR;
10886 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10887 	SKIP_BLANKS;
10888     }
10889 }
10890 
10891 /**
10892  * xmlXPathCompAdditiveExpr:
10893  * @ctxt:  the XPath Parser context
10894  *
10895  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10896  *                   | AdditiveExpr '+' MultiplicativeExpr
10897  *                   | AdditiveExpr '-' MultiplicativeExpr
10898  *
10899  * Compile an Additive expression.
10900  */
10901 
10902 static void
10903 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10904 
10905     xmlXPathCompMultiplicativeExpr(ctxt);
10906     CHECK_ERROR;
10907     SKIP_BLANKS;
10908     while ((CUR == '+') || (CUR == '-')) {
10909 	int plus;
10910 	int op1 = ctxt->comp->last;
10911 
10912         if (CUR == '+') plus = 1;
10913 	else plus = 0;
10914 	NEXT;
10915 	SKIP_BLANKS;
10916         xmlXPathCompMultiplicativeExpr(ctxt);
10917 	CHECK_ERROR;
10918 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10919 	SKIP_BLANKS;
10920     }
10921 }
10922 
10923 /**
10924  * xmlXPathCompRelationalExpr:
10925  * @ctxt:  the XPath Parser context
10926  *
10927  *  [24]   RelationalExpr ::=   AdditiveExpr
10928  *                 | RelationalExpr '<' AdditiveExpr
10929  *                 | RelationalExpr '>' AdditiveExpr
10930  *                 | RelationalExpr '<=' AdditiveExpr
10931  *                 | RelationalExpr '>=' AdditiveExpr
10932  *
10933  *  A <= B > C is allowed ? Answer from James, yes with
10934  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10935  *  which is basically what got implemented.
10936  *
10937  * Compile a Relational expression, then push the result
10938  * on the stack
10939  */
10940 
10941 static void
10942 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10943     xmlXPathCompAdditiveExpr(ctxt);
10944     CHECK_ERROR;
10945     SKIP_BLANKS;
10946     while ((CUR == '<') ||
10947            (CUR == '>') ||
10948            ((CUR == '<') && (NXT(1) == '=')) ||
10949            ((CUR == '>') && (NXT(1) == '='))) {
10950 	int inf, strict;
10951 	int op1 = ctxt->comp->last;
10952 
10953         if (CUR == '<') inf = 1;
10954 	else inf = 0;
10955 	if (NXT(1) == '=') strict = 0;
10956 	else strict = 1;
10957 	NEXT;
10958 	if (!strict) NEXT;
10959 	SKIP_BLANKS;
10960         xmlXPathCompAdditiveExpr(ctxt);
10961 	CHECK_ERROR;
10962 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10963 	SKIP_BLANKS;
10964     }
10965 }
10966 
10967 /**
10968  * xmlXPathCompEqualityExpr:
10969  * @ctxt:  the XPath Parser context
10970  *
10971  *  [23]   EqualityExpr ::=   RelationalExpr
10972  *                 | EqualityExpr '=' RelationalExpr
10973  *                 | EqualityExpr '!=' RelationalExpr
10974  *
10975  *  A != B != C is allowed ? Answer from James, yes with
10976  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10977  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10978  *  which is basically what got implemented.
10979  *
10980  * Compile an Equality expression.
10981  *
10982  */
10983 static void
10984 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10985     xmlXPathCompRelationalExpr(ctxt);
10986     CHECK_ERROR;
10987     SKIP_BLANKS;
10988     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10989 	int eq;
10990 	int op1 = ctxt->comp->last;
10991 
10992         if (CUR == '=') eq = 1;
10993 	else eq = 0;
10994 	NEXT;
10995 	if (!eq) NEXT;
10996 	SKIP_BLANKS;
10997         xmlXPathCompRelationalExpr(ctxt);
10998 	CHECK_ERROR;
10999 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
11000 	SKIP_BLANKS;
11001     }
11002 }
11003 
11004 /**
11005  * xmlXPathCompAndExpr:
11006  * @ctxt:  the XPath Parser context
11007  *
11008  *  [22]   AndExpr ::=   EqualityExpr
11009  *                 | AndExpr 'and' EqualityExpr
11010  *
11011  * Compile an AND expression.
11012  *
11013  */
11014 static void
11015 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
11016     xmlXPathCompEqualityExpr(ctxt);
11017     CHECK_ERROR;
11018     SKIP_BLANKS;
11019     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
11020 	int op1 = ctxt->comp->last;
11021         SKIP(3);
11022 	SKIP_BLANKS;
11023         xmlXPathCompEqualityExpr(ctxt);
11024 	CHECK_ERROR;
11025 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
11026 	SKIP_BLANKS;
11027     }
11028 }
11029 
11030 /**
11031  * xmlXPathCompileExpr:
11032  * @ctxt:  the XPath Parser context
11033  *
11034  *  [14]   Expr ::=   OrExpr
11035  *  [21]   OrExpr ::=   AndExpr
11036  *                 | OrExpr 'or' AndExpr
11037  *
11038  * Parse and compile an expression
11039  */
11040 static void
11041 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11042     xmlXPathCompAndExpr(ctxt);
11043     CHECK_ERROR;
11044     SKIP_BLANKS;
11045     while ((CUR == 'o') && (NXT(1) == 'r')) {
11046 	int op1 = ctxt->comp->last;
11047         SKIP(2);
11048 	SKIP_BLANKS;
11049         xmlXPathCompAndExpr(ctxt);
11050 	CHECK_ERROR;
11051 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11052 	SKIP_BLANKS;
11053     }
11054     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11055 	/* more ops could be optimized too */
11056 	/*
11057 	* This is the main place to eliminate sorting for
11058 	* operations which don't require a sorted node-set.
11059 	* E.g. count().
11060 	*/
11061 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11062     }
11063 }
11064 
11065 /**
11066  * xmlXPathCompPredicate:
11067  * @ctxt:  the XPath Parser context
11068  * @filter:  act as a filter
11069  *
11070  *  [8]   Predicate ::=   '[' PredicateExpr ']'
11071  *  [9]   PredicateExpr ::=   Expr
11072  *
11073  * Compile a predicate expression
11074  */
11075 static void
11076 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11077     int op1 = ctxt->comp->last;
11078 
11079     SKIP_BLANKS;
11080     if (CUR != '[') {
11081 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11082     }
11083     NEXT;
11084     SKIP_BLANKS;
11085 
11086     ctxt->comp->last = -1;
11087     /*
11088     * This call to xmlXPathCompileExpr() will deactivate sorting
11089     * of the predicate result.
11090     * TODO: Sorting is still activated for filters, since I'm not
11091     *  sure if needed. Normally sorting should not be needed, since
11092     *  a filter can only diminish the number of items in a sequence,
11093     *  but won't change its order; so if the initial sequence is sorted,
11094     *  subsequent sorting is not needed.
11095     */
11096     if (! filter)
11097 	xmlXPathCompileExpr(ctxt, 0);
11098     else
11099 	xmlXPathCompileExpr(ctxt, 1);
11100     CHECK_ERROR;
11101 
11102     if (CUR != ']') {
11103 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11104     }
11105 
11106     if (filter)
11107 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11108     else
11109 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11110 
11111     NEXT;
11112     SKIP_BLANKS;
11113 }
11114 
11115 /**
11116  * xmlXPathCompNodeTest:
11117  * @ctxt:  the XPath Parser context
11118  * @test:  pointer to a xmlXPathTestVal
11119  * @type:  pointer to a xmlXPathTypeVal
11120  * @prefix:  placeholder for a possible name prefix
11121  *
11122  * [7] NodeTest ::=   NameTest
11123  *		    | NodeType '(' ')'
11124  *		    | 'processing-instruction' '(' Literal ')'
11125  *
11126  * [37] NameTest ::=  '*'
11127  *		    | NCName ':' '*'
11128  *		    | QName
11129  * [38] NodeType ::= 'comment'
11130  *		   | 'text'
11131  *		   | 'processing-instruction'
11132  *		   | 'node'
11133  *
11134  * Returns the name found and updates @test, @type and @prefix appropriately
11135  */
11136 static xmlChar *
11137 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11138 	             xmlXPathTypeVal *type, const xmlChar **prefix,
11139 		     xmlChar *name) {
11140     int blanks;
11141 
11142     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11143 	STRANGE;
11144 	return(NULL);
11145     }
11146     *type = (xmlXPathTypeVal) 0;
11147     *test = (xmlXPathTestVal) 0;
11148     *prefix = NULL;
11149     SKIP_BLANKS;
11150 
11151     if ((name == NULL) && (CUR == '*')) {
11152 	/*
11153 	 * All elements
11154 	 */
11155 	NEXT;
11156 	*test = NODE_TEST_ALL;
11157 	return(NULL);
11158     }
11159 
11160     if (name == NULL)
11161 	name = xmlXPathParseNCName(ctxt);
11162     if (name == NULL) {
11163 	XP_ERRORNULL(XPATH_EXPR_ERROR);
11164     }
11165 
11166     blanks = IS_BLANK_CH(CUR);
11167     SKIP_BLANKS;
11168     if (CUR == '(') {
11169 	NEXT;
11170 	/*
11171 	 * NodeType or PI search
11172 	 */
11173 	if (xmlStrEqual(name, BAD_CAST "comment"))
11174 	    *type = NODE_TYPE_COMMENT;
11175 	else if (xmlStrEqual(name, BAD_CAST "node"))
11176 	    *type = NODE_TYPE_NODE;
11177 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11178 	    *type = NODE_TYPE_PI;
11179 	else if (xmlStrEqual(name, BAD_CAST "text"))
11180 	    *type = NODE_TYPE_TEXT;
11181 	else {
11182 	    if (name != NULL)
11183 		xmlFree(name);
11184 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11185 	}
11186 
11187 	*test = NODE_TEST_TYPE;
11188 
11189 	SKIP_BLANKS;
11190 	if (*type == NODE_TYPE_PI) {
11191 	    /*
11192 	     * Specific case: search a PI by name.
11193 	     */
11194 	    if (name != NULL)
11195 		xmlFree(name);
11196 	    name = NULL;
11197 	    if (CUR != ')') {
11198 		name = xmlXPathParseLiteral(ctxt);
11199 		CHECK_ERROR NULL;
11200 		*test = NODE_TEST_PI;
11201 		SKIP_BLANKS;
11202 	    }
11203 	}
11204 	if (CUR != ')') {
11205 	    if (name != NULL)
11206 		xmlFree(name);
11207 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11208 	}
11209 	NEXT;
11210 	return(name);
11211     }
11212     *test = NODE_TEST_NAME;
11213     if ((!blanks) && (CUR == ':')) {
11214 	NEXT;
11215 
11216 	/*
11217 	 * Since currently the parser context don't have a
11218 	 * namespace list associated:
11219 	 * The namespace name for this prefix can be computed
11220 	 * only at evaluation time. The compilation is done
11221 	 * outside of any context.
11222 	 */
11223 #if 0
11224 	*prefix = xmlXPathNsLookup(ctxt->context, name);
11225 	if (name != NULL)
11226 	    xmlFree(name);
11227 	if (*prefix == NULL) {
11228 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11229 	}
11230 #else
11231 	*prefix = name;
11232 #endif
11233 
11234 	if (CUR == '*') {
11235 	    /*
11236 	     * All elements
11237 	     */
11238 	    NEXT;
11239 	    *test = NODE_TEST_ALL;
11240 	    return(NULL);
11241 	}
11242 
11243 	name = xmlXPathParseNCName(ctxt);
11244 	if (name == NULL) {
11245 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11246 	}
11247     }
11248     return(name);
11249 }
11250 
11251 /**
11252  * xmlXPathIsAxisName:
11253  * @name:  a preparsed name token
11254  *
11255  * [6] AxisName ::=   'ancestor'
11256  *                  | 'ancestor-or-self'
11257  *                  | 'attribute'
11258  *                  | 'child'
11259  *                  | 'descendant'
11260  *                  | 'descendant-or-self'
11261  *                  | 'following'
11262  *                  | 'following-sibling'
11263  *                  | 'namespace'
11264  *                  | 'parent'
11265  *                  | 'preceding'
11266  *                  | 'preceding-sibling'
11267  *                  | 'self'
11268  *
11269  * Returns the axis or 0
11270  */
11271 static xmlXPathAxisVal
11272 xmlXPathIsAxisName(const xmlChar *name) {
11273     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11274     switch (name[0]) {
11275 	case 'a':
11276 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11277 		ret = AXIS_ANCESTOR;
11278 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11279 		ret = AXIS_ANCESTOR_OR_SELF;
11280 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11281 		ret = AXIS_ATTRIBUTE;
11282 	    break;
11283 	case 'c':
11284 	    if (xmlStrEqual(name, BAD_CAST "child"))
11285 		ret = AXIS_CHILD;
11286 	    break;
11287 	case 'd':
11288 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11289 		ret = AXIS_DESCENDANT;
11290 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11291 		ret = AXIS_DESCENDANT_OR_SELF;
11292 	    break;
11293 	case 'f':
11294 	    if (xmlStrEqual(name, BAD_CAST "following"))
11295 		ret = AXIS_FOLLOWING;
11296 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11297 		ret = AXIS_FOLLOWING_SIBLING;
11298 	    break;
11299 	case 'n':
11300 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11301 		ret = AXIS_NAMESPACE;
11302 	    break;
11303 	case 'p':
11304 	    if (xmlStrEqual(name, BAD_CAST "parent"))
11305 		ret = AXIS_PARENT;
11306 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11307 		ret = AXIS_PRECEDING;
11308 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11309 		ret = AXIS_PRECEDING_SIBLING;
11310 	    break;
11311 	case 's':
11312 	    if (xmlStrEqual(name, BAD_CAST "self"))
11313 		ret = AXIS_SELF;
11314 	    break;
11315     }
11316     return(ret);
11317 }
11318 
11319 /**
11320  * xmlXPathCompStep:
11321  * @ctxt:  the XPath Parser context
11322  *
11323  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11324  *                  | AbbreviatedStep
11325  *
11326  * [12] AbbreviatedStep ::=   '.' | '..'
11327  *
11328  * [5] AxisSpecifier ::= AxisName '::'
11329  *                  | AbbreviatedAxisSpecifier
11330  *
11331  * [13] AbbreviatedAxisSpecifier ::= '@'?
11332  *
11333  * Modified for XPtr range support as:
11334  *
11335  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11336  *                     | AbbreviatedStep
11337  *                     | 'range-to' '(' Expr ')' Predicate*
11338  *
11339  * Compile one step in a Location Path
11340  * A location step of . is short for self::node(). This is
11341  * particularly useful in conjunction with //. For example, the
11342  * location path .//para is short for
11343  * self::node()/descendant-or-self::node()/child::para
11344  * and so will select all para descendant elements of the context
11345  * node.
11346  * Similarly, a location step of .. is short for parent::node().
11347  * For example, ../title is short for parent::node()/child::title
11348  * and so will select the title children of the parent of the context
11349  * node.
11350  */
11351 static void
11352 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11353 #ifdef LIBXML_XPTR_ENABLED
11354     int rangeto = 0;
11355     int op2 = -1;
11356 #endif
11357 
11358     SKIP_BLANKS;
11359     if ((CUR == '.') && (NXT(1) == '.')) {
11360 	SKIP(2);
11361 	SKIP_BLANKS;
11362 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11363 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11364     } else if (CUR == '.') {
11365 	NEXT;
11366 	SKIP_BLANKS;
11367     } else {
11368 	xmlChar *name = NULL;
11369 	const xmlChar *prefix = NULL;
11370 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11371 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11372 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11373 	int op1;
11374 
11375 	/*
11376 	 * The modification needed for XPointer change to the production
11377 	 */
11378 #ifdef LIBXML_XPTR_ENABLED
11379 	if (ctxt->xptr) {
11380 	    name = xmlXPathParseNCName(ctxt);
11381 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11382                 op2 = ctxt->comp->last;
11383 		xmlFree(name);
11384 		SKIP_BLANKS;
11385 		if (CUR != '(') {
11386 		    XP_ERROR(XPATH_EXPR_ERROR);
11387 		}
11388 		NEXT;
11389 		SKIP_BLANKS;
11390 
11391 		xmlXPathCompileExpr(ctxt, 1);
11392 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11393 		CHECK_ERROR;
11394 
11395 		SKIP_BLANKS;
11396 		if (CUR != ')') {
11397 		    XP_ERROR(XPATH_EXPR_ERROR);
11398 		}
11399 		NEXT;
11400 		rangeto = 1;
11401 		goto eval_predicates;
11402 	    }
11403 	}
11404 #endif
11405 	if (CUR == '*') {
11406 	    axis = AXIS_CHILD;
11407 	} else {
11408 	    if (name == NULL)
11409 		name = xmlXPathParseNCName(ctxt);
11410 	    if (name != NULL) {
11411 		axis = xmlXPathIsAxisName(name);
11412 		if (axis != 0) {
11413 		    SKIP_BLANKS;
11414 		    if ((CUR == ':') && (NXT(1) == ':')) {
11415 			SKIP(2);
11416 			xmlFree(name);
11417 			name = NULL;
11418 		    } else {
11419 			/* an element name can conflict with an axis one :-\ */
11420 			axis = AXIS_CHILD;
11421 		    }
11422 		} else {
11423 		    axis = AXIS_CHILD;
11424 		}
11425 	    } else if (CUR == '@') {
11426 		NEXT;
11427 		axis = AXIS_ATTRIBUTE;
11428 	    } else {
11429 		axis = AXIS_CHILD;
11430 	    }
11431 	}
11432 
11433         if (ctxt->error != XPATH_EXPRESSION_OK) {
11434             xmlFree(name);
11435             return;
11436         }
11437 
11438 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11439 	if (test == 0)
11440 	    return;
11441 
11442         if ((prefix != NULL) && (ctxt->context != NULL) &&
11443 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11444 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11445 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11446 	    }
11447 	}
11448 #ifdef DEBUG_STEP
11449 	xmlGenericError(xmlGenericErrorContext,
11450 		"Basis : computing new set\n");
11451 #endif
11452 
11453 #ifdef DEBUG_STEP
11454 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11455 	if (ctxt->value == NULL)
11456 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11457 	else if (ctxt->value->nodesetval == NULL)
11458 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11459 	else
11460 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11461 #endif
11462 
11463 #ifdef LIBXML_XPTR_ENABLED
11464 eval_predicates:
11465 #endif
11466 	op1 = ctxt->comp->last;
11467 	ctxt->comp->last = -1;
11468 
11469 	SKIP_BLANKS;
11470 	while (CUR == '[') {
11471 	    xmlXPathCompPredicate(ctxt, 0);
11472 	}
11473 
11474 #ifdef LIBXML_XPTR_ENABLED
11475 	if (rangeto) {
11476 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11477 	} else
11478 #endif
11479 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11480 			   test, type, (void *)prefix, (void *)name);
11481 
11482     }
11483 #ifdef DEBUG_STEP
11484     xmlGenericError(xmlGenericErrorContext, "Step : ");
11485     if (ctxt->value == NULL)
11486 	xmlGenericError(xmlGenericErrorContext, "no value\n");
11487     else if (ctxt->value->nodesetval == NULL)
11488 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11489     else
11490 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11491 		ctxt->value->nodesetval);
11492 #endif
11493 }
11494 
11495 /**
11496  * xmlXPathCompRelativeLocationPath:
11497  * @ctxt:  the XPath Parser context
11498  *
11499  *  [3]   RelativeLocationPath ::=   Step
11500  *                     | RelativeLocationPath '/' Step
11501  *                     | AbbreviatedRelativeLocationPath
11502  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11503  *
11504  * Compile a relative location path.
11505  */
11506 static void
11507 xmlXPathCompRelativeLocationPath
11508 (xmlXPathParserContextPtr ctxt) {
11509     SKIP_BLANKS;
11510     if ((CUR == '/') && (NXT(1) == '/')) {
11511 	SKIP(2);
11512 	SKIP_BLANKS;
11513 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11514 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11515     } else if (CUR == '/') {
11516 	    NEXT;
11517 	SKIP_BLANKS;
11518     }
11519     xmlXPathCompStep(ctxt);
11520     CHECK_ERROR;
11521     SKIP_BLANKS;
11522     while (CUR == '/') {
11523 	if ((CUR == '/') && (NXT(1) == '/')) {
11524 	    SKIP(2);
11525 	    SKIP_BLANKS;
11526 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11527 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11528 	    xmlXPathCompStep(ctxt);
11529 	} else if (CUR == '/') {
11530 	    NEXT;
11531 	    SKIP_BLANKS;
11532 	    xmlXPathCompStep(ctxt);
11533 	}
11534 	SKIP_BLANKS;
11535     }
11536 }
11537 
11538 /**
11539  * xmlXPathCompLocationPath:
11540  * @ctxt:  the XPath Parser context
11541  *
11542  *  [1]   LocationPath ::=   RelativeLocationPath
11543  *                     | AbsoluteLocationPath
11544  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11545  *                     | AbbreviatedAbsoluteLocationPath
11546  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11547  *                           '//' RelativeLocationPath
11548  *
11549  * Compile a location path
11550  *
11551  * // is short for /descendant-or-self::node()/. For example,
11552  * //para is short for /descendant-or-self::node()/child::para and
11553  * so will select any para element in the document (even a para element
11554  * that is a document element will be selected by //para since the
11555  * document element node is a child of the root node); div//para is
11556  * short for div/descendant-or-self::node()/child::para and so will
11557  * select all para descendants of div children.
11558  */
11559 static void
11560 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11561     SKIP_BLANKS;
11562     if (CUR != '/') {
11563         xmlXPathCompRelativeLocationPath(ctxt);
11564     } else {
11565 	while (CUR == '/') {
11566 	    if ((CUR == '/') && (NXT(1) == '/')) {
11567 		SKIP(2);
11568 		SKIP_BLANKS;
11569 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11570 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11571 		xmlXPathCompRelativeLocationPath(ctxt);
11572 	    } else if (CUR == '/') {
11573 		NEXT;
11574 		SKIP_BLANKS;
11575 		if ((CUR != 0 ) &&
11576 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11577 		     (CUR == '@') || (CUR == '*')))
11578 		    xmlXPathCompRelativeLocationPath(ctxt);
11579 	    }
11580 	    CHECK_ERROR;
11581 	}
11582     }
11583 }
11584 
11585 /************************************************************************
11586  *									*
11587  *		XPath precompiled expression evaluation			*
11588  *									*
11589  ************************************************************************/
11590 
11591 static int
11592 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11593 
11594 #ifdef DEBUG_STEP
11595 static void
11596 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11597 			  int nbNodes)
11598 {
11599     xmlGenericError(xmlGenericErrorContext, "new step : ");
11600     switch (op->value) {
11601         case AXIS_ANCESTOR:
11602             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11603             break;
11604         case AXIS_ANCESTOR_OR_SELF:
11605             xmlGenericError(xmlGenericErrorContext,
11606                             "axis 'ancestors-or-self' ");
11607             break;
11608         case AXIS_ATTRIBUTE:
11609             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11610             break;
11611         case AXIS_CHILD:
11612             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11613             break;
11614         case AXIS_DESCENDANT:
11615             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11616             break;
11617         case AXIS_DESCENDANT_OR_SELF:
11618             xmlGenericError(xmlGenericErrorContext,
11619                             "axis 'descendant-or-self' ");
11620             break;
11621         case AXIS_FOLLOWING:
11622             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11623             break;
11624         case AXIS_FOLLOWING_SIBLING:
11625             xmlGenericError(xmlGenericErrorContext,
11626                             "axis 'following-siblings' ");
11627             break;
11628         case AXIS_NAMESPACE:
11629             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11630             break;
11631         case AXIS_PARENT:
11632             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11633             break;
11634         case AXIS_PRECEDING:
11635             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11636             break;
11637         case AXIS_PRECEDING_SIBLING:
11638             xmlGenericError(xmlGenericErrorContext,
11639                             "axis 'preceding-sibling' ");
11640             break;
11641         case AXIS_SELF:
11642             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11643             break;
11644     }
11645     xmlGenericError(xmlGenericErrorContext,
11646 	" context contains %d nodes\n", nbNodes);
11647     switch (op->value2) {
11648         case NODE_TEST_NONE:
11649             xmlGenericError(xmlGenericErrorContext,
11650                             "           searching for none !!!\n");
11651             break;
11652         case NODE_TEST_TYPE:
11653             xmlGenericError(xmlGenericErrorContext,
11654                             "           searching for type %d\n", op->value3);
11655             break;
11656         case NODE_TEST_PI:
11657             xmlGenericError(xmlGenericErrorContext,
11658                             "           searching for PI !!!\n");
11659             break;
11660         case NODE_TEST_ALL:
11661             xmlGenericError(xmlGenericErrorContext,
11662                             "           searching for *\n");
11663             break;
11664         case NODE_TEST_NS:
11665             xmlGenericError(xmlGenericErrorContext,
11666                             "           searching for namespace %s\n",
11667                             op->value5);
11668             break;
11669         case NODE_TEST_NAME:
11670             xmlGenericError(xmlGenericErrorContext,
11671                             "           searching for name %s\n", op->value5);
11672             if (op->value4)
11673                 xmlGenericError(xmlGenericErrorContext,
11674                                 "           with namespace %s\n", op->value4);
11675             break;
11676     }
11677     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11678 }
11679 #endif /* DEBUG_STEP */
11680 
11681 static int
11682 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11683 			    xmlXPathStepOpPtr op,
11684 			    xmlNodeSetPtr set,
11685 			    int contextSize,
11686 			    int hasNsNodes)
11687 {
11688     if (op->ch1 != -1) {
11689 	xmlXPathCompExprPtr comp = ctxt->comp;
11690 	/*
11691 	* Process inner predicates first.
11692 	*/
11693 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11694 	    /*
11695 	    * TODO: raise an internal error.
11696 	    */
11697 	}
11698 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11699 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11700 	CHECK_ERROR0;
11701 	if (contextSize <= 0)
11702 	    return(0);
11703     }
11704     if (op->ch2 != -1) {
11705 	xmlXPathContextPtr xpctxt = ctxt->context;
11706 	xmlNodePtr contextNode, oldContextNode;
11707 	xmlDocPtr oldContextDoc;
11708 	int i, res, contextPos = 0, newContextSize;
11709 	xmlXPathStepOpPtr exprOp;
11710 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11711 
11712 #ifdef LIBXML_XPTR_ENABLED
11713 	/*
11714 	* URGENT TODO: Check the following:
11715 	*  We don't expect location sets if evaluating prediates, right?
11716 	*  Only filters should expect location sets, right?
11717 	*/
11718 #endif
11719 	/*
11720 	* SPEC XPath 1.0:
11721 	*  "For each node in the node-set to be filtered, the
11722 	*  PredicateExpr is evaluated with that node as the
11723 	*  context node, with the number of nodes in the
11724 	*  node-set as the context size, and with the proximity
11725 	*  position of the node in the node-set with respect to
11726 	*  the axis as the context position;"
11727 	* @oldset is the node-set" to be filtered.
11728 	*
11729 	* SPEC XPath 1.0:
11730 	*  "only predicates change the context position and
11731 	*  context size (see [2.4 Predicates])."
11732 	* Example:
11733 	*   node-set  context pos
11734 	*    nA         1
11735 	*    nB         2
11736 	*    nC         3
11737 	*   After applying predicate [position() > 1] :
11738 	*   node-set  context pos
11739 	*    nB         1
11740 	*    nC         2
11741 	*/
11742 	oldContextNode = xpctxt->node;
11743 	oldContextDoc = xpctxt->doc;
11744 	/*
11745 	* Get the expression of this predicate.
11746 	*/
11747 	exprOp = &ctxt->comp->steps[op->ch2];
11748 	newContextSize = 0;
11749 	for (i = 0; i < set->nodeNr; i++) {
11750 	    if (set->nodeTab[i] == NULL)
11751 		continue;
11752 
11753 	    contextNode = set->nodeTab[i];
11754 	    xpctxt->node = contextNode;
11755 	    xpctxt->contextSize = contextSize;
11756 	    xpctxt->proximityPosition = ++contextPos;
11757 
11758 	    /*
11759 	    * Also set the xpath document in case things like
11760 	    * key() are evaluated in the predicate.
11761 	    */
11762 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11763 		(contextNode->doc != NULL))
11764 		xpctxt->doc = contextNode->doc;
11765 	    /*
11766 	    * Evaluate the predicate expression with 1 context node
11767 	    * at a time; this node is packaged into a node set; this
11768 	    * node set is handed over to the evaluation mechanism.
11769 	    */
11770 	    if (contextObj == NULL)
11771 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11772 	    else {
11773 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11774 		    contextNode) < 0) {
11775 		    ctxt->error = XPATH_MEMORY_ERROR;
11776 		    goto evaluation_exit;
11777 		}
11778 	    }
11779 
11780 	    valuePush(ctxt, contextObj);
11781 
11782 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11783 
11784 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11785 		xmlXPathNodeSetClear(set, hasNsNodes);
11786 		newContextSize = 0;
11787 		goto evaluation_exit;
11788 	    }
11789 
11790 	    if (res != 0) {
11791 		newContextSize++;
11792 	    } else {
11793 		/*
11794 		* Remove the entry from the initial node set.
11795 		*/
11796 		set->nodeTab[i] = NULL;
11797 		if (contextNode->type == XML_NAMESPACE_DECL)
11798 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11799 	    }
11800 	    if (ctxt->value == contextObj) {
11801 		/*
11802 		* Don't free the temporary XPath object holding the
11803 		* context node, in order to avoid massive recreation
11804 		* inside this loop.
11805 		*/
11806 		valuePop(ctxt);
11807 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11808 	    } else {
11809 		/*
11810 		* TODO: The object was lost in the evaluation machinery.
11811 		*  Can this happen? Maybe in internal-error cases.
11812 		*/
11813 		contextObj = NULL;
11814 	    }
11815 	}
11816 
11817 	if (contextObj != NULL) {
11818 	    if (ctxt->value == contextObj)
11819 		valuePop(ctxt);
11820 	    xmlXPathReleaseObject(xpctxt, contextObj);
11821 	}
11822 evaluation_exit:
11823 	if (exprRes != NULL)
11824 	    xmlXPathReleaseObject(ctxt->context, exprRes);
11825 	/*
11826 	* Reset/invalidate the context.
11827 	*/
11828 	xpctxt->node = oldContextNode;
11829 	xpctxt->doc = oldContextDoc;
11830 	xpctxt->contextSize = -1;
11831 	xpctxt->proximityPosition = -1;
11832 	return(newContextSize);
11833     }
11834     return(contextSize);
11835 }
11836 
11837 static int
11838 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11839 				      xmlXPathStepOpPtr op,
11840 				      xmlNodeSetPtr set,
11841 				      int contextSize,
11842 				      int minPos,
11843 				      int maxPos,
11844 				      int hasNsNodes)
11845 {
11846     if (op->ch1 != -1) {
11847 	xmlXPathCompExprPtr comp = ctxt->comp;
11848 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11849 	    /*
11850 	    * TODO: raise an internal error.
11851 	    */
11852 	}
11853 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11854 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11855 	CHECK_ERROR0;
11856 	if (contextSize <= 0)
11857 	    return(0);
11858     }
11859     /*
11860     * Check if the node set contains a sufficient number of nodes for
11861     * the requested range.
11862     */
11863     if (contextSize < minPos) {
11864 	xmlXPathNodeSetClear(set, hasNsNodes);
11865 	return(0);
11866     }
11867     if (op->ch2 == -1) {
11868 	/*
11869 	* TODO: Can this ever happen?
11870 	*/
11871 	return (contextSize);
11872     } else {
11873 	xmlDocPtr oldContextDoc;
11874 	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11875 	xmlXPathStepOpPtr exprOp;
11876 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11877 	xmlNodePtr oldContextNode, contextNode = NULL;
11878 	xmlXPathContextPtr xpctxt = ctxt->context;
11879         int frame;
11880 
11881 #ifdef LIBXML_XPTR_ENABLED
11882 	    /*
11883 	    * URGENT TODO: Check the following:
11884 	    *  We don't expect location sets if evaluating prediates, right?
11885 	    *  Only filters should expect location sets, right?
11886 	*/
11887 #endif /* LIBXML_XPTR_ENABLED */
11888 
11889 	/*
11890 	* Save old context.
11891 	*/
11892 	oldContextNode = xpctxt->node;
11893 	oldContextDoc = xpctxt->doc;
11894 	/*
11895 	* Get the expression of this predicate.
11896 	*/
11897 	exprOp = &ctxt->comp->steps[op->ch2];
11898 	for (i = 0; i < set->nodeNr; i++) {
11899             xmlXPathObjectPtr tmp;
11900 
11901 	    if (set->nodeTab[i] == NULL)
11902 		continue;
11903 
11904 	    contextNode = set->nodeTab[i];
11905 	    xpctxt->node = contextNode;
11906 	    xpctxt->contextSize = contextSize;
11907 	    xpctxt->proximityPosition = ++contextPos;
11908 
11909 	    /*
11910 	    * Initialize the new set.
11911 	    * Also set the xpath document in case things like
11912 	    * key() evaluation are attempted on the predicate
11913 	    */
11914 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11915 		(contextNode->doc != NULL))
11916 		xpctxt->doc = contextNode->doc;
11917 	    /*
11918 	    * Evaluate the predicate expression with 1 context node
11919 	    * at a time; this node is packaged into a node set; this
11920 	    * node set is handed over to the evaluation mechanism.
11921 	    */
11922 	    if (contextObj == NULL)
11923 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11924 	    else {
11925 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11926 		    contextNode) < 0) {
11927 		    ctxt->error = XPATH_MEMORY_ERROR;
11928 		    goto evaluation_exit;
11929 		}
11930 	    }
11931 
11932 	    valuePush(ctxt, contextObj);
11933             frame = xmlXPathSetFrame(ctxt);
11934 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11935             xmlXPathPopFrame(ctxt, frame);
11936             tmp = valuePop(ctxt);
11937 
11938 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11939                 while (tmp != contextObj) {
11940                     /*
11941                      * Free up the result
11942                      * then pop off contextObj, which will be freed later
11943                      */
11944                     xmlXPathReleaseObject(xpctxt, tmp);
11945                     tmp = valuePop(ctxt);
11946                 }
11947 		goto evaluation_error;
11948 	    }
11949             /* push the result back onto the stack */
11950             valuePush(ctxt, tmp);
11951 
11952 	    if (res)
11953 		pos++;
11954 
11955 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
11956 		/*
11957 		* Fits in the requested range.
11958 		*/
11959 		newContextSize++;
11960 		if (minPos == maxPos) {
11961 		    /*
11962 		    * Only 1 node was requested.
11963 		    */
11964 		    if (contextNode->type == XML_NAMESPACE_DECL) {
11965 			/*
11966 			* As always: take care of those nasty
11967 			* namespace nodes.
11968 			*/
11969 			set->nodeTab[i] = NULL;
11970 		    }
11971 		    xmlXPathNodeSetClear(set, hasNsNodes);
11972 		    set->nodeNr = 1;
11973 		    set->nodeTab[0] = contextNode;
11974 		    goto evaluation_exit;
11975 		}
11976 		if (pos == maxPos) {
11977 		    /*
11978 		    * We are done.
11979 		    */
11980 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11981 		    goto evaluation_exit;
11982 		}
11983 	    } else {
11984 		/*
11985 		* Remove the entry from the initial node set.
11986 		*/
11987 		set->nodeTab[i] = NULL;
11988 		if (contextNode->type == XML_NAMESPACE_DECL)
11989 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11990 	    }
11991 	    if (exprRes != NULL) {
11992 		xmlXPathReleaseObject(ctxt->context, exprRes);
11993 		exprRes = NULL;
11994 	    }
11995 	    if (ctxt->value == contextObj) {
11996 		/*
11997 		* Don't free the temporary XPath object holding the
11998 		* context node, in order to avoid massive recreation
11999 		* inside this loop.
12000 		*/
12001 		valuePop(ctxt);
12002 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
12003 	    } else {
12004 		/*
12005 		* The object was lost in the evaluation machinery.
12006 		* Can this happen? Maybe in case of internal-errors.
12007 		*/
12008 		contextObj = NULL;
12009 	    }
12010 	}
12011 	goto evaluation_exit;
12012 
12013 evaluation_error:
12014 	xmlXPathNodeSetClear(set, hasNsNodes);
12015 	newContextSize = 0;
12016 
12017 evaluation_exit:
12018 	if (contextObj != NULL) {
12019 	    if (ctxt->value == contextObj)
12020 		valuePop(ctxt);
12021 	    xmlXPathReleaseObject(xpctxt, contextObj);
12022 	}
12023 	if (exprRes != NULL)
12024 	    xmlXPathReleaseObject(ctxt->context, exprRes);
12025 	/*
12026 	* Reset/invalidate the context.
12027 	*/
12028 	xpctxt->node = oldContextNode;
12029 	xpctxt->doc = oldContextDoc;
12030 	xpctxt->contextSize = -1;
12031 	xpctxt->proximityPosition = -1;
12032 	return(newContextSize);
12033     }
12034     return(contextSize);
12035 }
12036 
12037 static int
12038 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12039 			    xmlXPathStepOpPtr op,
12040 			    int *maxPos)
12041 {
12042 
12043     xmlXPathStepOpPtr exprOp;
12044 
12045     /*
12046     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12047     */
12048 
12049     /*
12050     * If not -1, then ch1 will point to:
12051     * 1) For predicates (XPATH_OP_PREDICATE):
12052     *    - an inner predicate operator
12053     * 2) For filters (XPATH_OP_FILTER):
12054     *    - an inner filter operater OR
12055     *    - an expression selecting the node set.
12056     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
12057     */
12058     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12059 	return(0);
12060 
12061     if (op->ch2 != -1) {
12062 	exprOp = &ctxt->comp->steps[op->ch2];
12063     } else
12064 	return(0);
12065 
12066     if ((exprOp != NULL) &&
12067 	(exprOp->op == XPATH_OP_VALUE) &&
12068 	(exprOp->value4 != NULL) &&
12069 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12070     {
12071         double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12072 
12073 	/*
12074 	* We have a "[n]" predicate here.
12075 	* TODO: Unfortunately this simplistic test here is not
12076 	* able to detect a position() predicate in compound
12077 	* expressions like "[@attr = 'a" and position() = 1],
12078 	* and even not the usage of position() in
12079 	* "[position() = 1]"; thus - obviously - a position-range,
12080 	* like it "[position() < 5]", is also not detected.
12081 	* Maybe we could rewrite the AST to ease the optimization.
12082 	*/
12083 
12084         if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
12085 	    *maxPos = (int) floatval;
12086             if (floatval == (double) *maxPos)
12087                 return(1);
12088         }
12089     }
12090     return(0);
12091 }
12092 
12093 static int
12094 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12095                            xmlXPathStepOpPtr op,
12096 			   xmlNodePtr * first, xmlNodePtr * last,
12097 			   int toBool)
12098 {
12099 
12100 #define XP_TEST_HIT \
12101     if (hasAxisRange != 0) { \
12102 	if (++pos == maxPos) { \
12103 	    if (addNode(seq, cur) < 0) \
12104 	        ctxt->error = XPATH_MEMORY_ERROR; \
12105 	    goto axis_range_end; } \
12106     } else { \
12107 	if (addNode(seq, cur) < 0) \
12108 	    ctxt->error = XPATH_MEMORY_ERROR; \
12109 	if (breakOnFirstHit) goto first_hit; }
12110 
12111 #define XP_TEST_HIT_NS \
12112     if (hasAxisRange != 0) { \
12113 	if (++pos == maxPos) { \
12114 	    hasNsNodes = 1; \
12115 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12116 	        ctxt->error = XPATH_MEMORY_ERROR; \
12117 	goto axis_range_end; } \
12118     } else { \
12119 	hasNsNodes = 1; \
12120 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12121 	    ctxt->error = XPATH_MEMORY_ERROR; \
12122 	if (breakOnFirstHit) goto first_hit; }
12123 
12124     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12125     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12126     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12127     const xmlChar *prefix = op->value4;
12128     const xmlChar *name = op->value5;
12129     const xmlChar *URI = NULL;
12130 
12131 #ifdef DEBUG_STEP
12132     int nbMatches = 0, prevMatches = 0;
12133 #endif
12134     int total = 0, hasNsNodes = 0;
12135     /* The popped object holding the context nodes */
12136     xmlXPathObjectPtr obj;
12137     /* The set of context nodes for the node tests */
12138     xmlNodeSetPtr contextSeq;
12139     int contextIdx;
12140     xmlNodePtr contextNode;
12141     /* The final resulting node set wrt to all context nodes */
12142     xmlNodeSetPtr outSeq;
12143     /*
12144     * The temporary resulting node set wrt 1 context node.
12145     * Used to feed predicate evaluation.
12146     */
12147     xmlNodeSetPtr seq;
12148     xmlNodePtr cur;
12149     /* First predicate operator */
12150     xmlXPathStepOpPtr predOp;
12151     int maxPos; /* The requested position() (when a "[n]" predicate) */
12152     int hasPredicateRange, hasAxisRange, pos, size, newSize;
12153     int breakOnFirstHit;
12154 
12155     xmlXPathTraversalFunction next = NULL;
12156     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12157     xmlXPathNodeSetMergeFunction mergeAndClear;
12158     xmlNodePtr oldContextNode;
12159     xmlXPathContextPtr xpctxt = ctxt->context;
12160 
12161 
12162     CHECK_TYPE0(XPATH_NODESET);
12163     obj = valuePop(ctxt);
12164     /*
12165     * Setup namespaces.
12166     */
12167     if (prefix != NULL) {
12168         URI = xmlXPathNsLookup(xpctxt, prefix);
12169         if (URI == NULL) {
12170 	    xmlXPathReleaseObject(xpctxt, obj);
12171             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12172 	}
12173     }
12174     /*
12175     * Setup axis.
12176     *
12177     * MAYBE FUTURE TODO: merging optimizations:
12178     * - If the nodes to be traversed wrt to the initial nodes and
12179     *   the current axis cannot overlap, then we could avoid searching
12180     *   for duplicates during the merge.
12181     *   But the question is how/when to evaluate if they cannot overlap.
12182     *   Example: if we know that for two initial nodes, the one is
12183     *   not in the ancestor-or-self axis of the other, then we could safely
12184     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12185     *   the descendant-or-self axis.
12186     */
12187     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12188     switch (axis) {
12189         case AXIS_ANCESTOR:
12190             first = NULL;
12191             next = xmlXPathNextAncestor;
12192             break;
12193         case AXIS_ANCESTOR_OR_SELF:
12194             first = NULL;
12195             next = xmlXPathNextAncestorOrSelf;
12196             break;
12197         case AXIS_ATTRIBUTE:
12198             first = NULL;
12199 	    last = NULL;
12200             next = xmlXPathNextAttribute;
12201 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12202             break;
12203         case AXIS_CHILD:
12204 	    last = NULL;
12205 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12206 		(type == NODE_TYPE_NODE))
12207 	    {
12208 		/*
12209 		* Optimization if an element node type is 'element'.
12210 		*/
12211 		next = xmlXPathNextChildElement;
12212 	    } else
12213 		next = xmlXPathNextChild;
12214 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12215             break;
12216         case AXIS_DESCENDANT:
12217 	    last = NULL;
12218             next = xmlXPathNextDescendant;
12219             break;
12220         case AXIS_DESCENDANT_OR_SELF:
12221 	    last = NULL;
12222             next = xmlXPathNextDescendantOrSelf;
12223             break;
12224         case AXIS_FOLLOWING:
12225 	    last = NULL;
12226             next = xmlXPathNextFollowing;
12227             break;
12228         case AXIS_FOLLOWING_SIBLING:
12229 	    last = NULL;
12230             next = xmlXPathNextFollowingSibling;
12231             break;
12232         case AXIS_NAMESPACE:
12233             first = NULL;
12234 	    last = NULL;
12235             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12236 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12237             break;
12238         case AXIS_PARENT:
12239             first = NULL;
12240             next = xmlXPathNextParent;
12241             break;
12242         case AXIS_PRECEDING:
12243             first = NULL;
12244             next = xmlXPathNextPrecedingInternal;
12245             break;
12246         case AXIS_PRECEDING_SIBLING:
12247             first = NULL;
12248             next = xmlXPathNextPrecedingSibling;
12249             break;
12250         case AXIS_SELF:
12251             first = NULL;
12252 	    last = NULL;
12253             next = xmlXPathNextSelf;
12254 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12255             break;
12256     }
12257 
12258 #ifdef DEBUG_STEP
12259     xmlXPathDebugDumpStepAxis(op,
12260 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12261 #endif
12262 
12263     if (next == NULL) {
12264 	xmlXPathReleaseObject(xpctxt, obj);
12265         return(0);
12266     }
12267     contextSeq = obj->nodesetval;
12268     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12269 	xmlXPathReleaseObject(xpctxt, obj);
12270         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12271         return(0);
12272     }
12273     /*
12274     * Predicate optimization ---------------------------------------------
12275     * If this step has a last predicate, which contains a position(),
12276     * then we'll optimize (although not exactly "position()", but only
12277     * the  short-hand form, i.e., "[n]".
12278     *
12279     * Example - expression "/foo[parent::bar][1]":
12280     *
12281     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12282     *   ROOT                               -- op->ch1
12283     *   PREDICATE                          -- op->ch2 (predOp)
12284     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12285     *       SORT
12286     *         COLLECT  'parent' 'name' 'node' bar
12287     *           NODE
12288     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12289     *
12290     */
12291     maxPos = 0;
12292     predOp = NULL;
12293     hasPredicateRange = 0;
12294     hasAxisRange = 0;
12295     if (op->ch2 != -1) {
12296 	/*
12297 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12298 	*/
12299 	predOp = &ctxt->comp->steps[op->ch2];
12300 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12301 	    if (predOp->ch1 != -1) {
12302 		/*
12303 		* Use the next inner predicate operator.
12304 		*/
12305 		predOp = &ctxt->comp->steps[predOp->ch1];
12306 		hasPredicateRange = 1;
12307 	    } else {
12308 		/*
12309 		* There's no other predicate than the [n] predicate.
12310 		*/
12311 		predOp = NULL;
12312 		hasAxisRange = 1;
12313 	    }
12314 	}
12315     }
12316     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12317     /*
12318     * Axis traversal -----------------------------------------------------
12319     */
12320     /*
12321      * 2.3 Node Tests
12322      *  - For the attribute axis, the principal node type is attribute.
12323      *  - For the namespace axis, the principal node type is namespace.
12324      *  - For other axes, the principal node type is element.
12325      *
12326      * A node test * is true for any node of the
12327      * principal node type. For example, child::* will
12328      * select all element children of the context node
12329      */
12330     oldContextNode = xpctxt->node;
12331     addNode = xmlXPathNodeSetAddUnique;
12332     outSeq = NULL;
12333     seq = NULL;
12334     contextNode = NULL;
12335     contextIdx = 0;
12336 
12337 
12338     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12339            (ctxt->error == XPATH_EXPRESSION_OK)) {
12340 	xpctxt->node = contextSeq->nodeTab[contextIdx++];
12341 
12342 	if (seq == NULL) {
12343 	    seq = xmlXPathNodeSetCreate(NULL);
12344 	    if (seq == NULL) {
12345 		total = 0;
12346 		goto error;
12347 	    }
12348 	}
12349 	/*
12350 	* Traverse the axis and test the nodes.
12351 	*/
12352 	pos = 0;
12353 	cur = NULL;
12354 	hasNsNodes = 0;
12355         do {
12356             cur = next(ctxt, cur);
12357             if (cur == NULL)
12358                 break;
12359 
12360 	    /*
12361 	    * QUESTION TODO: What does the "first" and "last" stuff do?
12362 	    */
12363             if ((first != NULL) && (*first != NULL)) {
12364 		if (*first == cur)
12365 		    break;
12366 		if (((total % 256) == 0) &&
12367 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12368 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12369 #else
12370 		    (xmlXPathCmpNodes(*first, cur) >= 0))
12371 #endif
12372 		{
12373 		    break;
12374 		}
12375 	    }
12376 	    if ((last != NULL) && (*last != NULL)) {
12377 		if (*last == cur)
12378 		    break;
12379 		if (((total % 256) == 0) &&
12380 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12381 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12382 #else
12383 		    (xmlXPathCmpNodes(cur, *last) >= 0))
12384 #endif
12385 		{
12386 		    break;
12387 		}
12388 	    }
12389 
12390             total++;
12391 
12392 #ifdef DEBUG_STEP
12393             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12394 #endif
12395 
12396 	    switch (test) {
12397                 case NODE_TEST_NONE:
12398 		    total = 0;
12399                     STRANGE
12400 		    goto error;
12401                 case NODE_TEST_TYPE:
12402 		    if (type == NODE_TYPE_NODE) {
12403 			switch (cur->type) {
12404 			    case XML_DOCUMENT_NODE:
12405 			    case XML_HTML_DOCUMENT_NODE:
12406 #ifdef LIBXML_DOCB_ENABLED
12407 			    case XML_DOCB_DOCUMENT_NODE:
12408 #endif
12409 			    case XML_ELEMENT_NODE:
12410 			    case XML_ATTRIBUTE_NODE:
12411 			    case XML_PI_NODE:
12412 			    case XML_COMMENT_NODE:
12413 			    case XML_CDATA_SECTION_NODE:
12414 			    case XML_TEXT_NODE:
12415 				XP_TEST_HIT
12416 				break;
12417 			    case XML_NAMESPACE_DECL: {
12418 				if (axis == AXIS_NAMESPACE) {
12419 				    XP_TEST_HIT_NS
12420 				} else {
12421 	                            hasNsNodes = 1;
12422 				    XP_TEST_HIT
12423 				}
12424 				break;
12425                             }
12426 			    default:
12427 				break;
12428 			}
12429 		    } else if (cur->type == type) {
12430 			if (cur->type == XML_NAMESPACE_DECL)
12431 			    XP_TEST_HIT_NS
12432 			else
12433 			    XP_TEST_HIT
12434 		    } else if ((type == NODE_TYPE_TEXT) &&
12435 			 (cur->type == XML_CDATA_SECTION_NODE))
12436 		    {
12437 			XP_TEST_HIT
12438 		    }
12439 		    break;
12440                 case NODE_TEST_PI:
12441                     if ((cur->type == XML_PI_NODE) &&
12442                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12443 		    {
12444 			XP_TEST_HIT
12445                     }
12446                     break;
12447                 case NODE_TEST_ALL:
12448                     if (axis == AXIS_ATTRIBUTE) {
12449                         if (cur->type == XML_ATTRIBUTE_NODE)
12450 			{
12451                             if (prefix == NULL)
12452 			    {
12453 				XP_TEST_HIT
12454                             } else if ((cur->ns != NULL) &&
12455 				(xmlStrEqual(URI, cur->ns->href)))
12456 			    {
12457 				XP_TEST_HIT
12458                             }
12459                         }
12460                     } else if (axis == AXIS_NAMESPACE) {
12461                         if (cur->type == XML_NAMESPACE_DECL)
12462 			{
12463 			    XP_TEST_HIT_NS
12464                         }
12465                     } else {
12466                         if (cur->type == XML_ELEMENT_NODE) {
12467                             if (prefix == NULL)
12468 			    {
12469 				XP_TEST_HIT
12470 
12471                             } else if ((cur->ns != NULL) &&
12472 				(xmlStrEqual(URI, cur->ns->href)))
12473 			    {
12474 				XP_TEST_HIT
12475                             }
12476                         }
12477                     }
12478                     break;
12479                 case NODE_TEST_NS:{
12480                         TODO;
12481                         break;
12482                     }
12483                 case NODE_TEST_NAME:
12484                     if (axis == AXIS_ATTRIBUTE) {
12485                         if (cur->type != XML_ATTRIBUTE_NODE)
12486 			    break;
12487 		    } else if (axis == AXIS_NAMESPACE) {
12488                         if (cur->type != XML_NAMESPACE_DECL)
12489 			    break;
12490 		    } else {
12491 		        if (cur->type != XML_ELEMENT_NODE)
12492 			    break;
12493 		    }
12494                     switch (cur->type) {
12495                         case XML_ELEMENT_NODE:
12496                             if (xmlStrEqual(name, cur->name)) {
12497                                 if (prefix == NULL) {
12498                                     if (cur->ns == NULL)
12499 				    {
12500 					XP_TEST_HIT
12501                                     }
12502                                 } else {
12503                                     if ((cur->ns != NULL) &&
12504                                         (xmlStrEqual(URI, cur->ns->href)))
12505 				    {
12506 					XP_TEST_HIT
12507                                     }
12508                                 }
12509                             }
12510                             break;
12511                         case XML_ATTRIBUTE_NODE:{
12512                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12513 
12514                                 if (xmlStrEqual(name, attr->name)) {
12515                                     if (prefix == NULL) {
12516                                         if ((attr->ns == NULL) ||
12517                                             (attr->ns->prefix == NULL))
12518 					{
12519 					    XP_TEST_HIT
12520                                         }
12521                                     } else {
12522                                         if ((attr->ns != NULL) &&
12523                                             (xmlStrEqual(URI,
12524 					      attr->ns->href)))
12525 					{
12526 					    XP_TEST_HIT
12527                                         }
12528                                     }
12529                                 }
12530                                 break;
12531                             }
12532                         case XML_NAMESPACE_DECL:
12533                             if (cur->type == XML_NAMESPACE_DECL) {
12534                                 xmlNsPtr ns = (xmlNsPtr) cur;
12535 
12536                                 if ((ns->prefix != NULL) && (name != NULL)
12537                                     && (xmlStrEqual(ns->prefix, name)))
12538 				{
12539 				    XP_TEST_HIT_NS
12540                                 }
12541                             }
12542                             break;
12543                         default:
12544                             break;
12545                     }
12546                     break;
12547 	    } /* switch(test) */
12548         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12549 
12550 	goto apply_predicates;
12551 
12552 axis_range_end: /* ----------------------------------------------------- */
12553 	/*
12554 	* We have a "/foo[n]", and position() = n was reached.
12555 	* Note that we can have as well "/foo/::parent::foo[1]", so
12556 	* a duplicate-aware merge is still needed.
12557 	* Merge with the result.
12558 	*/
12559 	if (outSeq == NULL) {
12560 	    outSeq = seq;
12561 	    seq = NULL;
12562 	} else
12563 	    outSeq = mergeAndClear(outSeq, seq, 0);
12564 	/*
12565 	* Break if only a true/false result was requested.
12566 	*/
12567 	if (toBool)
12568 	    break;
12569 	continue;
12570 
12571 first_hit: /* ---------------------------------------------------------- */
12572 	/*
12573 	* Break if only a true/false result was requested and
12574 	* no predicates existed and a node test succeeded.
12575 	*/
12576 	if (outSeq == NULL) {
12577 	    outSeq = seq;
12578 	    seq = NULL;
12579 	} else
12580 	    outSeq = mergeAndClear(outSeq, seq, 0);
12581 	break;
12582 
12583 #ifdef DEBUG_STEP
12584 	if (seq != NULL)
12585 	    nbMatches += seq->nodeNr;
12586 #endif
12587 
12588 apply_predicates: /* --------------------------------------------------- */
12589         if (ctxt->error != XPATH_EXPRESSION_OK)
12590 	    goto error;
12591 
12592         /*
12593 	* Apply predicates.
12594 	*/
12595         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12596 	    /*
12597 	    * E.g. when we have a "/foo[some expression][n]".
12598 	    */
12599 	    /*
12600 	    * QUESTION TODO: The old predicate evaluation took into
12601 	    *  account location-sets.
12602 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12603 	    *  Do we expect such a set here?
12604 	    *  All what I learned now from the evaluation semantics
12605 	    *  does not indicate that a location-set will be processed
12606 	    *  here, so this looks OK.
12607 	    */
12608 	    /*
12609 	    * Iterate over all predicates, starting with the outermost
12610 	    * predicate.
12611 	    * TODO: Problem: we cannot execute the inner predicates first
12612 	    *  since we cannot go back *up* the operator tree!
12613 	    *  Options we have:
12614 	    *  1) Use of recursive functions (like is it currently done
12615 	    *     via xmlXPathCompOpEval())
12616 	    *  2) Add a predicate evaluation information stack to the
12617 	    *     context struct
12618 	    *  3) Change the way the operators are linked; we need a
12619 	    *     "parent" field on xmlXPathStepOp
12620 	    *
12621 	    * For the moment, I'll try to solve this with a recursive
12622 	    * function: xmlXPathCompOpEvalPredicate().
12623 	    */
12624 	    size = seq->nodeNr;
12625 	    if (hasPredicateRange != 0)
12626 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12627 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12628 	    else
12629 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
12630 		    predOp, seq, size, hasNsNodes);
12631 
12632 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12633 		total = 0;
12634 		goto error;
12635 	    }
12636 	    /*
12637 	    * Add the filtered set of nodes to the result node set.
12638 	    */
12639 	    if (newSize == 0) {
12640 		/*
12641 		* The predicates filtered all nodes out.
12642 		*/
12643 		xmlXPathNodeSetClear(seq, hasNsNodes);
12644 	    } else if (seq->nodeNr > 0) {
12645 		/*
12646 		* Add to result set.
12647 		*/
12648 		if (outSeq == NULL) {
12649 		    if (size != newSize) {
12650 			/*
12651 			* We need to merge and clear here, since
12652 			* the sequence will contained NULLed entries.
12653 			*/
12654 			outSeq = mergeAndClear(NULL, seq, 1);
12655 		    } else {
12656 			outSeq = seq;
12657 			seq = NULL;
12658 		    }
12659 		} else
12660 		    outSeq = mergeAndClear(outSeq, seq,
12661 			(size != newSize) ? 1: 0);
12662 		/*
12663 		* Break if only a true/false result was requested.
12664 		*/
12665 		if (toBool)
12666 		    break;
12667 	    }
12668         } else if (seq->nodeNr > 0) {
12669 	    /*
12670 	    * Add to result set.
12671 	    */
12672 	    if (outSeq == NULL) {
12673 		outSeq = seq;
12674 		seq = NULL;
12675 	    } else {
12676 		outSeq = mergeAndClear(outSeq, seq, 0);
12677 	    }
12678 	}
12679     }
12680 
12681 error:
12682     if ((obj->boolval) && (obj->user != NULL)) {
12683 	/*
12684 	* QUESTION TODO: What does this do and why?
12685 	* TODO: Do we have to do this also for the "error"
12686 	* cleanup further down?
12687 	*/
12688 	ctxt->value->boolval = 1;
12689 	ctxt->value->user = obj->user;
12690 	obj->user = NULL;
12691 	obj->boolval = 0;
12692     }
12693     xmlXPathReleaseObject(xpctxt, obj);
12694 
12695     /*
12696     * Ensure we return at least an emtpy set.
12697     */
12698     if (outSeq == NULL) {
12699 	if ((seq != NULL) && (seq->nodeNr == 0))
12700 	    outSeq = seq;
12701 	else
12702 	    outSeq = xmlXPathNodeSetCreate(NULL);
12703         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12704     }
12705     if ((seq != NULL) && (seq != outSeq)) {
12706 	 xmlXPathFreeNodeSet(seq);
12707     }
12708     /*
12709     * Hand over the result. Better to push the set also in
12710     * case of errors.
12711     */
12712     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12713     /*
12714     * Reset the context node.
12715     */
12716     xpctxt->node = oldContextNode;
12717     /*
12718     * When traversing the namespace axis in "toBool" mode, it's
12719     * possible that tmpNsList wasn't freed.
12720     */
12721     if (xpctxt->tmpNsList != NULL) {
12722         xmlFree(xpctxt->tmpNsList);
12723         xpctxt->tmpNsList = NULL;
12724     }
12725 
12726 #ifdef DEBUG_STEP
12727     xmlGenericError(xmlGenericErrorContext,
12728 	"\nExamined %d nodes, found %d nodes at that step\n",
12729 	total, nbMatches);
12730 #endif
12731 
12732     return(total);
12733 }
12734 
12735 static int
12736 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12737 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12738 
12739 /**
12740  * xmlXPathCompOpEvalFirst:
12741  * @ctxt:  the XPath parser context with the compiled expression
12742  * @op:  an XPath compiled operation
12743  * @first:  the first elem found so far
12744  *
12745  * Evaluate the Precompiled XPath operation searching only the first
12746  * element in document order
12747  *
12748  * Returns the number of examined objects.
12749  */
12750 static int
12751 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12752                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12753 {
12754     int total = 0, cur;
12755     xmlXPathCompExprPtr comp;
12756     xmlXPathObjectPtr arg1, arg2;
12757 
12758     CHECK_ERROR0;
12759     comp = ctxt->comp;
12760     switch (op->op) {
12761         case XPATH_OP_END:
12762             return (0);
12763         case XPATH_OP_UNION:
12764             total =
12765                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12766                                         first);
12767 	    CHECK_ERROR0;
12768             if ((ctxt->value != NULL)
12769                 && (ctxt->value->type == XPATH_NODESET)
12770                 && (ctxt->value->nodesetval != NULL)
12771                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12772                 /*
12773                  * limit tree traversing to first node in the result
12774                  */
12775 		/*
12776 		* OPTIMIZE TODO: This implicitely sorts
12777 		*  the result, even if not needed. E.g. if the argument
12778 		*  of the count() function, no sorting is needed.
12779 		* OPTIMIZE TODO: How do we know if the node-list wasn't
12780 		*  aready sorted?
12781 		*/
12782 		if (ctxt->value->nodesetval->nodeNr > 1)
12783 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12784                 *first = ctxt->value->nodesetval->nodeTab[0];
12785             }
12786             cur =
12787                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12788                                         first);
12789 	    CHECK_ERROR0;
12790 
12791             arg2 = valuePop(ctxt);
12792             arg1 = valuePop(ctxt);
12793             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12794                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12795 	        xmlXPathReleaseObject(ctxt->context, arg1);
12796 	        xmlXPathReleaseObject(ctxt->context, arg2);
12797                 XP_ERROR0(XPATH_INVALID_TYPE);
12798             }
12799 
12800             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12801                                                     arg2->nodesetval);
12802             valuePush(ctxt, arg1);
12803 	    xmlXPathReleaseObject(ctxt->context, arg2);
12804             /* optimizer */
12805 	    if (total > cur)
12806 		xmlXPathCompSwap(op);
12807             return (total + cur);
12808         case XPATH_OP_ROOT:
12809             xmlXPathRoot(ctxt);
12810             return (0);
12811         case XPATH_OP_NODE:
12812             if (op->ch1 != -1)
12813                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12814 	    CHECK_ERROR0;
12815             if (op->ch2 != -1)
12816                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12817 	    CHECK_ERROR0;
12818 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12819 		ctxt->context->node));
12820             return (total);
12821         case XPATH_OP_RESET:
12822             if (op->ch1 != -1)
12823                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12824 	    CHECK_ERROR0;
12825             if (op->ch2 != -1)
12826                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12827 	    CHECK_ERROR0;
12828             ctxt->context->node = NULL;
12829             return (total);
12830         case XPATH_OP_COLLECT:{
12831                 if (op->ch1 == -1)
12832                     return (total);
12833 
12834                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12835 		CHECK_ERROR0;
12836 
12837                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12838                 return (total);
12839             }
12840         case XPATH_OP_VALUE:
12841             valuePush(ctxt,
12842                       xmlXPathCacheObjectCopy(ctxt->context,
12843 			(xmlXPathObjectPtr) op->value4));
12844             return (0);
12845         case XPATH_OP_SORT:
12846             if (op->ch1 != -1)
12847                 total +=
12848                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12849                                             first);
12850 	    CHECK_ERROR0;
12851             if ((ctxt->value != NULL)
12852                 && (ctxt->value->type == XPATH_NODESET)
12853                 && (ctxt->value->nodesetval != NULL)
12854 		&& (ctxt->value->nodesetval->nodeNr > 1))
12855                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12856             return (total);
12857 #ifdef XP_OPTIMIZED_FILTER_FIRST
12858 	case XPATH_OP_FILTER:
12859                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12860             return (total);
12861 #endif
12862         default:
12863             return (xmlXPathCompOpEval(ctxt, op));
12864     }
12865 }
12866 
12867 /**
12868  * xmlXPathCompOpEvalLast:
12869  * @ctxt:  the XPath parser context with the compiled expression
12870  * @op:  an XPath compiled operation
12871  * @last:  the last elem found so far
12872  *
12873  * Evaluate the Precompiled XPath operation searching only the last
12874  * element in document order
12875  *
12876  * Returns the number of nodes traversed
12877  */
12878 static int
12879 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12880                        xmlNodePtr * last)
12881 {
12882     int total = 0, cur;
12883     xmlXPathCompExprPtr comp;
12884     xmlXPathObjectPtr arg1, arg2;
12885     xmlNodePtr bak;
12886     xmlDocPtr bakd;
12887     int pp;
12888     int cs;
12889 
12890     CHECK_ERROR0;
12891     comp = ctxt->comp;
12892     switch (op->op) {
12893         case XPATH_OP_END:
12894             return (0);
12895         case XPATH_OP_UNION:
12896 	    bakd = ctxt->context->doc;
12897 	    bak = ctxt->context->node;
12898 	    pp = ctxt->context->proximityPosition;
12899 	    cs = ctxt->context->contextSize;
12900             total =
12901                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12902 	    CHECK_ERROR0;
12903             if ((ctxt->value != NULL)
12904                 && (ctxt->value->type == XPATH_NODESET)
12905                 && (ctxt->value->nodesetval != NULL)
12906                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12907                 /*
12908                  * limit tree traversing to first node in the result
12909                  */
12910 		if (ctxt->value->nodesetval->nodeNr > 1)
12911 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12912                 *last =
12913                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12914                                                      nodesetval->nodeNr -
12915                                                      1];
12916             }
12917 	    ctxt->context->doc = bakd;
12918 	    ctxt->context->node = bak;
12919 	    ctxt->context->proximityPosition = pp;
12920 	    ctxt->context->contextSize = cs;
12921             cur =
12922                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12923 	    CHECK_ERROR0;
12924             if ((ctxt->value != NULL)
12925                 && (ctxt->value->type == XPATH_NODESET)
12926                 && (ctxt->value->nodesetval != NULL)
12927                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12928             }
12929 
12930             arg2 = valuePop(ctxt);
12931             arg1 = valuePop(ctxt);
12932             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12933                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12934 	        xmlXPathReleaseObject(ctxt->context, arg1);
12935 	        xmlXPathReleaseObject(ctxt->context, arg2);
12936                 XP_ERROR0(XPATH_INVALID_TYPE);
12937             }
12938 
12939             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12940                                                     arg2->nodesetval);
12941             valuePush(ctxt, arg1);
12942 	    xmlXPathReleaseObject(ctxt->context, arg2);
12943             /* optimizer */
12944 	    if (total > cur)
12945 		xmlXPathCompSwap(op);
12946             return (total + cur);
12947         case XPATH_OP_ROOT:
12948             xmlXPathRoot(ctxt);
12949             return (0);
12950         case XPATH_OP_NODE:
12951             if (op->ch1 != -1)
12952                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12953 	    CHECK_ERROR0;
12954             if (op->ch2 != -1)
12955                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12956 	    CHECK_ERROR0;
12957 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12958 		ctxt->context->node));
12959             return (total);
12960         case XPATH_OP_RESET:
12961             if (op->ch1 != -1)
12962                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12963 	    CHECK_ERROR0;
12964             if (op->ch2 != -1)
12965                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12966 	    CHECK_ERROR0;
12967             ctxt->context->node = NULL;
12968             return (total);
12969         case XPATH_OP_COLLECT:{
12970                 if (op->ch1 == -1)
12971                     return (0);
12972 
12973                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12974 		CHECK_ERROR0;
12975 
12976                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12977                 return (total);
12978             }
12979         case XPATH_OP_VALUE:
12980             valuePush(ctxt,
12981                       xmlXPathCacheObjectCopy(ctxt->context,
12982 			(xmlXPathObjectPtr) op->value4));
12983             return (0);
12984         case XPATH_OP_SORT:
12985             if (op->ch1 != -1)
12986                 total +=
12987                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12988                                            last);
12989 	    CHECK_ERROR0;
12990             if ((ctxt->value != NULL)
12991                 && (ctxt->value->type == XPATH_NODESET)
12992                 && (ctxt->value->nodesetval != NULL)
12993 		&& (ctxt->value->nodesetval->nodeNr > 1))
12994                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12995             return (total);
12996         default:
12997             return (xmlXPathCompOpEval(ctxt, op));
12998     }
12999 }
13000 
13001 #ifdef XP_OPTIMIZED_FILTER_FIRST
13002 static int
13003 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
13004 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
13005 {
13006     int total = 0;
13007     xmlXPathCompExprPtr comp;
13008     xmlXPathObjectPtr res;
13009     xmlXPathObjectPtr obj;
13010     xmlNodeSetPtr oldset;
13011     xmlNodePtr oldnode;
13012     xmlDocPtr oldDoc;
13013     int i;
13014 
13015     CHECK_ERROR0;
13016     comp = ctxt->comp;
13017     /*
13018     * Optimization for ()[last()] selection i.e. the last elem
13019     */
13020     if ((op->ch1 != -1) && (op->ch2 != -1) &&
13021 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13022 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13023 	int f = comp->steps[op->ch2].ch1;
13024 
13025 	if ((f != -1) &&
13026 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13027 	    (comp->steps[f].value5 == NULL) &&
13028 	    (comp->steps[f].value == 0) &&
13029 	    (comp->steps[f].value4 != NULL) &&
13030 	    (xmlStrEqual
13031 	    (comp->steps[f].value4, BAD_CAST "last"))) {
13032 	    xmlNodePtr last = NULL;
13033 
13034 	    total +=
13035 		xmlXPathCompOpEvalLast(ctxt,
13036 		    &comp->steps[op->ch1],
13037 		    &last);
13038 	    CHECK_ERROR0;
13039 	    /*
13040 	    * The nodeset should be in document order,
13041 	    * Keep only the last value
13042 	    */
13043 	    if ((ctxt->value != NULL) &&
13044 		(ctxt->value->type == XPATH_NODESET) &&
13045 		(ctxt->value->nodesetval != NULL) &&
13046 		(ctxt->value->nodesetval->nodeTab != NULL) &&
13047 		(ctxt->value->nodesetval->nodeNr > 1)) {
13048                 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13049 		*first = *(ctxt->value->nodesetval->nodeTab);
13050 	    }
13051 	    return (total);
13052 	}
13053     }
13054 
13055     if (op->ch1 != -1)
13056 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13057     CHECK_ERROR0;
13058     if (op->ch2 == -1)
13059 	return (total);
13060     if (ctxt->value == NULL)
13061 	return (total);
13062 
13063 #ifdef LIBXML_XPTR_ENABLED
13064     oldnode = ctxt->context->node;
13065     /*
13066     * Hum are we filtering the result of an XPointer expression
13067     */
13068     if (ctxt->value->type == XPATH_LOCATIONSET) {
13069 	xmlXPathObjectPtr tmp = NULL;
13070 	xmlLocationSetPtr newlocset = NULL;
13071 	xmlLocationSetPtr oldlocset;
13072 
13073 	/*
13074 	* Extract the old locset, and then evaluate the result of the
13075 	* expression for all the element in the locset. use it to grow
13076 	* up a new locset.
13077 	*/
13078 	CHECK_TYPE0(XPATH_LOCATIONSET);
13079 	obj = valuePop(ctxt);
13080 	oldlocset = obj->user;
13081 	ctxt->context->node = NULL;
13082 
13083 	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13084 	    ctxt->context->contextSize = 0;
13085 	    ctxt->context->proximityPosition = 0;
13086 	    if (op->ch2 != -1)
13087 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13088 	    res = valuePop(ctxt);
13089 	    if (res != NULL) {
13090 		xmlXPathReleaseObject(ctxt->context, res);
13091 	    }
13092 	    valuePush(ctxt, obj);
13093 	    CHECK_ERROR0;
13094 	    return (total);
13095 	}
13096 	newlocset = xmlXPtrLocationSetCreate(NULL);
13097 
13098 	for (i = 0; i < oldlocset->locNr; i++) {
13099 	    /*
13100 	    * Run the evaluation with a node list made of a
13101 	    * single item in the nodelocset.
13102 	    */
13103 	    ctxt->context->node = oldlocset->locTab[i]->user;
13104 	    ctxt->context->contextSize = oldlocset->locNr;
13105 	    ctxt->context->proximityPosition = i + 1;
13106 	    if (tmp == NULL) {
13107 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13108 		    ctxt->context->node);
13109 	    } else {
13110 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13111 		                             ctxt->context->node) < 0) {
13112 		    ctxt->error = XPATH_MEMORY_ERROR;
13113 		}
13114 	    }
13115 	    valuePush(ctxt, tmp);
13116 	    if (op->ch2 != -1)
13117 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13118 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13119 		xmlXPathFreeObject(obj);
13120 		return(0);
13121 	    }
13122 	    /*
13123 	    * The result of the evaluation need to be tested to
13124 	    * decided whether the filter succeeded or not
13125 	    */
13126 	    res = valuePop(ctxt);
13127 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13128 		xmlXPtrLocationSetAdd(newlocset,
13129 		    xmlXPathCacheObjectCopy(ctxt->context,
13130 			oldlocset->locTab[i]));
13131 	    }
13132 	    /*
13133 	    * Cleanup
13134 	    */
13135 	    if (res != NULL) {
13136 		xmlXPathReleaseObject(ctxt->context, res);
13137 	    }
13138 	    if (ctxt->value == tmp) {
13139 		valuePop(ctxt);
13140 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13141 		/*
13142 		* REVISIT TODO: Don't create a temporary nodeset
13143 		* for everly iteration.
13144 		*/
13145 		/* OLD: xmlXPathFreeObject(res); */
13146 	    } else
13147 		tmp = NULL;
13148 	    ctxt->context->node = NULL;
13149 	    /*
13150 	    * Only put the first node in the result, then leave.
13151 	    */
13152 	    if (newlocset->locNr > 0) {
13153 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
13154 		break;
13155 	    }
13156 	}
13157 	if (tmp != NULL) {
13158 	    xmlXPathReleaseObject(ctxt->context, tmp);
13159 	}
13160 	/*
13161 	* The result is used as the new evaluation locset.
13162 	*/
13163 	xmlXPathReleaseObject(ctxt->context, obj);
13164 	ctxt->context->node = NULL;
13165 	ctxt->context->contextSize = -1;
13166 	ctxt->context->proximityPosition = -1;
13167 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13168 	ctxt->context->node = oldnode;
13169 	return (total);
13170     }
13171 #endif /* LIBXML_XPTR_ENABLED */
13172 
13173     /*
13174     * Extract the old set, and then evaluate the result of the
13175     * expression for all the element in the set. use it to grow
13176     * up a new set.
13177     */
13178     CHECK_TYPE0(XPATH_NODESET);
13179     obj = valuePop(ctxt);
13180     oldset = obj->nodesetval;
13181 
13182     oldnode = ctxt->context->node;
13183     oldDoc = ctxt->context->doc;
13184     ctxt->context->node = NULL;
13185 
13186     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13187 	ctxt->context->contextSize = 0;
13188 	ctxt->context->proximityPosition = 0;
13189 	/* QUESTION TODO: Why was this code commented out?
13190 	    if (op->ch2 != -1)
13191 		total +=
13192 		    xmlXPathCompOpEval(ctxt,
13193 			&comp->steps[op->ch2]);
13194 	    CHECK_ERROR0;
13195 	    res = valuePop(ctxt);
13196 	    if (res != NULL)
13197 		xmlXPathFreeObject(res);
13198 	*/
13199 	valuePush(ctxt, obj);
13200 	ctxt->context->node = oldnode;
13201 	CHECK_ERROR0;
13202     } else {
13203 	xmlNodeSetPtr newset;
13204 	xmlXPathObjectPtr tmp = NULL;
13205 	/*
13206 	* Initialize the new set.
13207 	* Also set the xpath document in case things like
13208 	* key() evaluation are attempted on the predicate
13209 	*/
13210 	newset = xmlXPathNodeSetCreate(NULL);
13211         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13212 
13213 	for (i = 0; i < oldset->nodeNr; i++) {
13214 	    /*
13215 	    * Run the evaluation with a node list made of
13216 	    * a single item in the nodeset.
13217 	    */
13218 	    ctxt->context->node = oldset->nodeTab[i];
13219 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13220 		(oldset->nodeTab[i]->doc != NULL))
13221 		ctxt->context->doc = oldset->nodeTab[i]->doc;
13222 	    if (tmp == NULL) {
13223 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13224 		    ctxt->context->node);
13225 	    } else {
13226 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13227 		                             ctxt->context->node) < 0) {
13228 		    ctxt->error = XPATH_MEMORY_ERROR;
13229 		}
13230 	    }
13231 	    valuePush(ctxt, tmp);
13232 	    ctxt->context->contextSize = oldset->nodeNr;
13233 	    ctxt->context->proximityPosition = i + 1;
13234 	    if (op->ch2 != -1)
13235 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13236 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13237 		xmlXPathFreeNodeSet(newset);
13238 		xmlXPathFreeObject(obj);
13239 		return(0);
13240 	    }
13241 	    /*
13242 	    * The result of the evaluation needs to be tested to
13243 	    * decide whether the filter succeeded or not
13244 	    */
13245 	    res = valuePop(ctxt);
13246 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13247 		if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13248 		    ctxt->error = XPATH_MEMORY_ERROR;
13249 	    }
13250 	    /*
13251 	    * Cleanup
13252 	    */
13253 	    if (res != NULL) {
13254 		xmlXPathReleaseObject(ctxt->context, res);
13255 	    }
13256 	    if (ctxt->value == tmp) {
13257 		valuePop(ctxt);
13258 		/*
13259 		* Don't free the temporary nodeset
13260 		* in order to avoid massive recreation inside this
13261 		* loop.
13262 		*/
13263 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13264 	    } else
13265 		tmp = NULL;
13266 	    ctxt->context->node = NULL;
13267 	    /*
13268 	    * Only put the first node in the result, then leave.
13269 	    */
13270 	    if (newset->nodeNr > 0) {
13271 		*first = *(newset->nodeTab);
13272 		break;
13273 	    }
13274 	}
13275 	if (tmp != NULL) {
13276 	    xmlXPathReleaseObject(ctxt->context, tmp);
13277 	}
13278 	/*
13279 	* The result is used as the new evaluation set.
13280 	*/
13281 	xmlXPathReleaseObject(ctxt->context, obj);
13282 	ctxt->context->node = NULL;
13283 	ctxt->context->contextSize = -1;
13284 	ctxt->context->proximityPosition = -1;
13285 	/* may want to move this past the '}' later */
13286 	ctxt->context->doc = oldDoc;
13287 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13288     }
13289     ctxt->context->node = oldnode;
13290     return(total);
13291 }
13292 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13293 
13294 /**
13295  * xmlXPathCompOpEval:
13296  * @ctxt:  the XPath parser context with the compiled expression
13297  * @op:  an XPath compiled operation
13298  *
13299  * Evaluate the Precompiled XPath operation
13300  * Returns the number of nodes traversed
13301  */
13302 static int
13303 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13304 {
13305     int total = 0;
13306     int equal, ret;
13307     xmlXPathCompExprPtr comp;
13308     xmlXPathObjectPtr arg1, arg2;
13309     xmlNodePtr bak;
13310     xmlDocPtr bakd;
13311     int pp;
13312     int cs;
13313 
13314     CHECK_ERROR0;
13315     comp = ctxt->comp;
13316     switch (op->op) {
13317         case XPATH_OP_END:
13318             return (0);
13319         case XPATH_OP_AND:
13320 	    bakd = ctxt->context->doc;
13321 	    bak = ctxt->context->node;
13322 	    pp = ctxt->context->proximityPosition;
13323 	    cs = ctxt->context->contextSize;
13324             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13325 	    CHECK_ERROR0;
13326             xmlXPathBooleanFunction(ctxt, 1);
13327             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13328                 return (total);
13329             arg2 = valuePop(ctxt);
13330 	    ctxt->context->doc = bakd;
13331 	    ctxt->context->node = bak;
13332 	    ctxt->context->proximityPosition = pp;
13333 	    ctxt->context->contextSize = cs;
13334             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13335 	    if (ctxt->error) {
13336 		xmlXPathFreeObject(arg2);
13337 		return(0);
13338 	    }
13339             xmlXPathBooleanFunction(ctxt, 1);
13340             arg1 = valuePop(ctxt);
13341             arg1->boolval &= arg2->boolval;
13342             valuePush(ctxt, arg1);
13343 	    xmlXPathReleaseObject(ctxt->context, arg2);
13344             return (total);
13345         case XPATH_OP_OR:
13346 	    bakd = ctxt->context->doc;
13347 	    bak = ctxt->context->node;
13348 	    pp = ctxt->context->proximityPosition;
13349 	    cs = ctxt->context->contextSize;
13350             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13351 	    CHECK_ERROR0;
13352             xmlXPathBooleanFunction(ctxt, 1);
13353             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13354                 return (total);
13355             arg2 = valuePop(ctxt);
13356 	    ctxt->context->doc = bakd;
13357 	    ctxt->context->node = bak;
13358 	    ctxt->context->proximityPosition = pp;
13359 	    ctxt->context->contextSize = cs;
13360             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13361 	    if (ctxt->error) {
13362 		xmlXPathFreeObject(arg2);
13363 		return(0);
13364 	    }
13365             xmlXPathBooleanFunction(ctxt, 1);
13366             arg1 = valuePop(ctxt);
13367             arg1->boolval |= arg2->boolval;
13368             valuePush(ctxt, arg1);
13369 	    xmlXPathReleaseObject(ctxt->context, arg2);
13370             return (total);
13371         case XPATH_OP_EQUAL:
13372 	    bakd = ctxt->context->doc;
13373 	    bak = ctxt->context->node;
13374 	    pp = ctxt->context->proximityPosition;
13375 	    cs = ctxt->context->contextSize;
13376             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13377 	    CHECK_ERROR0;
13378 	    ctxt->context->doc = bakd;
13379 	    ctxt->context->node = bak;
13380 	    ctxt->context->proximityPosition = pp;
13381 	    ctxt->context->contextSize = cs;
13382             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13383 	    CHECK_ERROR0;
13384 	    if (op->value)
13385 		equal = xmlXPathEqualValues(ctxt);
13386 	    else
13387 		equal = xmlXPathNotEqualValues(ctxt);
13388 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13389             return (total);
13390         case XPATH_OP_CMP:
13391 	    bakd = ctxt->context->doc;
13392 	    bak = ctxt->context->node;
13393 	    pp = ctxt->context->proximityPosition;
13394 	    cs = ctxt->context->contextSize;
13395             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13396 	    CHECK_ERROR0;
13397 	    ctxt->context->doc = bakd;
13398 	    ctxt->context->node = bak;
13399 	    ctxt->context->proximityPosition = pp;
13400 	    ctxt->context->contextSize = cs;
13401             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13402 	    CHECK_ERROR0;
13403             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13404 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13405             return (total);
13406         case XPATH_OP_PLUS:
13407 	    bakd = ctxt->context->doc;
13408 	    bak = ctxt->context->node;
13409 	    pp = ctxt->context->proximityPosition;
13410 	    cs = ctxt->context->contextSize;
13411             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13412 	    CHECK_ERROR0;
13413             if (op->ch2 != -1) {
13414 		ctxt->context->doc = bakd;
13415 		ctxt->context->node = bak;
13416 		ctxt->context->proximityPosition = pp;
13417 		ctxt->context->contextSize = cs;
13418                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13419 	    }
13420 	    CHECK_ERROR0;
13421             if (op->value == 0)
13422                 xmlXPathSubValues(ctxt);
13423             else if (op->value == 1)
13424                 xmlXPathAddValues(ctxt);
13425             else if (op->value == 2)
13426                 xmlXPathValueFlipSign(ctxt);
13427             else if (op->value == 3) {
13428                 CAST_TO_NUMBER;
13429                 CHECK_TYPE0(XPATH_NUMBER);
13430             }
13431             return (total);
13432         case XPATH_OP_MULT:
13433 	    bakd = ctxt->context->doc;
13434 	    bak = ctxt->context->node;
13435 	    pp = ctxt->context->proximityPosition;
13436 	    cs = ctxt->context->contextSize;
13437             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13438 	    CHECK_ERROR0;
13439 	    ctxt->context->doc = bakd;
13440 	    ctxt->context->node = bak;
13441 	    ctxt->context->proximityPosition = pp;
13442 	    ctxt->context->contextSize = cs;
13443             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13444 	    CHECK_ERROR0;
13445             if (op->value == 0)
13446                 xmlXPathMultValues(ctxt);
13447             else if (op->value == 1)
13448                 xmlXPathDivValues(ctxt);
13449             else if (op->value == 2)
13450                 xmlXPathModValues(ctxt);
13451             return (total);
13452         case XPATH_OP_UNION:
13453 	    bakd = ctxt->context->doc;
13454 	    bak = ctxt->context->node;
13455 	    pp = ctxt->context->proximityPosition;
13456 	    cs = ctxt->context->contextSize;
13457             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13458 	    CHECK_ERROR0;
13459 	    ctxt->context->doc = bakd;
13460 	    ctxt->context->node = bak;
13461 	    ctxt->context->proximityPosition = pp;
13462 	    ctxt->context->contextSize = cs;
13463             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13464 	    CHECK_ERROR0;
13465 
13466             arg2 = valuePop(ctxt);
13467             arg1 = valuePop(ctxt);
13468             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13469                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13470 	        xmlXPathReleaseObject(ctxt->context, arg1);
13471 	        xmlXPathReleaseObject(ctxt->context, arg2);
13472                 XP_ERROR0(XPATH_INVALID_TYPE);
13473             }
13474 
13475 	    if ((arg1->nodesetval == NULL) ||
13476 		((arg2->nodesetval != NULL) &&
13477 		 (arg2->nodesetval->nodeNr != 0)))
13478 	    {
13479 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13480 							arg2->nodesetval);
13481 	    }
13482 
13483             valuePush(ctxt, arg1);
13484 	    xmlXPathReleaseObject(ctxt->context, arg2);
13485             return (total);
13486         case XPATH_OP_ROOT:
13487             xmlXPathRoot(ctxt);
13488             return (total);
13489         case XPATH_OP_NODE:
13490             if (op->ch1 != -1)
13491                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13492 	    CHECK_ERROR0;
13493             if (op->ch2 != -1)
13494                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13495 	    CHECK_ERROR0;
13496 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13497 		ctxt->context->node));
13498             return (total);
13499         case XPATH_OP_RESET:
13500             if (op->ch1 != -1)
13501                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13502 	    CHECK_ERROR0;
13503             if (op->ch2 != -1)
13504                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13505 	    CHECK_ERROR0;
13506             ctxt->context->node = NULL;
13507             return (total);
13508         case XPATH_OP_COLLECT:{
13509                 if (op->ch1 == -1)
13510                     return (total);
13511 
13512                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13513 		CHECK_ERROR0;
13514 
13515                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13516                 return (total);
13517             }
13518         case XPATH_OP_VALUE:
13519             valuePush(ctxt,
13520                       xmlXPathCacheObjectCopy(ctxt->context,
13521 			(xmlXPathObjectPtr) op->value4));
13522             return (total);
13523         case XPATH_OP_VARIABLE:{
13524 		xmlXPathObjectPtr val;
13525 
13526                 if (op->ch1 != -1)
13527                     total +=
13528                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13529                 if (op->value5 == NULL) {
13530 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13531 		    if (val == NULL)
13532 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13533                     valuePush(ctxt, val);
13534 		} else {
13535                     const xmlChar *URI;
13536 
13537                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13538                     if (URI == NULL) {
13539                         xmlGenericError(xmlGenericErrorContext,
13540             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13541                                     (char *) op->value4, (char *)op->value5);
13542                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13543                         return (total);
13544                     }
13545 		    val = xmlXPathVariableLookupNS(ctxt->context,
13546                                                        op->value4, URI);
13547 		    if (val == NULL)
13548 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13549                     valuePush(ctxt, val);
13550                 }
13551                 return (total);
13552             }
13553         case XPATH_OP_FUNCTION:{
13554                 xmlXPathFunction func;
13555                 const xmlChar *oldFunc, *oldFuncURI;
13556 		int i;
13557                 int frame;
13558 
13559                 frame = xmlXPathSetFrame(ctxt);
13560                 if (op->ch1 != -1) {
13561                     total +=
13562                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13563                     if (ctxt->error != XPATH_EXPRESSION_OK) {
13564                         xmlXPathPopFrame(ctxt, frame);
13565                         return (total);
13566                     }
13567                 }
13568 		if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13569 		    xmlGenericError(xmlGenericErrorContext,
13570 			    "xmlXPathCompOpEval: parameter error\n");
13571 		    ctxt->error = XPATH_INVALID_OPERAND;
13572                     xmlXPathPopFrame(ctxt, frame);
13573 		    return (total);
13574 		}
13575 		for (i = 0; i < op->value; i++) {
13576 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13577 			xmlGenericError(xmlGenericErrorContext,
13578 				"xmlXPathCompOpEval: parameter error\n");
13579 			ctxt->error = XPATH_INVALID_OPERAND;
13580                         xmlXPathPopFrame(ctxt, frame);
13581 			return (total);
13582 		    }
13583                 }
13584                 if (op->cache != NULL)
13585                     func = op->cache;
13586                 else {
13587                     const xmlChar *URI = NULL;
13588 
13589                     if (op->value5 == NULL)
13590                         func =
13591                             xmlXPathFunctionLookup(ctxt->context,
13592                                                    op->value4);
13593                     else {
13594                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13595                         if (URI == NULL) {
13596                             xmlGenericError(xmlGenericErrorContext,
13597             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13598                                     (char *)op->value4, (char *)op->value5);
13599                             xmlXPathPopFrame(ctxt, frame);
13600                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13601                             return (total);
13602                         }
13603                         func = xmlXPathFunctionLookupNS(ctxt->context,
13604                                                         op->value4, URI);
13605                     }
13606                     if (func == NULL) {
13607                         xmlGenericError(xmlGenericErrorContext,
13608                                 "xmlXPathCompOpEval: function %s not found\n",
13609                                         (char *)op->value4);
13610                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13611                     }
13612                     op->cache = func;
13613                     op->cacheURI = (void *) URI;
13614                 }
13615                 oldFunc = ctxt->context->function;
13616                 oldFuncURI = ctxt->context->functionURI;
13617                 ctxt->context->function = op->value4;
13618                 ctxt->context->functionURI = op->cacheURI;
13619                 func(ctxt, op->value);
13620                 ctxt->context->function = oldFunc;
13621                 ctxt->context->functionURI = oldFuncURI;
13622                 xmlXPathPopFrame(ctxt, frame);
13623                 return (total);
13624             }
13625         case XPATH_OP_ARG:
13626 	    bakd = ctxt->context->doc;
13627 	    bak = ctxt->context->node;
13628 	    pp = ctxt->context->proximityPosition;
13629 	    cs = ctxt->context->contextSize;
13630             if (op->ch1 != -1) {
13631                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13632                 ctxt->context->contextSize = cs;
13633                 ctxt->context->proximityPosition = pp;
13634                 ctxt->context->node = bak;
13635                 ctxt->context->doc = bakd;
13636 	        CHECK_ERROR0;
13637             }
13638             if (op->ch2 != -1) {
13639                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13640                 ctxt->context->contextSize = cs;
13641                 ctxt->context->proximityPosition = pp;
13642                 ctxt->context->node = bak;
13643                 ctxt->context->doc = bakd;
13644 	        CHECK_ERROR0;
13645 	    }
13646             return (total);
13647         case XPATH_OP_PREDICATE:
13648         case XPATH_OP_FILTER:{
13649                 xmlXPathObjectPtr res;
13650                 xmlXPathObjectPtr obj, tmp;
13651                 xmlNodeSetPtr newset = NULL;
13652                 xmlNodeSetPtr oldset;
13653                 xmlNodePtr oldnode;
13654 		xmlDocPtr oldDoc;
13655                 int i;
13656 
13657                 /*
13658                  * Optimization for ()[1] selection i.e. the first elem
13659                  */
13660                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13661 #ifdef XP_OPTIMIZED_FILTER_FIRST
13662 		    /*
13663 		    * FILTER TODO: Can we assume that the inner processing
13664 		    *  will result in an ordered list if we have an
13665 		    *  XPATH_OP_FILTER?
13666 		    *  What about an additional field or flag on
13667 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13668 		    *  to assume anything, so it would be more robust and
13669 		    *  easier to optimize.
13670 		    */
13671                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13672 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13673 #else
13674 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13675 #endif
13676                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13677                     xmlXPathObjectPtr val;
13678 
13679                     val = comp->steps[op->ch2].value4;
13680                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13681                         (val->floatval == 1.0)) {
13682                         xmlNodePtr first = NULL;
13683 
13684                         total +=
13685                             xmlXPathCompOpEvalFirst(ctxt,
13686                                                     &comp->steps[op->ch1],
13687                                                     &first);
13688 			CHECK_ERROR0;
13689                         /*
13690                          * The nodeset should be in document order,
13691                          * Keep only the first value
13692                          */
13693                         if ((ctxt->value != NULL) &&
13694                             (ctxt->value->type == XPATH_NODESET) &&
13695                             (ctxt->value->nodesetval != NULL) &&
13696                             (ctxt->value->nodesetval->nodeNr > 1))
13697                             xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13698                                                         1, 1);
13699                         return (total);
13700                     }
13701                 }
13702                 /*
13703                  * Optimization for ()[last()] selection i.e. the last elem
13704                  */
13705                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13706                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13707                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13708                     int f = comp->steps[op->ch2].ch1;
13709 
13710                     if ((f != -1) &&
13711                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13712                         (comp->steps[f].value5 == NULL) &&
13713                         (comp->steps[f].value == 0) &&
13714                         (comp->steps[f].value4 != NULL) &&
13715                         (xmlStrEqual
13716                          (comp->steps[f].value4, BAD_CAST "last"))) {
13717                         xmlNodePtr last = NULL;
13718 
13719                         total +=
13720                             xmlXPathCompOpEvalLast(ctxt,
13721                                                    &comp->steps[op->ch1],
13722                                                    &last);
13723 			CHECK_ERROR0;
13724                         /*
13725                          * The nodeset should be in document order,
13726                          * Keep only the last value
13727                          */
13728                         if ((ctxt->value != NULL) &&
13729                             (ctxt->value->type == XPATH_NODESET) &&
13730                             (ctxt->value->nodesetval != NULL) &&
13731                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13732                             (ctxt->value->nodesetval->nodeNr > 1))
13733                             xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13734                         return (total);
13735                     }
13736                 }
13737 		/*
13738 		* Process inner predicates first.
13739 		* Example "index[parent::book][1]":
13740 		* ...
13741 		*   PREDICATE   <-- we are here "[1]"
13742 		*     PREDICATE <-- process "[parent::book]" first
13743 		*       SORT
13744 		*         COLLECT  'parent' 'name' 'node' book
13745 		*           NODE
13746 		*     ELEM Object is a number : 1
13747 		*/
13748                 if (op->ch1 != -1)
13749                     total +=
13750                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13751 		CHECK_ERROR0;
13752                 if (op->ch2 == -1)
13753                     return (total);
13754                 if (ctxt->value == NULL)
13755                     return (total);
13756 
13757                 oldnode = ctxt->context->node;
13758 
13759 #ifdef LIBXML_XPTR_ENABLED
13760                 /*
13761                  * Hum are we filtering the result of an XPointer expression
13762                  */
13763                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13764                     xmlLocationSetPtr newlocset = NULL;
13765                     xmlLocationSetPtr oldlocset;
13766 
13767                     /*
13768                      * Extract the old locset, and then evaluate the result of the
13769                      * expression for all the element in the locset. use it to grow
13770                      * up a new locset.
13771                      */
13772                     CHECK_TYPE0(XPATH_LOCATIONSET);
13773                     obj = valuePop(ctxt);
13774                     oldlocset = obj->user;
13775                     ctxt->context->node = NULL;
13776 
13777                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13778                         ctxt->context->contextSize = 0;
13779                         ctxt->context->proximityPosition = 0;
13780                         if (op->ch2 != -1)
13781                             total +=
13782                                 xmlXPathCompOpEval(ctxt,
13783                                                    &comp->steps[op->ch2]);
13784                         res = valuePop(ctxt);
13785                         if (res != NULL) {
13786 			    xmlXPathReleaseObject(ctxt->context, res);
13787 			}
13788                         valuePush(ctxt, obj);
13789                         CHECK_ERROR0;
13790                         return (total);
13791                     }
13792                     newlocset = xmlXPtrLocationSetCreate(NULL);
13793 
13794                     for (i = 0; i < oldlocset->locNr; i++) {
13795                         /*
13796                          * Run the evaluation with a node list made of a
13797                          * single item in the nodelocset.
13798                          */
13799                         ctxt->context->node = oldlocset->locTab[i]->user;
13800                         ctxt->context->contextSize = oldlocset->locNr;
13801                         ctxt->context->proximityPosition = i + 1;
13802 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13803 			    ctxt->context->node);
13804                         valuePush(ctxt, tmp);
13805 
13806                         if (op->ch2 != -1)
13807                             total +=
13808                                 xmlXPathCompOpEval(ctxt,
13809                                                    &comp->steps[op->ch2]);
13810 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13811 			    xmlXPathFreeObject(obj);
13812 			    return(0);
13813 			}
13814 
13815                         /*
13816                          * The result of the evaluation need to be tested to
13817                          * decided whether the filter succeeded or not
13818                          */
13819                         res = valuePop(ctxt);
13820                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13821                             xmlXPtrLocationSetAdd(newlocset,
13822                                                   xmlXPathObjectCopy
13823                                                   (oldlocset->locTab[i]));
13824                         }
13825 
13826                         /*
13827                          * Cleanup
13828                          */
13829                         if (res != NULL) {
13830 			    xmlXPathReleaseObject(ctxt->context, res);
13831 			}
13832                         if (ctxt->value == tmp) {
13833                             res = valuePop(ctxt);
13834 			    xmlXPathReleaseObject(ctxt->context, res);
13835                         }
13836 
13837                         ctxt->context->node = NULL;
13838                     }
13839 
13840                     /*
13841                      * The result is used as the new evaluation locset.
13842                      */
13843 		    xmlXPathReleaseObject(ctxt->context, obj);
13844                     ctxt->context->node = NULL;
13845                     ctxt->context->contextSize = -1;
13846                     ctxt->context->proximityPosition = -1;
13847                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13848                     ctxt->context->node = oldnode;
13849                     return (total);
13850                 }
13851 #endif /* LIBXML_XPTR_ENABLED */
13852 
13853                 /*
13854                  * Extract the old set, and then evaluate the result of the
13855                  * expression for all the element in the set. use it to grow
13856                  * up a new set.
13857                  */
13858                 CHECK_TYPE0(XPATH_NODESET);
13859                 obj = valuePop(ctxt);
13860                 oldset = obj->nodesetval;
13861 
13862                 oldnode = ctxt->context->node;
13863 		oldDoc = ctxt->context->doc;
13864                 ctxt->context->node = NULL;
13865 
13866                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13867                     ctxt->context->contextSize = 0;
13868                     ctxt->context->proximityPosition = 0;
13869 /*
13870                     if (op->ch2 != -1)
13871                         total +=
13872                             xmlXPathCompOpEval(ctxt,
13873                                                &comp->steps[op->ch2]);
13874 		    CHECK_ERROR0;
13875                     res = valuePop(ctxt);
13876                     if (res != NULL)
13877                         xmlXPathFreeObject(res);
13878 */
13879                     valuePush(ctxt, obj);
13880                     ctxt->context->node = oldnode;
13881                     CHECK_ERROR0;
13882                 } else {
13883 		    tmp = NULL;
13884                     /*
13885                      * Initialize the new set.
13886 		     * Also set the xpath document in case things like
13887 		     * key() evaluation are attempted on the predicate
13888                      */
13889                     newset = xmlXPathNodeSetCreate(NULL);
13890 		    /*
13891 		    * SPEC XPath 1.0:
13892 		    *  "For each node in the node-set to be filtered, the
13893 		    *  PredicateExpr is evaluated with that node as the
13894 		    *  context node, with the number of nodes in the
13895 		    *  node-set as the context size, and with the proximity
13896 		    *  position of the node in the node-set with respect to
13897 		    *  the axis as the context position;"
13898 		    * @oldset is the node-set" to be filtered.
13899 		    *
13900 		    * SPEC XPath 1.0:
13901 		    *  "only predicates change the context position and
13902 		    *  context size (see [2.4 Predicates])."
13903 		    * Example:
13904 		    *   node-set  context pos
13905 		    *    nA         1
13906 		    *    nB         2
13907 		    *    nC         3
13908 		    *   After applying predicate [position() > 1] :
13909 		    *   node-set  context pos
13910 		    *    nB         1
13911 		    *    nC         2
13912 		    *
13913 		    * removed the first node in the node-set, then
13914 		    * the context position of the
13915 		    */
13916                     for (i = 0; i < oldset->nodeNr; i++) {
13917                         /*
13918                          * Run the evaluation with a node list made of
13919                          * a single item in the nodeset.
13920                          */
13921                         ctxt->context->node = oldset->nodeTab[i];
13922 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13923 			    (oldset->nodeTab[i]->doc != NULL))
13924 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13925 			if (tmp == NULL) {
13926 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13927 				ctxt->context->node);
13928 			} else {
13929 			    if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13930 				               ctxt->context->node) < 0) {
13931 				ctxt->error = XPATH_MEMORY_ERROR;
13932 			    }
13933 			}
13934                         valuePush(ctxt, tmp);
13935                         ctxt->context->contextSize = oldset->nodeNr;
13936                         ctxt->context->proximityPosition = i + 1;
13937 			/*
13938 			* Evaluate the predicate against the context node.
13939 			* Can/should we optimize position() predicates
13940 			* here (e.g. "[1]")?
13941 			*/
13942                         if (op->ch2 != -1)
13943                             total +=
13944                                 xmlXPathCompOpEval(ctxt,
13945                                                    &comp->steps[op->ch2]);
13946 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13947 			    xmlXPathFreeNodeSet(newset);
13948 			    xmlXPathFreeObject(obj);
13949 			    return(0);
13950 			}
13951 
13952                         /*
13953                          * The result of the evaluation needs to be tested to
13954                          * decide whether the filter succeeded or not
13955                          */
13956 			/*
13957 			* OPTIMIZE TODO: Can we use
13958 			* xmlXPathNodeSetAdd*Unique()* instead?
13959 			*/
13960                         res = valuePop(ctxt);
13961                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13962                             if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13963 			        < 0)
13964 				ctxt->error = XPATH_MEMORY_ERROR;
13965                         }
13966 
13967                         /*
13968                          * Cleanup
13969                          */
13970                         if (res != NULL) {
13971 			    xmlXPathReleaseObject(ctxt->context, res);
13972 			}
13973                         if (ctxt->value == tmp) {
13974                             valuePop(ctxt);
13975 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13976 			    /*
13977 			    * Don't free the temporary nodeset
13978 			    * in order to avoid massive recreation inside this
13979 			    * loop.
13980 			    */
13981                         } else
13982 			    tmp = NULL;
13983                         ctxt->context->node = NULL;
13984                     }
13985 		    if (tmp != NULL)
13986 			xmlXPathReleaseObject(ctxt->context, tmp);
13987                     /*
13988                      * The result is used as the new evaluation set.
13989                      */
13990 		    xmlXPathReleaseObject(ctxt->context, obj);
13991                     ctxt->context->node = NULL;
13992                     ctxt->context->contextSize = -1;
13993                     ctxt->context->proximityPosition = -1;
13994 		    /* may want to move this past the '}' later */
13995 		    ctxt->context->doc = oldDoc;
13996 		    valuePush(ctxt,
13997 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13998                 }
13999                 ctxt->context->node = oldnode;
14000                 return (total);
14001             }
14002         case XPATH_OP_SORT:
14003             if (op->ch1 != -1)
14004                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
14005 	    CHECK_ERROR0;
14006             if ((ctxt->value != NULL) &&
14007                 (ctxt->value->type == XPATH_NODESET) &&
14008                 (ctxt->value->nodesetval != NULL) &&
14009 		(ctxt->value->nodesetval->nodeNr > 1))
14010 	    {
14011                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
14012 	    }
14013             return (total);
14014 #ifdef LIBXML_XPTR_ENABLED
14015         case XPATH_OP_RANGETO:{
14016                 xmlXPathObjectPtr range;
14017                 xmlXPathObjectPtr res, obj;
14018                 xmlXPathObjectPtr tmp;
14019                 xmlLocationSetPtr newlocset = NULL;
14020 		    xmlLocationSetPtr oldlocset;
14021                 xmlNodeSetPtr oldset;
14022                 int i, j;
14023 
14024                 if (op->ch1 != -1) {
14025                     total +=
14026                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
14027                     CHECK_ERROR0;
14028                 }
14029                 if (ctxt->value == NULL) {
14030                     XP_ERROR0(XPATH_INVALID_OPERAND);
14031                 }
14032                 if (op->ch2 == -1)
14033                     return (total);
14034 
14035                 if (ctxt->value->type == XPATH_LOCATIONSET) {
14036                     /*
14037                      * Extract the old locset, and then evaluate the result of the
14038                      * expression for all the element in the locset. use it to grow
14039                      * up a new locset.
14040                      */
14041                     CHECK_TYPE0(XPATH_LOCATIONSET);
14042                     obj = valuePop(ctxt);
14043                     oldlocset = obj->user;
14044 
14045                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
14046 		        ctxt->context->node = NULL;
14047                         ctxt->context->contextSize = 0;
14048                         ctxt->context->proximityPosition = 0;
14049                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
14050                         res = valuePop(ctxt);
14051                         if (res != NULL) {
14052 			    xmlXPathReleaseObject(ctxt->context, res);
14053 			}
14054                         valuePush(ctxt, obj);
14055                         CHECK_ERROR0;
14056                         return (total);
14057                     }
14058                     newlocset = xmlXPtrLocationSetCreate(NULL);
14059 
14060                     for (i = 0; i < oldlocset->locNr; i++) {
14061                         /*
14062                          * Run the evaluation with a node list made of a
14063                          * single item in the nodelocset.
14064                          */
14065                         ctxt->context->node = oldlocset->locTab[i]->user;
14066                         ctxt->context->contextSize = oldlocset->locNr;
14067                         ctxt->context->proximityPosition = i + 1;
14068 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14069 			    ctxt->context->node);
14070                         valuePush(ctxt, tmp);
14071 
14072                         if (op->ch2 != -1)
14073                             total +=
14074                                 xmlXPathCompOpEval(ctxt,
14075                                                    &comp->steps[op->ch2]);
14076 			if (ctxt->error != XPATH_EXPRESSION_OK) {
14077 			    xmlXPathFreeObject(obj);
14078 			    return(0);
14079 			}
14080 
14081                         res = valuePop(ctxt);
14082 			if (res->type == XPATH_LOCATIONSET) {
14083 			    xmlLocationSetPtr rloc =
14084 			        (xmlLocationSetPtr)res->user;
14085 			    for (j=0; j<rloc->locNr; j++) {
14086 			        range = xmlXPtrNewRange(
14087 				  oldlocset->locTab[i]->user,
14088 				  oldlocset->locTab[i]->index,
14089 				  rloc->locTab[j]->user2,
14090 				  rloc->locTab[j]->index2);
14091 				if (range != NULL) {
14092 				    xmlXPtrLocationSetAdd(newlocset, range);
14093 				}
14094 			    }
14095 			} else {
14096 			    range = xmlXPtrNewRangeNodeObject(
14097 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
14098                             if (range != NULL) {
14099                                 xmlXPtrLocationSetAdd(newlocset,range);
14100 			    }
14101                         }
14102 
14103                         /*
14104                          * Cleanup
14105                          */
14106                         if (res != NULL) {
14107 			    xmlXPathReleaseObject(ctxt->context, res);
14108 			}
14109                         if (ctxt->value == tmp) {
14110                             res = valuePop(ctxt);
14111 			    xmlXPathReleaseObject(ctxt->context, res);
14112                         }
14113 
14114                         ctxt->context->node = NULL;
14115                     }
14116 		} else {	/* Not a location set */
14117                     CHECK_TYPE0(XPATH_NODESET);
14118                     obj = valuePop(ctxt);
14119                     oldset = obj->nodesetval;
14120                     ctxt->context->node = NULL;
14121 
14122                     newlocset = xmlXPtrLocationSetCreate(NULL);
14123 
14124                     if (oldset != NULL) {
14125                         for (i = 0; i < oldset->nodeNr; i++) {
14126                             /*
14127                              * Run the evaluation with a node list made of a single item
14128                              * in the nodeset.
14129                              */
14130                             ctxt->context->node = oldset->nodeTab[i];
14131 			    /*
14132 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
14133 			    */
14134 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14135 				ctxt->context->node);
14136                             valuePush(ctxt, tmp);
14137 
14138                             if (op->ch2 != -1)
14139                                 total +=
14140                                     xmlXPathCompOpEval(ctxt,
14141                                                    &comp->steps[op->ch2]);
14142 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
14143 				xmlXPathFreeObject(obj);
14144 				return(0);
14145 			    }
14146 
14147                             res = valuePop(ctxt);
14148                             range =
14149                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14150                                                       res);
14151                             if (range != NULL) {
14152                                 xmlXPtrLocationSetAdd(newlocset, range);
14153                             }
14154 
14155                             /*
14156                              * Cleanup
14157                              */
14158                             if (res != NULL) {
14159 				xmlXPathReleaseObject(ctxt->context, res);
14160 			    }
14161                             if (ctxt->value == tmp) {
14162                                 res = valuePop(ctxt);
14163 				xmlXPathReleaseObject(ctxt->context, res);
14164                             }
14165 
14166                             ctxt->context->node = NULL;
14167                         }
14168                     }
14169                 }
14170 
14171                 /*
14172                  * The result is used as the new evaluation set.
14173                  */
14174 		xmlXPathReleaseObject(ctxt->context, obj);
14175                 ctxt->context->node = NULL;
14176                 ctxt->context->contextSize = -1;
14177                 ctxt->context->proximityPosition = -1;
14178                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14179                 return (total);
14180             }
14181 #endif /* LIBXML_XPTR_ENABLED */
14182     }
14183     xmlGenericError(xmlGenericErrorContext,
14184                     "XPath: unknown precompiled operation %d\n", op->op);
14185     ctxt->error = XPATH_INVALID_OPERAND;
14186     return (total);
14187 }
14188 
14189 /**
14190  * xmlXPathCompOpEvalToBoolean:
14191  * @ctxt:  the XPath parser context
14192  *
14193  * Evaluates if the expression evaluates to true.
14194  *
14195  * Returns 1 if true, 0 if false and -1 on API or internal errors.
14196  */
14197 static int
14198 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14199 			    xmlXPathStepOpPtr op,
14200 			    int isPredicate)
14201 {
14202     xmlXPathObjectPtr resObj = NULL;
14203 
14204 start:
14205     /* comp = ctxt->comp; */
14206     switch (op->op) {
14207         case XPATH_OP_END:
14208             return (0);
14209 	case XPATH_OP_VALUE:
14210 	    resObj = (xmlXPathObjectPtr) op->value4;
14211 	    if (isPredicate)
14212 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14213 	    return(xmlXPathCastToBoolean(resObj));
14214 	case XPATH_OP_SORT:
14215 	    /*
14216 	    * We don't need sorting for boolean results. Skip this one.
14217 	    */
14218             if (op->ch1 != -1) {
14219 		op = &ctxt->comp->steps[op->ch1];
14220 		goto start;
14221 	    }
14222 	    return(0);
14223 	case XPATH_OP_COLLECT:
14224 	    if (op->ch1 == -1)
14225 		return(0);
14226 
14227             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14228 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14229 		return(-1);
14230 
14231             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14232 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14233 		return(-1);
14234 
14235 	    resObj = valuePop(ctxt);
14236 	    if (resObj == NULL)
14237 		return(-1);
14238 	    break;
14239 	default:
14240 	    /*
14241 	    * Fallback to call xmlXPathCompOpEval().
14242 	    */
14243 	    xmlXPathCompOpEval(ctxt, op);
14244 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14245 		return(-1);
14246 
14247 	    resObj = valuePop(ctxt);
14248 	    if (resObj == NULL)
14249 		return(-1);
14250 	    break;
14251     }
14252 
14253     if (resObj) {
14254 	int res;
14255 
14256 	if (resObj->type == XPATH_BOOLEAN) {
14257 	    res = resObj->boolval;
14258 	} else if (isPredicate) {
14259 	    /*
14260 	    * For predicates a result of type "number" is handled
14261 	    * differently:
14262 	    * SPEC XPath 1.0:
14263 	    * "If the result is a number, the result will be converted
14264 	    *  to true if the number is equal to the context position
14265 	    *  and will be converted to false otherwise;"
14266 	    */
14267 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14268 	} else {
14269 	    res = xmlXPathCastToBoolean(resObj);
14270 	}
14271 	xmlXPathReleaseObject(ctxt->context, resObj);
14272 	return(res);
14273     }
14274 
14275     return(0);
14276 }
14277 
14278 #ifdef XPATH_STREAMING
14279 /**
14280  * xmlXPathRunStreamEval:
14281  * @ctxt:  the XPath parser context with the compiled expression
14282  *
14283  * Evaluate the Precompiled Streamable XPath expression in the given context.
14284  */
14285 static int
14286 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14287 		      xmlXPathObjectPtr *resultSeq, int toBool)
14288 {
14289     int max_depth, min_depth;
14290     int from_root;
14291     int ret, depth;
14292     int eval_all_nodes;
14293     xmlNodePtr cur = NULL, limit = NULL;
14294     xmlStreamCtxtPtr patstream = NULL;
14295 
14296     int nb_nodes = 0;
14297 
14298     if ((ctxt == NULL) || (comp == NULL))
14299         return(-1);
14300     max_depth = xmlPatternMaxDepth(comp);
14301     if (max_depth == -1)
14302         return(-1);
14303     if (max_depth == -2)
14304         max_depth = 10000;
14305     min_depth = xmlPatternMinDepth(comp);
14306     if (min_depth == -1)
14307         return(-1);
14308     from_root = xmlPatternFromRoot(comp);
14309     if (from_root < 0)
14310         return(-1);
14311 #if 0
14312     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14313 #endif
14314 
14315     if (! toBool) {
14316 	if (resultSeq == NULL)
14317 	    return(-1);
14318 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14319 	if (*resultSeq == NULL)
14320 	    return(-1);
14321     }
14322 
14323     /*
14324      * handle the special cases of "/" amd "." being matched
14325      */
14326     if (min_depth == 0) {
14327 	if (from_root) {
14328 	    /* Select "/" */
14329 	    if (toBool)
14330 		return(1);
14331 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14332 		                     (xmlNodePtr) ctxt->doc);
14333 	} else {
14334 	    /* Select "self::node()" */
14335 	    if (toBool)
14336 		return(1);
14337 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14338 	}
14339     }
14340     if (max_depth == 0) {
14341 	return(0);
14342     }
14343 
14344     if (from_root) {
14345         cur = (xmlNodePtr)ctxt->doc;
14346     } else if (ctxt->node != NULL) {
14347         switch (ctxt->node->type) {
14348             case XML_ELEMENT_NODE:
14349             case XML_DOCUMENT_NODE:
14350             case XML_DOCUMENT_FRAG_NODE:
14351             case XML_HTML_DOCUMENT_NODE:
14352 #ifdef LIBXML_DOCB_ENABLED
14353             case XML_DOCB_DOCUMENT_NODE:
14354 #endif
14355 	        cur = ctxt->node;
14356 		break;
14357             case XML_ATTRIBUTE_NODE:
14358             case XML_TEXT_NODE:
14359             case XML_CDATA_SECTION_NODE:
14360             case XML_ENTITY_REF_NODE:
14361             case XML_ENTITY_NODE:
14362             case XML_PI_NODE:
14363             case XML_COMMENT_NODE:
14364             case XML_NOTATION_NODE:
14365             case XML_DTD_NODE:
14366             case XML_DOCUMENT_TYPE_NODE:
14367             case XML_ELEMENT_DECL:
14368             case XML_ATTRIBUTE_DECL:
14369             case XML_ENTITY_DECL:
14370             case XML_NAMESPACE_DECL:
14371             case XML_XINCLUDE_START:
14372             case XML_XINCLUDE_END:
14373 		break;
14374 	}
14375 	limit = cur;
14376     }
14377     if (cur == NULL) {
14378         return(0);
14379     }
14380 
14381     patstream = xmlPatternGetStreamCtxt(comp);
14382     if (patstream == NULL) {
14383 	/*
14384 	* QUESTION TODO: Is this an error?
14385 	*/
14386 	return(0);
14387     }
14388 
14389     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14390 
14391     if (from_root) {
14392 	ret = xmlStreamPush(patstream, NULL, NULL);
14393 	if (ret < 0) {
14394 	} else if (ret == 1) {
14395 	    if (toBool)
14396 		goto return_1;
14397 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14398 	}
14399     }
14400     depth = 0;
14401     goto scan_children;
14402 next_node:
14403     do {
14404         nb_nodes++;
14405 
14406 	switch (cur->type) {
14407 	    case XML_ELEMENT_NODE:
14408 	    case XML_TEXT_NODE:
14409 	    case XML_CDATA_SECTION_NODE:
14410 	    case XML_COMMENT_NODE:
14411 	    case XML_PI_NODE:
14412 		if (cur->type == XML_ELEMENT_NODE) {
14413 		    ret = xmlStreamPush(patstream, cur->name,
14414 				(cur->ns ? cur->ns->href : NULL));
14415 		} else if (eval_all_nodes)
14416 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14417 		else
14418 		    break;
14419 
14420 		if (ret < 0) {
14421 		    /* NOP. */
14422 		} else if (ret == 1) {
14423 		    if (toBool)
14424 			goto return_1;
14425 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14426 		        < 0) {
14427 			ctxt->lastError.domain = XML_FROM_XPATH;
14428 			ctxt->lastError.code = XML_ERR_NO_MEMORY;
14429 		    }
14430 		}
14431 		if ((cur->children == NULL) || (depth >= max_depth)) {
14432 		    ret = xmlStreamPop(patstream);
14433 		    while (cur->next != NULL) {
14434 			cur = cur->next;
14435 			if ((cur->type != XML_ENTITY_DECL) &&
14436 			    (cur->type != XML_DTD_NODE))
14437 			    goto next_node;
14438 		    }
14439 		}
14440 	    default:
14441 		break;
14442 	}
14443 
14444 scan_children:
14445 	if (cur->type == XML_NAMESPACE_DECL) break;
14446 	if ((cur->children != NULL) && (depth < max_depth)) {
14447 	    /*
14448 	     * Do not descend on entities declarations
14449 	     */
14450 	    if (cur->children->type != XML_ENTITY_DECL) {
14451 		cur = cur->children;
14452 		depth++;
14453 		/*
14454 		 * Skip DTDs
14455 		 */
14456 		if (cur->type != XML_DTD_NODE)
14457 		    continue;
14458 	    }
14459 	}
14460 
14461 	if (cur == limit)
14462 	    break;
14463 
14464 	while (cur->next != NULL) {
14465 	    cur = cur->next;
14466 	    if ((cur->type != XML_ENTITY_DECL) &&
14467 		(cur->type != XML_DTD_NODE))
14468 		goto next_node;
14469 	}
14470 
14471 	do {
14472 	    cur = cur->parent;
14473 	    depth--;
14474 	    if ((cur == NULL) || (cur == limit))
14475 	        goto done;
14476 	    if (cur->type == XML_ELEMENT_NODE) {
14477 		ret = xmlStreamPop(patstream);
14478 	    } else if ((eval_all_nodes) &&
14479 		((cur->type == XML_TEXT_NODE) ||
14480 		 (cur->type == XML_CDATA_SECTION_NODE) ||
14481 		 (cur->type == XML_COMMENT_NODE) ||
14482 		 (cur->type == XML_PI_NODE)))
14483 	    {
14484 		ret = xmlStreamPop(patstream);
14485 	    }
14486 	    if (cur->next != NULL) {
14487 		cur = cur->next;
14488 		break;
14489 	    }
14490 	} while (cur != NULL);
14491 
14492     } while ((cur != NULL) && (depth >= 0));
14493 
14494 done:
14495 
14496 #if 0
14497     printf("stream eval: checked %d nodes selected %d\n",
14498            nb_nodes, retObj->nodesetval->nodeNr);
14499 #endif
14500 
14501     if (patstream)
14502 	xmlFreeStreamCtxt(patstream);
14503     return(0);
14504 
14505 return_1:
14506     if (patstream)
14507 	xmlFreeStreamCtxt(patstream);
14508     return(1);
14509 }
14510 #endif /* XPATH_STREAMING */
14511 
14512 /**
14513  * xmlXPathRunEval:
14514  * @ctxt:  the XPath parser context with the compiled expression
14515  * @toBool:  evaluate to a boolean result
14516  *
14517  * Evaluate the Precompiled XPath expression in the given context.
14518  */
14519 static int
14520 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14521 {
14522     xmlXPathCompExprPtr comp;
14523 
14524     if ((ctxt == NULL) || (ctxt->comp == NULL))
14525 	return(-1);
14526 
14527     if (ctxt->valueTab == NULL) {
14528 	/* Allocate the value stack */
14529 	ctxt->valueTab = (xmlXPathObjectPtr *)
14530 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14531 	if (ctxt->valueTab == NULL) {
14532 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14533 	    xmlFree(ctxt);
14534 	}
14535 	ctxt->valueNr = 0;
14536 	ctxt->valueMax = 10;
14537 	ctxt->value = NULL;
14538         ctxt->valueFrame = 0;
14539     }
14540 #ifdef XPATH_STREAMING
14541     if (ctxt->comp->stream) {
14542 	int res;
14543 
14544 	if (toBool) {
14545 	    /*
14546 	    * Evaluation to boolean result.
14547 	    */
14548 	    res = xmlXPathRunStreamEval(ctxt->context,
14549 		ctxt->comp->stream, NULL, 1);
14550 	    if (res != -1)
14551 		return(res);
14552 	} else {
14553 	    xmlXPathObjectPtr resObj = NULL;
14554 
14555 	    /*
14556 	    * Evaluation to a sequence.
14557 	    */
14558 	    res = xmlXPathRunStreamEval(ctxt->context,
14559 		ctxt->comp->stream, &resObj, 0);
14560 
14561 	    if ((res != -1) && (resObj != NULL)) {
14562 		valuePush(ctxt, resObj);
14563 		return(0);
14564 	    }
14565 	    if (resObj != NULL)
14566 		xmlXPathReleaseObject(ctxt->context, resObj);
14567 	}
14568 	/*
14569 	* QUESTION TODO: This falls back to normal XPath evaluation
14570 	* if res == -1. Is this intended?
14571 	*/
14572     }
14573 #endif
14574     comp = ctxt->comp;
14575     if (comp->last < 0) {
14576 	xmlGenericError(xmlGenericErrorContext,
14577 	    "xmlXPathRunEval: last is less than zero\n");
14578 	return(-1);
14579     }
14580     if (toBool)
14581 	return(xmlXPathCompOpEvalToBoolean(ctxt,
14582 	    &comp->steps[comp->last], 0));
14583     else
14584 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14585 
14586     return(0);
14587 }
14588 
14589 /************************************************************************
14590  *									*
14591  *			Public interfaces				*
14592  *									*
14593  ************************************************************************/
14594 
14595 /**
14596  * xmlXPathEvalPredicate:
14597  * @ctxt:  the XPath context
14598  * @res:  the Predicate Expression evaluation result
14599  *
14600  * Evaluate a predicate result for the current node.
14601  * A PredicateExpr is evaluated by evaluating the Expr and converting
14602  * the result to a boolean. If the result is a number, the result will
14603  * be converted to true if the number is equal to the position of the
14604  * context node in the context node list (as returned by the position
14605  * function) and will be converted to false otherwise; if the result
14606  * is not a number, then the result will be converted as if by a call
14607  * to the boolean function.
14608  *
14609  * Returns 1 if predicate is true, 0 otherwise
14610  */
14611 int
14612 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14613     if ((ctxt == NULL) || (res == NULL)) return(0);
14614     switch (res->type) {
14615         case XPATH_BOOLEAN:
14616 	    return(res->boolval);
14617         case XPATH_NUMBER:
14618 	    return(res->floatval == ctxt->proximityPosition);
14619         case XPATH_NODESET:
14620         case XPATH_XSLT_TREE:
14621 	    if (res->nodesetval == NULL)
14622 		return(0);
14623 	    return(res->nodesetval->nodeNr != 0);
14624         case XPATH_STRING:
14625 	    return((res->stringval != NULL) &&
14626 	           (xmlStrlen(res->stringval) != 0));
14627         default:
14628 	    STRANGE
14629     }
14630     return(0);
14631 }
14632 
14633 /**
14634  * xmlXPathEvaluatePredicateResult:
14635  * @ctxt:  the XPath Parser context
14636  * @res:  the Predicate Expression evaluation result
14637  *
14638  * Evaluate a predicate result for the current node.
14639  * A PredicateExpr is evaluated by evaluating the Expr and converting
14640  * the result to a boolean. If the result is a number, the result will
14641  * be converted to true if the number is equal to the position of the
14642  * context node in the context node list (as returned by the position
14643  * function) and will be converted to false otherwise; if the result
14644  * is not a number, then the result will be converted as if by a call
14645  * to the boolean function.
14646  *
14647  * Returns 1 if predicate is true, 0 otherwise
14648  */
14649 int
14650 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14651                                 xmlXPathObjectPtr res) {
14652     if ((ctxt == NULL) || (res == NULL)) return(0);
14653     switch (res->type) {
14654         case XPATH_BOOLEAN:
14655 	    return(res->boolval);
14656         case XPATH_NUMBER:
14657 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14658 	    return((res->floatval == ctxt->context->proximityPosition) &&
14659 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14660 #else
14661 	    return(res->floatval == ctxt->context->proximityPosition);
14662 #endif
14663         case XPATH_NODESET:
14664         case XPATH_XSLT_TREE:
14665 	    if (res->nodesetval == NULL)
14666 		return(0);
14667 	    return(res->nodesetval->nodeNr != 0);
14668         case XPATH_STRING:
14669 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14670 #ifdef LIBXML_XPTR_ENABLED
14671 	case XPATH_LOCATIONSET:{
14672 	    xmlLocationSetPtr ptr = res->user;
14673 	    if (ptr == NULL)
14674 	        return(0);
14675 	    return (ptr->locNr != 0);
14676 	    }
14677 #endif
14678         default:
14679 	    STRANGE
14680     }
14681     return(0);
14682 }
14683 
14684 #ifdef XPATH_STREAMING
14685 /**
14686  * xmlXPathTryStreamCompile:
14687  * @ctxt: an XPath context
14688  * @str:  the XPath expression
14689  *
14690  * Try to compile the XPath expression as a streamable subset.
14691  *
14692  * Returns the compiled expression or NULL if failed to compile.
14693  */
14694 static xmlXPathCompExprPtr
14695 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14696     /*
14697      * Optimization: use streaming patterns when the XPath expression can
14698      * be compiled to a stream lookup
14699      */
14700     xmlPatternPtr stream;
14701     xmlXPathCompExprPtr comp;
14702     xmlDictPtr dict = NULL;
14703     const xmlChar **namespaces = NULL;
14704     xmlNsPtr ns;
14705     int i, j;
14706 
14707     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14708         (!xmlStrchr(str, '@'))) {
14709 	const xmlChar *tmp;
14710 
14711 	/*
14712 	 * We don't try to handle expressions using the verbose axis
14713 	 * specifiers ("::"), just the simplied form at this point.
14714 	 * Additionally, if there is no list of namespaces available and
14715 	 *  there's a ":" in the expression, indicating a prefixed QName,
14716 	 *  then we won't try to compile either. xmlPatterncompile() needs
14717 	 *  to have a list of namespaces at compilation time in order to
14718 	 *  compile prefixed name tests.
14719 	 */
14720 	tmp = xmlStrchr(str, ':');
14721 	if ((tmp != NULL) &&
14722 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14723 	    return(NULL);
14724 
14725 	if (ctxt != NULL) {
14726 	    dict = ctxt->dict;
14727 	    if (ctxt->nsNr > 0) {
14728 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14729 		if (namespaces == NULL) {
14730 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14731 		    return(NULL);
14732 		}
14733 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14734 		    ns = ctxt->namespaces[j];
14735 		    namespaces[i++] = ns->href;
14736 		    namespaces[i++] = ns->prefix;
14737 		}
14738 		namespaces[i++] = NULL;
14739 		namespaces[i] = NULL;
14740 	    }
14741 	}
14742 
14743 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14744 			&namespaces[0]);
14745 	if (namespaces != NULL) {
14746 	    xmlFree((xmlChar **)namespaces);
14747 	}
14748 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14749 	    comp = xmlXPathNewCompExpr();
14750 	    if (comp == NULL) {
14751 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14752 		return(NULL);
14753 	    }
14754 	    comp->stream = stream;
14755 	    comp->dict = dict;
14756 	    if (comp->dict)
14757 		xmlDictReference(comp->dict);
14758 	    return(comp);
14759 	}
14760 	xmlFreePattern(stream);
14761     }
14762     return(NULL);
14763 }
14764 #endif /* XPATH_STREAMING */
14765 
14766 static void
14767 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14768 {
14769     /*
14770     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14771     * internal representation.
14772     */
14773 
14774     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14775         (op->ch1 != -1) &&
14776         (op->ch2 == -1 /* no predicate */))
14777     {
14778         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14779 
14780         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14781             ((xmlXPathAxisVal) prevop->value ==
14782                 AXIS_DESCENDANT_OR_SELF) &&
14783             (prevop->ch2 == -1) &&
14784             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14785             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14786         {
14787             /*
14788             * This is a "descendant-or-self::node()" without predicates.
14789             * Try to eliminate it.
14790             */
14791 
14792             switch ((xmlXPathAxisVal) op->value) {
14793                 case AXIS_CHILD:
14794                 case AXIS_DESCENDANT:
14795                     /*
14796                     * Convert "descendant-or-self::node()/child::" or
14797                     * "descendant-or-self::node()/descendant::" to
14798                     * "descendant::"
14799                     */
14800                     op->ch1   = prevop->ch1;
14801                     op->value = AXIS_DESCENDANT;
14802                     break;
14803                 case AXIS_SELF:
14804                 case AXIS_DESCENDANT_OR_SELF:
14805                     /*
14806                     * Convert "descendant-or-self::node()/self::" or
14807                     * "descendant-or-self::node()/descendant-or-self::" to
14808                     * to "descendant-or-self::"
14809                     */
14810                     op->ch1   = prevop->ch1;
14811                     op->value = AXIS_DESCENDANT_OR_SELF;
14812                     break;
14813                 default:
14814                     break;
14815             }
14816 	}
14817     }
14818 
14819     /* OP_VALUE has invalid ch1. */
14820     if (op->op == XPATH_OP_VALUE)
14821         return;
14822 
14823     /* Recurse */
14824     if (op->ch1 != -1)
14825         xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14826     if (op->ch2 != -1)
14827 	xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14828 }
14829 
14830 /**
14831  * xmlXPathCtxtCompile:
14832  * @ctxt: an XPath context
14833  * @str:  the XPath expression
14834  *
14835  * Compile an XPath expression
14836  *
14837  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14838  *         the caller has to free the object.
14839  */
14840 xmlXPathCompExprPtr
14841 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14842     xmlXPathParserContextPtr pctxt;
14843     xmlXPathCompExprPtr comp;
14844 
14845 #ifdef XPATH_STREAMING
14846     comp = xmlXPathTryStreamCompile(ctxt, str);
14847     if (comp != NULL)
14848         return(comp);
14849 #endif
14850 
14851     xmlXPathInit();
14852 
14853     pctxt = xmlXPathNewParserContext(str, ctxt);
14854     if (pctxt == NULL)
14855         return NULL;
14856     xmlXPathCompileExpr(pctxt, 1);
14857 
14858     if( pctxt->error != XPATH_EXPRESSION_OK )
14859     {
14860         xmlXPathFreeParserContext(pctxt);
14861         return(NULL);
14862     }
14863 
14864     if (*pctxt->cur != 0) {
14865 	/*
14866 	 * aleksey: in some cases this line prints *second* error message
14867 	 * (see bug #78858) and probably this should be fixed.
14868 	 * However, we are not sure that all error messages are printed
14869 	 * out in other places. It's not critical so we leave it as-is for now
14870 	 */
14871 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14872 	comp = NULL;
14873     } else {
14874 	comp = pctxt->comp;
14875 	pctxt->comp = NULL;
14876     }
14877     xmlXPathFreeParserContext(pctxt);
14878 
14879     if (comp != NULL) {
14880 	comp->expr = xmlStrdup(str);
14881 #ifdef DEBUG_EVAL_COUNTS
14882 	comp->string = xmlStrdup(str);
14883 	comp->nb = 0;
14884 #endif
14885 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
14886 	    xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14887 	}
14888     }
14889     return(comp);
14890 }
14891 
14892 /**
14893  * xmlXPathCompile:
14894  * @str:  the XPath expression
14895  *
14896  * Compile an XPath expression
14897  *
14898  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14899  *         the caller has to free the object.
14900  */
14901 xmlXPathCompExprPtr
14902 xmlXPathCompile(const xmlChar *str) {
14903     return(xmlXPathCtxtCompile(NULL, str));
14904 }
14905 
14906 /**
14907  * xmlXPathCompiledEvalInternal:
14908  * @comp:  the compiled XPath expression
14909  * @ctxt:  the XPath context
14910  * @resObj: the resulting XPath object or NULL
14911  * @toBool: 1 if only a boolean result is requested
14912  *
14913  * Evaluate the Precompiled XPath expression in the given context.
14914  * The caller has to free @resObj.
14915  *
14916  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14917  *         the caller has to free the object.
14918  */
14919 static int
14920 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14921 			     xmlXPathContextPtr ctxt,
14922 			     xmlXPathObjectPtr *resObjPtr,
14923 			     int toBool)
14924 {
14925     xmlXPathParserContextPtr pctxt;
14926     xmlXPathObjectPtr resObj;
14927 #ifndef LIBXML_THREAD_ENABLED
14928     static int reentance = 0;
14929 #endif
14930     int res;
14931 
14932     CHECK_CTXT_NEG(ctxt)
14933 
14934     if (comp == NULL)
14935 	return(-1);
14936     xmlXPathInit();
14937 
14938 #ifndef LIBXML_THREAD_ENABLED
14939     reentance++;
14940     if (reentance > 1)
14941 	xmlXPathDisableOptimizer = 1;
14942 #endif
14943 
14944 #ifdef DEBUG_EVAL_COUNTS
14945     comp->nb++;
14946     if ((comp->string != NULL) && (comp->nb > 100)) {
14947 	fprintf(stderr, "100 x %s\n", comp->string);
14948 	comp->nb = 0;
14949     }
14950 #endif
14951     pctxt = xmlXPathCompParserContext(comp, ctxt);
14952     res = xmlXPathRunEval(pctxt, toBool);
14953 
14954     if (pctxt->error != XPATH_EXPRESSION_OK) {
14955         resObj = NULL;
14956     } else {
14957         resObj = valuePop(pctxt);
14958         if (resObj == NULL) {
14959             if (!toBool)
14960                 xmlGenericError(xmlGenericErrorContext,
14961                     "xmlXPathCompiledEval: No result on the stack.\n");
14962         } else if (pctxt->valueNr > 0) {
14963             xmlGenericError(xmlGenericErrorContext,
14964                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14965                 pctxt->valueNr);
14966         }
14967     }
14968 
14969     if (resObjPtr)
14970         *resObjPtr = resObj;
14971     else
14972         xmlXPathReleaseObject(ctxt, resObj);
14973 
14974     pctxt->comp = NULL;
14975     xmlXPathFreeParserContext(pctxt);
14976 #ifndef LIBXML_THREAD_ENABLED
14977     reentance--;
14978 #endif
14979 
14980     return(res);
14981 }
14982 
14983 /**
14984  * xmlXPathCompiledEval:
14985  * @comp:  the compiled XPath expression
14986  * @ctx:  the XPath context
14987  *
14988  * Evaluate the Precompiled XPath expression in the given context.
14989  *
14990  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14991  *         the caller has to free the object.
14992  */
14993 xmlXPathObjectPtr
14994 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14995 {
14996     xmlXPathObjectPtr res = NULL;
14997 
14998     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14999     return(res);
15000 }
15001 
15002 /**
15003  * xmlXPathCompiledEvalToBoolean:
15004  * @comp:  the compiled XPath expression
15005  * @ctxt:  the XPath context
15006  *
15007  * Applies the XPath boolean() function on the result of the given
15008  * compiled expression.
15009  *
15010  * Returns 1 if the expression evaluated to true, 0 if to false and
15011  *         -1 in API and internal errors.
15012  */
15013 int
15014 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
15015 			      xmlXPathContextPtr ctxt)
15016 {
15017     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
15018 }
15019 
15020 /**
15021  * xmlXPathEvalExpr:
15022  * @ctxt:  the XPath Parser context
15023  *
15024  * Parse and evaluate an XPath expression in the given context,
15025  * then push the result on the context stack
15026  */
15027 void
15028 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
15029 #ifdef XPATH_STREAMING
15030     xmlXPathCompExprPtr comp;
15031 #endif
15032 
15033     if (ctxt == NULL) return;
15034 
15035 #ifdef XPATH_STREAMING
15036     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
15037     if (comp != NULL) {
15038         if (ctxt->comp != NULL)
15039 	    xmlXPathFreeCompExpr(ctxt->comp);
15040         ctxt->comp = comp;
15041     } else
15042 #endif
15043     {
15044 	xmlXPathCompileExpr(ctxt, 1);
15045         CHECK_ERROR;
15046 
15047         /* Check for trailing characters. */
15048         if (*ctxt->cur != 0)
15049             XP_ERROR(XPATH_EXPR_ERROR);
15050 
15051 	if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
15052 	    xmlXPathOptimizeExpression(ctxt->comp,
15053 		&ctxt->comp->steps[ctxt->comp->last]);
15054     }
15055 
15056     xmlXPathRunEval(ctxt, 0);
15057 }
15058 
15059 /**
15060  * xmlXPathEval:
15061  * @str:  the XPath expression
15062  * @ctx:  the XPath context
15063  *
15064  * Evaluate the XPath Location Path in the given context.
15065  *
15066  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15067  *         the caller has to free the object.
15068  */
15069 xmlXPathObjectPtr
15070 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15071     xmlXPathParserContextPtr ctxt;
15072     xmlXPathObjectPtr res;
15073 
15074     CHECK_CTXT(ctx)
15075 
15076     xmlXPathInit();
15077 
15078     ctxt = xmlXPathNewParserContext(str, ctx);
15079     if (ctxt == NULL)
15080         return NULL;
15081     xmlXPathEvalExpr(ctxt);
15082 
15083     if (ctxt->error != XPATH_EXPRESSION_OK) {
15084 	res = NULL;
15085     } else {
15086 	res = valuePop(ctxt);
15087         if (res == NULL) {
15088             xmlGenericError(xmlGenericErrorContext,
15089                 "xmlXPathCompiledEval: No result on the stack.\n");
15090         } else if (ctxt->valueNr > 0) {
15091             xmlGenericError(xmlGenericErrorContext,
15092                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
15093                 ctxt->valueNr);
15094         }
15095     }
15096 
15097     xmlXPathFreeParserContext(ctxt);
15098     return(res);
15099 }
15100 
15101 /**
15102  * xmlXPathSetContextNode:
15103  * @node: the node to to use as the context node
15104  * @ctx:  the XPath context
15105  *
15106  * Sets 'node' as the context node. The node must be in the same
15107  * document as that associated with the context.
15108  *
15109  * Returns -1 in case of error or 0 if successful
15110  */
15111 int
15112 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15113     if ((node == NULL) || (ctx == NULL))
15114         return(-1);
15115 
15116     if (node->doc == ctx->doc) {
15117         ctx->node = node;
15118 	return(0);
15119     }
15120     return(-1);
15121 }
15122 
15123 /**
15124  * xmlXPathNodeEval:
15125  * @node: the node to to use as the context node
15126  * @str:  the XPath expression
15127  * @ctx:  the XPath context
15128  *
15129  * Evaluate the XPath Location Path in the given context. The node 'node'
15130  * is set as the context node. The context node is not restored.
15131  *
15132  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15133  *         the caller has to free the object.
15134  */
15135 xmlXPathObjectPtr
15136 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15137     if (str == NULL)
15138         return(NULL);
15139     if (xmlXPathSetContextNode(node, ctx) < 0)
15140         return(NULL);
15141     return(xmlXPathEval(str, ctx));
15142 }
15143 
15144 /**
15145  * xmlXPathEvalExpression:
15146  * @str:  the XPath expression
15147  * @ctxt:  the XPath context
15148  *
15149  * Alias for xmlXPathEval().
15150  *
15151  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15152  *         the caller has to free the object.
15153  */
15154 xmlXPathObjectPtr
15155 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15156     return(xmlXPathEval(str, ctxt));
15157 }
15158 
15159 /************************************************************************
15160  *									*
15161  *	Extra functions not pertaining to the XPath spec		*
15162  *									*
15163  ************************************************************************/
15164 /**
15165  * xmlXPathEscapeUriFunction:
15166  * @ctxt:  the XPath Parser context
15167  * @nargs:  the number of arguments
15168  *
15169  * Implement the escape-uri() XPath function
15170  *    string escape-uri(string $str, bool $escape-reserved)
15171  *
15172  * This function applies the URI escaping rules defined in section 2 of [RFC
15173  * 2396] to the string supplied as $uri-part, which typically represents all
15174  * or part of a URI. The effect of the function is to replace any special
15175  * character in the string by an escape sequence of the form %xx%yy...,
15176  * where xxyy... is the hexadecimal representation of the octets used to
15177  * represent the character in UTF-8.
15178  *
15179  * The set of characters that are escaped depends on the setting of the
15180  * boolean argument $escape-reserved.
15181  *
15182  * If $escape-reserved is true, all characters are escaped other than lower
15183  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15184  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15185  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15186  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15187  * A-F).
15188  *
15189  * If $escape-reserved is false, the behavior differs in that characters
15190  * referred to in [RFC 2396] as reserved characters are not escaped. These
15191  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15192  *
15193  * [RFC 2396] does not define whether escaped URIs should use lower case or
15194  * upper case for hexadecimal digits. To ensure that escaped URIs can be
15195  * compared using string comparison functions, this function must always use
15196  * the upper-case letters A-F.
15197  *
15198  * Generally, $escape-reserved should be set to true when escaping a string
15199  * that is to form a single part of a URI, and to false when escaping an
15200  * entire URI or URI reference.
15201  *
15202  * In the case of non-ascii characters, the string is encoded according to
15203  * utf-8 and then converted according to RFC 2396.
15204  *
15205  * Examples
15206  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15207  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15208  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15209  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15210  *
15211  */
15212 static void
15213 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15214     xmlXPathObjectPtr str;
15215     int escape_reserved;
15216     xmlBufPtr target;
15217     xmlChar *cptr;
15218     xmlChar escape[4];
15219 
15220     CHECK_ARITY(2);
15221 
15222     escape_reserved = xmlXPathPopBoolean(ctxt);
15223 
15224     CAST_TO_STRING;
15225     str = valuePop(ctxt);
15226 
15227     target = xmlBufCreate();
15228 
15229     escape[0] = '%';
15230     escape[3] = 0;
15231 
15232     if (target) {
15233 	for (cptr = str->stringval; *cptr; cptr++) {
15234 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
15235 		(*cptr >= 'a' && *cptr <= 'z') ||
15236 		(*cptr >= '0' && *cptr <= '9') ||
15237 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
15238 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
15239 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15240 		(*cptr == '%' &&
15241 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15242 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15243 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
15244 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15245 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15246 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15247 		(!escape_reserved &&
15248 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15249 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15250 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15251 		  *cptr == ','))) {
15252 		xmlBufAdd(target, cptr, 1);
15253 	    } else {
15254 		if ((*cptr >> 4) < 10)
15255 		    escape[1] = '0' + (*cptr >> 4);
15256 		else
15257 		    escape[1] = 'A' - 10 + (*cptr >> 4);
15258 		if ((*cptr & 0xF) < 10)
15259 		    escape[2] = '0' + (*cptr & 0xF);
15260 		else
15261 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
15262 
15263 		xmlBufAdd(target, &escape[0], 3);
15264 	    }
15265 	}
15266     }
15267     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15268 	xmlBufContent(target)));
15269     xmlBufFree(target);
15270     xmlXPathReleaseObject(ctxt->context, str);
15271 }
15272 
15273 /**
15274  * xmlXPathRegisterAllFunctions:
15275  * @ctxt:  the XPath context
15276  *
15277  * Registers all default XPath functions in this context
15278  */
15279 void
15280 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15281 {
15282     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15283                          xmlXPathBooleanFunction);
15284     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15285                          xmlXPathCeilingFunction);
15286     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15287                          xmlXPathCountFunction);
15288     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15289                          xmlXPathConcatFunction);
15290     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15291                          xmlXPathContainsFunction);
15292     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15293                          xmlXPathIdFunction);
15294     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15295                          xmlXPathFalseFunction);
15296     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15297                          xmlXPathFloorFunction);
15298     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15299                          xmlXPathLastFunction);
15300     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15301                          xmlXPathLangFunction);
15302     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15303                          xmlXPathLocalNameFunction);
15304     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15305                          xmlXPathNotFunction);
15306     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15307                          xmlXPathNameFunction);
15308     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15309                          xmlXPathNamespaceURIFunction);
15310     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15311                          xmlXPathNormalizeFunction);
15312     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15313                          xmlXPathNumberFunction);
15314     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15315                          xmlXPathPositionFunction);
15316     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15317                          xmlXPathRoundFunction);
15318     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15319                          xmlXPathStringFunction);
15320     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15321                          xmlXPathStringLengthFunction);
15322     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15323                          xmlXPathStartsWithFunction);
15324     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15325                          xmlXPathSubstringFunction);
15326     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15327                          xmlXPathSubstringBeforeFunction);
15328     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15329                          xmlXPathSubstringAfterFunction);
15330     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15331                          xmlXPathSumFunction);
15332     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15333                          xmlXPathTrueFunction);
15334     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15335                          xmlXPathTranslateFunction);
15336 
15337     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15338 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15339                          xmlXPathEscapeUriFunction);
15340 }
15341 
15342 #endif /* LIBXML_XPATH_ENABLED */
15343 #define bottom_xpath
15344 #include "elfgcchack.h"
15345