xpath.c revision 47881284aeaeeb93b3444419adeffc9e11ed1093
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/*
139 * Wrapper for the Timsort argorithm from timsort.h
140 */
141#ifdef WITH_TIM_SORT
142#define SORT_NAME libxml_domnode
143#define SORT_TYPE xmlNodePtr
144/**
145 * wrap_cmp:
146 * @x: a node
147 * @y: another node
148 *
149 * Comparison function for the Timsort implementation
150 *
151 * Returns -2 in case of error -1 if first point < second point, 0 if
152 *         it's the same node, +1 otherwise
153 */
154static
155int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
156#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
157    static int xmlXPathCmpNodesExt(xmlNodePtr, xmlNodePtr);
158    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
159    {
160        int res = xmlXPathCmpNodesExt(x, y);
161        return res == -2 ? res : -res;
162    }
163#else
164    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
165    {
166        int res = xmlXPathCmpNodes(x, y);
167        return res == -2 ? res : -res;
168    }
169#endif
170#define SORT_CMP(x, y)  (wrap_cmp(x, y))
171#include "timsort.h"
172#endif /* WITH_TIM_SORT */
173
174#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
175
176/************************************************************************
177 *									*
178 *			Floating point stuff				*
179 *									*
180 ************************************************************************/
181
182#ifndef TRIO_REPLACE_STDIO
183#define TRIO_PUBLIC static
184#endif
185#include "trionan.c"
186
187/*
188 * The lack of portability of this section of the libc is annoying !
189 */
190double xmlXPathNAN = 0;
191double xmlXPathPINF = 1;
192double xmlXPathNINF = -1;
193static double xmlXPathNZERO = 0; /* not exported from headers */
194static int xmlXPathInitialized = 0;
195
196/**
197 * xmlXPathInit:
198 *
199 * Initialize the XPath environment
200 */
201void
202xmlXPathInit(void) {
203    if (xmlXPathInitialized) return;
204
205    xmlXPathPINF = trio_pinf();
206    xmlXPathNINF = trio_ninf();
207    xmlXPathNAN = trio_nan();
208    xmlXPathNZERO = trio_nzero();
209
210    xmlXPathInitialized = 1;
211}
212
213/**
214 * xmlXPathIsNaN:
215 * @val:  a double value
216 *
217 * Provides a portable isnan() function to detect whether a double
218 * is a NotaNumber. Based on trio code
219 * http://sourceforge.net/projects/ctrio/
220 *
221 * Returns 1 if the value is a NaN, 0 otherwise
222 */
223int
224xmlXPathIsNaN(double val) {
225    return(trio_isnan(val));
226}
227
228/**
229 * xmlXPathIsInf:
230 * @val:  a double value
231 *
232 * Provides a portable isinf() function to detect whether a double
233 * is a +Infinite or -Infinite. Based on trio code
234 * http://sourceforge.net/projects/ctrio/
235 *
236 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
237 */
238int
239xmlXPathIsInf(double val) {
240    return(trio_isinf(val));
241}
242
243#endif /* SCHEMAS or XPATH */
244#ifdef LIBXML_XPATH_ENABLED
245/**
246 * xmlXPathGetSign:
247 * @val:  a double value
248 *
249 * Provides a portable function to detect the sign of a double
250 * Modified from trio code
251 * http://sourceforge.net/projects/ctrio/
252 *
253 * Returns 1 if the value is Negative, 0 if positive
254 */
255static int
256xmlXPathGetSign(double val) {
257    return(trio_signbit(val));
258}
259
260
261/*
262 * TODO: when compatibility allows remove all "fake node libxslt" strings
263 *       the test should just be name[0] = ' '
264 */
265#ifdef DEBUG_XPATH_EXPRESSION
266#define DEBUG_STEP
267#define DEBUG_EXPR
268#define DEBUG_EVAL_COUNTS
269#endif
270
271static xmlNs xmlXPathXMLNamespaceStruct = {
272    NULL,
273    XML_NAMESPACE_DECL,
274    XML_XML_NAMESPACE,
275    BAD_CAST "xml",
276    NULL,
277    NULL
278};
279static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
280#ifndef LIBXML_THREAD_ENABLED
281/*
282 * Optimizer is disabled only when threaded apps are detected while
283 * the library ain't compiled for thread safety.
284 */
285static int xmlXPathDisableOptimizer = 0;
286#endif
287
288/************************************************************************
289 *									*
290 *			Error handling routines				*
291 *									*
292 ************************************************************************/
293
294/**
295 * XP_ERRORNULL:
296 * @X:  the error code
297 *
298 * Macro to raise an XPath error and return NULL.
299 */
300#define XP_ERRORNULL(X)							\
301    { xmlXPathErr(ctxt, X); return(NULL); }
302
303/*
304 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
305 */
306static const char *xmlXPathErrorMessages[] = {
307    "Ok\n",
308    "Number encoding\n",
309    "Unfinished literal\n",
310    "Start of literal\n",
311    "Expected $ for variable reference\n",
312    "Undefined variable\n",
313    "Invalid predicate\n",
314    "Invalid expression\n",
315    "Missing closing curly brace\n",
316    "Unregistered function\n",
317    "Invalid operand\n",
318    "Invalid type\n",
319    "Invalid number of arguments\n",
320    "Invalid context size\n",
321    "Invalid context position\n",
322    "Memory allocation error\n",
323    "Syntax error\n",
324    "Resource error\n",
325    "Sub resource error\n",
326    "Undefined namespace prefix\n",
327    "Encoding error\n",
328    "Char out of XML range\n",
329    "Invalid or incomplete context\n",
330    "Stack usage errror\n",
331    "Forbidden variable\n",
332    "?? Unknown error ??\n"	/* Must be last in the list! */
333};
334#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
335		   sizeof(xmlXPathErrorMessages[0])) - 1)
336/**
337 * xmlXPathErrMemory:
338 * @ctxt:  an XPath context
339 * @extra:  extra informations
340 *
341 * Handle a redefinition of attribute error
342 */
343static void
344xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
345{
346    if (ctxt != NULL) {
347        if (extra) {
348            xmlChar buf[200];
349
350            xmlStrPrintf(buf, 200,
351                         BAD_CAST "Memory allocation failed : %s\n",
352                         extra);
353            ctxt->lastError.message = (char *) xmlStrdup(buf);
354        } else {
355            ctxt->lastError.message = (char *)
356	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
357        }
358        ctxt->lastError.domain = XML_FROM_XPATH;
359        ctxt->lastError.code = XML_ERR_NO_MEMORY;
360	if (ctxt->error != NULL)
361	    ctxt->error(ctxt->userData, &ctxt->lastError);
362    } else {
363        if (extra)
364            __xmlRaiseError(NULL, NULL, NULL,
365                            NULL, NULL, XML_FROM_XPATH,
366                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
367                            extra, NULL, NULL, 0, 0,
368                            "Memory allocation failed : %s\n", extra);
369        else
370            __xmlRaiseError(NULL, NULL, NULL,
371                            NULL, NULL, XML_FROM_XPATH,
372                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
373                            NULL, NULL, NULL, 0, 0,
374                            "Memory allocation failed\n");
375    }
376}
377
378/**
379 * xmlXPathPErrMemory:
380 * @ctxt:  an XPath parser context
381 * @extra:  extra informations
382 *
383 * Handle a redefinition of attribute error
384 */
385static void
386xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
387{
388    if (ctxt == NULL)
389	xmlXPathErrMemory(NULL, extra);
390    else {
391	ctxt->error = XPATH_MEMORY_ERROR;
392	xmlXPathErrMemory(ctxt->context, extra);
393    }
394}
395
396/**
397 * xmlXPathErr:
398 * @ctxt:  a XPath parser context
399 * @error:  the error code
400 *
401 * Handle an XPath error
402 */
403void
404xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
405{
406    if ((error < 0) || (error > MAXERRNO))
407	error = MAXERRNO;
408    if (ctxt == NULL) {
409	__xmlRaiseError(NULL, NULL, NULL,
410			NULL, NULL, XML_FROM_XPATH,
411			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
412			XML_ERR_ERROR, NULL, 0,
413			NULL, NULL, NULL, 0, 0,
414			"%s", xmlXPathErrorMessages[error]);
415	return;
416    }
417    ctxt->error = error;
418    if (ctxt->context == NULL) {
419	__xmlRaiseError(NULL, NULL, NULL,
420			NULL, NULL, XML_FROM_XPATH,
421			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
422			XML_ERR_ERROR, NULL, 0,
423			(const char *) ctxt->base, NULL, NULL,
424			ctxt->cur - ctxt->base, 0,
425			"%s", xmlXPathErrorMessages[error]);
426	return;
427    }
428
429    /* cleanup current last error */
430    xmlResetError(&ctxt->context->lastError);
431
432    ctxt->context->lastError.domain = XML_FROM_XPATH;
433    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
434                           XPATH_EXPRESSION_OK;
435    ctxt->context->lastError.level = XML_ERR_ERROR;
436    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
437    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
438    ctxt->context->lastError.node = ctxt->context->debugNode;
439    if (ctxt->context->error != NULL) {
440	ctxt->context->error(ctxt->context->userData,
441	                     &ctxt->context->lastError);
442    } else {
443	__xmlRaiseError(NULL, NULL, NULL,
444			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
445			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
446			XML_ERR_ERROR, NULL, 0,
447			(const char *) ctxt->base, NULL, NULL,
448			ctxt->cur - ctxt->base, 0,
449			"%s", xmlXPathErrorMessages[error]);
450    }
451
452}
453
454/**
455 * xmlXPatherror:
456 * @ctxt:  the XPath Parser context
457 * @file:  the file name
458 * @line:  the line number
459 * @no:  the error number
460 *
461 * Formats an error message.
462 */
463void
464xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
465              int line ATTRIBUTE_UNUSED, int no) {
466    xmlXPathErr(ctxt, no);
467}
468
469/************************************************************************
470 *									*
471 *			Utilities					*
472 *									*
473 ************************************************************************/
474
475/**
476 * xsltPointerList:
477 *
478 * Pointer-list for various purposes.
479 */
480typedef struct _xmlPointerList xmlPointerList;
481typedef xmlPointerList *xmlPointerListPtr;
482struct _xmlPointerList {
483    void **items;
484    int number;
485    int size;
486};
487/*
488* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
489* and here, we should make the functions public.
490*/
491static int
492xmlPointerListAddSize(xmlPointerListPtr list,
493		       void *item,
494		       int initialSize)
495{
496    if (list->items == NULL) {
497	if (initialSize <= 0)
498	    initialSize = 1;
499	list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
500	if (list->items == NULL) {
501	    xmlXPathErrMemory(NULL,
502		"xmlPointerListCreate: allocating item\n");
503	    return(-1);
504	}
505	list->number = 0;
506	list->size = initialSize;
507    } else if (list->size <= list->number) {
508        if (list->size > 50000000) {
509	    xmlXPathErrMemory(NULL,
510		"xmlPointerListAddSize: re-allocating item\n");
511            return(-1);
512        }
513	list->size *= 2;
514	list->items = (void **) xmlRealloc(list->items,
515	    list->size * sizeof(void *));
516	if (list->items == NULL) {
517	    xmlXPathErrMemory(NULL,
518		"xmlPointerListAddSize: re-allocating item\n");
519	    list->size = 0;
520	    return(-1);
521	}
522    }
523    list->items[list->number++] = item;
524    return(0);
525}
526
527/**
528 * xsltPointerListCreate:
529 *
530 * Creates an xsltPointerList structure.
531 *
532 * Returns a xsltPointerList structure or NULL in case of an error.
533 */
534static xmlPointerListPtr
535xmlPointerListCreate(int initialSize)
536{
537    xmlPointerListPtr ret;
538
539    ret = xmlMalloc(sizeof(xmlPointerList));
540    if (ret == NULL) {
541	xmlXPathErrMemory(NULL,
542	    "xmlPointerListCreate: allocating item\n");
543	return (NULL);
544    }
545    memset(ret, 0, sizeof(xmlPointerList));
546    if (initialSize > 0) {
547	xmlPointerListAddSize(ret, NULL, initialSize);
548	ret->number = 0;
549    }
550    return (ret);
551}
552
553/**
554 * xsltPointerListFree:
555 *
556 * Frees the xsltPointerList structure. This does not free
557 * the content of the list.
558 */
559static void
560xmlPointerListFree(xmlPointerListPtr list)
561{
562    if (list == NULL)
563	return;
564    if (list->items != NULL)
565	xmlFree(list->items);
566    xmlFree(list);
567}
568
569/************************************************************************
570 *									*
571 *			Parser Types					*
572 *									*
573 ************************************************************************/
574
575/*
576 * Types are private:
577 */
578
579typedef enum {
580    XPATH_OP_END=0,
581    XPATH_OP_AND,
582    XPATH_OP_OR,
583    XPATH_OP_EQUAL,
584    XPATH_OP_CMP,
585    XPATH_OP_PLUS,
586    XPATH_OP_MULT,
587    XPATH_OP_UNION,
588    XPATH_OP_ROOT,
589    XPATH_OP_NODE,
590    XPATH_OP_RESET, /* 10 */
591    XPATH_OP_COLLECT,
592    XPATH_OP_VALUE, /* 12 */
593    XPATH_OP_VARIABLE,
594    XPATH_OP_FUNCTION,
595    XPATH_OP_ARG,
596    XPATH_OP_PREDICATE,
597    XPATH_OP_FILTER, /* 17 */
598    XPATH_OP_SORT /* 18 */
599#ifdef LIBXML_XPTR_ENABLED
600    ,XPATH_OP_RANGETO
601#endif
602} xmlXPathOp;
603
604typedef enum {
605    AXIS_ANCESTOR = 1,
606    AXIS_ANCESTOR_OR_SELF,
607    AXIS_ATTRIBUTE,
608    AXIS_CHILD,
609    AXIS_DESCENDANT,
610    AXIS_DESCENDANT_OR_SELF,
611    AXIS_FOLLOWING,
612    AXIS_FOLLOWING_SIBLING,
613    AXIS_NAMESPACE,
614    AXIS_PARENT,
615    AXIS_PRECEDING,
616    AXIS_PRECEDING_SIBLING,
617    AXIS_SELF
618} xmlXPathAxisVal;
619
620typedef enum {
621    NODE_TEST_NONE = 0,
622    NODE_TEST_TYPE = 1,
623    NODE_TEST_PI = 2,
624    NODE_TEST_ALL = 3,
625    NODE_TEST_NS = 4,
626    NODE_TEST_NAME = 5
627} xmlXPathTestVal;
628
629typedef enum {
630    NODE_TYPE_NODE = 0,
631    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
632    NODE_TYPE_TEXT = XML_TEXT_NODE,
633    NODE_TYPE_PI = XML_PI_NODE
634} xmlXPathTypeVal;
635
636typedef struct _xmlXPathStepOp xmlXPathStepOp;
637typedef xmlXPathStepOp *xmlXPathStepOpPtr;
638struct _xmlXPathStepOp {
639    xmlXPathOp op;		/* The identifier of the operation */
640    int ch1;			/* First child */
641    int ch2;			/* Second child */
642    int value;
643    int value2;
644    int value3;
645    void *value4;
646    void *value5;
647    void *cache;
648    void *cacheURI;
649};
650
651struct _xmlXPathCompExpr {
652    int nbStep;			/* Number of steps in this expression */
653    int maxStep;		/* Maximum number of steps allocated */
654    xmlXPathStepOp *steps;	/* ops for computation of this expression */
655    int last;			/* index of last step in expression */
656    xmlChar *expr;		/* the expression being computed */
657    xmlDictPtr dict;		/* the dictionnary to use if any */
658#ifdef DEBUG_EVAL_COUNTS
659    int nb;
660    xmlChar *string;
661#endif
662#ifdef XPATH_STREAMING
663    xmlPatternPtr stream;
664#endif
665};
666
667/************************************************************************
668 *									*
669 *			Forward declarations				*
670 *									*
671 ************************************************************************/
672static void
673xmlXPathFreeValueTree(xmlNodeSetPtr obj);
674static void
675xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
676static int
677xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
678                        xmlXPathStepOpPtr op, xmlNodePtr *first);
679static int
680xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
681			    xmlXPathStepOpPtr op,
682			    int isPredicate);
683
684/************************************************************************
685 *									*
686 *			Parser Type functions				*
687 *									*
688 ************************************************************************/
689
690/**
691 * xmlXPathNewCompExpr:
692 *
693 * Create a new Xpath component
694 *
695 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
696 */
697static xmlXPathCompExprPtr
698xmlXPathNewCompExpr(void) {
699    xmlXPathCompExprPtr cur;
700
701    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
702    if (cur == NULL) {
703        xmlXPathErrMemory(NULL, "allocating component\n");
704	return(NULL);
705    }
706    memset(cur, 0, sizeof(xmlXPathCompExpr));
707    cur->maxStep = 10;
708    cur->nbStep = 0;
709    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
710	                                   sizeof(xmlXPathStepOp));
711    if (cur->steps == NULL) {
712        xmlXPathErrMemory(NULL, "allocating steps\n");
713	xmlFree(cur);
714	return(NULL);
715    }
716    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
717    cur->last = -1;
718#ifdef DEBUG_EVAL_COUNTS
719    cur->nb = 0;
720#endif
721    return(cur);
722}
723
724/**
725 * xmlXPathFreeCompExpr:
726 * @comp:  an XPATH comp
727 *
728 * Free up the memory allocated by @comp
729 */
730void
731xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
732{
733    xmlXPathStepOpPtr op;
734    int i;
735
736    if (comp == NULL)
737        return;
738    if (comp->dict == NULL) {
739	for (i = 0; i < comp->nbStep; i++) {
740	    op = &comp->steps[i];
741	    if (op->value4 != NULL) {
742		if (op->op == XPATH_OP_VALUE)
743		    xmlXPathFreeObject(op->value4);
744		else
745		    xmlFree(op->value4);
746	    }
747	    if (op->value5 != NULL)
748		xmlFree(op->value5);
749	}
750    } else {
751	for (i = 0; i < comp->nbStep; i++) {
752	    op = &comp->steps[i];
753	    if (op->value4 != NULL) {
754		if (op->op == XPATH_OP_VALUE)
755		    xmlXPathFreeObject(op->value4);
756	    }
757	}
758        xmlDictFree(comp->dict);
759    }
760    if (comp->steps != NULL) {
761        xmlFree(comp->steps);
762    }
763#ifdef DEBUG_EVAL_COUNTS
764    if (comp->string != NULL) {
765        xmlFree(comp->string);
766    }
767#endif
768#ifdef XPATH_STREAMING
769    if (comp->stream != NULL) {
770        xmlFreePatternList(comp->stream);
771    }
772#endif
773    if (comp->expr != NULL) {
774        xmlFree(comp->expr);
775    }
776
777    xmlFree(comp);
778}
779
780/**
781 * xmlXPathCompExprAdd:
782 * @comp:  the compiled expression
783 * @ch1: first child index
784 * @ch2: second child index
785 * @op:  an op
786 * @value:  the first int value
787 * @value2:  the second int value
788 * @value3:  the third int value
789 * @value4:  the first string value
790 * @value5:  the second string value
791 *
792 * Add a step to an XPath Compiled Expression
793 *
794 * Returns -1 in case of failure, the index otherwise
795 */
796static int
797xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
798   xmlXPathOp op, int value,
799   int value2, int value3, void *value4, void *value5) {
800    if (comp->nbStep >= comp->maxStep) {
801	xmlXPathStepOp *real;
802
803        if (comp->maxStep >= XPATH_MAX_STEPS) {
804	    xmlXPathErrMemory(NULL, "adding step\n");
805	    return(-1);
806        }
807	comp->maxStep *= 2;
808	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
809		                      comp->maxStep * sizeof(xmlXPathStepOp));
810	if (real == NULL) {
811	    comp->maxStep /= 2;
812	    xmlXPathErrMemory(NULL, "adding step\n");
813	    return(-1);
814	}
815	comp->steps = real;
816    }
817    comp->last = comp->nbStep;
818    comp->steps[comp->nbStep].ch1 = ch1;
819    comp->steps[comp->nbStep].ch2 = ch2;
820    comp->steps[comp->nbStep].op = op;
821    comp->steps[comp->nbStep].value = value;
822    comp->steps[comp->nbStep].value2 = value2;
823    comp->steps[comp->nbStep].value3 = value3;
824    if ((comp->dict != NULL) &&
825        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
826	 (op == XPATH_OP_COLLECT))) {
827        if (value4 != NULL) {
828	    comp->steps[comp->nbStep].value4 = (xmlChar *)
829	        (void *)xmlDictLookup(comp->dict, value4, -1);
830	    xmlFree(value4);
831	} else
832	    comp->steps[comp->nbStep].value4 = NULL;
833        if (value5 != NULL) {
834	    comp->steps[comp->nbStep].value5 = (xmlChar *)
835	        (void *)xmlDictLookup(comp->dict, value5, -1);
836	    xmlFree(value5);
837	} else
838	    comp->steps[comp->nbStep].value5 = NULL;
839    } else {
840	comp->steps[comp->nbStep].value4 = value4;
841	comp->steps[comp->nbStep].value5 = value5;
842    }
843    comp->steps[comp->nbStep].cache = NULL;
844    return(comp->nbStep++);
845}
846
847/**
848 * xmlXPathCompSwap:
849 * @comp:  the compiled expression
850 * @op: operation index
851 *
852 * Swaps 2 operations in the compiled expression
853 */
854static void
855xmlXPathCompSwap(xmlXPathStepOpPtr op) {
856    int tmp;
857
858#ifndef LIBXML_THREAD_ENABLED
859    /*
860     * Since this manipulates possibly shared variables, this is
861     * disabled if one detects that the library is used in a multithreaded
862     * application
863     */
864    if (xmlXPathDisableOptimizer)
865	return;
866#endif
867
868    tmp = op->ch1;
869    op->ch1 = op->ch2;
870    op->ch2 = tmp;
871}
872
873#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
874    xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
875	                (op), (val), (val2), (val3), (val4), (val5))
876#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
877    xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
878	                (op), (val), (val2), (val3), (val4), (val5))
879
880#define PUSH_LEAVE_EXPR(op, val, val2)					\
881xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
882
883#define PUSH_UNARY_EXPR(op, ch, val, val2)				\
884xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
885
886#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
887xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
888			(val), (val2), 0 ,NULL ,NULL)
889
890/************************************************************************
891 *									*
892 *		XPath object cache structures				*
893 *									*
894 ************************************************************************/
895
896/* #define XP_DEFAULT_CACHE_ON */
897
898#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
899
900typedef struct _xmlXPathContextCache xmlXPathContextCache;
901typedef xmlXPathContextCache *xmlXPathContextCachePtr;
902struct _xmlXPathContextCache {
903    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
904    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
905    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
906    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
907    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
908    int maxNodeset;
909    int maxString;
910    int maxBoolean;
911    int maxNumber;
912    int maxMisc;
913#ifdef XP_DEBUG_OBJ_USAGE
914    int dbgCachedAll;
915    int dbgCachedNodeset;
916    int dbgCachedString;
917    int dbgCachedBool;
918    int dbgCachedNumber;
919    int dbgCachedPoint;
920    int dbgCachedRange;
921    int dbgCachedLocset;
922    int dbgCachedUsers;
923    int dbgCachedXSLTTree;
924    int dbgCachedUndefined;
925
926
927    int dbgReusedAll;
928    int dbgReusedNodeset;
929    int dbgReusedString;
930    int dbgReusedBool;
931    int dbgReusedNumber;
932    int dbgReusedPoint;
933    int dbgReusedRange;
934    int dbgReusedLocset;
935    int dbgReusedUsers;
936    int dbgReusedXSLTTree;
937    int dbgReusedUndefined;
938
939#endif
940};
941
942/************************************************************************
943 *									*
944 *		Debugging related functions				*
945 *									*
946 ************************************************************************/
947
948#define STRANGE							\
949    xmlGenericError(xmlGenericErrorContext,				\
950	    "Internal error at %s:%d\n",				\
951            __FILE__, __LINE__);
952
953#ifdef LIBXML_DEBUG_ENABLED
954static void
955xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
956    int i;
957    char shift[100];
958
959    for (i = 0;((i < depth) && (i < 25));i++)
960        shift[2 * i] = shift[2 * i + 1] = ' ';
961    shift[2 * i] = shift[2 * i + 1] = 0;
962    if (cur == NULL) {
963	fprintf(output, "%s", shift);
964	fprintf(output, "Node is NULL !\n");
965	return;
966
967    }
968
969    if ((cur->type == XML_DOCUMENT_NODE) ||
970	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
971	fprintf(output, "%s", shift);
972	fprintf(output, " /\n");
973    } else if (cur->type == XML_ATTRIBUTE_NODE)
974	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
975    else
976	xmlDebugDumpOneNode(output, cur, depth);
977}
978static void
979xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
980    xmlNodePtr tmp;
981    int i;
982    char shift[100];
983
984    for (i = 0;((i < depth) && (i < 25));i++)
985        shift[2 * i] = shift[2 * i + 1] = ' ';
986    shift[2 * i] = shift[2 * i + 1] = 0;
987    if (cur == NULL) {
988	fprintf(output, "%s", shift);
989	fprintf(output, "Node is NULL !\n");
990	return;
991
992    }
993
994    while (cur != NULL) {
995	tmp = cur;
996	cur = cur->next;
997	xmlDebugDumpOneNode(output, tmp, depth);
998    }
999}
1000
1001static void
1002xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1003    int i;
1004    char shift[100];
1005
1006    for (i = 0;((i < depth) && (i < 25));i++)
1007        shift[2 * i] = shift[2 * i + 1] = ' ';
1008    shift[2 * i] = shift[2 * i + 1] = 0;
1009
1010    if (cur == NULL) {
1011	fprintf(output, "%s", shift);
1012	fprintf(output, "NodeSet is NULL !\n");
1013	return;
1014
1015    }
1016
1017    if (cur != NULL) {
1018	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1019	for (i = 0;i < cur->nodeNr;i++) {
1020	    fprintf(output, "%s", shift);
1021	    fprintf(output, "%d", i + 1);
1022	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1023	}
1024    }
1025}
1026
1027static void
1028xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1029    int i;
1030    char shift[100];
1031
1032    for (i = 0;((i < depth) && (i < 25));i++)
1033        shift[2 * i] = shift[2 * i + 1] = ' ';
1034    shift[2 * i] = shift[2 * i + 1] = 0;
1035
1036    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1037	fprintf(output, "%s", shift);
1038	fprintf(output, "Value Tree is NULL !\n");
1039	return;
1040
1041    }
1042
1043    fprintf(output, "%s", shift);
1044    fprintf(output, "%d", i + 1);
1045    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1046}
1047#if defined(LIBXML_XPTR_ENABLED)
1048static void
1049xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1050    int i;
1051    char shift[100];
1052
1053    for (i = 0;((i < depth) && (i < 25));i++)
1054        shift[2 * i] = shift[2 * i + 1] = ' ';
1055    shift[2 * i] = shift[2 * i + 1] = 0;
1056
1057    if (cur == NULL) {
1058	fprintf(output, "%s", shift);
1059	fprintf(output, "LocationSet is NULL !\n");
1060	return;
1061
1062    }
1063
1064    for (i = 0;i < cur->locNr;i++) {
1065	fprintf(output, "%s", shift);
1066        fprintf(output, "%d : ", i + 1);
1067	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1068    }
1069}
1070#endif /* LIBXML_XPTR_ENABLED */
1071
1072/**
1073 * xmlXPathDebugDumpObject:
1074 * @output:  the FILE * to dump the output
1075 * @cur:  the object to inspect
1076 * @depth:  indentation level
1077 *
1078 * Dump the content of the object for debugging purposes
1079 */
1080void
1081xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1082    int i;
1083    char shift[100];
1084
1085    if (output == NULL) return;
1086
1087    for (i = 0;((i < depth) && (i < 25));i++)
1088        shift[2 * i] = shift[2 * i + 1] = ' ';
1089    shift[2 * i] = shift[2 * i + 1] = 0;
1090
1091
1092    fprintf(output, "%s", shift);
1093
1094    if (cur == NULL) {
1095        fprintf(output, "Object is empty (NULL)\n");
1096	return;
1097    }
1098    switch(cur->type) {
1099        case XPATH_UNDEFINED:
1100	    fprintf(output, "Object is uninitialized\n");
1101	    break;
1102        case XPATH_NODESET:
1103	    fprintf(output, "Object is a Node Set :\n");
1104	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1105	    break;
1106	case XPATH_XSLT_TREE:
1107	    fprintf(output, "Object is an XSLT value tree :\n");
1108	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1109	    break;
1110        case XPATH_BOOLEAN:
1111	    fprintf(output, "Object is a Boolean : ");
1112	    if (cur->boolval) fprintf(output, "true\n");
1113	    else fprintf(output, "false\n");
1114	    break;
1115        case XPATH_NUMBER:
1116	    switch (xmlXPathIsInf(cur->floatval)) {
1117	    case 1:
1118		fprintf(output, "Object is a number : Infinity\n");
1119		break;
1120	    case -1:
1121		fprintf(output, "Object is a number : -Infinity\n");
1122		break;
1123	    default:
1124		if (xmlXPathIsNaN(cur->floatval)) {
1125		    fprintf(output, "Object is a number : NaN\n");
1126		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1127		    fprintf(output, "Object is a number : 0\n");
1128		} else {
1129		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1130		}
1131	    }
1132	    break;
1133        case XPATH_STRING:
1134	    fprintf(output, "Object is a string : ");
1135	    xmlDebugDumpString(output, cur->stringval);
1136	    fprintf(output, "\n");
1137	    break;
1138	case XPATH_POINT:
1139	    fprintf(output, "Object is a point : index %d in node", cur->index);
1140	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1141	    fprintf(output, "\n");
1142	    break;
1143	case XPATH_RANGE:
1144	    if ((cur->user2 == NULL) ||
1145		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1146		fprintf(output, "Object is a collapsed range :\n");
1147		fprintf(output, "%s", shift);
1148		if (cur->index >= 0)
1149		    fprintf(output, "index %d in ", cur->index);
1150		fprintf(output, "node\n");
1151		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1152			              depth + 1);
1153	    } else  {
1154		fprintf(output, "Object is a range :\n");
1155		fprintf(output, "%s", shift);
1156		fprintf(output, "From ");
1157		if (cur->index >= 0)
1158		    fprintf(output, "index %d in ", cur->index);
1159		fprintf(output, "node\n");
1160		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1161			              depth + 1);
1162		fprintf(output, "%s", shift);
1163		fprintf(output, "To ");
1164		if (cur->index2 >= 0)
1165		    fprintf(output, "index %d in ", cur->index2);
1166		fprintf(output, "node\n");
1167		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1168			              depth + 1);
1169		fprintf(output, "\n");
1170	    }
1171	    break;
1172	case XPATH_LOCATIONSET:
1173#if defined(LIBXML_XPTR_ENABLED)
1174	    fprintf(output, "Object is a Location Set:\n");
1175	    xmlXPathDebugDumpLocationSet(output,
1176		    (xmlLocationSetPtr) cur->user, depth);
1177#endif
1178	    break;
1179	case XPATH_USERS:
1180	    fprintf(output, "Object is user defined\n");
1181	    break;
1182    }
1183}
1184
1185static void
1186xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1187	                     xmlXPathStepOpPtr op, int depth) {
1188    int i;
1189    char shift[100];
1190
1191    for (i = 0;((i < depth) && (i < 25));i++)
1192        shift[2 * i] = shift[2 * i + 1] = ' ';
1193    shift[2 * i] = shift[2 * i + 1] = 0;
1194
1195    fprintf(output, "%s", shift);
1196    if (op == NULL) {
1197	fprintf(output, "Step is NULL\n");
1198	return;
1199    }
1200    switch (op->op) {
1201        case XPATH_OP_END:
1202	    fprintf(output, "END"); break;
1203        case XPATH_OP_AND:
1204	    fprintf(output, "AND"); break;
1205        case XPATH_OP_OR:
1206	    fprintf(output, "OR"); break;
1207        case XPATH_OP_EQUAL:
1208	     if (op->value)
1209		 fprintf(output, "EQUAL =");
1210	     else
1211		 fprintf(output, "EQUAL !=");
1212	     break;
1213        case XPATH_OP_CMP:
1214	     if (op->value)
1215		 fprintf(output, "CMP <");
1216	     else
1217		 fprintf(output, "CMP >");
1218	     if (!op->value2)
1219		 fprintf(output, "=");
1220	     break;
1221        case XPATH_OP_PLUS:
1222	     if (op->value == 0)
1223		 fprintf(output, "PLUS -");
1224	     else if (op->value == 1)
1225		 fprintf(output, "PLUS +");
1226	     else if (op->value == 2)
1227		 fprintf(output, "PLUS unary -");
1228	     else if (op->value == 3)
1229		 fprintf(output, "PLUS unary - -");
1230	     break;
1231        case XPATH_OP_MULT:
1232	     if (op->value == 0)
1233		 fprintf(output, "MULT *");
1234	     else if (op->value == 1)
1235		 fprintf(output, "MULT div");
1236	     else
1237		 fprintf(output, "MULT mod");
1238	     break;
1239        case XPATH_OP_UNION:
1240	     fprintf(output, "UNION"); break;
1241        case XPATH_OP_ROOT:
1242	     fprintf(output, "ROOT"); break;
1243        case XPATH_OP_NODE:
1244	     fprintf(output, "NODE"); break;
1245        case XPATH_OP_RESET:
1246	     fprintf(output, "RESET"); break;
1247        case XPATH_OP_SORT:
1248	     fprintf(output, "SORT"); break;
1249        case XPATH_OP_COLLECT: {
1250	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1251	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1252	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1253	    const xmlChar *prefix = op->value4;
1254	    const xmlChar *name = op->value5;
1255
1256	    fprintf(output, "COLLECT ");
1257	    switch (axis) {
1258		case AXIS_ANCESTOR:
1259		    fprintf(output, " 'ancestors' "); break;
1260		case AXIS_ANCESTOR_OR_SELF:
1261		    fprintf(output, " 'ancestors-or-self' "); break;
1262		case AXIS_ATTRIBUTE:
1263		    fprintf(output, " 'attributes' "); break;
1264		case AXIS_CHILD:
1265		    fprintf(output, " 'child' "); break;
1266		case AXIS_DESCENDANT:
1267		    fprintf(output, " 'descendant' "); break;
1268		case AXIS_DESCENDANT_OR_SELF:
1269		    fprintf(output, " 'descendant-or-self' "); break;
1270		case AXIS_FOLLOWING:
1271		    fprintf(output, " 'following' "); break;
1272		case AXIS_FOLLOWING_SIBLING:
1273		    fprintf(output, " 'following-siblings' "); break;
1274		case AXIS_NAMESPACE:
1275		    fprintf(output, " 'namespace' "); break;
1276		case AXIS_PARENT:
1277		    fprintf(output, " 'parent' "); break;
1278		case AXIS_PRECEDING:
1279		    fprintf(output, " 'preceding' "); break;
1280		case AXIS_PRECEDING_SIBLING:
1281		    fprintf(output, " 'preceding-sibling' "); break;
1282		case AXIS_SELF:
1283		    fprintf(output, " 'self' "); break;
1284	    }
1285	    switch (test) {
1286                case NODE_TEST_NONE:
1287		    fprintf(output, "'none' "); break;
1288                case NODE_TEST_TYPE:
1289		    fprintf(output, "'type' "); break;
1290                case NODE_TEST_PI:
1291		    fprintf(output, "'PI' "); break;
1292                case NODE_TEST_ALL:
1293		    fprintf(output, "'all' "); break;
1294                case NODE_TEST_NS:
1295		    fprintf(output, "'namespace' "); break;
1296                case NODE_TEST_NAME:
1297		    fprintf(output, "'name' "); break;
1298	    }
1299	    switch (type) {
1300                case NODE_TYPE_NODE:
1301		    fprintf(output, "'node' "); break;
1302                case NODE_TYPE_COMMENT:
1303		    fprintf(output, "'comment' "); break;
1304                case NODE_TYPE_TEXT:
1305		    fprintf(output, "'text' "); break;
1306                case NODE_TYPE_PI:
1307		    fprintf(output, "'PI' "); break;
1308	    }
1309	    if (prefix != NULL)
1310		fprintf(output, "%s:", prefix);
1311	    if (name != NULL)
1312		fprintf(output, "%s", (const char *) name);
1313	    break;
1314
1315        }
1316	case XPATH_OP_VALUE: {
1317	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1318
1319	    fprintf(output, "ELEM ");
1320	    xmlXPathDebugDumpObject(output, object, 0);
1321	    goto finish;
1322	}
1323	case XPATH_OP_VARIABLE: {
1324	    const xmlChar *prefix = op->value5;
1325	    const xmlChar *name = op->value4;
1326
1327	    if (prefix != NULL)
1328		fprintf(output, "VARIABLE %s:%s", prefix, name);
1329	    else
1330		fprintf(output, "VARIABLE %s", name);
1331	    break;
1332	}
1333	case XPATH_OP_FUNCTION: {
1334	    int nbargs = op->value;
1335	    const xmlChar *prefix = op->value5;
1336	    const xmlChar *name = op->value4;
1337
1338	    if (prefix != NULL)
1339		fprintf(output, "FUNCTION %s:%s(%d args)",
1340			prefix, name, nbargs);
1341	    else
1342		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1343	    break;
1344	}
1345        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1346        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1347        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1348#ifdef LIBXML_XPTR_ENABLED
1349        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1350#endif
1351	default:
1352        fprintf(output, "UNKNOWN %d\n", op->op); return;
1353    }
1354    fprintf(output, "\n");
1355finish:
1356    if (op->ch1 >= 0)
1357	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1358    if (op->ch2 >= 0)
1359	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1360}
1361
1362/**
1363 * xmlXPathDebugDumpCompExpr:
1364 * @output:  the FILE * for the output
1365 * @comp:  the precompiled XPath expression
1366 * @depth:  the indentation level.
1367 *
1368 * Dumps the tree of the compiled XPath expression.
1369 */
1370void
1371xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1372	                  int depth) {
1373    int i;
1374    char shift[100];
1375
1376    if ((output == NULL) || (comp == 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    fprintf(output, "%s", shift);
1383
1384    fprintf(output, "Compiled Expression : %d elements\n",
1385	    comp->nbStep);
1386    i = comp->last;
1387    xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1388}
1389
1390#ifdef XP_DEBUG_OBJ_USAGE
1391
1392/*
1393* XPath object usage related debugging variables.
1394*/
1395static int xmlXPathDebugObjCounterUndefined = 0;
1396static int xmlXPathDebugObjCounterNodeset = 0;
1397static int xmlXPathDebugObjCounterBool = 0;
1398static int xmlXPathDebugObjCounterNumber = 0;
1399static int xmlXPathDebugObjCounterString = 0;
1400static int xmlXPathDebugObjCounterPoint = 0;
1401static int xmlXPathDebugObjCounterRange = 0;
1402static int xmlXPathDebugObjCounterLocset = 0;
1403static int xmlXPathDebugObjCounterUsers = 0;
1404static int xmlXPathDebugObjCounterXSLTTree = 0;
1405static int xmlXPathDebugObjCounterAll = 0;
1406
1407static int xmlXPathDebugObjTotalUndefined = 0;
1408static int xmlXPathDebugObjTotalNodeset = 0;
1409static int xmlXPathDebugObjTotalBool = 0;
1410static int xmlXPathDebugObjTotalNumber = 0;
1411static int xmlXPathDebugObjTotalString = 0;
1412static int xmlXPathDebugObjTotalPoint = 0;
1413static int xmlXPathDebugObjTotalRange = 0;
1414static int xmlXPathDebugObjTotalLocset = 0;
1415static int xmlXPathDebugObjTotalUsers = 0;
1416static int xmlXPathDebugObjTotalXSLTTree = 0;
1417static int xmlXPathDebugObjTotalAll = 0;
1418
1419static int xmlXPathDebugObjMaxUndefined = 0;
1420static int xmlXPathDebugObjMaxNodeset = 0;
1421static int xmlXPathDebugObjMaxBool = 0;
1422static int xmlXPathDebugObjMaxNumber = 0;
1423static int xmlXPathDebugObjMaxString = 0;
1424static int xmlXPathDebugObjMaxPoint = 0;
1425static int xmlXPathDebugObjMaxRange = 0;
1426static int xmlXPathDebugObjMaxLocset = 0;
1427static int xmlXPathDebugObjMaxUsers = 0;
1428static int xmlXPathDebugObjMaxXSLTTree = 0;
1429static int xmlXPathDebugObjMaxAll = 0;
1430
1431/* REVISIT TODO: Make this static when committing */
1432static void
1433xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1434{
1435    if (ctxt != NULL) {
1436	if (ctxt->cache != NULL) {
1437	    xmlXPathContextCachePtr cache =
1438		(xmlXPathContextCachePtr) ctxt->cache;
1439
1440	    cache->dbgCachedAll = 0;
1441	    cache->dbgCachedNodeset = 0;
1442	    cache->dbgCachedString = 0;
1443	    cache->dbgCachedBool = 0;
1444	    cache->dbgCachedNumber = 0;
1445	    cache->dbgCachedPoint = 0;
1446	    cache->dbgCachedRange = 0;
1447	    cache->dbgCachedLocset = 0;
1448	    cache->dbgCachedUsers = 0;
1449	    cache->dbgCachedXSLTTree = 0;
1450	    cache->dbgCachedUndefined = 0;
1451
1452	    cache->dbgReusedAll = 0;
1453	    cache->dbgReusedNodeset = 0;
1454	    cache->dbgReusedString = 0;
1455	    cache->dbgReusedBool = 0;
1456	    cache->dbgReusedNumber = 0;
1457	    cache->dbgReusedPoint = 0;
1458	    cache->dbgReusedRange = 0;
1459	    cache->dbgReusedLocset = 0;
1460	    cache->dbgReusedUsers = 0;
1461	    cache->dbgReusedXSLTTree = 0;
1462	    cache->dbgReusedUndefined = 0;
1463	}
1464    }
1465
1466    xmlXPathDebugObjCounterUndefined = 0;
1467    xmlXPathDebugObjCounterNodeset = 0;
1468    xmlXPathDebugObjCounterBool = 0;
1469    xmlXPathDebugObjCounterNumber = 0;
1470    xmlXPathDebugObjCounterString = 0;
1471    xmlXPathDebugObjCounterPoint = 0;
1472    xmlXPathDebugObjCounterRange = 0;
1473    xmlXPathDebugObjCounterLocset = 0;
1474    xmlXPathDebugObjCounterUsers = 0;
1475    xmlXPathDebugObjCounterXSLTTree = 0;
1476    xmlXPathDebugObjCounterAll = 0;
1477
1478    xmlXPathDebugObjTotalUndefined = 0;
1479    xmlXPathDebugObjTotalNodeset = 0;
1480    xmlXPathDebugObjTotalBool = 0;
1481    xmlXPathDebugObjTotalNumber = 0;
1482    xmlXPathDebugObjTotalString = 0;
1483    xmlXPathDebugObjTotalPoint = 0;
1484    xmlXPathDebugObjTotalRange = 0;
1485    xmlXPathDebugObjTotalLocset = 0;
1486    xmlXPathDebugObjTotalUsers = 0;
1487    xmlXPathDebugObjTotalXSLTTree = 0;
1488    xmlXPathDebugObjTotalAll = 0;
1489
1490    xmlXPathDebugObjMaxUndefined = 0;
1491    xmlXPathDebugObjMaxNodeset = 0;
1492    xmlXPathDebugObjMaxBool = 0;
1493    xmlXPathDebugObjMaxNumber = 0;
1494    xmlXPathDebugObjMaxString = 0;
1495    xmlXPathDebugObjMaxPoint = 0;
1496    xmlXPathDebugObjMaxRange = 0;
1497    xmlXPathDebugObjMaxLocset = 0;
1498    xmlXPathDebugObjMaxUsers = 0;
1499    xmlXPathDebugObjMaxXSLTTree = 0;
1500    xmlXPathDebugObjMaxAll = 0;
1501
1502}
1503
1504static void
1505xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1506			      xmlXPathObjectType objType)
1507{
1508    int isCached = 0;
1509
1510    if (ctxt != NULL) {
1511	if (ctxt->cache != NULL) {
1512	    xmlXPathContextCachePtr cache =
1513		(xmlXPathContextCachePtr) ctxt->cache;
1514
1515	    isCached = 1;
1516
1517	    cache->dbgReusedAll++;
1518	    switch (objType) {
1519		case XPATH_UNDEFINED:
1520		    cache->dbgReusedUndefined++;
1521		    break;
1522		case XPATH_NODESET:
1523		    cache->dbgReusedNodeset++;
1524		    break;
1525		case XPATH_BOOLEAN:
1526		    cache->dbgReusedBool++;
1527		    break;
1528		case XPATH_NUMBER:
1529		    cache->dbgReusedNumber++;
1530		    break;
1531		case XPATH_STRING:
1532		    cache->dbgReusedString++;
1533		    break;
1534		case XPATH_POINT:
1535		    cache->dbgReusedPoint++;
1536		    break;
1537		case XPATH_RANGE:
1538		    cache->dbgReusedRange++;
1539		    break;
1540		case XPATH_LOCATIONSET:
1541		    cache->dbgReusedLocset++;
1542		    break;
1543		case XPATH_USERS:
1544		    cache->dbgReusedUsers++;
1545		    break;
1546		case XPATH_XSLT_TREE:
1547		    cache->dbgReusedXSLTTree++;
1548		    break;
1549		default:
1550		    break;
1551	    }
1552	}
1553    }
1554
1555    switch (objType) {
1556	case XPATH_UNDEFINED:
1557	    if (! isCached)
1558		xmlXPathDebugObjTotalUndefined++;
1559	    xmlXPathDebugObjCounterUndefined++;
1560	    if (xmlXPathDebugObjCounterUndefined >
1561		xmlXPathDebugObjMaxUndefined)
1562		xmlXPathDebugObjMaxUndefined =
1563		    xmlXPathDebugObjCounterUndefined;
1564	    break;
1565	case XPATH_NODESET:
1566	    if (! isCached)
1567		xmlXPathDebugObjTotalNodeset++;
1568	    xmlXPathDebugObjCounterNodeset++;
1569	    if (xmlXPathDebugObjCounterNodeset >
1570		xmlXPathDebugObjMaxNodeset)
1571		xmlXPathDebugObjMaxNodeset =
1572		    xmlXPathDebugObjCounterNodeset;
1573	    break;
1574	case XPATH_BOOLEAN:
1575	    if (! isCached)
1576		xmlXPathDebugObjTotalBool++;
1577	    xmlXPathDebugObjCounterBool++;
1578	    if (xmlXPathDebugObjCounterBool >
1579		xmlXPathDebugObjMaxBool)
1580		xmlXPathDebugObjMaxBool =
1581		    xmlXPathDebugObjCounterBool;
1582	    break;
1583	case XPATH_NUMBER:
1584	    if (! isCached)
1585		xmlXPathDebugObjTotalNumber++;
1586	    xmlXPathDebugObjCounterNumber++;
1587	    if (xmlXPathDebugObjCounterNumber >
1588		xmlXPathDebugObjMaxNumber)
1589		xmlXPathDebugObjMaxNumber =
1590		    xmlXPathDebugObjCounterNumber;
1591	    break;
1592	case XPATH_STRING:
1593	    if (! isCached)
1594		xmlXPathDebugObjTotalString++;
1595	    xmlXPathDebugObjCounterString++;
1596	    if (xmlXPathDebugObjCounterString >
1597		xmlXPathDebugObjMaxString)
1598		xmlXPathDebugObjMaxString =
1599		    xmlXPathDebugObjCounterString;
1600	    break;
1601	case XPATH_POINT:
1602	    if (! isCached)
1603		xmlXPathDebugObjTotalPoint++;
1604	    xmlXPathDebugObjCounterPoint++;
1605	    if (xmlXPathDebugObjCounterPoint >
1606		xmlXPathDebugObjMaxPoint)
1607		xmlXPathDebugObjMaxPoint =
1608		    xmlXPathDebugObjCounterPoint;
1609	    break;
1610	case XPATH_RANGE:
1611	    if (! isCached)
1612		xmlXPathDebugObjTotalRange++;
1613	    xmlXPathDebugObjCounterRange++;
1614	    if (xmlXPathDebugObjCounterRange >
1615		xmlXPathDebugObjMaxRange)
1616		xmlXPathDebugObjMaxRange =
1617		    xmlXPathDebugObjCounterRange;
1618	    break;
1619	case XPATH_LOCATIONSET:
1620	    if (! isCached)
1621		xmlXPathDebugObjTotalLocset++;
1622	    xmlXPathDebugObjCounterLocset++;
1623	    if (xmlXPathDebugObjCounterLocset >
1624		xmlXPathDebugObjMaxLocset)
1625		xmlXPathDebugObjMaxLocset =
1626		    xmlXPathDebugObjCounterLocset;
1627	    break;
1628	case XPATH_USERS:
1629	    if (! isCached)
1630		xmlXPathDebugObjTotalUsers++;
1631	    xmlXPathDebugObjCounterUsers++;
1632	    if (xmlXPathDebugObjCounterUsers >
1633		xmlXPathDebugObjMaxUsers)
1634		xmlXPathDebugObjMaxUsers =
1635		    xmlXPathDebugObjCounterUsers;
1636	    break;
1637	case XPATH_XSLT_TREE:
1638	    if (! isCached)
1639		xmlXPathDebugObjTotalXSLTTree++;
1640	    xmlXPathDebugObjCounterXSLTTree++;
1641	    if (xmlXPathDebugObjCounterXSLTTree >
1642		xmlXPathDebugObjMaxXSLTTree)
1643		xmlXPathDebugObjMaxXSLTTree =
1644		    xmlXPathDebugObjCounterXSLTTree;
1645	    break;
1646	default:
1647	    break;
1648    }
1649    if (! isCached)
1650	xmlXPathDebugObjTotalAll++;
1651    xmlXPathDebugObjCounterAll++;
1652    if (xmlXPathDebugObjCounterAll >
1653	xmlXPathDebugObjMaxAll)
1654	xmlXPathDebugObjMaxAll =
1655	    xmlXPathDebugObjCounterAll;
1656}
1657
1658static void
1659xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1660			      xmlXPathObjectType objType)
1661{
1662    int isCached = 0;
1663
1664    if (ctxt != NULL) {
1665	if (ctxt->cache != NULL) {
1666	    xmlXPathContextCachePtr cache =
1667		(xmlXPathContextCachePtr) ctxt->cache;
1668
1669	    isCached = 1;
1670
1671	    cache->dbgCachedAll++;
1672	    switch (objType) {
1673		case XPATH_UNDEFINED:
1674		    cache->dbgCachedUndefined++;
1675		    break;
1676		case XPATH_NODESET:
1677		    cache->dbgCachedNodeset++;
1678		    break;
1679		case XPATH_BOOLEAN:
1680		    cache->dbgCachedBool++;
1681		    break;
1682		case XPATH_NUMBER:
1683		    cache->dbgCachedNumber++;
1684		    break;
1685		case XPATH_STRING:
1686		    cache->dbgCachedString++;
1687		    break;
1688		case XPATH_POINT:
1689		    cache->dbgCachedPoint++;
1690		    break;
1691		case XPATH_RANGE:
1692		    cache->dbgCachedRange++;
1693		    break;
1694		case XPATH_LOCATIONSET:
1695		    cache->dbgCachedLocset++;
1696		    break;
1697		case XPATH_USERS:
1698		    cache->dbgCachedUsers++;
1699		    break;
1700		case XPATH_XSLT_TREE:
1701		    cache->dbgCachedXSLTTree++;
1702		    break;
1703		default:
1704		    break;
1705	    }
1706
1707	}
1708    }
1709    switch (objType) {
1710	case XPATH_UNDEFINED:
1711	    xmlXPathDebugObjCounterUndefined--;
1712	    break;
1713	case XPATH_NODESET:
1714	    xmlXPathDebugObjCounterNodeset--;
1715	    break;
1716	case XPATH_BOOLEAN:
1717	    xmlXPathDebugObjCounterBool--;
1718	    break;
1719	case XPATH_NUMBER:
1720	    xmlXPathDebugObjCounterNumber--;
1721	    break;
1722	case XPATH_STRING:
1723	    xmlXPathDebugObjCounterString--;
1724	    break;
1725	case XPATH_POINT:
1726	    xmlXPathDebugObjCounterPoint--;
1727	    break;
1728	case XPATH_RANGE:
1729	    xmlXPathDebugObjCounterRange--;
1730	    break;
1731	case XPATH_LOCATIONSET:
1732	    xmlXPathDebugObjCounterLocset--;
1733	    break;
1734	case XPATH_USERS:
1735	    xmlXPathDebugObjCounterUsers--;
1736	    break;
1737	case XPATH_XSLT_TREE:
1738	    xmlXPathDebugObjCounterXSLTTree--;
1739	    break;
1740	default:
1741	    break;
1742    }
1743    xmlXPathDebugObjCounterAll--;
1744}
1745
1746/* REVISIT TODO: Make this static when committing */
1747static void
1748xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1749{
1750    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1751	reqXSLTTree, reqUndefined;
1752    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1753	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1754    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1755	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1756    int leftObjs = xmlXPathDebugObjCounterAll;
1757
1758    reqAll = xmlXPathDebugObjTotalAll;
1759    reqNodeset = xmlXPathDebugObjTotalNodeset;
1760    reqString = xmlXPathDebugObjTotalString;
1761    reqBool = xmlXPathDebugObjTotalBool;
1762    reqNumber = xmlXPathDebugObjTotalNumber;
1763    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1764    reqUndefined = xmlXPathDebugObjTotalUndefined;
1765
1766    printf("# XPath object usage:\n");
1767
1768    if (ctxt != NULL) {
1769	if (ctxt->cache != NULL) {
1770	    xmlXPathContextCachePtr cache =
1771		(xmlXPathContextCachePtr) ctxt->cache;
1772
1773	    reAll = cache->dbgReusedAll;
1774	    reqAll += reAll;
1775	    reNodeset = cache->dbgReusedNodeset;
1776	    reqNodeset += reNodeset;
1777	    reString = cache->dbgReusedString;
1778	    reqString += reString;
1779	    reBool = cache->dbgReusedBool;
1780	    reqBool += reBool;
1781	    reNumber = cache->dbgReusedNumber;
1782	    reqNumber += reNumber;
1783	    reXSLTTree = cache->dbgReusedXSLTTree;
1784	    reqXSLTTree += reXSLTTree;
1785	    reUndefined = cache->dbgReusedUndefined;
1786	    reqUndefined += reUndefined;
1787
1788	    caAll = cache->dbgCachedAll;
1789	    caBool = cache->dbgCachedBool;
1790	    caNodeset = cache->dbgCachedNodeset;
1791	    caString = cache->dbgCachedString;
1792	    caNumber = cache->dbgCachedNumber;
1793	    caXSLTTree = cache->dbgCachedXSLTTree;
1794	    caUndefined = cache->dbgCachedUndefined;
1795
1796	    if (cache->nodesetObjs)
1797		leftObjs -= cache->nodesetObjs->number;
1798	    if (cache->stringObjs)
1799		leftObjs -= cache->stringObjs->number;
1800	    if (cache->booleanObjs)
1801		leftObjs -= cache->booleanObjs->number;
1802	    if (cache->numberObjs)
1803		leftObjs -= cache->numberObjs->number;
1804	    if (cache->miscObjs)
1805		leftObjs -= cache->miscObjs->number;
1806	}
1807    }
1808
1809    printf("# all\n");
1810    printf("#   total  : %d\n", reqAll);
1811    printf("#   left  : %d\n", leftObjs);
1812    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
1813    printf("#   reused : %d\n", reAll);
1814    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
1815
1816    printf("# node-sets\n");
1817    printf("#   total  : %d\n", reqNodeset);
1818    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
1819    printf("#   reused : %d\n", reNodeset);
1820    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
1821
1822    printf("# strings\n");
1823    printf("#   total  : %d\n", reqString);
1824    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
1825    printf("#   reused : %d\n", reString);
1826    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
1827
1828    printf("# booleans\n");
1829    printf("#   total  : %d\n", reqBool);
1830    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
1831    printf("#   reused : %d\n", reBool);
1832    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
1833
1834    printf("# numbers\n");
1835    printf("#   total  : %d\n", reqNumber);
1836    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
1837    printf("#   reused : %d\n", reNumber);
1838    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
1839
1840    printf("# XSLT result tree fragments\n");
1841    printf("#   total  : %d\n", reqXSLTTree);
1842    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1843    printf("#   reused : %d\n", reXSLTTree);
1844    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
1845
1846    printf("# undefined\n");
1847    printf("#   total  : %d\n", reqUndefined);
1848    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
1849    printf("#   reused : %d\n", reUndefined);
1850    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
1851
1852}
1853
1854#endif /* XP_DEBUG_OBJ_USAGE */
1855
1856#endif /* LIBXML_DEBUG_ENABLED */
1857
1858/************************************************************************
1859 *									*
1860 *			XPath object caching				*
1861 *									*
1862 ************************************************************************/
1863
1864/**
1865 * xmlXPathNewCache:
1866 *
1867 * Create a new object cache
1868 *
1869 * Returns the xmlXPathCache just allocated.
1870 */
1871static xmlXPathContextCachePtr
1872xmlXPathNewCache(void)
1873{
1874    xmlXPathContextCachePtr ret;
1875
1876    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1877    if (ret == NULL) {
1878        xmlXPathErrMemory(NULL, "creating object cache\n");
1879	return(NULL);
1880    }
1881    memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
1882    ret->maxNodeset = 100;
1883    ret->maxString = 100;
1884    ret->maxBoolean = 100;
1885    ret->maxNumber = 100;
1886    ret->maxMisc = 100;
1887    return(ret);
1888}
1889
1890static void
1891xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1892{
1893    int i;
1894    xmlXPathObjectPtr obj;
1895
1896    if (list == NULL)
1897	return;
1898
1899    for (i = 0; i < list->number; i++) {
1900	obj = list->items[i];
1901	/*
1902	* Note that it is already assured that we don't need to
1903	* look out for namespace nodes in the node-set.
1904	*/
1905	if (obj->nodesetval != NULL) {
1906	    if (obj->nodesetval->nodeTab != NULL)
1907		xmlFree(obj->nodesetval->nodeTab);
1908	    xmlFree(obj->nodesetval);
1909	}
1910	xmlFree(obj);
1911#ifdef XP_DEBUG_OBJ_USAGE
1912	xmlXPathDebugObjCounterAll--;
1913#endif
1914    }
1915    xmlPointerListFree(list);
1916}
1917
1918static void
1919xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1920{
1921    if (cache == NULL)
1922	return;
1923    if (cache->nodesetObjs)
1924	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1925    if (cache->stringObjs)
1926	xmlXPathCacheFreeObjectList(cache->stringObjs);
1927    if (cache->booleanObjs)
1928	xmlXPathCacheFreeObjectList(cache->booleanObjs);
1929    if (cache->numberObjs)
1930	xmlXPathCacheFreeObjectList(cache->numberObjs);
1931    if (cache->miscObjs)
1932	xmlXPathCacheFreeObjectList(cache->miscObjs);
1933    xmlFree(cache);
1934}
1935
1936/**
1937 * xmlXPathContextSetCache:
1938 *
1939 * @ctxt:  the XPath context
1940 * @active: enables/disables (creates/frees) the cache
1941 * @value: a value with semantics dependant on @options
1942 * @options: options (currently only the value 0 is used)
1943 *
1944 * Creates/frees an object cache on the XPath context.
1945 * If activates XPath objects (xmlXPathObject) will be cached internally
1946 * to be reused.
1947 * @options:
1948 *   0: This will set the XPath object caching:
1949 *      @value:
1950 *        This will set the maximum number of XPath objects
1951 *        to be cached per slot
1952 *        There are 5 slots for: node-set, string, number, boolean, and
1953 *        misc objects. Use <0 for the default number (100).
1954 *   Other values for @options have currently no effect.
1955 *
1956 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1957 */
1958int
1959xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1960			int active,
1961			int value,
1962			int options)
1963{
1964    if (ctxt == NULL)
1965	return(-1);
1966    if (active) {
1967	xmlXPathContextCachePtr cache;
1968
1969	if (ctxt->cache == NULL) {
1970	    ctxt->cache = xmlXPathNewCache();
1971	    if (ctxt->cache == NULL)
1972		return(-1);
1973	}
1974	cache = (xmlXPathContextCachePtr) ctxt->cache;
1975	if (options == 0) {
1976	    if (value < 0)
1977		value = 100;
1978	    cache->maxNodeset = value;
1979	    cache->maxString = value;
1980	    cache->maxNumber = value;
1981	    cache->maxBoolean = value;
1982	    cache->maxMisc = value;
1983	}
1984    } else if (ctxt->cache != NULL) {
1985	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1986	ctxt->cache = NULL;
1987    }
1988    return(0);
1989}
1990
1991/**
1992 * xmlXPathCacheWrapNodeSet:
1993 * @ctxt: the XPath context
1994 * @val:  the NodePtr value
1995 *
1996 * This is the cached version of xmlXPathWrapNodeSet().
1997 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1998 *
1999 * Returns the created or reused object.
2000 */
2001static xmlXPathObjectPtr
2002xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2003{
2004    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2005	xmlXPathContextCachePtr cache =
2006	    (xmlXPathContextCachePtr) ctxt->cache;
2007
2008	if ((cache->miscObjs != NULL) &&
2009	    (cache->miscObjs->number != 0))
2010	{
2011	    xmlXPathObjectPtr ret;
2012
2013	    ret = (xmlXPathObjectPtr)
2014		cache->miscObjs->items[--cache->miscObjs->number];
2015	    ret->type = XPATH_NODESET;
2016	    ret->nodesetval = val;
2017#ifdef XP_DEBUG_OBJ_USAGE
2018	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2019#endif
2020	    return(ret);
2021	}
2022    }
2023
2024    return(xmlXPathWrapNodeSet(val));
2025
2026}
2027
2028/**
2029 * xmlXPathCacheWrapString:
2030 * @ctxt: the XPath context
2031 * @val:  the xmlChar * value
2032 *
2033 * This is the cached version of xmlXPathWrapString().
2034 * Wraps the @val string into an XPath object.
2035 *
2036 * Returns the created or reused object.
2037 */
2038static xmlXPathObjectPtr
2039xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2040{
2041    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2042	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2043
2044	if ((cache->stringObjs != NULL) &&
2045	    (cache->stringObjs->number != 0))
2046	{
2047
2048	    xmlXPathObjectPtr ret;
2049
2050	    ret = (xmlXPathObjectPtr)
2051		cache->stringObjs->items[--cache->stringObjs->number];
2052	    ret->type = XPATH_STRING;
2053	    ret->stringval = val;
2054#ifdef XP_DEBUG_OBJ_USAGE
2055	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2056#endif
2057	    return(ret);
2058	} else if ((cache->miscObjs != NULL) &&
2059	    (cache->miscObjs->number != 0))
2060	{
2061	    xmlXPathObjectPtr ret;
2062	    /*
2063	    * Fallback to misc-cache.
2064	    */
2065	    ret = (xmlXPathObjectPtr)
2066		cache->miscObjs->items[--cache->miscObjs->number];
2067
2068	    ret->type = XPATH_STRING;
2069	    ret->stringval = val;
2070#ifdef XP_DEBUG_OBJ_USAGE
2071	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2072#endif
2073	    return(ret);
2074	}
2075    }
2076    return(xmlXPathWrapString(val));
2077}
2078
2079/**
2080 * xmlXPathCacheNewNodeSet:
2081 * @ctxt: the XPath context
2082 * @val:  the NodePtr value
2083 *
2084 * This is the cached version of xmlXPathNewNodeSet().
2085 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2086 * it with the single Node @val
2087 *
2088 * Returns the created or reused object.
2089 */
2090static xmlXPathObjectPtr
2091xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2092{
2093    if ((ctxt != NULL) && (ctxt->cache)) {
2094	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2095
2096	if ((cache->nodesetObjs != NULL) &&
2097	    (cache->nodesetObjs->number != 0))
2098	{
2099	    xmlXPathObjectPtr ret;
2100	    /*
2101	    * Use the nodset-cache.
2102	    */
2103	    ret = (xmlXPathObjectPtr)
2104		cache->nodesetObjs->items[--cache->nodesetObjs->number];
2105	    ret->type = XPATH_NODESET;
2106	    ret->boolval = 0;
2107	    if (val) {
2108		if ((ret->nodesetval->nodeMax == 0) ||
2109		    (val->type == XML_NAMESPACE_DECL))
2110		{
2111		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2112		} else {
2113		    ret->nodesetval->nodeTab[0] = val;
2114		    ret->nodesetval->nodeNr = 1;
2115		}
2116	    }
2117#ifdef XP_DEBUG_OBJ_USAGE
2118	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2119#endif
2120	    return(ret);
2121	} else if ((cache->miscObjs != NULL) &&
2122	    (cache->miscObjs->number != 0))
2123	{
2124	    xmlXPathObjectPtr ret;
2125	    /*
2126	    * Fallback to misc-cache.
2127	    */
2128
2129	    ret = (xmlXPathObjectPtr)
2130		cache->miscObjs->items[--cache->miscObjs->number];
2131
2132	    ret->type = XPATH_NODESET;
2133	    ret->boolval = 0;
2134	    ret->nodesetval = xmlXPathNodeSetCreate(val);
2135	    if (ret->nodesetval == NULL) {
2136		ctxt->lastError.domain = XML_FROM_XPATH;
2137		ctxt->lastError.code = XML_ERR_NO_MEMORY;
2138		return(NULL);
2139	    }
2140#ifdef XP_DEBUG_OBJ_USAGE
2141	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2142#endif
2143	    return(ret);
2144	}
2145    }
2146    return(xmlXPathNewNodeSet(val));
2147}
2148
2149/**
2150 * xmlXPathCacheNewCString:
2151 * @ctxt: the XPath context
2152 * @val:  the char * value
2153 *
2154 * This is the cached version of xmlXPathNewCString().
2155 * Acquire an xmlXPathObjectPtr of type string and of value @val
2156 *
2157 * Returns the created or reused object.
2158 */
2159static xmlXPathObjectPtr
2160xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2161{
2162    if ((ctxt != NULL) && (ctxt->cache)) {
2163	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2164
2165	if ((cache->stringObjs != NULL) &&
2166	    (cache->stringObjs->number != 0))
2167	{
2168	    xmlXPathObjectPtr ret;
2169
2170	    ret = (xmlXPathObjectPtr)
2171		cache->stringObjs->items[--cache->stringObjs->number];
2172
2173	    ret->type = XPATH_STRING;
2174	    ret->stringval = xmlStrdup(BAD_CAST val);
2175#ifdef XP_DEBUG_OBJ_USAGE
2176	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2177#endif
2178	    return(ret);
2179	} else if ((cache->miscObjs != NULL) &&
2180	    (cache->miscObjs->number != 0))
2181	{
2182	    xmlXPathObjectPtr ret;
2183
2184	    ret = (xmlXPathObjectPtr)
2185		cache->miscObjs->items[--cache->miscObjs->number];
2186
2187	    ret->type = XPATH_STRING;
2188	    ret->stringval = xmlStrdup(BAD_CAST val);
2189#ifdef XP_DEBUG_OBJ_USAGE
2190	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2191#endif
2192	    return(ret);
2193	}
2194    }
2195    return(xmlXPathNewCString(val));
2196}
2197
2198/**
2199 * xmlXPathCacheNewString:
2200 * @ctxt: the XPath context
2201 * @val:  the xmlChar * value
2202 *
2203 * This is the cached version of xmlXPathNewString().
2204 * Acquire an xmlXPathObjectPtr of type string and of value @val
2205 *
2206 * Returns the created or reused object.
2207 */
2208static xmlXPathObjectPtr
2209xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2210{
2211    if ((ctxt != NULL) && (ctxt->cache)) {
2212	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2213
2214	if ((cache->stringObjs != NULL) &&
2215	    (cache->stringObjs->number != 0))
2216	{
2217	    xmlXPathObjectPtr ret;
2218
2219	    ret = (xmlXPathObjectPtr)
2220		cache->stringObjs->items[--cache->stringObjs->number];
2221	    ret->type = XPATH_STRING;
2222	    if (val != NULL)
2223		ret->stringval = xmlStrdup(val);
2224	    else
2225		ret->stringval = xmlStrdup((const xmlChar *)"");
2226#ifdef XP_DEBUG_OBJ_USAGE
2227	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2228#endif
2229	    return(ret);
2230	} else if ((cache->miscObjs != NULL) &&
2231	    (cache->miscObjs->number != 0))
2232	{
2233	    xmlXPathObjectPtr ret;
2234
2235	    ret = (xmlXPathObjectPtr)
2236		cache->miscObjs->items[--cache->miscObjs->number];
2237
2238	    ret->type = XPATH_STRING;
2239	    if (val != NULL)
2240		ret->stringval = xmlStrdup(val);
2241	    else
2242		ret->stringval = xmlStrdup((const xmlChar *)"");
2243#ifdef XP_DEBUG_OBJ_USAGE
2244	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2245#endif
2246	    return(ret);
2247	}
2248    }
2249    return(xmlXPathNewString(val));
2250}
2251
2252/**
2253 * xmlXPathCacheNewBoolean:
2254 * @ctxt: the XPath context
2255 * @val:  the boolean value
2256 *
2257 * This is the cached version of xmlXPathNewBoolean().
2258 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2259 *
2260 * Returns the created or reused object.
2261 */
2262static xmlXPathObjectPtr
2263xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2264{
2265    if ((ctxt != NULL) && (ctxt->cache)) {
2266	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2267
2268	if ((cache->booleanObjs != NULL) &&
2269	    (cache->booleanObjs->number != 0))
2270	{
2271	    xmlXPathObjectPtr ret;
2272
2273	    ret = (xmlXPathObjectPtr)
2274		cache->booleanObjs->items[--cache->booleanObjs->number];
2275	    ret->type = XPATH_BOOLEAN;
2276	    ret->boolval = (val != 0);
2277#ifdef XP_DEBUG_OBJ_USAGE
2278	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2279#endif
2280	    return(ret);
2281	} else if ((cache->miscObjs != NULL) &&
2282	    (cache->miscObjs->number != 0))
2283	{
2284	    xmlXPathObjectPtr ret;
2285
2286	    ret = (xmlXPathObjectPtr)
2287		cache->miscObjs->items[--cache->miscObjs->number];
2288
2289	    ret->type = XPATH_BOOLEAN;
2290	    ret->boolval = (val != 0);
2291#ifdef XP_DEBUG_OBJ_USAGE
2292	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2293#endif
2294	    return(ret);
2295	}
2296    }
2297    return(xmlXPathNewBoolean(val));
2298}
2299
2300/**
2301 * xmlXPathCacheNewFloat:
2302 * @ctxt: the XPath context
2303 * @val:  the double value
2304 *
2305 * This is the cached version of xmlXPathNewFloat().
2306 * Acquires an xmlXPathObjectPtr of type double and of value @val
2307 *
2308 * Returns the created or reused object.
2309 */
2310static xmlXPathObjectPtr
2311xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2312{
2313     if ((ctxt != NULL) && (ctxt->cache)) {
2314	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2315
2316	if ((cache->numberObjs != NULL) &&
2317	    (cache->numberObjs->number != 0))
2318	{
2319	    xmlXPathObjectPtr ret;
2320
2321	    ret = (xmlXPathObjectPtr)
2322		cache->numberObjs->items[--cache->numberObjs->number];
2323	    ret->type = XPATH_NUMBER;
2324	    ret->floatval = val;
2325#ifdef XP_DEBUG_OBJ_USAGE
2326	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2327#endif
2328	    return(ret);
2329	} else if ((cache->miscObjs != NULL) &&
2330	    (cache->miscObjs->number != 0))
2331	{
2332	    xmlXPathObjectPtr ret;
2333
2334	    ret = (xmlXPathObjectPtr)
2335		cache->miscObjs->items[--cache->miscObjs->number];
2336
2337	    ret->type = XPATH_NUMBER;
2338	    ret->floatval = val;
2339#ifdef XP_DEBUG_OBJ_USAGE
2340	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2341#endif
2342	    return(ret);
2343	}
2344    }
2345    return(xmlXPathNewFloat(val));
2346}
2347
2348/**
2349 * xmlXPathCacheConvertString:
2350 * @ctxt: the XPath context
2351 * @val:  an XPath object
2352 *
2353 * This is the cached version of xmlXPathConvertString().
2354 * Converts an existing object to its string() equivalent
2355 *
2356 * Returns a created or reused object, the old one is freed (cached)
2357 *         (or the operation is done directly on @val)
2358 */
2359
2360static xmlXPathObjectPtr
2361xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2362    xmlChar *res = NULL;
2363
2364    if (val == NULL)
2365	return(xmlXPathCacheNewCString(ctxt, ""));
2366
2367    switch (val->type) {
2368    case XPATH_UNDEFINED:
2369#ifdef DEBUG_EXPR
2370	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2371#endif
2372	break;
2373    case XPATH_NODESET:
2374    case XPATH_XSLT_TREE:
2375	res = xmlXPathCastNodeSetToString(val->nodesetval);
2376	break;
2377    case XPATH_STRING:
2378	return(val);
2379    case XPATH_BOOLEAN:
2380	res = xmlXPathCastBooleanToString(val->boolval);
2381	break;
2382    case XPATH_NUMBER:
2383	res = xmlXPathCastNumberToString(val->floatval);
2384	break;
2385    case XPATH_USERS:
2386    case XPATH_POINT:
2387    case XPATH_RANGE:
2388    case XPATH_LOCATIONSET:
2389	TODO;
2390	break;
2391    }
2392    xmlXPathReleaseObject(ctxt, val);
2393    if (res == NULL)
2394	return(xmlXPathCacheNewCString(ctxt, ""));
2395    return(xmlXPathCacheWrapString(ctxt, res));
2396}
2397
2398/**
2399 * xmlXPathCacheObjectCopy:
2400 * @ctxt: the XPath context
2401 * @val:  the original object
2402 *
2403 * This is the cached version of xmlXPathObjectCopy().
2404 * Acquire a copy of a given object
2405 *
2406 * Returns a created or reused created object.
2407 */
2408static xmlXPathObjectPtr
2409xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2410{
2411    if (val == NULL)
2412	return(NULL);
2413
2414    if (XP_HAS_CACHE(ctxt)) {
2415	switch (val->type) {
2416	    case XPATH_NODESET:
2417		return(xmlXPathCacheWrapNodeSet(ctxt,
2418		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2419	    case XPATH_STRING:
2420		return(xmlXPathCacheNewString(ctxt, val->stringval));
2421	    case XPATH_BOOLEAN:
2422		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2423	    case XPATH_NUMBER:
2424		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2425	    default:
2426		break;
2427	}
2428    }
2429    return(xmlXPathObjectCopy(val));
2430}
2431
2432/**
2433 * xmlXPathCacheConvertBoolean:
2434 * @ctxt: the XPath context
2435 * @val:  an XPath object
2436 *
2437 * This is the cached version of xmlXPathConvertBoolean().
2438 * Converts an existing object to its boolean() equivalent
2439 *
2440 * Returns a created or reused object, the old one is freed (or the operation
2441 *         is done directly on @val)
2442 */
2443static xmlXPathObjectPtr
2444xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2445    xmlXPathObjectPtr ret;
2446
2447    if (val == NULL)
2448	return(xmlXPathCacheNewBoolean(ctxt, 0));
2449    if (val->type == XPATH_BOOLEAN)
2450	return(val);
2451    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2452    xmlXPathReleaseObject(ctxt, val);
2453    return(ret);
2454}
2455
2456/**
2457 * xmlXPathCacheConvertNumber:
2458 * @ctxt: the XPath context
2459 * @val:  an XPath object
2460 *
2461 * This is the cached version of xmlXPathConvertNumber().
2462 * Converts an existing object to its number() equivalent
2463 *
2464 * Returns a created or reused object, the old one is freed (or the operation
2465 *         is done directly on @val)
2466 */
2467static xmlXPathObjectPtr
2468xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2469    xmlXPathObjectPtr ret;
2470
2471    if (val == NULL)
2472	return(xmlXPathCacheNewFloat(ctxt, 0.0));
2473    if (val->type == XPATH_NUMBER)
2474	return(val);
2475    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2476    xmlXPathReleaseObject(ctxt, val);
2477    return(ret);
2478}
2479
2480/************************************************************************
2481 *									*
2482 *		Parser stacks related functions and macros		*
2483 *									*
2484 ************************************************************************/
2485
2486/**
2487 * xmlXPathSetFrame:
2488 * @ctxt: an XPath parser context
2489 *
2490 * Set the callee evaluation frame
2491 *
2492 * Returns the previous frame value to be restored once done
2493 */
2494static int
2495xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2496    int ret;
2497
2498    if (ctxt == NULL)
2499        return(0);
2500    ret = ctxt->valueFrame;
2501    ctxt->valueFrame = ctxt->valueNr;
2502    return(ret);
2503}
2504
2505/**
2506 * xmlXPathPopFrame:
2507 * @ctxt: an XPath parser context
2508 * @frame: the previous frame value
2509 *
2510 * Remove the callee evaluation frame
2511 */
2512static void
2513xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2514    if (ctxt == NULL)
2515        return;
2516    if (ctxt->valueNr < ctxt->valueFrame) {
2517        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2518    }
2519    ctxt->valueFrame = frame;
2520}
2521
2522/**
2523 * valuePop:
2524 * @ctxt: an XPath evaluation context
2525 *
2526 * Pops the top XPath object from the value stack
2527 *
2528 * Returns the XPath object just removed
2529 */
2530xmlXPathObjectPtr
2531valuePop(xmlXPathParserContextPtr ctxt)
2532{
2533    xmlXPathObjectPtr ret;
2534
2535    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2536        return (NULL);
2537
2538    if (ctxt->valueNr <= ctxt->valueFrame) {
2539        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2540        return (NULL);
2541    }
2542
2543    ctxt->valueNr--;
2544    if (ctxt->valueNr > 0)
2545        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2546    else
2547        ctxt->value = NULL;
2548    ret = ctxt->valueTab[ctxt->valueNr];
2549    ctxt->valueTab[ctxt->valueNr] = NULL;
2550    return (ret);
2551}
2552/**
2553 * valuePush:
2554 * @ctxt:  an XPath evaluation context
2555 * @value:  the XPath object
2556 *
2557 * Pushes a new XPath object on top of the value stack
2558 *
2559 * returns the number of items on the value stack
2560 */
2561int
2562valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2563{
2564    if ((ctxt == NULL) || (value == NULL)) return(-1);
2565    if (ctxt->valueNr >= ctxt->valueMax) {
2566        xmlXPathObjectPtr *tmp;
2567
2568        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2569            xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2570            ctxt->error = XPATH_MEMORY_ERROR;
2571            return (0);
2572        }
2573        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2574                                             2 * ctxt->valueMax *
2575                                             sizeof(ctxt->valueTab[0]));
2576        if (tmp == NULL) {
2577            xmlXPathErrMemory(NULL, "pushing value\n");
2578            ctxt->error = XPATH_MEMORY_ERROR;
2579            return (0);
2580        }
2581        ctxt->valueMax *= 2;
2582	ctxt->valueTab = tmp;
2583    }
2584    ctxt->valueTab[ctxt->valueNr] = value;
2585    ctxt->value = value;
2586    return (ctxt->valueNr++);
2587}
2588
2589/**
2590 * xmlXPathPopBoolean:
2591 * @ctxt:  an XPath parser context
2592 *
2593 * Pops a boolean from the stack, handling conversion if needed.
2594 * Check error with #xmlXPathCheckError.
2595 *
2596 * Returns the boolean
2597 */
2598int
2599xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2600    xmlXPathObjectPtr obj;
2601    int ret;
2602
2603    obj = valuePop(ctxt);
2604    if (obj == NULL) {
2605	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2606	return(0);
2607    }
2608    if (obj->type != XPATH_BOOLEAN)
2609	ret = xmlXPathCastToBoolean(obj);
2610    else
2611        ret = obj->boolval;
2612    xmlXPathReleaseObject(ctxt->context, obj);
2613    return(ret);
2614}
2615
2616/**
2617 * xmlXPathPopNumber:
2618 * @ctxt:  an XPath parser context
2619 *
2620 * Pops a number from the stack, handling conversion if needed.
2621 * Check error with #xmlXPathCheckError.
2622 *
2623 * Returns the number
2624 */
2625double
2626xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2627    xmlXPathObjectPtr obj;
2628    double ret;
2629
2630    obj = valuePop(ctxt);
2631    if (obj == NULL) {
2632	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2633	return(0);
2634    }
2635    if (obj->type != XPATH_NUMBER)
2636	ret = xmlXPathCastToNumber(obj);
2637    else
2638        ret = obj->floatval;
2639    xmlXPathReleaseObject(ctxt->context, obj);
2640    return(ret);
2641}
2642
2643/**
2644 * xmlXPathPopString:
2645 * @ctxt:  an XPath parser context
2646 *
2647 * Pops a string from the stack, handling conversion if needed.
2648 * Check error with #xmlXPathCheckError.
2649 *
2650 * Returns the string
2651 */
2652xmlChar *
2653xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2654    xmlXPathObjectPtr obj;
2655    xmlChar * ret;
2656
2657    obj = valuePop(ctxt);
2658    if (obj == NULL) {
2659	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2660	return(NULL);
2661    }
2662    ret = xmlXPathCastToString(obj);	/* this does required strdup */
2663    /* TODO: needs refactoring somewhere else */
2664    if (obj->stringval == ret)
2665	obj->stringval = NULL;
2666    xmlXPathReleaseObject(ctxt->context, obj);
2667    return(ret);
2668}
2669
2670/**
2671 * xmlXPathPopNodeSet:
2672 * @ctxt:  an XPath parser context
2673 *
2674 * Pops a node-set from the stack, handling conversion if needed.
2675 * Check error with #xmlXPathCheckError.
2676 *
2677 * Returns the node-set
2678 */
2679xmlNodeSetPtr
2680xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2681    xmlXPathObjectPtr obj;
2682    xmlNodeSetPtr ret;
2683
2684    if (ctxt == NULL) return(NULL);
2685    if (ctxt->value == NULL) {
2686	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2687	return(NULL);
2688    }
2689    if (!xmlXPathStackIsNodeSet(ctxt)) {
2690	xmlXPathSetTypeError(ctxt);
2691	return(NULL);
2692    }
2693    obj = valuePop(ctxt);
2694    ret = obj->nodesetval;
2695#if 0
2696    /* to fix memory leak of not clearing obj->user */
2697    if (obj->boolval && obj->user != NULL)
2698        xmlFreeNodeList((xmlNodePtr) obj->user);
2699#endif
2700    obj->nodesetval = NULL;
2701    xmlXPathReleaseObject(ctxt->context, obj);
2702    return(ret);
2703}
2704
2705/**
2706 * xmlXPathPopExternal:
2707 * @ctxt:  an XPath parser context
2708 *
2709 * Pops an external object from the stack, handling conversion if needed.
2710 * Check error with #xmlXPathCheckError.
2711 *
2712 * Returns the object
2713 */
2714void *
2715xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2716    xmlXPathObjectPtr obj;
2717    void * ret;
2718
2719    if ((ctxt == NULL) || (ctxt->value == NULL)) {
2720	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2721	return(NULL);
2722    }
2723    if (ctxt->value->type != XPATH_USERS) {
2724	xmlXPathSetTypeError(ctxt);
2725	return(NULL);
2726    }
2727    obj = valuePop(ctxt);
2728    ret = obj->user;
2729    obj->user = NULL;
2730    xmlXPathReleaseObject(ctxt->context, obj);
2731    return(ret);
2732}
2733
2734/*
2735 * Macros for accessing the content. Those should be used only by the parser,
2736 * and not exported.
2737 *
2738 * Dirty macros, i.e. one need to make assumption on the context to use them
2739 *
2740 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2741 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2742 *           in ISO-Latin or UTF-8.
2743 *           This should be used internally by the parser
2744 *           only to compare to ASCII values otherwise it would break when
2745 *           running with UTF-8 encoding.
2746 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2747 *           to compare on ASCII based substring.
2748 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2749 *           strings within the parser.
2750 *   CURRENT Returns the current char value, with the full decoding of
2751 *           UTF-8 if we are using this mode. It returns an int.
2752 *   NEXT    Skip to the next character, this does the proper decoding
2753 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2754 *           It returns the pointer to the current xmlChar.
2755 */
2756
2757#define CUR (*ctxt->cur)
2758#define SKIP(val) ctxt->cur += (val)
2759#define NXT(val) ctxt->cur[(val)]
2760#define CUR_PTR ctxt->cur
2761#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2762
2763#define COPY_BUF(l,b,i,v)                                              \
2764    if (l == 1) b[i++] = (xmlChar) v;                                  \
2765    else i += xmlCopyChar(l,&b[i],v)
2766
2767#define NEXTL(l)  ctxt->cur += l
2768
2769#define SKIP_BLANKS							\
2770    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2771
2772#define CURRENT (*ctxt->cur)
2773#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2774
2775
2776#ifndef DBL_DIG
2777#define DBL_DIG 16
2778#endif
2779#ifndef DBL_EPSILON
2780#define DBL_EPSILON 1E-9
2781#endif
2782
2783#define UPPER_DOUBLE 1E9
2784#define LOWER_DOUBLE 1E-5
2785#define	LOWER_DOUBLE_EXP 5
2786
2787#define INTEGER_DIGITS DBL_DIG
2788#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2789#define EXPONENT_DIGITS (3 + 2)
2790
2791/**
2792 * xmlXPathFormatNumber:
2793 * @number:     number to format
2794 * @buffer:     output buffer
2795 * @buffersize: size of output buffer
2796 *
2797 * Convert the number into a string representation.
2798 */
2799static void
2800xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2801{
2802    switch (xmlXPathIsInf(number)) {
2803    case 1:
2804	if (buffersize > (int)sizeof("Infinity"))
2805	    snprintf(buffer, buffersize, "Infinity");
2806	break;
2807    case -1:
2808	if (buffersize > (int)sizeof("-Infinity"))
2809	    snprintf(buffer, buffersize, "-Infinity");
2810	break;
2811    default:
2812	if (xmlXPathIsNaN(number)) {
2813	    if (buffersize > (int)sizeof("NaN"))
2814		snprintf(buffer, buffersize, "NaN");
2815	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
2816	    snprintf(buffer, buffersize, "0");
2817	} else if (number == ((int) number)) {
2818	    char work[30];
2819	    char *ptr, *cur;
2820	    int value = (int) number;
2821
2822            ptr = &buffer[0];
2823	    if (value == 0) {
2824		*ptr++ = '0';
2825	    } else {
2826		snprintf(work, 29, "%d", value);
2827		cur = &work[0];
2828		while ((*cur) && (ptr - buffer < buffersize)) {
2829		    *ptr++ = *cur++;
2830		}
2831	    }
2832	    if (ptr - buffer < buffersize) {
2833		*ptr = 0;
2834	    } else if (buffersize > 0) {
2835		ptr--;
2836		*ptr = 0;
2837	    }
2838	} else {
2839	    /*
2840	      For the dimension of work,
2841	          DBL_DIG is number of significant digits
2842		  EXPONENT is only needed for "scientific notation"
2843	          3 is sign, decimal point, and terminating zero
2844		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2845	      Note that this dimension is slightly (a few characters)
2846	      larger than actually necessary.
2847	    */
2848	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2849	    int integer_place, fraction_place;
2850	    char *ptr;
2851	    char *after_fraction;
2852	    double absolute_value;
2853	    int size;
2854
2855	    absolute_value = fabs(number);
2856
2857	    /*
2858	     * First choose format - scientific or regular floating point.
2859	     * In either case, result is in work, and after_fraction points
2860	     * just past the fractional part.
2861	    */
2862	    if ( ((absolute_value > UPPER_DOUBLE) ||
2863		  (absolute_value < LOWER_DOUBLE)) &&
2864		 (absolute_value != 0.0) ) {
2865		/* Use scientific notation */
2866		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2867		fraction_place = DBL_DIG - 1;
2868		size = snprintf(work, sizeof(work),"%*.*e",
2869			 integer_place, fraction_place, number);
2870		while ((size > 0) && (work[size] != 'e')) size--;
2871
2872	    }
2873	    else {
2874		/* Use regular notation */
2875		if (absolute_value > 0.0) {
2876		    integer_place = (int)log10(absolute_value);
2877		    if (integer_place > 0)
2878		        fraction_place = DBL_DIG - integer_place - 1;
2879		    else
2880		        fraction_place = DBL_DIG - integer_place;
2881		} else {
2882		    fraction_place = 1;
2883		}
2884		size = snprintf(work, sizeof(work), "%0.*f",
2885				fraction_place, number);
2886	    }
2887
2888	    /* Remove fractional trailing zeroes */
2889	    after_fraction = work + size;
2890	    ptr = after_fraction;
2891	    while (*(--ptr) == '0')
2892		;
2893	    if (*ptr != '.')
2894	        ptr++;
2895	    while ((*ptr++ = *after_fraction++) != 0);
2896
2897	    /* Finally copy result back to caller */
2898	    size = strlen(work) + 1;
2899	    if (size > buffersize) {
2900		work[buffersize - 1] = 0;
2901		size = buffersize;
2902	    }
2903	    memmove(buffer, work, size);
2904	}
2905	break;
2906    }
2907}
2908
2909
2910/************************************************************************
2911 *									*
2912 *			Routines to handle NodeSets			*
2913 *									*
2914 ************************************************************************/
2915
2916/**
2917 * xmlXPathOrderDocElems:
2918 * @doc:  an input document
2919 *
2920 * Call this routine to speed up XPath computation on static documents.
2921 * This stamps all the element nodes with the document order
2922 * Like for line information, the order is kept in the element->content
2923 * field, the value stored is actually - the node number (starting at -1)
2924 * to be able to differentiate from line numbers.
2925 *
2926 * Returns the number of elements found in the document or -1 in case
2927 *    of error.
2928 */
2929long
2930xmlXPathOrderDocElems(xmlDocPtr doc) {
2931    long count = 0;
2932    xmlNodePtr cur;
2933
2934    if (doc == NULL)
2935	return(-1);
2936    cur = doc->children;
2937    while (cur != NULL) {
2938	if (cur->type == XML_ELEMENT_NODE) {
2939	    cur->content = (void *) (-(++count));
2940	    if (cur->children != NULL) {
2941		cur = cur->children;
2942		continue;
2943	    }
2944	}
2945	if (cur->next != NULL) {
2946	    cur = cur->next;
2947	    continue;
2948	}
2949	do {
2950	    cur = cur->parent;
2951	    if (cur == NULL)
2952		break;
2953	    if (cur == (xmlNodePtr) doc) {
2954		cur = NULL;
2955		break;
2956	    }
2957	    if (cur->next != NULL) {
2958		cur = cur->next;
2959		break;
2960	    }
2961	} while (cur != NULL);
2962    }
2963    return(count);
2964}
2965
2966/**
2967 * xmlXPathCmpNodes:
2968 * @node1:  the first node
2969 * @node2:  the second node
2970 *
2971 * Compare two nodes w.r.t document order
2972 *
2973 * Returns -2 in case of error 1 if first point < second point, 0 if
2974 *         it's the same node, -1 otherwise
2975 */
2976int
2977xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2978    int depth1, depth2;
2979    int attr1 = 0, attr2 = 0;
2980    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2981    xmlNodePtr cur, root;
2982
2983    if ((node1 == NULL) || (node2 == NULL))
2984	return(-2);
2985    /*
2986     * a couple of optimizations which will avoid computations in most cases
2987     */
2988    if (node1 == node2)		/* trivial case */
2989	return(0);
2990    if (node1->type == XML_ATTRIBUTE_NODE) {
2991	attr1 = 1;
2992	attrNode1 = node1;
2993	node1 = node1->parent;
2994    }
2995    if (node2->type == XML_ATTRIBUTE_NODE) {
2996	attr2 = 1;
2997	attrNode2 = node2;
2998	node2 = node2->parent;
2999    }
3000    if (node1 == node2) {
3001	if (attr1 == attr2) {
3002	    /* not required, but we keep attributes in order */
3003	    if (attr1 != 0) {
3004	        cur = attrNode2->prev;
3005		while (cur != NULL) {
3006		    if (cur == attrNode1)
3007		        return (1);
3008		    cur = cur->prev;
3009		}
3010		return (-1);
3011	    }
3012	    return(0);
3013	}
3014	if (attr2 == 1)
3015	    return(1);
3016	return(-1);
3017    }
3018    if ((node1->type == XML_NAMESPACE_DECL) ||
3019        (node2->type == XML_NAMESPACE_DECL))
3020	return(1);
3021    if (node1 == node2->prev)
3022	return(1);
3023    if (node1 == node2->next)
3024	return(-1);
3025
3026    /*
3027     * Speedup using document order if availble.
3028     */
3029    if ((node1->type == XML_ELEMENT_NODE) &&
3030	(node2->type == XML_ELEMENT_NODE) &&
3031	(0 > (long) node1->content) &&
3032	(0 > (long) node2->content) &&
3033	(node1->doc == node2->doc)) {
3034	long l1, l2;
3035
3036	l1 = -((long) node1->content);
3037	l2 = -((long) node2->content);
3038	if (l1 < l2)
3039	    return(1);
3040	if (l1 > l2)
3041	    return(-1);
3042    }
3043
3044    /*
3045     * compute depth to root
3046     */
3047    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3048	if (cur == node1)
3049	    return(1);
3050	depth2++;
3051    }
3052    root = cur;
3053    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3054	if (cur == node2)
3055	    return(-1);
3056	depth1++;
3057    }
3058    /*
3059     * Distinct document (or distinct entities :-( ) case.
3060     */
3061    if (root != cur) {
3062	return(-2);
3063    }
3064    /*
3065     * get the nearest common ancestor.
3066     */
3067    while (depth1 > depth2) {
3068	depth1--;
3069	node1 = node1->parent;
3070    }
3071    while (depth2 > depth1) {
3072	depth2--;
3073	node2 = node2->parent;
3074    }
3075    while (node1->parent != node2->parent) {
3076	node1 = node1->parent;
3077	node2 = node2->parent;
3078	/* should not happen but just in case ... */
3079	if ((node1 == NULL) || (node2 == NULL))
3080	    return(-2);
3081    }
3082    /*
3083     * Find who's first.
3084     */
3085    if (node1 == node2->prev)
3086	return(1);
3087    if (node1 == node2->next)
3088	return(-1);
3089    /*
3090     * Speedup using document order if availble.
3091     */
3092    if ((node1->type == XML_ELEMENT_NODE) &&
3093	(node2->type == XML_ELEMENT_NODE) &&
3094	(0 > (long) node1->content) &&
3095	(0 > (long) node2->content) &&
3096	(node1->doc == node2->doc)) {
3097	long l1, l2;
3098
3099	l1 = -((long) node1->content);
3100	l2 = -((long) node2->content);
3101	if (l1 < l2)
3102	    return(1);
3103	if (l1 > l2)
3104	    return(-1);
3105    }
3106
3107    for (cur = node1->next;cur != NULL;cur = cur->next)
3108	if (cur == node2)
3109	    return(1);
3110    return(-1); /* assume there is no sibling list corruption */
3111}
3112
3113#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3114/**
3115 * xmlXPathCmpNodesExt:
3116 * @node1:  the first node
3117 * @node2:  the second node
3118 *
3119 * Compare two nodes w.r.t document order.
3120 * This one is optimized for handling of non-element nodes.
3121 *
3122 * Returns -2 in case of error 1 if first point < second point, 0 if
3123 *         it's the same node, -1 otherwise
3124 */
3125static int
3126xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
3127    int depth1, depth2;
3128    int misc = 0, precedence1 = 0, precedence2 = 0;
3129    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
3130    xmlNodePtr cur, root;
3131    long l1, l2;
3132
3133    if ((node1 == NULL) || (node2 == NULL))
3134	return(-2);
3135
3136    if (node1 == node2)
3137	return(0);
3138
3139    /*
3140     * a couple of optimizations which will avoid computations in most cases
3141     */
3142    switch (node1->type) {
3143	case XML_ELEMENT_NODE:
3144	    if (node2->type == XML_ELEMENT_NODE) {
3145		if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3146		    (0 > (long) node2->content) &&
3147		    (node1->doc == node2->doc))
3148		{
3149		    l1 = -((long) node1->content);
3150		    l2 = -((long) node2->content);
3151		    if (l1 < l2)
3152			return(1);
3153		    if (l1 > l2)
3154			return(-1);
3155		} else
3156		    goto turtle_comparison;
3157	    }
3158	    break;
3159	case XML_ATTRIBUTE_NODE:
3160	    precedence1 = 1; /* element is owner */
3161	    miscNode1 = node1;
3162	    node1 = node1->parent;
3163	    misc = 1;
3164	    break;
3165	case XML_TEXT_NODE:
3166	case XML_CDATA_SECTION_NODE:
3167	case XML_COMMENT_NODE:
3168	case XML_PI_NODE: {
3169	    miscNode1 = node1;
3170	    /*
3171	    * Find nearest element node.
3172	    */
3173	    if (node1->prev != NULL) {
3174		do {
3175		    node1 = node1->prev;
3176		    if (node1->type == XML_ELEMENT_NODE) {
3177			precedence1 = 3; /* element in prev-sibl axis */
3178			break;
3179		    }
3180		    if (node1->prev == NULL) {
3181			precedence1 = 2; /* element is parent */
3182			/*
3183			* URGENT TODO: Are there any cases, where the
3184			* parent of such a node is not an element node?
3185			*/
3186			node1 = node1->parent;
3187			break;
3188		    }
3189		} while (1);
3190	    } else {
3191		precedence1 = 2; /* element is parent */
3192		node1 = node1->parent;
3193	    }
3194	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3195		(0 <= (long) node1->content)) {
3196		/*
3197		* Fallback for whatever case.
3198		*/
3199		node1 = miscNode1;
3200		precedence1 = 0;
3201	    } else
3202		misc = 1;
3203	}
3204	    break;
3205	case XML_NAMESPACE_DECL:
3206	    /*
3207	    * TODO: why do we return 1 for namespace nodes?
3208	    */
3209	    return(1);
3210	default:
3211	    break;
3212    }
3213    switch (node2->type) {
3214	case XML_ELEMENT_NODE:
3215	    break;
3216	case XML_ATTRIBUTE_NODE:
3217	    precedence2 = 1; /* element is owner */
3218	    miscNode2 = node2;
3219	    node2 = node2->parent;
3220	    misc = 1;
3221	    break;
3222	case XML_TEXT_NODE:
3223	case XML_CDATA_SECTION_NODE:
3224	case XML_COMMENT_NODE:
3225	case XML_PI_NODE: {
3226	    miscNode2 = node2;
3227	    if (node2->prev != NULL) {
3228		do {
3229		    node2 = node2->prev;
3230		    if (node2->type == XML_ELEMENT_NODE) {
3231			precedence2 = 3; /* element in prev-sibl axis */
3232			break;
3233		    }
3234		    if (node2->prev == NULL) {
3235			precedence2 = 2; /* element is parent */
3236			node2 = node2->parent;
3237			break;
3238		    }
3239		} while (1);
3240	    } else {
3241		precedence2 = 2; /* element is parent */
3242		node2 = node2->parent;
3243	    }
3244	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3245		(0 <= (long) node1->content))
3246	    {
3247		node2 = miscNode2;
3248		precedence2 = 0;
3249	    } else
3250		misc = 1;
3251	}
3252	    break;
3253	case XML_NAMESPACE_DECL:
3254	    return(1);
3255	default:
3256	    break;
3257    }
3258    if (misc) {
3259	if (node1 == node2) {
3260	    if (precedence1 == precedence2) {
3261		/*
3262		* The ugly case; but normally there aren't many
3263		* adjacent non-element nodes around.
3264		*/
3265		cur = miscNode2->prev;
3266		while (cur != NULL) {
3267		    if (cur == miscNode1)
3268			return(1);
3269		    if (cur->type == XML_ELEMENT_NODE)
3270			return(-1);
3271		    cur = cur->prev;
3272		}
3273		return (-1);
3274	    } else {
3275		/*
3276		* Evaluate based on higher precedence wrt to the element.
3277		* TODO: This assumes attributes are sorted before content.
3278		*   Is this 100% correct?
3279		*/
3280		if (precedence1 < precedence2)
3281		    return(1);
3282		else
3283		    return(-1);
3284	    }
3285	}
3286	/*
3287	* Special case: One of the helper-elements is contained by the other.
3288	* <foo>
3289	*   <node2>
3290	*     <node1>Text-1(precedence1 == 2)</node1>
3291	*   </node2>
3292	*   Text-6(precedence2 == 3)
3293	* </foo>
3294	*/
3295	if ((precedence2 == 3) && (precedence1 > 1)) {
3296	    cur = node1->parent;
3297	    while (cur) {
3298		if (cur == node2)
3299		    return(1);
3300		cur = cur->parent;
3301	    }
3302	}
3303	if ((precedence1 == 3) && (precedence2 > 1)) {
3304	    cur = node2->parent;
3305	    while (cur) {
3306		if (cur == node1)
3307		    return(-1);
3308		cur = cur->parent;
3309	    }
3310	}
3311    }
3312
3313    /*
3314     * Speedup using document order if availble.
3315     */
3316    if ((node1->type == XML_ELEMENT_NODE) &&
3317	(node2->type == XML_ELEMENT_NODE) &&
3318	(0 > (long) node1->content) &&
3319	(0 > (long) node2->content) &&
3320	(node1->doc == node2->doc)) {
3321
3322	l1 = -((long) node1->content);
3323	l2 = -((long) node2->content);
3324	if (l1 < l2)
3325	    return(1);
3326	if (l1 > l2)
3327	    return(-1);
3328    }
3329
3330turtle_comparison:
3331
3332    if (node1 == node2->prev)
3333	return(1);
3334    if (node1 == node2->next)
3335	return(-1);
3336    /*
3337     * compute depth to root
3338     */
3339    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3340	if (cur == node1)
3341	    return(1);
3342	depth2++;
3343    }
3344    root = cur;
3345    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3346	if (cur == node2)
3347	    return(-1);
3348	depth1++;
3349    }
3350    /*
3351     * Distinct document (or distinct entities :-( ) case.
3352     */
3353    if (root != cur) {
3354	return(-2);
3355    }
3356    /*
3357     * get the nearest common ancestor.
3358     */
3359    while (depth1 > depth2) {
3360	depth1--;
3361	node1 = node1->parent;
3362    }
3363    while (depth2 > depth1) {
3364	depth2--;
3365	node2 = node2->parent;
3366    }
3367    while (node1->parent != node2->parent) {
3368	node1 = node1->parent;
3369	node2 = node2->parent;
3370	/* should not happen but just in case ... */
3371	if ((node1 == NULL) || (node2 == NULL))
3372	    return(-2);
3373    }
3374    /*
3375     * Find who's first.
3376     */
3377    if (node1 == node2->prev)
3378	return(1);
3379    if (node1 == node2->next)
3380	return(-1);
3381    /*
3382     * Speedup using document order if availble.
3383     */
3384    if ((node1->type == XML_ELEMENT_NODE) &&
3385	(node2->type == XML_ELEMENT_NODE) &&
3386	(0 > (long) node1->content) &&
3387	(0 > (long) node2->content) &&
3388	(node1->doc == node2->doc)) {
3389
3390	l1 = -((long) node1->content);
3391	l2 = -((long) node2->content);
3392	if (l1 < l2)
3393	    return(1);
3394	if (l1 > l2)
3395	    return(-1);
3396    }
3397
3398    for (cur = node1->next;cur != NULL;cur = cur->next)
3399	if (cur == node2)
3400	    return(1);
3401    return(-1); /* assume there is no sibling list corruption */
3402}
3403#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
3404
3405/**
3406 * xmlXPathNodeSetSort:
3407 * @set:  the node set
3408 *
3409 * Sort the node set in document order
3410 */
3411void
3412xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3413#ifndef WITH_TIM_SORT
3414    int i, j, incr, len;
3415    xmlNodePtr tmp;
3416#endif
3417
3418    if (set == NULL)
3419	return;
3420
3421#ifndef WITH_TIM_SORT
3422    /*
3423     * Use the old Shell's sort implementation to sort the node-set
3424     * Timsort ought to be quite faster
3425     */
3426    len = set->nodeNr;
3427    for (incr = len / 2; incr > 0; incr /= 2) {
3428	for (i = incr; i < len; i++) {
3429	    j = i - incr;
3430	    while (j >= 0) {
3431#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3432		if (xmlXPathCmpNodesExt(set->nodeTab[j],
3433			set->nodeTab[j + incr]) == -1)
3434#else
3435		if (xmlXPathCmpNodes(set->nodeTab[j],
3436			set->nodeTab[j + incr]) == -1)
3437#endif
3438		{
3439		    tmp = set->nodeTab[j];
3440		    set->nodeTab[j] = set->nodeTab[j + incr];
3441		    set->nodeTab[j + incr] = tmp;
3442		    j -= incr;
3443		} else
3444		    break;
3445	    }
3446	}
3447    }
3448#else /* WITH_TIM_SORT */
3449    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3450#endif /* WITH_TIM_SORT */
3451}
3452
3453#define XML_NODESET_DEFAULT	10
3454/**
3455 * xmlXPathNodeSetDupNs:
3456 * @node:  the parent node of the namespace XPath node
3457 * @ns:  the libxml namespace declaration node.
3458 *
3459 * Namespace node in libxml don't match the XPath semantic. In a node set
3460 * the namespace nodes are duplicated and the next pointer is set to the
3461 * parent node in the XPath semantic.
3462 *
3463 * Returns the newly created object.
3464 */
3465static xmlNodePtr
3466xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3467    xmlNsPtr cur;
3468
3469    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3470	return(NULL);
3471    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3472	return((xmlNodePtr) ns);
3473
3474    /*
3475     * Allocate a new Namespace and fill the fields.
3476     */
3477    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3478    if (cur == NULL) {
3479        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3480	return(NULL);
3481    }
3482    memset(cur, 0, sizeof(xmlNs));
3483    cur->type = XML_NAMESPACE_DECL;
3484    if (ns->href != NULL)
3485	cur->href = xmlStrdup(ns->href);
3486    if (ns->prefix != NULL)
3487	cur->prefix = xmlStrdup(ns->prefix);
3488    cur->next = (xmlNsPtr) node;
3489    return((xmlNodePtr) cur);
3490}
3491
3492/**
3493 * xmlXPathNodeSetFreeNs:
3494 * @ns:  the XPath namespace node found in a nodeset.
3495 *
3496 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3497 * the namespace nodes are duplicated and the next pointer is set to the
3498 * parent node in the XPath semantic. Check if such a node needs to be freed
3499 */
3500void
3501xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3502    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3503	return;
3504
3505    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3506	if (ns->href != NULL)
3507	    xmlFree((xmlChar *)ns->href);
3508	if (ns->prefix != NULL)
3509	    xmlFree((xmlChar *)ns->prefix);
3510	xmlFree(ns);
3511    }
3512}
3513
3514/**
3515 * xmlXPathNodeSetCreate:
3516 * @val:  an initial xmlNodePtr, or NULL
3517 *
3518 * Create a new xmlNodeSetPtr of type double and of value @val
3519 *
3520 * Returns the newly created object.
3521 */
3522xmlNodeSetPtr
3523xmlXPathNodeSetCreate(xmlNodePtr val) {
3524    xmlNodeSetPtr ret;
3525
3526    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3527    if (ret == NULL) {
3528        xmlXPathErrMemory(NULL, "creating nodeset\n");
3529	return(NULL);
3530    }
3531    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3532    if (val != NULL) {
3533        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3534					     sizeof(xmlNodePtr));
3535	if (ret->nodeTab == NULL) {
3536	    xmlXPathErrMemory(NULL, "creating nodeset\n");
3537	    xmlFree(ret);
3538	    return(NULL);
3539	}
3540	memset(ret->nodeTab, 0 ,
3541	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3542        ret->nodeMax = XML_NODESET_DEFAULT;
3543	if (val->type == XML_NAMESPACE_DECL) {
3544	    xmlNsPtr ns = (xmlNsPtr) val;
3545
3546	    ret->nodeTab[ret->nodeNr++] =
3547		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3548	} else
3549	    ret->nodeTab[ret->nodeNr++] = val;
3550    }
3551    return(ret);
3552}
3553
3554/**
3555 * xmlXPathNodeSetCreateSize:
3556 * @size:  the initial size of the set
3557 *
3558 * Create a new xmlNodeSetPtr of type double and of value @val
3559 *
3560 * Returns the newly created object.
3561 */
3562static xmlNodeSetPtr
3563xmlXPathNodeSetCreateSize(int size) {
3564    xmlNodeSetPtr ret;
3565
3566    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3567    if (ret == NULL) {
3568        xmlXPathErrMemory(NULL, "creating nodeset\n");
3569	return(NULL);
3570    }
3571    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3572    if (size < XML_NODESET_DEFAULT)
3573	size = XML_NODESET_DEFAULT;
3574    ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3575    if (ret->nodeTab == NULL) {
3576	xmlXPathErrMemory(NULL, "creating nodeset\n");
3577	xmlFree(ret);
3578	return(NULL);
3579    }
3580    memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3581    ret->nodeMax = size;
3582    return(ret);
3583}
3584
3585/**
3586 * xmlXPathNodeSetContains:
3587 * @cur:  the node-set
3588 * @val:  the node
3589 *
3590 * checks whether @cur contains @val
3591 *
3592 * Returns true (1) if @cur contains @val, false (0) otherwise
3593 */
3594int
3595xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3596    int i;
3597
3598    if ((cur == NULL) || (val == NULL)) return(0);
3599    if (val->type == XML_NAMESPACE_DECL) {
3600	for (i = 0; i < cur->nodeNr; i++) {
3601	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3602		xmlNsPtr ns1, ns2;
3603
3604		ns1 = (xmlNsPtr) val;
3605		ns2 = (xmlNsPtr) cur->nodeTab[i];
3606		if (ns1 == ns2)
3607		    return(1);
3608		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3609	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
3610		    return(1);
3611	    }
3612	}
3613    } else {
3614	for (i = 0; i < cur->nodeNr; i++) {
3615	    if (cur->nodeTab[i] == val)
3616		return(1);
3617	}
3618    }
3619    return(0);
3620}
3621
3622/**
3623 * xmlXPathNodeSetAddNs:
3624 * @cur:  the initial node set
3625 * @node:  the hosting node
3626 * @ns:  a the namespace node
3627 *
3628 * add a new namespace node to an existing NodeSet
3629 *
3630 * Returns 0 in case of success and -1 in case of error
3631 */
3632int
3633xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3634    int i;
3635
3636
3637    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3638        (ns->type != XML_NAMESPACE_DECL) ||
3639	(node->type != XML_ELEMENT_NODE))
3640	return(-1);
3641
3642    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3643    /*
3644     * prevent duplicates
3645     */
3646    for (i = 0;i < cur->nodeNr;i++) {
3647        if ((cur->nodeTab[i] != NULL) &&
3648	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3649	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3650	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3651	    return(0);
3652    }
3653
3654    /*
3655     * grow the nodeTab if needed
3656     */
3657    if (cur->nodeMax == 0) {
3658        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3659					     sizeof(xmlNodePtr));
3660	if (cur->nodeTab == NULL) {
3661	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3662	    return(-1);
3663	}
3664	memset(cur->nodeTab, 0 ,
3665	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3666        cur->nodeMax = XML_NODESET_DEFAULT;
3667    } else if (cur->nodeNr == cur->nodeMax) {
3668        xmlNodePtr *temp;
3669
3670        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3671            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3672            return(-1);
3673        }
3674	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3675				      sizeof(xmlNodePtr));
3676	if (temp == NULL) {
3677	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3678	    return(-1);
3679	}
3680        cur->nodeMax *= 2;
3681	cur->nodeTab = temp;
3682    }
3683    cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3684    return(0);
3685}
3686
3687/**
3688 * xmlXPathNodeSetAdd:
3689 * @cur:  the initial node set
3690 * @val:  a new xmlNodePtr
3691 *
3692 * add a new xmlNodePtr to an existing NodeSet
3693 *
3694 * Returns 0 in case of success, and -1 in case of error
3695 */
3696int
3697xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3698    int i;
3699
3700    if ((cur == NULL) || (val == NULL)) return(-1);
3701
3702    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3703    /*
3704     * prevent duplcates
3705     */
3706    for (i = 0;i < cur->nodeNr;i++)
3707        if (cur->nodeTab[i] == val) return(0);
3708
3709    /*
3710     * grow the nodeTab if needed
3711     */
3712    if (cur->nodeMax == 0) {
3713        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3714					     sizeof(xmlNodePtr));
3715	if (cur->nodeTab == NULL) {
3716	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3717	    return(-1);
3718	}
3719	memset(cur->nodeTab, 0 ,
3720	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3721        cur->nodeMax = XML_NODESET_DEFAULT;
3722    } else if (cur->nodeNr == cur->nodeMax) {
3723        xmlNodePtr *temp;
3724
3725        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3726            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3727            return(-1);
3728        }
3729	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3730				      sizeof(xmlNodePtr));
3731	if (temp == NULL) {
3732	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3733	    return(-1);
3734	}
3735        cur->nodeMax *= 2;
3736	cur->nodeTab = temp;
3737    }
3738    if (val->type == XML_NAMESPACE_DECL) {
3739	xmlNsPtr ns = (xmlNsPtr) val;
3740
3741	cur->nodeTab[cur->nodeNr++] =
3742	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3743    } else
3744	cur->nodeTab[cur->nodeNr++] = val;
3745    return(0);
3746}
3747
3748/**
3749 * xmlXPathNodeSetAddUnique:
3750 * @cur:  the initial node set
3751 * @val:  a new xmlNodePtr
3752 *
3753 * add a new xmlNodePtr to an existing NodeSet, optimized version
3754 * when we are sure the node is not already in the set.
3755 *
3756 * Returns 0 in case of success and -1 in case of failure
3757 */
3758int
3759xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3760    if ((cur == NULL) || (val == NULL)) return(-1);
3761
3762    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3763    /*
3764     * grow the nodeTab if needed
3765     */
3766    if (cur->nodeMax == 0) {
3767        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3768					     sizeof(xmlNodePtr));
3769	if (cur->nodeTab == NULL) {
3770	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3771	    return(-1);
3772	}
3773	memset(cur->nodeTab, 0 ,
3774	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3775        cur->nodeMax = XML_NODESET_DEFAULT;
3776    } else if (cur->nodeNr == cur->nodeMax) {
3777        xmlNodePtr *temp;
3778
3779        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3780            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3781            return(-1);
3782        }
3783	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3784				      sizeof(xmlNodePtr));
3785	if (temp == NULL) {
3786	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3787	    return(-1);
3788	}
3789	cur->nodeTab = temp;
3790        cur->nodeMax *= 2;
3791    }
3792    if (val->type == XML_NAMESPACE_DECL) {
3793	xmlNsPtr ns = (xmlNsPtr) val;
3794
3795	cur->nodeTab[cur->nodeNr++] =
3796	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3797    } else
3798	cur->nodeTab[cur->nodeNr++] = val;
3799    return(0);
3800}
3801
3802/**
3803 * xmlXPathNodeSetMerge:
3804 * @val1:  the first NodeSet or NULL
3805 * @val2:  the second NodeSet
3806 *
3807 * Merges two nodesets, all nodes from @val2 are added to @val1
3808 * if @val1 is NULL, a new set is created and copied from @val2
3809 *
3810 * Returns @val1 once extended or NULL in case of error.
3811 */
3812xmlNodeSetPtr
3813xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3814    int i, j, initNr, skip;
3815    xmlNodePtr n1, n2;
3816
3817    if (val2 == NULL) return(val1);
3818    if (val1 == NULL) {
3819	val1 = xmlXPathNodeSetCreate(NULL);
3820    if (val1 == NULL)
3821        return (NULL);
3822#if 0
3823	/*
3824	* TODO: The optimization won't work in every case, since
3825	*  those nasty namespace nodes need to be added with
3826	*  xmlXPathNodeSetDupNs() to the set; thus a pure
3827	*  memcpy is not possible.
3828	*  If there was a flag on the nodesetval, indicating that
3829	*  some temporary nodes are in, that would be helpfull.
3830	*/
3831	/*
3832	* Optimization: Create an equally sized node-set
3833	* and memcpy the content.
3834	*/
3835	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3836	if (val1 == NULL)
3837	    return(NULL);
3838	if (val2->nodeNr != 0) {
3839	    if (val2->nodeNr == 1)
3840		*(val1->nodeTab) = *(val2->nodeTab);
3841	    else {
3842		memcpy(val1->nodeTab, val2->nodeTab,
3843		    val2->nodeNr * sizeof(xmlNodePtr));
3844	    }
3845	    val1->nodeNr = val2->nodeNr;
3846	}
3847	return(val1);
3848#endif
3849    }
3850
3851    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3852    initNr = val1->nodeNr;
3853
3854    for (i = 0;i < val2->nodeNr;i++) {
3855	n2 = val2->nodeTab[i];
3856	/*
3857	 * check against duplicates
3858	 */
3859	skip = 0;
3860	for (j = 0; j < initNr; j++) {
3861	    n1 = val1->nodeTab[j];
3862	    if (n1 == n2) {
3863		skip = 1;
3864		break;
3865	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3866		       (n2->type == XML_NAMESPACE_DECL)) {
3867		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3868		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3869			((xmlNsPtr) n2)->prefix)))
3870		{
3871		    skip = 1;
3872		    break;
3873		}
3874	    }
3875	}
3876	if (skip)
3877	    continue;
3878
3879	/*
3880	 * grow the nodeTab if needed
3881	 */
3882	if (val1->nodeMax == 0) {
3883	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3884						    sizeof(xmlNodePtr));
3885	    if (val1->nodeTab == NULL) {
3886	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3887		return(NULL);
3888	    }
3889	    memset(val1->nodeTab, 0 ,
3890		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3891	    val1->nodeMax = XML_NODESET_DEFAULT;
3892	} else if (val1->nodeNr == val1->nodeMax) {
3893	    xmlNodePtr *temp;
3894
3895            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3896                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3897                return(NULL);
3898            }
3899	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3900					     sizeof(xmlNodePtr));
3901	    if (temp == NULL) {
3902	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3903		return(NULL);
3904	    }
3905	    val1->nodeTab = temp;
3906	    val1->nodeMax *= 2;
3907	}
3908	if (n2->type == XML_NAMESPACE_DECL) {
3909	    xmlNsPtr ns = (xmlNsPtr) n2;
3910
3911	    val1->nodeTab[val1->nodeNr++] =
3912		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3913	} else
3914	    val1->nodeTab[val1->nodeNr++] = n2;
3915    }
3916
3917    return(val1);
3918}
3919
3920
3921/**
3922 * xmlXPathNodeSetMergeAndClear:
3923 * @set1:  the first NodeSet or NULL
3924 * @set2:  the second NodeSet
3925 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3926 *
3927 * Merges two nodesets, all nodes from @set2 are added to @set1
3928 * if @set1 is NULL, a new set is created and copied from @set2.
3929 * Checks for duplicate nodes. Clears set2.
3930 *
3931 * Returns @set1 once extended or NULL in case of error.
3932 */
3933static xmlNodeSetPtr
3934xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3935			     int hasNullEntries)
3936{
3937    if ((set1 == NULL) && (hasNullEntries == 0)) {
3938	/*
3939	* Note that doing a memcpy of the list, namespace nodes are
3940	* just assigned to set1, since set2 is cleared anyway.
3941	*/
3942	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3943	if (set1 == NULL)
3944	    return(NULL);
3945	if (set2->nodeNr != 0) {
3946	    memcpy(set1->nodeTab, set2->nodeTab,
3947		set2->nodeNr * sizeof(xmlNodePtr));
3948	    set1->nodeNr = set2->nodeNr;
3949	}
3950    } else {
3951	int i, j, initNbSet1;
3952	xmlNodePtr n1, n2;
3953
3954	if (set1 == NULL)
3955            set1 = xmlXPathNodeSetCreate(NULL);
3956        if (set1 == NULL)
3957            return (NULL);
3958
3959	initNbSet1 = set1->nodeNr;
3960	for (i = 0;i < set2->nodeNr;i++) {
3961	    n2 = set2->nodeTab[i];
3962	    /*
3963	    * Skip NULLed entries.
3964	    */
3965	    if (n2 == NULL)
3966		continue;
3967	    /*
3968	    * Skip duplicates.
3969	    */
3970	    for (j = 0; j < initNbSet1; j++) {
3971		n1 = set1->nodeTab[j];
3972		if (n1 == n2) {
3973		    goto skip_node;
3974		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3975		    (n2->type == XML_NAMESPACE_DECL))
3976		{
3977		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3978			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3979			((xmlNsPtr) n2)->prefix)))
3980		    {
3981			/*
3982			* Free the namespace node.
3983			*/
3984			set2->nodeTab[i] = NULL;
3985			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3986			goto skip_node;
3987		    }
3988		}
3989	    }
3990	    /*
3991	    * grow the nodeTab if needed
3992	    */
3993	    if (set1->nodeMax == 0) {
3994		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3995		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3996		if (set1->nodeTab == NULL) {
3997		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3998		    return(NULL);
3999		}
4000		memset(set1->nodeTab, 0,
4001		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4002		set1->nodeMax = XML_NODESET_DEFAULT;
4003	    } else if (set1->nodeNr >= set1->nodeMax) {
4004		xmlNodePtr *temp;
4005
4006                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4007                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4008                    return(NULL);
4009                }
4010		temp = (xmlNodePtr *) xmlRealloc(
4011		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4012		if (temp == NULL) {
4013		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4014		    return(NULL);
4015		}
4016		set1->nodeTab = temp;
4017		set1->nodeMax *= 2;
4018	    }
4019	    if (n2->type == XML_NAMESPACE_DECL) {
4020		xmlNsPtr ns = (xmlNsPtr) n2;
4021
4022		set1->nodeTab[set1->nodeNr++] =
4023		    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
4024	    } else
4025		set1->nodeTab[set1->nodeNr++] = n2;
4026skip_node:
4027	    {}
4028	}
4029    }
4030    set2->nodeNr = 0;
4031    return(set1);
4032}
4033
4034/**
4035 * xmlXPathNodeSetMergeAndClearNoDupls:
4036 * @set1:  the first NodeSet or NULL
4037 * @set2:  the second NodeSet
4038 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4039 *
4040 * Merges two nodesets, all nodes from @set2 are added to @set1
4041 * if @set1 is NULL, a new set is created and copied from @set2.
4042 * Doesn't chack for duplicate nodes. Clears set2.
4043 *
4044 * Returns @set1 once extended or NULL in case of error.
4045 */
4046static xmlNodeSetPtr
4047xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4048				    int hasNullEntries)
4049{
4050    if (set2 == NULL)
4051	return(set1);
4052    if ((set1 == NULL) && (hasNullEntries == 0)) {
4053	/*
4054	* Note that doing a memcpy of the list, namespace nodes are
4055	* just assigned to set1, since set2 is cleared anyway.
4056	*/
4057	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4058	if (set1 == NULL)
4059	    return(NULL);
4060	if (set2->nodeNr != 0) {
4061	    memcpy(set1->nodeTab, set2->nodeTab,
4062		set2->nodeNr * sizeof(xmlNodePtr));
4063	    set1->nodeNr = set2->nodeNr;
4064	}
4065    } else {
4066	int i;
4067	xmlNodePtr n2;
4068
4069	if (set1 == NULL)
4070	    set1 = xmlXPathNodeSetCreate(NULL);
4071        if (set1 == NULL)
4072            return (NULL);
4073
4074	for (i = 0;i < set2->nodeNr;i++) {
4075	    n2 = set2->nodeTab[i];
4076	    /*
4077	    * Skip NULLed entries.
4078	    */
4079	    if (n2 == NULL)
4080		continue;
4081	    if (set1->nodeMax == 0) {
4082		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4083		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4084		if (set1->nodeTab == NULL) {
4085		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4086		    return(NULL);
4087		}
4088		memset(set1->nodeTab, 0,
4089		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4090		set1->nodeMax = XML_NODESET_DEFAULT;
4091	    } else if (set1->nodeNr >= set1->nodeMax) {
4092		xmlNodePtr *temp;
4093
4094                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4095                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4096                    return(NULL);
4097                }
4098		temp = (xmlNodePtr *) xmlRealloc(
4099		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4100		if (temp == NULL) {
4101		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4102		    return(NULL);
4103		}
4104		set1->nodeTab = temp;
4105		set1->nodeMax *= 2;
4106	    }
4107	    set1->nodeTab[set1->nodeNr++] = n2;
4108	}
4109    }
4110    set2->nodeNr = 0;
4111    return(set1);
4112}
4113
4114/**
4115 * xmlXPathNodeSetDel:
4116 * @cur:  the initial node set
4117 * @val:  an xmlNodePtr
4118 *
4119 * Removes an xmlNodePtr from an existing NodeSet
4120 */
4121void
4122xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4123    int i;
4124
4125    if (cur == NULL) return;
4126    if (val == NULL) return;
4127
4128    /*
4129     * find node in nodeTab
4130     */
4131    for (i = 0;i < cur->nodeNr;i++)
4132        if (cur->nodeTab[i] == val) break;
4133
4134    if (i >= cur->nodeNr) {	/* not found */
4135#ifdef DEBUG
4136        xmlGenericError(xmlGenericErrorContext,
4137	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4138		val->name);
4139#endif
4140        return;
4141    }
4142    if ((cur->nodeTab[i] != NULL) &&
4143	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4144	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4145    cur->nodeNr--;
4146    for (;i < cur->nodeNr;i++)
4147        cur->nodeTab[i] = cur->nodeTab[i + 1];
4148    cur->nodeTab[cur->nodeNr] = NULL;
4149}
4150
4151/**
4152 * xmlXPathNodeSetRemove:
4153 * @cur:  the initial node set
4154 * @val:  the index to remove
4155 *
4156 * Removes an entry from an existing NodeSet list.
4157 */
4158void
4159xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4160    if (cur == NULL) return;
4161    if (val >= cur->nodeNr) return;
4162    if ((cur->nodeTab[val] != NULL) &&
4163	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4164	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4165    cur->nodeNr--;
4166    for (;val < cur->nodeNr;val++)
4167        cur->nodeTab[val] = cur->nodeTab[val + 1];
4168    cur->nodeTab[cur->nodeNr] = NULL;
4169}
4170
4171/**
4172 * xmlXPathFreeNodeSet:
4173 * @obj:  the xmlNodeSetPtr to free
4174 *
4175 * Free the NodeSet compound (not the actual nodes !).
4176 */
4177void
4178xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4179    if (obj == NULL) return;
4180    if (obj->nodeTab != NULL) {
4181	int i;
4182
4183	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
4184	for (i = 0;i < obj->nodeNr;i++)
4185	    if ((obj->nodeTab[i] != NULL) &&
4186		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4187		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4188	xmlFree(obj->nodeTab);
4189    }
4190    xmlFree(obj);
4191}
4192
4193/**
4194 * xmlXPathNodeSetClear:
4195 * @set:  the node set to clear
4196 *
4197 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4198 * are feed), but does *not* free the list itself. Sets the length of the
4199 * list to 0.
4200 */
4201static void
4202xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4203{
4204    if ((set == NULL) || (set->nodeNr <= 0))
4205	return;
4206    else if (hasNsNodes) {
4207	int i;
4208	xmlNodePtr node;
4209
4210	for (i = 0; i < set->nodeNr; i++) {
4211	    node = set->nodeTab[i];
4212	    if ((node != NULL) &&
4213		(node->type == XML_NAMESPACE_DECL))
4214		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4215	}
4216    }
4217    set->nodeNr = 0;
4218}
4219
4220/**
4221 * xmlXPathNodeSetClearFromPos:
4222 * @set: the node set to be cleared
4223 * @pos: the start position to clear from
4224 *
4225 * Clears the list from temporary XPath objects (e.g. namespace nodes
4226 * are feed) starting with the entry at @pos, but does *not* free the list
4227 * itself. Sets the length of the list to @pos.
4228 */
4229static void
4230xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4231{
4232    if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4233	return;
4234    else if ((hasNsNodes)) {
4235	int i;
4236	xmlNodePtr node;
4237
4238	for (i = pos; i < set->nodeNr; i++) {
4239	    node = set->nodeTab[i];
4240	    if ((node != NULL) &&
4241		(node->type == XML_NAMESPACE_DECL))
4242		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4243	}
4244    }
4245    set->nodeNr = pos;
4246}
4247
4248/**
4249 * xmlXPathFreeValueTree:
4250 * @obj:  the xmlNodeSetPtr to free
4251 *
4252 * Free the NodeSet compound and the actual tree, this is different
4253 * from xmlXPathFreeNodeSet()
4254 */
4255static void
4256xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4257    int i;
4258
4259    if (obj == NULL) return;
4260
4261    if (obj->nodeTab != NULL) {
4262	for (i = 0;i < obj->nodeNr;i++) {
4263	    if (obj->nodeTab[i] != NULL) {
4264		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4265		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4266		} else {
4267		    xmlFreeNodeList(obj->nodeTab[i]);
4268		}
4269	    }
4270	}
4271	xmlFree(obj->nodeTab);
4272    }
4273    xmlFree(obj);
4274}
4275
4276#if defined(DEBUG) || defined(DEBUG_STEP)
4277/**
4278 * xmlGenericErrorContextNodeSet:
4279 * @output:  a FILE * for the output
4280 * @obj:  the xmlNodeSetPtr to display
4281 *
4282 * Quick display of a NodeSet
4283 */
4284void
4285xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4286    int i;
4287
4288    if (output == NULL) output = xmlGenericErrorContext;
4289    if (obj == NULL)  {
4290        fprintf(output, "NodeSet == NULL !\n");
4291	return;
4292    }
4293    if (obj->nodeNr == 0) {
4294        fprintf(output, "NodeSet is empty\n");
4295	return;
4296    }
4297    if (obj->nodeTab == NULL) {
4298	fprintf(output, " nodeTab == NULL !\n");
4299	return;
4300    }
4301    for (i = 0; i < obj->nodeNr; i++) {
4302        if (obj->nodeTab[i] == NULL) {
4303	    fprintf(output, " NULL !\n");
4304	    return;
4305        }
4306	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4307	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4308	    fprintf(output, " /");
4309	else if (obj->nodeTab[i]->name == NULL)
4310	    fprintf(output, " noname!");
4311	else fprintf(output, " %s", obj->nodeTab[i]->name);
4312    }
4313    fprintf(output, "\n");
4314}
4315#endif
4316
4317/**
4318 * xmlXPathNewNodeSet:
4319 * @val:  the NodePtr value
4320 *
4321 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4322 * it with the single Node @val
4323 *
4324 * Returns the newly created object.
4325 */
4326xmlXPathObjectPtr
4327xmlXPathNewNodeSet(xmlNodePtr val) {
4328    xmlXPathObjectPtr ret;
4329
4330    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4331    if (ret == NULL) {
4332        xmlXPathErrMemory(NULL, "creating nodeset\n");
4333	return(NULL);
4334    }
4335    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4336    ret->type = XPATH_NODESET;
4337    ret->boolval = 0;
4338    ret->nodesetval = xmlXPathNodeSetCreate(val);
4339    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4340#ifdef XP_DEBUG_OBJ_USAGE
4341    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4342#endif
4343    return(ret);
4344}
4345
4346/**
4347 * xmlXPathNewValueTree:
4348 * @val:  the NodePtr value
4349 *
4350 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4351 * it with the tree root @val
4352 *
4353 * Returns the newly created object.
4354 */
4355xmlXPathObjectPtr
4356xmlXPathNewValueTree(xmlNodePtr val) {
4357    xmlXPathObjectPtr ret;
4358
4359    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4360    if (ret == NULL) {
4361        xmlXPathErrMemory(NULL, "creating result value tree\n");
4362	return(NULL);
4363    }
4364    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4365    ret->type = XPATH_XSLT_TREE;
4366    ret->boolval = 1;
4367    ret->user = (void *) val;
4368    ret->nodesetval = xmlXPathNodeSetCreate(val);
4369#ifdef XP_DEBUG_OBJ_USAGE
4370    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4371#endif
4372    return(ret);
4373}
4374
4375/**
4376 * xmlXPathNewNodeSetList:
4377 * @val:  an existing NodeSet
4378 *
4379 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4380 * it with the Nodeset @val
4381 *
4382 * Returns the newly created object.
4383 */
4384xmlXPathObjectPtr
4385xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4386{
4387    xmlXPathObjectPtr ret;
4388    int i;
4389
4390    if (val == NULL)
4391        ret = NULL;
4392    else if (val->nodeTab == NULL)
4393        ret = xmlXPathNewNodeSet(NULL);
4394    else {
4395        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4396        if (ret) {
4397            for (i = 1; i < val->nodeNr; ++i) {
4398                if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4399		    < 0) break;
4400	    }
4401	}
4402    }
4403
4404    return (ret);
4405}
4406
4407/**
4408 * xmlXPathWrapNodeSet:
4409 * @val:  the NodePtr value
4410 *
4411 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4412 *
4413 * Returns the newly created object.
4414 */
4415xmlXPathObjectPtr
4416xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4417    xmlXPathObjectPtr ret;
4418
4419    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4420    if (ret == NULL) {
4421        xmlXPathErrMemory(NULL, "creating node set object\n");
4422	return(NULL);
4423    }
4424    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4425    ret->type = XPATH_NODESET;
4426    ret->nodesetval = val;
4427#ifdef XP_DEBUG_OBJ_USAGE
4428    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4429#endif
4430    return(ret);
4431}
4432
4433/**
4434 * xmlXPathFreeNodeSetList:
4435 * @obj:  an existing NodeSetList object
4436 *
4437 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4438 * the list contrary to xmlXPathFreeObject().
4439 */
4440void
4441xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4442    if (obj == NULL) return;
4443#ifdef XP_DEBUG_OBJ_USAGE
4444    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4445#endif
4446    xmlFree(obj);
4447}
4448
4449/**
4450 * xmlXPathDifference:
4451 * @nodes1:  a node-set
4452 * @nodes2:  a node-set
4453 *
4454 * Implements the EXSLT - Sets difference() function:
4455 *    node-set set:difference (node-set, node-set)
4456 *
4457 * Returns the difference between the two node sets, or nodes1 if
4458 *         nodes2 is empty
4459 */
4460xmlNodeSetPtr
4461xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4462    xmlNodeSetPtr ret;
4463    int i, l1;
4464    xmlNodePtr cur;
4465
4466    if (xmlXPathNodeSetIsEmpty(nodes2))
4467	return(nodes1);
4468
4469    ret = xmlXPathNodeSetCreate(NULL);
4470    if (xmlXPathNodeSetIsEmpty(nodes1))
4471	return(ret);
4472
4473    l1 = xmlXPathNodeSetGetLength(nodes1);
4474
4475    for (i = 0; i < l1; i++) {
4476	cur = xmlXPathNodeSetItem(nodes1, i);
4477	if (!xmlXPathNodeSetContains(nodes2, cur)) {
4478	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4479	        break;
4480	}
4481    }
4482    return(ret);
4483}
4484
4485/**
4486 * xmlXPathIntersection:
4487 * @nodes1:  a node-set
4488 * @nodes2:  a node-set
4489 *
4490 * Implements the EXSLT - Sets intersection() function:
4491 *    node-set set:intersection (node-set, node-set)
4492 *
4493 * Returns a node set comprising the nodes that are within both the
4494 *         node sets passed as arguments
4495 */
4496xmlNodeSetPtr
4497xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4498    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4499    int i, l1;
4500    xmlNodePtr cur;
4501
4502    if (ret == NULL)
4503        return(ret);
4504    if (xmlXPathNodeSetIsEmpty(nodes1))
4505	return(ret);
4506    if (xmlXPathNodeSetIsEmpty(nodes2))
4507	return(ret);
4508
4509    l1 = xmlXPathNodeSetGetLength(nodes1);
4510
4511    for (i = 0; i < l1; i++) {
4512	cur = xmlXPathNodeSetItem(nodes1, i);
4513	if (xmlXPathNodeSetContains(nodes2, cur)) {
4514	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4515	        break;
4516	}
4517    }
4518    return(ret);
4519}
4520
4521/**
4522 * xmlXPathDistinctSorted:
4523 * @nodes:  a node-set, sorted by document order
4524 *
4525 * Implements the EXSLT - Sets distinct() function:
4526 *    node-set set:distinct (node-set)
4527 *
4528 * Returns a subset of the nodes contained in @nodes, or @nodes if
4529 *         it is empty
4530 */
4531xmlNodeSetPtr
4532xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4533    xmlNodeSetPtr ret;
4534    xmlHashTablePtr hash;
4535    int i, l;
4536    xmlChar * strval;
4537    xmlNodePtr cur;
4538
4539    if (xmlXPathNodeSetIsEmpty(nodes))
4540	return(nodes);
4541
4542    ret = xmlXPathNodeSetCreate(NULL);
4543    if (ret == NULL)
4544        return(ret);
4545    l = xmlXPathNodeSetGetLength(nodes);
4546    hash = xmlHashCreate (l);
4547    for (i = 0; i < l; i++) {
4548	cur = xmlXPathNodeSetItem(nodes, i);
4549	strval = xmlXPathCastNodeToString(cur);
4550	if (xmlHashLookup(hash, strval) == NULL) {
4551	    xmlHashAddEntry(hash, strval, strval);
4552	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4553	        break;
4554	} else {
4555	    xmlFree(strval);
4556	}
4557    }
4558    xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4559    return(ret);
4560}
4561
4562/**
4563 * xmlXPathDistinct:
4564 * @nodes:  a node-set
4565 *
4566 * Implements the EXSLT - Sets distinct() function:
4567 *    node-set set:distinct (node-set)
4568 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4569 * is called with the sorted node-set
4570 *
4571 * Returns a subset of the nodes contained in @nodes, or @nodes if
4572 *         it is empty
4573 */
4574xmlNodeSetPtr
4575xmlXPathDistinct (xmlNodeSetPtr nodes) {
4576    if (xmlXPathNodeSetIsEmpty(nodes))
4577	return(nodes);
4578
4579    xmlXPathNodeSetSort(nodes);
4580    return(xmlXPathDistinctSorted(nodes));
4581}
4582
4583/**
4584 * xmlXPathHasSameNodes:
4585 * @nodes1:  a node-set
4586 * @nodes2:  a node-set
4587 *
4588 * Implements the EXSLT - Sets has-same-nodes function:
4589 *    boolean set:has-same-node(node-set, node-set)
4590 *
4591 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4592 *         otherwise
4593 */
4594int
4595xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4596    int i, l;
4597    xmlNodePtr cur;
4598
4599    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4600	xmlXPathNodeSetIsEmpty(nodes2))
4601	return(0);
4602
4603    l = xmlXPathNodeSetGetLength(nodes1);
4604    for (i = 0; i < l; i++) {
4605	cur = xmlXPathNodeSetItem(nodes1, i);
4606	if (xmlXPathNodeSetContains(nodes2, cur))
4607	    return(1);
4608    }
4609    return(0);
4610}
4611
4612/**
4613 * xmlXPathNodeLeadingSorted:
4614 * @nodes: a node-set, sorted by document order
4615 * @node: a node
4616 *
4617 * Implements the EXSLT - Sets leading() function:
4618 *    node-set set:leading (node-set, node-set)
4619 *
4620 * Returns the nodes in @nodes that precede @node in document order,
4621 *         @nodes if @node is NULL or an empty node-set if @nodes
4622 *         doesn't contain @node
4623 */
4624xmlNodeSetPtr
4625xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4626    int i, l;
4627    xmlNodePtr cur;
4628    xmlNodeSetPtr ret;
4629
4630    if (node == NULL)
4631	return(nodes);
4632
4633    ret = xmlXPathNodeSetCreate(NULL);
4634    if (ret == NULL)
4635        return(ret);
4636    if (xmlXPathNodeSetIsEmpty(nodes) ||
4637	(!xmlXPathNodeSetContains(nodes, node)))
4638	return(ret);
4639
4640    l = xmlXPathNodeSetGetLength(nodes);
4641    for (i = 0; i < l; i++) {
4642	cur = xmlXPathNodeSetItem(nodes, i);
4643	if (cur == node)
4644	    break;
4645	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4646	    break;
4647    }
4648    return(ret);
4649}
4650
4651/**
4652 * xmlXPathNodeLeading:
4653 * @nodes:  a node-set
4654 * @node:  a node
4655 *
4656 * Implements the EXSLT - Sets leading() function:
4657 *    node-set set:leading (node-set, node-set)
4658 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4659 * is called.
4660 *
4661 * Returns the nodes in @nodes that precede @node in document order,
4662 *         @nodes if @node is NULL or an empty node-set if @nodes
4663 *         doesn't contain @node
4664 */
4665xmlNodeSetPtr
4666xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4667    xmlXPathNodeSetSort(nodes);
4668    return(xmlXPathNodeLeadingSorted(nodes, node));
4669}
4670
4671/**
4672 * xmlXPathLeadingSorted:
4673 * @nodes1:  a node-set, sorted by document order
4674 * @nodes2:  a node-set, sorted by document order
4675 *
4676 * Implements the EXSLT - Sets leading() function:
4677 *    node-set set:leading (node-set, node-set)
4678 *
4679 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4680 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4681 *         an empty node-set if @nodes1 doesn't contain @nodes2
4682 */
4683xmlNodeSetPtr
4684xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4685    if (xmlXPathNodeSetIsEmpty(nodes2))
4686	return(nodes1);
4687    return(xmlXPathNodeLeadingSorted(nodes1,
4688				     xmlXPathNodeSetItem(nodes2, 1)));
4689}
4690
4691/**
4692 * xmlXPathLeading:
4693 * @nodes1:  a node-set
4694 * @nodes2:  a node-set
4695 *
4696 * Implements the EXSLT - Sets leading() function:
4697 *    node-set set:leading (node-set, node-set)
4698 * @nodes1 and @nodes2 are sorted by document order, then
4699 * #exslSetsLeadingSorted is called.
4700 *
4701 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4702 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4703 *         an empty node-set if @nodes1 doesn't contain @nodes2
4704 */
4705xmlNodeSetPtr
4706xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4707    if (xmlXPathNodeSetIsEmpty(nodes2))
4708	return(nodes1);
4709    if (xmlXPathNodeSetIsEmpty(nodes1))
4710	return(xmlXPathNodeSetCreate(NULL));
4711    xmlXPathNodeSetSort(nodes1);
4712    xmlXPathNodeSetSort(nodes2);
4713    return(xmlXPathNodeLeadingSorted(nodes1,
4714				     xmlXPathNodeSetItem(nodes2, 1)));
4715}
4716
4717/**
4718 * xmlXPathNodeTrailingSorted:
4719 * @nodes: a node-set, sorted by document order
4720 * @node: a node
4721 *
4722 * Implements the EXSLT - Sets trailing() function:
4723 *    node-set set:trailing (node-set, node-set)
4724 *
4725 * Returns the nodes in @nodes that follow @node in document order,
4726 *         @nodes if @node is NULL or an empty node-set if @nodes
4727 *         doesn't contain @node
4728 */
4729xmlNodeSetPtr
4730xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4731    int i, l;
4732    xmlNodePtr cur;
4733    xmlNodeSetPtr ret;
4734
4735    if (node == NULL)
4736	return(nodes);
4737
4738    ret = xmlXPathNodeSetCreate(NULL);
4739    if (ret == NULL)
4740        return(ret);
4741    if (xmlXPathNodeSetIsEmpty(nodes) ||
4742	(!xmlXPathNodeSetContains(nodes, node)))
4743	return(ret);
4744
4745    l = xmlXPathNodeSetGetLength(nodes);
4746    for (i = l - 1; i >= 0; i--) {
4747	cur = xmlXPathNodeSetItem(nodes, i);
4748	if (cur == node)
4749	    break;
4750	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4751	    break;
4752    }
4753    xmlXPathNodeSetSort(ret);	/* bug 413451 */
4754    return(ret);
4755}
4756
4757/**
4758 * xmlXPathNodeTrailing:
4759 * @nodes:  a node-set
4760 * @node:  a node
4761 *
4762 * Implements the EXSLT - Sets trailing() function:
4763 *    node-set set:trailing (node-set, node-set)
4764 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4765 * is called.
4766 *
4767 * Returns the nodes in @nodes that follow @node in document order,
4768 *         @nodes if @node is NULL or an empty node-set if @nodes
4769 *         doesn't contain @node
4770 */
4771xmlNodeSetPtr
4772xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4773    xmlXPathNodeSetSort(nodes);
4774    return(xmlXPathNodeTrailingSorted(nodes, node));
4775}
4776
4777/**
4778 * xmlXPathTrailingSorted:
4779 * @nodes1:  a node-set, sorted by document order
4780 * @nodes2:  a node-set, sorted by document order
4781 *
4782 * Implements the EXSLT - Sets trailing() function:
4783 *    node-set set:trailing (node-set, node-set)
4784 *
4785 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4786 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4787 *         an empty node-set if @nodes1 doesn't contain @nodes2
4788 */
4789xmlNodeSetPtr
4790xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4791    if (xmlXPathNodeSetIsEmpty(nodes2))
4792	return(nodes1);
4793    return(xmlXPathNodeTrailingSorted(nodes1,
4794				      xmlXPathNodeSetItem(nodes2, 0)));
4795}
4796
4797/**
4798 * xmlXPathTrailing:
4799 * @nodes1:  a node-set
4800 * @nodes2:  a node-set
4801 *
4802 * Implements the EXSLT - Sets trailing() function:
4803 *    node-set set:trailing (node-set, node-set)
4804 * @nodes1 and @nodes2 are sorted by document order, then
4805 * #xmlXPathTrailingSorted is called.
4806 *
4807 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4808 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4809 *         an empty node-set if @nodes1 doesn't contain @nodes2
4810 */
4811xmlNodeSetPtr
4812xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4813    if (xmlXPathNodeSetIsEmpty(nodes2))
4814	return(nodes1);
4815    if (xmlXPathNodeSetIsEmpty(nodes1))
4816	return(xmlXPathNodeSetCreate(NULL));
4817    xmlXPathNodeSetSort(nodes1);
4818    xmlXPathNodeSetSort(nodes2);
4819    return(xmlXPathNodeTrailingSorted(nodes1,
4820				      xmlXPathNodeSetItem(nodes2, 0)));
4821}
4822
4823/************************************************************************
4824 *									*
4825 *		Routines to handle extra functions			*
4826 *									*
4827 ************************************************************************/
4828
4829/**
4830 * xmlXPathRegisterFunc:
4831 * @ctxt:  the XPath context
4832 * @name:  the function name
4833 * @f:  the function implementation or NULL
4834 *
4835 * Register a new function. If @f is NULL it unregisters the function
4836 *
4837 * Returns 0 in case of success, -1 in case of error
4838 */
4839int
4840xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4841		     xmlXPathFunction f) {
4842    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4843}
4844
4845/**
4846 * xmlXPathRegisterFuncNS:
4847 * @ctxt:  the XPath context
4848 * @name:  the function name
4849 * @ns_uri:  the function namespace URI
4850 * @f:  the function implementation or NULL
4851 *
4852 * Register a new function. If @f is NULL it unregisters the function
4853 *
4854 * Returns 0 in case of success, -1 in case of error
4855 */
4856int
4857xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4858		       const xmlChar *ns_uri, xmlXPathFunction f) {
4859    if (ctxt == NULL)
4860	return(-1);
4861    if (name == NULL)
4862	return(-1);
4863
4864    if (ctxt->funcHash == NULL)
4865	ctxt->funcHash = xmlHashCreate(0);
4866    if (ctxt->funcHash == NULL)
4867	return(-1);
4868    if (f == NULL)
4869        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4870    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4871}
4872
4873/**
4874 * xmlXPathRegisterFuncLookup:
4875 * @ctxt:  the XPath context
4876 * @f:  the lookup function
4877 * @funcCtxt:  the lookup data
4878 *
4879 * Registers an external mechanism to do function lookup.
4880 */
4881void
4882xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4883			    xmlXPathFuncLookupFunc f,
4884			    void *funcCtxt) {
4885    if (ctxt == NULL)
4886	return;
4887    ctxt->funcLookupFunc = f;
4888    ctxt->funcLookupData = funcCtxt;
4889}
4890
4891/**
4892 * xmlXPathFunctionLookup:
4893 * @ctxt:  the XPath context
4894 * @name:  the function name
4895 *
4896 * Search in the Function array of the context for the given
4897 * function.
4898 *
4899 * Returns the xmlXPathFunction or NULL if not found
4900 */
4901xmlXPathFunction
4902xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4903    if (ctxt == NULL)
4904	return (NULL);
4905
4906    if (ctxt->funcLookupFunc != NULL) {
4907	xmlXPathFunction ret;
4908	xmlXPathFuncLookupFunc f;
4909
4910	f = ctxt->funcLookupFunc;
4911	ret = f(ctxt->funcLookupData, name, NULL);
4912	if (ret != NULL)
4913	    return(ret);
4914    }
4915    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4916}
4917
4918/**
4919 * xmlXPathFunctionLookupNS:
4920 * @ctxt:  the XPath context
4921 * @name:  the function name
4922 * @ns_uri:  the function namespace URI
4923 *
4924 * Search in the Function array of the context for the given
4925 * function.
4926 *
4927 * Returns the xmlXPathFunction or NULL if not found
4928 */
4929xmlXPathFunction
4930xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4931			 const xmlChar *ns_uri) {
4932    xmlXPathFunction ret;
4933
4934    if (ctxt == NULL)
4935	return(NULL);
4936    if (name == NULL)
4937	return(NULL);
4938
4939    if (ctxt->funcLookupFunc != NULL) {
4940	xmlXPathFuncLookupFunc f;
4941
4942	f = ctxt->funcLookupFunc;
4943	ret = f(ctxt->funcLookupData, name, ns_uri);
4944	if (ret != NULL)
4945	    return(ret);
4946    }
4947
4948    if (ctxt->funcHash == NULL)
4949	return(NULL);
4950
4951    XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4952    return(ret);
4953}
4954
4955/**
4956 * xmlXPathRegisteredFuncsCleanup:
4957 * @ctxt:  the XPath context
4958 *
4959 * Cleanup the XPath context data associated to registered functions
4960 */
4961void
4962xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4963    if (ctxt == NULL)
4964	return;
4965
4966    xmlHashFree(ctxt->funcHash, NULL);
4967    ctxt->funcHash = NULL;
4968}
4969
4970/************************************************************************
4971 *									*
4972 *			Routines to handle Variables			*
4973 *									*
4974 ************************************************************************/
4975
4976/**
4977 * xmlXPathRegisterVariable:
4978 * @ctxt:  the XPath context
4979 * @name:  the variable name
4980 * @value:  the variable value or NULL
4981 *
4982 * Register a new variable value. If @value is NULL it unregisters
4983 * the variable
4984 *
4985 * Returns 0 in case of success, -1 in case of error
4986 */
4987int
4988xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4989			 xmlXPathObjectPtr value) {
4990    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4991}
4992
4993/**
4994 * xmlXPathRegisterVariableNS:
4995 * @ctxt:  the XPath context
4996 * @name:  the variable name
4997 * @ns_uri:  the variable namespace URI
4998 * @value:  the variable value or NULL
4999 *
5000 * Register a new variable value. If @value is NULL it unregisters
5001 * the variable
5002 *
5003 * Returns 0 in case of success, -1 in case of error
5004 */
5005int
5006xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5007			   const xmlChar *ns_uri,
5008			   xmlXPathObjectPtr value) {
5009    if (ctxt == NULL)
5010	return(-1);
5011    if (name == NULL)
5012	return(-1);
5013
5014    if (ctxt->varHash == NULL)
5015	ctxt->varHash = xmlHashCreate(0);
5016    if (ctxt->varHash == NULL)
5017	return(-1);
5018    if (value == NULL)
5019        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5020	                           (xmlHashDeallocator)xmlXPathFreeObject));
5021    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5022			       (void *) value,
5023			       (xmlHashDeallocator)xmlXPathFreeObject));
5024}
5025
5026/**
5027 * xmlXPathRegisterVariableLookup:
5028 * @ctxt:  the XPath context
5029 * @f:  the lookup function
5030 * @data:  the lookup data
5031 *
5032 * register an external mechanism to do variable lookup
5033 */
5034void
5035xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5036	 xmlXPathVariableLookupFunc f, void *data) {
5037    if (ctxt == NULL)
5038	return;
5039    ctxt->varLookupFunc = f;
5040    ctxt->varLookupData = data;
5041}
5042
5043/**
5044 * xmlXPathVariableLookup:
5045 * @ctxt:  the XPath context
5046 * @name:  the variable name
5047 *
5048 * Search in the Variable array of the context for the given
5049 * variable value.
5050 *
5051 * Returns a copy of the value or NULL if not found
5052 */
5053xmlXPathObjectPtr
5054xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5055    if (ctxt == NULL)
5056	return(NULL);
5057
5058    if (ctxt->varLookupFunc != NULL) {
5059	xmlXPathObjectPtr ret;
5060
5061	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5062	        (ctxt->varLookupData, name, NULL);
5063	return(ret);
5064    }
5065    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5066}
5067
5068/**
5069 * xmlXPathVariableLookupNS:
5070 * @ctxt:  the XPath context
5071 * @name:  the variable name
5072 * @ns_uri:  the variable namespace URI
5073 *
5074 * Search in the Variable array of the context for the given
5075 * variable value.
5076 *
5077 * Returns the a copy of the value or NULL if not found
5078 */
5079xmlXPathObjectPtr
5080xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5081			 const xmlChar *ns_uri) {
5082    if (ctxt == NULL)
5083	return(NULL);
5084
5085    if (ctxt->varLookupFunc != NULL) {
5086	xmlXPathObjectPtr ret;
5087
5088	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5089	        (ctxt->varLookupData, name, ns_uri);
5090	if (ret != NULL) return(ret);
5091    }
5092
5093    if (ctxt->varHash == NULL)
5094	return(NULL);
5095    if (name == NULL)
5096	return(NULL);
5097
5098    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5099		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5100}
5101
5102/**
5103 * xmlXPathRegisteredVariablesCleanup:
5104 * @ctxt:  the XPath context
5105 *
5106 * Cleanup the XPath context data associated to registered variables
5107 */
5108void
5109xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5110    if (ctxt == NULL)
5111	return;
5112
5113    xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5114    ctxt->varHash = NULL;
5115}
5116
5117/**
5118 * xmlXPathRegisterNs:
5119 * @ctxt:  the XPath context
5120 * @prefix:  the namespace prefix cannot be NULL or empty string
5121 * @ns_uri:  the namespace name
5122 *
5123 * Register a new namespace. If @ns_uri is NULL it unregisters
5124 * the namespace
5125 *
5126 * Returns 0 in case of success, -1 in case of error
5127 */
5128int
5129xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5130			   const xmlChar *ns_uri) {
5131    if (ctxt == NULL)
5132	return(-1);
5133    if (prefix == NULL)
5134	return(-1);
5135    if (prefix[0] == 0)
5136	return(-1);
5137
5138    if (ctxt->nsHash == NULL)
5139	ctxt->nsHash = xmlHashCreate(10);
5140    if (ctxt->nsHash == NULL)
5141	return(-1);
5142    if (ns_uri == NULL)
5143        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5144	                          (xmlHashDeallocator)xmlFree));
5145    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5146			      (xmlHashDeallocator)xmlFree));
5147}
5148
5149/**
5150 * xmlXPathNsLookup:
5151 * @ctxt:  the XPath context
5152 * @prefix:  the namespace prefix value
5153 *
5154 * Search in the namespace declaration array of the context for the given
5155 * namespace name associated to the given prefix
5156 *
5157 * Returns the value or NULL if not found
5158 */
5159const xmlChar *
5160xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5161    if (ctxt == NULL)
5162	return(NULL);
5163    if (prefix == NULL)
5164	return(NULL);
5165
5166#ifdef XML_XML_NAMESPACE
5167    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5168	return(XML_XML_NAMESPACE);
5169#endif
5170
5171    if (ctxt->namespaces != NULL) {
5172	int i;
5173
5174	for (i = 0;i < ctxt->nsNr;i++) {
5175	    if ((ctxt->namespaces[i] != NULL) &&
5176		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5177		return(ctxt->namespaces[i]->href);
5178	}
5179    }
5180
5181    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5182}
5183
5184/**
5185 * xmlXPathRegisteredNsCleanup:
5186 * @ctxt:  the XPath context
5187 *
5188 * Cleanup the XPath context data associated to registered variables
5189 */
5190void
5191xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5192    if (ctxt == NULL)
5193	return;
5194
5195    xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5196    ctxt->nsHash = NULL;
5197}
5198
5199/************************************************************************
5200 *									*
5201 *			Routines to handle Values			*
5202 *									*
5203 ************************************************************************/
5204
5205/* Allocations are terrible, one needs to optimize all this !!! */
5206
5207/**
5208 * xmlXPathNewFloat:
5209 * @val:  the double value
5210 *
5211 * Create a new xmlXPathObjectPtr of type double and of value @val
5212 *
5213 * Returns the newly created object.
5214 */
5215xmlXPathObjectPtr
5216xmlXPathNewFloat(double val) {
5217    xmlXPathObjectPtr ret;
5218
5219    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5220    if (ret == NULL) {
5221        xmlXPathErrMemory(NULL, "creating float object\n");
5222	return(NULL);
5223    }
5224    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5225    ret->type = XPATH_NUMBER;
5226    ret->floatval = val;
5227#ifdef XP_DEBUG_OBJ_USAGE
5228    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5229#endif
5230    return(ret);
5231}
5232
5233/**
5234 * xmlXPathNewBoolean:
5235 * @val:  the boolean value
5236 *
5237 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5238 *
5239 * Returns the newly created object.
5240 */
5241xmlXPathObjectPtr
5242xmlXPathNewBoolean(int val) {
5243    xmlXPathObjectPtr ret;
5244
5245    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5246    if (ret == NULL) {
5247        xmlXPathErrMemory(NULL, "creating boolean object\n");
5248	return(NULL);
5249    }
5250    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5251    ret->type = XPATH_BOOLEAN;
5252    ret->boolval = (val != 0);
5253#ifdef XP_DEBUG_OBJ_USAGE
5254    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5255#endif
5256    return(ret);
5257}
5258
5259/**
5260 * xmlXPathNewString:
5261 * @val:  the xmlChar * value
5262 *
5263 * Create a new xmlXPathObjectPtr of type string and of value @val
5264 *
5265 * Returns the newly created object.
5266 */
5267xmlXPathObjectPtr
5268xmlXPathNewString(const xmlChar *val) {
5269    xmlXPathObjectPtr ret;
5270
5271    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5272    if (ret == NULL) {
5273        xmlXPathErrMemory(NULL, "creating string object\n");
5274	return(NULL);
5275    }
5276    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5277    ret->type = XPATH_STRING;
5278    if (val != NULL)
5279	ret->stringval = xmlStrdup(val);
5280    else
5281	ret->stringval = xmlStrdup((const xmlChar *)"");
5282#ifdef XP_DEBUG_OBJ_USAGE
5283    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5284#endif
5285    return(ret);
5286}
5287
5288/**
5289 * xmlXPathWrapString:
5290 * @val:  the xmlChar * value
5291 *
5292 * Wraps the @val string into an XPath object.
5293 *
5294 * Returns the newly created object.
5295 */
5296xmlXPathObjectPtr
5297xmlXPathWrapString (xmlChar *val) {
5298    xmlXPathObjectPtr ret;
5299
5300    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5301    if (ret == NULL) {
5302        xmlXPathErrMemory(NULL, "creating string object\n");
5303	return(NULL);
5304    }
5305    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5306    ret->type = XPATH_STRING;
5307    ret->stringval = val;
5308#ifdef XP_DEBUG_OBJ_USAGE
5309    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5310#endif
5311    return(ret);
5312}
5313
5314/**
5315 * xmlXPathNewCString:
5316 * @val:  the char * value
5317 *
5318 * Create a new xmlXPathObjectPtr of type string and of value @val
5319 *
5320 * Returns the newly created object.
5321 */
5322xmlXPathObjectPtr
5323xmlXPathNewCString(const char *val) {
5324    xmlXPathObjectPtr ret;
5325
5326    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5327    if (ret == NULL) {
5328        xmlXPathErrMemory(NULL, "creating string object\n");
5329	return(NULL);
5330    }
5331    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5332    ret->type = XPATH_STRING;
5333    ret->stringval = xmlStrdup(BAD_CAST val);
5334#ifdef XP_DEBUG_OBJ_USAGE
5335    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5336#endif
5337    return(ret);
5338}
5339
5340/**
5341 * xmlXPathWrapCString:
5342 * @val:  the char * value
5343 *
5344 * Wraps a string into an XPath object.
5345 *
5346 * Returns the newly created object.
5347 */
5348xmlXPathObjectPtr
5349xmlXPathWrapCString (char * val) {
5350    return(xmlXPathWrapString((xmlChar *)(val)));
5351}
5352
5353/**
5354 * xmlXPathWrapExternal:
5355 * @val:  the user data
5356 *
5357 * Wraps the @val data into an XPath object.
5358 *
5359 * Returns the newly created object.
5360 */
5361xmlXPathObjectPtr
5362xmlXPathWrapExternal (void *val) {
5363    xmlXPathObjectPtr ret;
5364
5365    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5366    if (ret == NULL) {
5367        xmlXPathErrMemory(NULL, "creating user object\n");
5368	return(NULL);
5369    }
5370    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5371    ret->type = XPATH_USERS;
5372    ret->user = val;
5373#ifdef XP_DEBUG_OBJ_USAGE
5374    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5375#endif
5376    return(ret);
5377}
5378
5379/**
5380 * xmlXPathObjectCopy:
5381 * @val:  the original object
5382 *
5383 * allocate a new copy of a given object
5384 *
5385 * Returns the newly created object.
5386 */
5387xmlXPathObjectPtr
5388xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5389    xmlXPathObjectPtr ret;
5390
5391    if (val == NULL)
5392	return(NULL);
5393
5394    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5395    if (ret == NULL) {
5396        xmlXPathErrMemory(NULL, "copying object\n");
5397	return(NULL);
5398    }
5399    memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5400#ifdef XP_DEBUG_OBJ_USAGE
5401    xmlXPathDebugObjUsageRequested(NULL, val->type);
5402#endif
5403    switch (val->type) {
5404	case XPATH_BOOLEAN:
5405	case XPATH_NUMBER:
5406	case XPATH_POINT:
5407	case XPATH_RANGE:
5408	    break;
5409	case XPATH_STRING:
5410	    ret->stringval = xmlStrdup(val->stringval);
5411	    break;
5412	case XPATH_XSLT_TREE:
5413#if 0
5414/*
5415  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5416  this previous handling is no longer correct, and can cause some serious
5417  problems (ref. bug 145547)
5418*/
5419	    if ((val->nodesetval != NULL) &&
5420		(val->nodesetval->nodeTab != NULL)) {
5421		xmlNodePtr cur, tmp;
5422		xmlDocPtr top;
5423
5424		ret->boolval = 1;
5425		top =  xmlNewDoc(NULL);
5426		top->name = (char *)
5427		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5428		ret->user = top;
5429		if (top != NULL) {
5430		    top->doc = top;
5431		    cur = val->nodesetval->nodeTab[0]->children;
5432		    while (cur != NULL) {
5433			tmp = xmlDocCopyNode(cur, top, 1);
5434			xmlAddChild((xmlNodePtr) top, tmp);
5435			cur = cur->next;
5436		    }
5437		}
5438
5439		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5440	    } else
5441		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5442	    /* Deallocate the copied tree value */
5443	    break;
5444#endif
5445	case XPATH_NODESET:
5446	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5447	    /* Do not deallocate the copied tree value */
5448	    ret->boolval = 0;
5449	    break;
5450	case XPATH_LOCATIONSET:
5451#ifdef LIBXML_XPTR_ENABLED
5452	{
5453	    xmlLocationSetPtr loc = val->user;
5454	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5455	    break;
5456	}
5457#endif
5458        case XPATH_USERS:
5459	    ret->user = val->user;
5460	    break;
5461        case XPATH_UNDEFINED:
5462	    xmlGenericError(xmlGenericErrorContext,
5463		    "xmlXPathObjectCopy: unsupported type %d\n",
5464		    val->type);
5465	    break;
5466    }
5467    return(ret);
5468}
5469
5470/**
5471 * xmlXPathFreeObject:
5472 * @obj:  the object to free
5473 *
5474 * Free up an xmlXPathObjectPtr object.
5475 */
5476void
5477xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5478    if (obj == NULL) return;
5479    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5480	if (obj->boolval) {
5481#if 0
5482	    if (obj->user != NULL) {
5483                xmlXPathFreeNodeSet(obj->nodesetval);
5484		xmlFreeNodeList((xmlNodePtr) obj->user);
5485	    } else
5486#endif
5487	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5488	    if (obj->nodesetval != NULL)
5489		xmlXPathFreeValueTree(obj->nodesetval);
5490	} else {
5491	    if (obj->nodesetval != NULL)
5492		xmlXPathFreeNodeSet(obj->nodesetval);
5493	}
5494#ifdef LIBXML_XPTR_ENABLED
5495    } else if (obj->type == XPATH_LOCATIONSET) {
5496	if (obj->user != NULL)
5497	    xmlXPtrFreeLocationSet(obj->user);
5498#endif
5499    } else if (obj->type == XPATH_STRING) {
5500	if (obj->stringval != NULL)
5501	    xmlFree(obj->stringval);
5502    }
5503#ifdef XP_DEBUG_OBJ_USAGE
5504    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5505#endif
5506    xmlFree(obj);
5507}
5508
5509/**
5510 * xmlXPathReleaseObject:
5511 * @obj:  the xmlXPathObjectPtr to free or to cache
5512 *
5513 * Depending on the state of the cache this frees the given
5514 * XPath object or stores it in the cache.
5515 */
5516static void
5517xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5518{
5519#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5520	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5521    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5522
5523#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5524
5525    if (obj == NULL)
5526	return;
5527    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5528	 xmlXPathFreeObject(obj);
5529    } else {
5530	xmlXPathContextCachePtr cache =
5531	    (xmlXPathContextCachePtr) ctxt->cache;
5532
5533	switch (obj->type) {
5534	    case XPATH_NODESET:
5535	    case XPATH_XSLT_TREE:
5536		if (obj->nodesetval != NULL) {
5537		    if (obj->boolval) {
5538			/*
5539			* It looks like the @boolval is used for
5540			* evaluation if this an XSLT Result Tree Fragment.
5541			* TODO: Check if this assumption is correct.
5542			*/
5543			obj->type = XPATH_XSLT_TREE; /* just for debugging */
5544			xmlXPathFreeValueTree(obj->nodesetval);
5545			obj->nodesetval = NULL;
5546		    } else if ((obj->nodesetval->nodeMax <= 40) &&
5547			(XP_CACHE_WANTS(cache->nodesetObjs,
5548					cache->maxNodeset)))
5549		    {
5550			XP_CACHE_ADD(cache->nodesetObjs, obj);
5551			goto obj_cached;
5552		    } else {
5553			xmlXPathFreeNodeSet(obj->nodesetval);
5554			obj->nodesetval = NULL;
5555		    }
5556		}
5557		break;
5558	    case XPATH_STRING:
5559		if (obj->stringval != NULL)
5560		    xmlFree(obj->stringval);
5561
5562		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5563		    XP_CACHE_ADD(cache->stringObjs, obj);
5564		    goto obj_cached;
5565		}
5566		break;
5567	    case XPATH_BOOLEAN:
5568		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5569		    XP_CACHE_ADD(cache->booleanObjs, obj);
5570		    goto obj_cached;
5571		}
5572		break;
5573	    case XPATH_NUMBER:
5574		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5575		    XP_CACHE_ADD(cache->numberObjs, obj);
5576		    goto obj_cached;
5577		}
5578		break;
5579#ifdef LIBXML_XPTR_ENABLED
5580	    case XPATH_LOCATIONSET:
5581		if (obj->user != NULL) {
5582		    xmlXPtrFreeLocationSet(obj->user);
5583		}
5584		goto free_obj;
5585#endif
5586	    default:
5587		goto free_obj;
5588	}
5589
5590	/*
5591	* Fallback to adding to the misc-objects slot.
5592	*/
5593	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5594	    XP_CACHE_ADD(cache->miscObjs, obj);
5595	} else
5596	    goto free_obj;
5597
5598obj_cached:
5599
5600#ifdef XP_DEBUG_OBJ_USAGE
5601	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5602#endif
5603
5604	if (obj->nodesetval != NULL) {
5605	    xmlNodeSetPtr tmpset = obj->nodesetval;
5606
5607	    /*
5608	    * TODO: Due to those nasty ns-nodes, we need to traverse
5609	    *  the list and free the ns-nodes.
5610	    * URGENT TODO: Check if it's actually slowing things down.
5611	    *  Maybe we shouldn't try to preserve the list.
5612	    */
5613	    if (tmpset->nodeNr > 1) {
5614		int i;
5615		xmlNodePtr node;
5616
5617		for (i = 0; i < tmpset->nodeNr; i++) {
5618		    node = tmpset->nodeTab[i];
5619		    if ((node != NULL) &&
5620			(node->type == XML_NAMESPACE_DECL))
5621		    {
5622			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5623		    }
5624		}
5625	    } else if (tmpset->nodeNr == 1) {
5626		if ((tmpset->nodeTab[0] != NULL) &&
5627		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5628		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5629	    }
5630	    tmpset->nodeNr = 0;
5631	    memset(obj, 0, sizeof(xmlXPathObject));
5632	    obj->nodesetval = tmpset;
5633	} else
5634	    memset(obj, 0, sizeof(xmlXPathObject));
5635
5636	return;
5637
5638free_obj:
5639	/*
5640	* Cache is full; free the object.
5641	*/
5642	if (obj->nodesetval != NULL)
5643	    xmlXPathFreeNodeSet(obj->nodesetval);
5644#ifdef XP_DEBUG_OBJ_USAGE
5645	xmlXPathDebugObjUsageReleased(NULL, obj->type);
5646#endif
5647	xmlFree(obj);
5648    }
5649    return;
5650}
5651
5652
5653/************************************************************************
5654 *									*
5655 *			Type Casting Routines				*
5656 *									*
5657 ************************************************************************/
5658
5659/**
5660 * xmlXPathCastBooleanToString:
5661 * @val:  a boolean
5662 *
5663 * Converts a boolean to its string value.
5664 *
5665 * Returns a newly allocated string.
5666 */
5667xmlChar *
5668xmlXPathCastBooleanToString (int val) {
5669    xmlChar *ret;
5670    if (val)
5671	ret = xmlStrdup((const xmlChar *) "true");
5672    else
5673	ret = xmlStrdup((const xmlChar *) "false");
5674    return(ret);
5675}
5676
5677/**
5678 * xmlXPathCastNumberToString:
5679 * @val:  a number
5680 *
5681 * Converts a number to its string value.
5682 *
5683 * Returns a newly allocated string.
5684 */
5685xmlChar *
5686xmlXPathCastNumberToString (double val) {
5687    xmlChar *ret;
5688    switch (xmlXPathIsInf(val)) {
5689    case 1:
5690	ret = xmlStrdup((const xmlChar *) "Infinity");
5691	break;
5692    case -1:
5693	ret = xmlStrdup((const xmlChar *) "-Infinity");
5694	break;
5695    default:
5696	if (xmlXPathIsNaN(val)) {
5697	    ret = xmlStrdup((const xmlChar *) "NaN");
5698	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
5699	    ret = xmlStrdup((const xmlChar *) "0");
5700	} else {
5701	    /* could be improved */
5702	    char buf[100];
5703	    xmlXPathFormatNumber(val, buf, 99);
5704	    buf[99] = 0;
5705	    ret = xmlStrdup((const xmlChar *) buf);
5706	}
5707    }
5708    return(ret);
5709}
5710
5711/**
5712 * xmlXPathCastNodeToString:
5713 * @node:  a node
5714 *
5715 * Converts a node to its string value.
5716 *
5717 * Returns a newly allocated string.
5718 */
5719xmlChar *
5720xmlXPathCastNodeToString (xmlNodePtr node) {
5721xmlChar *ret;
5722    if ((ret = xmlNodeGetContent(node)) == NULL)
5723	ret = xmlStrdup((const xmlChar *) "");
5724    return(ret);
5725}
5726
5727/**
5728 * xmlXPathCastNodeSetToString:
5729 * @ns:  a node-set
5730 *
5731 * Converts a node-set to its string value.
5732 *
5733 * Returns a newly allocated string.
5734 */
5735xmlChar *
5736xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5737    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5738	return(xmlStrdup((const xmlChar *) ""));
5739
5740    if (ns->nodeNr > 1)
5741	xmlXPathNodeSetSort(ns);
5742    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5743}
5744
5745/**
5746 * xmlXPathCastToString:
5747 * @val:  an XPath object
5748 *
5749 * Converts an existing object to its string() equivalent
5750 *
5751 * Returns the allocated string value of the object, NULL in case of error.
5752 *         It's up to the caller to free the string memory with xmlFree().
5753 */
5754xmlChar *
5755xmlXPathCastToString(xmlXPathObjectPtr val) {
5756    xmlChar *ret = NULL;
5757
5758    if (val == NULL)
5759	return(xmlStrdup((const xmlChar *) ""));
5760    switch (val->type) {
5761	case XPATH_UNDEFINED:
5762#ifdef DEBUG_EXPR
5763	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5764#endif
5765	    ret = xmlStrdup((const xmlChar *) "");
5766	    break;
5767        case XPATH_NODESET:
5768        case XPATH_XSLT_TREE:
5769	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5770	    break;
5771	case XPATH_STRING:
5772	    return(xmlStrdup(val->stringval));
5773        case XPATH_BOOLEAN:
5774	    ret = xmlXPathCastBooleanToString(val->boolval);
5775	    break;
5776	case XPATH_NUMBER: {
5777	    ret = xmlXPathCastNumberToString(val->floatval);
5778	    break;
5779	}
5780	case XPATH_USERS:
5781	case XPATH_POINT:
5782	case XPATH_RANGE:
5783	case XPATH_LOCATIONSET:
5784	    TODO
5785	    ret = xmlStrdup((const xmlChar *) "");
5786	    break;
5787    }
5788    return(ret);
5789}
5790
5791/**
5792 * xmlXPathConvertString:
5793 * @val:  an XPath object
5794 *
5795 * Converts an existing object to its string() equivalent
5796 *
5797 * Returns the new object, the old one is freed (or the operation
5798 *         is done directly on @val)
5799 */
5800xmlXPathObjectPtr
5801xmlXPathConvertString(xmlXPathObjectPtr val) {
5802    xmlChar *res = NULL;
5803
5804    if (val == NULL)
5805	return(xmlXPathNewCString(""));
5806
5807    switch (val->type) {
5808    case XPATH_UNDEFINED:
5809#ifdef DEBUG_EXPR
5810	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5811#endif
5812	break;
5813    case XPATH_NODESET:
5814    case XPATH_XSLT_TREE:
5815	res = xmlXPathCastNodeSetToString(val->nodesetval);
5816	break;
5817    case XPATH_STRING:
5818	return(val);
5819    case XPATH_BOOLEAN:
5820	res = xmlXPathCastBooleanToString(val->boolval);
5821	break;
5822    case XPATH_NUMBER:
5823	res = xmlXPathCastNumberToString(val->floatval);
5824	break;
5825    case XPATH_USERS:
5826    case XPATH_POINT:
5827    case XPATH_RANGE:
5828    case XPATH_LOCATIONSET:
5829	TODO;
5830	break;
5831    }
5832    xmlXPathFreeObject(val);
5833    if (res == NULL)
5834	return(xmlXPathNewCString(""));
5835    return(xmlXPathWrapString(res));
5836}
5837
5838/**
5839 * xmlXPathCastBooleanToNumber:
5840 * @val:  a boolean
5841 *
5842 * Converts a boolean to its number value
5843 *
5844 * Returns the number value
5845 */
5846double
5847xmlXPathCastBooleanToNumber(int val) {
5848    if (val)
5849	return(1.0);
5850    return(0.0);
5851}
5852
5853/**
5854 * xmlXPathCastStringToNumber:
5855 * @val:  a string
5856 *
5857 * Converts a string to its number value
5858 *
5859 * Returns the number value
5860 */
5861double
5862xmlXPathCastStringToNumber(const xmlChar * val) {
5863    return(xmlXPathStringEvalNumber(val));
5864}
5865
5866/**
5867 * xmlXPathCastNodeToNumber:
5868 * @node:  a node
5869 *
5870 * Converts a node to its number value
5871 *
5872 * Returns the number value
5873 */
5874double
5875xmlXPathCastNodeToNumber (xmlNodePtr node) {
5876    xmlChar *strval;
5877    double ret;
5878
5879    if (node == NULL)
5880	return(xmlXPathNAN);
5881    strval = xmlXPathCastNodeToString(node);
5882    if (strval == NULL)
5883	return(xmlXPathNAN);
5884    ret = xmlXPathCastStringToNumber(strval);
5885    xmlFree(strval);
5886
5887    return(ret);
5888}
5889
5890/**
5891 * xmlXPathCastNodeSetToNumber:
5892 * @ns:  a node-set
5893 *
5894 * Converts a node-set to its number value
5895 *
5896 * Returns the number value
5897 */
5898double
5899xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5900    xmlChar *str;
5901    double ret;
5902
5903    if (ns == NULL)
5904	return(xmlXPathNAN);
5905    str = xmlXPathCastNodeSetToString(ns);
5906    ret = xmlXPathCastStringToNumber(str);
5907    xmlFree(str);
5908    return(ret);
5909}
5910
5911/**
5912 * xmlXPathCastToNumber:
5913 * @val:  an XPath object
5914 *
5915 * Converts an XPath object to its number value
5916 *
5917 * Returns the number value
5918 */
5919double
5920xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5921    double ret = 0.0;
5922
5923    if (val == NULL)
5924	return(xmlXPathNAN);
5925    switch (val->type) {
5926    case XPATH_UNDEFINED:
5927#ifdef DEGUB_EXPR
5928	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5929#endif
5930	ret = xmlXPathNAN;
5931	break;
5932    case XPATH_NODESET:
5933    case XPATH_XSLT_TREE:
5934	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5935	break;
5936    case XPATH_STRING:
5937	ret = xmlXPathCastStringToNumber(val->stringval);
5938	break;
5939    case XPATH_NUMBER:
5940	ret = val->floatval;
5941	break;
5942    case XPATH_BOOLEAN:
5943	ret = xmlXPathCastBooleanToNumber(val->boolval);
5944	break;
5945    case XPATH_USERS:
5946    case XPATH_POINT:
5947    case XPATH_RANGE:
5948    case XPATH_LOCATIONSET:
5949	TODO;
5950	ret = xmlXPathNAN;
5951	break;
5952    }
5953    return(ret);
5954}
5955
5956/**
5957 * xmlXPathConvertNumber:
5958 * @val:  an XPath object
5959 *
5960 * Converts an existing object to its number() equivalent
5961 *
5962 * Returns the new object, the old one is freed (or the operation
5963 *         is done directly on @val)
5964 */
5965xmlXPathObjectPtr
5966xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5967    xmlXPathObjectPtr ret;
5968
5969    if (val == NULL)
5970	return(xmlXPathNewFloat(0.0));
5971    if (val->type == XPATH_NUMBER)
5972	return(val);
5973    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5974    xmlXPathFreeObject(val);
5975    return(ret);
5976}
5977
5978/**
5979 * xmlXPathCastNumberToBoolean:
5980 * @val:  a number
5981 *
5982 * Converts a number to its boolean value
5983 *
5984 * Returns the boolean value
5985 */
5986int
5987xmlXPathCastNumberToBoolean (double val) {
5988     if (xmlXPathIsNaN(val) || (val == 0.0))
5989	 return(0);
5990     return(1);
5991}
5992
5993/**
5994 * xmlXPathCastStringToBoolean:
5995 * @val:  a string
5996 *
5997 * Converts a string to its boolean value
5998 *
5999 * Returns the boolean value
6000 */
6001int
6002xmlXPathCastStringToBoolean (const xmlChar *val) {
6003    if ((val == NULL) || (xmlStrlen(val) == 0))
6004	return(0);
6005    return(1);
6006}
6007
6008/**
6009 * xmlXPathCastNodeSetToBoolean:
6010 * @ns:  a node-set
6011 *
6012 * Converts a node-set to its boolean value
6013 *
6014 * Returns the boolean value
6015 */
6016int
6017xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6018    if ((ns == NULL) || (ns->nodeNr == 0))
6019	return(0);
6020    return(1);
6021}
6022
6023/**
6024 * xmlXPathCastToBoolean:
6025 * @val:  an XPath object
6026 *
6027 * Converts an XPath object to its boolean value
6028 *
6029 * Returns the boolean value
6030 */
6031int
6032xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6033    int ret = 0;
6034
6035    if (val == NULL)
6036	return(0);
6037    switch (val->type) {
6038    case XPATH_UNDEFINED:
6039#ifdef DEBUG_EXPR
6040	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6041#endif
6042	ret = 0;
6043	break;
6044    case XPATH_NODESET:
6045    case XPATH_XSLT_TREE:
6046	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6047	break;
6048    case XPATH_STRING:
6049	ret = xmlXPathCastStringToBoolean(val->stringval);
6050	break;
6051    case XPATH_NUMBER:
6052	ret = xmlXPathCastNumberToBoolean(val->floatval);
6053	break;
6054    case XPATH_BOOLEAN:
6055	ret = val->boolval;
6056	break;
6057    case XPATH_USERS:
6058    case XPATH_POINT:
6059    case XPATH_RANGE:
6060    case XPATH_LOCATIONSET:
6061	TODO;
6062	ret = 0;
6063	break;
6064    }
6065    return(ret);
6066}
6067
6068
6069/**
6070 * xmlXPathConvertBoolean:
6071 * @val:  an XPath object
6072 *
6073 * Converts an existing object to its boolean() equivalent
6074 *
6075 * Returns the new object, the old one is freed (or the operation
6076 *         is done directly on @val)
6077 */
6078xmlXPathObjectPtr
6079xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6080    xmlXPathObjectPtr ret;
6081
6082    if (val == NULL)
6083	return(xmlXPathNewBoolean(0));
6084    if (val->type == XPATH_BOOLEAN)
6085	return(val);
6086    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6087    xmlXPathFreeObject(val);
6088    return(ret);
6089}
6090
6091/************************************************************************
6092 *									*
6093 *		Routines to handle XPath contexts			*
6094 *									*
6095 ************************************************************************/
6096
6097/**
6098 * xmlXPathNewContext:
6099 * @doc:  the XML document
6100 *
6101 * Create a new xmlXPathContext
6102 *
6103 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6104 */
6105xmlXPathContextPtr
6106xmlXPathNewContext(xmlDocPtr doc) {
6107    xmlXPathContextPtr ret;
6108
6109    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6110    if (ret == NULL) {
6111        xmlXPathErrMemory(NULL, "creating context\n");
6112	return(NULL);
6113    }
6114    memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6115    ret->doc = doc;
6116    ret->node = NULL;
6117
6118    ret->varHash = NULL;
6119
6120    ret->nb_types = 0;
6121    ret->max_types = 0;
6122    ret->types = NULL;
6123
6124    ret->funcHash = xmlHashCreate(0);
6125
6126    ret->nb_axis = 0;
6127    ret->max_axis = 0;
6128    ret->axis = NULL;
6129
6130    ret->nsHash = NULL;
6131    ret->user = NULL;
6132
6133    ret->contextSize = -1;
6134    ret->proximityPosition = -1;
6135
6136#ifdef XP_DEFAULT_CACHE_ON
6137    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6138	xmlXPathFreeContext(ret);
6139	return(NULL);
6140    }
6141#endif
6142
6143    xmlXPathRegisterAllFunctions(ret);
6144
6145    return(ret);
6146}
6147
6148/**
6149 * xmlXPathFreeContext:
6150 * @ctxt:  the context to free
6151 *
6152 * Free up an xmlXPathContext
6153 */
6154void
6155xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6156    if (ctxt == NULL) return;
6157
6158    if (ctxt->cache != NULL)
6159	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6160    xmlXPathRegisteredNsCleanup(ctxt);
6161    xmlXPathRegisteredFuncsCleanup(ctxt);
6162    xmlXPathRegisteredVariablesCleanup(ctxt);
6163    xmlResetError(&ctxt->lastError);
6164    xmlFree(ctxt);
6165}
6166
6167/************************************************************************
6168 *									*
6169 *		Routines to handle XPath parser contexts		*
6170 *									*
6171 ************************************************************************/
6172
6173#define CHECK_CTXT(ctxt)						\
6174    if (ctxt == NULL) {						\
6175	__xmlRaiseError(NULL, NULL, NULL,				\
6176		NULL, NULL, XML_FROM_XPATH,				\
6177		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6178		__FILE__, __LINE__,					\
6179		NULL, NULL, NULL, 0, 0,					\
6180		"NULL context pointer\n");				\
6181	return(NULL);							\
6182    }									\
6183
6184#define CHECK_CTXT_NEG(ctxt)						\
6185    if (ctxt == NULL) {						\
6186	__xmlRaiseError(NULL, NULL, NULL,				\
6187		NULL, NULL, XML_FROM_XPATH,				\
6188		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6189		__FILE__, __LINE__,					\
6190		NULL, NULL, NULL, 0, 0,					\
6191		"NULL context pointer\n");				\
6192	return(-1);							\
6193    }									\
6194
6195
6196#define CHECK_CONTEXT(ctxt)						\
6197    if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
6198        (ctxt->doc->children == NULL)) {				\
6199	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
6200	return(NULL);							\
6201    }
6202
6203
6204/**
6205 * xmlXPathNewParserContext:
6206 * @str:  the XPath expression
6207 * @ctxt:  the XPath context
6208 *
6209 * Create a new xmlXPathParserContext
6210 *
6211 * Returns the xmlXPathParserContext just allocated.
6212 */
6213xmlXPathParserContextPtr
6214xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6215    xmlXPathParserContextPtr ret;
6216
6217    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6218    if (ret == NULL) {
6219        xmlXPathErrMemory(ctxt, "creating parser context\n");
6220	return(NULL);
6221    }
6222    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6223    ret->cur = ret->base = str;
6224    ret->context = ctxt;
6225
6226    ret->comp = xmlXPathNewCompExpr();
6227    if (ret->comp == NULL) {
6228	xmlFree(ret->valueTab);
6229	xmlFree(ret);
6230	return(NULL);
6231    }
6232    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6233        ret->comp->dict = ctxt->dict;
6234	xmlDictReference(ret->comp->dict);
6235    }
6236
6237    return(ret);
6238}
6239
6240/**
6241 * xmlXPathCompParserContext:
6242 * @comp:  the XPath compiled expression
6243 * @ctxt:  the XPath context
6244 *
6245 * Create a new xmlXPathParserContext when processing a compiled expression
6246 *
6247 * Returns the xmlXPathParserContext just allocated.
6248 */
6249static xmlXPathParserContextPtr
6250xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6251    xmlXPathParserContextPtr ret;
6252
6253    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6254    if (ret == NULL) {
6255        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6256	return(NULL);
6257    }
6258    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6259
6260    /* Allocate the value stack */
6261    ret->valueTab = (xmlXPathObjectPtr *)
6262                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6263    if (ret->valueTab == NULL) {
6264	xmlFree(ret);
6265	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6266	return(NULL);
6267    }
6268    ret->valueNr = 0;
6269    ret->valueMax = 10;
6270    ret->value = NULL;
6271    ret->valueFrame = 0;
6272
6273    ret->context = ctxt;
6274    ret->comp = comp;
6275
6276    return(ret);
6277}
6278
6279/**
6280 * xmlXPathFreeParserContext:
6281 * @ctxt:  the context to free
6282 *
6283 * Free up an xmlXPathParserContext
6284 */
6285void
6286xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6287    if (ctxt->valueTab != NULL) {
6288        xmlFree(ctxt->valueTab);
6289    }
6290    if (ctxt->comp != NULL) {
6291#ifdef XPATH_STREAMING
6292	if (ctxt->comp->stream != NULL) {
6293	    xmlFreePatternList(ctxt->comp->stream);
6294	    ctxt->comp->stream = NULL;
6295	}
6296#endif
6297	xmlXPathFreeCompExpr(ctxt->comp);
6298    }
6299    xmlFree(ctxt);
6300}
6301
6302/************************************************************************
6303 *									*
6304 *		The implicit core function library			*
6305 *									*
6306 ************************************************************************/
6307
6308/**
6309 * xmlXPathNodeValHash:
6310 * @node:  a node pointer
6311 *
6312 * Function computing the beginning of the string value of the node,
6313 * used to speed up comparisons
6314 *
6315 * Returns an int usable as a hash
6316 */
6317static unsigned int
6318xmlXPathNodeValHash(xmlNodePtr node) {
6319    int len = 2;
6320    const xmlChar * string = NULL;
6321    xmlNodePtr tmp = NULL;
6322    unsigned int ret = 0;
6323
6324    if (node == NULL)
6325	return(0);
6326
6327    if (node->type == XML_DOCUMENT_NODE) {
6328	tmp = xmlDocGetRootElement((xmlDocPtr) node);
6329	if (tmp == NULL)
6330	    node = node->children;
6331	else
6332	    node = tmp;
6333
6334	if (node == NULL)
6335	    return(0);
6336    }
6337
6338    switch (node->type) {
6339	case XML_COMMENT_NODE:
6340	case XML_PI_NODE:
6341	case XML_CDATA_SECTION_NODE:
6342	case XML_TEXT_NODE:
6343	    string = node->content;
6344	    if (string == NULL)
6345		return(0);
6346	    if (string[0] == 0)
6347		return(0);
6348	    return(((unsigned int) string[0]) +
6349		   (((unsigned int) string[1]) << 8));
6350	case XML_NAMESPACE_DECL:
6351	    string = ((xmlNsPtr)node)->href;
6352	    if (string == NULL)
6353		return(0);
6354	    if (string[0] == 0)
6355		return(0);
6356	    return(((unsigned int) string[0]) +
6357		   (((unsigned int) string[1]) << 8));
6358	case XML_ATTRIBUTE_NODE:
6359	    tmp = ((xmlAttrPtr) node)->children;
6360	    break;
6361	case XML_ELEMENT_NODE:
6362	    tmp = node->children;
6363	    break;
6364	default:
6365	    return(0);
6366    }
6367    while (tmp != NULL) {
6368	switch (tmp->type) {
6369	    case XML_COMMENT_NODE:
6370	    case XML_PI_NODE:
6371	    case XML_CDATA_SECTION_NODE:
6372	    case XML_TEXT_NODE:
6373		string = tmp->content;
6374		break;
6375	    case XML_NAMESPACE_DECL:
6376		string = ((xmlNsPtr)tmp)->href;
6377		break;
6378	    default:
6379		break;
6380	}
6381	if ((string != NULL) && (string[0] != 0)) {
6382	    if (len == 1) {
6383		return(ret + (((unsigned int) string[0]) << 8));
6384	    }
6385	    if (string[1] == 0) {
6386		len = 1;
6387		ret = (unsigned int) string[0];
6388	    } else {
6389		return(((unsigned int) string[0]) +
6390		       (((unsigned int) string[1]) << 8));
6391	    }
6392	}
6393	/*
6394	 * Skip to next node
6395	 */
6396	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6397	    if (tmp->children->type != XML_ENTITY_DECL) {
6398		tmp = tmp->children;
6399		continue;
6400	    }
6401	}
6402	if (tmp == node)
6403	    break;
6404
6405	if (tmp->next != NULL) {
6406	    tmp = tmp->next;
6407	    continue;
6408	}
6409
6410	do {
6411	    tmp = tmp->parent;
6412	    if (tmp == NULL)
6413		break;
6414	    if (tmp == node) {
6415		tmp = NULL;
6416		break;
6417	    }
6418	    if (tmp->next != NULL) {
6419		tmp = tmp->next;
6420		break;
6421	    }
6422	} while (tmp != NULL);
6423    }
6424    return(ret);
6425}
6426
6427/**
6428 * xmlXPathStringHash:
6429 * @string:  a string
6430 *
6431 * Function computing the beginning of the string value of the node,
6432 * used to speed up comparisons
6433 *
6434 * Returns an int usable as a hash
6435 */
6436static unsigned int
6437xmlXPathStringHash(const xmlChar * string) {
6438    if (string == NULL)
6439	return((unsigned int) 0);
6440    if (string[0] == 0)
6441	return(0);
6442    return(((unsigned int) string[0]) +
6443	   (((unsigned int) string[1]) << 8));
6444}
6445
6446/**
6447 * xmlXPathCompareNodeSetFloat:
6448 * @ctxt:  the XPath Parser context
6449 * @inf:  less than (1) or greater than (0)
6450 * @strict:  is the comparison strict
6451 * @arg:  the node set
6452 * @f:  the value
6453 *
6454 * Implement the compare operation between a nodeset and a number
6455 *     @ns < @val    (1, 1, ...
6456 *     @ns <= @val   (1, 0, ...
6457 *     @ns > @val    (0, 1, ...
6458 *     @ns >= @val   (0, 0, ...
6459 *
6460 * If one object to be compared is a node-set and the other is a number,
6461 * then the comparison will be true if and only if there is a node in the
6462 * node-set such that the result of performing the comparison on the number
6463 * to be compared and on the result of converting the string-value of that
6464 * node to a number using the number function is true.
6465 *
6466 * Returns 0 or 1 depending on the results of the test.
6467 */
6468static int
6469xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6470	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6471    int i, ret = 0;
6472    xmlNodeSetPtr ns;
6473    xmlChar *str2;
6474
6475    if ((f == NULL) || (arg == NULL) ||
6476	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6477	xmlXPathReleaseObject(ctxt->context, arg);
6478	xmlXPathReleaseObject(ctxt->context, f);
6479        return(0);
6480    }
6481    ns = arg->nodesetval;
6482    if (ns != NULL) {
6483	for (i = 0;i < ns->nodeNr;i++) {
6484	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6485	     if (str2 != NULL) {
6486		 valuePush(ctxt,
6487			   xmlXPathCacheNewString(ctxt->context, str2));
6488		 xmlFree(str2);
6489		 xmlXPathNumberFunction(ctxt, 1);
6490		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6491		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6492		 if (ret)
6493		     break;
6494	     }
6495	}
6496    }
6497    xmlXPathReleaseObject(ctxt->context, arg);
6498    xmlXPathReleaseObject(ctxt->context, f);
6499    return(ret);
6500}
6501
6502/**
6503 * xmlXPathCompareNodeSetString:
6504 * @ctxt:  the XPath Parser context
6505 * @inf:  less than (1) or greater than (0)
6506 * @strict:  is the comparison strict
6507 * @arg:  the node set
6508 * @s:  the value
6509 *
6510 * Implement the compare operation between a nodeset and a string
6511 *     @ns < @val    (1, 1, ...
6512 *     @ns <= @val   (1, 0, ...
6513 *     @ns > @val    (0, 1, ...
6514 *     @ns >= @val   (0, 0, ...
6515 *
6516 * If one object to be compared is a node-set and the other is a string,
6517 * then the comparison will be true if and only if there is a node in
6518 * the node-set such that the result of performing the comparison on the
6519 * string-value of the node and the other string is true.
6520 *
6521 * Returns 0 or 1 depending on the results of the test.
6522 */
6523static int
6524xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6525	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6526    int i, ret = 0;
6527    xmlNodeSetPtr ns;
6528    xmlChar *str2;
6529
6530    if ((s == NULL) || (arg == NULL) ||
6531	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6532	xmlXPathReleaseObject(ctxt->context, arg);
6533	xmlXPathReleaseObject(ctxt->context, s);
6534        return(0);
6535    }
6536    ns = arg->nodesetval;
6537    if (ns != NULL) {
6538	for (i = 0;i < ns->nodeNr;i++) {
6539	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6540	     if (str2 != NULL) {
6541		 valuePush(ctxt,
6542			   xmlXPathCacheNewString(ctxt->context, str2));
6543		 xmlFree(str2);
6544		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6545		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6546		 if (ret)
6547		     break;
6548	     }
6549	}
6550    }
6551    xmlXPathReleaseObject(ctxt->context, arg);
6552    xmlXPathReleaseObject(ctxt->context, s);
6553    return(ret);
6554}
6555
6556/**
6557 * xmlXPathCompareNodeSets:
6558 * @inf:  less than (1) or greater than (0)
6559 * @strict:  is the comparison strict
6560 * @arg1:  the first node set object
6561 * @arg2:  the second node set object
6562 *
6563 * Implement the compare operation on nodesets:
6564 *
6565 * If both objects to be compared are node-sets, then the comparison
6566 * will be true if and only if there is a node in the first node-set
6567 * and a node in the second node-set such that the result of performing
6568 * the comparison on the string-values of the two nodes is true.
6569 * ....
6570 * When neither object to be compared is a node-set and the operator
6571 * is <=, <, >= or >, then the objects are compared by converting both
6572 * objects to numbers and comparing the numbers according to IEEE 754.
6573 * ....
6574 * The number function converts its argument to a number as follows:
6575 *  - a string that consists of optional whitespace followed by an
6576 *    optional minus sign followed by a Number followed by whitespace
6577 *    is converted to the IEEE 754 number that is nearest (according
6578 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6579 *    represented by the string; any other string is converted to NaN
6580 *
6581 * Conclusion all nodes need to be converted first to their string value
6582 * and then the comparison must be done when possible
6583 */
6584static int
6585xmlXPathCompareNodeSets(int inf, int strict,
6586	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6587    int i, j, init = 0;
6588    double val1;
6589    double *values2;
6590    int ret = 0;
6591    xmlNodeSetPtr ns1;
6592    xmlNodeSetPtr ns2;
6593
6594    if ((arg1 == NULL) ||
6595	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6596	xmlXPathFreeObject(arg2);
6597        return(0);
6598    }
6599    if ((arg2 == NULL) ||
6600	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6601	xmlXPathFreeObject(arg1);
6602	xmlXPathFreeObject(arg2);
6603        return(0);
6604    }
6605
6606    ns1 = arg1->nodesetval;
6607    ns2 = arg2->nodesetval;
6608
6609    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6610	xmlXPathFreeObject(arg1);
6611	xmlXPathFreeObject(arg2);
6612	return(0);
6613    }
6614    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6615	xmlXPathFreeObject(arg1);
6616	xmlXPathFreeObject(arg2);
6617	return(0);
6618    }
6619
6620    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6621    if (values2 == NULL) {
6622        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6623	xmlXPathFreeObject(arg1);
6624	xmlXPathFreeObject(arg2);
6625	return(0);
6626    }
6627    for (i = 0;i < ns1->nodeNr;i++) {
6628	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6629	if (xmlXPathIsNaN(val1))
6630	    continue;
6631	for (j = 0;j < ns2->nodeNr;j++) {
6632	    if (init == 0) {
6633		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6634	    }
6635	    if (xmlXPathIsNaN(values2[j]))
6636		continue;
6637	    if (inf && strict)
6638		ret = (val1 < values2[j]);
6639	    else if (inf && !strict)
6640		ret = (val1 <= values2[j]);
6641	    else if (!inf && strict)
6642		ret = (val1 > values2[j]);
6643	    else if (!inf && !strict)
6644		ret = (val1 >= values2[j]);
6645	    if (ret)
6646		break;
6647	}
6648	if (ret)
6649	    break;
6650	init = 1;
6651    }
6652    xmlFree(values2);
6653    xmlXPathFreeObject(arg1);
6654    xmlXPathFreeObject(arg2);
6655    return(ret);
6656}
6657
6658/**
6659 * xmlXPathCompareNodeSetValue:
6660 * @ctxt:  the XPath Parser context
6661 * @inf:  less than (1) or greater than (0)
6662 * @strict:  is the comparison strict
6663 * @arg:  the node set
6664 * @val:  the value
6665 *
6666 * Implement the compare operation between a nodeset and a value
6667 *     @ns < @val    (1, 1, ...
6668 *     @ns <= @val   (1, 0, ...
6669 *     @ns > @val    (0, 1, ...
6670 *     @ns >= @val   (0, 0, ...
6671 *
6672 * If one object to be compared is a node-set and the other is a boolean,
6673 * then the comparison will be true if and only if the result of performing
6674 * the comparison on the boolean and on the result of converting
6675 * the node-set to a boolean using the boolean function is true.
6676 *
6677 * Returns 0 or 1 depending on the results of the test.
6678 */
6679static int
6680xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6681	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6682    if ((val == NULL) || (arg == NULL) ||
6683	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6684        return(0);
6685
6686    switch(val->type) {
6687        case XPATH_NUMBER:
6688	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6689        case XPATH_NODESET:
6690        case XPATH_XSLT_TREE:
6691	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6692        case XPATH_STRING:
6693	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6694        case XPATH_BOOLEAN:
6695	    valuePush(ctxt, arg);
6696	    xmlXPathBooleanFunction(ctxt, 1);
6697	    valuePush(ctxt, val);
6698	    return(xmlXPathCompareValues(ctxt, inf, strict));
6699	default:
6700	    TODO
6701    }
6702    return(0);
6703}
6704
6705/**
6706 * xmlXPathEqualNodeSetString:
6707 * @arg:  the nodeset object argument
6708 * @str:  the string to compare to.
6709 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6710 *
6711 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6712 * If one object to be compared is a node-set and the other is a string,
6713 * then the comparison will be true if and only if there is a node in
6714 * the node-set such that the result of performing the comparison on the
6715 * string-value of the node and the other string is true.
6716 *
6717 * Returns 0 or 1 depending on the results of the test.
6718 */
6719static int
6720xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6721{
6722    int i;
6723    xmlNodeSetPtr ns;
6724    xmlChar *str2;
6725    unsigned int hash;
6726
6727    if ((str == NULL) || (arg == NULL) ||
6728        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6729        return (0);
6730    ns = arg->nodesetval;
6731    /*
6732     * A NULL nodeset compared with a string is always false
6733     * (since there is no node equal, and no node not equal)
6734     */
6735    if ((ns == NULL) || (ns->nodeNr <= 0) )
6736        return (0);
6737    hash = xmlXPathStringHash(str);
6738    for (i = 0; i < ns->nodeNr; i++) {
6739        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6740            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6741            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6742                xmlFree(str2);
6743		if (neq)
6744		    continue;
6745                return (1);
6746	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6747		if (neq)
6748		    continue;
6749                return (1);
6750            } else if (neq) {
6751		if (str2 != NULL)
6752		    xmlFree(str2);
6753		return (1);
6754	    }
6755            if (str2 != NULL)
6756                xmlFree(str2);
6757        } else if (neq)
6758	    return (1);
6759    }
6760    return (0);
6761}
6762
6763/**
6764 * xmlXPathEqualNodeSetFloat:
6765 * @arg:  the nodeset object argument
6766 * @f:  the float to compare to
6767 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6768 *
6769 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6770 * If one object to be compared is a node-set and the other is a number,
6771 * then the comparison will be true if and only if there is a node in
6772 * the node-set such that the result of performing the comparison on the
6773 * number to be compared and on the result of converting the string-value
6774 * of that node to a number using the number function is true.
6775 *
6776 * Returns 0 or 1 depending on the results of the test.
6777 */
6778static int
6779xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6780    xmlXPathObjectPtr arg, double f, int neq) {
6781  int i, ret=0;
6782  xmlNodeSetPtr ns;
6783  xmlChar *str2;
6784  xmlXPathObjectPtr val;
6785  double v;
6786
6787    if ((arg == NULL) ||
6788	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6789        return(0);
6790
6791    ns = arg->nodesetval;
6792    if (ns != NULL) {
6793	for (i=0;i<ns->nodeNr;i++) {
6794	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6795	    if (str2 != NULL) {
6796		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6797		xmlFree(str2);
6798		xmlXPathNumberFunction(ctxt, 1);
6799		val = valuePop(ctxt);
6800		v = val->floatval;
6801		xmlXPathReleaseObject(ctxt->context, val);
6802		if (!xmlXPathIsNaN(v)) {
6803		    if ((!neq) && (v==f)) {
6804			ret = 1;
6805			break;
6806		    } else if ((neq) && (v!=f)) {
6807			ret = 1;
6808			break;
6809		    }
6810		} else {	/* NaN is unequal to any value */
6811		    if (neq)
6812			ret = 1;
6813		}
6814	    }
6815	}
6816    }
6817
6818    return(ret);
6819}
6820
6821
6822/**
6823 * xmlXPathEqualNodeSets:
6824 * @arg1:  first nodeset object argument
6825 * @arg2:  second nodeset object argument
6826 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6827 *
6828 * Implement the equal / not equal operation on XPath nodesets:
6829 * @arg1 == @arg2  or  @arg1 != @arg2
6830 * If both objects to be compared are node-sets, then the comparison
6831 * will be true if and only if there is a node in the first node-set and
6832 * a node in the second node-set such that the result of performing the
6833 * comparison on the string-values of the two nodes is true.
6834 *
6835 * (needless to say, this is a costly operation)
6836 *
6837 * Returns 0 or 1 depending on the results of the test.
6838 */
6839static int
6840xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6841    int i, j;
6842    unsigned int *hashs1;
6843    unsigned int *hashs2;
6844    xmlChar **values1;
6845    xmlChar **values2;
6846    int ret = 0;
6847    xmlNodeSetPtr ns1;
6848    xmlNodeSetPtr ns2;
6849
6850    if ((arg1 == NULL) ||
6851	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6852        return(0);
6853    if ((arg2 == NULL) ||
6854	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6855        return(0);
6856
6857    ns1 = arg1->nodesetval;
6858    ns2 = arg2->nodesetval;
6859
6860    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6861	return(0);
6862    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6863	return(0);
6864
6865    /*
6866     * for equal, check if there is a node pertaining to both sets
6867     */
6868    if (neq == 0)
6869	for (i = 0;i < ns1->nodeNr;i++)
6870	    for (j = 0;j < ns2->nodeNr;j++)
6871		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6872		    return(1);
6873
6874    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6875    if (values1 == NULL) {
6876        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6877	return(0);
6878    }
6879    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6880    if (hashs1 == NULL) {
6881        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6882	xmlFree(values1);
6883	return(0);
6884    }
6885    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6886    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6887    if (values2 == NULL) {
6888        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6889	xmlFree(hashs1);
6890	xmlFree(values1);
6891	return(0);
6892    }
6893    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6894    if (hashs2 == NULL) {
6895        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6896	xmlFree(hashs1);
6897	xmlFree(values1);
6898	xmlFree(values2);
6899	return(0);
6900    }
6901    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6902    for (i = 0;i < ns1->nodeNr;i++) {
6903	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6904	for (j = 0;j < ns2->nodeNr;j++) {
6905	    if (i == 0)
6906		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6907	    if (hashs1[i] != hashs2[j]) {
6908		if (neq) {
6909		    ret = 1;
6910		    break;
6911		}
6912	    }
6913	    else {
6914		if (values1[i] == NULL)
6915		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6916		if (values2[j] == NULL)
6917		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6918		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6919		if (ret)
6920		    break;
6921	    }
6922	}
6923	if (ret)
6924	    break;
6925    }
6926    for (i = 0;i < ns1->nodeNr;i++)
6927	if (values1[i] != NULL)
6928	    xmlFree(values1[i]);
6929    for (j = 0;j < ns2->nodeNr;j++)
6930	if (values2[j] != NULL)
6931	    xmlFree(values2[j]);
6932    xmlFree(values1);
6933    xmlFree(values2);
6934    xmlFree(hashs1);
6935    xmlFree(hashs2);
6936    return(ret);
6937}
6938
6939static int
6940xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6941  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6942    int ret = 0;
6943    /*
6944     *At this point we are assured neither arg1 nor arg2
6945     *is a nodeset, so we can just pick the appropriate routine.
6946     */
6947    switch (arg1->type) {
6948        case XPATH_UNDEFINED:
6949#ifdef DEBUG_EXPR
6950	    xmlGenericError(xmlGenericErrorContext,
6951		    "Equal: undefined\n");
6952#endif
6953	    break;
6954        case XPATH_BOOLEAN:
6955	    switch (arg2->type) {
6956	        case XPATH_UNDEFINED:
6957#ifdef DEBUG_EXPR
6958		    xmlGenericError(xmlGenericErrorContext,
6959			    "Equal: undefined\n");
6960#endif
6961		    break;
6962		case XPATH_BOOLEAN:
6963#ifdef DEBUG_EXPR
6964		    xmlGenericError(xmlGenericErrorContext,
6965			    "Equal: %d boolean %d \n",
6966			    arg1->boolval, arg2->boolval);
6967#endif
6968		    ret = (arg1->boolval == arg2->boolval);
6969		    break;
6970		case XPATH_NUMBER:
6971		    ret = (arg1->boolval ==
6972			   xmlXPathCastNumberToBoolean(arg2->floatval));
6973		    break;
6974		case XPATH_STRING:
6975		    if ((arg2->stringval == NULL) ||
6976			(arg2->stringval[0] == 0)) ret = 0;
6977		    else
6978			ret = 1;
6979		    ret = (arg1->boolval == ret);
6980		    break;
6981		case XPATH_USERS:
6982		case XPATH_POINT:
6983		case XPATH_RANGE:
6984		case XPATH_LOCATIONSET:
6985		    TODO
6986		    break;
6987		case XPATH_NODESET:
6988		case XPATH_XSLT_TREE:
6989		    break;
6990	    }
6991	    break;
6992        case XPATH_NUMBER:
6993	    switch (arg2->type) {
6994	        case XPATH_UNDEFINED:
6995#ifdef DEBUG_EXPR
6996		    xmlGenericError(xmlGenericErrorContext,
6997			    "Equal: undefined\n");
6998#endif
6999		    break;
7000		case XPATH_BOOLEAN:
7001		    ret = (arg2->boolval==
7002			   xmlXPathCastNumberToBoolean(arg1->floatval));
7003		    break;
7004		case XPATH_STRING:
7005		    valuePush(ctxt, arg2);
7006		    xmlXPathNumberFunction(ctxt, 1);
7007		    arg2 = valuePop(ctxt);
7008		    /* no break on purpose */
7009		case XPATH_NUMBER:
7010		    /* Hand check NaN and Infinity equalities */
7011		    if (xmlXPathIsNaN(arg1->floatval) ||
7012			    xmlXPathIsNaN(arg2->floatval)) {
7013		        ret = 0;
7014		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7015		        if (xmlXPathIsInf(arg2->floatval) == 1)
7016			    ret = 1;
7017			else
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(arg2->floatval) == 1) {
7025			if (xmlXPathIsInf(arg1->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 {
7035		        ret = (arg1->floatval == arg2->floatval);
7036		    }
7037		    break;
7038		case XPATH_USERS:
7039		case XPATH_POINT:
7040		case XPATH_RANGE:
7041		case XPATH_LOCATIONSET:
7042		    TODO
7043		    break;
7044		case XPATH_NODESET:
7045		case XPATH_XSLT_TREE:
7046		    break;
7047	    }
7048	    break;
7049        case XPATH_STRING:
7050	    switch (arg2->type) {
7051	        case XPATH_UNDEFINED:
7052#ifdef DEBUG_EXPR
7053		    xmlGenericError(xmlGenericErrorContext,
7054			    "Equal: undefined\n");
7055#endif
7056		    break;
7057		case XPATH_BOOLEAN:
7058		    if ((arg1->stringval == NULL) ||
7059			(arg1->stringval[0] == 0)) ret = 0;
7060		    else
7061			ret = 1;
7062		    ret = (arg2->boolval == ret);
7063		    break;
7064		case XPATH_STRING:
7065		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7066		    break;
7067		case XPATH_NUMBER:
7068		    valuePush(ctxt, arg1);
7069		    xmlXPathNumberFunction(ctxt, 1);
7070		    arg1 = valuePop(ctxt);
7071		    /* Hand check NaN and Infinity equalities */
7072		    if (xmlXPathIsNaN(arg1->floatval) ||
7073			    xmlXPathIsNaN(arg2->floatval)) {
7074		        ret = 0;
7075		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7076			if (xmlXPathIsInf(arg2->floatval) == 1)
7077			    ret = 1;
7078			else
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(arg2->floatval) == 1) {
7086			if (xmlXPathIsInf(arg1->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 {
7096		        ret = (arg1->floatval == arg2->floatval);
7097		    }
7098		    break;
7099		case XPATH_USERS:
7100		case XPATH_POINT:
7101		case XPATH_RANGE:
7102		case XPATH_LOCATIONSET:
7103		    TODO
7104		    break;
7105		case XPATH_NODESET:
7106		case XPATH_XSLT_TREE:
7107		    break;
7108	    }
7109	    break;
7110        case XPATH_USERS:
7111	case XPATH_POINT:
7112	case XPATH_RANGE:
7113	case XPATH_LOCATIONSET:
7114	    TODO
7115	    break;
7116	case XPATH_NODESET:
7117	case XPATH_XSLT_TREE:
7118	    break;
7119    }
7120    xmlXPathReleaseObject(ctxt->context, arg1);
7121    xmlXPathReleaseObject(ctxt->context, arg2);
7122    return(ret);
7123}
7124
7125/**
7126 * xmlXPathEqualValues:
7127 * @ctxt:  the XPath Parser context
7128 *
7129 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7130 *
7131 * Returns 0 or 1 depending on the results of the test.
7132 */
7133int
7134xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7135    xmlXPathObjectPtr arg1, arg2, argtmp;
7136    int ret = 0;
7137
7138    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7139    arg2 = valuePop(ctxt);
7140    arg1 = valuePop(ctxt);
7141    if ((arg1 == NULL) || (arg2 == NULL)) {
7142	if (arg1 != NULL)
7143	    xmlXPathReleaseObject(ctxt->context, arg1);
7144	else
7145	    xmlXPathReleaseObject(ctxt->context, arg2);
7146	XP_ERROR0(XPATH_INVALID_OPERAND);
7147    }
7148
7149    if (arg1 == arg2) {
7150#ifdef DEBUG_EXPR
7151        xmlGenericError(xmlGenericErrorContext,
7152		"Equal: by pointer\n");
7153#endif
7154	xmlXPathFreeObject(arg1);
7155        return(1);
7156    }
7157
7158    /*
7159     *If either argument is a nodeset, it's a 'special case'
7160     */
7161    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7162      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7163	/*
7164	 *Hack it to assure arg1 is the nodeset
7165	 */
7166	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7167		argtmp = arg2;
7168		arg2 = arg1;
7169		arg1 = argtmp;
7170	}
7171	switch (arg2->type) {
7172	    case XPATH_UNDEFINED:
7173#ifdef DEBUG_EXPR
7174		xmlGenericError(xmlGenericErrorContext,
7175			"Equal: undefined\n");
7176#endif
7177		break;
7178	    case XPATH_NODESET:
7179	    case XPATH_XSLT_TREE:
7180		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7181		break;
7182	    case XPATH_BOOLEAN:
7183		if ((arg1->nodesetval == NULL) ||
7184		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7185		else
7186		    ret = 1;
7187		ret = (ret == arg2->boolval);
7188		break;
7189	    case XPATH_NUMBER:
7190		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7191		break;
7192	    case XPATH_STRING:
7193		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7194		break;
7195	    case XPATH_USERS:
7196	    case XPATH_POINT:
7197	    case XPATH_RANGE:
7198	    case XPATH_LOCATIONSET:
7199		TODO
7200		break;
7201	}
7202	xmlXPathReleaseObject(ctxt->context, arg1);
7203	xmlXPathReleaseObject(ctxt->context, arg2);
7204	return(ret);
7205    }
7206
7207    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7208}
7209
7210/**
7211 * xmlXPathNotEqualValues:
7212 * @ctxt:  the XPath Parser context
7213 *
7214 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7215 *
7216 * Returns 0 or 1 depending on the results of the test.
7217 */
7218int
7219xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7220    xmlXPathObjectPtr arg1, arg2, argtmp;
7221    int ret = 0;
7222
7223    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7224    arg2 = valuePop(ctxt);
7225    arg1 = valuePop(ctxt);
7226    if ((arg1 == NULL) || (arg2 == NULL)) {
7227	if (arg1 != NULL)
7228	    xmlXPathReleaseObject(ctxt->context, arg1);
7229	else
7230	    xmlXPathReleaseObject(ctxt->context, arg2);
7231	XP_ERROR0(XPATH_INVALID_OPERAND);
7232    }
7233
7234    if (arg1 == arg2) {
7235#ifdef DEBUG_EXPR
7236        xmlGenericError(xmlGenericErrorContext,
7237		"NotEqual: by pointer\n");
7238#endif
7239	xmlXPathReleaseObject(ctxt->context, arg1);
7240        return(0);
7241    }
7242
7243    /*
7244     *If either argument is a nodeset, it's a 'special case'
7245     */
7246    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7247      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7248	/*
7249	 *Hack it to assure arg1 is the nodeset
7250	 */
7251	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7252		argtmp = arg2;
7253		arg2 = arg1;
7254		arg1 = argtmp;
7255	}
7256	switch (arg2->type) {
7257	    case XPATH_UNDEFINED:
7258#ifdef DEBUG_EXPR
7259		xmlGenericError(xmlGenericErrorContext,
7260			"NotEqual: undefined\n");
7261#endif
7262		break;
7263	    case XPATH_NODESET:
7264	    case XPATH_XSLT_TREE:
7265		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7266		break;
7267	    case XPATH_BOOLEAN:
7268		if ((arg1->nodesetval == NULL) ||
7269		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7270		else
7271		    ret = 1;
7272		ret = (ret != arg2->boolval);
7273		break;
7274	    case XPATH_NUMBER:
7275		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7276		break;
7277	    case XPATH_STRING:
7278		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7279		break;
7280	    case XPATH_USERS:
7281	    case XPATH_POINT:
7282	    case XPATH_RANGE:
7283	    case XPATH_LOCATIONSET:
7284		TODO
7285		break;
7286	}
7287	xmlXPathReleaseObject(ctxt->context, arg1);
7288	xmlXPathReleaseObject(ctxt->context, arg2);
7289	return(ret);
7290    }
7291
7292    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7293}
7294
7295/**
7296 * xmlXPathCompareValues:
7297 * @ctxt:  the XPath Parser context
7298 * @inf:  less than (1) or greater than (0)
7299 * @strict:  is the comparison strict
7300 *
7301 * Implement the compare operation on XPath objects:
7302 *     @arg1 < @arg2    (1, 1, ...
7303 *     @arg1 <= @arg2   (1, 0, ...
7304 *     @arg1 > @arg2    (0, 1, ...
7305 *     @arg1 >= @arg2   (0, 0, ...
7306 *
7307 * When neither object to be compared is a node-set and the operator is
7308 * <=, <, >=, >, then the objects are compared by converted both objects
7309 * to numbers and comparing the numbers according to IEEE 754. The <
7310 * comparison will be true if and only if the first number is less than the
7311 * second number. The <= comparison will be true if and only if the first
7312 * number is less than or equal to the second number. The > comparison
7313 * will be true if and only if the first number is greater than the second
7314 * number. The >= comparison will be true if and only if the first number
7315 * is greater than or equal to the second number.
7316 *
7317 * Returns 1 if the comparison succeeded, 0 if it failed
7318 */
7319int
7320xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7321    int ret = 0, arg1i = 0, arg2i = 0;
7322    xmlXPathObjectPtr arg1, arg2;
7323
7324    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7325    arg2 = valuePop(ctxt);
7326    arg1 = valuePop(ctxt);
7327    if ((arg1 == NULL) || (arg2 == NULL)) {
7328	if (arg1 != NULL)
7329	    xmlXPathReleaseObject(ctxt->context, arg1);
7330	else
7331	    xmlXPathReleaseObject(ctxt->context, arg2);
7332	XP_ERROR0(XPATH_INVALID_OPERAND);
7333    }
7334
7335    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7336      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7337	/*
7338	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7339	 * are not freed from within this routine; they will be freed from the
7340	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7341	 */
7342	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7343	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7344	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7345	} else {
7346	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7347		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7348			                          arg1, arg2);
7349	    } else {
7350		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7351			                          arg2, arg1);
7352	    }
7353	}
7354	return(ret);
7355    }
7356
7357    if (arg1->type != XPATH_NUMBER) {
7358	valuePush(ctxt, arg1);
7359	xmlXPathNumberFunction(ctxt, 1);
7360	arg1 = valuePop(ctxt);
7361    }
7362    if (arg1->type != XPATH_NUMBER) {
7363	xmlXPathFreeObject(arg1);
7364	xmlXPathFreeObject(arg2);
7365	XP_ERROR0(XPATH_INVALID_OPERAND);
7366    }
7367    if (arg2->type != XPATH_NUMBER) {
7368	valuePush(ctxt, arg2);
7369	xmlXPathNumberFunction(ctxt, 1);
7370	arg2 = valuePop(ctxt);
7371    }
7372    if (arg2->type != XPATH_NUMBER) {
7373	xmlXPathReleaseObject(ctxt->context, arg1);
7374	xmlXPathReleaseObject(ctxt->context, arg2);
7375	XP_ERROR0(XPATH_INVALID_OPERAND);
7376    }
7377    /*
7378     * Add tests for infinity and nan
7379     * => feedback on 3.4 for Inf and NaN
7380     */
7381    /* Hand check NaN and Infinity comparisons */
7382    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7383	ret=0;
7384    } else {
7385	arg1i=xmlXPathIsInf(arg1->floatval);
7386	arg2i=xmlXPathIsInf(arg2->floatval);
7387	if (inf && strict) {
7388	    if ((arg1i == -1 && arg2i != -1) ||
7389		(arg2i == 1 && arg1i != 1)) {
7390		ret = 1;
7391	    } else if (arg1i == 0 && arg2i == 0) {
7392		ret = (arg1->floatval < arg2->floatval);
7393	    } else {
7394		ret = 0;
7395	    }
7396	}
7397	else if (inf && !strict) {
7398	    if (arg1i == -1 || arg2i == 1) {
7399		ret = 1;
7400	    } else if (arg1i == 0 && arg2i == 0) {
7401		ret = (arg1->floatval <= arg2->floatval);
7402	    } else {
7403		ret = 0;
7404	    }
7405	}
7406	else if (!inf && strict) {
7407	    if ((arg1i == 1 && arg2i != 1) ||
7408		(arg2i == -1 && arg1i != -1)) {
7409		ret = 1;
7410	    } else if (arg1i == 0 && arg2i == 0) {
7411		ret = (arg1->floatval > arg2->floatval);
7412	    } else {
7413		ret = 0;
7414	    }
7415	}
7416	else if (!inf && !strict) {
7417	    if (arg1i == 1 || arg2i == -1) {
7418		ret = 1;
7419	    } else if (arg1i == 0 && arg2i == 0) {
7420		ret = (arg1->floatval >= arg2->floatval);
7421	    } else {
7422		ret = 0;
7423	    }
7424	}
7425    }
7426    xmlXPathReleaseObject(ctxt->context, arg1);
7427    xmlXPathReleaseObject(ctxt->context, arg2);
7428    return(ret);
7429}
7430
7431/**
7432 * xmlXPathValueFlipSign:
7433 * @ctxt:  the XPath Parser context
7434 *
7435 * Implement the unary - operation on an XPath object
7436 * The numeric operators convert their operands to numbers as if
7437 * by calling the number function.
7438 */
7439void
7440xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7441    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7442    CAST_TO_NUMBER;
7443    CHECK_TYPE(XPATH_NUMBER);
7444    if (xmlXPathIsNaN(ctxt->value->floatval))
7445        ctxt->value->floatval=xmlXPathNAN;
7446    else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7447        ctxt->value->floatval=xmlXPathNINF;
7448    else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7449        ctxt->value->floatval=xmlXPathPINF;
7450    else if (ctxt->value->floatval == 0) {
7451        if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7452	    ctxt->value->floatval = xmlXPathNZERO;
7453	else
7454	    ctxt->value->floatval = 0;
7455    }
7456    else
7457        ctxt->value->floatval = - ctxt->value->floatval;
7458}
7459
7460/**
7461 * xmlXPathAddValues:
7462 * @ctxt:  the XPath Parser context
7463 *
7464 * Implement the add operation on XPath objects:
7465 * The numeric operators convert their operands to numbers as if
7466 * by calling the number function.
7467 */
7468void
7469xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7470    xmlXPathObjectPtr arg;
7471    double val;
7472
7473    arg = valuePop(ctxt);
7474    if (arg == NULL)
7475	XP_ERROR(XPATH_INVALID_OPERAND);
7476    val = xmlXPathCastToNumber(arg);
7477    xmlXPathReleaseObject(ctxt->context, arg);
7478    CAST_TO_NUMBER;
7479    CHECK_TYPE(XPATH_NUMBER);
7480    ctxt->value->floatval += val;
7481}
7482
7483/**
7484 * xmlXPathSubValues:
7485 * @ctxt:  the XPath Parser context
7486 *
7487 * Implement the subtraction operation on XPath objects:
7488 * The numeric operators convert their operands to numbers as if
7489 * by calling the number function.
7490 */
7491void
7492xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7493    xmlXPathObjectPtr arg;
7494    double val;
7495
7496    arg = valuePop(ctxt);
7497    if (arg == NULL)
7498	XP_ERROR(XPATH_INVALID_OPERAND);
7499    val = xmlXPathCastToNumber(arg);
7500    xmlXPathReleaseObject(ctxt->context, arg);
7501    CAST_TO_NUMBER;
7502    CHECK_TYPE(XPATH_NUMBER);
7503    ctxt->value->floatval -= val;
7504}
7505
7506/**
7507 * xmlXPathMultValues:
7508 * @ctxt:  the XPath Parser context
7509 *
7510 * Implement the multiply operation on XPath objects:
7511 * The numeric operators convert their operands to numbers as if
7512 * by calling the number function.
7513 */
7514void
7515xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7516    xmlXPathObjectPtr arg;
7517    double val;
7518
7519    arg = valuePop(ctxt);
7520    if (arg == NULL)
7521	XP_ERROR(XPATH_INVALID_OPERAND);
7522    val = xmlXPathCastToNumber(arg);
7523    xmlXPathReleaseObject(ctxt->context, arg);
7524    CAST_TO_NUMBER;
7525    CHECK_TYPE(XPATH_NUMBER);
7526    ctxt->value->floatval *= val;
7527}
7528
7529/**
7530 * xmlXPathDivValues:
7531 * @ctxt:  the XPath Parser context
7532 *
7533 * Implement the div operation on XPath objects @arg1 / @arg2:
7534 * The numeric operators convert their operands to numbers as if
7535 * by calling the number function.
7536 */
7537void
7538xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7539    xmlXPathObjectPtr arg;
7540    double val;
7541
7542    arg = valuePop(ctxt);
7543    if (arg == NULL)
7544	XP_ERROR(XPATH_INVALID_OPERAND);
7545    val = xmlXPathCastToNumber(arg);
7546    xmlXPathReleaseObject(ctxt->context, arg);
7547    CAST_TO_NUMBER;
7548    CHECK_TYPE(XPATH_NUMBER);
7549    if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7550	ctxt->value->floatval = xmlXPathNAN;
7551    else if (val == 0 && xmlXPathGetSign(val) != 0) {
7552	if (ctxt->value->floatval == 0)
7553	    ctxt->value->floatval = xmlXPathNAN;
7554	else if (ctxt->value->floatval > 0)
7555	    ctxt->value->floatval = xmlXPathNINF;
7556	else if (ctxt->value->floatval < 0)
7557	    ctxt->value->floatval = xmlXPathPINF;
7558    }
7559    else if (val == 0) {
7560	if (ctxt->value->floatval == 0)
7561	    ctxt->value->floatval = xmlXPathNAN;
7562	else if (ctxt->value->floatval > 0)
7563	    ctxt->value->floatval = xmlXPathPINF;
7564	else if (ctxt->value->floatval < 0)
7565	    ctxt->value->floatval = xmlXPathNINF;
7566    } else
7567	ctxt->value->floatval /= val;
7568}
7569
7570/**
7571 * xmlXPathModValues:
7572 * @ctxt:  the XPath Parser context
7573 *
7574 * Implement the mod operation on XPath objects: @arg1 / @arg2
7575 * The numeric operators convert their operands to numbers as if
7576 * by calling the number function.
7577 */
7578void
7579xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7580    xmlXPathObjectPtr arg;
7581    double arg1, arg2;
7582
7583    arg = valuePop(ctxt);
7584    if (arg == NULL)
7585	XP_ERROR(XPATH_INVALID_OPERAND);
7586    arg2 = xmlXPathCastToNumber(arg);
7587    xmlXPathReleaseObject(ctxt->context, arg);
7588    CAST_TO_NUMBER;
7589    CHECK_TYPE(XPATH_NUMBER);
7590    arg1 = ctxt->value->floatval;
7591    if (arg2 == 0)
7592	ctxt->value->floatval = xmlXPathNAN;
7593    else {
7594	ctxt->value->floatval = fmod(arg1, arg2);
7595    }
7596}
7597
7598/************************************************************************
7599 *									*
7600 *		The traversal functions					*
7601 *									*
7602 ************************************************************************/
7603
7604/*
7605 * A traversal function enumerates nodes along an axis.
7606 * Initially it must be called with NULL, and it indicates
7607 * termination on the axis by returning NULL.
7608 */
7609typedef xmlNodePtr (*xmlXPathTraversalFunction)
7610                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7611
7612/*
7613 * xmlXPathTraversalFunctionExt:
7614 * A traversal function enumerates nodes along an axis.
7615 * Initially it must be called with NULL, and it indicates
7616 * termination on the axis by returning NULL.
7617 * The context node of the traversal is specified via @contextNode.
7618 */
7619typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7620                    (xmlNodePtr cur, xmlNodePtr contextNode);
7621
7622/*
7623 * xmlXPathNodeSetMergeFunction:
7624 * Used for merging node sets in xmlXPathCollectAndTest().
7625 */
7626typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7627		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
7628
7629
7630/**
7631 * xmlXPathNextSelf:
7632 * @ctxt:  the XPath Parser context
7633 * @cur:  the current node in the traversal
7634 *
7635 * Traversal function for the "self" direction
7636 * The self axis contains just the context node itself
7637 *
7638 * Returns the next element following that axis
7639 */
7640xmlNodePtr
7641xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7642    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7643    if (cur == NULL)
7644        return(ctxt->context->node);
7645    return(NULL);
7646}
7647
7648/**
7649 * xmlXPathNextChild:
7650 * @ctxt:  the XPath Parser context
7651 * @cur:  the current node in the traversal
7652 *
7653 * Traversal function for the "child" direction
7654 * The child axis contains the children of the context node in document order.
7655 *
7656 * Returns the next element following that axis
7657 */
7658xmlNodePtr
7659xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7660    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7661    if (cur == NULL) {
7662	if (ctxt->context->node == NULL) return(NULL);
7663	switch (ctxt->context->node->type) {
7664            case XML_ELEMENT_NODE:
7665            case XML_TEXT_NODE:
7666            case XML_CDATA_SECTION_NODE:
7667            case XML_ENTITY_REF_NODE:
7668            case XML_ENTITY_NODE:
7669            case XML_PI_NODE:
7670            case XML_COMMENT_NODE:
7671            case XML_NOTATION_NODE:
7672            case XML_DTD_NODE:
7673		return(ctxt->context->node->children);
7674            case XML_DOCUMENT_NODE:
7675            case XML_DOCUMENT_TYPE_NODE:
7676            case XML_DOCUMENT_FRAG_NODE:
7677            case XML_HTML_DOCUMENT_NODE:
7678#ifdef LIBXML_DOCB_ENABLED
7679	    case XML_DOCB_DOCUMENT_NODE:
7680#endif
7681		return(((xmlDocPtr) ctxt->context->node)->children);
7682	    case XML_ELEMENT_DECL:
7683	    case XML_ATTRIBUTE_DECL:
7684	    case XML_ENTITY_DECL:
7685            case XML_ATTRIBUTE_NODE:
7686	    case XML_NAMESPACE_DECL:
7687	    case XML_XINCLUDE_START:
7688	    case XML_XINCLUDE_END:
7689		return(NULL);
7690	}
7691	return(NULL);
7692    }
7693    if ((cur->type == XML_DOCUMENT_NODE) ||
7694        (cur->type == XML_HTML_DOCUMENT_NODE))
7695	return(NULL);
7696    return(cur->next);
7697}
7698
7699/**
7700 * xmlXPathNextChildElement:
7701 * @ctxt:  the XPath Parser context
7702 * @cur:  the current node in the traversal
7703 *
7704 * Traversal function for the "child" direction and nodes of type element.
7705 * The child axis contains the children of the context node in document order.
7706 *
7707 * Returns the next element following that axis
7708 */
7709static xmlNodePtr
7710xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7711    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7712    if (cur == NULL) {
7713	cur = ctxt->context->node;
7714	if (cur == NULL) return(NULL);
7715	/*
7716	* Get the first element child.
7717	*/
7718	switch (cur->type) {
7719            case XML_ELEMENT_NODE:
7720	    case XML_DOCUMENT_FRAG_NODE:
7721	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7722            case XML_ENTITY_NODE:
7723		cur = cur->children;
7724		if (cur != NULL) {
7725		    if (cur->type == XML_ELEMENT_NODE)
7726			return(cur);
7727		    do {
7728			cur = cur->next;
7729		    } while ((cur != NULL) &&
7730			(cur->type != XML_ELEMENT_NODE));
7731		    return(cur);
7732		}
7733		return(NULL);
7734            case XML_DOCUMENT_NODE:
7735            case XML_HTML_DOCUMENT_NODE:
7736#ifdef LIBXML_DOCB_ENABLED
7737	    case XML_DOCB_DOCUMENT_NODE:
7738#endif
7739		return(xmlDocGetRootElement((xmlDocPtr) cur));
7740	    default:
7741		return(NULL);
7742	}
7743	return(NULL);
7744    }
7745    /*
7746    * Get the next sibling element node.
7747    */
7748    switch (cur->type) {
7749	case XML_ELEMENT_NODE:
7750	case XML_TEXT_NODE:
7751	case XML_ENTITY_REF_NODE:
7752	case XML_ENTITY_NODE:
7753	case XML_CDATA_SECTION_NODE:
7754	case XML_PI_NODE:
7755	case XML_COMMENT_NODE:
7756	case XML_XINCLUDE_END:
7757	    break;
7758	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7759	default:
7760	    return(NULL);
7761    }
7762    if (cur->next != NULL) {
7763	if (cur->next->type == XML_ELEMENT_NODE)
7764	    return(cur->next);
7765	cur = cur->next;
7766	do {
7767	    cur = cur->next;
7768	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7769	return(cur);
7770    }
7771    return(NULL);
7772}
7773
7774/**
7775 * xmlXPathNextDescendantOrSelfElemParent:
7776 * @ctxt:  the XPath Parser context
7777 * @cur:  the current node in the traversal
7778 *
7779 * Traversal function for the "descendant-or-self" axis.
7780 * Additionally it returns only nodes which can be parents of
7781 * element nodes.
7782 *
7783 *
7784 * Returns the next element following that axis
7785 */
7786static xmlNodePtr
7787xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7788				       xmlNodePtr contextNode)
7789{
7790    if (cur == NULL) {
7791	if (contextNode == NULL)
7792	    return(NULL);
7793	switch (contextNode->type) {
7794	    case XML_ELEMENT_NODE:
7795	    case XML_XINCLUDE_START:
7796	    case XML_DOCUMENT_FRAG_NODE:
7797	    case XML_DOCUMENT_NODE:
7798#ifdef LIBXML_DOCB_ENABLED
7799	    case XML_DOCB_DOCUMENT_NODE:
7800#endif
7801	    case XML_HTML_DOCUMENT_NODE:
7802		return(contextNode);
7803	    default:
7804		return(NULL);
7805	}
7806	return(NULL);
7807    } else {
7808	xmlNodePtr start = cur;
7809
7810	while (cur != NULL) {
7811	    switch (cur->type) {
7812		case XML_ELEMENT_NODE:
7813		/* TODO: OK to have XInclude here? */
7814		case XML_XINCLUDE_START:
7815		case XML_DOCUMENT_FRAG_NODE:
7816		    if (cur != start)
7817			return(cur);
7818		    if (cur->children != NULL) {
7819			cur = cur->children;
7820			continue;
7821		    }
7822		    break;
7823		/* Not sure if we need those here. */
7824		case XML_DOCUMENT_NODE:
7825#ifdef LIBXML_DOCB_ENABLED
7826		case XML_DOCB_DOCUMENT_NODE:
7827#endif
7828		case XML_HTML_DOCUMENT_NODE:
7829		    if (cur != start)
7830			return(cur);
7831		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7832		default:
7833		    break;
7834	    }
7835
7836next_sibling:
7837	    if ((cur == NULL) || (cur == contextNode))
7838		return(NULL);
7839	    if (cur->next != NULL) {
7840		cur = cur->next;
7841	    } else {
7842		cur = cur->parent;
7843		goto next_sibling;
7844	    }
7845	}
7846    }
7847    return(NULL);
7848}
7849
7850/**
7851 * xmlXPathNextDescendant:
7852 * @ctxt:  the XPath Parser context
7853 * @cur:  the current node in the traversal
7854 *
7855 * Traversal function for the "descendant" direction
7856 * the descendant axis contains the descendants of the context node in document
7857 * order; a descendant is a child or a child of a child and so on.
7858 *
7859 * Returns the next element following that axis
7860 */
7861xmlNodePtr
7862xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7863    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7864    if (cur == NULL) {
7865	if (ctxt->context->node == NULL)
7866	    return(NULL);
7867	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7868	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7869	    return(NULL);
7870
7871        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7872	    return(ctxt->context->doc->children);
7873        return(ctxt->context->node->children);
7874    }
7875
7876    if (cur->type == XML_NAMESPACE_DECL)
7877        return(NULL);
7878    if (cur->children != NULL) {
7879	/*
7880	 * Do not descend on entities declarations
7881	 */
7882	if (cur->children->type != XML_ENTITY_DECL) {
7883	    cur = cur->children;
7884	    /*
7885	     * Skip DTDs
7886	     */
7887	    if (cur->type != XML_DTD_NODE)
7888		return(cur);
7889	}
7890    }
7891
7892    if (cur == ctxt->context->node) return(NULL);
7893
7894    while (cur->next != NULL) {
7895	cur = cur->next;
7896	if ((cur->type != XML_ENTITY_DECL) &&
7897	    (cur->type != XML_DTD_NODE))
7898	    return(cur);
7899    }
7900
7901    do {
7902        cur = cur->parent;
7903	if (cur == NULL) break;
7904	if (cur == ctxt->context->node) return(NULL);
7905	if (cur->next != NULL) {
7906	    cur = cur->next;
7907	    return(cur);
7908	}
7909    } while (cur != NULL);
7910    return(cur);
7911}
7912
7913/**
7914 * xmlXPathNextDescendantOrSelf:
7915 * @ctxt:  the XPath Parser context
7916 * @cur:  the current node in the traversal
7917 *
7918 * Traversal function for the "descendant-or-self" direction
7919 * the descendant-or-self axis contains the context node and the descendants
7920 * of the context node in document order; thus the context node is the first
7921 * node on the axis, and the first child of the context node is the second node
7922 * on the axis
7923 *
7924 * Returns the next element following that axis
7925 */
7926xmlNodePtr
7927xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7928    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7929    if (cur == NULL) {
7930	if (ctxt->context->node == NULL)
7931	    return(NULL);
7932	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7933	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7934	    return(NULL);
7935        return(ctxt->context->node);
7936    }
7937
7938    return(xmlXPathNextDescendant(ctxt, cur));
7939}
7940
7941/**
7942 * xmlXPathNextParent:
7943 * @ctxt:  the XPath Parser context
7944 * @cur:  the current node in the traversal
7945 *
7946 * Traversal function for the "parent" direction
7947 * The parent axis contains the parent of the context node, if there is one.
7948 *
7949 * Returns the next element following that axis
7950 */
7951xmlNodePtr
7952xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7953    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7954    /*
7955     * the parent of an attribute or namespace node is the element
7956     * to which the attribute or namespace node is attached
7957     * Namespace handling !!!
7958     */
7959    if (cur == NULL) {
7960	if (ctxt->context->node == NULL) return(NULL);
7961	switch (ctxt->context->node->type) {
7962            case XML_ELEMENT_NODE:
7963            case XML_TEXT_NODE:
7964            case XML_CDATA_SECTION_NODE:
7965            case XML_ENTITY_REF_NODE:
7966            case XML_ENTITY_NODE:
7967            case XML_PI_NODE:
7968            case XML_COMMENT_NODE:
7969            case XML_NOTATION_NODE:
7970            case XML_DTD_NODE:
7971	    case XML_ELEMENT_DECL:
7972	    case XML_ATTRIBUTE_DECL:
7973	    case XML_XINCLUDE_START:
7974	    case XML_XINCLUDE_END:
7975	    case XML_ENTITY_DECL:
7976		if (ctxt->context->node->parent == NULL)
7977		    return((xmlNodePtr) ctxt->context->doc);
7978		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7979		    ((ctxt->context->node->parent->name[0] == ' ') ||
7980		     (xmlStrEqual(ctxt->context->node->parent->name,
7981				 BAD_CAST "fake node libxslt"))))
7982		    return(NULL);
7983		return(ctxt->context->node->parent);
7984            case XML_ATTRIBUTE_NODE: {
7985		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7986
7987		return(att->parent);
7988	    }
7989            case XML_DOCUMENT_NODE:
7990            case XML_DOCUMENT_TYPE_NODE:
7991            case XML_DOCUMENT_FRAG_NODE:
7992            case XML_HTML_DOCUMENT_NODE:
7993#ifdef LIBXML_DOCB_ENABLED
7994	    case XML_DOCB_DOCUMENT_NODE:
7995#endif
7996                return(NULL);
7997	    case XML_NAMESPACE_DECL: {
7998		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7999
8000		if ((ns->next != NULL) &&
8001		    (ns->next->type != XML_NAMESPACE_DECL))
8002		    return((xmlNodePtr) ns->next);
8003                return(NULL);
8004	    }
8005	}
8006    }
8007    return(NULL);
8008}
8009
8010/**
8011 * xmlXPathNextAncestor:
8012 * @ctxt:  the XPath Parser context
8013 * @cur:  the current node in the traversal
8014 *
8015 * Traversal function for the "ancestor" direction
8016 * the ancestor axis contains the ancestors of the context node; the ancestors
8017 * of the context node consist of the parent of context node and the parent's
8018 * parent and so on; the nodes are ordered in reverse document order; thus the
8019 * parent is the first node on the axis, and the parent's parent is the second
8020 * node on the axis
8021 *
8022 * Returns the next element following that axis
8023 */
8024xmlNodePtr
8025xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8026    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8027    /*
8028     * the parent of an attribute or namespace node is the element
8029     * to which the attribute or namespace node is attached
8030     * !!!!!!!!!!!!!
8031     */
8032    if (cur == NULL) {
8033	if (ctxt->context->node == NULL) return(NULL);
8034	switch (ctxt->context->node->type) {
8035            case XML_ELEMENT_NODE:
8036            case XML_TEXT_NODE:
8037            case XML_CDATA_SECTION_NODE:
8038            case XML_ENTITY_REF_NODE:
8039            case XML_ENTITY_NODE:
8040            case XML_PI_NODE:
8041            case XML_COMMENT_NODE:
8042	    case XML_DTD_NODE:
8043	    case XML_ELEMENT_DECL:
8044	    case XML_ATTRIBUTE_DECL:
8045	    case XML_ENTITY_DECL:
8046            case XML_NOTATION_NODE:
8047	    case XML_XINCLUDE_START:
8048	    case XML_XINCLUDE_END:
8049		if (ctxt->context->node->parent == NULL)
8050		    return((xmlNodePtr) ctxt->context->doc);
8051		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8052		    ((ctxt->context->node->parent->name[0] == ' ') ||
8053		     (xmlStrEqual(ctxt->context->node->parent->name,
8054				 BAD_CAST "fake node libxslt"))))
8055		    return(NULL);
8056		return(ctxt->context->node->parent);
8057            case XML_ATTRIBUTE_NODE: {
8058		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8059
8060		return(tmp->parent);
8061	    }
8062            case XML_DOCUMENT_NODE:
8063            case XML_DOCUMENT_TYPE_NODE:
8064            case XML_DOCUMENT_FRAG_NODE:
8065            case XML_HTML_DOCUMENT_NODE:
8066#ifdef LIBXML_DOCB_ENABLED
8067	    case XML_DOCB_DOCUMENT_NODE:
8068#endif
8069                return(NULL);
8070	    case XML_NAMESPACE_DECL: {
8071		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8072
8073		if ((ns->next != NULL) &&
8074		    (ns->next->type != XML_NAMESPACE_DECL))
8075		    return((xmlNodePtr) ns->next);
8076		/* Bad, how did that namespace end up here ? */
8077                return(NULL);
8078	    }
8079	}
8080	return(NULL);
8081    }
8082    if (cur == ctxt->context->doc->children)
8083	return((xmlNodePtr) ctxt->context->doc);
8084    if (cur == (xmlNodePtr) ctxt->context->doc)
8085	return(NULL);
8086    switch (cur->type) {
8087	case XML_ELEMENT_NODE:
8088	case XML_TEXT_NODE:
8089	case XML_CDATA_SECTION_NODE:
8090	case XML_ENTITY_REF_NODE:
8091	case XML_ENTITY_NODE:
8092	case XML_PI_NODE:
8093	case XML_COMMENT_NODE:
8094	case XML_NOTATION_NODE:
8095	case XML_DTD_NODE:
8096        case XML_ELEMENT_DECL:
8097        case XML_ATTRIBUTE_DECL:
8098        case XML_ENTITY_DECL:
8099	case XML_XINCLUDE_START:
8100	case XML_XINCLUDE_END:
8101	    if (cur->parent == NULL)
8102		return(NULL);
8103	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
8104		((cur->parent->name[0] == ' ') ||
8105		 (xmlStrEqual(cur->parent->name,
8106			      BAD_CAST "fake node libxslt"))))
8107		return(NULL);
8108	    return(cur->parent);
8109	case XML_ATTRIBUTE_NODE: {
8110	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8111
8112	    return(att->parent);
8113	}
8114	case XML_NAMESPACE_DECL: {
8115	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8116
8117	    if ((ns->next != NULL) &&
8118	        (ns->next->type != XML_NAMESPACE_DECL))
8119	        return((xmlNodePtr) ns->next);
8120	    /* Bad, how did that namespace end up here ? */
8121            return(NULL);
8122	}
8123	case XML_DOCUMENT_NODE:
8124	case XML_DOCUMENT_TYPE_NODE:
8125	case XML_DOCUMENT_FRAG_NODE:
8126	case XML_HTML_DOCUMENT_NODE:
8127#ifdef LIBXML_DOCB_ENABLED
8128	case XML_DOCB_DOCUMENT_NODE:
8129#endif
8130	    return(NULL);
8131    }
8132    return(NULL);
8133}
8134
8135/**
8136 * xmlXPathNextAncestorOrSelf:
8137 * @ctxt:  the XPath Parser context
8138 * @cur:  the current node in the traversal
8139 *
8140 * Traversal function for the "ancestor-or-self" direction
8141 * he ancestor-or-self axis contains the context node and ancestors of
8142 * the context node in reverse document order; thus the context node is
8143 * the first node on the axis, and the context node's parent the second;
8144 * parent here is defined the same as with the parent axis.
8145 *
8146 * Returns the next element following that axis
8147 */
8148xmlNodePtr
8149xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8150    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8151    if (cur == NULL)
8152        return(ctxt->context->node);
8153    return(xmlXPathNextAncestor(ctxt, cur));
8154}
8155
8156/**
8157 * xmlXPathNextFollowingSibling:
8158 * @ctxt:  the XPath Parser context
8159 * @cur:  the current node in the traversal
8160 *
8161 * Traversal function for the "following-sibling" direction
8162 * The following-sibling axis contains the following siblings of the context
8163 * node in document order.
8164 *
8165 * Returns the next element following that axis
8166 */
8167xmlNodePtr
8168xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8169    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8170    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8171	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8172	return(NULL);
8173    if (cur == (xmlNodePtr) ctxt->context->doc)
8174        return(NULL);
8175    if (cur == NULL)
8176        return(ctxt->context->node->next);
8177    return(cur->next);
8178}
8179
8180/**
8181 * xmlXPathNextPrecedingSibling:
8182 * @ctxt:  the XPath Parser context
8183 * @cur:  the current node in the traversal
8184 *
8185 * Traversal function for the "preceding-sibling" direction
8186 * The preceding-sibling axis contains the preceding siblings of the context
8187 * node in reverse document order; the first preceding sibling is first on the
8188 * axis; the sibling preceding that node is the second on the axis and so on.
8189 *
8190 * Returns the next element following that axis
8191 */
8192xmlNodePtr
8193xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8194    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8195    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8196	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8197	return(NULL);
8198    if (cur == (xmlNodePtr) ctxt->context->doc)
8199        return(NULL);
8200    if (cur == NULL)
8201        return(ctxt->context->node->prev);
8202    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8203	cur = cur->prev;
8204	if (cur == NULL)
8205	    return(ctxt->context->node->prev);
8206    }
8207    return(cur->prev);
8208}
8209
8210/**
8211 * xmlXPathNextFollowing:
8212 * @ctxt:  the XPath Parser context
8213 * @cur:  the current node in the traversal
8214 *
8215 * Traversal function for the "following" direction
8216 * The following axis contains all nodes in the same document as the context
8217 * node that are after the context node in document order, excluding any
8218 * descendants and excluding attribute nodes and namespace nodes; the nodes
8219 * are ordered in document order
8220 *
8221 * Returns the next element following that axis
8222 */
8223xmlNodePtr
8224xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8225    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8226    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8227        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8228        return(cur->children);
8229
8230    if (cur == NULL) {
8231        cur = ctxt->context->node;
8232        if (cur->type == XML_NAMESPACE_DECL)
8233            return(NULL);
8234        if (cur->type == XML_ATTRIBUTE_NODE)
8235            cur = cur->parent;
8236    }
8237    if (cur == NULL) return(NULL) ; /* ERROR */
8238    if (cur->next != NULL) return(cur->next) ;
8239    do {
8240        cur = cur->parent;
8241        if (cur == NULL) break;
8242        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8243        if (cur->next != NULL) return(cur->next);
8244    } while (cur != NULL);
8245    return(cur);
8246}
8247
8248/*
8249 * xmlXPathIsAncestor:
8250 * @ancestor:  the ancestor node
8251 * @node:  the current node
8252 *
8253 * Check that @ancestor is a @node's ancestor
8254 *
8255 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8256 */
8257static int
8258xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8259    if ((ancestor == NULL) || (node == NULL)) return(0);
8260    if (node->type == XML_NAMESPACE_DECL)
8261        return(0);
8262    if (ancestor->type == XML_NAMESPACE_DECL)
8263        return(0);
8264    /* nodes need to be in the same document */
8265    if (ancestor->doc != node->doc) return(0);
8266    /* avoid searching if ancestor or node is the root node */
8267    if (ancestor == (xmlNodePtr) node->doc) return(1);
8268    if (node == (xmlNodePtr) ancestor->doc) return(0);
8269    while (node->parent != NULL) {
8270        if (node->parent == ancestor)
8271            return(1);
8272	node = node->parent;
8273    }
8274    return(0);
8275}
8276
8277/**
8278 * xmlXPathNextPreceding:
8279 * @ctxt:  the XPath Parser context
8280 * @cur:  the current node in the traversal
8281 *
8282 * Traversal function for the "preceding" direction
8283 * the preceding axis contains all nodes in the same document as the context
8284 * node that are before the context node in document order, excluding any
8285 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8286 * ordered in reverse document order
8287 *
8288 * Returns the next element following that axis
8289 */
8290xmlNodePtr
8291xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8292{
8293    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8294    if (cur == NULL) {
8295        cur = ctxt->context->node;
8296        if (cur->type == XML_NAMESPACE_DECL)
8297            return(NULL);
8298        if (cur->type == XML_ATTRIBUTE_NODE)
8299            return(cur->parent);
8300    }
8301    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8302	return (NULL);
8303    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8304	cur = cur->prev;
8305    do {
8306        if (cur->prev != NULL) {
8307            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8308            return (cur);
8309        }
8310
8311        cur = cur->parent;
8312        if (cur == NULL)
8313            return (NULL);
8314        if (cur == ctxt->context->doc->children)
8315            return (NULL);
8316    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8317    return (cur);
8318}
8319
8320/**
8321 * xmlXPathNextPrecedingInternal:
8322 * @ctxt:  the XPath Parser context
8323 * @cur:  the current node in the traversal
8324 *
8325 * Traversal function for the "preceding" direction
8326 * the preceding axis contains all nodes in the same document as the context
8327 * node that are before the context node in document order, excluding any
8328 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8329 * ordered in reverse document order
8330 * This is a faster implementation but internal only since it requires a
8331 * state kept in the parser context: ctxt->ancestor.
8332 *
8333 * Returns the next element following that axis
8334 */
8335static xmlNodePtr
8336xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8337                              xmlNodePtr cur)
8338{
8339    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8340    if (cur == NULL) {
8341        cur = ctxt->context->node;
8342        if (cur == NULL)
8343            return (NULL);
8344        if (cur->type == XML_NAMESPACE_DECL)
8345            return (NULL);
8346        ctxt->ancestor = cur->parent;
8347    }
8348    if (cur->type == XML_NAMESPACE_DECL)
8349        return(NULL);
8350    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8351	cur = cur->prev;
8352    while (cur->prev == NULL) {
8353        cur = cur->parent;
8354        if (cur == NULL)
8355            return (NULL);
8356        if (cur == ctxt->context->doc->children)
8357            return (NULL);
8358        if (cur != ctxt->ancestor)
8359            return (cur);
8360        ctxt->ancestor = cur->parent;
8361    }
8362    cur = cur->prev;
8363    while (cur->last != NULL)
8364        cur = cur->last;
8365    return (cur);
8366}
8367
8368/**
8369 * xmlXPathNextNamespace:
8370 * @ctxt:  the XPath Parser context
8371 * @cur:  the current attribute in the traversal
8372 *
8373 * Traversal function for the "namespace" direction
8374 * the namespace axis contains the namespace nodes of the context node;
8375 * the order of nodes on this axis is implementation-defined; the axis will
8376 * be empty unless the context node is an element
8377 *
8378 * We keep the XML namespace node at the end of the list.
8379 *
8380 * Returns the next element following that axis
8381 */
8382xmlNodePtr
8383xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8384    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8385    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8386    if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8387        if (ctxt->context->tmpNsList != NULL)
8388	    xmlFree(ctxt->context->tmpNsList);
8389	ctxt->context->tmpNsList =
8390	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8391	ctxt->context->tmpNsNr = 0;
8392	if (ctxt->context->tmpNsList != NULL) {
8393	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8394		ctxt->context->tmpNsNr++;
8395	    }
8396	}
8397	return((xmlNodePtr) xmlXPathXMLNamespace);
8398    }
8399    if (ctxt->context->tmpNsNr > 0) {
8400	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8401    } else {
8402	if (ctxt->context->tmpNsList != NULL)
8403	    xmlFree(ctxt->context->tmpNsList);
8404	ctxt->context->tmpNsList = NULL;
8405	return(NULL);
8406    }
8407}
8408
8409/**
8410 * xmlXPathNextAttribute:
8411 * @ctxt:  the XPath Parser context
8412 * @cur:  the current attribute in the traversal
8413 *
8414 * Traversal function for the "attribute" direction
8415 * TODO: support DTD inherited default attributes
8416 *
8417 * Returns the next element following that axis
8418 */
8419xmlNodePtr
8420xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8421    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8422    if (ctxt->context->node == NULL)
8423	return(NULL);
8424    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8425	return(NULL);
8426    if (cur == NULL) {
8427        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8428	    return(NULL);
8429        return((xmlNodePtr)ctxt->context->node->properties);
8430    }
8431    return((xmlNodePtr)cur->next);
8432}
8433
8434/************************************************************************
8435 *									*
8436 *		NodeTest Functions					*
8437 *									*
8438 ************************************************************************/
8439
8440#define IS_FUNCTION			200
8441
8442
8443/************************************************************************
8444 *									*
8445 *		Implicit tree core function library			*
8446 *									*
8447 ************************************************************************/
8448
8449/**
8450 * xmlXPathRoot:
8451 * @ctxt:  the XPath Parser context
8452 *
8453 * Initialize the context to the root of the document
8454 */
8455void
8456xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8457    if ((ctxt == NULL) || (ctxt->context == NULL))
8458	return;
8459    ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8460    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8461	ctxt->context->node));
8462}
8463
8464/************************************************************************
8465 *									*
8466 *		The explicit core function library			*
8467 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8468 *									*
8469 ************************************************************************/
8470
8471
8472/**
8473 * xmlXPathLastFunction:
8474 * @ctxt:  the XPath Parser context
8475 * @nargs:  the number of arguments
8476 *
8477 * Implement the last() XPath function
8478 *    number last()
8479 * The last function returns the number of nodes in the context node list.
8480 */
8481void
8482xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8483    CHECK_ARITY(0);
8484    if (ctxt->context->contextSize >= 0) {
8485	valuePush(ctxt,
8486	    xmlXPathCacheNewFloat(ctxt->context,
8487		(double) ctxt->context->contextSize));
8488#ifdef DEBUG_EXPR
8489	xmlGenericError(xmlGenericErrorContext,
8490		"last() : %d\n", ctxt->context->contextSize);
8491#endif
8492    } else {
8493	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8494    }
8495}
8496
8497/**
8498 * xmlXPathPositionFunction:
8499 * @ctxt:  the XPath Parser context
8500 * @nargs:  the number of arguments
8501 *
8502 * Implement the position() XPath function
8503 *    number position()
8504 * The position function returns the position of the context node in the
8505 * context node list. The first position is 1, and so the last position
8506 * will be equal to last().
8507 */
8508void
8509xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8510    CHECK_ARITY(0);
8511    if (ctxt->context->proximityPosition >= 0) {
8512	valuePush(ctxt,
8513	      xmlXPathCacheNewFloat(ctxt->context,
8514		(double) ctxt->context->proximityPosition));
8515#ifdef DEBUG_EXPR
8516	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8517		ctxt->context->proximityPosition);
8518#endif
8519    } else {
8520	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8521    }
8522}
8523
8524/**
8525 * xmlXPathCountFunction:
8526 * @ctxt:  the XPath Parser context
8527 * @nargs:  the number of arguments
8528 *
8529 * Implement the count() XPath function
8530 *    number count(node-set)
8531 */
8532void
8533xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8534    xmlXPathObjectPtr cur;
8535
8536    CHECK_ARITY(1);
8537    if ((ctxt->value == NULL) ||
8538	((ctxt->value->type != XPATH_NODESET) &&
8539	 (ctxt->value->type != XPATH_XSLT_TREE)))
8540	XP_ERROR(XPATH_INVALID_TYPE);
8541    cur = valuePop(ctxt);
8542
8543    if ((cur == NULL) || (cur->nodesetval == NULL))
8544	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8545    else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8546	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8547	    (double) cur->nodesetval->nodeNr));
8548    } else {
8549	if ((cur->nodesetval->nodeNr != 1) ||
8550	    (cur->nodesetval->nodeTab == NULL)) {
8551	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8552	} else {
8553	    xmlNodePtr tmp;
8554	    int i = 0;
8555
8556	    tmp = cur->nodesetval->nodeTab[0];
8557	    if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8558		tmp = tmp->children;
8559		while (tmp != NULL) {
8560		    tmp = tmp->next;
8561		    i++;
8562		}
8563	    }
8564	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8565	}
8566    }
8567    xmlXPathReleaseObject(ctxt->context, cur);
8568}
8569
8570/**
8571 * xmlXPathGetElementsByIds:
8572 * @doc:  the document
8573 * @ids:  a whitespace separated list of IDs
8574 *
8575 * Selects elements by their unique ID.
8576 *
8577 * Returns a node-set of selected elements.
8578 */
8579static xmlNodeSetPtr
8580xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8581    xmlNodeSetPtr ret;
8582    const xmlChar *cur = ids;
8583    xmlChar *ID;
8584    xmlAttrPtr attr;
8585    xmlNodePtr elem = NULL;
8586
8587    if (ids == NULL) return(NULL);
8588
8589    ret = xmlXPathNodeSetCreate(NULL);
8590    if (ret == NULL)
8591        return(ret);
8592
8593    while (IS_BLANK_CH(*cur)) cur++;
8594    while (*cur != 0) {
8595	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8596	    cur++;
8597
8598        ID = xmlStrndup(ids, cur - ids);
8599	if (ID != NULL) {
8600	    /*
8601	     * We used to check the fact that the value passed
8602	     * was an NCName, but this generated much troubles for
8603	     * me and Aleksey Sanin, people blatantly violated that
8604	     * constaint, like Visa3D spec.
8605	     * if (xmlValidateNCName(ID, 1) == 0)
8606	     */
8607	    attr = xmlGetID(doc, ID);
8608	    if (attr != NULL) {
8609		if (attr->type == XML_ATTRIBUTE_NODE)
8610		    elem = attr->parent;
8611		else if (attr->type == XML_ELEMENT_NODE)
8612		    elem = (xmlNodePtr) attr;
8613		else
8614		    elem = NULL;
8615		if (elem != NULL)
8616		    xmlXPathNodeSetAdd(ret, elem);
8617	    }
8618	    xmlFree(ID);
8619	}
8620
8621	while (IS_BLANK_CH(*cur)) cur++;
8622	ids = cur;
8623    }
8624    return(ret);
8625}
8626
8627/**
8628 * xmlXPathIdFunction:
8629 * @ctxt:  the XPath Parser context
8630 * @nargs:  the number of arguments
8631 *
8632 * Implement the id() XPath function
8633 *    node-set id(object)
8634 * The id function selects elements by their unique ID
8635 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8636 * then the result is the union of the result of applying id to the
8637 * string value of each of the nodes in the argument node-set. When the
8638 * argument to id is of any other type, the argument is converted to a
8639 * string as if by a call to the string function; the string is split
8640 * into a whitespace-separated list of tokens (whitespace is any sequence
8641 * of characters matching the production S); the result is a node-set
8642 * containing the elements in the same document as the context node that
8643 * have a unique ID equal to any of the tokens in the list.
8644 */
8645void
8646xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8647    xmlChar *tokens;
8648    xmlNodeSetPtr ret;
8649    xmlXPathObjectPtr obj;
8650
8651    CHECK_ARITY(1);
8652    obj = valuePop(ctxt);
8653    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8654    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8655	xmlNodeSetPtr ns;
8656	int i;
8657
8658	ret = xmlXPathNodeSetCreate(NULL);
8659        /*
8660         * FIXME -- in an out-of-memory condition this will behave badly.
8661         * The solution is not clear -- we already popped an item from
8662         * ctxt, so the object is in a corrupt state.
8663         */
8664
8665	if (obj->nodesetval != NULL) {
8666	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8667		tokens =
8668		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8669		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8670		ret = xmlXPathNodeSetMerge(ret, ns);
8671		xmlXPathFreeNodeSet(ns);
8672		if (tokens != NULL)
8673		    xmlFree(tokens);
8674	    }
8675	}
8676	xmlXPathReleaseObject(ctxt->context, obj);
8677	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8678	return;
8679    }
8680    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8681    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8682    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8683    xmlXPathReleaseObject(ctxt->context, obj);
8684    return;
8685}
8686
8687/**
8688 * xmlXPathLocalNameFunction:
8689 * @ctxt:  the XPath Parser context
8690 * @nargs:  the number of arguments
8691 *
8692 * Implement the local-name() XPath function
8693 *    string local-name(node-set?)
8694 * The local-name function returns a string containing the local part
8695 * of the name of the node in the argument node-set that is first in
8696 * document order. If the node-set is empty or the first node has no
8697 * name, an empty string is returned. If the argument is omitted it
8698 * defaults to the context node.
8699 */
8700void
8701xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8702    xmlXPathObjectPtr cur;
8703
8704    if (ctxt == NULL) return;
8705
8706    if (nargs == 0) {
8707	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8708	    ctxt->context->node));
8709	nargs = 1;
8710    }
8711
8712    CHECK_ARITY(1);
8713    if ((ctxt->value == NULL) ||
8714	((ctxt->value->type != XPATH_NODESET) &&
8715	 (ctxt->value->type != XPATH_XSLT_TREE)))
8716	XP_ERROR(XPATH_INVALID_TYPE);
8717    cur = valuePop(ctxt);
8718
8719    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8720	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8721    } else {
8722	int i = 0; /* Should be first in document order !!!!! */
8723	switch (cur->nodesetval->nodeTab[i]->type) {
8724	case XML_ELEMENT_NODE:
8725	case XML_ATTRIBUTE_NODE:
8726	case XML_PI_NODE:
8727	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8728		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8729	    else
8730		valuePush(ctxt,
8731		      xmlXPathCacheNewString(ctxt->context,
8732			cur->nodesetval->nodeTab[i]->name));
8733	    break;
8734	case XML_NAMESPACE_DECL:
8735	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8736			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8737	    break;
8738	default:
8739	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8740	}
8741    }
8742    xmlXPathReleaseObject(ctxt->context, cur);
8743}
8744
8745/**
8746 * xmlXPathNamespaceURIFunction:
8747 * @ctxt:  the XPath Parser context
8748 * @nargs:  the number of arguments
8749 *
8750 * Implement the namespace-uri() XPath function
8751 *    string namespace-uri(node-set?)
8752 * The namespace-uri function returns a string containing the
8753 * namespace URI of the expanded name of the node in the argument
8754 * node-set that is first in document order. If the node-set is empty,
8755 * the first node has no name, or the expanded name has no namespace
8756 * URI, an empty string is returned. If the argument is omitted it
8757 * defaults to the context node.
8758 */
8759void
8760xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8761    xmlXPathObjectPtr cur;
8762
8763    if (ctxt == NULL) return;
8764
8765    if (nargs == 0) {
8766	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8767	    ctxt->context->node));
8768	nargs = 1;
8769    }
8770    CHECK_ARITY(1);
8771    if ((ctxt->value == NULL) ||
8772	((ctxt->value->type != XPATH_NODESET) &&
8773	 (ctxt->value->type != XPATH_XSLT_TREE)))
8774	XP_ERROR(XPATH_INVALID_TYPE);
8775    cur = valuePop(ctxt);
8776
8777    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8778	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8779    } else {
8780	int i = 0; /* Should be first in document order !!!!! */
8781	switch (cur->nodesetval->nodeTab[i]->type) {
8782	case XML_ELEMENT_NODE:
8783	case XML_ATTRIBUTE_NODE:
8784	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8785		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8786	    else
8787		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8788			  cur->nodesetval->nodeTab[i]->ns->href));
8789	    break;
8790	default:
8791	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8792	}
8793    }
8794    xmlXPathReleaseObject(ctxt->context, cur);
8795}
8796
8797/**
8798 * xmlXPathNameFunction:
8799 * @ctxt:  the XPath Parser context
8800 * @nargs:  the number of arguments
8801 *
8802 * Implement the name() XPath function
8803 *    string name(node-set?)
8804 * The name function returns a string containing a QName representing
8805 * the name of the node in the argument node-set that is first in document
8806 * order. The QName must represent the name with respect to the namespace
8807 * declarations in effect on the node whose name is being represented.
8808 * Typically, this will be the form in which the name occurred in the XML
8809 * source. This need not be the case if there are namespace declarations
8810 * in effect on the node that associate multiple prefixes with the same
8811 * namespace. However, an implementation may include information about
8812 * the original prefix in its representation of nodes; in this case, an
8813 * implementation can ensure that the returned string is always the same
8814 * as the QName used in the XML source. If the argument it omitted it
8815 * defaults to the context node.
8816 * Libxml keep the original prefix so the "real qualified name" used is
8817 * returned.
8818 */
8819static void
8820xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8821{
8822    xmlXPathObjectPtr cur;
8823
8824    if (nargs == 0) {
8825	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8826	    ctxt->context->node));
8827        nargs = 1;
8828    }
8829
8830    CHECK_ARITY(1);
8831    if ((ctxt->value == NULL) ||
8832        ((ctxt->value->type != XPATH_NODESET) &&
8833         (ctxt->value->type != XPATH_XSLT_TREE)))
8834        XP_ERROR(XPATH_INVALID_TYPE);
8835    cur = valuePop(ctxt);
8836
8837    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8838        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8839    } else {
8840        int i = 0;              /* Should be first in document order !!!!! */
8841
8842        switch (cur->nodesetval->nodeTab[i]->type) {
8843            case XML_ELEMENT_NODE:
8844            case XML_ATTRIBUTE_NODE:
8845		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8846		    valuePush(ctxt,
8847			xmlXPathCacheNewCString(ctxt->context, ""));
8848		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8849                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8850		    valuePush(ctxt,
8851		        xmlXPathCacheNewString(ctxt->context,
8852			    cur->nodesetval->nodeTab[i]->name));
8853		} else {
8854		    xmlChar *fullname;
8855
8856		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8857				     cur->nodesetval->nodeTab[i]->ns->prefix,
8858				     NULL, 0);
8859		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8860			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8861		    if (fullname == NULL) {
8862			XP_ERROR(XPATH_MEMORY_ERROR);
8863		    }
8864		    valuePush(ctxt, xmlXPathCacheWrapString(
8865			ctxt->context, fullname));
8866                }
8867                break;
8868            default:
8869		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8870		    cur->nodesetval->nodeTab[i]));
8871                xmlXPathLocalNameFunction(ctxt, 1);
8872        }
8873    }
8874    xmlXPathReleaseObject(ctxt->context, cur);
8875}
8876
8877
8878/**
8879 * xmlXPathStringFunction:
8880 * @ctxt:  the XPath Parser context
8881 * @nargs:  the number of arguments
8882 *
8883 * Implement the string() XPath function
8884 *    string string(object?)
8885 * The string function converts an object to a string as follows:
8886 *    - A node-set is converted to a string by returning the value of
8887 *      the node in the node-set that is first in document order.
8888 *      If the node-set is empty, an empty string is returned.
8889 *    - A number is converted to a string as follows
8890 *      + NaN is converted to the string NaN
8891 *      + positive zero is converted to the string 0
8892 *      + negative zero is converted to the string 0
8893 *      + positive infinity is converted to the string Infinity
8894 *      + negative infinity is converted to the string -Infinity
8895 *      + if the number is an integer, the number is represented in
8896 *        decimal form as a Number with no decimal point and no leading
8897 *        zeros, preceded by a minus sign (-) if the number is negative
8898 *      + otherwise, the number is represented in decimal form as a
8899 *        Number including a decimal point with at least one digit
8900 *        before the decimal point and at least one digit after the
8901 *        decimal point, preceded by a minus sign (-) if the number
8902 *        is negative; there must be no leading zeros before the decimal
8903 *        point apart possibly from the one required digit immediately
8904 *        before the decimal point; beyond the one required digit
8905 *        after the decimal point there must be as many, but only as
8906 *        many, more digits as are needed to uniquely distinguish the
8907 *        number from all other IEEE 754 numeric values.
8908 *    - The boolean false value is converted to the string false.
8909 *      The boolean true value is converted to the string true.
8910 *
8911 * If the argument is omitted, it defaults to a node-set with the
8912 * context node as its only member.
8913 */
8914void
8915xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8916    xmlXPathObjectPtr cur;
8917
8918    if (ctxt == NULL) return;
8919    if (nargs == 0) {
8920    valuePush(ctxt,
8921	xmlXPathCacheWrapString(ctxt->context,
8922	    xmlXPathCastNodeToString(ctxt->context->node)));
8923	return;
8924    }
8925
8926    CHECK_ARITY(1);
8927    cur = valuePop(ctxt);
8928    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8929    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8930}
8931
8932/**
8933 * xmlXPathStringLengthFunction:
8934 * @ctxt:  the XPath Parser context
8935 * @nargs:  the number of arguments
8936 *
8937 * Implement the string-length() XPath function
8938 *    number string-length(string?)
8939 * The string-length returns the number of characters in the string
8940 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8941 * the context node converted to a string, in other words the value
8942 * of the context node.
8943 */
8944void
8945xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8946    xmlXPathObjectPtr cur;
8947
8948    if (nargs == 0) {
8949        if ((ctxt == NULL) || (ctxt->context == NULL))
8950	    return;
8951	if (ctxt->context->node == NULL) {
8952	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8953	} else {
8954	    xmlChar *content;
8955
8956	    content = xmlXPathCastNodeToString(ctxt->context->node);
8957	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8958		xmlUTF8Strlen(content)));
8959	    xmlFree(content);
8960	}
8961	return;
8962    }
8963    CHECK_ARITY(1);
8964    CAST_TO_STRING;
8965    CHECK_TYPE(XPATH_STRING);
8966    cur = valuePop(ctxt);
8967    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8968	xmlUTF8Strlen(cur->stringval)));
8969    xmlXPathReleaseObject(ctxt->context, cur);
8970}
8971
8972/**
8973 * xmlXPathConcatFunction:
8974 * @ctxt:  the XPath Parser context
8975 * @nargs:  the number of arguments
8976 *
8977 * Implement the concat() XPath function
8978 *    string concat(string, string, string*)
8979 * The concat function returns the concatenation of its arguments.
8980 */
8981void
8982xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8983    xmlXPathObjectPtr cur, newobj;
8984    xmlChar *tmp;
8985
8986    if (ctxt == NULL) return;
8987    if (nargs < 2) {
8988	CHECK_ARITY(2);
8989    }
8990
8991    CAST_TO_STRING;
8992    cur = valuePop(ctxt);
8993    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8994	xmlXPathReleaseObject(ctxt->context, cur);
8995	return;
8996    }
8997    nargs--;
8998
8999    while (nargs > 0) {
9000	CAST_TO_STRING;
9001	newobj = valuePop(ctxt);
9002	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9003	    xmlXPathReleaseObject(ctxt->context, newobj);
9004	    xmlXPathReleaseObject(ctxt->context, cur);
9005	    XP_ERROR(XPATH_INVALID_TYPE);
9006	}
9007	tmp = xmlStrcat(newobj->stringval, cur->stringval);
9008	newobj->stringval = cur->stringval;
9009	cur->stringval = tmp;
9010	xmlXPathReleaseObject(ctxt->context, newobj);
9011	nargs--;
9012    }
9013    valuePush(ctxt, cur);
9014}
9015
9016/**
9017 * xmlXPathContainsFunction:
9018 * @ctxt:  the XPath Parser context
9019 * @nargs:  the number of arguments
9020 *
9021 * Implement the contains() XPath function
9022 *    boolean contains(string, string)
9023 * The contains function returns true if the first argument string
9024 * contains the second argument string, and otherwise returns false.
9025 */
9026void
9027xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9028    xmlXPathObjectPtr hay, needle;
9029
9030    CHECK_ARITY(2);
9031    CAST_TO_STRING;
9032    CHECK_TYPE(XPATH_STRING);
9033    needle = valuePop(ctxt);
9034    CAST_TO_STRING;
9035    hay = valuePop(ctxt);
9036
9037    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9038	xmlXPathReleaseObject(ctxt->context, hay);
9039	xmlXPathReleaseObject(ctxt->context, needle);
9040	XP_ERROR(XPATH_INVALID_TYPE);
9041    }
9042    if (xmlStrstr(hay->stringval, needle->stringval))
9043	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9044    else
9045	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9046    xmlXPathReleaseObject(ctxt->context, hay);
9047    xmlXPathReleaseObject(ctxt->context, needle);
9048}
9049
9050/**
9051 * xmlXPathStartsWithFunction:
9052 * @ctxt:  the XPath Parser context
9053 * @nargs:  the number of arguments
9054 *
9055 * Implement the starts-with() XPath function
9056 *    boolean starts-with(string, string)
9057 * The starts-with function returns true if the first argument string
9058 * starts with the second argument string, and otherwise returns false.
9059 */
9060void
9061xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9062    xmlXPathObjectPtr hay, needle;
9063    int n;
9064
9065    CHECK_ARITY(2);
9066    CAST_TO_STRING;
9067    CHECK_TYPE(XPATH_STRING);
9068    needle = valuePop(ctxt);
9069    CAST_TO_STRING;
9070    hay = valuePop(ctxt);
9071
9072    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9073	xmlXPathReleaseObject(ctxt->context, hay);
9074	xmlXPathReleaseObject(ctxt->context, needle);
9075	XP_ERROR(XPATH_INVALID_TYPE);
9076    }
9077    n = xmlStrlen(needle->stringval);
9078    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9079        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9080    else
9081        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9082    xmlXPathReleaseObject(ctxt->context, hay);
9083    xmlXPathReleaseObject(ctxt->context, needle);
9084}
9085
9086/**
9087 * xmlXPathSubstringFunction:
9088 * @ctxt:  the XPath Parser context
9089 * @nargs:  the number of arguments
9090 *
9091 * Implement the substring() XPath function
9092 *    string substring(string, number, number?)
9093 * The substring function returns the substring of the first argument
9094 * starting at the position specified in the second argument with
9095 * length specified in the third argument. For example,
9096 * substring("12345",2,3) returns "234". If the third argument is not
9097 * specified, it returns the substring starting at the position specified
9098 * in the second argument and continuing to the end of the string. For
9099 * example, substring("12345",2) returns "2345".  More precisely, each
9100 * character in the string (see [3.6 Strings]) is considered to have a
9101 * numeric position: the position of the first character is 1, the position
9102 * of the second character is 2 and so on. The returned substring contains
9103 * those characters for which the position of the character is greater than
9104 * or equal to the second argument and, if the third argument is specified,
9105 * less than the sum of the second and third arguments; the comparisons
9106 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9107 *  - substring("12345", 1.5, 2.6) returns "234"
9108 *  - substring("12345", 0, 3) returns "12"
9109 *  - substring("12345", 0 div 0, 3) returns ""
9110 *  - substring("12345", 1, 0 div 0) returns ""
9111 *  - substring("12345", -42, 1 div 0) returns "12345"
9112 *  - substring("12345", -1 div 0, 1 div 0) returns ""
9113 */
9114void
9115xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9116    xmlXPathObjectPtr str, start, len;
9117    double le=0, in;
9118    int i, l, m;
9119    xmlChar *ret;
9120
9121    if (nargs < 2) {
9122	CHECK_ARITY(2);
9123    }
9124    if (nargs > 3) {
9125	CHECK_ARITY(3);
9126    }
9127    /*
9128     * take care of possible last (position) argument
9129    */
9130    if (nargs == 3) {
9131	CAST_TO_NUMBER;
9132	CHECK_TYPE(XPATH_NUMBER);
9133	len = valuePop(ctxt);
9134	le = len->floatval;
9135	xmlXPathReleaseObject(ctxt->context, len);
9136    }
9137
9138    CAST_TO_NUMBER;
9139    CHECK_TYPE(XPATH_NUMBER);
9140    start = valuePop(ctxt);
9141    in = start->floatval;
9142    xmlXPathReleaseObject(ctxt->context, start);
9143    CAST_TO_STRING;
9144    CHECK_TYPE(XPATH_STRING);
9145    str = valuePop(ctxt);
9146    m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9147
9148    /*
9149     * If last pos not present, calculate last position
9150    */
9151    if (nargs != 3) {
9152	le = (double)m;
9153	if (in < 1.0)
9154	    in = 1.0;
9155    }
9156
9157    /* Need to check for the special cases where either
9158     * the index is NaN, the length is NaN, or both
9159     * arguments are infinity (relying on Inf + -Inf = NaN)
9160     */
9161    if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9162        /*
9163         * To meet the requirements of the spec, the arguments
9164	 * must be converted to integer format before
9165	 * initial index calculations are done
9166         *
9167         * First we go to integer form, rounding up
9168	 * and checking for special cases
9169         */
9170        i = (int) in;
9171        if (((double)i)+0.5 <= in) i++;
9172
9173	if (xmlXPathIsInf(le) == 1) {
9174	    l = m;
9175	    if (i < 1)
9176		i = 1;
9177	}
9178	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9179	    l = 0;
9180	else {
9181	    l = (int) le;
9182	    if (((double)l)+0.5 <= le) l++;
9183	}
9184
9185	/* Now we normalize inidices */
9186        i -= 1;
9187        l += i;
9188        if (i < 0)
9189            i = 0;
9190        if (l > m)
9191            l = m;
9192
9193        /* number of chars to copy */
9194        l -= i;
9195
9196        ret = xmlUTF8Strsub(str->stringval, i, l);
9197    }
9198    else {
9199        ret = NULL;
9200    }
9201    if (ret == NULL)
9202	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9203    else {
9204	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9205	xmlFree(ret);
9206    }
9207    xmlXPathReleaseObject(ctxt->context, str);
9208}
9209
9210/**
9211 * xmlXPathSubstringBeforeFunction:
9212 * @ctxt:  the XPath Parser context
9213 * @nargs:  the number of arguments
9214 *
9215 * Implement the substring-before() XPath function
9216 *    string substring-before(string, string)
9217 * The substring-before function returns the substring of the first
9218 * argument string that precedes the first occurrence of the second
9219 * argument string in the first argument string, or the empty string
9220 * if the first argument string does not contain the second argument
9221 * string. For example, substring-before("1999/04/01","/") returns 1999.
9222 */
9223void
9224xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9225  xmlXPathObjectPtr str;
9226  xmlXPathObjectPtr find;
9227  xmlBufPtr target;
9228  const xmlChar *point;
9229  int offset;
9230
9231  CHECK_ARITY(2);
9232  CAST_TO_STRING;
9233  find = valuePop(ctxt);
9234  CAST_TO_STRING;
9235  str = valuePop(ctxt);
9236
9237  target = xmlBufCreate();
9238  if (target) {
9239    point = xmlStrstr(str->stringval, find->stringval);
9240    if (point) {
9241      offset = (int)(point - str->stringval);
9242      xmlBufAdd(target, str->stringval, offset);
9243    }
9244    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9245	xmlBufContent(target)));
9246    xmlBufFree(target);
9247  }
9248  xmlXPathReleaseObject(ctxt->context, str);
9249  xmlXPathReleaseObject(ctxt->context, find);
9250}
9251
9252/**
9253 * xmlXPathSubstringAfterFunction:
9254 * @ctxt:  the XPath Parser context
9255 * @nargs:  the number of arguments
9256 *
9257 * Implement the substring-after() XPath function
9258 *    string substring-after(string, string)
9259 * The substring-after function returns the substring of the first
9260 * argument string that follows the first occurrence of the second
9261 * argument string in the first argument string, or the empty stringi
9262 * if the first argument string does not contain the second argument
9263 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9264 * and substring-after("1999/04/01","19") returns 99/04/01.
9265 */
9266void
9267xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9268  xmlXPathObjectPtr str;
9269  xmlXPathObjectPtr find;
9270  xmlBufPtr target;
9271  const xmlChar *point;
9272  int offset;
9273
9274  CHECK_ARITY(2);
9275  CAST_TO_STRING;
9276  find = valuePop(ctxt);
9277  CAST_TO_STRING;
9278  str = valuePop(ctxt);
9279
9280  target = xmlBufCreate();
9281  if (target) {
9282    point = xmlStrstr(str->stringval, find->stringval);
9283    if (point) {
9284      offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9285      xmlBufAdd(target, &str->stringval[offset],
9286		   xmlStrlen(str->stringval) - offset);
9287    }
9288    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9289	xmlBufContent(target)));
9290    xmlBufFree(target);
9291  }
9292  xmlXPathReleaseObject(ctxt->context, str);
9293  xmlXPathReleaseObject(ctxt->context, find);
9294}
9295
9296/**
9297 * xmlXPathNormalizeFunction:
9298 * @ctxt:  the XPath Parser context
9299 * @nargs:  the number of arguments
9300 *
9301 * Implement the normalize-space() XPath function
9302 *    string normalize-space(string?)
9303 * The normalize-space function returns the argument string with white
9304 * space normalized by stripping leading and trailing whitespace
9305 * and replacing sequences of whitespace characters by a single
9306 * space. Whitespace characters are the same allowed by the S production
9307 * in XML. If the argument is omitted, it defaults to the context
9308 * node converted to a string, in other words the value of the context node.
9309 */
9310void
9311xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9312  xmlXPathObjectPtr obj = NULL;
9313  xmlChar *source = NULL;
9314  xmlBufPtr target;
9315  xmlChar blank;
9316
9317  if (ctxt == NULL) return;
9318  if (nargs == 0) {
9319    /* Use current context node */
9320      valuePush(ctxt,
9321	  xmlXPathCacheWrapString(ctxt->context,
9322	    xmlXPathCastNodeToString(ctxt->context->node)));
9323    nargs = 1;
9324  }
9325
9326  CHECK_ARITY(1);
9327  CAST_TO_STRING;
9328  CHECK_TYPE(XPATH_STRING);
9329  obj = valuePop(ctxt);
9330  source = obj->stringval;
9331
9332  target = xmlBufCreate();
9333  if (target && source) {
9334
9335    /* Skip leading whitespaces */
9336    while (IS_BLANK_CH(*source))
9337      source++;
9338
9339    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9340    blank = 0;
9341    while (*source) {
9342      if (IS_BLANK_CH(*source)) {
9343	blank = 0x20;
9344      } else {
9345	if (blank) {
9346	  xmlBufAdd(target, &blank, 1);
9347	  blank = 0;
9348	}
9349	xmlBufAdd(target, source, 1);
9350      }
9351      source++;
9352    }
9353    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9354	xmlBufContent(target)));
9355    xmlBufFree(target);
9356  }
9357  xmlXPathReleaseObject(ctxt->context, obj);
9358}
9359
9360/**
9361 * xmlXPathTranslateFunction:
9362 * @ctxt:  the XPath Parser context
9363 * @nargs:  the number of arguments
9364 *
9365 * Implement the translate() XPath function
9366 *    string translate(string, string, string)
9367 * The translate function returns the first argument string with
9368 * occurrences of characters in the second argument string replaced
9369 * by the character at the corresponding position in the third argument
9370 * string. For example, translate("bar","abc","ABC") returns the string
9371 * BAr. If there is a character in the second argument string with no
9372 * character at a corresponding position in the third argument string
9373 * (because the second argument string is longer than the third argument
9374 * string), then occurrences of that character in the first argument
9375 * string are removed. For example, translate("--aaa--","abc-","ABC")
9376 * returns "AAA". If a character occurs more than once in second
9377 * argument string, then the first occurrence determines the replacement
9378 * character. If the third argument string is longer than the second
9379 * argument string, then excess characters are ignored.
9380 */
9381void
9382xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9383    xmlXPathObjectPtr str;
9384    xmlXPathObjectPtr from;
9385    xmlXPathObjectPtr to;
9386    xmlBufPtr target;
9387    int offset, max;
9388    xmlChar ch;
9389    const xmlChar *point;
9390    xmlChar *cptr;
9391
9392    CHECK_ARITY(3);
9393
9394    CAST_TO_STRING;
9395    to = valuePop(ctxt);
9396    CAST_TO_STRING;
9397    from = valuePop(ctxt);
9398    CAST_TO_STRING;
9399    str = valuePop(ctxt);
9400
9401    target = xmlBufCreate();
9402    if (target) {
9403	max = xmlUTF8Strlen(to->stringval);
9404	for (cptr = str->stringval; (ch=*cptr); ) {
9405	    offset = xmlUTF8Strloc(from->stringval, cptr);
9406	    if (offset >= 0) {
9407		if (offset < max) {
9408		    point = xmlUTF8Strpos(to->stringval, offset);
9409		    if (point)
9410			xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9411		}
9412	    } else
9413		xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9414
9415	    /* Step to next character in input */
9416	    cptr++;
9417	    if ( ch & 0x80 ) {
9418		/* if not simple ascii, verify proper format */
9419		if ( (ch & 0xc0) != 0xc0 ) {
9420		    xmlGenericError(xmlGenericErrorContext,
9421			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
9422                    /* not asserting an XPath error is probably better */
9423		    break;
9424		}
9425		/* then skip over remaining bytes for this char */
9426		while ( (ch <<= 1) & 0x80 )
9427		    if ( (*cptr++ & 0xc0) != 0x80 ) {
9428			xmlGenericError(xmlGenericErrorContext,
9429			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9430                        /* not asserting an XPath error is probably better */
9431			break;
9432		    }
9433		if (ch & 0x80) /* must have had error encountered */
9434		    break;
9435	    }
9436	}
9437    }
9438    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9439	xmlBufContent(target)));
9440    xmlBufFree(target);
9441    xmlXPathReleaseObject(ctxt->context, str);
9442    xmlXPathReleaseObject(ctxt->context, from);
9443    xmlXPathReleaseObject(ctxt->context, to);
9444}
9445
9446/**
9447 * xmlXPathBooleanFunction:
9448 * @ctxt:  the XPath Parser context
9449 * @nargs:  the number of arguments
9450 *
9451 * Implement the boolean() XPath function
9452 *    boolean boolean(object)
9453 * The boolean function converts its argument to a boolean as follows:
9454 *    - a number is true if and only if it is neither positive or
9455 *      negative zero nor NaN
9456 *    - a node-set is true if and only if it is non-empty
9457 *    - a string is true if and only if its length is non-zero
9458 */
9459void
9460xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9461    xmlXPathObjectPtr cur;
9462
9463    CHECK_ARITY(1);
9464    cur = valuePop(ctxt);
9465    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9466    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9467    valuePush(ctxt, cur);
9468}
9469
9470/**
9471 * xmlXPathNotFunction:
9472 * @ctxt:  the XPath Parser context
9473 * @nargs:  the number of arguments
9474 *
9475 * Implement the not() XPath function
9476 *    boolean not(boolean)
9477 * The not function returns true if its argument is false,
9478 * and false otherwise.
9479 */
9480void
9481xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9482    CHECK_ARITY(1);
9483    CAST_TO_BOOLEAN;
9484    CHECK_TYPE(XPATH_BOOLEAN);
9485    ctxt->value->boolval = ! ctxt->value->boolval;
9486}
9487
9488/**
9489 * xmlXPathTrueFunction:
9490 * @ctxt:  the XPath Parser context
9491 * @nargs:  the number of arguments
9492 *
9493 * Implement the true() XPath function
9494 *    boolean true()
9495 */
9496void
9497xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9498    CHECK_ARITY(0);
9499    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9500}
9501
9502/**
9503 * xmlXPathFalseFunction:
9504 * @ctxt:  the XPath Parser context
9505 * @nargs:  the number of arguments
9506 *
9507 * Implement the false() XPath function
9508 *    boolean false()
9509 */
9510void
9511xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9512    CHECK_ARITY(0);
9513    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9514}
9515
9516/**
9517 * xmlXPathLangFunction:
9518 * @ctxt:  the XPath Parser context
9519 * @nargs:  the number of arguments
9520 *
9521 * Implement the lang() XPath function
9522 *    boolean lang(string)
9523 * The lang function returns true or false depending on whether the
9524 * language of the context node as specified by xml:lang attributes
9525 * is the same as or is a sublanguage of the language specified by
9526 * the argument string. The language of the context node is determined
9527 * by the value of the xml:lang attribute on the context node, or, if
9528 * the context node has no xml:lang attribute, by the value of the
9529 * xml:lang attribute on the nearest ancestor of the context node that
9530 * has an xml:lang attribute. If there is no such attribute, then lang
9531 * returns false. If there is such an attribute, then lang returns
9532 * true if the attribute value is equal to the argument ignoring case,
9533 * or if there is some suffix starting with - such that the attribute
9534 * value is equal to the argument ignoring that suffix of the attribute
9535 * value and ignoring case.
9536 */
9537void
9538xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9539    xmlXPathObjectPtr val = NULL;
9540    const xmlChar *theLang = NULL;
9541    const xmlChar *lang;
9542    int ret = 0;
9543    int i;
9544
9545    CHECK_ARITY(1);
9546    CAST_TO_STRING;
9547    CHECK_TYPE(XPATH_STRING);
9548    val = valuePop(ctxt);
9549    lang = val->stringval;
9550    theLang = xmlNodeGetLang(ctxt->context->node);
9551    if ((theLang != NULL) && (lang != NULL)) {
9552        for (i = 0;lang[i] != 0;i++)
9553	    if (toupper(lang[i]) != toupper(theLang[i]))
9554	        goto not_equal;
9555	if ((theLang[i] == 0) || (theLang[i] == '-'))
9556	    ret = 1;
9557    }
9558not_equal:
9559    if (theLang != NULL)
9560	xmlFree((void *)theLang);
9561
9562    xmlXPathReleaseObject(ctxt->context, val);
9563    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9564}
9565
9566/**
9567 * xmlXPathNumberFunction:
9568 * @ctxt:  the XPath Parser context
9569 * @nargs:  the number of arguments
9570 *
9571 * Implement the number() XPath function
9572 *    number number(object?)
9573 */
9574void
9575xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9576    xmlXPathObjectPtr cur;
9577    double res;
9578
9579    if (ctxt == NULL) return;
9580    if (nargs == 0) {
9581	if (ctxt->context->node == NULL) {
9582	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9583	} else {
9584	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9585
9586	    res = xmlXPathStringEvalNumber(content);
9587	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9588	    xmlFree(content);
9589	}
9590	return;
9591    }
9592
9593    CHECK_ARITY(1);
9594    cur = valuePop(ctxt);
9595    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9596}
9597
9598/**
9599 * xmlXPathSumFunction:
9600 * @ctxt:  the XPath Parser context
9601 * @nargs:  the number of arguments
9602 *
9603 * Implement the sum() XPath function
9604 *    number sum(node-set)
9605 * The sum function returns the sum of the values of the nodes in
9606 * the argument node-set.
9607 */
9608void
9609xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9610    xmlXPathObjectPtr cur;
9611    int i;
9612    double res = 0.0;
9613
9614    CHECK_ARITY(1);
9615    if ((ctxt->value == NULL) ||
9616	((ctxt->value->type != XPATH_NODESET) &&
9617	 (ctxt->value->type != XPATH_XSLT_TREE)))
9618	XP_ERROR(XPATH_INVALID_TYPE);
9619    cur = valuePop(ctxt);
9620
9621    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9622	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9623	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9624	}
9625    }
9626    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9627    xmlXPathReleaseObject(ctxt->context, cur);
9628}
9629
9630/*
9631 * To assure working code on multiple platforms, we want to only depend
9632 * upon the characteristic truncation of converting a floating point value
9633 * to an integer.  Unfortunately, because of the different storage sizes
9634 * of our internal floating point value (double) and integer (int), we
9635 * can't directly convert (see bug 301162).  This macro is a messy
9636 * 'workaround'
9637 */
9638#define XTRUNC(f, v)            \
9639    f = fmod((v), INT_MAX);     \
9640    f = (v) - (f) + (double)((int)(f));
9641
9642/**
9643 * xmlXPathFloorFunction:
9644 * @ctxt:  the XPath Parser context
9645 * @nargs:  the number of arguments
9646 *
9647 * Implement the floor() XPath function
9648 *    number floor(number)
9649 * The floor function returns the largest (closest to positive infinity)
9650 * number that is not greater than the argument and that is an integer.
9651 */
9652void
9653xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9654    double f;
9655
9656    CHECK_ARITY(1);
9657    CAST_TO_NUMBER;
9658    CHECK_TYPE(XPATH_NUMBER);
9659
9660    XTRUNC(f, ctxt->value->floatval);
9661    if (f != ctxt->value->floatval) {
9662	if (ctxt->value->floatval > 0)
9663	    ctxt->value->floatval = f;
9664	else
9665	    ctxt->value->floatval = f - 1;
9666    }
9667}
9668
9669/**
9670 * xmlXPathCeilingFunction:
9671 * @ctxt:  the XPath Parser context
9672 * @nargs:  the number of arguments
9673 *
9674 * Implement the ceiling() XPath function
9675 *    number ceiling(number)
9676 * The ceiling function returns the smallest (closest to negative infinity)
9677 * number that is not less than the argument and that is an integer.
9678 */
9679void
9680xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9681    double f;
9682
9683    CHECK_ARITY(1);
9684    CAST_TO_NUMBER;
9685    CHECK_TYPE(XPATH_NUMBER);
9686
9687#if 0
9688    ctxt->value->floatval = ceil(ctxt->value->floatval);
9689#else
9690    XTRUNC(f, ctxt->value->floatval);
9691    if (f != ctxt->value->floatval) {
9692	if (ctxt->value->floatval > 0)
9693	    ctxt->value->floatval = f + 1;
9694	else {
9695	    if (ctxt->value->floatval < 0 && f == 0)
9696	        ctxt->value->floatval = xmlXPathNZERO;
9697	    else
9698	        ctxt->value->floatval = f;
9699	}
9700
9701    }
9702#endif
9703}
9704
9705/**
9706 * xmlXPathRoundFunction:
9707 * @ctxt:  the XPath Parser context
9708 * @nargs:  the number of arguments
9709 *
9710 * Implement the round() XPath function
9711 *    number round(number)
9712 * The round function returns the number that is closest to the
9713 * argument and that is an integer. If there are two such numbers,
9714 * then the one that is even is returned.
9715 */
9716void
9717xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9718    double f;
9719
9720    CHECK_ARITY(1);
9721    CAST_TO_NUMBER;
9722    CHECK_TYPE(XPATH_NUMBER);
9723
9724    if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9725	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9726	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9727	(ctxt->value->floatval == 0.0))
9728	return;
9729
9730    XTRUNC(f, ctxt->value->floatval);
9731    if (ctxt->value->floatval < 0) {
9732	if (ctxt->value->floatval < f - 0.5)
9733	    ctxt->value->floatval = f - 1;
9734	else
9735	    ctxt->value->floatval = f;
9736	if (ctxt->value->floatval == 0)
9737	    ctxt->value->floatval = xmlXPathNZERO;
9738    } else {
9739	if (ctxt->value->floatval < f + 0.5)
9740	    ctxt->value->floatval = f;
9741	else
9742	    ctxt->value->floatval = f + 1;
9743    }
9744}
9745
9746/************************************************************************
9747 *									*
9748 *			The Parser					*
9749 *									*
9750 ************************************************************************/
9751
9752/*
9753 * a few forward declarations since we use a recursive call based
9754 * implementation.
9755 */
9756static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9757static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9758static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9759static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9760static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9761	                                  int qualified);
9762
9763/**
9764 * xmlXPathCurrentChar:
9765 * @ctxt:  the XPath parser context
9766 * @cur:  pointer to the beginning of the char
9767 * @len:  pointer to the length of the char read
9768 *
9769 * The current char value, if using UTF-8 this may actually span multiple
9770 * bytes in the input buffer.
9771 *
9772 * Returns the current char value and its length
9773 */
9774
9775static int
9776xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9777    unsigned char c;
9778    unsigned int val;
9779    const xmlChar *cur;
9780
9781    if (ctxt == NULL)
9782	return(0);
9783    cur = ctxt->cur;
9784
9785    /*
9786     * We are supposed to handle UTF8, check it's valid
9787     * From rfc2044: encoding of the Unicode values on UTF-8:
9788     *
9789     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9790     * 0000 0000-0000 007F   0xxxxxxx
9791     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9792     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9793     *
9794     * Check for the 0x110000 limit too
9795     */
9796    c = *cur;
9797    if (c & 0x80) {
9798	if ((cur[1] & 0xc0) != 0x80)
9799	    goto encoding_error;
9800	if ((c & 0xe0) == 0xe0) {
9801
9802	    if ((cur[2] & 0xc0) != 0x80)
9803		goto encoding_error;
9804	    if ((c & 0xf0) == 0xf0) {
9805		if (((c & 0xf8) != 0xf0) ||
9806		    ((cur[3] & 0xc0) != 0x80))
9807		    goto encoding_error;
9808		/* 4-byte code */
9809		*len = 4;
9810		val = (cur[0] & 0x7) << 18;
9811		val |= (cur[1] & 0x3f) << 12;
9812		val |= (cur[2] & 0x3f) << 6;
9813		val |= cur[3] & 0x3f;
9814	    } else {
9815	      /* 3-byte code */
9816		*len = 3;
9817		val = (cur[0] & 0xf) << 12;
9818		val |= (cur[1] & 0x3f) << 6;
9819		val |= cur[2] & 0x3f;
9820	    }
9821	} else {
9822	  /* 2-byte code */
9823	    *len = 2;
9824	    val = (cur[0] & 0x1f) << 6;
9825	    val |= cur[1] & 0x3f;
9826	}
9827	if (!IS_CHAR(val)) {
9828	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9829	}
9830	return(val);
9831    } else {
9832	/* 1-byte code */
9833	*len = 1;
9834	return((int) *cur);
9835    }
9836encoding_error:
9837    /*
9838     * If we detect an UTF8 error that probably means that the
9839     * input encoding didn't get properly advertised in the
9840     * declaration header. Report the error and switch the encoding
9841     * to ISO-Latin-1 (if you don't like this policy, just declare the
9842     * encoding !)
9843     */
9844    *len = 0;
9845    XP_ERROR0(XPATH_ENCODING_ERROR);
9846}
9847
9848/**
9849 * xmlXPathParseNCName:
9850 * @ctxt:  the XPath Parser context
9851 *
9852 * parse an XML namespace non qualified name.
9853 *
9854 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9855 *
9856 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9857 *                       CombiningChar | Extender
9858 *
9859 * Returns the namespace name or NULL
9860 */
9861
9862xmlChar *
9863xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9864    const xmlChar *in;
9865    xmlChar *ret;
9866    int count = 0;
9867
9868    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9869    /*
9870     * Accelerator for simple ASCII names
9871     */
9872    in = ctxt->cur;
9873    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9874	((*in >= 0x41) && (*in <= 0x5A)) ||
9875	(*in == '_')) {
9876	in++;
9877	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9878	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9879	       ((*in >= 0x30) && (*in <= 0x39)) ||
9880	       (*in == '_') || (*in == '.') ||
9881	       (*in == '-'))
9882	    in++;
9883	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9884            (*in == '[') || (*in == ']') || (*in == ':') ||
9885            (*in == '@') || (*in == '*')) {
9886	    count = in - ctxt->cur;
9887	    if (count == 0)
9888		return(NULL);
9889	    ret = xmlStrndup(ctxt->cur, count);
9890	    ctxt->cur = in;
9891	    return(ret);
9892	}
9893    }
9894    return(xmlXPathParseNameComplex(ctxt, 0));
9895}
9896
9897
9898/**
9899 * xmlXPathParseQName:
9900 * @ctxt:  the XPath Parser context
9901 * @prefix:  a xmlChar **
9902 *
9903 * parse an XML qualified name
9904 *
9905 * [NS 5] QName ::= (Prefix ':')? LocalPart
9906 *
9907 * [NS 6] Prefix ::= NCName
9908 *
9909 * [NS 7] LocalPart ::= NCName
9910 *
9911 * Returns the function returns the local part, and prefix is updated
9912 *   to get the Prefix if any.
9913 */
9914
9915static xmlChar *
9916xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9917    xmlChar *ret = NULL;
9918
9919    *prefix = NULL;
9920    ret = xmlXPathParseNCName(ctxt);
9921    if (ret && CUR == ':') {
9922        *prefix = ret;
9923	NEXT;
9924	ret = xmlXPathParseNCName(ctxt);
9925    }
9926    return(ret);
9927}
9928
9929/**
9930 * xmlXPathParseName:
9931 * @ctxt:  the XPath Parser context
9932 *
9933 * parse an XML name
9934 *
9935 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9936 *                  CombiningChar | Extender
9937 *
9938 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9939 *
9940 * Returns the namespace name or NULL
9941 */
9942
9943xmlChar *
9944xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9945    const xmlChar *in;
9946    xmlChar *ret;
9947    size_t count = 0;
9948
9949    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9950    /*
9951     * Accelerator for simple ASCII names
9952     */
9953    in = ctxt->cur;
9954    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9955	((*in >= 0x41) && (*in <= 0x5A)) ||
9956	(*in == '_') || (*in == ':')) {
9957	in++;
9958	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9959	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9960	       ((*in >= 0x30) && (*in <= 0x39)) ||
9961	       (*in == '_') || (*in == '-') ||
9962	       (*in == ':') || (*in == '.'))
9963	    in++;
9964	if ((*in > 0) && (*in < 0x80)) {
9965	    count = in - ctxt->cur;
9966            if (count > XML_MAX_NAME_LENGTH) {
9967                ctxt->cur = in;
9968                XP_ERRORNULL(XPATH_EXPR_ERROR);
9969            }
9970	    ret = xmlStrndup(ctxt->cur, count);
9971	    ctxt->cur = in;
9972	    return(ret);
9973	}
9974    }
9975    return(xmlXPathParseNameComplex(ctxt, 1));
9976}
9977
9978static xmlChar *
9979xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9980    xmlChar buf[XML_MAX_NAMELEN + 5];
9981    int len = 0, l;
9982    int c;
9983
9984    /*
9985     * Handler for more complex cases
9986     */
9987    c = CUR_CHAR(l);
9988    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9989        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9990        (c == '*') || /* accelerators */
9991	(!IS_LETTER(c) && (c != '_') &&
9992         ((qualified) && (c != ':')))) {
9993	return(NULL);
9994    }
9995
9996    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9997	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9998            (c == '.') || (c == '-') ||
9999	    (c == '_') || ((qualified) && (c == ':')) ||
10000	    (IS_COMBINING(c)) ||
10001	    (IS_EXTENDER(c)))) {
10002	COPY_BUF(l,buf,len,c);
10003	NEXTL(l);
10004	c = CUR_CHAR(l);
10005	if (len >= XML_MAX_NAMELEN) {
10006	    /*
10007	     * Okay someone managed to make a huge name, so he's ready to pay
10008	     * for the processing speed.
10009	     */
10010	    xmlChar *buffer;
10011	    int max = len * 2;
10012
10013            if (len > XML_MAX_NAME_LENGTH) {
10014                XP_ERRORNULL(XPATH_EXPR_ERROR);
10015            }
10016	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
10017	    if (buffer == NULL) {
10018		XP_ERRORNULL(XPATH_MEMORY_ERROR);
10019	    }
10020	    memcpy(buffer, buf, len);
10021	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10022		   (c == '.') || (c == '-') ||
10023		   (c == '_') || ((qualified) && (c == ':')) ||
10024		   (IS_COMBINING(c)) ||
10025		   (IS_EXTENDER(c))) {
10026		if (len + 10 > max) {
10027                    if (max > XML_MAX_NAME_LENGTH) {
10028                        XP_ERRORNULL(XPATH_EXPR_ERROR);
10029                    }
10030		    max *= 2;
10031		    buffer = (xmlChar *) xmlRealloc(buffer,
10032			                            max * sizeof(xmlChar));
10033		    if (buffer == NULL) {
10034			XP_ERRORNULL(XPATH_MEMORY_ERROR);
10035		    }
10036		}
10037		COPY_BUF(l,buffer,len,c);
10038		NEXTL(l);
10039		c = CUR_CHAR(l);
10040	    }
10041	    buffer[len] = 0;
10042	    return(buffer);
10043	}
10044    }
10045    if (len == 0)
10046	return(NULL);
10047    return(xmlStrndup(buf, len));
10048}
10049
10050#define MAX_FRAC 20
10051
10052/*
10053 * These are used as divisors for the fractional part of a number.
10054 * Since the table includes 1.0 (representing '0' fractional digits),
10055 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
10056 */
10057static double my_pow10[MAX_FRAC+1] = {
10058    1.0, 10.0, 100.0, 1000.0, 10000.0,
10059    100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
10060    10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
10061    100000000000000.0,
10062    1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
10063    1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
10064};
10065
10066/**
10067 * xmlXPathStringEvalNumber:
10068 * @str:  A string to scan
10069 *
10070 *  [30a]  Float  ::= Number ('e' Digits?)?
10071 *
10072 *  [30]   Number ::=   Digits ('.' Digits?)?
10073 *                    | '.' Digits
10074 *  [31]   Digits ::=   [0-9]+
10075 *
10076 * Compile a Number in the string
10077 * In complement of the Number expression, this function also handles
10078 * negative values : '-' Number.
10079 *
10080 * Returns the double value.
10081 */
10082double
10083xmlXPathStringEvalNumber(const xmlChar *str) {
10084    const xmlChar *cur = str;
10085    double ret;
10086    int ok = 0;
10087    int isneg = 0;
10088    int exponent = 0;
10089    int is_exponent_negative = 0;
10090#ifdef __GNUC__
10091    unsigned long tmp = 0;
10092    double temp;
10093#endif
10094    if (cur == NULL) return(0);
10095    while (IS_BLANK_CH(*cur)) cur++;
10096    if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10097        return(xmlXPathNAN);
10098    }
10099    if (*cur == '-') {
10100	isneg = 1;
10101	cur++;
10102    }
10103
10104#ifdef __GNUC__
10105    /*
10106     * tmp/temp is a workaround against a gcc compiler bug
10107     * http://veillard.com/gcc.bug
10108     */
10109    ret = 0;
10110    while ((*cur >= '0') && (*cur <= '9')) {
10111	ret = ret * 10;
10112	tmp = (*cur - '0');
10113	ok = 1;
10114	cur++;
10115	temp = (double) tmp;
10116	ret = ret + temp;
10117    }
10118#else
10119    ret = 0;
10120    while ((*cur >= '0') && (*cur <= '9')) {
10121	ret = ret * 10 + (*cur - '0');
10122	ok = 1;
10123	cur++;
10124    }
10125#endif
10126
10127    if (*cur == '.') {
10128	int v, frac = 0;
10129	double fraction = 0;
10130
10131        cur++;
10132	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10133	    return(xmlXPathNAN);
10134	}
10135	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10136	    v = (*cur - '0');
10137	    fraction = fraction * 10 + v;
10138	    frac = frac + 1;
10139	    cur++;
10140	}
10141	fraction /= my_pow10[frac];
10142	ret = ret + fraction;
10143	while ((*cur >= '0') && (*cur <= '9'))
10144	    cur++;
10145    }
10146    if ((*cur == 'e') || (*cur == 'E')) {
10147      cur++;
10148      if (*cur == '-') {
10149	is_exponent_negative = 1;
10150	cur++;
10151      } else if (*cur == '+') {
10152        cur++;
10153      }
10154      while ((*cur >= '0') && (*cur <= '9')) {
10155	exponent = exponent * 10 + (*cur - '0');
10156	cur++;
10157      }
10158    }
10159    while (IS_BLANK_CH(*cur)) cur++;
10160    if (*cur != 0) return(xmlXPathNAN);
10161    if (isneg) ret = -ret;
10162    if (is_exponent_negative) exponent = -exponent;
10163    ret *= pow(10.0, (double)exponent);
10164    return(ret);
10165}
10166
10167/**
10168 * xmlXPathCompNumber:
10169 * @ctxt:  the XPath Parser context
10170 *
10171 *  [30]   Number ::=   Digits ('.' Digits?)?
10172 *                    | '.' Digits
10173 *  [31]   Digits ::=   [0-9]+
10174 *
10175 * Compile a Number, then push it on the stack
10176 *
10177 */
10178static void
10179xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10180{
10181    double ret = 0.0;
10182    int ok = 0;
10183    int exponent = 0;
10184    int is_exponent_negative = 0;
10185#ifdef __GNUC__
10186    unsigned long tmp = 0;
10187    double temp;
10188#endif
10189
10190    CHECK_ERROR;
10191    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10192        XP_ERROR(XPATH_NUMBER_ERROR);
10193    }
10194#ifdef __GNUC__
10195    /*
10196     * tmp/temp is a workaround against a gcc compiler bug
10197     * http://veillard.com/gcc.bug
10198     */
10199    ret = 0;
10200    while ((CUR >= '0') && (CUR <= '9')) {
10201	ret = ret * 10;
10202	tmp = (CUR - '0');
10203        ok = 1;
10204        NEXT;
10205	temp = (double) tmp;
10206	ret = ret + temp;
10207    }
10208#else
10209    ret = 0;
10210    while ((CUR >= '0') && (CUR <= '9')) {
10211	ret = ret * 10 + (CUR - '0');
10212	ok = 1;
10213	NEXT;
10214    }
10215#endif
10216    if (CUR == '.') {
10217	int v, frac = 0;
10218	double fraction = 0;
10219
10220        NEXT;
10221        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10222            XP_ERROR(XPATH_NUMBER_ERROR);
10223        }
10224        while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10225	    v = (CUR - '0');
10226	    fraction = fraction * 10 + v;
10227	    frac = frac + 1;
10228            NEXT;
10229        }
10230        fraction /= my_pow10[frac];
10231        ret = ret + fraction;
10232        while ((CUR >= '0') && (CUR <= '9'))
10233            NEXT;
10234    }
10235    if ((CUR == 'e') || (CUR == 'E')) {
10236        NEXT;
10237        if (CUR == '-') {
10238            is_exponent_negative = 1;
10239            NEXT;
10240        } else if (CUR == '+') {
10241	    NEXT;
10242	}
10243        while ((CUR >= '0') && (CUR <= '9')) {
10244            exponent = exponent * 10 + (CUR - '0');
10245            NEXT;
10246        }
10247        if (is_exponent_negative)
10248            exponent = -exponent;
10249        ret *= pow(10.0, (double) exponent);
10250    }
10251    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10252                   xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10253}
10254
10255/**
10256 * xmlXPathParseLiteral:
10257 * @ctxt:  the XPath Parser context
10258 *
10259 * Parse a Literal
10260 *
10261 *  [29]   Literal ::=   '"' [^"]* '"'
10262 *                    | "'" [^']* "'"
10263 *
10264 * Returns the value found or NULL in case of error
10265 */
10266static xmlChar *
10267xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10268    const xmlChar *q;
10269    xmlChar *ret = NULL;
10270
10271    if (CUR == '"') {
10272        NEXT;
10273	q = CUR_PTR;
10274	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10275	    NEXT;
10276	if (!IS_CHAR_CH(CUR)) {
10277	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10278	} else {
10279	    ret = xmlStrndup(q, CUR_PTR - q);
10280	    NEXT;
10281        }
10282    } else if (CUR == '\'') {
10283        NEXT;
10284	q = CUR_PTR;
10285	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10286	    NEXT;
10287	if (!IS_CHAR_CH(CUR)) {
10288	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10289	} else {
10290	    ret = xmlStrndup(q, CUR_PTR - q);
10291	    NEXT;
10292        }
10293    } else {
10294	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10295    }
10296    return(ret);
10297}
10298
10299/**
10300 * xmlXPathCompLiteral:
10301 * @ctxt:  the XPath Parser context
10302 *
10303 * Parse a Literal and push it on the stack.
10304 *
10305 *  [29]   Literal ::=   '"' [^"]* '"'
10306 *                    | "'" [^']* "'"
10307 *
10308 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10309 */
10310static void
10311xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10312    const xmlChar *q;
10313    xmlChar *ret = NULL;
10314
10315    if (CUR == '"') {
10316        NEXT;
10317	q = CUR_PTR;
10318	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10319	    NEXT;
10320	if (!IS_CHAR_CH(CUR)) {
10321	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10322	} else {
10323	    ret = xmlStrndup(q, CUR_PTR - q);
10324	    NEXT;
10325        }
10326    } else if (CUR == '\'') {
10327        NEXT;
10328	q = CUR_PTR;
10329	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10330	    NEXT;
10331	if (!IS_CHAR_CH(CUR)) {
10332	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10333	} else {
10334	    ret = xmlStrndup(q, CUR_PTR - q);
10335	    NEXT;
10336        }
10337    } else {
10338	XP_ERROR(XPATH_START_LITERAL_ERROR);
10339    }
10340    if (ret == NULL) return;
10341    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10342	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
10343    xmlFree(ret);
10344}
10345
10346/**
10347 * xmlXPathCompVariableReference:
10348 * @ctxt:  the XPath Parser context
10349 *
10350 * Parse a VariableReference, evaluate it and push it on the stack.
10351 *
10352 * The variable bindings consist of a mapping from variable names
10353 * to variable values. The value of a variable is an object, which can be
10354 * of any of the types that are possible for the value of an expression,
10355 * and may also be of additional types not specified here.
10356 *
10357 * Early evaluation is possible since:
10358 * The variable bindings [...] used to evaluate a subexpression are
10359 * always the same as those used to evaluate the containing expression.
10360 *
10361 *  [36]   VariableReference ::=   '$' QName
10362 */
10363static void
10364xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10365    xmlChar *name;
10366    xmlChar *prefix;
10367
10368    SKIP_BLANKS;
10369    if (CUR != '$') {
10370	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10371    }
10372    NEXT;
10373    name = xmlXPathParseQName(ctxt, &prefix);
10374    if (name == NULL) {
10375	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10376    }
10377    ctxt->comp->last = -1;
10378    PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10379	           name, prefix);
10380    SKIP_BLANKS;
10381    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10382	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10383    }
10384}
10385
10386/**
10387 * xmlXPathIsNodeType:
10388 * @name:  a name string
10389 *
10390 * Is the name given a NodeType one.
10391 *
10392 *  [38]   NodeType ::=   'comment'
10393 *                    | 'text'
10394 *                    | 'processing-instruction'
10395 *                    | 'node'
10396 *
10397 * Returns 1 if true 0 otherwise
10398 */
10399int
10400xmlXPathIsNodeType(const xmlChar *name) {
10401    if (name == NULL)
10402	return(0);
10403
10404    if (xmlStrEqual(name, BAD_CAST "node"))
10405	return(1);
10406    if (xmlStrEqual(name, BAD_CAST "text"))
10407	return(1);
10408    if (xmlStrEqual(name, BAD_CAST "comment"))
10409	return(1);
10410    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10411	return(1);
10412    return(0);
10413}
10414
10415/**
10416 * xmlXPathCompFunctionCall:
10417 * @ctxt:  the XPath Parser context
10418 *
10419 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10420 *  [17]   Argument ::=   Expr
10421 *
10422 * Compile a function call, the evaluation of all arguments are
10423 * pushed on the stack
10424 */
10425static void
10426xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10427    xmlChar *name;
10428    xmlChar *prefix;
10429    int nbargs = 0;
10430    int sort = 1;
10431
10432    name = xmlXPathParseQName(ctxt, &prefix);
10433    if (name == NULL) {
10434	xmlFree(prefix);
10435	XP_ERROR(XPATH_EXPR_ERROR);
10436    }
10437    SKIP_BLANKS;
10438#ifdef DEBUG_EXPR
10439    if (prefix == NULL)
10440	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10441			name);
10442    else
10443	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10444			prefix, name);
10445#endif
10446
10447    if (CUR != '(') {
10448	XP_ERROR(XPATH_EXPR_ERROR);
10449    }
10450    NEXT;
10451    SKIP_BLANKS;
10452
10453    /*
10454    * Optimization for count(): we don't need the node-set to be sorted.
10455    */
10456    if ((prefix == NULL) && (name[0] == 'c') &&
10457	xmlStrEqual(name, BAD_CAST "count"))
10458    {
10459	sort = 0;
10460    }
10461    ctxt->comp->last = -1;
10462    if (CUR != ')') {
10463	while (CUR != 0) {
10464	    int op1 = ctxt->comp->last;
10465	    ctxt->comp->last = -1;
10466	    xmlXPathCompileExpr(ctxt, sort);
10467	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10468		xmlFree(name);
10469		xmlFree(prefix);
10470		return;
10471	    }
10472	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10473	    nbargs++;
10474	    if (CUR == ')') break;
10475	    if (CUR != ',') {
10476		XP_ERROR(XPATH_EXPR_ERROR);
10477	    }
10478	    NEXT;
10479	    SKIP_BLANKS;
10480	}
10481    }
10482    PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10483	           name, prefix);
10484    NEXT;
10485    SKIP_BLANKS;
10486}
10487
10488/**
10489 * xmlXPathCompPrimaryExpr:
10490 * @ctxt:  the XPath Parser context
10491 *
10492 *  [15]   PrimaryExpr ::=   VariableReference
10493 *                | '(' Expr ')'
10494 *                | Literal
10495 *                | Number
10496 *                | FunctionCall
10497 *
10498 * Compile a primary expression.
10499 */
10500static void
10501xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10502    SKIP_BLANKS;
10503    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10504    else if (CUR == '(') {
10505	NEXT;
10506	SKIP_BLANKS;
10507	xmlXPathCompileExpr(ctxt, 1);
10508	CHECK_ERROR;
10509	if (CUR != ')') {
10510	    XP_ERROR(XPATH_EXPR_ERROR);
10511	}
10512	NEXT;
10513	SKIP_BLANKS;
10514    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10515	xmlXPathCompNumber(ctxt);
10516    } else if ((CUR == '\'') || (CUR == '"')) {
10517	xmlXPathCompLiteral(ctxt);
10518    } else {
10519	xmlXPathCompFunctionCall(ctxt);
10520    }
10521    SKIP_BLANKS;
10522}
10523
10524/**
10525 * xmlXPathCompFilterExpr:
10526 * @ctxt:  the XPath Parser context
10527 *
10528 *  [20]   FilterExpr ::=   PrimaryExpr
10529 *               | FilterExpr Predicate
10530 *
10531 * Compile a filter expression.
10532 * Square brackets are used to filter expressions in the same way that
10533 * they are used in location paths. It is an error if the expression to
10534 * be filtered does not evaluate to a node-set. The context node list
10535 * used for evaluating the expression in square brackets is the node-set
10536 * to be filtered listed in document order.
10537 */
10538
10539static void
10540xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10541    xmlXPathCompPrimaryExpr(ctxt);
10542    CHECK_ERROR;
10543    SKIP_BLANKS;
10544
10545    while (CUR == '[') {
10546	xmlXPathCompPredicate(ctxt, 1);
10547	SKIP_BLANKS;
10548    }
10549
10550
10551}
10552
10553/**
10554 * xmlXPathScanName:
10555 * @ctxt:  the XPath Parser context
10556 *
10557 * Trickery: parse an XML name but without consuming the input flow
10558 * Needed to avoid insanity in the parser state.
10559 *
10560 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10561 *                  CombiningChar | Extender
10562 *
10563 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10564 *
10565 * [6] Names ::= Name (S Name)*
10566 *
10567 * Returns the Name parsed or NULL
10568 */
10569
10570static xmlChar *
10571xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10572    int len = 0, l;
10573    int c;
10574    const xmlChar *cur;
10575    xmlChar *ret;
10576
10577    cur = ctxt->cur;
10578
10579    c = CUR_CHAR(l);
10580    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10581	(!IS_LETTER(c) && (c != '_') &&
10582         (c != ':'))) {
10583	return(NULL);
10584    }
10585
10586    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10587	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10588            (c == '.') || (c == '-') ||
10589	    (c == '_') || (c == ':') ||
10590	    (IS_COMBINING(c)) ||
10591	    (IS_EXTENDER(c)))) {
10592	len += l;
10593	NEXTL(l);
10594	c = CUR_CHAR(l);
10595    }
10596    ret = xmlStrndup(cur, ctxt->cur - cur);
10597    ctxt->cur = cur;
10598    return(ret);
10599}
10600
10601/**
10602 * xmlXPathCompPathExpr:
10603 * @ctxt:  the XPath Parser context
10604 *
10605 *  [19]   PathExpr ::=   LocationPath
10606 *               | FilterExpr
10607 *               | FilterExpr '/' RelativeLocationPath
10608 *               | FilterExpr '//' RelativeLocationPath
10609 *
10610 * Compile a path expression.
10611 * The / operator and // operators combine an arbitrary expression
10612 * and a relative location path. It is an error if the expression
10613 * does not evaluate to a node-set.
10614 * The / operator does composition in the same way as when / is
10615 * used in a location path. As in location paths, // is short for
10616 * /descendant-or-self::node()/.
10617 */
10618
10619static void
10620xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10621    int lc = 1;           /* Should we branch to LocationPath ?         */
10622    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10623
10624    SKIP_BLANKS;
10625    if ((CUR == '$') || (CUR == '(') ||
10626	(IS_ASCII_DIGIT(CUR)) ||
10627        (CUR == '\'') || (CUR == '"') ||
10628	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10629	lc = 0;
10630    } else if (CUR == '*') {
10631	/* relative or absolute location path */
10632	lc = 1;
10633    } else if (CUR == '/') {
10634	/* relative or absolute location path */
10635	lc = 1;
10636    } else if (CUR == '@') {
10637	/* relative abbreviated attribute location path */
10638	lc = 1;
10639    } else if (CUR == '.') {
10640	/* relative abbreviated attribute location path */
10641	lc = 1;
10642    } else {
10643	/*
10644	 * Problem is finding if we have a name here whether it's:
10645	 *   - a nodetype
10646	 *   - a function call in which case it's followed by '('
10647	 *   - an axis in which case it's followed by ':'
10648	 *   - a element name
10649	 * We do an a priori analysis here rather than having to
10650	 * maintain parsed token content through the recursive function
10651	 * calls. This looks uglier but makes the code easier to
10652	 * read/write/debug.
10653	 */
10654	SKIP_BLANKS;
10655	name = xmlXPathScanName(ctxt);
10656	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10657#ifdef DEBUG_STEP
10658	    xmlGenericError(xmlGenericErrorContext,
10659		    "PathExpr: Axis\n");
10660#endif
10661	    lc = 1;
10662	    xmlFree(name);
10663	} else if (name != NULL) {
10664	    int len =xmlStrlen(name);
10665
10666
10667	    while (NXT(len) != 0) {
10668		if (NXT(len) == '/') {
10669		    /* element name */
10670#ifdef DEBUG_STEP
10671		    xmlGenericError(xmlGenericErrorContext,
10672			    "PathExpr: AbbrRelLocation\n");
10673#endif
10674		    lc = 1;
10675		    break;
10676		} else if (IS_BLANK_CH(NXT(len))) {
10677		    /* ignore blanks */
10678		    ;
10679		} else if (NXT(len) == ':') {
10680#ifdef DEBUG_STEP
10681		    xmlGenericError(xmlGenericErrorContext,
10682			    "PathExpr: AbbrRelLocation\n");
10683#endif
10684		    lc = 1;
10685		    break;
10686		} else if ((NXT(len) == '(')) {
10687		    /* Note Type or Function */
10688		    if (xmlXPathIsNodeType(name)) {
10689#ifdef DEBUG_STEP
10690		        xmlGenericError(xmlGenericErrorContext,
10691				"PathExpr: Type search\n");
10692#endif
10693			lc = 1;
10694		    } else {
10695#ifdef DEBUG_STEP
10696		        xmlGenericError(xmlGenericErrorContext,
10697				"PathExpr: function call\n");
10698#endif
10699			lc = 0;
10700		    }
10701                    break;
10702		} else if ((NXT(len) == '[')) {
10703		    /* element name */
10704#ifdef DEBUG_STEP
10705		    xmlGenericError(xmlGenericErrorContext,
10706			    "PathExpr: AbbrRelLocation\n");
10707#endif
10708		    lc = 1;
10709		    break;
10710		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10711			   (NXT(len) == '=')) {
10712		    lc = 1;
10713		    break;
10714		} else {
10715		    lc = 1;
10716		    break;
10717		}
10718		len++;
10719	    }
10720	    if (NXT(len) == 0) {
10721#ifdef DEBUG_STEP
10722		xmlGenericError(xmlGenericErrorContext,
10723			"PathExpr: AbbrRelLocation\n");
10724#endif
10725		/* element name */
10726		lc = 1;
10727	    }
10728	    xmlFree(name);
10729	} else {
10730	    /* make sure all cases are covered explicitly */
10731	    XP_ERROR(XPATH_EXPR_ERROR);
10732	}
10733    }
10734
10735    if (lc) {
10736	if (CUR == '/') {
10737	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10738	} else {
10739	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10740	}
10741	xmlXPathCompLocationPath(ctxt);
10742    } else {
10743	xmlXPathCompFilterExpr(ctxt);
10744	CHECK_ERROR;
10745	if ((CUR == '/') && (NXT(1) == '/')) {
10746	    SKIP(2);
10747	    SKIP_BLANKS;
10748
10749	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10750		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10751	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10752
10753	    xmlXPathCompRelativeLocationPath(ctxt);
10754	} else if (CUR == '/') {
10755	    xmlXPathCompRelativeLocationPath(ctxt);
10756	}
10757    }
10758    SKIP_BLANKS;
10759}
10760
10761/**
10762 * xmlXPathCompUnionExpr:
10763 * @ctxt:  the XPath Parser context
10764 *
10765 *  [18]   UnionExpr ::=   PathExpr
10766 *               | UnionExpr '|' PathExpr
10767 *
10768 * Compile an union expression.
10769 */
10770
10771static void
10772xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10773    xmlXPathCompPathExpr(ctxt);
10774    CHECK_ERROR;
10775    SKIP_BLANKS;
10776    while (CUR == '|') {
10777	int op1 = ctxt->comp->last;
10778	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10779
10780	NEXT;
10781	SKIP_BLANKS;
10782	xmlXPathCompPathExpr(ctxt);
10783
10784	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10785
10786	SKIP_BLANKS;
10787    }
10788}
10789
10790/**
10791 * xmlXPathCompUnaryExpr:
10792 * @ctxt:  the XPath Parser context
10793 *
10794 *  [27]   UnaryExpr ::=   UnionExpr
10795 *                   | '-' UnaryExpr
10796 *
10797 * Compile an unary expression.
10798 */
10799
10800static void
10801xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10802    int minus = 0;
10803    int found = 0;
10804
10805    SKIP_BLANKS;
10806    while (CUR == '-') {
10807        minus = 1 - minus;
10808	found = 1;
10809	NEXT;
10810	SKIP_BLANKS;
10811    }
10812
10813    xmlXPathCompUnionExpr(ctxt);
10814    CHECK_ERROR;
10815    if (found) {
10816	if (minus)
10817	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10818	else
10819	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10820    }
10821}
10822
10823/**
10824 * xmlXPathCompMultiplicativeExpr:
10825 * @ctxt:  the XPath Parser context
10826 *
10827 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10828 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10829 *                   | MultiplicativeExpr 'div' UnaryExpr
10830 *                   | MultiplicativeExpr 'mod' UnaryExpr
10831 *  [34]   MultiplyOperator ::=   '*'
10832 *
10833 * Compile an Additive expression.
10834 */
10835
10836static void
10837xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10838    xmlXPathCompUnaryExpr(ctxt);
10839    CHECK_ERROR;
10840    SKIP_BLANKS;
10841    while ((CUR == '*') ||
10842           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10843           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10844	int op = -1;
10845	int op1 = ctxt->comp->last;
10846
10847        if (CUR == '*') {
10848	    op = 0;
10849	    NEXT;
10850	} else if (CUR == 'd') {
10851	    op = 1;
10852	    SKIP(3);
10853	} else if (CUR == 'm') {
10854	    op = 2;
10855	    SKIP(3);
10856	}
10857	SKIP_BLANKS;
10858        xmlXPathCompUnaryExpr(ctxt);
10859	CHECK_ERROR;
10860	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10861	SKIP_BLANKS;
10862    }
10863}
10864
10865/**
10866 * xmlXPathCompAdditiveExpr:
10867 * @ctxt:  the XPath Parser context
10868 *
10869 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10870 *                   | AdditiveExpr '+' MultiplicativeExpr
10871 *                   | AdditiveExpr '-' MultiplicativeExpr
10872 *
10873 * Compile an Additive expression.
10874 */
10875
10876static void
10877xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10878
10879    xmlXPathCompMultiplicativeExpr(ctxt);
10880    CHECK_ERROR;
10881    SKIP_BLANKS;
10882    while ((CUR == '+') || (CUR == '-')) {
10883	int plus;
10884	int op1 = ctxt->comp->last;
10885
10886        if (CUR == '+') plus = 1;
10887	else plus = 0;
10888	NEXT;
10889	SKIP_BLANKS;
10890        xmlXPathCompMultiplicativeExpr(ctxt);
10891	CHECK_ERROR;
10892	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10893	SKIP_BLANKS;
10894    }
10895}
10896
10897/**
10898 * xmlXPathCompRelationalExpr:
10899 * @ctxt:  the XPath Parser context
10900 *
10901 *  [24]   RelationalExpr ::=   AdditiveExpr
10902 *                 | RelationalExpr '<' AdditiveExpr
10903 *                 | RelationalExpr '>' AdditiveExpr
10904 *                 | RelationalExpr '<=' AdditiveExpr
10905 *                 | RelationalExpr '>=' AdditiveExpr
10906 *
10907 *  A <= B > C is allowed ? Answer from James, yes with
10908 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10909 *  which is basically what got implemented.
10910 *
10911 * Compile a Relational expression, then push the result
10912 * on the stack
10913 */
10914
10915static void
10916xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10917    xmlXPathCompAdditiveExpr(ctxt);
10918    CHECK_ERROR;
10919    SKIP_BLANKS;
10920    while ((CUR == '<') ||
10921           (CUR == '>') ||
10922           ((CUR == '<') && (NXT(1) == '=')) ||
10923           ((CUR == '>') && (NXT(1) == '='))) {
10924	int inf, strict;
10925	int op1 = ctxt->comp->last;
10926
10927        if (CUR == '<') inf = 1;
10928	else inf = 0;
10929	if (NXT(1) == '=') strict = 0;
10930	else strict = 1;
10931	NEXT;
10932	if (!strict) NEXT;
10933	SKIP_BLANKS;
10934        xmlXPathCompAdditiveExpr(ctxt);
10935	CHECK_ERROR;
10936	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10937	SKIP_BLANKS;
10938    }
10939}
10940
10941/**
10942 * xmlXPathCompEqualityExpr:
10943 * @ctxt:  the XPath Parser context
10944 *
10945 *  [23]   EqualityExpr ::=   RelationalExpr
10946 *                 | EqualityExpr '=' RelationalExpr
10947 *                 | EqualityExpr '!=' RelationalExpr
10948 *
10949 *  A != B != C is allowed ? Answer from James, yes with
10950 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10951 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10952 *  which is basically what got implemented.
10953 *
10954 * Compile an Equality expression.
10955 *
10956 */
10957static void
10958xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10959    xmlXPathCompRelationalExpr(ctxt);
10960    CHECK_ERROR;
10961    SKIP_BLANKS;
10962    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10963	int eq;
10964	int op1 = ctxt->comp->last;
10965
10966        if (CUR == '=') eq = 1;
10967	else eq = 0;
10968	NEXT;
10969	if (!eq) NEXT;
10970	SKIP_BLANKS;
10971        xmlXPathCompRelationalExpr(ctxt);
10972	CHECK_ERROR;
10973	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10974	SKIP_BLANKS;
10975    }
10976}
10977
10978/**
10979 * xmlXPathCompAndExpr:
10980 * @ctxt:  the XPath Parser context
10981 *
10982 *  [22]   AndExpr ::=   EqualityExpr
10983 *                 | AndExpr 'and' EqualityExpr
10984 *
10985 * Compile an AND expression.
10986 *
10987 */
10988static void
10989xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10990    xmlXPathCompEqualityExpr(ctxt);
10991    CHECK_ERROR;
10992    SKIP_BLANKS;
10993    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10994	int op1 = ctxt->comp->last;
10995        SKIP(3);
10996	SKIP_BLANKS;
10997        xmlXPathCompEqualityExpr(ctxt);
10998	CHECK_ERROR;
10999	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
11000	SKIP_BLANKS;
11001    }
11002}
11003
11004/**
11005 * xmlXPathCompileExpr:
11006 * @ctxt:  the XPath Parser context
11007 *
11008 *  [14]   Expr ::=   OrExpr
11009 *  [21]   OrExpr ::=   AndExpr
11010 *                 | OrExpr 'or' AndExpr
11011 *
11012 * Parse and compile an expression
11013 */
11014static void
11015xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11016    xmlXPathCompAndExpr(ctxt);
11017    CHECK_ERROR;
11018    SKIP_BLANKS;
11019    while ((CUR == 'o') && (NXT(1) == 'r')) {
11020	int op1 = ctxt->comp->last;
11021        SKIP(2);
11022	SKIP_BLANKS;
11023        xmlXPathCompAndExpr(ctxt);
11024	CHECK_ERROR;
11025	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11026	SKIP_BLANKS;
11027    }
11028    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11029	/* more ops could be optimized too */
11030	/*
11031	* This is the main place to eliminate sorting for
11032	* operations which don't require a sorted node-set.
11033	* E.g. count().
11034	*/
11035	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11036    }
11037}
11038
11039/**
11040 * xmlXPathCompPredicate:
11041 * @ctxt:  the XPath Parser context
11042 * @filter:  act as a filter
11043 *
11044 *  [8]   Predicate ::=   '[' PredicateExpr ']'
11045 *  [9]   PredicateExpr ::=   Expr
11046 *
11047 * Compile a predicate expression
11048 */
11049static void
11050xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11051    int op1 = ctxt->comp->last;
11052
11053    SKIP_BLANKS;
11054    if (CUR != '[') {
11055	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11056    }
11057    NEXT;
11058    SKIP_BLANKS;
11059
11060    ctxt->comp->last = -1;
11061    /*
11062    * This call to xmlXPathCompileExpr() will deactivate sorting
11063    * of the predicate result.
11064    * TODO: Sorting is still activated for filters, since I'm not
11065    *  sure if needed. Normally sorting should not be needed, since
11066    *  a filter can only diminish the number of items in a sequence,
11067    *  but won't change its order; so if the initial sequence is sorted,
11068    *  subsequent sorting is not needed.
11069    */
11070    if (! filter)
11071	xmlXPathCompileExpr(ctxt, 0);
11072    else
11073	xmlXPathCompileExpr(ctxt, 1);
11074    CHECK_ERROR;
11075
11076    if (CUR != ']') {
11077	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11078    }
11079
11080    if (filter)
11081	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11082    else
11083	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11084
11085    NEXT;
11086    SKIP_BLANKS;
11087}
11088
11089/**
11090 * xmlXPathCompNodeTest:
11091 * @ctxt:  the XPath Parser context
11092 * @test:  pointer to a xmlXPathTestVal
11093 * @type:  pointer to a xmlXPathTypeVal
11094 * @prefix:  placeholder for a possible name prefix
11095 *
11096 * [7] NodeTest ::=   NameTest
11097 *		    | NodeType '(' ')'
11098 *		    | 'processing-instruction' '(' Literal ')'
11099 *
11100 * [37] NameTest ::=  '*'
11101 *		    | NCName ':' '*'
11102 *		    | QName
11103 * [38] NodeType ::= 'comment'
11104 *		   | 'text'
11105 *		   | 'processing-instruction'
11106 *		   | 'node'
11107 *
11108 * Returns the name found and updates @test, @type and @prefix appropriately
11109 */
11110static xmlChar *
11111xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11112	             xmlXPathTypeVal *type, const xmlChar **prefix,
11113		     xmlChar *name) {
11114    int blanks;
11115
11116    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11117	STRANGE;
11118	return(NULL);
11119    }
11120    *type = (xmlXPathTypeVal) 0;
11121    *test = (xmlXPathTestVal) 0;
11122    *prefix = NULL;
11123    SKIP_BLANKS;
11124
11125    if ((name == NULL) && (CUR == '*')) {
11126	/*
11127	 * All elements
11128	 */
11129	NEXT;
11130	*test = NODE_TEST_ALL;
11131	return(NULL);
11132    }
11133
11134    if (name == NULL)
11135	name = xmlXPathParseNCName(ctxt);
11136    if (name == NULL) {
11137	XP_ERRORNULL(XPATH_EXPR_ERROR);
11138    }
11139
11140    blanks = IS_BLANK_CH(CUR);
11141    SKIP_BLANKS;
11142    if (CUR == '(') {
11143	NEXT;
11144	/*
11145	 * NodeType or PI search
11146	 */
11147	if (xmlStrEqual(name, BAD_CAST "comment"))
11148	    *type = NODE_TYPE_COMMENT;
11149	else if (xmlStrEqual(name, BAD_CAST "node"))
11150	    *type = NODE_TYPE_NODE;
11151	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11152	    *type = NODE_TYPE_PI;
11153	else if (xmlStrEqual(name, BAD_CAST "text"))
11154	    *type = NODE_TYPE_TEXT;
11155	else {
11156	    if (name != NULL)
11157		xmlFree(name);
11158	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11159	}
11160
11161	*test = NODE_TEST_TYPE;
11162
11163	SKIP_BLANKS;
11164	if (*type == NODE_TYPE_PI) {
11165	    /*
11166	     * Specific case: search a PI by name.
11167	     */
11168	    if (name != NULL)
11169		xmlFree(name);
11170	    name = NULL;
11171	    if (CUR != ')') {
11172		name = xmlXPathParseLiteral(ctxt);
11173		CHECK_ERROR NULL;
11174		*test = NODE_TEST_PI;
11175		SKIP_BLANKS;
11176	    }
11177	}
11178	if (CUR != ')') {
11179	    if (name != NULL)
11180		xmlFree(name);
11181	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11182	}
11183	NEXT;
11184	return(name);
11185    }
11186    *test = NODE_TEST_NAME;
11187    if ((!blanks) && (CUR == ':')) {
11188	NEXT;
11189
11190	/*
11191	 * Since currently the parser context don't have a
11192	 * namespace list associated:
11193	 * The namespace name for this prefix can be computed
11194	 * only at evaluation time. The compilation is done
11195	 * outside of any context.
11196	 */
11197#if 0
11198	*prefix = xmlXPathNsLookup(ctxt->context, name);
11199	if (name != NULL)
11200	    xmlFree(name);
11201	if (*prefix == NULL) {
11202	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11203	}
11204#else
11205	*prefix = name;
11206#endif
11207
11208	if (CUR == '*') {
11209	    /*
11210	     * All elements
11211	     */
11212	    NEXT;
11213	    *test = NODE_TEST_ALL;
11214	    return(NULL);
11215	}
11216
11217	name = xmlXPathParseNCName(ctxt);
11218	if (name == NULL) {
11219	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11220	}
11221    }
11222    return(name);
11223}
11224
11225/**
11226 * xmlXPathIsAxisName:
11227 * @name:  a preparsed name token
11228 *
11229 * [6] AxisName ::=   'ancestor'
11230 *                  | 'ancestor-or-self'
11231 *                  | 'attribute'
11232 *                  | 'child'
11233 *                  | 'descendant'
11234 *                  | 'descendant-or-self'
11235 *                  | 'following'
11236 *                  | 'following-sibling'
11237 *                  | 'namespace'
11238 *                  | 'parent'
11239 *                  | 'preceding'
11240 *                  | 'preceding-sibling'
11241 *                  | 'self'
11242 *
11243 * Returns the axis or 0
11244 */
11245static xmlXPathAxisVal
11246xmlXPathIsAxisName(const xmlChar *name) {
11247    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11248    switch (name[0]) {
11249	case 'a':
11250	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11251		ret = AXIS_ANCESTOR;
11252	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11253		ret = AXIS_ANCESTOR_OR_SELF;
11254	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11255		ret = AXIS_ATTRIBUTE;
11256	    break;
11257	case 'c':
11258	    if (xmlStrEqual(name, BAD_CAST "child"))
11259		ret = AXIS_CHILD;
11260	    break;
11261	case 'd':
11262	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11263		ret = AXIS_DESCENDANT;
11264	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11265		ret = AXIS_DESCENDANT_OR_SELF;
11266	    break;
11267	case 'f':
11268	    if (xmlStrEqual(name, BAD_CAST "following"))
11269		ret = AXIS_FOLLOWING;
11270	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11271		ret = AXIS_FOLLOWING_SIBLING;
11272	    break;
11273	case 'n':
11274	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11275		ret = AXIS_NAMESPACE;
11276	    break;
11277	case 'p':
11278	    if (xmlStrEqual(name, BAD_CAST "parent"))
11279		ret = AXIS_PARENT;
11280	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11281		ret = AXIS_PRECEDING;
11282	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11283		ret = AXIS_PRECEDING_SIBLING;
11284	    break;
11285	case 's':
11286	    if (xmlStrEqual(name, BAD_CAST "self"))
11287		ret = AXIS_SELF;
11288	    break;
11289    }
11290    return(ret);
11291}
11292
11293/**
11294 * xmlXPathCompStep:
11295 * @ctxt:  the XPath Parser context
11296 *
11297 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11298 *                  | AbbreviatedStep
11299 *
11300 * [12] AbbreviatedStep ::=   '.' | '..'
11301 *
11302 * [5] AxisSpecifier ::= AxisName '::'
11303 *                  | AbbreviatedAxisSpecifier
11304 *
11305 * [13] AbbreviatedAxisSpecifier ::= '@'?
11306 *
11307 * Modified for XPtr range support as:
11308 *
11309 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11310 *                     | AbbreviatedStep
11311 *                     | 'range-to' '(' Expr ')' Predicate*
11312 *
11313 * Compile one step in a Location Path
11314 * A location step of . is short for self::node(). This is
11315 * particularly useful in conjunction with //. For example, the
11316 * location path .//para is short for
11317 * self::node()/descendant-or-self::node()/child::para
11318 * and so will select all para descendant elements of the context
11319 * node.
11320 * Similarly, a location step of .. is short for parent::node().
11321 * For example, ../title is short for parent::node()/child::title
11322 * and so will select the title children of the parent of the context
11323 * node.
11324 */
11325static void
11326xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11327#ifdef LIBXML_XPTR_ENABLED
11328    int rangeto = 0;
11329    int op2 = -1;
11330#endif
11331
11332    SKIP_BLANKS;
11333    if ((CUR == '.') && (NXT(1) == '.')) {
11334	SKIP(2);
11335	SKIP_BLANKS;
11336	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11337		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11338    } else if (CUR == '.') {
11339	NEXT;
11340	SKIP_BLANKS;
11341    } else {
11342	xmlChar *name = NULL;
11343	const xmlChar *prefix = NULL;
11344	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11345	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11346	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11347	int op1;
11348
11349	/*
11350	 * The modification needed for XPointer change to the production
11351	 */
11352#ifdef LIBXML_XPTR_ENABLED
11353	if (ctxt->xptr) {
11354	    name = xmlXPathParseNCName(ctxt);
11355	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11356                op2 = ctxt->comp->last;
11357		xmlFree(name);
11358		SKIP_BLANKS;
11359		if (CUR != '(') {
11360		    XP_ERROR(XPATH_EXPR_ERROR);
11361		}
11362		NEXT;
11363		SKIP_BLANKS;
11364
11365		xmlXPathCompileExpr(ctxt, 1);
11366		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11367		CHECK_ERROR;
11368
11369		SKIP_BLANKS;
11370		if (CUR != ')') {
11371		    XP_ERROR(XPATH_EXPR_ERROR);
11372		}
11373		NEXT;
11374		rangeto = 1;
11375		goto eval_predicates;
11376	    }
11377	}
11378#endif
11379	if (CUR == '*') {
11380	    axis = AXIS_CHILD;
11381	} else {
11382	    if (name == NULL)
11383		name = xmlXPathParseNCName(ctxt);
11384	    if (name != NULL) {
11385		axis = xmlXPathIsAxisName(name);
11386		if (axis != 0) {
11387		    SKIP_BLANKS;
11388		    if ((CUR == ':') && (NXT(1) == ':')) {
11389			SKIP(2);
11390			xmlFree(name);
11391			name = NULL;
11392		    } else {
11393			/* an element name can conflict with an axis one :-\ */
11394			axis = AXIS_CHILD;
11395		    }
11396		} else {
11397		    axis = AXIS_CHILD;
11398		}
11399	    } else if (CUR == '@') {
11400		NEXT;
11401		axis = AXIS_ATTRIBUTE;
11402	    } else {
11403		axis = AXIS_CHILD;
11404	    }
11405	}
11406
11407        if (ctxt->error != XPATH_EXPRESSION_OK) {
11408            xmlFree(name);
11409            return;
11410        }
11411
11412	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11413	if (test == 0)
11414	    return;
11415
11416        if ((prefix != NULL) && (ctxt->context != NULL) &&
11417	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11418	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11419		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11420	    }
11421	}
11422#ifdef DEBUG_STEP
11423	xmlGenericError(xmlGenericErrorContext,
11424		"Basis : computing new set\n");
11425#endif
11426
11427#ifdef DEBUG_STEP
11428	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11429	if (ctxt->value == NULL)
11430	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11431	else if (ctxt->value->nodesetval == NULL)
11432	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11433	else
11434	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11435#endif
11436
11437#ifdef LIBXML_XPTR_ENABLED
11438eval_predicates:
11439#endif
11440	op1 = ctxt->comp->last;
11441	ctxt->comp->last = -1;
11442
11443	SKIP_BLANKS;
11444	while (CUR == '[') {
11445	    xmlXPathCompPredicate(ctxt, 0);
11446	}
11447
11448#ifdef LIBXML_XPTR_ENABLED
11449	if (rangeto) {
11450	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11451	} else
11452#endif
11453	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11454			   test, type, (void *)prefix, (void *)name);
11455
11456    }
11457#ifdef DEBUG_STEP
11458    xmlGenericError(xmlGenericErrorContext, "Step : ");
11459    if (ctxt->value == NULL)
11460	xmlGenericError(xmlGenericErrorContext, "no value\n");
11461    else if (ctxt->value->nodesetval == NULL)
11462	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11463    else
11464	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11465		ctxt->value->nodesetval);
11466#endif
11467}
11468
11469/**
11470 * xmlXPathCompRelativeLocationPath:
11471 * @ctxt:  the XPath Parser context
11472 *
11473 *  [3]   RelativeLocationPath ::=   Step
11474 *                     | RelativeLocationPath '/' Step
11475 *                     | AbbreviatedRelativeLocationPath
11476 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11477 *
11478 * Compile a relative location path.
11479 */
11480static void
11481xmlXPathCompRelativeLocationPath
11482(xmlXPathParserContextPtr ctxt) {
11483    SKIP_BLANKS;
11484    if ((CUR == '/') && (NXT(1) == '/')) {
11485	SKIP(2);
11486	SKIP_BLANKS;
11487	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11488		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11489    } else if (CUR == '/') {
11490	    NEXT;
11491	SKIP_BLANKS;
11492    }
11493    xmlXPathCompStep(ctxt);
11494    CHECK_ERROR;
11495    SKIP_BLANKS;
11496    while (CUR == '/') {
11497	if ((CUR == '/') && (NXT(1) == '/')) {
11498	    SKIP(2);
11499	    SKIP_BLANKS;
11500	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11501			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11502	    xmlXPathCompStep(ctxt);
11503	} else if (CUR == '/') {
11504	    NEXT;
11505	    SKIP_BLANKS;
11506	    xmlXPathCompStep(ctxt);
11507	}
11508	SKIP_BLANKS;
11509    }
11510}
11511
11512/**
11513 * xmlXPathCompLocationPath:
11514 * @ctxt:  the XPath Parser context
11515 *
11516 *  [1]   LocationPath ::=   RelativeLocationPath
11517 *                     | AbsoluteLocationPath
11518 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11519 *                     | AbbreviatedAbsoluteLocationPath
11520 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11521 *                           '//' RelativeLocationPath
11522 *
11523 * Compile a location path
11524 *
11525 * // is short for /descendant-or-self::node()/. For example,
11526 * //para is short for /descendant-or-self::node()/child::para and
11527 * so will select any para element in the document (even a para element
11528 * that is a document element will be selected by //para since the
11529 * document element node is a child of the root node); div//para is
11530 * short for div/descendant-or-self::node()/child::para and so will
11531 * select all para descendants of div children.
11532 */
11533static void
11534xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11535    SKIP_BLANKS;
11536    if (CUR != '/') {
11537        xmlXPathCompRelativeLocationPath(ctxt);
11538    } else {
11539	while (CUR == '/') {
11540	    if ((CUR == '/') && (NXT(1) == '/')) {
11541		SKIP(2);
11542		SKIP_BLANKS;
11543		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11544			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11545		xmlXPathCompRelativeLocationPath(ctxt);
11546	    } else if (CUR == '/') {
11547		NEXT;
11548		SKIP_BLANKS;
11549		if ((CUR != 0 ) &&
11550		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11551		     (CUR == '@') || (CUR == '*')))
11552		    xmlXPathCompRelativeLocationPath(ctxt);
11553	    }
11554	    CHECK_ERROR;
11555	}
11556    }
11557}
11558
11559/************************************************************************
11560 *									*
11561 *		XPath precompiled expression evaluation			*
11562 *									*
11563 ************************************************************************/
11564
11565static int
11566xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11567
11568#ifdef DEBUG_STEP
11569static void
11570xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11571			  int nbNodes)
11572{
11573    xmlGenericError(xmlGenericErrorContext, "new step : ");
11574    switch (op->value) {
11575        case AXIS_ANCESTOR:
11576            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11577            break;
11578        case AXIS_ANCESTOR_OR_SELF:
11579            xmlGenericError(xmlGenericErrorContext,
11580                            "axis 'ancestors-or-self' ");
11581            break;
11582        case AXIS_ATTRIBUTE:
11583            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11584            break;
11585        case AXIS_CHILD:
11586            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11587            break;
11588        case AXIS_DESCENDANT:
11589            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11590            break;
11591        case AXIS_DESCENDANT_OR_SELF:
11592            xmlGenericError(xmlGenericErrorContext,
11593                            "axis 'descendant-or-self' ");
11594            break;
11595        case AXIS_FOLLOWING:
11596            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11597            break;
11598        case AXIS_FOLLOWING_SIBLING:
11599            xmlGenericError(xmlGenericErrorContext,
11600                            "axis 'following-siblings' ");
11601            break;
11602        case AXIS_NAMESPACE:
11603            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11604            break;
11605        case AXIS_PARENT:
11606            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11607            break;
11608        case AXIS_PRECEDING:
11609            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11610            break;
11611        case AXIS_PRECEDING_SIBLING:
11612            xmlGenericError(xmlGenericErrorContext,
11613                            "axis 'preceding-sibling' ");
11614            break;
11615        case AXIS_SELF:
11616            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11617            break;
11618    }
11619    xmlGenericError(xmlGenericErrorContext,
11620	" context contains %d nodes\n", nbNodes);
11621    switch (op->value2) {
11622        case NODE_TEST_NONE:
11623            xmlGenericError(xmlGenericErrorContext,
11624                            "           searching for none !!!\n");
11625            break;
11626        case NODE_TEST_TYPE:
11627            xmlGenericError(xmlGenericErrorContext,
11628                            "           searching for type %d\n", op->value3);
11629            break;
11630        case NODE_TEST_PI:
11631            xmlGenericError(xmlGenericErrorContext,
11632                            "           searching for PI !!!\n");
11633            break;
11634        case NODE_TEST_ALL:
11635            xmlGenericError(xmlGenericErrorContext,
11636                            "           searching for *\n");
11637            break;
11638        case NODE_TEST_NS:
11639            xmlGenericError(xmlGenericErrorContext,
11640                            "           searching for namespace %s\n",
11641                            op->value5);
11642            break;
11643        case NODE_TEST_NAME:
11644            xmlGenericError(xmlGenericErrorContext,
11645                            "           searching for name %s\n", op->value5);
11646            if (op->value4)
11647                xmlGenericError(xmlGenericErrorContext,
11648                                "           with namespace %s\n", op->value4);
11649            break;
11650    }
11651    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11652}
11653#endif /* DEBUG_STEP */
11654
11655static int
11656xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11657			    xmlXPathStepOpPtr op,
11658			    xmlNodeSetPtr set,
11659			    int contextSize,
11660			    int hasNsNodes)
11661{
11662    if (op->ch1 != -1) {
11663	xmlXPathCompExprPtr comp = ctxt->comp;
11664	/*
11665	* Process inner predicates first.
11666	*/
11667	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11668	    /*
11669	    * TODO: raise an internal error.
11670	    */
11671	}
11672	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11673	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11674	CHECK_ERROR0;
11675	if (contextSize <= 0)
11676	    return(0);
11677    }
11678    if (op->ch2 != -1) {
11679	xmlXPathContextPtr xpctxt = ctxt->context;
11680	xmlNodePtr contextNode, oldContextNode;
11681	xmlDocPtr oldContextDoc;
11682	int i, res, contextPos = 0, newContextSize;
11683	xmlXPathStepOpPtr exprOp;
11684	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11685
11686#ifdef LIBXML_XPTR_ENABLED
11687	/*
11688	* URGENT TODO: Check the following:
11689	*  We don't expect location sets if evaluating prediates, right?
11690	*  Only filters should expect location sets, right?
11691	*/
11692#endif
11693	/*
11694	* SPEC XPath 1.0:
11695	*  "For each node in the node-set to be filtered, the
11696	*  PredicateExpr is evaluated with that node as the
11697	*  context node, with the number of nodes in the
11698	*  node-set as the context size, and with the proximity
11699	*  position of the node in the node-set with respect to
11700	*  the axis as the context position;"
11701	* @oldset is the node-set" to be filtered.
11702	*
11703	* SPEC XPath 1.0:
11704	*  "only predicates change the context position and
11705	*  context size (see [2.4 Predicates])."
11706	* Example:
11707	*   node-set  context pos
11708	*    nA         1
11709	*    nB         2
11710	*    nC         3
11711	*   After applying predicate [position() > 1] :
11712	*   node-set  context pos
11713	*    nB         1
11714	*    nC         2
11715	*/
11716	oldContextNode = xpctxt->node;
11717	oldContextDoc = xpctxt->doc;
11718	/*
11719	* Get the expression of this predicate.
11720	*/
11721	exprOp = &ctxt->comp->steps[op->ch2];
11722	newContextSize = 0;
11723	for (i = 0; i < set->nodeNr; i++) {
11724	    if (set->nodeTab[i] == NULL)
11725		continue;
11726
11727	    contextNode = set->nodeTab[i];
11728	    xpctxt->node = contextNode;
11729	    xpctxt->contextSize = contextSize;
11730	    xpctxt->proximityPosition = ++contextPos;
11731
11732	    /*
11733	    * Also set the xpath document in case things like
11734	    * key() are evaluated in the predicate.
11735	    */
11736	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11737		(contextNode->doc != NULL))
11738		xpctxt->doc = contextNode->doc;
11739	    /*
11740	    * Evaluate the predicate expression with 1 context node
11741	    * at a time; this node is packaged into a node set; this
11742	    * node set is handed over to the evaluation mechanism.
11743	    */
11744	    if (contextObj == NULL)
11745		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11746	    else {
11747		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11748		    contextNode) < 0) {
11749		    ctxt->error = XPATH_MEMORY_ERROR;
11750		    goto evaluation_exit;
11751		}
11752	    }
11753
11754	    valuePush(ctxt, contextObj);
11755
11756	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11757
11758	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11759		xmlXPathNodeSetClear(set, hasNsNodes);
11760		newContextSize = 0;
11761		goto evaluation_exit;
11762	    }
11763
11764	    if (res != 0) {
11765		newContextSize++;
11766	    } else {
11767		/*
11768		* Remove the entry from the initial node set.
11769		*/
11770		set->nodeTab[i] = NULL;
11771		if (contextNode->type == XML_NAMESPACE_DECL)
11772		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11773	    }
11774	    if (ctxt->value == contextObj) {
11775		/*
11776		* Don't free the temporary XPath object holding the
11777		* context node, in order to avoid massive recreation
11778		* inside this loop.
11779		*/
11780		valuePop(ctxt);
11781		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11782	    } else {
11783		/*
11784		* TODO: The object was lost in the evaluation machinery.
11785		*  Can this happen? Maybe in internal-error cases.
11786		*/
11787		contextObj = NULL;
11788	    }
11789	}
11790
11791	if (contextObj != NULL) {
11792	    if (ctxt->value == contextObj)
11793		valuePop(ctxt);
11794	    xmlXPathReleaseObject(xpctxt, contextObj);
11795	}
11796evaluation_exit:
11797	if (exprRes != NULL)
11798	    xmlXPathReleaseObject(ctxt->context, exprRes);
11799	/*
11800	* Reset/invalidate the context.
11801	*/
11802	xpctxt->node = oldContextNode;
11803	xpctxt->doc = oldContextDoc;
11804	xpctxt->contextSize = -1;
11805	xpctxt->proximityPosition = -1;
11806	return(newContextSize);
11807    }
11808    return(contextSize);
11809}
11810
11811static int
11812xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11813				      xmlXPathStepOpPtr op,
11814				      xmlNodeSetPtr set,
11815				      int contextSize,
11816				      int minPos,
11817				      int maxPos,
11818				      int hasNsNodes)
11819{
11820    if (op->ch1 != -1) {
11821	xmlXPathCompExprPtr comp = ctxt->comp;
11822	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11823	    /*
11824	    * TODO: raise an internal error.
11825	    */
11826	}
11827	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11828	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11829	CHECK_ERROR0;
11830	if (contextSize <= 0)
11831	    return(0);
11832    }
11833    /*
11834    * Check if the node set contains a sufficient number of nodes for
11835    * the requested range.
11836    */
11837    if (contextSize < minPos) {
11838	xmlXPathNodeSetClear(set, hasNsNodes);
11839	return(0);
11840    }
11841    if (op->ch2 == -1) {
11842	/*
11843	* TODO: Can this ever happen?
11844	*/
11845	return (contextSize);
11846    } else {
11847	xmlDocPtr oldContextDoc;
11848	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11849	xmlXPathStepOpPtr exprOp;
11850	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11851	xmlNodePtr oldContextNode, contextNode = NULL;
11852	xmlXPathContextPtr xpctxt = ctxt->context;
11853        int frame;
11854
11855#ifdef LIBXML_XPTR_ENABLED
11856	    /*
11857	    * URGENT TODO: Check the following:
11858	    *  We don't expect location sets if evaluating prediates, right?
11859	    *  Only filters should expect location sets, right?
11860	*/
11861#endif /* LIBXML_XPTR_ENABLED */
11862
11863	/*
11864	* Save old context.
11865	*/
11866	oldContextNode = xpctxt->node;
11867	oldContextDoc = xpctxt->doc;
11868	/*
11869	* Get the expression of this predicate.
11870	*/
11871	exprOp = &ctxt->comp->steps[op->ch2];
11872	for (i = 0; i < set->nodeNr; i++) {
11873            xmlXPathObjectPtr tmp;
11874
11875	    if (set->nodeTab[i] == NULL)
11876		continue;
11877
11878	    contextNode = set->nodeTab[i];
11879	    xpctxt->node = contextNode;
11880	    xpctxt->contextSize = contextSize;
11881	    xpctxt->proximityPosition = ++contextPos;
11882
11883	    /*
11884	    * Initialize the new set.
11885	    * Also set the xpath document in case things like
11886	    * key() evaluation are attempted on the predicate
11887	    */
11888	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11889		(contextNode->doc != NULL))
11890		xpctxt->doc = contextNode->doc;
11891	    /*
11892	    * Evaluate the predicate expression with 1 context node
11893	    * at a time; this node is packaged into a node set; this
11894	    * node set is handed over to the evaluation mechanism.
11895	    */
11896	    if (contextObj == NULL)
11897		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11898	    else {
11899		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11900		    contextNode) < 0) {
11901		    ctxt->error = XPATH_MEMORY_ERROR;
11902		    goto evaluation_exit;
11903		}
11904	    }
11905
11906            frame = xmlXPathSetFrame(ctxt);
11907	    valuePush(ctxt, contextObj);
11908	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11909            tmp = valuePop(ctxt);
11910            xmlXPathPopFrame(ctxt, frame);
11911
11912	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11913                while (tmp != contextObj) {
11914                    /*
11915                     * Free up the result
11916                     * then pop off contextObj, which will be freed later
11917                     */
11918                    xmlXPathReleaseObject(xpctxt, tmp);
11919                    tmp = valuePop(ctxt);
11920                }
11921		goto evaluation_error;
11922	    }
11923            /* push the result back onto the stack */
11924            valuePush(ctxt, tmp);
11925
11926	    if (res)
11927		pos++;
11928
11929	    if (res && (pos >= minPos) && (pos <= maxPos)) {
11930		/*
11931		* Fits in the requested range.
11932		*/
11933		newContextSize++;
11934		if (minPos == maxPos) {
11935		    /*
11936		    * Only 1 node was requested.
11937		    */
11938		    if (contextNode->type == XML_NAMESPACE_DECL) {
11939			/*
11940			* As always: take care of those nasty
11941			* namespace nodes.
11942			*/
11943			set->nodeTab[i] = NULL;
11944		    }
11945		    xmlXPathNodeSetClear(set, hasNsNodes);
11946		    set->nodeNr = 1;
11947		    set->nodeTab[0] = contextNode;
11948		    goto evaluation_exit;
11949		}
11950		if (pos == maxPos) {
11951		    /*
11952		    * We are done.
11953		    */
11954		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11955		    goto evaluation_exit;
11956		}
11957	    } else {
11958		/*
11959		* Remove the entry from the initial node set.
11960		*/
11961		set->nodeTab[i] = NULL;
11962		if (contextNode->type == XML_NAMESPACE_DECL)
11963		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11964	    }
11965	    if (exprRes != NULL) {
11966		xmlXPathReleaseObject(ctxt->context, exprRes);
11967		exprRes = NULL;
11968	    }
11969	    if (ctxt->value == contextObj) {
11970		/*
11971		* Don't free the temporary XPath object holding the
11972		* context node, in order to avoid massive recreation
11973		* inside this loop.
11974		*/
11975		valuePop(ctxt);
11976		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11977	    } else {
11978		/*
11979		* The object was lost in the evaluation machinery.
11980		* Can this happen? Maybe in case of internal-errors.
11981		*/
11982		contextObj = NULL;
11983	    }
11984	}
11985	goto evaluation_exit;
11986
11987evaluation_error:
11988	xmlXPathNodeSetClear(set, hasNsNodes);
11989	newContextSize = 0;
11990
11991evaluation_exit:
11992	if (contextObj != NULL) {
11993	    if (ctxt->value == contextObj)
11994		valuePop(ctxt);
11995	    xmlXPathReleaseObject(xpctxt, contextObj);
11996	}
11997	if (exprRes != NULL)
11998	    xmlXPathReleaseObject(ctxt->context, exprRes);
11999	/*
12000	* Reset/invalidate the context.
12001	*/
12002	xpctxt->node = oldContextNode;
12003	xpctxt->doc = oldContextDoc;
12004	xpctxt->contextSize = -1;
12005	xpctxt->proximityPosition = -1;
12006	return(newContextSize);
12007    }
12008    return(contextSize);
12009}
12010
12011static int
12012xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12013			    xmlXPathStepOpPtr op,
12014			    int *maxPos)
12015{
12016
12017    xmlXPathStepOpPtr exprOp;
12018
12019    /*
12020    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12021    */
12022
12023    /*
12024    * If not -1, then ch1 will point to:
12025    * 1) For predicates (XPATH_OP_PREDICATE):
12026    *    - an inner predicate operator
12027    * 2) For filters (XPATH_OP_FILTER):
12028    *    - an inner filter operater OR
12029    *    - an expression selecting the node set.
12030    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
12031    */
12032    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12033	return(0);
12034
12035    if (op->ch2 != -1) {
12036	exprOp = &ctxt->comp->steps[op->ch2];
12037    } else
12038	return(0);
12039
12040    if ((exprOp != NULL) &&
12041	(exprOp->op == XPATH_OP_VALUE) &&
12042	(exprOp->value4 != NULL) &&
12043	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12044    {
12045	/*
12046	* We have a "[n]" predicate here.
12047	* TODO: Unfortunately this simplistic test here is not
12048	* able to detect a position() predicate in compound
12049	* expressions like "[@attr = 'a" and position() = 1],
12050	* and even not the usage of position() in
12051	* "[position() = 1]"; thus - obviously - a position-range,
12052	* like it "[position() < 5]", is also not detected.
12053	* Maybe we could rewrite the AST to ease the optimization.
12054	*/
12055	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12056
12057	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
12058	    (float) *maxPos)
12059	{
12060	    return(1);
12061	}
12062    }
12063    return(0);
12064}
12065
12066static int
12067xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12068                           xmlXPathStepOpPtr op,
12069			   xmlNodePtr * first, xmlNodePtr * last,
12070			   int toBool)
12071{
12072
12073#define XP_TEST_HIT \
12074    if (hasAxisRange != 0) { \
12075	if (++pos == maxPos) { \
12076	    if (addNode(seq, cur) < 0) \
12077	        ctxt->error = XPATH_MEMORY_ERROR; \
12078	    goto axis_range_end; } \
12079    } else { \
12080	if (addNode(seq, cur) < 0) \
12081	    ctxt->error = XPATH_MEMORY_ERROR; \
12082	if (breakOnFirstHit) goto first_hit; }
12083
12084#define XP_TEST_HIT_NS \
12085    if (hasAxisRange != 0) { \
12086	if (++pos == maxPos) { \
12087	    hasNsNodes = 1; \
12088	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12089	        ctxt->error = XPATH_MEMORY_ERROR; \
12090	goto axis_range_end; } \
12091    } else { \
12092	hasNsNodes = 1; \
12093	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12094	    ctxt->error = XPATH_MEMORY_ERROR; \
12095	if (breakOnFirstHit) goto first_hit; }
12096
12097    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12098    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12099    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12100    const xmlChar *prefix = op->value4;
12101    const xmlChar *name = op->value5;
12102    const xmlChar *URI = NULL;
12103
12104#ifdef DEBUG_STEP
12105    int nbMatches = 0, prevMatches = 0;
12106#endif
12107    int total = 0, hasNsNodes = 0;
12108    /* The popped object holding the context nodes */
12109    xmlXPathObjectPtr obj;
12110    /* The set of context nodes for the node tests */
12111    xmlNodeSetPtr contextSeq;
12112    int contextIdx;
12113    xmlNodePtr contextNode;
12114    /* The context node for a compound traversal */
12115    xmlNodePtr outerContextNode;
12116    /* The final resulting node set wrt to all context nodes */
12117    xmlNodeSetPtr outSeq;
12118    /*
12119    * The temporary resulting node set wrt 1 context node.
12120    * Used to feed predicate evaluation.
12121    */
12122    xmlNodeSetPtr seq;
12123    xmlNodePtr cur;
12124    /* First predicate operator */
12125    xmlXPathStepOpPtr predOp;
12126    int maxPos; /* The requested position() (when a "[n]" predicate) */
12127    int hasPredicateRange, hasAxisRange, pos, size, newSize;
12128    int breakOnFirstHit;
12129
12130    xmlXPathTraversalFunction next = NULL;
12131    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12132    xmlXPathNodeSetMergeFunction mergeAndClear;
12133    xmlNodePtr oldContextNode;
12134    xmlXPathContextPtr xpctxt = ctxt->context;
12135
12136
12137    CHECK_TYPE0(XPATH_NODESET);
12138    obj = valuePop(ctxt);
12139    /*
12140    * Setup namespaces.
12141    */
12142    if (prefix != NULL) {
12143        URI = xmlXPathNsLookup(xpctxt, prefix);
12144        if (URI == NULL) {
12145	    xmlXPathReleaseObject(xpctxt, obj);
12146            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12147	}
12148    }
12149    /*
12150    * Setup axis.
12151    *
12152    * MAYBE FUTURE TODO: merging optimizations:
12153    * - If the nodes to be traversed wrt to the initial nodes and
12154    *   the current axis cannot overlap, then we could avoid searching
12155    *   for duplicates during the merge.
12156    *   But the question is how/when to evaluate if they cannot overlap.
12157    *   Example: if we know that for two initial nodes, the one is
12158    *   not in the ancestor-or-self axis of the other, then we could safely
12159    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12160    *   the descendant-or-self axis.
12161    */
12162    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12163    switch (axis) {
12164        case AXIS_ANCESTOR:
12165            first = NULL;
12166            next = xmlXPathNextAncestor;
12167            break;
12168        case AXIS_ANCESTOR_OR_SELF:
12169            first = NULL;
12170            next = xmlXPathNextAncestorOrSelf;
12171            break;
12172        case AXIS_ATTRIBUTE:
12173            first = NULL;
12174	    last = NULL;
12175            next = xmlXPathNextAttribute;
12176	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12177            break;
12178        case AXIS_CHILD:
12179	    last = NULL;
12180	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12181		(type == NODE_TYPE_NODE))
12182	    {
12183		/*
12184		* Optimization if an element node type is 'element'.
12185		*/
12186		next = xmlXPathNextChildElement;
12187	    } else
12188		next = xmlXPathNextChild;
12189	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12190            break;
12191        case AXIS_DESCENDANT:
12192	    last = NULL;
12193            next = xmlXPathNextDescendant;
12194            break;
12195        case AXIS_DESCENDANT_OR_SELF:
12196	    last = NULL;
12197            next = xmlXPathNextDescendantOrSelf;
12198            break;
12199        case AXIS_FOLLOWING:
12200	    last = NULL;
12201            next = xmlXPathNextFollowing;
12202            break;
12203        case AXIS_FOLLOWING_SIBLING:
12204	    last = NULL;
12205            next = xmlXPathNextFollowingSibling;
12206            break;
12207        case AXIS_NAMESPACE:
12208            first = NULL;
12209	    last = NULL;
12210            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12211	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12212            break;
12213        case AXIS_PARENT:
12214            first = NULL;
12215            next = xmlXPathNextParent;
12216            break;
12217        case AXIS_PRECEDING:
12218            first = NULL;
12219            next = xmlXPathNextPrecedingInternal;
12220            break;
12221        case AXIS_PRECEDING_SIBLING:
12222            first = NULL;
12223            next = xmlXPathNextPrecedingSibling;
12224            break;
12225        case AXIS_SELF:
12226            first = NULL;
12227	    last = NULL;
12228            next = xmlXPathNextSelf;
12229	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12230            break;
12231    }
12232
12233#ifdef DEBUG_STEP
12234    xmlXPathDebugDumpStepAxis(op,
12235	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12236#endif
12237
12238    if (next == NULL) {
12239	xmlXPathReleaseObject(xpctxt, obj);
12240        return(0);
12241    }
12242    contextSeq = obj->nodesetval;
12243    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12244	xmlXPathReleaseObject(xpctxt, obj);
12245        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12246        return(0);
12247    }
12248    /*
12249    * Predicate optimization ---------------------------------------------
12250    * If this step has a last predicate, which contains a position(),
12251    * then we'll optimize (although not exactly "position()", but only
12252    * the  short-hand form, i.e., "[n]".
12253    *
12254    * Example - expression "/foo[parent::bar][1]":
12255    *
12256    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12257    *   ROOT                               -- op->ch1
12258    *   PREDICATE                          -- op->ch2 (predOp)
12259    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12260    *       SORT
12261    *         COLLECT  'parent' 'name' 'node' bar
12262    *           NODE
12263    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12264    *
12265    */
12266    maxPos = 0;
12267    predOp = NULL;
12268    hasPredicateRange = 0;
12269    hasAxisRange = 0;
12270    if (op->ch2 != -1) {
12271	/*
12272	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12273	*/
12274	predOp = &ctxt->comp->steps[op->ch2];
12275	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12276	    if (predOp->ch1 != -1) {
12277		/*
12278		* Use the next inner predicate operator.
12279		*/
12280		predOp = &ctxt->comp->steps[predOp->ch1];
12281		hasPredicateRange = 1;
12282	    } else {
12283		/*
12284		* There's no other predicate than the [n] predicate.
12285		*/
12286		predOp = NULL;
12287		hasAxisRange = 1;
12288	    }
12289	}
12290    }
12291    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12292    /*
12293    * Axis traversal -----------------------------------------------------
12294    */
12295    /*
12296     * 2.3 Node Tests
12297     *  - For the attribute axis, the principal node type is attribute.
12298     *  - For the namespace axis, the principal node type is namespace.
12299     *  - For other axes, the principal node type is element.
12300     *
12301     * A node test * is true for any node of the
12302     * principal node type. For example, child::* will
12303     * select all element children of the context node
12304     */
12305    oldContextNode = xpctxt->node;
12306    addNode = xmlXPathNodeSetAddUnique;
12307    outSeq = NULL;
12308    seq = NULL;
12309    outerContextNode = NULL;
12310    contextNode = NULL;
12311    contextIdx = 0;
12312
12313
12314    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12315           (ctxt->error == XPATH_EXPRESSION_OK)) {
12316	xpctxt->node = contextSeq->nodeTab[contextIdx++];
12317
12318	if (seq == NULL) {
12319	    seq = xmlXPathNodeSetCreate(NULL);
12320	    if (seq == NULL) {
12321		total = 0;
12322		goto error;
12323	    }
12324	}
12325	/*
12326	* Traverse the axis and test the nodes.
12327	*/
12328	pos = 0;
12329	cur = NULL;
12330	hasNsNodes = 0;
12331        do {
12332            cur = next(ctxt, cur);
12333            if (cur == NULL)
12334                break;
12335
12336	    /*
12337	    * QUESTION TODO: What does the "first" and "last" stuff do?
12338	    */
12339            if ((first != NULL) && (*first != NULL)) {
12340		if (*first == cur)
12341		    break;
12342		if (((total % 256) == 0) &&
12343#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12344		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12345#else
12346		    (xmlXPathCmpNodes(*first, cur) >= 0))
12347#endif
12348		{
12349		    break;
12350		}
12351	    }
12352	    if ((last != NULL) && (*last != NULL)) {
12353		if (*last == cur)
12354		    break;
12355		if (((total % 256) == 0) &&
12356#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12357		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12358#else
12359		    (xmlXPathCmpNodes(cur, *last) >= 0))
12360#endif
12361		{
12362		    break;
12363		}
12364	    }
12365
12366            total++;
12367
12368#ifdef DEBUG_STEP
12369            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12370#endif
12371
12372	    switch (test) {
12373                case NODE_TEST_NONE:
12374		    total = 0;
12375                    STRANGE
12376		    goto error;
12377                case NODE_TEST_TYPE:
12378		    /*
12379		    * TODO: Don't we need to use
12380		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
12381		    *  Surprisingly, some c14n tests fail, if we do this.
12382		    */
12383		    if (type == NODE_TYPE_NODE) {
12384			switch (cur->type) {
12385			    case XML_DOCUMENT_NODE:
12386			    case XML_HTML_DOCUMENT_NODE:
12387#ifdef LIBXML_DOCB_ENABLED
12388			    case XML_DOCB_DOCUMENT_NODE:
12389#endif
12390			    case XML_ELEMENT_NODE:
12391			    case XML_ATTRIBUTE_NODE:
12392			    case XML_PI_NODE:
12393			    case XML_COMMENT_NODE:
12394			    case XML_CDATA_SECTION_NODE:
12395			    case XML_TEXT_NODE:
12396			    case XML_NAMESPACE_DECL:
12397				XP_TEST_HIT
12398				break;
12399			    default:
12400				break;
12401			}
12402		    } else if (cur->type == type) {
12403			if (type == XML_NAMESPACE_DECL)
12404			    XP_TEST_HIT_NS
12405			else
12406			    XP_TEST_HIT
12407		    } else if ((type == NODE_TYPE_TEXT) &&
12408			 (cur->type == XML_CDATA_SECTION_NODE))
12409		    {
12410			XP_TEST_HIT
12411		    }
12412		    break;
12413                case NODE_TEST_PI:
12414                    if ((cur->type == XML_PI_NODE) &&
12415                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12416		    {
12417			XP_TEST_HIT
12418                    }
12419                    break;
12420                case NODE_TEST_ALL:
12421                    if (axis == AXIS_ATTRIBUTE) {
12422                        if (cur->type == XML_ATTRIBUTE_NODE)
12423			{
12424			    XP_TEST_HIT
12425                        }
12426                    } else if (axis == AXIS_NAMESPACE) {
12427                        if (cur->type == XML_NAMESPACE_DECL)
12428			{
12429			    XP_TEST_HIT_NS
12430                        }
12431                    } else {
12432                        if (cur->type == XML_ELEMENT_NODE) {
12433                            if (prefix == NULL)
12434			    {
12435				XP_TEST_HIT
12436
12437                            } else if ((cur->ns != NULL) &&
12438				(xmlStrEqual(URI, cur->ns->href)))
12439			    {
12440				XP_TEST_HIT
12441                            }
12442                        }
12443                    }
12444                    break;
12445                case NODE_TEST_NS:{
12446                        TODO;
12447                        break;
12448                    }
12449                case NODE_TEST_NAME:
12450                    if (axis == AXIS_ATTRIBUTE) {
12451                        if (cur->type != XML_ATTRIBUTE_NODE)
12452			    break;
12453		    } else if (axis == AXIS_NAMESPACE) {
12454                        if (cur->type != XML_NAMESPACE_DECL)
12455			    break;
12456		    } else {
12457		        if (cur->type != XML_ELEMENT_NODE)
12458			    break;
12459		    }
12460                    switch (cur->type) {
12461                        case XML_ELEMENT_NODE:
12462                            if (xmlStrEqual(name, cur->name)) {
12463                                if (prefix == NULL) {
12464                                    if (cur->ns == NULL)
12465				    {
12466					XP_TEST_HIT
12467                                    }
12468                                } else {
12469                                    if ((cur->ns != NULL) &&
12470                                        (xmlStrEqual(URI, cur->ns->href)))
12471				    {
12472					XP_TEST_HIT
12473                                    }
12474                                }
12475                            }
12476                            break;
12477                        case XML_ATTRIBUTE_NODE:{
12478                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12479
12480                                if (xmlStrEqual(name, attr->name)) {
12481                                    if (prefix == NULL) {
12482                                        if ((attr->ns == NULL) ||
12483                                            (attr->ns->prefix == NULL))
12484					{
12485					    XP_TEST_HIT
12486                                        }
12487                                    } else {
12488                                        if ((attr->ns != NULL) &&
12489                                            (xmlStrEqual(URI,
12490					      attr->ns->href)))
12491					{
12492					    XP_TEST_HIT
12493                                        }
12494                                    }
12495                                }
12496                                break;
12497                            }
12498                        case XML_NAMESPACE_DECL:
12499                            if (cur->type == XML_NAMESPACE_DECL) {
12500                                xmlNsPtr ns = (xmlNsPtr) cur;
12501
12502                                if ((ns->prefix != NULL) && (name != NULL)
12503                                    && (xmlStrEqual(ns->prefix, name)))
12504				{
12505				    XP_TEST_HIT_NS
12506                                }
12507                            }
12508                            break;
12509                        default:
12510                            break;
12511                    }
12512                    break;
12513	    } /* switch(test) */
12514        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12515
12516	goto apply_predicates;
12517
12518axis_range_end: /* ----------------------------------------------------- */
12519	/*
12520	* We have a "/foo[n]", and position() = n was reached.
12521	* Note that we can have as well "/foo/::parent::foo[1]", so
12522	* a duplicate-aware merge is still needed.
12523	* Merge with the result.
12524	*/
12525	if (outSeq == NULL) {
12526	    outSeq = seq;
12527	    seq = NULL;
12528	} else
12529	    outSeq = mergeAndClear(outSeq, seq, 0);
12530	/*
12531	* Break if only a true/false result was requested.
12532	*/
12533	if (toBool)
12534	    break;
12535	continue;
12536
12537first_hit: /* ---------------------------------------------------------- */
12538	/*
12539	* Break if only a true/false result was requested and
12540	* no predicates existed and a node test succeeded.
12541	*/
12542	if (outSeq == NULL) {
12543	    outSeq = seq;
12544	    seq = NULL;
12545	} else
12546	    outSeq = mergeAndClear(outSeq, seq, 0);
12547	break;
12548
12549#ifdef DEBUG_STEP
12550	if (seq != NULL)
12551	    nbMatches += seq->nodeNr;
12552#endif
12553
12554apply_predicates: /* --------------------------------------------------- */
12555        if (ctxt->error != XPATH_EXPRESSION_OK)
12556	    goto error;
12557
12558        /*
12559	* Apply predicates.
12560	*/
12561        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12562	    /*
12563	    * E.g. when we have a "/foo[some expression][n]".
12564	    */
12565	    /*
12566	    * QUESTION TODO: The old predicate evaluation took into
12567	    *  account location-sets.
12568	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12569	    *  Do we expect such a set here?
12570	    *  All what I learned now from the evaluation semantics
12571	    *  does not indicate that a location-set will be processed
12572	    *  here, so this looks OK.
12573	    */
12574	    /*
12575	    * Iterate over all predicates, starting with the outermost
12576	    * predicate.
12577	    * TODO: Problem: we cannot execute the inner predicates first
12578	    *  since we cannot go back *up* the operator tree!
12579	    *  Options we have:
12580	    *  1) Use of recursive functions (like is it currently done
12581	    *     via xmlXPathCompOpEval())
12582	    *  2) Add a predicate evaluation information stack to the
12583	    *     context struct
12584	    *  3) Change the way the operators are linked; we need a
12585	    *     "parent" field on xmlXPathStepOp
12586	    *
12587	    * For the moment, I'll try to solve this with a recursive
12588	    * function: xmlXPathCompOpEvalPredicate().
12589	    */
12590	    size = seq->nodeNr;
12591	    if (hasPredicateRange != 0)
12592		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12593		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12594	    else
12595		newSize = xmlXPathCompOpEvalPredicate(ctxt,
12596		    predOp, seq, size, hasNsNodes);
12597
12598	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12599		total = 0;
12600		goto error;
12601	    }
12602	    /*
12603	    * Add the filtered set of nodes to the result node set.
12604	    */
12605	    if (newSize == 0) {
12606		/*
12607		* The predicates filtered all nodes out.
12608		*/
12609		xmlXPathNodeSetClear(seq, hasNsNodes);
12610	    } else if (seq->nodeNr > 0) {
12611		/*
12612		* Add to result set.
12613		*/
12614		if (outSeq == NULL) {
12615		    if (size != newSize) {
12616			/*
12617			* We need to merge and clear here, since
12618			* the sequence will contained NULLed entries.
12619			*/
12620			outSeq = mergeAndClear(NULL, seq, 1);
12621		    } else {
12622			outSeq = seq;
12623			seq = NULL;
12624		    }
12625		} else
12626		    outSeq = mergeAndClear(outSeq, seq,
12627			(size != newSize) ? 1: 0);
12628		/*
12629		* Break if only a true/false result was requested.
12630		*/
12631		if (toBool)
12632		    break;
12633	    }
12634        } else if (seq->nodeNr > 0) {
12635	    /*
12636	    * Add to result set.
12637	    */
12638	    if (outSeq == NULL) {
12639		outSeq = seq;
12640		seq = NULL;
12641	    } else {
12642		outSeq = mergeAndClear(outSeq, seq, 0);
12643	    }
12644	}
12645    }
12646
12647error:
12648    if ((obj->boolval) && (obj->user != NULL)) {
12649	/*
12650	* QUESTION TODO: What does this do and why?
12651	* TODO: Do we have to do this also for the "error"
12652	* cleanup further down?
12653	*/
12654	ctxt->value->boolval = 1;
12655	ctxt->value->user = obj->user;
12656	obj->user = NULL;
12657	obj->boolval = 0;
12658    }
12659    xmlXPathReleaseObject(xpctxt, obj);
12660
12661    /*
12662    * Ensure we return at least an emtpy set.
12663    */
12664    if (outSeq == NULL) {
12665	if ((seq != NULL) && (seq->nodeNr == 0))
12666	    outSeq = seq;
12667	else
12668	    outSeq = xmlXPathNodeSetCreate(NULL);
12669        /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12670    }
12671    if ((seq != NULL) && (seq != outSeq)) {
12672	 xmlXPathFreeNodeSet(seq);
12673    }
12674    /*
12675    * Hand over the result. Better to push the set also in
12676    * case of errors.
12677    */
12678    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12679    /*
12680    * Reset the context node.
12681    */
12682    xpctxt->node = oldContextNode;
12683
12684#ifdef DEBUG_STEP
12685    xmlGenericError(xmlGenericErrorContext,
12686	"\nExamined %d nodes, found %d nodes at that step\n",
12687	total, nbMatches);
12688#endif
12689
12690    return(total);
12691}
12692
12693static int
12694xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12695			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12696
12697/**
12698 * xmlXPathCompOpEvalFirst:
12699 * @ctxt:  the XPath parser context with the compiled expression
12700 * @op:  an XPath compiled operation
12701 * @first:  the first elem found so far
12702 *
12703 * Evaluate the Precompiled XPath operation searching only the first
12704 * element in document order
12705 *
12706 * Returns the number of examined objects.
12707 */
12708static int
12709xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12710                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12711{
12712    int total = 0, cur;
12713    xmlXPathCompExprPtr comp;
12714    xmlXPathObjectPtr arg1, arg2;
12715
12716    CHECK_ERROR0;
12717    comp = ctxt->comp;
12718    switch (op->op) {
12719        case XPATH_OP_END:
12720            return (0);
12721        case XPATH_OP_UNION:
12722            total =
12723                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12724                                        first);
12725	    CHECK_ERROR0;
12726            if ((ctxt->value != NULL)
12727                && (ctxt->value->type == XPATH_NODESET)
12728                && (ctxt->value->nodesetval != NULL)
12729                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12730                /*
12731                 * limit tree traversing to first node in the result
12732                 */
12733		/*
12734		* OPTIMIZE TODO: This implicitely sorts
12735		*  the result, even if not needed. E.g. if the argument
12736		*  of the count() function, no sorting is needed.
12737		* OPTIMIZE TODO: How do we know if the node-list wasn't
12738		*  aready sorted?
12739		*/
12740		if (ctxt->value->nodesetval->nodeNr > 1)
12741		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12742                *first = ctxt->value->nodesetval->nodeTab[0];
12743            }
12744            cur =
12745                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12746                                        first);
12747	    CHECK_ERROR0;
12748            CHECK_TYPE0(XPATH_NODESET);
12749            arg2 = valuePop(ctxt);
12750
12751            CHECK_TYPE0(XPATH_NODESET);
12752            arg1 = valuePop(ctxt);
12753
12754            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12755                                                    arg2->nodesetval);
12756            valuePush(ctxt, arg1);
12757	    xmlXPathReleaseObject(ctxt->context, arg2);
12758            /* optimizer */
12759	    if (total > cur)
12760		xmlXPathCompSwap(op);
12761            return (total + cur);
12762        case XPATH_OP_ROOT:
12763            xmlXPathRoot(ctxt);
12764            return (0);
12765        case XPATH_OP_NODE:
12766            if (op->ch1 != -1)
12767                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12768	    CHECK_ERROR0;
12769            if (op->ch2 != -1)
12770                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12771	    CHECK_ERROR0;
12772	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12773		ctxt->context->node));
12774            return (total);
12775        case XPATH_OP_RESET:
12776            if (op->ch1 != -1)
12777                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12778	    CHECK_ERROR0;
12779            if (op->ch2 != -1)
12780                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12781	    CHECK_ERROR0;
12782            ctxt->context->node = NULL;
12783            return (total);
12784        case XPATH_OP_COLLECT:{
12785                if (op->ch1 == -1)
12786                    return (total);
12787
12788                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12789		CHECK_ERROR0;
12790
12791                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12792                return (total);
12793            }
12794        case XPATH_OP_VALUE:
12795            valuePush(ctxt,
12796                      xmlXPathCacheObjectCopy(ctxt->context,
12797			(xmlXPathObjectPtr) op->value4));
12798            return (0);
12799        case XPATH_OP_SORT:
12800            if (op->ch1 != -1)
12801                total +=
12802                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12803                                            first);
12804	    CHECK_ERROR0;
12805            if ((ctxt->value != NULL)
12806                && (ctxt->value->type == XPATH_NODESET)
12807                && (ctxt->value->nodesetval != NULL)
12808		&& (ctxt->value->nodesetval->nodeNr > 1))
12809                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12810            return (total);
12811#ifdef XP_OPTIMIZED_FILTER_FIRST
12812	case XPATH_OP_FILTER:
12813                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12814            return (total);
12815#endif
12816        default:
12817            return (xmlXPathCompOpEval(ctxt, op));
12818    }
12819}
12820
12821/**
12822 * xmlXPathCompOpEvalLast:
12823 * @ctxt:  the XPath parser context with the compiled expression
12824 * @op:  an XPath compiled operation
12825 * @last:  the last elem found so far
12826 *
12827 * Evaluate the Precompiled XPath operation searching only the last
12828 * element in document order
12829 *
12830 * Returns the number of nodes traversed
12831 */
12832static int
12833xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12834                       xmlNodePtr * last)
12835{
12836    int total = 0, cur;
12837    xmlXPathCompExprPtr comp;
12838    xmlXPathObjectPtr arg1, arg2;
12839    xmlNodePtr bak;
12840    xmlDocPtr bakd;
12841    int pp;
12842    int cs;
12843
12844    CHECK_ERROR0;
12845    comp = ctxt->comp;
12846    switch (op->op) {
12847        case XPATH_OP_END:
12848            return (0);
12849        case XPATH_OP_UNION:
12850	    bakd = ctxt->context->doc;
12851	    bak = ctxt->context->node;
12852	    pp = ctxt->context->proximityPosition;
12853	    cs = ctxt->context->contextSize;
12854            total =
12855                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12856	    CHECK_ERROR0;
12857            if ((ctxt->value != NULL)
12858                && (ctxt->value->type == XPATH_NODESET)
12859                && (ctxt->value->nodesetval != NULL)
12860                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12861                /*
12862                 * limit tree traversing to first node in the result
12863                 */
12864		if (ctxt->value->nodesetval->nodeNr > 1)
12865		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12866                *last =
12867                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12868                                                     nodesetval->nodeNr -
12869                                                     1];
12870            }
12871	    ctxt->context->doc = bakd;
12872	    ctxt->context->node = bak;
12873	    ctxt->context->proximityPosition = pp;
12874	    ctxt->context->contextSize = cs;
12875            cur =
12876                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12877	    CHECK_ERROR0;
12878            if ((ctxt->value != NULL)
12879                && (ctxt->value->type == XPATH_NODESET)
12880                && (ctxt->value->nodesetval != NULL)
12881                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12882            }
12883            CHECK_TYPE0(XPATH_NODESET);
12884            arg2 = valuePop(ctxt);
12885
12886            CHECK_TYPE0(XPATH_NODESET);
12887            arg1 = valuePop(ctxt);
12888
12889            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12890                                                    arg2->nodesetval);
12891            valuePush(ctxt, arg1);
12892	    xmlXPathReleaseObject(ctxt->context, arg2);
12893            /* optimizer */
12894	    if (total > cur)
12895		xmlXPathCompSwap(op);
12896            return (total + cur);
12897        case XPATH_OP_ROOT:
12898            xmlXPathRoot(ctxt);
12899            return (0);
12900        case XPATH_OP_NODE:
12901            if (op->ch1 != -1)
12902                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12903	    CHECK_ERROR0;
12904            if (op->ch2 != -1)
12905                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12906	    CHECK_ERROR0;
12907	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12908		ctxt->context->node));
12909            return (total);
12910        case XPATH_OP_RESET:
12911            if (op->ch1 != -1)
12912                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12913	    CHECK_ERROR0;
12914            if (op->ch2 != -1)
12915                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12916	    CHECK_ERROR0;
12917            ctxt->context->node = NULL;
12918            return (total);
12919        case XPATH_OP_COLLECT:{
12920                if (op->ch1 == -1)
12921                    return (0);
12922
12923                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12924		CHECK_ERROR0;
12925
12926                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12927                return (total);
12928            }
12929        case XPATH_OP_VALUE:
12930            valuePush(ctxt,
12931                      xmlXPathCacheObjectCopy(ctxt->context,
12932			(xmlXPathObjectPtr) op->value4));
12933            return (0);
12934        case XPATH_OP_SORT:
12935            if (op->ch1 != -1)
12936                total +=
12937                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12938                                           last);
12939	    CHECK_ERROR0;
12940            if ((ctxt->value != NULL)
12941                && (ctxt->value->type == XPATH_NODESET)
12942                && (ctxt->value->nodesetval != NULL)
12943		&& (ctxt->value->nodesetval->nodeNr > 1))
12944                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12945            return (total);
12946        default:
12947            return (xmlXPathCompOpEval(ctxt, op));
12948    }
12949}
12950
12951#ifdef XP_OPTIMIZED_FILTER_FIRST
12952static int
12953xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12954			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12955{
12956    int total = 0;
12957    xmlXPathCompExprPtr comp;
12958    xmlXPathObjectPtr res;
12959    xmlXPathObjectPtr obj;
12960    xmlNodeSetPtr oldset;
12961    xmlNodePtr oldnode;
12962    xmlDocPtr oldDoc;
12963    int i;
12964
12965    CHECK_ERROR0;
12966    comp = ctxt->comp;
12967    /*
12968    * Optimization for ()[last()] selection i.e. the last elem
12969    */
12970    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12971	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12972	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12973	int f = comp->steps[op->ch2].ch1;
12974
12975	if ((f != -1) &&
12976	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12977	    (comp->steps[f].value5 == NULL) &&
12978	    (comp->steps[f].value == 0) &&
12979	    (comp->steps[f].value4 != NULL) &&
12980	    (xmlStrEqual
12981	    (comp->steps[f].value4, BAD_CAST "last"))) {
12982	    xmlNodePtr last = NULL;
12983
12984	    total +=
12985		xmlXPathCompOpEvalLast(ctxt,
12986		    &comp->steps[op->ch1],
12987		    &last);
12988	    CHECK_ERROR0;
12989	    /*
12990	    * The nodeset should be in document order,
12991	    * Keep only the last value
12992	    */
12993	    if ((ctxt->value != NULL) &&
12994		(ctxt->value->type == XPATH_NODESET) &&
12995		(ctxt->value->nodesetval != NULL) &&
12996		(ctxt->value->nodesetval->nodeTab != NULL) &&
12997		(ctxt->value->nodesetval->nodeNr > 1)) {
12998		ctxt->value->nodesetval->nodeTab[0] =
12999		    ctxt->value->nodesetval->nodeTab[ctxt->
13000		    value->
13001		    nodesetval->
13002		    nodeNr -
13003		    1];
13004		ctxt->value->nodesetval->nodeNr = 1;
13005		*first = *(ctxt->value->nodesetval->nodeTab);
13006	    }
13007	    return (total);
13008	}
13009    }
13010
13011    if (op->ch1 != -1)
13012	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13013    CHECK_ERROR0;
13014    if (op->ch2 == -1)
13015	return (total);
13016    if (ctxt->value == NULL)
13017	return (total);
13018
13019#ifdef LIBXML_XPTR_ENABLED
13020    oldnode = ctxt->context->node;
13021    /*
13022    * Hum are we filtering the result of an XPointer expression
13023    */
13024    if (ctxt->value->type == XPATH_LOCATIONSET) {
13025	xmlXPathObjectPtr tmp = NULL;
13026	xmlLocationSetPtr newlocset = NULL;
13027	xmlLocationSetPtr oldlocset;
13028
13029	/*
13030	* Extract the old locset, and then evaluate the result of the
13031	* expression for all the element in the locset. use it to grow
13032	* up a new locset.
13033	*/
13034	CHECK_TYPE0(XPATH_LOCATIONSET);
13035	obj = valuePop(ctxt);
13036	oldlocset = obj->user;
13037	ctxt->context->node = NULL;
13038
13039	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13040	    ctxt->context->contextSize = 0;
13041	    ctxt->context->proximityPosition = 0;
13042	    if (op->ch2 != -1)
13043		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13044	    res = valuePop(ctxt);
13045	    if (res != NULL) {
13046		xmlXPathReleaseObject(ctxt->context, res);
13047	    }
13048	    valuePush(ctxt, obj);
13049	    CHECK_ERROR0;
13050	    return (total);
13051	}
13052	newlocset = xmlXPtrLocationSetCreate(NULL);
13053
13054	for (i = 0; i < oldlocset->locNr; i++) {
13055	    /*
13056	    * Run the evaluation with a node list made of a
13057	    * single item in the nodelocset.
13058	    */
13059	    ctxt->context->node = oldlocset->locTab[i]->user;
13060	    ctxt->context->contextSize = oldlocset->locNr;
13061	    ctxt->context->proximityPosition = i + 1;
13062	    if (tmp == NULL) {
13063		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13064		    ctxt->context->node);
13065	    } else {
13066		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13067		                             ctxt->context->node) < 0) {
13068		    ctxt->error = XPATH_MEMORY_ERROR;
13069		}
13070	    }
13071	    valuePush(ctxt, tmp);
13072	    if (op->ch2 != -1)
13073		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13074	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13075		xmlXPathFreeObject(obj);
13076		return(0);
13077	    }
13078	    /*
13079	    * The result of the evaluation need to be tested to
13080	    * decided whether the filter succeeded or not
13081	    */
13082	    res = valuePop(ctxt);
13083	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13084		xmlXPtrLocationSetAdd(newlocset,
13085		    xmlXPathCacheObjectCopy(ctxt->context,
13086			oldlocset->locTab[i]));
13087	    }
13088	    /*
13089	    * Cleanup
13090	    */
13091	    if (res != NULL) {
13092		xmlXPathReleaseObject(ctxt->context, res);
13093	    }
13094	    if (ctxt->value == tmp) {
13095		valuePop(ctxt);
13096		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13097		/*
13098		* REVISIT TODO: Don't create a temporary nodeset
13099		* for everly iteration.
13100		*/
13101		/* OLD: xmlXPathFreeObject(res); */
13102	    } else
13103		tmp = NULL;
13104	    ctxt->context->node = NULL;
13105	    /*
13106	    * Only put the first node in the result, then leave.
13107	    */
13108	    if (newlocset->locNr > 0) {
13109		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
13110		break;
13111	    }
13112	}
13113	if (tmp != NULL) {
13114	    xmlXPathReleaseObject(ctxt->context, tmp);
13115	}
13116	/*
13117	* The result is used as the new evaluation locset.
13118	*/
13119	xmlXPathReleaseObject(ctxt->context, obj);
13120	ctxt->context->node = NULL;
13121	ctxt->context->contextSize = -1;
13122	ctxt->context->proximityPosition = -1;
13123	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13124	ctxt->context->node = oldnode;
13125	return (total);
13126    }
13127#endif /* LIBXML_XPTR_ENABLED */
13128
13129    /*
13130    * Extract the old set, and then evaluate the result of the
13131    * expression for all the element in the set. use it to grow
13132    * up a new set.
13133    */
13134    CHECK_TYPE0(XPATH_NODESET);
13135    obj = valuePop(ctxt);
13136    oldset = obj->nodesetval;
13137
13138    oldnode = ctxt->context->node;
13139    oldDoc = ctxt->context->doc;
13140    ctxt->context->node = NULL;
13141
13142    if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13143	ctxt->context->contextSize = 0;
13144	ctxt->context->proximityPosition = 0;
13145	/* QUESTION TODO: Why was this code commented out?
13146	    if (op->ch2 != -1)
13147		total +=
13148		    xmlXPathCompOpEval(ctxt,
13149			&comp->steps[op->ch2]);
13150	    CHECK_ERROR0;
13151	    res = valuePop(ctxt);
13152	    if (res != NULL)
13153		xmlXPathFreeObject(res);
13154	*/
13155	valuePush(ctxt, obj);
13156	ctxt->context->node = oldnode;
13157	CHECK_ERROR0;
13158    } else {
13159	xmlNodeSetPtr newset;
13160	xmlXPathObjectPtr tmp = NULL;
13161	/*
13162	* Initialize the new set.
13163	* Also set the xpath document in case things like
13164	* key() evaluation are attempted on the predicate
13165	*/
13166	newset = xmlXPathNodeSetCreate(NULL);
13167        /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13168
13169	for (i = 0; i < oldset->nodeNr; i++) {
13170	    /*
13171	    * Run the evaluation with a node list made of
13172	    * a single item in the nodeset.
13173	    */
13174	    ctxt->context->node = oldset->nodeTab[i];
13175	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13176		(oldset->nodeTab[i]->doc != NULL))
13177		ctxt->context->doc = oldset->nodeTab[i]->doc;
13178	    if (tmp == NULL) {
13179		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13180		    ctxt->context->node);
13181	    } else {
13182		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13183		                             ctxt->context->node) < 0) {
13184		    ctxt->error = XPATH_MEMORY_ERROR;
13185		}
13186	    }
13187	    valuePush(ctxt, tmp);
13188	    ctxt->context->contextSize = oldset->nodeNr;
13189	    ctxt->context->proximityPosition = i + 1;
13190	    if (op->ch2 != -1)
13191		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13192	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13193		xmlXPathFreeNodeSet(newset);
13194		xmlXPathFreeObject(obj);
13195		return(0);
13196	    }
13197	    /*
13198	    * The result of the evaluation needs to be tested to
13199	    * decide whether the filter succeeded or not
13200	    */
13201	    res = valuePop(ctxt);
13202	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13203		if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13204		    ctxt->error = XPATH_MEMORY_ERROR;
13205	    }
13206	    /*
13207	    * Cleanup
13208	    */
13209	    if (res != NULL) {
13210		xmlXPathReleaseObject(ctxt->context, res);
13211	    }
13212	    if (ctxt->value == tmp) {
13213		valuePop(ctxt);
13214		/*
13215		* Don't free the temporary nodeset
13216		* in order to avoid massive recreation inside this
13217		* loop.
13218		*/
13219		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13220	    } else
13221		tmp = NULL;
13222	    ctxt->context->node = NULL;
13223	    /*
13224	    * Only put the first node in the result, then leave.
13225	    */
13226	    if (newset->nodeNr > 0) {
13227		*first = *(newset->nodeTab);
13228		break;
13229	    }
13230	}
13231	if (tmp != NULL) {
13232	    xmlXPathReleaseObject(ctxt->context, tmp);
13233	}
13234	/*
13235	* The result is used as the new evaluation set.
13236	*/
13237	xmlXPathReleaseObject(ctxt->context, obj);
13238	ctxt->context->node = NULL;
13239	ctxt->context->contextSize = -1;
13240	ctxt->context->proximityPosition = -1;
13241	/* may want to move this past the '}' later */
13242	ctxt->context->doc = oldDoc;
13243	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13244    }
13245    ctxt->context->node = oldnode;
13246    return(total);
13247}
13248#endif /* XP_OPTIMIZED_FILTER_FIRST */
13249
13250/**
13251 * xmlXPathCompOpEval:
13252 * @ctxt:  the XPath parser context with the compiled expression
13253 * @op:  an XPath compiled operation
13254 *
13255 * Evaluate the Precompiled XPath operation
13256 * Returns the number of nodes traversed
13257 */
13258static int
13259xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13260{
13261    int total = 0;
13262    int equal, ret;
13263    xmlXPathCompExprPtr comp;
13264    xmlXPathObjectPtr arg1, arg2;
13265    xmlNodePtr bak;
13266    xmlDocPtr bakd;
13267    int pp;
13268    int cs;
13269
13270    CHECK_ERROR0;
13271    comp = ctxt->comp;
13272    switch (op->op) {
13273        case XPATH_OP_END:
13274            return (0);
13275        case XPATH_OP_AND:
13276	    bakd = ctxt->context->doc;
13277	    bak = ctxt->context->node;
13278	    pp = ctxt->context->proximityPosition;
13279	    cs = ctxt->context->contextSize;
13280            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13281	    CHECK_ERROR0;
13282            xmlXPathBooleanFunction(ctxt, 1);
13283            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13284                return (total);
13285            arg2 = valuePop(ctxt);
13286	    ctxt->context->doc = bakd;
13287	    ctxt->context->node = bak;
13288	    ctxt->context->proximityPosition = pp;
13289	    ctxt->context->contextSize = cs;
13290            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13291	    if (ctxt->error) {
13292		xmlXPathFreeObject(arg2);
13293		return(0);
13294	    }
13295            xmlXPathBooleanFunction(ctxt, 1);
13296            arg1 = valuePop(ctxt);
13297            arg1->boolval &= arg2->boolval;
13298            valuePush(ctxt, arg1);
13299	    xmlXPathReleaseObject(ctxt->context, arg2);
13300            return (total);
13301        case XPATH_OP_OR:
13302	    bakd = ctxt->context->doc;
13303	    bak = ctxt->context->node;
13304	    pp = ctxt->context->proximityPosition;
13305	    cs = ctxt->context->contextSize;
13306            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13307	    CHECK_ERROR0;
13308            xmlXPathBooleanFunction(ctxt, 1);
13309            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13310                return (total);
13311            arg2 = valuePop(ctxt);
13312	    ctxt->context->doc = bakd;
13313	    ctxt->context->node = bak;
13314	    ctxt->context->proximityPosition = pp;
13315	    ctxt->context->contextSize = cs;
13316            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13317	    if (ctxt->error) {
13318		xmlXPathFreeObject(arg2);
13319		return(0);
13320	    }
13321            xmlXPathBooleanFunction(ctxt, 1);
13322            arg1 = valuePop(ctxt);
13323            arg1->boolval |= arg2->boolval;
13324            valuePush(ctxt, arg1);
13325	    xmlXPathReleaseObject(ctxt->context, arg2);
13326            return (total);
13327        case XPATH_OP_EQUAL:
13328	    bakd = ctxt->context->doc;
13329	    bak = ctxt->context->node;
13330	    pp = ctxt->context->proximityPosition;
13331	    cs = ctxt->context->contextSize;
13332            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13333	    CHECK_ERROR0;
13334	    ctxt->context->doc = bakd;
13335	    ctxt->context->node = bak;
13336	    ctxt->context->proximityPosition = pp;
13337	    ctxt->context->contextSize = cs;
13338            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13339	    CHECK_ERROR0;
13340	    if (op->value)
13341		equal = xmlXPathEqualValues(ctxt);
13342	    else
13343		equal = xmlXPathNotEqualValues(ctxt);
13344	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13345            return (total);
13346        case XPATH_OP_CMP:
13347	    bakd = ctxt->context->doc;
13348	    bak = ctxt->context->node;
13349	    pp = ctxt->context->proximityPosition;
13350	    cs = ctxt->context->contextSize;
13351            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13352	    CHECK_ERROR0;
13353	    ctxt->context->doc = bakd;
13354	    ctxt->context->node = bak;
13355	    ctxt->context->proximityPosition = pp;
13356	    ctxt->context->contextSize = cs;
13357            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13358	    CHECK_ERROR0;
13359            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13360	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13361            return (total);
13362        case XPATH_OP_PLUS:
13363	    bakd = ctxt->context->doc;
13364	    bak = ctxt->context->node;
13365	    pp = ctxt->context->proximityPosition;
13366	    cs = ctxt->context->contextSize;
13367            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13368	    CHECK_ERROR0;
13369            if (op->ch2 != -1) {
13370		ctxt->context->doc = bakd;
13371		ctxt->context->node = bak;
13372		ctxt->context->proximityPosition = pp;
13373		ctxt->context->contextSize = cs;
13374                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13375	    }
13376	    CHECK_ERROR0;
13377            if (op->value == 0)
13378                xmlXPathSubValues(ctxt);
13379            else if (op->value == 1)
13380                xmlXPathAddValues(ctxt);
13381            else if (op->value == 2)
13382                xmlXPathValueFlipSign(ctxt);
13383            else if (op->value == 3) {
13384                CAST_TO_NUMBER;
13385                CHECK_TYPE0(XPATH_NUMBER);
13386            }
13387            return (total);
13388        case XPATH_OP_MULT:
13389	    bakd = ctxt->context->doc;
13390	    bak = ctxt->context->node;
13391	    pp = ctxt->context->proximityPosition;
13392	    cs = ctxt->context->contextSize;
13393            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13394	    CHECK_ERROR0;
13395	    ctxt->context->doc = bakd;
13396	    ctxt->context->node = bak;
13397	    ctxt->context->proximityPosition = pp;
13398	    ctxt->context->contextSize = cs;
13399            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13400	    CHECK_ERROR0;
13401            if (op->value == 0)
13402                xmlXPathMultValues(ctxt);
13403            else if (op->value == 1)
13404                xmlXPathDivValues(ctxt);
13405            else if (op->value == 2)
13406                xmlXPathModValues(ctxt);
13407            return (total);
13408        case XPATH_OP_UNION:
13409	    bakd = ctxt->context->doc;
13410	    bak = ctxt->context->node;
13411	    pp = ctxt->context->proximityPosition;
13412	    cs = ctxt->context->contextSize;
13413            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13414	    CHECK_ERROR0;
13415	    ctxt->context->doc = bakd;
13416	    ctxt->context->node = bak;
13417	    ctxt->context->proximityPosition = pp;
13418	    ctxt->context->contextSize = cs;
13419            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13420	    CHECK_ERROR0;
13421            CHECK_TYPE0(XPATH_NODESET);
13422            arg2 = valuePop(ctxt);
13423
13424            CHECK_TYPE0(XPATH_NODESET);
13425            arg1 = valuePop(ctxt);
13426
13427	    if ((arg1->nodesetval == NULL) ||
13428		((arg2->nodesetval != NULL) &&
13429		 (arg2->nodesetval->nodeNr != 0)))
13430	    {
13431		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13432							arg2->nodesetval);
13433	    }
13434
13435            valuePush(ctxt, arg1);
13436	    xmlXPathReleaseObject(ctxt->context, arg2);
13437            return (total);
13438        case XPATH_OP_ROOT:
13439            xmlXPathRoot(ctxt);
13440            return (total);
13441        case XPATH_OP_NODE:
13442            if (op->ch1 != -1)
13443                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13444	    CHECK_ERROR0;
13445            if (op->ch2 != -1)
13446                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13447	    CHECK_ERROR0;
13448	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13449		ctxt->context->node));
13450            return (total);
13451        case XPATH_OP_RESET:
13452            if (op->ch1 != -1)
13453                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13454	    CHECK_ERROR0;
13455            if (op->ch2 != -1)
13456                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13457	    CHECK_ERROR0;
13458            ctxt->context->node = NULL;
13459            return (total);
13460        case XPATH_OP_COLLECT:{
13461                if (op->ch1 == -1)
13462                    return (total);
13463
13464                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13465		CHECK_ERROR0;
13466
13467                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13468                return (total);
13469            }
13470        case XPATH_OP_VALUE:
13471            valuePush(ctxt,
13472                      xmlXPathCacheObjectCopy(ctxt->context,
13473			(xmlXPathObjectPtr) op->value4));
13474            return (total);
13475        case XPATH_OP_VARIABLE:{
13476		xmlXPathObjectPtr val;
13477
13478                if (op->ch1 != -1)
13479                    total +=
13480                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13481                if (op->value5 == NULL) {
13482		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13483		    if (val == NULL) {
13484			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13485			return(0);
13486		    }
13487                    valuePush(ctxt, val);
13488		} else {
13489                    const xmlChar *URI;
13490
13491                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13492                    if (URI == NULL) {
13493                        xmlGenericError(xmlGenericErrorContext,
13494            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13495                                    (char *) op->value4, (char *)op->value5);
13496                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13497                        return (total);
13498                    }
13499		    val = xmlXPathVariableLookupNS(ctxt->context,
13500                                                       op->value4, URI);
13501		    if (val == NULL) {
13502			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13503			return(0);
13504		    }
13505                    valuePush(ctxt, val);
13506                }
13507                return (total);
13508            }
13509        case XPATH_OP_FUNCTION:{
13510                xmlXPathFunction func;
13511                const xmlChar *oldFunc, *oldFuncURI;
13512		int i;
13513                int frame;
13514
13515                frame = xmlXPathSetFrame(ctxt);
13516                if (op->ch1 != -1)
13517                    total +=
13518                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13519		if (ctxt->valueNr < op->value) {
13520		    xmlGenericError(xmlGenericErrorContext,
13521			    "xmlXPathCompOpEval: parameter error\n");
13522		    ctxt->error = XPATH_INVALID_OPERAND;
13523                    xmlXPathPopFrame(ctxt, frame);
13524		    return (total);
13525		}
13526		for (i = 0; i < op->value; i++) {
13527		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13528			xmlGenericError(xmlGenericErrorContext,
13529				"xmlXPathCompOpEval: parameter error\n");
13530			ctxt->error = XPATH_INVALID_OPERAND;
13531                        xmlXPathPopFrame(ctxt, frame);
13532			return (total);
13533		    }
13534                }
13535                if (op->cache != NULL)
13536                    XML_CAST_FPTR(func) = op->cache;
13537                else {
13538                    const xmlChar *URI = NULL;
13539
13540                    if (op->value5 == NULL)
13541                        func =
13542                            xmlXPathFunctionLookup(ctxt->context,
13543                                                   op->value4);
13544                    else {
13545                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13546                        if (URI == NULL) {
13547                            xmlGenericError(xmlGenericErrorContext,
13548            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13549                                    (char *)op->value4, (char *)op->value5);
13550                            xmlXPathPopFrame(ctxt, frame);
13551                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13552                            return (total);
13553                        }
13554                        func = xmlXPathFunctionLookupNS(ctxt->context,
13555                                                        op->value4, URI);
13556                    }
13557                    if (func == NULL) {
13558                        xmlGenericError(xmlGenericErrorContext,
13559                                "xmlXPathCompOpEval: function %s not found\n",
13560                                        (char *)op->value4);
13561                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13562                    }
13563                    op->cache = XML_CAST_FPTR(func);
13564                    op->cacheURI = (void *) URI;
13565                }
13566                oldFunc = ctxt->context->function;
13567                oldFuncURI = ctxt->context->functionURI;
13568                ctxt->context->function = op->value4;
13569                ctxt->context->functionURI = op->cacheURI;
13570                func(ctxt, op->value);
13571                ctxt->context->function = oldFunc;
13572                ctxt->context->functionURI = oldFuncURI;
13573                xmlXPathPopFrame(ctxt, frame);
13574                return (total);
13575            }
13576        case XPATH_OP_ARG:
13577	    bakd = ctxt->context->doc;
13578	    bak = ctxt->context->node;
13579	    pp = ctxt->context->proximityPosition;
13580	    cs = ctxt->context->contextSize;
13581            if (op->ch1 != -1)
13582                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13583	    ctxt->context->contextSize = cs;
13584	    ctxt->context->proximityPosition = pp;
13585	    ctxt->context->node = bak;
13586	    ctxt->context->doc = bakd;
13587	    CHECK_ERROR0;
13588            if (op->ch2 != -1) {
13589                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13590	        ctxt->context->doc = bakd;
13591	        ctxt->context->node = bak;
13592	        CHECK_ERROR0;
13593	    }
13594            return (total);
13595        case XPATH_OP_PREDICATE:
13596        case XPATH_OP_FILTER:{
13597                xmlXPathObjectPtr res;
13598                xmlXPathObjectPtr obj, tmp;
13599                xmlNodeSetPtr newset = NULL;
13600                xmlNodeSetPtr oldset;
13601                xmlNodePtr oldnode;
13602		xmlDocPtr oldDoc;
13603                int i;
13604
13605                /*
13606                 * Optimization for ()[1] selection i.e. the first elem
13607                 */
13608                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13609#ifdef XP_OPTIMIZED_FILTER_FIRST
13610		    /*
13611		    * FILTER TODO: Can we assume that the inner processing
13612		    *  will result in an ordered list if we have an
13613		    *  XPATH_OP_FILTER?
13614		    *  What about an additional field or flag on
13615		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13616		    *  to assume anything, so it would be more robust and
13617		    *  easier to optimize.
13618		    */
13619                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13620		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13621#else
13622		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13623#endif
13624                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13625                    xmlXPathObjectPtr val;
13626
13627                    val = comp->steps[op->ch2].value4;
13628                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13629                        (val->floatval == 1.0)) {
13630                        xmlNodePtr first = NULL;
13631
13632                        total +=
13633                            xmlXPathCompOpEvalFirst(ctxt,
13634                                                    &comp->steps[op->ch1],
13635                                                    &first);
13636			CHECK_ERROR0;
13637                        /*
13638                         * The nodeset should be in document order,
13639                         * Keep only the first value
13640                         */
13641                        if ((ctxt->value != NULL) &&
13642                            (ctxt->value->type == XPATH_NODESET) &&
13643                            (ctxt->value->nodesetval != NULL) &&
13644                            (ctxt->value->nodesetval->nodeNr > 1))
13645                            ctxt->value->nodesetval->nodeNr = 1;
13646                        return (total);
13647                    }
13648                }
13649                /*
13650                 * Optimization for ()[last()] selection i.e. the last elem
13651                 */
13652                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13653                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13654                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13655                    int f = comp->steps[op->ch2].ch1;
13656
13657                    if ((f != -1) &&
13658                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13659                        (comp->steps[f].value5 == NULL) &&
13660                        (comp->steps[f].value == 0) &&
13661                        (comp->steps[f].value4 != NULL) &&
13662                        (xmlStrEqual
13663                         (comp->steps[f].value4, BAD_CAST "last"))) {
13664                        xmlNodePtr last = NULL;
13665
13666                        total +=
13667                            xmlXPathCompOpEvalLast(ctxt,
13668                                                   &comp->steps[op->ch1],
13669                                                   &last);
13670			CHECK_ERROR0;
13671                        /*
13672                         * The nodeset should be in document order,
13673                         * Keep only the last value
13674                         */
13675                        if ((ctxt->value != NULL) &&
13676                            (ctxt->value->type == XPATH_NODESET) &&
13677                            (ctxt->value->nodesetval != NULL) &&
13678                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13679                            (ctxt->value->nodesetval->nodeNr > 1)) {
13680                            ctxt->value->nodesetval->nodeTab[0] =
13681                                ctxt->value->nodesetval->nodeTab[ctxt->
13682                                                                 value->
13683                                                                 nodesetval->
13684                                                                 nodeNr -
13685                                                                 1];
13686                            ctxt->value->nodesetval->nodeNr = 1;
13687                        }
13688                        return (total);
13689                    }
13690                }
13691		/*
13692		* Process inner predicates first.
13693		* Example "index[parent::book][1]":
13694		* ...
13695		*   PREDICATE   <-- we are here "[1]"
13696		*     PREDICATE <-- process "[parent::book]" first
13697		*       SORT
13698		*         COLLECT  'parent' 'name' 'node' book
13699		*           NODE
13700		*     ELEM Object is a number : 1
13701		*/
13702                if (op->ch1 != -1)
13703                    total +=
13704                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13705		CHECK_ERROR0;
13706                if (op->ch2 == -1)
13707                    return (total);
13708                if (ctxt->value == NULL)
13709                    return (total);
13710
13711                oldnode = ctxt->context->node;
13712
13713#ifdef LIBXML_XPTR_ENABLED
13714                /*
13715                 * Hum are we filtering the result of an XPointer expression
13716                 */
13717                if (ctxt->value->type == XPATH_LOCATIONSET) {
13718                    xmlLocationSetPtr newlocset = NULL;
13719                    xmlLocationSetPtr oldlocset;
13720
13721                    /*
13722                     * Extract the old locset, and then evaluate the result of the
13723                     * expression for all the element in the locset. use it to grow
13724                     * up a new locset.
13725                     */
13726                    CHECK_TYPE0(XPATH_LOCATIONSET);
13727                    obj = valuePop(ctxt);
13728                    oldlocset = obj->user;
13729                    ctxt->context->node = NULL;
13730
13731                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13732                        ctxt->context->contextSize = 0;
13733                        ctxt->context->proximityPosition = 0;
13734                        if (op->ch2 != -1)
13735                            total +=
13736                                xmlXPathCompOpEval(ctxt,
13737                                                   &comp->steps[op->ch2]);
13738                        res = valuePop(ctxt);
13739                        if (res != NULL) {
13740			    xmlXPathReleaseObject(ctxt->context, res);
13741			}
13742                        valuePush(ctxt, obj);
13743                        CHECK_ERROR0;
13744                        return (total);
13745                    }
13746                    newlocset = xmlXPtrLocationSetCreate(NULL);
13747
13748                    for (i = 0; i < oldlocset->locNr; i++) {
13749                        /*
13750                         * Run the evaluation with a node list made of a
13751                         * single item in the nodelocset.
13752                         */
13753                        ctxt->context->node = oldlocset->locTab[i]->user;
13754                        ctxt->context->contextSize = oldlocset->locNr;
13755                        ctxt->context->proximityPosition = i + 1;
13756			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13757			    ctxt->context->node);
13758                        valuePush(ctxt, tmp);
13759
13760                        if (op->ch2 != -1)
13761                            total +=
13762                                xmlXPathCompOpEval(ctxt,
13763                                                   &comp->steps[op->ch2]);
13764			if (ctxt->error != XPATH_EXPRESSION_OK) {
13765			    xmlXPathFreeObject(obj);
13766			    return(0);
13767			}
13768
13769                        /*
13770                         * The result of the evaluation need to be tested to
13771                         * decided whether the filter succeeded or not
13772                         */
13773                        res = valuePop(ctxt);
13774                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13775                            xmlXPtrLocationSetAdd(newlocset,
13776                                                  xmlXPathObjectCopy
13777                                                  (oldlocset->locTab[i]));
13778                        }
13779
13780                        /*
13781                         * Cleanup
13782                         */
13783                        if (res != NULL) {
13784			    xmlXPathReleaseObject(ctxt->context, res);
13785			}
13786                        if (ctxt->value == tmp) {
13787                            res = valuePop(ctxt);
13788			    xmlXPathReleaseObject(ctxt->context, res);
13789                        }
13790
13791                        ctxt->context->node = NULL;
13792                    }
13793
13794                    /*
13795                     * The result is used as the new evaluation locset.
13796                     */
13797		    xmlXPathReleaseObject(ctxt->context, obj);
13798                    ctxt->context->node = NULL;
13799                    ctxt->context->contextSize = -1;
13800                    ctxt->context->proximityPosition = -1;
13801                    valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13802                    ctxt->context->node = oldnode;
13803                    return (total);
13804                }
13805#endif /* LIBXML_XPTR_ENABLED */
13806
13807                /*
13808                 * Extract the old set, and then evaluate the result of the
13809                 * expression for all the element in the set. use it to grow
13810                 * up a new set.
13811                 */
13812                CHECK_TYPE0(XPATH_NODESET);
13813                obj = valuePop(ctxt);
13814                oldset = obj->nodesetval;
13815
13816                oldnode = ctxt->context->node;
13817		oldDoc = ctxt->context->doc;
13818                ctxt->context->node = NULL;
13819
13820                if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13821                    ctxt->context->contextSize = 0;
13822                    ctxt->context->proximityPosition = 0;
13823/*
13824                    if (op->ch2 != -1)
13825                        total +=
13826                            xmlXPathCompOpEval(ctxt,
13827                                               &comp->steps[op->ch2]);
13828		    CHECK_ERROR0;
13829                    res = valuePop(ctxt);
13830                    if (res != NULL)
13831                        xmlXPathFreeObject(res);
13832*/
13833                    valuePush(ctxt, obj);
13834                    ctxt->context->node = oldnode;
13835                    CHECK_ERROR0;
13836                } else {
13837		    tmp = NULL;
13838                    /*
13839                     * Initialize the new set.
13840		     * Also set the xpath document in case things like
13841		     * key() evaluation are attempted on the predicate
13842                     */
13843                    newset = xmlXPathNodeSetCreate(NULL);
13844		    /*
13845		    * SPEC XPath 1.0:
13846		    *  "For each node in the node-set to be filtered, the
13847		    *  PredicateExpr is evaluated with that node as the
13848		    *  context node, with the number of nodes in the
13849		    *  node-set as the context size, and with the proximity
13850		    *  position of the node in the node-set with respect to
13851		    *  the axis as the context position;"
13852		    * @oldset is the node-set" to be filtered.
13853		    *
13854		    * SPEC XPath 1.0:
13855		    *  "only predicates change the context position and
13856		    *  context size (see [2.4 Predicates])."
13857		    * Example:
13858		    *   node-set  context pos
13859		    *    nA         1
13860		    *    nB         2
13861		    *    nC         3
13862		    *   After applying predicate [position() > 1] :
13863		    *   node-set  context pos
13864		    *    nB         1
13865		    *    nC         2
13866		    *
13867		    * removed the first node in the node-set, then
13868		    * the context position of the
13869		    */
13870                    for (i = 0; i < oldset->nodeNr; i++) {
13871                        /*
13872                         * Run the evaluation with a node list made of
13873                         * a single item in the nodeset.
13874                         */
13875                        ctxt->context->node = oldset->nodeTab[i];
13876			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13877			    (oldset->nodeTab[i]->doc != NULL))
13878		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13879			if (tmp == NULL) {
13880			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13881				ctxt->context->node);
13882			} else {
13883			    if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13884				               ctxt->context->node) < 0) {
13885				ctxt->error = XPATH_MEMORY_ERROR;
13886			    }
13887			}
13888                        valuePush(ctxt, tmp);
13889                        ctxt->context->contextSize = oldset->nodeNr;
13890                        ctxt->context->proximityPosition = i + 1;
13891			/*
13892			* Evaluate the predicate against the context node.
13893			* Can/should we optimize position() predicates
13894			* here (e.g. "[1]")?
13895			*/
13896                        if (op->ch2 != -1)
13897                            total +=
13898                                xmlXPathCompOpEval(ctxt,
13899                                                   &comp->steps[op->ch2]);
13900			if (ctxt->error != XPATH_EXPRESSION_OK) {
13901			    xmlXPathFreeNodeSet(newset);
13902			    xmlXPathFreeObject(obj);
13903			    return(0);
13904			}
13905
13906                        /*
13907                         * The result of the evaluation needs to be tested to
13908                         * decide whether the filter succeeded or not
13909                         */
13910			/*
13911			* OPTIMIZE TODO: Can we use
13912			* xmlXPathNodeSetAdd*Unique()* instead?
13913			*/
13914                        res = valuePop(ctxt);
13915                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13916                            if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13917			        < 0)
13918				ctxt->error = XPATH_MEMORY_ERROR;
13919                        }
13920
13921                        /*
13922                         * Cleanup
13923                         */
13924                        if (res != NULL) {
13925			    xmlXPathReleaseObject(ctxt->context, res);
13926			}
13927                        if (ctxt->value == tmp) {
13928                            valuePop(ctxt);
13929			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13930			    /*
13931			    * Don't free the temporary nodeset
13932			    * in order to avoid massive recreation inside this
13933			    * loop.
13934			    */
13935                        } else
13936			    tmp = NULL;
13937                        ctxt->context->node = NULL;
13938                    }
13939		    if (tmp != NULL)
13940			xmlXPathReleaseObject(ctxt->context, tmp);
13941                    /*
13942                     * The result is used as the new evaluation set.
13943                     */
13944		    xmlXPathReleaseObject(ctxt->context, obj);
13945                    ctxt->context->node = NULL;
13946                    ctxt->context->contextSize = -1;
13947                    ctxt->context->proximityPosition = -1;
13948		    /* may want to move this past the '}' later */
13949		    ctxt->context->doc = oldDoc;
13950		    valuePush(ctxt,
13951			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13952                }
13953                ctxt->context->node = oldnode;
13954                return (total);
13955            }
13956        case XPATH_OP_SORT:
13957            if (op->ch1 != -1)
13958                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13959	    CHECK_ERROR0;
13960            if ((ctxt->value != NULL) &&
13961                (ctxt->value->type == XPATH_NODESET) &&
13962                (ctxt->value->nodesetval != NULL) &&
13963		(ctxt->value->nodesetval->nodeNr > 1))
13964	    {
13965                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13966	    }
13967            return (total);
13968#ifdef LIBXML_XPTR_ENABLED
13969        case XPATH_OP_RANGETO:{
13970                xmlXPathObjectPtr range;
13971                xmlXPathObjectPtr res, obj;
13972                xmlXPathObjectPtr tmp;
13973                xmlLocationSetPtr newlocset = NULL;
13974		    xmlLocationSetPtr oldlocset;
13975                xmlNodeSetPtr oldset;
13976                int i, j;
13977
13978                if (op->ch1 != -1)
13979                    total +=
13980                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13981                if (op->ch2 == -1)
13982                    return (total);
13983
13984                if (ctxt->value->type == XPATH_LOCATIONSET) {
13985                    /*
13986                     * Extract the old locset, and then evaluate the result of the
13987                     * expression for all the element in the locset. use it to grow
13988                     * up a new locset.
13989                     */
13990                    CHECK_TYPE0(XPATH_LOCATIONSET);
13991                    obj = valuePop(ctxt);
13992                    oldlocset = obj->user;
13993
13994                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13995		        ctxt->context->node = NULL;
13996                        ctxt->context->contextSize = 0;
13997                        ctxt->context->proximityPosition = 0;
13998                        total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13999                        res = valuePop(ctxt);
14000                        if (res != NULL) {
14001			    xmlXPathReleaseObject(ctxt->context, res);
14002			}
14003                        valuePush(ctxt, obj);
14004                        CHECK_ERROR0;
14005                        return (total);
14006                    }
14007                    newlocset = xmlXPtrLocationSetCreate(NULL);
14008
14009                    for (i = 0; i < oldlocset->locNr; i++) {
14010                        /*
14011                         * Run the evaluation with a node list made of a
14012                         * single item in the nodelocset.
14013                         */
14014                        ctxt->context->node = oldlocset->locTab[i]->user;
14015                        ctxt->context->contextSize = oldlocset->locNr;
14016                        ctxt->context->proximityPosition = i + 1;
14017			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14018			    ctxt->context->node);
14019                        valuePush(ctxt, tmp);
14020
14021                        if (op->ch2 != -1)
14022                            total +=
14023                                xmlXPathCompOpEval(ctxt,
14024                                                   &comp->steps[op->ch2]);
14025			if (ctxt->error != XPATH_EXPRESSION_OK) {
14026			    xmlXPathFreeObject(obj);
14027			    return(0);
14028			}
14029
14030                        res = valuePop(ctxt);
14031			if (res->type == XPATH_LOCATIONSET) {
14032			    xmlLocationSetPtr rloc =
14033			        (xmlLocationSetPtr)res->user;
14034			    for (j=0; j<rloc->locNr; j++) {
14035			        range = xmlXPtrNewRange(
14036				  oldlocset->locTab[i]->user,
14037				  oldlocset->locTab[i]->index,
14038				  rloc->locTab[j]->user2,
14039				  rloc->locTab[j]->index2);
14040				if (range != NULL) {
14041				    xmlXPtrLocationSetAdd(newlocset, range);
14042				}
14043			    }
14044			} else {
14045			    range = xmlXPtrNewRangeNodeObject(
14046				(xmlNodePtr)oldlocset->locTab[i]->user, res);
14047                            if (range != NULL) {
14048                                xmlXPtrLocationSetAdd(newlocset,range);
14049			    }
14050                        }
14051
14052                        /*
14053                         * Cleanup
14054                         */
14055                        if (res != NULL) {
14056			    xmlXPathReleaseObject(ctxt->context, res);
14057			}
14058                        if (ctxt->value == tmp) {
14059                            res = valuePop(ctxt);
14060			    xmlXPathReleaseObject(ctxt->context, res);
14061                        }
14062
14063                        ctxt->context->node = NULL;
14064                    }
14065		} else {	/* Not a location set */
14066                    CHECK_TYPE0(XPATH_NODESET);
14067                    obj = valuePop(ctxt);
14068                    oldset = obj->nodesetval;
14069                    ctxt->context->node = NULL;
14070
14071                    newlocset = xmlXPtrLocationSetCreate(NULL);
14072
14073                    if (oldset != NULL) {
14074                        for (i = 0; i < oldset->nodeNr; i++) {
14075                            /*
14076                             * Run the evaluation with a node list made of a single item
14077                             * in the nodeset.
14078                             */
14079                            ctxt->context->node = oldset->nodeTab[i];
14080			    /*
14081			    * OPTIMIZE TODO: Avoid recreation for every iteration.
14082			    */
14083			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14084				ctxt->context->node);
14085                            valuePush(ctxt, tmp);
14086
14087                            if (op->ch2 != -1)
14088                                total +=
14089                                    xmlXPathCompOpEval(ctxt,
14090                                                   &comp->steps[op->ch2]);
14091			    if (ctxt->error != XPATH_EXPRESSION_OK) {
14092				xmlXPathFreeObject(obj);
14093				return(0);
14094			    }
14095
14096                            res = valuePop(ctxt);
14097                            range =
14098                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14099                                                      res);
14100                            if (range != NULL) {
14101                                xmlXPtrLocationSetAdd(newlocset, range);
14102                            }
14103
14104                            /*
14105                             * Cleanup
14106                             */
14107                            if (res != NULL) {
14108				xmlXPathReleaseObject(ctxt->context, res);
14109			    }
14110                            if (ctxt->value == tmp) {
14111                                res = valuePop(ctxt);
14112				xmlXPathReleaseObject(ctxt->context, res);
14113                            }
14114
14115                            ctxt->context->node = NULL;
14116                        }
14117                    }
14118                }
14119
14120                /*
14121                 * The result is used as the new evaluation set.
14122                 */
14123		xmlXPathReleaseObject(ctxt->context, obj);
14124                ctxt->context->node = NULL;
14125                ctxt->context->contextSize = -1;
14126                ctxt->context->proximityPosition = -1;
14127                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14128                return (total);
14129            }
14130#endif /* LIBXML_XPTR_ENABLED */
14131    }
14132    xmlGenericError(xmlGenericErrorContext,
14133                    "XPath: unknown precompiled operation %d\n", op->op);
14134    ctxt->error = XPATH_INVALID_OPERAND;
14135    return (total);
14136}
14137
14138/**
14139 * xmlXPathCompOpEvalToBoolean:
14140 * @ctxt:  the XPath parser context
14141 *
14142 * Evaluates if the expression evaluates to true.
14143 *
14144 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14145 */
14146static int
14147xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14148			    xmlXPathStepOpPtr op,
14149			    int isPredicate)
14150{
14151    xmlXPathObjectPtr resObj = NULL;
14152
14153start:
14154    /* comp = ctxt->comp; */
14155    switch (op->op) {
14156        case XPATH_OP_END:
14157            return (0);
14158	case XPATH_OP_VALUE:
14159	    resObj = (xmlXPathObjectPtr) op->value4;
14160	    if (isPredicate)
14161		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14162	    return(xmlXPathCastToBoolean(resObj));
14163	case XPATH_OP_SORT:
14164	    /*
14165	    * We don't need sorting for boolean results. Skip this one.
14166	    */
14167            if (op->ch1 != -1) {
14168		op = &ctxt->comp->steps[op->ch1];
14169		goto start;
14170	    }
14171	    return(0);
14172	case XPATH_OP_COLLECT:
14173	    if (op->ch1 == -1)
14174		return(0);
14175
14176            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14177	    if (ctxt->error != XPATH_EXPRESSION_OK)
14178		return(-1);
14179
14180            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14181	    if (ctxt->error != XPATH_EXPRESSION_OK)
14182		return(-1);
14183
14184	    resObj = valuePop(ctxt);
14185	    if (resObj == NULL)
14186		return(-1);
14187	    break;
14188	default:
14189	    /*
14190	    * Fallback to call xmlXPathCompOpEval().
14191	    */
14192	    xmlXPathCompOpEval(ctxt, op);
14193	    if (ctxt->error != XPATH_EXPRESSION_OK)
14194		return(-1);
14195
14196	    resObj = valuePop(ctxt);
14197	    if (resObj == NULL)
14198		return(-1);
14199	    break;
14200    }
14201
14202    if (resObj) {
14203	int res;
14204
14205	if (resObj->type == XPATH_BOOLEAN) {
14206	    res = resObj->boolval;
14207	} else if (isPredicate) {
14208	    /*
14209	    * For predicates a result of type "number" is handled
14210	    * differently:
14211	    * SPEC XPath 1.0:
14212	    * "If the result is a number, the result will be converted
14213	    *  to true if the number is equal to the context position
14214	    *  and will be converted to false otherwise;"
14215	    */
14216	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14217	} else {
14218	    res = xmlXPathCastToBoolean(resObj);
14219	}
14220	xmlXPathReleaseObject(ctxt->context, resObj);
14221	return(res);
14222    }
14223
14224    return(0);
14225}
14226
14227#ifdef XPATH_STREAMING
14228/**
14229 * xmlXPathRunStreamEval:
14230 * @ctxt:  the XPath parser context with the compiled expression
14231 *
14232 * Evaluate the Precompiled Streamable XPath expression in the given context.
14233 */
14234static int
14235xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14236		      xmlXPathObjectPtr *resultSeq, int toBool)
14237{
14238    int max_depth, min_depth;
14239    int from_root;
14240    int ret, depth;
14241    int eval_all_nodes;
14242    xmlNodePtr cur = NULL, limit = NULL;
14243    xmlStreamCtxtPtr patstream = NULL;
14244
14245    int nb_nodes = 0;
14246
14247    if ((ctxt == NULL) || (comp == NULL))
14248        return(-1);
14249    max_depth = xmlPatternMaxDepth(comp);
14250    if (max_depth == -1)
14251        return(-1);
14252    if (max_depth == -2)
14253        max_depth = 10000;
14254    min_depth = xmlPatternMinDepth(comp);
14255    if (min_depth == -1)
14256        return(-1);
14257    from_root = xmlPatternFromRoot(comp);
14258    if (from_root < 0)
14259        return(-1);
14260#if 0
14261    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14262#endif
14263
14264    if (! toBool) {
14265	if (resultSeq == NULL)
14266	    return(-1);
14267	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14268	if (*resultSeq == NULL)
14269	    return(-1);
14270    }
14271
14272    /*
14273     * handle the special cases of "/" amd "." being matched
14274     */
14275    if (min_depth == 0) {
14276	if (from_root) {
14277	    /* Select "/" */
14278	    if (toBool)
14279		return(1);
14280	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14281		                     (xmlNodePtr) ctxt->doc);
14282	} else {
14283	    /* Select "self::node()" */
14284	    if (toBool)
14285		return(1);
14286	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14287	}
14288    }
14289    if (max_depth == 0) {
14290	return(0);
14291    }
14292
14293    if (from_root) {
14294        cur = (xmlNodePtr)ctxt->doc;
14295    } else if (ctxt->node != NULL) {
14296        switch (ctxt->node->type) {
14297            case XML_ELEMENT_NODE:
14298            case XML_DOCUMENT_NODE:
14299            case XML_DOCUMENT_FRAG_NODE:
14300            case XML_HTML_DOCUMENT_NODE:
14301#ifdef LIBXML_DOCB_ENABLED
14302            case XML_DOCB_DOCUMENT_NODE:
14303#endif
14304	        cur = ctxt->node;
14305		break;
14306            case XML_ATTRIBUTE_NODE:
14307            case XML_TEXT_NODE:
14308            case XML_CDATA_SECTION_NODE:
14309            case XML_ENTITY_REF_NODE:
14310            case XML_ENTITY_NODE:
14311            case XML_PI_NODE:
14312            case XML_COMMENT_NODE:
14313            case XML_NOTATION_NODE:
14314            case XML_DTD_NODE:
14315            case XML_DOCUMENT_TYPE_NODE:
14316            case XML_ELEMENT_DECL:
14317            case XML_ATTRIBUTE_DECL:
14318            case XML_ENTITY_DECL:
14319            case XML_NAMESPACE_DECL:
14320            case XML_XINCLUDE_START:
14321            case XML_XINCLUDE_END:
14322		break;
14323	}
14324	limit = cur;
14325    }
14326    if (cur == NULL) {
14327        return(0);
14328    }
14329
14330    patstream = xmlPatternGetStreamCtxt(comp);
14331    if (patstream == NULL) {
14332	/*
14333	* QUESTION TODO: Is this an error?
14334	*/
14335	return(0);
14336    }
14337
14338    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14339
14340    if (from_root) {
14341	ret = xmlStreamPush(patstream, NULL, NULL);
14342	if (ret < 0) {
14343	} else if (ret == 1) {
14344	    if (toBool)
14345		goto return_1;
14346	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14347	}
14348    }
14349    depth = 0;
14350    goto scan_children;
14351next_node:
14352    do {
14353        nb_nodes++;
14354
14355	switch (cur->type) {
14356	    case XML_ELEMENT_NODE:
14357	    case XML_TEXT_NODE:
14358	    case XML_CDATA_SECTION_NODE:
14359	    case XML_COMMENT_NODE:
14360	    case XML_PI_NODE:
14361		if (cur->type == XML_ELEMENT_NODE) {
14362		    ret = xmlStreamPush(patstream, cur->name,
14363				(cur->ns ? cur->ns->href : NULL));
14364		} else if (eval_all_nodes)
14365		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14366		else
14367		    break;
14368
14369		if (ret < 0) {
14370		    /* NOP. */
14371		} else if (ret == 1) {
14372		    if (toBool)
14373			goto return_1;
14374		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14375		        < 0) {
14376			ctxt->lastError.domain = XML_FROM_XPATH;
14377			ctxt->lastError.code = XML_ERR_NO_MEMORY;
14378		    }
14379		}
14380		if ((cur->children == NULL) || (depth >= max_depth)) {
14381		    ret = xmlStreamPop(patstream);
14382		    while (cur->next != NULL) {
14383			cur = cur->next;
14384			if ((cur->type != XML_ENTITY_DECL) &&
14385			    (cur->type != XML_DTD_NODE))
14386			    goto next_node;
14387		    }
14388		}
14389	    default:
14390		break;
14391	}
14392
14393scan_children:
14394	if (cur->type == XML_NAMESPACE_DECL) break;
14395	if ((cur->children != NULL) && (depth < max_depth)) {
14396	    /*
14397	     * Do not descend on entities declarations
14398	     */
14399	    if (cur->children->type != XML_ENTITY_DECL) {
14400		cur = cur->children;
14401		depth++;
14402		/*
14403		 * Skip DTDs
14404		 */
14405		if (cur->type != XML_DTD_NODE)
14406		    continue;
14407	    }
14408	}
14409
14410	if (cur == limit)
14411	    break;
14412
14413	while (cur->next != NULL) {
14414	    cur = cur->next;
14415	    if ((cur->type != XML_ENTITY_DECL) &&
14416		(cur->type != XML_DTD_NODE))
14417		goto next_node;
14418	}
14419
14420	do {
14421	    cur = cur->parent;
14422	    depth--;
14423	    if ((cur == NULL) || (cur == limit))
14424	        goto done;
14425	    if (cur->type == XML_ELEMENT_NODE) {
14426		ret = xmlStreamPop(patstream);
14427	    } else if ((eval_all_nodes) &&
14428		((cur->type == XML_TEXT_NODE) ||
14429		 (cur->type == XML_CDATA_SECTION_NODE) ||
14430		 (cur->type == XML_COMMENT_NODE) ||
14431		 (cur->type == XML_PI_NODE)))
14432	    {
14433		ret = xmlStreamPop(patstream);
14434	    }
14435	    if (cur->next != NULL) {
14436		cur = cur->next;
14437		break;
14438	    }
14439	} while (cur != NULL);
14440
14441    } while ((cur != NULL) && (depth >= 0));
14442
14443done:
14444
14445#if 0
14446    printf("stream eval: checked %d nodes selected %d\n",
14447           nb_nodes, retObj->nodesetval->nodeNr);
14448#endif
14449
14450    if (patstream)
14451	xmlFreeStreamCtxt(patstream);
14452    return(0);
14453
14454return_1:
14455    if (patstream)
14456	xmlFreeStreamCtxt(patstream);
14457    return(1);
14458}
14459#endif /* XPATH_STREAMING */
14460
14461/**
14462 * xmlXPathRunEval:
14463 * @ctxt:  the XPath parser context with the compiled expression
14464 * @toBool:  evaluate to a boolean result
14465 *
14466 * Evaluate the Precompiled XPath expression in the given context.
14467 */
14468static int
14469xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14470{
14471    xmlXPathCompExprPtr comp;
14472
14473    if ((ctxt == NULL) || (ctxt->comp == NULL))
14474	return(-1);
14475
14476    if (ctxt->valueTab == NULL) {
14477	/* Allocate the value stack */
14478	ctxt->valueTab = (xmlXPathObjectPtr *)
14479			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14480	if (ctxt->valueTab == NULL) {
14481	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14482	    xmlFree(ctxt);
14483	}
14484	ctxt->valueNr = 0;
14485	ctxt->valueMax = 10;
14486	ctxt->value = NULL;
14487        ctxt->valueFrame = 0;
14488    }
14489#ifdef XPATH_STREAMING
14490    if (ctxt->comp->stream) {
14491	int res;
14492
14493	if (toBool) {
14494	    /*
14495	    * Evaluation to boolean result.
14496	    */
14497	    res = xmlXPathRunStreamEval(ctxt->context,
14498		ctxt->comp->stream, NULL, 1);
14499	    if (res != -1)
14500		return(res);
14501	} else {
14502	    xmlXPathObjectPtr resObj = NULL;
14503
14504	    /*
14505	    * Evaluation to a sequence.
14506	    */
14507	    res = xmlXPathRunStreamEval(ctxt->context,
14508		ctxt->comp->stream, &resObj, 0);
14509
14510	    if ((res != -1) && (resObj != NULL)) {
14511		valuePush(ctxt, resObj);
14512		return(0);
14513	    }
14514	    if (resObj != NULL)
14515		xmlXPathReleaseObject(ctxt->context, resObj);
14516	}
14517	/*
14518	* QUESTION TODO: This falls back to normal XPath evaluation
14519	* if res == -1. Is this intended?
14520	*/
14521    }
14522#endif
14523    comp = ctxt->comp;
14524    if (comp->last < 0) {
14525	xmlGenericError(xmlGenericErrorContext,
14526	    "xmlXPathRunEval: last is less than zero\n");
14527	return(-1);
14528    }
14529    if (toBool)
14530	return(xmlXPathCompOpEvalToBoolean(ctxt,
14531	    &comp->steps[comp->last], 0));
14532    else
14533	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14534
14535    return(0);
14536}
14537
14538/************************************************************************
14539 *									*
14540 *			Public interfaces				*
14541 *									*
14542 ************************************************************************/
14543
14544/**
14545 * xmlXPathEvalPredicate:
14546 * @ctxt:  the XPath context
14547 * @res:  the Predicate Expression evaluation result
14548 *
14549 * Evaluate a predicate result for the current node.
14550 * A PredicateExpr is evaluated by evaluating the Expr and converting
14551 * the result to a boolean. If the result is a number, the result will
14552 * be converted to true if the number is equal to the position of the
14553 * context node in the context node list (as returned by the position
14554 * function) and will be converted to false otherwise; if the result
14555 * is not a number, then the result will be converted as if by a call
14556 * to the boolean function.
14557 *
14558 * Returns 1 if predicate is true, 0 otherwise
14559 */
14560int
14561xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14562    if ((ctxt == NULL) || (res == NULL)) return(0);
14563    switch (res->type) {
14564        case XPATH_BOOLEAN:
14565	    return(res->boolval);
14566        case XPATH_NUMBER:
14567	    return(res->floatval == ctxt->proximityPosition);
14568        case XPATH_NODESET:
14569        case XPATH_XSLT_TREE:
14570	    if (res->nodesetval == NULL)
14571		return(0);
14572	    return(res->nodesetval->nodeNr != 0);
14573        case XPATH_STRING:
14574	    return((res->stringval != NULL) &&
14575	           (xmlStrlen(res->stringval) != 0));
14576        default:
14577	    STRANGE
14578    }
14579    return(0);
14580}
14581
14582/**
14583 * xmlXPathEvaluatePredicateResult:
14584 * @ctxt:  the XPath Parser context
14585 * @res:  the Predicate Expression evaluation result
14586 *
14587 * Evaluate a predicate result for the current node.
14588 * A PredicateExpr is evaluated by evaluating the Expr and converting
14589 * the result to a boolean. If the result is a number, the result will
14590 * be converted to true if the number is equal to the position of the
14591 * context node in the context node list (as returned by the position
14592 * function) and will be converted to false otherwise; if the result
14593 * is not a number, then the result will be converted as if by a call
14594 * to the boolean function.
14595 *
14596 * Returns 1 if predicate is true, 0 otherwise
14597 */
14598int
14599xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14600                                xmlXPathObjectPtr res) {
14601    if ((ctxt == NULL) || (res == NULL)) return(0);
14602    switch (res->type) {
14603        case XPATH_BOOLEAN:
14604	    return(res->boolval);
14605        case XPATH_NUMBER:
14606#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14607	    return((res->floatval == ctxt->context->proximityPosition) &&
14608	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14609#else
14610	    return(res->floatval == ctxt->context->proximityPosition);
14611#endif
14612        case XPATH_NODESET:
14613        case XPATH_XSLT_TREE:
14614	    if (res->nodesetval == NULL)
14615		return(0);
14616	    return(res->nodesetval->nodeNr != 0);
14617        case XPATH_STRING:
14618	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14619#ifdef LIBXML_XPTR_ENABLED
14620	case XPATH_LOCATIONSET:{
14621	    xmlLocationSetPtr ptr = res->user;
14622	    if (ptr == NULL)
14623	        return(0);
14624	    return (ptr->locNr != 0);
14625	    }
14626#endif
14627        default:
14628	    STRANGE
14629    }
14630    return(0);
14631}
14632
14633#ifdef XPATH_STREAMING
14634/**
14635 * xmlXPathTryStreamCompile:
14636 * @ctxt: an XPath context
14637 * @str:  the XPath expression
14638 *
14639 * Try to compile the XPath expression as a streamable subset.
14640 *
14641 * Returns the compiled expression or NULL if failed to compile.
14642 */
14643static xmlXPathCompExprPtr
14644xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14645    /*
14646     * Optimization: use streaming patterns when the XPath expression can
14647     * be compiled to a stream lookup
14648     */
14649    xmlPatternPtr stream;
14650    xmlXPathCompExprPtr comp;
14651    xmlDictPtr dict = NULL;
14652    const xmlChar **namespaces = NULL;
14653    xmlNsPtr ns;
14654    int i, j;
14655
14656    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14657        (!xmlStrchr(str, '@'))) {
14658	const xmlChar *tmp;
14659
14660	/*
14661	 * We don't try to handle expressions using the verbose axis
14662	 * specifiers ("::"), just the simplied form at this point.
14663	 * Additionally, if there is no list of namespaces available and
14664	 *  there's a ":" in the expression, indicating a prefixed QName,
14665	 *  then we won't try to compile either. xmlPatterncompile() needs
14666	 *  to have a list of namespaces at compilation time in order to
14667	 *  compile prefixed name tests.
14668	 */
14669	tmp = xmlStrchr(str, ':');
14670	if ((tmp != NULL) &&
14671	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14672	    return(NULL);
14673
14674	if (ctxt != NULL) {
14675	    dict = ctxt->dict;
14676	    if (ctxt->nsNr > 0) {
14677		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14678		if (namespaces == NULL) {
14679		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14680		    return(NULL);
14681		}
14682		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14683		    ns = ctxt->namespaces[j];
14684		    namespaces[i++] = ns->href;
14685		    namespaces[i++] = ns->prefix;
14686		}
14687		namespaces[i++] = NULL;
14688		namespaces[i] = NULL;
14689	    }
14690	}
14691
14692	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14693			&namespaces[0]);
14694	if (namespaces != NULL) {
14695	    xmlFree((xmlChar **)namespaces);
14696	}
14697	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14698	    comp = xmlXPathNewCompExpr();
14699	    if (comp == NULL) {
14700		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14701		return(NULL);
14702	    }
14703	    comp->stream = stream;
14704	    comp->dict = dict;
14705	    if (comp->dict)
14706		xmlDictReference(comp->dict);
14707	    return(comp);
14708	}
14709	xmlFreePattern(stream);
14710    }
14711    return(NULL);
14712}
14713#endif /* XPATH_STREAMING */
14714
14715static void
14716xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14717{
14718    /*
14719    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14720    * internal representation.
14721    */
14722
14723    if ((op->ch1 != -1) &&
14724        (op->op == XPATH_OP_COLLECT /* 11 */))
14725    {
14726        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14727
14728        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14729            ((xmlXPathAxisVal) prevop->value ==
14730                AXIS_DESCENDANT_OR_SELF) &&
14731            (prevop->ch2 == -1) &&
14732            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14733            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14734        {
14735            /*
14736            * This is a "descendant-or-self::node()" without predicates.
14737            * Try to eliminate it.
14738            */
14739
14740            switch ((xmlXPathAxisVal) op->value) {
14741                case AXIS_CHILD:
14742                case AXIS_DESCENDANT:
14743                    /*
14744                    * Convert "descendant-or-self::node()/child::" or
14745                    * "descendant-or-self::node()/descendant::" to
14746                    * "descendant::"
14747                    */
14748                    op->ch1   = prevop->ch1;
14749                    op->value = AXIS_DESCENDANT;
14750                    break;
14751                case AXIS_SELF:
14752                case AXIS_DESCENDANT_OR_SELF:
14753                    /*
14754                    * Convert "descendant-or-self::node()/self::" or
14755                    * "descendant-or-self::node()/descendant-or-self::" to
14756                    * to "descendant-or-self::"
14757                    */
14758                    op->ch1   = prevop->ch1;
14759                    op->value = AXIS_DESCENDANT_OR_SELF;
14760                    break;
14761                default:
14762                    break;
14763            }
14764	}
14765    }
14766
14767    /* Recurse */
14768    if (op->ch1 != -1)
14769        xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14770    if (op->ch2 != -1)
14771	xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14772}
14773
14774/**
14775 * xmlXPathCtxtCompile:
14776 * @ctxt: an XPath context
14777 * @str:  the XPath expression
14778 *
14779 * Compile an XPath expression
14780 *
14781 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14782 *         the caller has to free the object.
14783 */
14784xmlXPathCompExprPtr
14785xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14786    xmlXPathParserContextPtr pctxt;
14787    xmlXPathCompExprPtr comp;
14788
14789#ifdef XPATH_STREAMING
14790    comp = xmlXPathTryStreamCompile(ctxt, str);
14791    if (comp != NULL)
14792        return(comp);
14793#endif
14794
14795    xmlXPathInit();
14796
14797    pctxt = xmlXPathNewParserContext(str, ctxt);
14798    if (pctxt == NULL)
14799        return NULL;
14800    xmlXPathCompileExpr(pctxt, 1);
14801
14802    if( pctxt->error != XPATH_EXPRESSION_OK )
14803    {
14804        xmlXPathFreeParserContext(pctxt);
14805        return(NULL);
14806    }
14807
14808    if (*pctxt->cur != 0) {
14809	/*
14810	 * aleksey: in some cases this line prints *second* error message
14811	 * (see bug #78858) and probably this should be fixed.
14812	 * However, we are not sure that all error messages are printed
14813	 * out in other places. It's not critical so we leave it as-is for now
14814	 */
14815	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14816	comp = NULL;
14817    } else {
14818	comp = pctxt->comp;
14819	pctxt->comp = NULL;
14820    }
14821    xmlXPathFreeParserContext(pctxt);
14822
14823    if (comp != NULL) {
14824	comp->expr = xmlStrdup(str);
14825#ifdef DEBUG_EVAL_COUNTS
14826	comp->string = xmlStrdup(str);
14827	comp->nb = 0;
14828#endif
14829	if ((comp->nbStep > 1) && (comp->last >= 0)) {
14830	    xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14831	}
14832    }
14833    return(comp);
14834}
14835
14836/**
14837 * xmlXPathCompile:
14838 * @str:  the XPath expression
14839 *
14840 * Compile an XPath expression
14841 *
14842 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14843 *         the caller has to free the object.
14844 */
14845xmlXPathCompExprPtr
14846xmlXPathCompile(const xmlChar *str) {
14847    return(xmlXPathCtxtCompile(NULL, str));
14848}
14849
14850/**
14851 * xmlXPathCompiledEvalInternal:
14852 * @comp:  the compiled XPath expression
14853 * @ctxt:  the XPath context
14854 * @resObj: the resulting XPath object or NULL
14855 * @toBool: 1 if only a boolean result is requested
14856 *
14857 * Evaluate the Precompiled XPath expression in the given context.
14858 * The caller has to free @resObj.
14859 *
14860 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14861 *         the caller has to free the object.
14862 */
14863static int
14864xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14865			     xmlXPathContextPtr ctxt,
14866			     xmlXPathObjectPtr *resObj,
14867			     int toBool)
14868{
14869    xmlXPathParserContextPtr pctxt;
14870#ifndef LIBXML_THREAD_ENABLED
14871    static int reentance = 0;
14872#endif
14873    int res;
14874
14875    CHECK_CTXT_NEG(ctxt)
14876
14877    if (comp == NULL)
14878	return(-1);
14879    xmlXPathInit();
14880
14881#ifndef LIBXML_THREAD_ENABLED
14882    reentance++;
14883    if (reentance > 1)
14884	xmlXPathDisableOptimizer = 1;
14885#endif
14886
14887#ifdef DEBUG_EVAL_COUNTS
14888    comp->nb++;
14889    if ((comp->string != NULL) && (comp->nb > 100)) {
14890	fprintf(stderr, "100 x %s\n", comp->string);
14891	comp->nb = 0;
14892    }
14893#endif
14894    pctxt = xmlXPathCompParserContext(comp, ctxt);
14895    res = xmlXPathRunEval(pctxt, toBool);
14896
14897    if (resObj) {
14898	if (pctxt->value == NULL) {
14899	    xmlGenericError(xmlGenericErrorContext,
14900		"xmlXPathCompiledEval: evaluation failed\n");
14901	    *resObj = NULL;
14902	} else {
14903	    *resObj = valuePop(pctxt);
14904	}
14905    }
14906
14907    /*
14908    * Pop all remaining objects from the stack.
14909    */
14910    if (pctxt->valueNr > 0) {
14911	xmlXPathObjectPtr tmp;
14912	int stack = 0;
14913
14914	do {
14915	    tmp = valuePop(pctxt);
14916	    if (tmp != NULL) {
14917		stack++;
14918		xmlXPathReleaseObject(ctxt, tmp);
14919	    }
14920	} while (tmp != NULL);
14921	if ((stack != 0) &&
14922	    ((toBool) || ((resObj) && (*resObj))))
14923	{
14924	    xmlGenericError(xmlGenericErrorContext,
14925		"xmlXPathCompiledEval: %d objects left on the stack.\n",
14926		stack);
14927	}
14928    }
14929
14930    if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14931	xmlXPathFreeObject(*resObj);
14932	*resObj = NULL;
14933    }
14934    pctxt->comp = NULL;
14935    xmlXPathFreeParserContext(pctxt);
14936#ifndef LIBXML_THREAD_ENABLED
14937    reentance--;
14938#endif
14939
14940    return(res);
14941}
14942
14943/**
14944 * xmlXPathCompiledEval:
14945 * @comp:  the compiled XPath expression
14946 * @ctx:  the XPath context
14947 *
14948 * Evaluate the Precompiled XPath expression in the given context.
14949 *
14950 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14951 *         the caller has to free the object.
14952 */
14953xmlXPathObjectPtr
14954xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14955{
14956    xmlXPathObjectPtr res = NULL;
14957
14958    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14959    return(res);
14960}
14961
14962/**
14963 * xmlXPathCompiledEvalToBoolean:
14964 * @comp:  the compiled XPath expression
14965 * @ctxt:  the XPath context
14966 *
14967 * Applies the XPath boolean() function on the result of the given
14968 * compiled expression.
14969 *
14970 * Returns 1 if the expression evaluated to true, 0 if to false and
14971 *         -1 in API and internal errors.
14972 */
14973int
14974xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14975			      xmlXPathContextPtr ctxt)
14976{
14977    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14978}
14979
14980/**
14981 * xmlXPathEvalExpr:
14982 * @ctxt:  the XPath Parser context
14983 *
14984 * Parse and evaluate an XPath expression in the given context,
14985 * then push the result on the context stack
14986 */
14987void
14988xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14989#ifdef XPATH_STREAMING
14990    xmlXPathCompExprPtr comp;
14991#endif
14992
14993    if (ctxt == NULL) return;
14994
14995#ifdef XPATH_STREAMING
14996    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14997    if (comp != NULL) {
14998        if (ctxt->comp != NULL)
14999	    xmlXPathFreeCompExpr(ctxt->comp);
15000        ctxt->comp = comp;
15001	if (ctxt->cur != NULL)
15002	    while (*ctxt->cur != 0) ctxt->cur++;
15003    } else
15004#endif
15005    {
15006	xmlXPathCompileExpr(ctxt, 1);
15007	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
15008	    (ctxt->comp != NULL) &&
15009	    (ctxt->comp->nbStep > 1) &&
15010	    (ctxt->comp->last >= 0))
15011	{
15012	    xmlXPathOptimizeExpression(ctxt->comp,
15013		&ctxt->comp->steps[ctxt->comp->last]);
15014	}
15015    }
15016    CHECK_ERROR;
15017    xmlXPathRunEval(ctxt, 0);
15018}
15019
15020/**
15021 * xmlXPathEval:
15022 * @str:  the XPath expression
15023 * @ctx:  the XPath context
15024 *
15025 * Evaluate the XPath Location Path in the given context.
15026 *
15027 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15028 *         the caller has to free the object.
15029 */
15030xmlXPathObjectPtr
15031xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15032    xmlXPathParserContextPtr ctxt;
15033    xmlXPathObjectPtr res, tmp, init = NULL;
15034    int stack = 0;
15035
15036    CHECK_CTXT(ctx)
15037
15038    xmlXPathInit();
15039
15040    ctxt = xmlXPathNewParserContext(str, ctx);
15041    if (ctxt == NULL)
15042        return NULL;
15043    xmlXPathEvalExpr(ctxt);
15044
15045    if (ctxt->value == NULL) {
15046	xmlGenericError(xmlGenericErrorContext,
15047		"xmlXPathEval: evaluation failed\n");
15048	res = NULL;
15049    } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
15050#ifdef XPATH_STREAMING
15051            && (ctxt->comp->stream == NULL)
15052#endif
15053	      ) {
15054	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15055	res = NULL;
15056    } else {
15057	res = valuePop(ctxt);
15058    }
15059
15060    do {
15061        tmp = valuePop(ctxt);
15062	if (tmp != NULL) {
15063	    if (tmp != init)
15064		stack++;
15065	    xmlXPathReleaseObject(ctx, tmp);
15066        }
15067    } while (tmp != NULL);
15068    if ((stack != 0) && (res != NULL)) {
15069	xmlGenericError(xmlGenericErrorContext,
15070		"xmlXPathEval: %d object left on the stack\n",
15071	        stack);
15072    }
15073    if (ctxt->error != XPATH_EXPRESSION_OK) {
15074	xmlXPathFreeObject(res);
15075	res = NULL;
15076    }
15077
15078    xmlXPathFreeParserContext(ctxt);
15079    return(res);
15080}
15081
15082/**
15083 * xmlXPathEvalExpression:
15084 * @str:  the XPath expression
15085 * @ctxt:  the XPath context
15086 *
15087 * Evaluate the XPath expression in the given context.
15088 *
15089 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15090 *         the caller has to free the object.
15091 */
15092xmlXPathObjectPtr
15093xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15094    xmlXPathParserContextPtr pctxt;
15095    xmlXPathObjectPtr res, tmp;
15096    int stack = 0;
15097
15098    CHECK_CTXT(ctxt)
15099
15100    xmlXPathInit();
15101
15102    pctxt = xmlXPathNewParserContext(str, ctxt);
15103    if (pctxt == NULL)
15104        return NULL;
15105    xmlXPathEvalExpr(pctxt);
15106
15107    if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
15108	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15109	res = NULL;
15110    } else {
15111	res = valuePop(pctxt);
15112    }
15113    do {
15114        tmp = valuePop(pctxt);
15115	if (tmp != NULL) {
15116	    xmlXPathReleaseObject(ctxt, tmp);
15117	    stack++;
15118	}
15119    } while (tmp != NULL);
15120    if ((stack != 0) && (res != NULL)) {
15121	xmlGenericError(xmlGenericErrorContext,
15122		"xmlXPathEvalExpression: %d object left on the stack\n",
15123	        stack);
15124    }
15125    xmlXPathFreeParserContext(pctxt);
15126    return(res);
15127}
15128
15129/************************************************************************
15130 *									*
15131 *	Extra functions not pertaining to the XPath spec		*
15132 *									*
15133 ************************************************************************/
15134/**
15135 * xmlXPathEscapeUriFunction:
15136 * @ctxt:  the XPath Parser context
15137 * @nargs:  the number of arguments
15138 *
15139 * Implement the escape-uri() XPath function
15140 *    string escape-uri(string $str, bool $escape-reserved)
15141 *
15142 * This function applies the URI escaping rules defined in section 2 of [RFC
15143 * 2396] to the string supplied as $uri-part, which typically represents all
15144 * or part of a URI. The effect of the function is to replace any special
15145 * character in the string by an escape sequence of the form %xx%yy...,
15146 * where xxyy... is the hexadecimal representation of the octets used to
15147 * represent the character in UTF-8.
15148 *
15149 * The set of characters that are escaped depends on the setting of the
15150 * boolean argument $escape-reserved.
15151 *
15152 * If $escape-reserved is true, all characters are escaped other than lower
15153 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15154 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15155 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15156 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15157 * A-F).
15158 *
15159 * If $escape-reserved is false, the behavior differs in that characters
15160 * referred to in [RFC 2396] as reserved characters are not escaped. These
15161 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15162 *
15163 * [RFC 2396] does not define whether escaped URIs should use lower case or
15164 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15165 * compared using string comparison functions, this function must always use
15166 * the upper-case letters A-F.
15167 *
15168 * Generally, $escape-reserved should be set to true when escaping a string
15169 * that is to form a single part of a URI, and to false when escaping an
15170 * entire URI or URI reference.
15171 *
15172 * In the case of non-ascii characters, the string is encoded according to
15173 * utf-8 and then converted according to RFC 2396.
15174 *
15175 * Examples
15176 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15177 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15178 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15179 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15180 *
15181 */
15182static void
15183xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15184    xmlXPathObjectPtr str;
15185    int escape_reserved;
15186    xmlBufPtr target;
15187    xmlChar *cptr;
15188    xmlChar escape[4];
15189
15190    CHECK_ARITY(2);
15191
15192    escape_reserved = xmlXPathPopBoolean(ctxt);
15193
15194    CAST_TO_STRING;
15195    str = valuePop(ctxt);
15196
15197    target = xmlBufCreate();
15198
15199    escape[0] = '%';
15200    escape[3] = 0;
15201
15202    if (target) {
15203	for (cptr = str->stringval; *cptr; cptr++) {
15204	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
15205		(*cptr >= 'a' && *cptr <= 'z') ||
15206		(*cptr >= '0' && *cptr <= '9') ||
15207		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
15208		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
15209		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15210		(*cptr == '%' &&
15211		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15212		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15213		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
15214		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15215		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15216		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15217		(!escape_reserved &&
15218		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15219		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15220		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15221		  *cptr == ','))) {
15222		xmlBufAdd(target, cptr, 1);
15223	    } else {
15224		if ((*cptr >> 4) < 10)
15225		    escape[1] = '0' + (*cptr >> 4);
15226		else
15227		    escape[1] = 'A' - 10 + (*cptr >> 4);
15228		if ((*cptr & 0xF) < 10)
15229		    escape[2] = '0' + (*cptr & 0xF);
15230		else
15231		    escape[2] = 'A' - 10 + (*cptr & 0xF);
15232
15233		xmlBufAdd(target, &escape[0], 3);
15234	    }
15235	}
15236    }
15237    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15238	xmlBufContent(target)));
15239    xmlBufFree(target);
15240    xmlXPathReleaseObject(ctxt->context, str);
15241}
15242
15243/**
15244 * xmlXPathRegisterAllFunctions:
15245 * @ctxt:  the XPath context
15246 *
15247 * Registers all default XPath functions in this context
15248 */
15249void
15250xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15251{
15252    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15253                         xmlXPathBooleanFunction);
15254    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15255                         xmlXPathCeilingFunction);
15256    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15257                         xmlXPathCountFunction);
15258    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15259                         xmlXPathConcatFunction);
15260    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15261                         xmlXPathContainsFunction);
15262    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15263                         xmlXPathIdFunction);
15264    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15265                         xmlXPathFalseFunction);
15266    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15267                         xmlXPathFloorFunction);
15268    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15269                         xmlXPathLastFunction);
15270    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15271                         xmlXPathLangFunction);
15272    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15273                         xmlXPathLocalNameFunction);
15274    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15275                         xmlXPathNotFunction);
15276    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15277                         xmlXPathNameFunction);
15278    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15279                         xmlXPathNamespaceURIFunction);
15280    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15281                         xmlXPathNormalizeFunction);
15282    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15283                         xmlXPathNumberFunction);
15284    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15285                         xmlXPathPositionFunction);
15286    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15287                         xmlXPathRoundFunction);
15288    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15289                         xmlXPathStringFunction);
15290    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15291                         xmlXPathStringLengthFunction);
15292    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15293                         xmlXPathStartsWithFunction);
15294    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15295                         xmlXPathSubstringFunction);
15296    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15297                         xmlXPathSubstringBeforeFunction);
15298    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15299                         xmlXPathSubstringAfterFunction);
15300    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15301                         xmlXPathSumFunction);
15302    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15303                         xmlXPathTrueFunction);
15304    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15305                         xmlXPathTranslateFunction);
15306
15307    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15308	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15309                         xmlXPathEscapeUriFunction);
15310}
15311
15312#endif /* LIBXML_XPATH_ENABLED */
15313#define bottom_xpath
15314#include "elfgcchack.h"
15315