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#if 0
7775/**
7776 * xmlXPathNextDescendantOrSelfElemParent:
7777 * @ctxt:  the XPath Parser context
7778 * @cur:  the current node in the traversal
7779 *
7780 * Traversal function for the "descendant-or-self" axis.
7781 * Additionally it returns only nodes which can be parents of
7782 * element nodes.
7783 *
7784 *
7785 * Returns the next element following that axis
7786 */
7787static xmlNodePtr
7788xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7789				       xmlNodePtr contextNode)
7790{
7791    if (cur == NULL) {
7792	if (contextNode == NULL)
7793	    return(NULL);
7794	switch (contextNode->type) {
7795	    case XML_ELEMENT_NODE:
7796	    case XML_XINCLUDE_START:
7797	    case XML_DOCUMENT_FRAG_NODE:
7798	    case XML_DOCUMENT_NODE:
7799#ifdef LIBXML_DOCB_ENABLED
7800	    case XML_DOCB_DOCUMENT_NODE:
7801#endif
7802	    case XML_HTML_DOCUMENT_NODE:
7803		return(contextNode);
7804	    default:
7805		return(NULL);
7806	}
7807	return(NULL);
7808    } else {
7809	xmlNodePtr start = cur;
7810
7811	while (cur != NULL) {
7812	    switch (cur->type) {
7813		case XML_ELEMENT_NODE:
7814		/* TODO: OK to have XInclude here? */
7815		case XML_XINCLUDE_START:
7816		case XML_DOCUMENT_FRAG_NODE:
7817		    if (cur != start)
7818			return(cur);
7819		    if (cur->children != NULL) {
7820			cur = cur->children;
7821			continue;
7822		    }
7823		    break;
7824		/* Not sure if we need those here. */
7825		case XML_DOCUMENT_NODE:
7826#ifdef LIBXML_DOCB_ENABLED
7827		case XML_DOCB_DOCUMENT_NODE:
7828#endif
7829		case XML_HTML_DOCUMENT_NODE:
7830		    if (cur != start)
7831			return(cur);
7832		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7833		default:
7834		    break;
7835	    }
7836
7837next_sibling:
7838	    if ((cur == NULL) || (cur == contextNode))
7839		return(NULL);
7840	    if (cur->next != NULL) {
7841		cur = cur->next;
7842	    } else {
7843		cur = cur->parent;
7844		goto next_sibling;
7845	    }
7846	}
7847    }
7848    return(NULL);
7849}
7850#endif
7851
7852/**
7853 * xmlXPathNextDescendant:
7854 * @ctxt:  the XPath Parser context
7855 * @cur:  the current node in the traversal
7856 *
7857 * Traversal function for the "descendant" direction
7858 * the descendant axis contains the descendants of the context node in document
7859 * order; a descendant is a child or a child of a child and so on.
7860 *
7861 * Returns the next element following that axis
7862 */
7863xmlNodePtr
7864xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7865    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7866    if (cur == NULL) {
7867	if (ctxt->context->node == NULL)
7868	    return(NULL);
7869	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7870	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7871	    return(NULL);
7872
7873        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7874	    return(ctxt->context->doc->children);
7875        return(ctxt->context->node->children);
7876    }
7877
7878    if (cur->type == XML_NAMESPACE_DECL)
7879        return(NULL);
7880    if (cur->children != NULL) {
7881	/*
7882	 * Do not descend on entities declarations
7883	 */
7884	if (cur->children->type != XML_ENTITY_DECL) {
7885	    cur = cur->children;
7886	    /*
7887	     * Skip DTDs
7888	     */
7889	    if (cur->type != XML_DTD_NODE)
7890		return(cur);
7891	}
7892    }
7893
7894    if (cur == ctxt->context->node) return(NULL);
7895
7896    while (cur->next != NULL) {
7897	cur = cur->next;
7898	if ((cur->type != XML_ENTITY_DECL) &&
7899	    (cur->type != XML_DTD_NODE))
7900	    return(cur);
7901    }
7902
7903    do {
7904        cur = cur->parent;
7905	if (cur == NULL) break;
7906	if (cur == ctxt->context->node) return(NULL);
7907	if (cur->next != NULL) {
7908	    cur = cur->next;
7909	    return(cur);
7910	}
7911    } while (cur != NULL);
7912    return(cur);
7913}
7914
7915/**
7916 * xmlXPathNextDescendantOrSelf:
7917 * @ctxt:  the XPath Parser context
7918 * @cur:  the current node in the traversal
7919 *
7920 * Traversal function for the "descendant-or-self" direction
7921 * the descendant-or-self axis contains the context node and the descendants
7922 * of the context node in document order; thus the context node is the first
7923 * node on the axis, and the first child of the context node is the second node
7924 * on the axis
7925 *
7926 * Returns the next element following that axis
7927 */
7928xmlNodePtr
7929xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7930    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7931    if (cur == NULL) {
7932	if (ctxt->context->node == NULL)
7933	    return(NULL);
7934	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7935	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7936	    return(NULL);
7937        return(ctxt->context->node);
7938    }
7939
7940    return(xmlXPathNextDescendant(ctxt, cur));
7941}
7942
7943/**
7944 * xmlXPathNextParent:
7945 * @ctxt:  the XPath Parser context
7946 * @cur:  the current node in the traversal
7947 *
7948 * Traversal function for the "parent" direction
7949 * The parent axis contains the parent of the context node, if there is one.
7950 *
7951 * Returns the next element following that axis
7952 */
7953xmlNodePtr
7954xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7955    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7956    /*
7957     * the parent of an attribute or namespace node is the element
7958     * to which the attribute or namespace node is attached
7959     * Namespace handling !!!
7960     */
7961    if (cur == NULL) {
7962	if (ctxt->context->node == NULL) return(NULL);
7963	switch (ctxt->context->node->type) {
7964            case XML_ELEMENT_NODE:
7965            case XML_TEXT_NODE:
7966            case XML_CDATA_SECTION_NODE:
7967            case XML_ENTITY_REF_NODE:
7968            case XML_ENTITY_NODE:
7969            case XML_PI_NODE:
7970            case XML_COMMENT_NODE:
7971            case XML_NOTATION_NODE:
7972            case XML_DTD_NODE:
7973	    case XML_ELEMENT_DECL:
7974	    case XML_ATTRIBUTE_DECL:
7975	    case XML_XINCLUDE_START:
7976	    case XML_XINCLUDE_END:
7977	    case XML_ENTITY_DECL:
7978		if (ctxt->context->node->parent == NULL)
7979		    return((xmlNodePtr) ctxt->context->doc);
7980		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7981		    ((ctxt->context->node->parent->name[0] == ' ') ||
7982		     (xmlStrEqual(ctxt->context->node->parent->name,
7983				 BAD_CAST "fake node libxslt"))))
7984		    return(NULL);
7985		return(ctxt->context->node->parent);
7986            case XML_ATTRIBUTE_NODE: {
7987		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7988
7989		return(att->parent);
7990	    }
7991            case XML_DOCUMENT_NODE:
7992            case XML_DOCUMENT_TYPE_NODE:
7993            case XML_DOCUMENT_FRAG_NODE:
7994            case XML_HTML_DOCUMENT_NODE:
7995#ifdef LIBXML_DOCB_ENABLED
7996	    case XML_DOCB_DOCUMENT_NODE:
7997#endif
7998                return(NULL);
7999	    case XML_NAMESPACE_DECL: {
8000		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8001
8002		if ((ns->next != NULL) &&
8003		    (ns->next->type != XML_NAMESPACE_DECL))
8004		    return((xmlNodePtr) ns->next);
8005                return(NULL);
8006	    }
8007	}
8008    }
8009    return(NULL);
8010}
8011
8012/**
8013 * xmlXPathNextAncestor:
8014 * @ctxt:  the XPath Parser context
8015 * @cur:  the current node in the traversal
8016 *
8017 * Traversal function for the "ancestor" direction
8018 * the ancestor axis contains the ancestors of the context node; the ancestors
8019 * of the context node consist of the parent of context node and the parent's
8020 * parent and so on; the nodes are ordered in reverse document order; thus the
8021 * parent is the first node on the axis, and the parent's parent is the second
8022 * node on the axis
8023 *
8024 * Returns the next element following that axis
8025 */
8026xmlNodePtr
8027xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8028    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8029    /*
8030     * the parent of an attribute or namespace node is the element
8031     * to which the attribute or namespace node is attached
8032     * !!!!!!!!!!!!!
8033     */
8034    if (cur == NULL) {
8035	if (ctxt->context->node == NULL) return(NULL);
8036	switch (ctxt->context->node->type) {
8037            case XML_ELEMENT_NODE:
8038            case XML_TEXT_NODE:
8039            case XML_CDATA_SECTION_NODE:
8040            case XML_ENTITY_REF_NODE:
8041            case XML_ENTITY_NODE:
8042            case XML_PI_NODE:
8043            case XML_COMMENT_NODE:
8044	    case XML_DTD_NODE:
8045	    case XML_ELEMENT_DECL:
8046	    case XML_ATTRIBUTE_DECL:
8047	    case XML_ENTITY_DECL:
8048            case XML_NOTATION_NODE:
8049	    case XML_XINCLUDE_START:
8050	    case XML_XINCLUDE_END:
8051		if (ctxt->context->node->parent == NULL)
8052		    return((xmlNodePtr) ctxt->context->doc);
8053		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8054		    ((ctxt->context->node->parent->name[0] == ' ') ||
8055		     (xmlStrEqual(ctxt->context->node->parent->name,
8056				 BAD_CAST "fake node libxslt"))))
8057		    return(NULL);
8058		return(ctxt->context->node->parent);
8059            case XML_ATTRIBUTE_NODE: {
8060		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8061
8062		return(tmp->parent);
8063	    }
8064            case XML_DOCUMENT_NODE:
8065            case XML_DOCUMENT_TYPE_NODE:
8066            case XML_DOCUMENT_FRAG_NODE:
8067            case XML_HTML_DOCUMENT_NODE:
8068#ifdef LIBXML_DOCB_ENABLED
8069	    case XML_DOCB_DOCUMENT_NODE:
8070#endif
8071                return(NULL);
8072	    case XML_NAMESPACE_DECL: {
8073		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8074
8075		if ((ns->next != NULL) &&
8076		    (ns->next->type != XML_NAMESPACE_DECL))
8077		    return((xmlNodePtr) ns->next);
8078		/* Bad, how did that namespace end up here ? */
8079                return(NULL);
8080	    }
8081	}
8082	return(NULL);
8083    }
8084    if (cur == ctxt->context->doc->children)
8085	return((xmlNodePtr) ctxt->context->doc);
8086    if (cur == (xmlNodePtr) ctxt->context->doc)
8087	return(NULL);
8088    switch (cur->type) {
8089	case XML_ELEMENT_NODE:
8090	case XML_TEXT_NODE:
8091	case XML_CDATA_SECTION_NODE:
8092	case XML_ENTITY_REF_NODE:
8093	case XML_ENTITY_NODE:
8094	case XML_PI_NODE:
8095	case XML_COMMENT_NODE:
8096	case XML_NOTATION_NODE:
8097	case XML_DTD_NODE:
8098        case XML_ELEMENT_DECL:
8099        case XML_ATTRIBUTE_DECL:
8100        case XML_ENTITY_DECL:
8101	case XML_XINCLUDE_START:
8102	case XML_XINCLUDE_END:
8103	    if (cur->parent == NULL)
8104		return(NULL);
8105	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
8106		((cur->parent->name[0] == ' ') ||
8107		 (xmlStrEqual(cur->parent->name,
8108			      BAD_CAST "fake node libxslt"))))
8109		return(NULL);
8110	    return(cur->parent);
8111	case XML_ATTRIBUTE_NODE: {
8112	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8113
8114	    return(att->parent);
8115	}
8116	case XML_NAMESPACE_DECL: {
8117	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8118
8119	    if ((ns->next != NULL) &&
8120	        (ns->next->type != XML_NAMESPACE_DECL))
8121	        return((xmlNodePtr) ns->next);
8122	    /* Bad, how did that namespace end up here ? */
8123            return(NULL);
8124	}
8125	case XML_DOCUMENT_NODE:
8126	case XML_DOCUMENT_TYPE_NODE:
8127	case XML_DOCUMENT_FRAG_NODE:
8128	case XML_HTML_DOCUMENT_NODE:
8129#ifdef LIBXML_DOCB_ENABLED
8130	case XML_DOCB_DOCUMENT_NODE:
8131#endif
8132	    return(NULL);
8133    }
8134    return(NULL);
8135}
8136
8137/**
8138 * xmlXPathNextAncestorOrSelf:
8139 * @ctxt:  the XPath Parser context
8140 * @cur:  the current node in the traversal
8141 *
8142 * Traversal function for the "ancestor-or-self" direction
8143 * he ancestor-or-self axis contains the context node and ancestors of
8144 * the context node in reverse document order; thus the context node is
8145 * the first node on the axis, and the context node's parent the second;
8146 * parent here is defined the same as with the parent axis.
8147 *
8148 * Returns the next element following that axis
8149 */
8150xmlNodePtr
8151xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8152    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8153    if (cur == NULL)
8154        return(ctxt->context->node);
8155    return(xmlXPathNextAncestor(ctxt, cur));
8156}
8157
8158/**
8159 * xmlXPathNextFollowingSibling:
8160 * @ctxt:  the XPath Parser context
8161 * @cur:  the current node in the traversal
8162 *
8163 * Traversal function for the "following-sibling" direction
8164 * The following-sibling axis contains the following siblings of the context
8165 * node in document order.
8166 *
8167 * Returns the next element following that axis
8168 */
8169xmlNodePtr
8170xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8171    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8172    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8173	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8174	return(NULL);
8175    if (cur == (xmlNodePtr) ctxt->context->doc)
8176        return(NULL);
8177    if (cur == NULL)
8178        return(ctxt->context->node->next);
8179    return(cur->next);
8180}
8181
8182/**
8183 * xmlXPathNextPrecedingSibling:
8184 * @ctxt:  the XPath Parser context
8185 * @cur:  the current node in the traversal
8186 *
8187 * Traversal function for the "preceding-sibling" direction
8188 * The preceding-sibling axis contains the preceding siblings of the context
8189 * node in reverse document order; the first preceding sibling is first on the
8190 * axis; the sibling preceding that node is the second on the axis and so on.
8191 *
8192 * Returns the next element following that axis
8193 */
8194xmlNodePtr
8195xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8196    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8197    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8198	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8199	return(NULL);
8200    if (cur == (xmlNodePtr) ctxt->context->doc)
8201        return(NULL);
8202    if (cur == NULL)
8203        return(ctxt->context->node->prev);
8204    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8205	cur = cur->prev;
8206	if (cur == NULL)
8207	    return(ctxt->context->node->prev);
8208    }
8209    return(cur->prev);
8210}
8211
8212/**
8213 * xmlXPathNextFollowing:
8214 * @ctxt:  the XPath Parser context
8215 * @cur:  the current node in the traversal
8216 *
8217 * Traversal function for the "following" direction
8218 * The following axis contains all nodes in the same document as the context
8219 * node that are after the context node in document order, excluding any
8220 * descendants and excluding attribute nodes and namespace nodes; the nodes
8221 * are ordered in document order
8222 *
8223 * Returns the next element following that axis
8224 */
8225xmlNodePtr
8226xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8227    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8228    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8229        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8230        return(cur->children);
8231
8232    if (cur == NULL) {
8233        cur = ctxt->context->node;
8234        if (cur->type == XML_NAMESPACE_DECL)
8235            return(NULL);
8236        if (cur->type == XML_ATTRIBUTE_NODE)
8237            cur = cur->parent;
8238    }
8239    if (cur == NULL) return(NULL) ; /* ERROR */
8240    if (cur->next != NULL) return(cur->next) ;
8241    do {
8242        cur = cur->parent;
8243        if (cur == NULL) break;
8244        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8245        if (cur->next != NULL) return(cur->next);
8246    } while (cur != NULL);
8247    return(cur);
8248}
8249
8250/*
8251 * xmlXPathIsAncestor:
8252 * @ancestor:  the ancestor node
8253 * @node:  the current node
8254 *
8255 * Check that @ancestor is a @node's ancestor
8256 *
8257 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8258 */
8259static int
8260xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8261    if ((ancestor == NULL) || (node == NULL)) return(0);
8262    if (node->type == XML_NAMESPACE_DECL)
8263        return(0);
8264    if (ancestor->type == XML_NAMESPACE_DECL)
8265        return(0);
8266    /* nodes need to be in the same document */
8267    if (ancestor->doc != node->doc) return(0);
8268    /* avoid searching if ancestor or node is the root node */
8269    if (ancestor == (xmlNodePtr) node->doc) return(1);
8270    if (node == (xmlNodePtr) ancestor->doc) return(0);
8271    while (node->parent != NULL) {
8272        if (node->parent == ancestor)
8273            return(1);
8274	node = node->parent;
8275    }
8276    return(0);
8277}
8278
8279/**
8280 * xmlXPathNextPreceding:
8281 * @ctxt:  the XPath Parser context
8282 * @cur:  the current node in the traversal
8283 *
8284 * Traversal function for the "preceding" direction
8285 * the preceding axis contains all nodes in the same document as the context
8286 * node that are before the context node in document order, excluding any
8287 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8288 * ordered in reverse document order
8289 *
8290 * Returns the next element following that axis
8291 */
8292xmlNodePtr
8293xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8294{
8295    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8296    if (cur == NULL) {
8297        cur = ctxt->context->node;
8298        if (cur->type == XML_NAMESPACE_DECL)
8299            return(NULL);
8300        if (cur->type == XML_ATTRIBUTE_NODE)
8301            return(cur->parent);
8302    }
8303    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8304	return (NULL);
8305    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8306	cur = cur->prev;
8307    do {
8308        if (cur->prev != NULL) {
8309            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8310            return (cur);
8311        }
8312
8313        cur = cur->parent;
8314        if (cur == NULL)
8315            return (NULL);
8316        if (cur == ctxt->context->doc->children)
8317            return (NULL);
8318    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8319    return (cur);
8320}
8321
8322/**
8323 * xmlXPathNextPrecedingInternal:
8324 * @ctxt:  the XPath Parser context
8325 * @cur:  the current node in the traversal
8326 *
8327 * Traversal function for the "preceding" direction
8328 * the preceding axis contains all nodes in the same document as the context
8329 * node that are before the context node in document order, excluding any
8330 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8331 * ordered in reverse document order
8332 * This is a faster implementation but internal only since it requires a
8333 * state kept in the parser context: ctxt->ancestor.
8334 *
8335 * Returns the next element following that axis
8336 */
8337static xmlNodePtr
8338xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8339                              xmlNodePtr cur)
8340{
8341    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8342    if (cur == NULL) {
8343        cur = ctxt->context->node;
8344        if (cur == NULL)
8345            return (NULL);
8346        if (cur->type == XML_NAMESPACE_DECL)
8347            return (NULL);
8348        ctxt->ancestor = cur->parent;
8349    }
8350    if (cur->type == XML_NAMESPACE_DECL)
8351        return(NULL);
8352    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8353	cur = cur->prev;
8354    while (cur->prev == NULL) {
8355        cur = cur->parent;
8356        if (cur == NULL)
8357            return (NULL);
8358        if (cur == ctxt->context->doc->children)
8359            return (NULL);
8360        if (cur != ctxt->ancestor)
8361            return (cur);
8362        ctxt->ancestor = cur->parent;
8363    }
8364    cur = cur->prev;
8365    while (cur->last != NULL)
8366        cur = cur->last;
8367    return (cur);
8368}
8369
8370/**
8371 * xmlXPathNextNamespace:
8372 * @ctxt:  the XPath Parser context
8373 * @cur:  the current attribute in the traversal
8374 *
8375 * Traversal function for the "namespace" direction
8376 * the namespace axis contains the namespace nodes of the context node;
8377 * the order of nodes on this axis is implementation-defined; the axis will
8378 * be empty unless the context node is an element
8379 *
8380 * We keep the XML namespace node at the end of the list.
8381 *
8382 * Returns the next element following that axis
8383 */
8384xmlNodePtr
8385xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8386    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8387    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8388    if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8389        if (ctxt->context->tmpNsList != NULL)
8390	    xmlFree(ctxt->context->tmpNsList);
8391	ctxt->context->tmpNsList =
8392	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8393	ctxt->context->tmpNsNr = 0;
8394	if (ctxt->context->tmpNsList != NULL) {
8395	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8396		ctxt->context->tmpNsNr++;
8397	    }
8398	}
8399	return((xmlNodePtr) xmlXPathXMLNamespace);
8400    }
8401    if (ctxt->context->tmpNsNr > 0) {
8402	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8403    } else {
8404	if (ctxt->context->tmpNsList != NULL)
8405	    xmlFree(ctxt->context->tmpNsList);
8406	ctxt->context->tmpNsList = NULL;
8407	return(NULL);
8408    }
8409}
8410
8411/**
8412 * xmlXPathNextAttribute:
8413 * @ctxt:  the XPath Parser context
8414 * @cur:  the current attribute in the traversal
8415 *
8416 * Traversal function for the "attribute" direction
8417 * TODO: support DTD inherited default attributes
8418 *
8419 * Returns the next element following that axis
8420 */
8421xmlNodePtr
8422xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8423    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8424    if (ctxt->context->node == NULL)
8425	return(NULL);
8426    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8427	return(NULL);
8428    if (cur == NULL) {
8429        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8430	    return(NULL);
8431        return((xmlNodePtr)ctxt->context->node->properties);
8432    }
8433    return((xmlNodePtr)cur->next);
8434}
8435
8436/************************************************************************
8437 *									*
8438 *		NodeTest Functions					*
8439 *									*
8440 ************************************************************************/
8441
8442#define IS_FUNCTION			200
8443
8444
8445/************************************************************************
8446 *									*
8447 *		Implicit tree core function library			*
8448 *									*
8449 ************************************************************************/
8450
8451/**
8452 * xmlXPathRoot:
8453 * @ctxt:  the XPath Parser context
8454 *
8455 * Initialize the context to the root of the document
8456 */
8457void
8458xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8459    if ((ctxt == NULL) || (ctxt->context == NULL))
8460	return;
8461    ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8462    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8463	ctxt->context->node));
8464}
8465
8466/************************************************************************
8467 *									*
8468 *		The explicit core function library			*
8469 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8470 *									*
8471 ************************************************************************/
8472
8473
8474/**
8475 * xmlXPathLastFunction:
8476 * @ctxt:  the XPath Parser context
8477 * @nargs:  the number of arguments
8478 *
8479 * Implement the last() XPath function
8480 *    number last()
8481 * The last function returns the number of nodes in the context node list.
8482 */
8483void
8484xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8485    CHECK_ARITY(0);
8486    if (ctxt->context->contextSize >= 0) {
8487	valuePush(ctxt,
8488	    xmlXPathCacheNewFloat(ctxt->context,
8489		(double) ctxt->context->contextSize));
8490#ifdef DEBUG_EXPR
8491	xmlGenericError(xmlGenericErrorContext,
8492		"last() : %d\n", ctxt->context->contextSize);
8493#endif
8494    } else {
8495	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8496    }
8497}
8498
8499/**
8500 * xmlXPathPositionFunction:
8501 * @ctxt:  the XPath Parser context
8502 * @nargs:  the number of arguments
8503 *
8504 * Implement the position() XPath function
8505 *    number position()
8506 * The position function returns the position of the context node in the
8507 * context node list. The first position is 1, and so the last position
8508 * will be equal to last().
8509 */
8510void
8511xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8512    CHECK_ARITY(0);
8513    if (ctxt->context->proximityPosition >= 0) {
8514	valuePush(ctxt,
8515	      xmlXPathCacheNewFloat(ctxt->context,
8516		(double) ctxt->context->proximityPosition));
8517#ifdef DEBUG_EXPR
8518	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8519		ctxt->context->proximityPosition);
8520#endif
8521    } else {
8522	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8523    }
8524}
8525
8526/**
8527 * xmlXPathCountFunction:
8528 * @ctxt:  the XPath Parser context
8529 * @nargs:  the number of arguments
8530 *
8531 * Implement the count() XPath function
8532 *    number count(node-set)
8533 */
8534void
8535xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8536    xmlXPathObjectPtr cur;
8537
8538    CHECK_ARITY(1);
8539    if ((ctxt->value == NULL) ||
8540	((ctxt->value->type != XPATH_NODESET) &&
8541	 (ctxt->value->type != XPATH_XSLT_TREE)))
8542	XP_ERROR(XPATH_INVALID_TYPE);
8543    cur = valuePop(ctxt);
8544
8545    if ((cur == NULL) || (cur->nodesetval == NULL))
8546	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8547    else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8548	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8549	    (double) cur->nodesetval->nodeNr));
8550    } else {
8551	if ((cur->nodesetval->nodeNr != 1) ||
8552	    (cur->nodesetval->nodeTab == NULL)) {
8553	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8554	} else {
8555	    xmlNodePtr tmp;
8556	    int i = 0;
8557
8558	    tmp = cur->nodesetval->nodeTab[0];
8559	    if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8560		tmp = tmp->children;
8561		while (tmp != NULL) {
8562		    tmp = tmp->next;
8563		    i++;
8564		}
8565	    }
8566	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8567	}
8568    }
8569    xmlXPathReleaseObject(ctxt->context, cur);
8570}
8571
8572/**
8573 * xmlXPathGetElementsByIds:
8574 * @doc:  the document
8575 * @ids:  a whitespace separated list of IDs
8576 *
8577 * Selects elements by their unique ID.
8578 *
8579 * Returns a node-set of selected elements.
8580 */
8581static xmlNodeSetPtr
8582xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8583    xmlNodeSetPtr ret;
8584    const xmlChar *cur = ids;
8585    xmlChar *ID;
8586    xmlAttrPtr attr;
8587    xmlNodePtr elem = NULL;
8588
8589    if (ids == NULL) return(NULL);
8590
8591    ret = xmlXPathNodeSetCreate(NULL);
8592    if (ret == NULL)
8593        return(ret);
8594
8595    while (IS_BLANK_CH(*cur)) cur++;
8596    while (*cur != 0) {
8597	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8598	    cur++;
8599
8600        ID = xmlStrndup(ids, cur - ids);
8601	if (ID != NULL) {
8602	    /*
8603	     * We used to check the fact that the value passed
8604	     * was an NCName, but this generated much troubles for
8605	     * me and Aleksey Sanin, people blatantly violated that
8606	     * constaint, like Visa3D spec.
8607	     * if (xmlValidateNCName(ID, 1) == 0)
8608	     */
8609	    attr = xmlGetID(doc, ID);
8610	    if (attr != NULL) {
8611		if (attr->type == XML_ATTRIBUTE_NODE)
8612		    elem = attr->parent;
8613		else if (attr->type == XML_ELEMENT_NODE)
8614		    elem = (xmlNodePtr) attr;
8615		else
8616		    elem = NULL;
8617		if (elem != NULL)
8618		    xmlXPathNodeSetAdd(ret, elem);
8619	    }
8620	    xmlFree(ID);
8621	}
8622
8623	while (IS_BLANK_CH(*cur)) cur++;
8624	ids = cur;
8625    }
8626    return(ret);
8627}
8628
8629/**
8630 * xmlXPathIdFunction:
8631 * @ctxt:  the XPath Parser context
8632 * @nargs:  the number of arguments
8633 *
8634 * Implement the id() XPath function
8635 *    node-set id(object)
8636 * The id function selects elements by their unique ID
8637 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8638 * then the result is the union of the result of applying id to the
8639 * string value of each of the nodes in the argument node-set. When the
8640 * argument to id is of any other type, the argument is converted to a
8641 * string as if by a call to the string function; the string is split
8642 * into a whitespace-separated list of tokens (whitespace is any sequence
8643 * of characters matching the production S); the result is a node-set
8644 * containing the elements in the same document as the context node that
8645 * have a unique ID equal to any of the tokens in the list.
8646 */
8647void
8648xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8649    xmlChar *tokens;
8650    xmlNodeSetPtr ret;
8651    xmlXPathObjectPtr obj;
8652
8653    CHECK_ARITY(1);
8654    obj = valuePop(ctxt);
8655    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8656    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8657	xmlNodeSetPtr ns;
8658	int i;
8659
8660	ret = xmlXPathNodeSetCreate(NULL);
8661        /*
8662         * FIXME -- in an out-of-memory condition this will behave badly.
8663         * The solution is not clear -- we already popped an item from
8664         * ctxt, so the object is in a corrupt state.
8665         */
8666
8667	if (obj->nodesetval != NULL) {
8668	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8669		tokens =
8670		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8671		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8672		ret = xmlXPathNodeSetMerge(ret, ns);
8673		xmlXPathFreeNodeSet(ns);
8674		if (tokens != NULL)
8675		    xmlFree(tokens);
8676	    }
8677	}
8678	xmlXPathReleaseObject(ctxt->context, obj);
8679	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8680	return;
8681    }
8682    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8683    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8684    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8685    xmlXPathReleaseObject(ctxt->context, obj);
8686    return;
8687}
8688
8689/**
8690 * xmlXPathLocalNameFunction:
8691 * @ctxt:  the XPath Parser context
8692 * @nargs:  the number of arguments
8693 *
8694 * Implement the local-name() XPath function
8695 *    string local-name(node-set?)
8696 * The local-name function returns a string containing the local part
8697 * of the name of the node in the argument node-set that is first in
8698 * document order. If the node-set is empty or the first node has no
8699 * name, an empty string is returned. If the argument is omitted it
8700 * defaults to the context node.
8701 */
8702void
8703xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8704    xmlXPathObjectPtr cur;
8705
8706    if (ctxt == NULL) return;
8707
8708    if (nargs == 0) {
8709	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8710	    ctxt->context->node));
8711	nargs = 1;
8712    }
8713
8714    CHECK_ARITY(1);
8715    if ((ctxt->value == NULL) ||
8716	((ctxt->value->type != XPATH_NODESET) &&
8717	 (ctxt->value->type != XPATH_XSLT_TREE)))
8718	XP_ERROR(XPATH_INVALID_TYPE);
8719    cur = valuePop(ctxt);
8720
8721    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8722	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8723    } else {
8724	int i = 0; /* Should be first in document order !!!!! */
8725	switch (cur->nodesetval->nodeTab[i]->type) {
8726	case XML_ELEMENT_NODE:
8727	case XML_ATTRIBUTE_NODE:
8728	case XML_PI_NODE:
8729	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8730		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8731	    else
8732		valuePush(ctxt,
8733		      xmlXPathCacheNewString(ctxt->context,
8734			cur->nodesetval->nodeTab[i]->name));
8735	    break;
8736	case XML_NAMESPACE_DECL:
8737	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8738			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8739	    break;
8740	default:
8741	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8742	}
8743    }
8744    xmlXPathReleaseObject(ctxt->context, cur);
8745}
8746
8747/**
8748 * xmlXPathNamespaceURIFunction:
8749 * @ctxt:  the XPath Parser context
8750 * @nargs:  the number of arguments
8751 *
8752 * Implement the namespace-uri() XPath function
8753 *    string namespace-uri(node-set?)
8754 * The namespace-uri function returns a string containing the
8755 * namespace URI of the expanded name of the node in the argument
8756 * node-set that is first in document order. If the node-set is empty,
8757 * the first node has no name, or the expanded name has no namespace
8758 * URI, an empty string is returned. If the argument is omitted it
8759 * defaults to the context node.
8760 */
8761void
8762xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8763    xmlXPathObjectPtr cur;
8764
8765    if (ctxt == NULL) return;
8766
8767    if (nargs == 0) {
8768	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8769	    ctxt->context->node));
8770	nargs = 1;
8771    }
8772    CHECK_ARITY(1);
8773    if ((ctxt->value == NULL) ||
8774	((ctxt->value->type != XPATH_NODESET) &&
8775	 (ctxt->value->type != XPATH_XSLT_TREE)))
8776	XP_ERROR(XPATH_INVALID_TYPE);
8777    cur = valuePop(ctxt);
8778
8779    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8780	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8781    } else {
8782	int i = 0; /* Should be first in document order !!!!! */
8783	switch (cur->nodesetval->nodeTab[i]->type) {
8784	case XML_ELEMENT_NODE:
8785	case XML_ATTRIBUTE_NODE:
8786	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8787		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8788	    else
8789		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8790			  cur->nodesetval->nodeTab[i]->ns->href));
8791	    break;
8792	default:
8793	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8794	}
8795    }
8796    xmlXPathReleaseObject(ctxt->context, cur);
8797}
8798
8799/**
8800 * xmlXPathNameFunction:
8801 * @ctxt:  the XPath Parser context
8802 * @nargs:  the number of arguments
8803 *
8804 * Implement the name() XPath function
8805 *    string name(node-set?)
8806 * The name function returns a string containing a QName representing
8807 * the name of the node in the argument node-set that is first in document
8808 * order. The QName must represent the name with respect to the namespace
8809 * declarations in effect on the node whose name is being represented.
8810 * Typically, this will be the form in which the name occurred in the XML
8811 * source. This need not be the case if there are namespace declarations
8812 * in effect on the node that associate multiple prefixes with the same
8813 * namespace. However, an implementation may include information about
8814 * the original prefix in its representation of nodes; in this case, an
8815 * implementation can ensure that the returned string is always the same
8816 * as the QName used in the XML source. If the argument it omitted it
8817 * defaults to the context node.
8818 * Libxml keep the original prefix so the "real qualified name" used is
8819 * returned.
8820 */
8821static void
8822xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8823{
8824    xmlXPathObjectPtr cur;
8825
8826    if (nargs == 0) {
8827	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8828	    ctxt->context->node));
8829        nargs = 1;
8830    }
8831
8832    CHECK_ARITY(1);
8833    if ((ctxt->value == NULL) ||
8834        ((ctxt->value->type != XPATH_NODESET) &&
8835         (ctxt->value->type != XPATH_XSLT_TREE)))
8836        XP_ERROR(XPATH_INVALID_TYPE);
8837    cur = valuePop(ctxt);
8838
8839    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8840        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8841    } else {
8842        int i = 0;              /* Should be first in document order !!!!! */
8843
8844        switch (cur->nodesetval->nodeTab[i]->type) {
8845            case XML_ELEMENT_NODE:
8846            case XML_ATTRIBUTE_NODE:
8847		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8848		    valuePush(ctxt,
8849			xmlXPathCacheNewCString(ctxt->context, ""));
8850		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8851                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8852		    valuePush(ctxt,
8853		        xmlXPathCacheNewString(ctxt->context,
8854			    cur->nodesetval->nodeTab[i]->name));
8855		} else {
8856		    xmlChar *fullname;
8857
8858		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8859				     cur->nodesetval->nodeTab[i]->ns->prefix,
8860				     NULL, 0);
8861		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8862			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8863		    if (fullname == NULL) {
8864			XP_ERROR(XPATH_MEMORY_ERROR);
8865		    }
8866		    valuePush(ctxt, xmlXPathCacheWrapString(
8867			ctxt->context, fullname));
8868                }
8869                break;
8870            default:
8871		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8872		    cur->nodesetval->nodeTab[i]));
8873                xmlXPathLocalNameFunction(ctxt, 1);
8874        }
8875    }
8876    xmlXPathReleaseObject(ctxt->context, cur);
8877}
8878
8879
8880/**
8881 * xmlXPathStringFunction:
8882 * @ctxt:  the XPath Parser context
8883 * @nargs:  the number of arguments
8884 *
8885 * Implement the string() XPath function
8886 *    string string(object?)
8887 * The string function converts an object to a string as follows:
8888 *    - A node-set is converted to a string by returning the value of
8889 *      the node in the node-set that is first in document order.
8890 *      If the node-set is empty, an empty string is returned.
8891 *    - A number is converted to a string as follows
8892 *      + NaN is converted to the string NaN
8893 *      + positive zero is converted to the string 0
8894 *      + negative zero is converted to the string 0
8895 *      + positive infinity is converted to the string Infinity
8896 *      + negative infinity is converted to the string -Infinity
8897 *      + if the number is an integer, the number is represented in
8898 *        decimal form as a Number with no decimal point and no leading
8899 *        zeros, preceded by a minus sign (-) if the number is negative
8900 *      + otherwise, the number is represented in decimal form as a
8901 *        Number including a decimal point with at least one digit
8902 *        before the decimal point and at least one digit after the
8903 *        decimal point, preceded by a minus sign (-) if the number
8904 *        is negative; there must be no leading zeros before the decimal
8905 *        point apart possibly from the one required digit immediately
8906 *        before the decimal point; beyond the one required digit
8907 *        after the decimal point there must be as many, but only as
8908 *        many, more digits as are needed to uniquely distinguish the
8909 *        number from all other IEEE 754 numeric values.
8910 *    - The boolean false value is converted to the string false.
8911 *      The boolean true value is converted to the string true.
8912 *
8913 * If the argument is omitted, it defaults to a node-set with the
8914 * context node as its only member.
8915 */
8916void
8917xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8918    xmlXPathObjectPtr cur;
8919
8920    if (ctxt == NULL) return;
8921    if (nargs == 0) {
8922    valuePush(ctxt,
8923	xmlXPathCacheWrapString(ctxt->context,
8924	    xmlXPathCastNodeToString(ctxt->context->node)));
8925	return;
8926    }
8927
8928    CHECK_ARITY(1);
8929    cur = valuePop(ctxt);
8930    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8931    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8932}
8933
8934/**
8935 * xmlXPathStringLengthFunction:
8936 * @ctxt:  the XPath Parser context
8937 * @nargs:  the number of arguments
8938 *
8939 * Implement the string-length() XPath function
8940 *    number string-length(string?)
8941 * The string-length returns the number of characters in the string
8942 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8943 * the context node converted to a string, in other words the value
8944 * of the context node.
8945 */
8946void
8947xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8948    xmlXPathObjectPtr cur;
8949
8950    if (nargs == 0) {
8951        if ((ctxt == NULL) || (ctxt->context == NULL))
8952	    return;
8953	if (ctxt->context->node == NULL) {
8954	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8955	} else {
8956	    xmlChar *content;
8957
8958	    content = xmlXPathCastNodeToString(ctxt->context->node);
8959	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8960		xmlUTF8Strlen(content)));
8961	    xmlFree(content);
8962	}
8963	return;
8964    }
8965    CHECK_ARITY(1);
8966    CAST_TO_STRING;
8967    CHECK_TYPE(XPATH_STRING);
8968    cur = valuePop(ctxt);
8969    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8970	xmlUTF8Strlen(cur->stringval)));
8971    xmlXPathReleaseObject(ctxt->context, cur);
8972}
8973
8974/**
8975 * xmlXPathConcatFunction:
8976 * @ctxt:  the XPath Parser context
8977 * @nargs:  the number of arguments
8978 *
8979 * Implement the concat() XPath function
8980 *    string concat(string, string, string*)
8981 * The concat function returns the concatenation of its arguments.
8982 */
8983void
8984xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8985    xmlXPathObjectPtr cur, newobj;
8986    xmlChar *tmp;
8987
8988    if (ctxt == NULL) return;
8989    if (nargs < 2) {
8990	CHECK_ARITY(2);
8991    }
8992
8993    CAST_TO_STRING;
8994    cur = valuePop(ctxt);
8995    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8996	xmlXPathReleaseObject(ctxt->context, cur);
8997	return;
8998    }
8999    nargs--;
9000
9001    while (nargs > 0) {
9002	CAST_TO_STRING;
9003	newobj = valuePop(ctxt);
9004	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9005	    xmlXPathReleaseObject(ctxt->context, newobj);
9006	    xmlXPathReleaseObject(ctxt->context, cur);
9007	    XP_ERROR(XPATH_INVALID_TYPE);
9008	}
9009	tmp = xmlStrcat(newobj->stringval, cur->stringval);
9010	newobj->stringval = cur->stringval;
9011	cur->stringval = tmp;
9012	xmlXPathReleaseObject(ctxt->context, newobj);
9013	nargs--;
9014    }
9015    valuePush(ctxt, cur);
9016}
9017
9018/**
9019 * xmlXPathContainsFunction:
9020 * @ctxt:  the XPath Parser context
9021 * @nargs:  the number of arguments
9022 *
9023 * Implement the contains() XPath function
9024 *    boolean contains(string, string)
9025 * The contains function returns true if the first argument string
9026 * contains the second argument string, and otherwise returns false.
9027 */
9028void
9029xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9030    xmlXPathObjectPtr hay, needle;
9031
9032    CHECK_ARITY(2);
9033    CAST_TO_STRING;
9034    CHECK_TYPE(XPATH_STRING);
9035    needle = valuePop(ctxt);
9036    CAST_TO_STRING;
9037    hay = valuePop(ctxt);
9038
9039    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9040	xmlXPathReleaseObject(ctxt->context, hay);
9041	xmlXPathReleaseObject(ctxt->context, needle);
9042	XP_ERROR(XPATH_INVALID_TYPE);
9043    }
9044    if (xmlStrstr(hay->stringval, needle->stringval))
9045	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9046    else
9047	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9048    xmlXPathReleaseObject(ctxt->context, hay);
9049    xmlXPathReleaseObject(ctxt->context, needle);
9050}
9051
9052/**
9053 * xmlXPathStartsWithFunction:
9054 * @ctxt:  the XPath Parser context
9055 * @nargs:  the number of arguments
9056 *
9057 * Implement the starts-with() XPath function
9058 *    boolean starts-with(string, string)
9059 * The starts-with function returns true if the first argument string
9060 * starts with the second argument string, and otherwise returns false.
9061 */
9062void
9063xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9064    xmlXPathObjectPtr hay, needle;
9065    int n;
9066
9067    CHECK_ARITY(2);
9068    CAST_TO_STRING;
9069    CHECK_TYPE(XPATH_STRING);
9070    needle = valuePop(ctxt);
9071    CAST_TO_STRING;
9072    hay = valuePop(ctxt);
9073
9074    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9075	xmlXPathReleaseObject(ctxt->context, hay);
9076	xmlXPathReleaseObject(ctxt->context, needle);
9077	XP_ERROR(XPATH_INVALID_TYPE);
9078    }
9079    n = xmlStrlen(needle->stringval);
9080    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9081        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9082    else
9083        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9084    xmlXPathReleaseObject(ctxt->context, hay);
9085    xmlXPathReleaseObject(ctxt->context, needle);
9086}
9087
9088/**
9089 * xmlXPathSubstringFunction:
9090 * @ctxt:  the XPath Parser context
9091 * @nargs:  the number of arguments
9092 *
9093 * Implement the substring() XPath function
9094 *    string substring(string, number, number?)
9095 * The substring function returns the substring of the first argument
9096 * starting at the position specified in the second argument with
9097 * length specified in the third argument. For example,
9098 * substring("12345",2,3) returns "234". If the third argument is not
9099 * specified, it returns the substring starting at the position specified
9100 * in the second argument and continuing to the end of the string. For
9101 * example, substring("12345",2) returns "2345".  More precisely, each
9102 * character in the string (see [3.6 Strings]) is considered to have a
9103 * numeric position: the position of the first character is 1, the position
9104 * of the second character is 2 and so on. The returned substring contains
9105 * those characters for which the position of the character is greater than
9106 * or equal to the second argument and, if the third argument is specified,
9107 * less than the sum of the second and third arguments; the comparisons
9108 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9109 *  - substring("12345", 1.5, 2.6) returns "234"
9110 *  - substring("12345", 0, 3) returns "12"
9111 *  - substring("12345", 0 div 0, 3) returns ""
9112 *  - substring("12345", 1, 0 div 0) returns ""
9113 *  - substring("12345", -42, 1 div 0) returns "12345"
9114 *  - substring("12345", -1 div 0, 1 div 0) returns ""
9115 */
9116void
9117xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9118    xmlXPathObjectPtr str, start, len;
9119    double le=0, in;
9120    int i, l, m;
9121    xmlChar *ret;
9122
9123    if (nargs < 2) {
9124	CHECK_ARITY(2);
9125    }
9126    if (nargs > 3) {
9127	CHECK_ARITY(3);
9128    }
9129    /*
9130     * take care of possible last (position) argument
9131    */
9132    if (nargs == 3) {
9133	CAST_TO_NUMBER;
9134	CHECK_TYPE(XPATH_NUMBER);
9135	len = valuePop(ctxt);
9136	le = len->floatval;
9137	xmlXPathReleaseObject(ctxt->context, len);
9138    }
9139
9140    CAST_TO_NUMBER;
9141    CHECK_TYPE(XPATH_NUMBER);
9142    start = valuePop(ctxt);
9143    in = start->floatval;
9144    xmlXPathReleaseObject(ctxt->context, start);
9145    CAST_TO_STRING;
9146    CHECK_TYPE(XPATH_STRING);
9147    str = valuePop(ctxt);
9148    m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9149
9150    /*
9151     * If last pos not present, calculate last position
9152    */
9153    if (nargs != 3) {
9154	le = (double)m;
9155	if (in < 1.0)
9156	    in = 1.0;
9157    }
9158
9159    /* Need to check for the special cases where either
9160     * the index is NaN, the length is NaN, or both
9161     * arguments are infinity (relying on Inf + -Inf = NaN)
9162     */
9163    if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9164        /*
9165         * To meet the requirements of the spec, the arguments
9166	 * must be converted to integer format before
9167	 * initial index calculations are done
9168         *
9169         * First we go to integer form, rounding up
9170	 * and checking for special cases
9171         */
9172        i = (int) in;
9173        if (((double)i)+0.5 <= in) i++;
9174
9175	if (xmlXPathIsInf(le) == 1) {
9176	    l = m;
9177	    if (i < 1)
9178		i = 1;
9179	}
9180	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9181	    l = 0;
9182	else {
9183	    l = (int) le;
9184	    if (((double)l)+0.5 <= le) l++;
9185	}
9186
9187	/* Now we normalize inidices */
9188        i -= 1;
9189        l += i;
9190        if (i < 0)
9191            i = 0;
9192        if (l > m)
9193            l = m;
9194
9195        /* number of chars to copy */
9196        l -= i;
9197
9198        ret = xmlUTF8Strsub(str->stringval, i, l);
9199    }
9200    else {
9201        ret = NULL;
9202    }
9203    if (ret == NULL)
9204	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9205    else {
9206	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9207	xmlFree(ret);
9208    }
9209    xmlXPathReleaseObject(ctxt->context, str);
9210}
9211
9212/**
9213 * xmlXPathSubstringBeforeFunction:
9214 * @ctxt:  the XPath Parser context
9215 * @nargs:  the number of arguments
9216 *
9217 * Implement the substring-before() XPath function
9218 *    string substring-before(string, string)
9219 * The substring-before function returns the substring of the first
9220 * argument string that precedes the first occurrence of the second
9221 * argument string in the first argument string, or the empty string
9222 * if the first argument string does not contain the second argument
9223 * string. For example, substring-before("1999/04/01","/") returns 1999.
9224 */
9225void
9226xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9227  xmlXPathObjectPtr str;
9228  xmlXPathObjectPtr find;
9229  xmlBufPtr target;
9230  const xmlChar *point;
9231  int offset;
9232
9233  CHECK_ARITY(2);
9234  CAST_TO_STRING;
9235  find = valuePop(ctxt);
9236  CAST_TO_STRING;
9237  str = valuePop(ctxt);
9238
9239  target = xmlBufCreate();
9240  if (target) {
9241    point = xmlStrstr(str->stringval, find->stringval);
9242    if (point) {
9243      offset = (int)(point - str->stringval);
9244      xmlBufAdd(target, str->stringval, offset);
9245    }
9246    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9247	xmlBufContent(target)));
9248    xmlBufFree(target);
9249  }
9250  xmlXPathReleaseObject(ctxt->context, str);
9251  xmlXPathReleaseObject(ctxt->context, find);
9252}
9253
9254/**
9255 * xmlXPathSubstringAfterFunction:
9256 * @ctxt:  the XPath Parser context
9257 * @nargs:  the number of arguments
9258 *
9259 * Implement the substring-after() XPath function
9260 *    string substring-after(string, string)
9261 * The substring-after function returns the substring of the first
9262 * argument string that follows the first occurrence of the second
9263 * argument string in the first argument string, or the empty stringi
9264 * if the first argument string does not contain the second argument
9265 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9266 * and substring-after("1999/04/01","19") returns 99/04/01.
9267 */
9268void
9269xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9270  xmlXPathObjectPtr str;
9271  xmlXPathObjectPtr find;
9272  xmlBufPtr target;
9273  const xmlChar *point;
9274  int offset;
9275
9276  CHECK_ARITY(2);
9277  CAST_TO_STRING;
9278  find = valuePop(ctxt);
9279  CAST_TO_STRING;
9280  str = valuePop(ctxt);
9281
9282  target = xmlBufCreate();
9283  if (target) {
9284    point = xmlStrstr(str->stringval, find->stringval);
9285    if (point) {
9286      offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9287      xmlBufAdd(target, &str->stringval[offset],
9288		   xmlStrlen(str->stringval) - offset);
9289    }
9290    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9291	xmlBufContent(target)));
9292    xmlBufFree(target);
9293  }
9294  xmlXPathReleaseObject(ctxt->context, str);
9295  xmlXPathReleaseObject(ctxt->context, find);
9296}
9297
9298/**
9299 * xmlXPathNormalizeFunction:
9300 * @ctxt:  the XPath Parser context
9301 * @nargs:  the number of arguments
9302 *
9303 * Implement the normalize-space() XPath function
9304 *    string normalize-space(string?)
9305 * The normalize-space function returns the argument string with white
9306 * space normalized by stripping leading and trailing whitespace
9307 * and replacing sequences of whitespace characters by a single
9308 * space. Whitespace characters are the same allowed by the S production
9309 * in XML. If the argument is omitted, it defaults to the context
9310 * node converted to a string, in other words the value of the context node.
9311 */
9312void
9313xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9314  xmlXPathObjectPtr obj = NULL;
9315  xmlChar *source = NULL;
9316  xmlBufPtr target;
9317  xmlChar blank;
9318
9319  if (ctxt == NULL) return;
9320  if (nargs == 0) {
9321    /* Use current context node */
9322      valuePush(ctxt,
9323	  xmlXPathCacheWrapString(ctxt->context,
9324	    xmlXPathCastNodeToString(ctxt->context->node)));
9325    nargs = 1;
9326  }
9327
9328  CHECK_ARITY(1);
9329  CAST_TO_STRING;
9330  CHECK_TYPE(XPATH_STRING);
9331  obj = valuePop(ctxt);
9332  source = obj->stringval;
9333
9334  target = xmlBufCreate();
9335  if (target && source) {
9336
9337    /* Skip leading whitespaces */
9338    while (IS_BLANK_CH(*source))
9339      source++;
9340
9341    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9342    blank = 0;
9343    while (*source) {
9344      if (IS_BLANK_CH(*source)) {
9345	blank = 0x20;
9346      } else {
9347	if (blank) {
9348	  xmlBufAdd(target, &blank, 1);
9349	  blank = 0;
9350	}
9351	xmlBufAdd(target, source, 1);
9352      }
9353      source++;
9354    }
9355    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9356	xmlBufContent(target)));
9357    xmlBufFree(target);
9358  }
9359  xmlXPathReleaseObject(ctxt->context, obj);
9360}
9361
9362/**
9363 * xmlXPathTranslateFunction:
9364 * @ctxt:  the XPath Parser context
9365 * @nargs:  the number of arguments
9366 *
9367 * Implement the translate() XPath function
9368 *    string translate(string, string, string)
9369 * The translate function returns the first argument string with
9370 * occurrences of characters in the second argument string replaced
9371 * by the character at the corresponding position in the third argument
9372 * string. For example, translate("bar","abc","ABC") returns the string
9373 * BAr. If there is a character in the second argument string with no
9374 * character at a corresponding position in the third argument string
9375 * (because the second argument string is longer than the third argument
9376 * string), then occurrences of that character in the first argument
9377 * string are removed. For example, translate("--aaa--","abc-","ABC")
9378 * returns "AAA". If a character occurs more than once in second
9379 * argument string, then the first occurrence determines the replacement
9380 * character. If the third argument string is longer than the second
9381 * argument string, then excess characters are ignored.
9382 */
9383void
9384xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9385    xmlXPathObjectPtr str;
9386    xmlXPathObjectPtr from;
9387    xmlXPathObjectPtr to;
9388    xmlBufPtr target;
9389    int offset, max;
9390    xmlChar ch;
9391    const xmlChar *point;
9392    xmlChar *cptr;
9393
9394    CHECK_ARITY(3);
9395
9396    CAST_TO_STRING;
9397    to = valuePop(ctxt);
9398    CAST_TO_STRING;
9399    from = valuePop(ctxt);
9400    CAST_TO_STRING;
9401    str = valuePop(ctxt);
9402
9403    target = xmlBufCreate();
9404    if (target) {
9405	max = xmlUTF8Strlen(to->stringval);
9406	for (cptr = str->stringval; (ch=*cptr); ) {
9407	    offset = xmlUTF8Strloc(from->stringval, cptr);
9408	    if (offset >= 0) {
9409		if (offset < max) {
9410		    point = xmlUTF8Strpos(to->stringval, offset);
9411		    if (point)
9412			xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9413		}
9414	    } else
9415		xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9416
9417	    /* Step to next character in input */
9418	    cptr++;
9419	    if ( ch & 0x80 ) {
9420		/* if not simple ascii, verify proper format */
9421		if ( (ch & 0xc0) != 0xc0 ) {
9422		    xmlGenericError(xmlGenericErrorContext,
9423			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
9424                    /* not asserting an XPath error is probably better */
9425		    break;
9426		}
9427		/* then skip over remaining bytes for this char */
9428		while ( (ch <<= 1) & 0x80 )
9429		    if ( (*cptr++ & 0xc0) != 0x80 ) {
9430			xmlGenericError(xmlGenericErrorContext,
9431			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9432                        /* not asserting an XPath error is probably better */
9433			break;
9434		    }
9435		if (ch & 0x80) /* must have had error encountered */
9436		    break;
9437	    }
9438	}
9439    }
9440    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9441	xmlBufContent(target)));
9442    xmlBufFree(target);
9443    xmlXPathReleaseObject(ctxt->context, str);
9444    xmlXPathReleaseObject(ctxt->context, from);
9445    xmlXPathReleaseObject(ctxt->context, to);
9446}
9447
9448/**
9449 * xmlXPathBooleanFunction:
9450 * @ctxt:  the XPath Parser context
9451 * @nargs:  the number of arguments
9452 *
9453 * Implement the boolean() XPath function
9454 *    boolean boolean(object)
9455 * The boolean function converts its argument to a boolean as follows:
9456 *    - a number is true if and only if it is neither positive or
9457 *      negative zero nor NaN
9458 *    - a node-set is true if and only if it is non-empty
9459 *    - a string is true if and only if its length is non-zero
9460 */
9461void
9462xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9463    xmlXPathObjectPtr cur;
9464
9465    CHECK_ARITY(1);
9466    cur = valuePop(ctxt);
9467    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9468    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9469    valuePush(ctxt, cur);
9470}
9471
9472/**
9473 * xmlXPathNotFunction:
9474 * @ctxt:  the XPath Parser context
9475 * @nargs:  the number of arguments
9476 *
9477 * Implement the not() XPath function
9478 *    boolean not(boolean)
9479 * The not function returns true if its argument is false,
9480 * and false otherwise.
9481 */
9482void
9483xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9484    CHECK_ARITY(1);
9485    CAST_TO_BOOLEAN;
9486    CHECK_TYPE(XPATH_BOOLEAN);
9487    ctxt->value->boolval = ! ctxt->value->boolval;
9488}
9489
9490/**
9491 * xmlXPathTrueFunction:
9492 * @ctxt:  the XPath Parser context
9493 * @nargs:  the number of arguments
9494 *
9495 * Implement the true() XPath function
9496 *    boolean true()
9497 */
9498void
9499xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9500    CHECK_ARITY(0);
9501    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9502}
9503
9504/**
9505 * xmlXPathFalseFunction:
9506 * @ctxt:  the XPath Parser context
9507 * @nargs:  the number of arguments
9508 *
9509 * Implement the false() XPath function
9510 *    boolean false()
9511 */
9512void
9513xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9514    CHECK_ARITY(0);
9515    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9516}
9517
9518/**
9519 * xmlXPathLangFunction:
9520 * @ctxt:  the XPath Parser context
9521 * @nargs:  the number of arguments
9522 *
9523 * Implement the lang() XPath function
9524 *    boolean lang(string)
9525 * The lang function returns true or false depending on whether the
9526 * language of the context node as specified by xml:lang attributes
9527 * is the same as or is a sublanguage of the language specified by
9528 * the argument string. The language of the context node is determined
9529 * by the value of the xml:lang attribute on the context node, or, if
9530 * the context node has no xml:lang attribute, by the value of the
9531 * xml:lang attribute on the nearest ancestor of the context node that
9532 * has an xml:lang attribute. If there is no such attribute, then lang
9533 * returns false. If there is such an attribute, then lang returns
9534 * true if the attribute value is equal to the argument ignoring case,
9535 * or if there is some suffix starting with - such that the attribute
9536 * value is equal to the argument ignoring that suffix of the attribute
9537 * value and ignoring case.
9538 */
9539void
9540xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9541    xmlXPathObjectPtr val = NULL;
9542    const xmlChar *theLang = NULL;
9543    const xmlChar *lang;
9544    int ret = 0;
9545    int i;
9546
9547    CHECK_ARITY(1);
9548    CAST_TO_STRING;
9549    CHECK_TYPE(XPATH_STRING);
9550    val = valuePop(ctxt);
9551    lang = val->stringval;
9552    theLang = xmlNodeGetLang(ctxt->context->node);
9553    if ((theLang != NULL) && (lang != NULL)) {
9554        for (i = 0;lang[i] != 0;i++)
9555	    if (toupper(lang[i]) != toupper(theLang[i]))
9556	        goto not_equal;
9557	if ((theLang[i] == 0) || (theLang[i] == '-'))
9558	    ret = 1;
9559    }
9560not_equal:
9561    if (theLang != NULL)
9562	xmlFree((void *)theLang);
9563
9564    xmlXPathReleaseObject(ctxt->context, val);
9565    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9566}
9567
9568/**
9569 * xmlXPathNumberFunction:
9570 * @ctxt:  the XPath Parser context
9571 * @nargs:  the number of arguments
9572 *
9573 * Implement the number() XPath function
9574 *    number number(object?)
9575 */
9576void
9577xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9578    xmlXPathObjectPtr cur;
9579    double res;
9580
9581    if (ctxt == NULL) return;
9582    if (nargs == 0) {
9583	if (ctxt->context->node == NULL) {
9584	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9585	} else {
9586	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9587
9588	    res = xmlXPathStringEvalNumber(content);
9589	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9590	    xmlFree(content);
9591	}
9592	return;
9593    }
9594
9595    CHECK_ARITY(1);
9596    cur = valuePop(ctxt);
9597    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9598}
9599
9600/**
9601 * xmlXPathSumFunction:
9602 * @ctxt:  the XPath Parser context
9603 * @nargs:  the number of arguments
9604 *
9605 * Implement the sum() XPath function
9606 *    number sum(node-set)
9607 * The sum function returns the sum of the values of the nodes in
9608 * the argument node-set.
9609 */
9610void
9611xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9612    xmlXPathObjectPtr cur;
9613    int i;
9614    double res = 0.0;
9615
9616    CHECK_ARITY(1);
9617    if ((ctxt->value == NULL) ||
9618	((ctxt->value->type != XPATH_NODESET) &&
9619	 (ctxt->value->type != XPATH_XSLT_TREE)))
9620	XP_ERROR(XPATH_INVALID_TYPE);
9621    cur = valuePop(ctxt);
9622
9623    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9624	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9625	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9626	}
9627    }
9628    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9629    xmlXPathReleaseObject(ctxt->context, cur);
9630}
9631
9632/*
9633 * To assure working code on multiple platforms, we want to only depend
9634 * upon the characteristic truncation of converting a floating point value
9635 * to an integer.  Unfortunately, because of the different storage sizes
9636 * of our internal floating point value (double) and integer (int), we
9637 * can't directly convert (see bug 301162).  This macro is a messy
9638 * 'workaround'
9639 */
9640#define XTRUNC(f, v)            \
9641    f = fmod((v), INT_MAX);     \
9642    f = (v) - (f) + (double)((int)(f));
9643
9644/**
9645 * xmlXPathFloorFunction:
9646 * @ctxt:  the XPath Parser context
9647 * @nargs:  the number of arguments
9648 *
9649 * Implement the floor() XPath function
9650 *    number floor(number)
9651 * The floor function returns the largest (closest to positive infinity)
9652 * number that is not greater than the argument and that is an integer.
9653 */
9654void
9655xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9656    double f;
9657
9658    CHECK_ARITY(1);
9659    CAST_TO_NUMBER;
9660    CHECK_TYPE(XPATH_NUMBER);
9661
9662    XTRUNC(f, ctxt->value->floatval);
9663    if (f != ctxt->value->floatval) {
9664	if (ctxt->value->floatval > 0)
9665	    ctxt->value->floatval = f;
9666	else
9667	    ctxt->value->floatval = f - 1;
9668    }
9669}
9670
9671/**
9672 * xmlXPathCeilingFunction:
9673 * @ctxt:  the XPath Parser context
9674 * @nargs:  the number of arguments
9675 *
9676 * Implement the ceiling() XPath function
9677 *    number ceiling(number)
9678 * The ceiling function returns the smallest (closest to negative infinity)
9679 * number that is not less than the argument and that is an integer.
9680 */
9681void
9682xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9683    double f;
9684
9685    CHECK_ARITY(1);
9686    CAST_TO_NUMBER;
9687    CHECK_TYPE(XPATH_NUMBER);
9688
9689#if 0
9690    ctxt->value->floatval = ceil(ctxt->value->floatval);
9691#else
9692    XTRUNC(f, ctxt->value->floatval);
9693    if (f != ctxt->value->floatval) {
9694	if (ctxt->value->floatval > 0)
9695	    ctxt->value->floatval = f + 1;
9696	else {
9697	    if (ctxt->value->floatval < 0 && f == 0)
9698	        ctxt->value->floatval = xmlXPathNZERO;
9699	    else
9700	        ctxt->value->floatval = f;
9701	}
9702
9703    }
9704#endif
9705}
9706
9707/**
9708 * xmlXPathRoundFunction:
9709 * @ctxt:  the XPath Parser context
9710 * @nargs:  the number of arguments
9711 *
9712 * Implement the round() XPath function
9713 *    number round(number)
9714 * The round function returns the number that is closest to the
9715 * argument and that is an integer. If there are two such numbers,
9716 * then the one that is even is returned.
9717 */
9718void
9719xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9720    double f;
9721
9722    CHECK_ARITY(1);
9723    CAST_TO_NUMBER;
9724    CHECK_TYPE(XPATH_NUMBER);
9725
9726    if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9727	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9728	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9729	(ctxt->value->floatval == 0.0))
9730	return;
9731
9732    XTRUNC(f, ctxt->value->floatval);
9733    if (ctxt->value->floatval < 0) {
9734	if (ctxt->value->floatval < f - 0.5)
9735	    ctxt->value->floatval = f - 1;
9736	else
9737	    ctxt->value->floatval = f;
9738	if (ctxt->value->floatval == 0)
9739	    ctxt->value->floatval = xmlXPathNZERO;
9740    } else {
9741	if (ctxt->value->floatval < f + 0.5)
9742	    ctxt->value->floatval = f;
9743	else
9744	    ctxt->value->floatval = f + 1;
9745    }
9746}
9747
9748/************************************************************************
9749 *									*
9750 *			The Parser					*
9751 *									*
9752 ************************************************************************/
9753
9754/*
9755 * a few forward declarations since we use a recursive call based
9756 * implementation.
9757 */
9758static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9759static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9760static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9761static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9762static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9763	                                  int qualified);
9764
9765/**
9766 * xmlXPathCurrentChar:
9767 * @ctxt:  the XPath parser context
9768 * @cur:  pointer to the beginning of the char
9769 * @len:  pointer to the length of the char read
9770 *
9771 * The current char value, if using UTF-8 this may actually span multiple
9772 * bytes in the input buffer.
9773 *
9774 * Returns the current char value and its length
9775 */
9776
9777static int
9778xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9779    unsigned char c;
9780    unsigned int val;
9781    const xmlChar *cur;
9782
9783    if (ctxt == NULL)
9784	return(0);
9785    cur = ctxt->cur;
9786
9787    /*
9788     * We are supposed to handle UTF8, check it's valid
9789     * From rfc2044: encoding of the Unicode values on UTF-8:
9790     *
9791     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9792     * 0000 0000-0000 007F   0xxxxxxx
9793     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9794     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9795     *
9796     * Check for the 0x110000 limit too
9797     */
9798    c = *cur;
9799    if (c & 0x80) {
9800	if ((cur[1] & 0xc0) != 0x80)
9801	    goto encoding_error;
9802	if ((c & 0xe0) == 0xe0) {
9803
9804	    if ((cur[2] & 0xc0) != 0x80)
9805		goto encoding_error;
9806	    if ((c & 0xf0) == 0xf0) {
9807		if (((c & 0xf8) != 0xf0) ||
9808		    ((cur[3] & 0xc0) != 0x80))
9809		    goto encoding_error;
9810		/* 4-byte code */
9811		*len = 4;
9812		val = (cur[0] & 0x7) << 18;
9813		val |= (cur[1] & 0x3f) << 12;
9814		val |= (cur[2] & 0x3f) << 6;
9815		val |= cur[3] & 0x3f;
9816	    } else {
9817	      /* 3-byte code */
9818		*len = 3;
9819		val = (cur[0] & 0xf) << 12;
9820		val |= (cur[1] & 0x3f) << 6;
9821		val |= cur[2] & 0x3f;
9822	    }
9823	} else {
9824	  /* 2-byte code */
9825	    *len = 2;
9826	    val = (cur[0] & 0x1f) << 6;
9827	    val |= cur[1] & 0x3f;
9828	}
9829	if (!IS_CHAR(val)) {
9830	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9831	}
9832	return(val);
9833    } else {
9834	/* 1-byte code */
9835	*len = 1;
9836	return((int) *cur);
9837    }
9838encoding_error:
9839    /*
9840     * If we detect an UTF8 error that probably means that the
9841     * input encoding didn't get properly advertised in the
9842     * declaration header. Report the error and switch the encoding
9843     * to ISO-Latin-1 (if you don't like this policy, just declare the
9844     * encoding !)
9845     */
9846    *len = 0;
9847    XP_ERROR0(XPATH_ENCODING_ERROR);
9848}
9849
9850/**
9851 * xmlXPathParseNCName:
9852 * @ctxt:  the XPath Parser context
9853 *
9854 * parse an XML namespace non qualified name.
9855 *
9856 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9857 *
9858 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9859 *                       CombiningChar | Extender
9860 *
9861 * Returns the namespace name or NULL
9862 */
9863
9864xmlChar *
9865xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9866    const xmlChar *in;
9867    xmlChar *ret;
9868    int count = 0;
9869
9870    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9871    /*
9872     * Accelerator for simple ASCII names
9873     */
9874    in = ctxt->cur;
9875    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9876	((*in >= 0x41) && (*in <= 0x5A)) ||
9877	(*in == '_')) {
9878	in++;
9879	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9880	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9881	       ((*in >= 0x30) && (*in <= 0x39)) ||
9882	       (*in == '_') || (*in == '.') ||
9883	       (*in == '-'))
9884	    in++;
9885	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9886            (*in == '[') || (*in == ']') || (*in == ':') ||
9887            (*in == '@') || (*in == '*')) {
9888	    count = in - ctxt->cur;
9889	    if (count == 0)
9890		return(NULL);
9891	    ret = xmlStrndup(ctxt->cur, count);
9892	    ctxt->cur = in;
9893	    return(ret);
9894	}
9895    }
9896    return(xmlXPathParseNameComplex(ctxt, 0));
9897}
9898
9899
9900/**
9901 * xmlXPathParseQName:
9902 * @ctxt:  the XPath Parser context
9903 * @prefix:  a xmlChar **
9904 *
9905 * parse an XML qualified name
9906 *
9907 * [NS 5] QName ::= (Prefix ':')? LocalPart
9908 *
9909 * [NS 6] Prefix ::= NCName
9910 *
9911 * [NS 7] LocalPart ::= NCName
9912 *
9913 * Returns the function returns the local part, and prefix is updated
9914 *   to get the Prefix if any.
9915 */
9916
9917static xmlChar *
9918xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9919    xmlChar *ret = NULL;
9920
9921    *prefix = NULL;
9922    ret = xmlXPathParseNCName(ctxt);
9923    if (ret && CUR == ':') {
9924        *prefix = ret;
9925	NEXT;
9926	ret = xmlXPathParseNCName(ctxt);
9927    }
9928    return(ret);
9929}
9930
9931/**
9932 * xmlXPathParseName:
9933 * @ctxt:  the XPath Parser context
9934 *
9935 * parse an XML name
9936 *
9937 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9938 *                  CombiningChar | Extender
9939 *
9940 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9941 *
9942 * Returns the namespace name or NULL
9943 */
9944
9945xmlChar *
9946xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9947    const xmlChar *in;
9948    xmlChar *ret;
9949    size_t count = 0;
9950
9951    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9952    /*
9953     * Accelerator for simple ASCII names
9954     */
9955    in = ctxt->cur;
9956    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9957	((*in >= 0x41) && (*in <= 0x5A)) ||
9958	(*in == '_') || (*in == ':')) {
9959	in++;
9960	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9961	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9962	       ((*in >= 0x30) && (*in <= 0x39)) ||
9963	       (*in == '_') || (*in == '-') ||
9964	       (*in == ':') || (*in == '.'))
9965	    in++;
9966	if ((*in > 0) && (*in < 0x80)) {
9967	    count = in - ctxt->cur;
9968            if (count > XML_MAX_NAME_LENGTH) {
9969                ctxt->cur = in;
9970                XP_ERRORNULL(XPATH_EXPR_ERROR);
9971            }
9972	    ret = xmlStrndup(ctxt->cur, count);
9973	    ctxt->cur = in;
9974	    return(ret);
9975	}
9976    }
9977    return(xmlXPathParseNameComplex(ctxt, 1));
9978}
9979
9980static xmlChar *
9981xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9982    xmlChar buf[XML_MAX_NAMELEN + 5];
9983    int len = 0, l;
9984    int c;
9985
9986    /*
9987     * Handler for more complex cases
9988     */
9989    c = CUR_CHAR(l);
9990    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9991        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9992        (c == '*') || /* accelerators */
9993	(!IS_LETTER(c) && (c != '_') &&
9994         ((qualified) && (c != ':')))) {
9995	return(NULL);
9996    }
9997
9998    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9999	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10000            (c == '.') || (c == '-') ||
10001	    (c == '_') || ((qualified) && (c == ':')) ||
10002	    (IS_COMBINING(c)) ||
10003	    (IS_EXTENDER(c)))) {
10004	COPY_BUF(l,buf,len,c);
10005	NEXTL(l);
10006	c = CUR_CHAR(l);
10007	if (len >= XML_MAX_NAMELEN) {
10008	    /*
10009	     * Okay someone managed to make a huge name, so he's ready to pay
10010	     * for the processing speed.
10011	     */
10012	    xmlChar *buffer;
10013	    int max = len * 2;
10014
10015            if (len > XML_MAX_NAME_LENGTH) {
10016                XP_ERRORNULL(XPATH_EXPR_ERROR);
10017            }
10018	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
10019	    if (buffer == NULL) {
10020		XP_ERRORNULL(XPATH_MEMORY_ERROR);
10021	    }
10022	    memcpy(buffer, buf, len);
10023	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10024		   (c == '.') || (c == '-') ||
10025		   (c == '_') || ((qualified) && (c == ':')) ||
10026		   (IS_COMBINING(c)) ||
10027		   (IS_EXTENDER(c))) {
10028		if (len + 10 > max) {
10029                    if (max > XML_MAX_NAME_LENGTH) {
10030                        XP_ERRORNULL(XPATH_EXPR_ERROR);
10031                    }
10032		    max *= 2;
10033		    buffer = (xmlChar *) xmlRealloc(buffer,
10034			                            max * sizeof(xmlChar));
10035		    if (buffer == NULL) {
10036			XP_ERRORNULL(XPATH_MEMORY_ERROR);
10037		    }
10038		}
10039		COPY_BUF(l,buffer,len,c);
10040		NEXTL(l);
10041		c = CUR_CHAR(l);
10042	    }
10043	    buffer[len] = 0;
10044	    return(buffer);
10045	}
10046    }
10047    if (len == 0)
10048	return(NULL);
10049    return(xmlStrndup(buf, len));
10050}
10051
10052#define MAX_FRAC 20
10053
10054/*
10055 * These are used as divisors for the fractional part of a number.
10056 * Since the table includes 1.0 (representing '0' fractional digits),
10057 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
10058 */
10059static double my_pow10[MAX_FRAC+1] = {
10060    1.0, 10.0, 100.0, 1000.0, 10000.0,
10061    100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
10062    10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
10063    100000000000000.0,
10064    1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
10065    1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
10066};
10067
10068/**
10069 * xmlXPathStringEvalNumber:
10070 * @str:  A string to scan
10071 *
10072 *  [30a]  Float  ::= Number ('e' Digits?)?
10073 *
10074 *  [30]   Number ::=   Digits ('.' Digits?)?
10075 *                    | '.' Digits
10076 *  [31]   Digits ::=   [0-9]+
10077 *
10078 * Compile a Number in the string
10079 * In complement of the Number expression, this function also handles
10080 * negative values : '-' Number.
10081 *
10082 * Returns the double value.
10083 */
10084double
10085xmlXPathStringEvalNumber(const xmlChar *str) {
10086    const xmlChar *cur = str;
10087    double ret;
10088    int ok = 0;
10089    int isneg = 0;
10090    int exponent = 0;
10091    int is_exponent_negative = 0;
10092#ifdef __GNUC__
10093    unsigned long tmp = 0;
10094    double temp;
10095#endif
10096    if (cur == NULL) return(0);
10097    while (IS_BLANK_CH(*cur)) cur++;
10098    if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10099        return(xmlXPathNAN);
10100    }
10101    if (*cur == '-') {
10102	isneg = 1;
10103	cur++;
10104    }
10105
10106#ifdef __GNUC__
10107    /*
10108     * tmp/temp is a workaround against a gcc compiler bug
10109     * http://veillard.com/gcc.bug
10110     */
10111    ret = 0;
10112    while ((*cur >= '0') && (*cur <= '9')) {
10113	ret = ret * 10;
10114	tmp = (*cur - '0');
10115	ok = 1;
10116	cur++;
10117	temp = (double) tmp;
10118	ret = ret + temp;
10119    }
10120#else
10121    ret = 0;
10122    while ((*cur >= '0') && (*cur <= '9')) {
10123	ret = ret * 10 + (*cur - '0');
10124	ok = 1;
10125	cur++;
10126    }
10127#endif
10128
10129    if (*cur == '.') {
10130	int v, frac = 0;
10131	double fraction = 0;
10132
10133        cur++;
10134	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10135	    return(xmlXPathNAN);
10136	}
10137	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10138	    v = (*cur - '0');
10139	    fraction = fraction * 10 + v;
10140	    frac = frac + 1;
10141	    cur++;
10142	}
10143	fraction /= my_pow10[frac];
10144	ret = ret + fraction;
10145	while ((*cur >= '0') && (*cur <= '9'))
10146	    cur++;
10147    }
10148    if ((*cur == 'e') || (*cur == 'E')) {
10149      cur++;
10150      if (*cur == '-') {
10151	is_exponent_negative = 1;
10152	cur++;
10153      } else if (*cur == '+') {
10154        cur++;
10155      }
10156      while ((*cur >= '0') && (*cur <= '9')) {
10157	exponent = exponent * 10 + (*cur - '0');
10158	cur++;
10159      }
10160    }
10161    while (IS_BLANK_CH(*cur)) cur++;
10162    if (*cur != 0) return(xmlXPathNAN);
10163    if (isneg) ret = -ret;
10164    if (is_exponent_negative) exponent = -exponent;
10165    ret *= pow(10.0, (double)exponent);
10166    return(ret);
10167}
10168
10169/**
10170 * xmlXPathCompNumber:
10171 * @ctxt:  the XPath Parser context
10172 *
10173 *  [30]   Number ::=   Digits ('.' Digits?)?
10174 *                    | '.' Digits
10175 *  [31]   Digits ::=   [0-9]+
10176 *
10177 * Compile a Number, then push it on the stack
10178 *
10179 */
10180static void
10181xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10182{
10183    double ret = 0.0;
10184    int ok = 0;
10185    int exponent = 0;
10186    int is_exponent_negative = 0;
10187#ifdef __GNUC__
10188    unsigned long tmp = 0;
10189    double temp;
10190#endif
10191
10192    CHECK_ERROR;
10193    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10194        XP_ERROR(XPATH_NUMBER_ERROR);
10195    }
10196#ifdef __GNUC__
10197    /*
10198     * tmp/temp is a workaround against a gcc compiler bug
10199     * http://veillard.com/gcc.bug
10200     */
10201    ret = 0;
10202    while ((CUR >= '0') && (CUR <= '9')) {
10203	ret = ret * 10;
10204	tmp = (CUR - '0');
10205        ok = 1;
10206        NEXT;
10207	temp = (double) tmp;
10208	ret = ret + temp;
10209    }
10210#else
10211    ret = 0;
10212    while ((CUR >= '0') && (CUR <= '9')) {
10213	ret = ret * 10 + (CUR - '0');
10214	ok = 1;
10215	NEXT;
10216    }
10217#endif
10218    if (CUR == '.') {
10219	int v, frac = 0;
10220	double fraction = 0;
10221
10222        NEXT;
10223        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10224            XP_ERROR(XPATH_NUMBER_ERROR);
10225        }
10226        while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10227	    v = (CUR - '0');
10228	    fraction = fraction * 10 + v;
10229	    frac = frac + 1;
10230            NEXT;
10231        }
10232        fraction /= my_pow10[frac];
10233        ret = ret + fraction;
10234        while ((CUR >= '0') && (CUR <= '9'))
10235            NEXT;
10236    }
10237    if ((CUR == 'e') || (CUR == 'E')) {
10238        NEXT;
10239        if (CUR == '-') {
10240            is_exponent_negative = 1;
10241            NEXT;
10242        } else if (CUR == '+') {
10243	    NEXT;
10244	}
10245        while ((CUR >= '0') && (CUR <= '9')) {
10246            exponent = exponent * 10 + (CUR - '0');
10247            NEXT;
10248        }
10249        if (is_exponent_negative)
10250            exponent = -exponent;
10251        ret *= pow(10.0, (double) exponent);
10252    }
10253    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10254                   xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10255}
10256
10257/**
10258 * xmlXPathParseLiteral:
10259 * @ctxt:  the XPath Parser context
10260 *
10261 * Parse a Literal
10262 *
10263 *  [29]   Literal ::=   '"' [^"]* '"'
10264 *                    | "'" [^']* "'"
10265 *
10266 * Returns the value found or NULL in case of error
10267 */
10268static xmlChar *
10269xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10270    const xmlChar *q;
10271    xmlChar *ret = NULL;
10272
10273    if (CUR == '"') {
10274        NEXT;
10275	q = CUR_PTR;
10276	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10277	    NEXT;
10278	if (!IS_CHAR_CH(CUR)) {
10279	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10280	} else {
10281	    ret = xmlStrndup(q, CUR_PTR - q);
10282	    NEXT;
10283        }
10284    } else if (CUR == '\'') {
10285        NEXT;
10286	q = CUR_PTR;
10287	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10288	    NEXT;
10289	if (!IS_CHAR_CH(CUR)) {
10290	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10291	} else {
10292	    ret = xmlStrndup(q, CUR_PTR - q);
10293	    NEXT;
10294        }
10295    } else {
10296	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10297    }
10298    return(ret);
10299}
10300
10301/**
10302 * xmlXPathCompLiteral:
10303 * @ctxt:  the XPath Parser context
10304 *
10305 * Parse a Literal and push it on the stack.
10306 *
10307 *  [29]   Literal ::=   '"' [^"]* '"'
10308 *                    | "'" [^']* "'"
10309 *
10310 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10311 */
10312static void
10313xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10314    const xmlChar *q;
10315    xmlChar *ret = NULL;
10316
10317    if (CUR == '"') {
10318        NEXT;
10319	q = CUR_PTR;
10320	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10321	    NEXT;
10322	if (!IS_CHAR_CH(CUR)) {
10323	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10324	} else {
10325	    ret = xmlStrndup(q, CUR_PTR - q);
10326	    NEXT;
10327        }
10328    } else if (CUR == '\'') {
10329        NEXT;
10330	q = CUR_PTR;
10331	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10332	    NEXT;
10333	if (!IS_CHAR_CH(CUR)) {
10334	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10335	} else {
10336	    ret = xmlStrndup(q, CUR_PTR - q);
10337	    NEXT;
10338        }
10339    } else {
10340	XP_ERROR(XPATH_START_LITERAL_ERROR);
10341    }
10342    if (ret == NULL) return;
10343    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10344	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
10345    xmlFree(ret);
10346}
10347
10348/**
10349 * xmlXPathCompVariableReference:
10350 * @ctxt:  the XPath Parser context
10351 *
10352 * Parse a VariableReference, evaluate it and push it on the stack.
10353 *
10354 * The variable bindings consist of a mapping from variable names
10355 * to variable values. The value of a variable is an object, which can be
10356 * of any of the types that are possible for the value of an expression,
10357 * and may also be of additional types not specified here.
10358 *
10359 * Early evaluation is possible since:
10360 * The variable bindings [...] used to evaluate a subexpression are
10361 * always the same as those used to evaluate the containing expression.
10362 *
10363 *  [36]   VariableReference ::=   '$' QName
10364 */
10365static void
10366xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10367    xmlChar *name;
10368    xmlChar *prefix;
10369
10370    SKIP_BLANKS;
10371    if (CUR != '$') {
10372	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10373    }
10374    NEXT;
10375    name = xmlXPathParseQName(ctxt, &prefix);
10376    if (name == NULL) {
10377	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10378    }
10379    ctxt->comp->last = -1;
10380    PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10381	           name, prefix);
10382    SKIP_BLANKS;
10383    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10384	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10385    }
10386}
10387
10388/**
10389 * xmlXPathIsNodeType:
10390 * @name:  a name string
10391 *
10392 * Is the name given a NodeType one.
10393 *
10394 *  [38]   NodeType ::=   'comment'
10395 *                    | 'text'
10396 *                    | 'processing-instruction'
10397 *                    | 'node'
10398 *
10399 * Returns 1 if true 0 otherwise
10400 */
10401int
10402xmlXPathIsNodeType(const xmlChar *name) {
10403    if (name == NULL)
10404	return(0);
10405
10406    if (xmlStrEqual(name, BAD_CAST "node"))
10407	return(1);
10408    if (xmlStrEqual(name, BAD_CAST "text"))
10409	return(1);
10410    if (xmlStrEqual(name, BAD_CAST "comment"))
10411	return(1);
10412    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10413	return(1);
10414    return(0);
10415}
10416
10417/**
10418 * xmlXPathCompFunctionCall:
10419 * @ctxt:  the XPath Parser context
10420 *
10421 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10422 *  [17]   Argument ::=   Expr
10423 *
10424 * Compile a function call, the evaluation of all arguments are
10425 * pushed on the stack
10426 */
10427static void
10428xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10429    xmlChar *name;
10430    xmlChar *prefix;
10431    int nbargs = 0;
10432    int sort = 1;
10433
10434    name = xmlXPathParseQName(ctxt, &prefix);
10435    if (name == NULL) {
10436	xmlFree(prefix);
10437	XP_ERROR(XPATH_EXPR_ERROR);
10438    }
10439    SKIP_BLANKS;
10440#ifdef DEBUG_EXPR
10441    if (prefix == NULL)
10442	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10443			name);
10444    else
10445	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10446			prefix, name);
10447#endif
10448
10449    if (CUR != '(') {
10450	XP_ERROR(XPATH_EXPR_ERROR);
10451    }
10452    NEXT;
10453    SKIP_BLANKS;
10454
10455    /*
10456    * Optimization for count(): we don't need the node-set to be sorted.
10457    */
10458    if ((prefix == NULL) && (name[0] == 'c') &&
10459	xmlStrEqual(name, BAD_CAST "count"))
10460    {
10461	sort = 0;
10462    }
10463    ctxt->comp->last = -1;
10464    if (CUR != ')') {
10465	while (CUR != 0) {
10466	    int op1 = ctxt->comp->last;
10467	    ctxt->comp->last = -1;
10468	    xmlXPathCompileExpr(ctxt, sort);
10469	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10470		xmlFree(name);
10471		xmlFree(prefix);
10472		return;
10473	    }
10474	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10475	    nbargs++;
10476	    if (CUR == ')') break;
10477	    if (CUR != ',') {
10478		XP_ERROR(XPATH_EXPR_ERROR);
10479	    }
10480	    NEXT;
10481	    SKIP_BLANKS;
10482	}
10483    }
10484    PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10485	           name, prefix);
10486    NEXT;
10487    SKIP_BLANKS;
10488}
10489
10490/**
10491 * xmlXPathCompPrimaryExpr:
10492 * @ctxt:  the XPath Parser context
10493 *
10494 *  [15]   PrimaryExpr ::=   VariableReference
10495 *                | '(' Expr ')'
10496 *                | Literal
10497 *                | Number
10498 *                | FunctionCall
10499 *
10500 * Compile a primary expression.
10501 */
10502static void
10503xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10504    SKIP_BLANKS;
10505    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10506    else if (CUR == '(') {
10507	NEXT;
10508	SKIP_BLANKS;
10509	xmlXPathCompileExpr(ctxt, 1);
10510	CHECK_ERROR;
10511	if (CUR != ')') {
10512	    XP_ERROR(XPATH_EXPR_ERROR);
10513	}
10514	NEXT;
10515	SKIP_BLANKS;
10516    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10517	xmlXPathCompNumber(ctxt);
10518    } else if ((CUR == '\'') || (CUR == '"')) {
10519	xmlXPathCompLiteral(ctxt);
10520    } else {
10521	xmlXPathCompFunctionCall(ctxt);
10522    }
10523    SKIP_BLANKS;
10524}
10525
10526/**
10527 * xmlXPathCompFilterExpr:
10528 * @ctxt:  the XPath Parser context
10529 *
10530 *  [20]   FilterExpr ::=   PrimaryExpr
10531 *               | FilterExpr Predicate
10532 *
10533 * Compile a filter expression.
10534 * Square brackets are used to filter expressions in the same way that
10535 * they are used in location paths. It is an error if the expression to
10536 * be filtered does not evaluate to a node-set. The context node list
10537 * used for evaluating the expression in square brackets is the node-set
10538 * to be filtered listed in document order.
10539 */
10540
10541static void
10542xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10543    xmlXPathCompPrimaryExpr(ctxt);
10544    CHECK_ERROR;
10545    SKIP_BLANKS;
10546
10547    while (CUR == '[') {
10548	xmlXPathCompPredicate(ctxt, 1);
10549	SKIP_BLANKS;
10550    }
10551
10552
10553}
10554
10555/**
10556 * xmlXPathScanName:
10557 * @ctxt:  the XPath Parser context
10558 *
10559 * Trickery: parse an XML name but without consuming the input flow
10560 * Needed to avoid insanity in the parser state.
10561 *
10562 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10563 *                  CombiningChar | Extender
10564 *
10565 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10566 *
10567 * [6] Names ::= Name (S Name)*
10568 *
10569 * Returns the Name parsed or NULL
10570 */
10571
10572static xmlChar *
10573xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10574    int len = 0, l;
10575    int c;
10576    const xmlChar *cur;
10577    xmlChar *ret;
10578
10579    cur = ctxt->cur;
10580
10581    c = CUR_CHAR(l);
10582    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10583	(!IS_LETTER(c) && (c != '_') &&
10584         (c != ':'))) {
10585	return(NULL);
10586    }
10587
10588    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10589	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10590            (c == '.') || (c == '-') ||
10591	    (c == '_') || (c == ':') ||
10592	    (IS_COMBINING(c)) ||
10593	    (IS_EXTENDER(c)))) {
10594	len += l;
10595	NEXTL(l);
10596	c = CUR_CHAR(l);
10597    }
10598    ret = xmlStrndup(cur, ctxt->cur - cur);
10599    ctxt->cur = cur;
10600    return(ret);
10601}
10602
10603/**
10604 * xmlXPathCompPathExpr:
10605 * @ctxt:  the XPath Parser context
10606 *
10607 *  [19]   PathExpr ::=   LocationPath
10608 *               | FilterExpr
10609 *               | FilterExpr '/' RelativeLocationPath
10610 *               | FilterExpr '//' RelativeLocationPath
10611 *
10612 * Compile a path expression.
10613 * The / operator and // operators combine an arbitrary expression
10614 * and a relative location path. It is an error if the expression
10615 * does not evaluate to a node-set.
10616 * The / operator does composition in the same way as when / is
10617 * used in a location path. As in location paths, // is short for
10618 * /descendant-or-self::node()/.
10619 */
10620
10621static void
10622xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10623    int lc = 1;           /* Should we branch to LocationPath ?         */
10624    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10625
10626    SKIP_BLANKS;
10627    if ((CUR == '$') || (CUR == '(') ||
10628	(IS_ASCII_DIGIT(CUR)) ||
10629        (CUR == '\'') || (CUR == '"') ||
10630	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10631	lc = 0;
10632    } else if (CUR == '*') {
10633	/* relative or absolute location path */
10634	lc = 1;
10635    } else if (CUR == '/') {
10636	/* relative or absolute location path */
10637	lc = 1;
10638    } else if (CUR == '@') {
10639	/* relative abbreviated attribute location path */
10640	lc = 1;
10641    } else if (CUR == '.') {
10642	/* relative abbreviated attribute location path */
10643	lc = 1;
10644    } else {
10645	/*
10646	 * Problem is finding if we have a name here whether it's:
10647	 *   - a nodetype
10648	 *   - a function call in which case it's followed by '('
10649	 *   - an axis in which case it's followed by ':'
10650	 *   - a element name
10651	 * We do an a priori analysis here rather than having to
10652	 * maintain parsed token content through the recursive function
10653	 * calls. This looks uglier but makes the code easier to
10654	 * read/write/debug.
10655	 */
10656	SKIP_BLANKS;
10657	name = xmlXPathScanName(ctxt);
10658	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10659#ifdef DEBUG_STEP
10660	    xmlGenericError(xmlGenericErrorContext,
10661		    "PathExpr: Axis\n");
10662#endif
10663	    lc = 1;
10664	    xmlFree(name);
10665	} else if (name != NULL) {
10666	    int len =xmlStrlen(name);
10667
10668
10669	    while (NXT(len) != 0) {
10670		if (NXT(len) == '/') {
10671		    /* element name */
10672#ifdef DEBUG_STEP
10673		    xmlGenericError(xmlGenericErrorContext,
10674			    "PathExpr: AbbrRelLocation\n");
10675#endif
10676		    lc = 1;
10677		    break;
10678		} else if (IS_BLANK_CH(NXT(len))) {
10679		    /* ignore blanks */
10680		    ;
10681		} else if (NXT(len) == ':') {
10682#ifdef DEBUG_STEP
10683		    xmlGenericError(xmlGenericErrorContext,
10684			    "PathExpr: AbbrRelLocation\n");
10685#endif
10686		    lc = 1;
10687		    break;
10688		} else if ((NXT(len) == '(')) {
10689		    /* Note Type or Function */
10690		    if (xmlXPathIsNodeType(name)) {
10691#ifdef DEBUG_STEP
10692		        xmlGenericError(xmlGenericErrorContext,
10693				"PathExpr: Type search\n");
10694#endif
10695			lc = 1;
10696		    } else {
10697#ifdef DEBUG_STEP
10698		        xmlGenericError(xmlGenericErrorContext,
10699				"PathExpr: function call\n");
10700#endif
10701			lc = 0;
10702		    }
10703                    break;
10704		} else if ((NXT(len) == '[')) {
10705		    /* element name */
10706#ifdef DEBUG_STEP
10707		    xmlGenericError(xmlGenericErrorContext,
10708			    "PathExpr: AbbrRelLocation\n");
10709#endif
10710		    lc = 1;
10711		    break;
10712		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10713			   (NXT(len) == '=')) {
10714		    lc = 1;
10715		    break;
10716		} else {
10717		    lc = 1;
10718		    break;
10719		}
10720		len++;
10721	    }
10722	    if (NXT(len) == 0) {
10723#ifdef DEBUG_STEP
10724		xmlGenericError(xmlGenericErrorContext,
10725			"PathExpr: AbbrRelLocation\n");
10726#endif
10727		/* element name */
10728		lc = 1;
10729	    }
10730	    xmlFree(name);
10731	} else {
10732	    /* make sure all cases are covered explicitly */
10733	    XP_ERROR(XPATH_EXPR_ERROR);
10734	}
10735    }
10736
10737    if (lc) {
10738	if (CUR == '/') {
10739	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10740	} else {
10741	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10742	}
10743	xmlXPathCompLocationPath(ctxt);
10744    } else {
10745	xmlXPathCompFilterExpr(ctxt);
10746	CHECK_ERROR;
10747	if ((CUR == '/') && (NXT(1) == '/')) {
10748	    SKIP(2);
10749	    SKIP_BLANKS;
10750
10751	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10752		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10753	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10754
10755	    xmlXPathCompRelativeLocationPath(ctxt);
10756	} else if (CUR == '/') {
10757	    xmlXPathCompRelativeLocationPath(ctxt);
10758	}
10759    }
10760    SKIP_BLANKS;
10761}
10762
10763/**
10764 * xmlXPathCompUnionExpr:
10765 * @ctxt:  the XPath Parser context
10766 *
10767 *  [18]   UnionExpr ::=   PathExpr
10768 *               | UnionExpr '|' PathExpr
10769 *
10770 * Compile an union expression.
10771 */
10772
10773static void
10774xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10775    xmlXPathCompPathExpr(ctxt);
10776    CHECK_ERROR;
10777    SKIP_BLANKS;
10778    while (CUR == '|') {
10779	int op1 = ctxt->comp->last;
10780	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10781
10782	NEXT;
10783	SKIP_BLANKS;
10784	xmlXPathCompPathExpr(ctxt);
10785
10786	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10787
10788	SKIP_BLANKS;
10789    }
10790}
10791
10792/**
10793 * xmlXPathCompUnaryExpr:
10794 * @ctxt:  the XPath Parser context
10795 *
10796 *  [27]   UnaryExpr ::=   UnionExpr
10797 *                   | '-' UnaryExpr
10798 *
10799 * Compile an unary expression.
10800 */
10801
10802static void
10803xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10804    int minus = 0;
10805    int found = 0;
10806
10807    SKIP_BLANKS;
10808    while (CUR == '-') {
10809        minus = 1 - minus;
10810	found = 1;
10811	NEXT;
10812	SKIP_BLANKS;
10813    }
10814
10815    xmlXPathCompUnionExpr(ctxt);
10816    CHECK_ERROR;
10817    if (found) {
10818	if (minus)
10819	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10820	else
10821	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10822    }
10823}
10824
10825/**
10826 * xmlXPathCompMultiplicativeExpr:
10827 * @ctxt:  the XPath Parser context
10828 *
10829 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10830 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10831 *                   | MultiplicativeExpr 'div' UnaryExpr
10832 *                   | MultiplicativeExpr 'mod' UnaryExpr
10833 *  [34]   MultiplyOperator ::=   '*'
10834 *
10835 * Compile an Additive expression.
10836 */
10837
10838static void
10839xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10840    xmlXPathCompUnaryExpr(ctxt);
10841    CHECK_ERROR;
10842    SKIP_BLANKS;
10843    while ((CUR == '*') ||
10844           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10845           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10846	int op = -1;
10847	int op1 = ctxt->comp->last;
10848
10849        if (CUR == '*') {
10850	    op = 0;
10851	    NEXT;
10852	} else if (CUR == 'd') {
10853	    op = 1;
10854	    SKIP(3);
10855	} else if (CUR == 'm') {
10856	    op = 2;
10857	    SKIP(3);
10858	}
10859	SKIP_BLANKS;
10860        xmlXPathCompUnaryExpr(ctxt);
10861	CHECK_ERROR;
10862	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10863	SKIP_BLANKS;
10864    }
10865}
10866
10867/**
10868 * xmlXPathCompAdditiveExpr:
10869 * @ctxt:  the XPath Parser context
10870 *
10871 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10872 *                   | AdditiveExpr '+' MultiplicativeExpr
10873 *                   | AdditiveExpr '-' MultiplicativeExpr
10874 *
10875 * Compile an Additive expression.
10876 */
10877
10878static void
10879xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10880
10881    xmlXPathCompMultiplicativeExpr(ctxt);
10882    CHECK_ERROR;
10883    SKIP_BLANKS;
10884    while ((CUR == '+') || (CUR == '-')) {
10885	int plus;
10886	int op1 = ctxt->comp->last;
10887
10888        if (CUR == '+') plus = 1;
10889	else plus = 0;
10890	NEXT;
10891	SKIP_BLANKS;
10892        xmlXPathCompMultiplicativeExpr(ctxt);
10893	CHECK_ERROR;
10894	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10895	SKIP_BLANKS;
10896    }
10897}
10898
10899/**
10900 * xmlXPathCompRelationalExpr:
10901 * @ctxt:  the XPath Parser context
10902 *
10903 *  [24]   RelationalExpr ::=   AdditiveExpr
10904 *                 | RelationalExpr '<' AdditiveExpr
10905 *                 | RelationalExpr '>' AdditiveExpr
10906 *                 | RelationalExpr '<=' AdditiveExpr
10907 *                 | RelationalExpr '>=' AdditiveExpr
10908 *
10909 *  A <= B > C is allowed ? Answer from James, yes with
10910 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10911 *  which is basically what got implemented.
10912 *
10913 * Compile a Relational expression, then push the result
10914 * on the stack
10915 */
10916
10917static void
10918xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10919    xmlXPathCompAdditiveExpr(ctxt);
10920    CHECK_ERROR;
10921    SKIP_BLANKS;
10922    while ((CUR == '<') ||
10923           (CUR == '>') ||
10924           ((CUR == '<') && (NXT(1) == '=')) ||
10925           ((CUR == '>') && (NXT(1) == '='))) {
10926	int inf, strict;
10927	int op1 = ctxt->comp->last;
10928
10929        if (CUR == '<') inf = 1;
10930	else inf = 0;
10931	if (NXT(1) == '=') strict = 0;
10932	else strict = 1;
10933	NEXT;
10934	if (!strict) NEXT;
10935	SKIP_BLANKS;
10936        xmlXPathCompAdditiveExpr(ctxt);
10937	CHECK_ERROR;
10938	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10939	SKIP_BLANKS;
10940    }
10941}
10942
10943/**
10944 * xmlXPathCompEqualityExpr:
10945 * @ctxt:  the XPath Parser context
10946 *
10947 *  [23]   EqualityExpr ::=   RelationalExpr
10948 *                 | EqualityExpr '=' RelationalExpr
10949 *                 | EqualityExpr '!=' RelationalExpr
10950 *
10951 *  A != B != C is allowed ? Answer from James, yes with
10952 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10953 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10954 *  which is basically what got implemented.
10955 *
10956 * Compile an Equality expression.
10957 *
10958 */
10959static void
10960xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10961    xmlXPathCompRelationalExpr(ctxt);
10962    CHECK_ERROR;
10963    SKIP_BLANKS;
10964    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10965	int eq;
10966	int op1 = ctxt->comp->last;
10967
10968        if (CUR == '=') eq = 1;
10969	else eq = 0;
10970	NEXT;
10971	if (!eq) NEXT;
10972	SKIP_BLANKS;
10973        xmlXPathCompRelationalExpr(ctxt);
10974	CHECK_ERROR;
10975	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10976	SKIP_BLANKS;
10977    }
10978}
10979
10980/**
10981 * xmlXPathCompAndExpr:
10982 * @ctxt:  the XPath Parser context
10983 *
10984 *  [22]   AndExpr ::=   EqualityExpr
10985 *                 | AndExpr 'and' EqualityExpr
10986 *
10987 * Compile an AND expression.
10988 *
10989 */
10990static void
10991xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10992    xmlXPathCompEqualityExpr(ctxt);
10993    CHECK_ERROR;
10994    SKIP_BLANKS;
10995    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10996	int op1 = ctxt->comp->last;
10997        SKIP(3);
10998	SKIP_BLANKS;
10999        xmlXPathCompEqualityExpr(ctxt);
11000	CHECK_ERROR;
11001	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
11002	SKIP_BLANKS;
11003    }
11004}
11005
11006/**
11007 * xmlXPathCompileExpr:
11008 * @ctxt:  the XPath Parser context
11009 *
11010 *  [14]   Expr ::=   OrExpr
11011 *  [21]   OrExpr ::=   AndExpr
11012 *                 | OrExpr 'or' AndExpr
11013 *
11014 * Parse and compile an expression
11015 */
11016static void
11017xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11018    xmlXPathCompAndExpr(ctxt);
11019    CHECK_ERROR;
11020    SKIP_BLANKS;
11021    while ((CUR == 'o') && (NXT(1) == 'r')) {
11022	int op1 = ctxt->comp->last;
11023        SKIP(2);
11024	SKIP_BLANKS;
11025        xmlXPathCompAndExpr(ctxt);
11026	CHECK_ERROR;
11027	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11028	SKIP_BLANKS;
11029    }
11030    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11031	/* more ops could be optimized too */
11032	/*
11033	* This is the main place to eliminate sorting for
11034	* operations which don't require a sorted node-set.
11035	* E.g. count().
11036	*/
11037	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11038    }
11039}
11040
11041/**
11042 * xmlXPathCompPredicate:
11043 * @ctxt:  the XPath Parser context
11044 * @filter:  act as a filter
11045 *
11046 *  [8]   Predicate ::=   '[' PredicateExpr ']'
11047 *  [9]   PredicateExpr ::=   Expr
11048 *
11049 * Compile a predicate expression
11050 */
11051static void
11052xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11053    int op1 = ctxt->comp->last;
11054
11055    SKIP_BLANKS;
11056    if (CUR != '[') {
11057	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11058    }
11059    NEXT;
11060    SKIP_BLANKS;
11061
11062    ctxt->comp->last = -1;
11063    /*
11064    * This call to xmlXPathCompileExpr() will deactivate sorting
11065    * of the predicate result.
11066    * TODO: Sorting is still activated for filters, since I'm not
11067    *  sure if needed. Normally sorting should not be needed, since
11068    *  a filter can only diminish the number of items in a sequence,
11069    *  but won't change its order; so if the initial sequence is sorted,
11070    *  subsequent sorting is not needed.
11071    */
11072    if (! filter)
11073	xmlXPathCompileExpr(ctxt, 0);
11074    else
11075	xmlXPathCompileExpr(ctxt, 1);
11076    CHECK_ERROR;
11077
11078    if (CUR != ']') {
11079	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11080    }
11081
11082    if (filter)
11083	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11084    else
11085	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11086
11087    NEXT;
11088    SKIP_BLANKS;
11089}
11090
11091/**
11092 * xmlXPathCompNodeTest:
11093 * @ctxt:  the XPath Parser context
11094 * @test:  pointer to a xmlXPathTestVal
11095 * @type:  pointer to a xmlXPathTypeVal
11096 * @prefix:  placeholder for a possible name prefix
11097 *
11098 * [7] NodeTest ::=   NameTest
11099 *		    | NodeType '(' ')'
11100 *		    | 'processing-instruction' '(' Literal ')'
11101 *
11102 * [37] NameTest ::=  '*'
11103 *		    | NCName ':' '*'
11104 *		    | QName
11105 * [38] NodeType ::= 'comment'
11106 *		   | 'text'
11107 *		   | 'processing-instruction'
11108 *		   | 'node'
11109 *
11110 * Returns the name found and updates @test, @type and @prefix appropriately
11111 */
11112static xmlChar *
11113xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11114	             xmlXPathTypeVal *type, const xmlChar **prefix,
11115		     xmlChar *name) {
11116    int blanks;
11117
11118    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11119	STRANGE;
11120	return(NULL);
11121    }
11122    *type = (xmlXPathTypeVal) 0;
11123    *test = (xmlXPathTestVal) 0;
11124    *prefix = NULL;
11125    SKIP_BLANKS;
11126
11127    if ((name == NULL) && (CUR == '*')) {
11128	/*
11129	 * All elements
11130	 */
11131	NEXT;
11132	*test = NODE_TEST_ALL;
11133	return(NULL);
11134    }
11135
11136    if (name == NULL)
11137	name = xmlXPathParseNCName(ctxt);
11138    if (name == NULL) {
11139	XP_ERRORNULL(XPATH_EXPR_ERROR);
11140    }
11141
11142    blanks = IS_BLANK_CH(CUR);
11143    SKIP_BLANKS;
11144    if (CUR == '(') {
11145	NEXT;
11146	/*
11147	 * NodeType or PI search
11148	 */
11149	if (xmlStrEqual(name, BAD_CAST "comment"))
11150	    *type = NODE_TYPE_COMMENT;
11151	else if (xmlStrEqual(name, BAD_CAST "node"))
11152	    *type = NODE_TYPE_NODE;
11153	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11154	    *type = NODE_TYPE_PI;
11155	else if (xmlStrEqual(name, BAD_CAST "text"))
11156	    *type = NODE_TYPE_TEXT;
11157	else {
11158	    if (name != NULL)
11159		xmlFree(name);
11160	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11161	}
11162
11163	*test = NODE_TEST_TYPE;
11164
11165	SKIP_BLANKS;
11166	if (*type == NODE_TYPE_PI) {
11167	    /*
11168	     * Specific case: search a PI by name.
11169	     */
11170	    if (name != NULL)
11171		xmlFree(name);
11172	    name = NULL;
11173	    if (CUR != ')') {
11174		name = xmlXPathParseLiteral(ctxt);
11175		CHECK_ERROR NULL;
11176		*test = NODE_TEST_PI;
11177		SKIP_BLANKS;
11178	    }
11179	}
11180	if (CUR != ')') {
11181	    if (name != NULL)
11182		xmlFree(name);
11183	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11184	}
11185	NEXT;
11186	return(name);
11187    }
11188    *test = NODE_TEST_NAME;
11189    if ((!blanks) && (CUR == ':')) {
11190	NEXT;
11191
11192	/*
11193	 * Since currently the parser context don't have a
11194	 * namespace list associated:
11195	 * The namespace name for this prefix can be computed
11196	 * only at evaluation time. The compilation is done
11197	 * outside of any context.
11198	 */
11199#if 0
11200	*prefix = xmlXPathNsLookup(ctxt->context, name);
11201	if (name != NULL)
11202	    xmlFree(name);
11203	if (*prefix == NULL) {
11204	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11205	}
11206#else
11207	*prefix = name;
11208#endif
11209
11210	if (CUR == '*') {
11211	    /*
11212	     * All elements
11213	     */
11214	    NEXT;
11215	    *test = NODE_TEST_ALL;
11216	    return(NULL);
11217	}
11218
11219	name = xmlXPathParseNCName(ctxt);
11220	if (name == NULL) {
11221	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11222	}
11223    }
11224    return(name);
11225}
11226
11227/**
11228 * xmlXPathIsAxisName:
11229 * @name:  a preparsed name token
11230 *
11231 * [6] AxisName ::=   'ancestor'
11232 *                  | 'ancestor-or-self'
11233 *                  | 'attribute'
11234 *                  | 'child'
11235 *                  | 'descendant'
11236 *                  | 'descendant-or-self'
11237 *                  | 'following'
11238 *                  | 'following-sibling'
11239 *                  | 'namespace'
11240 *                  | 'parent'
11241 *                  | 'preceding'
11242 *                  | 'preceding-sibling'
11243 *                  | 'self'
11244 *
11245 * Returns the axis or 0
11246 */
11247static xmlXPathAxisVal
11248xmlXPathIsAxisName(const xmlChar *name) {
11249    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11250    switch (name[0]) {
11251	case 'a':
11252	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11253		ret = AXIS_ANCESTOR;
11254	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11255		ret = AXIS_ANCESTOR_OR_SELF;
11256	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11257		ret = AXIS_ATTRIBUTE;
11258	    break;
11259	case 'c':
11260	    if (xmlStrEqual(name, BAD_CAST "child"))
11261		ret = AXIS_CHILD;
11262	    break;
11263	case 'd':
11264	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11265		ret = AXIS_DESCENDANT;
11266	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11267		ret = AXIS_DESCENDANT_OR_SELF;
11268	    break;
11269	case 'f':
11270	    if (xmlStrEqual(name, BAD_CAST "following"))
11271		ret = AXIS_FOLLOWING;
11272	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11273		ret = AXIS_FOLLOWING_SIBLING;
11274	    break;
11275	case 'n':
11276	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11277		ret = AXIS_NAMESPACE;
11278	    break;
11279	case 'p':
11280	    if (xmlStrEqual(name, BAD_CAST "parent"))
11281		ret = AXIS_PARENT;
11282	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11283		ret = AXIS_PRECEDING;
11284	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11285		ret = AXIS_PRECEDING_SIBLING;
11286	    break;
11287	case 's':
11288	    if (xmlStrEqual(name, BAD_CAST "self"))
11289		ret = AXIS_SELF;
11290	    break;
11291    }
11292    return(ret);
11293}
11294
11295/**
11296 * xmlXPathCompStep:
11297 * @ctxt:  the XPath Parser context
11298 *
11299 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11300 *                  | AbbreviatedStep
11301 *
11302 * [12] AbbreviatedStep ::=   '.' | '..'
11303 *
11304 * [5] AxisSpecifier ::= AxisName '::'
11305 *                  | AbbreviatedAxisSpecifier
11306 *
11307 * [13] AbbreviatedAxisSpecifier ::= '@'?
11308 *
11309 * Modified for XPtr range support as:
11310 *
11311 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11312 *                     | AbbreviatedStep
11313 *                     | 'range-to' '(' Expr ')' Predicate*
11314 *
11315 * Compile one step in a Location Path
11316 * A location step of . is short for self::node(). This is
11317 * particularly useful in conjunction with //. For example, the
11318 * location path .//para is short for
11319 * self::node()/descendant-or-self::node()/child::para
11320 * and so will select all para descendant elements of the context
11321 * node.
11322 * Similarly, a location step of .. is short for parent::node().
11323 * For example, ../title is short for parent::node()/child::title
11324 * and so will select the title children of the parent of the context
11325 * node.
11326 */
11327static void
11328xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11329#ifdef LIBXML_XPTR_ENABLED
11330    int rangeto = 0;
11331    int op2 = -1;
11332#endif
11333
11334    SKIP_BLANKS;
11335    if ((CUR == '.') && (NXT(1) == '.')) {
11336	SKIP(2);
11337	SKIP_BLANKS;
11338	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11339		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11340    } else if (CUR == '.') {
11341	NEXT;
11342	SKIP_BLANKS;
11343    } else {
11344	xmlChar *name = NULL;
11345	const xmlChar *prefix = NULL;
11346	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11347	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11348	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11349	int op1;
11350
11351	/*
11352	 * The modification needed for XPointer change to the production
11353	 */
11354#ifdef LIBXML_XPTR_ENABLED
11355	if (ctxt->xptr) {
11356	    name = xmlXPathParseNCName(ctxt);
11357	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11358                op2 = ctxt->comp->last;
11359		xmlFree(name);
11360		SKIP_BLANKS;
11361		if (CUR != '(') {
11362		    XP_ERROR(XPATH_EXPR_ERROR);
11363		}
11364		NEXT;
11365		SKIP_BLANKS;
11366
11367		xmlXPathCompileExpr(ctxt, 1);
11368		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11369		CHECK_ERROR;
11370
11371		SKIP_BLANKS;
11372		if (CUR != ')') {
11373		    XP_ERROR(XPATH_EXPR_ERROR);
11374		}
11375		NEXT;
11376		rangeto = 1;
11377		goto eval_predicates;
11378	    }
11379	}
11380#endif
11381	if (CUR == '*') {
11382	    axis = AXIS_CHILD;
11383	} else {
11384	    if (name == NULL)
11385		name = xmlXPathParseNCName(ctxt);
11386	    if (name != NULL) {
11387		axis = xmlXPathIsAxisName(name);
11388		if (axis != 0) {
11389		    SKIP_BLANKS;
11390		    if ((CUR == ':') && (NXT(1) == ':')) {
11391			SKIP(2);
11392			xmlFree(name);
11393			name = NULL;
11394		    } else {
11395			/* an element name can conflict with an axis one :-\ */
11396			axis = AXIS_CHILD;
11397		    }
11398		} else {
11399		    axis = AXIS_CHILD;
11400		}
11401	    } else if (CUR == '@') {
11402		NEXT;
11403		axis = AXIS_ATTRIBUTE;
11404	    } else {
11405		axis = AXIS_CHILD;
11406	    }
11407	}
11408
11409        if (ctxt->error != XPATH_EXPRESSION_OK) {
11410            xmlFree(name);
11411            return;
11412        }
11413
11414	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11415	if (test == 0)
11416	    return;
11417
11418        if ((prefix != NULL) && (ctxt->context != NULL) &&
11419	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11420	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11421		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11422	    }
11423	}
11424#ifdef DEBUG_STEP
11425	xmlGenericError(xmlGenericErrorContext,
11426		"Basis : computing new set\n");
11427#endif
11428
11429#ifdef DEBUG_STEP
11430	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11431	if (ctxt->value == NULL)
11432	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11433	else if (ctxt->value->nodesetval == NULL)
11434	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11435	else
11436	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11437#endif
11438
11439#ifdef LIBXML_XPTR_ENABLED
11440eval_predicates:
11441#endif
11442	op1 = ctxt->comp->last;
11443	ctxt->comp->last = -1;
11444
11445	SKIP_BLANKS;
11446	while (CUR == '[') {
11447	    xmlXPathCompPredicate(ctxt, 0);
11448	}
11449
11450#ifdef LIBXML_XPTR_ENABLED
11451	if (rangeto) {
11452	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11453	} else
11454#endif
11455	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11456			   test, type, (void *)prefix, (void *)name);
11457
11458    }
11459#ifdef DEBUG_STEP
11460    xmlGenericError(xmlGenericErrorContext, "Step : ");
11461    if (ctxt->value == NULL)
11462	xmlGenericError(xmlGenericErrorContext, "no value\n");
11463    else if (ctxt->value->nodesetval == NULL)
11464	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11465    else
11466	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11467		ctxt->value->nodesetval);
11468#endif
11469}
11470
11471/**
11472 * xmlXPathCompRelativeLocationPath:
11473 * @ctxt:  the XPath Parser context
11474 *
11475 *  [3]   RelativeLocationPath ::=   Step
11476 *                     | RelativeLocationPath '/' Step
11477 *                     | AbbreviatedRelativeLocationPath
11478 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11479 *
11480 * Compile a relative location path.
11481 */
11482static void
11483xmlXPathCompRelativeLocationPath
11484(xmlXPathParserContextPtr ctxt) {
11485    SKIP_BLANKS;
11486    if ((CUR == '/') && (NXT(1) == '/')) {
11487	SKIP(2);
11488	SKIP_BLANKS;
11489	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11490		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11491    } else if (CUR == '/') {
11492	    NEXT;
11493	SKIP_BLANKS;
11494    }
11495    xmlXPathCompStep(ctxt);
11496    CHECK_ERROR;
11497    SKIP_BLANKS;
11498    while (CUR == '/') {
11499	if ((CUR == '/') && (NXT(1) == '/')) {
11500	    SKIP(2);
11501	    SKIP_BLANKS;
11502	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11503			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11504	    xmlXPathCompStep(ctxt);
11505	} else if (CUR == '/') {
11506	    NEXT;
11507	    SKIP_BLANKS;
11508	    xmlXPathCompStep(ctxt);
11509	}
11510	SKIP_BLANKS;
11511    }
11512}
11513
11514/**
11515 * xmlXPathCompLocationPath:
11516 * @ctxt:  the XPath Parser context
11517 *
11518 *  [1]   LocationPath ::=   RelativeLocationPath
11519 *                     | AbsoluteLocationPath
11520 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11521 *                     | AbbreviatedAbsoluteLocationPath
11522 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11523 *                           '//' RelativeLocationPath
11524 *
11525 * Compile a location path
11526 *
11527 * // is short for /descendant-or-self::node()/. For example,
11528 * //para is short for /descendant-or-self::node()/child::para and
11529 * so will select any para element in the document (even a para element
11530 * that is a document element will be selected by //para since the
11531 * document element node is a child of the root node); div//para is
11532 * short for div/descendant-or-self::node()/child::para and so will
11533 * select all para descendants of div children.
11534 */
11535static void
11536xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11537    SKIP_BLANKS;
11538    if (CUR != '/') {
11539        xmlXPathCompRelativeLocationPath(ctxt);
11540    } else {
11541	while (CUR == '/') {
11542	    if ((CUR == '/') && (NXT(1) == '/')) {
11543		SKIP(2);
11544		SKIP_BLANKS;
11545		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11546			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11547		xmlXPathCompRelativeLocationPath(ctxt);
11548	    } else if (CUR == '/') {
11549		NEXT;
11550		SKIP_BLANKS;
11551		if ((CUR != 0 ) &&
11552		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11553		     (CUR == '@') || (CUR == '*')))
11554		    xmlXPathCompRelativeLocationPath(ctxt);
11555	    }
11556	    CHECK_ERROR;
11557	}
11558    }
11559}
11560
11561/************************************************************************
11562 *									*
11563 *		XPath precompiled expression evaluation			*
11564 *									*
11565 ************************************************************************/
11566
11567static int
11568xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11569
11570#ifdef DEBUG_STEP
11571static void
11572xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11573			  int nbNodes)
11574{
11575    xmlGenericError(xmlGenericErrorContext, "new step : ");
11576    switch (op->value) {
11577        case AXIS_ANCESTOR:
11578            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11579            break;
11580        case AXIS_ANCESTOR_OR_SELF:
11581            xmlGenericError(xmlGenericErrorContext,
11582                            "axis 'ancestors-or-self' ");
11583            break;
11584        case AXIS_ATTRIBUTE:
11585            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11586            break;
11587        case AXIS_CHILD:
11588            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11589            break;
11590        case AXIS_DESCENDANT:
11591            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11592            break;
11593        case AXIS_DESCENDANT_OR_SELF:
11594            xmlGenericError(xmlGenericErrorContext,
11595                            "axis 'descendant-or-self' ");
11596            break;
11597        case AXIS_FOLLOWING:
11598            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11599            break;
11600        case AXIS_FOLLOWING_SIBLING:
11601            xmlGenericError(xmlGenericErrorContext,
11602                            "axis 'following-siblings' ");
11603            break;
11604        case AXIS_NAMESPACE:
11605            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11606            break;
11607        case AXIS_PARENT:
11608            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11609            break;
11610        case AXIS_PRECEDING:
11611            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11612            break;
11613        case AXIS_PRECEDING_SIBLING:
11614            xmlGenericError(xmlGenericErrorContext,
11615                            "axis 'preceding-sibling' ");
11616            break;
11617        case AXIS_SELF:
11618            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11619            break;
11620    }
11621    xmlGenericError(xmlGenericErrorContext,
11622	" context contains %d nodes\n", nbNodes);
11623    switch (op->value2) {
11624        case NODE_TEST_NONE:
11625            xmlGenericError(xmlGenericErrorContext,
11626                            "           searching for none !!!\n");
11627            break;
11628        case NODE_TEST_TYPE:
11629            xmlGenericError(xmlGenericErrorContext,
11630                            "           searching for type %d\n", op->value3);
11631            break;
11632        case NODE_TEST_PI:
11633            xmlGenericError(xmlGenericErrorContext,
11634                            "           searching for PI !!!\n");
11635            break;
11636        case NODE_TEST_ALL:
11637            xmlGenericError(xmlGenericErrorContext,
11638                            "           searching for *\n");
11639            break;
11640        case NODE_TEST_NS:
11641            xmlGenericError(xmlGenericErrorContext,
11642                            "           searching for namespace %s\n",
11643                            op->value5);
11644            break;
11645        case NODE_TEST_NAME:
11646            xmlGenericError(xmlGenericErrorContext,
11647                            "           searching for name %s\n", op->value5);
11648            if (op->value4)
11649                xmlGenericError(xmlGenericErrorContext,
11650                                "           with namespace %s\n", op->value4);
11651            break;
11652    }
11653    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11654}
11655#endif /* DEBUG_STEP */
11656
11657static int
11658xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11659			    xmlXPathStepOpPtr op,
11660			    xmlNodeSetPtr set,
11661			    int contextSize,
11662			    int hasNsNodes)
11663{
11664    if (op->ch1 != -1) {
11665	xmlXPathCompExprPtr comp = ctxt->comp;
11666	/*
11667	* Process inner predicates first.
11668	*/
11669	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11670	    /*
11671	    * TODO: raise an internal error.
11672	    */
11673	}
11674	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11675	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11676	CHECK_ERROR0;
11677	if (contextSize <= 0)
11678	    return(0);
11679    }
11680    if (op->ch2 != -1) {
11681	xmlXPathContextPtr xpctxt = ctxt->context;
11682	xmlNodePtr contextNode, oldContextNode;
11683	xmlDocPtr oldContextDoc;
11684	int i, res, contextPos = 0, newContextSize;
11685	xmlXPathStepOpPtr exprOp;
11686	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11687
11688#ifdef LIBXML_XPTR_ENABLED
11689	/*
11690	* URGENT TODO: Check the following:
11691	*  We don't expect location sets if evaluating prediates, right?
11692	*  Only filters should expect location sets, right?
11693	*/
11694#endif
11695	/*
11696	* SPEC XPath 1.0:
11697	*  "For each node in the node-set to be filtered, the
11698	*  PredicateExpr is evaluated with that node as the
11699	*  context node, with the number of nodes in the
11700	*  node-set as the context size, and with the proximity
11701	*  position of the node in the node-set with respect to
11702	*  the axis as the context position;"
11703	* @oldset is the node-set" to be filtered.
11704	*
11705	* SPEC XPath 1.0:
11706	*  "only predicates change the context position and
11707	*  context size (see [2.4 Predicates])."
11708	* Example:
11709	*   node-set  context pos
11710	*    nA         1
11711	*    nB         2
11712	*    nC         3
11713	*   After applying predicate [position() > 1] :
11714	*   node-set  context pos
11715	*    nB         1
11716	*    nC         2
11717	*/
11718	oldContextNode = xpctxt->node;
11719	oldContextDoc = xpctxt->doc;
11720	/*
11721	* Get the expression of this predicate.
11722	*/
11723	exprOp = &ctxt->comp->steps[op->ch2];
11724	newContextSize = 0;
11725	for (i = 0; i < set->nodeNr; i++) {
11726	    if (set->nodeTab[i] == NULL)
11727		continue;
11728
11729	    contextNode = set->nodeTab[i];
11730	    xpctxt->node = contextNode;
11731	    xpctxt->contextSize = contextSize;
11732	    xpctxt->proximityPosition = ++contextPos;
11733
11734	    /*
11735	    * Also set the xpath document in case things like
11736	    * key() are evaluated in the predicate.
11737	    */
11738	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11739		(contextNode->doc != NULL))
11740		xpctxt->doc = contextNode->doc;
11741	    /*
11742	    * Evaluate the predicate expression with 1 context node
11743	    * at a time; this node is packaged into a node set; this
11744	    * node set is handed over to the evaluation mechanism.
11745	    */
11746	    if (contextObj == NULL)
11747		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11748	    else {
11749		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11750		    contextNode) < 0) {
11751		    ctxt->error = XPATH_MEMORY_ERROR;
11752		    goto evaluation_exit;
11753		}
11754	    }
11755
11756	    valuePush(ctxt, contextObj);
11757
11758	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11759
11760	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11761		xmlXPathNodeSetClear(set, hasNsNodes);
11762		newContextSize = 0;
11763		goto evaluation_exit;
11764	    }
11765
11766	    if (res != 0) {
11767		newContextSize++;
11768	    } else {
11769		/*
11770		* Remove the entry from the initial node set.
11771		*/
11772		set->nodeTab[i] = NULL;
11773		if (contextNode->type == XML_NAMESPACE_DECL)
11774		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11775	    }
11776	    if (ctxt->value == contextObj) {
11777		/*
11778		* Don't free the temporary XPath object holding the
11779		* context node, in order to avoid massive recreation
11780		* inside this loop.
11781		*/
11782		valuePop(ctxt);
11783		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11784	    } else {
11785		/*
11786		* TODO: The object was lost in the evaluation machinery.
11787		*  Can this happen? Maybe in internal-error cases.
11788		*/
11789		contextObj = NULL;
11790	    }
11791	}
11792
11793	if (contextObj != NULL) {
11794	    if (ctxt->value == contextObj)
11795		valuePop(ctxt);
11796	    xmlXPathReleaseObject(xpctxt, contextObj);
11797	}
11798evaluation_exit:
11799	if (exprRes != NULL)
11800	    xmlXPathReleaseObject(ctxt->context, exprRes);
11801	/*
11802	* Reset/invalidate the context.
11803	*/
11804	xpctxt->node = oldContextNode;
11805	xpctxt->doc = oldContextDoc;
11806	xpctxt->contextSize = -1;
11807	xpctxt->proximityPosition = -1;
11808	return(newContextSize);
11809    }
11810    return(contextSize);
11811}
11812
11813static int
11814xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11815				      xmlXPathStepOpPtr op,
11816				      xmlNodeSetPtr set,
11817				      int contextSize,
11818				      int minPos,
11819				      int maxPos,
11820				      int hasNsNodes)
11821{
11822    if (op->ch1 != -1) {
11823	xmlXPathCompExprPtr comp = ctxt->comp;
11824	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11825	    /*
11826	    * TODO: raise an internal error.
11827	    */
11828	}
11829	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11830	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11831	CHECK_ERROR0;
11832	if (contextSize <= 0)
11833	    return(0);
11834    }
11835    /*
11836    * Check if the node set contains a sufficient number of nodes for
11837    * the requested range.
11838    */
11839    if (contextSize < minPos) {
11840	xmlXPathNodeSetClear(set, hasNsNodes);
11841	return(0);
11842    }
11843    if (op->ch2 == -1) {
11844	/*
11845	* TODO: Can this ever happen?
11846	*/
11847	return (contextSize);
11848    } else {
11849	xmlDocPtr oldContextDoc;
11850	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11851	xmlXPathStepOpPtr exprOp;
11852	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11853	xmlNodePtr oldContextNode, contextNode = NULL;
11854	xmlXPathContextPtr xpctxt = ctxt->context;
11855        int frame;
11856
11857#ifdef LIBXML_XPTR_ENABLED
11858	    /*
11859	    * URGENT TODO: Check the following:
11860	    *  We don't expect location sets if evaluating prediates, right?
11861	    *  Only filters should expect location sets, right?
11862	*/
11863#endif /* LIBXML_XPTR_ENABLED */
11864
11865	/*
11866	* Save old context.
11867	*/
11868	oldContextNode = xpctxt->node;
11869	oldContextDoc = xpctxt->doc;
11870	/*
11871	* Get the expression of this predicate.
11872	*/
11873	exprOp = &ctxt->comp->steps[op->ch2];
11874	for (i = 0; i < set->nodeNr; i++) {
11875            xmlXPathObjectPtr tmp;
11876
11877	    if (set->nodeTab[i] == NULL)
11878		continue;
11879
11880	    contextNode = set->nodeTab[i];
11881	    xpctxt->node = contextNode;
11882	    xpctxt->contextSize = contextSize;
11883	    xpctxt->proximityPosition = ++contextPos;
11884
11885	    /*
11886	    * Initialize the new set.
11887	    * Also set the xpath document in case things like
11888	    * key() evaluation are attempted on the predicate
11889	    */
11890	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11891		(contextNode->doc != NULL))
11892		xpctxt->doc = contextNode->doc;
11893	    /*
11894	    * Evaluate the predicate expression with 1 context node
11895	    * at a time; this node is packaged into a node set; this
11896	    * node set is handed over to the evaluation mechanism.
11897	    */
11898	    if (contextObj == NULL)
11899		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11900	    else {
11901		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11902		    contextNode) < 0) {
11903		    ctxt->error = XPATH_MEMORY_ERROR;
11904		    goto evaluation_exit;
11905		}
11906	    }
11907
11908            frame = xmlXPathSetFrame(ctxt);
11909	    valuePush(ctxt, contextObj);
11910	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11911            tmp = valuePop(ctxt);
11912            xmlXPathPopFrame(ctxt, frame);
11913
11914	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11915                while (tmp != contextObj) {
11916                    /*
11917                     * Free up the result
11918                     * then pop off contextObj, which will be freed later
11919                     */
11920                    xmlXPathReleaseObject(xpctxt, tmp);
11921                    tmp = valuePop(ctxt);
11922                }
11923		goto evaluation_error;
11924	    }
11925            /* push the result back onto the stack */
11926            valuePush(ctxt, tmp);
11927
11928	    if (res)
11929		pos++;
11930
11931	    if (res && (pos >= minPos) && (pos <= maxPos)) {
11932		/*
11933		* Fits in the requested range.
11934		*/
11935		newContextSize++;
11936		if (minPos == maxPos) {
11937		    /*
11938		    * Only 1 node was requested.
11939		    */
11940		    if (contextNode->type == XML_NAMESPACE_DECL) {
11941			/*
11942			* As always: take care of those nasty
11943			* namespace nodes.
11944			*/
11945			set->nodeTab[i] = NULL;
11946		    }
11947		    xmlXPathNodeSetClear(set, hasNsNodes);
11948		    set->nodeNr = 1;
11949		    set->nodeTab[0] = contextNode;
11950		    goto evaluation_exit;
11951		}
11952		if (pos == maxPos) {
11953		    /*
11954		    * We are done.
11955		    */
11956		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11957		    goto evaluation_exit;
11958		}
11959	    } else {
11960		/*
11961		* Remove the entry from the initial node set.
11962		*/
11963		set->nodeTab[i] = NULL;
11964		if (contextNode->type == XML_NAMESPACE_DECL)
11965		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11966	    }
11967	    if (exprRes != NULL) {
11968		xmlXPathReleaseObject(ctxt->context, exprRes);
11969		exprRes = NULL;
11970	    }
11971	    if (ctxt->value == contextObj) {
11972		/*
11973		* Don't free the temporary XPath object holding the
11974		* context node, in order to avoid massive recreation
11975		* inside this loop.
11976		*/
11977		valuePop(ctxt);
11978		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11979	    } else {
11980		/*
11981		* The object was lost in the evaluation machinery.
11982		* Can this happen? Maybe in case of internal-errors.
11983		*/
11984		contextObj = NULL;
11985	    }
11986	}
11987	goto evaluation_exit;
11988
11989evaluation_error:
11990	xmlXPathNodeSetClear(set, hasNsNodes);
11991	newContextSize = 0;
11992
11993evaluation_exit:
11994	if (contextObj != NULL) {
11995	    if (ctxt->value == contextObj)
11996		valuePop(ctxt);
11997	    xmlXPathReleaseObject(xpctxt, contextObj);
11998	}
11999	if (exprRes != NULL)
12000	    xmlXPathReleaseObject(ctxt->context, exprRes);
12001	/*
12002	* Reset/invalidate the context.
12003	*/
12004	xpctxt->node = oldContextNode;
12005	xpctxt->doc = oldContextDoc;
12006	xpctxt->contextSize = -1;
12007	xpctxt->proximityPosition = -1;
12008	return(newContextSize);
12009    }
12010    return(contextSize);
12011}
12012
12013static int
12014xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12015			    xmlXPathStepOpPtr op,
12016			    int *maxPos)
12017{
12018
12019    xmlXPathStepOpPtr exprOp;
12020
12021    /*
12022    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12023    */
12024
12025    /*
12026    * If not -1, then ch1 will point to:
12027    * 1) For predicates (XPATH_OP_PREDICATE):
12028    *    - an inner predicate operator
12029    * 2) For filters (XPATH_OP_FILTER):
12030    *    - an inner filter operater OR
12031    *    - an expression selecting the node set.
12032    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
12033    */
12034    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12035	return(0);
12036
12037    if (op->ch2 != -1) {
12038	exprOp = &ctxt->comp->steps[op->ch2];
12039    } else
12040	return(0);
12041
12042    if ((exprOp != NULL) &&
12043	(exprOp->op == XPATH_OP_VALUE) &&
12044	(exprOp->value4 != NULL) &&
12045	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12046    {
12047	/*
12048	* We have a "[n]" predicate here.
12049	* TODO: Unfortunately this simplistic test here is not
12050	* able to detect a position() predicate in compound
12051	* expressions like "[@attr = 'a" and position() = 1],
12052	* and even not the usage of position() in
12053	* "[position() = 1]"; thus - obviously - a position-range,
12054	* like it "[position() < 5]", is also not detected.
12055	* Maybe we could rewrite the AST to ease the optimization.
12056	*/
12057	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12058
12059	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
12060	    (float) *maxPos)
12061	{
12062	    return(1);
12063	}
12064    }
12065    return(0);
12066}
12067
12068static int
12069xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12070                           xmlXPathStepOpPtr op,
12071			   xmlNodePtr * first, xmlNodePtr * last,
12072			   int toBool)
12073{
12074
12075#define XP_TEST_HIT \
12076    if (hasAxisRange != 0) { \
12077	if (++pos == maxPos) { \
12078	    if (addNode(seq, cur) < 0) \
12079	        ctxt->error = XPATH_MEMORY_ERROR; \
12080	    goto axis_range_end; } \
12081    } else { \
12082	if (addNode(seq, cur) < 0) \
12083	    ctxt->error = XPATH_MEMORY_ERROR; \
12084	if (breakOnFirstHit) goto first_hit; }
12085
12086#define XP_TEST_HIT_NS \
12087    if (hasAxisRange != 0) { \
12088	if (++pos == maxPos) { \
12089	    hasNsNodes = 1; \
12090	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12091	        ctxt->error = XPATH_MEMORY_ERROR; \
12092	goto axis_range_end; } \
12093    } else { \
12094	hasNsNodes = 1; \
12095	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12096	    ctxt->error = XPATH_MEMORY_ERROR; \
12097	if (breakOnFirstHit) goto first_hit; }
12098
12099    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12100    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12101    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12102    const xmlChar *prefix = op->value4;
12103    const xmlChar *name = op->value5;
12104    const xmlChar *URI = NULL;
12105
12106#ifdef DEBUG_STEP
12107    int nbMatches = 0, prevMatches = 0;
12108#endif
12109    int total = 0, hasNsNodes = 0;
12110    /* The popped object holding the context nodes */
12111    xmlXPathObjectPtr obj;
12112    /* The set of context nodes for the node tests */
12113    xmlNodeSetPtr contextSeq;
12114    int contextIdx;
12115    xmlNodePtr contextNode;
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    contextNode = NULL;
12310    contextIdx = 0;
12311
12312
12313    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12314           (ctxt->error == XPATH_EXPRESSION_OK)) {
12315	xpctxt->node = contextSeq->nodeTab[contextIdx++];
12316
12317	if (seq == NULL) {
12318	    seq = xmlXPathNodeSetCreate(NULL);
12319	    if (seq == NULL) {
12320		total = 0;
12321		goto error;
12322	    }
12323	}
12324	/*
12325	* Traverse the axis and test the nodes.
12326	*/
12327	pos = 0;
12328	cur = NULL;
12329	hasNsNodes = 0;
12330        do {
12331            cur = next(ctxt, cur);
12332            if (cur == NULL)
12333                break;
12334
12335	    /*
12336	    * QUESTION TODO: What does the "first" and "last" stuff do?
12337	    */
12338            if ((first != NULL) && (*first != NULL)) {
12339		if (*first == cur)
12340		    break;
12341		if (((total % 256) == 0) &&
12342#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12343		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12344#else
12345		    (xmlXPathCmpNodes(*first, cur) >= 0))
12346#endif
12347		{
12348		    break;
12349		}
12350	    }
12351	    if ((last != NULL) && (*last != NULL)) {
12352		if (*last == cur)
12353		    break;
12354		if (((total % 256) == 0) &&
12355#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12356		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12357#else
12358		    (xmlXPathCmpNodes(cur, *last) >= 0))
12359#endif
12360		{
12361		    break;
12362		}
12363	    }
12364
12365            total++;
12366
12367#ifdef DEBUG_STEP
12368            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12369#endif
12370
12371	    switch (test) {
12372                case NODE_TEST_NONE:
12373		    total = 0;
12374                    STRANGE
12375		    goto error;
12376                case NODE_TEST_TYPE:
12377		    /*
12378		    * TODO: Don't we need to use
12379		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
12380		    *  Surprisingly, some c14n tests fail, if we do this.
12381		    */
12382		    if (type == NODE_TYPE_NODE) {
12383			switch (cur->type) {
12384			    case XML_DOCUMENT_NODE:
12385			    case XML_HTML_DOCUMENT_NODE:
12386#ifdef LIBXML_DOCB_ENABLED
12387			    case XML_DOCB_DOCUMENT_NODE:
12388#endif
12389			    case XML_ELEMENT_NODE:
12390			    case XML_ATTRIBUTE_NODE:
12391			    case XML_PI_NODE:
12392			    case XML_COMMENT_NODE:
12393			    case XML_CDATA_SECTION_NODE:
12394			    case XML_TEXT_NODE:
12395			    case XML_NAMESPACE_DECL:
12396				XP_TEST_HIT
12397				break;
12398			    default:
12399				break;
12400			}
12401		    } else if (cur->type == type) {
12402			if (cur->type == XML_NAMESPACE_DECL)
12403			    XP_TEST_HIT_NS
12404			else
12405			    XP_TEST_HIT
12406		    } else if ((type == NODE_TYPE_TEXT) &&
12407			 (cur->type == XML_CDATA_SECTION_NODE))
12408		    {
12409			XP_TEST_HIT
12410		    }
12411		    break;
12412                case NODE_TEST_PI:
12413                    if ((cur->type == XML_PI_NODE) &&
12414                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12415		    {
12416			XP_TEST_HIT
12417                    }
12418                    break;
12419                case NODE_TEST_ALL:
12420                    if (axis == AXIS_ATTRIBUTE) {
12421                        if (cur->type == XML_ATTRIBUTE_NODE)
12422			{
12423			    XP_TEST_HIT
12424                        }
12425                    } else if (axis == AXIS_NAMESPACE) {
12426                        if (cur->type == XML_NAMESPACE_DECL)
12427			{
12428			    XP_TEST_HIT_NS
12429                        }
12430                    } else {
12431                        if (cur->type == XML_ELEMENT_NODE) {
12432                            if (prefix == NULL)
12433			    {
12434				XP_TEST_HIT
12435
12436                            } else if ((cur->ns != NULL) &&
12437				(xmlStrEqual(URI, cur->ns->href)))
12438			    {
12439				XP_TEST_HIT
12440                            }
12441                        }
12442                    }
12443                    break;
12444                case NODE_TEST_NS:{
12445                        TODO;
12446                        break;
12447                    }
12448                case NODE_TEST_NAME:
12449                    if (axis == AXIS_ATTRIBUTE) {
12450                        if (cur->type != XML_ATTRIBUTE_NODE)
12451			    break;
12452		    } else if (axis == AXIS_NAMESPACE) {
12453                        if (cur->type != XML_NAMESPACE_DECL)
12454			    break;
12455		    } else {
12456		        if (cur->type != XML_ELEMENT_NODE)
12457			    break;
12458		    }
12459                    switch (cur->type) {
12460                        case XML_ELEMENT_NODE:
12461                            if (xmlStrEqual(name, cur->name)) {
12462                                if (prefix == NULL) {
12463                                    if (cur->ns == NULL)
12464				    {
12465					XP_TEST_HIT
12466                                    }
12467                                } else {
12468                                    if ((cur->ns != NULL) &&
12469                                        (xmlStrEqual(URI, cur->ns->href)))
12470				    {
12471					XP_TEST_HIT
12472                                    }
12473                                }
12474                            }
12475                            break;
12476                        case XML_ATTRIBUTE_NODE:{
12477                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12478
12479                                if (xmlStrEqual(name, attr->name)) {
12480                                    if (prefix == NULL) {
12481                                        if ((attr->ns == NULL) ||
12482                                            (attr->ns->prefix == NULL))
12483					{
12484					    XP_TEST_HIT
12485                                        }
12486                                    } else {
12487                                        if ((attr->ns != NULL) &&
12488                                            (xmlStrEqual(URI,
12489					      attr->ns->href)))
12490					{
12491					    XP_TEST_HIT
12492                                        }
12493                                    }
12494                                }
12495                                break;
12496                            }
12497                        case XML_NAMESPACE_DECL:
12498                            if (cur->type == XML_NAMESPACE_DECL) {
12499                                xmlNsPtr ns = (xmlNsPtr) cur;
12500
12501                                if ((ns->prefix != NULL) && (name != NULL)
12502                                    && (xmlStrEqual(ns->prefix, name)))
12503				{
12504				    XP_TEST_HIT_NS
12505                                }
12506                            }
12507                            break;
12508                        default:
12509                            break;
12510                    }
12511                    break;
12512	    } /* switch(test) */
12513        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12514
12515	goto apply_predicates;
12516
12517axis_range_end: /* ----------------------------------------------------- */
12518	/*
12519	* We have a "/foo[n]", and position() = n was reached.
12520	* Note that we can have as well "/foo/::parent::foo[1]", so
12521	* a duplicate-aware merge is still needed.
12522	* Merge with the result.
12523	*/
12524	if (outSeq == NULL) {
12525	    outSeq = seq;
12526	    seq = NULL;
12527	} else
12528	    outSeq = mergeAndClear(outSeq, seq, 0);
12529	/*
12530	* Break if only a true/false result was requested.
12531	*/
12532	if (toBool)
12533	    break;
12534	continue;
12535
12536first_hit: /* ---------------------------------------------------------- */
12537	/*
12538	* Break if only a true/false result was requested and
12539	* no predicates existed and a node test succeeded.
12540	*/
12541	if (outSeq == NULL) {
12542	    outSeq = seq;
12543	    seq = NULL;
12544	} else
12545	    outSeq = mergeAndClear(outSeq, seq, 0);
12546	break;
12547
12548#ifdef DEBUG_STEP
12549	if (seq != NULL)
12550	    nbMatches += seq->nodeNr;
12551#endif
12552
12553apply_predicates: /* --------------------------------------------------- */
12554        if (ctxt->error != XPATH_EXPRESSION_OK)
12555	    goto error;
12556
12557        /*
12558	* Apply predicates.
12559	*/
12560        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12561	    /*
12562	    * E.g. when we have a "/foo[some expression][n]".
12563	    */
12564	    /*
12565	    * QUESTION TODO: The old predicate evaluation took into
12566	    *  account location-sets.
12567	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12568	    *  Do we expect such a set here?
12569	    *  All what I learned now from the evaluation semantics
12570	    *  does not indicate that a location-set will be processed
12571	    *  here, so this looks OK.
12572	    */
12573	    /*
12574	    * Iterate over all predicates, starting with the outermost
12575	    * predicate.
12576	    * TODO: Problem: we cannot execute the inner predicates first
12577	    *  since we cannot go back *up* the operator tree!
12578	    *  Options we have:
12579	    *  1) Use of recursive functions (like is it currently done
12580	    *     via xmlXPathCompOpEval())
12581	    *  2) Add a predicate evaluation information stack to the
12582	    *     context struct
12583	    *  3) Change the way the operators are linked; we need a
12584	    *     "parent" field on xmlXPathStepOp
12585	    *
12586	    * For the moment, I'll try to solve this with a recursive
12587	    * function: xmlXPathCompOpEvalPredicate().
12588	    */
12589	    size = seq->nodeNr;
12590	    if (hasPredicateRange != 0)
12591		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12592		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12593	    else
12594		newSize = xmlXPathCompOpEvalPredicate(ctxt,
12595		    predOp, seq, size, hasNsNodes);
12596
12597	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12598		total = 0;
12599		goto error;
12600	    }
12601	    /*
12602	    * Add the filtered set of nodes to the result node set.
12603	    */
12604	    if (newSize == 0) {
12605		/*
12606		* The predicates filtered all nodes out.
12607		*/
12608		xmlXPathNodeSetClear(seq, hasNsNodes);
12609	    } else if (seq->nodeNr > 0) {
12610		/*
12611		* Add to result set.
12612		*/
12613		if (outSeq == NULL) {
12614		    if (size != newSize) {
12615			/*
12616			* We need to merge and clear here, since
12617			* the sequence will contained NULLed entries.
12618			*/
12619			outSeq = mergeAndClear(NULL, seq, 1);
12620		    } else {
12621			outSeq = seq;
12622			seq = NULL;
12623		    }
12624		} else
12625		    outSeq = mergeAndClear(outSeq, seq,
12626			(size != newSize) ? 1: 0);
12627		/*
12628		* Break if only a true/false result was requested.
12629		*/
12630		if (toBool)
12631		    break;
12632	    }
12633        } else if (seq->nodeNr > 0) {
12634	    /*
12635	    * Add to result set.
12636	    */
12637	    if (outSeq == NULL) {
12638		outSeq = seq;
12639		seq = NULL;
12640	    } else {
12641		outSeq = mergeAndClear(outSeq, seq, 0);
12642	    }
12643	}
12644    }
12645
12646error:
12647    if ((obj->boolval) && (obj->user != NULL)) {
12648	/*
12649	* QUESTION TODO: What does this do and why?
12650	* TODO: Do we have to do this also for the "error"
12651	* cleanup further down?
12652	*/
12653	ctxt->value->boolval = 1;
12654	ctxt->value->user = obj->user;
12655	obj->user = NULL;
12656	obj->boolval = 0;
12657    }
12658    xmlXPathReleaseObject(xpctxt, obj);
12659
12660    /*
12661    * Ensure we return at least an emtpy set.
12662    */
12663    if (outSeq == NULL) {
12664	if ((seq != NULL) && (seq->nodeNr == 0))
12665	    outSeq = seq;
12666	else
12667	    outSeq = xmlXPathNodeSetCreate(NULL);
12668        /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12669    }
12670    if ((seq != NULL) && (seq != outSeq)) {
12671	 xmlXPathFreeNodeSet(seq);
12672    }
12673    /*
12674    * Hand over the result. Better to push the set also in
12675    * case of errors.
12676    */
12677    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12678    /*
12679    * Reset the context node.
12680    */
12681    xpctxt->node = oldContextNode;
12682
12683#ifdef DEBUG_STEP
12684    xmlGenericError(xmlGenericErrorContext,
12685	"\nExamined %d nodes, found %d nodes at that step\n",
12686	total, nbMatches);
12687#endif
12688
12689    return(total);
12690}
12691
12692static int
12693xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12694			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12695
12696/**
12697 * xmlXPathCompOpEvalFirst:
12698 * @ctxt:  the XPath parser context with the compiled expression
12699 * @op:  an XPath compiled operation
12700 * @first:  the first elem found so far
12701 *
12702 * Evaluate the Precompiled XPath operation searching only the first
12703 * element in document order
12704 *
12705 * Returns the number of examined objects.
12706 */
12707static int
12708xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12709                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12710{
12711    int total = 0, cur;
12712    xmlXPathCompExprPtr comp;
12713    xmlXPathObjectPtr arg1, arg2;
12714
12715    CHECK_ERROR0;
12716    comp = ctxt->comp;
12717    switch (op->op) {
12718        case XPATH_OP_END:
12719            return (0);
12720        case XPATH_OP_UNION:
12721            total =
12722                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12723                                        first);
12724	    CHECK_ERROR0;
12725            if ((ctxt->value != NULL)
12726                && (ctxt->value->type == XPATH_NODESET)
12727                && (ctxt->value->nodesetval != NULL)
12728                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12729                /*
12730                 * limit tree traversing to first node in the result
12731                 */
12732		/*
12733		* OPTIMIZE TODO: This implicitely sorts
12734		*  the result, even if not needed. E.g. if the argument
12735		*  of the count() function, no sorting is needed.
12736		* OPTIMIZE TODO: How do we know if the node-list wasn't
12737		*  aready sorted?
12738		*/
12739		if (ctxt->value->nodesetval->nodeNr > 1)
12740		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12741                *first = ctxt->value->nodesetval->nodeTab[0];
12742            }
12743            cur =
12744                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12745                                        first);
12746	    CHECK_ERROR0;
12747            CHECK_TYPE0(XPATH_NODESET);
12748            arg2 = valuePop(ctxt);
12749
12750            CHECK_TYPE0(XPATH_NODESET);
12751            arg1 = valuePop(ctxt);
12752
12753            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12754                                                    arg2->nodesetval);
12755            valuePush(ctxt, arg1);
12756	    xmlXPathReleaseObject(ctxt->context, arg2);
12757            /* optimizer */
12758	    if (total > cur)
12759		xmlXPathCompSwap(op);
12760            return (total + cur);
12761        case XPATH_OP_ROOT:
12762            xmlXPathRoot(ctxt);
12763            return (0);
12764        case XPATH_OP_NODE:
12765            if (op->ch1 != -1)
12766                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12767	    CHECK_ERROR0;
12768            if (op->ch2 != -1)
12769                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12770	    CHECK_ERROR0;
12771	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12772		ctxt->context->node));
12773            return (total);
12774        case XPATH_OP_RESET:
12775            if (op->ch1 != -1)
12776                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12777	    CHECK_ERROR0;
12778            if (op->ch2 != -1)
12779                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12780	    CHECK_ERROR0;
12781            ctxt->context->node = NULL;
12782            return (total);
12783        case XPATH_OP_COLLECT:{
12784                if (op->ch1 == -1)
12785                    return (total);
12786
12787                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12788		CHECK_ERROR0;
12789
12790                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12791                return (total);
12792            }
12793        case XPATH_OP_VALUE:
12794            valuePush(ctxt,
12795                      xmlXPathCacheObjectCopy(ctxt->context,
12796			(xmlXPathObjectPtr) op->value4));
12797            return (0);
12798        case XPATH_OP_SORT:
12799            if (op->ch1 != -1)
12800                total +=
12801                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12802                                            first);
12803	    CHECK_ERROR0;
12804            if ((ctxt->value != NULL)
12805                && (ctxt->value->type == XPATH_NODESET)
12806                && (ctxt->value->nodesetval != NULL)
12807		&& (ctxt->value->nodesetval->nodeNr > 1))
12808                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12809            return (total);
12810#ifdef XP_OPTIMIZED_FILTER_FIRST
12811	case XPATH_OP_FILTER:
12812                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12813            return (total);
12814#endif
12815        default:
12816            return (xmlXPathCompOpEval(ctxt, op));
12817    }
12818}
12819
12820/**
12821 * xmlXPathCompOpEvalLast:
12822 * @ctxt:  the XPath parser context with the compiled expression
12823 * @op:  an XPath compiled operation
12824 * @last:  the last elem found so far
12825 *
12826 * Evaluate the Precompiled XPath operation searching only the last
12827 * element in document order
12828 *
12829 * Returns the number of nodes traversed
12830 */
12831static int
12832xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12833                       xmlNodePtr * last)
12834{
12835    int total = 0, cur;
12836    xmlXPathCompExprPtr comp;
12837    xmlXPathObjectPtr arg1, arg2;
12838    xmlNodePtr bak;
12839    xmlDocPtr bakd;
12840    int pp;
12841    int cs;
12842
12843    CHECK_ERROR0;
12844    comp = ctxt->comp;
12845    switch (op->op) {
12846        case XPATH_OP_END:
12847            return (0);
12848        case XPATH_OP_UNION:
12849	    bakd = ctxt->context->doc;
12850	    bak = ctxt->context->node;
12851	    pp = ctxt->context->proximityPosition;
12852	    cs = ctxt->context->contextSize;
12853            total =
12854                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12855	    CHECK_ERROR0;
12856            if ((ctxt->value != NULL)
12857                && (ctxt->value->type == XPATH_NODESET)
12858                && (ctxt->value->nodesetval != NULL)
12859                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12860                /*
12861                 * limit tree traversing to first node in the result
12862                 */
12863		if (ctxt->value->nodesetval->nodeNr > 1)
12864		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12865                *last =
12866                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12867                                                     nodesetval->nodeNr -
12868                                                     1];
12869            }
12870	    ctxt->context->doc = bakd;
12871	    ctxt->context->node = bak;
12872	    ctxt->context->proximityPosition = pp;
12873	    ctxt->context->contextSize = cs;
12874            cur =
12875                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12876	    CHECK_ERROR0;
12877            if ((ctxt->value != NULL)
12878                && (ctxt->value->type == XPATH_NODESET)
12879                && (ctxt->value->nodesetval != NULL)
12880                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12881            }
12882            CHECK_TYPE0(XPATH_NODESET);
12883            arg2 = valuePop(ctxt);
12884
12885            CHECK_TYPE0(XPATH_NODESET);
12886            arg1 = valuePop(ctxt);
12887
12888            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12889                                                    arg2->nodesetval);
12890            valuePush(ctxt, arg1);
12891	    xmlXPathReleaseObject(ctxt->context, arg2);
12892            /* optimizer */
12893	    if (total > cur)
12894		xmlXPathCompSwap(op);
12895            return (total + cur);
12896        case XPATH_OP_ROOT:
12897            xmlXPathRoot(ctxt);
12898            return (0);
12899        case XPATH_OP_NODE:
12900            if (op->ch1 != -1)
12901                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12902	    CHECK_ERROR0;
12903            if (op->ch2 != -1)
12904                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12905	    CHECK_ERROR0;
12906	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12907		ctxt->context->node));
12908            return (total);
12909        case XPATH_OP_RESET:
12910            if (op->ch1 != -1)
12911                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12912	    CHECK_ERROR0;
12913            if (op->ch2 != -1)
12914                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12915	    CHECK_ERROR0;
12916            ctxt->context->node = NULL;
12917            return (total);
12918        case XPATH_OP_COLLECT:{
12919                if (op->ch1 == -1)
12920                    return (0);
12921
12922                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12923		CHECK_ERROR0;
12924
12925                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12926                return (total);
12927            }
12928        case XPATH_OP_VALUE:
12929            valuePush(ctxt,
12930                      xmlXPathCacheObjectCopy(ctxt->context,
12931			(xmlXPathObjectPtr) op->value4));
12932            return (0);
12933        case XPATH_OP_SORT:
12934            if (op->ch1 != -1)
12935                total +=
12936                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12937                                           last);
12938	    CHECK_ERROR0;
12939            if ((ctxt->value != NULL)
12940                && (ctxt->value->type == XPATH_NODESET)
12941                && (ctxt->value->nodesetval != NULL)
12942		&& (ctxt->value->nodesetval->nodeNr > 1))
12943                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12944            return (total);
12945        default:
12946            return (xmlXPathCompOpEval(ctxt, op));
12947    }
12948}
12949
12950#ifdef XP_OPTIMIZED_FILTER_FIRST
12951static int
12952xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12953			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12954{
12955    int total = 0;
12956    xmlXPathCompExprPtr comp;
12957    xmlXPathObjectPtr res;
12958    xmlXPathObjectPtr obj;
12959    xmlNodeSetPtr oldset;
12960    xmlNodePtr oldnode;
12961    xmlDocPtr oldDoc;
12962    int i;
12963
12964    CHECK_ERROR0;
12965    comp = ctxt->comp;
12966    /*
12967    * Optimization for ()[last()] selection i.e. the last elem
12968    */
12969    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12970	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12971	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12972	int f = comp->steps[op->ch2].ch1;
12973
12974	if ((f != -1) &&
12975	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12976	    (comp->steps[f].value5 == NULL) &&
12977	    (comp->steps[f].value == 0) &&
12978	    (comp->steps[f].value4 != NULL) &&
12979	    (xmlStrEqual
12980	    (comp->steps[f].value4, BAD_CAST "last"))) {
12981	    xmlNodePtr last = NULL;
12982
12983	    total +=
12984		xmlXPathCompOpEvalLast(ctxt,
12985		    &comp->steps[op->ch1],
12986		    &last);
12987	    CHECK_ERROR0;
12988	    /*
12989	    * The nodeset should be in document order,
12990	    * Keep only the last value
12991	    */
12992	    if ((ctxt->value != NULL) &&
12993		(ctxt->value->type == XPATH_NODESET) &&
12994		(ctxt->value->nodesetval != NULL) &&
12995		(ctxt->value->nodesetval->nodeTab != NULL) &&
12996		(ctxt->value->nodesetval->nodeNr > 1)) {
12997		ctxt->value->nodesetval->nodeTab[0] =
12998		    ctxt->value->nodesetval->nodeTab[ctxt->
12999		    value->
13000		    nodesetval->
13001		    nodeNr -
13002		    1];
13003		ctxt->value->nodesetval->nodeNr = 1;
13004		*first = *(ctxt->value->nodesetval->nodeTab);
13005	    }
13006	    return (total);
13007	}
13008    }
13009
13010    if (op->ch1 != -1)
13011	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13012    CHECK_ERROR0;
13013    if (op->ch2 == -1)
13014	return (total);
13015    if (ctxt->value == NULL)
13016	return (total);
13017
13018#ifdef LIBXML_XPTR_ENABLED
13019    oldnode = ctxt->context->node;
13020    /*
13021    * Hum are we filtering the result of an XPointer expression
13022    */
13023    if (ctxt->value->type == XPATH_LOCATIONSET) {
13024	xmlXPathObjectPtr tmp = NULL;
13025	xmlLocationSetPtr newlocset = NULL;
13026	xmlLocationSetPtr oldlocset;
13027
13028	/*
13029	* Extract the old locset, and then evaluate the result of the
13030	* expression for all the element in the locset. use it to grow
13031	* up a new locset.
13032	*/
13033	CHECK_TYPE0(XPATH_LOCATIONSET);
13034	obj = valuePop(ctxt);
13035	oldlocset = obj->user;
13036	ctxt->context->node = NULL;
13037
13038	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13039	    ctxt->context->contextSize = 0;
13040	    ctxt->context->proximityPosition = 0;
13041	    if (op->ch2 != -1)
13042		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13043	    res = valuePop(ctxt);
13044	    if (res != NULL) {
13045		xmlXPathReleaseObject(ctxt->context, res);
13046	    }
13047	    valuePush(ctxt, obj);
13048	    CHECK_ERROR0;
13049	    return (total);
13050	}
13051	newlocset = xmlXPtrLocationSetCreate(NULL);
13052
13053	for (i = 0; i < oldlocset->locNr; i++) {
13054	    /*
13055	    * Run the evaluation with a node list made of a
13056	    * single item in the nodelocset.
13057	    */
13058	    ctxt->context->node = oldlocset->locTab[i]->user;
13059	    ctxt->context->contextSize = oldlocset->locNr;
13060	    ctxt->context->proximityPosition = i + 1;
13061	    if (tmp == NULL) {
13062		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13063		    ctxt->context->node);
13064	    } else {
13065		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13066		                             ctxt->context->node) < 0) {
13067		    ctxt->error = XPATH_MEMORY_ERROR;
13068		}
13069	    }
13070	    valuePush(ctxt, tmp);
13071	    if (op->ch2 != -1)
13072		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13073	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13074		xmlXPathFreeObject(obj);
13075		return(0);
13076	    }
13077	    /*
13078	    * The result of the evaluation need to be tested to
13079	    * decided whether the filter succeeded or not
13080	    */
13081	    res = valuePop(ctxt);
13082	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13083		xmlXPtrLocationSetAdd(newlocset,
13084		    xmlXPathCacheObjectCopy(ctxt->context,
13085			oldlocset->locTab[i]));
13086	    }
13087	    /*
13088	    * Cleanup
13089	    */
13090	    if (res != NULL) {
13091		xmlXPathReleaseObject(ctxt->context, res);
13092	    }
13093	    if (ctxt->value == tmp) {
13094		valuePop(ctxt);
13095		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13096		/*
13097		* REVISIT TODO: Don't create a temporary nodeset
13098		* for everly iteration.
13099		*/
13100		/* OLD: xmlXPathFreeObject(res); */
13101	    } else
13102		tmp = NULL;
13103	    ctxt->context->node = NULL;
13104	    /*
13105	    * Only put the first node in the result, then leave.
13106	    */
13107	    if (newlocset->locNr > 0) {
13108		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
13109		break;
13110	    }
13111	}
13112	if (tmp != NULL) {
13113	    xmlXPathReleaseObject(ctxt->context, tmp);
13114	}
13115	/*
13116	* The result is used as the new evaluation locset.
13117	*/
13118	xmlXPathReleaseObject(ctxt->context, obj);
13119	ctxt->context->node = NULL;
13120	ctxt->context->contextSize = -1;
13121	ctxt->context->proximityPosition = -1;
13122	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13123	ctxt->context->node = oldnode;
13124	return (total);
13125    }
13126#endif /* LIBXML_XPTR_ENABLED */
13127
13128    /*
13129    * Extract the old set, and then evaluate the result of the
13130    * expression for all the element in the set. use it to grow
13131    * up a new set.
13132    */
13133    CHECK_TYPE0(XPATH_NODESET);
13134    obj = valuePop(ctxt);
13135    oldset = obj->nodesetval;
13136
13137    oldnode = ctxt->context->node;
13138    oldDoc = ctxt->context->doc;
13139    ctxt->context->node = NULL;
13140
13141    if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13142	ctxt->context->contextSize = 0;
13143	ctxt->context->proximityPosition = 0;
13144	/* QUESTION TODO: Why was this code commented out?
13145	    if (op->ch2 != -1)
13146		total +=
13147		    xmlXPathCompOpEval(ctxt,
13148			&comp->steps[op->ch2]);
13149	    CHECK_ERROR0;
13150	    res = valuePop(ctxt);
13151	    if (res != NULL)
13152		xmlXPathFreeObject(res);
13153	*/
13154	valuePush(ctxt, obj);
13155	ctxt->context->node = oldnode;
13156	CHECK_ERROR0;
13157    } else {
13158	xmlNodeSetPtr newset;
13159	xmlXPathObjectPtr tmp = NULL;
13160	/*
13161	* Initialize the new set.
13162	* Also set the xpath document in case things like
13163	* key() evaluation are attempted on the predicate
13164	*/
13165	newset = xmlXPathNodeSetCreate(NULL);
13166        /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13167
13168	for (i = 0; i < oldset->nodeNr; i++) {
13169	    /*
13170	    * Run the evaluation with a node list made of
13171	    * a single item in the nodeset.
13172	    */
13173	    ctxt->context->node = oldset->nodeTab[i];
13174	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13175		(oldset->nodeTab[i]->doc != NULL))
13176		ctxt->context->doc = oldset->nodeTab[i]->doc;
13177	    if (tmp == NULL) {
13178		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13179		    ctxt->context->node);
13180	    } else {
13181		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13182		                             ctxt->context->node) < 0) {
13183		    ctxt->error = XPATH_MEMORY_ERROR;
13184		}
13185	    }
13186	    valuePush(ctxt, tmp);
13187	    ctxt->context->contextSize = oldset->nodeNr;
13188	    ctxt->context->proximityPosition = i + 1;
13189	    if (op->ch2 != -1)
13190		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13191	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13192		xmlXPathFreeNodeSet(newset);
13193		xmlXPathFreeObject(obj);
13194		return(0);
13195	    }
13196	    /*
13197	    * The result of the evaluation needs to be tested to
13198	    * decide whether the filter succeeded or not
13199	    */
13200	    res = valuePop(ctxt);
13201	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13202		if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13203		    ctxt->error = XPATH_MEMORY_ERROR;
13204	    }
13205	    /*
13206	    * Cleanup
13207	    */
13208	    if (res != NULL) {
13209		xmlXPathReleaseObject(ctxt->context, res);
13210	    }
13211	    if (ctxt->value == tmp) {
13212		valuePop(ctxt);
13213		/*
13214		* Don't free the temporary nodeset
13215		* in order to avoid massive recreation inside this
13216		* loop.
13217		*/
13218		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13219	    } else
13220		tmp = NULL;
13221	    ctxt->context->node = NULL;
13222	    /*
13223	    * Only put the first node in the result, then leave.
13224	    */
13225	    if (newset->nodeNr > 0) {
13226		*first = *(newset->nodeTab);
13227		break;
13228	    }
13229	}
13230	if (tmp != NULL) {
13231	    xmlXPathReleaseObject(ctxt->context, tmp);
13232	}
13233	/*
13234	* The result is used as the new evaluation set.
13235	*/
13236	xmlXPathReleaseObject(ctxt->context, obj);
13237	ctxt->context->node = NULL;
13238	ctxt->context->contextSize = -1;
13239	ctxt->context->proximityPosition = -1;
13240	/* may want to move this past the '}' later */
13241	ctxt->context->doc = oldDoc;
13242	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13243    }
13244    ctxt->context->node = oldnode;
13245    return(total);
13246}
13247#endif /* XP_OPTIMIZED_FILTER_FIRST */
13248
13249/**
13250 * xmlXPathCompOpEval:
13251 * @ctxt:  the XPath parser context with the compiled expression
13252 * @op:  an XPath compiled operation
13253 *
13254 * Evaluate the Precompiled XPath operation
13255 * Returns the number of nodes traversed
13256 */
13257static int
13258xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13259{
13260    int total = 0;
13261    int equal, ret;
13262    xmlXPathCompExprPtr comp;
13263    xmlXPathObjectPtr arg1, arg2;
13264    xmlNodePtr bak;
13265    xmlDocPtr bakd;
13266    int pp;
13267    int cs;
13268
13269    CHECK_ERROR0;
13270    comp = ctxt->comp;
13271    switch (op->op) {
13272        case XPATH_OP_END:
13273            return (0);
13274        case XPATH_OP_AND:
13275	    bakd = ctxt->context->doc;
13276	    bak = ctxt->context->node;
13277	    pp = ctxt->context->proximityPosition;
13278	    cs = ctxt->context->contextSize;
13279            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13280	    CHECK_ERROR0;
13281            xmlXPathBooleanFunction(ctxt, 1);
13282            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13283                return (total);
13284            arg2 = valuePop(ctxt);
13285	    ctxt->context->doc = bakd;
13286	    ctxt->context->node = bak;
13287	    ctxt->context->proximityPosition = pp;
13288	    ctxt->context->contextSize = cs;
13289            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13290	    if (ctxt->error) {
13291		xmlXPathFreeObject(arg2);
13292		return(0);
13293	    }
13294            xmlXPathBooleanFunction(ctxt, 1);
13295            arg1 = valuePop(ctxt);
13296            arg1->boolval &= arg2->boolval;
13297            valuePush(ctxt, arg1);
13298	    xmlXPathReleaseObject(ctxt->context, arg2);
13299            return (total);
13300        case XPATH_OP_OR:
13301	    bakd = ctxt->context->doc;
13302	    bak = ctxt->context->node;
13303	    pp = ctxt->context->proximityPosition;
13304	    cs = ctxt->context->contextSize;
13305            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13306	    CHECK_ERROR0;
13307            xmlXPathBooleanFunction(ctxt, 1);
13308            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13309                return (total);
13310            arg2 = valuePop(ctxt);
13311	    ctxt->context->doc = bakd;
13312	    ctxt->context->node = bak;
13313	    ctxt->context->proximityPosition = pp;
13314	    ctxt->context->contextSize = cs;
13315            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13316	    if (ctxt->error) {
13317		xmlXPathFreeObject(arg2);
13318		return(0);
13319	    }
13320            xmlXPathBooleanFunction(ctxt, 1);
13321            arg1 = valuePop(ctxt);
13322            arg1->boolval |= arg2->boolval;
13323            valuePush(ctxt, arg1);
13324	    xmlXPathReleaseObject(ctxt->context, arg2);
13325            return (total);
13326        case XPATH_OP_EQUAL:
13327	    bakd = ctxt->context->doc;
13328	    bak = ctxt->context->node;
13329	    pp = ctxt->context->proximityPosition;
13330	    cs = ctxt->context->contextSize;
13331            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13332	    CHECK_ERROR0;
13333	    ctxt->context->doc = bakd;
13334	    ctxt->context->node = bak;
13335	    ctxt->context->proximityPosition = pp;
13336	    ctxt->context->contextSize = cs;
13337            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13338	    CHECK_ERROR0;
13339	    if (op->value)
13340		equal = xmlXPathEqualValues(ctxt);
13341	    else
13342		equal = xmlXPathNotEqualValues(ctxt);
13343	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13344            return (total);
13345        case XPATH_OP_CMP:
13346	    bakd = ctxt->context->doc;
13347	    bak = ctxt->context->node;
13348	    pp = ctxt->context->proximityPosition;
13349	    cs = ctxt->context->contextSize;
13350            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13351	    CHECK_ERROR0;
13352	    ctxt->context->doc = bakd;
13353	    ctxt->context->node = bak;
13354	    ctxt->context->proximityPosition = pp;
13355	    ctxt->context->contextSize = cs;
13356            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13357	    CHECK_ERROR0;
13358            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13359	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13360            return (total);
13361        case XPATH_OP_PLUS:
13362	    bakd = ctxt->context->doc;
13363	    bak = ctxt->context->node;
13364	    pp = ctxt->context->proximityPosition;
13365	    cs = ctxt->context->contextSize;
13366            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13367	    CHECK_ERROR0;
13368            if (op->ch2 != -1) {
13369		ctxt->context->doc = bakd;
13370		ctxt->context->node = bak;
13371		ctxt->context->proximityPosition = pp;
13372		ctxt->context->contextSize = cs;
13373                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13374	    }
13375	    CHECK_ERROR0;
13376            if (op->value == 0)
13377                xmlXPathSubValues(ctxt);
13378            else if (op->value == 1)
13379                xmlXPathAddValues(ctxt);
13380            else if (op->value == 2)
13381                xmlXPathValueFlipSign(ctxt);
13382            else if (op->value == 3) {
13383                CAST_TO_NUMBER;
13384                CHECK_TYPE0(XPATH_NUMBER);
13385            }
13386            return (total);
13387        case XPATH_OP_MULT:
13388	    bakd = ctxt->context->doc;
13389	    bak = ctxt->context->node;
13390	    pp = ctxt->context->proximityPosition;
13391	    cs = ctxt->context->contextSize;
13392            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13393	    CHECK_ERROR0;
13394	    ctxt->context->doc = bakd;
13395	    ctxt->context->node = bak;
13396	    ctxt->context->proximityPosition = pp;
13397	    ctxt->context->contextSize = cs;
13398            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13399	    CHECK_ERROR0;
13400            if (op->value == 0)
13401                xmlXPathMultValues(ctxt);
13402            else if (op->value == 1)
13403                xmlXPathDivValues(ctxt);
13404            else if (op->value == 2)
13405                xmlXPathModValues(ctxt);
13406            return (total);
13407        case XPATH_OP_UNION:
13408	    bakd = ctxt->context->doc;
13409	    bak = ctxt->context->node;
13410	    pp = ctxt->context->proximityPosition;
13411	    cs = ctxt->context->contextSize;
13412            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13413	    CHECK_ERROR0;
13414	    ctxt->context->doc = bakd;
13415	    ctxt->context->node = bak;
13416	    ctxt->context->proximityPosition = pp;
13417	    ctxt->context->contextSize = cs;
13418            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13419	    CHECK_ERROR0;
13420            CHECK_TYPE0(XPATH_NODESET);
13421            arg2 = valuePop(ctxt);
13422
13423            CHECK_TYPE0(XPATH_NODESET);
13424            arg1 = valuePop(ctxt);
13425
13426	    if ((arg1->nodesetval == NULL) ||
13427		((arg2->nodesetval != NULL) &&
13428		 (arg2->nodesetval->nodeNr != 0)))
13429	    {
13430		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13431							arg2->nodesetval);
13432	    }
13433
13434            valuePush(ctxt, arg1);
13435	    xmlXPathReleaseObject(ctxt->context, arg2);
13436            return (total);
13437        case XPATH_OP_ROOT:
13438            xmlXPathRoot(ctxt);
13439            return (total);
13440        case XPATH_OP_NODE:
13441            if (op->ch1 != -1)
13442                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13443	    CHECK_ERROR0;
13444            if (op->ch2 != -1)
13445                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13446	    CHECK_ERROR0;
13447	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13448		ctxt->context->node));
13449            return (total);
13450        case XPATH_OP_RESET:
13451            if (op->ch1 != -1)
13452                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13453	    CHECK_ERROR0;
13454            if (op->ch2 != -1)
13455                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13456	    CHECK_ERROR0;
13457            ctxt->context->node = NULL;
13458            return (total);
13459        case XPATH_OP_COLLECT:{
13460                if (op->ch1 == -1)
13461                    return (total);
13462
13463                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13464		CHECK_ERROR0;
13465
13466                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13467                return (total);
13468            }
13469        case XPATH_OP_VALUE:
13470            valuePush(ctxt,
13471                      xmlXPathCacheObjectCopy(ctxt->context,
13472			(xmlXPathObjectPtr) op->value4));
13473            return (total);
13474        case XPATH_OP_VARIABLE:{
13475		xmlXPathObjectPtr val;
13476
13477                if (op->ch1 != -1)
13478                    total +=
13479                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13480                if (op->value5 == NULL) {
13481		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13482		    if (val == NULL) {
13483			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13484			return(0);
13485		    }
13486                    valuePush(ctxt, val);
13487		} else {
13488                    const xmlChar *URI;
13489
13490                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13491                    if (URI == NULL) {
13492                        xmlGenericError(xmlGenericErrorContext,
13493            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13494                                    (char *) op->value4, (char *)op->value5);
13495                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13496                        return (total);
13497                    }
13498		    val = xmlXPathVariableLookupNS(ctxt->context,
13499                                                       op->value4, URI);
13500		    if (val == NULL) {
13501			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13502			return(0);
13503		    }
13504                    valuePush(ctxt, val);
13505                }
13506                return (total);
13507            }
13508        case XPATH_OP_FUNCTION:{
13509                xmlXPathFunction func;
13510                const xmlChar *oldFunc, *oldFuncURI;
13511		int i;
13512                int frame;
13513
13514                frame = xmlXPathSetFrame(ctxt);
13515                if (op->ch1 != -1)
13516                    total +=
13517                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13518		if (ctxt->valueNr < op->value) {
13519		    xmlGenericError(xmlGenericErrorContext,
13520			    "xmlXPathCompOpEval: parameter error\n");
13521		    ctxt->error = XPATH_INVALID_OPERAND;
13522                    xmlXPathPopFrame(ctxt, frame);
13523		    return (total);
13524		}
13525		for (i = 0; i < op->value; i++) {
13526		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13527			xmlGenericError(xmlGenericErrorContext,
13528				"xmlXPathCompOpEval: parameter error\n");
13529			ctxt->error = XPATH_INVALID_OPERAND;
13530                        xmlXPathPopFrame(ctxt, frame);
13531			return (total);
13532		    }
13533                }
13534                if (op->cache != NULL)
13535                    XML_CAST_FPTR(func) = op->cache;
13536                else {
13537                    const xmlChar *URI = NULL;
13538
13539                    if (op->value5 == NULL)
13540                        func =
13541                            xmlXPathFunctionLookup(ctxt->context,
13542                                                   op->value4);
13543                    else {
13544                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13545                        if (URI == NULL) {
13546                            xmlGenericError(xmlGenericErrorContext,
13547            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13548                                    (char *)op->value4, (char *)op->value5);
13549                            xmlXPathPopFrame(ctxt, frame);
13550                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13551                            return (total);
13552                        }
13553                        func = xmlXPathFunctionLookupNS(ctxt->context,
13554                                                        op->value4, URI);
13555                    }
13556                    if (func == NULL) {
13557                        xmlGenericError(xmlGenericErrorContext,
13558                                "xmlXPathCompOpEval: function %s not found\n",
13559                                        (char *)op->value4);
13560                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13561                    }
13562                    op->cache = XML_CAST_FPTR(func);
13563                    op->cacheURI = (void *) URI;
13564                }
13565                oldFunc = ctxt->context->function;
13566                oldFuncURI = ctxt->context->functionURI;
13567                ctxt->context->function = op->value4;
13568                ctxt->context->functionURI = op->cacheURI;
13569                func(ctxt, op->value);
13570                ctxt->context->function = oldFunc;
13571                ctxt->context->functionURI = oldFuncURI;
13572                xmlXPathPopFrame(ctxt, frame);
13573                return (total);
13574            }
13575        case XPATH_OP_ARG:
13576	    bakd = ctxt->context->doc;
13577	    bak = ctxt->context->node;
13578	    pp = ctxt->context->proximityPosition;
13579	    cs = ctxt->context->contextSize;
13580            if (op->ch1 != -1)
13581                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13582	    ctxt->context->contextSize = cs;
13583	    ctxt->context->proximityPosition = pp;
13584	    ctxt->context->node = bak;
13585	    ctxt->context->doc = bakd;
13586	    CHECK_ERROR0;
13587            if (op->ch2 != -1) {
13588                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13589	        ctxt->context->doc = bakd;
13590	        ctxt->context->node = bak;
13591	        CHECK_ERROR0;
13592	    }
13593            return (total);
13594        case XPATH_OP_PREDICATE:
13595        case XPATH_OP_FILTER:{
13596                xmlXPathObjectPtr res;
13597                xmlXPathObjectPtr obj, tmp;
13598                xmlNodeSetPtr newset = NULL;
13599                xmlNodeSetPtr oldset;
13600                xmlNodePtr oldnode;
13601		xmlDocPtr oldDoc;
13602                int i;
13603
13604                /*
13605                 * Optimization for ()[1] selection i.e. the first elem
13606                 */
13607                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13608#ifdef XP_OPTIMIZED_FILTER_FIRST
13609		    /*
13610		    * FILTER TODO: Can we assume that the inner processing
13611		    *  will result in an ordered list if we have an
13612		    *  XPATH_OP_FILTER?
13613		    *  What about an additional field or flag on
13614		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13615		    *  to assume anything, so it would be more robust and
13616		    *  easier to optimize.
13617		    */
13618                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13619		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13620#else
13621		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13622#endif
13623                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13624                    xmlXPathObjectPtr val;
13625
13626                    val = comp->steps[op->ch2].value4;
13627                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13628                        (val->floatval == 1.0)) {
13629                        xmlNodePtr first = NULL;
13630
13631                        total +=
13632                            xmlXPathCompOpEvalFirst(ctxt,
13633                                                    &comp->steps[op->ch1],
13634                                                    &first);
13635			CHECK_ERROR0;
13636                        /*
13637                         * The nodeset should be in document order,
13638                         * Keep only the first value
13639                         */
13640                        if ((ctxt->value != NULL) &&
13641                            (ctxt->value->type == XPATH_NODESET) &&
13642                            (ctxt->value->nodesetval != NULL) &&
13643                            (ctxt->value->nodesetval->nodeNr > 1))
13644                            ctxt->value->nodesetval->nodeNr = 1;
13645                        return (total);
13646                    }
13647                }
13648                /*
13649                 * Optimization for ()[last()] selection i.e. the last elem
13650                 */
13651                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13652                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13653                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13654                    int f = comp->steps[op->ch2].ch1;
13655
13656                    if ((f != -1) &&
13657                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13658                        (comp->steps[f].value5 == NULL) &&
13659                        (comp->steps[f].value == 0) &&
13660                        (comp->steps[f].value4 != NULL) &&
13661                        (xmlStrEqual
13662                         (comp->steps[f].value4, BAD_CAST "last"))) {
13663                        xmlNodePtr last = NULL;
13664
13665                        total +=
13666                            xmlXPathCompOpEvalLast(ctxt,
13667                                                   &comp->steps[op->ch1],
13668                                                   &last);
13669			CHECK_ERROR0;
13670                        /*
13671                         * The nodeset should be in document order,
13672                         * Keep only the last value
13673                         */
13674                        if ((ctxt->value != NULL) &&
13675                            (ctxt->value->type == XPATH_NODESET) &&
13676                            (ctxt->value->nodesetval != NULL) &&
13677                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13678                            (ctxt->value->nodesetval->nodeNr > 1)) {
13679                            ctxt->value->nodesetval->nodeTab[0] =
13680                                ctxt->value->nodesetval->nodeTab[ctxt->
13681                                                                 value->
13682                                                                 nodesetval->
13683                                                                 nodeNr -
13684                                                                 1];
13685                            ctxt->value->nodesetval->nodeNr = 1;
13686                        }
13687                        return (total);
13688                    }
13689                }
13690		/*
13691		* Process inner predicates first.
13692		* Example "index[parent::book][1]":
13693		* ...
13694		*   PREDICATE   <-- we are here "[1]"
13695		*     PREDICATE <-- process "[parent::book]" first
13696		*       SORT
13697		*         COLLECT  'parent' 'name' 'node' book
13698		*           NODE
13699		*     ELEM Object is a number : 1
13700		*/
13701                if (op->ch1 != -1)
13702                    total +=
13703                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13704		CHECK_ERROR0;
13705                if (op->ch2 == -1)
13706                    return (total);
13707                if (ctxt->value == NULL)
13708                    return (total);
13709
13710                oldnode = ctxt->context->node;
13711
13712#ifdef LIBXML_XPTR_ENABLED
13713                /*
13714                 * Hum are we filtering the result of an XPointer expression
13715                 */
13716                if (ctxt->value->type == XPATH_LOCATIONSET) {
13717                    xmlLocationSetPtr newlocset = NULL;
13718                    xmlLocationSetPtr oldlocset;
13719
13720                    /*
13721                     * Extract the old locset, and then evaluate the result of the
13722                     * expression for all the element in the locset. use it to grow
13723                     * up a new locset.
13724                     */
13725                    CHECK_TYPE0(XPATH_LOCATIONSET);
13726                    obj = valuePop(ctxt);
13727                    oldlocset = obj->user;
13728                    ctxt->context->node = NULL;
13729
13730                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13731                        ctxt->context->contextSize = 0;
13732                        ctxt->context->proximityPosition = 0;
13733                        if (op->ch2 != -1)
13734                            total +=
13735                                xmlXPathCompOpEval(ctxt,
13736                                                   &comp->steps[op->ch2]);
13737                        res = valuePop(ctxt);
13738                        if (res != NULL) {
13739			    xmlXPathReleaseObject(ctxt->context, res);
13740			}
13741                        valuePush(ctxt, obj);
13742                        CHECK_ERROR0;
13743                        return (total);
13744                    }
13745                    newlocset = xmlXPtrLocationSetCreate(NULL);
13746
13747                    for (i = 0; i < oldlocset->locNr; i++) {
13748                        /*
13749                         * Run the evaluation with a node list made of a
13750                         * single item in the nodelocset.
13751                         */
13752                        ctxt->context->node = oldlocset->locTab[i]->user;
13753                        ctxt->context->contextSize = oldlocset->locNr;
13754                        ctxt->context->proximityPosition = i + 1;
13755			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13756			    ctxt->context->node);
13757                        valuePush(ctxt, tmp);
13758
13759                        if (op->ch2 != -1)
13760                            total +=
13761                                xmlXPathCompOpEval(ctxt,
13762                                                   &comp->steps[op->ch2]);
13763			if (ctxt->error != XPATH_EXPRESSION_OK) {
13764			    xmlXPathFreeObject(obj);
13765			    return(0);
13766			}
13767
13768                        /*
13769                         * The result of the evaluation need to be tested to
13770                         * decided whether the filter succeeded or not
13771                         */
13772                        res = valuePop(ctxt);
13773                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13774                            xmlXPtrLocationSetAdd(newlocset,
13775                                                  xmlXPathObjectCopy
13776                                                  (oldlocset->locTab[i]));
13777                        }
13778
13779                        /*
13780                         * Cleanup
13781                         */
13782                        if (res != NULL) {
13783			    xmlXPathReleaseObject(ctxt->context, res);
13784			}
13785                        if (ctxt->value == tmp) {
13786                            res = valuePop(ctxt);
13787			    xmlXPathReleaseObject(ctxt->context, res);
13788                        }
13789
13790                        ctxt->context->node = NULL;
13791                    }
13792
13793                    /*
13794                     * The result is used as the new evaluation locset.
13795                     */
13796		    xmlXPathReleaseObject(ctxt->context, obj);
13797                    ctxt->context->node = NULL;
13798                    ctxt->context->contextSize = -1;
13799                    ctxt->context->proximityPosition = -1;
13800                    valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13801                    ctxt->context->node = oldnode;
13802                    return (total);
13803                }
13804#endif /* LIBXML_XPTR_ENABLED */
13805
13806                /*
13807                 * Extract the old set, and then evaluate the result of the
13808                 * expression for all the element in the set. use it to grow
13809                 * up a new set.
13810                 */
13811                CHECK_TYPE0(XPATH_NODESET);
13812                obj = valuePop(ctxt);
13813                oldset = obj->nodesetval;
13814
13815                oldnode = ctxt->context->node;
13816		oldDoc = ctxt->context->doc;
13817                ctxt->context->node = NULL;
13818
13819                if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13820                    ctxt->context->contextSize = 0;
13821                    ctxt->context->proximityPosition = 0;
13822/*
13823                    if (op->ch2 != -1)
13824                        total +=
13825                            xmlXPathCompOpEval(ctxt,
13826                                               &comp->steps[op->ch2]);
13827		    CHECK_ERROR0;
13828                    res = valuePop(ctxt);
13829                    if (res != NULL)
13830                        xmlXPathFreeObject(res);
13831*/
13832                    valuePush(ctxt, obj);
13833                    ctxt->context->node = oldnode;
13834                    CHECK_ERROR0;
13835                } else {
13836		    tmp = NULL;
13837                    /*
13838                     * Initialize the new set.
13839		     * Also set the xpath document in case things like
13840		     * key() evaluation are attempted on the predicate
13841                     */
13842                    newset = xmlXPathNodeSetCreate(NULL);
13843		    /*
13844		    * SPEC XPath 1.0:
13845		    *  "For each node in the node-set to be filtered, the
13846		    *  PredicateExpr is evaluated with that node as the
13847		    *  context node, with the number of nodes in the
13848		    *  node-set as the context size, and with the proximity
13849		    *  position of the node in the node-set with respect to
13850		    *  the axis as the context position;"
13851		    * @oldset is the node-set" to be filtered.
13852		    *
13853		    * SPEC XPath 1.0:
13854		    *  "only predicates change the context position and
13855		    *  context size (see [2.4 Predicates])."
13856		    * Example:
13857		    *   node-set  context pos
13858		    *    nA         1
13859		    *    nB         2
13860		    *    nC         3
13861		    *   After applying predicate [position() > 1] :
13862		    *   node-set  context pos
13863		    *    nB         1
13864		    *    nC         2
13865		    *
13866		    * removed the first node in the node-set, then
13867		    * the context position of the
13868		    */
13869                    for (i = 0; i < oldset->nodeNr; i++) {
13870                        /*
13871                         * Run the evaluation with a node list made of
13872                         * a single item in the nodeset.
13873                         */
13874                        ctxt->context->node = oldset->nodeTab[i];
13875			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13876			    (oldset->nodeTab[i]->doc != NULL))
13877		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13878			if (tmp == NULL) {
13879			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13880				ctxt->context->node);
13881			} else {
13882			    if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13883				               ctxt->context->node) < 0) {
13884				ctxt->error = XPATH_MEMORY_ERROR;
13885			    }
13886			}
13887                        valuePush(ctxt, tmp);
13888                        ctxt->context->contextSize = oldset->nodeNr;
13889                        ctxt->context->proximityPosition = i + 1;
13890			/*
13891			* Evaluate the predicate against the context node.
13892			* Can/should we optimize position() predicates
13893			* here (e.g. "[1]")?
13894			*/
13895                        if (op->ch2 != -1)
13896                            total +=
13897                                xmlXPathCompOpEval(ctxt,
13898                                                   &comp->steps[op->ch2]);
13899			if (ctxt->error != XPATH_EXPRESSION_OK) {
13900			    xmlXPathFreeNodeSet(newset);
13901			    xmlXPathFreeObject(obj);
13902			    return(0);
13903			}
13904
13905                        /*
13906                         * The result of the evaluation needs to be tested to
13907                         * decide whether the filter succeeded or not
13908                         */
13909			/*
13910			* OPTIMIZE TODO: Can we use
13911			* xmlXPathNodeSetAdd*Unique()* instead?
13912			*/
13913                        res = valuePop(ctxt);
13914                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13915                            if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13916			        < 0)
13917				ctxt->error = XPATH_MEMORY_ERROR;
13918                        }
13919
13920                        /*
13921                         * Cleanup
13922                         */
13923                        if (res != NULL) {
13924			    xmlXPathReleaseObject(ctxt->context, res);
13925			}
13926                        if (ctxt->value == tmp) {
13927                            valuePop(ctxt);
13928			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13929			    /*
13930			    * Don't free the temporary nodeset
13931			    * in order to avoid massive recreation inside this
13932			    * loop.
13933			    */
13934                        } else
13935			    tmp = NULL;
13936                        ctxt->context->node = NULL;
13937                    }
13938		    if (tmp != NULL)
13939			xmlXPathReleaseObject(ctxt->context, tmp);
13940                    /*
13941                     * The result is used as the new evaluation set.
13942                     */
13943		    xmlXPathReleaseObject(ctxt->context, obj);
13944                    ctxt->context->node = NULL;
13945                    ctxt->context->contextSize = -1;
13946                    ctxt->context->proximityPosition = -1;
13947		    /* may want to move this past the '}' later */
13948		    ctxt->context->doc = oldDoc;
13949		    valuePush(ctxt,
13950			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13951                }
13952                ctxt->context->node = oldnode;
13953                return (total);
13954            }
13955        case XPATH_OP_SORT:
13956            if (op->ch1 != -1)
13957                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13958	    CHECK_ERROR0;
13959            if ((ctxt->value != NULL) &&
13960                (ctxt->value->type == XPATH_NODESET) &&
13961                (ctxt->value->nodesetval != NULL) &&
13962		(ctxt->value->nodesetval->nodeNr > 1))
13963	    {
13964                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13965	    }
13966            return (total);
13967#ifdef LIBXML_XPTR_ENABLED
13968        case XPATH_OP_RANGETO:{
13969                xmlXPathObjectPtr range;
13970                xmlXPathObjectPtr res, obj;
13971                xmlXPathObjectPtr tmp;
13972                xmlLocationSetPtr newlocset = NULL;
13973		    xmlLocationSetPtr oldlocset;
13974                xmlNodeSetPtr oldset;
13975                int i, j;
13976
13977                if (op->ch1 != -1)
13978                    total +=
13979                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13980                if (op->ch2 == -1)
13981                    return (total);
13982
13983                if (ctxt->value->type == XPATH_LOCATIONSET) {
13984                    /*
13985                     * Extract the old locset, and then evaluate the result of the
13986                     * expression for all the element in the locset. use it to grow
13987                     * up a new locset.
13988                     */
13989                    CHECK_TYPE0(XPATH_LOCATIONSET);
13990                    obj = valuePop(ctxt);
13991                    oldlocset = obj->user;
13992
13993                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13994		        ctxt->context->node = NULL;
13995                        ctxt->context->contextSize = 0;
13996                        ctxt->context->proximityPosition = 0;
13997                        total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13998                        res = valuePop(ctxt);
13999                        if (res != NULL) {
14000			    xmlXPathReleaseObject(ctxt->context, res);
14001			}
14002                        valuePush(ctxt, obj);
14003                        CHECK_ERROR0;
14004                        return (total);
14005                    }
14006                    newlocset = xmlXPtrLocationSetCreate(NULL);
14007
14008                    for (i = 0; i < oldlocset->locNr; i++) {
14009                        /*
14010                         * Run the evaluation with a node list made of a
14011                         * single item in the nodelocset.
14012                         */
14013                        ctxt->context->node = oldlocset->locTab[i]->user;
14014                        ctxt->context->contextSize = oldlocset->locNr;
14015                        ctxt->context->proximityPosition = i + 1;
14016			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14017			    ctxt->context->node);
14018                        valuePush(ctxt, tmp);
14019
14020                        if (op->ch2 != -1)
14021                            total +=
14022                                xmlXPathCompOpEval(ctxt,
14023                                                   &comp->steps[op->ch2]);
14024			if (ctxt->error != XPATH_EXPRESSION_OK) {
14025			    xmlXPathFreeObject(obj);
14026			    return(0);
14027			}
14028
14029                        res = valuePop(ctxt);
14030			if (res->type == XPATH_LOCATIONSET) {
14031			    xmlLocationSetPtr rloc =
14032			        (xmlLocationSetPtr)res->user;
14033			    for (j=0; j<rloc->locNr; j++) {
14034			        range = xmlXPtrNewRange(
14035				  oldlocset->locTab[i]->user,
14036				  oldlocset->locTab[i]->index,
14037				  rloc->locTab[j]->user2,
14038				  rloc->locTab[j]->index2);
14039				if (range != NULL) {
14040				    xmlXPtrLocationSetAdd(newlocset, range);
14041				}
14042			    }
14043			} else {
14044			    range = xmlXPtrNewRangeNodeObject(
14045				(xmlNodePtr)oldlocset->locTab[i]->user, res);
14046                            if (range != NULL) {
14047                                xmlXPtrLocationSetAdd(newlocset,range);
14048			    }
14049                        }
14050
14051                        /*
14052                         * Cleanup
14053                         */
14054                        if (res != NULL) {
14055			    xmlXPathReleaseObject(ctxt->context, res);
14056			}
14057                        if (ctxt->value == tmp) {
14058                            res = valuePop(ctxt);
14059			    xmlXPathReleaseObject(ctxt->context, res);
14060                        }
14061
14062                        ctxt->context->node = NULL;
14063                    }
14064		} else {	/* Not a location set */
14065                    CHECK_TYPE0(XPATH_NODESET);
14066                    obj = valuePop(ctxt);
14067                    oldset = obj->nodesetval;
14068                    ctxt->context->node = NULL;
14069
14070                    newlocset = xmlXPtrLocationSetCreate(NULL);
14071
14072                    if (oldset != NULL) {
14073                        for (i = 0; i < oldset->nodeNr; i++) {
14074                            /*
14075                             * Run the evaluation with a node list made of a single item
14076                             * in the nodeset.
14077                             */
14078                            ctxt->context->node = oldset->nodeTab[i];
14079			    /*
14080			    * OPTIMIZE TODO: Avoid recreation for every iteration.
14081			    */
14082			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14083				ctxt->context->node);
14084                            valuePush(ctxt, tmp);
14085
14086                            if (op->ch2 != -1)
14087                                total +=
14088                                    xmlXPathCompOpEval(ctxt,
14089                                                   &comp->steps[op->ch2]);
14090			    if (ctxt->error != XPATH_EXPRESSION_OK) {
14091				xmlXPathFreeObject(obj);
14092				return(0);
14093			    }
14094
14095                            res = valuePop(ctxt);
14096                            range =
14097                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14098                                                      res);
14099                            if (range != NULL) {
14100                                xmlXPtrLocationSetAdd(newlocset, range);
14101                            }
14102
14103                            /*
14104                             * Cleanup
14105                             */
14106                            if (res != NULL) {
14107				xmlXPathReleaseObject(ctxt->context, res);
14108			    }
14109                            if (ctxt->value == tmp) {
14110                                res = valuePop(ctxt);
14111				xmlXPathReleaseObject(ctxt->context, res);
14112                            }
14113
14114                            ctxt->context->node = NULL;
14115                        }
14116                    }
14117                }
14118
14119                /*
14120                 * The result is used as the new evaluation set.
14121                 */
14122		xmlXPathReleaseObject(ctxt->context, obj);
14123                ctxt->context->node = NULL;
14124                ctxt->context->contextSize = -1;
14125                ctxt->context->proximityPosition = -1;
14126                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14127                return (total);
14128            }
14129#endif /* LIBXML_XPTR_ENABLED */
14130    }
14131    xmlGenericError(xmlGenericErrorContext,
14132                    "XPath: unknown precompiled operation %d\n", op->op);
14133    ctxt->error = XPATH_INVALID_OPERAND;
14134    return (total);
14135}
14136
14137/**
14138 * xmlXPathCompOpEvalToBoolean:
14139 * @ctxt:  the XPath parser context
14140 *
14141 * Evaluates if the expression evaluates to true.
14142 *
14143 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14144 */
14145static int
14146xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14147			    xmlXPathStepOpPtr op,
14148			    int isPredicate)
14149{
14150    xmlXPathObjectPtr resObj = NULL;
14151
14152start:
14153    /* comp = ctxt->comp; */
14154    switch (op->op) {
14155        case XPATH_OP_END:
14156            return (0);
14157	case XPATH_OP_VALUE:
14158	    resObj = (xmlXPathObjectPtr) op->value4;
14159	    if (isPredicate)
14160		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14161	    return(xmlXPathCastToBoolean(resObj));
14162	case XPATH_OP_SORT:
14163	    /*
14164	    * We don't need sorting for boolean results. Skip this one.
14165	    */
14166            if (op->ch1 != -1) {
14167		op = &ctxt->comp->steps[op->ch1];
14168		goto start;
14169	    }
14170	    return(0);
14171	case XPATH_OP_COLLECT:
14172	    if (op->ch1 == -1)
14173		return(0);
14174
14175            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14176	    if (ctxt->error != XPATH_EXPRESSION_OK)
14177		return(-1);
14178
14179            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14180	    if (ctxt->error != XPATH_EXPRESSION_OK)
14181		return(-1);
14182
14183	    resObj = valuePop(ctxt);
14184	    if (resObj == NULL)
14185		return(-1);
14186	    break;
14187	default:
14188	    /*
14189	    * Fallback to call xmlXPathCompOpEval().
14190	    */
14191	    xmlXPathCompOpEval(ctxt, op);
14192	    if (ctxt->error != XPATH_EXPRESSION_OK)
14193		return(-1);
14194
14195	    resObj = valuePop(ctxt);
14196	    if (resObj == NULL)
14197		return(-1);
14198	    break;
14199    }
14200
14201    if (resObj) {
14202	int res;
14203
14204	if (resObj->type == XPATH_BOOLEAN) {
14205	    res = resObj->boolval;
14206	} else if (isPredicate) {
14207	    /*
14208	    * For predicates a result of type "number" is handled
14209	    * differently:
14210	    * SPEC XPath 1.0:
14211	    * "If the result is a number, the result will be converted
14212	    *  to true if the number is equal to the context position
14213	    *  and will be converted to false otherwise;"
14214	    */
14215	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14216	} else {
14217	    res = xmlXPathCastToBoolean(resObj);
14218	}
14219	xmlXPathReleaseObject(ctxt->context, resObj);
14220	return(res);
14221    }
14222
14223    return(0);
14224}
14225
14226#ifdef XPATH_STREAMING
14227/**
14228 * xmlXPathRunStreamEval:
14229 * @ctxt:  the XPath parser context with the compiled expression
14230 *
14231 * Evaluate the Precompiled Streamable XPath expression in the given context.
14232 */
14233static int
14234xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14235		      xmlXPathObjectPtr *resultSeq, int toBool)
14236{
14237    int max_depth, min_depth;
14238    int from_root;
14239    int ret, depth;
14240    int eval_all_nodes;
14241    xmlNodePtr cur = NULL, limit = NULL;
14242    xmlStreamCtxtPtr patstream = NULL;
14243
14244    int nb_nodes = 0;
14245
14246    if ((ctxt == NULL) || (comp == NULL))
14247        return(-1);
14248    max_depth = xmlPatternMaxDepth(comp);
14249    if (max_depth == -1)
14250        return(-1);
14251    if (max_depth == -2)
14252        max_depth = 10000;
14253    min_depth = xmlPatternMinDepth(comp);
14254    if (min_depth == -1)
14255        return(-1);
14256    from_root = xmlPatternFromRoot(comp);
14257    if (from_root < 0)
14258        return(-1);
14259#if 0
14260    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14261#endif
14262
14263    if (! toBool) {
14264	if (resultSeq == NULL)
14265	    return(-1);
14266	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14267	if (*resultSeq == NULL)
14268	    return(-1);
14269    }
14270
14271    /*
14272     * handle the special cases of "/" amd "." being matched
14273     */
14274    if (min_depth == 0) {
14275	if (from_root) {
14276	    /* Select "/" */
14277	    if (toBool)
14278		return(1);
14279	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14280		                     (xmlNodePtr) ctxt->doc);
14281	} else {
14282	    /* Select "self::node()" */
14283	    if (toBool)
14284		return(1);
14285	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14286	}
14287    }
14288    if (max_depth == 0) {
14289	return(0);
14290    }
14291
14292    if (from_root) {
14293        cur = (xmlNodePtr)ctxt->doc;
14294    } else if (ctxt->node != NULL) {
14295        switch (ctxt->node->type) {
14296            case XML_ELEMENT_NODE:
14297            case XML_DOCUMENT_NODE:
14298            case XML_DOCUMENT_FRAG_NODE:
14299            case XML_HTML_DOCUMENT_NODE:
14300#ifdef LIBXML_DOCB_ENABLED
14301            case XML_DOCB_DOCUMENT_NODE:
14302#endif
14303	        cur = ctxt->node;
14304		break;
14305            case XML_ATTRIBUTE_NODE:
14306            case XML_TEXT_NODE:
14307            case XML_CDATA_SECTION_NODE:
14308            case XML_ENTITY_REF_NODE:
14309            case XML_ENTITY_NODE:
14310            case XML_PI_NODE:
14311            case XML_COMMENT_NODE:
14312            case XML_NOTATION_NODE:
14313            case XML_DTD_NODE:
14314            case XML_DOCUMENT_TYPE_NODE:
14315            case XML_ELEMENT_DECL:
14316            case XML_ATTRIBUTE_DECL:
14317            case XML_ENTITY_DECL:
14318            case XML_NAMESPACE_DECL:
14319            case XML_XINCLUDE_START:
14320            case XML_XINCLUDE_END:
14321		break;
14322	}
14323	limit = cur;
14324    }
14325    if (cur == NULL) {
14326        return(0);
14327    }
14328
14329    patstream = xmlPatternGetStreamCtxt(comp);
14330    if (patstream == NULL) {
14331	/*
14332	* QUESTION TODO: Is this an error?
14333	*/
14334	return(0);
14335    }
14336
14337    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14338
14339    if (from_root) {
14340	ret = xmlStreamPush(patstream, NULL, NULL);
14341	if (ret < 0) {
14342	} else if (ret == 1) {
14343	    if (toBool)
14344		goto return_1;
14345	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14346	}
14347    }
14348    depth = 0;
14349    goto scan_children;
14350next_node:
14351    do {
14352        nb_nodes++;
14353
14354	switch (cur->type) {
14355	    case XML_ELEMENT_NODE:
14356	    case XML_TEXT_NODE:
14357	    case XML_CDATA_SECTION_NODE:
14358	    case XML_COMMENT_NODE:
14359	    case XML_PI_NODE:
14360		if (cur->type == XML_ELEMENT_NODE) {
14361		    ret = xmlStreamPush(patstream, cur->name,
14362				(cur->ns ? cur->ns->href : NULL));
14363		} else if (eval_all_nodes)
14364		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14365		else
14366		    break;
14367
14368		if (ret < 0) {
14369		    /* NOP. */
14370		} else if (ret == 1) {
14371		    if (toBool)
14372			goto return_1;
14373		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14374		        < 0) {
14375			ctxt->lastError.domain = XML_FROM_XPATH;
14376			ctxt->lastError.code = XML_ERR_NO_MEMORY;
14377		    }
14378		}
14379		if ((cur->children == NULL) || (depth >= max_depth)) {
14380		    ret = xmlStreamPop(patstream);
14381		    while (cur->next != NULL) {
14382			cur = cur->next;
14383			if ((cur->type != XML_ENTITY_DECL) &&
14384			    (cur->type != XML_DTD_NODE))
14385			    goto next_node;
14386		    }
14387		}
14388	    default:
14389		break;
14390	}
14391
14392scan_children:
14393	if (cur->type == XML_NAMESPACE_DECL) break;
14394	if ((cur->children != NULL) && (depth < max_depth)) {
14395	    /*
14396	     * Do not descend on entities declarations
14397	     */
14398	    if (cur->children->type != XML_ENTITY_DECL) {
14399		cur = cur->children;
14400		depth++;
14401		/*
14402		 * Skip DTDs
14403		 */
14404		if (cur->type != XML_DTD_NODE)
14405		    continue;
14406	    }
14407	}
14408
14409	if (cur == limit)
14410	    break;
14411
14412	while (cur->next != NULL) {
14413	    cur = cur->next;
14414	    if ((cur->type != XML_ENTITY_DECL) &&
14415		(cur->type != XML_DTD_NODE))
14416		goto next_node;
14417	}
14418
14419	do {
14420	    cur = cur->parent;
14421	    depth--;
14422	    if ((cur == NULL) || (cur == limit))
14423	        goto done;
14424	    if (cur->type == XML_ELEMENT_NODE) {
14425		ret = xmlStreamPop(patstream);
14426	    } else if ((eval_all_nodes) &&
14427		((cur->type == XML_TEXT_NODE) ||
14428		 (cur->type == XML_CDATA_SECTION_NODE) ||
14429		 (cur->type == XML_COMMENT_NODE) ||
14430		 (cur->type == XML_PI_NODE)))
14431	    {
14432		ret = xmlStreamPop(patstream);
14433	    }
14434	    if (cur->next != NULL) {
14435		cur = cur->next;
14436		break;
14437	    }
14438	} while (cur != NULL);
14439
14440    } while ((cur != NULL) && (depth >= 0));
14441
14442done:
14443
14444#if 0
14445    printf("stream eval: checked %d nodes selected %d\n",
14446           nb_nodes, retObj->nodesetval->nodeNr);
14447#endif
14448
14449    if (patstream)
14450	xmlFreeStreamCtxt(patstream);
14451    return(0);
14452
14453return_1:
14454    if (patstream)
14455	xmlFreeStreamCtxt(patstream);
14456    return(1);
14457}
14458#endif /* XPATH_STREAMING */
14459
14460/**
14461 * xmlXPathRunEval:
14462 * @ctxt:  the XPath parser context with the compiled expression
14463 * @toBool:  evaluate to a boolean result
14464 *
14465 * Evaluate the Precompiled XPath expression in the given context.
14466 */
14467static int
14468xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14469{
14470    xmlXPathCompExprPtr comp;
14471
14472    if ((ctxt == NULL) || (ctxt->comp == NULL))
14473	return(-1);
14474
14475    if (ctxt->valueTab == NULL) {
14476	/* Allocate the value stack */
14477	ctxt->valueTab = (xmlXPathObjectPtr *)
14478			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14479	if (ctxt->valueTab == NULL) {
14480	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14481	    xmlFree(ctxt);
14482	}
14483	ctxt->valueNr = 0;
14484	ctxt->valueMax = 10;
14485	ctxt->value = NULL;
14486        ctxt->valueFrame = 0;
14487    }
14488#ifdef XPATH_STREAMING
14489    if (ctxt->comp->stream) {
14490	int res;
14491
14492	if (toBool) {
14493	    /*
14494	    * Evaluation to boolean result.
14495	    */
14496	    res = xmlXPathRunStreamEval(ctxt->context,
14497		ctxt->comp->stream, NULL, 1);
14498	    if (res != -1)
14499		return(res);
14500	} else {
14501	    xmlXPathObjectPtr resObj = NULL;
14502
14503	    /*
14504	    * Evaluation to a sequence.
14505	    */
14506	    res = xmlXPathRunStreamEval(ctxt->context,
14507		ctxt->comp->stream, &resObj, 0);
14508
14509	    if ((res != -1) && (resObj != NULL)) {
14510		valuePush(ctxt, resObj);
14511		return(0);
14512	    }
14513	    if (resObj != NULL)
14514		xmlXPathReleaseObject(ctxt->context, resObj);
14515	}
14516	/*
14517	* QUESTION TODO: This falls back to normal XPath evaluation
14518	* if res == -1. Is this intended?
14519	*/
14520    }
14521#endif
14522    comp = ctxt->comp;
14523    if (comp->last < 0) {
14524	xmlGenericError(xmlGenericErrorContext,
14525	    "xmlXPathRunEval: last is less than zero\n");
14526	return(-1);
14527    }
14528    if (toBool)
14529	return(xmlXPathCompOpEvalToBoolean(ctxt,
14530	    &comp->steps[comp->last], 0));
14531    else
14532	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14533
14534    return(0);
14535}
14536
14537/************************************************************************
14538 *									*
14539 *			Public interfaces				*
14540 *									*
14541 ************************************************************************/
14542
14543/**
14544 * xmlXPathEvalPredicate:
14545 * @ctxt:  the XPath context
14546 * @res:  the Predicate Expression evaluation result
14547 *
14548 * Evaluate a predicate result for the current node.
14549 * A PredicateExpr is evaluated by evaluating the Expr and converting
14550 * the result to a boolean. If the result is a number, the result will
14551 * be converted to true if the number is equal to the position of the
14552 * context node in the context node list (as returned by the position
14553 * function) and will be converted to false otherwise; if the result
14554 * is not a number, then the result will be converted as if by a call
14555 * to the boolean function.
14556 *
14557 * Returns 1 if predicate is true, 0 otherwise
14558 */
14559int
14560xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14561    if ((ctxt == NULL) || (res == NULL)) return(0);
14562    switch (res->type) {
14563        case XPATH_BOOLEAN:
14564	    return(res->boolval);
14565        case XPATH_NUMBER:
14566	    return(res->floatval == ctxt->proximityPosition);
14567        case XPATH_NODESET:
14568        case XPATH_XSLT_TREE:
14569	    if (res->nodesetval == NULL)
14570		return(0);
14571	    return(res->nodesetval->nodeNr != 0);
14572        case XPATH_STRING:
14573	    return((res->stringval != NULL) &&
14574	           (xmlStrlen(res->stringval) != 0));
14575        default:
14576	    STRANGE
14577    }
14578    return(0);
14579}
14580
14581/**
14582 * xmlXPathEvaluatePredicateResult:
14583 * @ctxt:  the XPath Parser context
14584 * @res:  the Predicate Expression evaluation result
14585 *
14586 * Evaluate a predicate result for the current node.
14587 * A PredicateExpr is evaluated by evaluating the Expr and converting
14588 * the result to a boolean. If the result is a number, the result will
14589 * be converted to true if the number is equal to the position of the
14590 * context node in the context node list (as returned by the position
14591 * function) and will be converted to false otherwise; if the result
14592 * is not a number, then the result will be converted as if by a call
14593 * to the boolean function.
14594 *
14595 * Returns 1 if predicate is true, 0 otherwise
14596 */
14597int
14598xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14599                                xmlXPathObjectPtr res) {
14600    if ((ctxt == NULL) || (res == NULL)) return(0);
14601    switch (res->type) {
14602        case XPATH_BOOLEAN:
14603	    return(res->boolval);
14604        case XPATH_NUMBER:
14605#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14606	    return((res->floatval == ctxt->context->proximityPosition) &&
14607	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14608#else
14609	    return(res->floatval == ctxt->context->proximityPosition);
14610#endif
14611        case XPATH_NODESET:
14612        case XPATH_XSLT_TREE:
14613	    if (res->nodesetval == NULL)
14614		return(0);
14615	    return(res->nodesetval->nodeNr != 0);
14616        case XPATH_STRING:
14617	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14618#ifdef LIBXML_XPTR_ENABLED
14619	case XPATH_LOCATIONSET:{
14620	    xmlLocationSetPtr ptr = res->user;
14621	    if (ptr == NULL)
14622	        return(0);
14623	    return (ptr->locNr != 0);
14624	    }
14625#endif
14626        default:
14627	    STRANGE
14628    }
14629    return(0);
14630}
14631
14632#ifdef XPATH_STREAMING
14633/**
14634 * xmlXPathTryStreamCompile:
14635 * @ctxt: an XPath context
14636 * @str:  the XPath expression
14637 *
14638 * Try to compile the XPath expression as a streamable subset.
14639 *
14640 * Returns the compiled expression or NULL if failed to compile.
14641 */
14642static xmlXPathCompExprPtr
14643xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14644    /*
14645     * Optimization: use streaming patterns when the XPath expression can
14646     * be compiled to a stream lookup
14647     */
14648    xmlPatternPtr stream;
14649    xmlXPathCompExprPtr comp;
14650    xmlDictPtr dict = NULL;
14651    const xmlChar **namespaces = NULL;
14652    xmlNsPtr ns;
14653    int i, j;
14654
14655    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14656        (!xmlStrchr(str, '@'))) {
14657	const xmlChar *tmp;
14658
14659	/*
14660	 * We don't try to handle expressions using the verbose axis
14661	 * specifiers ("::"), just the simplied form at this point.
14662	 * Additionally, if there is no list of namespaces available and
14663	 *  there's a ":" in the expression, indicating a prefixed QName,
14664	 *  then we won't try to compile either. xmlPatterncompile() needs
14665	 *  to have a list of namespaces at compilation time in order to
14666	 *  compile prefixed name tests.
14667	 */
14668	tmp = xmlStrchr(str, ':');
14669	if ((tmp != NULL) &&
14670	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14671	    return(NULL);
14672
14673	if (ctxt != NULL) {
14674	    dict = ctxt->dict;
14675	    if (ctxt->nsNr > 0) {
14676		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14677		if (namespaces == NULL) {
14678		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14679		    return(NULL);
14680		}
14681		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14682		    ns = ctxt->namespaces[j];
14683		    namespaces[i++] = ns->href;
14684		    namespaces[i++] = ns->prefix;
14685		}
14686		namespaces[i++] = NULL;
14687		namespaces[i] = NULL;
14688	    }
14689	}
14690
14691	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14692			&namespaces[0]);
14693	if (namespaces != NULL) {
14694	    xmlFree((xmlChar **)namespaces);
14695	}
14696	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14697	    comp = xmlXPathNewCompExpr();
14698	    if (comp == NULL) {
14699		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14700		return(NULL);
14701	    }
14702	    comp->stream = stream;
14703	    comp->dict = dict;
14704	    if (comp->dict)
14705		xmlDictReference(comp->dict);
14706	    return(comp);
14707	}
14708	xmlFreePattern(stream);
14709    }
14710    return(NULL);
14711}
14712#endif /* XPATH_STREAMING */
14713
14714static void
14715xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14716{
14717    /*
14718    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14719    * internal representation.
14720    */
14721
14722    if ((op->ch1 != -1) &&
14723        (op->op == XPATH_OP_COLLECT /* 11 */))
14724    {
14725        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14726
14727        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14728            ((xmlXPathAxisVal) prevop->value ==
14729                AXIS_DESCENDANT_OR_SELF) &&
14730            (prevop->ch2 == -1) &&
14731            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14732            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14733        {
14734            /*
14735            * This is a "descendant-or-self::node()" without predicates.
14736            * Try to eliminate it.
14737            */
14738
14739            switch ((xmlXPathAxisVal) op->value) {
14740                case AXIS_CHILD:
14741                case AXIS_DESCENDANT:
14742                    /*
14743                    * Convert "descendant-or-self::node()/child::" or
14744                    * "descendant-or-self::node()/descendant::" to
14745                    * "descendant::"
14746                    */
14747                    op->ch1   = prevop->ch1;
14748                    op->value = AXIS_DESCENDANT;
14749                    break;
14750                case AXIS_SELF:
14751                case AXIS_DESCENDANT_OR_SELF:
14752                    /*
14753                    * Convert "descendant-or-self::node()/self::" or
14754                    * "descendant-or-self::node()/descendant-or-self::" to
14755                    * to "descendant-or-self::"
14756                    */
14757                    op->ch1   = prevop->ch1;
14758                    op->value = AXIS_DESCENDANT_OR_SELF;
14759                    break;
14760                default:
14761                    break;
14762            }
14763	}
14764    }
14765
14766    /* Recurse */
14767    if (op->ch1 != -1)
14768        xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14769    if (op->ch2 != -1)
14770	xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14771}
14772
14773/**
14774 * xmlXPathCtxtCompile:
14775 * @ctxt: an XPath context
14776 * @str:  the XPath expression
14777 *
14778 * Compile an XPath expression
14779 *
14780 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14781 *         the caller has to free the object.
14782 */
14783xmlXPathCompExprPtr
14784xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14785    xmlXPathParserContextPtr pctxt;
14786    xmlXPathCompExprPtr comp;
14787
14788#ifdef XPATH_STREAMING
14789    comp = xmlXPathTryStreamCompile(ctxt, str);
14790    if (comp != NULL)
14791        return(comp);
14792#endif
14793
14794    xmlXPathInit();
14795
14796    pctxt = xmlXPathNewParserContext(str, ctxt);
14797    if (pctxt == NULL)
14798        return NULL;
14799    xmlXPathCompileExpr(pctxt, 1);
14800
14801    if( pctxt->error != XPATH_EXPRESSION_OK )
14802    {
14803        xmlXPathFreeParserContext(pctxt);
14804        return(NULL);
14805    }
14806
14807    if (*pctxt->cur != 0) {
14808	/*
14809	 * aleksey: in some cases this line prints *second* error message
14810	 * (see bug #78858) and probably this should be fixed.
14811	 * However, we are not sure that all error messages are printed
14812	 * out in other places. It's not critical so we leave it as-is for now
14813	 */
14814	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14815	comp = NULL;
14816    } else {
14817	comp = pctxt->comp;
14818	pctxt->comp = NULL;
14819    }
14820    xmlXPathFreeParserContext(pctxt);
14821
14822    if (comp != NULL) {
14823	comp->expr = xmlStrdup(str);
14824#ifdef DEBUG_EVAL_COUNTS
14825	comp->string = xmlStrdup(str);
14826	comp->nb = 0;
14827#endif
14828	if ((comp->nbStep > 1) && (comp->last >= 0)) {
14829	    xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14830	}
14831    }
14832    return(comp);
14833}
14834
14835/**
14836 * xmlXPathCompile:
14837 * @str:  the XPath expression
14838 *
14839 * Compile an XPath expression
14840 *
14841 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14842 *         the caller has to free the object.
14843 */
14844xmlXPathCompExprPtr
14845xmlXPathCompile(const xmlChar *str) {
14846    return(xmlXPathCtxtCompile(NULL, str));
14847}
14848
14849/**
14850 * xmlXPathCompiledEvalInternal:
14851 * @comp:  the compiled XPath expression
14852 * @ctxt:  the XPath context
14853 * @resObj: the resulting XPath object or NULL
14854 * @toBool: 1 if only a boolean result is requested
14855 *
14856 * Evaluate the Precompiled XPath expression in the given context.
14857 * The caller has to free @resObj.
14858 *
14859 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14860 *         the caller has to free the object.
14861 */
14862static int
14863xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14864			     xmlXPathContextPtr ctxt,
14865			     xmlXPathObjectPtr *resObj,
14866			     int toBool)
14867{
14868    xmlXPathParserContextPtr pctxt;
14869#ifndef LIBXML_THREAD_ENABLED
14870    static int reentance = 0;
14871#endif
14872    int res;
14873
14874    CHECK_CTXT_NEG(ctxt)
14875
14876    if (comp == NULL)
14877	return(-1);
14878    xmlXPathInit();
14879
14880#ifndef LIBXML_THREAD_ENABLED
14881    reentance++;
14882    if (reentance > 1)
14883	xmlXPathDisableOptimizer = 1;
14884#endif
14885
14886#ifdef DEBUG_EVAL_COUNTS
14887    comp->nb++;
14888    if ((comp->string != NULL) && (comp->nb > 100)) {
14889	fprintf(stderr, "100 x %s\n", comp->string);
14890	comp->nb = 0;
14891    }
14892#endif
14893    pctxt = xmlXPathCompParserContext(comp, ctxt);
14894    res = xmlXPathRunEval(pctxt, toBool);
14895
14896    if (resObj) {
14897	if (pctxt->value == NULL) {
14898	    xmlGenericError(xmlGenericErrorContext,
14899		"xmlXPathCompiledEval: evaluation failed\n");
14900	    *resObj = NULL;
14901	} else {
14902	    *resObj = valuePop(pctxt);
14903	}
14904    }
14905
14906    /*
14907    * Pop all remaining objects from the stack.
14908    */
14909    if (pctxt->valueNr > 0) {
14910	xmlXPathObjectPtr tmp;
14911	int stack = 0;
14912
14913	do {
14914	    tmp = valuePop(pctxt);
14915	    if (tmp != NULL) {
14916		stack++;
14917		xmlXPathReleaseObject(ctxt, tmp);
14918	    }
14919	} while (tmp != NULL);
14920	if ((stack != 0) &&
14921	    ((toBool) || ((resObj) && (*resObj))))
14922	{
14923	    xmlGenericError(xmlGenericErrorContext,
14924		"xmlXPathCompiledEval: %d objects left on the stack.\n",
14925		stack);
14926	}
14927    }
14928
14929    if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14930	xmlXPathFreeObject(*resObj);
14931	*resObj = NULL;
14932    }
14933    pctxt->comp = NULL;
14934    xmlXPathFreeParserContext(pctxt);
14935#ifndef LIBXML_THREAD_ENABLED
14936    reentance--;
14937#endif
14938
14939    return(res);
14940}
14941
14942/**
14943 * xmlXPathCompiledEval:
14944 * @comp:  the compiled XPath expression
14945 * @ctx:  the XPath context
14946 *
14947 * Evaluate the Precompiled XPath expression in the given context.
14948 *
14949 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14950 *         the caller has to free the object.
14951 */
14952xmlXPathObjectPtr
14953xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14954{
14955    xmlXPathObjectPtr res = NULL;
14956
14957    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14958    return(res);
14959}
14960
14961/**
14962 * xmlXPathCompiledEvalToBoolean:
14963 * @comp:  the compiled XPath expression
14964 * @ctxt:  the XPath context
14965 *
14966 * Applies the XPath boolean() function on the result of the given
14967 * compiled expression.
14968 *
14969 * Returns 1 if the expression evaluated to true, 0 if to false and
14970 *         -1 in API and internal errors.
14971 */
14972int
14973xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14974			      xmlXPathContextPtr ctxt)
14975{
14976    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14977}
14978
14979/**
14980 * xmlXPathEvalExpr:
14981 * @ctxt:  the XPath Parser context
14982 *
14983 * Parse and evaluate an XPath expression in the given context,
14984 * then push the result on the context stack
14985 */
14986void
14987xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14988#ifdef XPATH_STREAMING
14989    xmlXPathCompExprPtr comp;
14990#endif
14991
14992    if (ctxt == NULL) return;
14993
14994#ifdef XPATH_STREAMING
14995    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14996    if (comp != NULL) {
14997        if (ctxt->comp != NULL)
14998	    xmlXPathFreeCompExpr(ctxt->comp);
14999        ctxt->comp = comp;
15000	if (ctxt->cur != NULL)
15001	    while (*ctxt->cur != 0) ctxt->cur++;
15002    } else
15003#endif
15004    {
15005	xmlXPathCompileExpr(ctxt, 1);
15006	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
15007	    (ctxt->comp != NULL) &&
15008	    (ctxt->comp->nbStep > 1) &&
15009	    (ctxt->comp->last >= 0))
15010	{
15011	    xmlXPathOptimizeExpression(ctxt->comp,
15012		&ctxt->comp->steps[ctxt->comp->last]);
15013	}
15014    }
15015    CHECK_ERROR;
15016    xmlXPathRunEval(ctxt, 0);
15017}
15018
15019/**
15020 * xmlXPathEval:
15021 * @str:  the XPath expression
15022 * @ctx:  the XPath context
15023 *
15024 * Evaluate the XPath Location Path in the given context.
15025 *
15026 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15027 *         the caller has to free the object.
15028 */
15029xmlXPathObjectPtr
15030xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15031    xmlXPathParserContextPtr ctxt;
15032    xmlXPathObjectPtr res, tmp, init = NULL;
15033    int stack = 0;
15034
15035    CHECK_CTXT(ctx)
15036
15037    xmlXPathInit();
15038
15039    ctxt = xmlXPathNewParserContext(str, ctx);
15040    if (ctxt == NULL)
15041        return NULL;
15042    xmlXPathEvalExpr(ctxt);
15043
15044    if (ctxt->value == NULL) {
15045	xmlGenericError(xmlGenericErrorContext,
15046		"xmlXPathEval: evaluation failed\n");
15047	res = NULL;
15048    } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
15049#ifdef XPATH_STREAMING
15050            && (ctxt->comp->stream == NULL)
15051#endif
15052	      ) {
15053	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15054	res = NULL;
15055    } else {
15056	res = valuePop(ctxt);
15057    }
15058
15059    do {
15060        tmp = valuePop(ctxt);
15061	if (tmp != NULL) {
15062	    if (tmp != init)
15063		stack++;
15064	    xmlXPathReleaseObject(ctx, tmp);
15065        }
15066    } while (tmp != NULL);
15067    if ((stack != 0) && (res != NULL)) {
15068	xmlGenericError(xmlGenericErrorContext,
15069		"xmlXPathEval: %d object left on the stack\n",
15070	        stack);
15071    }
15072    if (ctxt->error != XPATH_EXPRESSION_OK) {
15073	xmlXPathFreeObject(res);
15074	res = NULL;
15075    }
15076
15077    xmlXPathFreeParserContext(ctxt);
15078    return(res);
15079}
15080
15081/**
15082 * xmlXPathSetContextNode:
15083 * @node: the node to to use as the context node
15084 * @ctx:  the XPath context
15085 *
15086 * Sets 'node' as the context node. The node must be in the same
15087 * document as that associated with the context.
15088 *
15089 * Returns -1 in case of error or 0 if successful
15090 */
15091int
15092xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15093    if ((node == NULL) || (ctx == NULL))
15094        return(-1);
15095
15096    if (node->doc == ctx->doc) {
15097        ctx->node = node;
15098	return(0);
15099    }
15100    return(-1);
15101}
15102
15103/**
15104 * xmlXPathNodeEval:
15105 * @node: the node to to use as the context node
15106 * @str:  the XPath expression
15107 * @ctx:  the XPath context
15108 *
15109 * Evaluate the XPath Location Path in the given context. The node 'node'
15110 * is set as the context node. The context node is not restored.
15111 *
15112 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15113 *         the caller has to free the object.
15114 */
15115xmlXPathObjectPtr
15116xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15117    if (str == NULL)
15118        return(NULL);
15119    if (xmlXPathSetContextNode(node, ctx) < 0)
15120        return(NULL);
15121    return(xmlXPathEval(str, ctx));
15122}
15123
15124/**
15125 * xmlXPathEvalExpression:
15126 * @str:  the XPath expression
15127 * @ctxt:  the XPath context
15128 *
15129 * Evaluate the XPath expression in the given context.
15130 *
15131 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15132 *         the caller has to free the object.
15133 */
15134xmlXPathObjectPtr
15135xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15136    xmlXPathParserContextPtr pctxt;
15137    xmlXPathObjectPtr res, tmp;
15138    int stack = 0;
15139
15140    CHECK_CTXT(ctxt)
15141
15142    xmlXPathInit();
15143
15144    pctxt = xmlXPathNewParserContext(str, ctxt);
15145    if (pctxt == NULL)
15146        return NULL;
15147    xmlXPathEvalExpr(pctxt);
15148
15149    if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
15150	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15151	res = NULL;
15152    } else {
15153	res = valuePop(pctxt);
15154    }
15155    do {
15156        tmp = valuePop(pctxt);
15157	if (tmp != NULL) {
15158	    xmlXPathReleaseObject(ctxt, tmp);
15159	    stack++;
15160	}
15161    } while (tmp != NULL);
15162    if ((stack != 0) && (res != NULL)) {
15163	xmlGenericError(xmlGenericErrorContext,
15164		"xmlXPathEvalExpression: %d object left on the stack\n",
15165	        stack);
15166    }
15167    xmlXPathFreeParserContext(pctxt);
15168    return(res);
15169}
15170
15171/************************************************************************
15172 *									*
15173 *	Extra functions not pertaining to the XPath spec		*
15174 *									*
15175 ************************************************************************/
15176/**
15177 * xmlXPathEscapeUriFunction:
15178 * @ctxt:  the XPath Parser context
15179 * @nargs:  the number of arguments
15180 *
15181 * Implement the escape-uri() XPath function
15182 *    string escape-uri(string $str, bool $escape-reserved)
15183 *
15184 * This function applies the URI escaping rules defined in section 2 of [RFC
15185 * 2396] to the string supplied as $uri-part, which typically represents all
15186 * or part of a URI. The effect of the function is to replace any special
15187 * character in the string by an escape sequence of the form %xx%yy...,
15188 * where xxyy... is the hexadecimal representation of the octets used to
15189 * represent the character in UTF-8.
15190 *
15191 * The set of characters that are escaped depends on the setting of the
15192 * boolean argument $escape-reserved.
15193 *
15194 * If $escape-reserved is true, all characters are escaped other than lower
15195 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15196 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15197 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15198 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15199 * A-F).
15200 *
15201 * If $escape-reserved is false, the behavior differs in that characters
15202 * referred to in [RFC 2396] as reserved characters are not escaped. These
15203 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15204 *
15205 * [RFC 2396] does not define whether escaped URIs should use lower case or
15206 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15207 * compared using string comparison functions, this function must always use
15208 * the upper-case letters A-F.
15209 *
15210 * Generally, $escape-reserved should be set to true when escaping a string
15211 * that is to form a single part of a URI, and to false when escaping an
15212 * entire URI or URI reference.
15213 *
15214 * In the case of non-ascii characters, the string is encoded according to
15215 * utf-8 and then converted according to RFC 2396.
15216 *
15217 * Examples
15218 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15219 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15220 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15221 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15222 *
15223 */
15224static void
15225xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15226    xmlXPathObjectPtr str;
15227    int escape_reserved;
15228    xmlBufPtr target;
15229    xmlChar *cptr;
15230    xmlChar escape[4];
15231
15232    CHECK_ARITY(2);
15233
15234    escape_reserved = xmlXPathPopBoolean(ctxt);
15235
15236    CAST_TO_STRING;
15237    str = valuePop(ctxt);
15238
15239    target = xmlBufCreate();
15240
15241    escape[0] = '%';
15242    escape[3] = 0;
15243
15244    if (target) {
15245	for (cptr = str->stringval; *cptr; cptr++) {
15246	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
15247		(*cptr >= 'a' && *cptr <= 'z') ||
15248		(*cptr >= '0' && *cptr <= '9') ||
15249		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
15250		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
15251		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15252		(*cptr == '%' &&
15253		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15254		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15255		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
15256		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15257		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15258		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15259		(!escape_reserved &&
15260		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15261		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15262		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15263		  *cptr == ','))) {
15264		xmlBufAdd(target, cptr, 1);
15265	    } else {
15266		if ((*cptr >> 4) < 10)
15267		    escape[1] = '0' + (*cptr >> 4);
15268		else
15269		    escape[1] = 'A' - 10 + (*cptr >> 4);
15270		if ((*cptr & 0xF) < 10)
15271		    escape[2] = '0' + (*cptr & 0xF);
15272		else
15273		    escape[2] = 'A' - 10 + (*cptr & 0xF);
15274
15275		xmlBufAdd(target, &escape[0], 3);
15276	    }
15277	}
15278    }
15279    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15280	xmlBufContent(target)));
15281    xmlBufFree(target);
15282    xmlXPathReleaseObject(ctxt->context, str);
15283}
15284
15285/**
15286 * xmlXPathRegisterAllFunctions:
15287 * @ctxt:  the XPath context
15288 *
15289 * Registers all default XPath functions in this context
15290 */
15291void
15292xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15293{
15294    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15295                         xmlXPathBooleanFunction);
15296    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15297                         xmlXPathCeilingFunction);
15298    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15299                         xmlXPathCountFunction);
15300    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15301                         xmlXPathConcatFunction);
15302    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15303                         xmlXPathContainsFunction);
15304    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15305                         xmlXPathIdFunction);
15306    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15307                         xmlXPathFalseFunction);
15308    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15309                         xmlXPathFloorFunction);
15310    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15311                         xmlXPathLastFunction);
15312    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15313                         xmlXPathLangFunction);
15314    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15315                         xmlXPathLocalNameFunction);
15316    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15317                         xmlXPathNotFunction);
15318    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15319                         xmlXPathNameFunction);
15320    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15321                         xmlXPathNamespaceURIFunction);
15322    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15323                         xmlXPathNormalizeFunction);
15324    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15325                         xmlXPathNumberFunction);
15326    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15327                         xmlXPathPositionFunction);
15328    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15329                         xmlXPathRoundFunction);
15330    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15331                         xmlXPathStringFunction);
15332    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15333                         xmlXPathStringLengthFunction);
15334    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15335                         xmlXPathStartsWithFunction);
15336    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15337                         xmlXPathSubstringFunction);
15338    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15339                         xmlXPathSubstringBeforeFunction);
15340    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15341                         xmlXPathSubstringAfterFunction);
15342    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15343                         xmlXPathSumFunction);
15344    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15345                         xmlXPathTrueFunction);
15346    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15347                         xmlXPathTranslateFunction);
15348
15349    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15350	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15351                         xmlXPathEscapeUriFunction);
15352}
15353
15354#endif /* LIBXML_XPATH_ENABLED */
15355#define bottom_xpath
15356#include "elfgcchack.h"
15357