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#define IN_LIBXML
18#include "libxml.h"
19
20#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
31#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
34#ifdef HAVE_SIGNAL_H
35#include <signal.h>
36#endif
37
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
52#include <libxml/threads.h>
53#include <libxml/globals.h>
54#ifdef LIBXML_PATTERN_ENABLED
55#include <libxml/pattern.h>
56#endif
57
58#include "buf.h"
59
60#ifdef LIBXML_PATTERN_ENABLED
61#define XPATH_STREAMING
62#endif
63
64#define TODO								\
65    xmlGenericError(xmlGenericErrorContext,				\
66	    "Unimplemented block at %s:%d\n",				\
67            __FILE__, __LINE__);
68
69/**
70 * WITH_TIM_SORT:
71 *
72 * Use the Timsort algorithm provided in timsort.h to sort
73 * nodeset as this is a great improvement over the old Shell sort
74 * used in xmlXPathNodeSetSort()
75 */
76#define WITH_TIM_SORT
77
78/*
79* XP_OPTIMIZED_NON_ELEM_COMPARISON:
80* If defined, this will use xmlXPathCmpNodesExt() instead of
81* xmlXPathCmpNodes(). The new function is optimized comparison of
82* non-element nodes; actually it will speed up comparison only if
83* xmlXPathOrderDocElems() was called in order to index the elements of
84* a tree in document order; Libxslt does such an indexing, thus it will
85* benefit from this optimization.
86*/
87#define XP_OPTIMIZED_NON_ELEM_COMPARISON
88
89/*
90* XP_OPTIMIZED_FILTER_FIRST:
91* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
92* in a way, that it stop evaluation at the first node.
93*/
94#define XP_OPTIMIZED_FILTER_FIRST
95
96/*
97* XP_DEBUG_OBJ_USAGE:
98* Internal flag to enable tracking of how much XPath objects have been
99* created.
100*/
101/* #define XP_DEBUG_OBJ_USAGE */
102
103/*
104 * XPATH_MAX_STEPS:
105 * when compiling an XPath expression we arbitrary limit the maximum
106 * number of step operation in the compiled expression. 1000000 is
107 * an insanely large value which should never be reached under normal
108 * circumstances
109 */
110#define XPATH_MAX_STEPS 1000000
111
112/*
113 * XPATH_MAX_STACK_DEPTH:
114 * when evaluating an XPath expression we arbitrary limit the maximum
115 * number of object allowed to be pushed on the stack. 1000000 is
116 * an insanely large value which should never be reached under normal
117 * circumstances
118 */
119#define XPATH_MAX_STACK_DEPTH 1000000
120
121/*
122 * XPATH_MAX_NODESET_LENGTH:
123 * when evaluating an XPath expression nodesets are created and we
124 * arbitrary limit the maximum length of those node set. 10000000 is
125 * an insanely large value which should never be reached under normal
126 * circumstances, one would first need to construct an in memory tree
127 * with more than 10 millions nodes.
128 */
129#define XPATH_MAX_NODESET_LENGTH 10000000
130
131/*
132 * TODO:
133 * There are a few spots where some tests are done which depend upon ascii
134 * data.  These should be enhanced for full UTF8 support (see particularly
135 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
136 */
137
138#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
139/**
140 * xmlXPathCmpNodesExt:
141 * @node1:  the first node
142 * @node2:  the second node
143 *
144 * Compare two nodes w.r.t document order.
145 * This one is optimized for handling of non-element nodes.
146 *
147 * Returns -2 in case of error 1 if first point < second point, 0 if
148 *         it's the same node, -1 otherwise
149 */
150static int
151xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
152    int depth1, depth2;
153    int misc = 0, precedence1 = 0, precedence2 = 0;
154    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
155    xmlNodePtr cur, root;
156    long l1, l2;
157
158    if ((node1 == NULL) || (node2 == NULL))
159	return(-2);
160
161    if (node1 == node2)
162	return(0);
163
164    /*
165     * a couple of optimizations which will avoid computations in most cases
166     */
167    switch (node1->type) {
168	case XML_ELEMENT_NODE:
169	    if (node2->type == XML_ELEMENT_NODE) {
170		if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
171		    (0 > (long) node2->content) &&
172		    (node1->doc == node2->doc))
173		{
174		    l1 = -((long) node1->content);
175		    l2 = -((long) node2->content);
176		    if (l1 < l2)
177			return(1);
178		    if (l1 > l2)
179			return(-1);
180		} else
181		    goto turtle_comparison;
182	    }
183	    break;
184	case XML_ATTRIBUTE_NODE:
185	    precedence1 = 1; /* element is owner */
186	    miscNode1 = node1;
187	    node1 = node1->parent;
188	    misc = 1;
189	    break;
190	case XML_TEXT_NODE:
191	case XML_CDATA_SECTION_NODE:
192	case XML_COMMENT_NODE:
193	case XML_PI_NODE: {
194	    miscNode1 = node1;
195	    /*
196	    * Find nearest element node.
197	    */
198	    if (node1->prev != NULL) {
199		do {
200		    node1 = node1->prev;
201		    if (node1->type == XML_ELEMENT_NODE) {
202			precedence1 = 3; /* element in prev-sibl axis */
203			break;
204		    }
205		    if (node1->prev == NULL) {
206			precedence1 = 2; /* element is parent */
207			/*
208			* URGENT TODO: Are there any cases, where the
209			* parent of such a node is not an element node?
210			*/
211			node1 = node1->parent;
212			break;
213		    }
214		} while (1);
215	    } else {
216		precedence1 = 2; /* element is parent */
217		node1 = node1->parent;
218	    }
219	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
220		(0 <= (long) node1->content)) {
221		/*
222		* Fallback for whatever case.
223		*/
224		node1 = miscNode1;
225		precedence1 = 0;
226	    } else
227		misc = 1;
228	}
229	    break;
230	case XML_NAMESPACE_DECL:
231	    /*
232	    * TODO: why do we return 1 for namespace nodes?
233	    */
234	    return(1);
235	default:
236	    break;
237    }
238    switch (node2->type) {
239	case XML_ELEMENT_NODE:
240	    break;
241	case XML_ATTRIBUTE_NODE:
242	    precedence2 = 1; /* element is owner */
243	    miscNode2 = node2;
244	    node2 = node2->parent;
245	    misc = 1;
246	    break;
247	case XML_TEXT_NODE:
248	case XML_CDATA_SECTION_NODE:
249	case XML_COMMENT_NODE:
250	case XML_PI_NODE: {
251	    miscNode2 = node2;
252	    if (node2->prev != NULL) {
253		do {
254		    node2 = node2->prev;
255		    if (node2->type == XML_ELEMENT_NODE) {
256			precedence2 = 3; /* element in prev-sibl axis */
257			break;
258		    }
259		    if (node2->prev == NULL) {
260			precedence2 = 2; /* element is parent */
261			node2 = node2->parent;
262			break;
263		    }
264		} while (1);
265	    } else {
266		precedence2 = 2; /* element is parent */
267		node2 = node2->parent;
268	    }
269	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
270		(0 <= (long) node2->content))
271	    {
272		node2 = miscNode2;
273		precedence2 = 0;
274	    } else
275		misc = 1;
276	}
277	    break;
278	case XML_NAMESPACE_DECL:
279	    return(1);
280	default:
281	    break;
282    }
283    if (misc) {
284	if (node1 == node2) {
285	    if (precedence1 == precedence2) {
286		/*
287		* The ugly case; but normally there aren't many
288		* adjacent non-element nodes around.
289		*/
290		cur = miscNode2->prev;
291		while (cur != NULL) {
292		    if (cur == miscNode1)
293			return(1);
294		    if (cur->type == XML_ELEMENT_NODE)
295			return(-1);
296		    cur = cur->prev;
297		}
298		return (-1);
299	    } else {
300		/*
301		* Evaluate based on higher precedence wrt to the element.
302		* TODO: This assumes attributes are sorted before content.
303		*   Is this 100% correct?
304		*/
305		if (precedence1 < precedence2)
306		    return(1);
307		else
308		    return(-1);
309	    }
310	}
311	/*
312	* Special case: One of the helper-elements is contained by the other.
313	* <foo>
314	*   <node2>
315	*     <node1>Text-1(precedence1 == 2)</node1>
316	*   </node2>
317	*   Text-6(precedence2 == 3)
318	* </foo>
319	*/
320	if ((precedence2 == 3) && (precedence1 > 1)) {
321	    cur = node1->parent;
322	    while (cur) {
323		if (cur == node2)
324		    return(1);
325		cur = cur->parent;
326	    }
327	}
328	if ((precedence1 == 3) && (precedence2 > 1)) {
329	    cur = node2->parent;
330	    while (cur) {
331		if (cur == node1)
332		    return(-1);
333		cur = cur->parent;
334	    }
335	}
336    }
337
338    /*
339     * Speedup using document order if availble.
340     */
341    if ((node1->type == XML_ELEMENT_NODE) &&
342	(node2->type == XML_ELEMENT_NODE) &&
343	(0 > (long) node1->content) &&
344	(0 > (long) node2->content) &&
345	(node1->doc == node2->doc)) {
346
347	l1 = -((long) node1->content);
348	l2 = -((long) node2->content);
349	if (l1 < l2)
350	    return(1);
351	if (l1 > l2)
352	    return(-1);
353    }
354
355turtle_comparison:
356
357    if (node1 == node2->prev)
358	return(1);
359    if (node1 == node2->next)
360	return(-1);
361    /*
362     * compute depth to root
363     */
364    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
365	if (cur->parent == node1)
366	    return(1);
367	depth2++;
368    }
369    root = cur;
370    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
371	if (cur->parent == node2)
372	    return(-1);
373	depth1++;
374    }
375    /*
376     * Distinct document (or distinct entities :-( ) case.
377     */
378    if (root != cur) {
379	return(-2);
380    }
381    /*
382     * get the nearest common ancestor.
383     */
384    while (depth1 > depth2) {
385	depth1--;
386	node1 = node1->parent;
387    }
388    while (depth2 > depth1) {
389	depth2--;
390	node2 = node2->parent;
391    }
392    while (node1->parent != node2->parent) {
393	node1 = node1->parent;
394	node2 = node2->parent;
395	/* should not happen but just in case ... */
396	if ((node1 == NULL) || (node2 == NULL))
397	    return(-2);
398    }
399    /*
400     * Find who's first.
401     */
402    if (node1 == node2->prev)
403	return(1);
404    if (node1 == node2->next)
405	return(-1);
406    /*
407     * Speedup using document order if availble.
408     */
409    if ((node1->type == XML_ELEMENT_NODE) &&
410	(node2->type == XML_ELEMENT_NODE) &&
411	(0 > (long) node1->content) &&
412	(0 > (long) node2->content) &&
413	(node1->doc == node2->doc)) {
414
415	l1 = -((long) node1->content);
416	l2 = -((long) node2->content);
417	if (l1 < l2)
418	    return(1);
419	if (l1 > l2)
420	    return(-1);
421    }
422
423    for (cur = node1->next;cur != NULL;cur = cur->next)
424	if (cur == node2)
425	    return(1);
426    return(-1); /* assume there is no sibling list corruption */
427}
428#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
429
430/*
431 * Wrapper for the Timsort argorithm from timsort.h
432 */
433#ifdef WITH_TIM_SORT
434#define SORT_NAME libxml_domnode
435#define SORT_TYPE xmlNodePtr
436/**
437 * wrap_cmp:
438 * @x: a node
439 * @y: another node
440 *
441 * Comparison function for the Timsort implementation
442 *
443 * Returns -2 in case of error -1 if first point < second point, 0 if
444 *         it's the same node, +1 otherwise
445 */
446static
447int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
448#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
449    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
450    {
451        int res = xmlXPathCmpNodesExt(x, y);
452        return res == -2 ? res : -res;
453    }
454#else
455    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
456    {
457        int res = xmlXPathCmpNodes(x, y);
458        return res == -2 ? res : -res;
459    }
460#endif
461#define SORT_CMP(x, y)  (wrap_cmp(x, y))
462#include "timsort.h"
463#endif /* WITH_TIM_SORT */
464
465#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
466
467/************************************************************************
468 *									*
469 *			Floating point stuff				*
470 *									*
471 ************************************************************************/
472
473#ifndef TRIO_REPLACE_STDIO
474#define TRIO_PUBLIC static
475#endif
476#include "trionan.c"
477
478/*
479 * The lack of portability of this section of the libc is annoying !
480 */
481double xmlXPathNAN = 0;
482double xmlXPathPINF = 1;
483double xmlXPathNINF = -1;
484static double xmlXPathNZERO = 0; /* not exported from headers */
485static int xmlXPathInitialized = 0;
486
487/**
488 * xmlXPathInit:
489 *
490 * Initialize the XPath environment
491 */
492void
493xmlXPathInit(void) {
494    if (xmlXPathInitialized) return;
495
496    xmlXPathPINF = trio_pinf();
497    xmlXPathNINF = trio_ninf();
498    xmlXPathNAN = trio_nan();
499    xmlXPathNZERO = trio_nzero();
500
501    xmlXPathInitialized = 1;
502}
503
504/**
505 * xmlXPathIsNaN:
506 * @val:  a double value
507 *
508 * Provides a portable isnan() function to detect whether a double
509 * is a NotaNumber. Based on trio code
510 * http://sourceforge.net/projects/ctrio/
511 *
512 * Returns 1 if the value is a NaN, 0 otherwise
513 */
514int
515xmlXPathIsNaN(double val) {
516    return(trio_isnan(val));
517}
518
519/**
520 * xmlXPathIsInf:
521 * @val:  a double value
522 *
523 * Provides a portable isinf() function to detect whether a double
524 * is a +Infinite or -Infinite. Based on trio code
525 * http://sourceforge.net/projects/ctrio/
526 *
527 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
528 */
529int
530xmlXPathIsInf(double val) {
531    return(trio_isinf(val));
532}
533
534#endif /* SCHEMAS or XPATH */
535#ifdef LIBXML_XPATH_ENABLED
536/**
537 * xmlXPathGetSign:
538 * @val:  a double value
539 *
540 * Provides a portable function to detect the sign of a double
541 * Modified from trio code
542 * http://sourceforge.net/projects/ctrio/
543 *
544 * Returns 1 if the value is Negative, 0 if positive
545 */
546static int
547xmlXPathGetSign(double val) {
548    return(trio_signbit(val));
549}
550
551
552/*
553 * TODO: when compatibility allows remove all "fake node libxslt" strings
554 *       the test should just be name[0] = ' '
555 */
556#ifdef DEBUG_XPATH_EXPRESSION
557#define DEBUG_STEP
558#define DEBUG_EXPR
559#define DEBUG_EVAL_COUNTS
560#endif
561
562static xmlNs xmlXPathXMLNamespaceStruct = {
563    NULL,
564    XML_NAMESPACE_DECL,
565    XML_XML_NAMESPACE,
566    BAD_CAST "xml",
567    NULL,
568    NULL
569};
570static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
571#ifndef LIBXML_THREAD_ENABLED
572/*
573 * Optimizer is disabled only when threaded apps are detected while
574 * the library ain't compiled for thread safety.
575 */
576static int xmlXPathDisableOptimizer = 0;
577#endif
578
579/************************************************************************
580 *									*
581 *			Error handling routines				*
582 *									*
583 ************************************************************************/
584
585/**
586 * XP_ERRORNULL:
587 * @X:  the error code
588 *
589 * Macro to raise an XPath error and return NULL.
590 */
591#define XP_ERRORNULL(X)							\
592    { xmlXPathErr(ctxt, X); return(NULL); }
593
594/*
595 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
596 */
597static const char *xmlXPathErrorMessages[] = {
598    "Ok\n",
599    "Number encoding\n",
600    "Unfinished literal\n",
601    "Start of literal\n",
602    "Expected $ for variable reference\n",
603    "Undefined variable\n",
604    "Invalid predicate\n",
605    "Invalid expression\n",
606    "Missing closing curly brace\n",
607    "Unregistered function\n",
608    "Invalid operand\n",
609    "Invalid type\n",
610    "Invalid number of arguments\n",
611    "Invalid context size\n",
612    "Invalid context position\n",
613    "Memory allocation error\n",
614    "Syntax error\n",
615    "Resource error\n",
616    "Sub resource error\n",
617    "Undefined namespace prefix\n",
618    "Encoding error\n",
619    "Char out of XML range\n",
620    "Invalid or incomplete context\n",
621    "Stack usage error\n",
622    "Forbidden variable\n",
623    "?? Unknown error ??\n"	/* Must be last in the list! */
624};
625#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
626		   sizeof(xmlXPathErrorMessages[0])) - 1)
627/**
628 * xmlXPathErrMemory:
629 * @ctxt:  an XPath context
630 * @extra:  extra informations
631 *
632 * Handle a redefinition of attribute error
633 */
634static void
635xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
636{
637    if (ctxt != NULL) {
638        if (extra) {
639            xmlChar buf[200];
640
641            xmlStrPrintf(buf, 200,
642                         "Memory allocation failed : %s\n",
643                         extra);
644            ctxt->lastError.message = (char *) xmlStrdup(buf);
645        } else {
646            ctxt->lastError.message = (char *)
647	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
648        }
649        ctxt->lastError.domain = XML_FROM_XPATH;
650        ctxt->lastError.code = XML_ERR_NO_MEMORY;
651	if (ctxt->error != NULL)
652	    ctxt->error(ctxt->userData, &ctxt->lastError);
653    } else {
654        if (extra)
655            __xmlRaiseError(NULL, NULL, NULL,
656                            NULL, NULL, XML_FROM_XPATH,
657                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
658                            extra, NULL, NULL, 0, 0,
659                            "Memory allocation failed : %s\n", extra);
660        else
661            __xmlRaiseError(NULL, NULL, NULL,
662                            NULL, NULL, XML_FROM_XPATH,
663                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
664                            NULL, NULL, NULL, 0, 0,
665                            "Memory allocation failed\n");
666    }
667}
668
669/**
670 * xmlXPathPErrMemory:
671 * @ctxt:  an XPath parser context
672 * @extra:  extra informations
673 *
674 * Handle a redefinition of attribute error
675 */
676static void
677xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
678{
679    if (ctxt == NULL)
680	xmlXPathErrMemory(NULL, extra);
681    else {
682	ctxt->error = XPATH_MEMORY_ERROR;
683	xmlXPathErrMemory(ctxt->context, extra);
684    }
685}
686
687/**
688 * xmlXPathErr:
689 * @ctxt:  a XPath parser context
690 * @error:  the error code
691 *
692 * Handle an XPath error
693 */
694void
695xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
696{
697    if ((error < 0) || (error > MAXERRNO))
698	error = MAXERRNO;
699    if (ctxt == NULL) {
700	__xmlRaiseError(NULL, NULL, NULL,
701			NULL, NULL, XML_FROM_XPATH,
702			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
703			XML_ERR_ERROR, NULL, 0,
704			NULL, NULL, NULL, 0, 0,
705			"%s", xmlXPathErrorMessages[error]);
706	return;
707    }
708    ctxt->error = error;
709    if (ctxt->context == NULL) {
710	__xmlRaiseError(NULL, NULL, NULL,
711			NULL, NULL, XML_FROM_XPATH,
712			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
713			XML_ERR_ERROR, NULL, 0,
714			(const char *) ctxt->base, NULL, NULL,
715			ctxt->cur - ctxt->base, 0,
716			"%s", xmlXPathErrorMessages[error]);
717	return;
718    }
719
720    /* cleanup current last error */
721    xmlResetError(&ctxt->context->lastError);
722
723    ctxt->context->lastError.domain = XML_FROM_XPATH;
724    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
725                           XPATH_EXPRESSION_OK;
726    ctxt->context->lastError.level = XML_ERR_ERROR;
727    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
728    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
729    ctxt->context->lastError.node = ctxt->context->debugNode;
730    if (ctxt->context->error != NULL) {
731	ctxt->context->error(ctxt->context->userData,
732	                     &ctxt->context->lastError);
733    } else {
734	__xmlRaiseError(NULL, NULL, NULL,
735			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
736			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
737			XML_ERR_ERROR, NULL, 0,
738			(const char *) ctxt->base, NULL, NULL,
739			ctxt->cur - ctxt->base, 0,
740			"%s", xmlXPathErrorMessages[error]);
741    }
742
743}
744
745/**
746 * xmlXPatherror:
747 * @ctxt:  the XPath Parser context
748 * @file:  the file name
749 * @line:  the line number
750 * @no:  the error number
751 *
752 * Formats an error message.
753 */
754void
755xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
756              int line ATTRIBUTE_UNUSED, int no) {
757    xmlXPathErr(ctxt, no);
758}
759
760/************************************************************************
761 *									*
762 *			Utilities					*
763 *									*
764 ************************************************************************/
765
766/**
767 * xsltPointerList:
768 *
769 * Pointer-list for various purposes.
770 */
771typedef struct _xmlPointerList xmlPointerList;
772typedef xmlPointerList *xmlPointerListPtr;
773struct _xmlPointerList {
774    void **items;
775    int number;
776    int size;
777};
778/*
779* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
780* and here, we should make the functions public.
781*/
782static int
783xmlPointerListAddSize(xmlPointerListPtr list,
784		       void *item,
785		       int initialSize)
786{
787    if (list->items == NULL) {
788	if (initialSize <= 0)
789	    initialSize = 1;
790	list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
791	if (list->items == NULL) {
792	    xmlXPathErrMemory(NULL,
793		"xmlPointerListCreate: allocating item\n");
794	    return(-1);
795	}
796	list->number = 0;
797	list->size = initialSize;
798    } else if (list->size <= list->number) {
799        if (list->size > 50000000) {
800	    xmlXPathErrMemory(NULL,
801		"xmlPointerListAddSize: re-allocating item\n");
802            return(-1);
803        }
804	list->size *= 2;
805	list->items = (void **) xmlRealloc(list->items,
806	    list->size * sizeof(void *));
807	if (list->items == NULL) {
808	    xmlXPathErrMemory(NULL,
809		"xmlPointerListAddSize: re-allocating item\n");
810	    list->size = 0;
811	    return(-1);
812	}
813    }
814    list->items[list->number++] = item;
815    return(0);
816}
817
818/**
819 * xsltPointerListCreate:
820 *
821 * Creates an xsltPointerList structure.
822 *
823 * Returns a xsltPointerList structure or NULL in case of an error.
824 */
825static xmlPointerListPtr
826xmlPointerListCreate(int initialSize)
827{
828    xmlPointerListPtr ret;
829
830    ret = xmlMalloc(sizeof(xmlPointerList));
831    if (ret == NULL) {
832	xmlXPathErrMemory(NULL,
833	    "xmlPointerListCreate: allocating item\n");
834	return (NULL);
835    }
836    memset(ret, 0, sizeof(xmlPointerList));
837    if (initialSize > 0) {
838	xmlPointerListAddSize(ret, NULL, initialSize);
839	ret->number = 0;
840    }
841    return (ret);
842}
843
844/**
845 * xsltPointerListFree:
846 *
847 * Frees the xsltPointerList structure. This does not free
848 * the content of the list.
849 */
850static void
851xmlPointerListFree(xmlPointerListPtr list)
852{
853    if (list == NULL)
854	return;
855    if (list->items != NULL)
856	xmlFree(list->items);
857    xmlFree(list);
858}
859
860/************************************************************************
861 *									*
862 *			Parser Types					*
863 *									*
864 ************************************************************************/
865
866/*
867 * Types are private:
868 */
869
870typedef enum {
871    XPATH_OP_END=0,
872    XPATH_OP_AND,
873    XPATH_OP_OR,
874    XPATH_OP_EQUAL,
875    XPATH_OP_CMP,
876    XPATH_OP_PLUS,
877    XPATH_OP_MULT,
878    XPATH_OP_UNION,
879    XPATH_OP_ROOT,
880    XPATH_OP_NODE,
881    XPATH_OP_RESET, /* 10 */
882    XPATH_OP_COLLECT,
883    XPATH_OP_VALUE, /* 12 */
884    XPATH_OP_VARIABLE,
885    XPATH_OP_FUNCTION,
886    XPATH_OP_ARG,
887    XPATH_OP_PREDICATE,
888    XPATH_OP_FILTER, /* 17 */
889    XPATH_OP_SORT /* 18 */
890#ifdef LIBXML_XPTR_ENABLED
891    ,XPATH_OP_RANGETO
892#endif
893} xmlXPathOp;
894
895typedef enum {
896    AXIS_ANCESTOR = 1,
897    AXIS_ANCESTOR_OR_SELF,
898    AXIS_ATTRIBUTE,
899    AXIS_CHILD,
900    AXIS_DESCENDANT,
901    AXIS_DESCENDANT_OR_SELF,
902    AXIS_FOLLOWING,
903    AXIS_FOLLOWING_SIBLING,
904    AXIS_NAMESPACE,
905    AXIS_PARENT,
906    AXIS_PRECEDING,
907    AXIS_PRECEDING_SIBLING,
908    AXIS_SELF
909} xmlXPathAxisVal;
910
911typedef enum {
912    NODE_TEST_NONE = 0,
913    NODE_TEST_TYPE = 1,
914    NODE_TEST_PI = 2,
915    NODE_TEST_ALL = 3,
916    NODE_TEST_NS = 4,
917    NODE_TEST_NAME = 5
918} xmlXPathTestVal;
919
920typedef enum {
921    NODE_TYPE_NODE = 0,
922    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
923    NODE_TYPE_TEXT = XML_TEXT_NODE,
924    NODE_TYPE_PI = XML_PI_NODE
925} xmlXPathTypeVal;
926
927typedef struct _xmlXPathStepOp xmlXPathStepOp;
928typedef xmlXPathStepOp *xmlXPathStepOpPtr;
929struct _xmlXPathStepOp {
930    xmlXPathOp op;		/* The identifier of the operation */
931    int ch1;			/* First child */
932    int ch2;			/* Second child */
933    int value;
934    int value2;
935    int value3;
936    void *value4;
937    void *value5;
938    void *cache;
939    void *cacheURI;
940};
941
942struct _xmlXPathCompExpr {
943    int nbStep;			/* Number of steps in this expression */
944    int maxStep;		/* Maximum number of steps allocated */
945    xmlXPathStepOp *steps;	/* ops for computation of this expression */
946    int last;			/* index of last step in expression */
947    xmlChar *expr;		/* the expression being computed */
948    xmlDictPtr dict;		/* the dictionary to use if any */
949#ifdef DEBUG_EVAL_COUNTS
950    int nb;
951    xmlChar *string;
952#endif
953#ifdef XPATH_STREAMING
954    xmlPatternPtr stream;
955#endif
956};
957
958/************************************************************************
959 *									*
960 *			Forward declarations				*
961 *									*
962 ************************************************************************/
963static void
964xmlXPathFreeValueTree(xmlNodeSetPtr obj);
965static void
966xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
967static int
968xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
969                        xmlXPathStepOpPtr op, xmlNodePtr *first);
970static int
971xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
972			    xmlXPathStepOpPtr op,
973			    int isPredicate);
974
975/************************************************************************
976 *									*
977 *			Parser Type functions				*
978 *									*
979 ************************************************************************/
980
981/**
982 * xmlXPathNewCompExpr:
983 *
984 * Create a new Xpath component
985 *
986 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
987 */
988static xmlXPathCompExprPtr
989xmlXPathNewCompExpr(void) {
990    xmlXPathCompExprPtr cur;
991
992    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
993    if (cur == NULL) {
994        xmlXPathErrMemory(NULL, "allocating component\n");
995	return(NULL);
996    }
997    memset(cur, 0, sizeof(xmlXPathCompExpr));
998    cur->maxStep = 10;
999    cur->nbStep = 0;
1000    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1001	                                   sizeof(xmlXPathStepOp));
1002    if (cur->steps == NULL) {
1003        xmlXPathErrMemory(NULL, "allocating steps\n");
1004	xmlFree(cur);
1005	return(NULL);
1006    }
1007    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1008    cur->last = -1;
1009#ifdef DEBUG_EVAL_COUNTS
1010    cur->nb = 0;
1011#endif
1012    return(cur);
1013}
1014
1015/**
1016 * xmlXPathFreeCompExpr:
1017 * @comp:  an XPATH comp
1018 *
1019 * Free up the memory allocated by @comp
1020 */
1021void
1022xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1023{
1024    xmlXPathStepOpPtr op;
1025    int i;
1026
1027    if (comp == NULL)
1028        return;
1029    if (comp->dict == NULL) {
1030	for (i = 0; i < comp->nbStep; i++) {
1031	    op = &comp->steps[i];
1032	    if (op->value4 != NULL) {
1033		if (op->op == XPATH_OP_VALUE)
1034		    xmlXPathFreeObject(op->value4);
1035		else
1036		    xmlFree(op->value4);
1037	    }
1038	    if (op->value5 != NULL)
1039		xmlFree(op->value5);
1040	}
1041    } else {
1042	for (i = 0; i < comp->nbStep; i++) {
1043	    op = &comp->steps[i];
1044	    if (op->value4 != NULL) {
1045		if (op->op == XPATH_OP_VALUE)
1046		    xmlXPathFreeObject(op->value4);
1047	    }
1048	}
1049        xmlDictFree(comp->dict);
1050    }
1051    if (comp->steps != NULL) {
1052        xmlFree(comp->steps);
1053    }
1054#ifdef DEBUG_EVAL_COUNTS
1055    if (comp->string != NULL) {
1056        xmlFree(comp->string);
1057    }
1058#endif
1059#ifdef XPATH_STREAMING
1060    if (comp->stream != NULL) {
1061        xmlFreePatternList(comp->stream);
1062    }
1063#endif
1064    if (comp->expr != NULL) {
1065        xmlFree(comp->expr);
1066    }
1067
1068    xmlFree(comp);
1069}
1070
1071/**
1072 * xmlXPathCompExprAdd:
1073 * @comp:  the compiled expression
1074 * @ch1: first child index
1075 * @ch2: second child index
1076 * @op:  an op
1077 * @value:  the first int value
1078 * @value2:  the second int value
1079 * @value3:  the third int value
1080 * @value4:  the first string value
1081 * @value5:  the second string value
1082 *
1083 * Add a step to an XPath Compiled Expression
1084 *
1085 * Returns -1 in case of failure, the index otherwise
1086 */
1087static int
1088xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1089   xmlXPathOp op, int value,
1090   int value2, int value3, void *value4, void *value5) {
1091    if (comp->nbStep >= comp->maxStep) {
1092	xmlXPathStepOp *real;
1093
1094        if (comp->maxStep >= XPATH_MAX_STEPS) {
1095	    xmlXPathErrMemory(NULL, "adding step\n");
1096	    return(-1);
1097        }
1098	comp->maxStep *= 2;
1099	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1100		                      comp->maxStep * sizeof(xmlXPathStepOp));
1101	if (real == NULL) {
1102	    comp->maxStep /= 2;
1103	    xmlXPathErrMemory(NULL, "adding step\n");
1104	    return(-1);
1105	}
1106	comp->steps = real;
1107    }
1108    comp->last = comp->nbStep;
1109    comp->steps[comp->nbStep].ch1 = ch1;
1110    comp->steps[comp->nbStep].ch2 = ch2;
1111    comp->steps[comp->nbStep].op = op;
1112    comp->steps[comp->nbStep].value = value;
1113    comp->steps[comp->nbStep].value2 = value2;
1114    comp->steps[comp->nbStep].value3 = value3;
1115    if ((comp->dict != NULL) &&
1116        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1117	 (op == XPATH_OP_COLLECT))) {
1118        if (value4 != NULL) {
1119	    comp->steps[comp->nbStep].value4 = (xmlChar *)
1120	        (void *)xmlDictLookup(comp->dict, value4, -1);
1121	    xmlFree(value4);
1122	} else
1123	    comp->steps[comp->nbStep].value4 = NULL;
1124        if (value5 != NULL) {
1125	    comp->steps[comp->nbStep].value5 = (xmlChar *)
1126	        (void *)xmlDictLookup(comp->dict, value5, -1);
1127	    xmlFree(value5);
1128	} else
1129	    comp->steps[comp->nbStep].value5 = NULL;
1130    } else {
1131	comp->steps[comp->nbStep].value4 = value4;
1132	comp->steps[comp->nbStep].value5 = value5;
1133    }
1134    comp->steps[comp->nbStep].cache = NULL;
1135    return(comp->nbStep++);
1136}
1137
1138/**
1139 * xmlXPathCompSwap:
1140 * @comp:  the compiled expression
1141 * @op: operation index
1142 *
1143 * Swaps 2 operations in the compiled expression
1144 */
1145static void
1146xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1147    int tmp;
1148
1149#ifndef LIBXML_THREAD_ENABLED
1150    /*
1151     * Since this manipulates possibly shared variables, this is
1152     * disabled if one detects that the library is used in a multithreaded
1153     * application
1154     */
1155    if (xmlXPathDisableOptimizer)
1156	return;
1157#endif
1158
1159    tmp = op->ch1;
1160    op->ch1 = op->ch2;
1161    op->ch2 = tmp;
1162}
1163
1164#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
1165    xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
1166	                (op), (val), (val2), (val3), (val4), (val5))
1167#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
1168    xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
1169	                (op), (val), (val2), (val3), (val4), (val5))
1170
1171#define PUSH_LEAVE_EXPR(op, val, val2)					\
1172xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1173
1174#define PUSH_UNARY_EXPR(op, ch, val, val2)				\
1175xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1176
1177#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
1178xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
1179			(val), (val2), 0 ,NULL ,NULL)
1180
1181/************************************************************************
1182 *									*
1183 *		XPath object cache structures				*
1184 *									*
1185 ************************************************************************/
1186
1187/* #define XP_DEFAULT_CACHE_ON */
1188
1189#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1190
1191typedef struct _xmlXPathContextCache xmlXPathContextCache;
1192typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1193struct _xmlXPathContextCache {
1194    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1195    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1196    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1197    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1198    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1199    int maxNodeset;
1200    int maxString;
1201    int maxBoolean;
1202    int maxNumber;
1203    int maxMisc;
1204#ifdef XP_DEBUG_OBJ_USAGE
1205    int dbgCachedAll;
1206    int dbgCachedNodeset;
1207    int dbgCachedString;
1208    int dbgCachedBool;
1209    int dbgCachedNumber;
1210    int dbgCachedPoint;
1211    int dbgCachedRange;
1212    int dbgCachedLocset;
1213    int dbgCachedUsers;
1214    int dbgCachedXSLTTree;
1215    int dbgCachedUndefined;
1216
1217
1218    int dbgReusedAll;
1219    int dbgReusedNodeset;
1220    int dbgReusedString;
1221    int dbgReusedBool;
1222    int dbgReusedNumber;
1223    int dbgReusedPoint;
1224    int dbgReusedRange;
1225    int dbgReusedLocset;
1226    int dbgReusedUsers;
1227    int dbgReusedXSLTTree;
1228    int dbgReusedUndefined;
1229
1230#endif
1231};
1232
1233/************************************************************************
1234 *									*
1235 *		Debugging related functions				*
1236 *									*
1237 ************************************************************************/
1238
1239#define STRANGE							\
1240    xmlGenericError(xmlGenericErrorContext,				\
1241	    "Internal error at %s:%d\n",				\
1242            __FILE__, __LINE__);
1243
1244#ifdef LIBXML_DEBUG_ENABLED
1245static void
1246xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1247    int i;
1248    char shift[100];
1249
1250    for (i = 0;((i < depth) && (i < 25));i++)
1251        shift[2 * i] = shift[2 * i + 1] = ' ';
1252    shift[2 * i] = shift[2 * i + 1] = 0;
1253    if (cur == NULL) {
1254	fprintf(output, "%s", shift);
1255	fprintf(output, "Node is NULL !\n");
1256	return;
1257
1258    }
1259
1260    if ((cur->type == XML_DOCUMENT_NODE) ||
1261	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
1262	fprintf(output, "%s", shift);
1263	fprintf(output, " /\n");
1264    } else if (cur->type == XML_ATTRIBUTE_NODE)
1265	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1266    else
1267	xmlDebugDumpOneNode(output, cur, depth);
1268}
1269static void
1270xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1271    xmlNodePtr tmp;
1272    int i;
1273    char shift[100];
1274
1275    for (i = 0;((i < depth) && (i < 25));i++)
1276        shift[2 * i] = shift[2 * i + 1] = ' ';
1277    shift[2 * i] = shift[2 * i + 1] = 0;
1278    if (cur == NULL) {
1279	fprintf(output, "%s", shift);
1280	fprintf(output, "Node is NULL !\n");
1281	return;
1282
1283    }
1284
1285    while (cur != NULL) {
1286	tmp = cur;
1287	cur = cur->next;
1288	xmlDebugDumpOneNode(output, tmp, depth);
1289    }
1290}
1291
1292static void
1293xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1294    int i;
1295    char shift[100];
1296
1297    for (i = 0;((i < depth) && (i < 25));i++)
1298        shift[2 * i] = shift[2 * i + 1] = ' ';
1299    shift[2 * i] = shift[2 * i + 1] = 0;
1300
1301    if (cur == NULL) {
1302	fprintf(output, "%s", shift);
1303	fprintf(output, "NodeSet is NULL !\n");
1304	return;
1305
1306    }
1307
1308    if (cur != NULL) {
1309	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1310	for (i = 0;i < cur->nodeNr;i++) {
1311	    fprintf(output, "%s", shift);
1312	    fprintf(output, "%d", i + 1);
1313	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1314	}
1315    }
1316}
1317
1318static void
1319xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1320    int i;
1321    char shift[100];
1322
1323    for (i = 0;((i < depth) && (i < 25));i++)
1324        shift[2 * i] = shift[2 * i + 1] = ' ';
1325    shift[2 * i] = shift[2 * i + 1] = 0;
1326
1327    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1328	fprintf(output, "%s", shift);
1329	fprintf(output, "Value Tree is NULL !\n");
1330	return;
1331
1332    }
1333
1334    fprintf(output, "%s", shift);
1335    fprintf(output, "%d", i + 1);
1336    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1337}
1338#if defined(LIBXML_XPTR_ENABLED)
1339static void
1340xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1341    int i;
1342    char shift[100];
1343
1344    for (i = 0;((i < depth) && (i < 25));i++)
1345        shift[2 * i] = shift[2 * i + 1] = ' ';
1346    shift[2 * i] = shift[2 * i + 1] = 0;
1347
1348    if (cur == NULL) {
1349	fprintf(output, "%s", shift);
1350	fprintf(output, "LocationSet is NULL !\n");
1351	return;
1352
1353    }
1354
1355    for (i = 0;i < cur->locNr;i++) {
1356	fprintf(output, "%s", shift);
1357        fprintf(output, "%d : ", i + 1);
1358	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1359    }
1360}
1361#endif /* LIBXML_XPTR_ENABLED */
1362
1363/**
1364 * xmlXPathDebugDumpObject:
1365 * @output:  the FILE * to dump the output
1366 * @cur:  the object to inspect
1367 * @depth:  indentation level
1368 *
1369 * Dump the content of the object for debugging purposes
1370 */
1371void
1372xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1373    int i;
1374    char shift[100];
1375
1376    if (output == NULL) return;
1377
1378    for (i = 0;((i < depth) && (i < 25));i++)
1379        shift[2 * i] = shift[2 * i + 1] = ' ';
1380    shift[2 * i] = shift[2 * i + 1] = 0;
1381
1382
1383    fprintf(output, "%s", shift);
1384
1385    if (cur == NULL) {
1386        fprintf(output, "Object is empty (NULL)\n");
1387	return;
1388    }
1389    switch(cur->type) {
1390        case XPATH_UNDEFINED:
1391	    fprintf(output, "Object is uninitialized\n");
1392	    break;
1393        case XPATH_NODESET:
1394	    fprintf(output, "Object is a Node Set :\n");
1395	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1396	    break;
1397	case XPATH_XSLT_TREE:
1398	    fprintf(output, "Object is an XSLT value tree :\n");
1399	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1400	    break;
1401        case XPATH_BOOLEAN:
1402	    fprintf(output, "Object is a Boolean : ");
1403	    if (cur->boolval) fprintf(output, "true\n");
1404	    else fprintf(output, "false\n");
1405	    break;
1406        case XPATH_NUMBER:
1407	    switch (xmlXPathIsInf(cur->floatval)) {
1408	    case 1:
1409		fprintf(output, "Object is a number : Infinity\n");
1410		break;
1411	    case -1:
1412		fprintf(output, "Object is a number : -Infinity\n");
1413		break;
1414	    default:
1415		if (xmlXPathIsNaN(cur->floatval)) {
1416		    fprintf(output, "Object is a number : NaN\n");
1417		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1418		    fprintf(output, "Object is a number : 0\n");
1419		} else {
1420		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1421		}
1422	    }
1423	    break;
1424        case XPATH_STRING:
1425	    fprintf(output, "Object is a string : ");
1426	    xmlDebugDumpString(output, cur->stringval);
1427	    fprintf(output, "\n");
1428	    break;
1429	case XPATH_POINT:
1430	    fprintf(output, "Object is a point : index %d in node", cur->index);
1431	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1432	    fprintf(output, "\n");
1433	    break;
1434	case XPATH_RANGE:
1435	    if ((cur->user2 == NULL) ||
1436		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1437		fprintf(output, "Object is a collapsed range :\n");
1438		fprintf(output, "%s", shift);
1439		if (cur->index >= 0)
1440		    fprintf(output, "index %d in ", cur->index);
1441		fprintf(output, "node\n");
1442		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1443			              depth + 1);
1444	    } else  {
1445		fprintf(output, "Object is a range :\n");
1446		fprintf(output, "%s", shift);
1447		fprintf(output, "From ");
1448		if (cur->index >= 0)
1449		    fprintf(output, "index %d in ", cur->index);
1450		fprintf(output, "node\n");
1451		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1452			              depth + 1);
1453		fprintf(output, "%s", shift);
1454		fprintf(output, "To ");
1455		if (cur->index2 >= 0)
1456		    fprintf(output, "index %d in ", cur->index2);
1457		fprintf(output, "node\n");
1458		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1459			              depth + 1);
1460		fprintf(output, "\n");
1461	    }
1462	    break;
1463	case XPATH_LOCATIONSET:
1464#if defined(LIBXML_XPTR_ENABLED)
1465	    fprintf(output, "Object is a Location Set:\n");
1466	    xmlXPathDebugDumpLocationSet(output,
1467		    (xmlLocationSetPtr) cur->user, depth);
1468#endif
1469	    break;
1470	case XPATH_USERS:
1471	    fprintf(output, "Object is user defined\n");
1472	    break;
1473    }
1474}
1475
1476static void
1477xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1478	                     xmlXPathStepOpPtr op, int depth) {
1479    int i;
1480    char shift[100];
1481
1482    for (i = 0;((i < depth) && (i < 25));i++)
1483        shift[2 * i] = shift[2 * i + 1] = ' ';
1484    shift[2 * i] = shift[2 * i + 1] = 0;
1485
1486    fprintf(output, "%s", shift);
1487    if (op == NULL) {
1488	fprintf(output, "Step is NULL\n");
1489	return;
1490    }
1491    switch (op->op) {
1492        case XPATH_OP_END:
1493	    fprintf(output, "END"); break;
1494        case XPATH_OP_AND:
1495	    fprintf(output, "AND"); break;
1496        case XPATH_OP_OR:
1497	    fprintf(output, "OR"); break;
1498        case XPATH_OP_EQUAL:
1499	     if (op->value)
1500		 fprintf(output, "EQUAL =");
1501	     else
1502		 fprintf(output, "EQUAL !=");
1503	     break;
1504        case XPATH_OP_CMP:
1505	     if (op->value)
1506		 fprintf(output, "CMP <");
1507	     else
1508		 fprintf(output, "CMP >");
1509	     if (!op->value2)
1510		 fprintf(output, "=");
1511	     break;
1512        case XPATH_OP_PLUS:
1513	     if (op->value == 0)
1514		 fprintf(output, "PLUS -");
1515	     else if (op->value == 1)
1516		 fprintf(output, "PLUS +");
1517	     else if (op->value == 2)
1518		 fprintf(output, "PLUS unary -");
1519	     else if (op->value == 3)
1520		 fprintf(output, "PLUS unary - -");
1521	     break;
1522        case XPATH_OP_MULT:
1523	     if (op->value == 0)
1524		 fprintf(output, "MULT *");
1525	     else if (op->value == 1)
1526		 fprintf(output, "MULT div");
1527	     else
1528		 fprintf(output, "MULT mod");
1529	     break;
1530        case XPATH_OP_UNION:
1531	     fprintf(output, "UNION"); break;
1532        case XPATH_OP_ROOT:
1533	     fprintf(output, "ROOT"); break;
1534        case XPATH_OP_NODE:
1535	     fprintf(output, "NODE"); break;
1536        case XPATH_OP_RESET:
1537	     fprintf(output, "RESET"); break;
1538        case XPATH_OP_SORT:
1539	     fprintf(output, "SORT"); break;
1540        case XPATH_OP_COLLECT: {
1541	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1542	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1543	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1544	    const xmlChar *prefix = op->value4;
1545	    const xmlChar *name = op->value5;
1546
1547	    fprintf(output, "COLLECT ");
1548	    switch (axis) {
1549		case AXIS_ANCESTOR:
1550		    fprintf(output, " 'ancestors' "); break;
1551		case AXIS_ANCESTOR_OR_SELF:
1552		    fprintf(output, " 'ancestors-or-self' "); break;
1553		case AXIS_ATTRIBUTE:
1554		    fprintf(output, " 'attributes' "); break;
1555		case AXIS_CHILD:
1556		    fprintf(output, " 'child' "); break;
1557		case AXIS_DESCENDANT:
1558		    fprintf(output, " 'descendant' "); break;
1559		case AXIS_DESCENDANT_OR_SELF:
1560		    fprintf(output, " 'descendant-or-self' "); break;
1561		case AXIS_FOLLOWING:
1562		    fprintf(output, " 'following' "); break;
1563		case AXIS_FOLLOWING_SIBLING:
1564		    fprintf(output, " 'following-siblings' "); break;
1565		case AXIS_NAMESPACE:
1566		    fprintf(output, " 'namespace' "); break;
1567		case AXIS_PARENT:
1568		    fprintf(output, " 'parent' "); break;
1569		case AXIS_PRECEDING:
1570		    fprintf(output, " 'preceding' "); break;
1571		case AXIS_PRECEDING_SIBLING:
1572		    fprintf(output, " 'preceding-sibling' "); break;
1573		case AXIS_SELF:
1574		    fprintf(output, " 'self' "); break;
1575	    }
1576	    switch (test) {
1577                case NODE_TEST_NONE:
1578		    fprintf(output, "'none' "); break;
1579                case NODE_TEST_TYPE:
1580		    fprintf(output, "'type' "); break;
1581                case NODE_TEST_PI:
1582		    fprintf(output, "'PI' "); break;
1583                case NODE_TEST_ALL:
1584		    fprintf(output, "'all' "); break;
1585                case NODE_TEST_NS:
1586		    fprintf(output, "'namespace' "); break;
1587                case NODE_TEST_NAME:
1588		    fprintf(output, "'name' "); break;
1589	    }
1590	    switch (type) {
1591                case NODE_TYPE_NODE:
1592		    fprintf(output, "'node' "); break;
1593                case NODE_TYPE_COMMENT:
1594		    fprintf(output, "'comment' "); break;
1595                case NODE_TYPE_TEXT:
1596		    fprintf(output, "'text' "); break;
1597                case NODE_TYPE_PI:
1598		    fprintf(output, "'PI' "); break;
1599	    }
1600	    if (prefix != NULL)
1601		fprintf(output, "%s:", prefix);
1602	    if (name != NULL)
1603		fprintf(output, "%s", (const char *) name);
1604	    break;
1605
1606        }
1607	case XPATH_OP_VALUE: {
1608	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1609
1610	    fprintf(output, "ELEM ");
1611	    xmlXPathDebugDumpObject(output, object, 0);
1612	    goto finish;
1613	}
1614	case XPATH_OP_VARIABLE: {
1615	    const xmlChar *prefix = op->value5;
1616	    const xmlChar *name = op->value4;
1617
1618	    if (prefix != NULL)
1619		fprintf(output, "VARIABLE %s:%s", prefix, name);
1620	    else
1621		fprintf(output, "VARIABLE %s", name);
1622	    break;
1623	}
1624	case XPATH_OP_FUNCTION: {
1625	    int nbargs = op->value;
1626	    const xmlChar *prefix = op->value5;
1627	    const xmlChar *name = op->value4;
1628
1629	    if (prefix != NULL)
1630		fprintf(output, "FUNCTION %s:%s(%d args)",
1631			prefix, name, nbargs);
1632	    else
1633		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1634	    break;
1635	}
1636        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1637        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1638        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1639#ifdef LIBXML_XPTR_ENABLED
1640        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1641#endif
1642	default:
1643        fprintf(output, "UNKNOWN %d\n", op->op); return;
1644    }
1645    fprintf(output, "\n");
1646finish:
1647    if (op->ch1 >= 0)
1648	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1649    if (op->ch2 >= 0)
1650	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1651}
1652
1653/**
1654 * xmlXPathDebugDumpCompExpr:
1655 * @output:  the FILE * for the output
1656 * @comp:  the precompiled XPath expression
1657 * @depth:  the indentation level.
1658 *
1659 * Dumps the tree of the compiled XPath expression.
1660 */
1661void
1662xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1663	                  int depth) {
1664    int i;
1665    char shift[100];
1666
1667    if ((output == NULL) || (comp == NULL)) return;
1668
1669    for (i = 0;((i < depth) && (i < 25));i++)
1670        shift[2 * i] = shift[2 * i + 1] = ' ';
1671    shift[2 * i] = shift[2 * i + 1] = 0;
1672
1673    fprintf(output, "%s", shift);
1674
1675    fprintf(output, "Compiled Expression : %d elements\n",
1676	    comp->nbStep);
1677    i = comp->last;
1678    xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1679}
1680
1681#ifdef XP_DEBUG_OBJ_USAGE
1682
1683/*
1684* XPath object usage related debugging variables.
1685*/
1686static int xmlXPathDebugObjCounterUndefined = 0;
1687static int xmlXPathDebugObjCounterNodeset = 0;
1688static int xmlXPathDebugObjCounterBool = 0;
1689static int xmlXPathDebugObjCounterNumber = 0;
1690static int xmlXPathDebugObjCounterString = 0;
1691static int xmlXPathDebugObjCounterPoint = 0;
1692static int xmlXPathDebugObjCounterRange = 0;
1693static int xmlXPathDebugObjCounterLocset = 0;
1694static int xmlXPathDebugObjCounterUsers = 0;
1695static int xmlXPathDebugObjCounterXSLTTree = 0;
1696static int xmlXPathDebugObjCounterAll = 0;
1697
1698static int xmlXPathDebugObjTotalUndefined = 0;
1699static int xmlXPathDebugObjTotalNodeset = 0;
1700static int xmlXPathDebugObjTotalBool = 0;
1701static int xmlXPathDebugObjTotalNumber = 0;
1702static int xmlXPathDebugObjTotalString = 0;
1703static int xmlXPathDebugObjTotalPoint = 0;
1704static int xmlXPathDebugObjTotalRange = 0;
1705static int xmlXPathDebugObjTotalLocset = 0;
1706static int xmlXPathDebugObjTotalUsers = 0;
1707static int xmlXPathDebugObjTotalXSLTTree = 0;
1708static int xmlXPathDebugObjTotalAll = 0;
1709
1710static int xmlXPathDebugObjMaxUndefined = 0;
1711static int xmlXPathDebugObjMaxNodeset = 0;
1712static int xmlXPathDebugObjMaxBool = 0;
1713static int xmlXPathDebugObjMaxNumber = 0;
1714static int xmlXPathDebugObjMaxString = 0;
1715static int xmlXPathDebugObjMaxPoint = 0;
1716static int xmlXPathDebugObjMaxRange = 0;
1717static int xmlXPathDebugObjMaxLocset = 0;
1718static int xmlXPathDebugObjMaxUsers = 0;
1719static int xmlXPathDebugObjMaxXSLTTree = 0;
1720static int xmlXPathDebugObjMaxAll = 0;
1721
1722/* REVISIT TODO: Make this static when committing */
1723static void
1724xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1725{
1726    if (ctxt != NULL) {
1727	if (ctxt->cache != NULL) {
1728	    xmlXPathContextCachePtr cache =
1729		(xmlXPathContextCachePtr) ctxt->cache;
1730
1731	    cache->dbgCachedAll = 0;
1732	    cache->dbgCachedNodeset = 0;
1733	    cache->dbgCachedString = 0;
1734	    cache->dbgCachedBool = 0;
1735	    cache->dbgCachedNumber = 0;
1736	    cache->dbgCachedPoint = 0;
1737	    cache->dbgCachedRange = 0;
1738	    cache->dbgCachedLocset = 0;
1739	    cache->dbgCachedUsers = 0;
1740	    cache->dbgCachedXSLTTree = 0;
1741	    cache->dbgCachedUndefined = 0;
1742
1743	    cache->dbgReusedAll = 0;
1744	    cache->dbgReusedNodeset = 0;
1745	    cache->dbgReusedString = 0;
1746	    cache->dbgReusedBool = 0;
1747	    cache->dbgReusedNumber = 0;
1748	    cache->dbgReusedPoint = 0;
1749	    cache->dbgReusedRange = 0;
1750	    cache->dbgReusedLocset = 0;
1751	    cache->dbgReusedUsers = 0;
1752	    cache->dbgReusedXSLTTree = 0;
1753	    cache->dbgReusedUndefined = 0;
1754	}
1755    }
1756
1757    xmlXPathDebugObjCounterUndefined = 0;
1758    xmlXPathDebugObjCounterNodeset = 0;
1759    xmlXPathDebugObjCounterBool = 0;
1760    xmlXPathDebugObjCounterNumber = 0;
1761    xmlXPathDebugObjCounterString = 0;
1762    xmlXPathDebugObjCounterPoint = 0;
1763    xmlXPathDebugObjCounterRange = 0;
1764    xmlXPathDebugObjCounterLocset = 0;
1765    xmlXPathDebugObjCounterUsers = 0;
1766    xmlXPathDebugObjCounterXSLTTree = 0;
1767    xmlXPathDebugObjCounterAll = 0;
1768
1769    xmlXPathDebugObjTotalUndefined = 0;
1770    xmlXPathDebugObjTotalNodeset = 0;
1771    xmlXPathDebugObjTotalBool = 0;
1772    xmlXPathDebugObjTotalNumber = 0;
1773    xmlXPathDebugObjTotalString = 0;
1774    xmlXPathDebugObjTotalPoint = 0;
1775    xmlXPathDebugObjTotalRange = 0;
1776    xmlXPathDebugObjTotalLocset = 0;
1777    xmlXPathDebugObjTotalUsers = 0;
1778    xmlXPathDebugObjTotalXSLTTree = 0;
1779    xmlXPathDebugObjTotalAll = 0;
1780
1781    xmlXPathDebugObjMaxUndefined = 0;
1782    xmlXPathDebugObjMaxNodeset = 0;
1783    xmlXPathDebugObjMaxBool = 0;
1784    xmlXPathDebugObjMaxNumber = 0;
1785    xmlXPathDebugObjMaxString = 0;
1786    xmlXPathDebugObjMaxPoint = 0;
1787    xmlXPathDebugObjMaxRange = 0;
1788    xmlXPathDebugObjMaxLocset = 0;
1789    xmlXPathDebugObjMaxUsers = 0;
1790    xmlXPathDebugObjMaxXSLTTree = 0;
1791    xmlXPathDebugObjMaxAll = 0;
1792
1793}
1794
1795static void
1796xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1797			      xmlXPathObjectType objType)
1798{
1799    int isCached = 0;
1800
1801    if (ctxt != NULL) {
1802	if (ctxt->cache != NULL) {
1803	    xmlXPathContextCachePtr cache =
1804		(xmlXPathContextCachePtr) ctxt->cache;
1805
1806	    isCached = 1;
1807
1808	    cache->dbgReusedAll++;
1809	    switch (objType) {
1810		case XPATH_UNDEFINED:
1811		    cache->dbgReusedUndefined++;
1812		    break;
1813		case XPATH_NODESET:
1814		    cache->dbgReusedNodeset++;
1815		    break;
1816		case XPATH_BOOLEAN:
1817		    cache->dbgReusedBool++;
1818		    break;
1819		case XPATH_NUMBER:
1820		    cache->dbgReusedNumber++;
1821		    break;
1822		case XPATH_STRING:
1823		    cache->dbgReusedString++;
1824		    break;
1825		case XPATH_POINT:
1826		    cache->dbgReusedPoint++;
1827		    break;
1828		case XPATH_RANGE:
1829		    cache->dbgReusedRange++;
1830		    break;
1831		case XPATH_LOCATIONSET:
1832		    cache->dbgReusedLocset++;
1833		    break;
1834		case XPATH_USERS:
1835		    cache->dbgReusedUsers++;
1836		    break;
1837		case XPATH_XSLT_TREE:
1838		    cache->dbgReusedXSLTTree++;
1839		    break;
1840		default:
1841		    break;
1842	    }
1843	}
1844    }
1845
1846    switch (objType) {
1847	case XPATH_UNDEFINED:
1848	    if (! isCached)
1849		xmlXPathDebugObjTotalUndefined++;
1850	    xmlXPathDebugObjCounterUndefined++;
1851	    if (xmlXPathDebugObjCounterUndefined >
1852		xmlXPathDebugObjMaxUndefined)
1853		xmlXPathDebugObjMaxUndefined =
1854		    xmlXPathDebugObjCounterUndefined;
1855	    break;
1856	case XPATH_NODESET:
1857	    if (! isCached)
1858		xmlXPathDebugObjTotalNodeset++;
1859	    xmlXPathDebugObjCounterNodeset++;
1860	    if (xmlXPathDebugObjCounterNodeset >
1861		xmlXPathDebugObjMaxNodeset)
1862		xmlXPathDebugObjMaxNodeset =
1863		    xmlXPathDebugObjCounterNodeset;
1864	    break;
1865	case XPATH_BOOLEAN:
1866	    if (! isCached)
1867		xmlXPathDebugObjTotalBool++;
1868	    xmlXPathDebugObjCounterBool++;
1869	    if (xmlXPathDebugObjCounterBool >
1870		xmlXPathDebugObjMaxBool)
1871		xmlXPathDebugObjMaxBool =
1872		    xmlXPathDebugObjCounterBool;
1873	    break;
1874	case XPATH_NUMBER:
1875	    if (! isCached)
1876		xmlXPathDebugObjTotalNumber++;
1877	    xmlXPathDebugObjCounterNumber++;
1878	    if (xmlXPathDebugObjCounterNumber >
1879		xmlXPathDebugObjMaxNumber)
1880		xmlXPathDebugObjMaxNumber =
1881		    xmlXPathDebugObjCounterNumber;
1882	    break;
1883	case XPATH_STRING:
1884	    if (! isCached)
1885		xmlXPathDebugObjTotalString++;
1886	    xmlXPathDebugObjCounterString++;
1887	    if (xmlXPathDebugObjCounterString >
1888		xmlXPathDebugObjMaxString)
1889		xmlXPathDebugObjMaxString =
1890		    xmlXPathDebugObjCounterString;
1891	    break;
1892	case XPATH_POINT:
1893	    if (! isCached)
1894		xmlXPathDebugObjTotalPoint++;
1895	    xmlXPathDebugObjCounterPoint++;
1896	    if (xmlXPathDebugObjCounterPoint >
1897		xmlXPathDebugObjMaxPoint)
1898		xmlXPathDebugObjMaxPoint =
1899		    xmlXPathDebugObjCounterPoint;
1900	    break;
1901	case XPATH_RANGE:
1902	    if (! isCached)
1903		xmlXPathDebugObjTotalRange++;
1904	    xmlXPathDebugObjCounterRange++;
1905	    if (xmlXPathDebugObjCounterRange >
1906		xmlXPathDebugObjMaxRange)
1907		xmlXPathDebugObjMaxRange =
1908		    xmlXPathDebugObjCounterRange;
1909	    break;
1910	case XPATH_LOCATIONSET:
1911	    if (! isCached)
1912		xmlXPathDebugObjTotalLocset++;
1913	    xmlXPathDebugObjCounterLocset++;
1914	    if (xmlXPathDebugObjCounterLocset >
1915		xmlXPathDebugObjMaxLocset)
1916		xmlXPathDebugObjMaxLocset =
1917		    xmlXPathDebugObjCounterLocset;
1918	    break;
1919	case XPATH_USERS:
1920	    if (! isCached)
1921		xmlXPathDebugObjTotalUsers++;
1922	    xmlXPathDebugObjCounterUsers++;
1923	    if (xmlXPathDebugObjCounterUsers >
1924		xmlXPathDebugObjMaxUsers)
1925		xmlXPathDebugObjMaxUsers =
1926		    xmlXPathDebugObjCounterUsers;
1927	    break;
1928	case XPATH_XSLT_TREE:
1929	    if (! isCached)
1930		xmlXPathDebugObjTotalXSLTTree++;
1931	    xmlXPathDebugObjCounterXSLTTree++;
1932	    if (xmlXPathDebugObjCounterXSLTTree >
1933		xmlXPathDebugObjMaxXSLTTree)
1934		xmlXPathDebugObjMaxXSLTTree =
1935		    xmlXPathDebugObjCounterXSLTTree;
1936	    break;
1937	default:
1938	    break;
1939    }
1940    if (! isCached)
1941	xmlXPathDebugObjTotalAll++;
1942    xmlXPathDebugObjCounterAll++;
1943    if (xmlXPathDebugObjCounterAll >
1944	xmlXPathDebugObjMaxAll)
1945	xmlXPathDebugObjMaxAll =
1946	    xmlXPathDebugObjCounterAll;
1947}
1948
1949static void
1950xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1951			      xmlXPathObjectType objType)
1952{
1953    int isCached = 0;
1954
1955    if (ctxt != NULL) {
1956	if (ctxt->cache != NULL) {
1957	    xmlXPathContextCachePtr cache =
1958		(xmlXPathContextCachePtr) ctxt->cache;
1959
1960	    isCached = 1;
1961
1962	    cache->dbgCachedAll++;
1963	    switch (objType) {
1964		case XPATH_UNDEFINED:
1965		    cache->dbgCachedUndefined++;
1966		    break;
1967		case XPATH_NODESET:
1968		    cache->dbgCachedNodeset++;
1969		    break;
1970		case XPATH_BOOLEAN:
1971		    cache->dbgCachedBool++;
1972		    break;
1973		case XPATH_NUMBER:
1974		    cache->dbgCachedNumber++;
1975		    break;
1976		case XPATH_STRING:
1977		    cache->dbgCachedString++;
1978		    break;
1979		case XPATH_POINT:
1980		    cache->dbgCachedPoint++;
1981		    break;
1982		case XPATH_RANGE:
1983		    cache->dbgCachedRange++;
1984		    break;
1985		case XPATH_LOCATIONSET:
1986		    cache->dbgCachedLocset++;
1987		    break;
1988		case XPATH_USERS:
1989		    cache->dbgCachedUsers++;
1990		    break;
1991		case XPATH_XSLT_TREE:
1992		    cache->dbgCachedXSLTTree++;
1993		    break;
1994		default:
1995		    break;
1996	    }
1997
1998	}
1999    }
2000    switch (objType) {
2001	case XPATH_UNDEFINED:
2002	    xmlXPathDebugObjCounterUndefined--;
2003	    break;
2004	case XPATH_NODESET:
2005	    xmlXPathDebugObjCounterNodeset--;
2006	    break;
2007	case XPATH_BOOLEAN:
2008	    xmlXPathDebugObjCounterBool--;
2009	    break;
2010	case XPATH_NUMBER:
2011	    xmlXPathDebugObjCounterNumber--;
2012	    break;
2013	case XPATH_STRING:
2014	    xmlXPathDebugObjCounterString--;
2015	    break;
2016	case XPATH_POINT:
2017	    xmlXPathDebugObjCounterPoint--;
2018	    break;
2019	case XPATH_RANGE:
2020	    xmlXPathDebugObjCounterRange--;
2021	    break;
2022	case XPATH_LOCATIONSET:
2023	    xmlXPathDebugObjCounterLocset--;
2024	    break;
2025	case XPATH_USERS:
2026	    xmlXPathDebugObjCounterUsers--;
2027	    break;
2028	case XPATH_XSLT_TREE:
2029	    xmlXPathDebugObjCounterXSLTTree--;
2030	    break;
2031	default:
2032	    break;
2033    }
2034    xmlXPathDebugObjCounterAll--;
2035}
2036
2037/* REVISIT TODO: Make this static when committing */
2038static void
2039xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2040{
2041    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2042	reqXSLTTree, reqUndefined;
2043    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2044	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2045    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2046	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2047    int leftObjs = xmlXPathDebugObjCounterAll;
2048
2049    reqAll = xmlXPathDebugObjTotalAll;
2050    reqNodeset = xmlXPathDebugObjTotalNodeset;
2051    reqString = xmlXPathDebugObjTotalString;
2052    reqBool = xmlXPathDebugObjTotalBool;
2053    reqNumber = xmlXPathDebugObjTotalNumber;
2054    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2055    reqUndefined = xmlXPathDebugObjTotalUndefined;
2056
2057    printf("# XPath object usage:\n");
2058
2059    if (ctxt != NULL) {
2060	if (ctxt->cache != NULL) {
2061	    xmlXPathContextCachePtr cache =
2062		(xmlXPathContextCachePtr) ctxt->cache;
2063
2064	    reAll = cache->dbgReusedAll;
2065	    reqAll += reAll;
2066	    reNodeset = cache->dbgReusedNodeset;
2067	    reqNodeset += reNodeset;
2068	    reString = cache->dbgReusedString;
2069	    reqString += reString;
2070	    reBool = cache->dbgReusedBool;
2071	    reqBool += reBool;
2072	    reNumber = cache->dbgReusedNumber;
2073	    reqNumber += reNumber;
2074	    reXSLTTree = cache->dbgReusedXSLTTree;
2075	    reqXSLTTree += reXSLTTree;
2076	    reUndefined = cache->dbgReusedUndefined;
2077	    reqUndefined += reUndefined;
2078
2079	    caAll = cache->dbgCachedAll;
2080	    caBool = cache->dbgCachedBool;
2081	    caNodeset = cache->dbgCachedNodeset;
2082	    caString = cache->dbgCachedString;
2083	    caNumber = cache->dbgCachedNumber;
2084	    caXSLTTree = cache->dbgCachedXSLTTree;
2085	    caUndefined = cache->dbgCachedUndefined;
2086
2087	    if (cache->nodesetObjs)
2088		leftObjs -= cache->nodesetObjs->number;
2089	    if (cache->stringObjs)
2090		leftObjs -= cache->stringObjs->number;
2091	    if (cache->booleanObjs)
2092		leftObjs -= cache->booleanObjs->number;
2093	    if (cache->numberObjs)
2094		leftObjs -= cache->numberObjs->number;
2095	    if (cache->miscObjs)
2096		leftObjs -= cache->miscObjs->number;
2097	}
2098    }
2099
2100    printf("# all\n");
2101    printf("#   total  : %d\n", reqAll);
2102    printf("#   left  : %d\n", leftObjs);
2103    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2104    printf("#   reused : %d\n", reAll);
2105    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2106
2107    printf("# node-sets\n");
2108    printf("#   total  : %d\n", reqNodeset);
2109    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2110    printf("#   reused : %d\n", reNodeset);
2111    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2112
2113    printf("# strings\n");
2114    printf("#   total  : %d\n", reqString);
2115    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2116    printf("#   reused : %d\n", reString);
2117    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2118
2119    printf("# booleans\n");
2120    printf("#   total  : %d\n", reqBool);
2121    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2122    printf("#   reused : %d\n", reBool);
2123    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2124
2125    printf("# numbers\n");
2126    printf("#   total  : %d\n", reqNumber);
2127    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2128    printf("#   reused : %d\n", reNumber);
2129    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2130
2131    printf("# XSLT result tree fragments\n");
2132    printf("#   total  : %d\n", reqXSLTTree);
2133    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2134    printf("#   reused : %d\n", reXSLTTree);
2135    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2136
2137    printf("# undefined\n");
2138    printf("#   total  : %d\n", reqUndefined);
2139    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2140    printf("#   reused : %d\n", reUndefined);
2141    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2142
2143}
2144
2145#endif /* XP_DEBUG_OBJ_USAGE */
2146
2147#endif /* LIBXML_DEBUG_ENABLED */
2148
2149/************************************************************************
2150 *									*
2151 *			XPath object caching				*
2152 *									*
2153 ************************************************************************/
2154
2155/**
2156 * xmlXPathNewCache:
2157 *
2158 * Create a new object cache
2159 *
2160 * Returns the xmlXPathCache just allocated.
2161 */
2162static xmlXPathContextCachePtr
2163xmlXPathNewCache(void)
2164{
2165    xmlXPathContextCachePtr ret;
2166
2167    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2168    if (ret == NULL) {
2169        xmlXPathErrMemory(NULL, "creating object cache\n");
2170	return(NULL);
2171    }
2172    memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2173    ret->maxNodeset = 100;
2174    ret->maxString = 100;
2175    ret->maxBoolean = 100;
2176    ret->maxNumber = 100;
2177    ret->maxMisc = 100;
2178    return(ret);
2179}
2180
2181static void
2182xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2183{
2184    int i;
2185    xmlXPathObjectPtr obj;
2186
2187    if (list == NULL)
2188	return;
2189
2190    for (i = 0; i < list->number; i++) {
2191	obj = list->items[i];
2192	/*
2193	* Note that it is already assured that we don't need to
2194	* look out for namespace nodes in the node-set.
2195	*/
2196	if (obj->nodesetval != NULL) {
2197	    if (obj->nodesetval->nodeTab != NULL)
2198		xmlFree(obj->nodesetval->nodeTab);
2199	    xmlFree(obj->nodesetval);
2200	}
2201	xmlFree(obj);
2202#ifdef XP_DEBUG_OBJ_USAGE
2203	xmlXPathDebugObjCounterAll--;
2204#endif
2205    }
2206    xmlPointerListFree(list);
2207}
2208
2209static void
2210xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2211{
2212    if (cache == NULL)
2213	return;
2214    if (cache->nodesetObjs)
2215	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2216    if (cache->stringObjs)
2217	xmlXPathCacheFreeObjectList(cache->stringObjs);
2218    if (cache->booleanObjs)
2219	xmlXPathCacheFreeObjectList(cache->booleanObjs);
2220    if (cache->numberObjs)
2221	xmlXPathCacheFreeObjectList(cache->numberObjs);
2222    if (cache->miscObjs)
2223	xmlXPathCacheFreeObjectList(cache->miscObjs);
2224    xmlFree(cache);
2225}
2226
2227/**
2228 * xmlXPathContextSetCache:
2229 *
2230 * @ctxt:  the XPath context
2231 * @active: enables/disables (creates/frees) the cache
2232 * @value: a value with semantics dependant on @options
2233 * @options: options (currently only the value 0 is used)
2234 *
2235 * Creates/frees an object cache on the XPath context.
2236 * If activates XPath objects (xmlXPathObject) will be cached internally
2237 * to be reused.
2238 * @options:
2239 *   0: This will set the XPath object caching:
2240 *      @value:
2241 *        This will set the maximum number of XPath objects
2242 *        to be cached per slot
2243 *        There are 5 slots for: node-set, string, number, boolean, and
2244 *        misc objects. Use <0 for the default number (100).
2245 *   Other values for @options have currently no effect.
2246 *
2247 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2248 */
2249int
2250xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2251			int active,
2252			int value,
2253			int options)
2254{
2255    if (ctxt == NULL)
2256	return(-1);
2257    if (active) {
2258	xmlXPathContextCachePtr cache;
2259
2260	if (ctxt->cache == NULL) {
2261	    ctxt->cache = xmlXPathNewCache();
2262	    if (ctxt->cache == NULL)
2263		return(-1);
2264	}
2265	cache = (xmlXPathContextCachePtr) ctxt->cache;
2266	if (options == 0) {
2267	    if (value < 0)
2268		value = 100;
2269	    cache->maxNodeset = value;
2270	    cache->maxString = value;
2271	    cache->maxNumber = value;
2272	    cache->maxBoolean = value;
2273	    cache->maxMisc = value;
2274	}
2275    } else if (ctxt->cache != NULL) {
2276	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2277	ctxt->cache = NULL;
2278    }
2279    return(0);
2280}
2281
2282/**
2283 * xmlXPathCacheWrapNodeSet:
2284 * @ctxt: the XPath context
2285 * @val:  the NodePtr value
2286 *
2287 * This is the cached version of xmlXPathWrapNodeSet().
2288 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2289 *
2290 * Returns the created or reused object.
2291 */
2292static xmlXPathObjectPtr
2293xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2294{
2295    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2296	xmlXPathContextCachePtr cache =
2297	    (xmlXPathContextCachePtr) ctxt->cache;
2298
2299	if ((cache->miscObjs != NULL) &&
2300	    (cache->miscObjs->number != 0))
2301	{
2302	    xmlXPathObjectPtr ret;
2303
2304	    ret = (xmlXPathObjectPtr)
2305		cache->miscObjs->items[--cache->miscObjs->number];
2306	    ret->type = XPATH_NODESET;
2307	    ret->nodesetval = val;
2308#ifdef XP_DEBUG_OBJ_USAGE
2309	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2310#endif
2311	    return(ret);
2312	}
2313    }
2314
2315    return(xmlXPathWrapNodeSet(val));
2316
2317}
2318
2319/**
2320 * xmlXPathCacheWrapString:
2321 * @ctxt: the XPath context
2322 * @val:  the xmlChar * value
2323 *
2324 * This is the cached version of xmlXPathWrapString().
2325 * Wraps the @val string into an XPath object.
2326 *
2327 * Returns the created or reused object.
2328 */
2329static xmlXPathObjectPtr
2330xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2331{
2332    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2333	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2334
2335	if ((cache->stringObjs != NULL) &&
2336	    (cache->stringObjs->number != 0))
2337	{
2338
2339	    xmlXPathObjectPtr ret;
2340
2341	    ret = (xmlXPathObjectPtr)
2342		cache->stringObjs->items[--cache->stringObjs->number];
2343	    ret->type = XPATH_STRING;
2344	    ret->stringval = val;
2345#ifdef XP_DEBUG_OBJ_USAGE
2346	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2347#endif
2348	    return(ret);
2349	} else if ((cache->miscObjs != NULL) &&
2350	    (cache->miscObjs->number != 0))
2351	{
2352	    xmlXPathObjectPtr ret;
2353	    /*
2354	    * Fallback to misc-cache.
2355	    */
2356	    ret = (xmlXPathObjectPtr)
2357		cache->miscObjs->items[--cache->miscObjs->number];
2358
2359	    ret->type = XPATH_STRING;
2360	    ret->stringval = val;
2361#ifdef XP_DEBUG_OBJ_USAGE
2362	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2363#endif
2364	    return(ret);
2365	}
2366    }
2367    return(xmlXPathWrapString(val));
2368}
2369
2370/**
2371 * xmlXPathCacheNewNodeSet:
2372 * @ctxt: the XPath context
2373 * @val:  the NodePtr value
2374 *
2375 * This is the cached version of xmlXPathNewNodeSet().
2376 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2377 * it with the single Node @val
2378 *
2379 * Returns the created or reused object.
2380 */
2381static xmlXPathObjectPtr
2382xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2383{
2384    if ((ctxt != NULL) && (ctxt->cache)) {
2385	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2386
2387	if ((cache->nodesetObjs != NULL) &&
2388	    (cache->nodesetObjs->number != 0))
2389	{
2390	    xmlXPathObjectPtr ret;
2391	    /*
2392	    * Use the nodset-cache.
2393	    */
2394	    ret = (xmlXPathObjectPtr)
2395		cache->nodesetObjs->items[--cache->nodesetObjs->number];
2396	    ret->type = XPATH_NODESET;
2397	    ret->boolval = 0;
2398	    if (val) {
2399		if ((ret->nodesetval->nodeMax == 0) ||
2400		    (val->type == XML_NAMESPACE_DECL))
2401		{
2402		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2403		} else {
2404		    ret->nodesetval->nodeTab[0] = val;
2405		    ret->nodesetval->nodeNr = 1;
2406		}
2407	    }
2408#ifdef XP_DEBUG_OBJ_USAGE
2409	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2410#endif
2411	    return(ret);
2412	} else if ((cache->miscObjs != NULL) &&
2413	    (cache->miscObjs->number != 0))
2414	{
2415	    xmlXPathObjectPtr ret;
2416	    /*
2417	    * Fallback to misc-cache.
2418	    */
2419
2420	    ret = (xmlXPathObjectPtr)
2421		cache->miscObjs->items[--cache->miscObjs->number];
2422
2423	    ret->type = XPATH_NODESET;
2424	    ret->boolval = 0;
2425	    ret->nodesetval = xmlXPathNodeSetCreate(val);
2426	    if (ret->nodesetval == NULL) {
2427		ctxt->lastError.domain = XML_FROM_XPATH;
2428		ctxt->lastError.code = XML_ERR_NO_MEMORY;
2429		return(NULL);
2430	    }
2431#ifdef XP_DEBUG_OBJ_USAGE
2432	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2433#endif
2434	    return(ret);
2435	}
2436    }
2437    return(xmlXPathNewNodeSet(val));
2438}
2439
2440/**
2441 * xmlXPathCacheNewCString:
2442 * @ctxt: the XPath context
2443 * @val:  the char * value
2444 *
2445 * This is the cached version of xmlXPathNewCString().
2446 * Acquire an xmlXPathObjectPtr of type string and of value @val
2447 *
2448 * Returns the created or reused object.
2449 */
2450static xmlXPathObjectPtr
2451xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2452{
2453    if ((ctxt != NULL) && (ctxt->cache)) {
2454	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2455
2456	if ((cache->stringObjs != NULL) &&
2457	    (cache->stringObjs->number != 0))
2458	{
2459	    xmlXPathObjectPtr ret;
2460
2461	    ret = (xmlXPathObjectPtr)
2462		cache->stringObjs->items[--cache->stringObjs->number];
2463
2464	    ret->type = XPATH_STRING;
2465	    ret->stringval = xmlStrdup(BAD_CAST val);
2466#ifdef XP_DEBUG_OBJ_USAGE
2467	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2468#endif
2469	    return(ret);
2470	} else if ((cache->miscObjs != NULL) &&
2471	    (cache->miscObjs->number != 0))
2472	{
2473	    xmlXPathObjectPtr ret;
2474
2475	    ret = (xmlXPathObjectPtr)
2476		cache->miscObjs->items[--cache->miscObjs->number];
2477
2478	    ret->type = XPATH_STRING;
2479	    ret->stringval = xmlStrdup(BAD_CAST val);
2480#ifdef XP_DEBUG_OBJ_USAGE
2481	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2482#endif
2483	    return(ret);
2484	}
2485    }
2486    return(xmlXPathNewCString(val));
2487}
2488
2489/**
2490 * xmlXPathCacheNewString:
2491 * @ctxt: the XPath context
2492 * @val:  the xmlChar * value
2493 *
2494 * This is the cached version of xmlXPathNewString().
2495 * Acquire an xmlXPathObjectPtr of type string and of value @val
2496 *
2497 * Returns the created or reused object.
2498 */
2499static xmlXPathObjectPtr
2500xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2501{
2502    if ((ctxt != NULL) && (ctxt->cache)) {
2503	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2504
2505	if ((cache->stringObjs != NULL) &&
2506	    (cache->stringObjs->number != 0))
2507	{
2508	    xmlXPathObjectPtr ret;
2509
2510	    ret = (xmlXPathObjectPtr)
2511		cache->stringObjs->items[--cache->stringObjs->number];
2512	    ret->type = XPATH_STRING;
2513	    if (val != NULL)
2514		ret->stringval = xmlStrdup(val);
2515	    else
2516		ret->stringval = xmlStrdup((const xmlChar *)"");
2517#ifdef XP_DEBUG_OBJ_USAGE
2518	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2519#endif
2520	    return(ret);
2521	} else if ((cache->miscObjs != NULL) &&
2522	    (cache->miscObjs->number != 0))
2523	{
2524	    xmlXPathObjectPtr ret;
2525
2526	    ret = (xmlXPathObjectPtr)
2527		cache->miscObjs->items[--cache->miscObjs->number];
2528
2529	    ret->type = XPATH_STRING;
2530	    if (val != NULL)
2531		ret->stringval = xmlStrdup(val);
2532	    else
2533		ret->stringval = xmlStrdup((const xmlChar *)"");
2534#ifdef XP_DEBUG_OBJ_USAGE
2535	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2536#endif
2537	    return(ret);
2538	}
2539    }
2540    return(xmlXPathNewString(val));
2541}
2542
2543/**
2544 * xmlXPathCacheNewBoolean:
2545 * @ctxt: the XPath context
2546 * @val:  the boolean value
2547 *
2548 * This is the cached version of xmlXPathNewBoolean().
2549 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2550 *
2551 * Returns the created or reused object.
2552 */
2553static xmlXPathObjectPtr
2554xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2555{
2556    if ((ctxt != NULL) && (ctxt->cache)) {
2557	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2558
2559	if ((cache->booleanObjs != NULL) &&
2560	    (cache->booleanObjs->number != 0))
2561	{
2562	    xmlXPathObjectPtr ret;
2563
2564	    ret = (xmlXPathObjectPtr)
2565		cache->booleanObjs->items[--cache->booleanObjs->number];
2566	    ret->type = XPATH_BOOLEAN;
2567	    ret->boolval = (val != 0);
2568#ifdef XP_DEBUG_OBJ_USAGE
2569	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2570#endif
2571	    return(ret);
2572	} else if ((cache->miscObjs != NULL) &&
2573	    (cache->miscObjs->number != 0))
2574	{
2575	    xmlXPathObjectPtr ret;
2576
2577	    ret = (xmlXPathObjectPtr)
2578		cache->miscObjs->items[--cache->miscObjs->number];
2579
2580	    ret->type = XPATH_BOOLEAN;
2581	    ret->boolval = (val != 0);
2582#ifdef XP_DEBUG_OBJ_USAGE
2583	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2584#endif
2585	    return(ret);
2586	}
2587    }
2588    return(xmlXPathNewBoolean(val));
2589}
2590
2591/**
2592 * xmlXPathCacheNewFloat:
2593 * @ctxt: the XPath context
2594 * @val:  the double value
2595 *
2596 * This is the cached version of xmlXPathNewFloat().
2597 * Acquires an xmlXPathObjectPtr of type double and of value @val
2598 *
2599 * Returns the created or reused object.
2600 */
2601static xmlXPathObjectPtr
2602xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2603{
2604     if ((ctxt != NULL) && (ctxt->cache)) {
2605	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2606
2607	if ((cache->numberObjs != NULL) &&
2608	    (cache->numberObjs->number != 0))
2609	{
2610	    xmlXPathObjectPtr ret;
2611
2612	    ret = (xmlXPathObjectPtr)
2613		cache->numberObjs->items[--cache->numberObjs->number];
2614	    ret->type = XPATH_NUMBER;
2615	    ret->floatval = val;
2616#ifdef XP_DEBUG_OBJ_USAGE
2617	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2618#endif
2619	    return(ret);
2620	} else if ((cache->miscObjs != NULL) &&
2621	    (cache->miscObjs->number != 0))
2622	{
2623	    xmlXPathObjectPtr ret;
2624
2625	    ret = (xmlXPathObjectPtr)
2626		cache->miscObjs->items[--cache->miscObjs->number];
2627
2628	    ret->type = XPATH_NUMBER;
2629	    ret->floatval = val;
2630#ifdef XP_DEBUG_OBJ_USAGE
2631	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2632#endif
2633	    return(ret);
2634	}
2635    }
2636    return(xmlXPathNewFloat(val));
2637}
2638
2639/**
2640 * xmlXPathCacheConvertString:
2641 * @ctxt: the XPath context
2642 * @val:  an XPath object
2643 *
2644 * This is the cached version of xmlXPathConvertString().
2645 * Converts an existing object to its string() equivalent
2646 *
2647 * Returns a created or reused object, the old one is freed (cached)
2648 *         (or the operation is done directly on @val)
2649 */
2650
2651static xmlXPathObjectPtr
2652xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2653    xmlChar *res = NULL;
2654
2655    if (val == NULL)
2656	return(xmlXPathCacheNewCString(ctxt, ""));
2657
2658    switch (val->type) {
2659    case XPATH_UNDEFINED:
2660#ifdef DEBUG_EXPR
2661	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2662#endif
2663	break;
2664    case XPATH_NODESET:
2665    case XPATH_XSLT_TREE:
2666	res = xmlXPathCastNodeSetToString(val->nodesetval);
2667	break;
2668    case XPATH_STRING:
2669	return(val);
2670    case XPATH_BOOLEAN:
2671	res = xmlXPathCastBooleanToString(val->boolval);
2672	break;
2673    case XPATH_NUMBER:
2674	res = xmlXPathCastNumberToString(val->floatval);
2675	break;
2676    case XPATH_USERS:
2677    case XPATH_POINT:
2678    case XPATH_RANGE:
2679    case XPATH_LOCATIONSET:
2680	TODO;
2681	break;
2682    }
2683    xmlXPathReleaseObject(ctxt, val);
2684    if (res == NULL)
2685	return(xmlXPathCacheNewCString(ctxt, ""));
2686    return(xmlXPathCacheWrapString(ctxt, res));
2687}
2688
2689/**
2690 * xmlXPathCacheObjectCopy:
2691 * @ctxt: the XPath context
2692 * @val:  the original object
2693 *
2694 * This is the cached version of xmlXPathObjectCopy().
2695 * Acquire a copy of a given object
2696 *
2697 * Returns a created or reused created object.
2698 */
2699static xmlXPathObjectPtr
2700xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2701{
2702    if (val == NULL)
2703	return(NULL);
2704
2705    if (XP_HAS_CACHE(ctxt)) {
2706	switch (val->type) {
2707	    case XPATH_NODESET:
2708		return(xmlXPathCacheWrapNodeSet(ctxt,
2709		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2710	    case XPATH_STRING:
2711		return(xmlXPathCacheNewString(ctxt, val->stringval));
2712	    case XPATH_BOOLEAN:
2713		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2714	    case XPATH_NUMBER:
2715		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2716	    default:
2717		break;
2718	}
2719    }
2720    return(xmlXPathObjectCopy(val));
2721}
2722
2723/**
2724 * xmlXPathCacheConvertBoolean:
2725 * @ctxt: the XPath context
2726 * @val:  an XPath object
2727 *
2728 * This is the cached version of xmlXPathConvertBoolean().
2729 * Converts an existing object to its boolean() equivalent
2730 *
2731 * Returns a created or reused object, the old one is freed (or the operation
2732 *         is done directly on @val)
2733 */
2734static xmlXPathObjectPtr
2735xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2736    xmlXPathObjectPtr ret;
2737
2738    if (val == NULL)
2739	return(xmlXPathCacheNewBoolean(ctxt, 0));
2740    if (val->type == XPATH_BOOLEAN)
2741	return(val);
2742    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2743    xmlXPathReleaseObject(ctxt, val);
2744    return(ret);
2745}
2746
2747/**
2748 * xmlXPathCacheConvertNumber:
2749 * @ctxt: the XPath context
2750 * @val:  an XPath object
2751 *
2752 * This is the cached version of xmlXPathConvertNumber().
2753 * Converts an existing object to its number() equivalent
2754 *
2755 * Returns a created or reused object, the old one is freed (or the operation
2756 *         is done directly on @val)
2757 */
2758static xmlXPathObjectPtr
2759xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2760    xmlXPathObjectPtr ret;
2761
2762    if (val == NULL)
2763	return(xmlXPathCacheNewFloat(ctxt, 0.0));
2764    if (val->type == XPATH_NUMBER)
2765	return(val);
2766    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2767    xmlXPathReleaseObject(ctxt, val);
2768    return(ret);
2769}
2770
2771/************************************************************************
2772 *									*
2773 *		Parser stacks related functions and macros		*
2774 *									*
2775 ************************************************************************/
2776
2777/**
2778 * xmlXPathSetFrame:
2779 * @ctxt: an XPath parser context
2780 *
2781 * Set the callee evaluation frame
2782 *
2783 * Returns the previous frame value to be restored once done
2784 */
2785static int
2786xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2787    int ret;
2788
2789    if (ctxt == NULL)
2790        return(0);
2791    ret = ctxt->valueFrame;
2792    ctxt->valueFrame = ctxt->valueNr;
2793    return(ret);
2794}
2795
2796/**
2797 * xmlXPathPopFrame:
2798 * @ctxt: an XPath parser context
2799 * @frame: the previous frame value
2800 *
2801 * Remove the callee evaluation frame
2802 */
2803static void
2804xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2805    if (ctxt == NULL)
2806        return;
2807    if (ctxt->valueNr < ctxt->valueFrame) {
2808        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2809    }
2810    ctxt->valueFrame = frame;
2811}
2812
2813/**
2814 * valuePop:
2815 * @ctxt: an XPath evaluation context
2816 *
2817 * Pops the top XPath object from the value stack
2818 *
2819 * Returns the XPath object just removed
2820 */
2821xmlXPathObjectPtr
2822valuePop(xmlXPathParserContextPtr ctxt)
2823{
2824    xmlXPathObjectPtr ret;
2825
2826    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2827        return (NULL);
2828
2829    if (ctxt->valueNr <= ctxt->valueFrame) {
2830        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2831        return (NULL);
2832    }
2833
2834    ctxt->valueNr--;
2835    if (ctxt->valueNr > 0)
2836        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2837    else
2838        ctxt->value = NULL;
2839    ret = ctxt->valueTab[ctxt->valueNr];
2840    ctxt->valueTab[ctxt->valueNr] = NULL;
2841    return (ret);
2842}
2843/**
2844 * valuePush:
2845 * @ctxt:  an XPath evaluation context
2846 * @value:  the XPath object
2847 *
2848 * Pushes a new XPath object on top of the value stack
2849 *
2850 * returns the number of items on the value stack
2851 */
2852int
2853valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2854{
2855    if ((ctxt == NULL) || (value == NULL)) return(-1);
2856    if (ctxt->valueNr >= ctxt->valueMax) {
2857        xmlXPathObjectPtr *tmp;
2858
2859        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2860            xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2861            ctxt->error = XPATH_MEMORY_ERROR;
2862            return (0);
2863        }
2864        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2865                                             2 * ctxt->valueMax *
2866                                             sizeof(ctxt->valueTab[0]));
2867        if (tmp == NULL) {
2868            xmlXPathErrMemory(NULL, "pushing value\n");
2869            ctxt->error = XPATH_MEMORY_ERROR;
2870            return (0);
2871        }
2872        ctxt->valueMax *= 2;
2873	ctxt->valueTab = tmp;
2874    }
2875    ctxt->valueTab[ctxt->valueNr] = value;
2876    ctxt->value = value;
2877    return (ctxt->valueNr++);
2878}
2879
2880/**
2881 * xmlXPathPopBoolean:
2882 * @ctxt:  an XPath parser context
2883 *
2884 * Pops a boolean from the stack, handling conversion if needed.
2885 * Check error with #xmlXPathCheckError.
2886 *
2887 * Returns the boolean
2888 */
2889int
2890xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2891    xmlXPathObjectPtr obj;
2892    int ret;
2893
2894    obj = valuePop(ctxt);
2895    if (obj == NULL) {
2896	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2897	return(0);
2898    }
2899    if (obj->type != XPATH_BOOLEAN)
2900	ret = xmlXPathCastToBoolean(obj);
2901    else
2902        ret = obj->boolval;
2903    xmlXPathReleaseObject(ctxt->context, obj);
2904    return(ret);
2905}
2906
2907/**
2908 * xmlXPathPopNumber:
2909 * @ctxt:  an XPath parser context
2910 *
2911 * Pops a number from the stack, handling conversion if needed.
2912 * Check error with #xmlXPathCheckError.
2913 *
2914 * Returns the number
2915 */
2916double
2917xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2918    xmlXPathObjectPtr obj;
2919    double ret;
2920
2921    obj = valuePop(ctxt);
2922    if (obj == NULL) {
2923	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2924	return(0);
2925    }
2926    if (obj->type != XPATH_NUMBER)
2927	ret = xmlXPathCastToNumber(obj);
2928    else
2929        ret = obj->floatval;
2930    xmlXPathReleaseObject(ctxt->context, obj);
2931    return(ret);
2932}
2933
2934/**
2935 * xmlXPathPopString:
2936 * @ctxt:  an XPath parser context
2937 *
2938 * Pops a string from the stack, handling conversion if needed.
2939 * Check error with #xmlXPathCheckError.
2940 *
2941 * Returns the string
2942 */
2943xmlChar *
2944xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2945    xmlXPathObjectPtr obj;
2946    xmlChar * ret;
2947
2948    obj = valuePop(ctxt);
2949    if (obj == NULL) {
2950	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2951	return(NULL);
2952    }
2953    ret = xmlXPathCastToString(obj);	/* this does required strdup */
2954    /* TODO: needs refactoring somewhere else */
2955    if (obj->stringval == ret)
2956	obj->stringval = NULL;
2957    xmlXPathReleaseObject(ctxt->context, obj);
2958    return(ret);
2959}
2960
2961/**
2962 * xmlXPathPopNodeSet:
2963 * @ctxt:  an XPath parser context
2964 *
2965 * Pops a node-set from the stack, handling conversion if needed.
2966 * Check error with #xmlXPathCheckError.
2967 *
2968 * Returns the node-set
2969 */
2970xmlNodeSetPtr
2971xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2972    xmlXPathObjectPtr obj;
2973    xmlNodeSetPtr ret;
2974
2975    if (ctxt == NULL) return(NULL);
2976    if (ctxt->value == NULL) {
2977	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2978	return(NULL);
2979    }
2980    if (!xmlXPathStackIsNodeSet(ctxt)) {
2981	xmlXPathSetTypeError(ctxt);
2982	return(NULL);
2983    }
2984    obj = valuePop(ctxt);
2985    ret = obj->nodesetval;
2986#if 0
2987    /* to fix memory leak of not clearing obj->user */
2988    if (obj->boolval && obj->user != NULL)
2989        xmlFreeNodeList((xmlNodePtr) obj->user);
2990#endif
2991    obj->nodesetval = NULL;
2992    xmlXPathReleaseObject(ctxt->context, obj);
2993    return(ret);
2994}
2995
2996/**
2997 * xmlXPathPopExternal:
2998 * @ctxt:  an XPath parser context
2999 *
3000 * Pops an external object from the stack, handling conversion if needed.
3001 * Check error with #xmlXPathCheckError.
3002 *
3003 * Returns the object
3004 */
3005void *
3006xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3007    xmlXPathObjectPtr obj;
3008    void * ret;
3009
3010    if ((ctxt == NULL) || (ctxt->value == NULL)) {
3011	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3012	return(NULL);
3013    }
3014    if (ctxt->value->type != XPATH_USERS) {
3015	xmlXPathSetTypeError(ctxt);
3016	return(NULL);
3017    }
3018    obj = valuePop(ctxt);
3019    ret = obj->user;
3020    obj->user = NULL;
3021    xmlXPathReleaseObject(ctxt->context, obj);
3022    return(ret);
3023}
3024
3025/*
3026 * Macros for accessing the content. Those should be used only by the parser,
3027 * and not exported.
3028 *
3029 * Dirty macros, i.e. one need to make assumption on the context to use them
3030 *
3031 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3032 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3033 *           in ISO-Latin or UTF-8.
3034 *           This should be used internally by the parser
3035 *           only to compare to ASCII values otherwise it would break when
3036 *           running with UTF-8 encoding.
3037 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3038 *           to compare on ASCII based substring.
3039 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3040 *           strings within the parser.
3041 *   CURRENT Returns the current char value, with the full decoding of
3042 *           UTF-8 if we are using this mode. It returns an int.
3043 *   NEXT    Skip to the next character, this does the proper decoding
3044 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3045 *           It returns the pointer to the current xmlChar.
3046 */
3047
3048#define CUR (*ctxt->cur)
3049#define SKIP(val) ctxt->cur += (val)
3050#define NXT(val) ctxt->cur[(val)]
3051#define CUR_PTR ctxt->cur
3052#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3053
3054#define COPY_BUF(l,b,i,v)                                              \
3055    if (l == 1) b[i++] = (xmlChar) v;                                  \
3056    else i += xmlCopyChar(l,&b[i],v)
3057
3058#define NEXTL(l)  ctxt->cur += l
3059
3060#define SKIP_BLANKS							\
3061    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3062
3063#define CURRENT (*ctxt->cur)
3064#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3065
3066
3067#ifndef DBL_DIG
3068#define DBL_DIG 16
3069#endif
3070#ifndef DBL_EPSILON
3071#define DBL_EPSILON 1E-9
3072#endif
3073
3074#define UPPER_DOUBLE 1E9
3075#define LOWER_DOUBLE 1E-5
3076#define	LOWER_DOUBLE_EXP 5
3077
3078#define INTEGER_DIGITS DBL_DIG
3079#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3080#define EXPONENT_DIGITS (3 + 2)
3081
3082/**
3083 * xmlXPathFormatNumber:
3084 * @number:     number to format
3085 * @buffer:     output buffer
3086 * @buffersize: size of output buffer
3087 *
3088 * Convert the number into a string representation.
3089 */
3090static void
3091xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3092{
3093    switch (xmlXPathIsInf(number)) {
3094    case 1:
3095	if (buffersize > (int)sizeof("Infinity"))
3096	    snprintf(buffer, buffersize, "Infinity");
3097	break;
3098    case -1:
3099	if (buffersize > (int)sizeof("-Infinity"))
3100	    snprintf(buffer, buffersize, "-Infinity");
3101	break;
3102    default:
3103	if (xmlXPathIsNaN(number)) {
3104	    if (buffersize > (int)sizeof("NaN"))
3105		snprintf(buffer, buffersize, "NaN");
3106	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
3107	    snprintf(buffer, buffersize, "0");
3108	} else if (number == ((int) number)) {
3109	    char work[30];
3110	    char *ptr, *cur;
3111	    int value = (int) number;
3112
3113            ptr = &buffer[0];
3114	    if (value == 0) {
3115		*ptr++ = '0';
3116	    } else {
3117		snprintf(work, 29, "%d", value);
3118		cur = &work[0];
3119		while ((*cur) && (ptr - buffer < buffersize)) {
3120		    *ptr++ = *cur++;
3121		}
3122	    }
3123	    if (ptr - buffer < buffersize) {
3124		*ptr = 0;
3125	    } else if (buffersize > 0) {
3126		ptr--;
3127		*ptr = 0;
3128	    }
3129	} else {
3130	    /*
3131	      For the dimension of work,
3132	          DBL_DIG is number of significant digits
3133		  EXPONENT is only needed for "scientific notation"
3134	          3 is sign, decimal point, and terminating zero
3135		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3136	      Note that this dimension is slightly (a few characters)
3137	      larger than actually necessary.
3138	    */
3139	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3140	    int integer_place, fraction_place;
3141	    char *ptr;
3142	    char *after_fraction;
3143	    double absolute_value;
3144	    int size;
3145
3146	    absolute_value = fabs(number);
3147
3148	    /*
3149	     * First choose format - scientific or regular floating point.
3150	     * In either case, result is in work, and after_fraction points
3151	     * just past the fractional part.
3152	    */
3153	    if ( ((absolute_value > UPPER_DOUBLE) ||
3154		  (absolute_value < LOWER_DOUBLE)) &&
3155		 (absolute_value != 0.0) ) {
3156		/* Use scientific notation */
3157		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3158		fraction_place = DBL_DIG - 1;
3159		size = snprintf(work, sizeof(work),"%*.*e",
3160			 integer_place, fraction_place, number);
3161		while ((size > 0) && (work[size] != 'e')) size--;
3162
3163	    }
3164	    else {
3165		/* Use regular notation */
3166		if (absolute_value > 0.0) {
3167		    integer_place = (int)log10(absolute_value);
3168		    if (integer_place > 0)
3169		        fraction_place = DBL_DIG - integer_place - 1;
3170		    else
3171		        fraction_place = DBL_DIG - integer_place;
3172		} else {
3173		    fraction_place = 1;
3174		}
3175		size = snprintf(work, sizeof(work), "%0.*f",
3176				fraction_place, number);
3177	    }
3178
3179	    /* Remove leading spaces sometimes inserted by snprintf */
3180	    while (work[0] == ' ') {
3181	        for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3182		size--;
3183	    }
3184
3185	    /* Remove fractional trailing zeroes */
3186	    after_fraction = work + size;
3187	    ptr = after_fraction;
3188	    while (*(--ptr) == '0')
3189		;
3190	    if (*ptr != '.')
3191	        ptr++;
3192	    while ((*ptr++ = *after_fraction++) != 0);
3193
3194	    /* Finally copy result back to caller */
3195	    size = strlen(work) + 1;
3196	    if (size > buffersize) {
3197		work[buffersize - 1] = 0;
3198		size = buffersize;
3199	    }
3200	    memmove(buffer, work, size);
3201	}
3202	break;
3203    }
3204}
3205
3206
3207/************************************************************************
3208 *									*
3209 *			Routines to handle NodeSets			*
3210 *									*
3211 ************************************************************************/
3212
3213/**
3214 * xmlXPathOrderDocElems:
3215 * @doc:  an input document
3216 *
3217 * Call this routine to speed up XPath computation on static documents.
3218 * This stamps all the element nodes with the document order
3219 * Like for line information, the order is kept in the element->content
3220 * field, the value stored is actually - the node number (starting at -1)
3221 * to be able to differentiate from line numbers.
3222 *
3223 * Returns the number of elements found in the document or -1 in case
3224 *    of error.
3225 */
3226long
3227xmlXPathOrderDocElems(xmlDocPtr doc) {
3228    long count = 0;
3229    xmlNodePtr cur;
3230
3231    if (doc == NULL)
3232	return(-1);
3233    cur = doc->children;
3234    while (cur != NULL) {
3235	if (cur->type == XML_ELEMENT_NODE) {
3236	    cur->content = (void *) (-(++count));
3237	    if (cur->children != NULL) {
3238		cur = cur->children;
3239		continue;
3240	    }
3241	}
3242	if (cur->next != NULL) {
3243	    cur = cur->next;
3244	    continue;
3245	}
3246	do {
3247	    cur = cur->parent;
3248	    if (cur == NULL)
3249		break;
3250	    if (cur == (xmlNodePtr) doc) {
3251		cur = NULL;
3252		break;
3253	    }
3254	    if (cur->next != NULL) {
3255		cur = cur->next;
3256		break;
3257	    }
3258	} while (cur != NULL);
3259    }
3260    return(count);
3261}
3262
3263/**
3264 * xmlXPathCmpNodes:
3265 * @node1:  the first node
3266 * @node2:  the second node
3267 *
3268 * Compare two nodes w.r.t document order
3269 *
3270 * Returns -2 in case of error 1 if first point < second point, 0 if
3271 *         it's the same node, -1 otherwise
3272 */
3273int
3274xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3275    int depth1, depth2;
3276    int attr1 = 0, attr2 = 0;
3277    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3278    xmlNodePtr cur, root;
3279
3280    if ((node1 == NULL) || (node2 == NULL))
3281	return(-2);
3282    /*
3283     * a couple of optimizations which will avoid computations in most cases
3284     */
3285    if (node1 == node2)		/* trivial case */
3286	return(0);
3287    if (node1->type == XML_ATTRIBUTE_NODE) {
3288	attr1 = 1;
3289	attrNode1 = node1;
3290	node1 = node1->parent;
3291    }
3292    if (node2->type == XML_ATTRIBUTE_NODE) {
3293	attr2 = 1;
3294	attrNode2 = node2;
3295	node2 = node2->parent;
3296    }
3297    if (node1 == node2) {
3298	if (attr1 == attr2) {
3299	    /* not required, but we keep attributes in order */
3300	    if (attr1 != 0) {
3301	        cur = attrNode2->prev;
3302		while (cur != NULL) {
3303		    if (cur == attrNode1)
3304		        return (1);
3305		    cur = cur->prev;
3306		}
3307		return (-1);
3308	    }
3309	    return(0);
3310	}
3311	if (attr2 == 1)
3312	    return(1);
3313	return(-1);
3314    }
3315    if ((node1->type == XML_NAMESPACE_DECL) ||
3316        (node2->type == XML_NAMESPACE_DECL))
3317	return(1);
3318    if (node1 == node2->prev)
3319	return(1);
3320    if (node1 == node2->next)
3321	return(-1);
3322
3323    /*
3324     * Speedup using document order if availble.
3325     */
3326    if ((node1->type == XML_ELEMENT_NODE) &&
3327	(node2->type == XML_ELEMENT_NODE) &&
3328	(0 > (long) node1->content) &&
3329	(0 > (long) node2->content) &&
3330	(node1->doc == node2->doc)) {
3331	long l1, l2;
3332
3333	l1 = -((long) node1->content);
3334	l2 = -((long) node2->content);
3335	if (l1 < l2)
3336	    return(1);
3337	if (l1 > l2)
3338	    return(-1);
3339    }
3340
3341    /*
3342     * compute depth to root
3343     */
3344    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3345	if (cur == node1)
3346	    return(1);
3347	depth2++;
3348    }
3349    root = cur;
3350    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3351	if (cur == node2)
3352	    return(-1);
3353	depth1++;
3354    }
3355    /*
3356     * Distinct document (or distinct entities :-( ) case.
3357     */
3358    if (root != cur) {
3359	return(-2);
3360    }
3361    /*
3362     * get the nearest common ancestor.
3363     */
3364    while (depth1 > depth2) {
3365	depth1--;
3366	node1 = node1->parent;
3367    }
3368    while (depth2 > depth1) {
3369	depth2--;
3370	node2 = node2->parent;
3371    }
3372    while (node1->parent != node2->parent) {
3373	node1 = node1->parent;
3374	node2 = node2->parent;
3375	/* should not happen but just in case ... */
3376	if ((node1 == NULL) || (node2 == NULL))
3377	    return(-2);
3378    }
3379    /*
3380     * Find who's first.
3381     */
3382    if (node1 == node2->prev)
3383	return(1);
3384    if (node1 == node2->next)
3385	return(-1);
3386    /*
3387     * Speedup using document order if availble.
3388     */
3389    if ((node1->type == XML_ELEMENT_NODE) &&
3390	(node2->type == XML_ELEMENT_NODE) &&
3391	(0 > (long) node1->content) &&
3392	(0 > (long) node2->content) &&
3393	(node1->doc == node2->doc)) {
3394	long l1, l2;
3395
3396	l1 = -((long) node1->content);
3397	l2 = -((long) node2->content);
3398	if (l1 < l2)
3399	    return(1);
3400	if (l1 > l2)
3401	    return(-1);
3402    }
3403
3404    for (cur = node1->next;cur != NULL;cur = cur->next)
3405	if (cur == node2)
3406	    return(1);
3407    return(-1); /* assume there is no sibling list corruption */
3408}
3409
3410/**
3411 * xmlXPathNodeSetSort:
3412 * @set:  the node set
3413 *
3414 * Sort the node set in document order
3415 */
3416void
3417xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3418#ifndef WITH_TIM_SORT
3419    int i, j, incr, len;
3420    xmlNodePtr tmp;
3421#endif
3422
3423    if (set == NULL)
3424	return;
3425
3426#ifndef WITH_TIM_SORT
3427    /*
3428     * Use the old Shell's sort implementation to sort the node-set
3429     * Timsort ought to be quite faster
3430     */
3431    len = set->nodeNr;
3432    for (incr = len / 2; incr > 0; incr /= 2) {
3433	for (i = incr; i < len; i++) {
3434	    j = i - incr;
3435	    while (j >= 0) {
3436#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3437		if (xmlXPathCmpNodesExt(set->nodeTab[j],
3438			set->nodeTab[j + incr]) == -1)
3439#else
3440		if (xmlXPathCmpNodes(set->nodeTab[j],
3441			set->nodeTab[j + incr]) == -1)
3442#endif
3443		{
3444		    tmp = set->nodeTab[j];
3445		    set->nodeTab[j] = set->nodeTab[j + incr];
3446		    set->nodeTab[j + incr] = tmp;
3447		    j -= incr;
3448		} else
3449		    break;
3450	    }
3451	}
3452    }
3453#else /* WITH_TIM_SORT */
3454    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3455#endif /* WITH_TIM_SORT */
3456}
3457
3458#define XML_NODESET_DEFAULT	10
3459/**
3460 * xmlXPathNodeSetDupNs:
3461 * @node:  the parent node of the namespace XPath node
3462 * @ns:  the libxml namespace declaration node.
3463 *
3464 * Namespace node in libxml don't match the XPath semantic. In a node set
3465 * the namespace nodes are duplicated and the next pointer is set to the
3466 * parent node in the XPath semantic.
3467 *
3468 * Returns the newly created object.
3469 */
3470static xmlNodePtr
3471xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3472    xmlNsPtr cur;
3473
3474    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3475	return(NULL);
3476    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3477	return((xmlNodePtr) ns);
3478
3479    /*
3480     * Allocate a new Namespace and fill the fields.
3481     */
3482    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3483    if (cur == NULL) {
3484        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3485	return(NULL);
3486    }
3487    memset(cur, 0, sizeof(xmlNs));
3488    cur->type = XML_NAMESPACE_DECL;
3489    if (ns->href != NULL)
3490	cur->href = xmlStrdup(ns->href);
3491    if (ns->prefix != NULL)
3492	cur->prefix = xmlStrdup(ns->prefix);
3493    cur->next = (xmlNsPtr) node;
3494    return((xmlNodePtr) cur);
3495}
3496
3497/**
3498 * xmlXPathNodeSetFreeNs:
3499 * @ns:  the XPath namespace node found in a nodeset.
3500 *
3501 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3502 * the namespace nodes are duplicated and the next pointer is set to the
3503 * parent node in the XPath semantic. Check if such a node needs to be freed
3504 */
3505void
3506xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3507    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3508	return;
3509
3510    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3511	if (ns->href != NULL)
3512	    xmlFree((xmlChar *)ns->href);
3513	if (ns->prefix != NULL)
3514	    xmlFree((xmlChar *)ns->prefix);
3515	xmlFree(ns);
3516    }
3517}
3518
3519/**
3520 * xmlXPathNodeSetCreate:
3521 * @val:  an initial xmlNodePtr, or NULL
3522 *
3523 * Create a new xmlNodeSetPtr of type double and of value @val
3524 *
3525 * Returns the newly created object.
3526 */
3527xmlNodeSetPtr
3528xmlXPathNodeSetCreate(xmlNodePtr val) {
3529    xmlNodeSetPtr ret;
3530
3531    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3532    if (ret == NULL) {
3533        xmlXPathErrMemory(NULL, "creating nodeset\n");
3534	return(NULL);
3535    }
3536    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3537    if (val != NULL) {
3538        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3539					     sizeof(xmlNodePtr));
3540	if (ret->nodeTab == NULL) {
3541	    xmlXPathErrMemory(NULL, "creating nodeset\n");
3542	    xmlFree(ret);
3543	    return(NULL);
3544	}
3545	memset(ret->nodeTab, 0 ,
3546	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3547        ret->nodeMax = XML_NODESET_DEFAULT;
3548	if (val->type == XML_NAMESPACE_DECL) {
3549	    xmlNsPtr ns = (xmlNsPtr) val;
3550
3551	    ret->nodeTab[ret->nodeNr++] =
3552		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3553	} else
3554	    ret->nodeTab[ret->nodeNr++] = val;
3555    }
3556    return(ret);
3557}
3558
3559/**
3560 * xmlXPathNodeSetCreateSize:
3561 * @size:  the initial size of the set
3562 *
3563 * Create a new xmlNodeSetPtr of type double and of value @val
3564 *
3565 * Returns the newly created object.
3566 */
3567static xmlNodeSetPtr
3568xmlXPathNodeSetCreateSize(int size) {
3569    xmlNodeSetPtr ret;
3570
3571    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3572    if (ret == NULL) {
3573        xmlXPathErrMemory(NULL, "creating nodeset\n");
3574	return(NULL);
3575    }
3576    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3577    if (size < XML_NODESET_DEFAULT)
3578	size = XML_NODESET_DEFAULT;
3579    ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3580    if (ret->nodeTab == NULL) {
3581	xmlXPathErrMemory(NULL, "creating nodeset\n");
3582	xmlFree(ret);
3583	return(NULL);
3584    }
3585    memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3586    ret->nodeMax = size;
3587    return(ret);
3588}
3589
3590/**
3591 * xmlXPathNodeSetContains:
3592 * @cur:  the node-set
3593 * @val:  the node
3594 *
3595 * checks whether @cur contains @val
3596 *
3597 * Returns true (1) if @cur contains @val, false (0) otherwise
3598 */
3599int
3600xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3601    int i;
3602
3603    if ((cur == NULL) || (val == NULL)) return(0);
3604    if (val->type == XML_NAMESPACE_DECL) {
3605	for (i = 0; i < cur->nodeNr; i++) {
3606	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3607		xmlNsPtr ns1, ns2;
3608
3609		ns1 = (xmlNsPtr) val;
3610		ns2 = (xmlNsPtr) cur->nodeTab[i];
3611		if (ns1 == ns2)
3612		    return(1);
3613		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3614	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
3615		    return(1);
3616	    }
3617	}
3618    } else {
3619	for (i = 0; i < cur->nodeNr; i++) {
3620	    if (cur->nodeTab[i] == val)
3621		return(1);
3622	}
3623    }
3624    return(0);
3625}
3626
3627/**
3628 * xmlXPathNodeSetAddNs:
3629 * @cur:  the initial node set
3630 * @node:  the hosting node
3631 * @ns:  a the namespace node
3632 *
3633 * add a new namespace node to an existing NodeSet
3634 *
3635 * Returns 0 in case of success and -1 in case of error
3636 */
3637int
3638xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3639    int i;
3640
3641
3642    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3643        (ns->type != XML_NAMESPACE_DECL) ||
3644	(node->type != XML_ELEMENT_NODE))
3645	return(-1);
3646
3647    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3648    /*
3649     * prevent duplicates
3650     */
3651    for (i = 0;i < cur->nodeNr;i++) {
3652        if ((cur->nodeTab[i] != NULL) &&
3653	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3654	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3655	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3656	    return(0);
3657    }
3658
3659    /*
3660     * grow the nodeTab if needed
3661     */
3662    if (cur->nodeMax == 0) {
3663        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3664					     sizeof(xmlNodePtr));
3665	if (cur->nodeTab == NULL) {
3666	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3667	    return(-1);
3668	}
3669	memset(cur->nodeTab, 0 ,
3670	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3671        cur->nodeMax = XML_NODESET_DEFAULT;
3672    } else if (cur->nodeNr == cur->nodeMax) {
3673        xmlNodePtr *temp;
3674
3675        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3676            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3677            return(-1);
3678        }
3679	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3680				      sizeof(xmlNodePtr));
3681	if (temp == NULL) {
3682	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3683	    return(-1);
3684	}
3685        cur->nodeMax *= 2;
3686	cur->nodeTab = temp;
3687    }
3688    cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3689    return(0);
3690}
3691
3692/**
3693 * xmlXPathNodeSetAdd:
3694 * @cur:  the initial node set
3695 * @val:  a new xmlNodePtr
3696 *
3697 * add a new xmlNodePtr to an existing NodeSet
3698 *
3699 * Returns 0 in case of success, and -1 in case of error
3700 */
3701int
3702xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3703    int i;
3704
3705    if ((cur == NULL) || (val == NULL)) return(-1);
3706
3707    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3708    /*
3709     * prevent duplicates
3710     */
3711    for (i = 0;i < cur->nodeNr;i++)
3712        if (cur->nodeTab[i] == val) return(0);
3713
3714    /*
3715     * grow the nodeTab if needed
3716     */
3717    if (cur->nodeMax == 0) {
3718        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3719					     sizeof(xmlNodePtr));
3720	if (cur->nodeTab == NULL) {
3721	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3722	    return(-1);
3723	}
3724	memset(cur->nodeTab, 0 ,
3725	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3726        cur->nodeMax = XML_NODESET_DEFAULT;
3727    } else if (cur->nodeNr == cur->nodeMax) {
3728        xmlNodePtr *temp;
3729
3730        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3731            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3732            return(-1);
3733        }
3734	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3735				      sizeof(xmlNodePtr));
3736	if (temp == NULL) {
3737	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3738	    return(-1);
3739	}
3740        cur->nodeMax *= 2;
3741	cur->nodeTab = temp;
3742    }
3743    if (val->type == XML_NAMESPACE_DECL) {
3744	xmlNsPtr ns = (xmlNsPtr) val;
3745
3746	cur->nodeTab[cur->nodeNr++] =
3747	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3748    } else
3749	cur->nodeTab[cur->nodeNr++] = val;
3750    return(0);
3751}
3752
3753/**
3754 * xmlXPathNodeSetAddUnique:
3755 * @cur:  the initial node set
3756 * @val:  a new xmlNodePtr
3757 *
3758 * add a new xmlNodePtr to an existing NodeSet, optimized version
3759 * when we are sure the node is not already in the set.
3760 *
3761 * Returns 0 in case of success and -1 in case of failure
3762 */
3763int
3764xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3765    if ((cur == NULL) || (val == NULL)) return(-1);
3766
3767    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3768    /*
3769     * grow the nodeTab if needed
3770     */
3771    if (cur->nodeMax == 0) {
3772        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3773					     sizeof(xmlNodePtr));
3774	if (cur->nodeTab == NULL) {
3775	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3776	    return(-1);
3777	}
3778	memset(cur->nodeTab, 0 ,
3779	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3780        cur->nodeMax = XML_NODESET_DEFAULT;
3781    } else if (cur->nodeNr == cur->nodeMax) {
3782        xmlNodePtr *temp;
3783
3784        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3785            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3786            return(-1);
3787        }
3788	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3789				      sizeof(xmlNodePtr));
3790	if (temp == NULL) {
3791	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3792	    return(-1);
3793	}
3794	cur->nodeTab = temp;
3795        cur->nodeMax *= 2;
3796    }
3797    if (val->type == XML_NAMESPACE_DECL) {
3798	xmlNsPtr ns = (xmlNsPtr) val;
3799
3800	cur->nodeTab[cur->nodeNr++] =
3801	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3802    } else
3803	cur->nodeTab[cur->nodeNr++] = val;
3804    return(0);
3805}
3806
3807/**
3808 * xmlXPathNodeSetMerge:
3809 * @val1:  the first NodeSet or NULL
3810 * @val2:  the second NodeSet
3811 *
3812 * Merges two nodesets, all nodes from @val2 are added to @val1
3813 * if @val1 is NULL, a new set is created and copied from @val2
3814 *
3815 * Returns @val1 once extended or NULL in case of error.
3816 */
3817xmlNodeSetPtr
3818xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3819    int i, j, initNr, skip;
3820    xmlNodePtr n1, n2;
3821
3822    if (val2 == NULL) return(val1);
3823    if (val1 == NULL) {
3824	val1 = xmlXPathNodeSetCreate(NULL);
3825    if (val1 == NULL)
3826        return (NULL);
3827#if 0
3828	/*
3829	* TODO: The optimization won't work in every case, since
3830	*  those nasty namespace nodes need to be added with
3831	*  xmlXPathNodeSetDupNs() to the set; thus a pure
3832	*  memcpy is not possible.
3833	*  If there was a flag on the nodesetval, indicating that
3834	*  some temporary nodes are in, that would be helpfull.
3835	*/
3836	/*
3837	* Optimization: Create an equally sized node-set
3838	* and memcpy the content.
3839	*/
3840	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3841	if (val1 == NULL)
3842	    return(NULL);
3843	if (val2->nodeNr != 0) {
3844	    if (val2->nodeNr == 1)
3845		*(val1->nodeTab) = *(val2->nodeTab);
3846	    else {
3847		memcpy(val1->nodeTab, val2->nodeTab,
3848		    val2->nodeNr * sizeof(xmlNodePtr));
3849	    }
3850	    val1->nodeNr = val2->nodeNr;
3851	}
3852	return(val1);
3853#endif
3854    }
3855
3856    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3857    initNr = val1->nodeNr;
3858
3859    for (i = 0;i < val2->nodeNr;i++) {
3860	n2 = val2->nodeTab[i];
3861	/*
3862	 * check against duplicates
3863	 */
3864	skip = 0;
3865	for (j = 0; j < initNr; j++) {
3866	    n1 = val1->nodeTab[j];
3867	    if (n1 == n2) {
3868		skip = 1;
3869		break;
3870	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3871		       (n2->type == XML_NAMESPACE_DECL)) {
3872		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3873		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3874			((xmlNsPtr) n2)->prefix)))
3875		{
3876		    skip = 1;
3877		    break;
3878		}
3879	    }
3880	}
3881	if (skip)
3882	    continue;
3883
3884	/*
3885	 * grow the nodeTab if needed
3886	 */
3887	if (val1->nodeMax == 0) {
3888	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3889						    sizeof(xmlNodePtr));
3890	    if (val1->nodeTab == NULL) {
3891	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3892		return(NULL);
3893	    }
3894	    memset(val1->nodeTab, 0 ,
3895		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3896	    val1->nodeMax = XML_NODESET_DEFAULT;
3897	} else if (val1->nodeNr == val1->nodeMax) {
3898	    xmlNodePtr *temp;
3899
3900            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3901                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3902                return(NULL);
3903            }
3904	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3905					     sizeof(xmlNodePtr));
3906	    if (temp == NULL) {
3907	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3908		return(NULL);
3909	    }
3910	    val1->nodeTab = temp;
3911	    val1->nodeMax *= 2;
3912	}
3913	if (n2->type == XML_NAMESPACE_DECL) {
3914	    xmlNsPtr ns = (xmlNsPtr) n2;
3915
3916	    val1->nodeTab[val1->nodeNr++] =
3917		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3918	} else
3919	    val1->nodeTab[val1->nodeNr++] = n2;
3920    }
3921
3922    return(val1);
3923}
3924
3925
3926/**
3927 * xmlXPathNodeSetMergeAndClear:
3928 * @set1:  the first NodeSet or NULL
3929 * @set2:  the second NodeSet
3930 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3931 *
3932 * Merges two nodesets, all nodes from @set2 are added to @set1
3933 * if @set1 is NULL, a new set is created and copied from @set2.
3934 * Checks for duplicate nodes. Clears set2.
3935 *
3936 * Returns @set1 once extended or NULL in case of error.
3937 */
3938static xmlNodeSetPtr
3939xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3940			     int hasNullEntries)
3941{
3942    if ((set1 == NULL) && (hasNullEntries == 0)) {
3943	/*
3944	* Note that doing a memcpy of the list, namespace nodes are
3945	* just assigned to set1, since set2 is cleared anyway.
3946	*/
3947	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3948	if (set1 == NULL)
3949	    return(NULL);
3950	if (set2->nodeNr != 0) {
3951	    memcpy(set1->nodeTab, set2->nodeTab,
3952		set2->nodeNr * sizeof(xmlNodePtr));
3953	    set1->nodeNr = set2->nodeNr;
3954	}
3955    } else {
3956	int i, j, initNbSet1;
3957	xmlNodePtr n1, n2;
3958
3959	if (set1 == NULL)
3960            set1 = xmlXPathNodeSetCreate(NULL);
3961        if (set1 == NULL)
3962            return (NULL);
3963
3964	initNbSet1 = set1->nodeNr;
3965	for (i = 0;i < set2->nodeNr;i++) {
3966	    n2 = set2->nodeTab[i];
3967	    /*
3968	    * Skip NULLed entries.
3969	    */
3970	    if (n2 == NULL)
3971		continue;
3972	    /*
3973	    * Skip duplicates.
3974	    */
3975	    for (j = 0; j < initNbSet1; j++) {
3976		n1 = set1->nodeTab[j];
3977		if (n1 == n2) {
3978		    goto skip_node;
3979		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3980		    (n2->type == XML_NAMESPACE_DECL))
3981		{
3982		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3983			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3984			((xmlNsPtr) n2)->prefix)))
3985		    {
3986			/*
3987			* Free the namespace node.
3988			*/
3989			set2->nodeTab[i] = NULL;
3990			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3991			goto skip_node;
3992		    }
3993		}
3994	    }
3995	    /*
3996	    * grow the nodeTab if needed
3997	    */
3998	    if (set1->nodeMax == 0) {
3999		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4000		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4001		if (set1->nodeTab == NULL) {
4002		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4003		    return(NULL);
4004		}
4005		memset(set1->nodeTab, 0,
4006		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4007		set1->nodeMax = XML_NODESET_DEFAULT;
4008	    } else if (set1->nodeNr >= set1->nodeMax) {
4009		xmlNodePtr *temp;
4010
4011                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4012                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4013                    return(NULL);
4014                }
4015		temp = (xmlNodePtr *) xmlRealloc(
4016		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4017		if (temp == NULL) {
4018		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4019		    return(NULL);
4020		}
4021		set1->nodeTab = temp;
4022		set1->nodeMax *= 2;
4023	    }
4024	    if (n2->type == XML_NAMESPACE_DECL) {
4025		xmlNsPtr ns = (xmlNsPtr) n2;
4026
4027		set1->nodeTab[set1->nodeNr++] =
4028		    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
4029	    } else
4030		set1->nodeTab[set1->nodeNr++] = n2;
4031skip_node:
4032	    {}
4033	}
4034    }
4035    set2->nodeNr = 0;
4036    return(set1);
4037}
4038
4039/**
4040 * xmlXPathNodeSetMergeAndClearNoDupls:
4041 * @set1:  the first NodeSet or NULL
4042 * @set2:  the second NodeSet
4043 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4044 *
4045 * Merges two nodesets, all nodes from @set2 are added to @set1
4046 * if @set1 is NULL, a new set is created and copied from @set2.
4047 * Doesn't chack for duplicate nodes. Clears set2.
4048 *
4049 * Returns @set1 once extended or NULL in case of error.
4050 */
4051static xmlNodeSetPtr
4052xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4053				    int hasNullEntries)
4054{
4055    if (set2 == NULL)
4056	return(set1);
4057    if ((set1 == NULL) && (hasNullEntries == 0)) {
4058	/*
4059	* Note that doing a memcpy of the list, namespace nodes are
4060	* just assigned to set1, since set2 is cleared anyway.
4061	*/
4062	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4063	if (set1 == NULL)
4064	    return(NULL);
4065	if (set2->nodeNr != 0) {
4066	    memcpy(set1->nodeTab, set2->nodeTab,
4067		set2->nodeNr * sizeof(xmlNodePtr));
4068	    set1->nodeNr = set2->nodeNr;
4069	}
4070    } else {
4071	int i;
4072	xmlNodePtr n2;
4073
4074	if (set1 == NULL)
4075	    set1 = xmlXPathNodeSetCreate(NULL);
4076        if (set1 == NULL)
4077            return (NULL);
4078
4079	for (i = 0;i < set2->nodeNr;i++) {
4080	    n2 = set2->nodeTab[i];
4081	    /*
4082	    * Skip NULLed entries.
4083	    */
4084	    if (n2 == NULL)
4085		continue;
4086	    if (set1->nodeMax == 0) {
4087		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4088		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4089		if (set1->nodeTab == NULL) {
4090		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4091		    return(NULL);
4092		}
4093		memset(set1->nodeTab, 0,
4094		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4095		set1->nodeMax = XML_NODESET_DEFAULT;
4096	    } else if (set1->nodeNr >= set1->nodeMax) {
4097		xmlNodePtr *temp;
4098
4099                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4100                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4101                    return(NULL);
4102                }
4103		temp = (xmlNodePtr *) xmlRealloc(
4104		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4105		if (temp == NULL) {
4106		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4107		    return(NULL);
4108		}
4109		set1->nodeTab = temp;
4110		set1->nodeMax *= 2;
4111	    }
4112	    set1->nodeTab[set1->nodeNr++] = n2;
4113	}
4114    }
4115    set2->nodeNr = 0;
4116    return(set1);
4117}
4118
4119/**
4120 * xmlXPathNodeSetDel:
4121 * @cur:  the initial node set
4122 * @val:  an xmlNodePtr
4123 *
4124 * Removes an xmlNodePtr from an existing NodeSet
4125 */
4126void
4127xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4128    int i;
4129
4130    if (cur == NULL) return;
4131    if (val == NULL) return;
4132
4133    /*
4134     * find node in nodeTab
4135     */
4136    for (i = 0;i < cur->nodeNr;i++)
4137        if (cur->nodeTab[i] == val) break;
4138
4139    if (i >= cur->nodeNr) {	/* not found */
4140#ifdef DEBUG
4141        xmlGenericError(xmlGenericErrorContext,
4142	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4143		val->name);
4144#endif
4145        return;
4146    }
4147    if ((cur->nodeTab[i] != NULL) &&
4148	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4149	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4150    cur->nodeNr--;
4151    for (;i < cur->nodeNr;i++)
4152        cur->nodeTab[i] = cur->nodeTab[i + 1];
4153    cur->nodeTab[cur->nodeNr] = NULL;
4154}
4155
4156/**
4157 * xmlXPathNodeSetRemove:
4158 * @cur:  the initial node set
4159 * @val:  the index to remove
4160 *
4161 * Removes an entry from an existing NodeSet list.
4162 */
4163void
4164xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4165    if (cur == NULL) return;
4166    if (val >= cur->nodeNr) return;
4167    if ((cur->nodeTab[val] != NULL) &&
4168	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4169	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4170    cur->nodeNr--;
4171    for (;val < cur->nodeNr;val++)
4172        cur->nodeTab[val] = cur->nodeTab[val + 1];
4173    cur->nodeTab[cur->nodeNr] = NULL;
4174}
4175
4176/**
4177 * xmlXPathFreeNodeSet:
4178 * @obj:  the xmlNodeSetPtr to free
4179 *
4180 * Free the NodeSet compound (not the actual nodes !).
4181 */
4182void
4183xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4184    if (obj == NULL) return;
4185    if (obj->nodeTab != NULL) {
4186	int i;
4187
4188	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
4189	for (i = 0;i < obj->nodeNr;i++)
4190	    if ((obj->nodeTab[i] != NULL) &&
4191		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4192		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4193	xmlFree(obj->nodeTab);
4194    }
4195    xmlFree(obj);
4196}
4197
4198/**
4199 * xmlXPathNodeSetClear:
4200 * @set:  the node set to clear
4201 *
4202 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4203 * are feed), but does *not* free the list itself. Sets the length of the
4204 * list to 0.
4205 */
4206static void
4207xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4208{
4209    if ((set == NULL) || (set->nodeNr <= 0))
4210	return;
4211    else if (hasNsNodes) {
4212	int i;
4213	xmlNodePtr node;
4214
4215	for (i = 0; i < set->nodeNr; i++) {
4216	    node = set->nodeTab[i];
4217	    if ((node != NULL) &&
4218		(node->type == XML_NAMESPACE_DECL))
4219		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4220	}
4221    }
4222    set->nodeNr = 0;
4223}
4224
4225/**
4226 * xmlXPathNodeSetClearFromPos:
4227 * @set: the node set to be cleared
4228 * @pos: the start position to clear from
4229 *
4230 * Clears the list from temporary XPath objects (e.g. namespace nodes
4231 * are feed) starting with the entry at @pos, but does *not* free the list
4232 * itself. Sets the length of the list to @pos.
4233 */
4234static void
4235xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4236{
4237    if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4238	return;
4239    else if ((hasNsNodes)) {
4240	int i;
4241	xmlNodePtr node;
4242
4243	for (i = pos; i < set->nodeNr; i++) {
4244	    node = set->nodeTab[i];
4245	    if ((node != NULL) &&
4246		(node->type == XML_NAMESPACE_DECL))
4247		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4248	}
4249    }
4250    set->nodeNr = pos;
4251}
4252
4253/**
4254 * xmlXPathFreeValueTree:
4255 * @obj:  the xmlNodeSetPtr to free
4256 *
4257 * Free the NodeSet compound and the actual tree, this is different
4258 * from xmlXPathFreeNodeSet()
4259 */
4260static void
4261xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4262    int i;
4263
4264    if (obj == NULL) return;
4265
4266    if (obj->nodeTab != NULL) {
4267	for (i = 0;i < obj->nodeNr;i++) {
4268	    if (obj->nodeTab[i] != NULL) {
4269		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4270		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4271		} else {
4272		    xmlFreeNodeList(obj->nodeTab[i]);
4273		}
4274	    }
4275	}
4276	xmlFree(obj->nodeTab);
4277    }
4278    xmlFree(obj);
4279}
4280
4281#if defined(DEBUG) || defined(DEBUG_STEP)
4282/**
4283 * xmlGenericErrorContextNodeSet:
4284 * @output:  a FILE * for the output
4285 * @obj:  the xmlNodeSetPtr to display
4286 *
4287 * Quick display of a NodeSet
4288 */
4289void
4290xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4291    int i;
4292
4293    if (output == NULL) output = xmlGenericErrorContext;
4294    if (obj == NULL)  {
4295        fprintf(output, "NodeSet == NULL !\n");
4296	return;
4297    }
4298    if (obj->nodeNr == 0) {
4299        fprintf(output, "NodeSet is empty\n");
4300	return;
4301    }
4302    if (obj->nodeTab == NULL) {
4303	fprintf(output, " nodeTab == NULL !\n");
4304	return;
4305    }
4306    for (i = 0; i < obj->nodeNr; i++) {
4307        if (obj->nodeTab[i] == NULL) {
4308	    fprintf(output, " NULL !\n");
4309	    return;
4310        }
4311	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4312	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4313	    fprintf(output, " /");
4314	else if (obj->nodeTab[i]->name == NULL)
4315	    fprintf(output, " noname!");
4316	else fprintf(output, " %s", obj->nodeTab[i]->name);
4317    }
4318    fprintf(output, "\n");
4319}
4320#endif
4321
4322/**
4323 * xmlXPathNewNodeSet:
4324 * @val:  the NodePtr value
4325 *
4326 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4327 * it with the single Node @val
4328 *
4329 * Returns the newly created object.
4330 */
4331xmlXPathObjectPtr
4332xmlXPathNewNodeSet(xmlNodePtr val) {
4333    xmlXPathObjectPtr ret;
4334
4335    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4336    if (ret == NULL) {
4337        xmlXPathErrMemory(NULL, "creating nodeset\n");
4338	return(NULL);
4339    }
4340    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4341    ret->type = XPATH_NODESET;
4342    ret->boolval = 0;
4343    ret->nodesetval = xmlXPathNodeSetCreate(val);
4344    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4345#ifdef XP_DEBUG_OBJ_USAGE
4346    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4347#endif
4348    return(ret);
4349}
4350
4351/**
4352 * xmlXPathNewValueTree:
4353 * @val:  the NodePtr value
4354 *
4355 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4356 * it with the tree root @val
4357 *
4358 * Returns the newly created object.
4359 */
4360xmlXPathObjectPtr
4361xmlXPathNewValueTree(xmlNodePtr val) {
4362    xmlXPathObjectPtr ret;
4363
4364    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4365    if (ret == NULL) {
4366        xmlXPathErrMemory(NULL, "creating result value tree\n");
4367	return(NULL);
4368    }
4369    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4370    ret->type = XPATH_XSLT_TREE;
4371    ret->boolval = 0;
4372    ret->user = (void *) val;
4373    ret->nodesetval = xmlXPathNodeSetCreate(val);
4374#ifdef XP_DEBUG_OBJ_USAGE
4375    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4376#endif
4377    return(ret);
4378}
4379
4380/**
4381 * xmlXPathNewNodeSetList:
4382 * @val:  an existing NodeSet
4383 *
4384 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4385 * it with the Nodeset @val
4386 *
4387 * Returns the newly created object.
4388 */
4389xmlXPathObjectPtr
4390xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4391{
4392    xmlXPathObjectPtr ret;
4393    int i;
4394
4395    if (val == NULL)
4396        ret = NULL;
4397    else if (val->nodeTab == NULL)
4398        ret = xmlXPathNewNodeSet(NULL);
4399    else {
4400        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4401        if (ret) {
4402            for (i = 1; i < val->nodeNr; ++i) {
4403                if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4404		    < 0) break;
4405	    }
4406	}
4407    }
4408
4409    return (ret);
4410}
4411
4412/**
4413 * xmlXPathWrapNodeSet:
4414 * @val:  the NodePtr value
4415 *
4416 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4417 *
4418 * Returns the newly created object.
4419 */
4420xmlXPathObjectPtr
4421xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4422    xmlXPathObjectPtr ret;
4423
4424    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4425    if (ret == NULL) {
4426        xmlXPathErrMemory(NULL, "creating node set object\n");
4427	return(NULL);
4428    }
4429    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4430    ret->type = XPATH_NODESET;
4431    ret->nodesetval = val;
4432#ifdef XP_DEBUG_OBJ_USAGE
4433    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4434#endif
4435    return(ret);
4436}
4437
4438/**
4439 * xmlXPathFreeNodeSetList:
4440 * @obj:  an existing NodeSetList object
4441 *
4442 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4443 * the list contrary to xmlXPathFreeObject().
4444 */
4445void
4446xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4447    if (obj == NULL) return;
4448#ifdef XP_DEBUG_OBJ_USAGE
4449    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4450#endif
4451    xmlFree(obj);
4452}
4453
4454/**
4455 * xmlXPathDifference:
4456 * @nodes1:  a node-set
4457 * @nodes2:  a node-set
4458 *
4459 * Implements the EXSLT - Sets difference() function:
4460 *    node-set set:difference (node-set, node-set)
4461 *
4462 * Returns the difference between the two node sets, or nodes1 if
4463 *         nodes2 is empty
4464 */
4465xmlNodeSetPtr
4466xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4467    xmlNodeSetPtr ret;
4468    int i, l1;
4469    xmlNodePtr cur;
4470
4471    if (xmlXPathNodeSetIsEmpty(nodes2))
4472	return(nodes1);
4473
4474    ret = xmlXPathNodeSetCreate(NULL);
4475    if (xmlXPathNodeSetIsEmpty(nodes1))
4476	return(ret);
4477
4478    l1 = xmlXPathNodeSetGetLength(nodes1);
4479
4480    for (i = 0; i < l1; i++) {
4481	cur = xmlXPathNodeSetItem(nodes1, i);
4482	if (!xmlXPathNodeSetContains(nodes2, cur)) {
4483	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4484	        break;
4485	}
4486    }
4487    return(ret);
4488}
4489
4490/**
4491 * xmlXPathIntersection:
4492 * @nodes1:  a node-set
4493 * @nodes2:  a node-set
4494 *
4495 * Implements the EXSLT - Sets intersection() function:
4496 *    node-set set:intersection (node-set, node-set)
4497 *
4498 * Returns a node set comprising the nodes that are within both the
4499 *         node sets passed as arguments
4500 */
4501xmlNodeSetPtr
4502xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4503    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4504    int i, l1;
4505    xmlNodePtr cur;
4506
4507    if (ret == NULL)
4508        return(ret);
4509    if (xmlXPathNodeSetIsEmpty(nodes1))
4510	return(ret);
4511    if (xmlXPathNodeSetIsEmpty(nodes2))
4512	return(ret);
4513
4514    l1 = xmlXPathNodeSetGetLength(nodes1);
4515
4516    for (i = 0; i < l1; i++) {
4517	cur = xmlXPathNodeSetItem(nodes1, i);
4518	if (xmlXPathNodeSetContains(nodes2, cur)) {
4519	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4520	        break;
4521	}
4522    }
4523    return(ret);
4524}
4525
4526/**
4527 * xmlXPathDistinctSorted:
4528 * @nodes:  a node-set, sorted by document order
4529 *
4530 * Implements the EXSLT - Sets distinct() function:
4531 *    node-set set:distinct (node-set)
4532 *
4533 * Returns a subset of the nodes contained in @nodes, or @nodes if
4534 *         it is empty
4535 */
4536xmlNodeSetPtr
4537xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4538    xmlNodeSetPtr ret;
4539    xmlHashTablePtr hash;
4540    int i, l;
4541    xmlChar * strval;
4542    xmlNodePtr cur;
4543
4544    if (xmlXPathNodeSetIsEmpty(nodes))
4545	return(nodes);
4546
4547    ret = xmlXPathNodeSetCreate(NULL);
4548    if (ret == NULL)
4549        return(ret);
4550    l = xmlXPathNodeSetGetLength(nodes);
4551    hash = xmlHashCreate (l);
4552    for (i = 0; i < l; i++) {
4553	cur = xmlXPathNodeSetItem(nodes, i);
4554	strval = xmlXPathCastNodeToString(cur);
4555	if (xmlHashLookup(hash, strval) == NULL) {
4556	    xmlHashAddEntry(hash, strval, strval);
4557	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4558	        break;
4559	} else {
4560	    xmlFree(strval);
4561	}
4562    }
4563    xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4564    return(ret);
4565}
4566
4567/**
4568 * xmlXPathDistinct:
4569 * @nodes:  a node-set
4570 *
4571 * Implements the EXSLT - Sets distinct() function:
4572 *    node-set set:distinct (node-set)
4573 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4574 * is called with the sorted node-set
4575 *
4576 * Returns a subset of the nodes contained in @nodes, or @nodes if
4577 *         it is empty
4578 */
4579xmlNodeSetPtr
4580xmlXPathDistinct (xmlNodeSetPtr nodes) {
4581    if (xmlXPathNodeSetIsEmpty(nodes))
4582	return(nodes);
4583
4584    xmlXPathNodeSetSort(nodes);
4585    return(xmlXPathDistinctSorted(nodes));
4586}
4587
4588/**
4589 * xmlXPathHasSameNodes:
4590 * @nodes1:  a node-set
4591 * @nodes2:  a node-set
4592 *
4593 * Implements the EXSLT - Sets has-same-nodes function:
4594 *    boolean set:has-same-node(node-set, node-set)
4595 *
4596 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4597 *         otherwise
4598 */
4599int
4600xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4601    int i, l;
4602    xmlNodePtr cur;
4603
4604    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4605	xmlXPathNodeSetIsEmpty(nodes2))
4606	return(0);
4607
4608    l = xmlXPathNodeSetGetLength(nodes1);
4609    for (i = 0; i < l; i++) {
4610	cur = xmlXPathNodeSetItem(nodes1, i);
4611	if (xmlXPathNodeSetContains(nodes2, cur))
4612	    return(1);
4613    }
4614    return(0);
4615}
4616
4617/**
4618 * xmlXPathNodeLeadingSorted:
4619 * @nodes: a node-set, sorted by document order
4620 * @node: a node
4621 *
4622 * Implements the EXSLT - Sets leading() function:
4623 *    node-set set:leading (node-set, node-set)
4624 *
4625 * Returns the nodes in @nodes that precede @node in document order,
4626 *         @nodes if @node is NULL or an empty node-set if @nodes
4627 *         doesn't contain @node
4628 */
4629xmlNodeSetPtr
4630xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4631    int i, l;
4632    xmlNodePtr cur;
4633    xmlNodeSetPtr ret;
4634
4635    if (node == NULL)
4636	return(nodes);
4637
4638    ret = xmlXPathNodeSetCreate(NULL);
4639    if (ret == NULL)
4640        return(ret);
4641    if (xmlXPathNodeSetIsEmpty(nodes) ||
4642	(!xmlXPathNodeSetContains(nodes, node)))
4643	return(ret);
4644
4645    l = xmlXPathNodeSetGetLength(nodes);
4646    for (i = 0; i < l; i++) {
4647	cur = xmlXPathNodeSetItem(nodes, i);
4648	if (cur == node)
4649	    break;
4650	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4651	    break;
4652    }
4653    return(ret);
4654}
4655
4656/**
4657 * xmlXPathNodeLeading:
4658 * @nodes:  a node-set
4659 * @node:  a node
4660 *
4661 * Implements the EXSLT - Sets leading() function:
4662 *    node-set set:leading (node-set, node-set)
4663 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4664 * is called.
4665 *
4666 * Returns the nodes in @nodes that precede @node in document order,
4667 *         @nodes if @node is NULL or an empty node-set if @nodes
4668 *         doesn't contain @node
4669 */
4670xmlNodeSetPtr
4671xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4672    xmlXPathNodeSetSort(nodes);
4673    return(xmlXPathNodeLeadingSorted(nodes, node));
4674}
4675
4676/**
4677 * xmlXPathLeadingSorted:
4678 * @nodes1:  a node-set, sorted by document order
4679 * @nodes2:  a node-set, sorted by document order
4680 *
4681 * Implements the EXSLT - Sets leading() function:
4682 *    node-set set:leading (node-set, node-set)
4683 *
4684 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4685 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4686 *         an empty node-set if @nodes1 doesn't contain @nodes2
4687 */
4688xmlNodeSetPtr
4689xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4690    if (xmlXPathNodeSetIsEmpty(nodes2))
4691	return(nodes1);
4692    return(xmlXPathNodeLeadingSorted(nodes1,
4693				     xmlXPathNodeSetItem(nodes2, 1)));
4694}
4695
4696/**
4697 * xmlXPathLeading:
4698 * @nodes1:  a node-set
4699 * @nodes2:  a node-set
4700 *
4701 * Implements the EXSLT - Sets leading() function:
4702 *    node-set set:leading (node-set, node-set)
4703 * @nodes1 and @nodes2 are sorted by document order, then
4704 * #exslSetsLeadingSorted is called.
4705 *
4706 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4707 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4708 *         an empty node-set if @nodes1 doesn't contain @nodes2
4709 */
4710xmlNodeSetPtr
4711xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4712    if (xmlXPathNodeSetIsEmpty(nodes2))
4713	return(nodes1);
4714    if (xmlXPathNodeSetIsEmpty(nodes1))
4715	return(xmlXPathNodeSetCreate(NULL));
4716    xmlXPathNodeSetSort(nodes1);
4717    xmlXPathNodeSetSort(nodes2);
4718    return(xmlXPathNodeLeadingSorted(nodes1,
4719				     xmlXPathNodeSetItem(nodes2, 1)));
4720}
4721
4722/**
4723 * xmlXPathNodeTrailingSorted:
4724 * @nodes: a node-set, sorted by document order
4725 * @node: a node
4726 *
4727 * Implements the EXSLT - Sets trailing() function:
4728 *    node-set set:trailing (node-set, node-set)
4729 *
4730 * Returns the nodes in @nodes that follow @node in document order,
4731 *         @nodes if @node is NULL or an empty node-set if @nodes
4732 *         doesn't contain @node
4733 */
4734xmlNodeSetPtr
4735xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4736    int i, l;
4737    xmlNodePtr cur;
4738    xmlNodeSetPtr ret;
4739
4740    if (node == NULL)
4741	return(nodes);
4742
4743    ret = xmlXPathNodeSetCreate(NULL);
4744    if (ret == NULL)
4745        return(ret);
4746    if (xmlXPathNodeSetIsEmpty(nodes) ||
4747	(!xmlXPathNodeSetContains(nodes, node)))
4748	return(ret);
4749
4750    l = xmlXPathNodeSetGetLength(nodes);
4751    for (i = l - 1; i >= 0; i--) {
4752	cur = xmlXPathNodeSetItem(nodes, i);
4753	if (cur == node)
4754	    break;
4755	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4756	    break;
4757    }
4758    xmlXPathNodeSetSort(ret);	/* bug 413451 */
4759    return(ret);
4760}
4761
4762/**
4763 * xmlXPathNodeTrailing:
4764 * @nodes:  a node-set
4765 * @node:  a node
4766 *
4767 * Implements the EXSLT - Sets trailing() function:
4768 *    node-set set:trailing (node-set, node-set)
4769 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4770 * is called.
4771 *
4772 * Returns the nodes in @nodes that follow @node in document order,
4773 *         @nodes if @node is NULL or an empty node-set if @nodes
4774 *         doesn't contain @node
4775 */
4776xmlNodeSetPtr
4777xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4778    xmlXPathNodeSetSort(nodes);
4779    return(xmlXPathNodeTrailingSorted(nodes, node));
4780}
4781
4782/**
4783 * xmlXPathTrailingSorted:
4784 * @nodes1:  a node-set, sorted by document order
4785 * @nodes2:  a node-set, sorted by document order
4786 *
4787 * Implements the EXSLT - Sets trailing() function:
4788 *    node-set set:trailing (node-set, node-set)
4789 *
4790 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4791 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4792 *         an empty node-set if @nodes1 doesn't contain @nodes2
4793 */
4794xmlNodeSetPtr
4795xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4796    if (xmlXPathNodeSetIsEmpty(nodes2))
4797	return(nodes1);
4798    return(xmlXPathNodeTrailingSorted(nodes1,
4799				      xmlXPathNodeSetItem(nodes2, 0)));
4800}
4801
4802/**
4803 * xmlXPathTrailing:
4804 * @nodes1:  a node-set
4805 * @nodes2:  a node-set
4806 *
4807 * Implements the EXSLT - Sets trailing() function:
4808 *    node-set set:trailing (node-set, node-set)
4809 * @nodes1 and @nodes2 are sorted by document order, then
4810 * #xmlXPathTrailingSorted is called.
4811 *
4812 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4813 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4814 *         an empty node-set if @nodes1 doesn't contain @nodes2
4815 */
4816xmlNodeSetPtr
4817xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4818    if (xmlXPathNodeSetIsEmpty(nodes2))
4819	return(nodes1);
4820    if (xmlXPathNodeSetIsEmpty(nodes1))
4821	return(xmlXPathNodeSetCreate(NULL));
4822    xmlXPathNodeSetSort(nodes1);
4823    xmlXPathNodeSetSort(nodes2);
4824    return(xmlXPathNodeTrailingSorted(nodes1,
4825				      xmlXPathNodeSetItem(nodes2, 0)));
4826}
4827
4828/************************************************************************
4829 *									*
4830 *		Routines to handle extra functions			*
4831 *									*
4832 ************************************************************************/
4833
4834/**
4835 * xmlXPathRegisterFunc:
4836 * @ctxt:  the XPath context
4837 * @name:  the function name
4838 * @f:  the function implementation or NULL
4839 *
4840 * Register a new function. If @f is NULL it unregisters the function
4841 *
4842 * Returns 0 in case of success, -1 in case of error
4843 */
4844int
4845xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4846		     xmlXPathFunction f) {
4847    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4848}
4849
4850/**
4851 * xmlXPathRegisterFuncNS:
4852 * @ctxt:  the XPath context
4853 * @name:  the function name
4854 * @ns_uri:  the function namespace URI
4855 * @f:  the function implementation or NULL
4856 *
4857 * Register a new function. If @f is NULL it unregisters the function
4858 *
4859 * Returns 0 in case of success, -1 in case of error
4860 */
4861int
4862xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4863		       const xmlChar *ns_uri, xmlXPathFunction f) {
4864    if (ctxt == NULL)
4865	return(-1);
4866    if (name == NULL)
4867	return(-1);
4868
4869    if (ctxt->funcHash == NULL)
4870	ctxt->funcHash = xmlHashCreate(0);
4871    if (ctxt->funcHash == NULL)
4872	return(-1);
4873    if (f == NULL)
4874        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4875    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4876}
4877
4878/**
4879 * xmlXPathRegisterFuncLookup:
4880 * @ctxt:  the XPath context
4881 * @f:  the lookup function
4882 * @funcCtxt:  the lookup data
4883 *
4884 * Registers an external mechanism to do function lookup.
4885 */
4886void
4887xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4888			    xmlXPathFuncLookupFunc f,
4889			    void *funcCtxt) {
4890    if (ctxt == NULL)
4891	return;
4892    ctxt->funcLookupFunc = f;
4893    ctxt->funcLookupData = funcCtxt;
4894}
4895
4896/**
4897 * xmlXPathFunctionLookup:
4898 * @ctxt:  the XPath context
4899 * @name:  the function name
4900 *
4901 * Search in the Function array of the context for the given
4902 * function.
4903 *
4904 * Returns the xmlXPathFunction or NULL if not found
4905 */
4906xmlXPathFunction
4907xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4908    if (ctxt == NULL)
4909	return (NULL);
4910
4911    if (ctxt->funcLookupFunc != NULL) {
4912	xmlXPathFunction ret;
4913	xmlXPathFuncLookupFunc f;
4914
4915	f = ctxt->funcLookupFunc;
4916	ret = f(ctxt->funcLookupData, name, NULL);
4917	if (ret != NULL)
4918	    return(ret);
4919    }
4920    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4921}
4922
4923/**
4924 * xmlXPathFunctionLookupNS:
4925 * @ctxt:  the XPath context
4926 * @name:  the function name
4927 * @ns_uri:  the function namespace URI
4928 *
4929 * Search in the Function array of the context for the given
4930 * function.
4931 *
4932 * Returns the xmlXPathFunction or NULL if not found
4933 */
4934xmlXPathFunction
4935xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4936			 const xmlChar *ns_uri) {
4937    xmlXPathFunction ret;
4938
4939    if (ctxt == NULL)
4940	return(NULL);
4941    if (name == NULL)
4942	return(NULL);
4943
4944    if (ctxt->funcLookupFunc != NULL) {
4945	xmlXPathFuncLookupFunc f;
4946
4947	f = ctxt->funcLookupFunc;
4948	ret = f(ctxt->funcLookupData, name, ns_uri);
4949	if (ret != NULL)
4950	    return(ret);
4951    }
4952
4953    if (ctxt->funcHash == NULL)
4954	return(NULL);
4955
4956    XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4957    return(ret);
4958}
4959
4960/**
4961 * xmlXPathRegisteredFuncsCleanup:
4962 * @ctxt:  the XPath context
4963 *
4964 * Cleanup the XPath context data associated to registered functions
4965 */
4966void
4967xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4968    if (ctxt == NULL)
4969	return;
4970
4971    xmlHashFree(ctxt->funcHash, NULL);
4972    ctxt->funcHash = NULL;
4973}
4974
4975/************************************************************************
4976 *									*
4977 *			Routines to handle Variables			*
4978 *									*
4979 ************************************************************************/
4980
4981/**
4982 * xmlXPathRegisterVariable:
4983 * @ctxt:  the XPath context
4984 * @name:  the variable name
4985 * @value:  the variable value or NULL
4986 *
4987 * Register a new variable value. If @value is NULL it unregisters
4988 * the variable
4989 *
4990 * Returns 0 in case of success, -1 in case of error
4991 */
4992int
4993xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4994			 xmlXPathObjectPtr value) {
4995    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4996}
4997
4998/**
4999 * xmlXPathRegisterVariableNS:
5000 * @ctxt:  the XPath context
5001 * @name:  the variable name
5002 * @ns_uri:  the variable namespace URI
5003 * @value:  the variable value or NULL
5004 *
5005 * Register a new variable value. If @value is NULL it unregisters
5006 * the variable
5007 *
5008 * Returns 0 in case of success, -1 in case of error
5009 */
5010int
5011xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5012			   const xmlChar *ns_uri,
5013			   xmlXPathObjectPtr value) {
5014    if (ctxt == NULL)
5015	return(-1);
5016    if (name == NULL)
5017	return(-1);
5018
5019    if (ctxt->varHash == NULL)
5020	ctxt->varHash = xmlHashCreate(0);
5021    if (ctxt->varHash == NULL)
5022	return(-1);
5023    if (value == NULL)
5024        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5025	                           (xmlHashDeallocator)xmlXPathFreeObject));
5026    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5027			       (void *) value,
5028			       (xmlHashDeallocator)xmlXPathFreeObject));
5029}
5030
5031/**
5032 * xmlXPathRegisterVariableLookup:
5033 * @ctxt:  the XPath context
5034 * @f:  the lookup function
5035 * @data:  the lookup data
5036 *
5037 * register an external mechanism to do variable lookup
5038 */
5039void
5040xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5041	 xmlXPathVariableLookupFunc f, void *data) {
5042    if (ctxt == NULL)
5043	return;
5044    ctxt->varLookupFunc = f;
5045    ctxt->varLookupData = data;
5046}
5047
5048/**
5049 * xmlXPathVariableLookup:
5050 * @ctxt:  the XPath context
5051 * @name:  the variable name
5052 *
5053 * Search in the Variable array of the context for the given
5054 * variable value.
5055 *
5056 * Returns a copy of the value or NULL if not found
5057 */
5058xmlXPathObjectPtr
5059xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5060    if (ctxt == NULL)
5061	return(NULL);
5062
5063    if (ctxt->varLookupFunc != NULL) {
5064	xmlXPathObjectPtr ret;
5065
5066	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5067	        (ctxt->varLookupData, name, NULL);
5068	return(ret);
5069    }
5070    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5071}
5072
5073/**
5074 * xmlXPathVariableLookupNS:
5075 * @ctxt:  the XPath context
5076 * @name:  the variable name
5077 * @ns_uri:  the variable namespace URI
5078 *
5079 * Search in the Variable array of the context for the given
5080 * variable value.
5081 *
5082 * Returns the a copy of the value or NULL if not found
5083 */
5084xmlXPathObjectPtr
5085xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5086			 const xmlChar *ns_uri) {
5087    if (ctxt == NULL)
5088	return(NULL);
5089
5090    if (ctxt->varLookupFunc != NULL) {
5091	xmlXPathObjectPtr ret;
5092
5093	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5094	        (ctxt->varLookupData, name, ns_uri);
5095	if (ret != NULL) return(ret);
5096    }
5097
5098    if (ctxt->varHash == NULL)
5099	return(NULL);
5100    if (name == NULL)
5101	return(NULL);
5102
5103    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5104		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5105}
5106
5107/**
5108 * xmlXPathRegisteredVariablesCleanup:
5109 * @ctxt:  the XPath context
5110 *
5111 * Cleanup the XPath context data associated to registered variables
5112 */
5113void
5114xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5115    if (ctxt == NULL)
5116	return;
5117
5118    xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5119    ctxt->varHash = NULL;
5120}
5121
5122/**
5123 * xmlXPathRegisterNs:
5124 * @ctxt:  the XPath context
5125 * @prefix:  the namespace prefix cannot be NULL or empty string
5126 * @ns_uri:  the namespace name
5127 *
5128 * Register a new namespace. If @ns_uri is NULL it unregisters
5129 * the namespace
5130 *
5131 * Returns 0 in case of success, -1 in case of error
5132 */
5133int
5134xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5135			   const xmlChar *ns_uri) {
5136    if (ctxt == NULL)
5137	return(-1);
5138    if (prefix == NULL)
5139	return(-1);
5140    if (prefix[0] == 0)
5141	return(-1);
5142
5143    if (ctxt->nsHash == NULL)
5144	ctxt->nsHash = xmlHashCreate(10);
5145    if (ctxt->nsHash == NULL)
5146	return(-1);
5147    if (ns_uri == NULL)
5148        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5149	                          (xmlHashDeallocator)xmlFree));
5150    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5151			      (xmlHashDeallocator)xmlFree));
5152}
5153
5154/**
5155 * xmlXPathNsLookup:
5156 * @ctxt:  the XPath context
5157 * @prefix:  the namespace prefix value
5158 *
5159 * Search in the namespace declaration array of the context for the given
5160 * namespace name associated to the given prefix
5161 *
5162 * Returns the value or NULL if not found
5163 */
5164const xmlChar *
5165xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5166    if (ctxt == NULL)
5167	return(NULL);
5168    if (prefix == NULL)
5169	return(NULL);
5170
5171#ifdef XML_XML_NAMESPACE
5172    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5173	return(XML_XML_NAMESPACE);
5174#endif
5175
5176    if (ctxt->namespaces != NULL) {
5177	int i;
5178
5179	for (i = 0;i < ctxt->nsNr;i++) {
5180	    if ((ctxt->namespaces[i] != NULL) &&
5181		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5182		return(ctxt->namespaces[i]->href);
5183	}
5184    }
5185
5186    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5187}
5188
5189/**
5190 * xmlXPathRegisteredNsCleanup:
5191 * @ctxt:  the XPath context
5192 *
5193 * Cleanup the XPath context data associated to registered variables
5194 */
5195void
5196xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5197    if (ctxt == NULL)
5198	return;
5199
5200    xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5201    ctxt->nsHash = NULL;
5202}
5203
5204/************************************************************************
5205 *									*
5206 *			Routines to handle Values			*
5207 *									*
5208 ************************************************************************/
5209
5210/* Allocations are terrible, one needs to optimize all this !!! */
5211
5212/**
5213 * xmlXPathNewFloat:
5214 * @val:  the double value
5215 *
5216 * Create a new xmlXPathObjectPtr of type double and of value @val
5217 *
5218 * Returns the newly created object.
5219 */
5220xmlXPathObjectPtr
5221xmlXPathNewFloat(double val) {
5222    xmlXPathObjectPtr ret;
5223
5224    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5225    if (ret == NULL) {
5226        xmlXPathErrMemory(NULL, "creating float object\n");
5227	return(NULL);
5228    }
5229    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5230    ret->type = XPATH_NUMBER;
5231    ret->floatval = val;
5232#ifdef XP_DEBUG_OBJ_USAGE
5233    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5234#endif
5235    return(ret);
5236}
5237
5238/**
5239 * xmlXPathNewBoolean:
5240 * @val:  the boolean value
5241 *
5242 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5243 *
5244 * Returns the newly created object.
5245 */
5246xmlXPathObjectPtr
5247xmlXPathNewBoolean(int val) {
5248    xmlXPathObjectPtr ret;
5249
5250    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5251    if (ret == NULL) {
5252        xmlXPathErrMemory(NULL, "creating boolean object\n");
5253	return(NULL);
5254    }
5255    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5256    ret->type = XPATH_BOOLEAN;
5257    ret->boolval = (val != 0);
5258#ifdef XP_DEBUG_OBJ_USAGE
5259    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5260#endif
5261    return(ret);
5262}
5263
5264/**
5265 * xmlXPathNewString:
5266 * @val:  the xmlChar * value
5267 *
5268 * Create a new xmlXPathObjectPtr of type string and of value @val
5269 *
5270 * Returns the newly created object.
5271 */
5272xmlXPathObjectPtr
5273xmlXPathNewString(const xmlChar *val) {
5274    xmlXPathObjectPtr ret;
5275
5276    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5277    if (ret == NULL) {
5278        xmlXPathErrMemory(NULL, "creating string object\n");
5279	return(NULL);
5280    }
5281    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5282    ret->type = XPATH_STRING;
5283    if (val != NULL)
5284	ret->stringval = xmlStrdup(val);
5285    else
5286	ret->stringval = xmlStrdup((const xmlChar *)"");
5287#ifdef XP_DEBUG_OBJ_USAGE
5288    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5289#endif
5290    return(ret);
5291}
5292
5293/**
5294 * xmlXPathWrapString:
5295 * @val:  the xmlChar * value
5296 *
5297 * Wraps the @val string into an XPath object.
5298 *
5299 * Returns the newly created object.
5300 */
5301xmlXPathObjectPtr
5302xmlXPathWrapString (xmlChar *val) {
5303    xmlXPathObjectPtr ret;
5304
5305    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5306    if (ret == NULL) {
5307        xmlXPathErrMemory(NULL, "creating string object\n");
5308	return(NULL);
5309    }
5310    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5311    ret->type = XPATH_STRING;
5312    ret->stringval = val;
5313#ifdef XP_DEBUG_OBJ_USAGE
5314    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5315#endif
5316    return(ret);
5317}
5318
5319/**
5320 * xmlXPathNewCString:
5321 * @val:  the char * value
5322 *
5323 * Create a new xmlXPathObjectPtr of type string and of value @val
5324 *
5325 * Returns the newly created object.
5326 */
5327xmlXPathObjectPtr
5328xmlXPathNewCString(const char *val) {
5329    xmlXPathObjectPtr ret;
5330
5331    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5332    if (ret == NULL) {
5333        xmlXPathErrMemory(NULL, "creating string object\n");
5334	return(NULL);
5335    }
5336    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5337    ret->type = XPATH_STRING;
5338    ret->stringval = xmlStrdup(BAD_CAST val);
5339#ifdef XP_DEBUG_OBJ_USAGE
5340    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5341#endif
5342    return(ret);
5343}
5344
5345/**
5346 * xmlXPathWrapCString:
5347 * @val:  the char * value
5348 *
5349 * Wraps a string into an XPath object.
5350 *
5351 * Returns the newly created object.
5352 */
5353xmlXPathObjectPtr
5354xmlXPathWrapCString (char * val) {
5355    return(xmlXPathWrapString((xmlChar *)(val)));
5356}
5357
5358/**
5359 * xmlXPathWrapExternal:
5360 * @val:  the user data
5361 *
5362 * Wraps the @val data into an XPath object.
5363 *
5364 * Returns the newly created object.
5365 */
5366xmlXPathObjectPtr
5367xmlXPathWrapExternal (void *val) {
5368    xmlXPathObjectPtr ret;
5369
5370    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5371    if (ret == NULL) {
5372        xmlXPathErrMemory(NULL, "creating user object\n");
5373	return(NULL);
5374    }
5375    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5376    ret->type = XPATH_USERS;
5377    ret->user = val;
5378#ifdef XP_DEBUG_OBJ_USAGE
5379    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5380#endif
5381    return(ret);
5382}
5383
5384/**
5385 * xmlXPathObjectCopy:
5386 * @val:  the original object
5387 *
5388 * allocate a new copy of a given object
5389 *
5390 * Returns the newly created object.
5391 */
5392xmlXPathObjectPtr
5393xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5394    xmlXPathObjectPtr ret;
5395
5396    if (val == NULL)
5397	return(NULL);
5398
5399    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5400    if (ret == NULL) {
5401        xmlXPathErrMemory(NULL, "copying object\n");
5402	return(NULL);
5403    }
5404    memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5405#ifdef XP_DEBUG_OBJ_USAGE
5406    xmlXPathDebugObjUsageRequested(NULL, val->type);
5407#endif
5408    switch (val->type) {
5409	case XPATH_BOOLEAN:
5410	case XPATH_NUMBER:
5411	case XPATH_POINT:
5412	case XPATH_RANGE:
5413	    break;
5414	case XPATH_STRING:
5415	    ret->stringval = xmlStrdup(val->stringval);
5416	    break;
5417	case XPATH_XSLT_TREE:
5418#if 0
5419/*
5420  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5421  this previous handling is no longer correct, and can cause some serious
5422  problems (ref. bug 145547)
5423*/
5424	    if ((val->nodesetval != NULL) &&
5425		(val->nodesetval->nodeTab != NULL)) {
5426		xmlNodePtr cur, tmp;
5427		xmlDocPtr top;
5428
5429		ret->boolval = 1;
5430		top =  xmlNewDoc(NULL);
5431		top->name = (char *)
5432		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5433		ret->user = top;
5434		if (top != NULL) {
5435		    top->doc = top;
5436		    cur = val->nodesetval->nodeTab[0]->children;
5437		    while (cur != NULL) {
5438			tmp = xmlDocCopyNode(cur, top, 1);
5439			xmlAddChild((xmlNodePtr) top, tmp);
5440			cur = cur->next;
5441		    }
5442		}
5443
5444		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5445	    } else
5446		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5447	    /* Deallocate the copied tree value */
5448	    break;
5449#endif
5450	case XPATH_NODESET:
5451	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5452	    /* Do not deallocate the copied tree value */
5453	    ret->boolval = 0;
5454	    break;
5455	case XPATH_LOCATIONSET:
5456#ifdef LIBXML_XPTR_ENABLED
5457	{
5458	    xmlLocationSetPtr loc = val->user;
5459	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5460	    break;
5461	}
5462#endif
5463        case XPATH_USERS:
5464	    ret->user = val->user;
5465	    break;
5466        case XPATH_UNDEFINED:
5467	    xmlGenericError(xmlGenericErrorContext,
5468		    "xmlXPathObjectCopy: unsupported type %d\n",
5469		    val->type);
5470	    break;
5471    }
5472    return(ret);
5473}
5474
5475/**
5476 * xmlXPathFreeObject:
5477 * @obj:  the object to free
5478 *
5479 * Free up an xmlXPathObjectPtr object.
5480 */
5481void
5482xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5483    if (obj == NULL) return;
5484    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5485	if (obj->boolval) {
5486#if 0
5487	    if (obj->user != NULL) {
5488                xmlXPathFreeNodeSet(obj->nodesetval);
5489		xmlFreeNodeList((xmlNodePtr) obj->user);
5490	    } else
5491#endif
5492	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5493	    if (obj->nodesetval != NULL)
5494		xmlXPathFreeValueTree(obj->nodesetval);
5495	} else {
5496	    if (obj->nodesetval != NULL)
5497		xmlXPathFreeNodeSet(obj->nodesetval);
5498	}
5499#ifdef LIBXML_XPTR_ENABLED
5500    } else if (obj->type == XPATH_LOCATIONSET) {
5501	if (obj->user != NULL)
5502	    xmlXPtrFreeLocationSet(obj->user);
5503#endif
5504    } else if (obj->type == XPATH_STRING) {
5505	if (obj->stringval != NULL)
5506	    xmlFree(obj->stringval);
5507    }
5508#ifdef XP_DEBUG_OBJ_USAGE
5509    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5510#endif
5511    xmlFree(obj);
5512}
5513
5514/**
5515 * xmlXPathReleaseObject:
5516 * @obj:  the xmlXPathObjectPtr to free or to cache
5517 *
5518 * Depending on the state of the cache this frees the given
5519 * XPath object or stores it in the cache.
5520 */
5521static void
5522xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5523{
5524#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5525	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5526    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5527
5528#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5529
5530    if (obj == NULL)
5531	return;
5532    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5533	 xmlXPathFreeObject(obj);
5534    } else {
5535	xmlXPathContextCachePtr cache =
5536	    (xmlXPathContextCachePtr) ctxt->cache;
5537
5538	switch (obj->type) {
5539	    case XPATH_NODESET:
5540	    case XPATH_XSLT_TREE:
5541		if (obj->nodesetval != NULL) {
5542		    if (obj->boolval) {
5543			/*
5544			* It looks like the @boolval is used for
5545			* evaluation if this an XSLT Result Tree Fragment.
5546			* TODO: Check if this assumption is correct.
5547			*/
5548			obj->type = XPATH_XSLT_TREE; /* just for debugging */
5549			xmlXPathFreeValueTree(obj->nodesetval);
5550			obj->nodesetval = NULL;
5551		    } else if ((obj->nodesetval->nodeMax <= 40) &&
5552			(XP_CACHE_WANTS(cache->nodesetObjs,
5553					cache->maxNodeset)))
5554		    {
5555			XP_CACHE_ADD(cache->nodesetObjs, obj);
5556			goto obj_cached;
5557		    } else {
5558			xmlXPathFreeNodeSet(obj->nodesetval);
5559			obj->nodesetval = NULL;
5560		    }
5561		}
5562		break;
5563	    case XPATH_STRING:
5564		if (obj->stringval != NULL)
5565		    xmlFree(obj->stringval);
5566
5567		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5568		    XP_CACHE_ADD(cache->stringObjs, obj);
5569		    goto obj_cached;
5570		}
5571		break;
5572	    case XPATH_BOOLEAN:
5573		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5574		    XP_CACHE_ADD(cache->booleanObjs, obj);
5575		    goto obj_cached;
5576		}
5577		break;
5578	    case XPATH_NUMBER:
5579		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5580		    XP_CACHE_ADD(cache->numberObjs, obj);
5581		    goto obj_cached;
5582		}
5583		break;
5584#ifdef LIBXML_XPTR_ENABLED
5585	    case XPATH_LOCATIONSET:
5586		if (obj->user != NULL) {
5587		    xmlXPtrFreeLocationSet(obj->user);
5588		}
5589		goto free_obj;
5590#endif
5591	    default:
5592		goto free_obj;
5593	}
5594
5595	/*
5596	* Fallback to adding to the misc-objects slot.
5597	*/
5598	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5599	    XP_CACHE_ADD(cache->miscObjs, obj);
5600	} else
5601	    goto free_obj;
5602
5603obj_cached:
5604
5605#ifdef XP_DEBUG_OBJ_USAGE
5606	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5607#endif
5608
5609	if (obj->nodesetval != NULL) {
5610	    xmlNodeSetPtr tmpset = obj->nodesetval;
5611
5612	    /*
5613	    * TODO: Due to those nasty ns-nodes, we need to traverse
5614	    *  the list and free the ns-nodes.
5615	    * URGENT TODO: Check if it's actually slowing things down.
5616	    *  Maybe we shouldn't try to preserve the list.
5617	    */
5618	    if (tmpset->nodeNr > 1) {
5619		int i;
5620		xmlNodePtr node;
5621
5622		for (i = 0; i < tmpset->nodeNr; i++) {
5623		    node = tmpset->nodeTab[i];
5624		    if ((node != NULL) &&
5625			(node->type == XML_NAMESPACE_DECL))
5626		    {
5627			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5628		    }
5629		}
5630	    } else if (tmpset->nodeNr == 1) {
5631		if ((tmpset->nodeTab[0] != NULL) &&
5632		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5633		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5634	    }
5635	    tmpset->nodeNr = 0;
5636	    memset(obj, 0, sizeof(xmlXPathObject));
5637	    obj->nodesetval = tmpset;
5638	} else
5639	    memset(obj, 0, sizeof(xmlXPathObject));
5640
5641	return;
5642
5643free_obj:
5644	/*
5645	* Cache is full; free the object.
5646	*/
5647	if (obj->nodesetval != NULL)
5648	    xmlXPathFreeNodeSet(obj->nodesetval);
5649#ifdef XP_DEBUG_OBJ_USAGE
5650	xmlXPathDebugObjUsageReleased(NULL, obj->type);
5651#endif
5652	xmlFree(obj);
5653    }
5654    return;
5655}
5656
5657
5658/************************************************************************
5659 *									*
5660 *			Type Casting Routines				*
5661 *									*
5662 ************************************************************************/
5663
5664/**
5665 * xmlXPathCastBooleanToString:
5666 * @val:  a boolean
5667 *
5668 * Converts a boolean to its string value.
5669 *
5670 * Returns a newly allocated string.
5671 */
5672xmlChar *
5673xmlXPathCastBooleanToString (int val) {
5674    xmlChar *ret;
5675    if (val)
5676	ret = xmlStrdup((const xmlChar *) "true");
5677    else
5678	ret = xmlStrdup((const xmlChar *) "false");
5679    return(ret);
5680}
5681
5682/**
5683 * xmlXPathCastNumberToString:
5684 * @val:  a number
5685 *
5686 * Converts a number to its string value.
5687 *
5688 * Returns a newly allocated string.
5689 */
5690xmlChar *
5691xmlXPathCastNumberToString (double val) {
5692    xmlChar *ret;
5693    switch (xmlXPathIsInf(val)) {
5694    case 1:
5695	ret = xmlStrdup((const xmlChar *) "Infinity");
5696	break;
5697    case -1:
5698	ret = xmlStrdup((const xmlChar *) "-Infinity");
5699	break;
5700    default:
5701	if (xmlXPathIsNaN(val)) {
5702	    ret = xmlStrdup((const xmlChar *) "NaN");
5703	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
5704	    ret = xmlStrdup((const xmlChar *) "0");
5705	} else {
5706	    /* could be improved */
5707	    char buf[100];
5708	    xmlXPathFormatNumber(val, buf, 99);
5709	    buf[99] = 0;
5710	    ret = xmlStrdup((const xmlChar *) buf);
5711	}
5712    }
5713    return(ret);
5714}
5715
5716/**
5717 * xmlXPathCastNodeToString:
5718 * @node:  a node
5719 *
5720 * Converts a node to its string value.
5721 *
5722 * Returns a newly allocated string.
5723 */
5724xmlChar *
5725xmlXPathCastNodeToString (xmlNodePtr node) {
5726xmlChar *ret;
5727    if ((ret = xmlNodeGetContent(node)) == NULL)
5728	ret = xmlStrdup((const xmlChar *) "");
5729    return(ret);
5730}
5731
5732/**
5733 * xmlXPathCastNodeSetToString:
5734 * @ns:  a node-set
5735 *
5736 * Converts a node-set to its string value.
5737 *
5738 * Returns a newly allocated string.
5739 */
5740xmlChar *
5741xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5742    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5743	return(xmlStrdup((const xmlChar *) ""));
5744
5745    if (ns->nodeNr > 1)
5746	xmlXPathNodeSetSort(ns);
5747    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5748}
5749
5750/**
5751 * xmlXPathCastToString:
5752 * @val:  an XPath object
5753 *
5754 * Converts an existing object to its string() equivalent
5755 *
5756 * Returns the allocated string value of the object, NULL in case of error.
5757 *         It's up to the caller to free the string memory with xmlFree().
5758 */
5759xmlChar *
5760xmlXPathCastToString(xmlXPathObjectPtr val) {
5761    xmlChar *ret = NULL;
5762
5763    if (val == NULL)
5764	return(xmlStrdup((const xmlChar *) ""));
5765    switch (val->type) {
5766	case XPATH_UNDEFINED:
5767#ifdef DEBUG_EXPR
5768	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5769#endif
5770	    ret = xmlStrdup((const xmlChar *) "");
5771	    break;
5772        case XPATH_NODESET:
5773        case XPATH_XSLT_TREE:
5774	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5775	    break;
5776	case XPATH_STRING:
5777	    return(xmlStrdup(val->stringval));
5778        case XPATH_BOOLEAN:
5779	    ret = xmlXPathCastBooleanToString(val->boolval);
5780	    break;
5781	case XPATH_NUMBER: {
5782	    ret = xmlXPathCastNumberToString(val->floatval);
5783	    break;
5784	}
5785	case XPATH_USERS:
5786	case XPATH_POINT:
5787	case XPATH_RANGE:
5788	case XPATH_LOCATIONSET:
5789	    TODO
5790	    ret = xmlStrdup((const xmlChar *) "");
5791	    break;
5792    }
5793    return(ret);
5794}
5795
5796/**
5797 * xmlXPathConvertString:
5798 * @val:  an XPath object
5799 *
5800 * Converts an existing object to its string() equivalent
5801 *
5802 * Returns the new object, the old one is freed (or the operation
5803 *         is done directly on @val)
5804 */
5805xmlXPathObjectPtr
5806xmlXPathConvertString(xmlXPathObjectPtr val) {
5807    xmlChar *res = NULL;
5808
5809    if (val == NULL)
5810	return(xmlXPathNewCString(""));
5811
5812    switch (val->type) {
5813    case XPATH_UNDEFINED:
5814#ifdef DEBUG_EXPR
5815	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5816#endif
5817	break;
5818    case XPATH_NODESET:
5819    case XPATH_XSLT_TREE:
5820	res = xmlXPathCastNodeSetToString(val->nodesetval);
5821	break;
5822    case XPATH_STRING:
5823	return(val);
5824    case XPATH_BOOLEAN:
5825	res = xmlXPathCastBooleanToString(val->boolval);
5826	break;
5827    case XPATH_NUMBER:
5828	res = xmlXPathCastNumberToString(val->floatval);
5829	break;
5830    case XPATH_USERS:
5831    case XPATH_POINT:
5832    case XPATH_RANGE:
5833    case XPATH_LOCATIONSET:
5834	TODO;
5835	break;
5836    }
5837    xmlXPathFreeObject(val);
5838    if (res == NULL)
5839	return(xmlXPathNewCString(""));
5840    return(xmlXPathWrapString(res));
5841}
5842
5843/**
5844 * xmlXPathCastBooleanToNumber:
5845 * @val:  a boolean
5846 *
5847 * Converts a boolean to its number value
5848 *
5849 * Returns the number value
5850 */
5851double
5852xmlXPathCastBooleanToNumber(int val) {
5853    if (val)
5854	return(1.0);
5855    return(0.0);
5856}
5857
5858/**
5859 * xmlXPathCastStringToNumber:
5860 * @val:  a string
5861 *
5862 * Converts a string to its number value
5863 *
5864 * Returns the number value
5865 */
5866double
5867xmlXPathCastStringToNumber(const xmlChar * val) {
5868    return(xmlXPathStringEvalNumber(val));
5869}
5870
5871/**
5872 * xmlXPathCastNodeToNumber:
5873 * @node:  a node
5874 *
5875 * Converts a node to its number value
5876 *
5877 * Returns the number value
5878 */
5879double
5880xmlXPathCastNodeToNumber (xmlNodePtr node) {
5881    xmlChar *strval;
5882    double ret;
5883
5884    if (node == NULL)
5885	return(xmlXPathNAN);
5886    strval = xmlXPathCastNodeToString(node);
5887    if (strval == NULL)
5888	return(xmlXPathNAN);
5889    ret = xmlXPathCastStringToNumber(strval);
5890    xmlFree(strval);
5891
5892    return(ret);
5893}
5894
5895/**
5896 * xmlXPathCastNodeSetToNumber:
5897 * @ns:  a node-set
5898 *
5899 * Converts a node-set to its number value
5900 *
5901 * Returns the number value
5902 */
5903double
5904xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5905    xmlChar *str;
5906    double ret;
5907
5908    if (ns == NULL)
5909	return(xmlXPathNAN);
5910    str = xmlXPathCastNodeSetToString(ns);
5911    ret = xmlXPathCastStringToNumber(str);
5912    xmlFree(str);
5913    return(ret);
5914}
5915
5916/**
5917 * xmlXPathCastToNumber:
5918 * @val:  an XPath object
5919 *
5920 * Converts an XPath object to its number value
5921 *
5922 * Returns the number value
5923 */
5924double
5925xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5926    double ret = 0.0;
5927
5928    if (val == NULL)
5929	return(xmlXPathNAN);
5930    switch (val->type) {
5931    case XPATH_UNDEFINED:
5932#ifdef DEGUB_EXPR
5933	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5934#endif
5935	ret = xmlXPathNAN;
5936	break;
5937    case XPATH_NODESET:
5938    case XPATH_XSLT_TREE:
5939	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5940	break;
5941    case XPATH_STRING:
5942	ret = xmlXPathCastStringToNumber(val->stringval);
5943	break;
5944    case XPATH_NUMBER:
5945	ret = val->floatval;
5946	break;
5947    case XPATH_BOOLEAN:
5948	ret = xmlXPathCastBooleanToNumber(val->boolval);
5949	break;
5950    case XPATH_USERS:
5951    case XPATH_POINT:
5952    case XPATH_RANGE:
5953    case XPATH_LOCATIONSET:
5954	TODO;
5955	ret = xmlXPathNAN;
5956	break;
5957    }
5958    return(ret);
5959}
5960
5961/**
5962 * xmlXPathConvertNumber:
5963 * @val:  an XPath object
5964 *
5965 * Converts an existing object to its number() equivalent
5966 *
5967 * Returns the new object, the old one is freed (or the operation
5968 *         is done directly on @val)
5969 */
5970xmlXPathObjectPtr
5971xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5972    xmlXPathObjectPtr ret;
5973
5974    if (val == NULL)
5975	return(xmlXPathNewFloat(0.0));
5976    if (val->type == XPATH_NUMBER)
5977	return(val);
5978    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5979    xmlXPathFreeObject(val);
5980    return(ret);
5981}
5982
5983/**
5984 * xmlXPathCastNumberToBoolean:
5985 * @val:  a number
5986 *
5987 * Converts a number to its boolean value
5988 *
5989 * Returns the boolean value
5990 */
5991int
5992xmlXPathCastNumberToBoolean (double val) {
5993     if (xmlXPathIsNaN(val) || (val == 0.0))
5994	 return(0);
5995     return(1);
5996}
5997
5998/**
5999 * xmlXPathCastStringToBoolean:
6000 * @val:  a string
6001 *
6002 * Converts a string to its boolean value
6003 *
6004 * Returns the boolean value
6005 */
6006int
6007xmlXPathCastStringToBoolean (const xmlChar *val) {
6008    if ((val == NULL) || (xmlStrlen(val) == 0))
6009	return(0);
6010    return(1);
6011}
6012
6013/**
6014 * xmlXPathCastNodeSetToBoolean:
6015 * @ns:  a node-set
6016 *
6017 * Converts a node-set to its boolean value
6018 *
6019 * Returns the boolean value
6020 */
6021int
6022xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6023    if ((ns == NULL) || (ns->nodeNr == 0))
6024	return(0);
6025    return(1);
6026}
6027
6028/**
6029 * xmlXPathCastToBoolean:
6030 * @val:  an XPath object
6031 *
6032 * Converts an XPath object to its boolean value
6033 *
6034 * Returns the boolean value
6035 */
6036int
6037xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6038    int ret = 0;
6039
6040    if (val == NULL)
6041	return(0);
6042    switch (val->type) {
6043    case XPATH_UNDEFINED:
6044#ifdef DEBUG_EXPR
6045	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6046#endif
6047	ret = 0;
6048	break;
6049    case XPATH_NODESET:
6050    case XPATH_XSLT_TREE:
6051	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6052	break;
6053    case XPATH_STRING:
6054	ret = xmlXPathCastStringToBoolean(val->stringval);
6055	break;
6056    case XPATH_NUMBER:
6057	ret = xmlXPathCastNumberToBoolean(val->floatval);
6058	break;
6059    case XPATH_BOOLEAN:
6060	ret = val->boolval;
6061	break;
6062    case XPATH_USERS:
6063    case XPATH_POINT:
6064    case XPATH_RANGE:
6065    case XPATH_LOCATIONSET:
6066	TODO;
6067	ret = 0;
6068	break;
6069    }
6070    return(ret);
6071}
6072
6073
6074/**
6075 * xmlXPathConvertBoolean:
6076 * @val:  an XPath object
6077 *
6078 * Converts an existing object to its boolean() equivalent
6079 *
6080 * Returns the new object, the old one is freed (or the operation
6081 *         is done directly on @val)
6082 */
6083xmlXPathObjectPtr
6084xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6085    xmlXPathObjectPtr ret;
6086
6087    if (val == NULL)
6088	return(xmlXPathNewBoolean(0));
6089    if (val->type == XPATH_BOOLEAN)
6090	return(val);
6091    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6092    xmlXPathFreeObject(val);
6093    return(ret);
6094}
6095
6096/************************************************************************
6097 *									*
6098 *		Routines to handle XPath contexts			*
6099 *									*
6100 ************************************************************************/
6101
6102/**
6103 * xmlXPathNewContext:
6104 * @doc:  the XML document
6105 *
6106 * Create a new xmlXPathContext
6107 *
6108 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6109 */
6110xmlXPathContextPtr
6111xmlXPathNewContext(xmlDocPtr doc) {
6112    xmlXPathContextPtr ret;
6113
6114    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6115    if (ret == NULL) {
6116        xmlXPathErrMemory(NULL, "creating context\n");
6117	return(NULL);
6118    }
6119    memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6120    ret->doc = doc;
6121    ret->node = NULL;
6122
6123    ret->varHash = NULL;
6124
6125    ret->nb_types = 0;
6126    ret->max_types = 0;
6127    ret->types = NULL;
6128
6129    ret->funcHash = xmlHashCreate(0);
6130
6131    ret->nb_axis = 0;
6132    ret->max_axis = 0;
6133    ret->axis = NULL;
6134
6135    ret->nsHash = NULL;
6136    ret->user = NULL;
6137
6138    ret->contextSize = -1;
6139    ret->proximityPosition = -1;
6140
6141#ifdef XP_DEFAULT_CACHE_ON
6142    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6143	xmlXPathFreeContext(ret);
6144	return(NULL);
6145    }
6146#endif
6147
6148    xmlXPathRegisterAllFunctions(ret);
6149
6150    return(ret);
6151}
6152
6153/**
6154 * xmlXPathFreeContext:
6155 * @ctxt:  the context to free
6156 *
6157 * Free up an xmlXPathContext
6158 */
6159void
6160xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6161    if (ctxt == NULL) return;
6162
6163    if (ctxt->cache != NULL)
6164	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6165    xmlXPathRegisteredNsCleanup(ctxt);
6166    xmlXPathRegisteredFuncsCleanup(ctxt);
6167    xmlXPathRegisteredVariablesCleanup(ctxt);
6168    xmlResetError(&ctxt->lastError);
6169    xmlFree(ctxt);
6170}
6171
6172/************************************************************************
6173 *									*
6174 *		Routines to handle XPath parser contexts		*
6175 *									*
6176 ************************************************************************/
6177
6178#define CHECK_CTXT(ctxt)						\
6179    if (ctxt == NULL) {						\
6180	__xmlRaiseError(NULL, NULL, NULL,				\
6181		NULL, NULL, XML_FROM_XPATH,				\
6182		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6183		__FILE__, __LINE__,					\
6184		NULL, NULL, NULL, 0, 0,					\
6185		"NULL context pointer\n");				\
6186	return(NULL);							\
6187    }									\
6188
6189#define CHECK_CTXT_NEG(ctxt)						\
6190    if (ctxt == NULL) {						\
6191	__xmlRaiseError(NULL, NULL, NULL,				\
6192		NULL, NULL, XML_FROM_XPATH,				\
6193		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6194		__FILE__, __LINE__,					\
6195		NULL, NULL, NULL, 0, 0,					\
6196		"NULL context pointer\n");				\
6197	return(-1);							\
6198    }									\
6199
6200
6201#define CHECK_CONTEXT(ctxt)						\
6202    if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
6203        (ctxt->doc->children == NULL)) {				\
6204	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
6205	return(NULL);							\
6206    }
6207
6208
6209/**
6210 * xmlXPathNewParserContext:
6211 * @str:  the XPath expression
6212 * @ctxt:  the XPath context
6213 *
6214 * Create a new xmlXPathParserContext
6215 *
6216 * Returns the xmlXPathParserContext just allocated.
6217 */
6218xmlXPathParserContextPtr
6219xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6220    xmlXPathParserContextPtr ret;
6221
6222    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6223    if (ret == NULL) {
6224        xmlXPathErrMemory(ctxt, "creating parser context\n");
6225	return(NULL);
6226    }
6227    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6228    ret->cur = ret->base = str;
6229    ret->context = ctxt;
6230
6231    ret->comp = xmlXPathNewCompExpr();
6232    if (ret->comp == NULL) {
6233	xmlFree(ret->valueTab);
6234	xmlFree(ret);
6235	return(NULL);
6236    }
6237    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6238        ret->comp->dict = ctxt->dict;
6239	xmlDictReference(ret->comp->dict);
6240    }
6241
6242    return(ret);
6243}
6244
6245/**
6246 * xmlXPathCompParserContext:
6247 * @comp:  the XPath compiled expression
6248 * @ctxt:  the XPath context
6249 *
6250 * Create a new xmlXPathParserContext when processing a compiled expression
6251 *
6252 * Returns the xmlXPathParserContext just allocated.
6253 */
6254static xmlXPathParserContextPtr
6255xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6256    xmlXPathParserContextPtr ret;
6257
6258    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6259    if (ret == NULL) {
6260        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6261	return(NULL);
6262    }
6263    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6264
6265    /* Allocate the value stack */
6266    ret->valueTab = (xmlXPathObjectPtr *)
6267                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6268    if (ret->valueTab == NULL) {
6269	xmlFree(ret);
6270	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6271	return(NULL);
6272    }
6273    ret->valueNr = 0;
6274    ret->valueMax = 10;
6275    ret->value = NULL;
6276    ret->valueFrame = 0;
6277
6278    ret->context = ctxt;
6279    ret->comp = comp;
6280
6281    return(ret);
6282}
6283
6284/**
6285 * xmlXPathFreeParserContext:
6286 * @ctxt:  the context to free
6287 *
6288 * Free up an xmlXPathParserContext
6289 */
6290void
6291xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6292    if (ctxt->valueTab != NULL) {
6293        xmlFree(ctxt->valueTab);
6294    }
6295    if (ctxt->comp != NULL) {
6296#ifdef XPATH_STREAMING
6297	if (ctxt->comp->stream != NULL) {
6298	    xmlFreePatternList(ctxt->comp->stream);
6299	    ctxt->comp->stream = NULL;
6300	}
6301#endif
6302	xmlXPathFreeCompExpr(ctxt->comp);
6303    }
6304    xmlFree(ctxt);
6305}
6306
6307/************************************************************************
6308 *									*
6309 *		The implicit core function library			*
6310 *									*
6311 ************************************************************************/
6312
6313/**
6314 * xmlXPathNodeValHash:
6315 * @node:  a node pointer
6316 *
6317 * Function computing the beginning of the string value of the node,
6318 * used to speed up comparisons
6319 *
6320 * Returns an int usable as a hash
6321 */
6322static unsigned int
6323xmlXPathNodeValHash(xmlNodePtr node) {
6324    int len = 2;
6325    const xmlChar * string = NULL;
6326    xmlNodePtr tmp = NULL;
6327    unsigned int ret = 0;
6328
6329    if (node == NULL)
6330	return(0);
6331
6332    if (node->type == XML_DOCUMENT_NODE) {
6333	tmp = xmlDocGetRootElement((xmlDocPtr) node);
6334	if (tmp == NULL)
6335	    node = node->children;
6336	else
6337	    node = tmp;
6338
6339	if (node == NULL)
6340	    return(0);
6341    }
6342
6343    switch (node->type) {
6344	case XML_COMMENT_NODE:
6345	case XML_PI_NODE:
6346	case XML_CDATA_SECTION_NODE:
6347	case XML_TEXT_NODE:
6348	    string = node->content;
6349	    if (string == NULL)
6350		return(0);
6351	    if (string[0] == 0)
6352		return(0);
6353	    return(((unsigned int) string[0]) +
6354		   (((unsigned int) string[1]) << 8));
6355	case XML_NAMESPACE_DECL:
6356	    string = ((xmlNsPtr)node)->href;
6357	    if (string == NULL)
6358		return(0);
6359	    if (string[0] == 0)
6360		return(0);
6361	    return(((unsigned int) string[0]) +
6362		   (((unsigned int) string[1]) << 8));
6363	case XML_ATTRIBUTE_NODE:
6364	    tmp = ((xmlAttrPtr) node)->children;
6365	    break;
6366	case XML_ELEMENT_NODE:
6367	    tmp = node->children;
6368	    break;
6369	default:
6370	    return(0);
6371    }
6372    while (tmp != NULL) {
6373	switch (tmp->type) {
6374	    case XML_COMMENT_NODE:
6375	    case XML_PI_NODE:
6376	    case XML_CDATA_SECTION_NODE:
6377	    case XML_TEXT_NODE:
6378		string = tmp->content;
6379		break;
6380	    case XML_NAMESPACE_DECL:
6381		string = ((xmlNsPtr)tmp)->href;
6382		break;
6383	    default:
6384		break;
6385	}
6386	if ((string != NULL) && (string[0] != 0)) {
6387	    if (len == 1) {
6388		return(ret + (((unsigned int) string[0]) << 8));
6389	    }
6390	    if (string[1] == 0) {
6391		len = 1;
6392		ret = (unsigned int) string[0];
6393	    } else {
6394		return(((unsigned int) string[0]) +
6395		       (((unsigned int) string[1]) << 8));
6396	    }
6397	}
6398	/*
6399	 * Skip to next node
6400	 */
6401	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6402	    if (tmp->children->type != XML_ENTITY_DECL) {
6403		tmp = tmp->children;
6404		continue;
6405	    }
6406	}
6407	if (tmp == node)
6408	    break;
6409
6410	if (tmp->next != NULL) {
6411	    tmp = tmp->next;
6412	    continue;
6413	}
6414
6415	do {
6416	    tmp = tmp->parent;
6417	    if (tmp == NULL)
6418		break;
6419	    if (tmp == node) {
6420		tmp = NULL;
6421		break;
6422	    }
6423	    if (tmp->next != NULL) {
6424		tmp = tmp->next;
6425		break;
6426	    }
6427	} while (tmp != NULL);
6428    }
6429    return(ret);
6430}
6431
6432/**
6433 * xmlXPathStringHash:
6434 * @string:  a string
6435 *
6436 * Function computing the beginning of the string value of the node,
6437 * used to speed up comparisons
6438 *
6439 * Returns an int usable as a hash
6440 */
6441static unsigned int
6442xmlXPathStringHash(const xmlChar * string) {
6443    if (string == NULL)
6444	return((unsigned int) 0);
6445    if (string[0] == 0)
6446	return(0);
6447    return(((unsigned int) string[0]) +
6448	   (((unsigned int) string[1]) << 8));
6449}
6450
6451/**
6452 * xmlXPathCompareNodeSetFloat:
6453 * @ctxt:  the XPath Parser context
6454 * @inf:  less than (1) or greater than (0)
6455 * @strict:  is the comparison strict
6456 * @arg:  the node set
6457 * @f:  the value
6458 *
6459 * Implement the compare operation between a nodeset and a number
6460 *     @ns < @val    (1, 1, ...
6461 *     @ns <= @val   (1, 0, ...
6462 *     @ns > @val    (0, 1, ...
6463 *     @ns >= @val   (0, 0, ...
6464 *
6465 * If one object to be compared is a node-set and the other is a number,
6466 * then the comparison will be true if and only if there is a node in the
6467 * node-set such that the result of performing the comparison on the number
6468 * to be compared and on the result of converting the string-value of that
6469 * node to a number using the number function is true.
6470 *
6471 * Returns 0 or 1 depending on the results of the test.
6472 */
6473static int
6474xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6475	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6476    int i, ret = 0;
6477    xmlNodeSetPtr ns;
6478    xmlChar *str2;
6479
6480    if ((f == NULL) || (arg == NULL) ||
6481	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6482	xmlXPathReleaseObject(ctxt->context, arg);
6483	xmlXPathReleaseObject(ctxt->context, f);
6484        return(0);
6485    }
6486    ns = arg->nodesetval;
6487    if (ns != NULL) {
6488	for (i = 0;i < ns->nodeNr;i++) {
6489	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6490	     if (str2 != NULL) {
6491		 valuePush(ctxt,
6492			   xmlXPathCacheNewString(ctxt->context, str2));
6493		 xmlFree(str2);
6494		 xmlXPathNumberFunction(ctxt, 1);
6495		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6496		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6497		 if (ret)
6498		     break;
6499	     }
6500	}
6501    }
6502    xmlXPathReleaseObject(ctxt->context, arg);
6503    xmlXPathReleaseObject(ctxt->context, f);
6504    return(ret);
6505}
6506
6507/**
6508 * xmlXPathCompareNodeSetString:
6509 * @ctxt:  the XPath Parser context
6510 * @inf:  less than (1) or greater than (0)
6511 * @strict:  is the comparison strict
6512 * @arg:  the node set
6513 * @s:  the value
6514 *
6515 * Implement the compare operation between a nodeset and a string
6516 *     @ns < @val    (1, 1, ...
6517 *     @ns <= @val   (1, 0, ...
6518 *     @ns > @val    (0, 1, ...
6519 *     @ns >= @val   (0, 0, ...
6520 *
6521 * If one object to be compared is a node-set and the other is a string,
6522 * then the comparison will be true if and only if there is a node in
6523 * the node-set such that the result of performing the comparison on the
6524 * string-value of the node and the other string is true.
6525 *
6526 * Returns 0 or 1 depending on the results of the test.
6527 */
6528static int
6529xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6530	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6531    int i, ret = 0;
6532    xmlNodeSetPtr ns;
6533    xmlChar *str2;
6534
6535    if ((s == NULL) || (arg == NULL) ||
6536	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6537	xmlXPathReleaseObject(ctxt->context, arg);
6538	xmlXPathReleaseObject(ctxt->context, s);
6539        return(0);
6540    }
6541    ns = arg->nodesetval;
6542    if (ns != NULL) {
6543	for (i = 0;i < ns->nodeNr;i++) {
6544	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6545	     if (str2 != NULL) {
6546		 valuePush(ctxt,
6547			   xmlXPathCacheNewString(ctxt->context, str2));
6548		 xmlFree(str2);
6549		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6550		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6551		 if (ret)
6552		     break;
6553	     }
6554	}
6555    }
6556    xmlXPathReleaseObject(ctxt->context, arg);
6557    xmlXPathReleaseObject(ctxt->context, s);
6558    return(ret);
6559}
6560
6561/**
6562 * xmlXPathCompareNodeSets:
6563 * @inf:  less than (1) or greater than (0)
6564 * @strict:  is the comparison strict
6565 * @arg1:  the first node set object
6566 * @arg2:  the second node set object
6567 *
6568 * Implement the compare operation on nodesets:
6569 *
6570 * If both objects to be compared are node-sets, then the comparison
6571 * will be true if and only if there is a node in the first node-set
6572 * and a node in the second node-set such that the result of performing
6573 * the comparison on the string-values of the two nodes is true.
6574 * ....
6575 * When neither object to be compared is a node-set and the operator
6576 * is <=, <, >= or >, then the objects are compared by converting both
6577 * objects to numbers and comparing the numbers according to IEEE 754.
6578 * ....
6579 * The number function converts its argument to a number as follows:
6580 *  - a string that consists of optional whitespace followed by an
6581 *    optional minus sign followed by a Number followed by whitespace
6582 *    is converted to the IEEE 754 number that is nearest (according
6583 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6584 *    represented by the string; any other string is converted to NaN
6585 *
6586 * Conclusion all nodes need to be converted first to their string value
6587 * and then the comparison must be done when possible
6588 */
6589static int
6590xmlXPathCompareNodeSets(int inf, int strict,
6591	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6592    int i, j, init = 0;
6593    double val1;
6594    double *values2;
6595    int ret = 0;
6596    xmlNodeSetPtr ns1;
6597    xmlNodeSetPtr ns2;
6598
6599    if ((arg1 == NULL) ||
6600	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6601	xmlXPathFreeObject(arg2);
6602        return(0);
6603    }
6604    if ((arg2 == NULL) ||
6605	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6606	xmlXPathFreeObject(arg1);
6607	xmlXPathFreeObject(arg2);
6608        return(0);
6609    }
6610
6611    ns1 = arg1->nodesetval;
6612    ns2 = arg2->nodesetval;
6613
6614    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6615	xmlXPathFreeObject(arg1);
6616	xmlXPathFreeObject(arg2);
6617	return(0);
6618    }
6619    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6620	xmlXPathFreeObject(arg1);
6621	xmlXPathFreeObject(arg2);
6622	return(0);
6623    }
6624
6625    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6626    if (values2 == NULL) {
6627        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6628	xmlXPathFreeObject(arg1);
6629	xmlXPathFreeObject(arg2);
6630	return(0);
6631    }
6632    for (i = 0;i < ns1->nodeNr;i++) {
6633	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6634	if (xmlXPathIsNaN(val1))
6635	    continue;
6636	for (j = 0;j < ns2->nodeNr;j++) {
6637	    if (init == 0) {
6638		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6639	    }
6640	    if (xmlXPathIsNaN(values2[j]))
6641		continue;
6642	    if (inf && strict)
6643		ret = (val1 < values2[j]);
6644	    else if (inf && !strict)
6645		ret = (val1 <= values2[j]);
6646	    else if (!inf && strict)
6647		ret = (val1 > values2[j]);
6648	    else if (!inf && !strict)
6649		ret = (val1 >= values2[j]);
6650	    if (ret)
6651		break;
6652	}
6653	if (ret)
6654	    break;
6655	init = 1;
6656    }
6657    xmlFree(values2);
6658    xmlXPathFreeObject(arg1);
6659    xmlXPathFreeObject(arg2);
6660    return(ret);
6661}
6662
6663/**
6664 * xmlXPathCompareNodeSetValue:
6665 * @ctxt:  the XPath Parser context
6666 * @inf:  less than (1) or greater than (0)
6667 * @strict:  is the comparison strict
6668 * @arg:  the node set
6669 * @val:  the value
6670 *
6671 * Implement the compare operation between a nodeset and a value
6672 *     @ns < @val    (1, 1, ...
6673 *     @ns <= @val   (1, 0, ...
6674 *     @ns > @val    (0, 1, ...
6675 *     @ns >= @val   (0, 0, ...
6676 *
6677 * If one object to be compared is a node-set and the other is a boolean,
6678 * then the comparison will be true if and only if the result of performing
6679 * the comparison on the boolean and on the result of converting
6680 * the node-set to a boolean using the boolean function is true.
6681 *
6682 * Returns 0 or 1 depending on the results of the test.
6683 */
6684static int
6685xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6686	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6687    if ((val == NULL) || (arg == NULL) ||
6688	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6689        return(0);
6690
6691    switch(val->type) {
6692        case XPATH_NUMBER:
6693	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6694        case XPATH_NODESET:
6695        case XPATH_XSLT_TREE:
6696	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6697        case XPATH_STRING:
6698	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6699        case XPATH_BOOLEAN:
6700	    valuePush(ctxt, arg);
6701	    xmlXPathBooleanFunction(ctxt, 1);
6702	    valuePush(ctxt, val);
6703	    return(xmlXPathCompareValues(ctxt, inf, strict));
6704	default:
6705	    TODO
6706    }
6707    return(0);
6708}
6709
6710/**
6711 * xmlXPathEqualNodeSetString:
6712 * @arg:  the nodeset object argument
6713 * @str:  the string to compare to.
6714 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6715 *
6716 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6717 * If one object to be compared is a node-set and the other is a string,
6718 * then the comparison will be true if and only if there is a node in
6719 * the node-set such that the result of performing the comparison on the
6720 * string-value of the node and the other string is true.
6721 *
6722 * Returns 0 or 1 depending on the results of the test.
6723 */
6724static int
6725xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6726{
6727    int i;
6728    xmlNodeSetPtr ns;
6729    xmlChar *str2;
6730    unsigned int hash;
6731
6732    if ((str == NULL) || (arg == NULL) ||
6733        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6734        return (0);
6735    ns = arg->nodesetval;
6736    /*
6737     * A NULL nodeset compared with a string is always false
6738     * (since there is no node equal, and no node not equal)
6739     */
6740    if ((ns == NULL) || (ns->nodeNr <= 0) )
6741        return (0);
6742    hash = xmlXPathStringHash(str);
6743    for (i = 0; i < ns->nodeNr; i++) {
6744        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6745            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6746            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6747                xmlFree(str2);
6748		if (neq)
6749		    continue;
6750                return (1);
6751	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6752		if (neq)
6753		    continue;
6754                return (1);
6755            } else if (neq) {
6756		if (str2 != NULL)
6757		    xmlFree(str2);
6758		return (1);
6759	    }
6760            if (str2 != NULL)
6761                xmlFree(str2);
6762        } else if (neq)
6763	    return (1);
6764    }
6765    return (0);
6766}
6767
6768/**
6769 * xmlXPathEqualNodeSetFloat:
6770 * @arg:  the nodeset object argument
6771 * @f:  the float to compare to
6772 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6773 *
6774 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6775 * If one object to be compared is a node-set and the other is a number,
6776 * then the comparison will be true if and only if there is a node in
6777 * the node-set such that the result of performing the comparison on the
6778 * number to be compared and on the result of converting the string-value
6779 * of that node to a number using the number function is true.
6780 *
6781 * Returns 0 or 1 depending on the results of the test.
6782 */
6783static int
6784xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6785    xmlXPathObjectPtr arg, double f, int neq) {
6786  int i, ret=0;
6787  xmlNodeSetPtr ns;
6788  xmlChar *str2;
6789  xmlXPathObjectPtr val;
6790  double v;
6791
6792    if ((arg == NULL) ||
6793	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6794        return(0);
6795
6796    ns = arg->nodesetval;
6797    if (ns != NULL) {
6798	for (i=0;i<ns->nodeNr;i++) {
6799	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6800	    if (str2 != NULL) {
6801		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6802		xmlFree(str2);
6803		xmlXPathNumberFunction(ctxt, 1);
6804		val = valuePop(ctxt);
6805		v = val->floatval;
6806		xmlXPathReleaseObject(ctxt->context, val);
6807		if (!xmlXPathIsNaN(v)) {
6808		    if ((!neq) && (v==f)) {
6809			ret = 1;
6810			break;
6811		    } else if ((neq) && (v!=f)) {
6812			ret = 1;
6813			break;
6814		    }
6815		} else {	/* NaN is unequal to any value */
6816		    if (neq)
6817			ret = 1;
6818		}
6819	    }
6820	}
6821    }
6822
6823    return(ret);
6824}
6825
6826
6827/**
6828 * xmlXPathEqualNodeSets:
6829 * @arg1:  first nodeset object argument
6830 * @arg2:  second nodeset object argument
6831 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6832 *
6833 * Implement the equal / not equal operation on XPath nodesets:
6834 * @arg1 == @arg2  or  @arg1 != @arg2
6835 * If both objects to be compared are node-sets, then the comparison
6836 * will be true if and only if there is a node in the first node-set and
6837 * a node in the second node-set such that the result of performing the
6838 * comparison on the string-values of the two nodes is true.
6839 *
6840 * (needless to say, this is a costly operation)
6841 *
6842 * Returns 0 or 1 depending on the results of the test.
6843 */
6844static int
6845xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6846    int i, j;
6847    unsigned int *hashs1;
6848    unsigned int *hashs2;
6849    xmlChar **values1;
6850    xmlChar **values2;
6851    int ret = 0;
6852    xmlNodeSetPtr ns1;
6853    xmlNodeSetPtr ns2;
6854
6855    if ((arg1 == NULL) ||
6856	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6857        return(0);
6858    if ((arg2 == NULL) ||
6859	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6860        return(0);
6861
6862    ns1 = arg1->nodesetval;
6863    ns2 = arg2->nodesetval;
6864
6865    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6866	return(0);
6867    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6868	return(0);
6869
6870    /*
6871     * for equal, check if there is a node pertaining to both sets
6872     */
6873    if (neq == 0)
6874	for (i = 0;i < ns1->nodeNr;i++)
6875	    for (j = 0;j < ns2->nodeNr;j++)
6876		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6877		    return(1);
6878
6879    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6880    if (values1 == NULL) {
6881        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6882	return(0);
6883    }
6884    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6885    if (hashs1 == NULL) {
6886        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6887	xmlFree(values1);
6888	return(0);
6889    }
6890    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6891    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6892    if (values2 == NULL) {
6893        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6894	xmlFree(hashs1);
6895	xmlFree(values1);
6896	return(0);
6897    }
6898    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6899    if (hashs2 == NULL) {
6900        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6901	xmlFree(hashs1);
6902	xmlFree(values1);
6903	xmlFree(values2);
6904	return(0);
6905    }
6906    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6907    for (i = 0;i < ns1->nodeNr;i++) {
6908	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6909	for (j = 0;j < ns2->nodeNr;j++) {
6910	    if (i == 0)
6911		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6912	    if (hashs1[i] != hashs2[j]) {
6913		if (neq) {
6914		    ret = 1;
6915		    break;
6916		}
6917	    }
6918	    else {
6919		if (values1[i] == NULL)
6920		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6921		if (values2[j] == NULL)
6922		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6923		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6924		if (ret)
6925		    break;
6926	    }
6927	}
6928	if (ret)
6929	    break;
6930    }
6931    for (i = 0;i < ns1->nodeNr;i++)
6932	if (values1[i] != NULL)
6933	    xmlFree(values1[i]);
6934    for (j = 0;j < ns2->nodeNr;j++)
6935	if (values2[j] != NULL)
6936	    xmlFree(values2[j]);
6937    xmlFree(values1);
6938    xmlFree(values2);
6939    xmlFree(hashs1);
6940    xmlFree(hashs2);
6941    return(ret);
6942}
6943
6944static int
6945xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6946  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6947    int ret = 0;
6948    /*
6949     *At this point we are assured neither arg1 nor arg2
6950     *is a nodeset, so we can just pick the appropriate routine.
6951     */
6952    switch (arg1->type) {
6953        case XPATH_UNDEFINED:
6954#ifdef DEBUG_EXPR
6955	    xmlGenericError(xmlGenericErrorContext,
6956		    "Equal: undefined\n");
6957#endif
6958	    break;
6959        case XPATH_BOOLEAN:
6960	    switch (arg2->type) {
6961	        case XPATH_UNDEFINED:
6962#ifdef DEBUG_EXPR
6963		    xmlGenericError(xmlGenericErrorContext,
6964			    "Equal: undefined\n");
6965#endif
6966		    break;
6967		case XPATH_BOOLEAN:
6968#ifdef DEBUG_EXPR
6969		    xmlGenericError(xmlGenericErrorContext,
6970			    "Equal: %d boolean %d \n",
6971			    arg1->boolval, arg2->boolval);
6972#endif
6973		    ret = (arg1->boolval == arg2->boolval);
6974		    break;
6975		case XPATH_NUMBER:
6976		    ret = (arg1->boolval ==
6977			   xmlXPathCastNumberToBoolean(arg2->floatval));
6978		    break;
6979		case XPATH_STRING:
6980		    if ((arg2->stringval == NULL) ||
6981			(arg2->stringval[0] == 0)) ret = 0;
6982		    else
6983			ret = 1;
6984		    ret = (arg1->boolval == ret);
6985		    break;
6986		case XPATH_USERS:
6987		case XPATH_POINT:
6988		case XPATH_RANGE:
6989		case XPATH_LOCATIONSET:
6990		    TODO
6991		    break;
6992		case XPATH_NODESET:
6993		case XPATH_XSLT_TREE:
6994		    break;
6995	    }
6996	    break;
6997        case XPATH_NUMBER:
6998	    switch (arg2->type) {
6999	        case XPATH_UNDEFINED:
7000#ifdef DEBUG_EXPR
7001		    xmlGenericError(xmlGenericErrorContext,
7002			    "Equal: undefined\n");
7003#endif
7004		    break;
7005		case XPATH_BOOLEAN:
7006		    ret = (arg2->boolval==
7007			   xmlXPathCastNumberToBoolean(arg1->floatval));
7008		    break;
7009		case XPATH_STRING:
7010		    valuePush(ctxt, arg2);
7011		    xmlXPathNumberFunction(ctxt, 1);
7012		    arg2 = valuePop(ctxt);
7013		    /* no break on purpose */
7014		case XPATH_NUMBER:
7015		    /* Hand check NaN and Infinity equalities */
7016		    if (xmlXPathIsNaN(arg1->floatval) ||
7017			    xmlXPathIsNaN(arg2->floatval)) {
7018		        ret = 0;
7019		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7020		        if (xmlXPathIsInf(arg2->floatval) == 1)
7021			    ret = 1;
7022			else
7023			    ret = 0;
7024		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7025			if (xmlXPathIsInf(arg2->floatval) == -1)
7026			    ret = 1;
7027			else
7028			    ret = 0;
7029		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7030			if (xmlXPathIsInf(arg1->floatval) == 1)
7031			    ret = 1;
7032			else
7033			    ret = 0;
7034		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7035			if (xmlXPathIsInf(arg1->floatval) == -1)
7036			    ret = 1;
7037			else
7038			    ret = 0;
7039		    } else {
7040		        ret = (arg1->floatval == arg2->floatval);
7041		    }
7042		    break;
7043		case XPATH_USERS:
7044		case XPATH_POINT:
7045		case XPATH_RANGE:
7046		case XPATH_LOCATIONSET:
7047		    TODO
7048		    break;
7049		case XPATH_NODESET:
7050		case XPATH_XSLT_TREE:
7051		    break;
7052	    }
7053	    break;
7054        case XPATH_STRING:
7055	    switch (arg2->type) {
7056	        case XPATH_UNDEFINED:
7057#ifdef DEBUG_EXPR
7058		    xmlGenericError(xmlGenericErrorContext,
7059			    "Equal: undefined\n");
7060#endif
7061		    break;
7062		case XPATH_BOOLEAN:
7063		    if ((arg1->stringval == NULL) ||
7064			(arg1->stringval[0] == 0)) ret = 0;
7065		    else
7066			ret = 1;
7067		    ret = (arg2->boolval == ret);
7068		    break;
7069		case XPATH_STRING:
7070		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7071		    break;
7072		case XPATH_NUMBER:
7073		    valuePush(ctxt, arg1);
7074		    xmlXPathNumberFunction(ctxt, 1);
7075		    arg1 = valuePop(ctxt);
7076		    /* Hand check NaN and Infinity equalities */
7077		    if (xmlXPathIsNaN(arg1->floatval) ||
7078			    xmlXPathIsNaN(arg2->floatval)) {
7079		        ret = 0;
7080		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7081			if (xmlXPathIsInf(arg2->floatval) == 1)
7082			    ret = 1;
7083			else
7084			    ret = 0;
7085		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7086			if (xmlXPathIsInf(arg2->floatval) == -1)
7087			    ret = 1;
7088			else
7089			    ret = 0;
7090		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7091			if (xmlXPathIsInf(arg1->floatval) == 1)
7092			    ret = 1;
7093			else
7094			    ret = 0;
7095		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7096			if (xmlXPathIsInf(arg1->floatval) == -1)
7097			    ret = 1;
7098			else
7099			    ret = 0;
7100		    } else {
7101		        ret = (arg1->floatval == arg2->floatval);
7102		    }
7103		    break;
7104		case XPATH_USERS:
7105		case XPATH_POINT:
7106		case XPATH_RANGE:
7107		case XPATH_LOCATIONSET:
7108		    TODO
7109		    break;
7110		case XPATH_NODESET:
7111		case XPATH_XSLT_TREE:
7112		    break;
7113	    }
7114	    break;
7115        case XPATH_USERS:
7116	case XPATH_POINT:
7117	case XPATH_RANGE:
7118	case XPATH_LOCATIONSET:
7119	    TODO
7120	    break;
7121	case XPATH_NODESET:
7122	case XPATH_XSLT_TREE:
7123	    break;
7124    }
7125    xmlXPathReleaseObject(ctxt->context, arg1);
7126    xmlXPathReleaseObject(ctxt->context, arg2);
7127    return(ret);
7128}
7129
7130/**
7131 * xmlXPathEqualValues:
7132 * @ctxt:  the XPath Parser context
7133 *
7134 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7135 *
7136 * Returns 0 or 1 depending on the results of the test.
7137 */
7138int
7139xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7140    xmlXPathObjectPtr arg1, arg2, argtmp;
7141    int ret = 0;
7142
7143    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7144    arg2 = valuePop(ctxt);
7145    arg1 = valuePop(ctxt);
7146    if ((arg1 == NULL) || (arg2 == NULL)) {
7147	if (arg1 != NULL)
7148	    xmlXPathReleaseObject(ctxt->context, arg1);
7149	else
7150	    xmlXPathReleaseObject(ctxt->context, arg2);
7151	XP_ERROR0(XPATH_INVALID_OPERAND);
7152    }
7153
7154    if (arg1 == arg2) {
7155#ifdef DEBUG_EXPR
7156        xmlGenericError(xmlGenericErrorContext,
7157		"Equal: by pointer\n");
7158#endif
7159	xmlXPathFreeObject(arg1);
7160        return(1);
7161    }
7162
7163    /*
7164     *If either argument is a nodeset, it's a 'special case'
7165     */
7166    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7167      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7168	/*
7169	 *Hack it to assure arg1 is the nodeset
7170	 */
7171	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7172		argtmp = arg2;
7173		arg2 = arg1;
7174		arg1 = argtmp;
7175	}
7176	switch (arg2->type) {
7177	    case XPATH_UNDEFINED:
7178#ifdef DEBUG_EXPR
7179		xmlGenericError(xmlGenericErrorContext,
7180			"Equal: undefined\n");
7181#endif
7182		break;
7183	    case XPATH_NODESET:
7184	    case XPATH_XSLT_TREE:
7185		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7186		break;
7187	    case XPATH_BOOLEAN:
7188		if ((arg1->nodesetval == NULL) ||
7189		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7190		else
7191		    ret = 1;
7192		ret = (ret == arg2->boolval);
7193		break;
7194	    case XPATH_NUMBER:
7195		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7196		break;
7197	    case XPATH_STRING:
7198		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7199		break;
7200	    case XPATH_USERS:
7201	    case XPATH_POINT:
7202	    case XPATH_RANGE:
7203	    case XPATH_LOCATIONSET:
7204		TODO
7205		break;
7206	}
7207	xmlXPathReleaseObject(ctxt->context, arg1);
7208	xmlXPathReleaseObject(ctxt->context, arg2);
7209	return(ret);
7210    }
7211
7212    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7213}
7214
7215/**
7216 * xmlXPathNotEqualValues:
7217 * @ctxt:  the XPath Parser context
7218 *
7219 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7220 *
7221 * Returns 0 or 1 depending on the results of the test.
7222 */
7223int
7224xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7225    xmlXPathObjectPtr arg1, arg2, argtmp;
7226    int ret = 0;
7227
7228    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7229    arg2 = valuePop(ctxt);
7230    arg1 = valuePop(ctxt);
7231    if ((arg1 == NULL) || (arg2 == NULL)) {
7232	if (arg1 != NULL)
7233	    xmlXPathReleaseObject(ctxt->context, arg1);
7234	else
7235	    xmlXPathReleaseObject(ctxt->context, arg2);
7236	XP_ERROR0(XPATH_INVALID_OPERAND);
7237    }
7238
7239    if (arg1 == arg2) {
7240#ifdef DEBUG_EXPR
7241        xmlGenericError(xmlGenericErrorContext,
7242		"NotEqual: by pointer\n");
7243#endif
7244	xmlXPathReleaseObject(ctxt->context, arg1);
7245        return(0);
7246    }
7247
7248    /*
7249     *If either argument is a nodeset, it's a 'special case'
7250     */
7251    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7252      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7253	/*
7254	 *Hack it to assure arg1 is the nodeset
7255	 */
7256	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7257		argtmp = arg2;
7258		arg2 = arg1;
7259		arg1 = argtmp;
7260	}
7261	switch (arg2->type) {
7262	    case XPATH_UNDEFINED:
7263#ifdef DEBUG_EXPR
7264		xmlGenericError(xmlGenericErrorContext,
7265			"NotEqual: undefined\n");
7266#endif
7267		break;
7268	    case XPATH_NODESET:
7269	    case XPATH_XSLT_TREE:
7270		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7271		break;
7272	    case XPATH_BOOLEAN:
7273		if ((arg1->nodesetval == NULL) ||
7274		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7275		else
7276		    ret = 1;
7277		ret = (ret != arg2->boolval);
7278		break;
7279	    case XPATH_NUMBER:
7280		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7281		break;
7282	    case XPATH_STRING:
7283		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7284		break;
7285	    case XPATH_USERS:
7286	    case XPATH_POINT:
7287	    case XPATH_RANGE:
7288	    case XPATH_LOCATIONSET:
7289		TODO
7290		break;
7291	}
7292	xmlXPathReleaseObject(ctxt->context, arg1);
7293	xmlXPathReleaseObject(ctxt->context, arg2);
7294	return(ret);
7295    }
7296
7297    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7298}
7299
7300/**
7301 * xmlXPathCompareValues:
7302 * @ctxt:  the XPath Parser context
7303 * @inf:  less than (1) or greater than (0)
7304 * @strict:  is the comparison strict
7305 *
7306 * Implement the compare operation on XPath objects:
7307 *     @arg1 < @arg2    (1, 1, ...
7308 *     @arg1 <= @arg2   (1, 0, ...
7309 *     @arg1 > @arg2    (0, 1, ...
7310 *     @arg1 >= @arg2   (0, 0, ...
7311 *
7312 * When neither object to be compared is a node-set and the operator is
7313 * <=, <, >=, >, then the objects are compared by converted both objects
7314 * to numbers and comparing the numbers according to IEEE 754. The <
7315 * comparison will be true if and only if the first number is less than the
7316 * second number. The <= comparison will be true if and only if the first
7317 * number is less than or equal to the second number. The > comparison
7318 * will be true if and only if the first number is greater than the second
7319 * number. The >= comparison will be true if and only if the first number
7320 * is greater than or equal to the second number.
7321 *
7322 * Returns 1 if the comparison succeeded, 0 if it failed
7323 */
7324int
7325xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7326    int ret = 0, arg1i = 0, arg2i = 0;
7327    xmlXPathObjectPtr arg1, arg2;
7328
7329    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7330    arg2 = valuePop(ctxt);
7331    arg1 = valuePop(ctxt);
7332    if ((arg1 == NULL) || (arg2 == NULL)) {
7333	if (arg1 != NULL)
7334	    xmlXPathReleaseObject(ctxt->context, arg1);
7335	else
7336	    xmlXPathReleaseObject(ctxt->context, arg2);
7337	XP_ERROR0(XPATH_INVALID_OPERAND);
7338    }
7339
7340    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7341      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7342	/*
7343	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7344	 * are not freed from within this routine; they will be freed from the
7345	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7346	 */
7347	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7348	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7349	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7350	} else {
7351	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7352		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7353			                          arg1, arg2);
7354	    } else {
7355		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7356			                          arg2, arg1);
7357	    }
7358	}
7359	return(ret);
7360    }
7361
7362    if (arg1->type != XPATH_NUMBER) {
7363	valuePush(ctxt, arg1);
7364	xmlXPathNumberFunction(ctxt, 1);
7365	arg1 = valuePop(ctxt);
7366    }
7367    if (arg1->type != XPATH_NUMBER) {
7368	xmlXPathFreeObject(arg1);
7369	xmlXPathFreeObject(arg2);
7370	XP_ERROR0(XPATH_INVALID_OPERAND);
7371    }
7372    if (arg2->type != XPATH_NUMBER) {
7373	valuePush(ctxt, arg2);
7374	xmlXPathNumberFunction(ctxt, 1);
7375	arg2 = valuePop(ctxt);
7376    }
7377    if (arg2->type != XPATH_NUMBER) {
7378	xmlXPathReleaseObject(ctxt->context, arg1);
7379	xmlXPathReleaseObject(ctxt->context, arg2);
7380	XP_ERROR0(XPATH_INVALID_OPERAND);
7381    }
7382    /*
7383     * Add tests for infinity and nan
7384     * => feedback on 3.4 for Inf and NaN
7385     */
7386    /* Hand check NaN and Infinity comparisons */
7387    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7388	ret=0;
7389    } else {
7390	arg1i=xmlXPathIsInf(arg1->floatval);
7391	arg2i=xmlXPathIsInf(arg2->floatval);
7392	if (inf && strict) {
7393	    if ((arg1i == -1 && arg2i != -1) ||
7394		(arg2i == 1 && arg1i != 1)) {
7395		ret = 1;
7396	    } else if (arg1i == 0 && arg2i == 0) {
7397		ret = (arg1->floatval < arg2->floatval);
7398	    } else {
7399		ret = 0;
7400	    }
7401	}
7402	else if (inf && !strict) {
7403	    if (arg1i == -1 || arg2i == 1) {
7404		ret = 1;
7405	    } else if (arg1i == 0 && arg2i == 0) {
7406		ret = (arg1->floatval <= arg2->floatval);
7407	    } else {
7408		ret = 0;
7409	    }
7410	}
7411	else if (!inf && strict) {
7412	    if ((arg1i == 1 && arg2i != 1) ||
7413		(arg2i == -1 && arg1i != -1)) {
7414		ret = 1;
7415	    } else if (arg1i == 0 && arg2i == 0) {
7416		ret = (arg1->floatval > arg2->floatval);
7417	    } else {
7418		ret = 0;
7419	    }
7420	}
7421	else if (!inf && !strict) {
7422	    if (arg1i == 1 || arg2i == -1) {
7423		ret = 1;
7424	    } else if (arg1i == 0 && arg2i == 0) {
7425		ret = (arg1->floatval >= arg2->floatval);
7426	    } else {
7427		ret = 0;
7428	    }
7429	}
7430    }
7431    xmlXPathReleaseObject(ctxt->context, arg1);
7432    xmlXPathReleaseObject(ctxt->context, arg2);
7433    return(ret);
7434}
7435
7436/**
7437 * xmlXPathValueFlipSign:
7438 * @ctxt:  the XPath Parser context
7439 *
7440 * Implement the unary - operation on an XPath object
7441 * The numeric operators convert their operands to numbers as if
7442 * by calling the number function.
7443 */
7444void
7445xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7446    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7447    CAST_TO_NUMBER;
7448    CHECK_TYPE(XPATH_NUMBER);
7449    if (xmlXPathIsNaN(ctxt->value->floatval))
7450        ctxt->value->floatval=xmlXPathNAN;
7451    else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7452        ctxt->value->floatval=xmlXPathNINF;
7453    else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7454        ctxt->value->floatval=xmlXPathPINF;
7455    else if (ctxt->value->floatval == 0) {
7456        if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7457	    ctxt->value->floatval = xmlXPathNZERO;
7458	else
7459	    ctxt->value->floatval = 0;
7460    }
7461    else
7462        ctxt->value->floatval = - ctxt->value->floatval;
7463}
7464
7465/**
7466 * xmlXPathAddValues:
7467 * @ctxt:  the XPath Parser context
7468 *
7469 * Implement the add operation on XPath objects:
7470 * The numeric operators convert their operands to numbers as if
7471 * by calling the number function.
7472 */
7473void
7474xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7475    xmlXPathObjectPtr arg;
7476    double val;
7477
7478    arg = valuePop(ctxt);
7479    if (arg == NULL)
7480	XP_ERROR(XPATH_INVALID_OPERAND);
7481    val = xmlXPathCastToNumber(arg);
7482    xmlXPathReleaseObject(ctxt->context, arg);
7483    CAST_TO_NUMBER;
7484    CHECK_TYPE(XPATH_NUMBER);
7485    ctxt->value->floatval += val;
7486}
7487
7488/**
7489 * xmlXPathSubValues:
7490 * @ctxt:  the XPath Parser context
7491 *
7492 * Implement the subtraction operation on XPath objects:
7493 * The numeric operators convert their operands to numbers as if
7494 * by calling the number function.
7495 */
7496void
7497xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7498    xmlXPathObjectPtr arg;
7499    double val;
7500
7501    arg = valuePop(ctxt);
7502    if (arg == NULL)
7503	XP_ERROR(XPATH_INVALID_OPERAND);
7504    val = xmlXPathCastToNumber(arg);
7505    xmlXPathReleaseObject(ctxt->context, arg);
7506    CAST_TO_NUMBER;
7507    CHECK_TYPE(XPATH_NUMBER);
7508    ctxt->value->floatval -= val;
7509}
7510
7511/**
7512 * xmlXPathMultValues:
7513 * @ctxt:  the XPath Parser context
7514 *
7515 * Implement the multiply operation on XPath objects:
7516 * The numeric operators convert their operands to numbers as if
7517 * by calling the number function.
7518 */
7519void
7520xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7521    xmlXPathObjectPtr arg;
7522    double val;
7523
7524    arg = valuePop(ctxt);
7525    if (arg == NULL)
7526	XP_ERROR(XPATH_INVALID_OPERAND);
7527    val = xmlXPathCastToNumber(arg);
7528    xmlXPathReleaseObject(ctxt->context, arg);
7529    CAST_TO_NUMBER;
7530    CHECK_TYPE(XPATH_NUMBER);
7531    ctxt->value->floatval *= val;
7532}
7533
7534/**
7535 * xmlXPathDivValues:
7536 * @ctxt:  the XPath Parser context
7537 *
7538 * Implement the div operation on XPath objects @arg1 / @arg2:
7539 * The numeric operators convert their operands to numbers as if
7540 * by calling the number function.
7541 */
7542void
7543xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7544    xmlXPathObjectPtr arg;
7545    double val;
7546
7547    arg = valuePop(ctxt);
7548    if (arg == NULL)
7549	XP_ERROR(XPATH_INVALID_OPERAND);
7550    val = xmlXPathCastToNumber(arg);
7551    xmlXPathReleaseObject(ctxt->context, arg);
7552    CAST_TO_NUMBER;
7553    CHECK_TYPE(XPATH_NUMBER);
7554    if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7555	ctxt->value->floatval = xmlXPathNAN;
7556    else if (val == 0 && xmlXPathGetSign(val) != 0) {
7557	if (ctxt->value->floatval == 0)
7558	    ctxt->value->floatval = xmlXPathNAN;
7559	else if (ctxt->value->floatval > 0)
7560	    ctxt->value->floatval = xmlXPathNINF;
7561	else if (ctxt->value->floatval < 0)
7562	    ctxt->value->floatval = xmlXPathPINF;
7563    }
7564    else if (val == 0) {
7565	if (ctxt->value->floatval == 0)
7566	    ctxt->value->floatval = xmlXPathNAN;
7567	else if (ctxt->value->floatval > 0)
7568	    ctxt->value->floatval = xmlXPathPINF;
7569	else if (ctxt->value->floatval < 0)
7570	    ctxt->value->floatval = xmlXPathNINF;
7571    } else
7572	ctxt->value->floatval /= val;
7573}
7574
7575/**
7576 * xmlXPathModValues:
7577 * @ctxt:  the XPath Parser context
7578 *
7579 * Implement the mod operation on XPath objects: @arg1 / @arg2
7580 * The numeric operators convert their operands to numbers as if
7581 * by calling the number function.
7582 */
7583void
7584xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7585    xmlXPathObjectPtr arg;
7586    double arg1, arg2;
7587
7588    arg = valuePop(ctxt);
7589    if (arg == NULL)
7590	XP_ERROR(XPATH_INVALID_OPERAND);
7591    arg2 = xmlXPathCastToNumber(arg);
7592    xmlXPathReleaseObject(ctxt->context, arg);
7593    CAST_TO_NUMBER;
7594    CHECK_TYPE(XPATH_NUMBER);
7595    arg1 = ctxt->value->floatval;
7596    if (arg2 == 0)
7597	ctxt->value->floatval = xmlXPathNAN;
7598    else {
7599	ctxt->value->floatval = fmod(arg1, arg2);
7600    }
7601}
7602
7603/************************************************************************
7604 *									*
7605 *		The traversal functions					*
7606 *									*
7607 ************************************************************************/
7608
7609/*
7610 * A traversal function enumerates nodes along an axis.
7611 * Initially it must be called with NULL, and it indicates
7612 * termination on the axis by returning NULL.
7613 */
7614typedef xmlNodePtr (*xmlXPathTraversalFunction)
7615                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7616
7617/*
7618 * xmlXPathTraversalFunctionExt:
7619 * A traversal function enumerates nodes along an axis.
7620 * Initially it must be called with NULL, and it indicates
7621 * termination on the axis by returning NULL.
7622 * The context node of the traversal is specified via @contextNode.
7623 */
7624typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7625                    (xmlNodePtr cur, xmlNodePtr contextNode);
7626
7627/*
7628 * xmlXPathNodeSetMergeFunction:
7629 * Used for merging node sets in xmlXPathCollectAndTest().
7630 */
7631typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7632		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
7633
7634
7635/**
7636 * xmlXPathNextSelf:
7637 * @ctxt:  the XPath Parser context
7638 * @cur:  the current node in the traversal
7639 *
7640 * Traversal function for the "self" direction
7641 * The self axis contains just the context node itself
7642 *
7643 * Returns the next element following that axis
7644 */
7645xmlNodePtr
7646xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7647    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7648    if (cur == NULL)
7649        return(ctxt->context->node);
7650    return(NULL);
7651}
7652
7653/**
7654 * xmlXPathNextChild:
7655 * @ctxt:  the XPath Parser context
7656 * @cur:  the current node in the traversal
7657 *
7658 * Traversal function for the "child" direction
7659 * The child axis contains the children of the context node in document order.
7660 *
7661 * Returns the next element following that axis
7662 */
7663xmlNodePtr
7664xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7665    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7666    if (cur == NULL) {
7667	if (ctxt->context->node == NULL) return(NULL);
7668	switch (ctxt->context->node->type) {
7669            case XML_ELEMENT_NODE:
7670            case XML_TEXT_NODE:
7671            case XML_CDATA_SECTION_NODE:
7672            case XML_ENTITY_REF_NODE:
7673            case XML_ENTITY_NODE:
7674            case XML_PI_NODE:
7675            case XML_COMMENT_NODE:
7676            case XML_NOTATION_NODE:
7677            case XML_DTD_NODE:
7678		return(ctxt->context->node->children);
7679            case XML_DOCUMENT_NODE:
7680            case XML_DOCUMENT_TYPE_NODE:
7681            case XML_DOCUMENT_FRAG_NODE:
7682            case XML_HTML_DOCUMENT_NODE:
7683#ifdef LIBXML_DOCB_ENABLED
7684	    case XML_DOCB_DOCUMENT_NODE:
7685#endif
7686		return(((xmlDocPtr) ctxt->context->node)->children);
7687	    case XML_ELEMENT_DECL:
7688	    case XML_ATTRIBUTE_DECL:
7689	    case XML_ENTITY_DECL:
7690            case XML_ATTRIBUTE_NODE:
7691	    case XML_NAMESPACE_DECL:
7692	    case XML_XINCLUDE_START:
7693	    case XML_XINCLUDE_END:
7694		return(NULL);
7695	}
7696	return(NULL);
7697    }
7698    if ((cur->type == XML_DOCUMENT_NODE) ||
7699        (cur->type == XML_HTML_DOCUMENT_NODE))
7700	return(NULL);
7701    return(cur->next);
7702}
7703
7704/**
7705 * xmlXPathNextChildElement:
7706 * @ctxt:  the XPath Parser context
7707 * @cur:  the current node in the traversal
7708 *
7709 * Traversal function for the "child" direction and nodes of type element.
7710 * The child axis contains the children of the context node in document order.
7711 *
7712 * Returns the next element following that axis
7713 */
7714static xmlNodePtr
7715xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7716    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7717    if (cur == NULL) {
7718	cur = ctxt->context->node;
7719	if (cur == NULL) return(NULL);
7720	/*
7721	* Get the first element child.
7722	*/
7723	switch (cur->type) {
7724            case XML_ELEMENT_NODE:
7725	    case XML_DOCUMENT_FRAG_NODE:
7726	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7727            case XML_ENTITY_NODE:
7728		cur = cur->children;
7729		if (cur != NULL) {
7730		    if (cur->type == XML_ELEMENT_NODE)
7731			return(cur);
7732		    do {
7733			cur = cur->next;
7734		    } while ((cur != NULL) &&
7735			(cur->type != XML_ELEMENT_NODE));
7736		    return(cur);
7737		}
7738		return(NULL);
7739            case XML_DOCUMENT_NODE:
7740            case XML_HTML_DOCUMENT_NODE:
7741#ifdef LIBXML_DOCB_ENABLED
7742	    case XML_DOCB_DOCUMENT_NODE:
7743#endif
7744		return(xmlDocGetRootElement((xmlDocPtr) cur));
7745	    default:
7746		return(NULL);
7747	}
7748	return(NULL);
7749    }
7750    /*
7751    * Get the next sibling element node.
7752    */
7753    switch (cur->type) {
7754	case XML_ELEMENT_NODE:
7755	case XML_TEXT_NODE:
7756	case XML_ENTITY_REF_NODE:
7757	case XML_ENTITY_NODE:
7758	case XML_CDATA_SECTION_NODE:
7759	case XML_PI_NODE:
7760	case XML_COMMENT_NODE:
7761	case XML_XINCLUDE_END:
7762	    break;
7763	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7764	default:
7765	    return(NULL);
7766    }
7767    if (cur->next != NULL) {
7768	if (cur->next->type == XML_ELEMENT_NODE)
7769	    return(cur->next);
7770	cur = cur->next;
7771	do {
7772	    cur = cur->next;
7773	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7774	return(cur);
7775    }
7776    return(NULL);
7777}
7778
7779#if 0
7780/**
7781 * xmlXPathNextDescendantOrSelfElemParent:
7782 * @ctxt:  the XPath Parser context
7783 * @cur:  the current node in the traversal
7784 *
7785 * Traversal function for the "descendant-or-self" axis.
7786 * Additionally it returns only nodes which can be parents of
7787 * element nodes.
7788 *
7789 *
7790 * Returns the next element following that axis
7791 */
7792static xmlNodePtr
7793xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7794				       xmlNodePtr contextNode)
7795{
7796    if (cur == NULL) {
7797	if (contextNode == NULL)
7798	    return(NULL);
7799	switch (contextNode->type) {
7800	    case XML_ELEMENT_NODE:
7801	    case XML_XINCLUDE_START:
7802	    case XML_DOCUMENT_FRAG_NODE:
7803	    case XML_DOCUMENT_NODE:
7804#ifdef LIBXML_DOCB_ENABLED
7805	    case XML_DOCB_DOCUMENT_NODE:
7806#endif
7807	    case XML_HTML_DOCUMENT_NODE:
7808		return(contextNode);
7809	    default:
7810		return(NULL);
7811	}
7812	return(NULL);
7813    } else {
7814	xmlNodePtr start = cur;
7815
7816	while (cur != NULL) {
7817	    switch (cur->type) {
7818		case XML_ELEMENT_NODE:
7819		/* TODO: OK to have XInclude here? */
7820		case XML_XINCLUDE_START:
7821		case XML_DOCUMENT_FRAG_NODE:
7822		    if (cur != start)
7823			return(cur);
7824		    if (cur->children != NULL) {
7825			cur = cur->children;
7826			continue;
7827		    }
7828		    break;
7829		/* Not sure if we need those here. */
7830		case XML_DOCUMENT_NODE:
7831#ifdef LIBXML_DOCB_ENABLED
7832		case XML_DOCB_DOCUMENT_NODE:
7833#endif
7834		case XML_HTML_DOCUMENT_NODE:
7835		    if (cur != start)
7836			return(cur);
7837		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7838		default:
7839		    break;
7840	    }
7841
7842next_sibling:
7843	    if ((cur == NULL) || (cur == contextNode))
7844		return(NULL);
7845	    if (cur->next != NULL) {
7846		cur = cur->next;
7847	    } else {
7848		cur = cur->parent;
7849		goto next_sibling;
7850	    }
7851	}
7852    }
7853    return(NULL);
7854}
7855#endif
7856
7857/**
7858 * xmlXPathNextDescendant:
7859 * @ctxt:  the XPath Parser context
7860 * @cur:  the current node in the traversal
7861 *
7862 * Traversal function for the "descendant" direction
7863 * the descendant axis contains the descendants of the context node in document
7864 * order; a descendant is a child or a child of a child and so on.
7865 *
7866 * Returns the next element following that axis
7867 */
7868xmlNodePtr
7869xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7870    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7871    if (cur == NULL) {
7872	if (ctxt->context->node == NULL)
7873	    return(NULL);
7874	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7875	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7876	    return(NULL);
7877
7878        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7879	    return(ctxt->context->doc->children);
7880        return(ctxt->context->node->children);
7881    }
7882
7883    if (cur->type == XML_NAMESPACE_DECL)
7884        return(NULL);
7885    if (cur->children != NULL) {
7886	/*
7887	 * Do not descend on entities declarations
7888	 */
7889	if (cur->children->type != XML_ENTITY_DECL) {
7890	    cur = cur->children;
7891	    /*
7892	     * Skip DTDs
7893	     */
7894	    if (cur->type != XML_DTD_NODE)
7895		return(cur);
7896	}
7897    }
7898
7899    if (cur == ctxt->context->node) return(NULL);
7900
7901    while (cur->next != NULL) {
7902	cur = cur->next;
7903	if ((cur->type != XML_ENTITY_DECL) &&
7904	    (cur->type != XML_DTD_NODE))
7905	    return(cur);
7906    }
7907
7908    do {
7909        cur = cur->parent;
7910	if (cur == NULL) break;
7911	if (cur == ctxt->context->node) return(NULL);
7912	if (cur->next != NULL) {
7913	    cur = cur->next;
7914	    return(cur);
7915	}
7916    } while (cur != NULL);
7917    return(cur);
7918}
7919
7920/**
7921 * xmlXPathNextDescendantOrSelf:
7922 * @ctxt:  the XPath Parser context
7923 * @cur:  the current node in the traversal
7924 *
7925 * Traversal function for the "descendant-or-self" direction
7926 * the descendant-or-self axis contains the context node and the descendants
7927 * of the context node in document order; thus the context node is the first
7928 * node on the axis, and the first child of the context node is the second node
7929 * on the axis
7930 *
7931 * Returns the next element following that axis
7932 */
7933xmlNodePtr
7934xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7935    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7936    if (cur == NULL)
7937        return(ctxt->context->node);
7938
7939    if (ctxt->context->node == NULL)
7940        return(NULL);
7941    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7942        (ctxt->context->node->type == XML_NAMESPACE_DECL))
7943        return(NULL);
7944
7945    return(xmlXPathNextDescendant(ctxt, cur));
7946}
7947
7948/**
7949 * xmlXPathNextParent:
7950 * @ctxt:  the XPath Parser context
7951 * @cur:  the current node in the traversal
7952 *
7953 * Traversal function for the "parent" direction
7954 * The parent axis contains the parent of the context node, if there is one.
7955 *
7956 * Returns the next element following that axis
7957 */
7958xmlNodePtr
7959xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7960    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7961    /*
7962     * the parent of an attribute or namespace node is the element
7963     * to which the attribute or namespace node is attached
7964     * Namespace handling !!!
7965     */
7966    if (cur == NULL) {
7967	if (ctxt->context->node == NULL) return(NULL);
7968	switch (ctxt->context->node->type) {
7969            case XML_ELEMENT_NODE:
7970            case XML_TEXT_NODE:
7971            case XML_CDATA_SECTION_NODE:
7972            case XML_ENTITY_REF_NODE:
7973            case XML_ENTITY_NODE:
7974            case XML_PI_NODE:
7975            case XML_COMMENT_NODE:
7976            case XML_NOTATION_NODE:
7977            case XML_DTD_NODE:
7978	    case XML_ELEMENT_DECL:
7979	    case XML_ATTRIBUTE_DECL:
7980	    case XML_XINCLUDE_START:
7981	    case XML_XINCLUDE_END:
7982	    case XML_ENTITY_DECL:
7983		if (ctxt->context->node->parent == NULL)
7984		    return((xmlNodePtr) ctxt->context->doc);
7985		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7986		    ((ctxt->context->node->parent->name[0] == ' ') ||
7987		     (xmlStrEqual(ctxt->context->node->parent->name,
7988				 BAD_CAST "fake node libxslt"))))
7989		    return(NULL);
7990		return(ctxt->context->node->parent);
7991            case XML_ATTRIBUTE_NODE: {
7992		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7993
7994		return(att->parent);
7995	    }
7996            case XML_DOCUMENT_NODE:
7997            case XML_DOCUMENT_TYPE_NODE:
7998            case XML_DOCUMENT_FRAG_NODE:
7999            case XML_HTML_DOCUMENT_NODE:
8000#ifdef LIBXML_DOCB_ENABLED
8001	    case XML_DOCB_DOCUMENT_NODE:
8002#endif
8003                return(NULL);
8004	    case XML_NAMESPACE_DECL: {
8005		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8006
8007		if ((ns->next != NULL) &&
8008		    (ns->next->type != XML_NAMESPACE_DECL))
8009		    return((xmlNodePtr) ns->next);
8010                return(NULL);
8011	    }
8012	}
8013    }
8014    return(NULL);
8015}
8016
8017/**
8018 * xmlXPathNextAncestor:
8019 * @ctxt:  the XPath Parser context
8020 * @cur:  the current node in the traversal
8021 *
8022 * Traversal function for the "ancestor" direction
8023 * the ancestor axis contains the ancestors of the context node; the ancestors
8024 * of the context node consist of the parent of context node and the parent's
8025 * parent and so on; the nodes are ordered in reverse document order; thus the
8026 * parent is the first node on the axis, and the parent's parent is the second
8027 * node on the axis
8028 *
8029 * Returns the next element following that axis
8030 */
8031xmlNodePtr
8032xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8033    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8034    /*
8035     * the parent of an attribute or namespace node is the element
8036     * to which the attribute or namespace node is attached
8037     * !!!!!!!!!!!!!
8038     */
8039    if (cur == NULL) {
8040	if (ctxt->context->node == NULL) return(NULL);
8041	switch (ctxt->context->node->type) {
8042            case XML_ELEMENT_NODE:
8043            case XML_TEXT_NODE:
8044            case XML_CDATA_SECTION_NODE:
8045            case XML_ENTITY_REF_NODE:
8046            case XML_ENTITY_NODE:
8047            case XML_PI_NODE:
8048            case XML_COMMENT_NODE:
8049	    case XML_DTD_NODE:
8050	    case XML_ELEMENT_DECL:
8051	    case XML_ATTRIBUTE_DECL:
8052	    case XML_ENTITY_DECL:
8053            case XML_NOTATION_NODE:
8054	    case XML_XINCLUDE_START:
8055	    case XML_XINCLUDE_END:
8056		if (ctxt->context->node->parent == NULL)
8057		    return((xmlNodePtr) ctxt->context->doc);
8058		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8059		    ((ctxt->context->node->parent->name[0] == ' ') ||
8060		     (xmlStrEqual(ctxt->context->node->parent->name,
8061				 BAD_CAST "fake node libxslt"))))
8062		    return(NULL);
8063		return(ctxt->context->node->parent);
8064            case XML_ATTRIBUTE_NODE: {
8065		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8066
8067		return(tmp->parent);
8068	    }
8069            case XML_DOCUMENT_NODE:
8070            case XML_DOCUMENT_TYPE_NODE:
8071            case XML_DOCUMENT_FRAG_NODE:
8072            case XML_HTML_DOCUMENT_NODE:
8073#ifdef LIBXML_DOCB_ENABLED
8074	    case XML_DOCB_DOCUMENT_NODE:
8075#endif
8076                return(NULL);
8077	    case XML_NAMESPACE_DECL: {
8078		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8079
8080		if ((ns->next != NULL) &&
8081		    (ns->next->type != XML_NAMESPACE_DECL))
8082		    return((xmlNodePtr) ns->next);
8083		/* Bad, how did that namespace end up here ? */
8084                return(NULL);
8085	    }
8086	}
8087	return(NULL);
8088    }
8089    if (cur == ctxt->context->doc->children)
8090	return((xmlNodePtr) ctxt->context->doc);
8091    if (cur == (xmlNodePtr) ctxt->context->doc)
8092	return(NULL);
8093    switch (cur->type) {
8094	case XML_ELEMENT_NODE:
8095	case XML_TEXT_NODE:
8096	case XML_CDATA_SECTION_NODE:
8097	case XML_ENTITY_REF_NODE:
8098	case XML_ENTITY_NODE:
8099	case XML_PI_NODE:
8100	case XML_COMMENT_NODE:
8101	case XML_NOTATION_NODE:
8102	case XML_DTD_NODE:
8103        case XML_ELEMENT_DECL:
8104        case XML_ATTRIBUTE_DECL:
8105        case XML_ENTITY_DECL:
8106	case XML_XINCLUDE_START:
8107	case XML_XINCLUDE_END:
8108	    if (cur->parent == NULL)
8109		return(NULL);
8110	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
8111		((cur->parent->name[0] == ' ') ||
8112		 (xmlStrEqual(cur->parent->name,
8113			      BAD_CAST "fake node libxslt"))))
8114		return(NULL);
8115	    return(cur->parent);
8116	case XML_ATTRIBUTE_NODE: {
8117	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8118
8119	    return(att->parent);
8120	}
8121	case XML_NAMESPACE_DECL: {
8122	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8123
8124	    if ((ns->next != NULL) &&
8125	        (ns->next->type != XML_NAMESPACE_DECL))
8126	        return((xmlNodePtr) ns->next);
8127	    /* Bad, how did that namespace end up here ? */
8128            return(NULL);
8129	}
8130	case XML_DOCUMENT_NODE:
8131	case XML_DOCUMENT_TYPE_NODE:
8132	case XML_DOCUMENT_FRAG_NODE:
8133	case XML_HTML_DOCUMENT_NODE:
8134#ifdef LIBXML_DOCB_ENABLED
8135	case XML_DOCB_DOCUMENT_NODE:
8136#endif
8137	    return(NULL);
8138    }
8139    return(NULL);
8140}
8141
8142/**
8143 * xmlXPathNextAncestorOrSelf:
8144 * @ctxt:  the XPath Parser context
8145 * @cur:  the current node in the traversal
8146 *
8147 * Traversal function for the "ancestor-or-self" direction
8148 * he ancestor-or-self axis contains the context node and ancestors of
8149 * the context node in reverse document order; thus the context node is
8150 * the first node on the axis, and the context node's parent the second;
8151 * parent here is defined the same as with the parent axis.
8152 *
8153 * Returns the next element following that axis
8154 */
8155xmlNodePtr
8156xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8157    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8158    if (cur == NULL)
8159        return(ctxt->context->node);
8160    return(xmlXPathNextAncestor(ctxt, cur));
8161}
8162
8163/**
8164 * xmlXPathNextFollowingSibling:
8165 * @ctxt:  the XPath Parser context
8166 * @cur:  the current node in the traversal
8167 *
8168 * Traversal function for the "following-sibling" direction
8169 * The following-sibling axis contains the following siblings of the context
8170 * node in document order.
8171 *
8172 * Returns the next element following that axis
8173 */
8174xmlNodePtr
8175xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8176    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8177    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8178	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8179	return(NULL);
8180    if (cur == (xmlNodePtr) ctxt->context->doc)
8181        return(NULL);
8182    if (cur == NULL)
8183        return(ctxt->context->node->next);
8184    return(cur->next);
8185}
8186
8187/**
8188 * xmlXPathNextPrecedingSibling:
8189 * @ctxt:  the XPath Parser context
8190 * @cur:  the current node in the traversal
8191 *
8192 * Traversal function for the "preceding-sibling" direction
8193 * The preceding-sibling axis contains the preceding siblings of the context
8194 * node in reverse document order; the first preceding sibling is first on the
8195 * axis; the sibling preceding that node is the second on the axis and so on.
8196 *
8197 * Returns the next element following that axis
8198 */
8199xmlNodePtr
8200xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8201    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8202    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8203	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8204	return(NULL);
8205    if (cur == (xmlNodePtr) ctxt->context->doc)
8206        return(NULL);
8207    if (cur == NULL)
8208        return(ctxt->context->node->prev);
8209    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8210	cur = cur->prev;
8211	if (cur == NULL)
8212	    return(ctxt->context->node->prev);
8213    }
8214    return(cur->prev);
8215}
8216
8217/**
8218 * xmlXPathNextFollowing:
8219 * @ctxt:  the XPath Parser context
8220 * @cur:  the current node in the traversal
8221 *
8222 * Traversal function for the "following" direction
8223 * The following axis contains all nodes in the same document as the context
8224 * node that are after the context node in document order, excluding any
8225 * descendants and excluding attribute nodes and namespace nodes; the nodes
8226 * are ordered in document order
8227 *
8228 * Returns the next element following that axis
8229 */
8230xmlNodePtr
8231xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8232    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8233    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8234        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8235        return(cur->children);
8236
8237    if (cur == NULL) {
8238        cur = ctxt->context->node;
8239        if (cur->type == XML_NAMESPACE_DECL)
8240            return(NULL);
8241        if (cur->type == XML_ATTRIBUTE_NODE)
8242            cur = cur->parent;
8243    }
8244    if (cur == NULL) return(NULL) ; /* ERROR */
8245    if (cur->next != NULL) return(cur->next) ;
8246    do {
8247        cur = cur->parent;
8248        if (cur == NULL) break;
8249        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8250        if (cur->next != NULL) return(cur->next);
8251    } while (cur != NULL);
8252    return(cur);
8253}
8254
8255/*
8256 * xmlXPathIsAncestor:
8257 * @ancestor:  the ancestor node
8258 * @node:  the current node
8259 *
8260 * Check that @ancestor is a @node's ancestor
8261 *
8262 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8263 */
8264static int
8265xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8266    if ((ancestor == NULL) || (node == NULL)) return(0);
8267    if (node->type == XML_NAMESPACE_DECL)
8268        return(0);
8269    if (ancestor->type == XML_NAMESPACE_DECL)
8270        return(0);
8271    /* nodes need to be in the same document */
8272    if (ancestor->doc != node->doc) return(0);
8273    /* avoid searching if ancestor or node is the root node */
8274    if (ancestor == (xmlNodePtr) node->doc) return(1);
8275    if (node == (xmlNodePtr) ancestor->doc) return(0);
8276    while (node->parent != NULL) {
8277        if (node->parent == ancestor)
8278            return(1);
8279	node = node->parent;
8280    }
8281    return(0);
8282}
8283
8284/**
8285 * xmlXPathNextPreceding:
8286 * @ctxt:  the XPath Parser context
8287 * @cur:  the current node in the traversal
8288 *
8289 * Traversal function for the "preceding" direction
8290 * the preceding axis contains all nodes in the same document as the context
8291 * node that are before the context node in document order, excluding any
8292 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8293 * ordered in reverse document order
8294 *
8295 * Returns the next element following that axis
8296 */
8297xmlNodePtr
8298xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8299{
8300    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8301    if (cur == NULL) {
8302        cur = ctxt->context->node;
8303        if (cur->type == XML_NAMESPACE_DECL)
8304            return(NULL);
8305        if (cur->type == XML_ATTRIBUTE_NODE)
8306            return(cur->parent);
8307    }
8308    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8309	return (NULL);
8310    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8311	cur = cur->prev;
8312    do {
8313        if (cur->prev != NULL) {
8314            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8315            return (cur);
8316        }
8317
8318        cur = cur->parent;
8319        if (cur == NULL)
8320            return (NULL);
8321        if (cur == ctxt->context->doc->children)
8322            return (NULL);
8323    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8324    return (cur);
8325}
8326
8327/**
8328 * xmlXPathNextPrecedingInternal:
8329 * @ctxt:  the XPath Parser context
8330 * @cur:  the current node in the traversal
8331 *
8332 * Traversal function for the "preceding" direction
8333 * the preceding axis contains all nodes in the same document as the context
8334 * node that are before the context node in document order, excluding any
8335 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8336 * ordered in reverse document order
8337 * This is a faster implementation but internal only since it requires a
8338 * state kept in the parser context: ctxt->ancestor.
8339 *
8340 * Returns the next element following that axis
8341 */
8342static xmlNodePtr
8343xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8344                              xmlNodePtr cur)
8345{
8346    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8347    if (cur == NULL) {
8348        cur = ctxt->context->node;
8349        if (cur == NULL)
8350            return (NULL);
8351        if (cur->type == XML_NAMESPACE_DECL)
8352            return (NULL);
8353        ctxt->ancestor = cur->parent;
8354    }
8355    if (cur->type == XML_NAMESPACE_DECL)
8356        return(NULL);
8357    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8358	cur = cur->prev;
8359    while (cur->prev == NULL) {
8360        cur = cur->parent;
8361        if (cur == NULL)
8362            return (NULL);
8363        if (cur == ctxt->context->doc->children)
8364            return (NULL);
8365        if (cur != ctxt->ancestor)
8366            return (cur);
8367        ctxt->ancestor = cur->parent;
8368    }
8369    cur = cur->prev;
8370    while (cur->last != NULL)
8371        cur = cur->last;
8372    return (cur);
8373}
8374
8375/**
8376 * xmlXPathNextNamespace:
8377 * @ctxt:  the XPath Parser context
8378 * @cur:  the current attribute in the traversal
8379 *
8380 * Traversal function for the "namespace" direction
8381 * the namespace axis contains the namespace nodes of the context node;
8382 * the order of nodes on this axis is implementation-defined; the axis will
8383 * be empty unless the context node is an element
8384 *
8385 * We keep the XML namespace node at the end of the list.
8386 *
8387 * Returns the next element following that axis
8388 */
8389xmlNodePtr
8390xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8391    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8392    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8393    if (cur == NULL) {
8394        if (ctxt->context->tmpNsList != NULL)
8395	    xmlFree(ctxt->context->tmpNsList);
8396	ctxt->context->tmpNsList =
8397	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8398	ctxt->context->tmpNsNr = 0;
8399	if (ctxt->context->tmpNsList != NULL) {
8400	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8401		ctxt->context->tmpNsNr++;
8402	    }
8403	}
8404	return((xmlNodePtr) xmlXPathXMLNamespace);
8405    }
8406    if (ctxt->context->tmpNsNr > 0) {
8407	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8408    } else {
8409	if (ctxt->context->tmpNsList != NULL)
8410	    xmlFree(ctxt->context->tmpNsList);
8411	ctxt->context->tmpNsList = NULL;
8412	return(NULL);
8413    }
8414}
8415
8416/**
8417 * xmlXPathNextAttribute:
8418 * @ctxt:  the XPath Parser context
8419 * @cur:  the current attribute in the traversal
8420 *
8421 * Traversal function for the "attribute" direction
8422 * TODO: support DTD inherited default attributes
8423 *
8424 * Returns the next element following that axis
8425 */
8426xmlNodePtr
8427xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8428    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8429    if (ctxt->context->node == NULL)
8430	return(NULL);
8431    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8432	return(NULL);
8433    if (cur == NULL) {
8434        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8435	    return(NULL);
8436        return((xmlNodePtr)ctxt->context->node->properties);
8437    }
8438    return((xmlNodePtr)cur->next);
8439}
8440
8441/************************************************************************
8442 *									*
8443 *		NodeTest Functions					*
8444 *									*
8445 ************************************************************************/
8446
8447#define IS_FUNCTION			200
8448
8449
8450/************************************************************************
8451 *									*
8452 *		Implicit tree core function library			*
8453 *									*
8454 ************************************************************************/
8455
8456/**
8457 * xmlXPathRoot:
8458 * @ctxt:  the XPath Parser context
8459 *
8460 * Initialize the context to the root of the document
8461 */
8462void
8463xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8464    if ((ctxt == NULL) || (ctxt->context == NULL))
8465	return;
8466    ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8467    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8468	ctxt->context->node));
8469}
8470
8471/************************************************************************
8472 *									*
8473 *		The explicit core function library			*
8474 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8475 *									*
8476 ************************************************************************/
8477
8478
8479/**
8480 * xmlXPathLastFunction:
8481 * @ctxt:  the XPath Parser context
8482 * @nargs:  the number of arguments
8483 *
8484 * Implement the last() XPath function
8485 *    number last()
8486 * The last function returns the number of nodes in the context node list.
8487 */
8488void
8489xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8490    CHECK_ARITY(0);
8491    if (ctxt->context->contextSize >= 0) {
8492	valuePush(ctxt,
8493	    xmlXPathCacheNewFloat(ctxt->context,
8494		(double) ctxt->context->contextSize));
8495#ifdef DEBUG_EXPR
8496	xmlGenericError(xmlGenericErrorContext,
8497		"last() : %d\n", ctxt->context->contextSize);
8498#endif
8499    } else {
8500	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8501    }
8502}
8503
8504/**
8505 * xmlXPathPositionFunction:
8506 * @ctxt:  the XPath Parser context
8507 * @nargs:  the number of arguments
8508 *
8509 * Implement the position() XPath function
8510 *    number position()
8511 * The position function returns the position of the context node in the
8512 * context node list. The first position is 1, and so the last position
8513 * will be equal to last().
8514 */
8515void
8516xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8517    CHECK_ARITY(0);
8518    if (ctxt->context->proximityPosition >= 0) {
8519	valuePush(ctxt,
8520	      xmlXPathCacheNewFloat(ctxt->context,
8521		(double) ctxt->context->proximityPosition));
8522#ifdef DEBUG_EXPR
8523	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8524		ctxt->context->proximityPosition);
8525#endif
8526    } else {
8527	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8528    }
8529}
8530
8531/**
8532 * xmlXPathCountFunction:
8533 * @ctxt:  the XPath Parser context
8534 * @nargs:  the number of arguments
8535 *
8536 * Implement the count() XPath function
8537 *    number count(node-set)
8538 */
8539void
8540xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8541    xmlXPathObjectPtr cur;
8542
8543    CHECK_ARITY(1);
8544    if ((ctxt->value == NULL) ||
8545	((ctxt->value->type != XPATH_NODESET) &&
8546	 (ctxt->value->type != XPATH_XSLT_TREE)))
8547	XP_ERROR(XPATH_INVALID_TYPE);
8548    cur = valuePop(ctxt);
8549
8550    if ((cur == NULL) || (cur->nodesetval == NULL))
8551	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8552    else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8553	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8554	    (double) cur->nodesetval->nodeNr));
8555    } else {
8556	if ((cur->nodesetval->nodeNr != 1) ||
8557	    (cur->nodesetval->nodeTab == NULL)) {
8558	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8559	} else {
8560	    xmlNodePtr tmp;
8561	    int i = 0;
8562
8563	    tmp = cur->nodesetval->nodeTab[0];
8564	    if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8565		tmp = tmp->children;
8566		while (tmp != NULL) {
8567		    tmp = tmp->next;
8568		    i++;
8569		}
8570	    }
8571	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8572	}
8573    }
8574    xmlXPathReleaseObject(ctxt->context, cur);
8575}
8576
8577/**
8578 * xmlXPathGetElementsByIds:
8579 * @doc:  the document
8580 * @ids:  a whitespace separated list of IDs
8581 *
8582 * Selects elements by their unique ID.
8583 *
8584 * Returns a node-set of selected elements.
8585 */
8586static xmlNodeSetPtr
8587xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8588    xmlNodeSetPtr ret;
8589    const xmlChar *cur = ids;
8590    xmlChar *ID;
8591    xmlAttrPtr attr;
8592    xmlNodePtr elem = NULL;
8593
8594    if (ids == NULL) return(NULL);
8595
8596    ret = xmlXPathNodeSetCreate(NULL);
8597    if (ret == NULL)
8598        return(ret);
8599
8600    while (IS_BLANK_CH(*cur)) cur++;
8601    while (*cur != 0) {
8602	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8603	    cur++;
8604
8605        ID = xmlStrndup(ids, cur - ids);
8606	if (ID != NULL) {
8607	    /*
8608	     * We used to check the fact that the value passed
8609	     * was an NCName, but this generated much troubles for
8610	     * me and Aleksey Sanin, people blatantly violated that
8611	     * constaint, like Visa3D spec.
8612	     * if (xmlValidateNCName(ID, 1) == 0)
8613	     */
8614	    attr = xmlGetID(doc, ID);
8615	    if (attr != NULL) {
8616		if (attr->type == XML_ATTRIBUTE_NODE)
8617		    elem = attr->parent;
8618		else if (attr->type == XML_ELEMENT_NODE)
8619		    elem = (xmlNodePtr) attr;
8620		else
8621		    elem = NULL;
8622		if (elem != NULL)
8623		    xmlXPathNodeSetAdd(ret, elem);
8624	    }
8625	    xmlFree(ID);
8626	}
8627
8628	while (IS_BLANK_CH(*cur)) cur++;
8629	ids = cur;
8630    }
8631    return(ret);
8632}
8633
8634/**
8635 * xmlXPathIdFunction:
8636 * @ctxt:  the XPath Parser context
8637 * @nargs:  the number of arguments
8638 *
8639 * Implement the id() XPath function
8640 *    node-set id(object)
8641 * The id function selects elements by their unique ID
8642 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8643 * then the result is the union of the result of applying id to the
8644 * string value of each of the nodes in the argument node-set. When the
8645 * argument to id is of any other type, the argument is converted to a
8646 * string as if by a call to the string function; the string is split
8647 * into a whitespace-separated list of tokens (whitespace is any sequence
8648 * of characters matching the production S); the result is a node-set
8649 * containing the elements in the same document as the context node that
8650 * have a unique ID equal to any of the tokens in the list.
8651 */
8652void
8653xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8654    xmlChar *tokens;
8655    xmlNodeSetPtr ret;
8656    xmlXPathObjectPtr obj;
8657
8658    CHECK_ARITY(1);
8659    obj = valuePop(ctxt);
8660    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8661    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8662	xmlNodeSetPtr ns;
8663	int i;
8664
8665	ret = xmlXPathNodeSetCreate(NULL);
8666        /*
8667         * FIXME -- in an out-of-memory condition this will behave badly.
8668         * The solution is not clear -- we already popped an item from
8669         * ctxt, so the object is in a corrupt state.
8670         */
8671
8672	if (obj->nodesetval != NULL) {
8673	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8674		tokens =
8675		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8676		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8677		ret = xmlXPathNodeSetMerge(ret, ns);
8678		xmlXPathFreeNodeSet(ns);
8679		if (tokens != NULL)
8680		    xmlFree(tokens);
8681	    }
8682	}
8683	xmlXPathReleaseObject(ctxt->context, obj);
8684	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8685	return;
8686    }
8687    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8688    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8689    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8690    xmlXPathReleaseObject(ctxt->context, obj);
8691    return;
8692}
8693
8694/**
8695 * xmlXPathLocalNameFunction:
8696 * @ctxt:  the XPath Parser context
8697 * @nargs:  the number of arguments
8698 *
8699 * Implement the local-name() XPath function
8700 *    string local-name(node-set?)
8701 * The local-name function returns a string containing the local part
8702 * of the name of the node in the argument node-set that is first in
8703 * document order. If the node-set is empty or the first node has no
8704 * name, an empty string is returned. If the argument is omitted it
8705 * defaults to the context node.
8706 */
8707void
8708xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8709    xmlXPathObjectPtr cur;
8710
8711    if (ctxt == NULL) return;
8712
8713    if (nargs == 0) {
8714	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8715	    ctxt->context->node));
8716	nargs = 1;
8717    }
8718
8719    CHECK_ARITY(1);
8720    if ((ctxt->value == NULL) ||
8721	((ctxt->value->type != XPATH_NODESET) &&
8722	 (ctxt->value->type != XPATH_XSLT_TREE)))
8723	XP_ERROR(XPATH_INVALID_TYPE);
8724    cur = valuePop(ctxt);
8725
8726    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8727	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8728    } else {
8729	int i = 0; /* Should be first in document order !!!!! */
8730	switch (cur->nodesetval->nodeTab[i]->type) {
8731	case XML_ELEMENT_NODE:
8732	case XML_ATTRIBUTE_NODE:
8733	case XML_PI_NODE:
8734	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8735		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8736	    else
8737		valuePush(ctxt,
8738		      xmlXPathCacheNewString(ctxt->context,
8739			cur->nodesetval->nodeTab[i]->name));
8740	    break;
8741	case XML_NAMESPACE_DECL:
8742	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8743			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8744	    break;
8745	default:
8746	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8747	}
8748    }
8749    xmlXPathReleaseObject(ctxt->context, cur);
8750}
8751
8752/**
8753 * xmlXPathNamespaceURIFunction:
8754 * @ctxt:  the XPath Parser context
8755 * @nargs:  the number of arguments
8756 *
8757 * Implement the namespace-uri() XPath function
8758 *    string namespace-uri(node-set?)
8759 * The namespace-uri function returns a string containing the
8760 * namespace URI of the expanded name of the node in the argument
8761 * node-set that is first in document order. If the node-set is empty,
8762 * the first node has no name, or the expanded name has no namespace
8763 * URI, an empty string is returned. If the argument is omitted it
8764 * defaults to the context node.
8765 */
8766void
8767xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8768    xmlXPathObjectPtr cur;
8769
8770    if (ctxt == NULL) return;
8771
8772    if (nargs == 0) {
8773	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8774	    ctxt->context->node));
8775	nargs = 1;
8776    }
8777    CHECK_ARITY(1);
8778    if ((ctxt->value == NULL) ||
8779	((ctxt->value->type != XPATH_NODESET) &&
8780	 (ctxt->value->type != XPATH_XSLT_TREE)))
8781	XP_ERROR(XPATH_INVALID_TYPE);
8782    cur = valuePop(ctxt);
8783
8784    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8785	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8786    } else {
8787	int i = 0; /* Should be first in document order !!!!! */
8788	switch (cur->nodesetval->nodeTab[i]->type) {
8789	case XML_ELEMENT_NODE:
8790	case XML_ATTRIBUTE_NODE:
8791	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8792		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8793	    else
8794		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8795			  cur->nodesetval->nodeTab[i]->ns->href));
8796	    break;
8797	default:
8798	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8799	}
8800    }
8801    xmlXPathReleaseObject(ctxt->context, cur);
8802}
8803
8804/**
8805 * xmlXPathNameFunction:
8806 * @ctxt:  the XPath Parser context
8807 * @nargs:  the number of arguments
8808 *
8809 * Implement the name() XPath function
8810 *    string name(node-set?)
8811 * The name function returns a string containing a QName representing
8812 * the name of the node in the argument node-set that is first in document
8813 * order. The QName must represent the name with respect to the namespace
8814 * declarations in effect on the node whose name is being represented.
8815 * Typically, this will be the form in which the name occurred in the XML
8816 * source. This need not be the case if there are namespace declarations
8817 * in effect on the node that associate multiple prefixes with the same
8818 * namespace. However, an implementation may include information about
8819 * the original prefix in its representation of nodes; in this case, an
8820 * implementation can ensure that the returned string is always the same
8821 * as the QName used in the XML source. If the argument it omitted it
8822 * defaults to the context node.
8823 * Libxml keep the original prefix so the "real qualified name" used is
8824 * returned.
8825 */
8826static void
8827xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8828{
8829    xmlXPathObjectPtr cur;
8830
8831    if (nargs == 0) {
8832	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8833	    ctxt->context->node));
8834        nargs = 1;
8835    }
8836
8837    CHECK_ARITY(1);
8838    if ((ctxt->value == NULL) ||
8839        ((ctxt->value->type != XPATH_NODESET) &&
8840         (ctxt->value->type != XPATH_XSLT_TREE)))
8841        XP_ERROR(XPATH_INVALID_TYPE);
8842    cur = valuePop(ctxt);
8843
8844    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8845        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8846    } else {
8847        int i = 0;              /* Should be first in document order !!!!! */
8848
8849        switch (cur->nodesetval->nodeTab[i]->type) {
8850            case XML_ELEMENT_NODE:
8851            case XML_ATTRIBUTE_NODE:
8852		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8853		    valuePush(ctxt,
8854			xmlXPathCacheNewCString(ctxt->context, ""));
8855		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8856                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8857		    valuePush(ctxt,
8858		        xmlXPathCacheNewString(ctxt->context,
8859			    cur->nodesetval->nodeTab[i]->name));
8860		} else {
8861		    xmlChar *fullname;
8862
8863		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8864				     cur->nodesetval->nodeTab[i]->ns->prefix,
8865				     NULL, 0);
8866		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8867			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8868		    if (fullname == NULL) {
8869			XP_ERROR(XPATH_MEMORY_ERROR);
8870		    }
8871		    valuePush(ctxt, xmlXPathCacheWrapString(
8872			ctxt->context, fullname));
8873                }
8874                break;
8875            default:
8876		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8877		    cur->nodesetval->nodeTab[i]));
8878                xmlXPathLocalNameFunction(ctxt, 1);
8879        }
8880    }
8881    xmlXPathReleaseObject(ctxt->context, cur);
8882}
8883
8884
8885/**
8886 * xmlXPathStringFunction:
8887 * @ctxt:  the XPath Parser context
8888 * @nargs:  the number of arguments
8889 *
8890 * Implement the string() XPath function
8891 *    string string(object?)
8892 * The string function converts an object to a string as follows:
8893 *    - A node-set is converted to a string by returning the value of
8894 *      the node in the node-set that is first in document order.
8895 *      If the node-set is empty, an empty string is returned.
8896 *    - A number is converted to a string as follows
8897 *      + NaN is converted to the string NaN
8898 *      + positive zero is converted to the string 0
8899 *      + negative zero is converted to the string 0
8900 *      + positive infinity is converted to the string Infinity
8901 *      + negative infinity is converted to the string -Infinity
8902 *      + if the number is an integer, the number is represented in
8903 *        decimal form as a Number with no decimal point and no leading
8904 *        zeros, preceded by a minus sign (-) if the number is negative
8905 *      + otherwise, the number is represented in decimal form as a
8906 *        Number including a decimal point with at least one digit
8907 *        before the decimal point and at least one digit after the
8908 *        decimal point, preceded by a minus sign (-) if the number
8909 *        is negative; there must be no leading zeros before the decimal
8910 *        point apart possibly from the one required digit immediately
8911 *        before the decimal point; beyond the one required digit
8912 *        after the decimal point there must be as many, but only as
8913 *        many, more digits as are needed to uniquely distinguish the
8914 *        number from all other IEEE 754 numeric values.
8915 *    - The boolean false value is converted to the string false.
8916 *      The boolean true value is converted to the string true.
8917 *
8918 * If the argument is omitted, it defaults to a node-set with the
8919 * context node as its only member.
8920 */
8921void
8922xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8923    xmlXPathObjectPtr cur;
8924
8925    if (ctxt == NULL) return;
8926    if (nargs == 0) {
8927    valuePush(ctxt,
8928	xmlXPathCacheWrapString(ctxt->context,
8929	    xmlXPathCastNodeToString(ctxt->context->node)));
8930	return;
8931    }
8932
8933    CHECK_ARITY(1);
8934    cur = valuePop(ctxt);
8935    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8936    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8937}
8938
8939/**
8940 * xmlXPathStringLengthFunction:
8941 * @ctxt:  the XPath Parser context
8942 * @nargs:  the number of arguments
8943 *
8944 * Implement the string-length() XPath function
8945 *    number string-length(string?)
8946 * The string-length returns the number of characters in the string
8947 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8948 * the context node converted to a string, in other words the value
8949 * of the context node.
8950 */
8951void
8952xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8953    xmlXPathObjectPtr cur;
8954
8955    if (nargs == 0) {
8956        if ((ctxt == NULL) || (ctxt->context == NULL))
8957	    return;
8958	if (ctxt->context->node == NULL) {
8959	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8960	} else {
8961	    xmlChar *content;
8962
8963	    content = xmlXPathCastNodeToString(ctxt->context->node);
8964	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8965		xmlUTF8Strlen(content)));
8966	    xmlFree(content);
8967	}
8968	return;
8969    }
8970    CHECK_ARITY(1);
8971    CAST_TO_STRING;
8972    CHECK_TYPE(XPATH_STRING);
8973    cur = valuePop(ctxt);
8974    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8975	xmlUTF8Strlen(cur->stringval)));
8976    xmlXPathReleaseObject(ctxt->context, cur);
8977}
8978
8979/**
8980 * xmlXPathConcatFunction:
8981 * @ctxt:  the XPath Parser context
8982 * @nargs:  the number of arguments
8983 *
8984 * Implement the concat() XPath function
8985 *    string concat(string, string, string*)
8986 * The concat function returns the concatenation of its arguments.
8987 */
8988void
8989xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8990    xmlXPathObjectPtr cur, newobj;
8991    xmlChar *tmp;
8992
8993    if (ctxt == NULL) return;
8994    if (nargs < 2) {
8995	CHECK_ARITY(2);
8996    }
8997
8998    CAST_TO_STRING;
8999    cur = valuePop(ctxt);
9000    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
9001	xmlXPathReleaseObject(ctxt->context, cur);
9002	return;
9003    }
9004    nargs--;
9005
9006    while (nargs > 0) {
9007	CAST_TO_STRING;
9008	newobj = valuePop(ctxt);
9009	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9010	    xmlXPathReleaseObject(ctxt->context, newobj);
9011	    xmlXPathReleaseObject(ctxt->context, cur);
9012	    XP_ERROR(XPATH_INVALID_TYPE);
9013	}
9014	tmp = xmlStrcat(newobj->stringval, cur->stringval);
9015	newobj->stringval = cur->stringval;
9016	cur->stringval = tmp;
9017	xmlXPathReleaseObject(ctxt->context, newobj);
9018	nargs--;
9019    }
9020    valuePush(ctxt, cur);
9021}
9022
9023/**
9024 * xmlXPathContainsFunction:
9025 * @ctxt:  the XPath Parser context
9026 * @nargs:  the number of arguments
9027 *
9028 * Implement the contains() XPath function
9029 *    boolean contains(string, string)
9030 * The contains function returns true if the first argument string
9031 * contains the second argument string, and otherwise returns false.
9032 */
9033void
9034xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9035    xmlXPathObjectPtr hay, needle;
9036
9037    CHECK_ARITY(2);
9038    CAST_TO_STRING;
9039    CHECK_TYPE(XPATH_STRING);
9040    needle = valuePop(ctxt);
9041    CAST_TO_STRING;
9042    hay = valuePop(ctxt);
9043
9044    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9045	xmlXPathReleaseObject(ctxt->context, hay);
9046	xmlXPathReleaseObject(ctxt->context, needle);
9047	XP_ERROR(XPATH_INVALID_TYPE);
9048    }
9049    if (xmlStrstr(hay->stringval, needle->stringval))
9050	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9051    else
9052	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9053    xmlXPathReleaseObject(ctxt->context, hay);
9054    xmlXPathReleaseObject(ctxt->context, needle);
9055}
9056
9057/**
9058 * xmlXPathStartsWithFunction:
9059 * @ctxt:  the XPath Parser context
9060 * @nargs:  the number of arguments
9061 *
9062 * Implement the starts-with() XPath function
9063 *    boolean starts-with(string, string)
9064 * The starts-with function returns true if the first argument string
9065 * starts with the second argument string, and otherwise returns false.
9066 */
9067void
9068xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9069    xmlXPathObjectPtr hay, needle;
9070    int n;
9071
9072    CHECK_ARITY(2);
9073    CAST_TO_STRING;
9074    CHECK_TYPE(XPATH_STRING);
9075    needle = valuePop(ctxt);
9076    CAST_TO_STRING;
9077    hay = valuePop(ctxt);
9078
9079    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9080	xmlXPathReleaseObject(ctxt->context, hay);
9081	xmlXPathReleaseObject(ctxt->context, needle);
9082	XP_ERROR(XPATH_INVALID_TYPE);
9083    }
9084    n = xmlStrlen(needle->stringval);
9085    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9086        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9087    else
9088        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9089    xmlXPathReleaseObject(ctxt->context, hay);
9090    xmlXPathReleaseObject(ctxt->context, needle);
9091}
9092
9093/**
9094 * xmlXPathSubstringFunction:
9095 * @ctxt:  the XPath Parser context
9096 * @nargs:  the number of arguments
9097 *
9098 * Implement the substring() XPath function
9099 *    string substring(string, number, number?)
9100 * The substring function returns the substring of the first argument
9101 * starting at the position specified in the second argument with
9102 * length specified in the third argument. For example,
9103 * substring("12345",2,3) returns "234". If the third argument is not
9104 * specified, it returns the substring starting at the position specified
9105 * in the second argument and continuing to the end of the string. For
9106 * example, substring("12345",2) returns "2345".  More precisely, each
9107 * character in the string (see [3.6 Strings]) is considered to have a
9108 * numeric position: the position of the first character is 1, the position
9109 * of the second character is 2 and so on. The returned substring contains
9110 * those characters for which the position of the character is greater than
9111 * or equal to the second argument and, if the third argument is specified,
9112 * less than the sum of the second and third arguments; the comparisons
9113 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9114 *  - substring("12345", 1.5, 2.6) returns "234"
9115 *  - substring("12345", 0, 3) returns "12"
9116 *  - substring("12345", 0 div 0, 3) returns ""
9117 *  - substring("12345", 1, 0 div 0) returns ""
9118 *  - substring("12345", -42, 1 div 0) returns "12345"
9119 *  - substring("12345", -1 div 0, 1 div 0) returns ""
9120 */
9121void
9122xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9123    xmlXPathObjectPtr str, start, len;
9124    double le=0, in;
9125    int i, l, m;
9126    xmlChar *ret;
9127
9128    if (nargs < 2) {
9129	CHECK_ARITY(2);
9130    }
9131    if (nargs > 3) {
9132	CHECK_ARITY(3);
9133    }
9134    /*
9135     * take care of possible last (position) argument
9136    */
9137    if (nargs == 3) {
9138	CAST_TO_NUMBER;
9139	CHECK_TYPE(XPATH_NUMBER);
9140	len = valuePop(ctxt);
9141	le = len->floatval;
9142	xmlXPathReleaseObject(ctxt->context, len);
9143    }
9144
9145    CAST_TO_NUMBER;
9146    CHECK_TYPE(XPATH_NUMBER);
9147    start = valuePop(ctxt);
9148    in = start->floatval;
9149    xmlXPathReleaseObject(ctxt->context, start);
9150    CAST_TO_STRING;
9151    CHECK_TYPE(XPATH_STRING);
9152    str = valuePop(ctxt);
9153    m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9154
9155    /*
9156     * If last pos not present, calculate last position
9157    */
9158    if (nargs != 3) {
9159	le = (double)m;
9160	if (in < 1.0)
9161	    in = 1.0;
9162    }
9163
9164    /* Need to check for the special cases where either
9165     * the index is NaN, the length is NaN, or both
9166     * arguments are infinity (relying on Inf + -Inf = NaN)
9167     */
9168    if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9169        /*
9170         * To meet the requirements of the spec, the arguments
9171	 * must be converted to integer format before
9172	 * initial index calculations are done
9173         *
9174         * First we go to integer form, rounding up
9175	 * and checking for special cases
9176         */
9177        i = (int) in;
9178        if (((double)i)+0.5 <= in) i++;
9179
9180	if (xmlXPathIsInf(le) == 1) {
9181	    l = m;
9182	    if (i < 1)
9183		i = 1;
9184	}
9185	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9186	    l = 0;
9187	else {
9188	    l = (int) le;
9189	    if (((double)l)+0.5 <= le) l++;
9190	}
9191
9192	/* Now we normalize inidices */
9193        i -= 1;
9194        l += i;
9195        if (i < 0)
9196            i = 0;
9197        if (l > m)
9198            l = m;
9199
9200        /* number of chars to copy */
9201        l -= i;
9202
9203        ret = xmlUTF8Strsub(str->stringval, i, l);
9204    }
9205    else {
9206        ret = NULL;
9207    }
9208    if (ret == NULL)
9209	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9210    else {
9211	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9212	xmlFree(ret);
9213    }
9214    xmlXPathReleaseObject(ctxt->context, str);
9215}
9216
9217/**
9218 * xmlXPathSubstringBeforeFunction:
9219 * @ctxt:  the XPath Parser context
9220 * @nargs:  the number of arguments
9221 *
9222 * Implement the substring-before() XPath function
9223 *    string substring-before(string, string)
9224 * The substring-before function returns the substring of the first
9225 * argument string that precedes the first occurrence of the second
9226 * argument string in the first argument string, or the empty string
9227 * if the first argument string does not contain the second argument
9228 * string. For example, substring-before("1999/04/01","/") returns 1999.
9229 */
9230void
9231xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9232  xmlXPathObjectPtr str;
9233  xmlXPathObjectPtr find;
9234  xmlBufPtr target;
9235  const xmlChar *point;
9236  int offset;
9237
9238  CHECK_ARITY(2);
9239  CAST_TO_STRING;
9240  find = valuePop(ctxt);
9241  CAST_TO_STRING;
9242  str = valuePop(ctxt);
9243
9244  target = xmlBufCreate();
9245  if (target) {
9246    point = xmlStrstr(str->stringval, find->stringval);
9247    if (point) {
9248      offset = (int)(point - str->stringval);
9249      xmlBufAdd(target, str->stringval, offset);
9250    }
9251    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9252	xmlBufContent(target)));
9253    xmlBufFree(target);
9254  }
9255  xmlXPathReleaseObject(ctxt->context, str);
9256  xmlXPathReleaseObject(ctxt->context, find);
9257}
9258
9259/**
9260 * xmlXPathSubstringAfterFunction:
9261 * @ctxt:  the XPath Parser context
9262 * @nargs:  the number of arguments
9263 *
9264 * Implement the substring-after() XPath function
9265 *    string substring-after(string, string)
9266 * The substring-after function returns the substring of the first
9267 * argument string that follows the first occurrence of the second
9268 * argument string in the first argument string, or the empty stringi
9269 * if the first argument string does not contain the second argument
9270 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9271 * and substring-after("1999/04/01","19") returns 99/04/01.
9272 */
9273void
9274xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9275  xmlXPathObjectPtr str;
9276  xmlXPathObjectPtr find;
9277  xmlBufPtr target;
9278  const xmlChar *point;
9279  int offset;
9280
9281  CHECK_ARITY(2);
9282  CAST_TO_STRING;
9283  find = valuePop(ctxt);
9284  CAST_TO_STRING;
9285  str = valuePop(ctxt);
9286
9287  target = xmlBufCreate();
9288  if (target) {
9289    point = xmlStrstr(str->stringval, find->stringval);
9290    if (point) {
9291      offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9292      xmlBufAdd(target, &str->stringval[offset],
9293		   xmlStrlen(str->stringval) - offset);
9294    }
9295    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9296	xmlBufContent(target)));
9297    xmlBufFree(target);
9298  }
9299  xmlXPathReleaseObject(ctxt->context, str);
9300  xmlXPathReleaseObject(ctxt->context, find);
9301}
9302
9303/**
9304 * xmlXPathNormalizeFunction:
9305 * @ctxt:  the XPath Parser context
9306 * @nargs:  the number of arguments
9307 *
9308 * Implement the normalize-space() XPath function
9309 *    string normalize-space(string?)
9310 * The normalize-space function returns the argument string with white
9311 * space normalized by stripping leading and trailing whitespace
9312 * and replacing sequences of whitespace characters by a single
9313 * space. Whitespace characters are the same allowed by the S production
9314 * in XML. If the argument is omitted, it defaults to the context
9315 * node converted to a string, in other words the value of the context node.
9316 */
9317void
9318xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9319  xmlXPathObjectPtr obj = NULL;
9320  xmlChar *source = NULL;
9321  xmlBufPtr target;
9322  xmlChar blank;
9323
9324  if (ctxt == NULL) return;
9325  if (nargs == 0) {
9326    /* Use current context node */
9327      valuePush(ctxt,
9328	  xmlXPathCacheWrapString(ctxt->context,
9329	    xmlXPathCastNodeToString(ctxt->context->node)));
9330    nargs = 1;
9331  }
9332
9333  CHECK_ARITY(1);
9334  CAST_TO_STRING;
9335  CHECK_TYPE(XPATH_STRING);
9336  obj = valuePop(ctxt);
9337  source = obj->stringval;
9338
9339  target = xmlBufCreate();
9340  if (target && source) {
9341
9342    /* Skip leading whitespaces */
9343    while (IS_BLANK_CH(*source))
9344      source++;
9345
9346    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9347    blank = 0;
9348    while (*source) {
9349      if (IS_BLANK_CH(*source)) {
9350	blank = 0x20;
9351      } else {
9352	if (blank) {
9353	  xmlBufAdd(target, &blank, 1);
9354	  blank = 0;
9355	}
9356	xmlBufAdd(target, source, 1);
9357      }
9358      source++;
9359    }
9360    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9361	xmlBufContent(target)));
9362    xmlBufFree(target);
9363  }
9364  xmlXPathReleaseObject(ctxt->context, obj);
9365}
9366
9367/**
9368 * xmlXPathTranslateFunction:
9369 * @ctxt:  the XPath Parser context
9370 * @nargs:  the number of arguments
9371 *
9372 * Implement the translate() XPath function
9373 *    string translate(string, string, string)
9374 * The translate function returns the first argument string with
9375 * occurrences of characters in the second argument string replaced
9376 * by the character at the corresponding position in the third argument
9377 * string. For example, translate("bar","abc","ABC") returns the string
9378 * BAr. If there is a character in the second argument string with no
9379 * character at a corresponding position in the third argument string
9380 * (because the second argument string is longer than the third argument
9381 * string), then occurrences of that character in the first argument
9382 * string are removed. For example, translate("--aaa--","abc-","ABC")
9383 * returns "AAA". If a character occurs more than once in second
9384 * argument string, then the first occurrence determines the replacement
9385 * character. If the third argument string is longer than the second
9386 * argument string, then excess characters are ignored.
9387 */
9388void
9389xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9390    xmlXPathObjectPtr str;
9391    xmlXPathObjectPtr from;
9392    xmlXPathObjectPtr to;
9393    xmlBufPtr target;
9394    int offset, max;
9395    xmlChar ch;
9396    const xmlChar *point;
9397    xmlChar *cptr;
9398
9399    CHECK_ARITY(3);
9400
9401    CAST_TO_STRING;
9402    to = valuePop(ctxt);
9403    CAST_TO_STRING;
9404    from = valuePop(ctxt);
9405    CAST_TO_STRING;
9406    str = valuePop(ctxt);
9407
9408    target = xmlBufCreate();
9409    if (target) {
9410	max = xmlUTF8Strlen(to->stringval);
9411	for (cptr = str->stringval; (ch=*cptr); ) {
9412	    offset = xmlUTF8Strloc(from->stringval, cptr);
9413	    if (offset >= 0) {
9414		if (offset < max) {
9415		    point = xmlUTF8Strpos(to->stringval, offset);
9416		    if (point)
9417			xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9418		}
9419	    } else
9420		xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9421
9422	    /* Step to next character in input */
9423	    cptr++;
9424	    if ( ch & 0x80 ) {
9425		/* if not simple ascii, verify proper format */
9426		if ( (ch & 0xc0) != 0xc0 ) {
9427		    xmlGenericError(xmlGenericErrorContext,
9428			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
9429                    /* not asserting an XPath error is probably better */
9430		    break;
9431		}
9432		/* then skip over remaining bytes for this char */
9433		while ( (ch <<= 1) & 0x80 )
9434		    if ( (*cptr++ & 0xc0) != 0x80 ) {
9435			xmlGenericError(xmlGenericErrorContext,
9436			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9437                        /* not asserting an XPath error is probably better */
9438			break;
9439		    }
9440		if (ch & 0x80) /* must have had error encountered */
9441		    break;
9442	    }
9443	}
9444    }
9445    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9446	xmlBufContent(target)));
9447    xmlBufFree(target);
9448    xmlXPathReleaseObject(ctxt->context, str);
9449    xmlXPathReleaseObject(ctxt->context, from);
9450    xmlXPathReleaseObject(ctxt->context, to);
9451}
9452
9453/**
9454 * xmlXPathBooleanFunction:
9455 * @ctxt:  the XPath Parser context
9456 * @nargs:  the number of arguments
9457 *
9458 * Implement the boolean() XPath function
9459 *    boolean boolean(object)
9460 * The boolean function converts its argument to a boolean as follows:
9461 *    - a number is true if and only if it is neither positive or
9462 *      negative zero nor NaN
9463 *    - a node-set is true if and only if it is non-empty
9464 *    - a string is true if and only if its length is non-zero
9465 */
9466void
9467xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9468    xmlXPathObjectPtr cur;
9469
9470    CHECK_ARITY(1);
9471    cur = valuePop(ctxt);
9472    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9473    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9474    valuePush(ctxt, cur);
9475}
9476
9477/**
9478 * xmlXPathNotFunction:
9479 * @ctxt:  the XPath Parser context
9480 * @nargs:  the number of arguments
9481 *
9482 * Implement the not() XPath function
9483 *    boolean not(boolean)
9484 * The not function returns true if its argument is false,
9485 * and false otherwise.
9486 */
9487void
9488xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9489    CHECK_ARITY(1);
9490    CAST_TO_BOOLEAN;
9491    CHECK_TYPE(XPATH_BOOLEAN);
9492    ctxt->value->boolval = ! ctxt->value->boolval;
9493}
9494
9495/**
9496 * xmlXPathTrueFunction:
9497 * @ctxt:  the XPath Parser context
9498 * @nargs:  the number of arguments
9499 *
9500 * Implement the true() XPath function
9501 *    boolean true()
9502 */
9503void
9504xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9505    CHECK_ARITY(0);
9506    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9507}
9508
9509/**
9510 * xmlXPathFalseFunction:
9511 * @ctxt:  the XPath Parser context
9512 * @nargs:  the number of arguments
9513 *
9514 * Implement the false() XPath function
9515 *    boolean false()
9516 */
9517void
9518xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9519    CHECK_ARITY(0);
9520    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9521}
9522
9523/**
9524 * xmlXPathLangFunction:
9525 * @ctxt:  the XPath Parser context
9526 * @nargs:  the number of arguments
9527 *
9528 * Implement the lang() XPath function
9529 *    boolean lang(string)
9530 * The lang function returns true or false depending on whether the
9531 * language of the context node as specified by xml:lang attributes
9532 * is the same as or is a sublanguage of the language specified by
9533 * the argument string. The language of the context node is determined
9534 * by the value of the xml:lang attribute on the context node, or, if
9535 * the context node has no xml:lang attribute, by the value of the
9536 * xml:lang attribute on the nearest ancestor of the context node that
9537 * has an xml:lang attribute. If there is no such attribute, then lang
9538 * returns false. If there is such an attribute, then lang returns
9539 * true if the attribute value is equal to the argument ignoring case,
9540 * or if there is some suffix starting with - such that the attribute
9541 * value is equal to the argument ignoring that suffix of the attribute
9542 * value and ignoring case.
9543 */
9544void
9545xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9546    xmlXPathObjectPtr val = NULL;
9547    const xmlChar *theLang = NULL;
9548    const xmlChar *lang;
9549    int ret = 0;
9550    int i;
9551
9552    CHECK_ARITY(1);
9553    CAST_TO_STRING;
9554    CHECK_TYPE(XPATH_STRING);
9555    val = valuePop(ctxt);
9556    lang = val->stringval;
9557    theLang = xmlNodeGetLang(ctxt->context->node);
9558    if ((theLang != NULL) && (lang != NULL)) {
9559        for (i = 0;lang[i] != 0;i++)
9560	    if (toupper(lang[i]) != toupper(theLang[i]))
9561	        goto not_equal;
9562	if ((theLang[i] == 0) || (theLang[i] == '-'))
9563	    ret = 1;
9564    }
9565not_equal:
9566    if (theLang != NULL)
9567	xmlFree((void *)theLang);
9568
9569    xmlXPathReleaseObject(ctxt->context, val);
9570    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9571}
9572
9573/**
9574 * xmlXPathNumberFunction:
9575 * @ctxt:  the XPath Parser context
9576 * @nargs:  the number of arguments
9577 *
9578 * Implement the number() XPath function
9579 *    number number(object?)
9580 */
9581void
9582xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9583    xmlXPathObjectPtr cur;
9584    double res;
9585
9586    if (ctxt == NULL) return;
9587    if (nargs == 0) {
9588	if (ctxt->context->node == NULL) {
9589	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9590	} else {
9591	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9592
9593	    res = xmlXPathStringEvalNumber(content);
9594	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9595	    xmlFree(content);
9596	}
9597	return;
9598    }
9599
9600    CHECK_ARITY(1);
9601    cur = valuePop(ctxt);
9602    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9603}
9604
9605/**
9606 * xmlXPathSumFunction:
9607 * @ctxt:  the XPath Parser context
9608 * @nargs:  the number of arguments
9609 *
9610 * Implement the sum() XPath function
9611 *    number sum(node-set)
9612 * The sum function returns the sum of the values of the nodes in
9613 * the argument node-set.
9614 */
9615void
9616xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9617    xmlXPathObjectPtr cur;
9618    int i;
9619    double res = 0.0;
9620
9621    CHECK_ARITY(1);
9622    if ((ctxt->value == NULL) ||
9623	((ctxt->value->type != XPATH_NODESET) &&
9624	 (ctxt->value->type != XPATH_XSLT_TREE)))
9625	XP_ERROR(XPATH_INVALID_TYPE);
9626    cur = valuePop(ctxt);
9627
9628    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9629	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9630	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9631	}
9632    }
9633    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9634    xmlXPathReleaseObject(ctxt->context, cur);
9635}
9636
9637/*
9638 * To assure working code on multiple platforms, we want to only depend
9639 * upon the characteristic truncation of converting a floating point value
9640 * to an integer.  Unfortunately, because of the different storage sizes
9641 * of our internal floating point value (double) and integer (int), we
9642 * can't directly convert (see bug 301162).  This macro is a messy
9643 * 'workaround'
9644 */
9645#define XTRUNC(f, v)            \
9646    f = fmod((v), INT_MAX);     \
9647    f = (v) - (f) + (double)((int)(f));
9648
9649/**
9650 * xmlXPathFloorFunction:
9651 * @ctxt:  the XPath Parser context
9652 * @nargs:  the number of arguments
9653 *
9654 * Implement the floor() XPath function
9655 *    number floor(number)
9656 * The floor function returns the largest (closest to positive infinity)
9657 * number that is not greater than the argument and that is an integer.
9658 */
9659void
9660xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9661    double f;
9662
9663    CHECK_ARITY(1);
9664    CAST_TO_NUMBER;
9665    CHECK_TYPE(XPATH_NUMBER);
9666
9667    XTRUNC(f, ctxt->value->floatval);
9668    if (f != ctxt->value->floatval) {
9669	if (ctxt->value->floatval > 0)
9670	    ctxt->value->floatval = f;
9671	else
9672	    ctxt->value->floatval = f - 1;
9673    }
9674}
9675
9676/**
9677 * xmlXPathCeilingFunction:
9678 * @ctxt:  the XPath Parser context
9679 * @nargs:  the number of arguments
9680 *
9681 * Implement the ceiling() XPath function
9682 *    number ceiling(number)
9683 * The ceiling function returns the smallest (closest to negative infinity)
9684 * number that is not less than the argument and that is an integer.
9685 */
9686void
9687xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9688    double f;
9689
9690    CHECK_ARITY(1);
9691    CAST_TO_NUMBER;
9692    CHECK_TYPE(XPATH_NUMBER);
9693
9694#if 0
9695    ctxt->value->floatval = ceil(ctxt->value->floatval);
9696#else
9697    XTRUNC(f, ctxt->value->floatval);
9698    if (f != ctxt->value->floatval) {
9699	if (ctxt->value->floatval > 0)
9700	    ctxt->value->floatval = f + 1;
9701	else {
9702	    if (ctxt->value->floatval < 0 && f == 0)
9703	        ctxt->value->floatval = xmlXPathNZERO;
9704	    else
9705	        ctxt->value->floatval = f;
9706	}
9707
9708    }
9709#endif
9710}
9711
9712/**
9713 * xmlXPathRoundFunction:
9714 * @ctxt:  the XPath Parser context
9715 * @nargs:  the number of arguments
9716 *
9717 * Implement the round() XPath function
9718 *    number round(number)
9719 * The round function returns the number that is closest to the
9720 * argument and that is an integer. If there are two such numbers,
9721 * then the one that is even is returned.
9722 */
9723void
9724xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9725    double f;
9726
9727    CHECK_ARITY(1);
9728    CAST_TO_NUMBER;
9729    CHECK_TYPE(XPATH_NUMBER);
9730
9731    if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9732	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9733	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9734	(ctxt->value->floatval == 0.0))
9735	return;
9736
9737    XTRUNC(f, ctxt->value->floatval);
9738    if (ctxt->value->floatval < 0) {
9739	if (ctxt->value->floatval < f - 0.5)
9740	    ctxt->value->floatval = f - 1;
9741	else
9742	    ctxt->value->floatval = f;
9743	if (ctxt->value->floatval == 0)
9744	    ctxt->value->floatval = xmlXPathNZERO;
9745    } else {
9746	if (ctxt->value->floatval < f + 0.5)
9747	    ctxt->value->floatval = f;
9748	else
9749	    ctxt->value->floatval = f + 1;
9750    }
9751}
9752
9753/************************************************************************
9754 *									*
9755 *			The Parser					*
9756 *									*
9757 ************************************************************************/
9758
9759/*
9760 * a few forward declarations since we use a recursive call based
9761 * implementation.
9762 */
9763static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9764static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9765static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9766static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9767static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9768	                                  int qualified);
9769
9770/**
9771 * xmlXPathCurrentChar:
9772 * @ctxt:  the XPath parser context
9773 * @cur:  pointer to the beginning of the char
9774 * @len:  pointer to the length of the char read
9775 *
9776 * The current char value, if using UTF-8 this may actually span multiple
9777 * bytes in the input buffer.
9778 *
9779 * Returns the current char value and its length
9780 */
9781
9782static int
9783xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9784    unsigned char c;
9785    unsigned int val;
9786    const xmlChar *cur;
9787
9788    if (ctxt == NULL)
9789	return(0);
9790    cur = ctxt->cur;
9791
9792    /*
9793     * We are supposed to handle UTF8, check it's valid
9794     * From rfc2044: encoding of the Unicode values on UTF-8:
9795     *
9796     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9797     * 0000 0000-0000 007F   0xxxxxxx
9798     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9799     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9800     *
9801     * Check for the 0x110000 limit too
9802     */
9803    c = *cur;
9804    if (c & 0x80) {
9805	if ((cur[1] & 0xc0) != 0x80)
9806	    goto encoding_error;
9807	if ((c & 0xe0) == 0xe0) {
9808
9809	    if ((cur[2] & 0xc0) != 0x80)
9810		goto encoding_error;
9811	    if ((c & 0xf0) == 0xf0) {
9812		if (((c & 0xf8) != 0xf0) ||
9813		    ((cur[3] & 0xc0) != 0x80))
9814		    goto encoding_error;
9815		/* 4-byte code */
9816		*len = 4;
9817		val = (cur[0] & 0x7) << 18;
9818		val |= (cur[1] & 0x3f) << 12;
9819		val |= (cur[2] & 0x3f) << 6;
9820		val |= cur[3] & 0x3f;
9821	    } else {
9822	      /* 3-byte code */
9823		*len = 3;
9824		val = (cur[0] & 0xf) << 12;
9825		val |= (cur[1] & 0x3f) << 6;
9826		val |= cur[2] & 0x3f;
9827	    }
9828	} else {
9829	  /* 2-byte code */
9830	    *len = 2;
9831	    val = (cur[0] & 0x1f) << 6;
9832	    val |= cur[1] & 0x3f;
9833	}
9834	if (!IS_CHAR(val)) {
9835	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9836	}
9837	return(val);
9838    } else {
9839	/* 1-byte code */
9840	*len = 1;
9841	return((int) *cur);
9842    }
9843encoding_error:
9844    /*
9845     * If we detect an UTF8 error that probably means that the
9846     * input encoding didn't get properly advertised in the
9847     * declaration header. Report the error and switch the encoding
9848     * to ISO-Latin-1 (if you don't like this policy, just declare the
9849     * encoding !)
9850     */
9851    *len = 0;
9852    XP_ERROR0(XPATH_ENCODING_ERROR);
9853}
9854
9855/**
9856 * xmlXPathParseNCName:
9857 * @ctxt:  the XPath Parser context
9858 *
9859 * parse an XML namespace non qualified name.
9860 *
9861 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9862 *
9863 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9864 *                       CombiningChar | Extender
9865 *
9866 * Returns the namespace name or NULL
9867 */
9868
9869xmlChar *
9870xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9871    const xmlChar *in;
9872    xmlChar *ret;
9873    int count = 0;
9874
9875    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9876    /*
9877     * Accelerator for simple ASCII names
9878     */
9879    in = ctxt->cur;
9880    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9881	((*in >= 0x41) && (*in <= 0x5A)) ||
9882	(*in == '_')) {
9883	in++;
9884	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9885	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9886	       ((*in >= 0x30) && (*in <= 0x39)) ||
9887	       (*in == '_') || (*in == '.') ||
9888	       (*in == '-'))
9889	    in++;
9890	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9891            (*in == '[') || (*in == ']') || (*in == ':') ||
9892            (*in == '@') || (*in == '*')) {
9893	    count = in - ctxt->cur;
9894	    if (count == 0)
9895		return(NULL);
9896	    ret = xmlStrndup(ctxt->cur, count);
9897	    ctxt->cur = in;
9898	    return(ret);
9899	}
9900    }
9901    return(xmlXPathParseNameComplex(ctxt, 0));
9902}
9903
9904
9905/**
9906 * xmlXPathParseQName:
9907 * @ctxt:  the XPath Parser context
9908 * @prefix:  a xmlChar **
9909 *
9910 * parse an XML qualified name
9911 *
9912 * [NS 5] QName ::= (Prefix ':')? LocalPart
9913 *
9914 * [NS 6] Prefix ::= NCName
9915 *
9916 * [NS 7] LocalPart ::= NCName
9917 *
9918 * Returns the function returns the local part, and prefix is updated
9919 *   to get the Prefix if any.
9920 */
9921
9922static xmlChar *
9923xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9924    xmlChar *ret = NULL;
9925
9926    *prefix = NULL;
9927    ret = xmlXPathParseNCName(ctxt);
9928    if (ret && CUR == ':') {
9929        *prefix = ret;
9930	NEXT;
9931	ret = xmlXPathParseNCName(ctxt);
9932    }
9933    return(ret);
9934}
9935
9936/**
9937 * xmlXPathParseName:
9938 * @ctxt:  the XPath Parser context
9939 *
9940 * parse an XML name
9941 *
9942 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9943 *                  CombiningChar | Extender
9944 *
9945 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9946 *
9947 * Returns the namespace name or NULL
9948 */
9949
9950xmlChar *
9951xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9952    const xmlChar *in;
9953    xmlChar *ret;
9954    size_t count = 0;
9955
9956    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9957    /*
9958     * Accelerator for simple ASCII names
9959     */
9960    in = ctxt->cur;
9961    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9962	((*in >= 0x41) && (*in <= 0x5A)) ||
9963	(*in == '_') || (*in == ':')) {
9964	in++;
9965	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9966	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9967	       ((*in >= 0x30) && (*in <= 0x39)) ||
9968	       (*in == '_') || (*in == '-') ||
9969	       (*in == ':') || (*in == '.'))
9970	    in++;
9971	if ((*in > 0) && (*in < 0x80)) {
9972	    count = in - ctxt->cur;
9973            if (count > XML_MAX_NAME_LENGTH) {
9974                ctxt->cur = in;
9975                XP_ERRORNULL(XPATH_EXPR_ERROR);
9976            }
9977	    ret = xmlStrndup(ctxt->cur, count);
9978	    ctxt->cur = in;
9979	    return(ret);
9980	}
9981    }
9982    return(xmlXPathParseNameComplex(ctxt, 1));
9983}
9984
9985static xmlChar *
9986xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9987    xmlChar buf[XML_MAX_NAMELEN + 5];
9988    int len = 0, l;
9989    int c;
9990
9991    /*
9992     * Handler for more complex cases
9993     */
9994    c = CUR_CHAR(l);
9995    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9996        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9997        (c == '*') || /* accelerators */
9998	(!IS_LETTER(c) && (c != '_') &&
9999         ((!qualified) || (c != ':')))) {
10000	return(NULL);
10001    }
10002
10003    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10004	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10005            (c == '.') || (c == '-') ||
10006	    (c == '_') || ((qualified) && (c == ':')) ||
10007	    (IS_COMBINING(c)) ||
10008	    (IS_EXTENDER(c)))) {
10009	COPY_BUF(l,buf,len,c);
10010	NEXTL(l);
10011	c = CUR_CHAR(l);
10012	if (len >= XML_MAX_NAMELEN) {
10013	    /*
10014	     * Okay someone managed to make a huge name, so he's ready to pay
10015	     * for the processing speed.
10016	     */
10017	    xmlChar *buffer;
10018	    int max = len * 2;
10019
10020            if (len > XML_MAX_NAME_LENGTH) {
10021                XP_ERRORNULL(XPATH_EXPR_ERROR);
10022            }
10023	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
10024	    if (buffer == NULL) {
10025		XP_ERRORNULL(XPATH_MEMORY_ERROR);
10026	    }
10027	    memcpy(buffer, buf, len);
10028	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10029		   (c == '.') || (c == '-') ||
10030		   (c == '_') || ((qualified) && (c == ':')) ||
10031		   (IS_COMBINING(c)) ||
10032		   (IS_EXTENDER(c))) {
10033		if (len + 10 > max) {
10034                    if (max > XML_MAX_NAME_LENGTH) {
10035                        XP_ERRORNULL(XPATH_EXPR_ERROR);
10036                    }
10037		    max *= 2;
10038		    buffer = (xmlChar *) xmlRealloc(buffer,
10039			                            max * sizeof(xmlChar));
10040		    if (buffer == NULL) {
10041			XP_ERRORNULL(XPATH_MEMORY_ERROR);
10042		    }
10043		}
10044		COPY_BUF(l,buffer,len,c);
10045		NEXTL(l);
10046		c = CUR_CHAR(l);
10047	    }
10048	    buffer[len] = 0;
10049	    return(buffer);
10050	}
10051    }
10052    if (len == 0)
10053	return(NULL);
10054    return(xmlStrndup(buf, len));
10055}
10056
10057#define MAX_FRAC 20
10058
10059/*
10060 * These are used as divisors for the fractional part of a number.
10061 * Since the table includes 1.0 (representing '0' fractional digits),
10062 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
10063 */
10064static double my_pow10[MAX_FRAC+1] = {
10065    1.0, 10.0, 100.0, 1000.0, 10000.0,
10066    100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
10067    10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
10068    100000000000000.0,
10069    1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
10070    1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
10071};
10072
10073/**
10074 * xmlXPathStringEvalNumber:
10075 * @str:  A string to scan
10076 *
10077 *  [30a]  Float  ::= Number ('e' Digits?)?
10078 *
10079 *  [30]   Number ::=   Digits ('.' Digits?)?
10080 *                    | '.' Digits
10081 *  [31]   Digits ::=   [0-9]+
10082 *
10083 * Compile a Number in the string
10084 * In complement of the Number expression, this function also handles
10085 * negative values : '-' Number.
10086 *
10087 * Returns the double value.
10088 */
10089double
10090xmlXPathStringEvalNumber(const xmlChar *str) {
10091    const xmlChar *cur = str;
10092    double ret;
10093    int ok = 0;
10094    int isneg = 0;
10095    int exponent = 0;
10096    int is_exponent_negative = 0;
10097#ifdef __GNUC__
10098    unsigned long tmp = 0;
10099    double temp;
10100#endif
10101    if (cur == NULL) return(0);
10102    while (IS_BLANK_CH(*cur)) cur++;
10103    if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10104        return(xmlXPathNAN);
10105    }
10106    if (*cur == '-') {
10107	isneg = 1;
10108	cur++;
10109    }
10110
10111#ifdef __GNUC__
10112    /*
10113     * tmp/temp is a workaround against a gcc compiler bug
10114     * http://veillard.com/gcc.bug
10115     */
10116    ret = 0;
10117    while ((*cur >= '0') && (*cur <= '9')) {
10118	ret = ret * 10;
10119	tmp = (*cur - '0');
10120	ok = 1;
10121	cur++;
10122	temp = (double) tmp;
10123	ret = ret + temp;
10124    }
10125#else
10126    ret = 0;
10127    while ((*cur >= '0') && (*cur <= '9')) {
10128	ret = ret * 10 + (*cur - '0');
10129	ok = 1;
10130	cur++;
10131    }
10132#endif
10133
10134    if (*cur == '.') {
10135	int v, frac = 0;
10136	double fraction = 0;
10137
10138        cur++;
10139	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10140	    return(xmlXPathNAN);
10141	}
10142	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10143	    v = (*cur - '0');
10144	    fraction = fraction * 10 + v;
10145	    frac = frac + 1;
10146	    cur++;
10147	}
10148	fraction /= my_pow10[frac];
10149	ret = ret + fraction;
10150	while ((*cur >= '0') && (*cur <= '9'))
10151	    cur++;
10152    }
10153    if ((*cur == 'e') || (*cur == 'E')) {
10154      cur++;
10155      if (*cur == '-') {
10156	is_exponent_negative = 1;
10157	cur++;
10158      } else if (*cur == '+') {
10159        cur++;
10160      }
10161      while ((*cur >= '0') && (*cur <= '9')) {
10162	exponent = exponent * 10 + (*cur - '0');
10163	cur++;
10164      }
10165    }
10166    while (IS_BLANK_CH(*cur)) cur++;
10167    if (*cur != 0) return(xmlXPathNAN);
10168    if (isneg) ret = -ret;
10169    if (is_exponent_negative) exponent = -exponent;
10170    ret *= pow(10.0, (double)exponent);
10171    return(ret);
10172}
10173
10174/**
10175 * xmlXPathCompNumber:
10176 * @ctxt:  the XPath Parser context
10177 *
10178 *  [30]   Number ::=   Digits ('.' Digits?)?
10179 *                    | '.' Digits
10180 *  [31]   Digits ::=   [0-9]+
10181 *
10182 * Compile a Number, then push it on the stack
10183 *
10184 */
10185static void
10186xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10187{
10188    double ret = 0.0;
10189    int ok = 0;
10190    int exponent = 0;
10191    int is_exponent_negative = 0;
10192#ifdef __GNUC__
10193    unsigned long tmp = 0;
10194    double temp;
10195#endif
10196
10197    CHECK_ERROR;
10198    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10199        XP_ERROR(XPATH_NUMBER_ERROR);
10200    }
10201#ifdef __GNUC__
10202    /*
10203     * tmp/temp is a workaround against a gcc compiler bug
10204     * http://veillard.com/gcc.bug
10205     */
10206    ret = 0;
10207    while ((CUR >= '0') && (CUR <= '9')) {
10208	ret = ret * 10;
10209	tmp = (CUR - '0');
10210        ok = 1;
10211        NEXT;
10212	temp = (double) tmp;
10213	ret = ret + temp;
10214    }
10215#else
10216    ret = 0;
10217    while ((CUR >= '0') && (CUR <= '9')) {
10218	ret = ret * 10 + (CUR - '0');
10219	ok = 1;
10220	NEXT;
10221    }
10222#endif
10223    if (CUR == '.') {
10224	int v, frac = 0;
10225	double fraction = 0;
10226
10227        NEXT;
10228        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10229            XP_ERROR(XPATH_NUMBER_ERROR);
10230        }
10231        while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10232	    v = (CUR - '0');
10233	    fraction = fraction * 10 + v;
10234	    frac = frac + 1;
10235            NEXT;
10236        }
10237        fraction /= my_pow10[frac];
10238        ret = ret + fraction;
10239        while ((CUR >= '0') && (CUR <= '9'))
10240            NEXT;
10241    }
10242    if ((CUR == 'e') || (CUR == 'E')) {
10243        NEXT;
10244        if (CUR == '-') {
10245            is_exponent_negative = 1;
10246            NEXT;
10247        } else if (CUR == '+') {
10248	    NEXT;
10249	}
10250        while ((CUR >= '0') && (CUR <= '9')) {
10251            exponent = exponent * 10 + (CUR - '0');
10252            NEXT;
10253        }
10254        if (is_exponent_negative)
10255            exponent = -exponent;
10256        ret *= pow(10.0, (double) exponent);
10257    }
10258    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10259                   xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10260}
10261
10262/**
10263 * xmlXPathParseLiteral:
10264 * @ctxt:  the XPath Parser context
10265 *
10266 * Parse a Literal
10267 *
10268 *  [29]   Literal ::=   '"' [^"]* '"'
10269 *                    | "'" [^']* "'"
10270 *
10271 * Returns the value found or NULL in case of error
10272 */
10273static xmlChar *
10274xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10275    const xmlChar *q;
10276    xmlChar *ret = NULL;
10277
10278    if (CUR == '"') {
10279        NEXT;
10280	q = CUR_PTR;
10281	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10282	    NEXT;
10283	if (!IS_CHAR_CH(CUR)) {
10284	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10285	} else {
10286	    ret = xmlStrndup(q, CUR_PTR - q);
10287	    NEXT;
10288        }
10289    } else if (CUR == '\'') {
10290        NEXT;
10291	q = CUR_PTR;
10292	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10293	    NEXT;
10294	if (!IS_CHAR_CH(CUR)) {
10295	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10296	} else {
10297	    ret = xmlStrndup(q, CUR_PTR - q);
10298	    NEXT;
10299        }
10300    } else {
10301	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10302    }
10303    return(ret);
10304}
10305
10306/**
10307 * xmlXPathCompLiteral:
10308 * @ctxt:  the XPath Parser context
10309 *
10310 * Parse a Literal and push it on the stack.
10311 *
10312 *  [29]   Literal ::=   '"' [^"]* '"'
10313 *                    | "'" [^']* "'"
10314 *
10315 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10316 */
10317static void
10318xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10319    const xmlChar *q;
10320    xmlChar *ret = NULL;
10321
10322    if (CUR == '"') {
10323        NEXT;
10324	q = CUR_PTR;
10325	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10326	    NEXT;
10327	if (!IS_CHAR_CH(CUR)) {
10328	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10329	} else {
10330	    ret = xmlStrndup(q, CUR_PTR - q);
10331	    NEXT;
10332        }
10333    } else if (CUR == '\'') {
10334        NEXT;
10335	q = CUR_PTR;
10336	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10337	    NEXT;
10338	if (!IS_CHAR_CH(CUR)) {
10339	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10340	} else {
10341	    ret = xmlStrndup(q, CUR_PTR - q);
10342	    NEXT;
10343        }
10344    } else {
10345	XP_ERROR(XPATH_START_LITERAL_ERROR);
10346    }
10347    if (ret == NULL) return;
10348    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10349	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
10350    xmlFree(ret);
10351}
10352
10353/**
10354 * xmlXPathCompVariableReference:
10355 * @ctxt:  the XPath Parser context
10356 *
10357 * Parse a VariableReference, evaluate it and push it on the stack.
10358 *
10359 * The variable bindings consist of a mapping from variable names
10360 * to variable values. The value of a variable is an object, which can be
10361 * of any of the types that are possible for the value of an expression,
10362 * and may also be of additional types not specified here.
10363 *
10364 * Early evaluation is possible since:
10365 * The variable bindings [...] used to evaluate a subexpression are
10366 * always the same as those used to evaluate the containing expression.
10367 *
10368 *  [36]   VariableReference ::=   '$' QName
10369 */
10370static void
10371xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10372    xmlChar *name;
10373    xmlChar *prefix;
10374
10375    SKIP_BLANKS;
10376    if (CUR != '$') {
10377	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10378    }
10379    NEXT;
10380    name = xmlXPathParseQName(ctxt, &prefix);
10381    if (name == NULL) {
10382	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10383    }
10384    ctxt->comp->last = -1;
10385    PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10386	           name, prefix);
10387    SKIP_BLANKS;
10388    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10389	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10390    }
10391}
10392
10393/**
10394 * xmlXPathIsNodeType:
10395 * @name:  a name string
10396 *
10397 * Is the name given a NodeType one.
10398 *
10399 *  [38]   NodeType ::=   'comment'
10400 *                    | 'text'
10401 *                    | 'processing-instruction'
10402 *                    | 'node'
10403 *
10404 * Returns 1 if true 0 otherwise
10405 */
10406int
10407xmlXPathIsNodeType(const xmlChar *name) {
10408    if (name == NULL)
10409	return(0);
10410
10411    if (xmlStrEqual(name, BAD_CAST "node"))
10412	return(1);
10413    if (xmlStrEqual(name, BAD_CAST "text"))
10414	return(1);
10415    if (xmlStrEqual(name, BAD_CAST "comment"))
10416	return(1);
10417    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10418	return(1);
10419    return(0);
10420}
10421
10422/**
10423 * xmlXPathCompFunctionCall:
10424 * @ctxt:  the XPath Parser context
10425 *
10426 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10427 *  [17]   Argument ::=   Expr
10428 *
10429 * Compile a function call, the evaluation of all arguments are
10430 * pushed on the stack
10431 */
10432static void
10433xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10434    xmlChar *name;
10435    xmlChar *prefix;
10436    int nbargs = 0;
10437    int sort = 1;
10438
10439    name = xmlXPathParseQName(ctxt, &prefix);
10440    if (name == NULL) {
10441	xmlFree(prefix);
10442	XP_ERROR(XPATH_EXPR_ERROR);
10443    }
10444    SKIP_BLANKS;
10445#ifdef DEBUG_EXPR
10446    if (prefix == NULL)
10447	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10448			name);
10449    else
10450	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10451			prefix, name);
10452#endif
10453
10454    if (CUR != '(') {
10455	XP_ERROR(XPATH_EXPR_ERROR);
10456    }
10457    NEXT;
10458    SKIP_BLANKS;
10459
10460    /*
10461    * Optimization for count(): we don't need the node-set to be sorted.
10462    */
10463    if ((prefix == NULL) && (name[0] == 'c') &&
10464	xmlStrEqual(name, BAD_CAST "count"))
10465    {
10466	sort = 0;
10467    }
10468    ctxt->comp->last = -1;
10469    if (CUR != ')') {
10470	while (CUR != 0) {
10471	    int op1 = ctxt->comp->last;
10472	    ctxt->comp->last = -1;
10473	    xmlXPathCompileExpr(ctxt, sort);
10474	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10475		xmlFree(name);
10476		xmlFree(prefix);
10477		return;
10478	    }
10479	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10480	    nbargs++;
10481	    if (CUR == ')') break;
10482	    if (CUR != ',') {
10483		XP_ERROR(XPATH_EXPR_ERROR);
10484	    }
10485	    NEXT;
10486	    SKIP_BLANKS;
10487	}
10488    }
10489    PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10490	           name, prefix);
10491    NEXT;
10492    SKIP_BLANKS;
10493}
10494
10495/**
10496 * xmlXPathCompPrimaryExpr:
10497 * @ctxt:  the XPath Parser context
10498 *
10499 *  [15]   PrimaryExpr ::=   VariableReference
10500 *                | '(' Expr ')'
10501 *                | Literal
10502 *                | Number
10503 *                | FunctionCall
10504 *
10505 * Compile a primary expression.
10506 */
10507static void
10508xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10509    SKIP_BLANKS;
10510    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10511    else if (CUR == '(') {
10512	NEXT;
10513	SKIP_BLANKS;
10514	xmlXPathCompileExpr(ctxt, 1);
10515	CHECK_ERROR;
10516	if (CUR != ')') {
10517	    XP_ERROR(XPATH_EXPR_ERROR);
10518	}
10519	NEXT;
10520	SKIP_BLANKS;
10521    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10522	xmlXPathCompNumber(ctxt);
10523    } else if ((CUR == '\'') || (CUR == '"')) {
10524	xmlXPathCompLiteral(ctxt);
10525    } else {
10526	xmlXPathCompFunctionCall(ctxt);
10527    }
10528    SKIP_BLANKS;
10529}
10530
10531/**
10532 * xmlXPathCompFilterExpr:
10533 * @ctxt:  the XPath Parser context
10534 *
10535 *  [20]   FilterExpr ::=   PrimaryExpr
10536 *               | FilterExpr Predicate
10537 *
10538 * Compile a filter expression.
10539 * Square brackets are used to filter expressions in the same way that
10540 * they are used in location paths. It is an error if the expression to
10541 * be filtered does not evaluate to a node-set. The context node list
10542 * used for evaluating the expression in square brackets is the node-set
10543 * to be filtered listed in document order.
10544 */
10545
10546static void
10547xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10548    xmlXPathCompPrimaryExpr(ctxt);
10549    CHECK_ERROR;
10550    SKIP_BLANKS;
10551
10552    while (CUR == '[') {
10553	xmlXPathCompPredicate(ctxt, 1);
10554	SKIP_BLANKS;
10555    }
10556
10557
10558}
10559
10560/**
10561 * xmlXPathScanName:
10562 * @ctxt:  the XPath Parser context
10563 *
10564 * Trickery: parse an XML name but without consuming the input flow
10565 * Needed to avoid insanity in the parser state.
10566 *
10567 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10568 *                  CombiningChar | Extender
10569 *
10570 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10571 *
10572 * [6] Names ::= Name (S Name)*
10573 *
10574 * Returns the Name parsed or NULL
10575 */
10576
10577static xmlChar *
10578xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10579    int len = 0, l;
10580    int c;
10581    const xmlChar *cur;
10582    xmlChar *ret;
10583
10584    cur = ctxt->cur;
10585
10586    c = CUR_CHAR(l);
10587    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10588	(!IS_LETTER(c) && (c != '_') &&
10589         (c != ':'))) {
10590	return(NULL);
10591    }
10592
10593    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10594	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10595            (c == '.') || (c == '-') ||
10596	    (c == '_') || (c == ':') ||
10597	    (IS_COMBINING(c)) ||
10598	    (IS_EXTENDER(c)))) {
10599	len += l;
10600	NEXTL(l);
10601	c = CUR_CHAR(l);
10602    }
10603    ret = xmlStrndup(cur, ctxt->cur - cur);
10604    ctxt->cur = cur;
10605    return(ret);
10606}
10607
10608/**
10609 * xmlXPathCompPathExpr:
10610 * @ctxt:  the XPath Parser context
10611 *
10612 *  [19]   PathExpr ::=   LocationPath
10613 *               | FilterExpr
10614 *               | FilterExpr '/' RelativeLocationPath
10615 *               | FilterExpr '//' RelativeLocationPath
10616 *
10617 * Compile a path expression.
10618 * The / operator and // operators combine an arbitrary expression
10619 * and a relative location path. It is an error if the expression
10620 * does not evaluate to a node-set.
10621 * The / operator does composition in the same way as when / is
10622 * used in a location path. As in location paths, // is short for
10623 * /descendant-or-self::node()/.
10624 */
10625
10626static void
10627xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10628    int lc = 1;           /* Should we branch to LocationPath ?         */
10629    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10630
10631    SKIP_BLANKS;
10632    if ((CUR == '$') || (CUR == '(') ||
10633	(IS_ASCII_DIGIT(CUR)) ||
10634        (CUR == '\'') || (CUR == '"') ||
10635	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10636	lc = 0;
10637    } else if (CUR == '*') {
10638	/* relative or absolute location path */
10639	lc = 1;
10640    } else if (CUR == '/') {
10641	/* relative or absolute location path */
10642	lc = 1;
10643    } else if (CUR == '@') {
10644	/* relative abbreviated attribute location path */
10645	lc = 1;
10646    } else if (CUR == '.') {
10647	/* relative abbreviated attribute location path */
10648	lc = 1;
10649    } else {
10650	/*
10651	 * Problem is finding if we have a name here whether it's:
10652	 *   - a nodetype
10653	 *   - a function call in which case it's followed by '('
10654	 *   - an axis in which case it's followed by ':'
10655	 *   - a element name
10656	 * We do an a priori analysis here rather than having to
10657	 * maintain parsed token content through the recursive function
10658	 * calls. This looks uglier but makes the code easier to
10659	 * read/write/debug.
10660	 */
10661	SKIP_BLANKS;
10662	name = xmlXPathScanName(ctxt);
10663	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10664#ifdef DEBUG_STEP
10665	    xmlGenericError(xmlGenericErrorContext,
10666		    "PathExpr: Axis\n");
10667#endif
10668	    lc = 1;
10669	    xmlFree(name);
10670	} else if (name != NULL) {
10671	    int len =xmlStrlen(name);
10672
10673
10674	    while (NXT(len) != 0) {
10675		if (NXT(len) == '/') {
10676		    /* element name */
10677#ifdef DEBUG_STEP
10678		    xmlGenericError(xmlGenericErrorContext,
10679			    "PathExpr: AbbrRelLocation\n");
10680#endif
10681		    lc = 1;
10682		    break;
10683		} else if (IS_BLANK_CH(NXT(len))) {
10684		    /* ignore blanks */
10685		    ;
10686		} else if (NXT(len) == ':') {
10687#ifdef DEBUG_STEP
10688		    xmlGenericError(xmlGenericErrorContext,
10689			    "PathExpr: AbbrRelLocation\n");
10690#endif
10691		    lc = 1;
10692		    break;
10693		} else if ((NXT(len) == '(')) {
10694		    /* Node Type or Function */
10695		    if (xmlXPathIsNodeType(name)) {
10696#ifdef DEBUG_STEP
10697		        xmlGenericError(xmlGenericErrorContext,
10698				"PathExpr: Type search\n");
10699#endif
10700			lc = 1;
10701#ifdef LIBXML_XPTR_ENABLED
10702                    } else if (ctxt->xptr &&
10703                               xmlStrEqual(name, BAD_CAST "range-to")) {
10704                        lc = 1;
10705#endif
10706		    } else {
10707#ifdef DEBUG_STEP
10708		        xmlGenericError(xmlGenericErrorContext,
10709				"PathExpr: function call\n");
10710#endif
10711			lc = 0;
10712		    }
10713                    break;
10714		} else if ((NXT(len) == '[')) {
10715		    /* element name */
10716#ifdef DEBUG_STEP
10717		    xmlGenericError(xmlGenericErrorContext,
10718			    "PathExpr: AbbrRelLocation\n");
10719#endif
10720		    lc = 1;
10721		    break;
10722		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10723			   (NXT(len) == '=')) {
10724		    lc = 1;
10725		    break;
10726		} else {
10727		    lc = 1;
10728		    break;
10729		}
10730		len++;
10731	    }
10732	    if (NXT(len) == 0) {
10733#ifdef DEBUG_STEP
10734		xmlGenericError(xmlGenericErrorContext,
10735			"PathExpr: AbbrRelLocation\n");
10736#endif
10737		/* element name */
10738		lc = 1;
10739	    }
10740	    xmlFree(name);
10741	} else {
10742	    /* make sure all cases are covered explicitly */
10743	    XP_ERROR(XPATH_EXPR_ERROR);
10744	}
10745    }
10746
10747    if (lc) {
10748	if (CUR == '/') {
10749	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10750	} else {
10751	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10752	}
10753	xmlXPathCompLocationPath(ctxt);
10754    } else {
10755	xmlXPathCompFilterExpr(ctxt);
10756	CHECK_ERROR;
10757	if ((CUR == '/') && (NXT(1) == '/')) {
10758	    SKIP(2);
10759	    SKIP_BLANKS;
10760
10761	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10762		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10763	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10764
10765	    xmlXPathCompRelativeLocationPath(ctxt);
10766	} else if (CUR == '/') {
10767	    xmlXPathCompRelativeLocationPath(ctxt);
10768	}
10769    }
10770    SKIP_BLANKS;
10771}
10772
10773/**
10774 * xmlXPathCompUnionExpr:
10775 * @ctxt:  the XPath Parser context
10776 *
10777 *  [18]   UnionExpr ::=   PathExpr
10778 *               | UnionExpr '|' PathExpr
10779 *
10780 * Compile an union expression.
10781 */
10782
10783static void
10784xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10785    xmlXPathCompPathExpr(ctxt);
10786    CHECK_ERROR;
10787    SKIP_BLANKS;
10788    while (CUR == '|') {
10789	int op1 = ctxt->comp->last;
10790	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10791
10792	NEXT;
10793	SKIP_BLANKS;
10794	xmlXPathCompPathExpr(ctxt);
10795
10796	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10797
10798	SKIP_BLANKS;
10799    }
10800}
10801
10802/**
10803 * xmlXPathCompUnaryExpr:
10804 * @ctxt:  the XPath Parser context
10805 *
10806 *  [27]   UnaryExpr ::=   UnionExpr
10807 *                   | '-' UnaryExpr
10808 *
10809 * Compile an unary expression.
10810 */
10811
10812static void
10813xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10814    int minus = 0;
10815    int found = 0;
10816
10817    SKIP_BLANKS;
10818    while (CUR == '-') {
10819        minus = 1 - minus;
10820	found = 1;
10821	NEXT;
10822	SKIP_BLANKS;
10823    }
10824
10825    xmlXPathCompUnionExpr(ctxt);
10826    CHECK_ERROR;
10827    if (found) {
10828	if (minus)
10829	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10830	else
10831	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10832    }
10833}
10834
10835/**
10836 * xmlXPathCompMultiplicativeExpr:
10837 * @ctxt:  the XPath Parser context
10838 *
10839 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10840 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10841 *                   | MultiplicativeExpr 'div' UnaryExpr
10842 *                   | MultiplicativeExpr 'mod' UnaryExpr
10843 *  [34]   MultiplyOperator ::=   '*'
10844 *
10845 * Compile an Additive expression.
10846 */
10847
10848static void
10849xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10850    xmlXPathCompUnaryExpr(ctxt);
10851    CHECK_ERROR;
10852    SKIP_BLANKS;
10853    while ((CUR == '*') ||
10854           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10855           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10856	int op = -1;
10857	int op1 = ctxt->comp->last;
10858
10859        if (CUR == '*') {
10860	    op = 0;
10861	    NEXT;
10862	} else if (CUR == 'd') {
10863	    op = 1;
10864	    SKIP(3);
10865	} else if (CUR == 'm') {
10866	    op = 2;
10867	    SKIP(3);
10868	}
10869	SKIP_BLANKS;
10870        xmlXPathCompUnaryExpr(ctxt);
10871	CHECK_ERROR;
10872	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10873	SKIP_BLANKS;
10874    }
10875}
10876
10877/**
10878 * xmlXPathCompAdditiveExpr:
10879 * @ctxt:  the XPath Parser context
10880 *
10881 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10882 *                   | AdditiveExpr '+' MultiplicativeExpr
10883 *                   | AdditiveExpr '-' MultiplicativeExpr
10884 *
10885 * Compile an Additive expression.
10886 */
10887
10888static void
10889xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10890
10891    xmlXPathCompMultiplicativeExpr(ctxt);
10892    CHECK_ERROR;
10893    SKIP_BLANKS;
10894    while ((CUR == '+') || (CUR == '-')) {
10895	int plus;
10896	int op1 = ctxt->comp->last;
10897
10898        if (CUR == '+') plus = 1;
10899	else plus = 0;
10900	NEXT;
10901	SKIP_BLANKS;
10902        xmlXPathCompMultiplicativeExpr(ctxt);
10903	CHECK_ERROR;
10904	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10905	SKIP_BLANKS;
10906    }
10907}
10908
10909/**
10910 * xmlXPathCompRelationalExpr:
10911 * @ctxt:  the XPath Parser context
10912 *
10913 *  [24]   RelationalExpr ::=   AdditiveExpr
10914 *                 | RelationalExpr '<' AdditiveExpr
10915 *                 | RelationalExpr '>' AdditiveExpr
10916 *                 | RelationalExpr '<=' AdditiveExpr
10917 *                 | RelationalExpr '>=' AdditiveExpr
10918 *
10919 *  A <= B > C is allowed ? Answer from James, yes with
10920 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10921 *  which is basically what got implemented.
10922 *
10923 * Compile a Relational expression, then push the result
10924 * on the stack
10925 */
10926
10927static void
10928xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10929    xmlXPathCompAdditiveExpr(ctxt);
10930    CHECK_ERROR;
10931    SKIP_BLANKS;
10932    while ((CUR == '<') ||
10933           (CUR == '>') ||
10934           ((CUR == '<') && (NXT(1) == '=')) ||
10935           ((CUR == '>') && (NXT(1) == '='))) {
10936	int inf, strict;
10937	int op1 = ctxt->comp->last;
10938
10939        if (CUR == '<') inf = 1;
10940	else inf = 0;
10941	if (NXT(1) == '=') strict = 0;
10942	else strict = 1;
10943	NEXT;
10944	if (!strict) NEXT;
10945	SKIP_BLANKS;
10946        xmlXPathCompAdditiveExpr(ctxt);
10947	CHECK_ERROR;
10948	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10949	SKIP_BLANKS;
10950    }
10951}
10952
10953/**
10954 * xmlXPathCompEqualityExpr:
10955 * @ctxt:  the XPath Parser context
10956 *
10957 *  [23]   EqualityExpr ::=   RelationalExpr
10958 *                 | EqualityExpr '=' RelationalExpr
10959 *                 | EqualityExpr '!=' RelationalExpr
10960 *
10961 *  A != B != C is allowed ? Answer from James, yes with
10962 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10963 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10964 *  which is basically what got implemented.
10965 *
10966 * Compile an Equality expression.
10967 *
10968 */
10969static void
10970xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10971    xmlXPathCompRelationalExpr(ctxt);
10972    CHECK_ERROR;
10973    SKIP_BLANKS;
10974    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10975	int eq;
10976	int op1 = ctxt->comp->last;
10977
10978        if (CUR == '=') eq = 1;
10979	else eq = 0;
10980	NEXT;
10981	if (!eq) NEXT;
10982	SKIP_BLANKS;
10983        xmlXPathCompRelationalExpr(ctxt);
10984	CHECK_ERROR;
10985	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10986	SKIP_BLANKS;
10987    }
10988}
10989
10990/**
10991 * xmlXPathCompAndExpr:
10992 * @ctxt:  the XPath Parser context
10993 *
10994 *  [22]   AndExpr ::=   EqualityExpr
10995 *                 | AndExpr 'and' EqualityExpr
10996 *
10997 * Compile an AND expression.
10998 *
10999 */
11000static void
11001xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
11002    xmlXPathCompEqualityExpr(ctxt);
11003    CHECK_ERROR;
11004    SKIP_BLANKS;
11005    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
11006	int op1 = ctxt->comp->last;
11007        SKIP(3);
11008	SKIP_BLANKS;
11009        xmlXPathCompEqualityExpr(ctxt);
11010	CHECK_ERROR;
11011	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
11012	SKIP_BLANKS;
11013    }
11014}
11015
11016/**
11017 * xmlXPathCompileExpr:
11018 * @ctxt:  the XPath Parser context
11019 *
11020 *  [14]   Expr ::=   OrExpr
11021 *  [21]   OrExpr ::=   AndExpr
11022 *                 | OrExpr 'or' AndExpr
11023 *
11024 * Parse and compile an expression
11025 */
11026static void
11027xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11028    xmlXPathCompAndExpr(ctxt);
11029    CHECK_ERROR;
11030    SKIP_BLANKS;
11031    while ((CUR == 'o') && (NXT(1) == 'r')) {
11032	int op1 = ctxt->comp->last;
11033        SKIP(2);
11034	SKIP_BLANKS;
11035        xmlXPathCompAndExpr(ctxt);
11036	CHECK_ERROR;
11037	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11038	SKIP_BLANKS;
11039    }
11040    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11041	/* more ops could be optimized too */
11042	/*
11043	* This is the main place to eliminate sorting for
11044	* operations which don't require a sorted node-set.
11045	* E.g. count().
11046	*/
11047	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11048    }
11049}
11050
11051/**
11052 * xmlXPathCompPredicate:
11053 * @ctxt:  the XPath Parser context
11054 * @filter:  act as a filter
11055 *
11056 *  [8]   Predicate ::=   '[' PredicateExpr ']'
11057 *  [9]   PredicateExpr ::=   Expr
11058 *
11059 * Compile a predicate expression
11060 */
11061static void
11062xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11063    int op1 = ctxt->comp->last;
11064
11065    SKIP_BLANKS;
11066    if (CUR != '[') {
11067	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11068    }
11069    NEXT;
11070    SKIP_BLANKS;
11071
11072    ctxt->comp->last = -1;
11073    /*
11074    * This call to xmlXPathCompileExpr() will deactivate sorting
11075    * of the predicate result.
11076    * TODO: Sorting is still activated for filters, since I'm not
11077    *  sure if needed. Normally sorting should not be needed, since
11078    *  a filter can only diminish the number of items in a sequence,
11079    *  but won't change its order; so if the initial sequence is sorted,
11080    *  subsequent sorting is not needed.
11081    */
11082    if (! filter)
11083	xmlXPathCompileExpr(ctxt, 0);
11084    else
11085	xmlXPathCompileExpr(ctxt, 1);
11086    CHECK_ERROR;
11087
11088    if (CUR != ']') {
11089	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11090    }
11091
11092    if (filter)
11093	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11094    else
11095	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11096
11097    NEXT;
11098    SKIP_BLANKS;
11099}
11100
11101/**
11102 * xmlXPathCompNodeTest:
11103 * @ctxt:  the XPath Parser context
11104 * @test:  pointer to a xmlXPathTestVal
11105 * @type:  pointer to a xmlXPathTypeVal
11106 * @prefix:  placeholder for a possible name prefix
11107 *
11108 * [7] NodeTest ::=   NameTest
11109 *		    | NodeType '(' ')'
11110 *		    | 'processing-instruction' '(' Literal ')'
11111 *
11112 * [37] NameTest ::=  '*'
11113 *		    | NCName ':' '*'
11114 *		    | QName
11115 * [38] NodeType ::= 'comment'
11116 *		   | 'text'
11117 *		   | 'processing-instruction'
11118 *		   | 'node'
11119 *
11120 * Returns the name found and updates @test, @type and @prefix appropriately
11121 */
11122static xmlChar *
11123xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11124	             xmlXPathTypeVal *type, const xmlChar **prefix,
11125		     xmlChar *name) {
11126    int blanks;
11127
11128    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11129	STRANGE;
11130	return(NULL);
11131    }
11132    *type = (xmlXPathTypeVal) 0;
11133    *test = (xmlXPathTestVal) 0;
11134    *prefix = NULL;
11135    SKIP_BLANKS;
11136
11137    if ((name == NULL) && (CUR == '*')) {
11138	/*
11139	 * All elements
11140	 */
11141	NEXT;
11142	*test = NODE_TEST_ALL;
11143	return(NULL);
11144    }
11145
11146    if (name == NULL)
11147	name = xmlXPathParseNCName(ctxt);
11148    if (name == NULL) {
11149	XP_ERRORNULL(XPATH_EXPR_ERROR);
11150    }
11151
11152    blanks = IS_BLANK_CH(CUR);
11153    SKIP_BLANKS;
11154    if (CUR == '(') {
11155	NEXT;
11156	/*
11157	 * NodeType or PI search
11158	 */
11159	if (xmlStrEqual(name, BAD_CAST "comment"))
11160	    *type = NODE_TYPE_COMMENT;
11161	else if (xmlStrEqual(name, BAD_CAST "node"))
11162	    *type = NODE_TYPE_NODE;
11163	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11164	    *type = NODE_TYPE_PI;
11165	else if (xmlStrEqual(name, BAD_CAST "text"))
11166	    *type = NODE_TYPE_TEXT;
11167	else {
11168	    if (name != NULL)
11169		xmlFree(name);
11170	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11171	}
11172
11173	*test = NODE_TEST_TYPE;
11174
11175	SKIP_BLANKS;
11176	if (*type == NODE_TYPE_PI) {
11177	    /*
11178	     * Specific case: search a PI by name.
11179	     */
11180	    if (name != NULL)
11181		xmlFree(name);
11182	    name = NULL;
11183	    if (CUR != ')') {
11184		name = xmlXPathParseLiteral(ctxt);
11185		CHECK_ERROR NULL;
11186		*test = NODE_TEST_PI;
11187		SKIP_BLANKS;
11188	    }
11189	}
11190	if (CUR != ')') {
11191	    if (name != NULL)
11192		xmlFree(name);
11193	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11194	}
11195	NEXT;
11196	return(name);
11197    }
11198    *test = NODE_TEST_NAME;
11199    if ((!blanks) && (CUR == ':')) {
11200	NEXT;
11201
11202	/*
11203	 * Since currently the parser context don't have a
11204	 * namespace list associated:
11205	 * The namespace name for this prefix can be computed
11206	 * only at evaluation time. The compilation is done
11207	 * outside of any context.
11208	 */
11209#if 0
11210	*prefix = xmlXPathNsLookup(ctxt->context, name);
11211	if (name != NULL)
11212	    xmlFree(name);
11213	if (*prefix == NULL) {
11214	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11215	}
11216#else
11217	*prefix = name;
11218#endif
11219
11220	if (CUR == '*') {
11221	    /*
11222	     * All elements
11223	     */
11224	    NEXT;
11225	    *test = NODE_TEST_ALL;
11226	    return(NULL);
11227	}
11228
11229	name = xmlXPathParseNCName(ctxt);
11230	if (name == NULL) {
11231	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11232	}
11233    }
11234    return(name);
11235}
11236
11237/**
11238 * xmlXPathIsAxisName:
11239 * @name:  a preparsed name token
11240 *
11241 * [6] AxisName ::=   'ancestor'
11242 *                  | 'ancestor-or-self'
11243 *                  | 'attribute'
11244 *                  | 'child'
11245 *                  | 'descendant'
11246 *                  | 'descendant-or-self'
11247 *                  | 'following'
11248 *                  | 'following-sibling'
11249 *                  | 'namespace'
11250 *                  | 'parent'
11251 *                  | 'preceding'
11252 *                  | 'preceding-sibling'
11253 *                  | 'self'
11254 *
11255 * Returns the axis or 0
11256 */
11257static xmlXPathAxisVal
11258xmlXPathIsAxisName(const xmlChar *name) {
11259    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11260    switch (name[0]) {
11261	case 'a':
11262	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11263		ret = AXIS_ANCESTOR;
11264	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11265		ret = AXIS_ANCESTOR_OR_SELF;
11266	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11267		ret = AXIS_ATTRIBUTE;
11268	    break;
11269	case 'c':
11270	    if (xmlStrEqual(name, BAD_CAST "child"))
11271		ret = AXIS_CHILD;
11272	    break;
11273	case 'd':
11274	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11275		ret = AXIS_DESCENDANT;
11276	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11277		ret = AXIS_DESCENDANT_OR_SELF;
11278	    break;
11279	case 'f':
11280	    if (xmlStrEqual(name, BAD_CAST "following"))
11281		ret = AXIS_FOLLOWING;
11282	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11283		ret = AXIS_FOLLOWING_SIBLING;
11284	    break;
11285	case 'n':
11286	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11287		ret = AXIS_NAMESPACE;
11288	    break;
11289	case 'p':
11290	    if (xmlStrEqual(name, BAD_CAST "parent"))
11291		ret = AXIS_PARENT;
11292	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11293		ret = AXIS_PRECEDING;
11294	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11295		ret = AXIS_PRECEDING_SIBLING;
11296	    break;
11297	case 's':
11298	    if (xmlStrEqual(name, BAD_CAST "self"))
11299		ret = AXIS_SELF;
11300	    break;
11301    }
11302    return(ret);
11303}
11304
11305/**
11306 * xmlXPathCompStep:
11307 * @ctxt:  the XPath Parser context
11308 *
11309 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11310 *                  | AbbreviatedStep
11311 *
11312 * [12] AbbreviatedStep ::=   '.' | '..'
11313 *
11314 * [5] AxisSpecifier ::= AxisName '::'
11315 *                  | AbbreviatedAxisSpecifier
11316 *
11317 * [13] AbbreviatedAxisSpecifier ::= '@'?
11318 *
11319 * Modified for XPtr range support as:
11320 *
11321 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11322 *                     | AbbreviatedStep
11323 *                     | 'range-to' '(' Expr ')' Predicate*
11324 *
11325 * Compile one step in a Location Path
11326 * A location step of . is short for self::node(). This is
11327 * particularly useful in conjunction with //. For example, the
11328 * location path .//para is short for
11329 * self::node()/descendant-or-self::node()/child::para
11330 * and so will select all para descendant elements of the context
11331 * node.
11332 * Similarly, a location step of .. is short for parent::node().
11333 * For example, ../title is short for parent::node()/child::title
11334 * and so will select the title children of the parent of the context
11335 * node.
11336 */
11337static void
11338xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11339#ifdef LIBXML_XPTR_ENABLED
11340    int rangeto = 0;
11341    int op2 = -1;
11342#endif
11343
11344    SKIP_BLANKS;
11345    if ((CUR == '.') && (NXT(1) == '.')) {
11346	SKIP(2);
11347	SKIP_BLANKS;
11348	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11349		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11350    } else if (CUR == '.') {
11351	NEXT;
11352	SKIP_BLANKS;
11353    } else {
11354	xmlChar *name = NULL;
11355	const xmlChar *prefix = NULL;
11356	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11357	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11358	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11359	int op1;
11360
11361	/*
11362	 * The modification needed for XPointer change to the production
11363	 */
11364#ifdef LIBXML_XPTR_ENABLED
11365	if (ctxt->xptr) {
11366	    name = xmlXPathParseNCName(ctxt);
11367	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11368                op2 = ctxt->comp->last;
11369		xmlFree(name);
11370		SKIP_BLANKS;
11371		if (CUR != '(') {
11372		    XP_ERROR(XPATH_EXPR_ERROR);
11373		}
11374		NEXT;
11375		SKIP_BLANKS;
11376
11377		xmlXPathCompileExpr(ctxt, 1);
11378		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11379		CHECK_ERROR;
11380
11381		SKIP_BLANKS;
11382		if (CUR != ')') {
11383		    XP_ERROR(XPATH_EXPR_ERROR);
11384		}
11385		NEXT;
11386		rangeto = 1;
11387		goto eval_predicates;
11388	    }
11389	}
11390#endif
11391	if (CUR == '*') {
11392	    axis = AXIS_CHILD;
11393	} else {
11394	    if (name == NULL)
11395		name = xmlXPathParseNCName(ctxt);
11396	    if (name != NULL) {
11397		axis = xmlXPathIsAxisName(name);
11398		if (axis != 0) {
11399		    SKIP_BLANKS;
11400		    if ((CUR == ':') && (NXT(1) == ':')) {
11401			SKIP(2);
11402			xmlFree(name);
11403			name = NULL;
11404		    } else {
11405			/* an element name can conflict with an axis one :-\ */
11406			axis = AXIS_CHILD;
11407		    }
11408		} else {
11409		    axis = AXIS_CHILD;
11410		}
11411	    } else if (CUR == '@') {
11412		NEXT;
11413		axis = AXIS_ATTRIBUTE;
11414	    } else {
11415		axis = AXIS_CHILD;
11416	    }
11417	}
11418
11419        if (ctxt->error != XPATH_EXPRESSION_OK) {
11420            xmlFree(name);
11421            return;
11422        }
11423
11424	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11425	if (test == 0)
11426	    return;
11427
11428        if ((prefix != NULL) && (ctxt->context != NULL) &&
11429	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11430	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11431		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11432	    }
11433	}
11434#ifdef DEBUG_STEP
11435	xmlGenericError(xmlGenericErrorContext,
11436		"Basis : computing new set\n");
11437#endif
11438
11439#ifdef DEBUG_STEP
11440	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11441	if (ctxt->value == NULL)
11442	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11443	else if (ctxt->value->nodesetval == NULL)
11444	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11445	else
11446	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11447#endif
11448
11449#ifdef LIBXML_XPTR_ENABLED
11450eval_predicates:
11451#endif
11452	op1 = ctxt->comp->last;
11453	ctxt->comp->last = -1;
11454
11455	SKIP_BLANKS;
11456	while (CUR == '[') {
11457	    xmlXPathCompPredicate(ctxt, 0);
11458	}
11459
11460#ifdef LIBXML_XPTR_ENABLED
11461	if (rangeto) {
11462	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11463	} else
11464#endif
11465	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11466			   test, type, (void *)prefix, (void *)name);
11467
11468    }
11469#ifdef DEBUG_STEP
11470    xmlGenericError(xmlGenericErrorContext, "Step : ");
11471    if (ctxt->value == NULL)
11472	xmlGenericError(xmlGenericErrorContext, "no value\n");
11473    else if (ctxt->value->nodesetval == NULL)
11474	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11475    else
11476	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11477		ctxt->value->nodesetval);
11478#endif
11479}
11480
11481/**
11482 * xmlXPathCompRelativeLocationPath:
11483 * @ctxt:  the XPath Parser context
11484 *
11485 *  [3]   RelativeLocationPath ::=   Step
11486 *                     | RelativeLocationPath '/' Step
11487 *                     | AbbreviatedRelativeLocationPath
11488 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11489 *
11490 * Compile a relative location path.
11491 */
11492static void
11493xmlXPathCompRelativeLocationPath
11494(xmlXPathParserContextPtr ctxt) {
11495    SKIP_BLANKS;
11496    if ((CUR == '/') && (NXT(1) == '/')) {
11497	SKIP(2);
11498	SKIP_BLANKS;
11499	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11500		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11501    } else if (CUR == '/') {
11502	    NEXT;
11503	SKIP_BLANKS;
11504    }
11505    xmlXPathCompStep(ctxt);
11506    CHECK_ERROR;
11507    SKIP_BLANKS;
11508    while (CUR == '/') {
11509	if ((CUR == '/') && (NXT(1) == '/')) {
11510	    SKIP(2);
11511	    SKIP_BLANKS;
11512	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11513			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11514	    xmlXPathCompStep(ctxt);
11515	} else if (CUR == '/') {
11516	    NEXT;
11517	    SKIP_BLANKS;
11518	    xmlXPathCompStep(ctxt);
11519	}
11520	SKIP_BLANKS;
11521    }
11522}
11523
11524/**
11525 * xmlXPathCompLocationPath:
11526 * @ctxt:  the XPath Parser context
11527 *
11528 *  [1]   LocationPath ::=   RelativeLocationPath
11529 *                     | AbsoluteLocationPath
11530 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11531 *                     | AbbreviatedAbsoluteLocationPath
11532 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11533 *                           '//' RelativeLocationPath
11534 *
11535 * Compile a location path
11536 *
11537 * // is short for /descendant-or-self::node()/. For example,
11538 * //para is short for /descendant-or-self::node()/child::para and
11539 * so will select any para element in the document (even a para element
11540 * that is a document element will be selected by //para since the
11541 * document element node is a child of the root node); div//para is
11542 * short for div/descendant-or-self::node()/child::para and so will
11543 * select all para descendants of div children.
11544 */
11545static void
11546xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11547    SKIP_BLANKS;
11548    if (CUR != '/') {
11549        xmlXPathCompRelativeLocationPath(ctxt);
11550    } else {
11551	while (CUR == '/') {
11552	    if ((CUR == '/') && (NXT(1) == '/')) {
11553		SKIP(2);
11554		SKIP_BLANKS;
11555		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11556			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11557		xmlXPathCompRelativeLocationPath(ctxt);
11558	    } else if (CUR == '/') {
11559		NEXT;
11560		SKIP_BLANKS;
11561		if ((CUR != 0 ) &&
11562		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11563		     (CUR == '@') || (CUR == '*')))
11564		    xmlXPathCompRelativeLocationPath(ctxt);
11565	    }
11566	    CHECK_ERROR;
11567	}
11568    }
11569}
11570
11571/************************************************************************
11572 *									*
11573 *		XPath precompiled expression evaluation			*
11574 *									*
11575 ************************************************************************/
11576
11577static int
11578xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11579
11580#ifdef DEBUG_STEP
11581static void
11582xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11583			  int nbNodes)
11584{
11585    xmlGenericError(xmlGenericErrorContext, "new step : ");
11586    switch (op->value) {
11587        case AXIS_ANCESTOR:
11588            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11589            break;
11590        case AXIS_ANCESTOR_OR_SELF:
11591            xmlGenericError(xmlGenericErrorContext,
11592                            "axis 'ancestors-or-self' ");
11593            break;
11594        case AXIS_ATTRIBUTE:
11595            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11596            break;
11597        case AXIS_CHILD:
11598            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11599            break;
11600        case AXIS_DESCENDANT:
11601            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11602            break;
11603        case AXIS_DESCENDANT_OR_SELF:
11604            xmlGenericError(xmlGenericErrorContext,
11605                            "axis 'descendant-or-self' ");
11606            break;
11607        case AXIS_FOLLOWING:
11608            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11609            break;
11610        case AXIS_FOLLOWING_SIBLING:
11611            xmlGenericError(xmlGenericErrorContext,
11612                            "axis 'following-siblings' ");
11613            break;
11614        case AXIS_NAMESPACE:
11615            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11616            break;
11617        case AXIS_PARENT:
11618            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11619            break;
11620        case AXIS_PRECEDING:
11621            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11622            break;
11623        case AXIS_PRECEDING_SIBLING:
11624            xmlGenericError(xmlGenericErrorContext,
11625                            "axis 'preceding-sibling' ");
11626            break;
11627        case AXIS_SELF:
11628            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11629            break;
11630    }
11631    xmlGenericError(xmlGenericErrorContext,
11632	" context contains %d nodes\n", nbNodes);
11633    switch (op->value2) {
11634        case NODE_TEST_NONE:
11635            xmlGenericError(xmlGenericErrorContext,
11636                            "           searching for none !!!\n");
11637            break;
11638        case NODE_TEST_TYPE:
11639            xmlGenericError(xmlGenericErrorContext,
11640                            "           searching for type %d\n", op->value3);
11641            break;
11642        case NODE_TEST_PI:
11643            xmlGenericError(xmlGenericErrorContext,
11644                            "           searching for PI !!!\n");
11645            break;
11646        case NODE_TEST_ALL:
11647            xmlGenericError(xmlGenericErrorContext,
11648                            "           searching for *\n");
11649            break;
11650        case NODE_TEST_NS:
11651            xmlGenericError(xmlGenericErrorContext,
11652                            "           searching for namespace %s\n",
11653                            op->value5);
11654            break;
11655        case NODE_TEST_NAME:
11656            xmlGenericError(xmlGenericErrorContext,
11657                            "           searching for name %s\n", op->value5);
11658            if (op->value4)
11659                xmlGenericError(xmlGenericErrorContext,
11660                                "           with namespace %s\n", op->value4);
11661            break;
11662    }
11663    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11664}
11665#endif /* DEBUG_STEP */
11666
11667static int
11668xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11669			    xmlXPathStepOpPtr op,
11670			    xmlNodeSetPtr set,
11671			    int contextSize,
11672			    int hasNsNodes)
11673{
11674    if (op->ch1 != -1) {
11675	xmlXPathCompExprPtr comp = ctxt->comp;
11676	/*
11677	* Process inner predicates first.
11678	*/
11679	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11680	    /*
11681	    * TODO: raise an internal error.
11682	    */
11683	}
11684	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11685	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11686	CHECK_ERROR0;
11687	if (contextSize <= 0)
11688	    return(0);
11689    }
11690    if (op->ch2 != -1) {
11691	xmlXPathContextPtr xpctxt = ctxt->context;
11692	xmlNodePtr contextNode, oldContextNode;
11693	xmlDocPtr oldContextDoc;
11694	int i, res, contextPos = 0, newContextSize;
11695	xmlXPathStepOpPtr exprOp;
11696	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11697
11698#ifdef LIBXML_XPTR_ENABLED
11699	/*
11700	* URGENT TODO: Check the following:
11701	*  We don't expect location sets if evaluating prediates, right?
11702	*  Only filters should expect location sets, right?
11703	*/
11704#endif
11705	/*
11706	* SPEC XPath 1.0:
11707	*  "For each node in the node-set to be filtered, the
11708	*  PredicateExpr is evaluated with that node as the
11709	*  context node, with the number of nodes in the
11710	*  node-set as the context size, and with the proximity
11711	*  position of the node in the node-set with respect to
11712	*  the axis as the context position;"
11713	* @oldset is the node-set" to be filtered.
11714	*
11715	* SPEC XPath 1.0:
11716	*  "only predicates change the context position and
11717	*  context size (see [2.4 Predicates])."
11718	* Example:
11719	*   node-set  context pos
11720	*    nA         1
11721	*    nB         2
11722	*    nC         3
11723	*   After applying predicate [position() > 1] :
11724	*   node-set  context pos
11725	*    nB         1
11726	*    nC         2
11727	*/
11728	oldContextNode = xpctxt->node;
11729	oldContextDoc = xpctxt->doc;
11730	/*
11731	* Get the expression of this predicate.
11732	*/
11733	exprOp = &ctxt->comp->steps[op->ch2];
11734	newContextSize = 0;
11735	for (i = 0; i < set->nodeNr; i++) {
11736	    if (set->nodeTab[i] == NULL)
11737		continue;
11738
11739	    contextNode = set->nodeTab[i];
11740	    xpctxt->node = contextNode;
11741	    xpctxt->contextSize = contextSize;
11742	    xpctxt->proximityPosition = ++contextPos;
11743
11744	    /*
11745	    * Also set the xpath document in case things like
11746	    * key() are evaluated in the predicate.
11747	    */
11748	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11749		(contextNode->doc != NULL))
11750		xpctxt->doc = contextNode->doc;
11751	    /*
11752	    * Evaluate the predicate expression with 1 context node
11753	    * at a time; this node is packaged into a node set; this
11754	    * node set is handed over to the evaluation mechanism.
11755	    */
11756	    if (contextObj == NULL)
11757		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11758	    else {
11759		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11760		    contextNode) < 0) {
11761		    ctxt->error = XPATH_MEMORY_ERROR;
11762		    goto evaluation_exit;
11763		}
11764	    }
11765
11766	    valuePush(ctxt, contextObj);
11767
11768	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11769
11770	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11771		xmlXPathNodeSetClear(set, hasNsNodes);
11772		newContextSize = 0;
11773		goto evaluation_exit;
11774	    }
11775
11776	    if (res != 0) {
11777		newContextSize++;
11778	    } else {
11779		/*
11780		* Remove the entry from the initial node set.
11781		*/
11782		set->nodeTab[i] = NULL;
11783		if (contextNode->type == XML_NAMESPACE_DECL)
11784		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11785	    }
11786	    if (ctxt->value == contextObj) {
11787		/*
11788		* Don't free the temporary XPath object holding the
11789		* context node, in order to avoid massive recreation
11790		* inside this loop.
11791		*/
11792		valuePop(ctxt);
11793		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11794	    } else {
11795		/*
11796		* TODO: The object was lost in the evaluation machinery.
11797		*  Can this happen? Maybe in internal-error cases.
11798		*/
11799		contextObj = NULL;
11800	    }
11801	}
11802
11803	if (contextObj != NULL) {
11804	    if (ctxt->value == contextObj)
11805		valuePop(ctxt);
11806	    xmlXPathReleaseObject(xpctxt, contextObj);
11807	}
11808evaluation_exit:
11809	if (exprRes != NULL)
11810	    xmlXPathReleaseObject(ctxt->context, exprRes);
11811	/*
11812	* Reset/invalidate the context.
11813	*/
11814	xpctxt->node = oldContextNode;
11815	xpctxt->doc = oldContextDoc;
11816	xpctxt->contextSize = -1;
11817	xpctxt->proximityPosition = -1;
11818	return(newContextSize);
11819    }
11820    return(contextSize);
11821}
11822
11823static int
11824xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11825				      xmlXPathStepOpPtr op,
11826				      xmlNodeSetPtr set,
11827				      int contextSize,
11828				      int minPos,
11829				      int maxPos,
11830				      int hasNsNodes)
11831{
11832    if (op->ch1 != -1) {
11833	xmlXPathCompExprPtr comp = ctxt->comp;
11834	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11835	    /*
11836	    * TODO: raise an internal error.
11837	    */
11838	}
11839	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11840	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11841	CHECK_ERROR0;
11842	if (contextSize <= 0)
11843	    return(0);
11844    }
11845    /*
11846    * Check if the node set contains a sufficient number of nodes for
11847    * the requested range.
11848    */
11849    if (contextSize < minPos) {
11850	xmlXPathNodeSetClear(set, hasNsNodes);
11851	return(0);
11852    }
11853    if (op->ch2 == -1) {
11854	/*
11855	* TODO: Can this ever happen?
11856	*/
11857	return (contextSize);
11858    } else {
11859	xmlDocPtr oldContextDoc;
11860	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11861	xmlXPathStepOpPtr exprOp;
11862	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11863	xmlNodePtr oldContextNode, contextNode = NULL;
11864	xmlXPathContextPtr xpctxt = ctxt->context;
11865        int frame;
11866
11867#ifdef LIBXML_XPTR_ENABLED
11868	    /*
11869	    * URGENT TODO: Check the following:
11870	    *  We don't expect location sets if evaluating prediates, right?
11871	    *  Only filters should expect location sets, right?
11872	*/
11873#endif /* LIBXML_XPTR_ENABLED */
11874
11875	/*
11876	* Save old context.
11877	*/
11878	oldContextNode = xpctxt->node;
11879	oldContextDoc = xpctxt->doc;
11880	/*
11881	* Get the expression of this predicate.
11882	*/
11883	exprOp = &ctxt->comp->steps[op->ch2];
11884	for (i = 0; i < set->nodeNr; i++) {
11885            xmlXPathObjectPtr tmp;
11886
11887	    if (set->nodeTab[i] == NULL)
11888		continue;
11889
11890	    contextNode = set->nodeTab[i];
11891	    xpctxt->node = contextNode;
11892	    xpctxt->contextSize = contextSize;
11893	    xpctxt->proximityPosition = ++contextPos;
11894
11895	    /*
11896	    * Initialize the new set.
11897	    * Also set the xpath document in case things like
11898	    * key() evaluation are attempted on the predicate
11899	    */
11900	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11901		(contextNode->doc != NULL))
11902		xpctxt->doc = contextNode->doc;
11903	    /*
11904	    * Evaluate the predicate expression with 1 context node
11905	    * at a time; this node is packaged into a node set; this
11906	    * node set is handed over to the evaluation mechanism.
11907	    */
11908	    if (contextObj == NULL)
11909		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11910	    else {
11911		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11912		    contextNode) < 0) {
11913		    ctxt->error = XPATH_MEMORY_ERROR;
11914		    goto evaluation_exit;
11915		}
11916	    }
11917
11918            frame = xmlXPathSetFrame(ctxt);
11919	    valuePush(ctxt, contextObj);
11920	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11921            tmp = valuePop(ctxt);
11922            xmlXPathPopFrame(ctxt, frame);
11923
11924	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11925                while (tmp != contextObj) {
11926                    /*
11927                     * Free up the result
11928                     * then pop off contextObj, which will be freed later
11929                     */
11930                    xmlXPathReleaseObject(xpctxt, tmp);
11931                    tmp = valuePop(ctxt);
11932                }
11933		goto evaluation_error;
11934	    }
11935            /* push the result back onto the stack */
11936            valuePush(ctxt, tmp);
11937
11938	    if (res)
11939		pos++;
11940
11941	    if (res && (pos >= minPos) && (pos <= maxPos)) {
11942		/*
11943		* Fits in the requested range.
11944		*/
11945		newContextSize++;
11946		if (minPos == maxPos) {
11947		    /*
11948		    * Only 1 node was requested.
11949		    */
11950		    if (contextNode->type == XML_NAMESPACE_DECL) {
11951			/*
11952			* As always: take care of those nasty
11953			* namespace nodes.
11954			*/
11955			set->nodeTab[i] = NULL;
11956		    }
11957		    xmlXPathNodeSetClear(set, hasNsNodes);
11958		    set->nodeNr = 1;
11959		    set->nodeTab[0] = contextNode;
11960		    goto evaluation_exit;
11961		}
11962		if (pos == maxPos) {
11963		    /*
11964		    * We are done.
11965		    */
11966		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11967		    goto evaluation_exit;
11968		}
11969	    } else {
11970		/*
11971		* Remove the entry from the initial node set.
11972		*/
11973		set->nodeTab[i] = NULL;
11974		if (contextNode->type == XML_NAMESPACE_DECL)
11975		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11976	    }
11977	    if (exprRes != NULL) {
11978		xmlXPathReleaseObject(ctxt->context, exprRes);
11979		exprRes = NULL;
11980	    }
11981	    if (ctxt->value == contextObj) {
11982		/*
11983		* Don't free the temporary XPath object holding the
11984		* context node, in order to avoid massive recreation
11985		* inside this loop.
11986		*/
11987		valuePop(ctxt);
11988		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11989	    } else {
11990		/*
11991		* The object was lost in the evaluation machinery.
11992		* Can this happen? Maybe in case of internal-errors.
11993		*/
11994		contextObj = NULL;
11995	    }
11996	}
11997	goto evaluation_exit;
11998
11999evaluation_error:
12000	xmlXPathNodeSetClear(set, hasNsNodes);
12001	newContextSize = 0;
12002
12003evaluation_exit:
12004	if (contextObj != NULL) {
12005	    if (ctxt->value == contextObj)
12006		valuePop(ctxt);
12007	    xmlXPathReleaseObject(xpctxt, contextObj);
12008	}
12009	if (exprRes != NULL)
12010	    xmlXPathReleaseObject(ctxt->context, exprRes);
12011	/*
12012	* Reset/invalidate the context.
12013	*/
12014	xpctxt->node = oldContextNode;
12015	xpctxt->doc = oldContextDoc;
12016	xpctxt->contextSize = -1;
12017	xpctxt->proximityPosition = -1;
12018	return(newContextSize);
12019    }
12020    return(contextSize);
12021}
12022
12023static int
12024xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12025			    xmlXPathStepOpPtr op,
12026			    int *maxPos)
12027{
12028
12029    xmlXPathStepOpPtr exprOp;
12030
12031    /*
12032    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12033    */
12034
12035    /*
12036    * If not -1, then ch1 will point to:
12037    * 1) For predicates (XPATH_OP_PREDICATE):
12038    *    - an inner predicate operator
12039    * 2) For filters (XPATH_OP_FILTER):
12040    *    - an inner filter operater OR
12041    *    - an expression selecting the node set.
12042    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
12043    */
12044    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12045	return(0);
12046
12047    if (op->ch2 != -1) {
12048	exprOp = &ctxt->comp->steps[op->ch2];
12049    } else
12050	return(0);
12051
12052    if ((exprOp != NULL) &&
12053	(exprOp->op == XPATH_OP_VALUE) &&
12054	(exprOp->value4 != NULL) &&
12055	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12056    {
12057	/*
12058	* We have a "[n]" predicate here.
12059	* TODO: Unfortunately this simplistic test here is not
12060	* able to detect a position() predicate in compound
12061	* expressions like "[@attr = 'a" and position() = 1],
12062	* and even not the usage of position() in
12063	* "[position() = 1]"; thus - obviously - a position-range,
12064	* like it "[position() < 5]", is also not detected.
12065	* Maybe we could rewrite the AST to ease the optimization.
12066	*/
12067	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12068
12069	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
12070	    (float) *maxPos)
12071	{
12072	    return(1);
12073	}
12074    }
12075    return(0);
12076}
12077
12078static int
12079xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12080                           xmlXPathStepOpPtr op,
12081			   xmlNodePtr * first, xmlNodePtr * last,
12082			   int toBool)
12083{
12084
12085#define XP_TEST_HIT \
12086    if (hasAxisRange != 0) { \
12087	if (++pos == maxPos) { \
12088	    if (addNode(seq, cur) < 0) \
12089	        ctxt->error = XPATH_MEMORY_ERROR; \
12090	    goto axis_range_end; } \
12091    } else { \
12092	if (addNode(seq, cur) < 0) \
12093	    ctxt->error = XPATH_MEMORY_ERROR; \
12094	if (breakOnFirstHit) goto first_hit; }
12095
12096#define XP_TEST_HIT_NS \
12097    if (hasAxisRange != 0) { \
12098	if (++pos == maxPos) { \
12099	    hasNsNodes = 1; \
12100	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12101	        ctxt->error = XPATH_MEMORY_ERROR; \
12102	goto axis_range_end; } \
12103    } else { \
12104	hasNsNodes = 1; \
12105	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12106	    ctxt->error = XPATH_MEMORY_ERROR; \
12107	if (breakOnFirstHit) goto first_hit; }
12108
12109    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12110    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12111    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12112    const xmlChar *prefix = op->value4;
12113    const xmlChar *name = op->value5;
12114    const xmlChar *URI = NULL;
12115
12116#ifdef DEBUG_STEP
12117    int nbMatches = 0, prevMatches = 0;
12118#endif
12119    int total = 0, hasNsNodes = 0;
12120    /* The popped object holding the context nodes */
12121    xmlXPathObjectPtr obj;
12122    /* The set of context nodes for the node tests */
12123    xmlNodeSetPtr contextSeq;
12124    int contextIdx;
12125    xmlNodePtr contextNode;
12126    /* The final resulting node set wrt to all context nodes */
12127    xmlNodeSetPtr outSeq;
12128    /*
12129    * The temporary resulting node set wrt 1 context node.
12130    * Used to feed predicate evaluation.
12131    */
12132    xmlNodeSetPtr seq;
12133    xmlNodePtr cur;
12134    /* First predicate operator */
12135    xmlXPathStepOpPtr predOp;
12136    int maxPos; /* The requested position() (when a "[n]" predicate) */
12137    int hasPredicateRange, hasAxisRange, pos, size, newSize;
12138    int breakOnFirstHit;
12139
12140    xmlXPathTraversalFunction next = NULL;
12141    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12142    xmlXPathNodeSetMergeFunction mergeAndClear;
12143    xmlNodePtr oldContextNode;
12144    xmlXPathContextPtr xpctxt = ctxt->context;
12145
12146
12147    CHECK_TYPE0(XPATH_NODESET);
12148    obj = valuePop(ctxt);
12149    /*
12150    * Setup namespaces.
12151    */
12152    if (prefix != NULL) {
12153        URI = xmlXPathNsLookup(xpctxt, prefix);
12154        if (URI == NULL) {
12155	    xmlXPathReleaseObject(xpctxt, obj);
12156            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12157	}
12158    }
12159    /*
12160    * Setup axis.
12161    *
12162    * MAYBE FUTURE TODO: merging optimizations:
12163    * - If the nodes to be traversed wrt to the initial nodes and
12164    *   the current axis cannot overlap, then we could avoid searching
12165    *   for duplicates during the merge.
12166    *   But the question is how/when to evaluate if they cannot overlap.
12167    *   Example: if we know that for two initial nodes, the one is
12168    *   not in the ancestor-or-self axis of the other, then we could safely
12169    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12170    *   the descendant-or-self axis.
12171    */
12172    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12173    switch (axis) {
12174        case AXIS_ANCESTOR:
12175            first = NULL;
12176            next = xmlXPathNextAncestor;
12177            break;
12178        case AXIS_ANCESTOR_OR_SELF:
12179            first = NULL;
12180            next = xmlXPathNextAncestorOrSelf;
12181            break;
12182        case AXIS_ATTRIBUTE:
12183            first = NULL;
12184	    last = NULL;
12185            next = xmlXPathNextAttribute;
12186	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12187            break;
12188        case AXIS_CHILD:
12189	    last = NULL;
12190	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12191		(type == NODE_TYPE_NODE))
12192	    {
12193		/*
12194		* Optimization if an element node type is 'element'.
12195		*/
12196		next = xmlXPathNextChildElement;
12197	    } else
12198		next = xmlXPathNextChild;
12199	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12200            break;
12201        case AXIS_DESCENDANT:
12202	    last = NULL;
12203            next = xmlXPathNextDescendant;
12204            break;
12205        case AXIS_DESCENDANT_OR_SELF:
12206	    last = NULL;
12207            next = xmlXPathNextDescendantOrSelf;
12208            break;
12209        case AXIS_FOLLOWING:
12210	    last = NULL;
12211            next = xmlXPathNextFollowing;
12212            break;
12213        case AXIS_FOLLOWING_SIBLING:
12214	    last = NULL;
12215            next = xmlXPathNextFollowingSibling;
12216            break;
12217        case AXIS_NAMESPACE:
12218            first = NULL;
12219	    last = NULL;
12220            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12221	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12222            break;
12223        case AXIS_PARENT:
12224            first = NULL;
12225            next = xmlXPathNextParent;
12226            break;
12227        case AXIS_PRECEDING:
12228            first = NULL;
12229            next = xmlXPathNextPrecedingInternal;
12230            break;
12231        case AXIS_PRECEDING_SIBLING:
12232            first = NULL;
12233            next = xmlXPathNextPrecedingSibling;
12234            break;
12235        case AXIS_SELF:
12236            first = NULL;
12237	    last = NULL;
12238            next = xmlXPathNextSelf;
12239	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12240            break;
12241    }
12242
12243#ifdef DEBUG_STEP
12244    xmlXPathDebugDumpStepAxis(op,
12245	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12246#endif
12247
12248    if (next == NULL) {
12249	xmlXPathReleaseObject(xpctxt, obj);
12250        return(0);
12251    }
12252    contextSeq = obj->nodesetval;
12253    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12254	xmlXPathReleaseObject(xpctxt, obj);
12255        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12256        return(0);
12257    }
12258    /*
12259    * Predicate optimization ---------------------------------------------
12260    * If this step has a last predicate, which contains a position(),
12261    * then we'll optimize (although not exactly "position()", but only
12262    * the  short-hand form, i.e., "[n]".
12263    *
12264    * Example - expression "/foo[parent::bar][1]":
12265    *
12266    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12267    *   ROOT                               -- op->ch1
12268    *   PREDICATE                          -- op->ch2 (predOp)
12269    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12270    *       SORT
12271    *         COLLECT  'parent' 'name' 'node' bar
12272    *           NODE
12273    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12274    *
12275    */
12276    maxPos = 0;
12277    predOp = NULL;
12278    hasPredicateRange = 0;
12279    hasAxisRange = 0;
12280    if (op->ch2 != -1) {
12281	/*
12282	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12283	*/
12284	predOp = &ctxt->comp->steps[op->ch2];
12285	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12286	    if (predOp->ch1 != -1) {
12287		/*
12288		* Use the next inner predicate operator.
12289		*/
12290		predOp = &ctxt->comp->steps[predOp->ch1];
12291		hasPredicateRange = 1;
12292	    } else {
12293		/*
12294		* There's no other predicate than the [n] predicate.
12295		*/
12296		predOp = NULL;
12297		hasAxisRange = 1;
12298	    }
12299	}
12300    }
12301    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12302    /*
12303    * Axis traversal -----------------------------------------------------
12304    */
12305    /*
12306     * 2.3 Node Tests
12307     *  - For the attribute axis, the principal node type is attribute.
12308     *  - For the namespace axis, the principal node type is namespace.
12309     *  - For other axes, the principal node type is element.
12310     *
12311     * A node test * is true for any node of the
12312     * principal node type. For example, child::* will
12313     * select all element children of the context node
12314     */
12315    oldContextNode = xpctxt->node;
12316    addNode = xmlXPathNodeSetAddUnique;
12317    outSeq = NULL;
12318    seq = NULL;
12319    contextNode = NULL;
12320    contextIdx = 0;
12321
12322
12323    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12324           (ctxt->error == XPATH_EXPRESSION_OK)) {
12325	xpctxt->node = contextSeq->nodeTab[contextIdx++];
12326
12327	if (seq == NULL) {
12328	    seq = xmlXPathNodeSetCreate(NULL);
12329	    if (seq == NULL) {
12330		total = 0;
12331		goto error;
12332	    }
12333	}
12334	/*
12335	* Traverse the axis and test the nodes.
12336	*/
12337	pos = 0;
12338	cur = NULL;
12339	hasNsNodes = 0;
12340        do {
12341            cur = next(ctxt, cur);
12342            if (cur == NULL)
12343                break;
12344
12345	    /*
12346	    * QUESTION TODO: What does the "first" and "last" stuff do?
12347	    */
12348            if ((first != NULL) && (*first != NULL)) {
12349		if (*first == cur)
12350		    break;
12351		if (((total % 256) == 0) &&
12352#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12353		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12354#else
12355		    (xmlXPathCmpNodes(*first, cur) >= 0))
12356#endif
12357		{
12358		    break;
12359		}
12360	    }
12361	    if ((last != NULL) && (*last != NULL)) {
12362		if (*last == cur)
12363		    break;
12364		if (((total % 256) == 0) &&
12365#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12366		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12367#else
12368		    (xmlXPathCmpNodes(cur, *last) >= 0))
12369#endif
12370		{
12371		    break;
12372		}
12373	    }
12374
12375            total++;
12376
12377#ifdef DEBUG_STEP
12378            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12379#endif
12380
12381	    switch (test) {
12382                case NODE_TEST_NONE:
12383		    total = 0;
12384                    STRANGE
12385		    goto error;
12386                case NODE_TEST_TYPE:
12387		    if (type == NODE_TYPE_NODE) {
12388			switch (cur->type) {
12389			    case XML_DOCUMENT_NODE:
12390			    case XML_HTML_DOCUMENT_NODE:
12391#ifdef LIBXML_DOCB_ENABLED
12392			    case XML_DOCB_DOCUMENT_NODE:
12393#endif
12394			    case XML_ELEMENT_NODE:
12395			    case XML_ATTRIBUTE_NODE:
12396			    case XML_PI_NODE:
12397			    case XML_COMMENT_NODE:
12398			    case XML_CDATA_SECTION_NODE:
12399			    case XML_TEXT_NODE:
12400				XP_TEST_HIT
12401				break;
12402			    case XML_NAMESPACE_DECL: {
12403				if (axis == AXIS_NAMESPACE) {
12404				    XP_TEST_HIT_NS
12405				} else {
12406	                            hasNsNodes = 1;
12407				    XP_TEST_HIT
12408				}
12409				break;
12410                            }
12411			    default:
12412				break;
12413			}
12414		    } else if (cur->type == type) {
12415			if (cur->type == XML_NAMESPACE_DECL)
12416			    XP_TEST_HIT_NS
12417			else
12418			    XP_TEST_HIT
12419		    } else if ((type == NODE_TYPE_TEXT) &&
12420			 (cur->type == XML_CDATA_SECTION_NODE))
12421		    {
12422			XP_TEST_HIT
12423		    }
12424		    break;
12425                case NODE_TEST_PI:
12426                    if ((cur->type == XML_PI_NODE) &&
12427                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12428		    {
12429			XP_TEST_HIT
12430                    }
12431                    break;
12432                case NODE_TEST_ALL:
12433                    if (axis == AXIS_ATTRIBUTE) {
12434                        if (cur->type == XML_ATTRIBUTE_NODE)
12435			{
12436                            if (prefix == NULL)
12437			    {
12438				XP_TEST_HIT
12439                            } else if ((cur->ns != NULL) &&
12440				(xmlStrEqual(URI, cur->ns->href)))
12441			    {
12442				XP_TEST_HIT
12443                            }
12444                        }
12445                    } else if (axis == AXIS_NAMESPACE) {
12446                        if (cur->type == XML_NAMESPACE_DECL)
12447			{
12448			    XP_TEST_HIT_NS
12449                        }
12450                    } else {
12451                        if (cur->type == XML_ELEMENT_NODE) {
12452                            if (prefix == NULL)
12453			    {
12454				XP_TEST_HIT
12455
12456                            } else if ((cur->ns != NULL) &&
12457				(xmlStrEqual(URI, cur->ns->href)))
12458			    {
12459				XP_TEST_HIT
12460                            }
12461                        }
12462                    }
12463                    break;
12464                case NODE_TEST_NS:{
12465                        TODO;
12466                        break;
12467                    }
12468                case NODE_TEST_NAME:
12469                    if (axis == AXIS_ATTRIBUTE) {
12470                        if (cur->type != XML_ATTRIBUTE_NODE)
12471			    break;
12472		    } else if (axis == AXIS_NAMESPACE) {
12473                        if (cur->type != XML_NAMESPACE_DECL)
12474			    break;
12475		    } else {
12476		        if (cur->type != XML_ELEMENT_NODE)
12477			    break;
12478		    }
12479                    switch (cur->type) {
12480                        case XML_ELEMENT_NODE:
12481                            if (xmlStrEqual(name, cur->name)) {
12482                                if (prefix == NULL) {
12483                                    if (cur->ns == NULL)
12484				    {
12485					XP_TEST_HIT
12486                                    }
12487                                } else {
12488                                    if ((cur->ns != NULL) &&
12489                                        (xmlStrEqual(URI, cur->ns->href)))
12490				    {
12491					XP_TEST_HIT
12492                                    }
12493                                }
12494                            }
12495                            break;
12496                        case XML_ATTRIBUTE_NODE:{
12497                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12498
12499                                if (xmlStrEqual(name, attr->name)) {
12500                                    if (prefix == NULL) {
12501                                        if ((attr->ns == NULL) ||
12502                                            (attr->ns->prefix == NULL))
12503					{
12504					    XP_TEST_HIT
12505                                        }
12506                                    } else {
12507                                        if ((attr->ns != NULL) &&
12508                                            (xmlStrEqual(URI,
12509					      attr->ns->href)))
12510					{
12511					    XP_TEST_HIT
12512                                        }
12513                                    }
12514                                }
12515                                break;
12516                            }
12517                        case XML_NAMESPACE_DECL:
12518                            if (cur->type == XML_NAMESPACE_DECL) {
12519                                xmlNsPtr ns = (xmlNsPtr) cur;
12520
12521                                if ((ns->prefix != NULL) && (name != NULL)
12522                                    && (xmlStrEqual(ns->prefix, name)))
12523				{
12524				    XP_TEST_HIT_NS
12525                                }
12526                            }
12527                            break;
12528                        default:
12529                            break;
12530                    }
12531                    break;
12532	    } /* switch(test) */
12533        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12534
12535	goto apply_predicates;
12536
12537axis_range_end: /* ----------------------------------------------------- */
12538	/*
12539	* We have a "/foo[n]", and position() = n was reached.
12540	* Note that we can have as well "/foo/::parent::foo[1]", so
12541	* a duplicate-aware merge is still needed.
12542	* Merge with the result.
12543	*/
12544	if (outSeq == NULL) {
12545	    outSeq = seq;
12546	    seq = NULL;
12547	} else
12548	    outSeq = mergeAndClear(outSeq, seq, 0);
12549	/*
12550	* Break if only a true/false result was requested.
12551	*/
12552	if (toBool)
12553	    break;
12554	continue;
12555
12556first_hit: /* ---------------------------------------------------------- */
12557	/*
12558	* Break if only a true/false result was requested and
12559	* no predicates existed and a node test succeeded.
12560	*/
12561	if (outSeq == NULL) {
12562	    outSeq = seq;
12563	    seq = NULL;
12564	} else
12565	    outSeq = mergeAndClear(outSeq, seq, 0);
12566	break;
12567
12568#ifdef DEBUG_STEP
12569	if (seq != NULL)
12570	    nbMatches += seq->nodeNr;
12571#endif
12572
12573apply_predicates: /* --------------------------------------------------- */
12574        if (ctxt->error != XPATH_EXPRESSION_OK)
12575	    goto error;
12576
12577        /*
12578	* Apply predicates.
12579	*/
12580        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12581	    /*
12582	    * E.g. when we have a "/foo[some expression][n]".
12583	    */
12584	    /*
12585	    * QUESTION TODO: The old predicate evaluation took into
12586	    *  account location-sets.
12587	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12588	    *  Do we expect such a set here?
12589	    *  All what I learned now from the evaluation semantics
12590	    *  does not indicate that a location-set will be processed
12591	    *  here, so this looks OK.
12592	    */
12593	    /*
12594	    * Iterate over all predicates, starting with the outermost
12595	    * predicate.
12596	    * TODO: Problem: we cannot execute the inner predicates first
12597	    *  since we cannot go back *up* the operator tree!
12598	    *  Options we have:
12599	    *  1) Use of recursive functions (like is it currently done
12600	    *     via xmlXPathCompOpEval())
12601	    *  2) Add a predicate evaluation information stack to the
12602	    *     context struct
12603	    *  3) Change the way the operators are linked; we need a
12604	    *     "parent" field on xmlXPathStepOp
12605	    *
12606	    * For the moment, I'll try to solve this with a recursive
12607	    * function: xmlXPathCompOpEvalPredicate().
12608	    */
12609	    size = seq->nodeNr;
12610	    if (hasPredicateRange != 0)
12611		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12612		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12613	    else
12614		newSize = xmlXPathCompOpEvalPredicate(ctxt,
12615		    predOp, seq, size, hasNsNodes);
12616
12617	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12618		total = 0;
12619		goto error;
12620	    }
12621	    /*
12622	    * Add the filtered set of nodes to the result node set.
12623	    */
12624	    if (newSize == 0) {
12625		/*
12626		* The predicates filtered all nodes out.
12627		*/
12628		xmlXPathNodeSetClear(seq, hasNsNodes);
12629	    } else if (seq->nodeNr > 0) {
12630		/*
12631		* Add to result set.
12632		*/
12633		if (outSeq == NULL) {
12634		    if (size != newSize) {
12635			/*
12636			* We need to merge and clear here, since
12637			* the sequence will contained NULLed entries.
12638			*/
12639			outSeq = mergeAndClear(NULL, seq, 1);
12640		    } else {
12641			outSeq = seq;
12642			seq = NULL;
12643		    }
12644		} else
12645		    outSeq = mergeAndClear(outSeq, seq,
12646			(size != newSize) ? 1: 0);
12647		/*
12648		* Break if only a true/false result was requested.
12649		*/
12650		if (toBool)
12651		    break;
12652	    }
12653        } else if (seq->nodeNr > 0) {
12654	    /*
12655	    * Add to result set.
12656	    */
12657	    if (outSeq == NULL) {
12658		outSeq = seq;
12659		seq = NULL;
12660	    } else {
12661		outSeq = mergeAndClear(outSeq, seq, 0);
12662	    }
12663	}
12664    }
12665
12666error:
12667    if ((obj->boolval) && (obj->user != NULL)) {
12668	/*
12669	* QUESTION TODO: What does this do and why?
12670	* TODO: Do we have to do this also for the "error"
12671	* cleanup further down?
12672	*/
12673	ctxt->value->boolval = 1;
12674	ctxt->value->user = obj->user;
12675	obj->user = NULL;
12676	obj->boolval = 0;
12677    }
12678    xmlXPathReleaseObject(xpctxt, obj);
12679
12680    /*
12681    * Ensure we return at least an emtpy set.
12682    */
12683    if (outSeq == NULL) {
12684	if ((seq != NULL) && (seq->nodeNr == 0))
12685	    outSeq = seq;
12686	else
12687	    outSeq = xmlXPathNodeSetCreate(NULL);
12688        /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12689    }
12690    if ((seq != NULL) && (seq != outSeq)) {
12691	 xmlXPathFreeNodeSet(seq);
12692    }
12693    /*
12694    * Hand over the result. Better to push the set also in
12695    * case of errors.
12696    */
12697    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12698    /*
12699    * Reset the context node.
12700    */
12701    xpctxt->node = oldContextNode;
12702    /*
12703    * When traversing the namespace axis in "toBool" mode, it's
12704    * possible that tmpNsList wasn't freed.
12705    */
12706    if (xpctxt->tmpNsList != NULL) {
12707        xmlFree(xpctxt->tmpNsList);
12708        xpctxt->tmpNsList = NULL;
12709    }
12710
12711#ifdef DEBUG_STEP
12712    xmlGenericError(xmlGenericErrorContext,
12713	"\nExamined %d nodes, found %d nodes at that step\n",
12714	total, nbMatches);
12715#endif
12716
12717    return(total);
12718}
12719
12720static int
12721xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12722			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12723
12724/**
12725 * xmlXPathCompOpEvalFirst:
12726 * @ctxt:  the XPath parser context with the compiled expression
12727 * @op:  an XPath compiled operation
12728 * @first:  the first elem found so far
12729 *
12730 * Evaluate the Precompiled XPath operation searching only the first
12731 * element in document order
12732 *
12733 * Returns the number of examined objects.
12734 */
12735static int
12736xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12737                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12738{
12739    int total = 0, cur;
12740    xmlXPathCompExprPtr comp;
12741    xmlXPathObjectPtr arg1, arg2;
12742
12743    CHECK_ERROR0;
12744    comp = ctxt->comp;
12745    switch (op->op) {
12746        case XPATH_OP_END:
12747            return (0);
12748        case XPATH_OP_UNION:
12749            total =
12750                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12751                                        first);
12752	    CHECK_ERROR0;
12753            if ((ctxt->value != NULL)
12754                && (ctxt->value->type == XPATH_NODESET)
12755                && (ctxt->value->nodesetval != NULL)
12756                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12757                /*
12758                 * limit tree traversing to first node in the result
12759                 */
12760		/*
12761		* OPTIMIZE TODO: This implicitely sorts
12762		*  the result, even if not needed. E.g. if the argument
12763		*  of the count() function, no sorting is needed.
12764		* OPTIMIZE TODO: How do we know if the node-list wasn't
12765		*  aready sorted?
12766		*/
12767		if (ctxt->value->nodesetval->nodeNr > 1)
12768		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12769                *first = ctxt->value->nodesetval->nodeTab[0];
12770            }
12771            cur =
12772                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12773                                        first);
12774	    CHECK_ERROR0;
12775            CHECK_TYPE0(XPATH_NODESET);
12776            arg2 = valuePop(ctxt);
12777
12778            CHECK_TYPE0(XPATH_NODESET);
12779            arg1 = valuePop(ctxt);
12780
12781            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12782                                                    arg2->nodesetval);
12783            valuePush(ctxt, arg1);
12784	    xmlXPathReleaseObject(ctxt->context, arg2);
12785            /* optimizer */
12786	    if (total > cur)
12787		xmlXPathCompSwap(op);
12788            return (total + cur);
12789        case XPATH_OP_ROOT:
12790            xmlXPathRoot(ctxt);
12791            return (0);
12792        case XPATH_OP_NODE:
12793            if (op->ch1 != -1)
12794                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12795	    CHECK_ERROR0;
12796            if (op->ch2 != -1)
12797                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12798	    CHECK_ERROR0;
12799	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12800		ctxt->context->node));
12801            return (total);
12802        case XPATH_OP_RESET:
12803            if (op->ch1 != -1)
12804                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12805	    CHECK_ERROR0;
12806            if (op->ch2 != -1)
12807                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12808	    CHECK_ERROR0;
12809            ctxt->context->node = NULL;
12810            return (total);
12811        case XPATH_OP_COLLECT:{
12812                if (op->ch1 == -1)
12813                    return (total);
12814
12815                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12816		CHECK_ERROR0;
12817
12818                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12819                return (total);
12820            }
12821        case XPATH_OP_VALUE:
12822            valuePush(ctxt,
12823                      xmlXPathCacheObjectCopy(ctxt->context,
12824			(xmlXPathObjectPtr) op->value4));
12825            return (0);
12826        case XPATH_OP_SORT:
12827            if (op->ch1 != -1)
12828                total +=
12829                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12830                                            first);
12831	    CHECK_ERROR0;
12832            if ((ctxt->value != NULL)
12833                && (ctxt->value->type == XPATH_NODESET)
12834                && (ctxt->value->nodesetval != NULL)
12835		&& (ctxt->value->nodesetval->nodeNr > 1))
12836                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12837            return (total);
12838#ifdef XP_OPTIMIZED_FILTER_FIRST
12839	case XPATH_OP_FILTER:
12840                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12841            return (total);
12842#endif
12843        default:
12844            return (xmlXPathCompOpEval(ctxt, op));
12845    }
12846}
12847
12848/**
12849 * xmlXPathCompOpEvalLast:
12850 * @ctxt:  the XPath parser context with the compiled expression
12851 * @op:  an XPath compiled operation
12852 * @last:  the last elem found so far
12853 *
12854 * Evaluate the Precompiled XPath operation searching only the last
12855 * element in document order
12856 *
12857 * Returns the number of nodes traversed
12858 */
12859static int
12860xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12861                       xmlNodePtr * last)
12862{
12863    int total = 0, cur;
12864    xmlXPathCompExprPtr comp;
12865    xmlXPathObjectPtr arg1, arg2;
12866    xmlNodePtr bak;
12867    xmlDocPtr bakd;
12868    int pp;
12869    int cs;
12870
12871    CHECK_ERROR0;
12872    comp = ctxt->comp;
12873    switch (op->op) {
12874        case XPATH_OP_END:
12875            return (0);
12876        case XPATH_OP_UNION:
12877	    bakd = ctxt->context->doc;
12878	    bak = ctxt->context->node;
12879	    pp = ctxt->context->proximityPosition;
12880	    cs = ctxt->context->contextSize;
12881            total =
12882                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12883	    CHECK_ERROR0;
12884            if ((ctxt->value != NULL)
12885                && (ctxt->value->type == XPATH_NODESET)
12886                && (ctxt->value->nodesetval != NULL)
12887                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12888                /*
12889                 * limit tree traversing to first node in the result
12890                 */
12891		if (ctxt->value->nodesetval->nodeNr > 1)
12892		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12893                *last =
12894                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12895                                                     nodesetval->nodeNr -
12896                                                     1];
12897            }
12898	    ctxt->context->doc = bakd;
12899	    ctxt->context->node = bak;
12900	    ctxt->context->proximityPosition = pp;
12901	    ctxt->context->contextSize = cs;
12902            cur =
12903                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12904	    CHECK_ERROR0;
12905            if ((ctxt->value != NULL)
12906                && (ctxt->value->type == XPATH_NODESET)
12907                && (ctxt->value->nodesetval != NULL)
12908                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12909            }
12910            CHECK_TYPE0(XPATH_NODESET);
12911            arg2 = valuePop(ctxt);
12912
12913            CHECK_TYPE0(XPATH_NODESET);
12914            arg1 = valuePop(ctxt);
12915
12916            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12917                                                    arg2->nodesetval);
12918            valuePush(ctxt, arg1);
12919	    xmlXPathReleaseObject(ctxt->context, arg2);
12920            /* optimizer */
12921	    if (total > cur)
12922		xmlXPathCompSwap(op);
12923            return (total + cur);
12924        case XPATH_OP_ROOT:
12925            xmlXPathRoot(ctxt);
12926            return (0);
12927        case XPATH_OP_NODE:
12928            if (op->ch1 != -1)
12929                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12930	    CHECK_ERROR0;
12931            if (op->ch2 != -1)
12932                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12933	    CHECK_ERROR0;
12934	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12935		ctxt->context->node));
12936            return (total);
12937        case XPATH_OP_RESET:
12938            if (op->ch1 != -1)
12939                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12940	    CHECK_ERROR0;
12941            if (op->ch2 != -1)
12942                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12943	    CHECK_ERROR0;
12944            ctxt->context->node = NULL;
12945            return (total);
12946        case XPATH_OP_COLLECT:{
12947                if (op->ch1 == -1)
12948                    return (0);
12949
12950                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12951		CHECK_ERROR0;
12952
12953                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12954                return (total);
12955            }
12956        case XPATH_OP_VALUE:
12957            valuePush(ctxt,
12958                      xmlXPathCacheObjectCopy(ctxt->context,
12959			(xmlXPathObjectPtr) op->value4));
12960            return (0);
12961        case XPATH_OP_SORT:
12962            if (op->ch1 != -1)
12963                total +=
12964                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12965                                           last);
12966	    CHECK_ERROR0;
12967            if ((ctxt->value != NULL)
12968                && (ctxt->value->type == XPATH_NODESET)
12969                && (ctxt->value->nodesetval != NULL)
12970		&& (ctxt->value->nodesetval->nodeNr > 1))
12971                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12972            return (total);
12973        default:
12974            return (xmlXPathCompOpEval(ctxt, op));
12975    }
12976}
12977
12978#ifdef XP_OPTIMIZED_FILTER_FIRST
12979static int
12980xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12981			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12982{
12983    int total = 0;
12984    xmlXPathCompExprPtr comp;
12985    xmlXPathObjectPtr res;
12986    xmlXPathObjectPtr obj;
12987    xmlNodeSetPtr oldset;
12988    xmlNodePtr oldnode;
12989    xmlDocPtr oldDoc;
12990    int i;
12991
12992    CHECK_ERROR0;
12993    comp = ctxt->comp;
12994    /*
12995    * Optimization for ()[last()] selection i.e. the last elem
12996    */
12997    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12998	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12999	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13000	int f = comp->steps[op->ch2].ch1;
13001
13002	if ((f != -1) &&
13003	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13004	    (comp->steps[f].value5 == NULL) &&
13005	    (comp->steps[f].value == 0) &&
13006	    (comp->steps[f].value4 != NULL) &&
13007	    (xmlStrEqual
13008	    (comp->steps[f].value4, BAD_CAST "last"))) {
13009	    xmlNodePtr last = NULL;
13010
13011	    total +=
13012		xmlXPathCompOpEvalLast(ctxt,
13013		    &comp->steps[op->ch1],
13014		    &last);
13015	    CHECK_ERROR0;
13016	    /*
13017	    * The nodeset should be in document order,
13018	    * Keep only the last value
13019	    */
13020	    if ((ctxt->value != NULL) &&
13021		(ctxt->value->type == XPATH_NODESET) &&
13022		(ctxt->value->nodesetval != NULL) &&
13023		(ctxt->value->nodesetval->nodeTab != NULL) &&
13024		(ctxt->value->nodesetval->nodeNr > 1)) {
13025		ctxt->value->nodesetval->nodeTab[0] =
13026		    ctxt->value->nodesetval->nodeTab[ctxt->
13027		    value->
13028		    nodesetval->
13029		    nodeNr -
13030		    1];
13031		ctxt->value->nodesetval->nodeNr = 1;
13032		*first = *(ctxt->value->nodesetval->nodeTab);
13033	    }
13034	    return (total);
13035	}
13036    }
13037
13038    if (op->ch1 != -1)
13039	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13040    CHECK_ERROR0;
13041    if (op->ch2 == -1)
13042	return (total);
13043    if (ctxt->value == NULL)
13044	return (total);
13045
13046#ifdef LIBXML_XPTR_ENABLED
13047    oldnode = ctxt->context->node;
13048    /*
13049    * Hum are we filtering the result of an XPointer expression
13050    */
13051    if (ctxt->value->type == XPATH_LOCATIONSET) {
13052	xmlXPathObjectPtr tmp = NULL;
13053	xmlLocationSetPtr newlocset = NULL;
13054	xmlLocationSetPtr oldlocset;
13055
13056	/*
13057	* Extract the old locset, and then evaluate the result of the
13058	* expression for all the element in the locset. use it to grow
13059	* up a new locset.
13060	*/
13061	CHECK_TYPE0(XPATH_LOCATIONSET);
13062	obj = valuePop(ctxt);
13063	oldlocset = obj->user;
13064	ctxt->context->node = NULL;
13065
13066	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13067	    ctxt->context->contextSize = 0;
13068	    ctxt->context->proximityPosition = 0;
13069	    if (op->ch2 != -1)
13070		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13071	    res = valuePop(ctxt);
13072	    if (res != NULL) {
13073		xmlXPathReleaseObject(ctxt->context, res);
13074	    }
13075	    valuePush(ctxt, obj);
13076	    CHECK_ERROR0;
13077	    return (total);
13078	}
13079	newlocset = xmlXPtrLocationSetCreate(NULL);
13080
13081	for (i = 0; i < oldlocset->locNr; i++) {
13082	    /*
13083	    * Run the evaluation with a node list made of a
13084	    * single item in the nodelocset.
13085	    */
13086	    ctxt->context->node = oldlocset->locTab[i]->user;
13087	    ctxt->context->contextSize = oldlocset->locNr;
13088	    ctxt->context->proximityPosition = i + 1;
13089	    if (tmp == NULL) {
13090		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13091		    ctxt->context->node);
13092	    } else {
13093		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13094		                             ctxt->context->node) < 0) {
13095		    ctxt->error = XPATH_MEMORY_ERROR;
13096		}
13097	    }
13098	    valuePush(ctxt, tmp);
13099	    if (op->ch2 != -1)
13100		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13101	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13102		xmlXPathFreeObject(obj);
13103		return(0);
13104	    }
13105	    /*
13106	    * The result of the evaluation need to be tested to
13107	    * decided whether the filter succeeded or not
13108	    */
13109	    res = valuePop(ctxt);
13110	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13111		xmlXPtrLocationSetAdd(newlocset,
13112		    xmlXPathCacheObjectCopy(ctxt->context,
13113			oldlocset->locTab[i]));
13114	    }
13115	    /*
13116	    * Cleanup
13117	    */
13118	    if (res != NULL) {
13119		xmlXPathReleaseObject(ctxt->context, res);
13120	    }
13121	    if (ctxt->value == tmp) {
13122		valuePop(ctxt);
13123		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13124		/*
13125		* REVISIT TODO: Don't create a temporary nodeset
13126		* for everly iteration.
13127		*/
13128		/* OLD: xmlXPathFreeObject(res); */
13129	    } else
13130		tmp = NULL;
13131	    ctxt->context->node = NULL;
13132	    /*
13133	    * Only put the first node in the result, then leave.
13134	    */
13135	    if (newlocset->locNr > 0) {
13136		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
13137		break;
13138	    }
13139	}
13140	if (tmp != NULL) {
13141	    xmlXPathReleaseObject(ctxt->context, tmp);
13142	}
13143	/*
13144	* The result is used as the new evaluation locset.
13145	*/
13146	xmlXPathReleaseObject(ctxt->context, obj);
13147	ctxt->context->node = NULL;
13148	ctxt->context->contextSize = -1;
13149	ctxt->context->proximityPosition = -1;
13150	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13151	ctxt->context->node = oldnode;
13152	return (total);
13153    }
13154#endif /* LIBXML_XPTR_ENABLED */
13155
13156    /*
13157    * Extract the old set, and then evaluate the result of the
13158    * expression for all the element in the set. use it to grow
13159    * up a new set.
13160    */
13161    CHECK_TYPE0(XPATH_NODESET);
13162    obj = valuePop(ctxt);
13163    oldset = obj->nodesetval;
13164
13165    oldnode = ctxt->context->node;
13166    oldDoc = ctxt->context->doc;
13167    ctxt->context->node = NULL;
13168
13169    if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13170	ctxt->context->contextSize = 0;
13171	ctxt->context->proximityPosition = 0;
13172	/* QUESTION TODO: Why was this code commented out?
13173	    if (op->ch2 != -1)
13174		total +=
13175		    xmlXPathCompOpEval(ctxt,
13176			&comp->steps[op->ch2]);
13177	    CHECK_ERROR0;
13178	    res = valuePop(ctxt);
13179	    if (res != NULL)
13180		xmlXPathFreeObject(res);
13181	*/
13182	valuePush(ctxt, obj);
13183	ctxt->context->node = oldnode;
13184	CHECK_ERROR0;
13185    } else {
13186	xmlNodeSetPtr newset;
13187	xmlXPathObjectPtr tmp = NULL;
13188	/*
13189	* Initialize the new set.
13190	* Also set the xpath document in case things like
13191	* key() evaluation are attempted on the predicate
13192	*/
13193	newset = xmlXPathNodeSetCreate(NULL);
13194        /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13195
13196	for (i = 0; i < oldset->nodeNr; i++) {
13197	    /*
13198	    * Run the evaluation with a node list made of
13199	    * a single item in the nodeset.
13200	    */
13201	    ctxt->context->node = oldset->nodeTab[i];
13202	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13203		(oldset->nodeTab[i]->doc != NULL))
13204		ctxt->context->doc = oldset->nodeTab[i]->doc;
13205	    if (tmp == NULL) {
13206		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13207		    ctxt->context->node);
13208	    } else {
13209		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13210		                             ctxt->context->node) < 0) {
13211		    ctxt->error = XPATH_MEMORY_ERROR;
13212		}
13213	    }
13214	    valuePush(ctxt, tmp);
13215	    ctxt->context->contextSize = oldset->nodeNr;
13216	    ctxt->context->proximityPosition = i + 1;
13217	    if (op->ch2 != -1)
13218		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13219	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13220		xmlXPathFreeNodeSet(newset);
13221		xmlXPathFreeObject(obj);
13222		return(0);
13223	    }
13224	    /*
13225	    * The result of the evaluation needs to be tested to
13226	    * decide whether the filter succeeded or not
13227	    */
13228	    res = valuePop(ctxt);
13229	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13230		if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13231		    ctxt->error = XPATH_MEMORY_ERROR;
13232	    }
13233	    /*
13234	    * Cleanup
13235	    */
13236	    if (res != NULL) {
13237		xmlXPathReleaseObject(ctxt->context, res);
13238	    }
13239	    if (ctxt->value == tmp) {
13240		valuePop(ctxt);
13241		/*
13242		* Don't free the temporary nodeset
13243		* in order to avoid massive recreation inside this
13244		* loop.
13245		*/
13246		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13247	    } else
13248		tmp = NULL;
13249	    ctxt->context->node = NULL;
13250	    /*
13251	    * Only put the first node in the result, then leave.
13252	    */
13253	    if (newset->nodeNr > 0) {
13254		*first = *(newset->nodeTab);
13255		break;
13256	    }
13257	}
13258	if (tmp != NULL) {
13259	    xmlXPathReleaseObject(ctxt->context, tmp);
13260	}
13261	/*
13262	* The result is used as the new evaluation set.
13263	*/
13264	xmlXPathReleaseObject(ctxt->context, obj);
13265	ctxt->context->node = NULL;
13266	ctxt->context->contextSize = -1;
13267	ctxt->context->proximityPosition = -1;
13268	/* may want to move this past the '}' later */
13269	ctxt->context->doc = oldDoc;
13270	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13271    }
13272    ctxt->context->node = oldnode;
13273    return(total);
13274}
13275#endif /* XP_OPTIMIZED_FILTER_FIRST */
13276
13277/**
13278 * xmlXPathCompOpEval:
13279 * @ctxt:  the XPath parser context with the compiled expression
13280 * @op:  an XPath compiled operation
13281 *
13282 * Evaluate the Precompiled XPath operation
13283 * Returns the number of nodes traversed
13284 */
13285static int
13286xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13287{
13288    int total = 0;
13289    int equal, ret;
13290    xmlXPathCompExprPtr comp;
13291    xmlXPathObjectPtr arg1, arg2;
13292    xmlNodePtr bak;
13293    xmlDocPtr bakd;
13294    int pp;
13295    int cs;
13296
13297    CHECK_ERROR0;
13298    comp = ctxt->comp;
13299    switch (op->op) {
13300        case XPATH_OP_END:
13301            return (0);
13302        case XPATH_OP_AND:
13303	    bakd = ctxt->context->doc;
13304	    bak = ctxt->context->node;
13305	    pp = ctxt->context->proximityPosition;
13306	    cs = ctxt->context->contextSize;
13307            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13308	    CHECK_ERROR0;
13309            xmlXPathBooleanFunction(ctxt, 1);
13310            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13311                return (total);
13312            arg2 = valuePop(ctxt);
13313	    ctxt->context->doc = bakd;
13314	    ctxt->context->node = bak;
13315	    ctxt->context->proximityPosition = pp;
13316	    ctxt->context->contextSize = cs;
13317            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13318	    if (ctxt->error) {
13319		xmlXPathFreeObject(arg2);
13320		return(0);
13321	    }
13322            xmlXPathBooleanFunction(ctxt, 1);
13323            arg1 = valuePop(ctxt);
13324            arg1->boolval &= arg2->boolval;
13325            valuePush(ctxt, arg1);
13326	    xmlXPathReleaseObject(ctxt->context, arg2);
13327            return (total);
13328        case XPATH_OP_OR:
13329	    bakd = ctxt->context->doc;
13330	    bak = ctxt->context->node;
13331	    pp = ctxt->context->proximityPosition;
13332	    cs = ctxt->context->contextSize;
13333            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13334	    CHECK_ERROR0;
13335            xmlXPathBooleanFunction(ctxt, 1);
13336            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13337                return (total);
13338            arg2 = valuePop(ctxt);
13339	    ctxt->context->doc = bakd;
13340	    ctxt->context->node = bak;
13341	    ctxt->context->proximityPosition = pp;
13342	    ctxt->context->contextSize = cs;
13343            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13344	    if (ctxt->error) {
13345		xmlXPathFreeObject(arg2);
13346		return(0);
13347	    }
13348            xmlXPathBooleanFunction(ctxt, 1);
13349            arg1 = valuePop(ctxt);
13350            arg1->boolval |= arg2->boolval;
13351            valuePush(ctxt, arg1);
13352	    xmlXPathReleaseObject(ctxt->context, arg2);
13353            return (total);
13354        case XPATH_OP_EQUAL:
13355	    bakd = ctxt->context->doc;
13356	    bak = ctxt->context->node;
13357	    pp = ctxt->context->proximityPosition;
13358	    cs = ctxt->context->contextSize;
13359            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13360	    CHECK_ERROR0;
13361	    ctxt->context->doc = bakd;
13362	    ctxt->context->node = bak;
13363	    ctxt->context->proximityPosition = pp;
13364	    ctxt->context->contextSize = cs;
13365            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13366	    CHECK_ERROR0;
13367	    if (op->value)
13368		equal = xmlXPathEqualValues(ctxt);
13369	    else
13370		equal = xmlXPathNotEqualValues(ctxt);
13371	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13372            return (total);
13373        case XPATH_OP_CMP:
13374	    bakd = ctxt->context->doc;
13375	    bak = ctxt->context->node;
13376	    pp = ctxt->context->proximityPosition;
13377	    cs = ctxt->context->contextSize;
13378            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13379	    CHECK_ERROR0;
13380	    ctxt->context->doc = bakd;
13381	    ctxt->context->node = bak;
13382	    ctxt->context->proximityPosition = pp;
13383	    ctxt->context->contextSize = cs;
13384            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13385	    CHECK_ERROR0;
13386            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13387	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13388            return (total);
13389        case XPATH_OP_PLUS:
13390	    bakd = ctxt->context->doc;
13391	    bak = ctxt->context->node;
13392	    pp = ctxt->context->proximityPosition;
13393	    cs = ctxt->context->contextSize;
13394            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13395	    CHECK_ERROR0;
13396            if (op->ch2 != -1) {
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	    }
13403	    CHECK_ERROR0;
13404            if (op->value == 0)
13405                xmlXPathSubValues(ctxt);
13406            else if (op->value == 1)
13407                xmlXPathAddValues(ctxt);
13408            else if (op->value == 2)
13409                xmlXPathValueFlipSign(ctxt);
13410            else if (op->value == 3) {
13411                CAST_TO_NUMBER;
13412                CHECK_TYPE0(XPATH_NUMBER);
13413            }
13414            return (total);
13415        case XPATH_OP_MULT:
13416	    bakd = ctxt->context->doc;
13417	    bak = ctxt->context->node;
13418	    pp = ctxt->context->proximityPosition;
13419	    cs = ctxt->context->contextSize;
13420            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13421	    CHECK_ERROR0;
13422	    ctxt->context->doc = bakd;
13423	    ctxt->context->node = bak;
13424	    ctxt->context->proximityPosition = pp;
13425	    ctxt->context->contextSize = cs;
13426            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13427	    CHECK_ERROR0;
13428            if (op->value == 0)
13429                xmlXPathMultValues(ctxt);
13430            else if (op->value == 1)
13431                xmlXPathDivValues(ctxt);
13432            else if (op->value == 2)
13433                xmlXPathModValues(ctxt);
13434            return (total);
13435        case XPATH_OP_UNION:
13436	    bakd = ctxt->context->doc;
13437	    bak = ctxt->context->node;
13438	    pp = ctxt->context->proximityPosition;
13439	    cs = ctxt->context->contextSize;
13440            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13441	    CHECK_ERROR0;
13442	    ctxt->context->doc = bakd;
13443	    ctxt->context->node = bak;
13444	    ctxt->context->proximityPosition = pp;
13445	    ctxt->context->contextSize = cs;
13446            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13447	    CHECK_ERROR0;
13448            CHECK_TYPE0(XPATH_NODESET);
13449            arg2 = valuePop(ctxt);
13450
13451            CHECK_TYPE0(XPATH_NODESET);
13452            arg1 = valuePop(ctxt);
13453
13454	    if ((arg1->nodesetval == NULL) ||
13455		((arg2->nodesetval != NULL) &&
13456		 (arg2->nodesetval->nodeNr != 0)))
13457	    {
13458		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13459							arg2->nodesetval);
13460	    }
13461
13462            valuePush(ctxt, arg1);
13463	    xmlXPathReleaseObject(ctxt->context, arg2);
13464            return (total);
13465        case XPATH_OP_ROOT:
13466            xmlXPathRoot(ctxt);
13467            return (total);
13468        case XPATH_OP_NODE:
13469            if (op->ch1 != -1)
13470                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13471	    CHECK_ERROR0;
13472            if (op->ch2 != -1)
13473                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13474	    CHECK_ERROR0;
13475	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13476		ctxt->context->node));
13477            return (total);
13478        case XPATH_OP_RESET:
13479            if (op->ch1 != -1)
13480                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13481	    CHECK_ERROR0;
13482            if (op->ch2 != -1)
13483                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13484	    CHECK_ERROR0;
13485            ctxt->context->node = NULL;
13486            return (total);
13487        case XPATH_OP_COLLECT:{
13488                if (op->ch1 == -1)
13489                    return (total);
13490
13491                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13492		CHECK_ERROR0;
13493
13494                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13495                return (total);
13496            }
13497        case XPATH_OP_VALUE:
13498            valuePush(ctxt,
13499                      xmlXPathCacheObjectCopy(ctxt->context,
13500			(xmlXPathObjectPtr) op->value4));
13501            return (total);
13502        case XPATH_OP_VARIABLE:{
13503		xmlXPathObjectPtr val;
13504
13505                if (op->ch1 != -1)
13506                    total +=
13507                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13508                if (op->value5 == NULL) {
13509		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13510		    if (val == NULL) {
13511			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13512			return(0);
13513		    }
13514                    valuePush(ctxt, val);
13515		} else {
13516                    const xmlChar *URI;
13517
13518                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13519                    if (URI == NULL) {
13520                        xmlGenericError(xmlGenericErrorContext,
13521            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13522                                    (char *) op->value4, (char *)op->value5);
13523                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13524                        return (total);
13525                    }
13526		    val = xmlXPathVariableLookupNS(ctxt->context,
13527                                                       op->value4, URI);
13528		    if (val == NULL) {
13529			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13530			return(0);
13531		    }
13532                    valuePush(ctxt, val);
13533                }
13534                return (total);
13535            }
13536        case XPATH_OP_FUNCTION:{
13537                xmlXPathFunction func;
13538                const xmlChar *oldFunc, *oldFuncURI;
13539		int i;
13540                int frame;
13541
13542                frame = xmlXPathSetFrame(ctxt);
13543                if (op->ch1 != -1) {
13544                    total +=
13545                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13546                    if (ctxt->error != XPATH_EXPRESSION_OK) {
13547                        xmlXPathPopFrame(ctxt, frame);
13548                        return (total);
13549                    }
13550                }
13551		if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13552		    xmlGenericError(xmlGenericErrorContext,
13553			    "xmlXPathCompOpEval: parameter error\n");
13554		    ctxt->error = XPATH_INVALID_OPERAND;
13555                    xmlXPathPopFrame(ctxt, frame);
13556		    return (total);
13557		}
13558		for (i = 0; i < op->value; i++) {
13559		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13560			xmlGenericError(xmlGenericErrorContext,
13561				"xmlXPathCompOpEval: parameter error\n");
13562			ctxt->error = XPATH_INVALID_OPERAND;
13563                        xmlXPathPopFrame(ctxt, frame);
13564			return (total);
13565		    }
13566                }
13567                if (op->cache != NULL)
13568                    XML_CAST_FPTR(func) = op->cache;
13569                else {
13570                    const xmlChar *URI = NULL;
13571
13572                    if (op->value5 == NULL)
13573                        func =
13574                            xmlXPathFunctionLookup(ctxt->context,
13575                                                   op->value4);
13576                    else {
13577                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13578                        if (URI == NULL) {
13579                            xmlGenericError(xmlGenericErrorContext,
13580            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13581                                    (char *)op->value4, (char *)op->value5);
13582                            xmlXPathPopFrame(ctxt, frame);
13583                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13584                            return (total);
13585                        }
13586                        func = xmlXPathFunctionLookupNS(ctxt->context,
13587                                                        op->value4, URI);
13588                    }
13589                    if (func == NULL) {
13590                        xmlGenericError(xmlGenericErrorContext,
13591                                "xmlXPathCompOpEval: function %s not found\n",
13592                                        (char *)op->value4);
13593                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13594                    }
13595                    op->cache = XML_CAST_FPTR(func);
13596                    op->cacheURI = (void *) URI;
13597                }
13598                oldFunc = ctxt->context->function;
13599                oldFuncURI = ctxt->context->functionURI;
13600                ctxt->context->function = op->value4;
13601                ctxt->context->functionURI = op->cacheURI;
13602                func(ctxt, op->value);
13603                ctxt->context->function = oldFunc;
13604                ctxt->context->functionURI = oldFuncURI;
13605                xmlXPathPopFrame(ctxt, frame);
13606                return (total);
13607            }
13608        case XPATH_OP_ARG:
13609	    bakd = ctxt->context->doc;
13610	    bak = ctxt->context->node;
13611	    pp = ctxt->context->proximityPosition;
13612	    cs = ctxt->context->contextSize;
13613            if (op->ch1 != -1) {
13614                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13615                ctxt->context->contextSize = cs;
13616                ctxt->context->proximityPosition = pp;
13617                ctxt->context->node = bak;
13618                ctxt->context->doc = bakd;
13619	        CHECK_ERROR0;
13620            }
13621            if (op->ch2 != -1) {
13622                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13623                ctxt->context->contextSize = cs;
13624                ctxt->context->proximityPosition = pp;
13625                ctxt->context->node = bak;
13626                ctxt->context->doc = bakd;
13627	        CHECK_ERROR0;
13628	    }
13629            return (total);
13630        case XPATH_OP_PREDICATE:
13631        case XPATH_OP_FILTER:{
13632                xmlXPathObjectPtr res;
13633                xmlXPathObjectPtr obj, tmp;
13634                xmlNodeSetPtr newset = NULL;
13635                xmlNodeSetPtr oldset;
13636                xmlNodePtr oldnode;
13637		xmlDocPtr oldDoc;
13638                int i;
13639
13640                /*
13641                 * Optimization for ()[1] selection i.e. the first elem
13642                 */
13643                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13644#ifdef XP_OPTIMIZED_FILTER_FIRST
13645		    /*
13646		    * FILTER TODO: Can we assume that the inner processing
13647		    *  will result in an ordered list if we have an
13648		    *  XPATH_OP_FILTER?
13649		    *  What about an additional field or flag on
13650		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13651		    *  to assume anything, so it would be more robust and
13652		    *  easier to optimize.
13653		    */
13654                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13655		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13656#else
13657		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13658#endif
13659                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13660                    xmlXPathObjectPtr val;
13661
13662                    val = comp->steps[op->ch2].value4;
13663                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13664                        (val->floatval == 1.0)) {
13665                        xmlNodePtr first = NULL;
13666
13667                        total +=
13668                            xmlXPathCompOpEvalFirst(ctxt,
13669                                                    &comp->steps[op->ch1],
13670                                                    &first);
13671			CHECK_ERROR0;
13672                        /*
13673                         * The nodeset should be in document order,
13674                         * Keep only the first value
13675                         */
13676                        if ((ctxt->value != NULL) &&
13677                            (ctxt->value->type == XPATH_NODESET) &&
13678                            (ctxt->value->nodesetval != NULL) &&
13679                            (ctxt->value->nodesetval->nodeNr > 1))
13680                            ctxt->value->nodesetval->nodeNr = 1;
13681                        return (total);
13682                    }
13683                }
13684                /*
13685                 * Optimization for ()[last()] selection i.e. the last elem
13686                 */
13687                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13688                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13689                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13690                    int f = comp->steps[op->ch2].ch1;
13691
13692                    if ((f != -1) &&
13693                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13694                        (comp->steps[f].value5 == NULL) &&
13695                        (comp->steps[f].value == 0) &&
13696                        (comp->steps[f].value4 != NULL) &&
13697                        (xmlStrEqual
13698                         (comp->steps[f].value4, BAD_CAST "last"))) {
13699                        xmlNodePtr last = NULL;
13700
13701                        total +=
13702                            xmlXPathCompOpEvalLast(ctxt,
13703                                                   &comp->steps[op->ch1],
13704                                                   &last);
13705			CHECK_ERROR0;
13706                        /*
13707                         * The nodeset should be in document order,
13708                         * Keep only the last value
13709                         */
13710                        if ((ctxt->value != NULL) &&
13711                            (ctxt->value->type == XPATH_NODESET) &&
13712                            (ctxt->value->nodesetval != NULL) &&
13713                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13714                            (ctxt->value->nodesetval->nodeNr > 1)) {
13715                            ctxt->value->nodesetval->nodeTab[0] =
13716                                ctxt->value->nodesetval->nodeTab[ctxt->
13717                                                                 value->
13718                                                                 nodesetval->
13719                                                                 nodeNr -
13720                                                                 1];
13721                            ctxt->value->nodesetval->nodeNr = 1;
13722                        }
13723                        return (total);
13724                    }
13725                }
13726		/*
13727		* Process inner predicates first.
13728		* Example "index[parent::book][1]":
13729		* ...
13730		*   PREDICATE   <-- we are here "[1]"
13731		*     PREDICATE <-- process "[parent::book]" first
13732		*       SORT
13733		*         COLLECT  'parent' 'name' 'node' book
13734		*           NODE
13735		*     ELEM Object is a number : 1
13736		*/
13737                if (op->ch1 != -1)
13738                    total +=
13739                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13740		CHECK_ERROR0;
13741                if (op->ch2 == -1)
13742                    return (total);
13743                if (ctxt->value == NULL)
13744                    return (total);
13745
13746                oldnode = ctxt->context->node;
13747
13748#ifdef LIBXML_XPTR_ENABLED
13749                /*
13750                 * Hum are we filtering the result of an XPointer expression
13751                 */
13752                if (ctxt->value->type == XPATH_LOCATIONSET) {
13753                    xmlLocationSetPtr newlocset = NULL;
13754                    xmlLocationSetPtr oldlocset;
13755
13756                    /*
13757                     * Extract the old locset, and then evaluate the result of the
13758                     * expression for all the element in the locset. use it to grow
13759                     * up a new locset.
13760                     */
13761                    CHECK_TYPE0(XPATH_LOCATIONSET);
13762                    obj = valuePop(ctxt);
13763                    oldlocset = obj->user;
13764                    ctxt->context->node = NULL;
13765
13766                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13767                        ctxt->context->contextSize = 0;
13768                        ctxt->context->proximityPosition = 0;
13769                        if (op->ch2 != -1)
13770                            total +=
13771                                xmlXPathCompOpEval(ctxt,
13772                                                   &comp->steps[op->ch2]);
13773                        res = valuePop(ctxt);
13774                        if (res != NULL) {
13775			    xmlXPathReleaseObject(ctxt->context, res);
13776			}
13777                        valuePush(ctxt, obj);
13778                        CHECK_ERROR0;
13779                        return (total);
13780                    }
13781                    newlocset = xmlXPtrLocationSetCreate(NULL);
13782
13783                    for (i = 0; i < oldlocset->locNr; i++) {
13784                        /*
13785                         * Run the evaluation with a node list made of a
13786                         * single item in the nodelocset.
13787                         */
13788                        ctxt->context->node = oldlocset->locTab[i]->user;
13789                        ctxt->context->contextSize = oldlocset->locNr;
13790                        ctxt->context->proximityPosition = i + 1;
13791			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13792			    ctxt->context->node);
13793                        valuePush(ctxt, tmp);
13794
13795                        if (op->ch2 != -1)
13796                            total +=
13797                                xmlXPathCompOpEval(ctxt,
13798                                                   &comp->steps[op->ch2]);
13799			if (ctxt->error != XPATH_EXPRESSION_OK) {
13800			    xmlXPathFreeObject(obj);
13801			    return(0);
13802			}
13803
13804                        /*
13805                         * The result of the evaluation need to be tested to
13806                         * decided whether the filter succeeded or not
13807                         */
13808                        res = valuePop(ctxt);
13809                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13810                            xmlXPtrLocationSetAdd(newlocset,
13811                                                  xmlXPathObjectCopy
13812                                                  (oldlocset->locTab[i]));
13813                        }
13814
13815                        /*
13816                         * Cleanup
13817                         */
13818                        if (res != NULL) {
13819			    xmlXPathReleaseObject(ctxt->context, res);
13820			}
13821                        if (ctxt->value == tmp) {
13822                            res = valuePop(ctxt);
13823			    xmlXPathReleaseObject(ctxt->context, res);
13824                        }
13825
13826                        ctxt->context->node = NULL;
13827                    }
13828
13829                    /*
13830                     * The result is used as the new evaluation locset.
13831                     */
13832		    xmlXPathReleaseObject(ctxt->context, obj);
13833                    ctxt->context->node = NULL;
13834                    ctxt->context->contextSize = -1;
13835                    ctxt->context->proximityPosition = -1;
13836                    valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13837                    ctxt->context->node = oldnode;
13838                    return (total);
13839                }
13840#endif /* LIBXML_XPTR_ENABLED */
13841
13842                /*
13843                 * Extract the old set, and then evaluate the result of the
13844                 * expression for all the element in the set. use it to grow
13845                 * up a new set.
13846                 */
13847                CHECK_TYPE0(XPATH_NODESET);
13848                obj = valuePop(ctxt);
13849                oldset = obj->nodesetval;
13850
13851                oldnode = ctxt->context->node;
13852		oldDoc = ctxt->context->doc;
13853                ctxt->context->node = NULL;
13854
13855                if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13856                    ctxt->context->contextSize = 0;
13857                    ctxt->context->proximityPosition = 0;
13858/*
13859                    if (op->ch2 != -1)
13860                        total +=
13861                            xmlXPathCompOpEval(ctxt,
13862                                               &comp->steps[op->ch2]);
13863		    CHECK_ERROR0;
13864                    res = valuePop(ctxt);
13865                    if (res != NULL)
13866                        xmlXPathFreeObject(res);
13867*/
13868                    valuePush(ctxt, obj);
13869                    ctxt->context->node = oldnode;
13870                    CHECK_ERROR0;
13871                } else {
13872		    tmp = NULL;
13873                    /*
13874                     * Initialize the new set.
13875		     * Also set the xpath document in case things like
13876		     * key() evaluation are attempted on the predicate
13877                     */
13878                    newset = xmlXPathNodeSetCreate(NULL);
13879		    /*
13880		    * SPEC XPath 1.0:
13881		    *  "For each node in the node-set to be filtered, the
13882		    *  PredicateExpr is evaluated with that node as the
13883		    *  context node, with the number of nodes in the
13884		    *  node-set as the context size, and with the proximity
13885		    *  position of the node in the node-set with respect to
13886		    *  the axis as the context position;"
13887		    * @oldset is the node-set" to be filtered.
13888		    *
13889		    * SPEC XPath 1.0:
13890		    *  "only predicates change the context position and
13891		    *  context size (see [2.4 Predicates])."
13892		    * Example:
13893		    *   node-set  context pos
13894		    *    nA         1
13895		    *    nB         2
13896		    *    nC         3
13897		    *   After applying predicate [position() > 1] :
13898		    *   node-set  context pos
13899		    *    nB         1
13900		    *    nC         2
13901		    *
13902		    * removed the first node in the node-set, then
13903		    * the context position of the
13904		    */
13905                    for (i = 0; i < oldset->nodeNr; i++) {
13906                        /*
13907                         * Run the evaluation with a node list made of
13908                         * a single item in the nodeset.
13909                         */
13910                        ctxt->context->node = oldset->nodeTab[i];
13911			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13912			    (oldset->nodeTab[i]->doc != NULL))
13913		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13914			if (tmp == NULL) {
13915			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13916				ctxt->context->node);
13917			} else {
13918			    if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13919				               ctxt->context->node) < 0) {
13920				ctxt->error = XPATH_MEMORY_ERROR;
13921			    }
13922			}
13923                        valuePush(ctxt, tmp);
13924                        ctxt->context->contextSize = oldset->nodeNr;
13925                        ctxt->context->proximityPosition = i + 1;
13926			/*
13927			* Evaluate the predicate against the context node.
13928			* Can/should we optimize position() predicates
13929			* here (e.g. "[1]")?
13930			*/
13931                        if (op->ch2 != -1)
13932                            total +=
13933                                xmlXPathCompOpEval(ctxt,
13934                                                   &comp->steps[op->ch2]);
13935			if (ctxt->error != XPATH_EXPRESSION_OK) {
13936			    xmlXPathFreeNodeSet(newset);
13937			    xmlXPathFreeObject(obj);
13938			    return(0);
13939			}
13940
13941                        /*
13942                         * The result of the evaluation needs to be tested to
13943                         * decide whether the filter succeeded or not
13944                         */
13945			/*
13946			* OPTIMIZE TODO: Can we use
13947			* xmlXPathNodeSetAdd*Unique()* instead?
13948			*/
13949                        res = valuePop(ctxt);
13950                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13951                            if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13952			        < 0)
13953				ctxt->error = XPATH_MEMORY_ERROR;
13954                        }
13955
13956                        /*
13957                         * Cleanup
13958                         */
13959                        if (res != NULL) {
13960			    xmlXPathReleaseObject(ctxt->context, res);
13961			}
13962                        if (ctxt->value == tmp) {
13963                            valuePop(ctxt);
13964			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13965			    /*
13966			    * Don't free the temporary nodeset
13967			    * in order to avoid massive recreation inside this
13968			    * loop.
13969			    */
13970                        } else
13971			    tmp = NULL;
13972                        ctxt->context->node = NULL;
13973                    }
13974		    if (tmp != NULL)
13975			xmlXPathReleaseObject(ctxt->context, tmp);
13976                    /*
13977                     * The result is used as the new evaluation set.
13978                     */
13979		    xmlXPathReleaseObject(ctxt->context, obj);
13980                    ctxt->context->node = NULL;
13981                    ctxt->context->contextSize = -1;
13982                    ctxt->context->proximityPosition = -1;
13983		    /* may want to move this past the '}' later */
13984		    ctxt->context->doc = oldDoc;
13985		    valuePush(ctxt,
13986			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13987                }
13988                ctxt->context->node = oldnode;
13989                return (total);
13990            }
13991        case XPATH_OP_SORT:
13992            if (op->ch1 != -1)
13993                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13994	    CHECK_ERROR0;
13995            if ((ctxt->value != NULL) &&
13996                (ctxt->value->type == XPATH_NODESET) &&
13997                (ctxt->value->nodesetval != NULL) &&
13998		(ctxt->value->nodesetval->nodeNr > 1))
13999	    {
14000                xmlXPathNodeSetSort(ctxt->value->nodesetval);
14001	    }
14002            return (total);
14003#ifdef LIBXML_XPTR_ENABLED
14004        case XPATH_OP_RANGETO:{
14005                xmlXPathObjectPtr range;
14006                xmlXPathObjectPtr res, obj;
14007                xmlXPathObjectPtr tmp;
14008                xmlLocationSetPtr newlocset = NULL;
14009		    xmlLocationSetPtr oldlocset;
14010                xmlNodeSetPtr oldset;
14011                int i, j;
14012
14013                if (op->ch1 != -1) {
14014                    total +=
14015                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
14016                    CHECK_ERROR0;
14017                }
14018                if (ctxt->value == NULL) {
14019                    XP_ERROR0(XPATH_INVALID_OPERAND);
14020                }
14021                if (op->ch2 == -1)
14022                    return (total);
14023
14024                if (ctxt->value->type == XPATH_LOCATIONSET) {
14025                    /*
14026                     * Extract the old locset, and then evaluate the result of the
14027                     * expression for all the element in the locset. use it to grow
14028                     * up a new locset.
14029                     */
14030                    CHECK_TYPE0(XPATH_LOCATIONSET);
14031                    obj = valuePop(ctxt);
14032                    oldlocset = obj->user;
14033
14034                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
14035		        ctxt->context->node = NULL;
14036                        ctxt->context->contextSize = 0;
14037                        ctxt->context->proximityPosition = 0;
14038                        total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
14039                        res = valuePop(ctxt);
14040                        if (res != NULL) {
14041			    xmlXPathReleaseObject(ctxt->context, res);
14042			}
14043                        valuePush(ctxt, obj);
14044                        CHECK_ERROR0;
14045                        return (total);
14046                    }
14047                    newlocset = xmlXPtrLocationSetCreate(NULL);
14048
14049                    for (i = 0; i < oldlocset->locNr; i++) {
14050                        /*
14051                         * Run the evaluation with a node list made of a
14052                         * single item in the nodelocset.
14053                         */
14054                        ctxt->context->node = oldlocset->locTab[i]->user;
14055                        ctxt->context->contextSize = oldlocset->locNr;
14056                        ctxt->context->proximityPosition = i + 1;
14057			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14058			    ctxt->context->node);
14059                        valuePush(ctxt, tmp);
14060
14061                        if (op->ch2 != -1)
14062                            total +=
14063                                xmlXPathCompOpEval(ctxt,
14064                                                   &comp->steps[op->ch2]);
14065			if (ctxt->error != XPATH_EXPRESSION_OK) {
14066			    xmlXPathFreeObject(obj);
14067			    return(0);
14068			}
14069
14070                        res = valuePop(ctxt);
14071			if (res->type == XPATH_LOCATIONSET) {
14072			    xmlLocationSetPtr rloc =
14073			        (xmlLocationSetPtr)res->user;
14074			    for (j=0; j<rloc->locNr; j++) {
14075			        range = xmlXPtrNewRange(
14076				  oldlocset->locTab[i]->user,
14077				  oldlocset->locTab[i]->index,
14078				  rloc->locTab[j]->user2,
14079				  rloc->locTab[j]->index2);
14080				if (range != NULL) {
14081				    xmlXPtrLocationSetAdd(newlocset, range);
14082				}
14083			    }
14084			} else {
14085			    range = xmlXPtrNewRangeNodeObject(
14086				(xmlNodePtr)oldlocset->locTab[i]->user, res);
14087                            if (range != NULL) {
14088                                xmlXPtrLocationSetAdd(newlocset,range);
14089			    }
14090                        }
14091
14092                        /*
14093                         * Cleanup
14094                         */
14095                        if (res != NULL) {
14096			    xmlXPathReleaseObject(ctxt->context, res);
14097			}
14098                        if (ctxt->value == tmp) {
14099                            res = valuePop(ctxt);
14100			    xmlXPathReleaseObject(ctxt->context, res);
14101                        }
14102
14103                        ctxt->context->node = NULL;
14104                    }
14105		} else {	/* Not a location set */
14106                    CHECK_TYPE0(XPATH_NODESET);
14107                    obj = valuePop(ctxt);
14108                    oldset = obj->nodesetval;
14109                    ctxt->context->node = NULL;
14110
14111                    newlocset = xmlXPtrLocationSetCreate(NULL);
14112
14113                    if (oldset != NULL) {
14114                        for (i = 0; i < oldset->nodeNr; i++) {
14115                            /*
14116                             * Run the evaluation with a node list made of a single item
14117                             * in the nodeset.
14118                             */
14119                            ctxt->context->node = oldset->nodeTab[i];
14120			    /*
14121			    * OPTIMIZE TODO: Avoid recreation for every iteration.
14122			    */
14123			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14124				ctxt->context->node);
14125                            valuePush(ctxt, tmp);
14126
14127                            if (op->ch2 != -1)
14128                                total +=
14129                                    xmlXPathCompOpEval(ctxt,
14130                                                   &comp->steps[op->ch2]);
14131			    if (ctxt->error != XPATH_EXPRESSION_OK) {
14132				xmlXPathFreeObject(obj);
14133				return(0);
14134			    }
14135
14136                            res = valuePop(ctxt);
14137                            range =
14138                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14139                                                      res);
14140                            if (range != NULL) {
14141                                xmlXPtrLocationSetAdd(newlocset, range);
14142                            }
14143
14144                            /*
14145                             * Cleanup
14146                             */
14147                            if (res != NULL) {
14148				xmlXPathReleaseObject(ctxt->context, res);
14149			    }
14150                            if (ctxt->value == tmp) {
14151                                res = valuePop(ctxt);
14152				xmlXPathReleaseObject(ctxt->context, res);
14153                            }
14154
14155                            ctxt->context->node = NULL;
14156                        }
14157                    }
14158                }
14159
14160                /*
14161                 * The result is used as the new evaluation set.
14162                 */
14163		xmlXPathReleaseObject(ctxt->context, obj);
14164                ctxt->context->node = NULL;
14165                ctxt->context->contextSize = -1;
14166                ctxt->context->proximityPosition = -1;
14167                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14168                return (total);
14169            }
14170#endif /* LIBXML_XPTR_ENABLED */
14171    }
14172    xmlGenericError(xmlGenericErrorContext,
14173                    "XPath: unknown precompiled operation %d\n", op->op);
14174    ctxt->error = XPATH_INVALID_OPERAND;
14175    return (total);
14176}
14177
14178/**
14179 * xmlXPathCompOpEvalToBoolean:
14180 * @ctxt:  the XPath parser context
14181 *
14182 * Evaluates if the expression evaluates to true.
14183 *
14184 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14185 */
14186static int
14187xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14188			    xmlXPathStepOpPtr op,
14189			    int isPredicate)
14190{
14191    xmlXPathObjectPtr resObj = NULL;
14192
14193start:
14194    /* comp = ctxt->comp; */
14195    switch (op->op) {
14196        case XPATH_OP_END:
14197            return (0);
14198	case XPATH_OP_VALUE:
14199	    resObj = (xmlXPathObjectPtr) op->value4;
14200	    if (isPredicate)
14201		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14202	    return(xmlXPathCastToBoolean(resObj));
14203	case XPATH_OP_SORT:
14204	    /*
14205	    * We don't need sorting for boolean results. Skip this one.
14206	    */
14207            if (op->ch1 != -1) {
14208		op = &ctxt->comp->steps[op->ch1];
14209		goto start;
14210	    }
14211	    return(0);
14212	case XPATH_OP_COLLECT:
14213	    if (op->ch1 == -1)
14214		return(0);
14215
14216            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14217	    if (ctxt->error != XPATH_EXPRESSION_OK)
14218		return(-1);
14219
14220            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14221	    if (ctxt->error != XPATH_EXPRESSION_OK)
14222		return(-1);
14223
14224	    resObj = valuePop(ctxt);
14225	    if (resObj == NULL)
14226		return(-1);
14227	    break;
14228	default:
14229	    /*
14230	    * Fallback to call xmlXPathCompOpEval().
14231	    */
14232	    xmlXPathCompOpEval(ctxt, op);
14233	    if (ctxt->error != XPATH_EXPRESSION_OK)
14234		return(-1);
14235
14236	    resObj = valuePop(ctxt);
14237	    if (resObj == NULL)
14238		return(-1);
14239	    break;
14240    }
14241
14242    if (resObj) {
14243	int res;
14244
14245	if (resObj->type == XPATH_BOOLEAN) {
14246	    res = resObj->boolval;
14247	} else if (isPredicate) {
14248	    /*
14249	    * For predicates a result of type "number" is handled
14250	    * differently:
14251	    * SPEC XPath 1.0:
14252	    * "If the result is a number, the result will be converted
14253	    *  to true if the number is equal to the context position
14254	    *  and will be converted to false otherwise;"
14255	    */
14256	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14257	} else {
14258	    res = xmlXPathCastToBoolean(resObj);
14259	}
14260	xmlXPathReleaseObject(ctxt->context, resObj);
14261	return(res);
14262    }
14263
14264    return(0);
14265}
14266
14267#ifdef XPATH_STREAMING
14268/**
14269 * xmlXPathRunStreamEval:
14270 * @ctxt:  the XPath parser context with the compiled expression
14271 *
14272 * Evaluate the Precompiled Streamable XPath expression in the given context.
14273 */
14274static int
14275xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14276		      xmlXPathObjectPtr *resultSeq, int toBool)
14277{
14278    int max_depth, min_depth;
14279    int from_root;
14280    int ret, depth;
14281    int eval_all_nodes;
14282    xmlNodePtr cur = NULL, limit = NULL;
14283    xmlStreamCtxtPtr patstream = NULL;
14284
14285    int nb_nodes = 0;
14286
14287    if ((ctxt == NULL) || (comp == NULL))
14288        return(-1);
14289    max_depth = xmlPatternMaxDepth(comp);
14290    if (max_depth == -1)
14291        return(-1);
14292    if (max_depth == -2)
14293        max_depth = 10000;
14294    min_depth = xmlPatternMinDepth(comp);
14295    if (min_depth == -1)
14296        return(-1);
14297    from_root = xmlPatternFromRoot(comp);
14298    if (from_root < 0)
14299        return(-1);
14300#if 0
14301    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14302#endif
14303
14304    if (! toBool) {
14305	if (resultSeq == NULL)
14306	    return(-1);
14307	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14308	if (*resultSeq == NULL)
14309	    return(-1);
14310    }
14311
14312    /*
14313     * handle the special cases of "/" amd "." being matched
14314     */
14315    if (min_depth == 0) {
14316	if (from_root) {
14317	    /* Select "/" */
14318	    if (toBool)
14319		return(1);
14320	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14321		                     (xmlNodePtr) ctxt->doc);
14322	} else {
14323	    /* Select "self::node()" */
14324	    if (toBool)
14325		return(1);
14326	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14327	}
14328    }
14329    if (max_depth == 0) {
14330	return(0);
14331    }
14332
14333    if (from_root) {
14334        cur = (xmlNodePtr)ctxt->doc;
14335    } else if (ctxt->node != NULL) {
14336        switch (ctxt->node->type) {
14337            case XML_ELEMENT_NODE:
14338            case XML_DOCUMENT_NODE:
14339            case XML_DOCUMENT_FRAG_NODE:
14340            case XML_HTML_DOCUMENT_NODE:
14341#ifdef LIBXML_DOCB_ENABLED
14342            case XML_DOCB_DOCUMENT_NODE:
14343#endif
14344	        cur = ctxt->node;
14345		break;
14346            case XML_ATTRIBUTE_NODE:
14347            case XML_TEXT_NODE:
14348            case XML_CDATA_SECTION_NODE:
14349            case XML_ENTITY_REF_NODE:
14350            case XML_ENTITY_NODE:
14351            case XML_PI_NODE:
14352            case XML_COMMENT_NODE:
14353            case XML_NOTATION_NODE:
14354            case XML_DTD_NODE:
14355            case XML_DOCUMENT_TYPE_NODE:
14356            case XML_ELEMENT_DECL:
14357            case XML_ATTRIBUTE_DECL:
14358            case XML_ENTITY_DECL:
14359            case XML_NAMESPACE_DECL:
14360            case XML_XINCLUDE_START:
14361            case XML_XINCLUDE_END:
14362		break;
14363	}
14364	limit = cur;
14365    }
14366    if (cur == NULL) {
14367        return(0);
14368    }
14369
14370    patstream = xmlPatternGetStreamCtxt(comp);
14371    if (patstream == NULL) {
14372	/*
14373	* QUESTION TODO: Is this an error?
14374	*/
14375	return(0);
14376    }
14377
14378    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14379
14380    if (from_root) {
14381	ret = xmlStreamPush(patstream, NULL, NULL);
14382	if (ret < 0) {
14383	} else if (ret == 1) {
14384	    if (toBool)
14385		goto return_1;
14386	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14387	}
14388    }
14389    depth = 0;
14390    goto scan_children;
14391next_node:
14392    do {
14393        nb_nodes++;
14394
14395	switch (cur->type) {
14396	    case XML_ELEMENT_NODE:
14397	    case XML_TEXT_NODE:
14398	    case XML_CDATA_SECTION_NODE:
14399	    case XML_COMMENT_NODE:
14400	    case XML_PI_NODE:
14401		if (cur->type == XML_ELEMENT_NODE) {
14402		    ret = xmlStreamPush(patstream, cur->name,
14403				(cur->ns ? cur->ns->href : NULL));
14404		} else if (eval_all_nodes)
14405		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14406		else
14407		    break;
14408
14409		if (ret < 0) {
14410		    /* NOP. */
14411		} else if (ret == 1) {
14412		    if (toBool)
14413			goto return_1;
14414		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14415		        < 0) {
14416			ctxt->lastError.domain = XML_FROM_XPATH;
14417			ctxt->lastError.code = XML_ERR_NO_MEMORY;
14418		    }
14419		}
14420		if ((cur->children == NULL) || (depth >= max_depth)) {
14421		    ret = xmlStreamPop(patstream);
14422		    while (cur->next != NULL) {
14423			cur = cur->next;
14424			if ((cur->type != XML_ENTITY_DECL) &&
14425			    (cur->type != XML_DTD_NODE))
14426			    goto next_node;
14427		    }
14428		}
14429	    default:
14430		break;
14431	}
14432
14433scan_children:
14434	if (cur->type == XML_NAMESPACE_DECL) break;
14435	if ((cur->children != NULL) && (depth < max_depth)) {
14436	    /*
14437	     * Do not descend on entities declarations
14438	     */
14439	    if (cur->children->type != XML_ENTITY_DECL) {
14440		cur = cur->children;
14441		depth++;
14442		/*
14443		 * Skip DTDs
14444		 */
14445		if (cur->type != XML_DTD_NODE)
14446		    continue;
14447	    }
14448	}
14449
14450	if (cur == limit)
14451	    break;
14452
14453	while (cur->next != NULL) {
14454	    cur = cur->next;
14455	    if ((cur->type != XML_ENTITY_DECL) &&
14456		(cur->type != XML_DTD_NODE))
14457		goto next_node;
14458	}
14459
14460	do {
14461	    cur = cur->parent;
14462	    depth--;
14463	    if ((cur == NULL) || (cur == limit))
14464	        goto done;
14465	    if (cur->type == XML_ELEMENT_NODE) {
14466		ret = xmlStreamPop(patstream);
14467	    } else if ((eval_all_nodes) &&
14468		((cur->type == XML_TEXT_NODE) ||
14469		 (cur->type == XML_CDATA_SECTION_NODE) ||
14470		 (cur->type == XML_COMMENT_NODE) ||
14471		 (cur->type == XML_PI_NODE)))
14472	    {
14473		ret = xmlStreamPop(patstream);
14474	    }
14475	    if (cur->next != NULL) {
14476		cur = cur->next;
14477		break;
14478	    }
14479	} while (cur != NULL);
14480
14481    } while ((cur != NULL) && (depth >= 0));
14482
14483done:
14484
14485#if 0
14486    printf("stream eval: checked %d nodes selected %d\n",
14487           nb_nodes, retObj->nodesetval->nodeNr);
14488#endif
14489
14490    if (patstream)
14491	xmlFreeStreamCtxt(patstream);
14492    return(0);
14493
14494return_1:
14495    if (patstream)
14496	xmlFreeStreamCtxt(patstream);
14497    return(1);
14498}
14499#endif /* XPATH_STREAMING */
14500
14501/**
14502 * xmlXPathRunEval:
14503 * @ctxt:  the XPath parser context with the compiled expression
14504 * @toBool:  evaluate to a boolean result
14505 *
14506 * Evaluate the Precompiled XPath expression in the given context.
14507 */
14508static int
14509xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14510{
14511    xmlXPathCompExprPtr comp;
14512
14513    if ((ctxt == NULL) || (ctxt->comp == NULL))
14514	return(-1);
14515
14516    if (ctxt->valueTab == NULL) {
14517	/* Allocate the value stack */
14518	ctxt->valueTab = (xmlXPathObjectPtr *)
14519			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14520	if (ctxt->valueTab == NULL) {
14521	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14522	    xmlFree(ctxt);
14523	}
14524	ctxt->valueNr = 0;
14525	ctxt->valueMax = 10;
14526	ctxt->value = NULL;
14527        ctxt->valueFrame = 0;
14528    }
14529#ifdef XPATH_STREAMING
14530    if (ctxt->comp->stream) {
14531	int res;
14532
14533	if (toBool) {
14534	    /*
14535	    * Evaluation to boolean result.
14536	    */
14537	    res = xmlXPathRunStreamEval(ctxt->context,
14538		ctxt->comp->stream, NULL, 1);
14539	    if (res != -1)
14540		return(res);
14541	} else {
14542	    xmlXPathObjectPtr resObj = NULL;
14543
14544	    /*
14545	    * Evaluation to a sequence.
14546	    */
14547	    res = xmlXPathRunStreamEval(ctxt->context,
14548		ctxt->comp->stream, &resObj, 0);
14549
14550	    if ((res != -1) && (resObj != NULL)) {
14551		valuePush(ctxt, resObj);
14552		return(0);
14553	    }
14554	    if (resObj != NULL)
14555		xmlXPathReleaseObject(ctxt->context, resObj);
14556	}
14557	/*
14558	* QUESTION TODO: This falls back to normal XPath evaluation
14559	* if res == -1. Is this intended?
14560	*/
14561    }
14562#endif
14563    comp = ctxt->comp;
14564    if (comp->last < 0) {
14565	xmlGenericError(xmlGenericErrorContext,
14566	    "xmlXPathRunEval: last is less than zero\n");
14567	return(-1);
14568    }
14569    if (toBool)
14570	return(xmlXPathCompOpEvalToBoolean(ctxt,
14571	    &comp->steps[comp->last], 0));
14572    else
14573	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14574
14575    return(0);
14576}
14577
14578/************************************************************************
14579 *									*
14580 *			Public interfaces				*
14581 *									*
14582 ************************************************************************/
14583
14584/**
14585 * xmlXPathEvalPredicate:
14586 * @ctxt:  the XPath context
14587 * @res:  the Predicate Expression evaluation result
14588 *
14589 * Evaluate a predicate result for the current node.
14590 * A PredicateExpr is evaluated by evaluating the Expr and converting
14591 * the result to a boolean. If the result is a number, the result will
14592 * be converted to true if the number is equal to the position of the
14593 * context node in the context node list (as returned by the position
14594 * function) and will be converted to false otherwise; if the result
14595 * is not a number, then the result will be converted as if by a call
14596 * to the boolean function.
14597 *
14598 * Returns 1 if predicate is true, 0 otherwise
14599 */
14600int
14601xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14602    if ((ctxt == NULL) || (res == NULL)) return(0);
14603    switch (res->type) {
14604        case XPATH_BOOLEAN:
14605	    return(res->boolval);
14606        case XPATH_NUMBER:
14607	    return(res->floatval == ctxt->proximityPosition);
14608        case XPATH_NODESET:
14609        case XPATH_XSLT_TREE:
14610	    if (res->nodesetval == NULL)
14611		return(0);
14612	    return(res->nodesetval->nodeNr != 0);
14613        case XPATH_STRING:
14614	    return((res->stringval != NULL) &&
14615	           (xmlStrlen(res->stringval) != 0));
14616        default:
14617	    STRANGE
14618    }
14619    return(0);
14620}
14621
14622/**
14623 * xmlXPathEvaluatePredicateResult:
14624 * @ctxt:  the XPath Parser context
14625 * @res:  the Predicate Expression evaluation result
14626 *
14627 * Evaluate a predicate result for the current node.
14628 * A PredicateExpr is evaluated by evaluating the Expr and converting
14629 * the result to a boolean. If the result is a number, the result will
14630 * be converted to true if the number is equal to the position of the
14631 * context node in the context node list (as returned by the position
14632 * function) and will be converted to false otherwise; if the result
14633 * is not a number, then the result will be converted as if by a call
14634 * to the boolean function.
14635 *
14636 * Returns 1 if predicate is true, 0 otherwise
14637 */
14638int
14639xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14640                                xmlXPathObjectPtr res) {
14641    if ((ctxt == NULL) || (res == NULL)) return(0);
14642    switch (res->type) {
14643        case XPATH_BOOLEAN:
14644	    return(res->boolval);
14645        case XPATH_NUMBER:
14646#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14647	    return((res->floatval == ctxt->context->proximityPosition) &&
14648	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14649#else
14650	    return(res->floatval == ctxt->context->proximityPosition);
14651#endif
14652        case XPATH_NODESET:
14653        case XPATH_XSLT_TREE:
14654	    if (res->nodesetval == NULL)
14655		return(0);
14656	    return(res->nodesetval->nodeNr != 0);
14657        case XPATH_STRING:
14658	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14659#ifdef LIBXML_XPTR_ENABLED
14660	case XPATH_LOCATIONSET:{
14661	    xmlLocationSetPtr ptr = res->user;
14662	    if (ptr == NULL)
14663	        return(0);
14664	    return (ptr->locNr != 0);
14665	    }
14666#endif
14667        default:
14668	    STRANGE
14669    }
14670    return(0);
14671}
14672
14673#ifdef XPATH_STREAMING
14674/**
14675 * xmlXPathTryStreamCompile:
14676 * @ctxt: an XPath context
14677 * @str:  the XPath expression
14678 *
14679 * Try to compile the XPath expression as a streamable subset.
14680 *
14681 * Returns the compiled expression or NULL if failed to compile.
14682 */
14683static xmlXPathCompExprPtr
14684xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14685    /*
14686     * Optimization: use streaming patterns when the XPath expression can
14687     * be compiled to a stream lookup
14688     */
14689    xmlPatternPtr stream;
14690    xmlXPathCompExprPtr comp;
14691    xmlDictPtr dict = NULL;
14692    const xmlChar **namespaces = NULL;
14693    xmlNsPtr ns;
14694    int i, j;
14695
14696    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14697        (!xmlStrchr(str, '@'))) {
14698	const xmlChar *tmp;
14699
14700	/*
14701	 * We don't try to handle expressions using the verbose axis
14702	 * specifiers ("::"), just the simplied form at this point.
14703	 * Additionally, if there is no list of namespaces available and
14704	 *  there's a ":" in the expression, indicating a prefixed QName,
14705	 *  then we won't try to compile either. xmlPatterncompile() needs
14706	 *  to have a list of namespaces at compilation time in order to
14707	 *  compile prefixed name tests.
14708	 */
14709	tmp = xmlStrchr(str, ':');
14710	if ((tmp != NULL) &&
14711	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14712	    return(NULL);
14713
14714	if (ctxt != NULL) {
14715	    dict = ctxt->dict;
14716	    if (ctxt->nsNr > 0) {
14717		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14718		if (namespaces == NULL) {
14719		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14720		    return(NULL);
14721		}
14722		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14723		    ns = ctxt->namespaces[j];
14724		    namespaces[i++] = ns->href;
14725		    namespaces[i++] = ns->prefix;
14726		}
14727		namespaces[i++] = NULL;
14728		namespaces[i] = NULL;
14729	    }
14730	}
14731
14732	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14733			&namespaces[0]);
14734	if (namespaces != NULL) {
14735	    xmlFree((xmlChar **)namespaces);
14736	}
14737	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14738	    comp = xmlXPathNewCompExpr();
14739	    if (comp == NULL) {
14740		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14741		return(NULL);
14742	    }
14743	    comp->stream = stream;
14744	    comp->dict = dict;
14745	    if (comp->dict)
14746		xmlDictReference(comp->dict);
14747	    return(comp);
14748	}
14749	xmlFreePattern(stream);
14750    }
14751    return(NULL);
14752}
14753#endif /* XPATH_STREAMING */
14754
14755static void
14756xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14757{
14758    /*
14759    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14760    * internal representation.
14761    */
14762
14763    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14764        (op->ch1 != -1) &&
14765        (op->ch2 == -1 /* no predicate */))
14766    {
14767        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14768
14769        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14770            ((xmlXPathAxisVal) prevop->value ==
14771                AXIS_DESCENDANT_OR_SELF) &&
14772            (prevop->ch2 == -1) &&
14773            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14774            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14775        {
14776            /*
14777            * This is a "descendant-or-self::node()" without predicates.
14778            * Try to eliminate it.
14779            */
14780
14781            switch ((xmlXPathAxisVal) op->value) {
14782                case AXIS_CHILD:
14783                case AXIS_DESCENDANT:
14784                    /*
14785                    * Convert "descendant-or-self::node()/child::" or
14786                    * "descendant-or-self::node()/descendant::" to
14787                    * "descendant::"
14788                    */
14789                    op->ch1   = prevop->ch1;
14790                    op->value = AXIS_DESCENDANT;
14791                    break;
14792                case AXIS_SELF:
14793                case AXIS_DESCENDANT_OR_SELF:
14794                    /*
14795                    * Convert "descendant-or-self::node()/self::" or
14796                    * "descendant-or-self::node()/descendant-or-self::" to
14797                    * to "descendant-or-self::"
14798                    */
14799                    op->ch1   = prevop->ch1;
14800                    op->value = AXIS_DESCENDANT_OR_SELF;
14801                    break;
14802                default:
14803                    break;
14804            }
14805	}
14806    }
14807
14808    /* OP_VALUE has invalid ch1. */
14809    if (op->op == XPATH_OP_VALUE)
14810        return;
14811
14812    /* Recurse */
14813    if (op->ch1 != -1)
14814        xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14815    if (op->ch2 != -1)
14816	xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14817}
14818
14819/**
14820 * xmlXPathCtxtCompile:
14821 * @ctxt: an XPath context
14822 * @str:  the XPath expression
14823 *
14824 * Compile an XPath expression
14825 *
14826 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14827 *         the caller has to free the object.
14828 */
14829xmlXPathCompExprPtr
14830xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14831    xmlXPathParserContextPtr pctxt;
14832    xmlXPathCompExprPtr comp;
14833
14834#ifdef XPATH_STREAMING
14835    comp = xmlXPathTryStreamCompile(ctxt, str);
14836    if (comp != NULL)
14837        return(comp);
14838#endif
14839
14840    xmlXPathInit();
14841
14842    pctxt = xmlXPathNewParserContext(str, ctxt);
14843    if (pctxt == NULL)
14844        return NULL;
14845    xmlXPathCompileExpr(pctxt, 1);
14846
14847    if( pctxt->error != XPATH_EXPRESSION_OK )
14848    {
14849        xmlXPathFreeParserContext(pctxt);
14850        return(NULL);
14851    }
14852
14853    if (*pctxt->cur != 0) {
14854	/*
14855	 * aleksey: in some cases this line prints *second* error message
14856	 * (see bug #78858) and probably this should be fixed.
14857	 * However, we are not sure that all error messages are printed
14858	 * out in other places. It's not critical so we leave it as-is for now
14859	 */
14860	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14861	comp = NULL;
14862    } else {
14863	comp = pctxt->comp;
14864	pctxt->comp = NULL;
14865    }
14866    xmlXPathFreeParserContext(pctxt);
14867
14868    if (comp != NULL) {
14869	comp->expr = xmlStrdup(str);
14870#ifdef DEBUG_EVAL_COUNTS
14871	comp->string = xmlStrdup(str);
14872	comp->nb = 0;
14873#endif
14874	if ((comp->nbStep > 1) && (comp->last >= 0)) {
14875	    xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14876	}
14877    }
14878    return(comp);
14879}
14880
14881/**
14882 * xmlXPathCompile:
14883 * @str:  the XPath expression
14884 *
14885 * Compile an XPath expression
14886 *
14887 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14888 *         the caller has to free the object.
14889 */
14890xmlXPathCompExprPtr
14891xmlXPathCompile(const xmlChar *str) {
14892    return(xmlXPathCtxtCompile(NULL, str));
14893}
14894
14895/**
14896 * xmlXPathCompiledEvalInternal:
14897 * @comp:  the compiled XPath expression
14898 * @ctxt:  the XPath context
14899 * @resObj: the resulting XPath object or NULL
14900 * @toBool: 1 if only a boolean result is requested
14901 *
14902 * Evaluate the Precompiled XPath expression in the given context.
14903 * The caller has to free @resObj.
14904 *
14905 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14906 *         the caller has to free the object.
14907 */
14908static int
14909xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14910			     xmlXPathContextPtr ctxt,
14911			     xmlXPathObjectPtr *resObj,
14912			     int toBool)
14913{
14914    xmlXPathParserContextPtr pctxt;
14915#ifndef LIBXML_THREAD_ENABLED
14916    static int reentance = 0;
14917#endif
14918    int res;
14919
14920    CHECK_CTXT_NEG(ctxt)
14921
14922    if (comp == NULL)
14923	return(-1);
14924    xmlXPathInit();
14925
14926#ifndef LIBXML_THREAD_ENABLED
14927    reentance++;
14928    if (reentance > 1)
14929	xmlXPathDisableOptimizer = 1;
14930#endif
14931
14932#ifdef DEBUG_EVAL_COUNTS
14933    comp->nb++;
14934    if ((comp->string != NULL) && (comp->nb > 100)) {
14935	fprintf(stderr, "100 x %s\n", comp->string);
14936	comp->nb = 0;
14937    }
14938#endif
14939    pctxt = xmlXPathCompParserContext(comp, ctxt);
14940    res = xmlXPathRunEval(pctxt, toBool);
14941
14942    if (resObj) {
14943	if (pctxt->value == NULL) {
14944	    xmlGenericError(xmlGenericErrorContext,
14945		"xmlXPathCompiledEval: evaluation failed\n");
14946	    *resObj = NULL;
14947	} else {
14948	    *resObj = valuePop(pctxt);
14949	}
14950    }
14951
14952    /*
14953    * Pop all remaining objects from the stack.
14954    */
14955    if (pctxt->valueNr > 0) {
14956	xmlXPathObjectPtr tmp;
14957	int stack = 0;
14958
14959	do {
14960	    tmp = valuePop(pctxt);
14961	    if (tmp != NULL) {
14962		stack++;
14963		xmlXPathReleaseObject(ctxt, tmp);
14964	    }
14965	} while (tmp != NULL);
14966	if ((stack != 0) &&
14967	    ((toBool) || ((resObj) && (*resObj))))
14968	{
14969	    xmlGenericError(xmlGenericErrorContext,
14970		"xmlXPathCompiledEval: %d objects left on the stack.\n",
14971		stack);
14972	}
14973    }
14974
14975    if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14976	xmlXPathFreeObject(*resObj);
14977	*resObj = NULL;
14978    }
14979    pctxt->comp = NULL;
14980    xmlXPathFreeParserContext(pctxt);
14981#ifndef LIBXML_THREAD_ENABLED
14982    reentance--;
14983#endif
14984
14985    return(res);
14986}
14987
14988/**
14989 * xmlXPathCompiledEval:
14990 * @comp:  the compiled XPath expression
14991 * @ctx:  the XPath context
14992 *
14993 * Evaluate the Precompiled XPath expression in the given context.
14994 *
14995 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14996 *         the caller has to free the object.
14997 */
14998xmlXPathObjectPtr
14999xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
15000{
15001    xmlXPathObjectPtr res = NULL;
15002
15003    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
15004    return(res);
15005}
15006
15007/**
15008 * xmlXPathCompiledEvalToBoolean:
15009 * @comp:  the compiled XPath expression
15010 * @ctxt:  the XPath context
15011 *
15012 * Applies the XPath boolean() function on the result of the given
15013 * compiled expression.
15014 *
15015 * Returns 1 if the expression evaluated to true, 0 if to false and
15016 *         -1 in API and internal errors.
15017 */
15018int
15019xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
15020			      xmlXPathContextPtr ctxt)
15021{
15022    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
15023}
15024
15025/**
15026 * xmlXPathEvalExpr:
15027 * @ctxt:  the XPath Parser context
15028 *
15029 * Parse and evaluate an XPath expression in the given context,
15030 * then push the result on the context stack
15031 */
15032void
15033xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
15034#ifdef XPATH_STREAMING
15035    xmlXPathCompExprPtr comp;
15036#endif
15037
15038    if (ctxt == NULL) return;
15039
15040#ifdef XPATH_STREAMING
15041    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
15042    if (comp != NULL) {
15043        if (ctxt->comp != NULL)
15044	    xmlXPathFreeCompExpr(ctxt->comp);
15045        ctxt->comp = comp;
15046	if (ctxt->cur != NULL)
15047	    while (*ctxt->cur != 0) ctxt->cur++;
15048    } else
15049#endif
15050    {
15051	xmlXPathCompileExpr(ctxt, 1);
15052	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
15053	    (ctxt->comp != NULL) &&
15054	    (ctxt->comp->nbStep > 1) &&
15055	    (ctxt->comp->last >= 0))
15056	{
15057	    xmlXPathOptimizeExpression(ctxt->comp,
15058		&ctxt->comp->steps[ctxt->comp->last]);
15059	}
15060    }
15061    CHECK_ERROR;
15062    xmlXPathRunEval(ctxt, 0);
15063}
15064
15065/**
15066 * xmlXPathEval:
15067 * @str:  the XPath expression
15068 * @ctx:  the XPath context
15069 *
15070 * Evaluate the XPath Location Path in the given context.
15071 *
15072 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15073 *         the caller has to free the object.
15074 */
15075xmlXPathObjectPtr
15076xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15077    xmlXPathParserContextPtr ctxt;
15078    xmlXPathObjectPtr res, tmp, init = NULL;
15079    int stack = 0;
15080
15081    CHECK_CTXT(ctx)
15082
15083    xmlXPathInit();
15084
15085    ctxt = xmlXPathNewParserContext(str, ctx);
15086    if (ctxt == NULL)
15087        return NULL;
15088    xmlXPathEvalExpr(ctxt);
15089
15090    if (ctxt->value == NULL) {
15091	xmlGenericError(xmlGenericErrorContext,
15092		"xmlXPathEval: evaluation failed\n");
15093	res = NULL;
15094    } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
15095#ifdef XPATH_STREAMING
15096            && (ctxt->comp->stream == NULL)
15097#endif
15098	      ) {
15099	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15100	res = NULL;
15101    } else {
15102	res = valuePop(ctxt);
15103    }
15104
15105    do {
15106        tmp = valuePop(ctxt);
15107	if (tmp != NULL) {
15108	    if (tmp != init)
15109		stack++;
15110	    xmlXPathReleaseObject(ctx, tmp);
15111        }
15112    } while (tmp != NULL);
15113    if ((stack != 0) && (res != NULL)) {
15114	xmlGenericError(xmlGenericErrorContext,
15115		"xmlXPathEval: %d object left on the stack\n",
15116	        stack);
15117    }
15118    if (ctxt->error != XPATH_EXPRESSION_OK) {
15119	xmlXPathFreeObject(res);
15120	res = NULL;
15121    }
15122
15123    xmlXPathFreeParserContext(ctxt);
15124    return(res);
15125}
15126
15127/**
15128 * xmlXPathSetContextNode:
15129 * @node: the node to to use as the context node
15130 * @ctx:  the XPath context
15131 *
15132 * Sets 'node' as the context node. The node must be in the same
15133 * document as that associated with the context.
15134 *
15135 * Returns -1 in case of error or 0 if successful
15136 */
15137int
15138xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15139    if ((node == NULL) || (ctx == NULL))
15140        return(-1);
15141
15142    if (node->doc == ctx->doc) {
15143        ctx->node = node;
15144	return(0);
15145    }
15146    return(-1);
15147}
15148
15149/**
15150 * xmlXPathNodeEval:
15151 * @node: the node to to use as the context node
15152 * @str:  the XPath expression
15153 * @ctx:  the XPath context
15154 *
15155 * Evaluate the XPath Location Path in the given context. The node 'node'
15156 * is set as the context node. The context node is not restored.
15157 *
15158 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15159 *         the caller has to free the object.
15160 */
15161xmlXPathObjectPtr
15162xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15163    if (str == NULL)
15164        return(NULL);
15165    if (xmlXPathSetContextNode(node, ctx) < 0)
15166        return(NULL);
15167    return(xmlXPathEval(str, ctx));
15168}
15169
15170/**
15171 * xmlXPathEvalExpression:
15172 * @str:  the XPath expression
15173 * @ctxt:  the XPath context
15174 *
15175 * Evaluate the XPath expression in the given context.
15176 *
15177 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15178 *         the caller has to free the object.
15179 */
15180xmlXPathObjectPtr
15181xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15182    xmlXPathParserContextPtr pctxt;
15183    xmlXPathObjectPtr res, tmp;
15184    int stack = 0;
15185
15186    CHECK_CTXT(ctxt)
15187
15188    xmlXPathInit();
15189
15190    pctxt = xmlXPathNewParserContext(str, ctxt);
15191    if (pctxt == NULL)
15192        return NULL;
15193    xmlXPathEvalExpr(pctxt);
15194
15195    if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
15196	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15197	res = NULL;
15198    } else {
15199	res = valuePop(pctxt);
15200    }
15201    do {
15202        tmp = valuePop(pctxt);
15203	if (tmp != NULL) {
15204	    xmlXPathReleaseObject(ctxt, tmp);
15205	    stack++;
15206	}
15207    } while (tmp != NULL);
15208    if ((stack != 0) && (res != NULL)) {
15209	xmlGenericError(xmlGenericErrorContext,
15210		"xmlXPathEvalExpression: %d object left on the stack\n",
15211	        stack);
15212    }
15213    xmlXPathFreeParserContext(pctxt);
15214    return(res);
15215}
15216
15217/************************************************************************
15218 *									*
15219 *	Extra functions not pertaining to the XPath spec		*
15220 *									*
15221 ************************************************************************/
15222/**
15223 * xmlXPathEscapeUriFunction:
15224 * @ctxt:  the XPath Parser context
15225 * @nargs:  the number of arguments
15226 *
15227 * Implement the escape-uri() XPath function
15228 *    string escape-uri(string $str, bool $escape-reserved)
15229 *
15230 * This function applies the URI escaping rules defined in section 2 of [RFC
15231 * 2396] to the string supplied as $uri-part, which typically represents all
15232 * or part of a URI. The effect of the function is to replace any special
15233 * character in the string by an escape sequence of the form %xx%yy...,
15234 * where xxyy... is the hexadecimal representation of the octets used to
15235 * represent the character in UTF-8.
15236 *
15237 * The set of characters that are escaped depends on the setting of the
15238 * boolean argument $escape-reserved.
15239 *
15240 * If $escape-reserved is true, all characters are escaped other than lower
15241 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15242 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15243 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15244 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15245 * A-F).
15246 *
15247 * If $escape-reserved is false, the behavior differs in that characters
15248 * referred to in [RFC 2396] as reserved characters are not escaped. These
15249 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15250 *
15251 * [RFC 2396] does not define whether escaped URIs should use lower case or
15252 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15253 * compared using string comparison functions, this function must always use
15254 * the upper-case letters A-F.
15255 *
15256 * Generally, $escape-reserved should be set to true when escaping a string
15257 * that is to form a single part of a URI, and to false when escaping an
15258 * entire URI or URI reference.
15259 *
15260 * In the case of non-ascii characters, the string is encoded according to
15261 * utf-8 and then converted according to RFC 2396.
15262 *
15263 * Examples
15264 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15265 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15266 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15267 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15268 *
15269 */
15270static void
15271xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15272    xmlXPathObjectPtr str;
15273    int escape_reserved;
15274    xmlBufPtr target;
15275    xmlChar *cptr;
15276    xmlChar escape[4];
15277
15278    CHECK_ARITY(2);
15279
15280    escape_reserved = xmlXPathPopBoolean(ctxt);
15281
15282    CAST_TO_STRING;
15283    str = valuePop(ctxt);
15284
15285    target = xmlBufCreate();
15286
15287    escape[0] = '%';
15288    escape[3] = 0;
15289
15290    if (target) {
15291	for (cptr = str->stringval; *cptr; cptr++) {
15292	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
15293		(*cptr >= 'a' && *cptr <= 'z') ||
15294		(*cptr >= '0' && *cptr <= '9') ||
15295		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
15296		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
15297		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15298		(*cptr == '%' &&
15299		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15300		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15301		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
15302		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15303		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15304		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15305		(!escape_reserved &&
15306		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15307		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15308		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15309		  *cptr == ','))) {
15310		xmlBufAdd(target, cptr, 1);
15311	    } else {
15312		if ((*cptr >> 4) < 10)
15313		    escape[1] = '0' + (*cptr >> 4);
15314		else
15315		    escape[1] = 'A' - 10 + (*cptr >> 4);
15316		if ((*cptr & 0xF) < 10)
15317		    escape[2] = '0' + (*cptr & 0xF);
15318		else
15319		    escape[2] = 'A' - 10 + (*cptr & 0xF);
15320
15321		xmlBufAdd(target, &escape[0], 3);
15322	    }
15323	}
15324    }
15325    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15326	xmlBufContent(target)));
15327    xmlBufFree(target);
15328    xmlXPathReleaseObject(ctxt->context, str);
15329}
15330
15331/**
15332 * xmlXPathRegisterAllFunctions:
15333 * @ctxt:  the XPath context
15334 *
15335 * Registers all default XPath functions in this context
15336 */
15337void
15338xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15339{
15340    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15341                         xmlXPathBooleanFunction);
15342    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15343                         xmlXPathCeilingFunction);
15344    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15345                         xmlXPathCountFunction);
15346    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15347                         xmlXPathConcatFunction);
15348    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15349                         xmlXPathContainsFunction);
15350    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15351                         xmlXPathIdFunction);
15352    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15353                         xmlXPathFalseFunction);
15354    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15355                         xmlXPathFloorFunction);
15356    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15357                         xmlXPathLastFunction);
15358    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15359                         xmlXPathLangFunction);
15360    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15361                         xmlXPathLocalNameFunction);
15362    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15363                         xmlXPathNotFunction);
15364    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15365                         xmlXPathNameFunction);
15366    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15367                         xmlXPathNamespaceURIFunction);
15368    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15369                         xmlXPathNormalizeFunction);
15370    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15371                         xmlXPathNumberFunction);
15372    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15373                         xmlXPathPositionFunction);
15374    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15375                         xmlXPathRoundFunction);
15376    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15377                         xmlXPathStringFunction);
15378    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15379                         xmlXPathStringLengthFunction);
15380    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15381                         xmlXPathStartsWithFunction);
15382    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15383                         xmlXPathSubstringFunction);
15384    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15385                         xmlXPathSubstringBeforeFunction);
15386    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15387                         xmlXPathSubstringAfterFunction);
15388    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15389                         xmlXPathSumFunction);
15390    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15391                         xmlXPathTrueFunction);
15392    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15393                         xmlXPathTranslateFunction);
15394
15395    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15396	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15397                         xmlXPathEscapeUriFunction);
15398}
15399
15400#endif /* LIBXML_XPATH_ENABLED */
15401#define bottom_xpath
15402#include "elfgcchack.h"
15403