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#ifdef LIBXML_PATTERN_ENABLED
59#define XPATH_STREAMING
60#endif
61
62#define TODO								\
63    xmlGenericError(xmlGenericErrorContext,				\
64	    "Unimplemented block at %s:%d\n",				\
65            __FILE__, __LINE__);
66
67/*
68* XP_OPTIMIZED_NON_ELEM_COMPARISON:
69* If defined, this will use xmlXPathCmpNodesExt() instead of
70* xmlXPathCmpNodes(). The new function is optimized comparison of
71* non-element nodes; actually it will speed up comparison only if
72* xmlXPathOrderDocElems() was called in order to index the elements of
73* a tree in document order; Libxslt does such an indexing, thus it will
74* benefit from this optimization.
75*/
76#define XP_OPTIMIZED_NON_ELEM_COMPARISON
77
78/*
79* XP_OPTIMIZED_FILTER_FIRST:
80* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81* in a way, that it stop evaluation at the first node.
82*/
83#define XP_OPTIMIZED_FILTER_FIRST
84
85/*
86* XP_DEBUG_OBJ_USAGE:
87* Internal flag to enable tracking of how much XPath objects have been
88* created.
89*/
90/* #define XP_DEBUG_OBJ_USAGE */
91
92/*
93 * TODO:
94 * There are a few spots where some tests are done which depend upon ascii
95 * data.  These should be enhanced for full UTF8 support (see particularly
96 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
97 */
98
99#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
100
101/************************************************************************
102 *									*
103 *			Floating point stuff				*
104 *									*
105 ************************************************************************/
106
107#ifndef TRIO_REPLACE_STDIO
108#define TRIO_PUBLIC static
109#endif
110#include "trionan.c"
111
112/*
113 * The lack of portability of this section of the libc is annoying !
114 */
115double xmlXPathNAN = 0;
116double xmlXPathPINF = 1;
117double xmlXPathNINF = -1;
118static double xmlXPathNZERO = 0; /* not exported from headers */
119static int xmlXPathInitialized = 0;
120
121/**
122 * xmlXPathInit:
123 *
124 * Initialize the XPath environment
125 */
126void
127xmlXPathInit(void) {
128    if (xmlXPathInitialized) return;
129
130    xmlXPathPINF = trio_pinf();
131    xmlXPathNINF = trio_ninf();
132    xmlXPathNAN = trio_nan();
133    xmlXPathNZERO = trio_nzero();
134
135    xmlXPathInitialized = 1;
136}
137
138/**
139 * xmlXPathIsNaN:
140 * @val:  a double value
141 *
142 * Provides a portable isnan() function to detect whether a double
143 * is a NotaNumber. Based on trio code
144 * http://sourceforge.net/projects/ctrio/
145 *
146 * Returns 1 if the value is a NaN, 0 otherwise
147 */
148int
149xmlXPathIsNaN(double val) {
150    return(trio_isnan(val));
151}
152
153/**
154 * xmlXPathIsInf:
155 * @val:  a double value
156 *
157 * Provides a portable isinf() function to detect whether a double
158 * is a +Infinite or -Infinite. Based on trio code
159 * http://sourceforge.net/projects/ctrio/
160 *
161 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
162 */
163int
164xmlXPathIsInf(double val) {
165    return(trio_isinf(val));
166}
167
168#endif /* SCHEMAS or XPATH */
169#ifdef LIBXML_XPATH_ENABLED
170/**
171 * xmlXPathGetSign:
172 * @val:  a double value
173 *
174 * Provides a portable function to detect the sign of a double
175 * Modified from trio code
176 * http://sourceforge.net/projects/ctrio/
177 *
178 * Returns 1 if the value is Negative, 0 if positive
179 */
180static int
181xmlXPathGetSign(double val) {
182    return(trio_signbit(val));
183}
184
185
186/*
187 * TODO: when compatibility allows remove all "fake node libxslt" strings
188 *       the test should just be name[0] = ' '
189 */
190#ifdef DEBUG_XPATH_EXPRESSION
191#define DEBUG_STEP
192#define DEBUG_EXPR
193#define DEBUG_EVAL_COUNTS
194#endif
195
196static xmlNs xmlXPathXMLNamespaceStruct = {
197    NULL,
198    XML_NAMESPACE_DECL,
199    XML_XML_NAMESPACE,
200    BAD_CAST "xml",
201    NULL,
202    NULL
203};
204static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
205#ifndef LIBXML_THREAD_ENABLED
206/*
207 * Optimizer is disabled only when threaded apps are detected while
208 * the library ain't compiled for thread safety.
209 */
210static int xmlXPathDisableOptimizer = 0;
211#endif
212
213/************************************************************************
214 *									*
215 *			Error handling routines				*
216 *									*
217 ************************************************************************/
218
219/**
220 * XP_ERRORNULL:
221 * @X:  the error code
222 *
223 * Macro to raise an XPath error and return NULL.
224 */
225#define XP_ERRORNULL(X)							\
226    { xmlXPathErr(ctxt, X); return(NULL); }
227
228/*
229 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
230 */
231static const char *xmlXPathErrorMessages[] = {
232    "Ok\n",
233    "Number encoding\n",
234    "Unfinished literal\n",
235    "Start of literal\n",
236    "Expected $ for variable reference\n",
237    "Undefined variable\n",
238    "Invalid predicate\n",
239    "Invalid expression\n",
240    "Missing closing curly brace\n",
241    "Unregistered function\n",
242    "Invalid operand\n",
243    "Invalid type\n",
244    "Invalid number of arguments\n",
245    "Invalid context size\n",
246    "Invalid context position\n",
247    "Memory allocation error\n",
248    "Syntax error\n",
249    "Resource error\n",
250    "Sub resource error\n",
251    "Undefined namespace prefix\n",
252    "Encoding error\n",
253    "Char out of XML range\n",
254    "Invalid or incomplete context\n",
255    "Stack usage errror\n",
256    "?? Unknown error ??\n"	/* Must be last in the list! */
257};
258#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
259		   sizeof(xmlXPathErrorMessages[0])) - 1)
260/**
261 * xmlXPathErrMemory:
262 * @ctxt:  an XPath context
263 * @extra:  extra informations
264 *
265 * Handle a redefinition of attribute error
266 */
267static void
268xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
269{
270    if (ctxt != NULL) {
271        if (extra) {
272            xmlChar buf[200];
273
274            xmlStrPrintf(buf, 200,
275                         BAD_CAST "Memory allocation failed : %s\n",
276                         extra);
277            ctxt->lastError.message = (char *) xmlStrdup(buf);
278        } else {
279            ctxt->lastError.message = (char *)
280	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
281        }
282        ctxt->lastError.domain = XML_FROM_XPATH;
283        ctxt->lastError.code = XML_ERR_NO_MEMORY;
284	if (ctxt->error != NULL)
285	    ctxt->error(ctxt->userData, &ctxt->lastError);
286    } else {
287        if (extra)
288            __xmlRaiseError(NULL, NULL, NULL,
289                            NULL, NULL, XML_FROM_XPATH,
290                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
291                            extra, NULL, NULL, 0, 0,
292                            "Memory allocation failed : %s\n", extra);
293        else
294            __xmlRaiseError(NULL, NULL, NULL,
295                            NULL, NULL, XML_FROM_XPATH,
296                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
297                            NULL, NULL, NULL, 0, 0,
298                            "Memory allocation failed\n");
299    }
300}
301
302/**
303 * xmlXPathPErrMemory:
304 * @ctxt:  an XPath parser context
305 * @extra:  extra informations
306 *
307 * Handle a redefinition of attribute error
308 */
309static void
310xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
311{
312    if (ctxt == NULL)
313	xmlXPathErrMemory(NULL, extra);
314    else {
315	ctxt->error = XPATH_MEMORY_ERROR;
316	xmlXPathErrMemory(ctxt->context, extra);
317    }
318}
319
320/**
321 * xmlXPathErr:
322 * @ctxt:  a XPath parser context
323 * @error:  the error code
324 *
325 * Handle an XPath error
326 */
327void
328xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
329{
330    if ((error < 0) || (error > MAXERRNO))
331	error = MAXERRNO;
332    if (ctxt == NULL) {
333	__xmlRaiseError(NULL, NULL, NULL,
334			NULL, NULL, XML_FROM_XPATH,
335			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
336			XML_ERR_ERROR, NULL, 0,
337			NULL, NULL, NULL, 0, 0,
338			"%s", xmlXPathErrorMessages[error]);
339	return;
340    }
341    ctxt->error = error;
342    if (ctxt->context == NULL) {
343	__xmlRaiseError(NULL, NULL, NULL,
344			NULL, NULL, XML_FROM_XPATH,
345			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
346			XML_ERR_ERROR, NULL, 0,
347			(const char *) ctxt->base, NULL, NULL,
348			ctxt->cur - ctxt->base, 0,
349			"%s", xmlXPathErrorMessages[error]);
350	return;
351    }
352
353    /* cleanup current last error */
354    xmlResetError(&ctxt->context->lastError);
355
356    ctxt->context->lastError.domain = XML_FROM_XPATH;
357    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
358                           XPATH_EXPRESSION_OK;
359    ctxt->context->lastError.level = XML_ERR_ERROR;
360    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
361    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
362    ctxt->context->lastError.node = ctxt->context->debugNode;
363    if (ctxt->context->error != NULL) {
364	ctxt->context->error(ctxt->context->userData,
365	                     &ctxt->context->lastError);
366    } else {
367	__xmlRaiseError(NULL, NULL, NULL,
368			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
369			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
370			XML_ERR_ERROR, NULL, 0,
371			(const char *) ctxt->base, NULL, NULL,
372			ctxt->cur - ctxt->base, 0,
373			"%s", xmlXPathErrorMessages[error]);
374    }
375
376}
377
378/**
379 * xmlXPatherror:
380 * @ctxt:  the XPath Parser context
381 * @file:  the file name
382 * @line:  the line number
383 * @no:  the error number
384 *
385 * Formats an error message.
386 */
387void
388xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
389              int line ATTRIBUTE_UNUSED, int no) {
390    xmlXPathErr(ctxt, no);
391}
392
393/************************************************************************
394 *									*
395 *			Utilities					*
396 *									*
397 ************************************************************************/
398
399/**
400 * xsltPointerList:
401 *
402 * Pointer-list for various purposes.
403 */
404typedef struct _xmlPointerList xmlPointerList;
405typedef xmlPointerList *xmlPointerListPtr;
406struct _xmlPointerList {
407    void **items;
408    int number;
409    int size;
410};
411/*
412* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
413* and here, we should make the functions public.
414*/
415static int
416xmlPointerListAddSize(xmlPointerListPtr list,
417		       void *item,
418		       int initialSize)
419{
420    if (list->items == NULL) {
421	if (initialSize <= 0)
422	    initialSize = 1;
423	list->items = (void **) xmlMalloc(
424	    initialSize * sizeof(void *));
425	if (list->items == NULL) {
426	    xmlXPathErrMemory(NULL,
427		"xmlPointerListCreate: allocating item\n");
428	    return(-1);
429	}
430	list->number = 0;
431	list->size = initialSize;
432    } else if (list->size <= list->number) {
433	list->size *= 2;
434	list->items = (void **) xmlRealloc(list->items,
435	    list->size * sizeof(void *));
436	if (list->items == NULL) {
437	    xmlXPathErrMemory(NULL,
438		"xmlPointerListCreate: re-allocating item\n");
439	    list->size = 0;
440	    return(-1);
441	}
442    }
443    list->items[list->number++] = item;
444    return(0);
445}
446
447/**
448 * xsltPointerListCreate:
449 *
450 * Creates an xsltPointerList structure.
451 *
452 * Returns a xsltPointerList structure or NULL in case of an error.
453 */
454static xmlPointerListPtr
455xmlPointerListCreate(int initialSize)
456{
457    xmlPointerListPtr ret;
458
459    ret = xmlMalloc(sizeof(xmlPointerList));
460    if (ret == NULL) {
461	xmlXPathErrMemory(NULL,
462	    "xmlPointerListCreate: allocating item\n");
463	return (NULL);
464    }
465    memset(ret, 0, sizeof(xmlPointerList));
466    if (initialSize > 0) {
467	xmlPointerListAddSize(ret, NULL, initialSize);
468	ret->number = 0;
469    }
470    return (ret);
471}
472
473/**
474 * xsltPointerListFree:
475 *
476 * Frees the xsltPointerList structure. This does not free
477 * the content of the list.
478 */
479static void
480xmlPointerListFree(xmlPointerListPtr list)
481{
482    if (list == NULL)
483	return;
484    if (list->items != NULL)
485	xmlFree(list->items);
486    xmlFree(list);
487}
488
489/************************************************************************
490 *									*
491 *			Parser Types					*
492 *									*
493 ************************************************************************/
494
495/*
496 * Types are private:
497 */
498
499typedef enum {
500    XPATH_OP_END=0,
501    XPATH_OP_AND,
502    XPATH_OP_OR,
503    XPATH_OP_EQUAL,
504    XPATH_OP_CMP,
505    XPATH_OP_PLUS,
506    XPATH_OP_MULT,
507    XPATH_OP_UNION,
508    XPATH_OP_ROOT,
509    XPATH_OP_NODE,
510    XPATH_OP_RESET, /* 10 */
511    XPATH_OP_COLLECT,
512    XPATH_OP_VALUE, /* 12 */
513    XPATH_OP_VARIABLE,
514    XPATH_OP_FUNCTION,
515    XPATH_OP_ARG,
516    XPATH_OP_PREDICATE,
517    XPATH_OP_FILTER, /* 17 */
518    XPATH_OP_SORT /* 18 */
519#ifdef LIBXML_XPTR_ENABLED
520    ,XPATH_OP_RANGETO
521#endif
522} xmlXPathOp;
523
524typedef enum {
525    AXIS_ANCESTOR = 1,
526    AXIS_ANCESTOR_OR_SELF,
527    AXIS_ATTRIBUTE,
528    AXIS_CHILD,
529    AXIS_DESCENDANT,
530    AXIS_DESCENDANT_OR_SELF,
531    AXIS_FOLLOWING,
532    AXIS_FOLLOWING_SIBLING,
533    AXIS_NAMESPACE,
534    AXIS_PARENT,
535    AXIS_PRECEDING,
536    AXIS_PRECEDING_SIBLING,
537    AXIS_SELF
538} xmlXPathAxisVal;
539
540typedef enum {
541    NODE_TEST_NONE = 0,
542    NODE_TEST_TYPE = 1,
543    NODE_TEST_PI = 2,
544    NODE_TEST_ALL = 3,
545    NODE_TEST_NS = 4,
546    NODE_TEST_NAME = 5
547} xmlXPathTestVal;
548
549typedef enum {
550    NODE_TYPE_NODE = 0,
551    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
552    NODE_TYPE_TEXT = XML_TEXT_NODE,
553    NODE_TYPE_PI = XML_PI_NODE
554} xmlXPathTypeVal;
555
556#define XP_REWRITE_DOS_CHILD_ELEM 1
557
558typedef struct _xmlXPathStepOp xmlXPathStepOp;
559typedef xmlXPathStepOp *xmlXPathStepOpPtr;
560struct _xmlXPathStepOp {
561    xmlXPathOp op;		/* The identifier of the operation */
562    int ch1;			/* First child */
563    int ch2;			/* Second child */
564    int value;
565    int value2;
566    int value3;
567    void *value4;
568    void *value5;
569    void *cache;
570    void *cacheURI;
571    int rewriteType;
572};
573
574struct _xmlXPathCompExpr {
575    int nbStep;			/* Number of steps in this expression */
576    int maxStep;		/* Maximum number of steps allocated */
577    xmlXPathStepOp *steps;	/* ops for computation of this expression */
578    int last;			/* index of last step in expression */
579    xmlChar *expr;		/* the expression being computed */
580    xmlDictPtr dict;		/* the dictionnary to use if any */
581#ifdef DEBUG_EVAL_COUNTS
582    int nb;
583    xmlChar *string;
584#endif
585#ifdef XPATH_STREAMING
586    xmlPatternPtr stream;
587#endif
588};
589
590/************************************************************************
591 *									*
592 *			Forward declarations				*
593 *									*
594 ************************************************************************/
595static void
596xmlXPathFreeValueTree(xmlNodeSetPtr obj);
597static void
598xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
599static int
600xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
601                        xmlXPathStepOpPtr op, xmlNodePtr *first);
602static int
603xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
604			    xmlXPathStepOpPtr op,
605			    int isPredicate);
606
607/************************************************************************
608 *									*
609 *			Parser Type functions				*
610 *									*
611 ************************************************************************/
612
613/**
614 * xmlXPathNewCompExpr:
615 *
616 * Create a new Xpath component
617 *
618 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
619 */
620static xmlXPathCompExprPtr
621xmlXPathNewCompExpr(void) {
622    xmlXPathCompExprPtr cur;
623
624    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
625    if (cur == NULL) {
626        xmlXPathErrMemory(NULL, "allocating component\n");
627	return(NULL);
628    }
629    memset(cur, 0, sizeof(xmlXPathCompExpr));
630    cur->maxStep = 10;
631    cur->nbStep = 0;
632    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
633	                                   sizeof(xmlXPathStepOp));
634    if (cur->steps == NULL) {
635        xmlXPathErrMemory(NULL, "allocating steps\n");
636	xmlFree(cur);
637	return(NULL);
638    }
639    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
640    cur->last = -1;
641#ifdef DEBUG_EVAL_COUNTS
642    cur->nb = 0;
643#endif
644    return(cur);
645}
646
647/**
648 * xmlXPathFreeCompExpr:
649 * @comp:  an XPATH comp
650 *
651 * Free up the memory allocated by @comp
652 */
653void
654xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
655{
656    xmlXPathStepOpPtr op;
657    int i;
658
659    if (comp == NULL)
660        return;
661    if (comp->dict == NULL) {
662	for (i = 0; i < comp->nbStep; i++) {
663	    op = &comp->steps[i];
664	    if (op->value4 != NULL) {
665		if (op->op == XPATH_OP_VALUE)
666		    xmlXPathFreeObject(op->value4);
667		else
668		    xmlFree(op->value4);
669	    }
670	    if (op->value5 != NULL)
671		xmlFree(op->value5);
672	}
673    } else {
674	for (i = 0; i < comp->nbStep; i++) {
675	    op = &comp->steps[i];
676	    if (op->value4 != NULL) {
677		if (op->op == XPATH_OP_VALUE)
678		    xmlXPathFreeObject(op->value4);
679	    }
680	}
681        xmlDictFree(comp->dict);
682    }
683    if (comp->steps != NULL) {
684        xmlFree(comp->steps);
685    }
686#ifdef DEBUG_EVAL_COUNTS
687    if (comp->string != NULL) {
688        xmlFree(comp->string);
689    }
690#endif
691#ifdef XPATH_STREAMING
692    if (comp->stream != NULL) {
693        xmlFreePatternList(comp->stream);
694    }
695#endif
696    if (comp->expr != NULL) {
697        xmlFree(comp->expr);
698    }
699
700    xmlFree(comp);
701}
702
703/**
704 * xmlXPathCompExprAdd:
705 * @comp:  the compiled expression
706 * @ch1: first child index
707 * @ch2: second child index
708 * @op:  an op
709 * @value:  the first int value
710 * @value2:  the second int value
711 * @value3:  the third int value
712 * @value4:  the first string value
713 * @value5:  the second string value
714 *
715 * Add a step to an XPath Compiled Expression
716 *
717 * Returns -1 in case of failure, the index otherwise
718 */
719static int
720xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
721   xmlXPathOp op, int value,
722   int value2, int value3, void *value4, void *value5) {
723    if (comp->nbStep >= comp->maxStep) {
724	xmlXPathStepOp *real;
725
726	comp->maxStep *= 2;
727	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
728		                      comp->maxStep * sizeof(xmlXPathStepOp));
729	if (real == NULL) {
730	    comp->maxStep /= 2;
731	    xmlXPathErrMemory(NULL, "adding step\n");
732	    return(-1);
733	}
734	comp->steps = real;
735    }
736    comp->last = comp->nbStep;
737    comp->steps[comp->nbStep].rewriteType = 0;
738    comp->steps[comp->nbStep].ch1 = ch1;
739    comp->steps[comp->nbStep].ch2 = ch2;
740    comp->steps[comp->nbStep].op = op;
741    comp->steps[comp->nbStep].value = value;
742    comp->steps[comp->nbStep].value2 = value2;
743    comp->steps[comp->nbStep].value3 = value3;
744    if ((comp->dict != NULL) &&
745        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
746	 (op == XPATH_OP_COLLECT))) {
747        if (value4 != NULL) {
748	    comp->steps[comp->nbStep].value4 = (xmlChar *)
749	        (void *)xmlDictLookup(comp->dict, value4, -1);
750	    xmlFree(value4);
751	} else
752	    comp->steps[comp->nbStep].value4 = NULL;
753        if (value5 != NULL) {
754	    comp->steps[comp->nbStep].value5 = (xmlChar *)
755	        (void *)xmlDictLookup(comp->dict, value5, -1);
756	    xmlFree(value5);
757	} else
758	    comp->steps[comp->nbStep].value5 = NULL;
759    } else {
760	comp->steps[comp->nbStep].value4 = value4;
761	comp->steps[comp->nbStep].value5 = value5;
762    }
763    comp->steps[comp->nbStep].cache = NULL;
764    return(comp->nbStep++);
765}
766
767/**
768 * xmlXPathCompSwap:
769 * @comp:  the compiled expression
770 * @op: operation index
771 *
772 * Swaps 2 operations in the compiled expression
773 */
774static void
775xmlXPathCompSwap(xmlXPathStepOpPtr op) {
776    int tmp;
777
778#ifndef LIBXML_THREAD_ENABLED
779    /*
780     * Since this manipulates possibly shared variables, this is
781     * disabled if one detects that the library is used in a multithreaded
782     * application
783     */
784    if (xmlXPathDisableOptimizer)
785	return;
786#endif
787
788    tmp = op->ch1;
789    op->ch1 = op->ch2;
790    op->ch2 = tmp;
791}
792
793#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
794    xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
795	                (op), (val), (val2), (val3), (val4), (val5))
796#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
797    xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
798	                (op), (val), (val2), (val3), (val4), (val5))
799
800#define PUSH_LEAVE_EXPR(op, val, val2)					\
801xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
802
803#define PUSH_UNARY_EXPR(op, ch, val, val2)				\
804xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
805
806#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
807xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
808			(val), (val2), 0 ,NULL ,NULL)
809
810/************************************************************************
811 *									*
812 *		XPath object cache structures				*
813 *									*
814 ************************************************************************/
815
816/* #define XP_DEFAULT_CACHE_ON */
817
818#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
819
820typedef struct _xmlXPathContextCache xmlXPathContextCache;
821typedef xmlXPathContextCache *xmlXPathContextCachePtr;
822struct _xmlXPathContextCache {
823    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
824    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
825    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
826    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
827    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
828    int maxNodeset;
829    int maxString;
830    int maxBoolean;
831    int maxNumber;
832    int maxMisc;
833#ifdef XP_DEBUG_OBJ_USAGE
834    int dbgCachedAll;
835    int dbgCachedNodeset;
836    int dbgCachedString;
837    int dbgCachedBool;
838    int dbgCachedNumber;
839    int dbgCachedPoint;
840    int dbgCachedRange;
841    int dbgCachedLocset;
842    int dbgCachedUsers;
843    int dbgCachedXSLTTree;
844    int dbgCachedUndefined;
845
846
847    int dbgReusedAll;
848    int dbgReusedNodeset;
849    int dbgReusedString;
850    int dbgReusedBool;
851    int dbgReusedNumber;
852    int dbgReusedPoint;
853    int dbgReusedRange;
854    int dbgReusedLocset;
855    int dbgReusedUsers;
856    int dbgReusedXSLTTree;
857    int dbgReusedUndefined;
858
859#endif
860};
861
862/************************************************************************
863 *									*
864 *		Debugging related functions				*
865 *									*
866 ************************************************************************/
867
868#define STRANGE							\
869    xmlGenericError(xmlGenericErrorContext,				\
870	    "Internal error at %s:%d\n",				\
871            __FILE__, __LINE__);
872
873#ifdef LIBXML_DEBUG_ENABLED
874static void
875xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
876    int i;
877    char shift[100];
878
879    for (i = 0;((i < depth) && (i < 25));i++)
880        shift[2 * i] = shift[2 * i + 1] = ' ';
881    shift[2 * i] = shift[2 * i + 1] = 0;
882    if (cur == NULL) {
883	fprintf(output, "%s", shift);
884	fprintf(output, "Node is NULL !\n");
885	return;
886
887    }
888
889    if ((cur->type == XML_DOCUMENT_NODE) ||
890	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
891	fprintf(output, "%s", shift);
892	fprintf(output, " /\n");
893    } else if (cur->type == XML_ATTRIBUTE_NODE)
894	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
895    else
896	xmlDebugDumpOneNode(output, cur, depth);
897}
898static void
899xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
900    xmlNodePtr tmp;
901    int i;
902    char shift[100];
903
904    for (i = 0;((i < depth) && (i < 25));i++)
905        shift[2 * i] = shift[2 * i + 1] = ' ';
906    shift[2 * i] = shift[2 * i + 1] = 0;
907    if (cur == NULL) {
908	fprintf(output, "%s", shift);
909	fprintf(output, "Node is NULL !\n");
910	return;
911
912    }
913
914    while (cur != NULL) {
915	tmp = cur;
916	cur = cur->next;
917	xmlDebugDumpOneNode(output, tmp, depth);
918    }
919}
920
921static void
922xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
923    int i;
924    char shift[100];
925
926    for (i = 0;((i < depth) && (i < 25));i++)
927        shift[2 * i] = shift[2 * i + 1] = ' ';
928    shift[2 * i] = shift[2 * i + 1] = 0;
929
930    if (cur == NULL) {
931	fprintf(output, "%s", shift);
932	fprintf(output, "NodeSet is NULL !\n");
933	return;
934
935    }
936
937    if (cur != NULL) {
938	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
939	for (i = 0;i < cur->nodeNr;i++) {
940	    fprintf(output, "%s", shift);
941	    fprintf(output, "%d", i + 1);
942	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
943	}
944    }
945}
946
947static void
948xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
949    int i;
950    char shift[100];
951
952    for (i = 0;((i < depth) && (i < 25));i++)
953        shift[2 * i] = shift[2 * i + 1] = ' ';
954    shift[2 * i] = shift[2 * i + 1] = 0;
955
956    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
957	fprintf(output, "%s", shift);
958	fprintf(output, "Value Tree is NULL !\n");
959	return;
960
961    }
962
963    fprintf(output, "%s", shift);
964    fprintf(output, "%d", i + 1);
965    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
966}
967#if defined(LIBXML_XPTR_ENABLED)
968static void
969xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
970    int i;
971    char shift[100];
972
973    for (i = 0;((i < depth) && (i < 25));i++)
974        shift[2 * i] = shift[2 * i + 1] = ' ';
975    shift[2 * i] = shift[2 * i + 1] = 0;
976
977    if (cur == NULL) {
978	fprintf(output, "%s", shift);
979	fprintf(output, "LocationSet is NULL !\n");
980	return;
981
982    }
983
984    for (i = 0;i < cur->locNr;i++) {
985	fprintf(output, "%s", shift);
986        fprintf(output, "%d : ", i + 1);
987	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
988    }
989}
990#endif /* LIBXML_XPTR_ENABLED */
991
992/**
993 * xmlXPathDebugDumpObject:
994 * @output:  the FILE * to dump the output
995 * @cur:  the object to inspect
996 * @depth:  indentation level
997 *
998 * Dump the content of the object for debugging purposes
999 */
1000void
1001xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1002    int i;
1003    char shift[100];
1004
1005    if (output == NULL) return;
1006
1007    for (i = 0;((i < depth) && (i < 25));i++)
1008        shift[2 * i] = shift[2 * i + 1] = ' ';
1009    shift[2 * i] = shift[2 * i + 1] = 0;
1010
1011
1012    fprintf(output, "%s", shift);
1013
1014    if (cur == NULL) {
1015        fprintf(output, "Object is empty (NULL)\n");
1016	return;
1017    }
1018    switch(cur->type) {
1019        case XPATH_UNDEFINED:
1020	    fprintf(output, "Object is uninitialized\n");
1021	    break;
1022        case XPATH_NODESET:
1023	    fprintf(output, "Object is a Node Set :\n");
1024	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1025	    break;
1026	case XPATH_XSLT_TREE:
1027	    fprintf(output, "Object is an XSLT value tree :\n");
1028	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1029	    break;
1030        case XPATH_BOOLEAN:
1031	    fprintf(output, "Object is a Boolean : ");
1032	    if (cur->boolval) fprintf(output, "true\n");
1033	    else fprintf(output, "false\n");
1034	    break;
1035        case XPATH_NUMBER:
1036	    switch (xmlXPathIsInf(cur->floatval)) {
1037	    case 1:
1038		fprintf(output, "Object is a number : Infinity\n");
1039		break;
1040	    case -1:
1041		fprintf(output, "Object is a number : -Infinity\n");
1042		break;
1043	    default:
1044		if (xmlXPathIsNaN(cur->floatval)) {
1045		    fprintf(output, "Object is a number : NaN\n");
1046		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1047		    fprintf(output, "Object is a number : 0\n");
1048		} else {
1049		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1050		}
1051	    }
1052	    break;
1053        case XPATH_STRING:
1054	    fprintf(output, "Object is a string : ");
1055	    xmlDebugDumpString(output, cur->stringval);
1056	    fprintf(output, "\n");
1057	    break;
1058	case XPATH_POINT:
1059	    fprintf(output, "Object is a point : index %d in node", cur->index);
1060	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1061	    fprintf(output, "\n");
1062	    break;
1063	case XPATH_RANGE:
1064	    if ((cur->user2 == NULL) ||
1065		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1066		fprintf(output, "Object is a collapsed range :\n");
1067		fprintf(output, "%s", shift);
1068		if (cur->index >= 0)
1069		    fprintf(output, "index %d in ", cur->index);
1070		fprintf(output, "node\n");
1071		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1072			              depth + 1);
1073	    } else  {
1074		fprintf(output, "Object is a range :\n");
1075		fprintf(output, "%s", shift);
1076		fprintf(output, "From ");
1077		if (cur->index >= 0)
1078		    fprintf(output, "index %d in ", cur->index);
1079		fprintf(output, "node\n");
1080		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1081			              depth + 1);
1082		fprintf(output, "%s", shift);
1083		fprintf(output, "To ");
1084		if (cur->index2 >= 0)
1085		    fprintf(output, "index %d in ", cur->index2);
1086		fprintf(output, "node\n");
1087		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1088			              depth + 1);
1089		fprintf(output, "\n");
1090	    }
1091	    break;
1092	case XPATH_LOCATIONSET:
1093#if defined(LIBXML_XPTR_ENABLED)
1094	    fprintf(output, "Object is a Location Set:\n");
1095	    xmlXPathDebugDumpLocationSet(output,
1096		    (xmlLocationSetPtr) cur->user, depth);
1097#endif
1098	    break;
1099	case XPATH_USERS:
1100	    fprintf(output, "Object is user defined\n");
1101	    break;
1102    }
1103}
1104
1105static void
1106xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1107	                     xmlXPathStepOpPtr op, int depth) {
1108    int i;
1109    char shift[100];
1110
1111    for (i = 0;((i < depth) && (i < 25));i++)
1112        shift[2 * i] = shift[2 * i + 1] = ' ';
1113    shift[2 * i] = shift[2 * i + 1] = 0;
1114
1115    fprintf(output, "%s", shift);
1116    if (op == NULL) {
1117	fprintf(output, "Step is NULL\n");
1118	return;
1119    }
1120    switch (op->op) {
1121        case XPATH_OP_END:
1122	    fprintf(output, "END"); break;
1123        case XPATH_OP_AND:
1124	    fprintf(output, "AND"); break;
1125        case XPATH_OP_OR:
1126	    fprintf(output, "OR"); break;
1127        case XPATH_OP_EQUAL:
1128	     if (op->value)
1129		 fprintf(output, "EQUAL =");
1130	     else
1131		 fprintf(output, "EQUAL !=");
1132	     break;
1133        case XPATH_OP_CMP:
1134	     if (op->value)
1135		 fprintf(output, "CMP <");
1136	     else
1137		 fprintf(output, "CMP >");
1138	     if (!op->value2)
1139		 fprintf(output, "=");
1140	     break;
1141        case XPATH_OP_PLUS:
1142	     if (op->value == 0)
1143		 fprintf(output, "PLUS -");
1144	     else if (op->value == 1)
1145		 fprintf(output, "PLUS +");
1146	     else if (op->value == 2)
1147		 fprintf(output, "PLUS unary -");
1148	     else if (op->value == 3)
1149		 fprintf(output, "PLUS unary - -");
1150	     break;
1151        case XPATH_OP_MULT:
1152	     if (op->value == 0)
1153		 fprintf(output, "MULT *");
1154	     else if (op->value == 1)
1155		 fprintf(output, "MULT div");
1156	     else
1157		 fprintf(output, "MULT mod");
1158	     break;
1159        case XPATH_OP_UNION:
1160	     fprintf(output, "UNION"); break;
1161        case XPATH_OP_ROOT:
1162	     fprintf(output, "ROOT"); break;
1163        case XPATH_OP_NODE:
1164	     fprintf(output, "NODE"); break;
1165        case XPATH_OP_RESET:
1166	     fprintf(output, "RESET"); break;
1167        case XPATH_OP_SORT:
1168	     fprintf(output, "SORT"); break;
1169        case XPATH_OP_COLLECT: {
1170	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1171	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1172	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1173	    const xmlChar *prefix = op->value4;
1174	    const xmlChar *name = op->value5;
1175
1176	    fprintf(output, "COLLECT ");
1177	    switch (axis) {
1178		case AXIS_ANCESTOR:
1179		    fprintf(output, " 'ancestors' "); break;
1180		case AXIS_ANCESTOR_OR_SELF:
1181		    fprintf(output, " 'ancestors-or-self' "); break;
1182		case AXIS_ATTRIBUTE:
1183		    fprintf(output, " 'attributes' "); break;
1184		case AXIS_CHILD:
1185		    fprintf(output, " 'child' "); break;
1186		case AXIS_DESCENDANT:
1187		    fprintf(output, " 'descendant' "); break;
1188		case AXIS_DESCENDANT_OR_SELF:
1189		    fprintf(output, " 'descendant-or-self' "); break;
1190		case AXIS_FOLLOWING:
1191		    fprintf(output, " 'following' "); break;
1192		case AXIS_FOLLOWING_SIBLING:
1193		    fprintf(output, " 'following-siblings' "); break;
1194		case AXIS_NAMESPACE:
1195		    fprintf(output, " 'namespace' "); break;
1196		case AXIS_PARENT:
1197		    fprintf(output, " 'parent' "); break;
1198		case AXIS_PRECEDING:
1199		    fprintf(output, " 'preceding' "); break;
1200		case AXIS_PRECEDING_SIBLING:
1201		    fprintf(output, " 'preceding-sibling' "); break;
1202		case AXIS_SELF:
1203		    fprintf(output, " 'self' "); break;
1204	    }
1205	    switch (test) {
1206                case NODE_TEST_NONE:
1207		    fprintf(output, "'none' "); break;
1208                case NODE_TEST_TYPE:
1209		    fprintf(output, "'type' "); break;
1210                case NODE_TEST_PI:
1211		    fprintf(output, "'PI' "); break;
1212                case NODE_TEST_ALL:
1213		    fprintf(output, "'all' "); break;
1214                case NODE_TEST_NS:
1215		    fprintf(output, "'namespace' "); break;
1216                case NODE_TEST_NAME:
1217		    fprintf(output, "'name' "); break;
1218	    }
1219	    switch (type) {
1220                case NODE_TYPE_NODE:
1221		    fprintf(output, "'node' "); break;
1222                case NODE_TYPE_COMMENT:
1223		    fprintf(output, "'comment' "); break;
1224                case NODE_TYPE_TEXT:
1225		    fprintf(output, "'text' "); break;
1226                case NODE_TYPE_PI:
1227		    fprintf(output, "'PI' "); break;
1228	    }
1229	    if (prefix != NULL)
1230		fprintf(output, "%s:", prefix);
1231	    if (name != NULL)
1232		fprintf(output, "%s", (const char *) name);
1233	    break;
1234
1235        }
1236	case XPATH_OP_VALUE: {
1237	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1238
1239	    fprintf(output, "ELEM ");
1240	    xmlXPathDebugDumpObject(output, object, 0);
1241	    goto finish;
1242	}
1243	case XPATH_OP_VARIABLE: {
1244	    const xmlChar *prefix = op->value5;
1245	    const xmlChar *name = op->value4;
1246
1247	    if (prefix != NULL)
1248		fprintf(output, "VARIABLE %s:%s", prefix, name);
1249	    else
1250		fprintf(output, "VARIABLE %s", name);
1251	    break;
1252	}
1253	case XPATH_OP_FUNCTION: {
1254	    int nbargs = op->value;
1255	    const xmlChar *prefix = op->value5;
1256	    const xmlChar *name = op->value4;
1257
1258	    if (prefix != NULL)
1259		fprintf(output, "FUNCTION %s:%s(%d args)",
1260			prefix, name, nbargs);
1261	    else
1262		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1263	    break;
1264	}
1265        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1266        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1267        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1268#ifdef LIBXML_XPTR_ENABLED
1269        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1270#endif
1271	default:
1272        fprintf(output, "UNKNOWN %d\n", op->op); return;
1273    }
1274    fprintf(output, "\n");
1275finish:
1276    if (op->ch1 >= 0)
1277	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1278    if (op->ch2 >= 0)
1279	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1280}
1281
1282/**
1283 * xmlXPathDebugDumpCompExpr:
1284 * @output:  the FILE * for the output
1285 * @comp:  the precompiled XPath expression
1286 * @depth:  the indentation level.
1287 *
1288 * Dumps the tree of the compiled XPath expression.
1289 */
1290void
1291xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1292	                  int depth) {
1293    int i;
1294    char shift[100];
1295
1296    if ((output == NULL) || (comp == NULL)) return;
1297
1298    for (i = 0;((i < depth) && (i < 25));i++)
1299        shift[2 * i] = shift[2 * i + 1] = ' ';
1300    shift[2 * i] = shift[2 * i + 1] = 0;
1301
1302    fprintf(output, "%s", shift);
1303
1304    fprintf(output, "Compiled Expression : %d elements\n",
1305	    comp->nbStep);
1306    i = comp->last;
1307    xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1308}
1309
1310#ifdef XP_DEBUG_OBJ_USAGE
1311
1312/*
1313* XPath object usage related debugging variables.
1314*/
1315static int xmlXPathDebugObjCounterUndefined = 0;
1316static int xmlXPathDebugObjCounterNodeset = 0;
1317static int xmlXPathDebugObjCounterBool = 0;
1318static int xmlXPathDebugObjCounterNumber = 0;
1319static int xmlXPathDebugObjCounterString = 0;
1320static int xmlXPathDebugObjCounterPoint = 0;
1321static int xmlXPathDebugObjCounterRange = 0;
1322static int xmlXPathDebugObjCounterLocset = 0;
1323static int xmlXPathDebugObjCounterUsers = 0;
1324static int xmlXPathDebugObjCounterXSLTTree = 0;
1325static int xmlXPathDebugObjCounterAll = 0;
1326
1327static int xmlXPathDebugObjTotalUndefined = 0;
1328static int xmlXPathDebugObjTotalNodeset = 0;
1329static int xmlXPathDebugObjTotalBool = 0;
1330static int xmlXPathDebugObjTotalNumber = 0;
1331static int xmlXPathDebugObjTotalString = 0;
1332static int xmlXPathDebugObjTotalPoint = 0;
1333static int xmlXPathDebugObjTotalRange = 0;
1334static int xmlXPathDebugObjTotalLocset = 0;
1335static int xmlXPathDebugObjTotalUsers = 0;
1336static int xmlXPathDebugObjTotalXSLTTree = 0;
1337static int xmlXPathDebugObjTotalAll = 0;
1338
1339static int xmlXPathDebugObjMaxUndefined = 0;
1340static int xmlXPathDebugObjMaxNodeset = 0;
1341static int xmlXPathDebugObjMaxBool = 0;
1342static int xmlXPathDebugObjMaxNumber = 0;
1343static int xmlXPathDebugObjMaxString = 0;
1344static int xmlXPathDebugObjMaxPoint = 0;
1345static int xmlXPathDebugObjMaxRange = 0;
1346static int xmlXPathDebugObjMaxLocset = 0;
1347static int xmlXPathDebugObjMaxUsers = 0;
1348static int xmlXPathDebugObjMaxXSLTTree = 0;
1349static int xmlXPathDebugObjMaxAll = 0;
1350
1351/* REVISIT TODO: Make this static when committing */
1352static void
1353xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1354{
1355    if (ctxt != NULL) {
1356	if (ctxt->cache != NULL) {
1357	    xmlXPathContextCachePtr cache =
1358		(xmlXPathContextCachePtr) ctxt->cache;
1359
1360	    cache->dbgCachedAll = 0;
1361	    cache->dbgCachedNodeset = 0;
1362	    cache->dbgCachedString = 0;
1363	    cache->dbgCachedBool = 0;
1364	    cache->dbgCachedNumber = 0;
1365	    cache->dbgCachedPoint = 0;
1366	    cache->dbgCachedRange = 0;
1367	    cache->dbgCachedLocset = 0;
1368	    cache->dbgCachedUsers = 0;
1369	    cache->dbgCachedXSLTTree = 0;
1370	    cache->dbgCachedUndefined = 0;
1371
1372	    cache->dbgReusedAll = 0;
1373	    cache->dbgReusedNodeset = 0;
1374	    cache->dbgReusedString = 0;
1375	    cache->dbgReusedBool = 0;
1376	    cache->dbgReusedNumber = 0;
1377	    cache->dbgReusedPoint = 0;
1378	    cache->dbgReusedRange = 0;
1379	    cache->dbgReusedLocset = 0;
1380	    cache->dbgReusedUsers = 0;
1381	    cache->dbgReusedXSLTTree = 0;
1382	    cache->dbgReusedUndefined = 0;
1383	}
1384    }
1385
1386    xmlXPathDebugObjCounterUndefined = 0;
1387    xmlXPathDebugObjCounterNodeset = 0;
1388    xmlXPathDebugObjCounterBool = 0;
1389    xmlXPathDebugObjCounterNumber = 0;
1390    xmlXPathDebugObjCounterString = 0;
1391    xmlXPathDebugObjCounterPoint = 0;
1392    xmlXPathDebugObjCounterRange = 0;
1393    xmlXPathDebugObjCounterLocset = 0;
1394    xmlXPathDebugObjCounterUsers = 0;
1395    xmlXPathDebugObjCounterXSLTTree = 0;
1396    xmlXPathDebugObjCounterAll = 0;
1397
1398    xmlXPathDebugObjTotalUndefined = 0;
1399    xmlXPathDebugObjTotalNodeset = 0;
1400    xmlXPathDebugObjTotalBool = 0;
1401    xmlXPathDebugObjTotalNumber = 0;
1402    xmlXPathDebugObjTotalString = 0;
1403    xmlXPathDebugObjTotalPoint = 0;
1404    xmlXPathDebugObjTotalRange = 0;
1405    xmlXPathDebugObjTotalLocset = 0;
1406    xmlXPathDebugObjTotalUsers = 0;
1407    xmlXPathDebugObjTotalXSLTTree = 0;
1408    xmlXPathDebugObjTotalAll = 0;
1409
1410    xmlXPathDebugObjMaxUndefined = 0;
1411    xmlXPathDebugObjMaxNodeset = 0;
1412    xmlXPathDebugObjMaxBool = 0;
1413    xmlXPathDebugObjMaxNumber = 0;
1414    xmlXPathDebugObjMaxString = 0;
1415    xmlXPathDebugObjMaxPoint = 0;
1416    xmlXPathDebugObjMaxRange = 0;
1417    xmlXPathDebugObjMaxLocset = 0;
1418    xmlXPathDebugObjMaxUsers = 0;
1419    xmlXPathDebugObjMaxXSLTTree = 0;
1420    xmlXPathDebugObjMaxAll = 0;
1421
1422}
1423
1424static void
1425xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1426			      xmlXPathObjectType objType)
1427{
1428    int isCached = 0;
1429
1430    if (ctxt != NULL) {
1431	if (ctxt->cache != NULL) {
1432	    xmlXPathContextCachePtr cache =
1433		(xmlXPathContextCachePtr) ctxt->cache;
1434
1435	    isCached = 1;
1436
1437	    cache->dbgReusedAll++;
1438	    switch (objType) {
1439		case XPATH_UNDEFINED:
1440		    cache->dbgReusedUndefined++;
1441		    break;
1442		case XPATH_NODESET:
1443		    cache->dbgReusedNodeset++;
1444		    break;
1445		case XPATH_BOOLEAN:
1446		    cache->dbgReusedBool++;
1447		    break;
1448		case XPATH_NUMBER:
1449		    cache->dbgReusedNumber++;
1450		    break;
1451		case XPATH_STRING:
1452		    cache->dbgReusedString++;
1453		    break;
1454		case XPATH_POINT:
1455		    cache->dbgReusedPoint++;
1456		    break;
1457		case XPATH_RANGE:
1458		    cache->dbgReusedRange++;
1459		    break;
1460		case XPATH_LOCATIONSET:
1461		    cache->dbgReusedLocset++;
1462		    break;
1463		case XPATH_USERS:
1464		    cache->dbgReusedUsers++;
1465		    break;
1466		case XPATH_XSLT_TREE:
1467		    cache->dbgReusedXSLTTree++;
1468		    break;
1469		default:
1470		    break;
1471	    }
1472	}
1473    }
1474
1475    switch (objType) {
1476	case XPATH_UNDEFINED:
1477	    if (! isCached)
1478		xmlXPathDebugObjTotalUndefined++;
1479	    xmlXPathDebugObjCounterUndefined++;
1480	    if (xmlXPathDebugObjCounterUndefined >
1481		xmlXPathDebugObjMaxUndefined)
1482		xmlXPathDebugObjMaxUndefined =
1483		    xmlXPathDebugObjCounterUndefined;
1484	    break;
1485	case XPATH_NODESET:
1486	    if (! isCached)
1487		xmlXPathDebugObjTotalNodeset++;
1488	    xmlXPathDebugObjCounterNodeset++;
1489	    if (xmlXPathDebugObjCounterNodeset >
1490		xmlXPathDebugObjMaxNodeset)
1491		xmlXPathDebugObjMaxNodeset =
1492		    xmlXPathDebugObjCounterNodeset;
1493	    break;
1494	case XPATH_BOOLEAN:
1495	    if (! isCached)
1496		xmlXPathDebugObjTotalBool++;
1497	    xmlXPathDebugObjCounterBool++;
1498	    if (xmlXPathDebugObjCounterBool >
1499		xmlXPathDebugObjMaxBool)
1500		xmlXPathDebugObjMaxBool =
1501		    xmlXPathDebugObjCounterBool;
1502	    break;
1503	case XPATH_NUMBER:
1504	    if (! isCached)
1505		xmlXPathDebugObjTotalNumber++;
1506	    xmlXPathDebugObjCounterNumber++;
1507	    if (xmlXPathDebugObjCounterNumber >
1508		xmlXPathDebugObjMaxNumber)
1509		xmlXPathDebugObjMaxNumber =
1510		    xmlXPathDebugObjCounterNumber;
1511	    break;
1512	case XPATH_STRING:
1513	    if (! isCached)
1514		xmlXPathDebugObjTotalString++;
1515	    xmlXPathDebugObjCounterString++;
1516	    if (xmlXPathDebugObjCounterString >
1517		xmlXPathDebugObjMaxString)
1518		xmlXPathDebugObjMaxString =
1519		    xmlXPathDebugObjCounterString;
1520	    break;
1521	case XPATH_POINT:
1522	    if (! isCached)
1523		xmlXPathDebugObjTotalPoint++;
1524	    xmlXPathDebugObjCounterPoint++;
1525	    if (xmlXPathDebugObjCounterPoint >
1526		xmlXPathDebugObjMaxPoint)
1527		xmlXPathDebugObjMaxPoint =
1528		    xmlXPathDebugObjCounterPoint;
1529	    break;
1530	case XPATH_RANGE:
1531	    if (! isCached)
1532		xmlXPathDebugObjTotalRange++;
1533	    xmlXPathDebugObjCounterRange++;
1534	    if (xmlXPathDebugObjCounterRange >
1535		xmlXPathDebugObjMaxRange)
1536		xmlXPathDebugObjMaxRange =
1537		    xmlXPathDebugObjCounterRange;
1538	    break;
1539	case XPATH_LOCATIONSET:
1540	    if (! isCached)
1541		xmlXPathDebugObjTotalLocset++;
1542	    xmlXPathDebugObjCounterLocset++;
1543	    if (xmlXPathDebugObjCounterLocset >
1544		xmlXPathDebugObjMaxLocset)
1545		xmlXPathDebugObjMaxLocset =
1546		    xmlXPathDebugObjCounterLocset;
1547	    break;
1548	case XPATH_USERS:
1549	    if (! isCached)
1550		xmlXPathDebugObjTotalUsers++;
1551	    xmlXPathDebugObjCounterUsers++;
1552	    if (xmlXPathDebugObjCounterUsers >
1553		xmlXPathDebugObjMaxUsers)
1554		xmlXPathDebugObjMaxUsers =
1555		    xmlXPathDebugObjCounterUsers;
1556	    break;
1557	case XPATH_XSLT_TREE:
1558	    if (! isCached)
1559		xmlXPathDebugObjTotalXSLTTree++;
1560	    xmlXPathDebugObjCounterXSLTTree++;
1561	    if (xmlXPathDebugObjCounterXSLTTree >
1562		xmlXPathDebugObjMaxXSLTTree)
1563		xmlXPathDebugObjMaxXSLTTree =
1564		    xmlXPathDebugObjCounterXSLTTree;
1565	    break;
1566	default:
1567	    break;
1568    }
1569    if (! isCached)
1570	xmlXPathDebugObjTotalAll++;
1571    xmlXPathDebugObjCounterAll++;
1572    if (xmlXPathDebugObjCounterAll >
1573	xmlXPathDebugObjMaxAll)
1574	xmlXPathDebugObjMaxAll =
1575	    xmlXPathDebugObjCounterAll;
1576}
1577
1578static void
1579xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1580			      xmlXPathObjectType objType)
1581{
1582    int isCached = 0;
1583
1584    if (ctxt != NULL) {
1585	if (ctxt->cache != NULL) {
1586	    xmlXPathContextCachePtr cache =
1587		(xmlXPathContextCachePtr) ctxt->cache;
1588
1589	    isCached = 1;
1590
1591	    cache->dbgCachedAll++;
1592	    switch (objType) {
1593		case XPATH_UNDEFINED:
1594		    cache->dbgCachedUndefined++;
1595		    break;
1596		case XPATH_NODESET:
1597		    cache->dbgCachedNodeset++;
1598		    break;
1599		case XPATH_BOOLEAN:
1600		    cache->dbgCachedBool++;
1601		    break;
1602		case XPATH_NUMBER:
1603		    cache->dbgCachedNumber++;
1604		    break;
1605		case XPATH_STRING:
1606		    cache->dbgCachedString++;
1607		    break;
1608		case XPATH_POINT:
1609		    cache->dbgCachedPoint++;
1610		    break;
1611		case XPATH_RANGE:
1612		    cache->dbgCachedRange++;
1613		    break;
1614		case XPATH_LOCATIONSET:
1615		    cache->dbgCachedLocset++;
1616		    break;
1617		case XPATH_USERS:
1618		    cache->dbgCachedUsers++;
1619		    break;
1620		case XPATH_XSLT_TREE:
1621		    cache->dbgCachedXSLTTree++;
1622		    break;
1623		default:
1624		    break;
1625	    }
1626
1627	}
1628    }
1629    switch (objType) {
1630	case XPATH_UNDEFINED:
1631	    xmlXPathDebugObjCounterUndefined--;
1632	    break;
1633	case XPATH_NODESET:
1634	    xmlXPathDebugObjCounterNodeset--;
1635	    break;
1636	case XPATH_BOOLEAN:
1637	    xmlXPathDebugObjCounterBool--;
1638	    break;
1639	case XPATH_NUMBER:
1640	    xmlXPathDebugObjCounterNumber--;
1641	    break;
1642	case XPATH_STRING:
1643	    xmlXPathDebugObjCounterString--;
1644	    break;
1645	case XPATH_POINT:
1646	    xmlXPathDebugObjCounterPoint--;
1647	    break;
1648	case XPATH_RANGE:
1649	    xmlXPathDebugObjCounterRange--;
1650	    break;
1651	case XPATH_LOCATIONSET:
1652	    xmlXPathDebugObjCounterLocset--;
1653	    break;
1654	case XPATH_USERS:
1655	    xmlXPathDebugObjCounterUsers--;
1656	    break;
1657	case XPATH_XSLT_TREE:
1658	    xmlXPathDebugObjCounterXSLTTree--;
1659	    break;
1660	default:
1661	    break;
1662    }
1663    xmlXPathDebugObjCounterAll--;
1664}
1665
1666/* REVISIT TODO: Make this static when committing */
1667static void
1668xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1669{
1670    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1671	reqXSLTTree, reqUndefined;
1672    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1673	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1674    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1675	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1676    int leftObjs = xmlXPathDebugObjCounterAll;
1677
1678    reqAll = xmlXPathDebugObjTotalAll;
1679    reqNodeset = xmlXPathDebugObjTotalNodeset;
1680    reqString = xmlXPathDebugObjTotalString;
1681    reqBool = xmlXPathDebugObjTotalBool;
1682    reqNumber = xmlXPathDebugObjTotalNumber;
1683    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1684    reqUndefined = xmlXPathDebugObjTotalUndefined;
1685
1686    printf("# XPath object usage:\n");
1687
1688    if (ctxt != NULL) {
1689	if (ctxt->cache != NULL) {
1690	    xmlXPathContextCachePtr cache =
1691		(xmlXPathContextCachePtr) ctxt->cache;
1692
1693	    reAll = cache->dbgReusedAll;
1694	    reqAll += reAll;
1695	    reNodeset = cache->dbgReusedNodeset;
1696	    reqNodeset += reNodeset;
1697	    reString = cache->dbgReusedString;
1698	    reqString += reString;
1699	    reBool = cache->dbgReusedBool;
1700	    reqBool += reBool;
1701	    reNumber = cache->dbgReusedNumber;
1702	    reqNumber += reNumber;
1703	    reXSLTTree = cache->dbgReusedXSLTTree;
1704	    reqXSLTTree += reXSLTTree;
1705	    reUndefined = cache->dbgReusedUndefined;
1706	    reqUndefined += reUndefined;
1707
1708	    caAll = cache->dbgCachedAll;
1709	    caBool = cache->dbgCachedBool;
1710	    caNodeset = cache->dbgCachedNodeset;
1711	    caString = cache->dbgCachedString;
1712	    caNumber = cache->dbgCachedNumber;
1713	    caXSLTTree = cache->dbgCachedXSLTTree;
1714	    caUndefined = cache->dbgCachedUndefined;
1715
1716	    if (cache->nodesetObjs)
1717		leftObjs -= cache->nodesetObjs->number;
1718	    if (cache->stringObjs)
1719		leftObjs -= cache->stringObjs->number;
1720	    if (cache->booleanObjs)
1721		leftObjs -= cache->booleanObjs->number;
1722	    if (cache->numberObjs)
1723		leftObjs -= cache->numberObjs->number;
1724	    if (cache->miscObjs)
1725		leftObjs -= cache->miscObjs->number;
1726	}
1727    }
1728
1729    printf("# all\n");
1730    printf("#   total  : %d\n", reqAll);
1731    printf("#   left  : %d\n", leftObjs);
1732    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
1733    printf("#   reused : %d\n", reAll);
1734    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
1735
1736    printf("# node-sets\n");
1737    printf("#   total  : %d\n", reqNodeset);
1738    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
1739    printf("#   reused : %d\n", reNodeset);
1740    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
1741
1742    printf("# strings\n");
1743    printf("#   total  : %d\n", reqString);
1744    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
1745    printf("#   reused : %d\n", reString);
1746    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
1747
1748    printf("# booleans\n");
1749    printf("#   total  : %d\n", reqBool);
1750    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
1751    printf("#   reused : %d\n", reBool);
1752    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
1753
1754    printf("# numbers\n");
1755    printf("#   total  : %d\n", reqNumber);
1756    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
1757    printf("#   reused : %d\n", reNumber);
1758    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
1759
1760    printf("# XSLT result tree fragments\n");
1761    printf("#   total  : %d\n", reqXSLTTree);
1762    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1763    printf("#   reused : %d\n", reXSLTTree);
1764    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
1765
1766    printf("# undefined\n");
1767    printf("#   total  : %d\n", reqUndefined);
1768    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
1769    printf("#   reused : %d\n", reUndefined);
1770    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
1771
1772}
1773
1774#endif /* XP_DEBUG_OBJ_USAGE */
1775
1776#endif /* LIBXML_DEBUG_ENABLED */
1777
1778/************************************************************************
1779 *									*
1780 *			XPath object caching				*
1781 *									*
1782 ************************************************************************/
1783
1784/**
1785 * xmlXPathNewCache:
1786 *
1787 * Create a new object cache
1788 *
1789 * Returns the xmlXPathCache just allocated.
1790 */
1791static xmlXPathContextCachePtr
1792xmlXPathNewCache(void)
1793{
1794    xmlXPathContextCachePtr ret;
1795
1796    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1797    if (ret == NULL) {
1798        xmlXPathErrMemory(NULL, "creating object cache\n");
1799	return(NULL);
1800    }
1801    memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
1802    ret->maxNodeset = 100;
1803    ret->maxString = 100;
1804    ret->maxBoolean = 100;
1805    ret->maxNumber = 100;
1806    ret->maxMisc = 100;
1807    return(ret);
1808}
1809
1810static void
1811xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1812{
1813    int i;
1814    xmlXPathObjectPtr obj;
1815
1816    if (list == NULL)
1817	return;
1818
1819    for (i = 0; i < list->number; i++) {
1820	obj = list->items[i];
1821	/*
1822	* Note that it is already assured that we don't need to
1823	* look out for namespace nodes in the node-set.
1824	*/
1825	if (obj->nodesetval != NULL) {
1826	    if (obj->nodesetval->nodeTab != NULL)
1827		xmlFree(obj->nodesetval->nodeTab);
1828	    xmlFree(obj->nodesetval);
1829	}
1830	xmlFree(obj);
1831#ifdef XP_DEBUG_OBJ_USAGE
1832	xmlXPathDebugObjCounterAll--;
1833#endif
1834    }
1835    xmlPointerListFree(list);
1836}
1837
1838static void
1839xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1840{
1841    if (cache == NULL)
1842	return;
1843    if (cache->nodesetObjs)
1844	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1845    if (cache->stringObjs)
1846	xmlXPathCacheFreeObjectList(cache->stringObjs);
1847    if (cache->booleanObjs)
1848	xmlXPathCacheFreeObjectList(cache->booleanObjs);
1849    if (cache->numberObjs)
1850	xmlXPathCacheFreeObjectList(cache->numberObjs);
1851    if (cache->miscObjs)
1852	xmlXPathCacheFreeObjectList(cache->miscObjs);
1853    xmlFree(cache);
1854}
1855
1856/**
1857 * xmlXPathContextSetCache:
1858 *
1859 * @ctxt:  the XPath context
1860 * @active: enables/disables (creates/frees) the cache
1861 * @value: a value with semantics dependant on @options
1862 * @options: options (currently only the value 0 is used)
1863 *
1864 * Creates/frees an object cache on the XPath context.
1865 * If activates XPath objects (xmlXPathObject) will be cached internally
1866 * to be reused.
1867 * @options:
1868 *   0: This will set the XPath object caching:
1869 *      @value:
1870 *        This will set the maximum number of XPath objects
1871 *        to be cached per slot
1872 *        There are 5 slots for: node-set, string, number, boolean, and
1873 *        misc objects. Use <0 for the default number (100).
1874 *   Other values for @options have currently no effect.
1875 *
1876 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1877 */
1878int
1879xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1880			int active,
1881			int value,
1882			int options)
1883{
1884    if (ctxt == NULL)
1885	return(-1);
1886    if (active) {
1887	xmlXPathContextCachePtr cache;
1888
1889	if (ctxt->cache == NULL) {
1890	    ctxt->cache = xmlXPathNewCache();
1891	    if (ctxt->cache == NULL)
1892		return(-1);
1893	}
1894	cache = (xmlXPathContextCachePtr) ctxt->cache;
1895	if (options == 0) {
1896	    if (value < 0)
1897		value = 100;
1898	    cache->maxNodeset = value;
1899	    cache->maxString = value;
1900	    cache->maxNumber = value;
1901	    cache->maxBoolean = value;
1902	    cache->maxMisc = value;
1903	}
1904    } else if (ctxt->cache != NULL) {
1905	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1906	ctxt->cache = NULL;
1907    }
1908    return(0);
1909}
1910
1911/**
1912 * xmlXPathCacheWrapNodeSet:
1913 * @ctxt: the XPath context
1914 * @val:  the NodePtr value
1915 *
1916 * This is the cached version of xmlXPathWrapNodeSet().
1917 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1918 *
1919 * Returns the created or reused object.
1920 */
1921static xmlXPathObjectPtr
1922xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1923{
1924    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1925	xmlXPathContextCachePtr cache =
1926	    (xmlXPathContextCachePtr) ctxt->cache;
1927
1928	if ((cache->miscObjs != NULL) &&
1929	    (cache->miscObjs->number != 0))
1930	{
1931	    xmlXPathObjectPtr ret;
1932
1933	    ret = (xmlXPathObjectPtr)
1934		cache->miscObjs->items[--cache->miscObjs->number];
1935	    ret->type = XPATH_NODESET;
1936	    ret->nodesetval = val;
1937#ifdef XP_DEBUG_OBJ_USAGE
1938	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1939#endif
1940	    return(ret);
1941	}
1942    }
1943
1944    return(xmlXPathWrapNodeSet(val));
1945
1946}
1947
1948/**
1949 * xmlXPathCacheWrapString:
1950 * @ctxt: the XPath context
1951 * @val:  the xmlChar * value
1952 *
1953 * This is the cached version of xmlXPathWrapString().
1954 * Wraps the @val string into an XPath object.
1955 *
1956 * Returns the created or reused object.
1957 */
1958static xmlXPathObjectPtr
1959xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1960{
1961    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1962	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1963
1964	if ((cache->stringObjs != NULL) &&
1965	    (cache->stringObjs->number != 0))
1966	{
1967
1968	    xmlXPathObjectPtr ret;
1969
1970	    ret = (xmlXPathObjectPtr)
1971		cache->stringObjs->items[--cache->stringObjs->number];
1972	    ret->type = XPATH_STRING;
1973	    ret->stringval = val;
1974#ifdef XP_DEBUG_OBJ_USAGE
1975	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1976#endif
1977	    return(ret);
1978	} else if ((cache->miscObjs != NULL) &&
1979	    (cache->miscObjs->number != 0))
1980	{
1981	    xmlXPathObjectPtr ret;
1982	    /*
1983	    * Fallback to misc-cache.
1984	    */
1985	    ret = (xmlXPathObjectPtr)
1986		cache->miscObjs->items[--cache->miscObjs->number];
1987
1988	    ret->type = XPATH_STRING;
1989	    ret->stringval = val;
1990#ifdef XP_DEBUG_OBJ_USAGE
1991	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1992#endif
1993	    return(ret);
1994	}
1995    }
1996    return(xmlXPathWrapString(val));
1997}
1998
1999/**
2000 * xmlXPathCacheNewNodeSet:
2001 * @ctxt: the XPath context
2002 * @val:  the NodePtr value
2003 *
2004 * This is the cached version of xmlXPathNewNodeSet().
2005 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2006 * it with the single Node @val
2007 *
2008 * Returns the created or reused object.
2009 */
2010static xmlXPathObjectPtr
2011xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2012{
2013    if ((ctxt != NULL) && (ctxt->cache)) {
2014	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2015
2016	if ((cache->nodesetObjs != NULL) &&
2017	    (cache->nodesetObjs->number != 0))
2018	{
2019	    xmlXPathObjectPtr ret;
2020	    /*
2021	    * Use the nodset-cache.
2022	    */
2023	    ret = (xmlXPathObjectPtr)
2024		cache->nodesetObjs->items[--cache->nodesetObjs->number];
2025	    ret->type = XPATH_NODESET;
2026	    ret->boolval = 0;
2027	    if (val) {
2028		if ((ret->nodesetval->nodeMax == 0) ||
2029		    (val->type == XML_NAMESPACE_DECL))
2030		{
2031		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2032		} else {
2033		    ret->nodesetval->nodeTab[0] = val;
2034		    ret->nodesetval->nodeNr = 1;
2035		}
2036	    }
2037#ifdef XP_DEBUG_OBJ_USAGE
2038	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2039#endif
2040	    return(ret);
2041	} else if ((cache->miscObjs != NULL) &&
2042	    (cache->miscObjs->number != 0))
2043	{
2044	    xmlXPathObjectPtr ret;
2045	    /*
2046	    * Fallback to misc-cache.
2047	    */
2048
2049	    ret = (xmlXPathObjectPtr)
2050		cache->miscObjs->items[--cache->miscObjs->number];
2051
2052	    ret->type = XPATH_NODESET;
2053	    ret->boolval = 0;
2054	    ret->nodesetval = xmlXPathNodeSetCreate(val);
2055#ifdef XP_DEBUG_OBJ_USAGE
2056	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2057#endif
2058	    return(ret);
2059	}
2060    }
2061    return(xmlXPathNewNodeSet(val));
2062}
2063
2064/**
2065 * xmlXPathCacheNewCString:
2066 * @ctxt: the XPath context
2067 * @val:  the char * value
2068 *
2069 * This is the cached version of xmlXPathNewCString().
2070 * Acquire an xmlXPathObjectPtr of type string and of value @val
2071 *
2072 * Returns the created or reused object.
2073 */
2074static xmlXPathObjectPtr
2075xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2076{
2077    if ((ctxt != NULL) && (ctxt->cache)) {
2078	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2079
2080	if ((cache->stringObjs != NULL) &&
2081	    (cache->stringObjs->number != 0))
2082	{
2083	    xmlXPathObjectPtr ret;
2084
2085	    ret = (xmlXPathObjectPtr)
2086		cache->stringObjs->items[--cache->stringObjs->number];
2087
2088	    ret->type = XPATH_STRING;
2089	    ret->stringval = xmlStrdup(BAD_CAST val);
2090#ifdef XP_DEBUG_OBJ_USAGE
2091	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2092#endif
2093	    return(ret);
2094	} else if ((cache->miscObjs != NULL) &&
2095	    (cache->miscObjs->number != 0))
2096	{
2097	    xmlXPathObjectPtr ret;
2098
2099	    ret = (xmlXPathObjectPtr)
2100		cache->miscObjs->items[--cache->miscObjs->number];
2101
2102	    ret->type = XPATH_STRING;
2103	    ret->stringval = xmlStrdup(BAD_CAST val);
2104#ifdef XP_DEBUG_OBJ_USAGE
2105	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2106#endif
2107	    return(ret);
2108	}
2109    }
2110    return(xmlXPathNewCString(val));
2111}
2112
2113/**
2114 * xmlXPathCacheNewString:
2115 * @ctxt: the XPath context
2116 * @val:  the xmlChar * value
2117 *
2118 * This is the cached version of xmlXPathNewString().
2119 * Acquire an xmlXPathObjectPtr of type string and of value @val
2120 *
2121 * Returns the created or reused object.
2122 */
2123static xmlXPathObjectPtr
2124xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2125{
2126    if ((ctxt != NULL) && (ctxt->cache)) {
2127	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2128
2129	if ((cache->stringObjs != NULL) &&
2130	    (cache->stringObjs->number != 0))
2131	{
2132	    xmlXPathObjectPtr ret;
2133
2134	    ret = (xmlXPathObjectPtr)
2135		cache->stringObjs->items[--cache->stringObjs->number];
2136	    ret->type = XPATH_STRING;
2137	    if (val != NULL)
2138		ret->stringval = xmlStrdup(val);
2139	    else
2140		ret->stringval = xmlStrdup((const xmlChar *)"");
2141#ifdef XP_DEBUG_OBJ_USAGE
2142	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2143#endif
2144	    return(ret);
2145	} else if ((cache->miscObjs != NULL) &&
2146	    (cache->miscObjs->number != 0))
2147	{
2148	    xmlXPathObjectPtr ret;
2149
2150	    ret = (xmlXPathObjectPtr)
2151		cache->miscObjs->items[--cache->miscObjs->number];
2152
2153	    ret->type = XPATH_STRING;
2154	    if (val != NULL)
2155		ret->stringval = xmlStrdup(val);
2156	    else
2157		ret->stringval = xmlStrdup((const xmlChar *)"");
2158#ifdef XP_DEBUG_OBJ_USAGE
2159	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2160#endif
2161	    return(ret);
2162	}
2163    }
2164    return(xmlXPathNewString(val));
2165}
2166
2167/**
2168 * xmlXPathCacheNewBoolean:
2169 * @ctxt: the XPath context
2170 * @val:  the boolean value
2171 *
2172 * This is the cached version of xmlXPathNewBoolean().
2173 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2174 *
2175 * Returns the created or reused object.
2176 */
2177static xmlXPathObjectPtr
2178xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2179{
2180    if ((ctxt != NULL) && (ctxt->cache)) {
2181	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2182
2183	if ((cache->booleanObjs != NULL) &&
2184	    (cache->booleanObjs->number != 0))
2185	{
2186	    xmlXPathObjectPtr ret;
2187
2188	    ret = (xmlXPathObjectPtr)
2189		cache->booleanObjs->items[--cache->booleanObjs->number];
2190	    ret->type = XPATH_BOOLEAN;
2191	    ret->boolval = (val != 0);
2192#ifdef XP_DEBUG_OBJ_USAGE
2193	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2194#endif
2195	    return(ret);
2196	} else if ((cache->miscObjs != NULL) &&
2197	    (cache->miscObjs->number != 0))
2198	{
2199	    xmlXPathObjectPtr ret;
2200
2201	    ret = (xmlXPathObjectPtr)
2202		cache->miscObjs->items[--cache->miscObjs->number];
2203
2204	    ret->type = XPATH_BOOLEAN;
2205	    ret->boolval = (val != 0);
2206#ifdef XP_DEBUG_OBJ_USAGE
2207	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2208#endif
2209	    return(ret);
2210	}
2211    }
2212    return(xmlXPathNewBoolean(val));
2213}
2214
2215/**
2216 * xmlXPathCacheNewFloat:
2217 * @ctxt: the XPath context
2218 * @val:  the double value
2219 *
2220 * This is the cached version of xmlXPathNewFloat().
2221 * Acquires an xmlXPathObjectPtr of type double and of value @val
2222 *
2223 * Returns the created or reused object.
2224 */
2225static xmlXPathObjectPtr
2226xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2227{
2228     if ((ctxt != NULL) && (ctxt->cache)) {
2229	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2230
2231	if ((cache->numberObjs != NULL) &&
2232	    (cache->numberObjs->number != 0))
2233	{
2234	    xmlXPathObjectPtr ret;
2235
2236	    ret = (xmlXPathObjectPtr)
2237		cache->numberObjs->items[--cache->numberObjs->number];
2238	    ret->type = XPATH_NUMBER;
2239	    ret->floatval = val;
2240#ifdef XP_DEBUG_OBJ_USAGE
2241	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2242#endif
2243	    return(ret);
2244	} else if ((cache->miscObjs != NULL) &&
2245	    (cache->miscObjs->number != 0))
2246	{
2247	    xmlXPathObjectPtr ret;
2248
2249	    ret = (xmlXPathObjectPtr)
2250		cache->miscObjs->items[--cache->miscObjs->number];
2251
2252	    ret->type = XPATH_NUMBER;
2253	    ret->floatval = val;
2254#ifdef XP_DEBUG_OBJ_USAGE
2255	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2256#endif
2257	    return(ret);
2258	}
2259    }
2260    return(xmlXPathNewFloat(val));
2261}
2262
2263/**
2264 * xmlXPathCacheConvertString:
2265 * @ctxt: the XPath context
2266 * @val:  an XPath object
2267 *
2268 * This is the cached version of xmlXPathConvertString().
2269 * Converts an existing object to its string() equivalent
2270 *
2271 * Returns a created or reused object, the old one is freed (cached)
2272 *         (or the operation is done directly on @val)
2273 */
2274
2275static xmlXPathObjectPtr
2276xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2277    xmlChar *res = NULL;
2278
2279    if (val == NULL)
2280	return(xmlXPathCacheNewCString(ctxt, ""));
2281
2282    switch (val->type) {
2283    case XPATH_UNDEFINED:
2284#ifdef DEBUG_EXPR
2285	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2286#endif
2287	break;
2288    case XPATH_NODESET:
2289    case XPATH_XSLT_TREE:
2290	res = xmlXPathCastNodeSetToString(val->nodesetval);
2291	break;
2292    case XPATH_STRING:
2293	return(val);
2294    case XPATH_BOOLEAN:
2295	res = xmlXPathCastBooleanToString(val->boolval);
2296	break;
2297    case XPATH_NUMBER:
2298	res = xmlXPathCastNumberToString(val->floatval);
2299	break;
2300    case XPATH_USERS:
2301    case XPATH_POINT:
2302    case XPATH_RANGE:
2303    case XPATH_LOCATIONSET:
2304	TODO;
2305	break;
2306    }
2307    xmlXPathReleaseObject(ctxt, val);
2308    if (res == NULL)
2309	return(xmlXPathCacheNewCString(ctxt, ""));
2310    return(xmlXPathCacheWrapString(ctxt, res));
2311}
2312
2313/**
2314 * xmlXPathCacheObjectCopy:
2315 * @ctxt: the XPath context
2316 * @val:  the original object
2317 *
2318 * This is the cached version of xmlXPathObjectCopy().
2319 * Acquire a copy of a given object
2320 *
2321 * Returns a created or reused created object.
2322 */
2323static xmlXPathObjectPtr
2324xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2325{
2326    if (val == NULL)
2327	return(NULL);
2328
2329    if (XP_HAS_CACHE(ctxt)) {
2330	switch (val->type) {
2331	    case XPATH_NODESET:
2332		return(xmlXPathCacheWrapNodeSet(ctxt,
2333		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2334	    case XPATH_STRING:
2335		return(xmlXPathCacheNewString(ctxt, val->stringval));
2336	    case XPATH_BOOLEAN:
2337		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2338	    case XPATH_NUMBER:
2339		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2340	    default:
2341		break;
2342	}
2343    }
2344    return(xmlXPathObjectCopy(val));
2345}
2346
2347/**
2348 * xmlXPathCacheConvertBoolean:
2349 * @ctxt: the XPath context
2350 * @val:  an XPath object
2351 *
2352 * This is the cached version of xmlXPathConvertBoolean().
2353 * Converts an existing object to its boolean() equivalent
2354 *
2355 * Returns a created or reused object, the old one is freed (or the operation
2356 *         is done directly on @val)
2357 */
2358static xmlXPathObjectPtr
2359xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2360    xmlXPathObjectPtr ret;
2361
2362    if (val == NULL)
2363	return(xmlXPathCacheNewBoolean(ctxt, 0));
2364    if (val->type == XPATH_BOOLEAN)
2365	return(val);
2366    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2367    xmlXPathReleaseObject(ctxt, val);
2368    return(ret);
2369}
2370
2371/**
2372 * xmlXPathCacheConvertNumber:
2373 * @ctxt: the XPath context
2374 * @val:  an XPath object
2375 *
2376 * This is the cached version of xmlXPathConvertNumber().
2377 * Converts an existing object to its number() equivalent
2378 *
2379 * Returns a created or reused object, the old one is freed (or the operation
2380 *         is done directly on @val)
2381 */
2382static xmlXPathObjectPtr
2383xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2384    xmlXPathObjectPtr ret;
2385
2386    if (val == NULL)
2387	return(xmlXPathCacheNewFloat(ctxt, 0.0));
2388    if (val->type == XPATH_NUMBER)
2389	return(val);
2390    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2391    xmlXPathReleaseObject(ctxt, val);
2392    return(ret);
2393}
2394
2395/************************************************************************
2396 *									*
2397 *		Parser stacks related functions and macros		*
2398 *									*
2399 ************************************************************************/
2400
2401/**
2402 * xmlXPathSetFrame:
2403 * @ctxt: an XPath parser context
2404 *
2405 * Set the callee evaluation frame
2406 *
2407 * Returns the previous frame value to be restored once done
2408 */
2409static int
2410xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2411    int ret;
2412
2413    if (ctxt == NULL)
2414        return(0);
2415    ret = ctxt->valueFrame;
2416    ctxt->valueFrame = ctxt->valueNr;
2417    return(ret);
2418}
2419
2420/**
2421 * xmlXPathPopFrame:
2422 * @ctxt: an XPath parser context
2423 * @frame: the previous frame value
2424 *
2425 * Remove the callee evaluation frame
2426 */
2427static void
2428xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2429    if (ctxt == NULL)
2430        return;
2431    if (ctxt->valueNr < ctxt->valueFrame) {
2432        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2433    }
2434    ctxt->valueFrame = frame;
2435}
2436
2437/**
2438 * valuePop:
2439 * @ctxt: an XPath evaluation context
2440 *
2441 * Pops the top XPath object from the value stack
2442 *
2443 * Returns the XPath object just removed
2444 */
2445xmlXPathObjectPtr
2446valuePop(xmlXPathParserContextPtr ctxt)
2447{
2448    xmlXPathObjectPtr ret;
2449
2450    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2451        return (NULL);
2452
2453    if (ctxt->valueNr <= ctxt->valueFrame) {
2454        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2455        return (NULL);
2456    }
2457
2458    ctxt->valueNr--;
2459    if (ctxt->valueNr > 0)
2460        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2461    else
2462        ctxt->value = NULL;
2463    ret = ctxt->valueTab[ctxt->valueNr];
2464    ctxt->valueTab[ctxt->valueNr] = NULL;
2465    return (ret);
2466}
2467/**
2468 * valuePush:
2469 * @ctxt:  an XPath evaluation context
2470 * @value:  the XPath object
2471 *
2472 * Pushes a new XPath object on top of the value stack
2473 *
2474 * returns the number of items on the value stack
2475 */
2476int
2477valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2478{
2479    if ((ctxt == NULL) || (value == NULL)) return(-1);
2480    if (ctxt->valueNr >= ctxt->valueMax) {
2481        xmlXPathObjectPtr *tmp;
2482
2483        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2484                                             2 * ctxt->valueMax *
2485                                             sizeof(ctxt->valueTab[0]));
2486        if (tmp == NULL) {
2487            xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2488            ctxt->error = XPATH_MEMORY_ERROR;
2489            return (0);
2490        }
2491        ctxt->valueMax *= 2;
2492	ctxt->valueTab = tmp;
2493    }
2494    ctxt->valueTab[ctxt->valueNr] = value;
2495    ctxt->value = value;
2496    return (ctxt->valueNr++);
2497}
2498
2499/**
2500 * xmlXPathPopBoolean:
2501 * @ctxt:  an XPath parser context
2502 *
2503 * Pops a boolean from the stack, handling conversion if needed.
2504 * Check error with #xmlXPathCheckError.
2505 *
2506 * Returns the boolean
2507 */
2508int
2509xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2510    xmlXPathObjectPtr obj;
2511    int ret;
2512
2513    obj = valuePop(ctxt);
2514    if (obj == NULL) {
2515	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2516	return(0);
2517    }
2518    if (obj->type != XPATH_BOOLEAN)
2519	ret = xmlXPathCastToBoolean(obj);
2520    else
2521        ret = obj->boolval;
2522    xmlXPathReleaseObject(ctxt->context, obj);
2523    return(ret);
2524}
2525
2526/**
2527 * xmlXPathPopNumber:
2528 * @ctxt:  an XPath parser context
2529 *
2530 * Pops a number from the stack, handling conversion if needed.
2531 * Check error with #xmlXPathCheckError.
2532 *
2533 * Returns the number
2534 */
2535double
2536xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2537    xmlXPathObjectPtr obj;
2538    double ret;
2539
2540    obj = valuePop(ctxt);
2541    if (obj == NULL) {
2542	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2543	return(0);
2544    }
2545    if (obj->type != XPATH_NUMBER)
2546	ret = xmlXPathCastToNumber(obj);
2547    else
2548        ret = obj->floatval;
2549    xmlXPathReleaseObject(ctxt->context, obj);
2550    return(ret);
2551}
2552
2553/**
2554 * xmlXPathPopString:
2555 * @ctxt:  an XPath parser context
2556 *
2557 * Pops a string from the stack, handling conversion if needed.
2558 * Check error with #xmlXPathCheckError.
2559 *
2560 * Returns the string
2561 */
2562xmlChar *
2563xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2564    xmlXPathObjectPtr obj;
2565    xmlChar * ret;
2566
2567    obj = valuePop(ctxt);
2568    if (obj == NULL) {
2569	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2570	return(NULL);
2571    }
2572    ret = xmlXPathCastToString(obj);	/* this does required strdup */
2573    /* TODO: needs refactoring somewhere else */
2574    if (obj->stringval == ret)
2575	obj->stringval = NULL;
2576    xmlXPathReleaseObject(ctxt->context, obj);
2577    return(ret);
2578}
2579
2580/**
2581 * xmlXPathPopNodeSet:
2582 * @ctxt:  an XPath parser context
2583 *
2584 * Pops a node-set from the stack, handling conversion if needed.
2585 * Check error with #xmlXPathCheckError.
2586 *
2587 * Returns the node-set
2588 */
2589xmlNodeSetPtr
2590xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2591    xmlXPathObjectPtr obj;
2592    xmlNodeSetPtr ret;
2593
2594    if (ctxt == NULL) return(NULL);
2595    if (ctxt->value == NULL) {
2596	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2597	return(NULL);
2598    }
2599    if (!xmlXPathStackIsNodeSet(ctxt)) {
2600	xmlXPathSetTypeError(ctxt);
2601	return(NULL);
2602    }
2603    obj = valuePop(ctxt);
2604    ret = obj->nodesetval;
2605#if 0
2606    /* to fix memory leak of not clearing obj->user */
2607    if (obj->boolval && obj->user != NULL)
2608        xmlFreeNodeList((xmlNodePtr) obj->user);
2609#endif
2610    obj->nodesetval = NULL;
2611    xmlXPathReleaseObject(ctxt->context, obj);
2612    return(ret);
2613}
2614
2615/**
2616 * xmlXPathPopExternal:
2617 * @ctxt:  an XPath parser context
2618 *
2619 * Pops an external object from the stack, handling conversion if needed.
2620 * Check error with #xmlXPathCheckError.
2621 *
2622 * Returns the object
2623 */
2624void *
2625xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2626    xmlXPathObjectPtr obj;
2627    void * ret;
2628
2629    if ((ctxt == NULL) || (ctxt->value == NULL)) {
2630	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2631	return(NULL);
2632    }
2633    if (ctxt->value->type != XPATH_USERS) {
2634	xmlXPathSetTypeError(ctxt);
2635	return(NULL);
2636    }
2637    obj = valuePop(ctxt);
2638    ret = obj->user;
2639    obj->user = NULL;
2640    xmlXPathReleaseObject(ctxt->context, obj);
2641    return(ret);
2642}
2643
2644/*
2645 * Macros for accessing the content. Those should be used only by the parser,
2646 * and not exported.
2647 *
2648 * Dirty macros, i.e. one need to make assumption on the context to use them
2649 *
2650 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2651 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2652 *           in ISO-Latin or UTF-8.
2653 *           This should be used internally by the parser
2654 *           only to compare to ASCII values otherwise it would break when
2655 *           running with UTF-8 encoding.
2656 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2657 *           to compare on ASCII based substring.
2658 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2659 *           strings within the parser.
2660 *   CURRENT Returns the current char value, with the full decoding of
2661 *           UTF-8 if we are using this mode. It returns an int.
2662 *   NEXT    Skip to the next character, this does the proper decoding
2663 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2664 *           It returns the pointer to the current xmlChar.
2665 */
2666
2667#define CUR (*ctxt->cur)
2668#define SKIP(val) ctxt->cur += (val)
2669#define NXT(val) ctxt->cur[(val)]
2670#define CUR_PTR ctxt->cur
2671#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2672
2673#define COPY_BUF(l,b,i,v)                                              \
2674    if (l == 1) b[i++] = (xmlChar) v;                                  \
2675    else i += xmlCopyChar(l,&b[i],v)
2676
2677#define NEXTL(l)  ctxt->cur += l
2678
2679#define SKIP_BLANKS							\
2680    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2681
2682#define CURRENT (*ctxt->cur)
2683#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2684
2685
2686#ifndef DBL_DIG
2687#define DBL_DIG 16
2688#endif
2689#ifndef DBL_EPSILON
2690#define DBL_EPSILON 1E-9
2691#endif
2692
2693#define UPPER_DOUBLE 1E9
2694#define LOWER_DOUBLE 1E-5
2695#define	LOWER_DOUBLE_EXP 5
2696
2697#define INTEGER_DIGITS DBL_DIG
2698#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2699#define EXPONENT_DIGITS (3 + 2)
2700
2701/**
2702 * xmlXPathFormatNumber:
2703 * @number:     number to format
2704 * @buffer:     output buffer
2705 * @buffersize: size of output buffer
2706 *
2707 * Convert the number into a string representation.
2708 */
2709static void
2710xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2711{
2712    switch (xmlXPathIsInf(number)) {
2713    case 1:
2714	if (buffersize > (int)sizeof("Infinity"))
2715	    snprintf(buffer, buffersize, "Infinity");
2716	break;
2717    case -1:
2718	if (buffersize > (int)sizeof("-Infinity"))
2719	    snprintf(buffer, buffersize, "-Infinity");
2720	break;
2721    default:
2722	if (xmlXPathIsNaN(number)) {
2723	    if (buffersize > (int)sizeof("NaN"))
2724		snprintf(buffer, buffersize, "NaN");
2725	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
2726	    snprintf(buffer, buffersize, "0");
2727	} else if (number == ((int) number)) {
2728	    char work[30];
2729	    char *ptr, *cur;
2730	    int value = (int) number;
2731
2732            ptr = &buffer[0];
2733	    if (value == 0) {
2734		*ptr++ = '0';
2735	    } else {
2736		snprintf(work, 29, "%d", value);
2737		cur = &work[0];
2738		while ((*cur) && (ptr - buffer < buffersize)) {
2739		    *ptr++ = *cur++;
2740		}
2741	    }
2742	    if (ptr - buffer < buffersize) {
2743		*ptr = 0;
2744	    } else if (buffersize > 0) {
2745		ptr--;
2746		*ptr = 0;
2747	    }
2748	} else {
2749	    /*
2750	      For the dimension of work,
2751	          DBL_DIG is number of significant digits
2752		  EXPONENT is only needed for "scientific notation"
2753	          3 is sign, decimal point, and terminating zero
2754		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2755	      Note that this dimension is slightly (a few characters)
2756	      larger than actually necessary.
2757	    */
2758	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2759	    int integer_place, fraction_place;
2760	    char *ptr;
2761	    char *after_fraction;
2762	    double absolute_value;
2763	    int size;
2764
2765	    absolute_value = fabs(number);
2766
2767	    /*
2768	     * First choose format - scientific or regular floating point.
2769	     * In either case, result is in work, and after_fraction points
2770	     * just past the fractional part.
2771	    */
2772	    if ( ((absolute_value > UPPER_DOUBLE) ||
2773		  (absolute_value < LOWER_DOUBLE)) &&
2774		 (absolute_value != 0.0) ) {
2775		/* Use scientific notation */
2776		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2777		fraction_place = DBL_DIG - 1;
2778		size = snprintf(work, sizeof(work),"%*.*e",
2779			 integer_place, fraction_place, number);
2780		while ((size > 0) && (work[size] != 'e')) size--;
2781
2782	    }
2783	    else {
2784		/* Use regular notation */
2785		if (absolute_value > 0.0) {
2786		    integer_place = (int)log10(absolute_value);
2787		    if (integer_place > 0)
2788		        fraction_place = DBL_DIG - integer_place - 1;
2789		    else
2790		        fraction_place = DBL_DIG - integer_place;
2791		} else {
2792		    fraction_place = 1;
2793		}
2794		size = snprintf(work, sizeof(work), "%0.*f",
2795				fraction_place, number);
2796	    }
2797
2798	    /* Remove fractional trailing zeroes */
2799	    after_fraction = work + size;
2800	    ptr = after_fraction;
2801	    while (*(--ptr) == '0')
2802		;
2803	    if (*ptr != '.')
2804	        ptr++;
2805	    while ((*ptr++ = *after_fraction++) != 0);
2806
2807	    /* Finally copy result back to caller */
2808	    size = strlen(work) + 1;
2809	    if (size > buffersize && buffersize <= (int)sizeof(work)) {
2810		work[buffersize - 1] = 0;
2811		size = buffersize;
2812	    }
2813	    memmove(buffer, work, size);
2814	}
2815	break;
2816    }
2817}
2818
2819
2820/************************************************************************
2821 *									*
2822 *			Routines to handle NodeSets			*
2823 *									*
2824 ************************************************************************/
2825
2826/**
2827 * xmlXPathOrderDocElems:
2828 * @doc:  an input document
2829 *
2830 * Call this routine to speed up XPath computation on static documents.
2831 * This stamps all the element nodes with the document order
2832 * Like for line information, the order is kept in the element->content
2833 * field, the value stored is actually - the node number (starting at -1)
2834 * to be able to differentiate from line numbers.
2835 *
2836 * Returns the number of elements found in the document or -1 in case
2837 *    of error.
2838 */
2839long
2840xmlXPathOrderDocElems(xmlDocPtr doc) {
2841    long count = 0;
2842    xmlNodePtr cur;
2843
2844    if (doc == NULL)
2845	return(-1);
2846    cur = doc->children;
2847    while (cur != NULL) {
2848	if (cur->type == XML_ELEMENT_NODE) {
2849	    cur->content = (void *) (-(++count));
2850	    if (cur->children != NULL) {
2851		cur = cur->children;
2852		continue;
2853	    }
2854	}
2855	if (cur->next != NULL) {
2856	    cur = cur->next;
2857	    continue;
2858	}
2859	do {
2860	    cur = cur->parent;
2861	    if (cur == NULL)
2862		break;
2863	    if (cur == (xmlNodePtr) doc) {
2864		cur = NULL;
2865		break;
2866	    }
2867	    if (cur->next != NULL) {
2868		cur = cur->next;
2869		break;
2870	    }
2871	} while (cur != NULL);
2872    }
2873    return(count);
2874}
2875
2876/**
2877 * xmlXPathCmpNodes:
2878 * @node1:  the first node
2879 * @node2:  the second node
2880 *
2881 * Compare two nodes w.r.t document order
2882 *
2883 * Returns -2 in case of error 1 if first point < second point, 0 if
2884 *         it's the same node, -1 otherwise
2885 */
2886int
2887xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2888    int depth1, depth2;
2889    int attr1 = 0, attr2 = 0;
2890    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2891    xmlNodePtr cur, root;
2892
2893    if ((node1 == NULL) || (node2 == NULL))
2894	return(-2);
2895    /*
2896     * a couple of optimizations which will avoid computations in most cases
2897     */
2898    if (node1 == node2)		/* trivial case */
2899	return(0);
2900    if (node1->type == XML_ATTRIBUTE_NODE) {
2901	attr1 = 1;
2902	attrNode1 = node1;
2903	node1 = node1->parent;
2904    }
2905    if (node2->type == XML_ATTRIBUTE_NODE) {
2906	attr2 = 1;
2907	attrNode2 = node2;
2908	node2 = node2->parent;
2909    }
2910    if (node1 == node2) {
2911	if (attr1 == attr2) {
2912	    /* not required, but we keep attributes in order */
2913	    if (attr1 != 0) {
2914	        cur = attrNode2->prev;
2915		while (cur != NULL) {
2916		    if (cur == attrNode1)
2917		        return (1);
2918		    cur = cur->prev;
2919		}
2920		return (-1);
2921	    }
2922	    return(0);
2923	}
2924	if (attr2 == 1)
2925	    return(1);
2926	return(-1);
2927    }
2928    if ((node1->type == XML_NAMESPACE_DECL) ||
2929        (node2->type == XML_NAMESPACE_DECL))
2930	return(1);
2931    if (node1 == node2->prev)
2932	return(1);
2933    if (node1 == node2->next)
2934	return(-1);
2935
2936    /*
2937     * Speedup using document order if availble.
2938     */
2939    if ((node1->type == XML_ELEMENT_NODE) &&
2940	(node2->type == XML_ELEMENT_NODE) &&
2941	(0 > (long) node1->content) &&
2942	(0 > (long) node2->content) &&
2943	(node1->doc == node2->doc)) {
2944	long l1, l2;
2945
2946	l1 = -((long) node1->content);
2947	l2 = -((long) node2->content);
2948	if (l1 < l2)
2949	    return(1);
2950	if (l1 > l2)
2951	    return(-1);
2952    }
2953
2954    /*
2955     * compute depth to root
2956     */
2957    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2958	if (cur == node1)
2959	    return(1);
2960	depth2++;
2961    }
2962    root = cur;
2963    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2964	if (cur == node2)
2965	    return(-1);
2966	depth1++;
2967    }
2968    /*
2969     * Distinct document (or distinct entities :-( ) case.
2970     */
2971    if (root != cur) {
2972	return(-2);
2973    }
2974    /*
2975     * get the nearest common ancestor.
2976     */
2977    while (depth1 > depth2) {
2978	depth1--;
2979	node1 = node1->parent;
2980    }
2981    while (depth2 > depth1) {
2982	depth2--;
2983	node2 = node2->parent;
2984    }
2985    while (node1->parent != node2->parent) {
2986	node1 = node1->parent;
2987	node2 = node2->parent;
2988	/* should not happen but just in case ... */
2989	if ((node1 == NULL) || (node2 == NULL))
2990	    return(-2);
2991    }
2992    /*
2993     * Find who's first.
2994     */
2995    if (node1 == node2->prev)
2996	return(1);
2997    if (node1 == node2->next)
2998	return(-1);
2999    /*
3000     * Speedup using document order if availble.
3001     */
3002    if ((node1->type == XML_ELEMENT_NODE) &&
3003	(node2->type == XML_ELEMENT_NODE) &&
3004	(0 > (long) node1->content) &&
3005	(0 > (long) node2->content) &&
3006	(node1->doc == node2->doc)) {
3007	long l1, l2;
3008
3009	l1 = -((long) node1->content);
3010	l2 = -((long) node2->content);
3011	if (l1 < l2)
3012	    return(1);
3013	if (l1 > l2)
3014	    return(-1);
3015    }
3016
3017    for (cur = node1->next;cur != NULL;cur = cur->next)
3018	if (cur == node2)
3019	    return(1);
3020    return(-1); /* assume there is no sibling list corruption */
3021}
3022
3023#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3024/**
3025 * xmlXPathCmpNodesExt:
3026 * @node1:  the first node
3027 * @node2:  the second node
3028 *
3029 * Compare two nodes w.r.t document order.
3030 * This one is optimized for handling of non-element nodes.
3031 *
3032 * Returns -2 in case of error 1 if first point < second point, 0 if
3033 *         it's the same node, -1 otherwise
3034 */
3035static int
3036xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
3037    int depth1, depth2;
3038    int misc = 0, precedence1 = 0, precedence2 = 0;
3039    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
3040    xmlNodePtr cur, root;
3041    long l1, l2;
3042
3043    if ((node1 == NULL) || (node2 == NULL))
3044	return(-2);
3045
3046    if (node1 == node2)
3047	return(0);
3048
3049    /*
3050     * a couple of optimizations which will avoid computations in most cases
3051     */
3052    switch (node1->type) {
3053	case XML_ELEMENT_NODE:
3054	    if (node2->type == XML_ELEMENT_NODE) {
3055		if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3056		    (0 > (long) node2->content) &&
3057		    (node1->doc == node2->doc))
3058		{
3059		    l1 = -((long) node1->content);
3060		    l2 = -((long) node2->content);
3061		    if (l1 < l2)
3062			return(1);
3063		    if (l1 > l2)
3064			return(-1);
3065		} else
3066		    goto turtle_comparison;
3067	    }
3068	    break;
3069	case XML_ATTRIBUTE_NODE:
3070	    precedence1 = 1; /* element is owner */
3071	    miscNode1 = node1;
3072	    node1 = node1->parent;
3073	    misc = 1;
3074	    break;
3075	case XML_TEXT_NODE:
3076	case XML_CDATA_SECTION_NODE:
3077	case XML_COMMENT_NODE:
3078	case XML_PI_NODE: {
3079	    miscNode1 = node1;
3080	    /*
3081	    * Find nearest element node.
3082	    */
3083	    if (node1->prev != NULL) {
3084		do {
3085		    node1 = node1->prev;
3086		    if (node1->type == XML_ELEMENT_NODE) {
3087			precedence1 = 3; /* element in prev-sibl axis */
3088			break;
3089		    }
3090		    if (node1->prev == NULL) {
3091			precedence1 = 2; /* element is parent */
3092			/*
3093			* URGENT TODO: Are there any cases, where the
3094			* parent of such a node is not an element node?
3095			*/
3096			node1 = node1->parent;
3097			break;
3098		    }
3099		} while (1);
3100	    } else {
3101		precedence1 = 2; /* element is parent */
3102		node1 = node1->parent;
3103	    }
3104	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3105		(0 <= (long) node1->content)) {
3106		/*
3107		* Fallback for whatever case.
3108		*/
3109		node1 = miscNode1;
3110		precedence1 = 0;
3111	    } else
3112		misc = 1;
3113	}
3114	    break;
3115	case XML_NAMESPACE_DECL:
3116	    /*
3117	    * TODO: why do we return 1 for namespace nodes?
3118	    */
3119	    return(1);
3120	default:
3121	    break;
3122    }
3123    switch (node2->type) {
3124	case XML_ELEMENT_NODE:
3125	    break;
3126	case XML_ATTRIBUTE_NODE:
3127	    precedence2 = 1; /* element is owner */
3128	    miscNode2 = node2;
3129	    node2 = node2->parent;
3130	    misc = 1;
3131	    break;
3132	case XML_TEXT_NODE:
3133	case XML_CDATA_SECTION_NODE:
3134	case XML_COMMENT_NODE:
3135	case XML_PI_NODE: {
3136	    miscNode2 = node2;
3137	    if (node2->prev != NULL) {
3138		do {
3139		    node2 = node2->prev;
3140		    if (node2->type == XML_ELEMENT_NODE) {
3141			precedence2 = 3; /* element in prev-sibl axis */
3142			break;
3143		    }
3144		    if (node2->prev == NULL) {
3145			precedence2 = 2; /* element is parent */
3146			node2 = node2->parent;
3147			break;
3148		    }
3149		} while (1);
3150	    } else {
3151		precedence2 = 2; /* element is parent */
3152		node2 = node2->parent;
3153	    }
3154	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3155		(0 <= (long) node1->content))
3156	    {
3157		node2 = miscNode2;
3158		precedence2 = 0;
3159	    } else
3160		misc = 1;
3161	}
3162	    break;
3163	case XML_NAMESPACE_DECL:
3164	    return(1);
3165	default:
3166	    break;
3167    }
3168    if (misc) {
3169	if (node1 == node2) {
3170	    if (precedence1 == precedence2) {
3171		/*
3172		* The ugly case; but normally there aren't many
3173		* adjacent non-element nodes around.
3174		*/
3175		cur = miscNode2->prev;
3176		while (cur != NULL) {
3177		    if (cur == miscNode1)
3178			return(1);
3179		    if (cur->type == XML_ELEMENT_NODE)
3180			return(-1);
3181		    cur = cur->prev;
3182		}
3183		return (-1);
3184	    } else {
3185		/*
3186		* Evaluate based on higher precedence wrt to the element.
3187		* TODO: This assumes attributes are sorted before content.
3188		*   Is this 100% correct?
3189		*/
3190		if (precedence1 < precedence2)
3191		    return(1);
3192		else
3193		    return(-1);
3194	    }
3195	}
3196	/*
3197	* Special case: One of the helper-elements is contained by the other.
3198	* <foo>
3199	*   <node2>
3200	*     <node1>Text-1(precedence1 == 2)</node1>
3201	*   </node2>
3202	*   Text-6(precedence2 == 3)
3203	* </foo>
3204	*/
3205	if ((precedence2 == 3) && (precedence1 > 1)) {
3206	    cur = node1->parent;
3207	    while (cur) {
3208		if (cur == node2)
3209		    return(1);
3210		cur = cur->parent;
3211	    }
3212	}
3213	if ((precedence1 == 3) && (precedence2 > 1)) {
3214	    cur = node2->parent;
3215	    while (cur) {
3216		if (cur == node1)
3217		    return(-1);
3218		cur = cur->parent;
3219	    }
3220	}
3221    }
3222
3223    /*
3224     * Speedup using document order if availble.
3225     */
3226    if ((node1->type == XML_ELEMENT_NODE) &&
3227	(node2->type == XML_ELEMENT_NODE) &&
3228	(0 > (long) node1->content) &&
3229	(0 > (long) node2->content) &&
3230	(node1->doc == node2->doc)) {
3231
3232	l1 = -((long) node1->content);
3233	l2 = -((long) node2->content);
3234	if (l1 < l2)
3235	    return(1);
3236	if (l1 > l2)
3237	    return(-1);
3238    }
3239
3240turtle_comparison:
3241
3242    if (node1 == node2->prev)
3243	return(1);
3244    if (node1 == node2->next)
3245	return(-1);
3246    /*
3247     * compute depth to root
3248     */
3249    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3250	if (cur == node1)
3251	    return(1);
3252	depth2++;
3253    }
3254    root = cur;
3255    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3256	if (cur == node2)
3257	    return(-1);
3258	depth1++;
3259    }
3260    /*
3261     * Distinct document (or distinct entities :-( ) case.
3262     */
3263    if (root != cur) {
3264	return(-2);
3265    }
3266    /*
3267     * get the nearest common ancestor.
3268     */
3269    while (depth1 > depth2) {
3270	depth1--;
3271	node1 = node1->parent;
3272    }
3273    while (depth2 > depth1) {
3274	depth2--;
3275	node2 = node2->parent;
3276    }
3277    while (node1->parent != node2->parent) {
3278	node1 = node1->parent;
3279	node2 = node2->parent;
3280	/* should not happen but just in case ... */
3281	if ((node1 == NULL) || (node2 == NULL))
3282	    return(-2);
3283    }
3284    /*
3285     * Find who's first.
3286     */
3287    if (node1 == node2->prev)
3288	return(1);
3289    if (node1 == node2->next)
3290	return(-1);
3291    /*
3292     * Speedup using document order if availble.
3293     */
3294    if ((node1->type == XML_ELEMENT_NODE) &&
3295	(node2->type == XML_ELEMENT_NODE) &&
3296	(0 > (long) node1->content) &&
3297	(0 > (long) node2->content) &&
3298	(node1->doc == node2->doc)) {
3299
3300	l1 = -((long) node1->content);
3301	l2 = -((long) node2->content);
3302	if (l1 < l2)
3303	    return(1);
3304	if (l1 > l2)
3305	    return(-1);
3306    }
3307
3308    for (cur = node1->next;cur != NULL;cur = cur->next)
3309	if (cur == node2)
3310	    return(1);
3311    return(-1); /* assume there is no sibling list corruption */
3312}
3313#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
3314
3315/**
3316 * xmlXPathNodeSetSort:
3317 * @set:  the node set
3318 *
3319 * Sort the node set in document order
3320 */
3321void
3322xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3323    int i, j, incr, len;
3324    xmlNodePtr tmp;
3325
3326    if (set == NULL)
3327	return;
3328
3329    /* Use Shell's sort to sort the node-set */
3330    len = set->nodeNr;
3331    for (incr = len / 2; incr > 0; incr /= 2) {
3332	for (i = incr; i < len; i++) {
3333	    j = i - incr;
3334	    while (j >= 0) {
3335#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3336		if (xmlXPathCmpNodesExt(set->nodeTab[j],
3337			set->nodeTab[j + incr]) == -1)
3338#else
3339		if (xmlXPathCmpNodes(set->nodeTab[j],
3340			set->nodeTab[j + incr]) == -1)
3341#endif
3342		{
3343		    tmp = set->nodeTab[j];
3344		    set->nodeTab[j] = set->nodeTab[j + incr];
3345		    set->nodeTab[j + incr] = tmp;
3346		    j -= incr;
3347		} else
3348		    break;
3349	    }
3350	}
3351    }
3352}
3353
3354#define XML_NODESET_DEFAULT	10
3355/**
3356 * xmlXPathNodeSetDupNs:
3357 * @node:  the parent node of the namespace XPath node
3358 * @ns:  the libxml namespace declaration node.
3359 *
3360 * Namespace node in libxml don't match the XPath semantic. In a node set
3361 * the namespace nodes are duplicated and the next pointer is set to the
3362 * parent node in the XPath semantic.
3363 *
3364 * Returns the newly created object.
3365 */
3366static xmlNodePtr
3367xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3368    xmlNsPtr cur;
3369
3370    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3371	return(NULL);
3372    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3373	return((xmlNodePtr) ns);
3374
3375    /*
3376     * Allocate a new Namespace and fill the fields.
3377     */
3378    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3379    if (cur == NULL) {
3380        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3381	return(NULL);
3382    }
3383    memset(cur, 0, sizeof(xmlNs));
3384    cur->type = XML_NAMESPACE_DECL;
3385    if (ns->href != NULL)
3386	cur->href = xmlStrdup(ns->href);
3387    if (ns->prefix != NULL)
3388	cur->prefix = xmlStrdup(ns->prefix);
3389    cur->next = (xmlNsPtr) node;
3390    return((xmlNodePtr) cur);
3391}
3392
3393/**
3394 * xmlXPathNodeSetFreeNs:
3395 * @ns:  the XPath namespace node found in a nodeset.
3396 *
3397 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3398 * the namespace nodes are duplicated and the next pointer is set to the
3399 * parent node in the XPath semantic. Check if such a node needs to be freed
3400 */
3401void
3402xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3403    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3404	return;
3405
3406    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3407	if (ns->href != NULL)
3408	    xmlFree((xmlChar *)ns->href);
3409	if (ns->prefix != NULL)
3410	    xmlFree((xmlChar *)ns->prefix);
3411	xmlFree(ns);
3412    }
3413}
3414
3415/**
3416 * xmlXPathNodeSetCreate:
3417 * @val:  an initial xmlNodePtr, or NULL
3418 *
3419 * Create a new xmlNodeSetPtr of type double and of value @val
3420 *
3421 * Returns the newly created object.
3422 */
3423xmlNodeSetPtr
3424xmlXPathNodeSetCreate(xmlNodePtr val) {
3425    xmlNodeSetPtr ret;
3426
3427    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3428    if (ret == NULL) {
3429        xmlXPathErrMemory(NULL, "creating nodeset\n");
3430	return(NULL);
3431    }
3432    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3433    if (val != NULL) {
3434        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3435					     sizeof(xmlNodePtr));
3436	if (ret->nodeTab == NULL) {
3437	    xmlXPathErrMemory(NULL, "creating nodeset\n");
3438	    xmlFree(ret);
3439	    return(NULL);
3440	}
3441	memset(ret->nodeTab, 0 ,
3442	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3443        ret->nodeMax = XML_NODESET_DEFAULT;
3444	if (val->type == XML_NAMESPACE_DECL) {
3445	    xmlNsPtr ns = (xmlNsPtr) val;
3446
3447	    ret->nodeTab[ret->nodeNr++] =
3448		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3449	} else
3450	    ret->nodeTab[ret->nodeNr++] = val;
3451    }
3452    return(ret);
3453}
3454
3455/**
3456 * xmlXPathNodeSetCreateSize:
3457 * @size:  the initial size of the set
3458 *
3459 * Create a new xmlNodeSetPtr of type double and of value @val
3460 *
3461 * Returns the newly created object.
3462 */
3463static xmlNodeSetPtr
3464xmlXPathNodeSetCreateSize(int size) {
3465    xmlNodeSetPtr ret;
3466
3467    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3468    if (ret == NULL) {
3469        xmlXPathErrMemory(NULL, "creating nodeset\n");
3470	return(NULL);
3471    }
3472    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3473    if (size < XML_NODESET_DEFAULT)
3474	size = XML_NODESET_DEFAULT;
3475    ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3476    if (ret->nodeTab == NULL) {
3477	xmlXPathErrMemory(NULL, "creating nodeset\n");
3478	xmlFree(ret);
3479	return(NULL);
3480    }
3481    memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3482    ret->nodeMax = size;
3483    return(ret);
3484}
3485
3486/**
3487 * xmlXPathNodeSetContains:
3488 * @cur:  the node-set
3489 * @val:  the node
3490 *
3491 * checks whether @cur contains @val
3492 *
3493 * Returns true (1) if @cur contains @val, false (0) otherwise
3494 */
3495int
3496xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3497    int i;
3498
3499    if ((cur == NULL) || (val == NULL)) return(0);
3500    if (val->type == XML_NAMESPACE_DECL) {
3501	for (i = 0; i < cur->nodeNr; i++) {
3502	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3503		xmlNsPtr ns1, ns2;
3504
3505		ns1 = (xmlNsPtr) val;
3506		ns2 = (xmlNsPtr) cur->nodeTab[i];
3507		if (ns1 == ns2)
3508		    return(1);
3509		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3510	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
3511		    return(1);
3512	    }
3513	}
3514    } else {
3515	for (i = 0; i < cur->nodeNr; i++) {
3516	    if (cur->nodeTab[i] == val)
3517		return(1);
3518	}
3519    }
3520    return(0);
3521}
3522
3523/**
3524 * xmlXPathNodeSetAddNs:
3525 * @cur:  the initial node set
3526 * @node:  the hosting node
3527 * @ns:  a the namespace node
3528 *
3529 * add a new namespace node to an existing NodeSet
3530 */
3531void
3532xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3533    int i;
3534
3535
3536    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3537        (ns->type != XML_NAMESPACE_DECL) ||
3538	(node->type != XML_ELEMENT_NODE))
3539	return;
3540
3541    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3542    /*
3543     * prevent duplicates
3544     */
3545    for (i = 0;i < cur->nodeNr;i++) {
3546        if ((cur->nodeTab[i] != NULL) &&
3547	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3548	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3549	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3550	    return;
3551    }
3552
3553    /*
3554     * grow the nodeTab if needed
3555     */
3556    if (cur->nodeMax == 0) {
3557        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3558					     sizeof(xmlNodePtr));
3559	if (cur->nodeTab == NULL) {
3560	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3561	    return;
3562	}
3563	memset(cur->nodeTab, 0 ,
3564	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3565        cur->nodeMax = XML_NODESET_DEFAULT;
3566    } else if (cur->nodeNr == cur->nodeMax) {
3567        xmlNodePtr *temp;
3568
3569	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3570				      sizeof(xmlNodePtr));
3571	if (temp == NULL) {
3572	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3573	    return;
3574	}
3575        cur->nodeMax *= 2;
3576	cur->nodeTab = temp;
3577    }
3578    cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3579}
3580
3581/**
3582 * xmlXPathNodeSetAdd:
3583 * @cur:  the initial node set
3584 * @val:  a new xmlNodePtr
3585 *
3586 * add a new xmlNodePtr to an existing NodeSet
3587 */
3588void
3589xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3590    int i;
3591
3592    if ((cur == NULL) || (val == NULL)) return;
3593
3594#if 0
3595    if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3596	return;	/* an XSLT fake node */
3597#endif
3598
3599    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3600    /*
3601     * prevent duplcates
3602     */
3603    for (i = 0;i < cur->nodeNr;i++)
3604        if (cur->nodeTab[i] == val) return;
3605
3606    /*
3607     * grow the nodeTab if needed
3608     */
3609    if (cur->nodeMax == 0) {
3610        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3611					     sizeof(xmlNodePtr));
3612	if (cur->nodeTab == NULL) {
3613	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3614	    return;
3615	}
3616	memset(cur->nodeTab, 0 ,
3617	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3618        cur->nodeMax = XML_NODESET_DEFAULT;
3619    } else if (cur->nodeNr == cur->nodeMax) {
3620        xmlNodePtr *temp;
3621
3622	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3623				      sizeof(xmlNodePtr));
3624	if (temp == NULL) {
3625	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3626	    return;
3627	}
3628        cur->nodeMax *= 2;
3629	cur->nodeTab = temp;
3630    }
3631    if (val->type == XML_NAMESPACE_DECL) {
3632	xmlNsPtr ns = (xmlNsPtr) val;
3633
3634	cur->nodeTab[cur->nodeNr++] =
3635	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3636    } else
3637	cur->nodeTab[cur->nodeNr++] = val;
3638}
3639
3640/**
3641 * xmlXPathNodeSetAddUnique:
3642 * @cur:  the initial node set
3643 * @val:  a new xmlNodePtr
3644 *
3645 * add a new xmlNodePtr to an existing NodeSet, optimized version
3646 * when we are sure the node is not already in the set.
3647 */
3648void
3649xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3650    if ((cur == NULL) || (val == NULL)) return;
3651
3652#if 0
3653    if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3654	return;	/* an XSLT fake node */
3655#endif
3656
3657    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3658    /*
3659     * grow the nodeTab if needed
3660     */
3661    if (cur->nodeMax == 0) {
3662        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3663					     sizeof(xmlNodePtr));
3664	if (cur->nodeTab == NULL) {
3665	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3666	    return;
3667	}
3668	memset(cur->nodeTab, 0 ,
3669	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3670        cur->nodeMax = XML_NODESET_DEFAULT;
3671    } else if (cur->nodeNr == cur->nodeMax) {
3672        xmlNodePtr *temp;
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;
3679	}
3680	cur->nodeTab = temp;
3681        cur->nodeMax *= 2;
3682    }
3683    if (val->type == XML_NAMESPACE_DECL) {
3684	xmlNsPtr ns = (xmlNsPtr) val;
3685
3686	cur->nodeTab[cur->nodeNr++] =
3687	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3688    } else
3689	cur->nodeTab[cur->nodeNr++] = val;
3690}
3691
3692/**
3693 * xmlXPathNodeSetMerge:
3694 * @val1:  the first NodeSet or NULL
3695 * @val2:  the second NodeSet
3696 *
3697 * Merges two nodesets, all nodes from @val2 are added to @val1
3698 * if @val1 is NULL, a new set is created and copied from @val2
3699 *
3700 * Returns @val1 once extended or NULL in case of error.
3701 */
3702xmlNodeSetPtr
3703xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3704    int i, j, initNr, skip;
3705    xmlNodePtr n1, n2;
3706
3707    if (val2 == NULL) return(val1);
3708    if (val1 == NULL) {
3709	val1 = xmlXPathNodeSetCreate(NULL);
3710    if (val1 == NULL)
3711        return (NULL);
3712#if 0
3713	/*
3714	* TODO: The optimization won't work in every case, since
3715	*  those nasty namespace nodes need to be added with
3716	*  xmlXPathNodeSetDupNs() to the set; thus a pure
3717	*  memcpy is not possible.
3718	*  If there was a flag on the nodesetval, indicating that
3719	*  some temporary nodes are in, that would be helpfull.
3720	*/
3721	/*
3722	* Optimization: Create an equally sized node-set
3723	* and memcpy the content.
3724	*/
3725	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3726	if (val1 == NULL)
3727	    return(NULL);
3728	if (val2->nodeNr != 0) {
3729	    if (val2->nodeNr == 1)
3730		*(val1->nodeTab) = *(val2->nodeTab);
3731	    else {
3732		memcpy(val1->nodeTab, val2->nodeTab,
3733		    val2->nodeNr * sizeof(xmlNodePtr));
3734	    }
3735	    val1->nodeNr = val2->nodeNr;
3736	}
3737	return(val1);
3738#endif
3739    }
3740
3741    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3742    initNr = val1->nodeNr;
3743
3744    for (i = 0;i < val2->nodeNr;i++) {
3745	n2 = val2->nodeTab[i];
3746	/*
3747	 * check against duplicates
3748	 */
3749	skip = 0;
3750	for (j = 0; j < initNr; j++) {
3751	    n1 = val1->nodeTab[j];
3752	    if (n1 == n2) {
3753		skip = 1;
3754		break;
3755	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3756		       (n2->type == XML_NAMESPACE_DECL)) {
3757		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3758		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3759			((xmlNsPtr) n2)->prefix)))
3760		{
3761		    skip = 1;
3762		    break;
3763		}
3764	    }
3765	}
3766	if (skip)
3767	    continue;
3768
3769	/*
3770	 * grow the nodeTab if needed
3771	 */
3772	if (val1->nodeMax == 0) {
3773	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3774						    sizeof(xmlNodePtr));
3775	    if (val1->nodeTab == NULL) {
3776	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3777		return(NULL);
3778	    }
3779	    memset(val1->nodeTab, 0 ,
3780		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3781	    val1->nodeMax = XML_NODESET_DEFAULT;
3782	} else if (val1->nodeNr == val1->nodeMax) {
3783	    xmlNodePtr *temp;
3784
3785	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3786					     sizeof(xmlNodePtr));
3787	    if (temp == NULL) {
3788	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3789		return(NULL);
3790	    }
3791	    val1->nodeTab = temp;
3792	    val1->nodeMax *= 2;
3793	}
3794	if (n2->type == XML_NAMESPACE_DECL) {
3795	    xmlNsPtr ns = (xmlNsPtr) n2;
3796
3797	    val1->nodeTab[val1->nodeNr++] =
3798		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3799	} else
3800	    val1->nodeTab[val1->nodeNr++] = n2;
3801    }
3802
3803    return(val1);
3804}
3805
3806#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3807/**
3808 * xmlXPathNodeSetMergeUnique:
3809 * @val1:  the first NodeSet or NULL
3810 * @val2:  the second NodeSet
3811 *
3812 * Merges two nodesets, all nodes from @val2 are added to @val1
3813 * if @val1 is NULL, a new set is created and copied from @val2
3814 *
3815 * Returns @val1 once extended or NULL in case of error.
3816 */
3817static xmlNodeSetPtr
3818xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3819    int i;
3820
3821    if (val2 == NULL) return(val1);
3822    if (val1 == NULL) {
3823	val1 = xmlXPathNodeSetCreate(NULL);
3824    }
3825    if (val1 == NULL)
3826        return (NULL);
3827
3828    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3829
3830    for (i = 0;i < val2->nodeNr;i++) {
3831	/*
3832	 * grow the nodeTab if needed
3833	 */
3834	if (val1->nodeMax == 0) {
3835	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3836						    sizeof(xmlNodePtr));
3837	    if (val1->nodeTab == NULL) {
3838	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3839		return(NULL);
3840	    }
3841	    memset(val1->nodeTab, 0 ,
3842		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3843	    val1->nodeMax = XML_NODESET_DEFAULT;
3844	} else if (val1->nodeNr == val1->nodeMax) {
3845	    xmlNodePtr *temp;
3846
3847	    val1->nodeMax *= 2;
3848	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3849					     sizeof(xmlNodePtr));
3850	    if (temp == NULL) {
3851	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3852		return(NULL);
3853	    }
3854	    val1->nodeTab = temp;
3855	}
3856	if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3857	    xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3858
3859	    val1->nodeTab[val1->nodeNr++] =
3860		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3861	} else
3862	    val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3863    }
3864
3865    return(val1);
3866}
3867#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3868
3869/**
3870 * xmlXPathNodeSetMergeAndClear:
3871 * @set1:  the first NodeSet or NULL
3872 * @set2:  the second NodeSet
3873 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3874 *
3875 * Merges two nodesets, all nodes from @set2 are added to @set1
3876 * if @set1 is NULL, a new set is created and copied from @set2.
3877 * Checks for duplicate nodes. Clears set2.
3878 *
3879 * Returns @set1 once extended or NULL in case of error.
3880 */
3881static xmlNodeSetPtr
3882xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3883			     int hasNullEntries)
3884{
3885    if ((set1 == NULL) && (hasNullEntries == 0)) {
3886	/*
3887	* Note that doing a memcpy of the list, namespace nodes are
3888	* just assigned to set1, since set2 is cleared anyway.
3889	*/
3890	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3891	if (set1 == NULL)
3892	    return(NULL);
3893	if (set2->nodeNr != 0) {
3894	    memcpy(set1->nodeTab, set2->nodeTab,
3895		set2->nodeNr * sizeof(xmlNodePtr));
3896	    set1->nodeNr = set2->nodeNr;
3897	}
3898    } else {
3899	int i, j, initNbSet1;
3900	xmlNodePtr n1, n2;
3901
3902	if (set1 == NULL)
3903            set1 = xmlXPathNodeSetCreate(NULL);
3904        if (set1 == NULL)
3905            return (NULL);
3906
3907	initNbSet1 = set1->nodeNr;
3908	for (i = 0;i < set2->nodeNr;i++) {
3909	    n2 = set2->nodeTab[i];
3910	    /*
3911	    * Skip NULLed entries.
3912	    */
3913	    if (n2 == NULL)
3914		continue;
3915	    /*
3916	    * Skip duplicates.
3917	    */
3918	    for (j = 0; j < initNbSet1; j++) {
3919		n1 = set1->nodeTab[j];
3920		if (n1 == n2) {
3921		    goto skip_node;
3922		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3923		    (n2->type == XML_NAMESPACE_DECL))
3924		{
3925		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3926			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3927			((xmlNsPtr) n2)->prefix)))
3928		    {
3929			/*
3930			* Free the namespace node.
3931			*/
3932			set2->nodeTab[i] = NULL;
3933			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3934			goto skip_node;
3935		    }
3936		}
3937	    }
3938	    /*
3939	    * grow the nodeTab if needed
3940	    */
3941	    if (set1->nodeMax == 0) {
3942		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3943		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3944		if (set1->nodeTab == NULL) {
3945		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3946		    return(NULL);
3947		}
3948		memset(set1->nodeTab, 0,
3949		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3950		set1->nodeMax = XML_NODESET_DEFAULT;
3951	    } else if (set1->nodeNr >= set1->nodeMax) {
3952		xmlNodePtr *temp;
3953
3954		temp = (xmlNodePtr *) xmlRealloc(
3955		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3956		if (temp == NULL) {
3957		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3958		    return(NULL);
3959		}
3960		set1->nodeTab = temp;
3961		set1->nodeMax *= 2;
3962	    }
3963	    if (n2->type == XML_NAMESPACE_DECL) {
3964		xmlNsPtr ns = (xmlNsPtr) n2;
3965
3966		set1->nodeTab[set1->nodeNr++] =
3967		    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3968	    } else
3969		set1->nodeTab[set1->nodeNr++] = n2;
3970skip_node:
3971	    {}
3972	}
3973    }
3974    set2->nodeNr = 0;
3975    return(set1);
3976}
3977
3978/**
3979 * xmlXPathNodeSetMergeAndClearNoDupls:
3980 * @set1:  the first NodeSet or NULL
3981 * @set2:  the second NodeSet
3982 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3983 *
3984 * Merges two nodesets, all nodes from @set2 are added to @set1
3985 * if @set1 is NULL, a new set is created and copied from @set2.
3986 * Doesn't chack for duplicate nodes. Clears set2.
3987 *
3988 * Returns @set1 once extended or NULL in case of error.
3989 */
3990static xmlNodeSetPtr
3991xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3992				    int hasNullEntries)
3993{
3994    if (set2 == NULL)
3995	return(set1);
3996    if ((set1 == NULL) && (hasNullEntries == 0)) {
3997	/*
3998	* Note that doing a memcpy of the list, namespace nodes are
3999	* just assigned to set1, since set2 is cleared anyway.
4000	*/
4001	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4002	if (set1 == NULL)
4003	    return(NULL);
4004	if (set2->nodeNr != 0) {
4005	    memcpy(set1->nodeTab, set2->nodeTab,
4006		set2->nodeNr * sizeof(xmlNodePtr));
4007	    set1->nodeNr = set2->nodeNr;
4008	}
4009    } else {
4010	int i;
4011	xmlNodePtr n2;
4012
4013	if (set1 == NULL)
4014	    set1 = xmlXPathNodeSetCreate(NULL);
4015        if (set1 == NULL)
4016            return (NULL);
4017
4018	for (i = 0;i < set2->nodeNr;i++) {
4019	    n2 = set2->nodeTab[i];
4020	    /*
4021	    * Skip NULLed entries.
4022	    */
4023	    if (n2 == NULL)
4024		continue;
4025	    if (set1->nodeMax == 0) {
4026		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4027		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4028		if (set1->nodeTab == NULL) {
4029		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4030		    return(NULL);
4031		}
4032		memset(set1->nodeTab, 0,
4033		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4034		set1->nodeMax = XML_NODESET_DEFAULT;
4035	    } else if (set1->nodeNr >= set1->nodeMax) {
4036		xmlNodePtr *temp;
4037
4038		temp = (xmlNodePtr *) xmlRealloc(
4039		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4040		if (temp == NULL) {
4041		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4042		    return(NULL);
4043		}
4044		set1->nodeTab = temp;
4045		set1->nodeMax *= 2;
4046	    }
4047	    set1->nodeTab[set1->nodeNr++] = n2;
4048	}
4049    }
4050    set2->nodeNr = 0;
4051    return(set1);
4052}
4053
4054/**
4055 * xmlXPathNodeSetDel:
4056 * @cur:  the initial node set
4057 * @val:  an xmlNodePtr
4058 *
4059 * Removes an xmlNodePtr from an existing NodeSet
4060 */
4061void
4062xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4063    int i;
4064
4065    if (cur == NULL) return;
4066    if (val == NULL) return;
4067
4068    /*
4069     * find node in nodeTab
4070     */
4071    for (i = 0;i < cur->nodeNr;i++)
4072        if (cur->nodeTab[i] == val) break;
4073
4074    if (i >= cur->nodeNr) {	/* not found */
4075#ifdef DEBUG
4076        xmlGenericError(xmlGenericErrorContext,
4077	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4078		val->name);
4079#endif
4080        return;
4081    }
4082    if ((cur->nodeTab[i] != NULL) &&
4083	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4084	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4085    cur->nodeNr--;
4086    for (;i < cur->nodeNr;i++)
4087        cur->nodeTab[i] = cur->nodeTab[i + 1];
4088    cur->nodeTab[cur->nodeNr] = NULL;
4089}
4090
4091/**
4092 * xmlXPathNodeSetRemove:
4093 * @cur:  the initial node set
4094 * @val:  the index to remove
4095 *
4096 * Removes an entry from an existing NodeSet list.
4097 */
4098void
4099xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4100    if (cur == NULL) return;
4101    if (val >= cur->nodeNr) return;
4102    if ((cur->nodeTab[val] != NULL) &&
4103	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4104	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4105    cur->nodeNr--;
4106    for (;val < cur->nodeNr;val++)
4107        cur->nodeTab[val] = cur->nodeTab[val + 1];
4108    cur->nodeTab[cur->nodeNr] = NULL;
4109}
4110
4111/**
4112 * xmlXPathFreeNodeSet:
4113 * @obj:  the xmlNodeSetPtr to free
4114 *
4115 * Free the NodeSet compound (not the actual nodes !).
4116 */
4117void
4118xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4119    if (obj == NULL) return;
4120    if (obj->nodeTab != NULL) {
4121	int i;
4122
4123	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
4124	for (i = 0;i < obj->nodeNr;i++)
4125	    if ((obj->nodeTab[i] != NULL) &&
4126		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4127		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4128	xmlFree(obj->nodeTab);
4129    }
4130    xmlFree(obj);
4131}
4132
4133/**
4134 * xmlXPathNodeSetClear:
4135 * @set:  the node set to clear
4136 *
4137 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4138 * are feed), but does *not* free the list itself. Sets the length of the
4139 * list to 0.
4140 */
4141static void
4142xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4143{
4144    if ((set == NULL) || (set->nodeNr <= 0))
4145	return;
4146    else if (hasNsNodes) {
4147	int i;
4148	xmlNodePtr node;
4149
4150	for (i = 0; i < set->nodeNr; i++) {
4151	    node = set->nodeTab[i];
4152	    if ((node != NULL) &&
4153		(node->type == XML_NAMESPACE_DECL))
4154		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4155	}
4156    }
4157    set->nodeNr = 0;
4158}
4159
4160/**
4161 * xmlXPathNodeSetClearFromPos:
4162 * @set: the node set to be cleared
4163 * @pos: the start position to clear from
4164 *
4165 * Clears the list from temporary XPath objects (e.g. namespace nodes
4166 * are feed) starting with the entry at @pos, but does *not* free the list
4167 * itself. Sets the length of the list to @pos.
4168 */
4169static void
4170xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4171{
4172    if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4173	return;
4174    else if ((hasNsNodes)) {
4175	int i;
4176	xmlNodePtr node;
4177
4178	for (i = pos; i < set->nodeNr; i++) {
4179	    node = set->nodeTab[i];
4180	    if ((node != NULL) &&
4181		(node->type == XML_NAMESPACE_DECL))
4182		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4183	}
4184    }
4185    set->nodeNr = pos;
4186}
4187
4188/**
4189 * xmlXPathFreeValueTree:
4190 * @obj:  the xmlNodeSetPtr to free
4191 *
4192 * Free the NodeSet compound and the actual tree, this is different
4193 * from xmlXPathFreeNodeSet()
4194 */
4195static void
4196xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4197    int i;
4198
4199    if (obj == NULL) return;
4200
4201    if (obj->nodeTab != NULL) {
4202	for (i = 0;i < obj->nodeNr;i++) {
4203	    if (obj->nodeTab[i] != NULL) {
4204		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4205		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4206		} else {
4207		    xmlFreeNodeList(obj->nodeTab[i]);
4208		}
4209	    }
4210	}
4211	xmlFree(obj->nodeTab);
4212    }
4213    xmlFree(obj);
4214}
4215
4216#if defined(DEBUG) || defined(DEBUG_STEP)
4217/**
4218 * xmlGenericErrorContextNodeSet:
4219 * @output:  a FILE * for the output
4220 * @obj:  the xmlNodeSetPtr to display
4221 *
4222 * Quick display of a NodeSet
4223 */
4224void
4225xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4226    int i;
4227
4228    if (output == NULL) output = xmlGenericErrorContext;
4229    if (obj == NULL)  {
4230        fprintf(output, "NodeSet == NULL !\n");
4231	return;
4232    }
4233    if (obj->nodeNr == 0) {
4234        fprintf(output, "NodeSet is empty\n");
4235	return;
4236    }
4237    if (obj->nodeTab == NULL) {
4238	fprintf(output, " nodeTab == NULL !\n");
4239	return;
4240    }
4241    for (i = 0; i < obj->nodeNr; i++) {
4242        if (obj->nodeTab[i] == NULL) {
4243	    fprintf(output, " NULL !\n");
4244	    return;
4245        }
4246	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4247	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4248	    fprintf(output, " /");
4249	else if (obj->nodeTab[i]->name == NULL)
4250	    fprintf(output, " noname!");
4251	else fprintf(output, " %s", obj->nodeTab[i]->name);
4252    }
4253    fprintf(output, "\n");
4254}
4255#endif
4256
4257/**
4258 * xmlXPathNewNodeSet:
4259 * @val:  the NodePtr value
4260 *
4261 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4262 * it with the single Node @val
4263 *
4264 * Returns the newly created object.
4265 */
4266xmlXPathObjectPtr
4267xmlXPathNewNodeSet(xmlNodePtr val) {
4268    xmlXPathObjectPtr ret;
4269
4270    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4271    if (ret == NULL) {
4272        xmlXPathErrMemory(NULL, "creating nodeset\n");
4273	return(NULL);
4274    }
4275    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4276    ret->type = XPATH_NODESET;
4277    ret->boolval = 0;
4278    ret->nodesetval = xmlXPathNodeSetCreate(val);
4279    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4280#ifdef XP_DEBUG_OBJ_USAGE
4281    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4282#endif
4283    return(ret);
4284}
4285
4286/**
4287 * xmlXPathNewValueTree:
4288 * @val:  the NodePtr value
4289 *
4290 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4291 * it with the tree root @val
4292 *
4293 * Returns the newly created object.
4294 */
4295xmlXPathObjectPtr
4296xmlXPathNewValueTree(xmlNodePtr val) {
4297    xmlXPathObjectPtr ret;
4298
4299    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4300    if (ret == NULL) {
4301        xmlXPathErrMemory(NULL, "creating result value tree\n");
4302	return(NULL);
4303    }
4304    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4305    ret->type = XPATH_XSLT_TREE;
4306    ret->boolval = 1;
4307    ret->user = (void *) val;
4308    ret->nodesetval = xmlXPathNodeSetCreate(val);
4309#ifdef XP_DEBUG_OBJ_USAGE
4310    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4311#endif
4312    return(ret);
4313}
4314
4315/**
4316 * xmlXPathNewNodeSetList:
4317 * @val:  an existing NodeSet
4318 *
4319 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4320 * it with the Nodeset @val
4321 *
4322 * Returns the newly created object.
4323 */
4324xmlXPathObjectPtr
4325xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4326{
4327    xmlXPathObjectPtr ret;
4328    int i;
4329
4330    if (val == NULL)
4331        ret = NULL;
4332    else if (val->nodeTab == NULL)
4333        ret = xmlXPathNewNodeSet(NULL);
4334    else {
4335        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4336        if (ret)
4337            for (i = 1; i < val->nodeNr; ++i)
4338                xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4339    }
4340
4341    return (ret);
4342}
4343
4344/**
4345 * xmlXPathWrapNodeSet:
4346 * @val:  the NodePtr value
4347 *
4348 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4349 *
4350 * Returns the newly created object.
4351 */
4352xmlXPathObjectPtr
4353xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4354    xmlXPathObjectPtr ret;
4355
4356    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4357    if (ret == NULL) {
4358        xmlXPathErrMemory(NULL, "creating node set object\n");
4359	return(NULL);
4360    }
4361    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4362    ret->type = XPATH_NODESET;
4363    ret->nodesetval = val;
4364#ifdef XP_DEBUG_OBJ_USAGE
4365    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4366#endif
4367    return(ret);
4368}
4369
4370/**
4371 * xmlXPathFreeNodeSetList:
4372 * @obj:  an existing NodeSetList object
4373 *
4374 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4375 * the list contrary to xmlXPathFreeObject().
4376 */
4377void
4378xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4379    if (obj == NULL) return;
4380#ifdef XP_DEBUG_OBJ_USAGE
4381    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4382#endif
4383    xmlFree(obj);
4384}
4385
4386/**
4387 * xmlXPathDifference:
4388 * @nodes1:  a node-set
4389 * @nodes2:  a node-set
4390 *
4391 * Implements the EXSLT - Sets difference() function:
4392 *    node-set set:difference (node-set, node-set)
4393 *
4394 * Returns the difference between the two node sets, or nodes1 if
4395 *         nodes2 is empty
4396 */
4397xmlNodeSetPtr
4398xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4399    xmlNodeSetPtr ret;
4400    int i, l1;
4401    xmlNodePtr cur;
4402
4403    if (xmlXPathNodeSetIsEmpty(nodes2))
4404	return(nodes1);
4405
4406    ret = xmlXPathNodeSetCreate(NULL);
4407    if (xmlXPathNodeSetIsEmpty(nodes1))
4408	return(ret);
4409
4410    l1 = xmlXPathNodeSetGetLength(nodes1);
4411
4412    for (i = 0; i < l1; i++) {
4413	cur = xmlXPathNodeSetItem(nodes1, i);
4414	if (!xmlXPathNodeSetContains(nodes2, cur))
4415	    xmlXPathNodeSetAddUnique(ret, cur);
4416    }
4417    return(ret);
4418}
4419
4420/**
4421 * xmlXPathIntersection:
4422 * @nodes1:  a node-set
4423 * @nodes2:  a node-set
4424 *
4425 * Implements the EXSLT - Sets intersection() function:
4426 *    node-set set:intersection (node-set, node-set)
4427 *
4428 * Returns a node set comprising the nodes that are within both the
4429 *         node sets passed as arguments
4430 */
4431xmlNodeSetPtr
4432xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4433    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4434    int i, l1;
4435    xmlNodePtr cur;
4436
4437    if (ret == NULL)
4438        return(ret);
4439    if (xmlXPathNodeSetIsEmpty(nodes1))
4440	return(ret);
4441    if (xmlXPathNodeSetIsEmpty(nodes2))
4442	return(ret);
4443
4444    l1 = xmlXPathNodeSetGetLength(nodes1);
4445
4446    for (i = 0; i < l1; i++) {
4447	cur = xmlXPathNodeSetItem(nodes1, i);
4448	if (xmlXPathNodeSetContains(nodes2, cur))
4449	    xmlXPathNodeSetAddUnique(ret, cur);
4450    }
4451    return(ret);
4452}
4453
4454/**
4455 * xmlXPathDistinctSorted:
4456 * @nodes:  a node-set, sorted by document order
4457 *
4458 * Implements the EXSLT - Sets distinct() function:
4459 *    node-set set:distinct (node-set)
4460 *
4461 * Returns a subset of the nodes contained in @nodes, or @nodes if
4462 *         it is empty
4463 */
4464xmlNodeSetPtr
4465xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4466    xmlNodeSetPtr ret;
4467    xmlHashTablePtr hash;
4468    int i, l;
4469    xmlChar * strval;
4470    xmlNodePtr cur;
4471
4472    if (xmlXPathNodeSetIsEmpty(nodes))
4473	return(nodes);
4474
4475    ret = xmlXPathNodeSetCreate(NULL);
4476    if (ret == NULL)
4477        return(ret);
4478    l = xmlXPathNodeSetGetLength(nodes);
4479    hash = xmlHashCreate (l);
4480    for (i = 0; i < l; i++) {
4481	cur = xmlXPathNodeSetItem(nodes, i);
4482	strval = xmlXPathCastNodeToString(cur);
4483	if (xmlHashLookup(hash, strval) == NULL) {
4484	    xmlHashAddEntry(hash, strval, strval);
4485	    xmlXPathNodeSetAddUnique(ret, cur);
4486	} else {
4487	    xmlFree(strval);
4488	}
4489    }
4490    xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4491    return(ret);
4492}
4493
4494/**
4495 * xmlXPathDistinct:
4496 * @nodes:  a node-set
4497 *
4498 * Implements the EXSLT - Sets distinct() function:
4499 *    node-set set:distinct (node-set)
4500 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4501 * is called with the sorted node-set
4502 *
4503 * Returns a subset of the nodes contained in @nodes, or @nodes if
4504 *         it is empty
4505 */
4506xmlNodeSetPtr
4507xmlXPathDistinct (xmlNodeSetPtr nodes) {
4508    if (xmlXPathNodeSetIsEmpty(nodes))
4509	return(nodes);
4510
4511    xmlXPathNodeSetSort(nodes);
4512    return(xmlXPathDistinctSorted(nodes));
4513}
4514
4515/**
4516 * xmlXPathHasSameNodes:
4517 * @nodes1:  a node-set
4518 * @nodes2:  a node-set
4519 *
4520 * Implements the EXSLT - Sets has-same-nodes function:
4521 *    boolean set:has-same-node(node-set, node-set)
4522 *
4523 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4524 *         otherwise
4525 */
4526int
4527xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4528    int i, l;
4529    xmlNodePtr cur;
4530
4531    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4532	xmlXPathNodeSetIsEmpty(nodes2))
4533	return(0);
4534
4535    l = xmlXPathNodeSetGetLength(nodes1);
4536    for (i = 0; i < l; i++) {
4537	cur = xmlXPathNodeSetItem(nodes1, i);
4538	if (xmlXPathNodeSetContains(nodes2, cur))
4539	    return(1);
4540    }
4541    return(0);
4542}
4543
4544/**
4545 * xmlXPathNodeLeadingSorted:
4546 * @nodes: a node-set, sorted by document order
4547 * @node: a node
4548 *
4549 * Implements the EXSLT - Sets leading() function:
4550 *    node-set set:leading (node-set, node-set)
4551 *
4552 * Returns the nodes in @nodes that precede @node in document order,
4553 *         @nodes if @node is NULL or an empty node-set if @nodes
4554 *         doesn't contain @node
4555 */
4556xmlNodeSetPtr
4557xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4558    int i, l;
4559    xmlNodePtr cur;
4560    xmlNodeSetPtr ret;
4561
4562    if (node == NULL)
4563	return(nodes);
4564
4565    ret = xmlXPathNodeSetCreate(NULL);
4566    if (ret == NULL)
4567        return(ret);
4568    if (xmlXPathNodeSetIsEmpty(nodes) ||
4569	(!xmlXPathNodeSetContains(nodes, node)))
4570	return(ret);
4571
4572    l = xmlXPathNodeSetGetLength(nodes);
4573    for (i = 0; i < l; i++) {
4574	cur = xmlXPathNodeSetItem(nodes, i);
4575	if (cur == node)
4576	    break;
4577	xmlXPathNodeSetAddUnique(ret, cur);
4578    }
4579    return(ret);
4580}
4581
4582/**
4583 * xmlXPathNodeLeading:
4584 * @nodes:  a node-set
4585 * @node:  a node
4586 *
4587 * Implements the EXSLT - Sets leading() function:
4588 *    node-set set:leading (node-set, node-set)
4589 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4590 * is called.
4591 *
4592 * Returns the nodes in @nodes that precede @node in document order,
4593 *         @nodes if @node is NULL or an empty node-set if @nodes
4594 *         doesn't contain @node
4595 */
4596xmlNodeSetPtr
4597xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4598    xmlXPathNodeSetSort(nodes);
4599    return(xmlXPathNodeLeadingSorted(nodes, node));
4600}
4601
4602/**
4603 * xmlXPathLeadingSorted:
4604 * @nodes1:  a node-set, sorted by document order
4605 * @nodes2:  a node-set, sorted by document order
4606 *
4607 * Implements the EXSLT - Sets leading() function:
4608 *    node-set set:leading (node-set, node-set)
4609 *
4610 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4611 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4612 *         an empty node-set if @nodes1 doesn't contain @nodes2
4613 */
4614xmlNodeSetPtr
4615xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4616    if (xmlXPathNodeSetIsEmpty(nodes2))
4617	return(nodes1);
4618    return(xmlXPathNodeLeadingSorted(nodes1,
4619				     xmlXPathNodeSetItem(nodes2, 1)));
4620}
4621
4622/**
4623 * xmlXPathLeading:
4624 * @nodes1:  a node-set
4625 * @nodes2:  a node-set
4626 *
4627 * Implements the EXSLT - Sets leading() function:
4628 *    node-set set:leading (node-set, node-set)
4629 * @nodes1 and @nodes2 are sorted by document order, then
4630 * #exslSetsLeadingSorted is called.
4631 *
4632 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4633 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4634 *         an empty node-set if @nodes1 doesn't contain @nodes2
4635 */
4636xmlNodeSetPtr
4637xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4638    if (xmlXPathNodeSetIsEmpty(nodes2))
4639	return(nodes1);
4640    if (xmlXPathNodeSetIsEmpty(nodes1))
4641	return(xmlXPathNodeSetCreate(NULL));
4642    xmlXPathNodeSetSort(nodes1);
4643    xmlXPathNodeSetSort(nodes2);
4644    return(xmlXPathNodeLeadingSorted(nodes1,
4645				     xmlXPathNodeSetItem(nodes2, 1)));
4646}
4647
4648/**
4649 * xmlXPathNodeTrailingSorted:
4650 * @nodes: a node-set, sorted by document order
4651 * @node: a node
4652 *
4653 * Implements the EXSLT - Sets trailing() function:
4654 *    node-set set:trailing (node-set, node-set)
4655 *
4656 * Returns the nodes in @nodes that follow @node in document order,
4657 *         @nodes if @node is NULL or an empty node-set if @nodes
4658 *         doesn't contain @node
4659 */
4660xmlNodeSetPtr
4661xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4662    int i, l;
4663    xmlNodePtr cur;
4664    xmlNodeSetPtr ret;
4665
4666    if (node == NULL)
4667	return(nodes);
4668
4669    ret = xmlXPathNodeSetCreate(NULL);
4670    if (ret == NULL)
4671        return(ret);
4672    if (xmlXPathNodeSetIsEmpty(nodes) ||
4673	(!xmlXPathNodeSetContains(nodes, node)))
4674	return(ret);
4675
4676    l = xmlXPathNodeSetGetLength(nodes);
4677    for (i = l - 1; i >= 0; i--) {
4678	cur = xmlXPathNodeSetItem(nodes, i);
4679	if (cur == node)
4680	    break;
4681	xmlXPathNodeSetAddUnique(ret, cur);
4682    }
4683    xmlXPathNodeSetSort(ret);	/* bug 413451 */
4684    return(ret);
4685}
4686
4687/**
4688 * xmlXPathNodeTrailing:
4689 * @nodes:  a node-set
4690 * @node:  a node
4691 *
4692 * Implements the EXSLT - Sets trailing() function:
4693 *    node-set set:trailing (node-set, node-set)
4694 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4695 * is called.
4696 *
4697 * Returns the nodes in @nodes that follow @node in document order,
4698 *         @nodes if @node is NULL or an empty node-set if @nodes
4699 *         doesn't contain @node
4700 */
4701xmlNodeSetPtr
4702xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4703    xmlXPathNodeSetSort(nodes);
4704    return(xmlXPathNodeTrailingSorted(nodes, node));
4705}
4706
4707/**
4708 * xmlXPathTrailingSorted:
4709 * @nodes1:  a node-set, sorted by document order
4710 * @nodes2:  a node-set, sorted by document order
4711 *
4712 * Implements the EXSLT - Sets trailing() function:
4713 *    node-set set:trailing (node-set, node-set)
4714 *
4715 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4716 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4717 *         an empty node-set if @nodes1 doesn't contain @nodes2
4718 */
4719xmlNodeSetPtr
4720xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4721    if (xmlXPathNodeSetIsEmpty(nodes2))
4722	return(nodes1);
4723    return(xmlXPathNodeTrailingSorted(nodes1,
4724				      xmlXPathNodeSetItem(nodes2, 0)));
4725}
4726
4727/**
4728 * xmlXPathTrailing:
4729 * @nodes1:  a node-set
4730 * @nodes2:  a node-set
4731 *
4732 * Implements the EXSLT - Sets trailing() function:
4733 *    node-set set:trailing (node-set, node-set)
4734 * @nodes1 and @nodes2 are sorted by document order, then
4735 * #xmlXPathTrailingSorted is called.
4736 *
4737 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4738 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4739 *         an empty node-set if @nodes1 doesn't contain @nodes2
4740 */
4741xmlNodeSetPtr
4742xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4743    if (xmlXPathNodeSetIsEmpty(nodes2))
4744	return(nodes1);
4745    if (xmlXPathNodeSetIsEmpty(nodes1))
4746	return(xmlXPathNodeSetCreate(NULL));
4747    xmlXPathNodeSetSort(nodes1);
4748    xmlXPathNodeSetSort(nodes2);
4749    return(xmlXPathNodeTrailingSorted(nodes1,
4750				      xmlXPathNodeSetItem(nodes2, 0)));
4751}
4752
4753/************************************************************************
4754 *									*
4755 *		Routines to handle extra functions			*
4756 *									*
4757 ************************************************************************/
4758
4759/**
4760 * xmlXPathRegisterFunc:
4761 * @ctxt:  the XPath context
4762 * @name:  the function name
4763 * @f:  the function implementation or NULL
4764 *
4765 * Register a new function. If @f is NULL it unregisters the function
4766 *
4767 * Returns 0 in case of success, -1 in case of error
4768 */
4769int
4770xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4771		     xmlXPathFunction f) {
4772    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4773}
4774
4775/**
4776 * xmlXPathRegisterFuncNS:
4777 * @ctxt:  the XPath context
4778 * @name:  the function name
4779 * @ns_uri:  the function namespace URI
4780 * @f:  the function implementation or NULL
4781 *
4782 * Register a new function. If @f is NULL it unregisters the function
4783 *
4784 * Returns 0 in case of success, -1 in case of error
4785 */
4786int
4787xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4788		       const xmlChar *ns_uri, xmlXPathFunction f) {
4789    if (ctxt == NULL)
4790	return(-1);
4791    if (name == NULL)
4792	return(-1);
4793
4794    if (ctxt->funcHash == NULL)
4795	ctxt->funcHash = xmlHashCreate(0);
4796    if (ctxt->funcHash == NULL)
4797	return(-1);
4798    if (f == NULL)
4799        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4800    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4801}
4802
4803/**
4804 * xmlXPathRegisterFuncLookup:
4805 * @ctxt:  the XPath context
4806 * @f:  the lookup function
4807 * @funcCtxt:  the lookup data
4808 *
4809 * Registers an external mechanism to do function lookup.
4810 */
4811void
4812xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4813			    xmlXPathFuncLookupFunc f,
4814			    void *funcCtxt) {
4815    if (ctxt == NULL)
4816	return;
4817    ctxt->funcLookupFunc = f;
4818    ctxt->funcLookupData = funcCtxt;
4819}
4820
4821/**
4822 * xmlXPathFunctionLookup:
4823 * @ctxt:  the XPath context
4824 * @name:  the function name
4825 *
4826 * Search in the Function array of the context for the given
4827 * function.
4828 *
4829 * Returns the xmlXPathFunction or NULL if not found
4830 */
4831xmlXPathFunction
4832xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4833    if (ctxt == NULL)
4834	return (NULL);
4835
4836    if (ctxt->funcLookupFunc != NULL) {
4837	xmlXPathFunction ret;
4838	xmlXPathFuncLookupFunc f;
4839
4840	f = ctxt->funcLookupFunc;
4841	ret = f(ctxt->funcLookupData, name, NULL);
4842	if (ret != NULL)
4843	    return(ret);
4844    }
4845    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4846}
4847
4848/**
4849 * xmlXPathFunctionLookupNS:
4850 * @ctxt:  the XPath context
4851 * @name:  the function name
4852 * @ns_uri:  the function namespace URI
4853 *
4854 * Search in the Function array of the context for the given
4855 * function.
4856 *
4857 * Returns the xmlXPathFunction or NULL if not found
4858 */
4859xmlXPathFunction
4860xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4861			 const xmlChar *ns_uri) {
4862    xmlXPathFunction ret;
4863
4864    if (ctxt == NULL)
4865	return(NULL);
4866    if (name == NULL)
4867	return(NULL);
4868
4869    if (ctxt->funcLookupFunc != NULL) {
4870	xmlXPathFuncLookupFunc f;
4871
4872	f = ctxt->funcLookupFunc;
4873	ret = f(ctxt->funcLookupData, name, ns_uri);
4874	if (ret != NULL)
4875	    return(ret);
4876    }
4877
4878    if (ctxt->funcHash == NULL)
4879	return(NULL);
4880
4881    XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4882    return(ret);
4883}
4884
4885/**
4886 * xmlXPathRegisteredFuncsCleanup:
4887 * @ctxt:  the XPath context
4888 *
4889 * Cleanup the XPath context data associated to registered functions
4890 */
4891void
4892xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4893    if (ctxt == NULL)
4894	return;
4895
4896    xmlHashFree(ctxt->funcHash, NULL);
4897    ctxt->funcHash = NULL;
4898}
4899
4900/************************************************************************
4901 *									*
4902 *			Routines to handle Variables			*
4903 *									*
4904 ************************************************************************/
4905
4906/**
4907 * xmlXPathRegisterVariable:
4908 * @ctxt:  the XPath context
4909 * @name:  the variable name
4910 * @value:  the variable value or NULL
4911 *
4912 * Register a new variable value. If @value is NULL it unregisters
4913 * the variable
4914 *
4915 * Returns 0 in case of success, -1 in case of error
4916 */
4917int
4918xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4919			 xmlXPathObjectPtr value) {
4920    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4921}
4922
4923/**
4924 * xmlXPathRegisterVariableNS:
4925 * @ctxt:  the XPath context
4926 * @name:  the variable name
4927 * @ns_uri:  the variable namespace URI
4928 * @value:  the variable value or NULL
4929 *
4930 * Register a new variable value. If @value is NULL it unregisters
4931 * the variable
4932 *
4933 * Returns 0 in case of success, -1 in case of error
4934 */
4935int
4936xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4937			   const xmlChar *ns_uri,
4938			   xmlXPathObjectPtr value) {
4939    if (ctxt == NULL)
4940	return(-1);
4941    if (name == NULL)
4942	return(-1);
4943
4944    if (ctxt->varHash == NULL)
4945	ctxt->varHash = xmlHashCreate(0);
4946    if (ctxt->varHash == NULL)
4947	return(-1);
4948    if (value == NULL)
4949        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4950	                           (xmlHashDeallocator)xmlXPathFreeObject));
4951    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4952			       (void *) value,
4953			       (xmlHashDeallocator)xmlXPathFreeObject));
4954}
4955
4956/**
4957 * xmlXPathRegisterVariableLookup:
4958 * @ctxt:  the XPath context
4959 * @f:  the lookup function
4960 * @data:  the lookup data
4961 *
4962 * register an external mechanism to do variable lookup
4963 */
4964void
4965xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4966	 xmlXPathVariableLookupFunc f, void *data) {
4967    if (ctxt == NULL)
4968	return;
4969    ctxt->varLookupFunc = f;
4970    ctxt->varLookupData = data;
4971}
4972
4973/**
4974 * xmlXPathVariableLookup:
4975 * @ctxt:  the XPath context
4976 * @name:  the variable name
4977 *
4978 * Search in the Variable array of the context for the given
4979 * variable value.
4980 *
4981 * Returns a copy of the value or NULL if not found
4982 */
4983xmlXPathObjectPtr
4984xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4985    if (ctxt == NULL)
4986	return(NULL);
4987
4988    if (ctxt->varLookupFunc != NULL) {
4989	xmlXPathObjectPtr ret;
4990
4991	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4992	        (ctxt->varLookupData, name, NULL);
4993	return(ret);
4994    }
4995    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4996}
4997
4998/**
4999 * xmlXPathVariableLookupNS:
5000 * @ctxt:  the XPath context
5001 * @name:  the variable name
5002 * @ns_uri:  the variable namespace URI
5003 *
5004 * Search in the Variable array of the context for the given
5005 * variable value.
5006 *
5007 * Returns the a copy of the value or NULL if not found
5008 */
5009xmlXPathObjectPtr
5010xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5011			 const xmlChar *ns_uri) {
5012    if (ctxt == NULL)
5013	return(NULL);
5014
5015    if (ctxt->varLookupFunc != NULL) {
5016	xmlXPathObjectPtr ret;
5017
5018	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5019	        (ctxt->varLookupData, name, ns_uri);
5020	if (ret != NULL) return(ret);
5021    }
5022
5023    if (ctxt->varHash == NULL)
5024	return(NULL);
5025    if (name == NULL)
5026	return(NULL);
5027
5028    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5029		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5030}
5031
5032/**
5033 * xmlXPathRegisteredVariablesCleanup:
5034 * @ctxt:  the XPath context
5035 *
5036 * Cleanup the XPath context data associated to registered variables
5037 */
5038void
5039xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5040    if (ctxt == NULL)
5041	return;
5042
5043    xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5044    ctxt->varHash = NULL;
5045}
5046
5047/**
5048 * xmlXPathRegisterNs:
5049 * @ctxt:  the XPath context
5050 * @prefix:  the namespace prefix cannot be NULL or empty string
5051 * @ns_uri:  the namespace name
5052 *
5053 * Register a new namespace. If @ns_uri is NULL it unregisters
5054 * the namespace
5055 *
5056 * Returns 0 in case of success, -1 in case of error
5057 */
5058int
5059xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5060			   const xmlChar *ns_uri) {
5061    if (ctxt == NULL)
5062	return(-1);
5063    if (prefix == NULL)
5064	return(-1);
5065    if (prefix[0] == 0)
5066	return(-1);
5067
5068    if (ctxt->nsHash == NULL)
5069	ctxt->nsHash = xmlHashCreate(10);
5070    if (ctxt->nsHash == NULL)
5071	return(-1);
5072    if (ns_uri == NULL)
5073        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5074	                          (xmlHashDeallocator)xmlFree));
5075    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5076			      (xmlHashDeallocator)xmlFree));
5077}
5078
5079/**
5080 * xmlXPathNsLookup:
5081 * @ctxt:  the XPath context
5082 * @prefix:  the namespace prefix value
5083 *
5084 * Search in the namespace declaration array of the context for the given
5085 * namespace name associated to the given prefix
5086 *
5087 * Returns the value or NULL if not found
5088 */
5089const xmlChar *
5090xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5091    if (ctxt == NULL)
5092	return(NULL);
5093    if (prefix == NULL)
5094	return(NULL);
5095
5096#ifdef XML_XML_NAMESPACE
5097    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5098	return(XML_XML_NAMESPACE);
5099#endif
5100
5101    if (ctxt->namespaces != NULL) {
5102	int i;
5103
5104	for (i = 0;i < ctxt->nsNr;i++) {
5105	    if ((ctxt->namespaces[i] != NULL) &&
5106		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5107		return(ctxt->namespaces[i]->href);
5108	}
5109    }
5110
5111    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5112}
5113
5114/**
5115 * xmlXPathRegisteredNsCleanup:
5116 * @ctxt:  the XPath context
5117 *
5118 * Cleanup the XPath context data associated to registered variables
5119 */
5120void
5121xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5122    if (ctxt == NULL)
5123	return;
5124
5125    xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5126    ctxt->nsHash = NULL;
5127}
5128
5129/************************************************************************
5130 *									*
5131 *			Routines to handle Values			*
5132 *									*
5133 ************************************************************************/
5134
5135/* Allocations are terrible, one needs to optimize all this !!! */
5136
5137/**
5138 * xmlXPathNewFloat:
5139 * @val:  the double value
5140 *
5141 * Create a new xmlXPathObjectPtr of type double and of value @val
5142 *
5143 * Returns the newly created object.
5144 */
5145xmlXPathObjectPtr
5146xmlXPathNewFloat(double val) {
5147    xmlXPathObjectPtr ret;
5148
5149    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5150    if (ret == NULL) {
5151        xmlXPathErrMemory(NULL, "creating float object\n");
5152	return(NULL);
5153    }
5154    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5155    ret->type = XPATH_NUMBER;
5156    ret->floatval = val;
5157#ifdef XP_DEBUG_OBJ_USAGE
5158    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5159#endif
5160    return(ret);
5161}
5162
5163/**
5164 * xmlXPathNewBoolean:
5165 * @val:  the boolean value
5166 *
5167 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5168 *
5169 * Returns the newly created object.
5170 */
5171xmlXPathObjectPtr
5172xmlXPathNewBoolean(int val) {
5173    xmlXPathObjectPtr ret;
5174
5175    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5176    if (ret == NULL) {
5177        xmlXPathErrMemory(NULL, "creating boolean object\n");
5178	return(NULL);
5179    }
5180    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5181    ret->type = XPATH_BOOLEAN;
5182    ret->boolval = (val != 0);
5183#ifdef XP_DEBUG_OBJ_USAGE
5184    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5185#endif
5186    return(ret);
5187}
5188
5189/**
5190 * xmlXPathNewString:
5191 * @val:  the xmlChar * value
5192 *
5193 * Create a new xmlXPathObjectPtr of type string and of value @val
5194 *
5195 * Returns the newly created object.
5196 */
5197xmlXPathObjectPtr
5198xmlXPathNewString(const xmlChar *val) {
5199    xmlXPathObjectPtr ret;
5200
5201    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5202    if (ret == NULL) {
5203        xmlXPathErrMemory(NULL, "creating string object\n");
5204	return(NULL);
5205    }
5206    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5207    ret->type = XPATH_STRING;
5208    if (val != NULL)
5209	ret->stringval = xmlStrdup(val);
5210    else
5211	ret->stringval = xmlStrdup((const xmlChar *)"");
5212#ifdef XP_DEBUG_OBJ_USAGE
5213    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5214#endif
5215    return(ret);
5216}
5217
5218/**
5219 * xmlXPathWrapString:
5220 * @val:  the xmlChar * value
5221 *
5222 * Wraps the @val string into an XPath object.
5223 *
5224 * Returns the newly created object.
5225 */
5226xmlXPathObjectPtr
5227xmlXPathWrapString (xmlChar *val) {
5228    xmlXPathObjectPtr ret;
5229
5230    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5231    if (ret == NULL) {
5232        xmlXPathErrMemory(NULL, "creating string object\n");
5233	return(NULL);
5234    }
5235    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5236    ret->type = XPATH_STRING;
5237    ret->stringval = val;
5238#ifdef XP_DEBUG_OBJ_USAGE
5239    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5240#endif
5241    return(ret);
5242}
5243
5244/**
5245 * xmlXPathNewCString:
5246 * @val:  the char * value
5247 *
5248 * Create a new xmlXPathObjectPtr of type string and of value @val
5249 *
5250 * Returns the newly created object.
5251 */
5252xmlXPathObjectPtr
5253xmlXPathNewCString(const char *val) {
5254    xmlXPathObjectPtr ret;
5255
5256    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5257    if (ret == NULL) {
5258        xmlXPathErrMemory(NULL, "creating string object\n");
5259	return(NULL);
5260    }
5261    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5262    ret->type = XPATH_STRING;
5263    ret->stringval = xmlStrdup(BAD_CAST val);
5264#ifdef XP_DEBUG_OBJ_USAGE
5265    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5266#endif
5267    return(ret);
5268}
5269
5270/**
5271 * xmlXPathWrapCString:
5272 * @val:  the char * value
5273 *
5274 * Wraps a string into an XPath object.
5275 *
5276 * Returns the newly created object.
5277 */
5278xmlXPathObjectPtr
5279xmlXPathWrapCString (char * val) {
5280    return(xmlXPathWrapString((xmlChar *)(val)));
5281}
5282
5283/**
5284 * xmlXPathWrapExternal:
5285 * @val:  the user data
5286 *
5287 * Wraps the @val data into an XPath object.
5288 *
5289 * Returns the newly created object.
5290 */
5291xmlXPathObjectPtr
5292xmlXPathWrapExternal (void *val) {
5293    xmlXPathObjectPtr ret;
5294
5295    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5296    if (ret == NULL) {
5297        xmlXPathErrMemory(NULL, "creating user object\n");
5298	return(NULL);
5299    }
5300    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5301    ret->type = XPATH_USERS;
5302    ret->user = val;
5303#ifdef XP_DEBUG_OBJ_USAGE
5304    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5305#endif
5306    return(ret);
5307}
5308
5309/**
5310 * xmlXPathObjectCopy:
5311 * @val:  the original object
5312 *
5313 * allocate a new copy of a given object
5314 *
5315 * Returns the newly created object.
5316 */
5317xmlXPathObjectPtr
5318xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5319    xmlXPathObjectPtr ret;
5320
5321    if (val == NULL)
5322	return(NULL);
5323
5324    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5325    if (ret == NULL) {
5326        xmlXPathErrMemory(NULL, "copying object\n");
5327	return(NULL);
5328    }
5329    memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5330#ifdef XP_DEBUG_OBJ_USAGE
5331    xmlXPathDebugObjUsageRequested(NULL, val->type);
5332#endif
5333    switch (val->type) {
5334	case XPATH_BOOLEAN:
5335	case XPATH_NUMBER:
5336	case XPATH_POINT:
5337	case XPATH_RANGE:
5338	    break;
5339	case XPATH_STRING:
5340	    ret->stringval = xmlStrdup(val->stringval);
5341	    break;
5342	case XPATH_XSLT_TREE:
5343#if 0
5344/*
5345  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5346  this previous handling is no longer correct, and can cause some serious
5347  problems (ref. bug 145547)
5348*/
5349	    if ((val->nodesetval != NULL) &&
5350		(val->nodesetval->nodeTab != NULL)) {
5351		xmlNodePtr cur, tmp;
5352		xmlDocPtr top;
5353
5354		ret->boolval = 1;
5355		top =  xmlNewDoc(NULL);
5356		top->name = (char *)
5357		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5358		ret->user = top;
5359		if (top != NULL) {
5360		    top->doc = top;
5361		    cur = val->nodesetval->nodeTab[0]->children;
5362		    while (cur != NULL) {
5363			tmp = xmlDocCopyNode(cur, top, 1);
5364			xmlAddChild((xmlNodePtr) top, tmp);
5365			cur = cur->next;
5366		    }
5367		}
5368
5369		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5370	    } else
5371		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5372	    /* Deallocate the copied tree value */
5373	    break;
5374#endif
5375	case XPATH_NODESET:
5376	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5377	    /* Do not deallocate the copied tree value */
5378	    ret->boolval = 0;
5379	    break;
5380	case XPATH_LOCATIONSET:
5381#ifdef LIBXML_XPTR_ENABLED
5382	{
5383	    xmlLocationSetPtr loc = val->user;
5384	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5385	    break;
5386	}
5387#endif
5388        case XPATH_USERS:
5389	    ret->user = val->user;
5390	    break;
5391        case XPATH_UNDEFINED:
5392	    xmlGenericError(xmlGenericErrorContext,
5393		    "xmlXPathObjectCopy: unsupported type %d\n",
5394		    val->type);
5395	    break;
5396    }
5397    return(ret);
5398}
5399
5400/**
5401 * xmlXPathFreeObject:
5402 * @obj:  the object to free
5403 *
5404 * Free up an xmlXPathObjectPtr object.
5405 */
5406void
5407xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5408    if (obj == NULL) return;
5409    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5410	if (obj->boolval) {
5411#if 0
5412	    if (obj->user != NULL) {
5413                xmlXPathFreeNodeSet(obj->nodesetval);
5414		xmlFreeNodeList((xmlNodePtr) obj->user);
5415	    } else
5416#endif
5417	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5418	    if (obj->nodesetval != NULL)
5419		xmlXPathFreeValueTree(obj->nodesetval);
5420	} else {
5421	    if (obj->nodesetval != NULL)
5422		xmlXPathFreeNodeSet(obj->nodesetval);
5423	}
5424#ifdef LIBXML_XPTR_ENABLED
5425    } else if (obj->type == XPATH_LOCATIONSET) {
5426	if (obj->user != NULL)
5427	    xmlXPtrFreeLocationSet(obj->user);
5428#endif
5429    } else if (obj->type == XPATH_STRING) {
5430	if (obj->stringval != NULL)
5431	    xmlFree(obj->stringval);
5432    }
5433#ifdef XP_DEBUG_OBJ_USAGE
5434    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5435#endif
5436    xmlFree(obj);
5437}
5438
5439/**
5440 * xmlXPathReleaseObject:
5441 * @obj:  the xmlXPathObjectPtr to free or to cache
5442 *
5443 * Depending on the state of the cache this frees the given
5444 * XPath object or stores it in the cache.
5445 */
5446static void
5447xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5448{
5449#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5450	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5451    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5452
5453#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5454
5455    if (obj == NULL)
5456	return;
5457    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5458	 xmlXPathFreeObject(obj);
5459    } else {
5460	xmlXPathContextCachePtr cache =
5461	    (xmlXPathContextCachePtr) ctxt->cache;
5462
5463	switch (obj->type) {
5464	    case XPATH_NODESET:
5465	    case XPATH_XSLT_TREE:
5466		if (obj->nodesetval != NULL) {
5467		    if (obj->boolval) {
5468			/*
5469			* It looks like the @boolval is used for
5470			* evaluation if this an XSLT Result Tree Fragment.
5471			* TODO: Check if this assumption is correct.
5472			*/
5473			obj->type = XPATH_XSLT_TREE; /* just for debugging */
5474			xmlXPathFreeValueTree(obj->nodesetval);
5475			obj->nodesetval = NULL;
5476		    } else if ((obj->nodesetval->nodeMax <= 40) &&
5477			(XP_CACHE_WANTS(cache->nodesetObjs,
5478					cache->maxNodeset)))
5479		    {
5480			XP_CACHE_ADD(cache->nodesetObjs, obj);
5481			goto obj_cached;
5482		    } else {
5483			xmlXPathFreeNodeSet(obj->nodesetval);
5484			obj->nodesetval = NULL;
5485		    }
5486		}
5487		break;
5488	    case XPATH_STRING:
5489		if (obj->stringval != NULL)
5490		    xmlFree(obj->stringval);
5491
5492		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5493		    XP_CACHE_ADD(cache->stringObjs, obj);
5494		    goto obj_cached;
5495		}
5496		break;
5497	    case XPATH_BOOLEAN:
5498		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5499		    XP_CACHE_ADD(cache->booleanObjs, obj);
5500		    goto obj_cached;
5501		}
5502		break;
5503	    case XPATH_NUMBER:
5504		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5505		    XP_CACHE_ADD(cache->numberObjs, obj);
5506		    goto obj_cached;
5507		}
5508		break;
5509#ifdef LIBXML_XPTR_ENABLED
5510	    case XPATH_LOCATIONSET:
5511		if (obj->user != NULL) {
5512		    xmlXPtrFreeLocationSet(obj->user);
5513		}
5514		goto free_obj;
5515#endif
5516	    default:
5517		goto free_obj;
5518	}
5519
5520	/*
5521	* Fallback to adding to the misc-objects slot.
5522	*/
5523	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5524	    XP_CACHE_ADD(cache->miscObjs, obj);
5525	} else
5526	    goto free_obj;
5527
5528obj_cached:
5529
5530#ifdef XP_DEBUG_OBJ_USAGE
5531	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5532#endif
5533
5534	if (obj->nodesetval != NULL) {
5535	    xmlNodeSetPtr tmpset = obj->nodesetval;
5536
5537	    /*
5538	    * TODO: Due to those nasty ns-nodes, we need to traverse
5539	    *  the list and free the ns-nodes.
5540	    * URGENT TODO: Check if it's actually slowing things down.
5541	    *  Maybe we shouldn't try to preserve the list.
5542	    */
5543	    if (tmpset->nodeNr > 1) {
5544		int i;
5545		xmlNodePtr node;
5546
5547		for (i = 0; i < tmpset->nodeNr; i++) {
5548		    node = tmpset->nodeTab[i];
5549		    if ((node != NULL) &&
5550			(node->type == XML_NAMESPACE_DECL))
5551		    {
5552			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5553		    }
5554		}
5555	    } else if (tmpset->nodeNr == 1) {
5556		if ((tmpset->nodeTab[0] != NULL) &&
5557		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5558		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5559	    }
5560	    tmpset->nodeNr = 0;
5561	    memset(obj, 0, sizeof(xmlXPathObject));
5562	    obj->nodesetval = tmpset;
5563	} else
5564	    memset(obj, 0, sizeof(xmlXPathObject));
5565
5566	return;
5567
5568free_obj:
5569	/*
5570	* Cache is full; free the object.
5571	*/
5572	if (obj->nodesetval != NULL)
5573	    xmlXPathFreeNodeSet(obj->nodesetval);
5574#ifdef XP_DEBUG_OBJ_USAGE
5575	xmlXPathDebugObjUsageReleased(NULL, obj->type);
5576#endif
5577	xmlFree(obj);
5578    }
5579    return;
5580}
5581
5582
5583/************************************************************************
5584 *									*
5585 *			Type Casting Routines				*
5586 *									*
5587 ************************************************************************/
5588
5589/**
5590 * xmlXPathCastBooleanToString:
5591 * @val:  a boolean
5592 *
5593 * Converts a boolean to its string value.
5594 *
5595 * Returns a newly allocated string.
5596 */
5597xmlChar *
5598xmlXPathCastBooleanToString (int val) {
5599    xmlChar *ret;
5600    if (val)
5601	ret = xmlStrdup((const xmlChar *) "true");
5602    else
5603	ret = xmlStrdup((const xmlChar *) "false");
5604    return(ret);
5605}
5606
5607/**
5608 * xmlXPathCastNumberToString:
5609 * @val:  a number
5610 *
5611 * Converts a number to its string value.
5612 *
5613 * Returns a newly allocated string.
5614 */
5615xmlChar *
5616xmlXPathCastNumberToString (double val) {
5617    xmlChar *ret;
5618    switch (xmlXPathIsInf(val)) {
5619    case 1:
5620	ret = xmlStrdup((const xmlChar *) "Infinity");
5621	break;
5622    case -1:
5623	ret = xmlStrdup((const xmlChar *) "-Infinity");
5624	break;
5625    default:
5626	if (xmlXPathIsNaN(val)) {
5627	    ret = xmlStrdup((const xmlChar *) "NaN");
5628	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
5629	    ret = xmlStrdup((const xmlChar *) "0");
5630	} else {
5631	    /* could be improved */
5632	    char buf[100];
5633	    xmlXPathFormatNumber(val, buf, 99);
5634	    buf[99] = 0;
5635	    ret = xmlStrdup((const xmlChar *) buf);
5636	}
5637    }
5638    return(ret);
5639}
5640
5641/**
5642 * xmlXPathCastNodeToString:
5643 * @node:  a node
5644 *
5645 * Converts a node to its string value.
5646 *
5647 * Returns a newly allocated string.
5648 */
5649xmlChar *
5650xmlXPathCastNodeToString (xmlNodePtr node) {
5651xmlChar *ret;
5652    if ((ret = xmlNodeGetContent(node)) == NULL)
5653	ret = xmlStrdup((const xmlChar *) "");
5654    return(ret);
5655}
5656
5657/**
5658 * xmlXPathCastNodeSetToString:
5659 * @ns:  a node-set
5660 *
5661 * Converts a node-set to its string value.
5662 *
5663 * Returns a newly allocated string.
5664 */
5665xmlChar *
5666xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5667    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5668	return(xmlStrdup((const xmlChar *) ""));
5669
5670    if (ns->nodeNr > 1)
5671	xmlXPathNodeSetSort(ns);
5672    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5673}
5674
5675/**
5676 * xmlXPathCastToString:
5677 * @val:  an XPath object
5678 *
5679 * Converts an existing object to its string() equivalent
5680 *
5681 * Returns the allocated string value of the object, NULL in case of error.
5682 *         It's up to the caller to free the string memory with xmlFree().
5683 */
5684xmlChar *
5685xmlXPathCastToString(xmlXPathObjectPtr val) {
5686    xmlChar *ret = NULL;
5687
5688    if (val == NULL)
5689	return(xmlStrdup((const xmlChar *) ""));
5690    switch (val->type) {
5691	case XPATH_UNDEFINED:
5692#ifdef DEBUG_EXPR
5693	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5694#endif
5695	    ret = xmlStrdup((const xmlChar *) "");
5696	    break;
5697        case XPATH_NODESET:
5698        case XPATH_XSLT_TREE:
5699	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5700	    break;
5701	case XPATH_STRING:
5702	    return(xmlStrdup(val->stringval));
5703        case XPATH_BOOLEAN:
5704	    ret = xmlXPathCastBooleanToString(val->boolval);
5705	    break;
5706	case XPATH_NUMBER: {
5707	    ret = xmlXPathCastNumberToString(val->floatval);
5708	    break;
5709	}
5710	case XPATH_USERS:
5711	case XPATH_POINT:
5712	case XPATH_RANGE:
5713	case XPATH_LOCATIONSET:
5714	    TODO
5715	    ret = xmlStrdup((const xmlChar *) "");
5716	    break;
5717    }
5718    return(ret);
5719}
5720
5721/**
5722 * xmlXPathConvertString:
5723 * @val:  an XPath object
5724 *
5725 * Converts an existing object to its string() equivalent
5726 *
5727 * Returns the new object, the old one is freed (or the operation
5728 *         is done directly on @val)
5729 */
5730xmlXPathObjectPtr
5731xmlXPathConvertString(xmlXPathObjectPtr val) {
5732    xmlChar *res = NULL;
5733
5734    if (val == NULL)
5735	return(xmlXPathNewCString(""));
5736
5737    switch (val->type) {
5738    case XPATH_UNDEFINED:
5739#ifdef DEBUG_EXPR
5740	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5741#endif
5742	break;
5743    case XPATH_NODESET:
5744    case XPATH_XSLT_TREE:
5745	res = xmlXPathCastNodeSetToString(val->nodesetval);
5746	break;
5747    case XPATH_STRING:
5748	return(val);
5749    case XPATH_BOOLEAN:
5750	res = xmlXPathCastBooleanToString(val->boolval);
5751	break;
5752    case XPATH_NUMBER:
5753	res = xmlXPathCastNumberToString(val->floatval);
5754	break;
5755    case XPATH_USERS:
5756    case XPATH_POINT:
5757    case XPATH_RANGE:
5758    case XPATH_LOCATIONSET:
5759	TODO;
5760	break;
5761    }
5762    xmlXPathFreeObject(val);
5763    if (res == NULL)
5764	return(xmlXPathNewCString(""));
5765    return(xmlXPathWrapString(res));
5766}
5767
5768/**
5769 * xmlXPathCastBooleanToNumber:
5770 * @val:  a boolean
5771 *
5772 * Converts a boolean to its number value
5773 *
5774 * Returns the number value
5775 */
5776double
5777xmlXPathCastBooleanToNumber(int val) {
5778    if (val)
5779	return(1.0);
5780    return(0.0);
5781}
5782
5783/**
5784 * xmlXPathCastStringToNumber:
5785 * @val:  a string
5786 *
5787 * Converts a string to its number value
5788 *
5789 * Returns the number value
5790 */
5791double
5792xmlXPathCastStringToNumber(const xmlChar * val) {
5793    return(xmlXPathStringEvalNumber(val));
5794}
5795
5796/**
5797 * xmlXPathCastNodeToNumber:
5798 * @node:  a node
5799 *
5800 * Converts a node to its number value
5801 *
5802 * Returns the number value
5803 */
5804double
5805xmlXPathCastNodeToNumber (xmlNodePtr node) {
5806    xmlChar *strval;
5807    double ret;
5808
5809    if (node == NULL)
5810	return(xmlXPathNAN);
5811    strval = xmlXPathCastNodeToString(node);
5812    if (strval == NULL)
5813	return(xmlXPathNAN);
5814    ret = xmlXPathCastStringToNumber(strval);
5815    xmlFree(strval);
5816
5817    return(ret);
5818}
5819
5820/**
5821 * xmlXPathCastNodeSetToNumber:
5822 * @ns:  a node-set
5823 *
5824 * Converts a node-set to its number value
5825 *
5826 * Returns the number value
5827 */
5828double
5829xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5830    xmlChar *str;
5831    double ret;
5832
5833    if (ns == NULL)
5834	return(xmlXPathNAN);
5835    str = xmlXPathCastNodeSetToString(ns);
5836    ret = xmlXPathCastStringToNumber(str);
5837    xmlFree(str);
5838    return(ret);
5839}
5840
5841/**
5842 * xmlXPathCastToNumber:
5843 * @val:  an XPath object
5844 *
5845 * Converts an XPath object to its number value
5846 *
5847 * Returns the number value
5848 */
5849double
5850xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5851    double ret = 0.0;
5852
5853    if (val == NULL)
5854	return(xmlXPathNAN);
5855    switch (val->type) {
5856    case XPATH_UNDEFINED:
5857#ifdef DEGUB_EXPR
5858	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5859#endif
5860	ret = xmlXPathNAN;
5861	break;
5862    case XPATH_NODESET:
5863    case XPATH_XSLT_TREE:
5864	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5865	break;
5866    case XPATH_STRING:
5867	ret = xmlXPathCastStringToNumber(val->stringval);
5868	break;
5869    case XPATH_NUMBER:
5870	ret = val->floatval;
5871	break;
5872    case XPATH_BOOLEAN:
5873	ret = xmlXPathCastBooleanToNumber(val->boolval);
5874	break;
5875    case XPATH_USERS:
5876    case XPATH_POINT:
5877    case XPATH_RANGE:
5878    case XPATH_LOCATIONSET:
5879	TODO;
5880	ret = xmlXPathNAN;
5881	break;
5882    }
5883    return(ret);
5884}
5885
5886/**
5887 * xmlXPathConvertNumber:
5888 * @val:  an XPath object
5889 *
5890 * Converts an existing object to its number() equivalent
5891 *
5892 * Returns the new object, the old one is freed (or the operation
5893 *         is done directly on @val)
5894 */
5895xmlXPathObjectPtr
5896xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5897    xmlXPathObjectPtr ret;
5898
5899    if (val == NULL)
5900	return(xmlXPathNewFloat(0.0));
5901    if (val->type == XPATH_NUMBER)
5902	return(val);
5903    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5904    xmlXPathFreeObject(val);
5905    return(ret);
5906}
5907
5908/**
5909 * xmlXPathCastNumberToBoolean:
5910 * @val:  a number
5911 *
5912 * Converts a number to its boolean value
5913 *
5914 * Returns the boolean value
5915 */
5916int
5917xmlXPathCastNumberToBoolean (double val) {
5918     if (xmlXPathIsNaN(val) || (val == 0.0))
5919	 return(0);
5920     return(1);
5921}
5922
5923/**
5924 * xmlXPathCastStringToBoolean:
5925 * @val:  a string
5926 *
5927 * Converts a string to its boolean value
5928 *
5929 * Returns the boolean value
5930 */
5931int
5932xmlXPathCastStringToBoolean (const xmlChar *val) {
5933    if ((val == NULL) || (xmlStrlen(val) == 0))
5934	return(0);
5935    return(1);
5936}
5937
5938/**
5939 * xmlXPathCastNodeSetToBoolean:
5940 * @ns:  a node-set
5941 *
5942 * Converts a node-set to its boolean value
5943 *
5944 * Returns the boolean value
5945 */
5946int
5947xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5948    if ((ns == NULL) || (ns->nodeNr == 0))
5949	return(0);
5950    return(1);
5951}
5952
5953/**
5954 * xmlXPathCastToBoolean:
5955 * @val:  an XPath object
5956 *
5957 * Converts an XPath object to its boolean value
5958 *
5959 * Returns the boolean value
5960 */
5961int
5962xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5963    int ret = 0;
5964
5965    if (val == NULL)
5966	return(0);
5967    switch (val->type) {
5968    case XPATH_UNDEFINED:
5969#ifdef DEBUG_EXPR
5970	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5971#endif
5972	ret = 0;
5973	break;
5974    case XPATH_NODESET:
5975    case XPATH_XSLT_TREE:
5976	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5977	break;
5978    case XPATH_STRING:
5979	ret = xmlXPathCastStringToBoolean(val->stringval);
5980	break;
5981    case XPATH_NUMBER:
5982	ret = xmlXPathCastNumberToBoolean(val->floatval);
5983	break;
5984    case XPATH_BOOLEAN:
5985	ret = val->boolval;
5986	break;
5987    case XPATH_USERS:
5988    case XPATH_POINT:
5989    case XPATH_RANGE:
5990    case XPATH_LOCATIONSET:
5991	TODO;
5992	ret = 0;
5993	break;
5994    }
5995    return(ret);
5996}
5997
5998
5999/**
6000 * xmlXPathConvertBoolean:
6001 * @val:  an XPath object
6002 *
6003 * Converts an existing object to its boolean() equivalent
6004 *
6005 * Returns the new object, the old one is freed (or the operation
6006 *         is done directly on @val)
6007 */
6008xmlXPathObjectPtr
6009xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6010    xmlXPathObjectPtr ret;
6011
6012    if (val == NULL)
6013	return(xmlXPathNewBoolean(0));
6014    if (val->type == XPATH_BOOLEAN)
6015	return(val);
6016    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6017    xmlXPathFreeObject(val);
6018    return(ret);
6019}
6020
6021/************************************************************************
6022 *									*
6023 *		Routines to handle XPath contexts			*
6024 *									*
6025 ************************************************************************/
6026
6027/**
6028 * xmlXPathNewContext:
6029 * @doc:  the XML document
6030 *
6031 * Create a new xmlXPathContext
6032 *
6033 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6034 */
6035xmlXPathContextPtr
6036xmlXPathNewContext(xmlDocPtr doc) {
6037    xmlXPathContextPtr ret;
6038
6039    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6040    if (ret == NULL) {
6041        xmlXPathErrMemory(NULL, "creating context\n");
6042	return(NULL);
6043    }
6044    memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6045    ret->doc = doc;
6046    ret->node = NULL;
6047
6048    ret->varHash = NULL;
6049
6050    ret->nb_types = 0;
6051    ret->max_types = 0;
6052    ret->types = NULL;
6053
6054    ret->funcHash = xmlHashCreate(0);
6055
6056    ret->nb_axis = 0;
6057    ret->max_axis = 0;
6058    ret->axis = NULL;
6059
6060    ret->nsHash = NULL;
6061    ret->user = NULL;
6062
6063    ret->contextSize = -1;
6064    ret->proximityPosition = -1;
6065
6066#ifdef XP_DEFAULT_CACHE_ON
6067    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6068	xmlXPathFreeContext(ret);
6069	return(NULL);
6070    }
6071#endif
6072
6073    xmlXPathRegisterAllFunctions(ret);
6074
6075    return(ret);
6076}
6077
6078/**
6079 * xmlXPathFreeContext:
6080 * @ctxt:  the context to free
6081 *
6082 * Free up an xmlXPathContext
6083 */
6084void
6085xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6086    if (ctxt == NULL) return;
6087
6088    if (ctxt->cache != NULL)
6089	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6090    xmlXPathRegisteredNsCleanup(ctxt);
6091    xmlXPathRegisteredFuncsCleanup(ctxt);
6092    xmlXPathRegisteredVariablesCleanup(ctxt);
6093    xmlResetError(&ctxt->lastError);
6094    xmlFree(ctxt);
6095}
6096
6097/************************************************************************
6098 *									*
6099 *		Routines to handle XPath parser contexts		*
6100 *									*
6101 ************************************************************************/
6102
6103#define CHECK_CTXT(ctxt)						\
6104    if (ctxt == NULL) {						\
6105	__xmlRaiseError(NULL, NULL, NULL,				\
6106		NULL, NULL, XML_FROM_XPATH,				\
6107		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6108		__FILE__, __LINE__,					\
6109		NULL, NULL, NULL, 0, 0,					\
6110		"NULL context pointer\n");				\
6111	return(NULL);							\
6112    }									\
6113
6114#define CHECK_CTXT_NEG(ctxt)						\
6115    if (ctxt == NULL) {						\
6116	__xmlRaiseError(NULL, NULL, NULL,				\
6117		NULL, NULL, XML_FROM_XPATH,				\
6118		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6119		__FILE__, __LINE__,					\
6120		NULL, NULL, NULL, 0, 0,					\
6121		"NULL context pointer\n");				\
6122	return(-1);							\
6123    }									\
6124
6125
6126#define CHECK_CONTEXT(ctxt)						\
6127    if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
6128        (ctxt->doc->children == NULL)) {				\
6129	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
6130	return(NULL);							\
6131    }
6132
6133
6134/**
6135 * xmlXPathNewParserContext:
6136 * @str:  the XPath expression
6137 * @ctxt:  the XPath context
6138 *
6139 * Create a new xmlXPathParserContext
6140 *
6141 * Returns the xmlXPathParserContext just allocated.
6142 */
6143xmlXPathParserContextPtr
6144xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6145    xmlXPathParserContextPtr ret;
6146
6147    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6148    if (ret == NULL) {
6149        xmlXPathErrMemory(ctxt, "creating parser context\n");
6150	return(NULL);
6151    }
6152    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6153    ret->cur = ret->base = str;
6154    ret->context = ctxt;
6155
6156    ret->comp = xmlXPathNewCompExpr();
6157    if (ret->comp == NULL) {
6158	xmlFree(ret->valueTab);
6159	xmlFree(ret);
6160	return(NULL);
6161    }
6162    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6163        ret->comp->dict = ctxt->dict;
6164	xmlDictReference(ret->comp->dict);
6165    }
6166
6167    return(ret);
6168}
6169
6170/**
6171 * xmlXPathCompParserContext:
6172 * @comp:  the XPath compiled expression
6173 * @ctxt:  the XPath context
6174 *
6175 * Create a new xmlXPathParserContext when processing a compiled expression
6176 *
6177 * Returns the xmlXPathParserContext just allocated.
6178 */
6179static xmlXPathParserContextPtr
6180xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6181    xmlXPathParserContextPtr ret;
6182
6183    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6184    if (ret == NULL) {
6185        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6186	return(NULL);
6187    }
6188    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6189
6190    /* Allocate the value stack */
6191    ret->valueTab = (xmlXPathObjectPtr *)
6192                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6193    if (ret->valueTab == NULL) {
6194	xmlFree(ret);
6195	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6196	return(NULL);
6197    }
6198    ret->valueNr = 0;
6199    ret->valueMax = 10;
6200    ret->value = NULL;
6201    ret->valueFrame = 0;
6202
6203    ret->context = ctxt;
6204    ret->comp = comp;
6205
6206    return(ret);
6207}
6208
6209/**
6210 * xmlXPathFreeParserContext:
6211 * @ctxt:  the context to free
6212 *
6213 * Free up an xmlXPathParserContext
6214 */
6215void
6216xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6217    if (ctxt->valueTab != NULL) {
6218        xmlFree(ctxt->valueTab);
6219    }
6220    if (ctxt->comp != NULL) {
6221#ifdef XPATH_STREAMING
6222	if (ctxt->comp->stream != NULL) {
6223	    xmlFreePatternList(ctxt->comp->stream);
6224	    ctxt->comp->stream = NULL;
6225	}
6226#endif
6227	xmlXPathFreeCompExpr(ctxt->comp);
6228    }
6229    xmlFree(ctxt);
6230}
6231
6232/************************************************************************
6233 *									*
6234 *		The implicit core function library			*
6235 *									*
6236 ************************************************************************/
6237
6238/**
6239 * xmlXPathNodeValHash:
6240 * @node:  a node pointer
6241 *
6242 * Function computing the beginning of the string value of the node,
6243 * used to speed up comparisons
6244 *
6245 * Returns an int usable as a hash
6246 */
6247static unsigned int
6248xmlXPathNodeValHash(xmlNodePtr node) {
6249    int len = 2;
6250    const xmlChar * string = NULL;
6251    xmlNodePtr tmp = NULL;
6252    unsigned int ret = 0;
6253
6254    if (node == NULL)
6255	return(0);
6256
6257    if (node->type == XML_DOCUMENT_NODE) {
6258	tmp = xmlDocGetRootElement((xmlDocPtr) node);
6259	if (tmp == NULL)
6260	    node = node->children;
6261	else
6262	    node = tmp;
6263
6264	if (node == NULL)
6265	    return(0);
6266    }
6267
6268    switch (node->type) {
6269	case XML_COMMENT_NODE:
6270	case XML_PI_NODE:
6271	case XML_CDATA_SECTION_NODE:
6272	case XML_TEXT_NODE:
6273	    string = node->content;
6274	    if (string == NULL)
6275		return(0);
6276	    if (string[0] == 0)
6277		return(0);
6278	    return(((unsigned int) string[0]) +
6279		   (((unsigned int) string[1]) << 8));
6280	case XML_NAMESPACE_DECL:
6281	    string = ((xmlNsPtr)node)->href;
6282	    if (string == NULL)
6283		return(0);
6284	    if (string[0] == 0)
6285		return(0);
6286	    return(((unsigned int) string[0]) +
6287		   (((unsigned int) string[1]) << 8));
6288	case XML_ATTRIBUTE_NODE:
6289	    tmp = ((xmlAttrPtr) node)->children;
6290	    break;
6291	case XML_ELEMENT_NODE:
6292	    tmp = node->children;
6293	    break;
6294	default:
6295	    return(0);
6296    }
6297    while (tmp != NULL) {
6298	switch (tmp->type) {
6299	    case XML_COMMENT_NODE:
6300	    case XML_PI_NODE:
6301	    case XML_CDATA_SECTION_NODE:
6302	    case XML_TEXT_NODE:
6303		string = tmp->content;
6304		break;
6305	    case XML_NAMESPACE_DECL:
6306		string = ((xmlNsPtr)tmp)->href;
6307		break;
6308	    default:
6309		break;
6310	}
6311	if ((string != NULL) && (string[0] != 0)) {
6312	    if (len == 1) {
6313		return(ret + (((unsigned int) string[0]) << 8));
6314	    }
6315	    if (string[1] == 0) {
6316		len = 1;
6317		ret = (unsigned int) string[0];
6318	    } else {
6319		return(((unsigned int) string[0]) +
6320		       (((unsigned int) string[1]) << 8));
6321	    }
6322	}
6323	/*
6324	 * Skip to next node
6325	 */
6326	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6327	    if (tmp->children->type != XML_ENTITY_DECL) {
6328		tmp = tmp->children;
6329		continue;
6330	    }
6331	}
6332	if (tmp == node)
6333	    break;
6334
6335	if (tmp->next != NULL) {
6336	    tmp = tmp->next;
6337	    continue;
6338	}
6339
6340	do {
6341	    tmp = tmp->parent;
6342	    if (tmp == NULL)
6343		break;
6344	    if (tmp == node) {
6345		tmp = NULL;
6346		break;
6347	    }
6348	    if (tmp->next != NULL) {
6349		tmp = tmp->next;
6350		break;
6351	    }
6352	} while (tmp != NULL);
6353    }
6354    return(ret);
6355}
6356
6357/**
6358 * xmlXPathStringHash:
6359 * @string:  a string
6360 *
6361 * Function computing the beginning of the string value of the node,
6362 * used to speed up comparisons
6363 *
6364 * Returns an int usable as a hash
6365 */
6366static unsigned int
6367xmlXPathStringHash(const xmlChar * string) {
6368    if (string == NULL)
6369	return((unsigned int) 0);
6370    if (string[0] == 0)
6371	return(0);
6372    return(((unsigned int) string[0]) +
6373	   (((unsigned int) string[1]) << 8));
6374}
6375
6376/**
6377 * xmlXPathCompareNodeSetFloat:
6378 * @ctxt:  the XPath Parser context
6379 * @inf:  less than (1) or greater than (0)
6380 * @strict:  is the comparison strict
6381 * @arg:  the node set
6382 * @f:  the value
6383 *
6384 * Implement the compare operation between a nodeset and a number
6385 *     @ns < @val    (1, 1, ...
6386 *     @ns <= @val   (1, 0, ...
6387 *     @ns > @val    (0, 1, ...
6388 *     @ns >= @val   (0, 0, ...
6389 *
6390 * If one object to be compared is a node-set and the other is a number,
6391 * then the comparison will be true if and only if there is a node in the
6392 * node-set such that the result of performing the comparison on the number
6393 * to be compared and on the result of converting the string-value of that
6394 * node to a number using the number function is true.
6395 *
6396 * Returns 0 or 1 depending on the results of the test.
6397 */
6398static int
6399xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6400	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6401    int i, ret = 0;
6402    xmlNodeSetPtr ns;
6403    xmlChar *str2;
6404
6405    if ((f == NULL) || (arg == NULL) ||
6406	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6407	xmlXPathReleaseObject(ctxt->context, arg);
6408	xmlXPathReleaseObject(ctxt->context, f);
6409        return(0);
6410    }
6411    ns = arg->nodesetval;
6412    if (ns != NULL) {
6413	for (i = 0;i < ns->nodeNr;i++) {
6414	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6415	     if (str2 != NULL) {
6416		 valuePush(ctxt,
6417			   xmlXPathCacheNewString(ctxt->context, str2));
6418		 xmlFree(str2);
6419		 xmlXPathNumberFunction(ctxt, 1);
6420		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6421		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6422		 if (ret)
6423		     break;
6424	     }
6425	}
6426    }
6427    xmlXPathReleaseObject(ctxt->context, arg);
6428    xmlXPathReleaseObject(ctxt->context, f);
6429    return(ret);
6430}
6431
6432/**
6433 * xmlXPathCompareNodeSetString:
6434 * @ctxt:  the XPath Parser context
6435 * @inf:  less than (1) or greater than (0)
6436 * @strict:  is the comparison strict
6437 * @arg:  the node set
6438 * @s:  the value
6439 *
6440 * Implement the compare operation between a nodeset and a string
6441 *     @ns < @val    (1, 1, ...
6442 *     @ns <= @val   (1, 0, ...
6443 *     @ns > @val    (0, 1, ...
6444 *     @ns >= @val   (0, 0, ...
6445 *
6446 * If one object to be compared is a node-set and the other is a string,
6447 * then the comparison will be true if and only if there is a node in
6448 * the node-set such that the result of performing the comparison on the
6449 * string-value of the node and the other string is true.
6450 *
6451 * Returns 0 or 1 depending on the results of the test.
6452 */
6453static int
6454xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6455	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6456    int i, ret = 0;
6457    xmlNodeSetPtr ns;
6458    xmlChar *str2;
6459
6460    if ((s == NULL) || (arg == NULL) ||
6461	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6462	xmlXPathReleaseObject(ctxt->context, arg);
6463	xmlXPathReleaseObject(ctxt->context, s);
6464        return(0);
6465    }
6466    ns = arg->nodesetval;
6467    if (ns != NULL) {
6468	for (i = 0;i < ns->nodeNr;i++) {
6469	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6470	     if (str2 != NULL) {
6471		 valuePush(ctxt,
6472			   xmlXPathCacheNewString(ctxt->context, str2));
6473		 xmlFree(str2);
6474		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6475		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6476		 if (ret)
6477		     break;
6478	     }
6479	}
6480    }
6481    xmlXPathReleaseObject(ctxt->context, arg);
6482    xmlXPathReleaseObject(ctxt->context, s);
6483    return(ret);
6484}
6485
6486/**
6487 * xmlXPathCompareNodeSets:
6488 * @inf:  less than (1) or greater than (0)
6489 * @strict:  is the comparison strict
6490 * @arg1:  the first node set object
6491 * @arg2:  the second node set object
6492 *
6493 * Implement the compare operation on nodesets:
6494 *
6495 * If both objects to be compared are node-sets, then the comparison
6496 * will be true if and only if there is a node in the first node-set
6497 * and a node in the second node-set such that the result of performing
6498 * the comparison on the string-values of the two nodes is true.
6499 * ....
6500 * When neither object to be compared is a node-set and the operator
6501 * is <=, <, >= or >, then the objects are compared by converting both
6502 * objects to numbers and comparing the numbers according to IEEE 754.
6503 * ....
6504 * The number function converts its argument to a number as follows:
6505 *  - a string that consists of optional whitespace followed by an
6506 *    optional minus sign followed by a Number followed by whitespace
6507 *    is converted to the IEEE 754 number that is nearest (according
6508 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6509 *    represented by the string; any other string is converted to NaN
6510 *
6511 * Conclusion all nodes need to be converted first to their string value
6512 * and then the comparison must be done when possible
6513 */
6514static int
6515xmlXPathCompareNodeSets(int inf, int strict,
6516	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6517    int i, j, init = 0;
6518    double val1;
6519    double *values2;
6520    int ret = 0;
6521    xmlNodeSetPtr ns1;
6522    xmlNodeSetPtr ns2;
6523
6524    if ((arg1 == NULL) ||
6525	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6526	xmlXPathFreeObject(arg2);
6527        return(0);
6528    }
6529    if ((arg2 == NULL) ||
6530	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6531	xmlXPathFreeObject(arg1);
6532	xmlXPathFreeObject(arg2);
6533        return(0);
6534    }
6535
6536    ns1 = arg1->nodesetval;
6537    ns2 = arg2->nodesetval;
6538
6539    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6540	xmlXPathFreeObject(arg1);
6541	xmlXPathFreeObject(arg2);
6542	return(0);
6543    }
6544    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6545	xmlXPathFreeObject(arg1);
6546	xmlXPathFreeObject(arg2);
6547	return(0);
6548    }
6549
6550    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6551    if (values2 == NULL) {
6552        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6553	xmlXPathFreeObject(arg1);
6554	xmlXPathFreeObject(arg2);
6555	return(0);
6556    }
6557    for (i = 0;i < ns1->nodeNr;i++) {
6558	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6559	if (xmlXPathIsNaN(val1))
6560	    continue;
6561	for (j = 0;j < ns2->nodeNr;j++) {
6562	    if (init == 0) {
6563		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6564	    }
6565	    if (xmlXPathIsNaN(values2[j]))
6566		continue;
6567	    if (inf && strict)
6568		ret = (val1 < values2[j]);
6569	    else if (inf && !strict)
6570		ret = (val1 <= values2[j]);
6571	    else if (!inf && strict)
6572		ret = (val1 > values2[j]);
6573	    else if (!inf && !strict)
6574		ret = (val1 >= values2[j]);
6575	    if (ret)
6576		break;
6577	}
6578	if (ret)
6579	    break;
6580	init = 1;
6581    }
6582    xmlFree(values2);
6583    xmlXPathFreeObject(arg1);
6584    xmlXPathFreeObject(arg2);
6585    return(ret);
6586}
6587
6588/**
6589 * xmlXPathCompareNodeSetValue:
6590 * @ctxt:  the XPath Parser context
6591 * @inf:  less than (1) or greater than (0)
6592 * @strict:  is the comparison strict
6593 * @arg:  the node set
6594 * @val:  the value
6595 *
6596 * Implement the compare operation between a nodeset and a value
6597 *     @ns < @val    (1, 1, ...
6598 *     @ns <= @val   (1, 0, ...
6599 *     @ns > @val    (0, 1, ...
6600 *     @ns >= @val   (0, 0, ...
6601 *
6602 * If one object to be compared is a node-set and the other is a boolean,
6603 * then the comparison will be true if and only if the result of performing
6604 * the comparison on the boolean and on the result of converting
6605 * the node-set to a boolean using the boolean function is true.
6606 *
6607 * Returns 0 or 1 depending on the results of the test.
6608 */
6609static int
6610xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6611	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6612    if ((val == NULL) || (arg == NULL) ||
6613	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6614        return(0);
6615
6616    switch(val->type) {
6617        case XPATH_NUMBER:
6618	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6619        case XPATH_NODESET:
6620        case XPATH_XSLT_TREE:
6621	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6622        case XPATH_STRING:
6623	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6624        case XPATH_BOOLEAN:
6625	    valuePush(ctxt, arg);
6626	    xmlXPathBooleanFunction(ctxt, 1);
6627	    valuePush(ctxt, val);
6628	    return(xmlXPathCompareValues(ctxt, inf, strict));
6629	default:
6630	    TODO
6631    }
6632    return(0);
6633}
6634
6635/**
6636 * xmlXPathEqualNodeSetString:
6637 * @arg:  the nodeset object argument
6638 * @str:  the string to compare to.
6639 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6640 *
6641 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6642 * If one object to be compared is a node-set and the other is a string,
6643 * then the comparison will be true if and only if there is a node in
6644 * the node-set such that the result of performing the comparison on the
6645 * string-value of the node and the other string is true.
6646 *
6647 * Returns 0 or 1 depending on the results of the test.
6648 */
6649static int
6650xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6651{
6652    int i;
6653    xmlNodeSetPtr ns;
6654    xmlChar *str2;
6655    unsigned int hash;
6656
6657    if ((str == NULL) || (arg == NULL) ||
6658        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6659        return (0);
6660    ns = arg->nodesetval;
6661    /*
6662     * A NULL nodeset compared with a string is always false
6663     * (since there is no node equal, and no node not equal)
6664     */
6665    if ((ns == NULL) || (ns->nodeNr <= 0) )
6666        return (0);
6667    hash = xmlXPathStringHash(str);
6668    for (i = 0; i < ns->nodeNr; i++) {
6669        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6670            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6671            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6672                xmlFree(str2);
6673		if (neq)
6674		    continue;
6675                return (1);
6676	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6677		if (neq)
6678		    continue;
6679                return (1);
6680            } else if (neq) {
6681		if (str2 != NULL)
6682		    xmlFree(str2);
6683		return (1);
6684	    }
6685            if (str2 != NULL)
6686                xmlFree(str2);
6687        } else if (neq)
6688	    return (1);
6689    }
6690    return (0);
6691}
6692
6693/**
6694 * xmlXPathEqualNodeSetFloat:
6695 * @arg:  the nodeset object argument
6696 * @f:  the float to compare to
6697 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6698 *
6699 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6700 * If one object to be compared is a node-set and the other is a number,
6701 * then the comparison will be true if and only if there is a node in
6702 * the node-set such that the result of performing the comparison on the
6703 * number to be compared and on the result of converting the string-value
6704 * of that node to a number using the number function is true.
6705 *
6706 * Returns 0 or 1 depending on the results of the test.
6707 */
6708static int
6709xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6710    xmlXPathObjectPtr arg, double f, int neq) {
6711  int i, ret=0;
6712  xmlNodeSetPtr ns;
6713  xmlChar *str2;
6714  xmlXPathObjectPtr val;
6715  double v;
6716
6717    if ((arg == NULL) ||
6718	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6719        return(0);
6720
6721    ns = arg->nodesetval;
6722    if (ns != NULL) {
6723	for (i=0;i<ns->nodeNr;i++) {
6724	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6725	    if (str2 != NULL) {
6726		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6727		xmlFree(str2);
6728		xmlXPathNumberFunction(ctxt, 1);
6729		val = valuePop(ctxt);
6730		v = val->floatval;
6731		xmlXPathReleaseObject(ctxt->context, val);
6732		if (!xmlXPathIsNaN(v)) {
6733		    if ((!neq) && (v==f)) {
6734			ret = 1;
6735			break;
6736		    } else if ((neq) && (v!=f)) {
6737			ret = 1;
6738			break;
6739		    }
6740		} else {	/* NaN is unequal to any value */
6741		    if (neq)
6742			ret = 1;
6743		}
6744	    }
6745	}
6746    }
6747
6748    return(ret);
6749}
6750
6751
6752/**
6753 * xmlXPathEqualNodeSets:
6754 * @arg1:  first nodeset object argument
6755 * @arg2:  second nodeset object argument
6756 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6757 *
6758 * Implement the equal / not equal operation on XPath nodesets:
6759 * @arg1 == @arg2  or  @arg1 != @arg2
6760 * If both objects to be compared are node-sets, then the comparison
6761 * will be true if and only if there is a node in the first node-set and
6762 * a node in the second node-set such that the result of performing the
6763 * comparison on the string-values of the two nodes is true.
6764 *
6765 * (needless to say, this is a costly operation)
6766 *
6767 * Returns 0 or 1 depending on the results of the test.
6768 */
6769static int
6770xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6771    int i, j;
6772    unsigned int *hashs1;
6773    unsigned int *hashs2;
6774    xmlChar **values1;
6775    xmlChar **values2;
6776    int ret = 0;
6777    xmlNodeSetPtr ns1;
6778    xmlNodeSetPtr ns2;
6779
6780    if ((arg1 == NULL) ||
6781	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6782        return(0);
6783    if ((arg2 == NULL) ||
6784	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6785        return(0);
6786
6787    ns1 = arg1->nodesetval;
6788    ns2 = arg2->nodesetval;
6789
6790    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6791	return(0);
6792    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6793	return(0);
6794
6795    /*
6796     * for equal, check if there is a node pertaining to both sets
6797     */
6798    if (neq == 0)
6799	for (i = 0;i < ns1->nodeNr;i++)
6800	    for (j = 0;j < ns2->nodeNr;j++)
6801		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6802		    return(1);
6803
6804    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6805    if (values1 == NULL) {
6806        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6807	return(0);
6808    }
6809    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6810    if (hashs1 == NULL) {
6811        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6812	xmlFree(values1);
6813	return(0);
6814    }
6815    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6816    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6817    if (values2 == NULL) {
6818        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6819	xmlFree(hashs1);
6820	xmlFree(values1);
6821	return(0);
6822    }
6823    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6824    if (hashs2 == NULL) {
6825        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6826	xmlFree(hashs1);
6827	xmlFree(values1);
6828	xmlFree(values2);
6829	return(0);
6830    }
6831    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6832    for (i = 0;i < ns1->nodeNr;i++) {
6833	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6834	for (j = 0;j < ns2->nodeNr;j++) {
6835	    if (i == 0)
6836		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6837	    if (hashs1[i] != hashs2[j]) {
6838		if (neq) {
6839		    ret = 1;
6840		    break;
6841		}
6842	    }
6843	    else {
6844		if (values1[i] == NULL)
6845		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6846		if (values2[j] == NULL)
6847		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6848		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6849		if (ret)
6850		    break;
6851	    }
6852	}
6853	if (ret)
6854	    break;
6855    }
6856    for (i = 0;i < ns1->nodeNr;i++)
6857	if (values1[i] != NULL)
6858	    xmlFree(values1[i]);
6859    for (j = 0;j < ns2->nodeNr;j++)
6860	if (values2[j] != NULL)
6861	    xmlFree(values2[j]);
6862    xmlFree(values1);
6863    xmlFree(values2);
6864    xmlFree(hashs1);
6865    xmlFree(hashs2);
6866    return(ret);
6867}
6868
6869static int
6870xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6871  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6872    int ret = 0;
6873    /*
6874     *At this point we are assured neither arg1 nor arg2
6875     *is a nodeset, so we can just pick the appropriate routine.
6876     */
6877    switch (arg1->type) {
6878        case XPATH_UNDEFINED:
6879#ifdef DEBUG_EXPR
6880	    xmlGenericError(xmlGenericErrorContext,
6881		    "Equal: undefined\n");
6882#endif
6883	    break;
6884        case XPATH_BOOLEAN:
6885	    switch (arg2->type) {
6886	        case XPATH_UNDEFINED:
6887#ifdef DEBUG_EXPR
6888		    xmlGenericError(xmlGenericErrorContext,
6889			    "Equal: undefined\n");
6890#endif
6891		    break;
6892		case XPATH_BOOLEAN:
6893#ifdef DEBUG_EXPR
6894		    xmlGenericError(xmlGenericErrorContext,
6895			    "Equal: %d boolean %d \n",
6896			    arg1->boolval, arg2->boolval);
6897#endif
6898		    ret = (arg1->boolval == arg2->boolval);
6899		    break;
6900		case XPATH_NUMBER:
6901		    ret = (arg1->boolval ==
6902			   xmlXPathCastNumberToBoolean(arg2->floatval));
6903		    break;
6904		case XPATH_STRING:
6905		    if ((arg2->stringval == NULL) ||
6906			(arg2->stringval[0] == 0)) ret = 0;
6907		    else
6908			ret = 1;
6909		    ret = (arg1->boolval == ret);
6910		    break;
6911		case XPATH_USERS:
6912		case XPATH_POINT:
6913		case XPATH_RANGE:
6914		case XPATH_LOCATIONSET:
6915		    TODO
6916		    break;
6917		case XPATH_NODESET:
6918		case XPATH_XSLT_TREE:
6919		    break;
6920	    }
6921	    break;
6922        case XPATH_NUMBER:
6923	    switch (arg2->type) {
6924	        case XPATH_UNDEFINED:
6925#ifdef DEBUG_EXPR
6926		    xmlGenericError(xmlGenericErrorContext,
6927			    "Equal: undefined\n");
6928#endif
6929		    break;
6930		case XPATH_BOOLEAN:
6931		    ret = (arg2->boolval==
6932			   xmlXPathCastNumberToBoolean(arg1->floatval));
6933		    break;
6934		case XPATH_STRING:
6935		    valuePush(ctxt, arg2);
6936		    xmlXPathNumberFunction(ctxt, 1);
6937		    arg2 = valuePop(ctxt);
6938		    /* no break on purpose */
6939		case XPATH_NUMBER:
6940		    /* Hand check NaN and Infinity equalities */
6941		    if (xmlXPathIsNaN(arg1->floatval) ||
6942			    xmlXPathIsNaN(arg2->floatval)) {
6943		        ret = 0;
6944		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6945		        if (xmlXPathIsInf(arg2->floatval) == 1)
6946			    ret = 1;
6947			else
6948			    ret = 0;
6949		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6950			if (xmlXPathIsInf(arg2->floatval) == -1)
6951			    ret = 1;
6952			else
6953			    ret = 0;
6954		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6955			if (xmlXPathIsInf(arg1->floatval) == 1)
6956			    ret = 1;
6957			else
6958			    ret = 0;
6959		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6960			if (xmlXPathIsInf(arg1->floatval) == -1)
6961			    ret = 1;
6962			else
6963			    ret = 0;
6964		    } else {
6965		        ret = (arg1->floatval == arg2->floatval);
6966		    }
6967		    break;
6968		case XPATH_USERS:
6969		case XPATH_POINT:
6970		case XPATH_RANGE:
6971		case XPATH_LOCATIONSET:
6972		    TODO
6973		    break;
6974		case XPATH_NODESET:
6975		case XPATH_XSLT_TREE:
6976		    break;
6977	    }
6978	    break;
6979        case XPATH_STRING:
6980	    switch (arg2->type) {
6981	        case XPATH_UNDEFINED:
6982#ifdef DEBUG_EXPR
6983		    xmlGenericError(xmlGenericErrorContext,
6984			    "Equal: undefined\n");
6985#endif
6986		    break;
6987		case XPATH_BOOLEAN:
6988		    if ((arg1->stringval == NULL) ||
6989			(arg1->stringval[0] == 0)) ret = 0;
6990		    else
6991			ret = 1;
6992		    ret = (arg2->boolval == ret);
6993		    break;
6994		case XPATH_STRING:
6995		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6996		    break;
6997		case XPATH_NUMBER:
6998		    valuePush(ctxt, arg1);
6999		    xmlXPathNumberFunction(ctxt, 1);
7000		    arg1 = valuePop(ctxt);
7001		    /* Hand check NaN and Infinity equalities */
7002		    if (xmlXPathIsNaN(arg1->floatval) ||
7003			    xmlXPathIsNaN(arg2->floatval)) {
7004		        ret = 0;
7005		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7006			if (xmlXPathIsInf(arg2->floatval) == 1)
7007			    ret = 1;
7008			else
7009			    ret = 0;
7010		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7011			if (xmlXPathIsInf(arg2->floatval) == -1)
7012			    ret = 1;
7013			else
7014			    ret = 0;
7015		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7016			if (xmlXPathIsInf(arg1->floatval) == 1)
7017			    ret = 1;
7018			else
7019			    ret = 0;
7020		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7021			if (xmlXPathIsInf(arg1->floatval) == -1)
7022			    ret = 1;
7023			else
7024			    ret = 0;
7025		    } else {
7026		        ret = (arg1->floatval == arg2->floatval);
7027		    }
7028		    break;
7029		case XPATH_USERS:
7030		case XPATH_POINT:
7031		case XPATH_RANGE:
7032		case XPATH_LOCATIONSET:
7033		    TODO
7034		    break;
7035		case XPATH_NODESET:
7036		case XPATH_XSLT_TREE:
7037		    break;
7038	    }
7039	    break;
7040        case XPATH_USERS:
7041	case XPATH_POINT:
7042	case XPATH_RANGE:
7043	case XPATH_LOCATIONSET:
7044	    TODO
7045	    break;
7046	case XPATH_NODESET:
7047	case XPATH_XSLT_TREE:
7048	    break;
7049    }
7050    xmlXPathReleaseObject(ctxt->context, arg1);
7051    xmlXPathReleaseObject(ctxt->context, arg2);
7052    return(ret);
7053}
7054
7055/**
7056 * xmlXPathEqualValues:
7057 * @ctxt:  the XPath Parser context
7058 *
7059 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7060 *
7061 * Returns 0 or 1 depending on the results of the test.
7062 */
7063int
7064xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7065    xmlXPathObjectPtr arg1, arg2, argtmp;
7066    int ret = 0;
7067
7068    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7069    arg2 = valuePop(ctxt);
7070    arg1 = valuePop(ctxt);
7071    if ((arg1 == NULL) || (arg2 == NULL)) {
7072	if (arg1 != NULL)
7073	    xmlXPathReleaseObject(ctxt->context, arg1);
7074	else
7075	    xmlXPathReleaseObject(ctxt->context, arg2);
7076	XP_ERROR0(XPATH_INVALID_OPERAND);
7077    }
7078
7079    if (arg1 == arg2) {
7080#ifdef DEBUG_EXPR
7081        xmlGenericError(xmlGenericErrorContext,
7082		"Equal: by pointer\n");
7083#endif
7084	xmlXPathFreeObject(arg1);
7085        return(1);
7086    }
7087
7088    /*
7089     *If either argument is a nodeset, it's a 'special case'
7090     */
7091    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7092      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7093	/*
7094	 *Hack it to assure arg1 is the nodeset
7095	 */
7096	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7097		argtmp = arg2;
7098		arg2 = arg1;
7099		arg1 = argtmp;
7100	}
7101	switch (arg2->type) {
7102	    case XPATH_UNDEFINED:
7103#ifdef DEBUG_EXPR
7104		xmlGenericError(xmlGenericErrorContext,
7105			"Equal: undefined\n");
7106#endif
7107		break;
7108	    case XPATH_NODESET:
7109	    case XPATH_XSLT_TREE:
7110		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7111		break;
7112	    case XPATH_BOOLEAN:
7113		if ((arg1->nodesetval == NULL) ||
7114		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7115		else
7116		    ret = 1;
7117		ret = (ret == arg2->boolval);
7118		break;
7119	    case XPATH_NUMBER:
7120		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7121		break;
7122	    case XPATH_STRING:
7123		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7124		break;
7125	    case XPATH_USERS:
7126	    case XPATH_POINT:
7127	    case XPATH_RANGE:
7128	    case XPATH_LOCATIONSET:
7129		TODO
7130		break;
7131	}
7132	xmlXPathReleaseObject(ctxt->context, arg1);
7133	xmlXPathReleaseObject(ctxt->context, arg2);
7134	return(ret);
7135    }
7136
7137    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7138}
7139
7140/**
7141 * xmlXPathNotEqualValues:
7142 * @ctxt:  the XPath Parser context
7143 *
7144 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7145 *
7146 * Returns 0 or 1 depending on the results of the test.
7147 */
7148int
7149xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7150    xmlXPathObjectPtr arg1, arg2, argtmp;
7151    int ret = 0;
7152
7153    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7154    arg2 = valuePop(ctxt);
7155    arg1 = valuePop(ctxt);
7156    if ((arg1 == NULL) || (arg2 == NULL)) {
7157	if (arg1 != NULL)
7158	    xmlXPathReleaseObject(ctxt->context, arg1);
7159	else
7160	    xmlXPathReleaseObject(ctxt->context, arg2);
7161	XP_ERROR0(XPATH_INVALID_OPERAND);
7162    }
7163
7164    if (arg1 == arg2) {
7165#ifdef DEBUG_EXPR
7166        xmlGenericError(xmlGenericErrorContext,
7167		"NotEqual: by pointer\n");
7168#endif
7169	xmlXPathReleaseObject(ctxt->context, arg1);
7170        return(0);
7171    }
7172
7173    /*
7174     *If either argument is a nodeset, it's a 'special case'
7175     */
7176    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7177      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7178	/*
7179	 *Hack it to assure arg1 is the nodeset
7180	 */
7181	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7182		argtmp = arg2;
7183		arg2 = arg1;
7184		arg1 = argtmp;
7185	}
7186	switch (arg2->type) {
7187	    case XPATH_UNDEFINED:
7188#ifdef DEBUG_EXPR
7189		xmlGenericError(xmlGenericErrorContext,
7190			"NotEqual: undefined\n");
7191#endif
7192		break;
7193	    case XPATH_NODESET:
7194	    case XPATH_XSLT_TREE:
7195		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7196		break;
7197	    case XPATH_BOOLEAN:
7198		if ((arg1->nodesetval == NULL) ||
7199		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7200		else
7201		    ret = 1;
7202		ret = (ret != arg2->boolval);
7203		break;
7204	    case XPATH_NUMBER:
7205		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7206		break;
7207	    case XPATH_STRING:
7208		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7209		break;
7210	    case XPATH_USERS:
7211	    case XPATH_POINT:
7212	    case XPATH_RANGE:
7213	    case XPATH_LOCATIONSET:
7214		TODO
7215		break;
7216	}
7217	xmlXPathReleaseObject(ctxt->context, arg1);
7218	xmlXPathReleaseObject(ctxt->context, arg2);
7219	return(ret);
7220    }
7221
7222    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7223}
7224
7225/**
7226 * xmlXPathCompareValues:
7227 * @ctxt:  the XPath Parser context
7228 * @inf:  less than (1) or greater than (0)
7229 * @strict:  is the comparison strict
7230 *
7231 * Implement the compare operation on XPath objects:
7232 *     @arg1 < @arg2    (1, 1, ...
7233 *     @arg1 <= @arg2   (1, 0, ...
7234 *     @arg1 > @arg2    (0, 1, ...
7235 *     @arg1 >= @arg2   (0, 0, ...
7236 *
7237 * When neither object to be compared is a node-set and the operator is
7238 * <=, <, >=, >, then the objects are compared by converted both objects
7239 * to numbers and comparing the numbers according to IEEE 754. The <
7240 * comparison will be true if and only if the first number is less than the
7241 * second number. The <= comparison will be true if and only if the first
7242 * number is less than or equal to the second number. The > comparison
7243 * will be true if and only if the first number is greater than the second
7244 * number. The >= comparison will be true if and only if the first number
7245 * is greater than or equal to the second number.
7246 *
7247 * Returns 1 if the comparison succeeded, 0 if it failed
7248 */
7249int
7250xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7251    int ret = 0, arg1i = 0, arg2i = 0;
7252    xmlXPathObjectPtr arg1, arg2;
7253
7254    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7255    arg2 = valuePop(ctxt);
7256    arg1 = valuePop(ctxt);
7257    if ((arg1 == NULL) || (arg2 == NULL)) {
7258	if (arg1 != NULL)
7259	    xmlXPathReleaseObject(ctxt->context, arg1);
7260	else
7261	    xmlXPathReleaseObject(ctxt->context, arg2);
7262	XP_ERROR0(XPATH_INVALID_OPERAND);
7263    }
7264
7265    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7266      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7267	/*
7268	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7269	 * are not freed from within this routine; they will be freed from the
7270	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7271	 */
7272	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7273	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7274	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7275	} else {
7276	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7277		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7278			                          arg1, arg2);
7279	    } else {
7280		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7281			                          arg2, arg1);
7282	    }
7283	}
7284	return(ret);
7285    }
7286
7287    if (arg1->type != XPATH_NUMBER) {
7288	valuePush(ctxt, arg1);
7289	xmlXPathNumberFunction(ctxt, 1);
7290	arg1 = valuePop(ctxt);
7291    }
7292    if (arg1->type != XPATH_NUMBER) {
7293	xmlXPathFreeObject(arg1);
7294	xmlXPathFreeObject(arg2);
7295	XP_ERROR0(XPATH_INVALID_OPERAND);
7296    }
7297    if (arg2->type != XPATH_NUMBER) {
7298	valuePush(ctxt, arg2);
7299	xmlXPathNumberFunction(ctxt, 1);
7300	arg2 = valuePop(ctxt);
7301    }
7302    if (arg2->type != XPATH_NUMBER) {
7303	xmlXPathReleaseObject(ctxt->context, arg1);
7304	xmlXPathReleaseObject(ctxt->context, arg2);
7305	XP_ERROR0(XPATH_INVALID_OPERAND);
7306    }
7307    /*
7308     * Add tests for infinity and nan
7309     * => feedback on 3.4 for Inf and NaN
7310     */
7311    /* Hand check NaN and Infinity comparisons */
7312    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7313	ret=0;
7314    } else {
7315	arg1i=xmlXPathIsInf(arg1->floatval);
7316	arg2i=xmlXPathIsInf(arg2->floatval);
7317	if (inf && strict) {
7318	    if ((arg1i == -1 && arg2i != -1) ||
7319		(arg2i == 1 && arg1i != 1)) {
7320		ret = 1;
7321	    } else if (arg1i == 0 && arg2i == 0) {
7322		ret = (arg1->floatval < arg2->floatval);
7323	    } else {
7324		ret = 0;
7325	    }
7326	}
7327	else if (inf && !strict) {
7328	    if (arg1i == -1 || arg2i == 1) {
7329		ret = 1;
7330	    } else if (arg1i == 0 && arg2i == 0) {
7331		ret = (arg1->floatval <= arg2->floatval);
7332	    } else {
7333		ret = 0;
7334	    }
7335	}
7336	else if (!inf && strict) {
7337	    if ((arg1i == 1 && arg2i != 1) ||
7338		(arg2i == -1 && arg1i != -1)) {
7339		ret = 1;
7340	    } else if (arg1i == 0 && arg2i == 0) {
7341		ret = (arg1->floatval > arg2->floatval);
7342	    } else {
7343		ret = 0;
7344	    }
7345	}
7346	else if (!inf && !strict) {
7347	    if (arg1i == 1 || arg2i == -1) {
7348		ret = 1;
7349	    } else if (arg1i == 0 && arg2i == 0) {
7350		ret = (arg1->floatval >= arg2->floatval);
7351	    } else {
7352		ret = 0;
7353	    }
7354	}
7355    }
7356    xmlXPathReleaseObject(ctxt->context, arg1);
7357    xmlXPathReleaseObject(ctxt->context, arg2);
7358    return(ret);
7359}
7360
7361/**
7362 * xmlXPathValueFlipSign:
7363 * @ctxt:  the XPath Parser context
7364 *
7365 * Implement the unary - operation on an XPath object
7366 * The numeric operators convert their operands to numbers as if
7367 * by calling the number function.
7368 */
7369void
7370xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7371    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7372    CAST_TO_NUMBER;
7373    CHECK_TYPE(XPATH_NUMBER);
7374    if (xmlXPathIsNaN(ctxt->value->floatval))
7375        ctxt->value->floatval=xmlXPathNAN;
7376    else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7377        ctxt->value->floatval=xmlXPathNINF;
7378    else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7379        ctxt->value->floatval=xmlXPathPINF;
7380    else if (ctxt->value->floatval == 0) {
7381        if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7382	    ctxt->value->floatval = xmlXPathNZERO;
7383	else
7384	    ctxt->value->floatval = 0;
7385    }
7386    else
7387        ctxt->value->floatval = - ctxt->value->floatval;
7388}
7389
7390/**
7391 * xmlXPathAddValues:
7392 * @ctxt:  the XPath Parser context
7393 *
7394 * Implement the add operation on XPath objects:
7395 * The numeric operators convert their operands to numbers as if
7396 * by calling the number function.
7397 */
7398void
7399xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7400    xmlXPathObjectPtr arg;
7401    double val;
7402
7403    arg = valuePop(ctxt);
7404    if (arg == NULL)
7405	XP_ERROR(XPATH_INVALID_OPERAND);
7406    val = xmlXPathCastToNumber(arg);
7407    xmlXPathReleaseObject(ctxt->context, arg);
7408    CAST_TO_NUMBER;
7409    CHECK_TYPE(XPATH_NUMBER);
7410    ctxt->value->floatval += val;
7411}
7412
7413/**
7414 * xmlXPathSubValues:
7415 * @ctxt:  the XPath Parser context
7416 *
7417 * Implement the subtraction operation on XPath objects:
7418 * The numeric operators convert their operands to numbers as if
7419 * by calling the number function.
7420 */
7421void
7422xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7423    xmlXPathObjectPtr arg;
7424    double val;
7425
7426    arg = valuePop(ctxt);
7427    if (arg == NULL)
7428	XP_ERROR(XPATH_INVALID_OPERAND);
7429    val = xmlXPathCastToNumber(arg);
7430    xmlXPathReleaseObject(ctxt->context, arg);
7431    CAST_TO_NUMBER;
7432    CHECK_TYPE(XPATH_NUMBER);
7433    ctxt->value->floatval -= val;
7434}
7435
7436/**
7437 * xmlXPathMultValues:
7438 * @ctxt:  the XPath Parser context
7439 *
7440 * Implement the multiply operation on XPath objects:
7441 * The numeric operators convert their operands to numbers as if
7442 * by calling the number function.
7443 */
7444void
7445xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7446    xmlXPathObjectPtr arg;
7447    double val;
7448
7449    arg = valuePop(ctxt);
7450    if (arg == NULL)
7451	XP_ERROR(XPATH_INVALID_OPERAND);
7452    val = xmlXPathCastToNumber(arg);
7453    xmlXPathReleaseObject(ctxt->context, arg);
7454    CAST_TO_NUMBER;
7455    CHECK_TYPE(XPATH_NUMBER);
7456    ctxt->value->floatval *= val;
7457}
7458
7459/**
7460 * xmlXPathDivValues:
7461 * @ctxt:  the XPath Parser context
7462 *
7463 * Implement the div operation on XPath objects @arg1 / @arg2:
7464 * The numeric operators convert their operands to numbers as if
7465 * by calling the number function.
7466 */
7467void
7468xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7469    xmlXPathObjectPtr arg;
7470    double val;
7471
7472    arg = valuePop(ctxt);
7473    if (arg == NULL)
7474	XP_ERROR(XPATH_INVALID_OPERAND);
7475    val = xmlXPathCastToNumber(arg);
7476    xmlXPathReleaseObject(ctxt->context, arg);
7477    CAST_TO_NUMBER;
7478    CHECK_TYPE(XPATH_NUMBER);
7479    if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7480	ctxt->value->floatval = xmlXPathNAN;
7481    else if (val == 0 && xmlXPathGetSign(val) != 0) {
7482	if (ctxt->value->floatval == 0)
7483	    ctxt->value->floatval = xmlXPathNAN;
7484	else if (ctxt->value->floatval > 0)
7485	    ctxt->value->floatval = xmlXPathNINF;
7486	else if (ctxt->value->floatval < 0)
7487	    ctxt->value->floatval = xmlXPathPINF;
7488    }
7489    else if (val == 0) {
7490	if (ctxt->value->floatval == 0)
7491	    ctxt->value->floatval = xmlXPathNAN;
7492	else if (ctxt->value->floatval > 0)
7493	    ctxt->value->floatval = xmlXPathPINF;
7494	else if (ctxt->value->floatval < 0)
7495	    ctxt->value->floatval = xmlXPathNINF;
7496    } else
7497	ctxt->value->floatval /= val;
7498}
7499
7500/**
7501 * xmlXPathModValues:
7502 * @ctxt:  the XPath Parser context
7503 *
7504 * Implement the mod operation on XPath objects: @arg1 / @arg2
7505 * The numeric operators convert their operands to numbers as if
7506 * by calling the number function.
7507 */
7508void
7509xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7510    xmlXPathObjectPtr arg;
7511    double arg1, arg2;
7512
7513    arg = valuePop(ctxt);
7514    if (arg == NULL)
7515	XP_ERROR(XPATH_INVALID_OPERAND);
7516    arg2 = xmlXPathCastToNumber(arg);
7517    xmlXPathReleaseObject(ctxt->context, arg);
7518    CAST_TO_NUMBER;
7519    CHECK_TYPE(XPATH_NUMBER);
7520    arg1 = ctxt->value->floatval;
7521    if (arg2 == 0)
7522	ctxt->value->floatval = xmlXPathNAN;
7523    else {
7524	ctxt->value->floatval = fmod(arg1, arg2);
7525    }
7526}
7527
7528/************************************************************************
7529 *									*
7530 *		The traversal functions					*
7531 *									*
7532 ************************************************************************/
7533
7534/*
7535 * A traversal function enumerates nodes along an axis.
7536 * Initially it must be called with NULL, and it indicates
7537 * termination on the axis by returning NULL.
7538 */
7539typedef xmlNodePtr (*xmlXPathTraversalFunction)
7540                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7541
7542/*
7543 * xmlXPathTraversalFunctionExt:
7544 * A traversal function enumerates nodes along an axis.
7545 * Initially it must be called with NULL, and it indicates
7546 * termination on the axis by returning NULL.
7547 * The context node of the traversal is specified via @contextNode.
7548 */
7549typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7550                    (xmlNodePtr cur, xmlNodePtr contextNode);
7551
7552/*
7553 * xmlXPathNodeSetMergeFunction:
7554 * Used for merging node sets in xmlXPathCollectAndTest().
7555 */
7556typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7557		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
7558
7559
7560/**
7561 * xmlXPathNextSelf:
7562 * @ctxt:  the XPath Parser context
7563 * @cur:  the current node in the traversal
7564 *
7565 * Traversal function for the "self" direction
7566 * The self axis contains just the context node itself
7567 *
7568 * Returns the next element following that axis
7569 */
7570xmlNodePtr
7571xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7572    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7573    if (cur == NULL)
7574        return(ctxt->context->node);
7575    return(NULL);
7576}
7577
7578/**
7579 * xmlXPathNextChild:
7580 * @ctxt:  the XPath Parser context
7581 * @cur:  the current node in the traversal
7582 *
7583 * Traversal function for the "child" direction
7584 * The child axis contains the children of the context node in document order.
7585 *
7586 * Returns the next element following that axis
7587 */
7588xmlNodePtr
7589xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7590    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7591    if (cur == NULL) {
7592	if (ctxt->context->node == NULL) return(NULL);
7593	switch (ctxt->context->node->type) {
7594            case XML_ELEMENT_NODE:
7595            case XML_TEXT_NODE:
7596            case XML_CDATA_SECTION_NODE:
7597            case XML_ENTITY_REF_NODE:
7598            case XML_ENTITY_NODE:
7599            case XML_PI_NODE:
7600            case XML_COMMENT_NODE:
7601            case XML_NOTATION_NODE:
7602            case XML_DTD_NODE:
7603		return(ctxt->context->node->children);
7604            case XML_DOCUMENT_NODE:
7605            case XML_DOCUMENT_TYPE_NODE:
7606            case XML_DOCUMENT_FRAG_NODE:
7607            case XML_HTML_DOCUMENT_NODE:
7608#ifdef LIBXML_DOCB_ENABLED
7609	    case XML_DOCB_DOCUMENT_NODE:
7610#endif
7611		return(((xmlDocPtr) ctxt->context->node)->children);
7612	    case XML_ELEMENT_DECL:
7613	    case XML_ATTRIBUTE_DECL:
7614	    case XML_ENTITY_DECL:
7615            case XML_ATTRIBUTE_NODE:
7616	    case XML_NAMESPACE_DECL:
7617	    case XML_XINCLUDE_START:
7618	    case XML_XINCLUDE_END:
7619		return(NULL);
7620	}
7621	return(NULL);
7622    }
7623    if ((cur->type == XML_DOCUMENT_NODE) ||
7624        (cur->type == XML_HTML_DOCUMENT_NODE))
7625	return(NULL);
7626    return(cur->next);
7627}
7628
7629/**
7630 * xmlXPathNextChildElement:
7631 * @ctxt:  the XPath Parser context
7632 * @cur:  the current node in the traversal
7633 *
7634 * Traversal function for the "child" direction and nodes of type element.
7635 * The child axis contains the children of the context node in document order.
7636 *
7637 * Returns the next element following that axis
7638 */
7639static xmlNodePtr
7640xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7641    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7642    if (cur == NULL) {
7643	cur = ctxt->context->node;
7644	if (cur == NULL) return(NULL);
7645	/*
7646	* Get the first element child.
7647	*/
7648	switch (cur->type) {
7649            case XML_ELEMENT_NODE:
7650	    case XML_DOCUMENT_FRAG_NODE:
7651	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7652            case XML_ENTITY_NODE:
7653		cur = cur->children;
7654		if (cur != NULL) {
7655		    if (cur->type == XML_ELEMENT_NODE)
7656			return(cur);
7657		    do {
7658			cur = cur->next;
7659		    } while ((cur != NULL) &&
7660			(cur->type != XML_ELEMENT_NODE));
7661		    return(cur);
7662		}
7663		return(NULL);
7664            case XML_DOCUMENT_NODE:
7665            case XML_HTML_DOCUMENT_NODE:
7666#ifdef LIBXML_DOCB_ENABLED
7667	    case XML_DOCB_DOCUMENT_NODE:
7668#endif
7669		return(xmlDocGetRootElement((xmlDocPtr) cur));
7670	    default:
7671		return(NULL);
7672	}
7673	return(NULL);
7674    }
7675    /*
7676    * Get the next sibling element node.
7677    */
7678    switch (cur->type) {
7679	case XML_ELEMENT_NODE:
7680	case XML_TEXT_NODE:
7681	case XML_ENTITY_REF_NODE:
7682	case XML_ENTITY_NODE:
7683	case XML_CDATA_SECTION_NODE:
7684	case XML_PI_NODE:
7685	case XML_COMMENT_NODE:
7686	case XML_XINCLUDE_END:
7687	    break;
7688	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7689	default:
7690	    return(NULL);
7691    }
7692    if (cur->next != NULL) {
7693	if (cur->next->type == XML_ELEMENT_NODE)
7694	    return(cur->next);
7695	cur = cur->next;
7696	do {
7697	    cur = cur->next;
7698	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7699	return(cur);
7700    }
7701    return(NULL);
7702}
7703
7704/**
7705 * xmlXPathNextDescendantOrSelfElemParent:
7706 * @ctxt:  the XPath Parser context
7707 * @cur:  the current node in the traversal
7708 *
7709 * Traversal function for the "descendant-or-self" axis.
7710 * Additionally it returns only nodes which can be parents of
7711 * element nodes.
7712 *
7713 *
7714 * Returns the next element following that axis
7715 */
7716static xmlNodePtr
7717xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7718				       xmlNodePtr contextNode)
7719{
7720    if (cur == NULL) {
7721	if (contextNode == NULL)
7722	    return(NULL);
7723	switch (contextNode->type) {
7724	    case XML_ELEMENT_NODE:
7725	    case XML_XINCLUDE_START:
7726	    case XML_DOCUMENT_FRAG_NODE:
7727	    case XML_DOCUMENT_NODE:
7728#ifdef LIBXML_DOCB_ENABLED
7729	    case XML_DOCB_DOCUMENT_NODE:
7730#endif
7731	    case XML_HTML_DOCUMENT_NODE:
7732		return(contextNode);
7733	    default:
7734		return(NULL);
7735	}
7736	return(NULL);
7737    } else {
7738	xmlNodePtr start = cur;
7739
7740	while (cur != NULL) {
7741	    switch (cur->type) {
7742		case XML_ELEMENT_NODE:
7743		/* TODO: OK to have XInclude here? */
7744		case XML_XINCLUDE_START:
7745		case XML_DOCUMENT_FRAG_NODE:
7746		    if (cur != start)
7747			return(cur);
7748		    if (cur->children != NULL) {
7749			cur = cur->children;
7750			continue;
7751		    }
7752		    break;
7753		/* Not sure if we need those here. */
7754		case XML_DOCUMENT_NODE:
7755#ifdef LIBXML_DOCB_ENABLED
7756		case XML_DOCB_DOCUMENT_NODE:
7757#endif
7758		case XML_HTML_DOCUMENT_NODE:
7759		    if (cur != start)
7760			return(cur);
7761		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7762		default:
7763		    break;
7764	    }
7765
7766next_sibling:
7767	    if ((cur == NULL) || (cur == contextNode))
7768		return(NULL);
7769	    if (cur->next != NULL) {
7770		cur = cur->next;
7771	    } else {
7772		cur = cur->parent;
7773		goto next_sibling;
7774	    }
7775	}
7776    }
7777    return(NULL);
7778}
7779
7780/**
7781 * xmlXPathNextDescendant:
7782 * @ctxt:  the XPath Parser context
7783 * @cur:  the current node in the traversal
7784 *
7785 * Traversal function for the "descendant" direction
7786 * the descendant axis contains the descendants of the context node in document
7787 * order; a descendant is a child or a child of a child and so on.
7788 *
7789 * Returns the next element following that axis
7790 */
7791xmlNodePtr
7792xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7793    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7794    if (cur == NULL) {
7795	if (ctxt->context->node == NULL)
7796	    return(NULL);
7797	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7798	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7799	    return(NULL);
7800
7801        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7802	    return(ctxt->context->doc->children);
7803        return(ctxt->context->node->children);
7804    }
7805
7806    if (cur->children != NULL) {
7807	/*
7808	 * Do not descend on entities declarations
7809	 */
7810	if (cur->children->type != XML_ENTITY_DECL) {
7811	    cur = cur->children;
7812	    /*
7813	     * Skip DTDs
7814	     */
7815	    if (cur->type != XML_DTD_NODE)
7816		return(cur);
7817	}
7818    }
7819
7820    if (cur == ctxt->context->node) return(NULL);
7821
7822    while (cur->next != NULL) {
7823	cur = cur->next;
7824	if ((cur->type != XML_ENTITY_DECL) &&
7825	    (cur->type != XML_DTD_NODE))
7826	    return(cur);
7827    }
7828
7829    do {
7830        cur = cur->parent;
7831	if (cur == NULL) break;
7832	if (cur == ctxt->context->node) return(NULL);
7833	if (cur->next != NULL) {
7834	    cur = cur->next;
7835	    return(cur);
7836	}
7837    } while (cur != NULL);
7838    return(cur);
7839}
7840
7841/**
7842 * xmlXPathNextDescendantOrSelf:
7843 * @ctxt:  the XPath Parser context
7844 * @cur:  the current node in the traversal
7845 *
7846 * Traversal function for the "descendant-or-self" direction
7847 * the descendant-or-self axis contains the context node and the descendants
7848 * of the context node in document order; thus the context node is the first
7849 * node on the axis, and the first child of the context node is the second node
7850 * on the axis
7851 *
7852 * Returns the next element following that axis
7853 */
7854xmlNodePtr
7855xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7856    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7857    if (cur == NULL) {
7858	if (ctxt->context->node == NULL)
7859	    return(NULL);
7860	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7861	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7862	    return(NULL);
7863        return(ctxt->context->node);
7864    }
7865
7866    return(xmlXPathNextDescendant(ctxt, cur));
7867}
7868
7869/**
7870 * xmlXPathNextParent:
7871 * @ctxt:  the XPath Parser context
7872 * @cur:  the current node in the traversal
7873 *
7874 * Traversal function for the "parent" direction
7875 * The parent axis contains the parent of the context node, if there is one.
7876 *
7877 * Returns the next element following that axis
7878 */
7879xmlNodePtr
7880xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7881    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7882    /*
7883     * the parent of an attribute or namespace node is the element
7884     * to which the attribute or namespace node is attached
7885     * Namespace handling !!!
7886     */
7887    if (cur == NULL) {
7888	if (ctxt->context->node == NULL) return(NULL);
7889	switch (ctxt->context->node->type) {
7890            case XML_ELEMENT_NODE:
7891            case XML_TEXT_NODE:
7892            case XML_CDATA_SECTION_NODE:
7893            case XML_ENTITY_REF_NODE:
7894            case XML_ENTITY_NODE:
7895            case XML_PI_NODE:
7896            case XML_COMMENT_NODE:
7897            case XML_NOTATION_NODE:
7898            case XML_DTD_NODE:
7899	    case XML_ELEMENT_DECL:
7900	    case XML_ATTRIBUTE_DECL:
7901	    case XML_XINCLUDE_START:
7902	    case XML_XINCLUDE_END:
7903	    case XML_ENTITY_DECL:
7904		if (ctxt->context->node->parent == NULL)
7905		    return((xmlNodePtr) ctxt->context->doc);
7906		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7907		    ((ctxt->context->node->parent->name[0] == ' ') ||
7908		     (xmlStrEqual(ctxt->context->node->parent->name,
7909				 BAD_CAST "fake node libxslt"))))
7910		    return(NULL);
7911		return(ctxt->context->node->parent);
7912            case XML_ATTRIBUTE_NODE: {
7913		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7914
7915		return(att->parent);
7916	    }
7917            case XML_DOCUMENT_NODE:
7918            case XML_DOCUMENT_TYPE_NODE:
7919            case XML_DOCUMENT_FRAG_NODE:
7920            case XML_HTML_DOCUMENT_NODE:
7921#ifdef LIBXML_DOCB_ENABLED
7922	    case XML_DOCB_DOCUMENT_NODE:
7923#endif
7924                return(NULL);
7925	    case XML_NAMESPACE_DECL: {
7926		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7927
7928		if ((ns->next != NULL) &&
7929		    (ns->next->type != XML_NAMESPACE_DECL))
7930		    return((xmlNodePtr) ns->next);
7931                return(NULL);
7932	    }
7933	}
7934    }
7935    return(NULL);
7936}
7937
7938/**
7939 * xmlXPathNextAncestor:
7940 * @ctxt:  the XPath Parser context
7941 * @cur:  the current node in the traversal
7942 *
7943 * Traversal function for the "ancestor" direction
7944 * the ancestor axis contains the ancestors of the context node; the ancestors
7945 * of the context node consist of the parent of context node and the parent's
7946 * parent and so on; the nodes are ordered in reverse document order; thus the
7947 * parent is the first node on the axis, and the parent's parent is the second
7948 * node on the axis
7949 *
7950 * Returns the next element following that axis
7951 */
7952xmlNodePtr
7953xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7954    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7955    /*
7956     * the parent of an attribute or namespace node is the element
7957     * to which the attribute or namespace node is attached
7958     * !!!!!!!!!!!!!
7959     */
7960    if (cur == NULL) {
7961	if (ctxt->context->node == NULL) return(NULL);
7962	switch (ctxt->context->node->type) {
7963            case XML_ELEMENT_NODE:
7964            case XML_TEXT_NODE:
7965            case XML_CDATA_SECTION_NODE:
7966            case XML_ENTITY_REF_NODE:
7967            case XML_ENTITY_NODE:
7968            case XML_PI_NODE:
7969            case XML_COMMENT_NODE:
7970	    case XML_DTD_NODE:
7971	    case XML_ELEMENT_DECL:
7972	    case XML_ATTRIBUTE_DECL:
7973	    case XML_ENTITY_DECL:
7974            case XML_NOTATION_NODE:
7975	    case XML_XINCLUDE_START:
7976	    case XML_XINCLUDE_END:
7977		if (ctxt->context->node->parent == NULL)
7978		    return((xmlNodePtr) ctxt->context->doc);
7979		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7980		    ((ctxt->context->node->parent->name[0] == ' ') ||
7981		     (xmlStrEqual(ctxt->context->node->parent->name,
7982				 BAD_CAST "fake node libxslt"))))
7983		    return(NULL);
7984		return(ctxt->context->node->parent);
7985            case XML_ATTRIBUTE_NODE: {
7986		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7987
7988		return(tmp->parent);
7989	    }
7990            case XML_DOCUMENT_NODE:
7991            case XML_DOCUMENT_TYPE_NODE:
7992            case XML_DOCUMENT_FRAG_NODE:
7993            case XML_HTML_DOCUMENT_NODE:
7994#ifdef LIBXML_DOCB_ENABLED
7995	    case XML_DOCB_DOCUMENT_NODE:
7996#endif
7997                return(NULL);
7998	    case XML_NAMESPACE_DECL: {
7999		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8000
8001		if ((ns->next != NULL) &&
8002		    (ns->next->type != XML_NAMESPACE_DECL))
8003		    return((xmlNodePtr) ns->next);
8004		/* Bad, how did that namespace end up here ? */
8005                return(NULL);
8006	    }
8007	}
8008	return(NULL);
8009    }
8010    if (cur == ctxt->context->doc->children)
8011	return((xmlNodePtr) ctxt->context->doc);
8012    if (cur == (xmlNodePtr) ctxt->context->doc)
8013	return(NULL);
8014    switch (cur->type) {
8015	case XML_ELEMENT_NODE:
8016	case XML_TEXT_NODE:
8017	case XML_CDATA_SECTION_NODE:
8018	case XML_ENTITY_REF_NODE:
8019	case XML_ENTITY_NODE:
8020	case XML_PI_NODE:
8021	case XML_COMMENT_NODE:
8022	case XML_NOTATION_NODE:
8023	case XML_DTD_NODE:
8024        case XML_ELEMENT_DECL:
8025        case XML_ATTRIBUTE_DECL:
8026        case XML_ENTITY_DECL:
8027	case XML_XINCLUDE_START:
8028	case XML_XINCLUDE_END:
8029	    if (cur->parent == NULL)
8030		return(NULL);
8031	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
8032		((cur->parent->name[0] == ' ') ||
8033		 (xmlStrEqual(cur->parent->name,
8034			      BAD_CAST "fake node libxslt"))))
8035		return(NULL);
8036	    return(cur->parent);
8037	case XML_ATTRIBUTE_NODE: {
8038	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8039
8040	    return(att->parent);
8041	}
8042	case XML_NAMESPACE_DECL: {
8043	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8044
8045	    if ((ns->next != NULL) &&
8046	        (ns->next->type != XML_NAMESPACE_DECL))
8047	        return((xmlNodePtr) ns->next);
8048	    /* Bad, how did that namespace end up here ? */
8049            return(NULL);
8050	}
8051	case XML_DOCUMENT_NODE:
8052	case XML_DOCUMENT_TYPE_NODE:
8053	case XML_DOCUMENT_FRAG_NODE:
8054	case XML_HTML_DOCUMENT_NODE:
8055#ifdef LIBXML_DOCB_ENABLED
8056	case XML_DOCB_DOCUMENT_NODE:
8057#endif
8058	    return(NULL);
8059    }
8060    return(NULL);
8061}
8062
8063/**
8064 * xmlXPathNextAncestorOrSelf:
8065 * @ctxt:  the XPath Parser context
8066 * @cur:  the current node in the traversal
8067 *
8068 * Traversal function for the "ancestor-or-self" direction
8069 * he ancestor-or-self axis contains the context node and ancestors of
8070 * the context node in reverse document order; thus the context node is
8071 * the first node on the axis, and the context node's parent the second;
8072 * parent here is defined the same as with the parent axis.
8073 *
8074 * Returns the next element following that axis
8075 */
8076xmlNodePtr
8077xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8078    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8079    if (cur == NULL)
8080        return(ctxt->context->node);
8081    return(xmlXPathNextAncestor(ctxt, cur));
8082}
8083
8084/**
8085 * xmlXPathNextFollowingSibling:
8086 * @ctxt:  the XPath Parser context
8087 * @cur:  the current node in the traversal
8088 *
8089 * Traversal function for the "following-sibling" direction
8090 * The following-sibling axis contains the following siblings of the context
8091 * node in document order.
8092 *
8093 * Returns the next element following that axis
8094 */
8095xmlNodePtr
8096xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8097    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8098    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8099	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8100	return(NULL);
8101    if (cur == (xmlNodePtr) ctxt->context->doc)
8102        return(NULL);
8103    if (cur == NULL)
8104        return(ctxt->context->node->next);
8105    return(cur->next);
8106}
8107
8108/**
8109 * xmlXPathNextPrecedingSibling:
8110 * @ctxt:  the XPath Parser context
8111 * @cur:  the current node in the traversal
8112 *
8113 * Traversal function for the "preceding-sibling" direction
8114 * The preceding-sibling axis contains the preceding siblings of the context
8115 * node in reverse document order; the first preceding sibling is first on the
8116 * axis; the sibling preceding that node is the second on the axis and so on.
8117 *
8118 * Returns the next element following that axis
8119 */
8120xmlNodePtr
8121xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8122    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8123    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8124	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8125	return(NULL);
8126    if (cur == (xmlNodePtr) ctxt->context->doc)
8127        return(NULL);
8128    if (cur == NULL)
8129        return(ctxt->context->node->prev);
8130    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8131	cur = cur->prev;
8132	if (cur == NULL)
8133	    return(ctxt->context->node->prev);
8134    }
8135    return(cur->prev);
8136}
8137
8138/**
8139 * xmlXPathNextFollowing:
8140 * @ctxt:  the XPath Parser context
8141 * @cur:  the current node in the traversal
8142 *
8143 * Traversal function for the "following" direction
8144 * The following axis contains all nodes in the same document as the context
8145 * node that are after the context node in document order, excluding any
8146 * descendants and excluding attribute nodes and namespace nodes; the nodes
8147 * are ordered in document order
8148 *
8149 * Returns the next element following that axis
8150 */
8151xmlNodePtr
8152xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8153    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8154    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8155        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8156        return(cur->children);
8157
8158    if (cur == NULL) {
8159        cur = ctxt->context->node;
8160        if (cur->type == XML_NAMESPACE_DECL)
8161            return(NULL);
8162        if (cur->type == XML_ATTRIBUTE_NODE)
8163            cur = cur->parent;
8164    }
8165    if (cur == NULL) return(NULL) ; /* ERROR */
8166    if (cur->next != NULL) return(cur->next) ;
8167    do {
8168        cur = cur->parent;
8169        if (cur == NULL) break;
8170        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8171        if (cur->next != NULL) return(cur->next);
8172    } while (cur != NULL);
8173    return(cur);
8174}
8175
8176/*
8177 * xmlXPathIsAncestor:
8178 * @ancestor:  the ancestor node
8179 * @node:  the current node
8180 *
8181 * Check that @ancestor is a @node's ancestor
8182 *
8183 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8184 */
8185static int
8186xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8187    if ((ancestor == NULL) || (node == NULL)) return(0);
8188    /* nodes need to be in the same document */
8189    if (ancestor->doc != node->doc) return(0);
8190    /* avoid searching if ancestor or node is the root node */
8191    if (ancestor == (xmlNodePtr) node->doc) return(1);
8192    if (node == (xmlNodePtr) ancestor->doc) return(0);
8193    while (node->parent != NULL) {
8194        if (node->parent == ancestor)
8195            return(1);
8196	node = node->parent;
8197    }
8198    return(0);
8199}
8200
8201/**
8202 * xmlXPathNextPreceding:
8203 * @ctxt:  the XPath Parser context
8204 * @cur:  the current node in the traversal
8205 *
8206 * Traversal function for the "preceding" direction
8207 * the preceding axis contains all nodes in the same document as the context
8208 * node that are before the context node in document order, excluding any
8209 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8210 * ordered in reverse document order
8211 *
8212 * Returns the next element following that axis
8213 */
8214xmlNodePtr
8215xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8216{
8217    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8218    if (cur == NULL) {
8219        cur = ctxt->context->node;
8220        if (cur->type == XML_NAMESPACE_DECL)
8221            return(NULL);
8222        if (cur->type == XML_ATTRIBUTE_NODE)
8223            return(cur->parent);
8224    }
8225    if (cur == NULL)
8226	return (NULL);
8227    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8228	cur = cur->prev;
8229    do {
8230        if (cur->prev != NULL) {
8231            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8232            return (cur);
8233        }
8234
8235        cur = cur->parent;
8236        if (cur == NULL)
8237            return (NULL);
8238        if (cur == ctxt->context->doc->children)
8239            return (NULL);
8240    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8241    return (cur);
8242}
8243
8244/**
8245 * xmlXPathNextPrecedingInternal:
8246 * @ctxt:  the XPath Parser context
8247 * @cur:  the current node in the traversal
8248 *
8249 * Traversal function for the "preceding" direction
8250 * the preceding axis contains all nodes in the same document as the context
8251 * node that are before the context node in document order, excluding any
8252 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8253 * ordered in reverse document order
8254 * This is a faster implementation but internal only since it requires a
8255 * state kept in the parser context: ctxt->ancestor.
8256 *
8257 * Returns the next element following that axis
8258 */
8259static xmlNodePtr
8260xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8261                              xmlNodePtr cur)
8262{
8263    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8264    if (cur == NULL) {
8265        cur = ctxt->context->node;
8266        if (cur == NULL)
8267            return (NULL);
8268        if (cur->type == XML_NAMESPACE_DECL)
8269            return (NULL);
8270        ctxt->ancestor = cur->parent;
8271    }
8272    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8273	cur = cur->prev;
8274    while (cur->prev == NULL) {
8275        cur = cur->parent;
8276        if (cur == NULL)
8277            return (NULL);
8278        if (cur == ctxt->context->doc->children)
8279            return (NULL);
8280        if (cur != ctxt->ancestor)
8281            return (cur);
8282        ctxt->ancestor = cur->parent;
8283    }
8284    cur = cur->prev;
8285    while (cur->last != NULL)
8286        cur = cur->last;
8287    return (cur);
8288}
8289
8290/**
8291 * xmlXPathNextNamespace:
8292 * @ctxt:  the XPath Parser context
8293 * @cur:  the current attribute in the traversal
8294 *
8295 * Traversal function for the "namespace" direction
8296 * the namespace axis contains the namespace nodes of the context node;
8297 * the order of nodes on this axis is implementation-defined; the axis will
8298 * be empty unless the context node is an element
8299 *
8300 * We keep the XML namespace node at the end of the list.
8301 *
8302 * Returns the next element following that axis
8303 */
8304xmlNodePtr
8305xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8306    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8307    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8308    if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8309        if (ctxt->context->tmpNsList != NULL)
8310	    xmlFree(ctxt->context->tmpNsList);
8311	ctxt->context->tmpNsList =
8312	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8313	ctxt->context->tmpNsNr = 0;
8314	if (ctxt->context->tmpNsList != NULL) {
8315	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8316		ctxt->context->tmpNsNr++;
8317	    }
8318	}
8319	return((xmlNodePtr) xmlXPathXMLNamespace);
8320    }
8321    if (ctxt->context->tmpNsNr > 0) {
8322	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8323    } else {
8324	if (ctxt->context->tmpNsList != NULL)
8325	    xmlFree(ctxt->context->tmpNsList);
8326	ctxt->context->tmpNsList = NULL;
8327	return(NULL);
8328    }
8329}
8330
8331/**
8332 * xmlXPathNextAttribute:
8333 * @ctxt:  the XPath Parser context
8334 * @cur:  the current attribute in the traversal
8335 *
8336 * Traversal function for the "attribute" direction
8337 * TODO: support DTD inherited default attributes
8338 *
8339 * Returns the next element following that axis
8340 */
8341xmlNodePtr
8342xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8343    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8344    if (ctxt->context->node == NULL)
8345	return(NULL);
8346    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8347	return(NULL);
8348    if (cur == NULL) {
8349        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8350	    return(NULL);
8351        return((xmlNodePtr)ctxt->context->node->properties);
8352    }
8353    return((xmlNodePtr)cur->next);
8354}
8355
8356/************************************************************************
8357 *									*
8358 *		NodeTest Functions					*
8359 *									*
8360 ************************************************************************/
8361
8362#define IS_FUNCTION			200
8363
8364
8365/************************************************************************
8366 *									*
8367 *		Implicit tree core function library			*
8368 *									*
8369 ************************************************************************/
8370
8371/**
8372 * xmlXPathRoot:
8373 * @ctxt:  the XPath Parser context
8374 *
8375 * Initialize the context to the root of the document
8376 */
8377void
8378xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8379    if ((ctxt == NULL) || (ctxt->context == NULL))
8380	return;
8381    ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8382    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8383	ctxt->context->node));
8384}
8385
8386/************************************************************************
8387 *									*
8388 *		The explicit core function library			*
8389 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8390 *									*
8391 ************************************************************************/
8392
8393
8394/**
8395 * xmlXPathLastFunction:
8396 * @ctxt:  the XPath Parser context
8397 * @nargs:  the number of arguments
8398 *
8399 * Implement the last() XPath function
8400 *    number last()
8401 * The last function returns the number of nodes in the context node list.
8402 */
8403void
8404xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8405    CHECK_ARITY(0);
8406    if (ctxt->context->contextSize >= 0) {
8407	valuePush(ctxt,
8408	    xmlXPathCacheNewFloat(ctxt->context,
8409		(double) ctxt->context->contextSize));
8410#ifdef DEBUG_EXPR
8411	xmlGenericError(xmlGenericErrorContext,
8412		"last() : %d\n", ctxt->context->contextSize);
8413#endif
8414    } else {
8415	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8416    }
8417}
8418
8419/**
8420 * xmlXPathPositionFunction:
8421 * @ctxt:  the XPath Parser context
8422 * @nargs:  the number of arguments
8423 *
8424 * Implement the position() XPath function
8425 *    number position()
8426 * The position function returns the position of the context node in the
8427 * context node list. The first position is 1, and so the last position
8428 * will be equal to last().
8429 */
8430void
8431xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8432    CHECK_ARITY(0);
8433    if (ctxt->context->proximityPosition >= 0) {
8434	valuePush(ctxt,
8435	      xmlXPathCacheNewFloat(ctxt->context,
8436		(double) ctxt->context->proximityPosition));
8437#ifdef DEBUG_EXPR
8438	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8439		ctxt->context->proximityPosition);
8440#endif
8441    } else {
8442	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8443    }
8444}
8445
8446/**
8447 * xmlXPathCountFunction:
8448 * @ctxt:  the XPath Parser context
8449 * @nargs:  the number of arguments
8450 *
8451 * Implement the count() XPath function
8452 *    number count(node-set)
8453 */
8454void
8455xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8456    xmlXPathObjectPtr cur;
8457
8458    CHECK_ARITY(1);
8459    if ((ctxt->value == NULL) ||
8460	((ctxt->value->type != XPATH_NODESET) &&
8461	 (ctxt->value->type != XPATH_XSLT_TREE)))
8462	XP_ERROR(XPATH_INVALID_TYPE);
8463    cur = valuePop(ctxt);
8464
8465    if ((cur == NULL) || (cur->nodesetval == NULL))
8466	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8467    else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8468	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8469	    (double) cur->nodesetval->nodeNr));
8470    } else {
8471	if ((cur->nodesetval->nodeNr != 1) ||
8472	    (cur->nodesetval->nodeTab == NULL)) {
8473	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8474	} else {
8475	    xmlNodePtr tmp;
8476	    int i = 0;
8477
8478	    tmp = cur->nodesetval->nodeTab[0];
8479	    if (tmp != NULL) {
8480		tmp = tmp->children;
8481		while (tmp != NULL) {
8482		    tmp = tmp->next;
8483		    i++;
8484		}
8485	    }
8486	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8487	}
8488    }
8489    xmlXPathReleaseObject(ctxt->context, cur);
8490}
8491
8492/**
8493 * xmlXPathGetElementsByIds:
8494 * @doc:  the document
8495 * @ids:  a whitespace separated list of IDs
8496 *
8497 * Selects elements by their unique ID.
8498 *
8499 * Returns a node-set of selected elements.
8500 */
8501static xmlNodeSetPtr
8502xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8503    xmlNodeSetPtr ret;
8504    const xmlChar *cur = ids;
8505    xmlChar *ID;
8506    xmlAttrPtr attr;
8507    xmlNodePtr elem = NULL;
8508
8509    if (ids == NULL) return(NULL);
8510
8511    ret = xmlXPathNodeSetCreate(NULL);
8512    if (ret == NULL)
8513        return(ret);
8514
8515    while (IS_BLANK_CH(*cur)) cur++;
8516    while (*cur != 0) {
8517	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8518	    cur++;
8519
8520        ID = xmlStrndup(ids, cur - ids);
8521	if (ID != NULL) {
8522	    /*
8523	     * We used to check the fact that the value passed
8524	     * was an NCName, but this generated much troubles for
8525	     * me and Aleksey Sanin, people blatantly violated that
8526	     * constaint, like Visa3D spec.
8527	     * if (xmlValidateNCName(ID, 1) == 0)
8528	     */
8529	    attr = xmlGetID(doc, ID);
8530	    if (attr != NULL) {
8531		if (attr->type == XML_ATTRIBUTE_NODE)
8532		    elem = attr->parent;
8533		else if (attr->type == XML_ELEMENT_NODE)
8534		    elem = (xmlNodePtr) attr;
8535		else
8536		    elem = NULL;
8537		if (elem != NULL)
8538		    xmlXPathNodeSetAdd(ret, elem);
8539	    }
8540	    xmlFree(ID);
8541	}
8542
8543	while (IS_BLANK_CH(*cur)) cur++;
8544	ids = cur;
8545    }
8546    return(ret);
8547}
8548
8549/**
8550 * xmlXPathIdFunction:
8551 * @ctxt:  the XPath Parser context
8552 * @nargs:  the number of arguments
8553 *
8554 * Implement the id() XPath function
8555 *    node-set id(object)
8556 * The id function selects elements by their unique ID
8557 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8558 * then the result is the union of the result of applying id to the
8559 * string value of each of the nodes in the argument node-set. When the
8560 * argument to id is of any other type, the argument is converted to a
8561 * string as if by a call to the string function; the string is split
8562 * into a whitespace-separated list of tokens (whitespace is any sequence
8563 * of characters matching the production S); the result is a node-set
8564 * containing the elements in the same document as the context node that
8565 * have a unique ID equal to any of the tokens in the list.
8566 */
8567void
8568xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8569    xmlChar *tokens;
8570    xmlNodeSetPtr ret;
8571    xmlXPathObjectPtr obj;
8572
8573    CHECK_ARITY(1);
8574    obj = valuePop(ctxt);
8575    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8576    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8577	xmlNodeSetPtr ns;
8578	int i;
8579
8580	ret = xmlXPathNodeSetCreate(NULL);
8581        /*
8582         * FIXME -- in an out-of-memory condition this will behave badly.
8583         * The solution is not clear -- we already popped an item from
8584         * ctxt, so the object is in a corrupt state.
8585         */
8586
8587	if (obj->nodesetval != NULL) {
8588	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8589		tokens =
8590		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8591		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8592		ret = xmlXPathNodeSetMerge(ret, ns);
8593		xmlXPathFreeNodeSet(ns);
8594		if (tokens != NULL)
8595		    xmlFree(tokens);
8596	    }
8597	}
8598	xmlXPathReleaseObject(ctxt->context, obj);
8599	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8600	return;
8601    }
8602    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8603    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8604    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8605    xmlXPathReleaseObject(ctxt->context, obj);
8606    return;
8607}
8608
8609/**
8610 * xmlXPathLocalNameFunction:
8611 * @ctxt:  the XPath Parser context
8612 * @nargs:  the number of arguments
8613 *
8614 * Implement the local-name() XPath function
8615 *    string local-name(node-set?)
8616 * The local-name function returns a string containing the local part
8617 * of the name of the node in the argument node-set that is first in
8618 * document order. If the node-set is empty or the first node has no
8619 * name, an empty string is returned. If the argument is omitted it
8620 * defaults to the context node.
8621 */
8622void
8623xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8624    xmlXPathObjectPtr cur;
8625
8626    if (ctxt == NULL) return;
8627
8628    if (nargs == 0) {
8629	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8630	    ctxt->context->node));
8631	nargs = 1;
8632    }
8633
8634    CHECK_ARITY(1);
8635    if ((ctxt->value == NULL) ||
8636	((ctxt->value->type != XPATH_NODESET) &&
8637	 (ctxt->value->type != XPATH_XSLT_TREE)))
8638	XP_ERROR(XPATH_INVALID_TYPE);
8639    cur = valuePop(ctxt);
8640
8641    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8642	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8643    } else {
8644	int i = 0; /* Should be first in document order !!!!! */
8645	switch (cur->nodesetval->nodeTab[i]->type) {
8646	case XML_ELEMENT_NODE:
8647	case XML_ATTRIBUTE_NODE:
8648	case XML_PI_NODE:
8649	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8650		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8651	    else
8652		valuePush(ctxt,
8653		      xmlXPathCacheNewString(ctxt->context,
8654			cur->nodesetval->nodeTab[i]->name));
8655	    break;
8656	case XML_NAMESPACE_DECL:
8657	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8658			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8659	    break;
8660	default:
8661	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8662	}
8663    }
8664    xmlXPathReleaseObject(ctxt->context, cur);
8665}
8666
8667/**
8668 * xmlXPathNamespaceURIFunction:
8669 * @ctxt:  the XPath Parser context
8670 * @nargs:  the number of arguments
8671 *
8672 * Implement the namespace-uri() XPath function
8673 *    string namespace-uri(node-set?)
8674 * The namespace-uri function returns a string containing the
8675 * namespace URI of the expanded name of the node in the argument
8676 * node-set that is first in document order. If the node-set is empty,
8677 * the first node has no name, or the expanded name has no namespace
8678 * URI, an empty string is returned. If the argument is omitted it
8679 * defaults to the context node.
8680 */
8681void
8682xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8683    xmlXPathObjectPtr cur;
8684
8685    if (ctxt == NULL) return;
8686
8687    if (nargs == 0) {
8688	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8689	    ctxt->context->node));
8690	nargs = 1;
8691    }
8692    CHECK_ARITY(1);
8693    if ((ctxt->value == NULL) ||
8694	((ctxt->value->type != XPATH_NODESET) &&
8695	 (ctxt->value->type != XPATH_XSLT_TREE)))
8696	XP_ERROR(XPATH_INVALID_TYPE);
8697    cur = valuePop(ctxt);
8698
8699    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8700	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8701    } else {
8702	int i = 0; /* Should be first in document order !!!!! */
8703	switch (cur->nodesetval->nodeTab[i]->type) {
8704	case XML_ELEMENT_NODE:
8705	case XML_ATTRIBUTE_NODE:
8706	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8707		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8708	    else
8709		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8710			  cur->nodesetval->nodeTab[i]->ns->href));
8711	    break;
8712	default:
8713	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8714	}
8715    }
8716    xmlXPathReleaseObject(ctxt->context, cur);
8717}
8718
8719/**
8720 * xmlXPathNameFunction:
8721 * @ctxt:  the XPath Parser context
8722 * @nargs:  the number of arguments
8723 *
8724 * Implement the name() XPath function
8725 *    string name(node-set?)
8726 * The name function returns a string containing a QName representing
8727 * the name of the node in the argument node-set that is first in document
8728 * order. The QName must represent the name with respect to the namespace
8729 * declarations in effect on the node whose name is being represented.
8730 * Typically, this will be the form in which the name occurred in the XML
8731 * source. This need not be the case if there are namespace declarations
8732 * in effect on the node that associate multiple prefixes with the same
8733 * namespace. However, an implementation may include information about
8734 * the original prefix in its representation of nodes; in this case, an
8735 * implementation can ensure that the returned string is always the same
8736 * as the QName used in the XML source. If the argument it omitted it
8737 * defaults to the context node.
8738 * Libxml keep the original prefix so the "real qualified name" used is
8739 * returned.
8740 */
8741static void
8742xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8743{
8744    xmlXPathObjectPtr cur;
8745
8746    if (nargs == 0) {
8747	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8748	    ctxt->context->node));
8749        nargs = 1;
8750    }
8751
8752    CHECK_ARITY(1);
8753    if ((ctxt->value == NULL) ||
8754        ((ctxt->value->type != XPATH_NODESET) &&
8755         (ctxt->value->type != XPATH_XSLT_TREE)))
8756        XP_ERROR(XPATH_INVALID_TYPE);
8757    cur = valuePop(ctxt);
8758
8759    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8760        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8761    } else {
8762        int i = 0;              /* Should be first in document order !!!!! */
8763
8764        switch (cur->nodesetval->nodeTab[i]->type) {
8765            case XML_ELEMENT_NODE:
8766            case XML_ATTRIBUTE_NODE:
8767		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8768		    valuePush(ctxt,
8769			xmlXPathCacheNewCString(ctxt->context, ""));
8770		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8771                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8772		    valuePush(ctxt,
8773		        xmlXPathCacheNewString(ctxt->context,
8774			    cur->nodesetval->nodeTab[i]->name));
8775		} else {
8776		    xmlChar *fullname;
8777
8778		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8779				     cur->nodesetval->nodeTab[i]->ns->prefix,
8780				     NULL, 0);
8781		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8782			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8783		    if (fullname == NULL) {
8784			XP_ERROR(XPATH_MEMORY_ERROR);
8785		    }
8786		    valuePush(ctxt, xmlXPathCacheWrapString(
8787			ctxt->context, fullname));
8788                }
8789                break;
8790            default:
8791		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8792		    cur->nodesetval->nodeTab[i]));
8793                xmlXPathLocalNameFunction(ctxt, 1);
8794        }
8795    }
8796    xmlXPathReleaseObject(ctxt->context, cur);
8797}
8798
8799
8800/**
8801 * xmlXPathStringFunction:
8802 * @ctxt:  the XPath Parser context
8803 * @nargs:  the number of arguments
8804 *
8805 * Implement the string() XPath function
8806 *    string string(object?)
8807 * The string function converts an object to a string as follows:
8808 *    - A node-set is converted to a string by returning the value of
8809 *      the node in the node-set that is first in document order.
8810 *      If the node-set is empty, an empty string is returned.
8811 *    - A number is converted to a string as follows
8812 *      + NaN is converted to the string NaN
8813 *      + positive zero is converted to the string 0
8814 *      + negative zero is converted to the string 0
8815 *      + positive infinity is converted to the string Infinity
8816 *      + negative infinity is converted to the string -Infinity
8817 *      + if the number is an integer, the number is represented in
8818 *        decimal form as a Number with no decimal point and no leading
8819 *        zeros, preceded by a minus sign (-) if the number is negative
8820 *      + otherwise, the number is represented in decimal form as a
8821 *        Number including a decimal point with at least one digit
8822 *        before the decimal point and at least one digit after the
8823 *        decimal point, preceded by a minus sign (-) if the number
8824 *        is negative; there must be no leading zeros before the decimal
8825 *        point apart possibly from the one required digit immediately
8826 *        before the decimal point; beyond the one required digit
8827 *        after the decimal point there must be as many, but only as
8828 *        many, more digits as are needed to uniquely distinguish the
8829 *        number from all other IEEE 754 numeric values.
8830 *    - The boolean false value is converted to the string false.
8831 *      The boolean true value is converted to the string true.
8832 *
8833 * If the argument is omitted, it defaults to a node-set with the
8834 * context node as its only member.
8835 */
8836void
8837xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8838    xmlXPathObjectPtr cur;
8839
8840    if (ctxt == NULL) return;
8841    if (nargs == 0) {
8842    valuePush(ctxt,
8843	xmlXPathCacheWrapString(ctxt->context,
8844	    xmlXPathCastNodeToString(ctxt->context->node)));
8845	return;
8846    }
8847
8848    CHECK_ARITY(1);
8849    cur = valuePop(ctxt);
8850    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8851    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8852}
8853
8854/**
8855 * xmlXPathStringLengthFunction:
8856 * @ctxt:  the XPath Parser context
8857 * @nargs:  the number of arguments
8858 *
8859 * Implement the string-length() XPath function
8860 *    number string-length(string?)
8861 * The string-length returns the number of characters in the string
8862 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8863 * the context node converted to a string, in other words the value
8864 * of the context node.
8865 */
8866void
8867xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8868    xmlXPathObjectPtr cur;
8869
8870    if (nargs == 0) {
8871        if ((ctxt == NULL) || (ctxt->context == NULL))
8872	    return;
8873	if (ctxt->context->node == NULL) {
8874	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8875	} else {
8876	    xmlChar *content;
8877
8878	    content = xmlXPathCastNodeToString(ctxt->context->node);
8879	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8880		xmlUTF8Strlen(content)));
8881	    xmlFree(content);
8882	}
8883	return;
8884    }
8885    CHECK_ARITY(1);
8886    CAST_TO_STRING;
8887    CHECK_TYPE(XPATH_STRING);
8888    cur = valuePop(ctxt);
8889    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8890	xmlUTF8Strlen(cur->stringval)));
8891    xmlXPathReleaseObject(ctxt->context, cur);
8892}
8893
8894/**
8895 * xmlXPathConcatFunction:
8896 * @ctxt:  the XPath Parser context
8897 * @nargs:  the number of arguments
8898 *
8899 * Implement the concat() XPath function
8900 *    string concat(string, string, string*)
8901 * The concat function returns the concatenation of its arguments.
8902 */
8903void
8904xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8905    xmlXPathObjectPtr cur, newobj;
8906    xmlChar *tmp;
8907
8908    if (ctxt == NULL) return;
8909    if (nargs < 2) {
8910	CHECK_ARITY(2);
8911    }
8912
8913    CAST_TO_STRING;
8914    cur = valuePop(ctxt);
8915    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8916	xmlXPathReleaseObject(ctxt->context, cur);
8917	return;
8918    }
8919    nargs--;
8920
8921    while (nargs > 0) {
8922	CAST_TO_STRING;
8923	newobj = valuePop(ctxt);
8924	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8925	    xmlXPathReleaseObject(ctxt->context, newobj);
8926	    xmlXPathReleaseObject(ctxt->context, cur);
8927	    XP_ERROR(XPATH_INVALID_TYPE);
8928	}
8929	tmp = xmlStrcat(newobj->stringval, cur->stringval);
8930	newobj->stringval = cur->stringval;
8931	cur->stringval = tmp;
8932	xmlXPathReleaseObject(ctxt->context, newobj);
8933	nargs--;
8934    }
8935    valuePush(ctxt, cur);
8936}
8937
8938/**
8939 * xmlXPathContainsFunction:
8940 * @ctxt:  the XPath Parser context
8941 * @nargs:  the number of arguments
8942 *
8943 * Implement the contains() XPath function
8944 *    boolean contains(string, string)
8945 * The contains function returns true if the first argument string
8946 * contains the second argument string, and otherwise returns false.
8947 */
8948void
8949xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8950    xmlXPathObjectPtr hay, needle;
8951
8952    CHECK_ARITY(2);
8953    CAST_TO_STRING;
8954    CHECK_TYPE(XPATH_STRING);
8955    needle = valuePop(ctxt);
8956    CAST_TO_STRING;
8957    hay = valuePop(ctxt);
8958
8959    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8960	xmlXPathReleaseObject(ctxt->context, hay);
8961	xmlXPathReleaseObject(ctxt->context, needle);
8962	XP_ERROR(XPATH_INVALID_TYPE);
8963    }
8964    if (xmlStrstr(hay->stringval, needle->stringval))
8965	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8966    else
8967	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8968    xmlXPathReleaseObject(ctxt->context, hay);
8969    xmlXPathReleaseObject(ctxt->context, needle);
8970}
8971
8972/**
8973 * xmlXPathStartsWithFunction:
8974 * @ctxt:  the XPath Parser context
8975 * @nargs:  the number of arguments
8976 *
8977 * Implement the starts-with() XPath function
8978 *    boolean starts-with(string, string)
8979 * The starts-with function returns true if the first argument string
8980 * starts with the second argument string, and otherwise returns false.
8981 */
8982void
8983xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8984    xmlXPathObjectPtr hay, needle;
8985    int n;
8986
8987    CHECK_ARITY(2);
8988    CAST_TO_STRING;
8989    CHECK_TYPE(XPATH_STRING);
8990    needle = valuePop(ctxt);
8991    CAST_TO_STRING;
8992    hay = valuePop(ctxt);
8993
8994    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8995	xmlXPathReleaseObject(ctxt->context, hay);
8996	xmlXPathReleaseObject(ctxt->context, needle);
8997	XP_ERROR(XPATH_INVALID_TYPE);
8998    }
8999    n = xmlStrlen(needle->stringval);
9000    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9001        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9002    else
9003        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9004    xmlXPathReleaseObject(ctxt->context, hay);
9005    xmlXPathReleaseObject(ctxt->context, needle);
9006}
9007
9008/**
9009 * xmlXPathSubstringFunction:
9010 * @ctxt:  the XPath Parser context
9011 * @nargs:  the number of arguments
9012 *
9013 * Implement the substring() XPath function
9014 *    string substring(string, number, number?)
9015 * The substring function returns the substring of the first argument
9016 * starting at the position specified in the second argument with
9017 * length specified in the third argument. For example,
9018 * substring("12345",2,3) returns "234". If the third argument is not
9019 * specified, it returns the substring starting at the position specified
9020 * in the second argument and continuing to the end of the string. For
9021 * example, substring("12345",2) returns "2345".  More precisely, each
9022 * character in the string (see [3.6 Strings]) is considered to have a
9023 * numeric position: the position of the first character is 1, the position
9024 * of the second character is 2 and so on. The returned substring contains
9025 * those characters for which the position of the character is greater than
9026 * or equal to the second argument and, if the third argument is specified,
9027 * less than the sum of the second and third arguments; the comparisons
9028 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9029 *  - substring("12345", 1.5, 2.6) returns "234"
9030 *  - substring("12345", 0, 3) returns "12"
9031 *  - substring("12345", 0 div 0, 3) returns ""
9032 *  - substring("12345", 1, 0 div 0) returns ""
9033 *  - substring("12345", -42, 1 div 0) returns "12345"
9034 *  - substring("12345", -1 div 0, 1 div 0) returns ""
9035 */
9036void
9037xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9038    xmlXPathObjectPtr str, start, len;
9039    double le=0, in;
9040    int i, l, m;
9041    xmlChar *ret;
9042
9043    if (nargs < 2) {
9044	CHECK_ARITY(2);
9045    }
9046    if (nargs > 3) {
9047	CHECK_ARITY(3);
9048    }
9049    /*
9050     * take care of possible last (position) argument
9051    */
9052    if (nargs == 3) {
9053	CAST_TO_NUMBER;
9054	CHECK_TYPE(XPATH_NUMBER);
9055	len = valuePop(ctxt);
9056	le = len->floatval;
9057	xmlXPathReleaseObject(ctxt->context, len);
9058    }
9059
9060    CAST_TO_NUMBER;
9061    CHECK_TYPE(XPATH_NUMBER);
9062    start = valuePop(ctxt);
9063    in = start->floatval;
9064    xmlXPathReleaseObject(ctxt->context, start);
9065    CAST_TO_STRING;
9066    CHECK_TYPE(XPATH_STRING);
9067    str = valuePop(ctxt);
9068    m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9069
9070    /*
9071     * If last pos not present, calculate last position
9072    */
9073    if (nargs != 3) {
9074	le = (double)m;
9075	if (in < 1.0)
9076	    in = 1.0;
9077    }
9078
9079    /* Need to check for the special cases where either
9080     * the index is NaN, the length is NaN, or both
9081     * arguments are infinity (relying on Inf + -Inf = NaN)
9082     */
9083    if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9084        /*
9085         * To meet the requirements of the spec, the arguments
9086	 * must be converted to integer format before
9087	 * initial index calculations are done
9088         *
9089         * First we go to integer form, rounding up
9090	 * and checking for special cases
9091         */
9092        i = (int) in;
9093        if (((double)i)+0.5 <= in) i++;
9094
9095	if (xmlXPathIsInf(le) == 1) {
9096	    l = m;
9097	    if (i < 1)
9098		i = 1;
9099	}
9100	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9101	    l = 0;
9102	else {
9103	    l = (int) le;
9104	    if (((double)l)+0.5 <= le) l++;
9105	}
9106
9107	/* Now we normalize inidices */
9108        i -= 1;
9109        l += i;
9110        if (i < 0)
9111            i = 0;
9112        if (l > m)
9113            l = m;
9114
9115        /* number of chars to copy */
9116        l -= i;
9117
9118        ret = xmlUTF8Strsub(str->stringval, i, l);
9119    }
9120    else {
9121        ret = NULL;
9122    }
9123    if (ret == NULL)
9124	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9125    else {
9126	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9127	xmlFree(ret);
9128    }
9129    xmlXPathReleaseObject(ctxt->context, str);
9130}
9131
9132/**
9133 * xmlXPathSubstringBeforeFunction:
9134 * @ctxt:  the XPath Parser context
9135 * @nargs:  the number of arguments
9136 *
9137 * Implement the substring-before() XPath function
9138 *    string substring-before(string, string)
9139 * The substring-before function returns the substring of the first
9140 * argument string that precedes the first occurrence of the second
9141 * argument string in the first argument string, or the empty string
9142 * if the first argument string does not contain the second argument
9143 * string. For example, substring-before("1999/04/01","/") returns 1999.
9144 */
9145void
9146xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9147  xmlXPathObjectPtr str;
9148  xmlXPathObjectPtr find;
9149  xmlBufferPtr target;
9150  const xmlChar *point;
9151  int offset;
9152
9153  CHECK_ARITY(2);
9154  CAST_TO_STRING;
9155  find = valuePop(ctxt);
9156  CAST_TO_STRING;
9157  str = valuePop(ctxt);
9158
9159  target = xmlBufferCreate();
9160  if (target) {
9161    point = xmlStrstr(str->stringval, find->stringval);
9162    if (point) {
9163      offset = (int)(point - str->stringval);
9164      xmlBufferAdd(target, str->stringval, offset);
9165    }
9166    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9167	xmlBufferContent(target)));
9168    xmlBufferFree(target);
9169  }
9170  xmlXPathReleaseObject(ctxt->context, str);
9171  xmlXPathReleaseObject(ctxt->context, find);
9172}
9173
9174/**
9175 * xmlXPathSubstringAfterFunction:
9176 * @ctxt:  the XPath Parser context
9177 * @nargs:  the number of arguments
9178 *
9179 * Implement the substring-after() XPath function
9180 *    string substring-after(string, string)
9181 * The substring-after function returns the substring of the first
9182 * argument string that follows the first occurrence of the second
9183 * argument string in the first argument string, or the empty stringi
9184 * if the first argument string does not contain the second argument
9185 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9186 * and substring-after("1999/04/01","19") returns 99/04/01.
9187 */
9188void
9189xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9190  xmlXPathObjectPtr str;
9191  xmlXPathObjectPtr find;
9192  xmlBufferPtr target;
9193  const xmlChar *point;
9194  int offset;
9195
9196  CHECK_ARITY(2);
9197  CAST_TO_STRING;
9198  find = valuePop(ctxt);
9199  CAST_TO_STRING;
9200  str = valuePop(ctxt);
9201
9202  target = xmlBufferCreate();
9203  if (target) {
9204    point = xmlStrstr(str->stringval, find->stringval);
9205    if (point) {
9206      offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9207      xmlBufferAdd(target, &str->stringval[offset],
9208		   xmlStrlen(str->stringval) - offset);
9209    }
9210    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9211	xmlBufferContent(target)));
9212    xmlBufferFree(target);
9213  }
9214  xmlXPathReleaseObject(ctxt->context, str);
9215  xmlXPathReleaseObject(ctxt->context, find);
9216}
9217
9218/**
9219 * xmlXPathNormalizeFunction:
9220 * @ctxt:  the XPath Parser context
9221 * @nargs:  the number of arguments
9222 *
9223 * Implement the normalize-space() XPath function
9224 *    string normalize-space(string?)
9225 * The normalize-space function returns the argument string with white
9226 * space normalized by stripping leading and trailing whitespace
9227 * and replacing sequences of whitespace characters by a single
9228 * space. Whitespace characters are the same allowed by the S production
9229 * in XML. If the argument is omitted, it defaults to the context
9230 * node converted to a string, in other words the value of the context node.
9231 */
9232void
9233xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9234  xmlXPathObjectPtr obj = NULL;
9235  xmlChar *source = NULL;
9236  xmlBufferPtr target;
9237  xmlChar blank;
9238
9239  if (ctxt == NULL) return;
9240  if (nargs == 0) {
9241    /* Use current context node */
9242      valuePush(ctxt,
9243	  xmlXPathCacheWrapString(ctxt->context,
9244	    xmlXPathCastNodeToString(ctxt->context->node)));
9245    nargs = 1;
9246  }
9247
9248  CHECK_ARITY(1);
9249  CAST_TO_STRING;
9250  CHECK_TYPE(XPATH_STRING);
9251  obj = valuePop(ctxt);
9252  source = obj->stringval;
9253
9254  target = xmlBufferCreate();
9255  if (target && source) {
9256
9257    /* Skip leading whitespaces */
9258    while (IS_BLANK_CH(*source))
9259      source++;
9260
9261    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9262    blank = 0;
9263    while (*source) {
9264      if (IS_BLANK_CH(*source)) {
9265	blank = 0x20;
9266      } else {
9267	if (blank) {
9268	  xmlBufferAdd(target, &blank, 1);
9269	  blank = 0;
9270	}
9271	xmlBufferAdd(target, source, 1);
9272      }
9273      source++;
9274    }
9275    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9276	xmlBufferContent(target)));
9277    xmlBufferFree(target);
9278  }
9279  xmlXPathReleaseObject(ctxt->context, obj);
9280}
9281
9282/**
9283 * xmlXPathTranslateFunction:
9284 * @ctxt:  the XPath Parser context
9285 * @nargs:  the number of arguments
9286 *
9287 * Implement the translate() XPath function
9288 *    string translate(string, string, string)
9289 * The translate function returns the first argument string with
9290 * occurrences of characters in the second argument string replaced
9291 * by the character at the corresponding position in the third argument
9292 * string. For example, translate("bar","abc","ABC") returns the string
9293 * BAr. If there is a character in the second argument string with no
9294 * character at a corresponding position in the third argument string
9295 * (because the second argument string is longer than the third argument
9296 * string), then occurrences of that character in the first argument
9297 * string are removed. For example, translate("--aaa--","abc-","ABC")
9298 * returns "AAA". If a character occurs more than once in second
9299 * argument string, then the first occurrence determines the replacement
9300 * character. If the third argument string is longer than the second
9301 * argument string, then excess characters are ignored.
9302 */
9303void
9304xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9305    xmlXPathObjectPtr str;
9306    xmlXPathObjectPtr from;
9307    xmlXPathObjectPtr to;
9308    xmlBufferPtr target;
9309    int offset, max;
9310    xmlChar ch;
9311    const xmlChar *point;
9312    xmlChar *cptr;
9313
9314    CHECK_ARITY(3);
9315
9316    CAST_TO_STRING;
9317    to = valuePop(ctxt);
9318    CAST_TO_STRING;
9319    from = valuePop(ctxt);
9320    CAST_TO_STRING;
9321    str = valuePop(ctxt);
9322
9323    target = xmlBufferCreate();
9324    if (target) {
9325	max = xmlUTF8Strlen(to->stringval);
9326	for (cptr = str->stringval; (ch=*cptr); ) {
9327	    offset = xmlUTF8Strloc(from->stringval, cptr);
9328	    if (offset >= 0) {
9329		if (offset < max) {
9330		    point = xmlUTF8Strpos(to->stringval, offset);
9331		    if (point)
9332			xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9333		}
9334	    } else
9335		xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9336
9337	    /* Step to next character in input */
9338	    cptr++;
9339	    if ( ch & 0x80 ) {
9340		/* if not simple ascii, verify proper format */
9341		if ( (ch & 0xc0) != 0xc0 ) {
9342		    xmlGenericError(xmlGenericErrorContext,
9343			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
9344                    /* not asserting an XPath error is probably better */
9345		    break;
9346		}
9347		/* then skip over remaining bytes for this char */
9348		while ( (ch <<= 1) & 0x80 )
9349		    if ( (*cptr++ & 0xc0) != 0x80 ) {
9350			xmlGenericError(xmlGenericErrorContext,
9351			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9352                        /* not asserting an XPath error is probably better */
9353			break;
9354		    }
9355		if (ch & 0x80) /* must have had error encountered */
9356		    break;
9357	    }
9358	}
9359    }
9360    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9361	xmlBufferContent(target)));
9362    xmlBufferFree(target);
9363    xmlXPathReleaseObject(ctxt->context, str);
9364    xmlXPathReleaseObject(ctxt->context, from);
9365    xmlXPathReleaseObject(ctxt->context, to);
9366}
9367
9368/**
9369 * xmlXPathBooleanFunction:
9370 * @ctxt:  the XPath Parser context
9371 * @nargs:  the number of arguments
9372 *
9373 * Implement the boolean() XPath function
9374 *    boolean boolean(object)
9375 * The boolean function converts its argument to a boolean as follows:
9376 *    - a number is true if and only if it is neither positive or
9377 *      negative zero nor NaN
9378 *    - a node-set is true if and only if it is non-empty
9379 *    - a string is true if and only if its length is non-zero
9380 */
9381void
9382xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9383    xmlXPathObjectPtr cur;
9384
9385    CHECK_ARITY(1);
9386    cur = valuePop(ctxt);
9387    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9388    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9389    valuePush(ctxt, cur);
9390}
9391
9392/**
9393 * xmlXPathNotFunction:
9394 * @ctxt:  the XPath Parser context
9395 * @nargs:  the number of arguments
9396 *
9397 * Implement the not() XPath function
9398 *    boolean not(boolean)
9399 * The not function returns true if its argument is false,
9400 * and false otherwise.
9401 */
9402void
9403xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9404    CHECK_ARITY(1);
9405    CAST_TO_BOOLEAN;
9406    CHECK_TYPE(XPATH_BOOLEAN);
9407    ctxt->value->boolval = ! ctxt->value->boolval;
9408}
9409
9410/**
9411 * xmlXPathTrueFunction:
9412 * @ctxt:  the XPath Parser context
9413 * @nargs:  the number of arguments
9414 *
9415 * Implement the true() XPath function
9416 *    boolean true()
9417 */
9418void
9419xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9420    CHECK_ARITY(0);
9421    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9422}
9423
9424/**
9425 * xmlXPathFalseFunction:
9426 * @ctxt:  the XPath Parser context
9427 * @nargs:  the number of arguments
9428 *
9429 * Implement the false() XPath function
9430 *    boolean false()
9431 */
9432void
9433xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9434    CHECK_ARITY(0);
9435    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9436}
9437
9438/**
9439 * xmlXPathLangFunction:
9440 * @ctxt:  the XPath Parser context
9441 * @nargs:  the number of arguments
9442 *
9443 * Implement the lang() XPath function
9444 *    boolean lang(string)
9445 * The lang function returns true or false depending on whether the
9446 * language of the context node as specified by xml:lang attributes
9447 * is the same as or is a sublanguage of the language specified by
9448 * the argument string. The language of the context node is determined
9449 * by the value of the xml:lang attribute on the context node, or, if
9450 * the context node has no xml:lang attribute, by the value of the
9451 * xml:lang attribute on the nearest ancestor of the context node that
9452 * has an xml:lang attribute. If there is no such attribute, then lang
9453 * returns false. If there is such an attribute, then lang returns
9454 * true if the attribute value is equal to the argument ignoring case,
9455 * or if there is some suffix starting with - such that the attribute
9456 * value is equal to the argument ignoring that suffix of the attribute
9457 * value and ignoring case.
9458 */
9459void
9460xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9461    xmlXPathObjectPtr val = NULL;
9462    const xmlChar *theLang = NULL;
9463    const xmlChar *lang;
9464    int ret = 0;
9465    int i;
9466
9467    CHECK_ARITY(1);
9468    CAST_TO_STRING;
9469    CHECK_TYPE(XPATH_STRING);
9470    val = valuePop(ctxt);
9471    lang = val->stringval;
9472    theLang = xmlNodeGetLang(ctxt->context->node);
9473    if ((theLang != NULL) && (lang != NULL)) {
9474        for (i = 0;lang[i] != 0;i++)
9475	    if (toupper(lang[i]) != toupper(theLang[i]))
9476	        goto not_equal;
9477	if ((theLang[i] == 0) || (theLang[i] == '-'))
9478	    ret = 1;
9479    }
9480not_equal:
9481    if (theLang != NULL)
9482	xmlFree((void *)theLang);
9483
9484    xmlXPathReleaseObject(ctxt->context, val);
9485    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9486}
9487
9488/**
9489 * xmlXPathNumberFunction:
9490 * @ctxt:  the XPath Parser context
9491 * @nargs:  the number of arguments
9492 *
9493 * Implement the number() XPath function
9494 *    number number(object?)
9495 */
9496void
9497xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9498    xmlXPathObjectPtr cur;
9499    double res;
9500
9501    if (ctxt == NULL) return;
9502    if (nargs == 0) {
9503	if (ctxt->context->node == NULL) {
9504	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9505	} else {
9506	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9507
9508	    res = xmlXPathStringEvalNumber(content);
9509	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9510	    xmlFree(content);
9511	}
9512	return;
9513    }
9514
9515    CHECK_ARITY(1);
9516    cur = valuePop(ctxt);
9517    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9518}
9519
9520/**
9521 * xmlXPathSumFunction:
9522 * @ctxt:  the XPath Parser context
9523 * @nargs:  the number of arguments
9524 *
9525 * Implement the sum() XPath function
9526 *    number sum(node-set)
9527 * The sum function returns the sum of the values of the nodes in
9528 * the argument node-set.
9529 */
9530void
9531xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9532    xmlXPathObjectPtr cur;
9533    int i;
9534    double res = 0.0;
9535
9536    CHECK_ARITY(1);
9537    if ((ctxt->value == NULL) ||
9538	((ctxt->value->type != XPATH_NODESET) &&
9539	 (ctxt->value->type != XPATH_XSLT_TREE)))
9540	XP_ERROR(XPATH_INVALID_TYPE);
9541    cur = valuePop(ctxt);
9542
9543    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9544	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9545	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9546	}
9547    }
9548    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9549    xmlXPathReleaseObject(ctxt->context, cur);
9550}
9551
9552/*
9553 * To assure working code on multiple platforms, we want to only depend
9554 * upon the characteristic truncation of converting a floating point value
9555 * to an integer.  Unfortunately, because of the different storage sizes
9556 * of our internal floating point value (double) and integer (int), we
9557 * can't directly convert (see bug 301162).  This macro is a messy
9558 * 'workaround'
9559 */
9560#define XTRUNC(f, v)            \
9561    f = fmod((v), INT_MAX);     \
9562    f = (v) - (f) + (double)((int)(f));
9563
9564/**
9565 * xmlXPathFloorFunction:
9566 * @ctxt:  the XPath Parser context
9567 * @nargs:  the number of arguments
9568 *
9569 * Implement the floor() XPath function
9570 *    number floor(number)
9571 * The floor function returns the largest (closest to positive infinity)
9572 * number that is not greater than the argument and that is an integer.
9573 */
9574void
9575xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9576    double f;
9577
9578    CHECK_ARITY(1);
9579    CAST_TO_NUMBER;
9580    CHECK_TYPE(XPATH_NUMBER);
9581
9582    XTRUNC(f, ctxt->value->floatval);
9583    if (f != ctxt->value->floatval) {
9584	if (ctxt->value->floatval > 0)
9585	    ctxt->value->floatval = f;
9586	else
9587	    ctxt->value->floatval = f - 1;
9588    }
9589}
9590
9591/**
9592 * xmlXPathCeilingFunction:
9593 * @ctxt:  the XPath Parser context
9594 * @nargs:  the number of arguments
9595 *
9596 * Implement the ceiling() XPath function
9597 *    number ceiling(number)
9598 * The ceiling function returns the smallest (closest to negative infinity)
9599 * number that is not less than the argument and that is an integer.
9600 */
9601void
9602xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9603    double f;
9604
9605    CHECK_ARITY(1);
9606    CAST_TO_NUMBER;
9607    CHECK_TYPE(XPATH_NUMBER);
9608
9609#if 0
9610    ctxt->value->floatval = ceil(ctxt->value->floatval);
9611#else
9612    XTRUNC(f, ctxt->value->floatval);
9613    if (f != ctxt->value->floatval) {
9614	if (ctxt->value->floatval > 0)
9615	    ctxt->value->floatval = f + 1;
9616	else {
9617	    if (ctxt->value->floatval < 0 && f == 0)
9618	        ctxt->value->floatval = xmlXPathNZERO;
9619	    else
9620	        ctxt->value->floatval = f;
9621	}
9622
9623    }
9624#endif
9625}
9626
9627/**
9628 * xmlXPathRoundFunction:
9629 * @ctxt:  the XPath Parser context
9630 * @nargs:  the number of arguments
9631 *
9632 * Implement the round() XPath function
9633 *    number round(number)
9634 * The round function returns the number that is closest to the
9635 * argument and that is an integer. If there are two such numbers,
9636 * then the one that is even is returned.
9637 */
9638void
9639xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9640    double f;
9641
9642    CHECK_ARITY(1);
9643    CAST_TO_NUMBER;
9644    CHECK_TYPE(XPATH_NUMBER);
9645
9646    if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9647	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9648	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9649	(ctxt->value->floatval == 0.0))
9650	return;
9651
9652    XTRUNC(f, ctxt->value->floatval);
9653    if (ctxt->value->floatval < 0) {
9654	if (ctxt->value->floatval < f - 0.5)
9655	    ctxt->value->floatval = f - 1;
9656	else
9657	    ctxt->value->floatval = f;
9658	if (ctxt->value->floatval == 0)
9659	    ctxt->value->floatval = xmlXPathNZERO;
9660    } else {
9661	if (ctxt->value->floatval < f + 0.5)
9662	    ctxt->value->floatval = f;
9663	else
9664	    ctxt->value->floatval = f + 1;
9665    }
9666}
9667
9668/************************************************************************
9669 *									*
9670 *			The Parser					*
9671 *									*
9672 ************************************************************************/
9673
9674/*
9675 * a few forward declarations since we use a recursive call based
9676 * implementation.
9677 */
9678static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9679static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9680static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9681static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9682static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9683	                                  int qualified);
9684
9685/**
9686 * xmlXPathCurrentChar:
9687 * @ctxt:  the XPath parser context
9688 * @cur:  pointer to the beginning of the char
9689 * @len:  pointer to the length of the char read
9690 *
9691 * The current char value, if using UTF-8 this may actually span multiple
9692 * bytes in the input buffer.
9693 *
9694 * Returns the current char value and its length
9695 */
9696
9697static int
9698xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9699    unsigned char c;
9700    unsigned int val;
9701    const xmlChar *cur;
9702
9703    if (ctxt == NULL)
9704	return(0);
9705    cur = ctxt->cur;
9706
9707    /*
9708     * We are supposed to handle UTF8, check it's valid
9709     * From rfc2044: encoding of the Unicode values on UTF-8:
9710     *
9711     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9712     * 0000 0000-0000 007F   0xxxxxxx
9713     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9714     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9715     *
9716     * Check for the 0x110000 limit too
9717     */
9718    c = *cur;
9719    if (c & 0x80) {
9720	if ((cur[1] & 0xc0) != 0x80)
9721	    goto encoding_error;
9722	if ((c & 0xe0) == 0xe0) {
9723
9724	    if ((cur[2] & 0xc0) != 0x80)
9725		goto encoding_error;
9726	    if ((c & 0xf0) == 0xf0) {
9727		if (((c & 0xf8) != 0xf0) ||
9728		    ((cur[3] & 0xc0) != 0x80))
9729		    goto encoding_error;
9730		/* 4-byte code */
9731		*len = 4;
9732		val = (cur[0] & 0x7) << 18;
9733		val |= (cur[1] & 0x3f) << 12;
9734		val |= (cur[2] & 0x3f) << 6;
9735		val |= cur[3] & 0x3f;
9736	    } else {
9737	      /* 3-byte code */
9738		*len = 3;
9739		val = (cur[0] & 0xf) << 12;
9740		val |= (cur[1] & 0x3f) << 6;
9741		val |= cur[2] & 0x3f;
9742	    }
9743	} else {
9744	  /* 2-byte code */
9745	    *len = 2;
9746	    val = (cur[0] & 0x1f) << 6;
9747	    val |= cur[1] & 0x3f;
9748	}
9749	if (!IS_CHAR(val)) {
9750	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9751	}
9752	return(val);
9753    } else {
9754	/* 1-byte code */
9755	*len = 1;
9756	return((int) *cur);
9757    }
9758encoding_error:
9759    /*
9760     * If we detect an UTF8 error that probably means that the
9761     * input encoding didn't get properly advertised in the
9762     * declaration header. Report the error and switch the encoding
9763     * to ISO-Latin-1 (if you don't like this policy, just declare the
9764     * encoding !)
9765     */
9766    *len = 0;
9767    XP_ERROR0(XPATH_ENCODING_ERROR);
9768}
9769
9770/**
9771 * xmlXPathParseNCName:
9772 * @ctxt:  the XPath Parser context
9773 *
9774 * parse an XML namespace non qualified name.
9775 *
9776 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9777 *
9778 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9779 *                       CombiningChar | Extender
9780 *
9781 * Returns the namespace name or NULL
9782 */
9783
9784xmlChar *
9785xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9786    const xmlChar *in;
9787    xmlChar *ret;
9788    int count = 0;
9789
9790    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9791    /*
9792     * Accelerator for simple ASCII names
9793     */
9794    in = ctxt->cur;
9795    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9796	((*in >= 0x41) && (*in <= 0x5A)) ||
9797	(*in == '_')) {
9798	in++;
9799	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9800	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9801	       ((*in >= 0x30) && (*in <= 0x39)) ||
9802	       (*in == '_') || (*in == '.') ||
9803	       (*in == '-'))
9804	    in++;
9805	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9806            (*in == '[') || (*in == ']') || (*in == ':') ||
9807            (*in == '@') || (*in == '*')) {
9808	    count = in - ctxt->cur;
9809	    if (count == 0)
9810		return(NULL);
9811	    ret = xmlStrndup(ctxt->cur, count);
9812	    ctxt->cur = in;
9813	    return(ret);
9814	}
9815    }
9816    return(xmlXPathParseNameComplex(ctxt, 0));
9817}
9818
9819
9820/**
9821 * xmlXPathParseQName:
9822 * @ctxt:  the XPath Parser context
9823 * @prefix:  a xmlChar **
9824 *
9825 * parse an XML qualified name
9826 *
9827 * [NS 5] QName ::= (Prefix ':')? LocalPart
9828 *
9829 * [NS 6] Prefix ::= NCName
9830 *
9831 * [NS 7] LocalPart ::= NCName
9832 *
9833 * Returns the function returns the local part, and prefix is updated
9834 *   to get the Prefix if any.
9835 */
9836
9837static xmlChar *
9838xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9839    xmlChar *ret = NULL;
9840
9841    *prefix = NULL;
9842    ret = xmlXPathParseNCName(ctxt);
9843    if (ret && CUR == ':') {
9844        *prefix = ret;
9845	NEXT;
9846	ret = xmlXPathParseNCName(ctxt);
9847    }
9848    return(ret);
9849}
9850
9851/**
9852 * xmlXPathParseName:
9853 * @ctxt:  the XPath Parser context
9854 *
9855 * parse an XML name
9856 *
9857 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9858 *                  CombiningChar | Extender
9859 *
9860 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9861 *
9862 * Returns the namespace name or NULL
9863 */
9864
9865xmlChar *
9866xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9867    const xmlChar *in;
9868    xmlChar *ret;
9869    int count = 0;
9870
9871    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9872    /*
9873     * Accelerator for simple ASCII names
9874     */
9875    in = ctxt->cur;
9876    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9877	((*in >= 0x41) && (*in <= 0x5A)) ||
9878	(*in == '_') || (*in == ':')) {
9879	in++;
9880	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9881	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9882	       ((*in >= 0x30) && (*in <= 0x39)) ||
9883	       (*in == '_') || (*in == '-') ||
9884	       (*in == ':') || (*in == '.'))
9885	    in++;
9886	if ((*in > 0) && (*in < 0x80)) {
9887	    count = in - ctxt->cur;
9888	    ret = xmlStrndup(ctxt->cur, count);
9889	    ctxt->cur = in;
9890	    return(ret);
9891	}
9892    }
9893    return(xmlXPathParseNameComplex(ctxt, 1));
9894}
9895
9896static xmlChar *
9897xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9898    xmlChar buf[XML_MAX_NAMELEN + 5];
9899    int len = 0, l;
9900    int c;
9901
9902    /*
9903     * Handler for more complex cases
9904     */
9905    c = CUR_CHAR(l);
9906    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9907        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9908        (c == '*') || /* accelerators */
9909	(!IS_LETTER(c) && (c != '_') &&
9910         ((qualified) && (c != ':')))) {
9911	return(NULL);
9912    }
9913
9914    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9915	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9916            (c == '.') || (c == '-') ||
9917	    (c == '_') || ((qualified) && (c == ':')) ||
9918	    (IS_COMBINING(c)) ||
9919	    (IS_EXTENDER(c)))) {
9920	COPY_BUF(l,buf,len,c);
9921	NEXTL(l);
9922	c = CUR_CHAR(l);
9923	if (len >= XML_MAX_NAMELEN) {
9924	    /*
9925	     * Okay someone managed to make a huge name, so he's ready to pay
9926	     * for the processing speed.
9927	     */
9928	    xmlChar *buffer;
9929	    int max = len * 2;
9930
9931	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9932	    if (buffer == NULL) {
9933		XP_ERRORNULL(XPATH_MEMORY_ERROR);
9934	    }
9935	    memcpy(buffer, buf, len);
9936	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9937		   (c == '.') || (c == '-') ||
9938		   (c == '_') || ((qualified) && (c == ':')) ||
9939		   (IS_COMBINING(c)) ||
9940		   (IS_EXTENDER(c))) {
9941		if (len + 10 > max) {
9942		    max *= 2;
9943		    buffer = (xmlChar *) xmlRealloc(buffer,
9944			                            max * sizeof(xmlChar));
9945		    if (buffer == NULL) {
9946			XP_ERRORNULL(XPATH_MEMORY_ERROR);
9947		    }
9948		}
9949		COPY_BUF(l,buffer,len,c);
9950		NEXTL(l);
9951		c = CUR_CHAR(l);
9952	    }
9953	    buffer[len] = 0;
9954	    return(buffer);
9955	}
9956    }
9957    if (len == 0)
9958	return(NULL);
9959    return(xmlStrndup(buf, len));
9960}
9961
9962#define MAX_FRAC 20
9963
9964/*
9965 * These are used as divisors for the fractional part of a number.
9966 * Since the table includes 1.0 (representing '0' fractional digits),
9967 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9968 */
9969static double my_pow10[MAX_FRAC+1] = {
9970    1.0, 10.0, 100.0, 1000.0, 10000.0,
9971    100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9972    10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9973    100000000000000.0,
9974    1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
9975    1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
9976};
9977
9978/**
9979 * xmlXPathStringEvalNumber:
9980 * @str:  A string to scan
9981 *
9982 *  [30a]  Float  ::= Number ('e' Digits?)?
9983 *
9984 *  [30]   Number ::=   Digits ('.' Digits?)?
9985 *                    | '.' Digits
9986 *  [31]   Digits ::=   [0-9]+
9987 *
9988 * Compile a Number in the string
9989 * In complement of the Number expression, this function also handles
9990 * negative values : '-' Number.
9991 *
9992 * Returns the double value.
9993 */
9994double
9995xmlXPathStringEvalNumber(const xmlChar *str) {
9996    const xmlChar *cur = str;
9997    double ret;
9998    int ok = 0;
9999    int isneg = 0;
10000    int exponent = 0;
10001    int is_exponent_negative = 0;
10002#ifdef __GNUC__
10003    unsigned long tmp = 0;
10004    double temp;
10005#endif
10006    if (cur == NULL) return(0);
10007    while (IS_BLANK_CH(*cur)) cur++;
10008    if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10009        return(xmlXPathNAN);
10010    }
10011    if (*cur == '-') {
10012	isneg = 1;
10013	cur++;
10014    }
10015
10016#ifdef __GNUC__
10017    /*
10018     * tmp/temp is a workaround against a gcc compiler bug
10019     * http://veillard.com/gcc.bug
10020     */
10021    ret = 0;
10022    while ((*cur >= '0') && (*cur <= '9')) {
10023	ret = ret * 10;
10024	tmp = (*cur - '0');
10025	ok = 1;
10026	cur++;
10027	temp = (double) tmp;
10028	ret = ret + temp;
10029    }
10030#else
10031    ret = 0;
10032    while ((*cur >= '0') && (*cur <= '9')) {
10033	ret = ret * 10 + (*cur - '0');
10034	ok = 1;
10035	cur++;
10036    }
10037#endif
10038
10039    if (*cur == '.') {
10040	int v, frac = 0;
10041	double fraction = 0;
10042
10043        cur++;
10044	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10045	    return(xmlXPathNAN);
10046	}
10047	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10048	    v = (*cur - '0');
10049	    fraction = fraction * 10 + v;
10050	    frac = frac + 1;
10051	    cur++;
10052	}
10053	fraction /= my_pow10[frac];
10054	ret = ret + fraction;
10055	while ((*cur >= '0') && (*cur <= '9'))
10056	    cur++;
10057    }
10058    if ((*cur == 'e') || (*cur == 'E')) {
10059      cur++;
10060      if (*cur == '-') {
10061	is_exponent_negative = 1;
10062	cur++;
10063      } else if (*cur == '+') {
10064        cur++;
10065      }
10066      while ((*cur >= '0') && (*cur <= '9')) {
10067	exponent = exponent * 10 + (*cur - '0');
10068	cur++;
10069      }
10070    }
10071    while (IS_BLANK_CH(*cur)) cur++;
10072    if (*cur != 0) return(xmlXPathNAN);
10073    if (isneg) ret = -ret;
10074    if (is_exponent_negative) exponent = -exponent;
10075    ret *= pow(10.0, (double)exponent);
10076    return(ret);
10077}
10078
10079/**
10080 * xmlXPathCompNumber:
10081 * @ctxt:  the XPath Parser context
10082 *
10083 *  [30]   Number ::=   Digits ('.' Digits?)?
10084 *                    | '.' Digits
10085 *  [31]   Digits ::=   [0-9]+
10086 *
10087 * Compile a Number, then push it on the stack
10088 *
10089 */
10090static void
10091xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10092{
10093    double ret = 0.0;
10094    int ok = 0;
10095    int exponent = 0;
10096    int is_exponent_negative = 0;
10097#ifdef __GNUC__
10098    unsigned long tmp = 0;
10099    double temp;
10100#endif
10101
10102    CHECK_ERROR;
10103    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10104        XP_ERROR(XPATH_NUMBER_ERROR);
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        NEXT;
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	NEXT;
10126    }
10127#endif
10128    if (CUR == '.') {
10129	int v, frac = 0;
10130	double fraction = 0;
10131
10132        NEXT;
10133        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10134            XP_ERROR(XPATH_NUMBER_ERROR);
10135        }
10136        while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10137	    v = (CUR - '0');
10138	    fraction = fraction * 10 + v;
10139	    frac = frac + 1;
10140            NEXT;
10141        }
10142        fraction /= my_pow10[frac];
10143        ret = ret + fraction;
10144        while ((CUR >= '0') && (CUR <= '9'))
10145            NEXT;
10146    }
10147    if ((CUR == 'e') || (CUR == 'E')) {
10148        NEXT;
10149        if (CUR == '-') {
10150            is_exponent_negative = 1;
10151            NEXT;
10152        } else if (CUR == '+') {
10153	    NEXT;
10154	}
10155        while ((CUR >= '0') && (CUR <= '9')) {
10156            exponent = exponent * 10 + (CUR - '0');
10157            NEXT;
10158        }
10159        if (is_exponent_negative)
10160            exponent = -exponent;
10161        ret *= pow(10.0, (double) exponent);
10162    }
10163    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10164                   xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10165}
10166
10167/**
10168 * xmlXPathParseLiteral:
10169 * @ctxt:  the XPath Parser context
10170 *
10171 * Parse a Literal
10172 *
10173 *  [29]   Literal ::=   '"' [^"]* '"'
10174 *                    | "'" [^']* "'"
10175 *
10176 * Returns the value found or NULL in case of error
10177 */
10178static xmlChar *
10179xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10180    const xmlChar *q;
10181    xmlChar *ret = NULL;
10182
10183    if (CUR == '"') {
10184        NEXT;
10185	q = CUR_PTR;
10186	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10187	    NEXT;
10188	if (!IS_CHAR_CH(CUR)) {
10189	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10190	} else {
10191	    ret = xmlStrndup(q, CUR_PTR - q);
10192	    NEXT;
10193        }
10194    } else if (CUR == '\'') {
10195        NEXT;
10196	q = CUR_PTR;
10197	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10198	    NEXT;
10199	if (!IS_CHAR_CH(CUR)) {
10200	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10201	} else {
10202	    ret = xmlStrndup(q, CUR_PTR - q);
10203	    NEXT;
10204        }
10205    } else {
10206	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10207    }
10208    return(ret);
10209}
10210
10211/**
10212 * xmlXPathCompLiteral:
10213 * @ctxt:  the XPath Parser context
10214 *
10215 * Parse a Literal and push it on the stack.
10216 *
10217 *  [29]   Literal ::=   '"' [^"]* '"'
10218 *                    | "'" [^']* "'"
10219 *
10220 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10221 */
10222static void
10223xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10224    const xmlChar *q;
10225    xmlChar *ret = NULL;
10226
10227    if (CUR == '"') {
10228        NEXT;
10229	q = CUR_PTR;
10230	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10231	    NEXT;
10232	if (!IS_CHAR_CH(CUR)) {
10233	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10234	} else {
10235	    ret = xmlStrndup(q, CUR_PTR - q);
10236	    NEXT;
10237        }
10238    } else if (CUR == '\'') {
10239        NEXT;
10240	q = CUR_PTR;
10241	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10242	    NEXT;
10243	if (!IS_CHAR_CH(CUR)) {
10244	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10245	} else {
10246	    ret = xmlStrndup(q, CUR_PTR - q);
10247	    NEXT;
10248        }
10249    } else {
10250	XP_ERROR(XPATH_START_LITERAL_ERROR);
10251    }
10252    if (ret == NULL) return;
10253    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10254	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
10255    xmlFree(ret);
10256}
10257
10258/**
10259 * xmlXPathCompVariableReference:
10260 * @ctxt:  the XPath Parser context
10261 *
10262 * Parse a VariableReference, evaluate it and push it on the stack.
10263 *
10264 * The variable bindings consist of a mapping from variable names
10265 * to variable values. The value of a variable is an object, which can be
10266 * of any of the types that are possible for the value of an expression,
10267 * and may also be of additional types not specified here.
10268 *
10269 * Early evaluation is possible since:
10270 * The variable bindings [...] used to evaluate a subexpression are
10271 * always the same as those used to evaluate the containing expression.
10272 *
10273 *  [36]   VariableReference ::=   '$' QName
10274 */
10275static void
10276xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10277    xmlChar *name;
10278    xmlChar *prefix;
10279
10280    SKIP_BLANKS;
10281    if (CUR != '$') {
10282	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10283    }
10284    NEXT;
10285    name = xmlXPathParseQName(ctxt, &prefix);
10286    if (name == NULL) {
10287	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10288    }
10289    ctxt->comp->last = -1;
10290    PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10291	           name, prefix);
10292    SKIP_BLANKS;
10293    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10294	XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10295    }
10296}
10297
10298/**
10299 * xmlXPathIsNodeType:
10300 * @name:  a name string
10301 *
10302 * Is the name given a NodeType one.
10303 *
10304 *  [38]   NodeType ::=   'comment'
10305 *                    | 'text'
10306 *                    | 'processing-instruction'
10307 *                    | 'node'
10308 *
10309 * Returns 1 if true 0 otherwise
10310 */
10311int
10312xmlXPathIsNodeType(const xmlChar *name) {
10313    if (name == NULL)
10314	return(0);
10315
10316    if (xmlStrEqual(name, BAD_CAST "node"))
10317	return(1);
10318    if (xmlStrEqual(name, BAD_CAST "text"))
10319	return(1);
10320    if (xmlStrEqual(name, BAD_CAST "comment"))
10321	return(1);
10322    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10323	return(1);
10324    return(0);
10325}
10326
10327/**
10328 * xmlXPathCompFunctionCall:
10329 * @ctxt:  the XPath Parser context
10330 *
10331 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10332 *  [17]   Argument ::=   Expr
10333 *
10334 * Compile a function call, the evaluation of all arguments are
10335 * pushed on the stack
10336 */
10337static void
10338xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10339    xmlChar *name;
10340    xmlChar *prefix;
10341    int nbargs = 0;
10342    int sort = 1;
10343
10344    name = xmlXPathParseQName(ctxt, &prefix);
10345    if (name == NULL) {
10346	xmlFree(prefix);
10347	XP_ERROR(XPATH_EXPR_ERROR);
10348    }
10349    SKIP_BLANKS;
10350#ifdef DEBUG_EXPR
10351    if (prefix == NULL)
10352	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10353			name);
10354    else
10355	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10356			prefix, name);
10357#endif
10358
10359    if (CUR != '(') {
10360	XP_ERROR(XPATH_EXPR_ERROR);
10361    }
10362    NEXT;
10363    SKIP_BLANKS;
10364
10365    /*
10366    * Optimization for count(): we don't need the node-set to be sorted.
10367    */
10368    if ((prefix == NULL) && (name[0] == 'c') &&
10369	xmlStrEqual(name, BAD_CAST "count"))
10370    {
10371	sort = 0;
10372    }
10373    ctxt->comp->last = -1;
10374    if (CUR != ')') {
10375	while (CUR != 0) {
10376	    int op1 = ctxt->comp->last;
10377	    ctxt->comp->last = -1;
10378	    xmlXPathCompileExpr(ctxt, sort);
10379	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10380		xmlFree(name);
10381		xmlFree(prefix);
10382		return;
10383	    }
10384	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10385	    nbargs++;
10386	    if (CUR == ')') break;
10387	    if (CUR != ',') {
10388		XP_ERROR(XPATH_EXPR_ERROR);
10389	    }
10390	    NEXT;
10391	    SKIP_BLANKS;
10392	}
10393    }
10394    PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10395	           name, prefix);
10396    NEXT;
10397    SKIP_BLANKS;
10398}
10399
10400/**
10401 * xmlXPathCompPrimaryExpr:
10402 * @ctxt:  the XPath Parser context
10403 *
10404 *  [15]   PrimaryExpr ::=   VariableReference
10405 *                | '(' Expr ')'
10406 *                | Literal
10407 *                | Number
10408 *                | FunctionCall
10409 *
10410 * Compile a primary expression.
10411 */
10412static void
10413xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10414    SKIP_BLANKS;
10415    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10416    else if (CUR == '(') {
10417	NEXT;
10418	SKIP_BLANKS;
10419	xmlXPathCompileExpr(ctxt, 1);
10420	CHECK_ERROR;
10421	if (CUR != ')') {
10422	    XP_ERROR(XPATH_EXPR_ERROR);
10423	}
10424	NEXT;
10425	SKIP_BLANKS;
10426    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10427	xmlXPathCompNumber(ctxt);
10428    } else if ((CUR == '\'') || (CUR == '"')) {
10429	xmlXPathCompLiteral(ctxt);
10430    } else {
10431	xmlXPathCompFunctionCall(ctxt);
10432    }
10433    SKIP_BLANKS;
10434}
10435
10436/**
10437 * xmlXPathCompFilterExpr:
10438 * @ctxt:  the XPath Parser context
10439 *
10440 *  [20]   FilterExpr ::=   PrimaryExpr
10441 *               | FilterExpr Predicate
10442 *
10443 * Compile a filter expression.
10444 * Square brackets are used to filter expressions in the same way that
10445 * they are used in location paths. It is an error if the expression to
10446 * be filtered does not evaluate to a node-set. The context node list
10447 * used for evaluating the expression in square brackets is the node-set
10448 * to be filtered listed in document order.
10449 */
10450
10451static void
10452xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10453    xmlXPathCompPrimaryExpr(ctxt);
10454    CHECK_ERROR;
10455    SKIP_BLANKS;
10456
10457    while (CUR == '[') {
10458	xmlXPathCompPredicate(ctxt, 1);
10459	SKIP_BLANKS;
10460    }
10461
10462
10463}
10464
10465/**
10466 * xmlXPathScanName:
10467 * @ctxt:  the XPath Parser context
10468 *
10469 * Trickery: parse an XML name but without consuming the input flow
10470 * Needed to avoid insanity in the parser state.
10471 *
10472 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10473 *                  CombiningChar | Extender
10474 *
10475 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10476 *
10477 * [6] Names ::= Name (S Name)*
10478 *
10479 * Returns the Name parsed or NULL
10480 */
10481
10482static xmlChar *
10483xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10484    int len = 0, l;
10485    int c;
10486    const xmlChar *cur;
10487    xmlChar *ret;
10488
10489    cur = ctxt->cur;
10490
10491    c = CUR_CHAR(l);
10492    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10493	(!IS_LETTER(c) && (c != '_') &&
10494         (c != ':'))) {
10495	return(NULL);
10496    }
10497
10498    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10499	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10500            (c == '.') || (c == '-') ||
10501	    (c == '_') || (c == ':') ||
10502	    (IS_COMBINING(c)) ||
10503	    (IS_EXTENDER(c)))) {
10504	len += l;
10505	NEXTL(l);
10506	c = CUR_CHAR(l);
10507    }
10508    ret = xmlStrndup(cur, ctxt->cur - cur);
10509    ctxt->cur = cur;
10510    return(ret);
10511}
10512
10513/**
10514 * xmlXPathCompPathExpr:
10515 * @ctxt:  the XPath Parser context
10516 *
10517 *  [19]   PathExpr ::=   LocationPath
10518 *               | FilterExpr
10519 *               | FilterExpr '/' RelativeLocationPath
10520 *               | FilterExpr '//' RelativeLocationPath
10521 *
10522 * Compile a path expression.
10523 * The / operator and // operators combine an arbitrary expression
10524 * and a relative location path. It is an error if the expression
10525 * does not evaluate to a node-set.
10526 * The / operator does composition in the same way as when / is
10527 * used in a location path. As in location paths, // is short for
10528 * /descendant-or-self::node()/.
10529 */
10530
10531static void
10532xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10533    int lc = 1;           /* Should we branch to LocationPath ?         */
10534    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10535
10536    SKIP_BLANKS;
10537    if ((CUR == '$') || (CUR == '(') ||
10538	(IS_ASCII_DIGIT(CUR)) ||
10539        (CUR == '\'') || (CUR == '"') ||
10540	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10541	lc = 0;
10542    } else if (CUR == '*') {
10543	/* relative or absolute location path */
10544	lc = 1;
10545    } else if (CUR == '/') {
10546	/* relative or absolute location path */
10547	lc = 1;
10548    } else if (CUR == '@') {
10549	/* relative abbreviated attribute location path */
10550	lc = 1;
10551    } else if (CUR == '.') {
10552	/* relative abbreviated attribute location path */
10553	lc = 1;
10554    } else {
10555	/*
10556	 * Problem is finding if we have a name here whether it's:
10557	 *   - a nodetype
10558	 *   - a function call in which case it's followed by '('
10559	 *   - an axis in which case it's followed by ':'
10560	 *   - a element name
10561	 * We do an a priori analysis here rather than having to
10562	 * maintain parsed token content through the recursive function
10563	 * calls. This looks uglier but makes the code easier to
10564	 * read/write/debug.
10565	 */
10566	SKIP_BLANKS;
10567	name = xmlXPathScanName(ctxt);
10568	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10569#ifdef DEBUG_STEP
10570	    xmlGenericError(xmlGenericErrorContext,
10571		    "PathExpr: Axis\n");
10572#endif
10573	    lc = 1;
10574	    xmlFree(name);
10575	} else if (name != NULL) {
10576	    int len =xmlStrlen(name);
10577
10578
10579	    while (NXT(len) != 0) {
10580		if (NXT(len) == '/') {
10581		    /* element name */
10582#ifdef DEBUG_STEP
10583		    xmlGenericError(xmlGenericErrorContext,
10584			    "PathExpr: AbbrRelLocation\n");
10585#endif
10586		    lc = 1;
10587		    break;
10588		} else if (IS_BLANK_CH(NXT(len))) {
10589		    /* ignore blanks */
10590		    ;
10591		} else if (NXT(len) == ':') {
10592#ifdef DEBUG_STEP
10593		    xmlGenericError(xmlGenericErrorContext,
10594			    "PathExpr: AbbrRelLocation\n");
10595#endif
10596		    lc = 1;
10597		    break;
10598		} else if ((NXT(len) == '(')) {
10599		    /* Note Type or Function */
10600		    if (xmlXPathIsNodeType(name)) {
10601#ifdef DEBUG_STEP
10602		        xmlGenericError(xmlGenericErrorContext,
10603				"PathExpr: Type search\n");
10604#endif
10605			lc = 1;
10606		    } else {
10607#ifdef DEBUG_STEP
10608		        xmlGenericError(xmlGenericErrorContext,
10609				"PathExpr: function call\n");
10610#endif
10611			lc = 0;
10612		    }
10613                    break;
10614		} else if ((NXT(len) == '[')) {
10615		    /* element name */
10616#ifdef DEBUG_STEP
10617		    xmlGenericError(xmlGenericErrorContext,
10618			    "PathExpr: AbbrRelLocation\n");
10619#endif
10620		    lc = 1;
10621		    break;
10622		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10623			   (NXT(len) == '=')) {
10624		    lc = 1;
10625		    break;
10626		} else {
10627		    lc = 1;
10628		    break;
10629		}
10630		len++;
10631	    }
10632	    if (NXT(len) == 0) {
10633#ifdef DEBUG_STEP
10634		xmlGenericError(xmlGenericErrorContext,
10635			"PathExpr: AbbrRelLocation\n");
10636#endif
10637		/* element name */
10638		lc = 1;
10639	    }
10640	    xmlFree(name);
10641	} else {
10642	    /* make sure all cases are covered explicitly */
10643	    XP_ERROR(XPATH_EXPR_ERROR);
10644	}
10645    }
10646
10647    if (lc) {
10648	if (CUR == '/') {
10649	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10650	} else {
10651	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10652	}
10653	xmlXPathCompLocationPath(ctxt);
10654    } else {
10655	xmlXPathCompFilterExpr(ctxt);
10656	CHECK_ERROR;
10657	if ((CUR == '/') && (NXT(1) == '/')) {
10658	    SKIP(2);
10659	    SKIP_BLANKS;
10660
10661	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10662		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10663	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10664
10665	    xmlXPathCompRelativeLocationPath(ctxt);
10666	} else if (CUR == '/') {
10667	    xmlXPathCompRelativeLocationPath(ctxt);
10668	}
10669    }
10670    SKIP_BLANKS;
10671}
10672
10673/**
10674 * xmlXPathCompUnionExpr:
10675 * @ctxt:  the XPath Parser context
10676 *
10677 *  [18]   UnionExpr ::=   PathExpr
10678 *               | UnionExpr '|' PathExpr
10679 *
10680 * Compile an union expression.
10681 */
10682
10683static void
10684xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10685    xmlXPathCompPathExpr(ctxt);
10686    CHECK_ERROR;
10687    SKIP_BLANKS;
10688    while (CUR == '|') {
10689	int op1 = ctxt->comp->last;
10690	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10691
10692	NEXT;
10693	SKIP_BLANKS;
10694	xmlXPathCompPathExpr(ctxt);
10695
10696	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10697
10698	SKIP_BLANKS;
10699    }
10700}
10701
10702/**
10703 * xmlXPathCompUnaryExpr:
10704 * @ctxt:  the XPath Parser context
10705 *
10706 *  [27]   UnaryExpr ::=   UnionExpr
10707 *                   | '-' UnaryExpr
10708 *
10709 * Compile an unary expression.
10710 */
10711
10712static void
10713xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10714    int minus = 0;
10715    int found = 0;
10716
10717    SKIP_BLANKS;
10718    while (CUR == '-') {
10719        minus = 1 - minus;
10720	found = 1;
10721	NEXT;
10722	SKIP_BLANKS;
10723    }
10724
10725    xmlXPathCompUnionExpr(ctxt);
10726    CHECK_ERROR;
10727    if (found) {
10728	if (minus)
10729	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10730	else
10731	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10732    }
10733}
10734
10735/**
10736 * xmlXPathCompMultiplicativeExpr:
10737 * @ctxt:  the XPath Parser context
10738 *
10739 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10740 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10741 *                   | MultiplicativeExpr 'div' UnaryExpr
10742 *                   | MultiplicativeExpr 'mod' UnaryExpr
10743 *  [34]   MultiplyOperator ::=   '*'
10744 *
10745 * Compile an Additive expression.
10746 */
10747
10748static void
10749xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10750    xmlXPathCompUnaryExpr(ctxt);
10751    CHECK_ERROR;
10752    SKIP_BLANKS;
10753    while ((CUR == '*') ||
10754           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10755           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10756	int op = -1;
10757	int op1 = ctxt->comp->last;
10758
10759        if (CUR == '*') {
10760	    op = 0;
10761	    NEXT;
10762	} else if (CUR == 'd') {
10763	    op = 1;
10764	    SKIP(3);
10765	} else if (CUR == 'm') {
10766	    op = 2;
10767	    SKIP(3);
10768	}
10769	SKIP_BLANKS;
10770        xmlXPathCompUnaryExpr(ctxt);
10771	CHECK_ERROR;
10772	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10773	SKIP_BLANKS;
10774    }
10775}
10776
10777/**
10778 * xmlXPathCompAdditiveExpr:
10779 * @ctxt:  the XPath Parser context
10780 *
10781 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10782 *                   | AdditiveExpr '+' MultiplicativeExpr
10783 *                   | AdditiveExpr '-' MultiplicativeExpr
10784 *
10785 * Compile an Additive expression.
10786 */
10787
10788static void
10789xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10790
10791    xmlXPathCompMultiplicativeExpr(ctxt);
10792    CHECK_ERROR;
10793    SKIP_BLANKS;
10794    while ((CUR == '+') || (CUR == '-')) {
10795	int plus;
10796	int op1 = ctxt->comp->last;
10797
10798        if (CUR == '+') plus = 1;
10799	else plus = 0;
10800	NEXT;
10801	SKIP_BLANKS;
10802        xmlXPathCompMultiplicativeExpr(ctxt);
10803	CHECK_ERROR;
10804	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10805	SKIP_BLANKS;
10806    }
10807}
10808
10809/**
10810 * xmlXPathCompRelationalExpr:
10811 * @ctxt:  the XPath Parser context
10812 *
10813 *  [24]   RelationalExpr ::=   AdditiveExpr
10814 *                 | RelationalExpr '<' AdditiveExpr
10815 *                 | RelationalExpr '>' AdditiveExpr
10816 *                 | RelationalExpr '<=' AdditiveExpr
10817 *                 | RelationalExpr '>=' AdditiveExpr
10818 *
10819 *  A <= B > C is allowed ? Answer from James, yes with
10820 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10821 *  which is basically what got implemented.
10822 *
10823 * Compile a Relational expression, then push the result
10824 * on the stack
10825 */
10826
10827static void
10828xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10829    xmlXPathCompAdditiveExpr(ctxt);
10830    CHECK_ERROR;
10831    SKIP_BLANKS;
10832    while ((CUR == '<') ||
10833           (CUR == '>') ||
10834           ((CUR == '<') && (NXT(1) == '=')) ||
10835           ((CUR == '>') && (NXT(1) == '='))) {
10836	int inf, strict;
10837	int op1 = ctxt->comp->last;
10838
10839        if (CUR == '<') inf = 1;
10840	else inf = 0;
10841	if (NXT(1) == '=') strict = 0;
10842	else strict = 1;
10843	NEXT;
10844	if (!strict) NEXT;
10845	SKIP_BLANKS;
10846        xmlXPathCompAdditiveExpr(ctxt);
10847	CHECK_ERROR;
10848	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10849	SKIP_BLANKS;
10850    }
10851}
10852
10853/**
10854 * xmlXPathCompEqualityExpr:
10855 * @ctxt:  the XPath Parser context
10856 *
10857 *  [23]   EqualityExpr ::=   RelationalExpr
10858 *                 | EqualityExpr '=' RelationalExpr
10859 *                 | EqualityExpr '!=' RelationalExpr
10860 *
10861 *  A != B != C is allowed ? Answer from James, yes with
10862 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10863 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10864 *  which is basically what got implemented.
10865 *
10866 * Compile an Equality expression.
10867 *
10868 */
10869static void
10870xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10871    xmlXPathCompRelationalExpr(ctxt);
10872    CHECK_ERROR;
10873    SKIP_BLANKS;
10874    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10875	int eq;
10876	int op1 = ctxt->comp->last;
10877
10878        if (CUR == '=') eq = 1;
10879	else eq = 0;
10880	NEXT;
10881	if (!eq) NEXT;
10882	SKIP_BLANKS;
10883        xmlXPathCompRelationalExpr(ctxt);
10884	CHECK_ERROR;
10885	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10886	SKIP_BLANKS;
10887    }
10888}
10889
10890/**
10891 * xmlXPathCompAndExpr:
10892 * @ctxt:  the XPath Parser context
10893 *
10894 *  [22]   AndExpr ::=   EqualityExpr
10895 *                 | AndExpr 'and' EqualityExpr
10896 *
10897 * Compile an AND expression.
10898 *
10899 */
10900static void
10901xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10902    xmlXPathCompEqualityExpr(ctxt);
10903    CHECK_ERROR;
10904    SKIP_BLANKS;
10905    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10906	int op1 = ctxt->comp->last;
10907        SKIP(3);
10908	SKIP_BLANKS;
10909        xmlXPathCompEqualityExpr(ctxt);
10910	CHECK_ERROR;
10911	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10912	SKIP_BLANKS;
10913    }
10914}
10915
10916/**
10917 * xmlXPathCompileExpr:
10918 * @ctxt:  the XPath Parser context
10919 *
10920 *  [14]   Expr ::=   OrExpr
10921 *  [21]   OrExpr ::=   AndExpr
10922 *                 | OrExpr 'or' AndExpr
10923 *
10924 * Parse and compile an expression
10925 */
10926static void
10927xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10928    xmlXPathCompAndExpr(ctxt);
10929    CHECK_ERROR;
10930    SKIP_BLANKS;
10931    while ((CUR == 'o') && (NXT(1) == 'r')) {
10932	int op1 = ctxt->comp->last;
10933        SKIP(2);
10934	SKIP_BLANKS;
10935        xmlXPathCompAndExpr(ctxt);
10936	CHECK_ERROR;
10937	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10938	SKIP_BLANKS;
10939    }
10940    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10941	/* more ops could be optimized too */
10942	/*
10943	* This is the main place to eliminate sorting for
10944	* operations which don't require a sorted node-set.
10945	* E.g. count().
10946	*/
10947	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10948    }
10949}
10950
10951/**
10952 * xmlXPathCompPredicate:
10953 * @ctxt:  the XPath Parser context
10954 * @filter:  act as a filter
10955 *
10956 *  [8]   Predicate ::=   '[' PredicateExpr ']'
10957 *  [9]   PredicateExpr ::=   Expr
10958 *
10959 * Compile a predicate expression
10960 */
10961static void
10962xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10963    int op1 = ctxt->comp->last;
10964
10965    SKIP_BLANKS;
10966    if (CUR != '[') {
10967	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10968    }
10969    NEXT;
10970    SKIP_BLANKS;
10971
10972    ctxt->comp->last = -1;
10973    /*
10974    * This call to xmlXPathCompileExpr() will deactivate sorting
10975    * of the predicate result.
10976    * TODO: Sorting is still activated for filters, since I'm not
10977    *  sure if needed. Normally sorting should not be needed, since
10978    *  a filter can only diminish the number of items in a sequence,
10979    *  but won't change its order; so if the initial sequence is sorted,
10980    *  subsequent sorting is not needed.
10981    */
10982    if (! filter)
10983	xmlXPathCompileExpr(ctxt, 0);
10984    else
10985	xmlXPathCompileExpr(ctxt, 1);
10986    CHECK_ERROR;
10987
10988    if (CUR != ']') {
10989	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10990    }
10991
10992    if (filter)
10993	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10994    else
10995	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10996
10997    NEXT;
10998    SKIP_BLANKS;
10999}
11000
11001/**
11002 * xmlXPathCompNodeTest:
11003 * @ctxt:  the XPath Parser context
11004 * @test:  pointer to a xmlXPathTestVal
11005 * @type:  pointer to a xmlXPathTypeVal
11006 * @prefix:  placeholder for a possible name prefix
11007 *
11008 * [7] NodeTest ::=   NameTest
11009 *		    | NodeType '(' ')'
11010 *		    | 'processing-instruction' '(' Literal ')'
11011 *
11012 * [37] NameTest ::=  '*'
11013 *		    | NCName ':' '*'
11014 *		    | QName
11015 * [38] NodeType ::= 'comment'
11016 *		   | 'text'
11017 *		   | 'processing-instruction'
11018 *		   | 'node'
11019 *
11020 * Returns the name found and updates @test, @type and @prefix appropriately
11021 */
11022static xmlChar *
11023xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11024	             xmlXPathTypeVal *type, const xmlChar **prefix,
11025		     xmlChar *name) {
11026    int blanks;
11027
11028    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11029	STRANGE;
11030	return(NULL);
11031    }
11032    *type = (xmlXPathTypeVal) 0;
11033    *test = (xmlXPathTestVal) 0;
11034    *prefix = NULL;
11035    SKIP_BLANKS;
11036
11037    if ((name == NULL) && (CUR == '*')) {
11038	/*
11039	 * All elements
11040	 */
11041	NEXT;
11042	*test = NODE_TEST_ALL;
11043	return(NULL);
11044    }
11045
11046    if (name == NULL)
11047	name = xmlXPathParseNCName(ctxt);
11048    if (name == NULL) {
11049	XP_ERRORNULL(XPATH_EXPR_ERROR);
11050    }
11051
11052    blanks = IS_BLANK_CH(CUR);
11053    SKIP_BLANKS;
11054    if (CUR == '(') {
11055	NEXT;
11056	/*
11057	 * NodeType or PI search
11058	 */
11059	if (xmlStrEqual(name, BAD_CAST "comment"))
11060	    *type = NODE_TYPE_COMMENT;
11061	else if (xmlStrEqual(name, BAD_CAST "node"))
11062	    *type = NODE_TYPE_NODE;
11063	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11064	    *type = NODE_TYPE_PI;
11065	else if (xmlStrEqual(name, BAD_CAST "text"))
11066	    *type = NODE_TYPE_TEXT;
11067	else {
11068	    if (name != NULL)
11069		xmlFree(name);
11070	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11071	}
11072
11073	*test = NODE_TEST_TYPE;
11074
11075	SKIP_BLANKS;
11076	if (*type == NODE_TYPE_PI) {
11077	    /*
11078	     * Specific case: search a PI by name.
11079	     */
11080	    if (name != NULL)
11081		xmlFree(name);
11082	    name = NULL;
11083	    if (CUR != ')') {
11084		name = xmlXPathParseLiteral(ctxt);
11085		CHECK_ERROR NULL;
11086		*test = NODE_TEST_PI;
11087		SKIP_BLANKS;
11088	    }
11089	}
11090	if (CUR != ')') {
11091	    if (name != NULL)
11092		xmlFree(name);
11093	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11094	}
11095	NEXT;
11096	return(name);
11097    }
11098    *test = NODE_TEST_NAME;
11099    if ((!blanks) && (CUR == ':')) {
11100	NEXT;
11101
11102	/*
11103	 * Since currently the parser context don't have a
11104	 * namespace list associated:
11105	 * The namespace name for this prefix can be computed
11106	 * only at evaluation time. The compilation is done
11107	 * outside of any context.
11108	 */
11109#if 0
11110	*prefix = xmlXPathNsLookup(ctxt->context, name);
11111	if (name != NULL)
11112	    xmlFree(name);
11113	if (*prefix == NULL) {
11114	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11115	}
11116#else
11117	*prefix = name;
11118#endif
11119
11120	if (CUR == '*') {
11121	    /*
11122	     * All elements
11123	     */
11124	    NEXT;
11125	    *test = NODE_TEST_ALL;
11126	    return(NULL);
11127	}
11128
11129	name = xmlXPathParseNCName(ctxt);
11130	if (name == NULL) {
11131	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11132	}
11133    }
11134    return(name);
11135}
11136
11137/**
11138 * xmlXPathIsAxisName:
11139 * @name:  a preparsed name token
11140 *
11141 * [6] AxisName ::=   'ancestor'
11142 *                  | 'ancestor-or-self'
11143 *                  | 'attribute'
11144 *                  | 'child'
11145 *                  | 'descendant'
11146 *                  | 'descendant-or-self'
11147 *                  | 'following'
11148 *                  | 'following-sibling'
11149 *                  | 'namespace'
11150 *                  | 'parent'
11151 *                  | 'preceding'
11152 *                  | 'preceding-sibling'
11153 *                  | 'self'
11154 *
11155 * Returns the axis or 0
11156 */
11157static xmlXPathAxisVal
11158xmlXPathIsAxisName(const xmlChar *name) {
11159    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11160    switch (name[0]) {
11161	case 'a':
11162	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11163		ret = AXIS_ANCESTOR;
11164	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11165		ret = AXIS_ANCESTOR_OR_SELF;
11166	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11167		ret = AXIS_ATTRIBUTE;
11168	    break;
11169	case 'c':
11170	    if (xmlStrEqual(name, BAD_CAST "child"))
11171		ret = AXIS_CHILD;
11172	    break;
11173	case 'd':
11174	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11175		ret = AXIS_DESCENDANT;
11176	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11177		ret = AXIS_DESCENDANT_OR_SELF;
11178	    break;
11179	case 'f':
11180	    if (xmlStrEqual(name, BAD_CAST "following"))
11181		ret = AXIS_FOLLOWING;
11182	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11183		ret = AXIS_FOLLOWING_SIBLING;
11184	    break;
11185	case 'n':
11186	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11187		ret = AXIS_NAMESPACE;
11188	    break;
11189	case 'p':
11190	    if (xmlStrEqual(name, BAD_CAST "parent"))
11191		ret = AXIS_PARENT;
11192	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11193		ret = AXIS_PRECEDING;
11194	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11195		ret = AXIS_PRECEDING_SIBLING;
11196	    break;
11197	case 's':
11198	    if (xmlStrEqual(name, BAD_CAST "self"))
11199		ret = AXIS_SELF;
11200	    break;
11201    }
11202    return(ret);
11203}
11204
11205/**
11206 * xmlXPathCompStep:
11207 * @ctxt:  the XPath Parser context
11208 *
11209 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11210 *                  | AbbreviatedStep
11211 *
11212 * [12] AbbreviatedStep ::=   '.' | '..'
11213 *
11214 * [5] AxisSpecifier ::= AxisName '::'
11215 *                  | AbbreviatedAxisSpecifier
11216 *
11217 * [13] AbbreviatedAxisSpecifier ::= '@'?
11218 *
11219 * Modified for XPtr range support as:
11220 *
11221 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11222 *                     | AbbreviatedStep
11223 *                     | 'range-to' '(' Expr ')' Predicate*
11224 *
11225 * Compile one step in a Location Path
11226 * A location step of . is short for self::node(). This is
11227 * particularly useful in conjunction with //. For example, the
11228 * location path .//para is short for
11229 * self::node()/descendant-or-self::node()/child::para
11230 * and so will select all para descendant elements of the context
11231 * node.
11232 * Similarly, a location step of .. is short for parent::node().
11233 * For example, ../title is short for parent::node()/child::title
11234 * and so will select the title children of the parent of the context
11235 * node.
11236 */
11237static void
11238xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11239#ifdef LIBXML_XPTR_ENABLED
11240    int rangeto = 0;
11241    int op2 = -1;
11242#endif
11243
11244    SKIP_BLANKS;
11245    if ((CUR == '.') && (NXT(1) == '.')) {
11246	SKIP(2);
11247	SKIP_BLANKS;
11248	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11249		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11250    } else if (CUR == '.') {
11251	NEXT;
11252	SKIP_BLANKS;
11253    } else {
11254	xmlChar *name = NULL;
11255	const xmlChar *prefix = NULL;
11256	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11257	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11258	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11259	int op1;
11260
11261	/*
11262	 * The modification needed for XPointer change to the production
11263	 */
11264#ifdef LIBXML_XPTR_ENABLED
11265	if (ctxt->xptr) {
11266	    name = xmlXPathParseNCName(ctxt);
11267	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11268                op2 = ctxt->comp->last;
11269		xmlFree(name);
11270		SKIP_BLANKS;
11271		if (CUR != '(') {
11272		    XP_ERROR(XPATH_EXPR_ERROR);
11273		}
11274		NEXT;
11275		SKIP_BLANKS;
11276
11277		xmlXPathCompileExpr(ctxt, 1);
11278		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11279		CHECK_ERROR;
11280
11281		SKIP_BLANKS;
11282		if (CUR != ')') {
11283		    XP_ERROR(XPATH_EXPR_ERROR);
11284		}
11285		NEXT;
11286		rangeto = 1;
11287		goto eval_predicates;
11288	    }
11289	}
11290#endif
11291	if (CUR == '*') {
11292	    axis = AXIS_CHILD;
11293	} else {
11294	    if (name == NULL)
11295		name = xmlXPathParseNCName(ctxt);
11296	    if (name != NULL) {
11297		axis = xmlXPathIsAxisName(name);
11298		if (axis != 0) {
11299		    SKIP_BLANKS;
11300		    if ((CUR == ':') && (NXT(1) == ':')) {
11301			SKIP(2);
11302			xmlFree(name);
11303			name = NULL;
11304		    } else {
11305			/* an element name can conflict with an axis one :-\ */
11306			axis = AXIS_CHILD;
11307		    }
11308		} else {
11309		    axis = AXIS_CHILD;
11310		}
11311	    } else if (CUR == '@') {
11312		NEXT;
11313		axis = AXIS_ATTRIBUTE;
11314	    } else {
11315		axis = AXIS_CHILD;
11316	    }
11317	}
11318
11319        if (ctxt->error != XPATH_EXPRESSION_OK) {
11320            xmlFree(name);
11321            return;
11322        }
11323
11324	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11325	if (test == 0)
11326	    return;
11327
11328        if ((prefix != NULL) && (ctxt->context != NULL) &&
11329	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11330	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11331		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11332	    }
11333	}
11334#ifdef DEBUG_STEP
11335	xmlGenericError(xmlGenericErrorContext,
11336		"Basis : computing new set\n");
11337#endif
11338
11339#ifdef DEBUG_STEP
11340	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11341	if (ctxt->value == NULL)
11342	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11343	else if (ctxt->value->nodesetval == NULL)
11344	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11345	else
11346	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11347#endif
11348
11349#ifdef LIBXML_XPTR_ENABLED
11350eval_predicates:
11351#endif
11352	op1 = ctxt->comp->last;
11353	ctxt->comp->last = -1;
11354
11355	SKIP_BLANKS;
11356	while (CUR == '[') {
11357	    xmlXPathCompPredicate(ctxt, 0);
11358	}
11359
11360#ifdef LIBXML_XPTR_ENABLED
11361	if (rangeto) {
11362	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11363	} else
11364#endif
11365	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11366			   test, type, (void *)prefix, (void *)name);
11367
11368    }
11369#ifdef DEBUG_STEP
11370    xmlGenericError(xmlGenericErrorContext, "Step : ");
11371    if (ctxt->value == NULL)
11372	xmlGenericError(xmlGenericErrorContext, "no value\n");
11373    else if (ctxt->value->nodesetval == NULL)
11374	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11375    else
11376	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11377		ctxt->value->nodesetval);
11378#endif
11379}
11380
11381/**
11382 * xmlXPathCompRelativeLocationPath:
11383 * @ctxt:  the XPath Parser context
11384 *
11385 *  [3]   RelativeLocationPath ::=   Step
11386 *                     | RelativeLocationPath '/' Step
11387 *                     | AbbreviatedRelativeLocationPath
11388 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11389 *
11390 * Compile a relative location path.
11391 */
11392static void
11393xmlXPathCompRelativeLocationPath
11394(xmlXPathParserContextPtr ctxt) {
11395    SKIP_BLANKS;
11396    if ((CUR == '/') && (NXT(1) == '/')) {
11397	SKIP(2);
11398	SKIP_BLANKS;
11399	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11400		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11401    } else if (CUR == '/') {
11402	    NEXT;
11403	SKIP_BLANKS;
11404    }
11405    xmlXPathCompStep(ctxt);
11406    CHECK_ERROR;
11407    SKIP_BLANKS;
11408    while (CUR == '/') {
11409	if ((CUR == '/') && (NXT(1) == '/')) {
11410	    SKIP(2);
11411	    SKIP_BLANKS;
11412	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11413			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11414	    xmlXPathCompStep(ctxt);
11415	} else if (CUR == '/') {
11416	    NEXT;
11417	    SKIP_BLANKS;
11418	    xmlXPathCompStep(ctxt);
11419	}
11420	SKIP_BLANKS;
11421    }
11422}
11423
11424/**
11425 * xmlXPathCompLocationPath:
11426 * @ctxt:  the XPath Parser context
11427 *
11428 *  [1]   LocationPath ::=   RelativeLocationPath
11429 *                     | AbsoluteLocationPath
11430 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11431 *                     | AbbreviatedAbsoluteLocationPath
11432 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11433 *                           '//' RelativeLocationPath
11434 *
11435 * Compile a location path
11436 *
11437 * // is short for /descendant-or-self::node()/. For example,
11438 * //para is short for /descendant-or-self::node()/child::para and
11439 * so will select any para element in the document (even a para element
11440 * that is a document element will be selected by //para since the
11441 * document element node is a child of the root node); div//para is
11442 * short for div/descendant-or-self::node()/child::para and so will
11443 * select all para descendants of div children.
11444 */
11445static void
11446xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11447    SKIP_BLANKS;
11448    if (CUR != '/') {
11449        xmlXPathCompRelativeLocationPath(ctxt);
11450    } else {
11451	while (CUR == '/') {
11452	    if ((CUR == '/') && (NXT(1) == '/')) {
11453		SKIP(2);
11454		SKIP_BLANKS;
11455		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11456			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11457		xmlXPathCompRelativeLocationPath(ctxt);
11458	    } else if (CUR == '/') {
11459		NEXT;
11460		SKIP_BLANKS;
11461		if ((CUR != 0 ) &&
11462		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11463		     (CUR == '@') || (CUR == '*')))
11464		    xmlXPathCompRelativeLocationPath(ctxt);
11465	    }
11466	    CHECK_ERROR;
11467	}
11468    }
11469}
11470
11471/************************************************************************
11472 *									*
11473 *		XPath precompiled expression evaluation			*
11474 *									*
11475 ************************************************************************/
11476
11477static int
11478xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11479
11480#ifdef DEBUG_STEP
11481static void
11482xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11483			  int nbNodes)
11484{
11485    xmlGenericError(xmlGenericErrorContext, "new step : ");
11486    switch (op->value) {
11487        case AXIS_ANCESTOR:
11488            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11489            break;
11490        case AXIS_ANCESTOR_OR_SELF:
11491            xmlGenericError(xmlGenericErrorContext,
11492                            "axis 'ancestors-or-self' ");
11493            break;
11494        case AXIS_ATTRIBUTE:
11495            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11496            break;
11497        case AXIS_CHILD:
11498            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11499            break;
11500        case AXIS_DESCENDANT:
11501            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11502            break;
11503        case AXIS_DESCENDANT_OR_SELF:
11504            xmlGenericError(xmlGenericErrorContext,
11505                            "axis 'descendant-or-self' ");
11506            break;
11507        case AXIS_FOLLOWING:
11508            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11509            break;
11510        case AXIS_FOLLOWING_SIBLING:
11511            xmlGenericError(xmlGenericErrorContext,
11512                            "axis 'following-siblings' ");
11513            break;
11514        case AXIS_NAMESPACE:
11515            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11516            break;
11517        case AXIS_PARENT:
11518            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11519            break;
11520        case AXIS_PRECEDING:
11521            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11522            break;
11523        case AXIS_PRECEDING_SIBLING:
11524            xmlGenericError(xmlGenericErrorContext,
11525                            "axis 'preceding-sibling' ");
11526            break;
11527        case AXIS_SELF:
11528            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11529            break;
11530    }
11531    xmlGenericError(xmlGenericErrorContext,
11532	" context contains %d nodes\n", nbNodes);
11533    switch (op->value2) {
11534        case NODE_TEST_NONE:
11535            xmlGenericError(xmlGenericErrorContext,
11536                            "           searching for none !!!\n");
11537            break;
11538        case NODE_TEST_TYPE:
11539            xmlGenericError(xmlGenericErrorContext,
11540                            "           searching for type %d\n", op->value3);
11541            break;
11542        case NODE_TEST_PI:
11543            xmlGenericError(xmlGenericErrorContext,
11544                            "           searching for PI !!!\n");
11545            break;
11546        case NODE_TEST_ALL:
11547            xmlGenericError(xmlGenericErrorContext,
11548                            "           searching for *\n");
11549            break;
11550        case NODE_TEST_NS:
11551            xmlGenericError(xmlGenericErrorContext,
11552                            "           searching for namespace %s\n",
11553                            op->value5);
11554            break;
11555        case NODE_TEST_NAME:
11556            xmlGenericError(xmlGenericErrorContext,
11557                            "           searching for name %s\n", op->value5);
11558            if (op->value4)
11559                xmlGenericError(xmlGenericErrorContext,
11560                                "           with namespace %s\n", op->value4);
11561            break;
11562    }
11563    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11564}
11565#endif /* DEBUG_STEP */
11566
11567static int
11568xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11569			    xmlXPathStepOpPtr op,
11570			    xmlNodeSetPtr set,
11571			    int contextSize,
11572			    int hasNsNodes)
11573{
11574    if (op->ch1 != -1) {
11575	xmlXPathCompExprPtr comp = ctxt->comp;
11576	/*
11577	* Process inner predicates first.
11578	*/
11579	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11580	    /*
11581	    * TODO: raise an internal error.
11582	    */
11583	}
11584	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11585	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11586	CHECK_ERROR0;
11587	if (contextSize <= 0)
11588	    return(0);
11589    }
11590    if (op->ch2 != -1) {
11591	xmlXPathContextPtr xpctxt = ctxt->context;
11592	xmlNodePtr contextNode, oldContextNode;
11593	xmlDocPtr oldContextDoc;
11594	int i, res, contextPos = 0, newContextSize;
11595	xmlXPathStepOpPtr exprOp;
11596	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11597
11598#ifdef LIBXML_XPTR_ENABLED
11599	/*
11600	* URGENT TODO: Check the following:
11601	*  We don't expect location sets if evaluating prediates, right?
11602	*  Only filters should expect location sets, right?
11603	*/
11604#endif
11605	/*
11606	* SPEC XPath 1.0:
11607	*  "For each node in the node-set to be filtered, the
11608	*  PredicateExpr is evaluated with that node as the
11609	*  context node, with the number of nodes in the
11610	*  node-set as the context size, and with the proximity
11611	*  position of the node in the node-set with respect to
11612	*  the axis as the context position;"
11613	* @oldset is the node-set" to be filtered.
11614	*
11615	* SPEC XPath 1.0:
11616	*  "only predicates change the context position and
11617	*  context size (see [2.4 Predicates])."
11618	* Example:
11619	*   node-set  context pos
11620	*    nA         1
11621	*    nB         2
11622	*    nC         3
11623	*   After applying predicate [position() > 1] :
11624	*   node-set  context pos
11625	*    nB         1
11626	*    nC         2
11627	*/
11628	oldContextNode = xpctxt->node;
11629	oldContextDoc = xpctxt->doc;
11630	/*
11631	* Get the expression of this predicate.
11632	*/
11633	exprOp = &ctxt->comp->steps[op->ch2];
11634	newContextSize = 0;
11635	for (i = 0; i < set->nodeNr; i++) {
11636	    if (set->nodeTab[i] == NULL)
11637		continue;
11638
11639	    contextNode = set->nodeTab[i];
11640	    xpctxt->node = contextNode;
11641	    xpctxt->contextSize = contextSize;
11642	    xpctxt->proximityPosition = ++contextPos;
11643
11644	    /*
11645	    * Also set the xpath document in case things like
11646	    * key() are evaluated in the predicate.
11647	    */
11648	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11649		(contextNode->doc != NULL))
11650		xpctxt->doc = contextNode->doc;
11651	    /*
11652	    * Evaluate the predicate expression with 1 context node
11653	    * at a time; this node is packaged into a node set; this
11654	    * node set is handed over to the evaluation mechanism.
11655	    */
11656	    if (contextObj == NULL)
11657		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11658	    else
11659		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11660		    contextNode);
11661
11662	    valuePush(ctxt, contextObj);
11663
11664	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11665
11666	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11667		xmlXPathNodeSetClear(set, hasNsNodes);
11668		newContextSize = 0;
11669		goto evaluation_exit;
11670	    }
11671
11672	    if (res != 0) {
11673		newContextSize++;
11674	    } else {
11675		/*
11676		* Remove the entry from the initial node set.
11677		*/
11678		set->nodeTab[i] = NULL;
11679		if (contextNode->type == XML_NAMESPACE_DECL)
11680		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11681	    }
11682	    if (ctxt->value == contextObj) {
11683		/*
11684		* Don't free the temporary XPath object holding the
11685		* context node, in order to avoid massive recreation
11686		* inside this loop.
11687		*/
11688		valuePop(ctxt);
11689		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11690	    } else {
11691		/*
11692		* TODO: The object was lost in the evaluation machinery.
11693		*  Can this happen? Maybe in internal-error cases.
11694		*/
11695		contextObj = NULL;
11696	    }
11697	}
11698
11699	if (contextObj != NULL) {
11700	    if (ctxt->value == contextObj)
11701		valuePop(ctxt);
11702	    xmlXPathReleaseObject(xpctxt, contextObj);
11703	}
11704evaluation_exit:
11705	if (exprRes != NULL)
11706	    xmlXPathReleaseObject(ctxt->context, exprRes);
11707	/*
11708	* Reset/invalidate the context.
11709	*/
11710	xpctxt->node = oldContextNode;
11711	xpctxt->doc = oldContextDoc;
11712	xpctxt->contextSize = -1;
11713	xpctxt->proximityPosition = -1;
11714	return(newContextSize);
11715    }
11716    return(contextSize);
11717}
11718
11719static int
11720xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11721				      xmlXPathStepOpPtr op,
11722				      xmlNodeSetPtr set,
11723				      int contextSize,
11724				      int minPos,
11725				      int maxPos,
11726				      int hasNsNodes)
11727{
11728    if (op->ch1 != -1) {
11729	xmlXPathCompExprPtr comp = ctxt->comp;
11730	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11731	    /*
11732	    * TODO: raise an internal error.
11733	    */
11734	}
11735	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11736	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11737	CHECK_ERROR0;
11738	if (contextSize <= 0)
11739	    return(0);
11740    }
11741    /*
11742    * Check if the node set contains a sufficient number of nodes for
11743    * the requested range.
11744    */
11745    if (contextSize < minPos) {
11746	xmlXPathNodeSetClear(set, hasNsNodes);
11747	return(0);
11748    }
11749    if (op->ch2 == -1) {
11750	/*
11751	* TODO: Can this ever happen?
11752	*/
11753	return (contextSize);
11754    } else {
11755	xmlDocPtr oldContextDoc;
11756	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11757	xmlXPathStepOpPtr exprOp;
11758	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11759	xmlNodePtr oldContextNode, contextNode = NULL;
11760	xmlXPathContextPtr xpctxt = ctxt->context;
11761        int frame;
11762
11763#ifdef LIBXML_XPTR_ENABLED
11764	    /*
11765	    * URGENT TODO: Check the following:
11766	    *  We don't expect location sets if evaluating prediates, right?
11767	    *  Only filters should expect location sets, right?
11768	*/
11769#endif /* LIBXML_XPTR_ENABLED */
11770
11771	/*
11772	* Save old context.
11773	*/
11774	oldContextNode = xpctxt->node;
11775	oldContextDoc = xpctxt->doc;
11776	/*
11777	* Get the expression of this predicate.
11778	*/
11779	exprOp = &ctxt->comp->steps[op->ch2];
11780	for (i = 0; i < set->nodeNr; i++) {
11781            xmlXPathObjectPtr tmp;
11782
11783	    if (set->nodeTab[i] == NULL)
11784		continue;
11785
11786	    contextNode = set->nodeTab[i];
11787	    xpctxt->node = contextNode;
11788	    xpctxt->contextSize = contextSize;
11789	    xpctxt->proximityPosition = ++contextPos;
11790
11791	    /*
11792	    * Initialize the new set.
11793	    * Also set the xpath document in case things like
11794	    * key() evaluation are attempted on the predicate
11795	    */
11796	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11797		(contextNode->doc != NULL))
11798		xpctxt->doc = contextNode->doc;
11799	    /*
11800	    * Evaluate the predicate expression with 1 context node
11801	    * at a time; this node is packaged into a node set; this
11802	    * node set is handed over to the evaluation mechanism.
11803	    */
11804	    if (contextObj == NULL)
11805		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11806	    else
11807		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11808		    contextNode);
11809
11810            frame = xmlXPathSetFrame(ctxt);
11811	    valuePush(ctxt, contextObj);
11812	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11813            tmp = valuePop(ctxt);
11814            xmlXPathPopFrame(ctxt, frame);
11815
11816	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11817                while (tmp != contextObj) {
11818                    /*
11819                     * Free up the result
11820                     * then pop off contextObj, which will be freed later
11821                     */
11822                    xmlXPathReleaseObject(xpctxt, tmp);
11823                    tmp = valuePop(ctxt);
11824                }
11825		goto evaluation_error;
11826	    }
11827            /* push the result back onto the stack */
11828            valuePush(ctxt, tmp);
11829
11830	    if (res)
11831		pos++;
11832
11833	    if (res && (pos >= minPos) && (pos <= maxPos)) {
11834		/*
11835		* Fits in the requested range.
11836		*/
11837		newContextSize++;
11838		if (minPos == maxPos) {
11839		    /*
11840		    * Only 1 node was requested.
11841		    */
11842		    if (contextNode->type == XML_NAMESPACE_DECL) {
11843			/*
11844			* As always: take care of those nasty
11845			* namespace nodes.
11846			*/
11847			set->nodeTab[i] = NULL;
11848		    }
11849		    xmlXPathNodeSetClear(set, hasNsNodes);
11850		    set->nodeNr = 1;
11851		    set->nodeTab[0] = contextNode;
11852		    goto evaluation_exit;
11853		}
11854		if (pos == maxPos) {
11855		    /*
11856		    * We are done.
11857		    */
11858		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11859		    goto evaluation_exit;
11860		}
11861	    } else {
11862		/*
11863		* Remove the entry from the initial node set.
11864		*/
11865		set->nodeTab[i] = NULL;
11866		if (contextNode->type == XML_NAMESPACE_DECL)
11867		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11868	    }
11869	    if (exprRes != NULL) {
11870		xmlXPathReleaseObject(ctxt->context, exprRes);
11871		exprRes = NULL;
11872	    }
11873	    if (ctxt->value == contextObj) {
11874		/*
11875		* Don't free the temporary XPath object holding the
11876		* context node, in order to avoid massive recreation
11877		* inside this loop.
11878		*/
11879		valuePop(ctxt);
11880		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11881	    } else {
11882		/*
11883		* The object was lost in the evaluation machinery.
11884		* Can this happen? Maybe in case of internal-errors.
11885		*/
11886		contextObj = NULL;
11887	    }
11888	}
11889	goto evaluation_exit;
11890
11891evaluation_error:
11892	xmlXPathNodeSetClear(set, hasNsNodes);
11893	newContextSize = 0;
11894
11895evaluation_exit:
11896	if (contextObj != NULL) {
11897	    if (ctxt->value == contextObj)
11898		valuePop(ctxt);
11899	    xmlXPathReleaseObject(xpctxt, contextObj);
11900	}
11901	if (exprRes != NULL)
11902	    xmlXPathReleaseObject(ctxt->context, exprRes);
11903	/*
11904	* Reset/invalidate the context.
11905	*/
11906	xpctxt->node = oldContextNode;
11907	xpctxt->doc = oldContextDoc;
11908	xpctxt->contextSize = -1;
11909	xpctxt->proximityPosition = -1;
11910	return(newContextSize);
11911    }
11912    return(contextSize);
11913}
11914
11915static int
11916xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11917			    xmlXPathStepOpPtr op,
11918			    int *maxPos)
11919{
11920
11921    xmlXPathStepOpPtr exprOp;
11922
11923    /*
11924    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11925    */
11926
11927    /*
11928    * If not -1, then ch1 will point to:
11929    * 1) For predicates (XPATH_OP_PREDICATE):
11930    *    - an inner predicate operator
11931    * 2) For filters (XPATH_OP_FILTER):
11932    *    - an inner filter operater OR
11933    *    - an expression selecting the node set.
11934    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11935    */
11936    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11937	return(0);
11938
11939    if (op->ch2 != -1) {
11940	exprOp = &ctxt->comp->steps[op->ch2];
11941    } else
11942	return(0);
11943
11944    if ((exprOp != NULL) &&
11945	(exprOp->op == XPATH_OP_VALUE) &&
11946	(exprOp->value4 != NULL) &&
11947	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11948    {
11949	/*
11950	* We have a "[n]" predicate here.
11951	* TODO: Unfortunately this simplistic test here is not
11952	* able to detect a position() predicate in compound
11953	* expressions like "[@attr = 'a" and position() = 1],
11954	* and even not the usage of position() in
11955	* "[position() = 1]"; thus - obviously - a position-range,
11956	* like it "[position() < 5]", is also not detected.
11957	* Maybe we could rewrite the AST to ease the optimization.
11958	*/
11959	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11960
11961	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11962	    (float) *maxPos)
11963	{
11964	    return(1);
11965	}
11966    }
11967    return(0);
11968}
11969
11970static int
11971xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11972                           xmlXPathStepOpPtr op,
11973			   xmlNodePtr * first, xmlNodePtr * last,
11974			   int toBool)
11975{
11976
11977#define XP_TEST_HIT \
11978    if (hasAxisRange != 0) { \
11979	if (++pos == maxPos) { \
11980	    addNode(seq, cur); \
11981	goto axis_range_end; } \
11982    } else { \
11983	addNode(seq, cur); \
11984	if (breakOnFirstHit) goto first_hit; }
11985
11986#define XP_TEST_HIT_NS \
11987    if (hasAxisRange != 0) { \
11988	if (++pos == maxPos) { \
11989	    hasNsNodes = 1; \
11990	    xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11991	goto axis_range_end; } \
11992    } else { \
11993	hasNsNodes = 1; \
11994	xmlXPathNodeSetAddNs(seq, \
11995	xpctxt->node, (xmlNsPtr) cur); \
11996	if (breakOnFirstHit) goto first_hit; }
11997
11998    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11999    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12000    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12001    const xmlChar *prefix = op->value4;
12002    const xmlChar *name = op->value5;
12003    const xmlChar *URI = NULL;
12004
12005#ifdef DEBUG_STEP
12006    int nbMatches = 0, prevMatches = 0;
12007#endif
12008    int total = 0, hasNsNodes = 0;
12009    /* The popped object holding the context nodes */
12010    xmlXPathObjectPtr obj;
12011    /* The set of context nodes for the node tests */
12012    xmlNodeSetPtr contextSeq;
12013    int contextIdx;
12014    xmlNodePtr contextNode;
12015    /* The context node for a compound traversal */
12016    xmlNodePtr outerContextNode;
12017    /* The final resulting node set wrt to all context nodes */
12018    xmlNodeSetPtr outSeq;
12019    /*
12020    * The temporary resulting node set wrt 1 context node.
12021    * Used to feed predicate evaluation.
12022    */
12023    xmlNodeSetPtr seq;
12024    xmlNodePtr cur;
12025    /* First predicate operator */
12026    xmlXPathStepOpPtr predOp;
12027    int maxPos; /* The requested position() (when a "[n]" predicate) */
12028    int hasPredicateRange, hasAxisRange, pos, size, newSize;
12029    int breakOnFirstHit;
12030
12031    xmlXPathTraversalFunction next = NULL;
12032    /* compound axis traversal */
12033    xmlXPathTraversalFunctionExt outerNext = NULL;
12034    void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12035    xmlXPathNodeSetMergeFunction mergeAndClear;
12036    xmlNodePtr oldContextNode;
12037    xmlXPathContextPtr xpctxt = ctxt->context;
12038
12039
12040    CHECK_TYPE0(XPATH_NODESET);
12041    obj = valuePop(ctxt);
12042    /*
12043    * Setup namespaces.
12044    */
12045    if (prefix != NULL) {
12046        URI = xmlXPathNsLookup(xpctxt, prefix);
12047        if (URI == NULL) {
12048	    xmlXPathReleaseObject(xpctxt, obj);
12049            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12050	}
12051    }
12052    /*
12053    * Setup axis.
12054    *
12055    * MAYBE FUTURE TODO: merging optimizations:
12056    * - If the nodes to be traversed wrt to the initial nodes and
12057    *   the current axis cannot overlap, then we could avoid searching
12058    *   for duplicates during the merge.
12059    *   But the question is how/when to evaluate if they cannot overlap.
12060    *   Example: if we know that for two initial nodes, the one is
12061    *   not in the ancestor-or-self axis of the other, then we could safely
12062    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12063    *   the descendant-or-self axis.
12064    */
12065    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12066    switch (axis) {
12067        case AXIS_ANCESTOR:
12068            first = NULL;
12069            next = xmlXPathNextAncestor;
12070            break;
12071        case AXIS_ANCESTOR_OR_SELF:
12072            first = NULL;
12073            next = xmlXPathNextAncestorOrSelf;
12074            break;
12075        case AXIS_ATTRIBUTE:
12076            first = NULL;
12077	    last = NULL;
12078            next = xmlXPathNextAttribute;
12079	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12080            break;
12081        case AXIS_CHILD:
12082	    last = NULL;
12083	    if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12084		/*
12085		* This iterator will give us only nodes which can
12086		* hold element nodes.
12087		*/
12088		outerNext = xmlXPathNextDescendantOrSelfElemParent;
12089	    }
12090	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12091		(type == NODE_TYPE_NODE))
12092	    {
12093		/*
12094		* Optimization if an element node type is 'element'.
12095		*/
12096		next = xmlXPathNextChildElement;
12097	    } else
12098		next = xmlXPathNextChild;
12099	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12100            break;
12101        case AXIS_DESCENDANT:
12102	    last = NULL;
12103            next = xmlXPathNextDescendant;
12104            break;
12105        case AXIS_DESCENDANT_OR_SELF:
12106	    last = NULL;
12107            next = xmlXPathNextDescendantOrSelf;
12108            break;
12109        case AXIS_FOLLOWING:
12110	    last = NULL;
12111            next = xmlXPathNextFollowing;
12112            break;
12113        case AXIS_FOLLOWING_SIBLING:
12114	    last = NULL;
12115            next = xmlXPathNextFollowingSibling;
12116            break;
12117        case AXIS_NAMESPACE:
12118            first = NULL;
12119	    last = NULL;
12120            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12121	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12122            break;
12123        case AXIS_PARENT:
12124            first = NULL;
12125            next = xmlXPathNextParent;
12126            break;
12127        case AXIS_PRECEDING:
12128            first = NULL;
12129            next = xmlXPathNextPrecedingInternal;
12130            break;
12131        case AXIS_PRECEDING_SIBLING:
12132            first = NULL;
12133            next = xmlXPathNextPrecedingSibling;
12134            break;
12135        case AXIS_SELF:
12136            first = NULL;
12137	    last = NULL;
12138            next = xmlXPathNextSelf;
12139	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12140            break;
12141    }
12142
12143#ifdef DEBUG_STEP
12144    xmlXPathDebugDumpStepAxis(op,
12145	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12146#endif
12147
12148    if (next == NULL) {
12149	xmlXPathReleaseObject(xpctxt, obj);
12150        return(0);
12151    }
12152    contextSeq = obj->nodesetval;
12153    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12154	xmlXPathReleaseObject(xpctxt, obj);
12155        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12156        return(0);
12157    }
12158    /*
12159    * Predicate optimization ---------------------------------------------
12160    * If this step has a last predicate, which contains a position(),
12161    * then we'll optimize (although not exactly "position()", but only
12162    * the  short-hand form, i.e., "[n]".
12163    *
12164    * Example - expression "/foo[parent::bar][1]":
12165    *
12166    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12167    *   ROOT                               -- op->ch1
12168    *   PREDICATE                          -- op->ch2 (predOp)
12169    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12170    *       SORT
12171    *         COLLECT  'parent' 'name' 'node' bar
12172    *           NODE
12173    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12174    *
12175    */
12176    maxPos = 0;
12177    predOp = NULL;
12178    hasPredicateRange = 0;
12179    hasAxisRange = 0;
12180    if (op->ch2 != -1) {
12181	/*
12182	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12183	*/
12184	predOp = &ctxt->comp->steps[op->ch2];
12185	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12186	    if (predOp->ch1 != -1) {
12187		/*
12188		* Use the next inner predicate operator.
12189		*/
12190		predOp = &ctxt->comp->steps[predOp->ch1];
12191		hasPredicateRange = 1;
12192	    } else {
12193		/*
12194		* There's no other predicate than the [n] predicate.
12195		*/
12196		predOp = NULL;
12197		hasAxisRange = 1;
12198	    }
12199	}
12200    }
12201    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12202    /*
12203    * Axis traversal -----------------------------------------------------
12204    */
12205    /*
12206     * 2.3 Node Tests
12207     *  - For the attribute axis, the principal node type is attribute.
12208     *  - For the namespace axis, the principal node type is namespace.
12209     *  - For other axes, the principal node type is element.
12210     *
12211     * A node test * is true for any node of the
12212     * principal node type. For example, child::* will
12213     * select all element children of the context node
12214     */
12215    oldContextNode = xpctxt->node;
12216    addNode = xmlXPathNodeSetAddUnique;
12217    outSeq = NULL;
12218    seq = NULL;
12219    outerContextNode = NULL;
12220    contextNode = NULL;
12221    contextIdx = 0;
12222
12223
12224    while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12225	if (outerNext != NULL) {
12226	    /*
12227	    * This is a compound traversal.
12228	    */
12229	    if (contextNode == NULL) {
12230		/*
12231		* Set the context for the outer traversal.
12232		*/
12233		outerContextNode = contextSeq->nodeTab[contextIdx++];
12234		contextNode = outerNext(NULL, outerContextNode);
12235	    } else
12236		contextNode = outerNext(contextNode, outerContextNode);
12237	    if (contextNode == NULL)
12238		continue;
12239	    /*
12240	    * Set the context for the main traversal.
12241	    */
12242	    xpctxt->node = contextNode;
12243	} else
12244	    xpctxt->node = contextSeq->nodeTab[contextIdx++];
12245
12246	if (seq == NULL) {
12247	    seq = xmlXPathNodeSetCreate(NULL);
12248	    if (seq == NULL) {
12249		total = 0;
12250		goto error;
12251	    }
12252	}
12253	/*
12254	* Traverse the axis and test the nodes.
12255	*/
12256	pos = 0;
12257	cur = NULL;
12258	hasNsNodes = 0;
12259        do {
12260            cur = next(ctxt, cur);
12261            if (cur == NULL)
12262                break;
12263
12264	    /*
12265	    * QUESTION TODO: What does the "first" and "last" stuff do?
12266	    */
12267            if ((first != NULL) && (*first != NULL)) {
12268		if (*first == cur)
12269		    break;
12270		if (((total % 256) == 0) &&
12271#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12272		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12273#else
12274		    (xmlXPathCmpNodes(*first, cur) >= 0))
12275#endif
12276		{
12277		    break;
12278		}
12279	    }
12280	    if ((last != NULL) && (*last != NULL)) {
12281		if (*last == cur)
12282		    break;
12283		if (((total % 256) == 0) &&
12284#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12285		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12286#else
12287		    (xmlXPathCmpNodes(cur, *last) >= 0))
12288#endif
12289		{
12290		    break;
12291		}
12292	    }
12293
12294            total++;
12295
12296#ifdef DEBUG_STEP
12297            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12298#endif
12299
12300	    switch (test) {
12301                case NODE_TEST_NONE:
12302		    total = 0;
12303                    STRANGE
12304		    goto error;
12305                case NODE_TEST_TYPE:
12306		    /*
12307		    * TODO: Don't we need to use
12308		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
12309		    *  Surprisingly, some c14n tests fail, if we do this.
12310		    */
12311		    if (type == NODE_TYPE_NODE) {
12312			switch (cur->type) {
12313			    case XML_DOCUMENT_NODE:
12314			    case XML_HTML_DOCUMENT_NODE:
12315#ifdef LIBXML_DOCB_ENABLED
12316			    case XML_DOCB_DOCUMENT_NODE:
12317#endif
12318			    case XML_ELEMENT_NODE:
12319			    case XML_ATTRIBUTE_NODE:
12320			    case XML_PI_NODE:
12321			    case XML_COMMENT_NODE:
12322			    case XML_CDATA_SECTION_NODE:
12323			    case XML_TEXT_NODE:
12324			    case XML_NAMESPACE_DECL:
12325				XP_TEST_HIT
12326				break;
12327			    default:
12328				break;
12329			}
12330		    } else if (cur->type == type) {
12331			if (type == XML_NAMESPACE_DECL)
12332			    XP_TEST_HIT_NS
12333			else
12334			    XP_TEST_HIT
12335		    } else if ((type == NODE_TYPE_TEXT) &&
12336			 (cur->type == XML_CDATA_SECTION_NODE))
12337		    {
12338			XP_TEST_HIT
12339		    }
12340		    break;
12341                case NODE_TEST_PI:
12342                    if ((cur->type == XML_PI_NODE) &&
12343                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12344		    {
12345			XP_TEST_HIT
12346                    }
12347                    break;
12348                case NODE_TEST_ALL:
12349                    if (axis == AXIS_ATTRIBUTE) {
12350                        if (cur->type == XML_ATTRIBUTE_NODE)
12351			{
12352			    XP_TEST_HIT
12353                        }
12354                    } else if (axis == AXIS_NAMESPACE) {
12355                        if (cur->type == XML_NAMESPACE_DECL)
12356			{
12357			    XP_TEST_HIT_NS
12358                        }
12359                    } else {
12360                        if (cur->type == XML_ELEMENT_NODE) {
12361                            if (prefix == NULL)
12362			    {
12363				XP_TEST_HIT
12364
12365                            } else if ((cur->ns != NULL) &&
12366				(xmlStrEqual(URI, cur->ns->href)))
12367			    {
12368				XP_TEST_HIT
12369                            }
12370                        }
12371                    }
12372                    break;
12373                case NODE_TEST_NS:{
12374                        TODO;
12375                        break;
12376                    }
12377                case NODE_TEST_NAME:
12378                    if (axis == AXIS_ATTRIBUTE) {
12379                        if (cur->type != XML_ATTRIBUTE_NODE)
12380			    break;
12381		    } else if (axis == AXIS_NAMESPACE) {
12382                        if (cur->type != XML_NAMESPACE_DECL)
12383			    break;
12384		    } else {
12385		        if (cur->type != XML_ELEMENT_NODE)
12386			    break;
12387		    }
12388                    switch (cur->type) {
12389                        case XML_ELEMENT_NODE:
12390                            if (xmlStrEqual(name, cur->name)) {
12391                                if (prefix == NULL) {
12392                                    if (cur->ns == NULL)
12393				    {
12394					XP_TEST_HIT
12395                                    }
12396                                } else {
12397                                    if ((cur->ns != NULL) &&
12398                                        (xmlStrEqual(URI, cur->ns->href)))
12399				    {
12400					XP_TEST_HIT
12401                                    }
12402                                }
12403                            }
12404                            break;
12405                        case XML_ATTRIBUTE_NODE:{
12406                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12407
12408                                if (xmlStrEqual(name, attr->name)) {
12409                                    if (prefix == NULL) {
12410                                        if ((attr->ns == NULL) ||
12411                                            (attr->ns->prefix == NULL))
12412					{
12413					    XP_TEST_HIT
12414                                        }
12415                                    } else {
12416                                        if ((attr->ns != NULL) &&
12417                                            (xmlStrEqual(URI,
12418					      attr->ns->href)))
12419					{
12420					    XP_TEST_HIT
12421                                        }
12422                                    }
12423                                }
12424                                break;
12425                            }
12426                        case XML_NAMESPACE_DECL:
12427                            if (cur->type == XML_NAMESPACE_DECL) {
12428                                xmlNsPtr ns = (xmlNsPtr) cur;
12429
12430                                if ((ns->prefix != NULL) && (name != NULL)
12431                                    && (xmlStrEqual(ns->prefix, name)))
12432				{
12433				    XP_TEST_HIT_NS
12434                                }
12435                            }
12436                            break;
12437                        default:
12438                            break;
12439                    }
12440                    break;
12441	    } /* switch(test) */
12442        } while (cur != NULL);
12443
12444	goto apply_predicates;
12445
12446axis_range_end: /* ----------------------------------------------------- */
12447	/*
12448	* We have a "/foo[n]", and position() = n was reached.
12449	* Note that we can have as well "/foo/::parent::foo[1]", so
12450	* a duplicate-aware merge is still needed.
12451	* Merge with the result.
12452	*/
12453	if (outSeq == NULL) {
12454	    outSeq = seq;
12455	    seq = NULL;
12456	} else
12457	    outSeq = mergeAndClear(outSeq, seq, 0);
12458	/*
12459	* Break if only a true/false result was requested.
12460	*/
12461	if (toBool)
12462	    break;
12463	continue;
12464
12465first_hit: /* ---------------------------------------------------------- */
12466	/*
12467	* Break if only a true/false result was requested and
12468	* no predicates existed and a node test succeeded.
12469	*/
12470	if (outSeq == NULL) {
12471	    outSeq = seq;
12472	    seq = NULL;
12473	} else
12474	    outSeq = mergeAndClear(outSeq, seq, 0);
12475	break;
12476
12477#ifdef DEBUG_STEP
12478	if (seq != NULL)
12479	    nbMatches += seq->nodeNr;
12480#endif
12481
12482apply_predicates: /* --------------------------------------------------- */
12483        /*
12484	* Apply predicates.
12485	*/
12486        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12487	    /*
12488	    * E.g. when we have a "/foo[some expression][n]".
12489	    */
12490	    /*
12491	    * QUESTION TODO: The old predicate evaluation took into
12492	    *  account location-sets.
12493	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12494	    *  Do we expect such a set here?
12495	    *  All what I learned now from the evaluation semantics
12496	    *  does not indicate that a location-set will be processed
12497	    *  here, so this looks OK.
12498	    */
12499	    /*
12500	    * Iterate over all predicates, starting with the outermost
12501	    * predicate.
12502	    * TODO: Problem: we cannot execute the inner predicates first
12503	    *  since we cannot go back *up* the operator tree!
12504	    *  Options we have:
12505	    *  1) Use of recursive functions (like is it currently done
12506	    *     via xmlXPathCompOpEval())
12507	    *  2) Add a predicate evaluation information stack to the
12508	    *     context struct
12509	    *  3) Change the way the operators are linked; we need a
12510	    *     "parent" field on xmlXPathStepOp
12511	    *
12512	    * For the moment, I'll try to solve this with a recursive
12513	    * function: xmlXPathCompOpEvalPredicate().
12514	    */
12515	    size = seq->nodeNr;
12516	    if (hasPredicateRange != 0)
12517		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12518		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12519	    else
12520		newSize = xmlXPathCompOpEvalPredicate(ctxt,
12521		    predOp, seq, size, hasNsNodes);
12522
12523	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12524		total = 0;
12525		goto error;
12526	    }
12527	    /*
12528	    * Add the filtered set of nodes to the result node set.
12529	    */
12530	    if (newSize == 0) {
12531		/*
12532		* The predicates filtered all nodes out.
12533		*/
12534		xmlXPathNodeSetClear(seq, hasNsNodes);
12535	    } else if (seq->nodeNr > 0) {
12536		/*
12537		* Add to result set.
12538		*/
12539		if (outSeq == NULL) {
12540		    if (size != newSize) {
12541			/*
12542			* We need to merge and clear here, since
12543			* the sequence will contained NULLed entries.
12544			*/
12545			outSeq = mergeAndClear(NULL, seq, 1);
12546		    } else {
12547			outSeq = seq;
12548			seq = NULL;
12549		    }
12550		} else
12551		    outSeq = mergeAndClear(outSeq, seq,
12552			(size != newSize) ? 1: 0);
12553		/*
12554		* Break if only a true/false result was requested.
12555		*/
12556		if (toBool)
12557		    break;
12558	    }
12559        } else if (seq->nodeNr > 0) {
12560	    /*
12561	    * Add to result set.
12562	    */
12563	    if (outSeq == NULL) {
12564		outSeq = seq;
12565		seq = NULL;
12566	    } else {
12567		outSeq = mergeAndClear(outSeq, seq, 0);
12568	    }
12569	}
12570    }
12571
12572error:
12573    if ((obj->boolval) && (obj->user != NULL)) {
12574	/*
12575	* QUESTION TODO: What does this do and why?
12576	* TODO: Do we have to do this also for the "error"
12577	* cleanup further down?
12578	*/
12579	ctxt->value->boolval = 1;
12580	ctxt->value->user = obj->user;
12581	obj->user = NULL;
12582	obj->boolval = 0;
12583    }
12584    xmlXPathReleaseObject(xpctxt, obj);
12585
12586    /*
12587    * Ensure we return at least an emtpy set.
12588    */
12589    if (outSeq == NULL) {
12590	if ((seq != NULL) && (seq->nodeNr == 0))
12591	    outSeq = seq;
12592	else
12593	    outSeq = xmlXPathNodeSetCreate(NULL);
12594        /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12595    }
12596    if ((seq != NULL) && (seq != outSeq)) {
12597	 xmlXPathFreeNodeSet(seq);
12598    }
12599    /*
12600    * Hand over the result. Better to push the set also in
12601    * case of errors.
12602    */
12603    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12604    /*
12605    * Reset the context node.
12606    */
12607    xpctxt->node = oldContextNode;
12608
12609#ifdef DEBUG_STEP
12610    xmlGenericError(xmlGenericErrorContext,
12611	"\nExamined %d nodes, found %d nodes at that step\n",
12612	total, nbMatches);
12613#endif
12614
12615    return(total);
12616}
12617
12618static int
12619xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12620			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12621
12622/**
12623 * xmlXPathCompOpEvalFirst:
12624 * @ctxt:  the XPath parser context with the compiled expression
12625 * @op:  an XPath compiled operation
12626 * @first:  the first elem found so far
12627 *
12628 * Evaluate the Precompiled XPath operation searching only the first
12629 * element in document order
12630 *
12631 * Returns the number of examined objects.
12632 */
12633static int
12634xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12635                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12636{
12637    int total = 0, cur;
12638    xmlXPathCompExprPtr comp;
12639    xmlXPathObjectPtr arg1, arg2;
12640
12641    CHECK_ERROR0;
12642    comp = ctxt->comp;
12643    switch (op->op) {
12644        case XPATH_OP_END:
12645            return (0);
12646        case XPATH_OP_UNION:
12647            total =
12648                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12649                                        first);
12650	    CHECK_ERROR0;
12651            if ((ctxt->value != NULL)
12652                && (ctxt->value->type == XPATH_NODESET)
12653                && (ctxt->value->nodesetval != NULL)
12654                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12655                /*
12656                 * limit tree traversing to first node in the result
12657                 */
12658		/*
12659		* OPTIMIZE TODO: This implicitely sorts
12660		*  the result, even if not needed. E.g. if the argument
12661		*  of the count() function, no sorting is needed.
12662		* OPTIMIZE TODO: How do we know if the node-list wasn't
12663		*  aready sorted?
12664		*/
12665		if (ctxt->value->nodesetval->nodeNr > 1)
12666		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12667                *first = ctxt->value->nodesetval->nodeTab[0];
12668            }
12669            cur =
12670                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12671                                        first);
12672	    CHECK_ERROR0;
12673            CHECK_TYPE0(XPATH_NODESET);
12674            arg2 = valuePop(ctxt);
12675
12676            CHECK_TYPE0(XPATH_NODESET);
12677            arg1 = valuePop(ctxt);
12678
12679            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12680                                                    arg2->nodesetval);
12681            valuePush(ctxt, arg1);
12682	    xmlXPathReleaseObject(ctxt->context, arg2);
12683            /* optimizer */
12684	    if (total > cur)
12685		xmlXPathCompSwap(op);
12686            return (total + cur);
12687        case XPATH_OP_ROOT:
12688            xmlXPathRoot(ctxt);
12689            return (0);
12690        case XPATH_OP_NODE:
12691            if (op->ch1 != -1)
12692                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12693	    CHECK_ERROR0;
12694            if (op->ch2 != -1)
12695                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12696	    CHECK_ERROR0;
12697	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12698		ctxt->context->node));
12699            return (total);
12700        case XPATH_OP_RESET:
12701            if (op->ch1 != -1)
12702                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12703	    CHECK_ERROR0;
12704            if (op->ch2 != -1)
12705                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12706	    CHECK_ERROR0;
12707            ctxt->context->node = NULL;
12708            return (total);
12709        case XPATH_OP_COLLECT:{
12710                if (op->ch1 == -1)
12711                    return (total);
12712
12713                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12714		CHECK_ERROR0;
12715
12716                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12717                return (total);
12718            }
12719        case XPATH_OP_VALUE:
12720            valuePush(ctxt,
12721                      xmlXPathCacheObjectCopy(ctxt->context,
12722			(xmlXPathObjectPtr) op->value4));
12723            return (0);
12724        case XPATH_OP_SORT:
12725            if (op->ch1 != -1)
12726                total +=
12727                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12728                                            first);
12729	    CHECK_ERROR0;
12730            if ((ctxt->value != NULL)
12731                && (ctxt->value->type == XPATH_NODESET)
12732                && (ctxt->value->nodesetval != NULL)
12733		&& (ctxt->value->nodesetval->nodeNr > 1))
12734                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12735            return (total);
12736#ifdef XP_OPTIMIZED_FILTER_FIRST
12737	case XPATH_OP_FILTER:
12738                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12739            return (total);
12740#endif
12741        default:
12742            return (xmlXPathCompOpEval(ctxt, op));
12743    }
12744}
12745
12746/**
12747 * xmlXPathCompOpEvalLast:
12748 * @ctxt:  the XPath parser context with the compiled expression
12749 * @op:  an XPath compiled operation
12750 * @last:  the last elem found so far
12751 *
12752 * Evaluate the Precompiled XPath operation searching only the last
12753 * element in document order
12754 *
12755 * Returns the number of nodes traversed
12756 */
12757static int
12758xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12759                       xmlNodePtr * last)
12760{
12761    int total = 0, cur;
12762    xmlXPathCompExprPtr comp;
12763    xmlXPathObjectPtr arg1, arg2;
12764    xmlNodePtr bak;
12765    xmlDocPtr bakd;
12766    int pp;
12767    int cs;
12768
12769    CHECK_ERROR0;
12770    comp = ctxt->comp;
12771    switch (op->op) {
12772        case XPATH_OP_END:
12773            return (0);
12774        case XPATH_OP_UNION:
12775	    bakd = ctxt->context->doc;
12776	    bak = ctxt->context->node;
12777	    pp = ctxt->context->proximityPosition;
12778	    cs = ctxt->context->contextSize;
12779            total =
12780                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12781	    CHECK_ERROR0;
12782            if ((ctxt->value != NULL)
12783                && (ctxt->value->type == XPATH_NODESET)
12784                && (ctxt->value->nodesetval != NULL)
12785                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12786                /*
12787                 * limit tree traversing to first node in the result
12788                 */
12789		if (ctxt->value->nodesetval->nodeNr > 1)
12790		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12791                *last =
12792                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12793                                                     nodesetval->nodeNr -
12794                                                     1];
12795            }
12796	    ctxt->context->doc = bakd;
12797	    ctxt->context->node = bak;
12798	    ctxt->context->proximityPosition = pp;
12799	    ctxt->context->contextSize = cs;
12800            cur =
12801                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12802	    CHECK_ERROR0;
12803            if ((ctxt->value != NULL)
12804                && (ctxt->value->type == XPATH_NODESET)
12805                && (ctxt->value->nodesetval != NULL)
12806                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12807            }
12808            CHECK_TYPE0(XPATH_NODESET);
12809            arg2 = valuePop(ctxt);
12810
12811            CHECK_TYPE0(XPATH_NODESET);
12812            arg1 = valuePop(ctxt);
12813
12814            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12815                                                    arg2->nodesetval);
12816            valuePush(ctxt, arg1);
12817	    xmlXPathReleaseObject(ctxt->context, arg2);
12818            /* optimizer */
12819	    if (total > cur)
12820		xmlXPathCompSwap(op);
12821            return (total + cur);
12822        case XPATH_OP_ROOT:
12823            xmlXPathRoot(ctxt);
12824            return (0);
12825        case XPATH_OP_NODE:
12826            if (op->ch1 != -1)
12827                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12828	    CHECK_ERROR0;
12829            if (op->ch2 != -1)
12830                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12831	    CHECK_ERROR0;
12832	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12833		ctxt->context->node));
12834            return (total);
12835        case XPATH_OP_RESET:
12836            if (op->ch1 != -1)
12837                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12838	    CHECK_ERROR0;
12839            if (op->ch2 != -1)
12840                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12841	    CHECK_ERROR0;
12842            ctxt->context->node = NULL;
12843            return (total);
12844        case XPATH_OP_COLLECT:{
12845                if (op->ch1 == -1)
12846                    return (0);
12847
12848                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12849		CHECK_ERROR0;
12850
12851                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12852                return (total);
12853            }
12854        case XPATH_OP_VALUE:
12855            valuePush(ctxt,
12856                      xmlXPathCacheObjectCopy(ctxt->context,
12857			(xmlXPathObjectPtr) op->value4));
12858            return (0);
12859        case XPATH_OP_SORT:
12860            if (op->ch1 != -1)
12861                total +=
12862                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12863                                           last);
12864	    CHECK_ERROR0;
12865            if ((ctxt->value != NULL)
12866                && (ctxt->value->type == XPATH_NODESET)
12867                && (ctxt->value->nodesetval != NULL)
12868		&& (ctxt->value->nodesetval->nodeNr > 1))
12869                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12870            return (total);
12871        default:
12872            return (xmlXPathCompOpEval(ctxt, op));
12873    }
12874}
12875
12876#ifdef XP_OPTIMIZED_FILTER_FIRST
12877static int
12878xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12879			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12880{
12881    int total = 0;
12882    xmlXPathCompExprPtr comp;
12883    xmlXPathObjectPtr res;
12884    xmlXPathObjectPtr obj;
12885    xmlNodeSetPtr oldset;
12886    xmlNodePtr oldnode;
12887    xmlDocPtr oldDoc;
12888    int i;
12889
12890    CHECK_ERROR0;
12891    comp = ctxt->comp;
12892    /*
12893    * Optimization for ()[last()] selection i.e. the last elem
12894    */
12895    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12896	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12897	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12898	int f = comp->steps[op->ch2].ch1;
12899
12900	if ((f != -1) &&
12901	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12902	    (comp->steps[f].value5 == NULL) &&
12903	    (comp->steps[f].value == 0) &&
12904	    (comp->steps[f].value4 != NULL) &&
12905	    (xmlStrEqual
12906	    (comp->steps[f].value4, BAD_CAST "last"))) {
12907	    xmlNodePtr last = NULL;
12908
12909	    total +=
12910		xmlXPathCompOpEvalLast(ctxt,
12911		    &comp->steps[op->ch1],
12912		    &last);
12913	    CHECK_ERROR0;
12914	    /*
12915	    * The nodeset should be in document order,
12916	    * Keep only the last value
12917	    */
12918	    if ((ctxt->value != NULL) &&
12919		(ctxt->value->type == XPATH_NODESET) &&
12920		(ctxt->value->nodesetval != NULL) &&
12921		(ctxt->value->nodesetval->nodeTab != NULL) &&
12922		(ctxt->value->nodesetval->nodeNr > 1)) {
12923		ctxt->value->nodesetval->nodeTab[0] =
12924		    ctxt->value->nodesetval->nodeTab[ctxt->
12925		    value->
12926		    nodesetval->
12927		    nodeNr -
12928		    1];
12929		ctxt->value->nodesetval->nodeNr = 1;
12930		*first = *(ctxt->value->nodesetval->nodeTab);
12931	    }
12932	    return (total);
12933	}
12934    }
12935
12936    if (op->ch1 != -1)
12937	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12938    CHECK_ERROR0;
12939    if (op->ch2 == -1)
12940	return (total);
12941    if (ctxt->value == NULL)
12942	return (total);
12943
12944#ifdef LIBXML_XPTR_ENABLED
12945    oldnode = ctxt->context->node;
12946    /*
12947    * Hum are we filtering the result of an XPointer expression
12948    */
12949    if (ctxt->value->type == XPATH_LOCATIONSET) {
12950	xmlXPathObjectPtr tmp = NULL;
12951	xmlLocationSetPtr newlocset = NULL;
12952	xmlLocationSetPtr oldlocset;
12953
12954	/*
12955	* Extract the old locset, and then evaluate the result of the
12956	* expression for all the element in the locset. use it to grow
12957	* up a new locset.
12958	*/
12959	CHECK_TYPE0(XPATH_LOCATIONSET);
12960	obj = valuePop(ctxt);
12961	oldlocset = obj->user;
12962	ctxt->context->node = NULL;
12963
12964	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12965	    ctxt->context->contextSize = 0;
12966	    ctxt->context->proximityPosition = 0;
12967	    if (op->ch2 != -1)
12968		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12969	    res = valuePop(ctxt);
12970	    if (res != NULL) {
12971		xmlXPathReleaseObject(ctxt->context, res);
12972	    }
12973	    valuePush(ctxt, obj);
12974	    CHECK_ERROR0;
12975	    return (total);
12976	}
12977	newlocset = xmlXPtrLocationSetCreate(NULL);
12978
12979	for (i = 0; i < oldlocset->locNr; i++) {
12980	    /*
12981	    * Run the evaluation with a node list made of a
12982	    * single item in the nodelocset.
12983	    */
12984	    ctxt->context->node = oldlocset->locTab[i]->user;
12985	    ctxt->context->contextSize = oldlocset->locNr;
12986	    ctxt->context->proximityPosition = i + 1;
12987	    if (tmp == NULL) {
12988		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12989		    ctxt->context->node);
12990	    } else {
12991		xmlXPathNodeSetAddUnique(tmp->nodesetval,
12992		    ctxt->context->node);
12993	    }
12994	    valuePush(ctxt, tmp);
12995	    if (op->ch2 != -1)
12996		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12997	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12998		xmlXPathFreeObject(obj);
12999		return(0);
13000	    }
13001	    /*
13002	    * The result of the evaluation need to be tested to
13003	    * decided whether the filter succeeded or not
13004	    */
13005	    res = valuePop(ctxt);
13006	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13007		xmlXPtrLocationSetAdd(newlocset,
13008		    xmlXPathCacheObjectCopy(ctxt->context,
13009			oldlocset->locTab[i]));
13010	    }
13011	    /*
13012	    * Cleanup
13013	    */
13014	    if (res != NULL) {
13015		xmlXPathReleaseObject(ctxt->context, res);
13016	    }
13017	    if (ctxt->value == tmp) {
13018		valuePop(ctxt);
13019		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13020		/*
13021		* REVISIT TODO: Don't create a temporary nodeset
13022		* for everly iteration.
13023		*/
13024		/* OLD: xmlXPathFreeObject(res); */
13025	    } else
13026		tmp = NULL;
13027	    ctxt->context->node = NULL;
13028	    /*
13029	    * Only put the first node in the result, then leave.
13030	    */
13031	    if (newlocset->locNr > 0) {
13032		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
13033		break;
13034	    }
13035	}
13036	if (tmp != NULL) {
13037	    xmlXPathReleaseObject(ctxt->context, tmp);
13038	}
13039	/*
13040	* The result is used as the new evaluation locset.
13041	*/
13042	xmlXPathReleaseObject(ctxt->context, obj);
13043	ctxt->context->node = NULL;
13044	ctxt->context->contextSize = -1;
13045	ctxt->context->proximityPosition = -1;
13046	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13047	ctxt->context->node = oldnode;
13048	return (total);
13049    }
13050#endif /* LIBXML_XPTR_ENABLED */
13051
13052    /*
13053    * Extract the old set, and then evaluate the result of the
13054    * expression for all the element in the set. use it to grow
13055    * up a new set.
13056    */
13057    CHECK_TYPE0(XPATH_NODESET);
13058    obj = valuePop(ctxt);
13059    oldset = obj->nodesetval;
13060
13061    oldnode = ctxt->context->node;
13062    oldDoc = ctxt->context->doc;
13063    ctxt->context->node = NULL;
13064
13065    if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13066	ctxt->context->contextSize = 0;
13067	ctxt->context->proximityPosition = 0;
13068	/* QUESTION TODO: Why was this code commented out?
13069	    if (op->ch2 != -1)
13070		total +=
13071		    xmlXPathCompOpEval(ctxt,
13072			&comp->steps[op->ch2]);
13073	    CHECK_ERROR0;
13074	    res = valuePop(ctxt);
13075	    if (res != NULL)
13076		xmlXPathFreeObject(res);
13077	*/
13078	valuePush(ctxt, obj);
13079	ctxt->context->node = oldnode;
13080	CHECK_ERROR0;
13081    } else {
13082	xmlNodeSetPtr newset;
13083	xmlXPathObjectPtr tmp = NULL;
13084	/*
13085	* Initialize the new set.
13086	* Also set the xpath document in case things like
13087	* key() evaluation are attempted on the predicate
13088	*/
13089	newset = xmlXPathNodeSetCreate(NULL);
13090        /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13091
13092	for (i = 0; i < oldset->nodeNr; i++) {
13093	    /*
13094	    * Run the evaluation with a node list made of
13095	    * a single item in the nodeset.
13096	    */
13097	    ctxt->context->node = oldset->nodeTab[i];
13098	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13099		(oldset->nodeTab[i]->doc != NULL))
13100		ctxt->context->doc = oldset->nodeTab[i]->doc;
13101	    if (tmp == NULL) {
13102		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13103		    ctxt->context->node);
13104	    } else {
13105		xmlXPathNodeSetAddUnique(tmp->nodesetval,
13106		    ctxt->context->node);
13107	    }
13108	    valuePush(ctxt, tmp);
13109	    ctxt->context->contextSize = oldset->nodeNr;
13110	    ctxt->context->proximityPosition = i + 1;
13111	    if (op->ch2 != -1)
13112		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13113	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13114		xmlXPathFreeNodeSet(newset);
13115		xmlXPathFreeObject(obj);
13116		return(0);
13117	    }
13118	    /*
13119	    * The result of the evaluation needs to be tested to
13120	    * decide whether the filter succeeded or not
13121	    */
13122	    res = valuePop(ctxt);
13123	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13124		xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13125	    }
13126	    /*
13127	    * Cleanup
13128	    */
13129	    if (res != NULL) {
13130		xmlXPathReleaseObject(ctxt->context, res);
13131	    }
13132	    if (ctxt->value == tmp) {
13133		valuePop(ctxt);
13134		/*
13135		* Don't free the temporary nodeset
13136		* in order to avoid massive recreation inside this
13137		* loop.
13138		*/
13139		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13140	    } else
13141		tmp = NULL;
13142	    ctxt->context->node = NULL;
13143	    /*
13144	    * Only put the first node in the result, then leave.
13145	    */
13146	    if (newset->nodeNr > 0) {
13147		*first = *(newset->nodeTab);
13148		break;
13149	    }
13150	}
13151	if (tmp != NULL) {
13152	    xmlXPathReleaseObject(ctxt->context, tmp);
13153	}
13154	/*
13155	* The result is used as the new evaluation set.
13156	*/
13157	xmlXPathReleaseObject(ctxt->context, obj);
13158	ctxt->context->node = NULL;
13159	ctxt->context->contextSize = -1;
13160	ctxt->context->proximityPosition = -1;
13161	/* may want to move this past the '}' later */
13162	ctxt->context->doc = oldDoc;
13163	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13164    }
13165    ctxt->context->node = oldnode;
13166    return(total);
13167}
13168#endif /* XP_OPTIMIZED_FILTER_FIRST */
13169
13170/**
13171 * xmlXPathCompOpEval:
13172 * @ctxt:  the XPath parser context with the compiled expression
13173 * @op:  an XPath compiled operation
13174 *
13175 * Evaluate the Precompiled XPath operation
13176 * Returns the number of nodes traversed
13177 */
13178static int
13179xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13180{
13181    int total = 0;
13182    int equal, ret;
13183    xmlXPathCompExprPtr comp;
13184    xmlXPathObjectPtr arg1, arg2;
13185    xmlNodePtr bak;
13186    xmlDocPtr bakd;
13187    int pp;
13188    int cs;
13189
13190    CHECK_ERROR0;
13191    comp = ctxt->comp;
13192    switch (op->op) {
13193        case XPATH_OP_END:
13194            return (0);
13195        case XPATH_OP_AND:
13196	    bakd = ctxt->context->doc;
13197	    bak = ctxt->context->node;
13198	    pp = ctxt->context->proximityPosition;
13199	    cs = ctxt->context->contextSize;
13200            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13201	    CHECK_ERROR0;
13202            xmlXPathBooleanFunction(ctxt, 1);
13203            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13204                return (total);
13205            arg2 = valuePop(ctxt);
13206	    ctxt->context->doc = bakd;
13207	    ctxt->context->node = bak;
13208	    ctxt->context->proximityPosition = pp;
13209	    ctxt->context->contextSize = cs;
13210            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13211	    if (ctxt->error) {
13212		xmlXPathFreeObject(arg2);
13213		return(0);
13214	    }
13215            xmlXPathBooleanFunction(ctxt, 1);
13216            arg1 = valuePop(ctxt);
13217            arg1->boolval &= arg2->boolval;
13218            valuePush(ctxt, arg1);
13219	    xmlXPathReleaseObject(ctxt->context, arg2);
13220            return (total);
13221        case XPATH_OP_OR:
13222	    bakd = ctxt->context->doc;
13223	    bak = ctxt->context->node;
13224	    pp = ctxt->context->proximityPosition;
13225	    cs = ctxt->context->contextSize;
13226            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13227	    CHECK_ERROR0;
13228            xmlXPathBooleanFunction(ctxt, 1);
13229            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13230                return (total);
13231            arg2 = valuePop(ctxt);
13232	    ctxt->context->doc = bakd;
13233	    ctxt->context->node = bak;
13234	    ctxt->context->proximityPosition = pp;
13235	    ctxt->context->contextSize = cs;
13236            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13237	    if (ctxt->error) {
13238		xmlXPathFreeObject(arg2);
13239		return(0);
13240	    }
13241            xmlXPathBooleanFunction(ctxt, 1);
13242            arg1 = valuePop(ctxt);
13243            arg1->boolval |= arg2->boolval;
13244            valuePush(ctxt, arg1);
13245	    xmlXPathReleaseObject(ctxt->context, arg2);
13246            return (total);
13247        case XPATH_OP_EQUAL:
13248	    bakd = ctxt->context->doc;
13249	    bak = ctxt->context->node;
13250	    pp = ctxt->context->proximityPosition;
13251	    cs = ctxt->context->contextSize;
13252            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13253	    CHECK_ERROR0;
13254	    ctxt->context->doc = bakd;
13255	    ctxt->context->node = bak;
13256	    ctxt->context->proximityPosition = pp;
13257	    ctxt->context->contextSize = cs;
13258            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13259	    CHECK_ERROR0;
13260	    if (op->value)
13261		equal = xmlXPathEqualValues(ctxt);
13262	    else
13263		equal = xmlXPathNotEqualValues(ctxt);
13264	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13265            return (total);
13266        case XPATH_OP_CMP:
13267	    bakd = ctxt->context->doc;
13268	    bak = ctxt->context->node;
13269	    pp = ctxt->context->proximityPosition;
13270	    cs = ctxt->context->contextSize;
13271            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13272	    CHECK_ERROR0;
13273	    ctxt->context->doc = bakd;
13274	    ctxt->context->node = bak;
13275	    ctxt->context->proximityPosition = pp;
13276	    ctxt->context->contextSize = cs;
13277            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13278	    CHECK_ERROR0;
13279            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13280	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13281            return (total);
13282        case XPATH_OP_PLUS:
13283	    bakd = ctxt->context->doc;
13284	    bak = ctxt->context->node;
13285	    pp = ctxt->context->proximityPosition;
13286	    cs = ctxt->context->contextSize;
13287            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13288	    CHECK_ERROR0;
13289            if (op->ch2 != -1) {
13290		ctxt->context->doc = bakd;
13291		ctxt->context->node = bak;
13292		ctxt->context->proximityPosition = pp;
13293		ctxt->context->contextSize = cs;
13294                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13295	    }
13296	    CHECK_ERROR0;
13297            if (op->value == 0)
13298                xmlXPathSubValues(ctxt);
13299            else if (op->value == 1)
13300                xmlXPathAddValues(ctxt);
13301            else if (op->value == 2)
13302                xmlXPathValueFlipSign(ctxt);
13303            else if (op->value == 3) {
13304                CAST_TO_NUMBER;
13305                CHECK_TYPE0(XPATH_NUMBER);
13306            }
13307            return (total);
13308        case XPATH_OP_MULT:
13309	    bakd = ctxt->context->doc;
13310	    bak = ctxt->context->node;
13311	    pp = ctxt->context->proximityPosition;
13312	    cs = ctxt->context->contextSize;
13313            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13314	    CHECK_ERROR0;
13315	    ctxt->context->doc = bakd;
13316	    ctxt->context->node = bak;
13317	    ctxt->context->proximityPosition = pp;
13318	    ctxt->context->contextSize = cs;
13319            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13320	    CHECK_ERROR0;
13321            if (op->value == 0)
13322                xmlXPathMultValues(ctxt);
13323            else if (op->value == 1)
13324                xmlXPathDivValues(ctxt);
13325            else if (op->value == 2)
13326                xmlXPathModValues(ctxt);
13327            return (total);
13328        case XPATH_OP_UNION:
13329	    bakd = ctxt->context->doc;
13330	    bak = ctxt->context->node;
13331	    pp = ctxt->context->proximityPosition;
13332	    cs = ctxt->context->contextSize;
13333            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13334	    CHECK_ERROR0;
13335	    ctxt->context->doc = bakd;
13336	    ctxt->context->node = bak;
13337	    ctxt->context->proximityPosition = pp;
13338	    ctxt->context->contextSize = cs;
13339            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13340	    CHECK_ERROR0;
13341            CHECK_TYPE0(XPATH_NODESET);
13342            arg2 = valuePop(ctxt);
13343
13344            CHECK_TYPE0(XPATH_NODESET);
13345            arg1 = valuePop(ctxt);
13346
13347	    if ((arg1->nodesetval == NULL) ||
13348		((arg2->nodesetval != NULL) &&
13349		 (arg2->nodesetval->nodeNr != 0)))
13350	    {
13351		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13352							arg2->nodesetval);
13353	    }
13354
13355            valuePush(ctxt, arg1);
13356	    xmlXPathReleaseObject(ctxt->context, arg2);
13357            return (total);
13358        case XPATH_OP_ROOT:
13359            xmlXPathRoot(ctxt);
13360            return (total);
13361        case XPATH_OP_NODE:
13362            if (op->ch1 != -1)
13363                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13364	    CHECK_ERROR0;
13365            if (op->ch2 != -1)
13366                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13367	    CHECK_ERROR0;
13368	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13369		ctxt->context->node));
13370            return (total);
13371        case XPATH_OP_RESET:
13372            if (op->ch1 != -1)
13373                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13374	    CHECK_ERROR0;
13375            if (op->ch2 != -1)
13376                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13377	    CHECK_ERROR0;
13378            ctxt->context->node = NULL;
13379            return (total);
13380        case XPATH_OP_COLLECT:{
13381                if (op->ch1 == -1)
13382                    return (total);
13383
13384                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13385		CHECK_ERROR0;
13386
13387                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13388                return (total);
13389            }
13390        case XPATH_OP_VALUE:
13391            valuePush(ctxt,
13392                      xmlXPathCacheObjectCopy(ctxt->context,
13393			(xmlXPathObjectPtr) op->value4));
13394            return (total);
13395        case XPATH_OP_VARIABLE:{
13396		xmlXPathObjectPtr val;
13397
13398                if (op->ch1 != -1)
13399                    total +=
13400                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13401                if (op->value5 == NULL) {
13402		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13403		    if (val == NULL) {
13404			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13405			return(0);
13406		    }
13407                    valuePush(ctxt, val);
13408		} else {
13409                    const xmlChar *URI;
13410
13411                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13412                    if (URI == NULL) {
13413                        xmlGenericError(xmlGenericErrorContext,
13414            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13415                                    (char *) op->value4, (char *)op->value5);
13416                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13417                        return (total);
13418                    }
13419		    val = xmlXPathVariableLookupNS(ctxt->context,
13420                                                       op->value4, URI);
13421		    if (val == NULL) {
13422			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13423			return(0);
13424		    }
13425                    valuePush(ctxt, val);
13426                }
13427                return (total);
13428            }
13429        case XPATH_OP_FUNCTION:{
13430                xmlXPathFunction func;
13431                const xmlChar *oldFunc, *oldFuncURI;
13432		int i;
13433                int frame;
13434
13435                frame = xmlXPathSetFrame(ctxt);
13436                if (op->ch1 != -1)
13437                    total +=
13438                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13439		if (ctxt->valueNr < op->value) {
13440		    xmlGenericError(xmlGenericErrorContext,
13441			    "xmlXPathCompOpEval: parameter error\n");
13442		    ctxt->error = XPATH_INVALID_OPERAND;
13443                    xmlXPathPopFrame(ctxt, frame);
13444		    return (total);
13445		}
13446		for (i = 0; i < op->value; i++) {
13447		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13448			xmlGenericError(xmlGenericErrorContext,
13449				"xmlXPathCompOpEval: parameter error\n");
13450			ctxt->error = XPATH_INVALID_OPERAND;
13451                        xmlXPathPopFrame(ctxt, frame);
13452			return (total);
13453		    }
13454                }
13455                if (op->cache != NULL)
13456                    XML_CAST_FPTR(func) = op->cache;
13457                else {
13458                    const xmlChar *URI = NULL;
13459
13460                    if (op->value5 == NULL)
13461                        func =
13462                            xmlXPathFunctionLookup(ctxt->context,
13463                                                   op->value4);
13464                    else {
13465                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13466                        if (URI == NULL) {
13467                            xmlGenericError(xmlGenericErrorContext,
13468            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13469                                    (char *)op->value4, (char *)op->value5);
13470                            xmlXPathPopFrame(ctxt, frame);
13471                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13472                            return (total);
13473                        }
13474                        func = xmlXPathFunctionLookupNS(ctxt->context,
13475                                                        op->value4, URI);
13476                    }
13477                    if (func == NULL) {
13478                        xmlGenericError(xmlGenericErrorContext,
13479                                "xmlXPathCompOpEval: function %s not found\n",
13480                                        (char *)op->value4);
13481                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13482                    }
13483                    op->cache = XML_CAST_FPTR(func);
13484                    op->cacheURI = (void *) URI;
13485                }
13486                oldFunc = ctxt->context->function;
13487                oldFuncURI = ctxt->context->functionURI;
13488                ctxt->context->function = op->value4;
13489                ctxt->context->functionURI = op->cacheURI;
13490                func(ctxt, op->value);
13491                ctxt->context->function = oldFunc;
13492                ctxt->context->functionURI = oldFuncURI;
13493                xmlXPathPopFrame(ctxt, frame);
13494                return (total);
13495            }
13496        case XPATH_OP_ARG:
13497	    bakd = ctxt->context->doc;
13498	    bak = ctxt->context->node;
13499	    pp = ctxt->context->proximityPosition;
13500	    cs = ctxt->context->contextSize;
13501            if (op->ch1 != -1)
13502                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13503	    ctxt->context->contextSize = cs;
13504	    ctxt->context->proximityPosition = pp;
13505	    ctxt->context->node = bak;
13506	    ctxt->context->doc = bakd;
13507	    CHECK_ERROR0;
13508            if (op->ch2 != -1) {
13509                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13510	        ctxt->context->doc = bakd;
13511	        ctxt->context->node = bak;
13512	        CHECK_ERROR0;
13513	    }
13514            return (total);
13515        case XPATH_OP_PREDICATE:
13516        case XPATH_OP_FILTER:{
13517                xmlXPathObjectPtr res;
13518                xmlXPathObjectPtr obj, tmp;
13519                xmlNodeSetPtr newset = NULL;
13520                xmlNodeSetPtr oldset;
13521                xmlNodePtr oldnode;
13522		xmlDocPtr oldDoc;
13523                int i;
13524
13525                /*
13526                 * Optimization for ()[1] selection i.e. the first elem
13527                 */
13528                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13529#ifdef XP_OPTIMIZED_FILTER_FIRST
13530		    /*
13531		    * FILTER TODO: Can we assume that the inner processing
13532		    *  will result in an ordered list if we have an
13533		    *  XPATH_OP_FILTER?
13534		    *  What about an additional field or flag on
13535		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13536		    *  to assume anything, so it would be more robust and
13537		    *  easier to optimize.
13538		    */
13539                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13540		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13541#else
13542		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13543#endif
13544                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13545                    xmlXPathObjectPtr val;
13546
13547                    val = comp->steps[op->ch2].value4;
13548                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13549                        (val->floatval == 1.0)) {
13550                        xmlNodePtr first = NULL;
13551
13552                        total +=
13553                            xmlXPathCompOpEvalFirst(ctxt,
13554                                                    &comp->steps[op->ch1],
13555                                                    &first);
13556			CHECK_ERROR0;
13557                        /*
13558                         * The nodeset should be in document order,
13559                         * Keep only the first value
13560                         */
13561                        if ((ctxt->value != NULL) &&
13562                            (ctxt->value->type == XPATH_NODESET) &&
13563                            (ctxt->value->nodesetval != NULL) &&
13564                            (ctxt->value->nodesetval->nodeNr > 1))
13565                            ctxt->value->nodesetval->nodeNr = 1;
13566                        return (total);
13567                    }
13568                }
13569                /*
13570                 * Optimization for ()[last()] selection i.e. the last elem
13571                 */
13572                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13573                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13574                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13575                    int f = comp->steps[op->ch2].ch1;
13576
13577                    if ((f != -1) &&
13578                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13579                        (comp->steps[f].value5 == NULL) &&
13580                        (comp->steps[f].value == 0) &&
13581                        (comp->steps[f].value4 != NULL) &&
13582                        (xmlStrEqual
13583                         (comp->steps[f].value4, BAD_CAST "last"))) {
13584                        xmlNodePtr last = NULL;
13585
13586                        total +=
13587                            xmlXPathCompOpEvalLast(ctxt,
13588                                                   &comp->steps[op->ch1],
13589                                                   &last);
13590			CHECK_ERROR0;
13591                        /*
13592                         * The nodeset should be in document order,
13593                         * Keep only the last value
13594                         */
13595                        if ((ctxt->value != NULL) &&
13596                            (ctxt->value->type == XPATH_NODESET) &&
13597                            (ctxt->value->nodesetval != NULL) &&
13598                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13599                            (ctxt->value->nodesetval->nodeNr > 1)) {
13600                            ctxt->value->nodesetval->nodeTab[0] =
13601                                ctxt->value->nodesetval->nodeTab[ctxt->
13602                                                                 value->
13603                                                                 nodesetval->
13604                                                                 nodeNr -
13605                                                                 1];
13606                            ctxt->value->nodesetval->nodeNr = 1;
13607                        }
13608                        return (total);
13609                    }
13610                }
13611		/*
13612		* Process inner predicates first.
13613		* Example "index[parent::book][1]":
13614		* ...
13615		*   PREDICATE   <-- we are here "[1]"
13616		*     PREDICATE <-- process "[parent::book]" first
13617		*       SORT
13618		*         COLLECT  'parent' 'name' 'node' book
13619		*           NODE
13620		*     ELEM Object is a number : 1
13621		*/
13622                if (op->ch1 != -1)
13623                    total +=
13624                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13625		CHECK_ERROR0;
13626                if (op->ch2 == -1)
13627                    return (total);
13628                if (ctxt->value == NULL)
13629                    return (total);
13630
13631                oldnode = ctxt->context->node;
13632
13633#ifdef LIBXML_XPTR_ENABLED
13634                /*
13635                 * Hum are we filtering the result of an XPointer expression
13636                 */
13637                if (ctxt->value->type == XPATH_LOCATIONSET) {
13638                    xmlLocationSetPtr newlocset = NULL;
13639                    xmlLocationSetPtr oldlocset;
13640
13641                    /*
13642                     * Extract the old locset, and then evaluate the result of the
13643                     * expression for all the element in the locset. use it to grow
13644                     * up a new locset.
13645                     */
13646                    CHECK_TYPE0(XPATH_LOCATIONSET);
13647                    obj = valuePop(ctxt);
13648                    oldlocset = obj->user;
13649                    ctxt->context->node = NULL;
13650
13651                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13652                        ctxt->context->contextSize = 0;
13653                        ctxt->context->proximityPosition = 0;
13654                        if (op->ch2 != -1)
13655                            total +=
13656                                xmlXPathCompOpEval(ctxt,
13657                                                   &comp->steps[op->ch2]);
13658                        res = valuePop(ctxt);
13659                        if (res != NULL) {
13660			    xmlXPathReleaseObject(ctxt->context, res);
13661			}
13662                        valuePush(ctxt, obj);
13663                        CHECK_ERROR0;
13664                        return (total);
13665                    }
13666                    newlocset = xmlXPtrLocationSetCreate(NULL);
13667
13668                    for (i = 0; i < oldlocset->locNr; i++) {
13669                        /*
13670                         * Run the evaluation with a node list made of a
13671                         * single item in the nodelocset.
13672                         */
13673                        ctxt->context->node = oldlocset->locTab[i]->user;
13674                        ctxt->context->contextSize = oldlocset->locNr;
13675                        ctxt->context->proximityPosition = i + 1;
13676			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13677			    ctxt->context->node);
13678                        valuePush(ctxt, tmp);
13679
13680                        if (op->ch2 != -1)
13681                            total +=
13682                                xmlXPathCompOpEval(ctxt,
13683                                                   &comp->steps[op->ch2]);
13684			if (ctxt->error != XPATH_EXPRESSION_OK) {
13685			    xmlXPathFreeObject(obj);
13686			    return(0);
13687			}
13688
13689                        /*
13690                         * The result of the evaluation need to be tested to
13691                         * decided whether the filter succeeded or not
13692                         */
13693                        res = valuePop(ctxt);
13694                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13695                            xmlXPtrLocationSetAdd(newlocset,
13696                                                  xmlXPathObjectCopy
13697                                                  (oldlocset->locTab[i]));
13698                        }
13699
13700                        /*
13701                         * Cleanup
13702                         */
13703                        if (res != NULL) {
13704			    xmlXPathReleaseObject(ctxt->context, res);
13705			}
13706                        if (ctxt->value == tmp) {
13707                            res = valuePop(ctxt);
13708			    xmlXPathReleaseObject(ctxt->context, res);
13709                        }
13710
13711                        ctxt->context->node = NULL;
13712                    }
13713
13714                    /*
13715                     * The result is used as the new evaluation locset.
13716                     */
13717		    xmlXPathReleaseObject(ctxt->context, obj);
13718                    ctxt->context->node = NULL;
13719                    ctxt->context->contextSize = -1;
13720                    ctxt->context->proximityPosition = -1;
13721                    valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13722                    ctxt->context->node = oldnode;
13723                    return (total);
13724                }
13725#endif /* LIBXML_XPTR_ENABLED */
13726
13727                /*
13728                 * Extract the old set, and then evaluate the result of the
13729                 * expression for all the element in the set. use it to grow
13730                 * up a new set.
13731                 */
13732                CHECK_TYPE0(XPATH_NODESET);
13733                obj = valuePop(ctxt);
13734                oldset = obj->nodesetval;
13735
13736                oldnode = ctxt->context->node;
13737		oldDoc = ctxt->context->doc;
13738                ctxt->context->node = NULL;
13739
13740                if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13741                    ctxt->context->contextSize = 0;
13742                    ctxt->context->proximityPosition = 0;
13743/*
13744                    if (op->ch2 != -1)
13745                        total +=
13746                            xmlXPathCompOpEval(ctxt,
13747                                               &comp->steps[op->ch2]);
13748		    CHECK_ERROR0;
13749                    res = valuePop(ctxt);
13750                    if (res != NULL)
13751                        xmlXPathFreeObject(res);
13752*/
13753                    valuePush(ctxt, obj);
13754                    ctxt->context->node = oldnode;
13755                    CHECK_ERROR0;
13756                } else {
13757		    tmp = NULL;
13758                    /*
13759                     * Initialize the new set.
13760		     * Also set the xpath document in case things like
13761		     * key() evaluation are attempted on the predicate
13762                     */
13763                    newset = xmlXPathNodeSetCreate(NULL);
13764		    /*
13765		    * SPEC XPath 1.0:
13766		    *  "For each node in the node-set to be filtered, the
13767		    *  PredicateExpr is evaluated with that node as the
13768		    *  context node, with the number of nodes in the
13769		    *  node-set as the context size, and with the proximity
13770		    *  position of the node in the node-set with respect to
13771		    *  the axis as the context position;"
13772		    * @oldset is the node-set" to be filtered.
13773		    *
13774		    * SPEC XPath 1.0:
13775		    *  "only predicates change the context position and
13776		    *  context size (see [2.4 Predicates])."
13777		    * Example:
13778		    *   node-set  context pos
13779		    *    nA         1
13780		    *    nB         2
13781		    *    nC         3
13782		    *   After applying predicate [position() > 1] :
13783		    *   node-set  context pos
13784		    *    nB         1
13785		    *    nC         2
13786		    *
13787		    * removed the first node in the node-set, then
13788		    * the context position of the
13789		    */
13790                    for (i = 0; i < oldset->nodeNr; i++) {
13791                        /*
13792                         * Run the evaluation with a node list made of
13793                         * a single item in the nodeset.
13794                         */
13795                        ctxt->context->node = oldset->nodeTab[i];
13796			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13797			    (oldset->nodeTab[i]->doc != NULL))
13798		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13799			if (tmp == NULL) {
13800			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13801				ctxt->context->node);
13802			} else {
13803			    xmlXPathNodeSetAddUnique(tmp->nodesetval,
13804				ctxt->context->node);
13805			}
13806                        valuePush(ctxt, tmp);
13807                        ctxt->context->contextSize = oldset->nodeNr;
13808                        ctxt->context->proximityPosition = i + 1;
13809			/*
13810			* Evaluate the predicate against the context node.
13811			* Can/should we optimize position() predicates
13812			* here (e.g. "[1]")?
13813			*/
13814                        if (op->ch2 != -1)
13815                            total +=
13816                                xmlXPathCompOpEval(ctxt,
13817                                                   &comp->steps[op->ch2]);
13818			if (ctxt->error != XPATH_EXPRESSION_OK) {
13819			    xmlXPathFreeNodeSet(newset);
13820			    xmlXPathFreeObject(obj);
13821			    return(0);
13822			}
13823
13824                        /*
13825                         * The result of the evaluation needs to be tested to
13826                         * decide whether the filter succeeded or not
13827                         */
13828			/*
13829			* OPTIMIZE TODO: Can we use
13830			* xmlXPathNodeSetAdd*Unique()* instead?
13831			*/
13832                        res = valuePop(ctxt);
13833                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13834                            xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13835                        }
13836
13837                        /*
13838                         * Cleanup
13839                         */
13840                        if (res != NULL) {
13841			    xmlXPathReleaseObject(ctxt->context, res);
13842			}
13843                        if (ctxt->value == tmp) {
13844                            valuePop(ctxt);
13845			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13846			    /*
13847			    * Don't free the temporary nodeset
13848			    * in order to avoid massive recreation inside this
13849			    * loop.
13850			    */
13851                        } else
13852			    tmp = NULL;
13853                        ctxt->context->node = NULL;
13854                    }
13855		    if (tmp != NULL)
13856			xmlXPathReleaseObject(ctxt->context, tmp);
13857                    /*
13858                     * The result is used as the new evaluation set.
13859                     */
13860		    xmlXPathReleaseObject(ctxt->context, obj);
13861                    ctxt->context->node = NULL;
13862                    ctxt->context->contextSize = -1;
13863                    ctxt->context->proximityPosition = -1;
13864		    /* may want to move this past the '}' later */
13865		    ctxt->context->doc = oldDoc;
13866		    valuePush(ctxt,
13867			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13868                }
13869                ctxt->context->node = oldnode;
13870                return (total);
13871            }
13872        case XPATH_OP_SORT:
13873            if (op->ch1 != -1)
13874                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13875	    CHECK_ERROR0;
13876            if ((ctxt->value != NULL) &&
13877                (ctxt->value->type == XPATH_NODESET) &&
13878                (ctxt->value->nodesetval != NULL) &&
13879		(ctxt->value->nodesetval->nodeNr > 1))
13880	    {
13881                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13882	    }
13883            return (total);
13884#ifdef LIBXML_XPTR_ENABLED
13885        case XPATH_OP_RANGETO:{
13886                xmlXPathObjectPtr range;
13887                xmlXPathObjectPtr res, obj;
13888                xmlXPathObjectPtr tmp;
13889                xmlLocationSetPtr newlocset = NULL;
13890		    xmlLocationSetPtr oldlocset;
13891                xmlNodeSetPtr oldset;
13892                int i, j;
13893
13894                if (op->ch1 != -1)
13895                    total +=
13896                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13897                if (op->ch2 == -1)
13898                    return (total);
13899
13900                if (ctxt->value->type == XPATH_LOCATIONSET) {
13901                    /*
13902                     * Extract the old locset, and then evaluate the result of the
13903                     * expression for all the element in the locset. use it to grow
13904                     * up a new locset.
13905                     */
13906                    CHECK_TYPE0(XPATH_LOCATIONSET);
13907                    obj = valuePop(ctxt);
13908                    oldlocset = obj->user;
13909
13910                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13911		        ctxt->context->node = NULL;
13912                        ctxt->context->contextSize = 0;
13913                        ctxt->context->proximityPosition = 0;
13914                        total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13915                        res = valuePop(ctxt);
13916                        if (res != NULL) {
13917			    xmlXPathReleaseObject(ctxt->context, res);
13918			}
13919                        valuePush(ctxt, obj);
13920                        CHECK_ERROR0;
13921                        return (total);
13922                    }
13923                    newlocset = xmlXPtrLocationSetCreate(NULL);
13924
13925                    for (i = 0; i < oldlocset->locNr; i++) {
13926                        /*
13927                         * Run the evaluation with a node list made of a
13928                         * single item in the nodelocset.
13929                         */
13930                        ctxt->context->node = oldlocset->locTab[i]->user;
13931                        ctxt->context->contextSize = oldlocset->locNr;
13932                        ctxt->context->proximityPosition = i + 1;
13933			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13934			    ctxt->context->node);
13935                        valuePush(ctxt, tmp);
13936
13937                        if (op->ch2 != -1)
13938                            total +=
13939                                xmlXPathCompOpEval(ctxt,
13940                                                   &comp->steps[op->ch2]);
13941			if (ctxt->error != XPATH_EXPRESSION_OK) {
13942			    xmlXPathFreeObject(obj);
13943			    return(0);
13944			}
13945
13946                        res = valuePop(ctxt);
13947			if (res->type == XPATH_LOCATIONSET) {
13948			    xmlLocationSetPtr rloc =
13949			        (xmlLocationSetPtr)res->user;
13950			    for (j=0; j<rloc->locNr; j++) {
13951			        range = xmlXPtrNewRange(
13952				  oldlocset->locTab[i]->user,
13953				  oldlocset->locTab[i]->index,
13954				  rloc->locTab[j]->user2,
13955				  rloc->locTab[j]->index2);
13956				if (range != NULL) {
13957				    xmlXPtrLocationSetAdd(newlocset, range);
13958				}
13959			    }
13960			} else {
13961			    range = xmlXPtrNewRangeNodeObject(
13962				(xmlNodePtr)oldlocset->locTab[i]->user, res);
13963                            if (range != NULL) {
13964                                xmlXPtrLocationSetAdd(newlocset,range);
13965			    }
13966                        }
13967
13968                        /*
13969                         * Cleanup
13970                         */
13971                        if (res != NULL) {
13972			    xmlXPathReleaseObject(ctxt->context, res);
13973			}
13974                        if (ctxt->value == tmp) {
13975                            res = valuePop(ctxt);
13976			    xmlXPathReleaseObject(ctxt->context, res);
13977                        }
13978
13979                        ctxt->context->node = NULL;
13980                    }
13981		} else {	/* Not a location set */
13982                    CHECK_TYPE0(XPATH_NODESET);
13983                    obj = valuePop(ctxt);
13984                    oldset = obj->nodesetval;
13985                    ctxt->context->node = NULL;
13986
13987                    newlocset = xmlXPtrLocationSetCreate(NULL);
13988
13989                    if (oldset != NULL) {
13990                        for (i = 0; i < oldset->nodeNr; i++) {
13991                            /*
13992                             * Run the evaluation with a node list made of a single item
13993                             * in the nodeset.
13994                             */
13995                            ctxt->context->node = oldset->nodeTab[i];
13996			    /*
13997			    * OPTIMIZE TODO: Avoid recreation for every iteration.
13998			    */
13999			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14000				ctxt->context->node);
14001                            valuePush(ctxt, tmp);
14002
14003                            if (op->ch2 != -1)
14004                                total +=
14005                                    xmlXPathCompOpEval(ctxt,
14006                                                   &comp->steps[op->ch2]);
14007			    if (ctxt->error != XPATH_EXPRESSION_OK) {
14008				xmlXPathFreeObject(obj);
14009				return(0);
14010			    }
14011
14012                            res = valuePop(ctxt);
14013                            range =
14014                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14015                                                      res);
14016                            if (range != NULL) {
14017                                xmlXPtrLocationSetAdd(newlocset, range);
14018                            }
14019
14020                            /*
14021                             * Cleanup
14022                             */
14023                            if (res != NULL) {
14024				xmlXPathReleaseObject(ctxt->context, res);
14025			    }
14026                            if (ctxt->value == tmp) {
14027                                res = valuePop(ctxt);
14028				xmlXPathReleaseObject(ctxt->context, res);
14029                            }
14030
14031                            ctxt->context->node = NULL;
14032                        }
14033                    }
14034                }
14035
14036                /*
14037                 * The result is used as the new evaluation set.
14038                 */
14039		xmlXPathReleaseObject(ctxt->context, obj);
14040                ctxt->context->node = NULL;
14041                ctxt->context->contextSize = -1;
14042                ctxt->context->proximityPosition = -1;
14043                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14044                return (total);
14045            }
14046#endif /* LIBXML_XPTR_ENABLED */
14047    }
14048    xmlGenericError(xmlGenericErrorContext,
14049                    "XPath: unknown precompiled operation %d\n", op->op);
14050    ctxt->error = XPATH_INVALID_OPERAND;
14051    return (total);
14052}
14053
14054/**
14055 * xmlXPathCompOpEvalToBoolean:
14056 * @ctxt:  the XPath parser context
14057 *
14058 * Evaluates if the expression evaluates to true.
14059 *
14060 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14061 */
14062static int
14063xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14064			    xmlXPathStepOpPtr op,
14065			    int isPredicate)
14066{
14067    xmlXPathObjectPtr resObj = NULL;
14068
14069start:
14070    /* comp = ctxt->comp; */
14071    switch (op->op) {
14072        case XPATH_OP_END:
14073            return (0);
14074	case XPATH_OP_VALUE:
14075	    resObj = (xmlXPathObjectPtr) op->value4;
14076	    if (isPredicate)
14077		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14078	    return(xmlXPathCastToBoolean(resObj));
14079	case XPATH_OP_SORT:
14080	    /*
14081	    * We don't need sorting for boolean results. Skip this one.
14082	    */
14083            if (op->ch1 != -1) {
14084		op = &ctxt->comp->steps[op->ch1];
14085		goto start;
14086	    }
14087	    return(0);
14088	case XPATH_OP_COLLECT:
14089	    if (op->ch1 == -1)
14090		return(0);
14091
14092            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14093	    if (ctxt->error != XPATH_EXPRESSION_OK)
14094		return(-1);
14095
14096            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14097	    if (ctxt->error != XPATH_EXPRESSION_OK)
14098		return(-1);
14099
14100	    resObj = valuePop(ctxt);
14101	    if (resObj == NULL)
14102		return(-1);
14103	    break;
14104	default:
14105	    /*
14106	    * Fallback to call xmlXPathCompOpEval().
14107	    */
14108	    xmlXPathCompOpEval(ctxt, op);
14109	    if (ctxt->error != XPATH_EXPRESSION_OK)
14110		return(-1);
14111
14112	    resObj = valuePop(ctxt);
14113	    if (resObj == NULL)
14114		return(-1);
14115	    break;
14116    }
14117
14118    if (resObj) {
14119	int res;
14120
14121	if (resObj->type == XPATH_BOOLEAN) {
14122	    res = resObj->boolval;
14123	} else if (isPredicate) {
14124	    /*
14125	    * For predicates a result of type "number" is handled
14126	    * differently:
14127	    * SPEC XPath 1.0:
14128	    * "If the result is a number, the result will be converted
14129	    *  to true if the number is equal to the context position
14130	    *  and will be converted to false otherwise;"
14131	    */
14132	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14133	} else {
14134	    res = xmlXPathCastToBoolean(resObj);
14135	}
14136	xmlXPathReleaseObject(ctxt->context, resObj);
14137	return(res);
14138    }
14139
14140    return(0);
14141}
14142
14143#ifdef XPATH_STREAMING
14144/**
14145 * xmlXPathRunStreamEval:
14146 * @ctxt:  the XPath parser context with the compiled expression
14147 *
14148 * Evaluate the Precompiled Streamable XPath expression in the given context.
14149 */
14150static int
14151xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14152		      xmlXPathObjectPtr *resultSeq, int toBool)
14153{
14154    int max_depth, min_depth;
14155    int from_root;
14156    int ret, depth;
14157    int eval_all_nodes;
14158    xmlNodePtr cur = NULL, limit = NULL;
14159    xmlStreamCtxtPtr patstream = NULL;
14160
14161    int nb_nodes = 0;
14162
14163    if ((ctxt == NULL) || (comp == NULL))
14164        return(-1);
14165    max_depth = xmlPatternMaxDepth(comp);
14166    if (max_depth == -1)
14167        return(-1);
14168    if (max_depth == -2)
14169        max_depth = 10000;
14170    min_depth = xmlPatternMinDepth(comp);
14171    if (min_depth == -1)
14172        return(-1);
14173    from_root = xmlPatternFromRoot(comp);
14174    if (from_root < 0)
14175        return(-1);
14176#if 0
14177    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14178#endif
14179
14180    if (! toBool) {
14181	if (resultSeq == NULL)
14182	    return(-1);
14183	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14184	if (*resultSeq == NULL)
14185	    return(-1);
14186    }
14187
14188    /*
14189     * handle the special cases of "/" amd "." being matched
14190     */
14191    if (min_depth == 0) {
14192	if (from_root) {
14193	    /* Select "/" */
14194	    if (toBool)
14195		return(1);
14196	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14197		(xmlNodePtr) ctxt->doc);
14198	} else {
14199	    /* Select "self::node()" */
14200	    if (toBool)
14201		return(1);
14202	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14203	}
14204    }
14205    if (max_depth == 0) {
14206	return(0);
14207    }
14208
14209    if (from_root) {
14210        cur = (xmlNodePtr)ctxt->doc;
14211    } else if (ctxt->node != NULL) {
14212        switch (ctxt->node->type) {
14213            case XML_ELEMENT_NODE:
14214            case XML_DOCUMENT_NODE:
14215            case XML_DOCUMENT_FRAG_NODE:
14216            case XML_HTML_DOCUMENT_NODE:
14217#ifdef LIBXML_DOCB_ENABLED
14218            case XML_DOCB_DOCUMENT_NODE:
14219#endif
14220	        cur = ctxt->node;
14221		break;
14222            case XML_ATTRIBUTE_NODE:
14223            case XML_TEXT_NODE:
14224            case XML_CDATA_SECTION_NODE:
14225            case XML_ENTITY_REF_NODE:
14226            case XML_ENTITY_NODE:
14227            case XML_PI_NODE:
14228            case XML_COMMENT_NODE:
14229            case XML_NOTATION_NODE:
14230            case XML_DTD_NODE:
14231            case XML_DOCUMENT_TYPE_NODE:
14232            case XML_ELEMENT_DECL:
14233            case XML_ATTRIBUTE_DECL:
14234            case XML_ENTITY_DECL:
14235            case XML_NAMESPACE_DECL:
14236            case XML_XINCLUDE_START:
14237            case XML_XINCLUDE_END:
14238		break;
14239	}
14240	limit = cur;
14241    }
14242    if (cur == NULL) {
14243        return(0);
14244    }
14245
14246    patstream = xmlPatternGetStreamCtxt(comp);
14247    if (patstream == NULL) {
14248	/*
14249	* QUESTION TODO: Is this an error?
14250	*/
14251	return(0);
14252    }
14253
14254    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14255
14256    if (from_root) {
14257	ret = xmlStreamPush(patstream, NULL, NULL);
14258	if (ret < 0) {
14259	} else if (ret == 1) {
14260	    if (toBool)
14261		goto return_1;
14262	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14263	}
14264    }
14265    depth = 0;
14266    goto scan_children;
14267next_node:
14268    do {
14269        nb_nodes++;
14270
14271	switch (cur->type) {
14272	    case XML_ELEMENT_NODE:
14273	    case XML_TEXT_NODE:
14274	    case XML_CDATA_SECTION_NODE:
14275	    case XML_COMMENT_NODE:
14276	    case XML_PI_NODE:
14277		if (cur->type == XML_ELEMENT_NODE) {
14278		    ret = xmlStreamPush(patstream, cur->name,
14279				(cur->ns ? cur->ns->href : NULL));
14280		} else if (eval_all_nodes)
14281		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14282		else
14283		    break;
14284
14285		if (ret < 0) {
14286		    /* NOP. */
14287		} else if (ret == 1) {
14288		    if (toBool)
14289			goto return_1;
14290		    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14291		}
14292		if ((cur->children == NULL) || (depth >= max_depth)) {
14293		    ret = xmlStreamPop(patstream);
14294		    while (cur->next != NULL) {
14295			cur = cur->next;
14296			if ((cur->type != XML_ENTITY_DECL) &&
14297			    (cur->type != XML_DTD_NODE))
14298			    goto next_node;
14299		    }
14300		}
14301	    default:
14302		break;
14303	}
14304
14305scan_children:
14306	if ((cur->children != NULL) && (depth < max_depth)) {
14307	    /*
14308	     * Do not descend on entities declarations
14309	     */
14310	    if (cur->children->type != XML_ENTITY_DECL) {
14311		cur = cur->children;
14312		depth++;
14313		/*
14314		 * Skip DTDs
14315		 */
14316		if (cur->type != XML_DTD_NODE)
14317		    continue;
14318	    }
14319	}
14320
14321	if (cur == limit)
14322	    break;
14323
14324	while (cur->next != NULL) {
14325	    cur = cur->next;
14326	    if ((cur->type != XML_ENTITY_DECL) &&
14327		(cur->type != XML_DTD_NODE))
14328		goto next_node;
14329	}
14330
14331	do {
14332	    cur = cur->parent;
14333	    depth--;
14334	    if ((cur == NULL) || (cur == limit))
14335	        goto done;
14336	    if (cur->type == XML_ELEMENT_NODE) {
14337		ret = xmlStreamPop(patstream);
14338	    } else if ((eval_all_nodes) &&
14339		((cur->type == XML_TEXT_NODE) ||
14340		 (cur->type == XML_CDATA_SECTION_NODE) ||
14341		 (cur->type == XML_COMMENT_NODE) ||
14342		 (cur->type == XML_PI_NODE)))
14343	    {
14344		ret = xmlStreamPop(patstream);
14345	    }
14346	    if (cur->next != NULL) {
14347		cur = cur->next;
14348		break;
14349	    }
14350	} while (cur != NULL);
14351
14352    } while ((cur != NULL) && (depth >= 0));
14353
14354done:
14355
14356#if 0
14357    printf("stream eval: checked %d nodes selected %d\n",
14358           nb_nodes, retObj->nodesetval->nodeNr);
14359#endif
14360
14361    if (patstream)
14362	xmlFreeStreamCtxt(patstream);
14363    return(0);
14364
14365return_1:
14366    if (patstream)
14367	xmlFreeStreamCtxt(patstream);
14368    return(1);
14369}
14370#endif /* XPATH_STREAMING */
14371
14372/**
14373 * xmlXPathRunEval:
14374 * @ctxt:  the XPath parser context with the compiled expression
14375 * @toBool:  evaluate to a boolean result
14376 *
14377 * Evaluate the Precompiled XPath expression in the given context.
14378 */
14379static int
14380xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14381{
14382    xmlXPathCompExprPtr comp;
14383
14384    if ((ctxt == NULL) || (ctxt->comp == NULL))
14385	return(-1);
14386
14387    if (ctxt->valueTab == NULL) {
14388	/* Allocate the value stack */
14389	ctxt->valueTab = (xmlXPathObjectPtr *)
14390			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14391	if (ctxt->valueTab == NULL) {
14392	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14393	    xmlFree(ctxt);
14394	}
14395	ctxt->valueNr = 0;
14396	ctxt->valueMax = 10;
14397	ctxt->value = NULL;
14398        ctxt->valueFrame = 0;
14399    }
14400#ifdef XPATH_STREAMING
14401    if (ctxt->comp->stream) {
14402	int res;
14403
14404	if (toBool) {
14405	    /*
14406	    * Evaluation to boolean result.
14407	    */
14408	    res = xmlXPathRunStreamEval(ctxt->context,
14409		ctxt->comp->stream, NULL, 1);
14410	    if (res != -1)
14411		return(res);
14412	} else {
14413	    xmlXPathObjectPtr resObj = NULL;
14414
14415	    /*
14416	    * Evaluation to a sequence.
14417	    */
14418	    res = xmlXPathRunStreamEval(ctxt->context,
14419		ctxt->comp->stream, &resObj, 0);
14420
14421	    if ((res != -1) && (resObj != NULL)) {
14422		valuePush(ctxt, resObj);
14423		return(0);
14424	    }
14425	    if (resObj != NULL)
14426		xmlXPathReleaseObject(ctxt->context, resObj);
14427	}
14428	/*
14429	* QUESTION TODO: This falls back to normal XPath evaluation
14430	* if res == -1. Is this intended?
14431	*/
14432    }
14433#endif
14434    comp = ctxt->comp;
14435    if (comp->last < 0) {
14436	xmlGenericError(xmlGenericErrorContext,
14437	    "xmlXPathRunEval: last is less than zero\n");
14438	return(-1);
14439    }
14440    if (toBool)
14441	return(xmlXPathCompOpEvalToBoolean(ctxt,
14442	    &comp->steps[comp->last], 0));
14443    else
14444	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14445
14446    return(0);
14447}
14448
14449/************************************************************************
14450 *									*
14451 *			Public interfaces				*
14452 *									*
14453 ************************************************************************/
14454
14455/**
14456 * xmlXPathEvalPredicate:
14457 * @ctxt:  the XPath context
14458 * @res:  the Predicate Expression evaluation result
14459 *
14460 * Evaluate a predicate result for the current node.
14461 * A PredicateExpr is evaluated by evaluating the Expr and converting
14462 * the result to a boolean. If the result is a number, the result will
14463 * be converted to true if the number is equal to the position of the
14464 * context node in the context node list (as returned by the position
14465 * function) and will be converted to false otherwise; if the result
14466 * is not a number, then the result will be converted as if by a call
14467 * to the boolean function.
14468 *
14469 * Returns 1 if predicate is true, 0 otherwise
14470 */
14471int
14472xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14473    if ((ctxt == NULL) || (res == NULL)) return(0);
14474    switch (res->type) {
14475        case XPATH_BOOLEAN:
14476	    return(res->boolval);
14477        case XPATH_NUMBER:
14478	    return(res->floatval == ctxt->proximityPosition);
14479        case XPATH_NODESET:
14480        case XPATH_XSLT_TREE:
14481	    if (res->nodesetval == NULL)
14482		return(0);
14483	    return(res->nodesetval->nodeNr != 0);
14484        case XPATH_STRING:
14485	    return((res->stringval != NULL) &&
14486	           (xmlStrlen(res->stringval) != 0));
14487        default:
14488	    STRANGE
14489    }
14490    return(0);
14491}
14492
14493/**
14494 * xmlXPathEvaluatePredicateResult:
14495 * @ctxt:  the XPath Parser context
14496 * @res:  the Predicate Expression evaluation result
14497 *
14498 * Evaluate a predicate result for the current node.
14499 * A PredicateExpr is evaluated by evaluating the Expr and converting
14500 * the result to a boolean. If the result is a number, the result will
14501 * be converted to true if the number is equal to the position of the
14502 * context node in the context node list (as returned by the position
14503 * function) and will be converted to false otherwise; if the result
14504 * is not a number, then the result will be converted as if by a call
14505 * to the boolean function.
14506 *
14507 * Returns 1 if predicate is true, 0 otherwise
14508 */
14509int
14510xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14511                                xmlXPathObjectPtr res) {
14512    if ((ctxt == NULL) || (res == NULL)) return(0);
14513    switch (res->type) {
14514        case XPATH_BOOLEAN:
14515	    return(res->boolval);
14516        case XPATH_NUMBER:
14517#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14518	    return((res->floatval == ctxt->context->proximityPosition) &&
14519	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14520#else
14521	    return(res->floatval == ctxt->context->proximityPosition);
14522#endif
14523        case XPATH_NODESET:
14524        case XPATH_XSLT_TREE:
14525	    if (res->nodesetval == NULL)
14526		return(0);
14527	    return(res->nodesetval->nodeNr != 0);
14528        case XPATH_STRING:
14529	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14530#ifdef LIBXML_XPTR_ENABLED
14531	case XPATH_LOCATIONSET:{
14532	    xmlLocationSetPtr ptr = res->user;
14533	    if (ptr == NULL)
14534	        return(0);
14535	    return (ptr->locNr != 0);
14536	    }
14537#endif
14538        default:
14539	    STRANGE
14540    }
14541    return(0);
14542}
14543
14544#ifdef XPATH_STREAMING
14545/**
14546 * xmlXPathTryStreamCompile:
14547 * @ctxt: an XPath context
14548 * @str:  the XPath expression
14549 *
14550 * Try to compile the XPath expression as a streamable subset.
14551 *
14552 * Returns the compiled expression or NULL if failed to compile.
14553 */
14554static xmlXPathCompExprPtr
14555xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14556    /*
14557     * Optimization: use streaming patterns when the XPath expression can
14558     * be compiled to a stream lookup
14559     */
14560    xmlPatternPtr stream;
14561    xmlXPathCompExprPtr comp;
14562    xmlDictPtr dict = NULL;
14563    const xmlChar **namespaces = NULL;
14564    xmlNsPtr ns;
14565    int i, j;
14566
14567    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14568        (!xmlStrchr(str, '@'))) {
14569	const xmlChar *tmp;
14570
14571	/*
14572	 * We don't try to handle expressions using the verbose axis
14573	 * specifiers ("::"), just the simplied form at this point.
14574	 * Additionally, if there is no list of namespaces available and
14575	 *  there's a ":" in the expression, indicating a prefixed QName,
14576	 *  then we won't try to compile either. xmlPatterncompile() needs
14577	 *  to have a list of namespaces at compilation time in order to
14578	 *  compile prefixed name tests.
14579	 */
14580	tmp = xmlStrchr(str, ':');
14581	if ((tmp != NULL) &&
14582	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14583	    return(NULL);
14584
14585	if (ctxt != NULL) {
14586	    dict = ctxt->dict;
14587	    if (ctxt->nsNr > 0) {
14588		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14589		if (namespaces == NULL) {
14590		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14591		    return(NULL);
14592		}
14593		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14594		    ns = ctxt->namespaces[j];
14595		    namespaces[i++] = ns->href;
14596		    namespaces[i++] = ns->prefix;
14597		}
14598		namespaces[i++] = NULL;
14599		namespaces[i] = NULL;
14600	    }
14601	}
14602
14603	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14604			&namespaces[0]);
14605	if (namespaces != NULL) {
14606	    xmlFree((xmlChar **)namespaces);
14607	}
14608	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14609	    comp = xmlXPathNewCompExpr();
14610	    if (comp == NULL) {
14611		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14612		return(NULL);
14613	    }
14614	    comp->stream = stream;
14615	    comp->dict = dict;
14616	    if (comp->dict)
14617		xmlDictReference(comp->dict);
14618	    return(comp);
14619	}
14620	xmlFreePattern(stream);
14621    }
14622    return(NULL);
14623}
14624#endif /* XPATH_STREAMING */
14625
14626static int
14627xmlXPathCanRewriteDosExpression(xmlChar *expr)
14628{
14629    if (expr == NULL)
14630	return(0);
14631    do {
14632        if ((*expr == '/') && (*(++expr) == '/'))
14633	    return(1);
14634    } while (*expr++);
14635    return(0);
14636}
14637static void
14638xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14639{
14640    /*
14641    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14642    * internal representation.
14643    */
14644    if (op->ch1 != -1) {
14645	if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14646	    ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14647	    ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14648	    ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14649	{
14650	    /*
14651	    * This is a "child::foo"
14652	    */
14653	    xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14654
14655	    if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14656		(prevop->ch1 != -1) &&
14657		((xmlXPathAxisVal) prevop->value ==
14658		    AXIS_DESCENDANT_OR_SELF) &&
14659		(prevop->ch2 == -1) &&
14660		((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14661		((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14662		(comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14663	    {
14664		/*
14665		* This is a "/descendant-or-self::node()" without predicates.
14666		* Eliminate it.
14667		*/
14668		op->ch1 = prevop->ch1;
14669		op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14670	    }
14671	}
14672	if (op->ch1 != -1)
14673	    xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14674    }
14675    if (op->ch2 != -1)
14676	xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14677}
14678
14679/**
14680 * xmlXPathCtxtCompile:
14681 * @ctxt: an XPath context
14682 * @str:  the XPath expression
14683 *
14684 * Compile an XPath expression
14685 *
14686 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14687 *         the caller has to free the object.
14688 */
14689xmlXPathCompExprPtr
14690xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14691    xmlXPathParserContextPtr pctxt;
14692    xmlXPathCompExprPtr comp;
14693
14694#ifdef XPATH_STREAMING
14695    comp = xmlXPathTryStreamCompile(ctxt, str);
14696    if (comp != NULL)
14697        return(comp);
14698#endif
14699
14700    xmlXPathInit();
14701
14702    pctxt = xmlXPathNewParserContext(str, ctxt);
14703    if (pctxt == NULL)
14704        return NULL;
14705    xmlXPathCompileExpr(pctxt, 1);
14706
14707    if( pctxt->error != XPATH_EXPRESSION_OK )
14708    {
14709        xmlXPathFreeParserContext(pctxt);
14710        return(NULL);
14711    }
14712
14713    if (*pctxt->cur != 0) {
14714	/*
14715	 * aleksey: in some cases this line prints *second* error message
14716	 * (see bug #78858) and probably this should be fixed.
14717	 * However, we are not sure that all error messages are printed
14718	 * out in other places. It's not critical so we leave it as-is for now
14719	 */
14720	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14721	comp = NULL;
14722    } else {
14723	comp = pctxt->comp;
14724	pctxt->comp = NULL;
14725    }
14726    xmlXPathFreeParserContext(pctxt);
14727
14728    if (comp != NULL) {
14729	comp->expr = xmlStrdup(str);
14730#ifdef DEBUG_EVAL_COUNTS
14731	comp->string = xmlStrdup(str);
14732	comp->nb = 0;
14733#endif
14734	if ((comp->expr != NULL) &&
14735	    (comp->nbStep > 2) &&
14736	    (comp->last >= 0) &&
14737	    (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14738	{
14739	    xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14740	}
14741    }
14742    return(comp);
14743}
14744
14745/**
14746 * xmlXPathCompile:
14747 * @str:  the XPath expression
14748 *
14749 * Compile an XPath expression
14750 *
14751 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14752 *         the caller has to free the object.
14753 */
14754xmlXPathCompExprPtr
14755xmlXPathCompile(const xmlChar *str) {
14756    return(xmlXPathCtxtCompile(NULL, str));
14757}
14758
14759/**
14760 * xmlXPathCompiledEvalInternal:
14761 * @comp:  the compiled XPath expression
14762 * @ctxt:  the XPath context
14763 * @resObj: the resulting XPath object or NULL
14764 * @toBool: 1 if only a boolean result is requested
14765 *
14766 * Evaluate the Precompiled XPath expression in the given context.
14767 * The caller has to free @resObj.
14768 *
14769 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14770 *         the caller has to free the object.
14771 */
14772static int
14773xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14774			     xmlXPathContextPtr ctxt,
14775			     xmlXPathObjectPtr *resObj,
14776			     int toBool)
14777{
14778    xmlXPathParserContextPtr pctxt;
14779#ifndef LIBXML_THREAD_ENABLED
14780    static int reentance = 0;
14781#endif
14782    int res;
14783
14784    CHECK_CTXT_NEG(ctxt)
14785
14786    if (comp == NULL)
14787	return(-1);
14788    xmlXPathInit();
14789
14790#ifndef LIBXML_THREAD_ENABLED
14791    reentance++;
14792    if (reentance > 1)
14793	xmlXPathDisableOptimizer = 1;
14794#endif
14795
14796#ifdef DEBUG_EVAL_COUNTS
14797    comp->nb++;
14798    if ((comp->string != NULL) && (comp->nb > 100)) {
14799	fprintf(stderr, "100 x %s\n", comp->string);
14800	comp->nb = 0;
14801    }
14802#endif
14803    pctxt = xmlXPathCompParserContext(comp, ctxt);
14804    res = xmlXPathRunEval(pctxt, toBool);
14805
14806    if (resObj) {
14807	if (pctxt->value == NULL) {
14808	    xmlGenericError(xmlGenericErrorContext,
14809		"xmlXPathCompiledEval: evaluation failed\n");
14810	    *resObj = NULL;
14811	} else {
14812	    *resObj = valuePop(pctxt);
14813	}
14814    }
14815
14816    /*
14817    * Pop all remaining objects from the stack.
14818    */
14819    if (pctxt->valueNr > 0) {
14820	xmlXPathObjectPtr tmp;
14821	int stack = 0;
14822
14823	do {
14824	    tmp = valuePop(pctxt);
14825	    if (tmp != NULL) {
14826		stack++;
14827		xmlXPathReleaseObject(ctxt, tmp);
14828	    }
14829	} while (tmp != NULL);
14830	if ((stack != 0) &&
14831	    ((toBool) || ((resObj) && (*resObj))))
14832	{
14833	    xmlGenericError(xmlGenericErrorContext,
14834		"xmlXPathCompiledEval: %d objects left on the stack.\n",
14835		stack);
14836	}
14837    }
14838
14839    if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14840	xmlXPathFreeObject(*resObj);
14841	*resObj = NULL;
14842    }
14843    pctxt->comp = NULL;
14844    xmlXPathFreeParserContext(pctxt);
14845#ifndef LIBXML_THREAD_ENABLED
14846    reentance--;
14847#endif
14848
14849    return(res);
14850}
14851
14852/**
14853 * xmlXPathCompiledEval:
14854 * @comp:  the compiled XPath expression
14855 * @ctx:  the XPath context
14856 *
14857 * Evaluate the Precompiled XPath expression in the given context.
14858 *
14859 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14860 *         the caller has to free the object.
14861 */
14862xmlXPathObjectPtr
14863xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14864{
14865    xmlXPathObjectPtr res = NULL;
14866
14867    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14868    return(res);
14869}
14870
14871/**
14872 * xmlXPathCompiledEvalToBoolean:
14873 * @comp:  the compiled XPath expression
14874 * @ctxt:  the XPath context
14875 *
14876 * Applies the XPath boolean() function on the result of the given
14877 * compiled expression.
14878 *
14879 * Returns 1 if the expression evaluated to true, 0 if to false and
14880 *         -1 in API and internal errors.
14881 */
14882int
14883xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14884			      xmlXPathContextPtr ctxt)
14885{
14886    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14887}
14888
14889/**
14890 * xmlXPathEvalExpr:
14891 * @ctxt:  the XPath Parser context
14892 *
14893 * Parse and evaluate an XPath expression in the given context,
14894 * then push the result on the context stack
14895 */
14896void
14897xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14898#ifdef XPATH_STREAMING
14899    xmlXPathCompExprPtr comp;
14900#endif
14901
14902    if (ctxt == NULL) return;
14903
14904#ifdef XPATH_STREAMING
14905    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14906    if (comp != NULL) {
14907        if (ctxt->comp != NULL)
14908	    xmlXPathFreeCompExpr(ctxt->comp);
14909        ctxt->comp = comp;
14910	if (ctxt->cur != NULL)
14911	    while (*ctxt->cur != 0) ctxt->cur++;
14912    } else
14913#endif
14914    {
14915	xmlXPathCompileExpr(ctxt, 1);
14916	/*
14917	* In this scenario the expression string will sit in ctxt->base.
14918	*/
14919	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14920	    (ctxt->comp != NULL) &&
14921	    (ctxt->base != NULL) &&
14922	    (ctxt->comp->nbStep > 2) &&
14923	    (ctxt->comp->last >= 0) &&
14924	    (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14925	{
14926	    xmlXPathRewriteDOSExpression(ctxt->comp,
14927		&ctxt->comp->steps[ctxt->comp->last]);
14928	}
14929    }
14930    CHECK_ERROR;
14931    xmlXPathRunEval(ctxt, 0);
14932}
14933
14934/**
14935 * xmlXPathEval:
14936 * @str:  the XPath expression
14937 * @ctx:  the XPath context
14938 *
14939 * Evaluate the XPath Location Path in the given context.
14940 *
14941 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14942 *         the caller has to free the object.
14943 */
14944xmlXPathObjectPtr
14945xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14946    xmlXPathParserContextPtr ctxt;
14947    xmlXPathObjectPtr res, tmp, init = NULL;
14948    int stack = 0;
14949
14950    CHECK_CTXT(ctx)
14951
14952    xmlXPathInit();
14953
14954    ctxt = xmlXPathNewParserContext(str, ctx);
14955    if (ctxt == NULL)
14956        return NULL;
14957    xmlXPathEvalExpr(ctxt);
14958
14959    if (ctxt->value == NULL) {
14960	xmlGenericError(xmlGenericErrorContext,
14961		"xmlXPathEval: evaluation failed\n");
14962	res = NULL;
14963    } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14964#ifdef XPATH_STREAMING
14965            && (ctxt->comp->stream == NULL)
14966#endif
14967	      ) {
14968	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14969	res = NULL;
14970    } else {
14971	res = valuePop(ctxt);
14972    }
14973
14974    do {
14975        tmp = valuePop(ctxt);
14976	if (tmp != NULL) {
14977	    if (tmp != init)
14978		stack++;
14979	    xmlXPathReleaseObject(ctx, tmp);
14980        }
14981    } while (tmp != NULL);
14982    if ((stack != 0) && (res != NULL)) {
14983	xmlGenericError(xmlGenericErrorContext,
14984		"xmlXPathEval: %d object left on the stack\n",
14985	        stack);
14986    }
14987    if (ctxt->error != XPATH_EXPRESSION_OK) {
14988	xmlXPathFreeObject(res);
14989	res = NULL;
14990    }
14991
14992    xmlXPathFreeParserContext(ctxt);
14993    return(res);
14994}
14995
14996/**
14997 * xmlXPathEvalExpression:
14998 * @str:  the XPath expression
14999 * @ctxt:  the XPath context
15000 *
15001 * Evaluate the XPath expression in the given context.
15002 *
15003 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15004 *         the caller has to free the object.
15005 */
15006xmlXPathObjectPtr
15007xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15008    xmlXPathParserContextPtr pctxt;
15009    xmlXPathObjectPtr res, tmp;
15010    int stack = 0;
15011
15012    CHECK_CTXT(ctxt)
15013
15014    xmlXPathInit();
15015
15016    pctxt = xmlXPathNewParserContext(str, ctxt);
15017    if (pctxt == NULL)
15018        return NULL;
15019    xmlXPathEvalExpr(pctxt);
15020
15021    if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
15022	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15023	res = NULL;
15024    } else {
15025	res = valuePop(pctxt);
15026    }
15027    do {
15028        tmp = valuePop(pctxt);
15029	if (tmp != NULL) {
15030	    xmlXPathReleaseObject(ctxt, tmp);
15031	    stack++;
15032	}
15033    } while (tmp != NULL);
15034    if ((stack != 0) && (res != NULL)) {
15035	xmlGenericError(xmlGenericErrorContext,
15036		"xmlXPathEvalExpression: %d object left on the stack\n",
15037	        stack);
15038    }
15039    xmlXPathFreeParserContext(pctxt);
15040    return(res);
15041}
15042
15043/************************************************************************
15044 *									*
15045 *	Extra functions not pertaining to the XPath spec		*
15046 *									*
15047 ************************************************************************/
15048/**
15049 * xmlXPathEscapeUriFunction:
15050 * @ctxt:  the XPath Parser context
15051 * @nargs:  the number of arguments
15052 *
15053 * Implement the escape-uri() XPath function
15054 *    string escape-uri(string $str, bool $escape-reserved)
15055 *
15056 * This function applies the URI escaping rules defined in section 2 of [RFC
15057 * 2396] to the string supplied as $uri-part, which typically represents all
15058 * or part of a URI. The effect of the function is to replace any special
15059 * character in the string by an escape sequence of the form %xx%yy...,
15060 * where xxyy... is the hexadecimal representation of the octets used to
15061 * represent the character in UTF-8.
15062 *
15063 * The set of characters that are escaped depends on the setting of the
15064 * boolean argument $escape-reserved.
15065 *
15066 * If $escape-reserved is true, all characters are escaped other than lower
15067 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15068 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15069 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15070 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15071 * A-F).
15072 *
15073 * If $escape-reserved is false, the behavior differs in that characters
15074 * referred to in [RFC 2396] as reserved characters are not escaped. These
15075 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15076 *
15077 * [RFC 2396] does not define whether escaped URIs should use lower case or
15078 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15079 * compared using string comparison functions, this function must always use
15080 * the upper-case letters A-F.
15081 *
15082 * Generally, $escape-reserved should be set to true when escaping a string
15083 * that is to form a single part of a URI, and to false when escaping an
15084 * entire URI or URI reference.
15085 *
15086 * In the case of non-ascii characters, the string is encoded according to
15087 * utf-8 and then converted according to RFC 2396.
15088 *
15089 * Examples
15090 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15091 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15092 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15093 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15094 *
15095 */
15096static void
15097xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15098    xmlXPathObjectPtr str;
15099    int escape_reserved;
15100    xmlBufferPtr target;
15101    xmlChar *cptr;
15102    xmlChar escape[4];
15103
15104    CHECK_ARITY(2);
15105
15106    escape_reserved = xmlXPathPopBoolean(ctxt);
15107
15108    CAST_TO_STRING;
15109    str = valuePop(ctxt);
15110
15111    target = xmlBufferCreate();
15112
15113    escape[0] = '%';
15114    escape[3] = 0;
15115
15116    if (target) {
15117	for (cptr = str->stringval; *cptr; cptr++) {
15118	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
15119		(*cptr >= 'a' && *cptr <= 'z') ||
15120		(*cptr >= '0' && *cptr <= '9') ||
15121		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
15122		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
15123		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15124		(*cptr == '%' &&
15125		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15126		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15127		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
15128		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15129		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15130		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15131		(!escape_reserved &&
15132		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15133		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15134		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15135		  *cptr == ','))) {
15136		xmlBufferAdd(target, cptr, 1);
15137	    } else {
15138		if ((*cptr >> 4) < 10)
15139		    escape[1] = '0' + (*cptr >> 4);
15140		else
15141		    escape[1] = 'A' - 10 + (*cptr >> 4);
15142		if ((*cptr & 0xF) < 10)
15143		    escape[2] = '0' + (*cptr & 0xF);
15144		else
15145		    escape[2] = 'A' - 10 + (*cptr & 0xF);
15146
15147		xmlBufferAdd(target, &escape[0], 3);
15148	    }
15149	}
15150    }
15151    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15152	xmlBufferContent(target)));
15153    xmlBufferFree(target);
15154    xmlXPathReleaseObject(ctxt->context, str);
15155}
15156
15157/**
15158 * xmlXPathRegisterAllFunctions:
15159 * @ctxt:  the XPath context
15160 *
15161 * Registers all default XPath functions in this context
15162 */
15163void
15164xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15165{
15166    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15167                         xmlXPathBooleanFunction);
15168    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15169                         xmlXPathCeilingFunction);
15170    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15171                         xmlXPathCountFunction);
15172    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15173                         xmlXPathConcatFunction);
15174    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15175                         xmlXPathContainsFunction);
15176    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15177                         xmlXPathIdFunction);
15178    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15179                         xmlXPathFalseFunction);
15180    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15181                         xmlXPathFloorFunction);
15182    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15183                         xmlXPathLastFunction);
15184    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15185                         xmlXPathLangFunction);
15186    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15187                         xmlXPathLocalNameFunction);
15188    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15189                         xmlXPathNotFunction);
15190    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15191                         xmlXPathNameFunction);
15192    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15193                         xmlXPathNamespaceURIFunction);
15194    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15195                         xmlXPathNormalizeFunction);
15196    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15197                         xmlXPathNumberFunction);
15198    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15199                         xmlXPathPositionFunction);
15200    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15201                         xmlXPathRoundFunction);
15202    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15203                         xmlXPathStringFunction);
15204    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15205                         xmlXPathStringLengthFunction);
15206    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15207                         xmlXPathStartsWithFunction);
15208    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15209                         xmlXPathSubstringFunction);
15210    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15211                         xmlXPathSubstringBeforeFunction);
15212    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15213                         xmlXPathSubstringAfterFunction);
15214    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15215                         xmlXPathSumFunction);
15216    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15217                         xmlXPathTrueFunction);
15218    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15219                         xmlXPathTranslateFunction);
15220
15221    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15222	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15223                         xmlXPathEscapeUriFunction);
15224}
15225
15226#endif /* LIBXML_XPATH_ENABLED */
15227#define bottom_xpath
15228#include "elfgcchack.h"
15229