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    "?? Unknown error ??\n"	/* Must be last in the list! */
256};
257#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
258		   sizeof(xmlXPathErrorMessages[0])) - 1)
259/**
260 * xmlXPathErrMemory:
261 * @ctxt:  an XPath context
262 * @extra:  extra informations
263 *
264 * Handle a redefinition of attribute error
265 */
266static void
267xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
268{
269    if (ctxt != NULL) {
270        if (extra) {
271            xmlChar buf[200];
272
273            xmlStrPrintf(buf, 200,
274                         BAD_CAST "Memory allocation failed : %s\n",
275                         extra);
276            ctxt->lastError.message = (char *) xmlStrdup(buf);
277        } else {
278            ctxt->lastError.message = (char *)
279	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
280        }
281        ctxt->lastError.domain = XML_FROM_XPATH;
282        ctxt->lastError.code = XML_ERR_NO_MEMORY;
283	if (ctxt->error != NULL)
284	    ctxt->error(ctxt->userData, &ctxt->lastError);
285    } else {
286        if (extra)
287            __xmlRaiseError(NULL, NULL, NULL,
288                            NULL, NULL, XML_FROM_XPATH,
289                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
290                            extra, NULL, NULL, 0, 0,
291                            "Memory allocation failed : %s\n", extra);
292        else
293            __xmlRaiseError(NULL, NULL, NULL,
294                            NULL, NULL, XML_FROM_XPATH,
295                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
296                            NULL, NULL, NULL, 0, 0,
297                            "Memory allocation failed\n");
298    }
299}
300
301/**
302 * xmlXPathPErrMemory:
303 * @ctxt:  an XPath parser context
304 * @extra:  extra informations
305 *
306 * Handle a redefinition of attribute error
307 */
308static void
309xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
310{
311    if (ctxt == NULL)
312	xmlXPathErrMemory(NULL, extra);
313    else {
314	ctxt->error = XPATH_MEMORY_ERROR;
315	xmlXPathErrMemory(ctxt->context, extra);
316    }
317}
318
319/**
320 * xmlXPathErr:
321 * @ctxt:  a XPath parser context
322 * @error:  the error code
323 *
324 * Handle an XPath error
325 */
326void
327xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
328{
329    if ((error < 0) || (error > MAXERRNO))
330	error = MAXERRNO;
331    if (ctxt == NULL) {
332	__xmlRaiseError(NULL, NULL, NULL,
333			NULL, NULL, XML_FROM_XPATH,
334			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
335			XML_ERR_ERROR, NULL, 0,
336			NULL, NULL, NULL, 0, 0,
337			"%s", xmlXPathErrorMessages[error]);
338	return;
339    }
340    ctxt->error = error;
341    if (ctxt->context == NULL) {
342	__xmlRaiseError(NULL, NULL, NULL,
343			NULL, NULL, XML_FROM_XPATH,
344			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
345			XML_ERR_ERROR, NULL, 0,
346			(const char *) ctxt->base, NULL, NULL,
347			ctxt->cur - ctxt->base, 0,
348			"%s", xmlXPathErrorMessages[error]);
349	return;
350    }
351
352    /* cleanup current last error */
353    xmlResetError(&ctxt->context->lastError);
354
355    ctxt->context->lastError.domain = XML_FROM_XPATH;
356    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
357                           XPATH_EXPRESSION_OK;
358    ctxt->context->lastError.level = XML_ERR_ERROR;
359    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
360    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
361    ctxt->context->lastError.node = ctxt->context->debugNode;
362    if (ctxt->context->error != NULL) {
363	ctxt->context->error(ctxt->context->userData,
364	                     &ctxt->context->lastError);
365    } else {
366	__xmlRaiseError(NULL, NULL, NULL,
367			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
368			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
369			XML_ERR_ERROR, NULL, 0,
370			(const char *) ctxt->base, NULL, NULL,
371			ctxt->cur - ctxt->base, 0,
372			"%s", xmlXPathErrorMessages[error]);
373    }
374
375}
376
377/**
378 * xmlXPatherror:
379 * @ctxt:  the XPath Parser context
380 * @file:  the file name
381 * @line:  the line number
382 * @no:  the error number
383 *
384 * Formats an error message.
385 */
386void
387xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
388              int line ATTRIBUTE_UNUSED, int no) {
389    xmlXPathErr(ctxt, no);
390}
391
392/************************************************************************
393 *									*
394 *			Utilities					*
395 *									*
396 ************************************************************************/
397
398/**
399 * xsltPointerList:
400 *
401 * Pointer-list for various purposes.
402 */
403typedef struct _xmlPointerList xmlPointerList;
404typedef xmlPointerList *xmlPointerListPtr;
405struct _xmlPointerList {
406    void **items;
407    int number;
408    int size;
409};
410/*
411* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
412* and here, we should make the functions public.
413*/
414static int
415xmlPointerListAddSize(xmlPointerListPtr list,
416		       void *item,
417		       int initialSize)
418{
419    if (list->items == NULL) {
420	if (initialSize <= 0)
421	    initialSize = 1;
422	list->items = (void **) xmlMalloc(
423	    initialSize * sizeof(void *));
424	if (list->items == NULL) {
425	    xmlXPathErrMemory(NULL,
426		"xmlPointerListCreate: allocating item\n");
427	    return(-1);
428	}
429	list->number = 0;
430	list->size = initialSize;
431    } else if (list->size <= list->number) {
432	list->size *= 2;
433	list->items = (void **) xmlRealloc(list->items,
434	    list->size * sizeof(void *));
435	if (list->items == NULL) {
436	    xmlXPathErrMemory(NULL,
437		"xmlPointerListCreate: re-allocating item\n");
438	    list->size = 0;
439	    return(-1);
440	}
441    }
442    list->items[list->number++] = item;
443    return(0);
444}
445
446/**
447 * xsltPointerListCreate:
448 *
449 * Creates an xsltPointerList structure.
450 *
451 * Returns a xsltPointerList structure or NULL in case of an error.
452 */
453static xmlPointerListPtr
454xmlPointerListCreate(int initialSize)
455{
456    xmlPointerListPtr ret;
457
458    ret = xmlMalloc(sizeof(xmlPointerList));
459    if (ret == NULL) {
460	xmlXPathErrMemory(NULL,
461	    "xmlPointerListCreate: allocating item\n");
462	return (NULL);
463    }
464    memset(ret, 0, sizeof(xmlPointerList));
465    if (initialSize > 0) {
466	xmlPointerListAddSize(ret, NULL, initialSize);
467	ret->number = 0;
468    }
469    return (ret);
470}
471
472/**
473 * xsltPointerListFree:
474 *
475 * Frees the xsltPointerList structure. This does not free
476 * the content of the list.
477 */
478static void
479xmlPointerListFree(xmlPointerListPtr list)
480{
481    if (list == NULL)
482	return;
483    if (list->items != NULL)
484	xmlFree(list->items);
485    xmlFree(list);
486}
487
488/************************************************************************
489 *									*
490 *			Parser Types					*
491 *									*
492 ************************************************************************/
493
494/*
495 * Types are private:
496 */
497
498typedef enum {
499    XPATH_OP_END=0,
500    XPATH_OP_AND,
501    XPATH_OP_OR,
502    XPATH_OP_EQUAL,
503    XPATH_OP_CMP,
504    XPATH_OP_PLUS,
505    XPATH_OP_MULT,
506    XPATH_OP_UNION,
507    XPATH_OP_ROOT,
508    XPATH_OP_NODE,
509    XPATH_OP_RESET, /* 10 */
510    XPATH_OP_COLLECT,
511    XPATH_OP_VALUE, /* 12 */
512    XPATH_OP_VARIABLE,
513    XPATH_OP_FUNCTION,
514    XPATH_OP_ARG,
515    XPATH_OP_PREDICATE,
516    XPATH_OP_FILTER, /* 17 */
517    XPATH_OP_SORT /* 18 */
518#ifdef LIBXML_XPTR_ENABLED
519    ,XPATH_OP_RANGETO
520#endif
521} xmlXPathOp;
522
523typedef enum {
524    AXIS_ANCESTOR = 1,
525    AXIS_ANCESTOR_OR_SELF,
526    AXIS_ATTRIBUTE,
527    AXIS_CHILD,
528    AXIS_DESCENDANT,
529    AXIS_DESCENDANT_OR_SELF,
530    AXIS_FOLLOWING,
531    AXIS_FOLLOWING_SIBLING,
532    AXIS_NAMESPACE,
533    AXIS_PARENT,
534    AXIS_PRECEDING,
535    AXIS_PRECEDING_SIBLING,
536    AXIS_SELF
537} xmlXPathAxisVal;
538
539typedef enum {
540    NODE_TEST_NONE = 0,
541    NODE_TEST_TYPE = 1,
542    NODE_TEST_PI = 2,
543    NODE_TEST_ALL = 3,
544    NODE_TEST_NS = 4,
545    NODE_TEST_NAME = 5
546} xmlXPathTestVal;
547
548typedef enum {
549    NODE_TYPE_NODE = 0,
550    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
551    NODE_TYPE_TEXT = XML_TEXT_NODE,
552    NODE_TYPE_PI = XML_PI_NODE
553} xmlXPathTypeVal;
554
555#define XP_REWRITE_DOS_CHILD_ELEM 1
556
557typedef struct _xmlXPathStepOp xmlXPathStepOp;
558typedef xmlXPathStepOp *xmlXPathStepOpPtr;
559struct _xmlXPathStepOp {
560    xmlXPathOp op;		/* The identifier of the operation */
561    int ch1;			/* First child */
562    int ch2;			/* Second child */
563    int value;
564    int value2;
565    int value3;
566    void *value4;
567    void *value5;
568    void *cache;
569    void *cacheURI;
570    int rewriteType;
571};
572
573struct _xmlXPathCompExpr {
574    int nbStep;			/* Number of steps in this expression */
575    int maxStep;		/* Maximum number of steps allocated */
576    xmlXPathStepOp *steps;	/* ops for computation of this expression */
577    int last;			/* index of last step in expression */
578    xmlChar *expr;		/* the expression being computed */
579    xmlDictPtr dict;		/* the dictionnary to use if any */
580#ifdef DEBUG_EVAL_COUNTS
581    int nb;
582    xmlChar *string;
583#endif
584#ifdef XPATH_STREAMING
585    xmlPatternPtr stream;
586#endif
587};
588
589/************************************************************************
590 *									*
591 *			Forward declarations				*
592 *									*
593 ************************************************************************/
594static void
595xmlXPathFreeValueTree(xmlNodeSetPtr obj);
596static void
597xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
598static int
599xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
600                        xmlXPathStepOpPtr op, xmlNodePtr *first);
601static int
602xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
603			    xmlXPathStepOpPtr op,
604			    int isPredicate);
605
606/************************************************************************
607 *									*
608 *			Parser Type functions				*
609 *									*
610 ************************************************************************/
611
612/**
613 * xmlXPathNewCompExpr:
614 *
615 * Create a new Xpath component
616 *
617 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
618 */
619static xmlXPathCompExprPtr
620xmlXPathNewCompExpr(void) {
621    xmlXPathCompExprPtr cur;
622
623    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
624    if (cur == NULL) {
625        xmlXPathErrMemory(NULL, "allocating component\n");
626	return(NULL);
627    }
628    memset(cur, 0, sizeof(xmlXPathCompExpr));
629    cur->maxStep = 10;
630    cur->nbStep = 0;
631    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
632	                                   sizeof(xmlXPathStepOp));
633    if (cur->steps == NULL) {
634        xmlXPathErrMemory(NULL, "allocating steps\n");
635	xmlFree(cur);
636	return(NULL);
637    }
638    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
639    cur->last = -1;
640#ifdef DEBUG_EVAL_COUNTS
641    cur->nb = 0;
642#endif
643    return(cur);
644}
645
646/**
647 * xmlXPathFreeCompExpr:
648 * @comp:  an XPATH comp
649 *
650 * Free up the memory allocated by @comp
651 */
652void
653xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
654{
655    xmlXPathStepOpPtr op;
656    int i;
657
658    if (comp == NULL)
659        return;
660    if (comp->dict == NULL) {
661	for (i = 0; i < comp->nbStep; i++) {
662	    op = &comp->steps[i];
663	    if (op->value4 != NULL) {
664		if (op->op == XPATH_OP_VALUE)
665		    xmlXPathFreeObject(op->value4);
666		else
667		    xmlFree(op->value4);
668	    }
669	    if (op->value5 != NULL)
670		xmlFree(op->value5);
671	}
672    } else {
673	for (i = 0; i < comp->nbStep; i++) {
674	    op = &comp->steps[i];
675	    if (op->value4 != NULL) {
676		if (op->op == XPATH_OP_VALUE)
677		    xmlXPathFreeObject(op->value4);
678	    }
679	}
680        xmlDictFree(comp->dict);
681    }
682    if (comp->steps != NULL) {
683        xmlFree(comp->steps);
684    }
685#ifdef DEBUG_EVAL_COUNTS
686    if (comp->string != NULL) {
687        xmlFree(comp->string);
688    }
689#endif
690#ifdef XPATH_STREAMING
691    if (comp->stream != NULL) {
692        xmlFreePatternList(comp->stream);
693    }
694#endif
695    if (comp->expr != NULL) {
696        xmlFree(comp->expr);
697    }
698
699    xmlFree(comp);
700}
701
702/**
703 * xmlXPathCompExprAdd:
704 * @comp:  the compiled expression
705 * @ch1: first child index
706 * @ch2: second child index
707 * @op:  an op
708 * @value:  the first int value
709 * @value2:  the second int value
710 * @value3:  the third int value
711 * @value4:  the first string value
712 * @value5:  the second string value
713 *
714 * Add a step to an XPath Compiled Expression
715 *
716 * Returns -1 in case of failure, the index otherwise
717 */
718static int
719xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
720   xmlXPathOp op, int value,
721   int value2, int value3, void *value4, void *value5) {
722    if (comp->nbStep >= comp->maxStep) {
723	xmlXPathStepOp *real;
724
725	comp->maxStep *= 2;
726	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
727		                      comp->maxStep * sizeof(xmlXPathStepOp));
728	if (real == NULL) {
729	    comp->maxStep /= 2;
730	    xmlXPathErrMemory(NULL, "adding step\n");
731	    return(-1);
732	}
733	comp->steps = real;
734    }
735    comp->last = comp->nbStep;
736    comp->steps[comp->nbStep].rewriteType = 0;
737    comp->steps[comp->nbStep].ch1 = ch1;
738    comp->steps[comp->nbStep].ch2 = ch2;
739    comp->steps[comp->nbStep].op = op;
740    comp->steps[comp->nbStep].value = value;
741    comp->steps[comp->nbStep].value2 = value2;
742    comp->steps[comp->nbStep].value3 = value3;
743    if ((comp->dict != NULL) &&
744        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
745	 (op == XPATH_OP_COLLECT))) {
746        if (value4 != NULL) {
747	    comp->steps[comp->nbStep].value4 = (xmlChar *)
748	        (void *)xmlDictLookup(comp->dict, value4, -1);
749	    xmlFree(value4);
750	} else
751	    comp->steps[comp->nbStep].value4 = NULL;
752        if (value5 != NULL) {
753	    comp->steps[comp->nbStep].value5 = (xmlChar *)
754	        (void *)xmlDictLookup(comp->dict, value5, -1);
755	    xmlFree(value5);
756	} else
757	    comp->steps[comp->nbStep].value5 = NULL;
758    } else {
759	comp->steps[comp->nbStep].value4 = value4;
760	comp->steps[comp->nbStep].value5 = value5;
761    }
762    comp->steps[comp->nbStep].cache = NULL;
763    return(comp->nbStep++);
764}
765
766/**
767 * xmlXPathCompSwap:
768 * @comp:  the compiled expression
769 * @op: operation index
770 *
771 * Swaps 2 operations in the compiled expression
772 */
773static void
774xmlXPathCompSwap(xmlXPathStepOpPtr op) {
775    int tmp;
776
777#ifndef LIBXML_THREAD_ENABLED
778    /*
779     * Since this manipulates possibly shared variables, this is
780     * disabled if one detects that the library is used in a multithreaded
781     * application
782     */
783    if (xmlXPathDisableOptimizer)
784	return;
785#endif
786
787    tmp = op->ch1;
788    op->ch1 = op->ch2;
789    op->ch2 = tmp;
790}
791
792#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
793    xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
794	                (op), (val), (val2), (val3), (val4), (val5))
795#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
796    xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
797	                (op), (val), (val2), (val3), (val4), (val5))
798
799#define PUSH_LEAVE_EXPR(op, val, val2)					\
800xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
801
802#define PUSH_UNARY_EXPR(op, ch, val, val2)				\
803xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
804
805#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
806xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
807			(val), (val2), 0 ,NULL ,NULL)
808
809/************************************************************************
810 *									*
811 *		XPath object cache structures				*
812 *									*
813 ************************************************************************/
814
815/* #define XP_DEFAULT_CACHE_ON */
816
817#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
818
819typedef struct _xmlXPathContextCache xmlXPathContextCache;
820typedef xmlXPathContextCache *xmlXPathContextCachePtr;
821struct _xmlXPathContextCache {
822    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
823    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
824    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
825    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
826    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
827    int maxNodeset;
828    int maxString;
829    int maxBoolean;
830    int maxNumber;
831    int maxMisc;
832#ifdef XP_DEBUG_OBJ_USAGE
833    int dbgCachedAll;
834    int dbgCachedNodeset;
835    int dbgCachedString;
836    int dbgCachedBool;
837    int dbgCachedNumber;
838    int dbgCachedPoint;
839    int dbgCachedRange;
840    int dbgCachedLocset;
841    int dbgCachedUsers;
842    int dbgCachedXSLTTree;
843    int dbgCachedUndefined;
844
845
846    int dbgReusedAll;
847    int dbgReusedNodeset;
848    int dbgReusedString;
849    int dbgReusedBool;
850    int dbgReusedNumber;
851    int dbgReusedPoint;
852    int dbgReusedRange;
853    int dbgReusedLocset;
854    int dbgReusedUsers;
855    int dbgReusedXSLTTree;
856    int dbgReusedUndefined;
857
858#endif
859};
860
861/************************************************************************
862 *									*
863 *		Debugging related functions				*
864 *									*
865 ************************************************************************/
866
867#define STRANGE							\
868    xmlGenericError(xmlGenericErrorContext,				\
869	    "Internal error at %s:%d\n",				\
870            __FILE__, __LINE__);
871
872#ifdef LIBXML_DEBUG_ENABLED
873static void
874xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
875    int i;
876    char shift[100];
877
878    for (i = 0;((i < depth) && (i < 25));i++)
879        shift[2 * i] = shift[2 * i + 1] = ' ';
880    shift[2 * i] = shift[2 * i + 1] = 0;
881    if (cur == NULL) {
882	fprintf(output, "%s", shift);
883	fprintf(output, "Node is NULL !\n");
884	return;
885
886    }
887
888    if ((cur->type == XML_DOCUMENT_NODE) ||
889	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
890	fprintf(output, "%s", shift);
891	fprintf(output, " /\n");
892    } else if (cur->type == XML_ATTRIBUTE_NODE)
893	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
894    else
895	xmlDebugDumpOneNode(output, cur, depth);
896}
897static void
898xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
899    xmlNodePtr tmp;
900    int i;
901    char shift[100];
902
903    for (i = 0;((i < depth) && (i < 25));i++)
904        shift[2 * i] = shift[2 * i + 1] = ' ';
905    shift[2 * i] = shift[2 * i + 1] = 0;
906    if (cur == NULL) {
907	fprintf(output, "%s", shift);
908	fprintf(output, "Node is NULL !\n");
909	return;
910
911    }
912
913    while (cur != NULL) {
914	tmp = cur;
915	cur = cur->next;
916	xmlDebugDumpOneNode(output, tmp, depth);
917    }
918}
919
920static void
921xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
922    int i;
923    char shift[100];
924
925    for (i = 0;((i < depth) && (i < 25));i++)
926        shift[2 * i] = shift[2 * i + 1] = ' ';
927    shift[2 * i] = shift[2 * i + 1] = 0;
928
929    if (cur == NULL) {
930	fprintf(output, "%s", shift);
931	fprintf(output, "NodeSet is NULL !\n");
932	return;
933
934    }
935
936    if (cur != NULL) {
937	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
938	for (i = 0;i < cur->nodeNr;i++) {
939	    fprintf(output, "%s", shift);
940	    fprintf(output, "%d", i + 1);
941	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
942	}
943    }
944}
945
946static void
947xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
948    int i;
949    char shift[100];
950
951    for (i = 0;((i < depth) && (i < 25));i++)
952        shift[2 * i] = shift[2 * i + 1] = ' ';
953    shift[2 * i] = shift[2 * i + 1] = 0;
954
955    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
956	fprintf(output, "%s", shift);
957	fprintf(output, "Value Tree is NULL !\n");
958	return;
959
960    }
961
962    fprintf(output, "%s", shift);
963    fprintf(output, "%d", i + 1);
964    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
965}
966#if defined(LIBXML_XPTR_ENABLED)
967static void
968xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
969    int i;
970    char shift[100];
971
972    for (i = 0;((i < depth) && (i < 25));i++)
973        shift[2 * i] = shift[2 * i + 1] = ' ';
974    shift[2 * i] = shift[2 * i + 1] = 0;
975
976    if (cur == NULL) {
977	fprintf(output, "%s", shift);
978	fprintf(output, "LocationSet is NULL !\n");
979	return;
980
981    }
982
983    for (i = 0;i < cur->locNr;i++) {
984	fprintf(output, "%s", shift);
985        fprintf(output, "%d : ", i + 1);
986	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
987    }
988}
989#endif /* LIBXML_XPTR_ENABLED */
990
991/**
992 * xmlXPathDebugDumpObject:
993 * @output:  the FILE * to dump the output
994 * @cur:  the object to inspect
995 * @depth:  indentation level
996 *
997 * Dump the content of the object for debugging purposes
998 */
999void
1000xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1001    int i;
1002    char shift[100];
1003
1004    if (output == NULL) return;
1005
1006    for (i = 0;((i < depth) && (i < 25));i++)
1007        shift[2 * i] = shift[2 * i + 1] = ' ';
1008    shift[2 * i] = shift[2 * i + 1] = 0;
1009
1010
1011    fprintf(output, "%s", shift);
1012
1013    if (cur == NULL) {
1014        fprintf(output, "Object is empty (NULL)\n");
1015	return;
1016    }
1017    switch(cur->type) {
1018        case XPATH_UNDEFINED:
1019	    fprintf(output, "Object is uninitialized\n");
1020	    break;
1021        case XPATH_NODESET:
1022	    fprintf(output, "Object is a Node Set :\n");
1023	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1024	    break;
1025	case XPATH_XSLT_TREE:
1026	    fprintf(output, "Object is an XSLT value tree :\n");
1027	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1028	    break;
1029        case XPATH_BOOLEAN:
1030	    fprintf(output, "Object is a Boolean : ");
1031	    if (cur->boolval) fprintf(output, "true\n");
1032	    else fprintf(output, "false\n");
1033	    break;
1034        case XPATH_NUMBER:
1035	    switch (xmlXPathIsInf(cur->floatval)) {
1036	    case 1:
1037		fprintf(output, "Object is a number : Infinity\n");
1038		break;
1039	    case -1:
1040		fprintf(output, "Object is a number : -Infinity\n");
1041		break;
1042	    default:
1043		if (xmlXPathIsNaN(cur->floatval)) {
1044		    fprintf(output, "Object is a number : NaN\n");
1045		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1046		    fprintf(output, "Object is a number : 0\n");
1047		} else {
1048		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1049		}
1050	    }
1051	    break;
1052        case XPATH_STRING:
1053	    fprintf(output, "Object is a string : ");
1054	    xmlDebugDumpString(output, cur->stringval);
1055	    fprintf(output, "\n");
1056	    break;
1057	case XPATH_POINT:
1058	    fprintf(output, "Object is a point : index %d in node", cur->index);
1059	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1060	    fprintf(output, "\n");
1061	    break;
1062	case XPATH_RANGE:
1063	    if ((cur->user2 == NULL) ||
1064		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1065		fprintf(output, "Object is a collapsed range :\n");
1066		fprintf(output, "%s", shift);
1067		if (cur->index >= 0)
1068		    fprintf(output, "index %d in ", cur->index);
1069		fprintf(output, "node\n");
1070		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1071			              depth + 1);
1072	    } else  {
1073		fprintf(output, "Object is a range :\n");
1074		fprintf(output, "%s", shift);
1075		fprintf(output, "From ");
1076		if (cur->index >= 0)
1077		    fprintf(output, "index %d in ", cur->index);
1078		fprintf(output, "node\n");
1079		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1080			              depth + 1);
1081		fprintf(output, "%s", shift);
1082		fprintf(output, "To ");
1083		if (cur->index2 >= 0)
1084		    fprintf(output, "index %d in ", cur->index2);
1085		fprintf(output, "node\n");
1086		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1087			              depth + 1);
1088		fprintf(output, "\n");
1089	    }
1090	    break;
1091	case XPATH_LOCATIONSET:
1092#if defined(LIBXML_XPTR_ENABLED)
1093	    fprintf(output, "Object is a Location Set:\n");
1094	    xmlXPathDebugDumpLocationSet(output,
1095		    (xmlLocationSetPtr) cur->user, depth);
1096#endif
1097	    break;
1098	case XPATH_USERS:
1099	    fprintf(output, "Object is user defined\n");
1100	    break;
1101    }
1102}
1103
1104static void
1105xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1106	                     xmlXPathStepOpPtr op, int depth) {
1107    int i;
1108    char shift[100];
1109
1110    for (i = 0;((i < depth) && (i < 25));i++)
1111        shift[2 * i] = shift[2 * i + 1] = ' ';
1112    shift[2 * i] = shift[2 * i + 1] = 0;
1113
1114    fprintf(output, "%s", shift);
1115    if (op == NULL) {
1116	fprintf(output, "Step is NULL\n");
1117	return;
1118    }
1119    switch (op->op) {
1120        case XPATH_OP_END:
1121	    fprintf(output, "END"); break;
1122        case XPATH_OP_AND:
1123	    fprintf(output, "AND"); break;
1124        case XPATH_OP_OR:
1125	    fprintf(output, "OR"); break;
1126        case XPATH_OP_EQUAL:
1127	     if (op->value)
1128		 fprintf(output, "EQUAL =");
1129	     else
1130		 fprintf(output, "EQUAL !=");
1131	     break;
1132        case XPATH_OP_CMP:
1133	     if (op->value)
1134		 fprintf(output, "CMP <");
1135	     else
1136		 fprintf(output, "CMP >");
1137	     if (!op->value2)
1138		 fprintf(output, "=");
1139	     break;
1140        case XPATH_OP_PLUS:
1141	     if (op->value == 0)
1142		 fprintf(output, "PLUS -");
1143	     else if (op->value == 1)
1144		 fprintf(output, "PLUS +");
1145	     else if (op->value == 2)
1146		 fprintf(output, "PLUS unary -");
1147	     else if (op->value == 3)
1148		 fprintf(output, "PLUS unary - -");
1149	     break;
1150        case XPATH_OP_MULT:
1151	     if (op->value == 0)
1152		 fprintf(output, "MULT *");
1153	     else if (op->value == 1)
1154		 fprintf(output, "MULT div");
1155	     else
1156		 fprintf(output, "MULT mod");
1157	     break;
1158        case XPATH_OP_UNION:
1159	     fprintf(output, "UNION"); break;
1160        case XPATH_OP_ROOT:
1161	     fprintf(output, "ROOT"); break;
1162        case XPATH_OP_NODE:
1163	     fprintf(output, "NODE"); break;
1164        case XPATH_OP_RESET:
1165	     fprintf(output, "RESET"); break;
1166        case XPATH_OP_SORT:
1167	     fprintf(output, "SORT"); break;
1168        case XPATH_OP_COLLECT: {
1169	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1170	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1171	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1172	    const xmlChar *prefix = op->value4;
1173	    const xmlChar *name = op->value5;
1174
1175	    fprintf(output, "COLLECT ");
1176	    switch (axis) {
1177		case AXIS_ANCESTOR:
1178		    fprintf(output, " 'ancestors' "); break;
1179		case AXIS_ANCESTOR_OR_SELF:
1180		    fprintf(output, " 'ancestors-or-self' "); break;
1181		case AXIS_ATTRIBUTE:
1182		    fprintf(output, " 'attributes' "); break;
1183		case AXIS_CHILD:
1184		    fprintf(output, " 'child' "); break;
1185		case AXIS_DESCENDANT:
1186		    fprintf(output, " 'descendant' "); break;
1187		case AXIS_DESCENDANT_OR_SELF:
1188		    fprintf(output, " 'descendant-or-self' "); break;
1189		case AXIS_FOLLOWING:
1190		    fprintf(output, " 'following' "); break;
1191		case AXIS_FOLLOWING_SIBLING:
1192		    fprintf(output, " 'following-siblings' "); break;
1193		case AXIS_NAMESPACE:
1194		    fprintf(output, " 'namespace' "); break;
1195		case AXIS_PARENT:
1196		    fprintf(output, " 'parent' "); break;
1197		case AXIS_PRECEDING:
1198		    fprintf(output, " 'preceding' "); break;
1199		case AXIS_PRECEDING_SIBLING:
1200		    fprintf(output, " 'preceding-sibling' "); break;
1201		case AXIS_SELF:
1202		    fprintf(output, " 'self' "); break;
1203	    }
1204	    switch (test) {
1205                case NODE_TEST_NONE:
1206		    fprintf(output, "'none' "); break;
1207                case NODE_TEST_TYPE:
1208		    fprintf(output, "'type' "); break;
1209                case NODE_TEST_PI:
1210		    fprintf(output, "'PI' "); break;
1211                case NODE_TEST_ALL:
1212		    fprintf(output, "'all' "); break;
1213                case NODE_TEST_NS:
1214		    fprintf(output, "'namespace' "); break;
1215                case NODE_TEST_NAME:
1216		    fprintf(output, "'name' "); break;
1217	    }
1218	    switch (type) {
1219                case NODE_TYPE_NODE:
1220		    fprintf(output, "'node' "); break;
1221                case NODE_TYPE_COMMENT:
1222		    fprintf(output, "'comment' "); break;
1223                case NODE_TYPE_TEXT:
1224		    fprintf(output, "'text' "); break;
1225                case NODE_TYPE_PI:
1226		    fprintf(output, "'PI' "); break;
1227	    }
1228	    if (prefix != NULL)
1229		fprintf(output, "%s:", prefix);
1230	    if (name != NULL)
1231		fprintf(output, "%s", (const char *) name);
1232	    break;
1233
1234        }
1235	case XPATH_OP_VALUE: {
1236	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1237
1238	    fprintf(output, "ELEM ");
1239	    xmlXPathDebugDumpObject(output, object, 0);
1240	    goto finish;
1241	}
1242	case XPATH_OP_VARIABLE: {
1243	    const xmlChar *prefix = op->value5;
1244	    const xmlChar *name = op->value4;
1245
1246	    if (prefix != NULL)
1247		fprintf(output, "VARIABLE %s:%s", prefix, name);
1248	    else
1249		fprintf(output, "VARIABLE %s", name);
1250	    break;
1251	}
1252	case XPATH_OP_FUNCTION: {
1253	    int nbargs = op->value;
1254	    const xmlChar *prefix = op->value5;
1255	    const xmlChar *name = op->value4;
1256
1257	    if (prefix != NULL)
1258		fprintf(output, "FUNCTION %s:%s(%d args)",
1259			prefix, name, nbargs);
1260	    else
1261		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1262	    break;
1263	}
1264        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1265        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1266        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1267#ifdef LIBXML_XPTR_ENABLED
1268        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1269#endif
1270	default:
1271        fprintf(output, "UNKNOWN %d\n", op->op); return;
1272    }
1273    fprintf(output, "\n");
1274finish:
1275    if (op->ch1 >= 0)
1276	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1277    if (op->ch2 >= 0)
1278	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1279}
1280
1281/**
1282 * xmlXPathDebugDumpCompExpr:
1283 * @output:  the FILE * for the output
1284 * @comp:  the precompiled XPath expression
1285 * @depth:  the indentation level.
1286 *
1287 * Dumps the tree of the compiled XPath expression.
1288 */
1289void
1290xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1291	                  int depth) {
1292    int i;
1293    char shift[100];
1294
1295    if ((output == NULL) || (comp == NULL)) return;
1296
1297    for (i = 0;((i < depth) && (i < 25));i++)
1298        shift[2 * i] = shift[2 * i + 1] = ' ';
1299    shift[2 * i] = shift[2 * i + 1] = 0;
1300
1301    fprintf(output, "%s", shift);
1302
1303    fprintf(output, "Compiled Expression : %d elements\n",
1304	    comp->nbStep);
1305    i = comp->last;
1306    xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1307}
1308
1309#ifdef XP_DEBUG_OBJ_USAGE
1310
1311/*
1312* XPath object usage related debugging variables.
1313*/
1314static int xmlXPathDebugObjCounterUndefined = 0;
1315static int xmlXPathDebugObjCounterNodeset = 0;
1316static int xmlXPathDebugObjCounterBool = 0;
1317static int xmlXPathDebugObjCounterNumber = 0;
1318static int xmlXPathDebugObjCounterString = 0;
1319static int xmlXPathDebugObjCounterPoint = 0;
1320static int xmlXPathDebugObjCounterRange = 0;
1321static int xmlXPathDebugObjCounterLocset = 0;
1322static int xmlXPathDebugObjCounterUsers = 0;
1323static int xmlXPathDebugObjCounterXSLTTree = 0;
1324static int xmlXPathDebugObjCounterAll = 0;
1325
1326static int xmlXPathDebugObjTotalUndefined = 0;
1327static int xmlXPathDebugObjTotalNodeset = 0;
1328static int xmlXPathDebugObjTotalBool = 0;
1329static int xmlXPathDebugObjTotalNumber = 0;
1330static int xmlXPathDebugObjTotalString = 0;
1331static int xmlXPathDebugObjTotalPoint = 0;
1332static int xmlXPathDebugObjTotalRange = 0;
1333static int xmlXPathDebugObjTotalLocset = 0;
1334static int xmlXPathDebugObjTotalUsers = 0;
1335static int xmlXPathDebugObjTotalXSLTTree = 0;
1336static int xmlXPathDebugObjTotalAll = 0;
1337
1338static int xmlXPathDebugObjMaxUndefined = 0;
1339static int xmlXPathDebugObjMaxNodeset = 0;
1340static int xmlXPathDebugObjMaxBool = 0;
1341static int xmlXPathDebugObjMaxNumber = 0;
1342static int xmlXPathDebugObjMaxString = 0;
1343static int xmlXPathDebugObjMaxPoint = 0;
1344static int xmlXPathDebugObjMaxRange = 0;
1345static int xmlXPathDebugObjMaxLocset = 0;
1346static int xmlXPathDebugObjMaxUsers = 0;
1347static int xmlXPathDebugObjMaxXSLTTree = 0;
1348static int xmlXPathDebugObjMaxAll = 0;
1349
1350/* REVISIT TODO: Make this static when committing */
1351static void
1352xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1353{
1354    if (ctxt != NULL) {
1355	if (ctxt->cache != NULL) {
1356	    xmlXPathContextCachePtr cache =
1357		(xmlXPathContextCachePtr) ctxt->cache;
1358
1359	    cache->dbgCachedAll = 0;
1360	    cache->dbgCachedNodeset = 0;
1361	    cache->dbgCachedString = 0;
1362	    cache->dbgCachedBool = 0;
1363	    cache->dbgCachedNumber = 0;
1364	    cache->dbgCachedPoint = 0;
1365	    cache->dbgCachedRange = 0;
1366	    cache->dbgCachedLocset = 0;
1367	    cache->dbgCachedUsers = 0;
1368	    cache->dbgCachedXSLTTree = 0;
1369	    cache->dbgCachedUndefined = 0;
1370
1371	    cache->dbgReusedAll = 0;
1372	    cache->dbgReusedNodeset = 0;
1373	    cache->dbgReusedString = 0;
1374	    cache->dbgReusedBool = 0;
1375	    cache->dbgReusedNumber = 0;
1376	    cache->dbgReusedPoint = 0;
1377	    cache->dbgReusedRange = 0;
1378	    cache->dbgReusedLocset = 0;
1379	    cache->dbgReusedUsers = 0;
1380	    cache->dbgReusedXSLTTree = 0;
1381	    cache->dbgReusedUndefined = 0;
1382	}
1383    }
1384
1385    xmlXPathDebugObjCounterUndefined = 0;
1386    xmlXPathDebugObjCounterNodeset = 0;
1387    xmlXPathDebugObjCounterBool = 0;
1388    xmlXPathDebugObjCounterNumber = 0;
1389    xmlXPathDebugObjCounterString = 0;
1390    xmlXPathDebugObjCounterPoint = 0;
1391    xmlXPathDebugObjCounterRange = 0;
1392    xmlXPathDebugObjCounterLocset = 0;
1393    xmlXPathDebugObjCounterUsers = 0;
1394    xmlXPathDebugObjCounterXSLTTree = 0;
1395    xmlXPathDebugObjCounterAll = 0;
1396
1397    xmlXPathDebugObjTotalUndefined = 0;
1398    xmlXPathDebugObjTotalNodeset = 0;
1399    xmlXPathDebugObjTotalBool = 0;
1400    xmlXPathDebugObjTotalNumber = 0;
1401    xmlXPathDebugObjTotalString = 0;
1402    xmlXPathDebugObjTotalPoint = 0;
1403    xmlXPathDebugObjTotalRange = 0;
1404    xmlXPathDebugObjTotalLocset = 0;
1405    xmlXPathDebugObjTotalUsers = 0;
1406    xmlXPathDebugObjTotalXSLTTree = 0;
1407    xmlXPathDebugObjTotalAll = 0;
1408
1409    xmlXPathDebugObjMaxUndefined = 0;
1410    xmlXPathDebugObjMaxNodeset = 0;
1411    xmlXPathDebugObjMaxBool = 0;
1412    xmlXPathDebugObjMaxNumber = 0;
1413    xmlXPathDebugObjMaxString = 0;
1414    xmlXPathDebugObjMaxPoint = 0;
1415    xmlXPathDebugObjMaxRange = 0;
1416    xmlXPathDebugObjMaxLocset = 0;
1417    xmlXPathDebugObjMaxUsers = 0;
1418    xmlXPathDebugObjMaxXSLTTree = 0;
1419    xmlXPathDebugObjMaxAll = 0;
1420
1421}
1422
1423static void
1424xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1425			      xmlXPathObjectType objType)
1426{
1427    int isCached = 0;
1428
1429    if (ctxt != NULL) {
1430	if (ctxt->cache != NULL) {
1431	    xmlXPathContextCachePtr cache =
1432		(xmlXPathContextCachePtr) ctxt->cache;
1433
1434	    isCached = 1;
1435
1436	    cache->dbgReusedAll++;
1437	    switch (objType) {
1438		case XPATH_UNDEFINED:
1439		    cache->dbgReusedUndefined++;
1440		    break;
1441		case XPATH_NODESET:
1442		    cache->dbgReusedNodeset++;
1443		    break;
1444		case XPATH_BOOLEAN:
1445		    cache->dbgReusedBool++;
1446		    break;
1447		case XPATH_NUMBER:
1448		    cache->dbgReusedNumber++;
1449		    break;
1450		case XPATH_STRING:
1451		    cache->dbgReusedString++;
1452		    break;
1453		case XPATH_POINT:
1454		    cache->dbgReusedPoint++;
1455		    break;
1456		case XPATH_RANGE:
1457		    cache->dbgReusedRange++;
1458		    break;
1459		case XPATH_LOCATIONSET:
1460		    cache->dbgReusedLocset++;
1461		    break;
1462		case XPATH_USERS:
1463		    cache->dbgReusedUsers++;
1464		    break;
1465		case XPATH_XSLT_TREE:
1466		    cache->dbgReusedXSLTTree++;
1467		    break;
1468		default:
1469		    break;
1470	    }
1471	}
1472    }
1473
1474    switch (objType) {
1475	case XPATH_UNDEFINED:
1476	    if (! isCached)
1477		xmlXPathDebugObjTotalUndefined++;
1478	    xmlXPathDebugObjCounterUndefined++;
1479	    if (xmlXPathDebugObjCounterUndefined >
1480		xmlXPathDebugObjMaxUndefined)
1481		xmlXPathDebugObjMaxUndefined =
1482		    xmlXPathDebugObjCounterUndefined;
1483	    break;
1484	case XPATH_NODESET:
1485	    if (! isCached)
1486		xmlXPathDebugObjTotalNodeset++;
1487	    xmlXPathDebugObjCounterNodeset++;
1488	    if (xmlXPathDebugObjCounterNodeset >
1489		xmlXPathDebugObjMaxNodeset)
1490		xmlXPathDebugObjMaxNodeset =
1491		    xmlXPathDebugObjCounterNodeset;
1492	    break;
1493	case XPATH_BOOLEAN:
1494	    if (! isCached)
1495		xmlXPathDebugObjTotalBool++;
1496	    xmlXPathDebugObjCounterBool++;
1497	    if (xmlXPathDebugObjCounterBool >
1498		xmlXPathDebugObjMaxBool)
1499		xmlXPathDebugObjMaxBool =
1500		    xmlXPathDebugObjCounterBool;
1501	    break;
1502	case XPATH_NUMBER:
1503	    if (! isCached)
1504		xmlXPathDebugObjTotalNumber++;
1505	    xmlXPathDebugObjCounterNumber++;
1506	    if (xmlXPathDebugObjCounterNumber >
1507		xmlXPathDebugObjMaxNumber)
1508		xmlXPathDebugObjMaxNumber =
1509		    xmlXPathDebugObjCounterNumber;
1510	    break;
1511	case XPATH_STRING:
1512	    if (! isCached)
1513		xmlXPathDebugObjTotalString++;
1514	    xmlXPathDebugObjCounterString++;
1515	    if (xmlXPathDebugObjCounterString >
1516		xmlXPathDebugObjMaxString)
1517		xmlXPathDebugObjMaxString =
1518		    xmlXPathDebugObjCounterString;
1519	    break;
1520	case XPATH_POINT:
1521	    if (! isCached)
1522		xmlXPathDebugObjTotalPoint++;
1523	    xmlXPathDebugObjCounterPoint++;
1524	    if (xmlXPathDebugObjCounterPoint >
1525		xmlXPathDebugObjMaxPoint)
1526		xmlXPathDebugObjMaxPoint =
1527		    xmlXPathDebugObjCounterPoint;
1528	    break;
1529	case XPATH_RANGE:
1530	    if (! isCached)
1531		xmlXPathDebugObjTotalRange++;
1532	    xmlXPathDebugObjCounterRange++;
1533	    if (xmlXPathDebugObjCounterRange >
1534		xmlXPathDebugObjMaxRange)
1535		xmlXPathDebugObjMaxRange =
1536		    xmlXPathDebugObjCounterRange;
1537	    break;
1538	case XPATH_LOCATIONSET:
1539	    if (! isCached)
1540		xmlXPathDebugObjTotalLocset++;
1541	    xmlXPathDebugObjCounterLocset++;
1542	    if (xmlXPathDebugObjCounterLocset >
1543		xmlXPathDebugObjMaxLocset)
1544		xmlXPathDebugObjMaxLocset =
1545		    xmlXPathDebugObjCounterLocset;
1546	    break;
1547	case XPATH_USERS:
1548	    if (! isCached)
1549		xmlXPathDebugObjTotalUsers++;
1550	    xmlXPathDebugObjCounterUsers++;
1551	    if (xmlXPathDebugObjCounterUsers >
1552		xmlXPathDebugObjMaxUsers)
1553		xmlXPathDebugObjMaxUsers =
1554		    xmlXPathDebugObjCounterUsers;
1555	    break;
1556	case XPATH_XSLT_TREE:
1557	    if (! isCached)
1558		xmlXPathDebugObjTotalXSLTTree++;
1559	    xmlXPathDebugObjCounterXSLTTree++;
1560	    if (xmlXPathDebugObjCounterXSLTTree >
1561		xmlXPathDebugObjMaxXSLTTree)
1562		xmlXPathDebugObjMaxXSLTTree =
1563		    xmlXPathDebugObjCounterXSLTTree;
1564	    break;
1565	default:
1566	    break;
1567    }
1568    if (! isCached)
1569	xmlXPathDebugObjTotalAll++;
1570    xmlXPathDebugObjCounterAll++;
1571    if (xmlXPathDebugObjCounterAll >
1572	xmlXPathDebugObjMaxAll)
1573	xmlXPathDebugObjMaxAll =
1574	    xmlXPathDebugObjCounterAll;
1575}
1576
1577static void
1578xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1579			      xmlXPathObjectType objType)
1580{
1581    int isCached = 0;
1582
1583    if (ctxt != NULL) {
1584	if (ctxt->cache != NULL) {
1585	    xmlXPathContextCachePtr cache =
1586		(xmlXPathContextCachePtr) ctxt->cache;
1587
1588	    isCached = 1;
1589
1590	    cache->dbgCachedAll++;
1591	    switch (objType) {
1592		case XPATH_UNDEFINED:
1593		    cache->dbgCachedUndefined++;
1594		    break;
1595		case XPATH_NODESET:
1596		    cache->dbgCachedNodeset++;
1597		    break;
1598		case XPATH_BOOLEAN:
1599		    cache->dbgCachedBool++;
1600		    break;
1601		case XPATH_NUMBER:
1602		    cache->dbgCachedNumber++;
1603		    break;
1604		case XPATH_STRING:
1605		    cache->dbgCachedString++;
1606		    break;
1607		case XPATH_POINT:
1608		    cache->dbgCachedPoint++;
1609		    break;
1610		case XPATH_RANGE:
1611		    cache->dbgCachedRange++;
1612		    break;
1613		case XPATH_LOCATIONSET:
1614		    cache->dbgCachedLocset++;
1615		    break;
1616		case XPATH_USERS:
1617		    cache->dbgCachedUsers++;
1618		    break;
1619		case XPATH_XSLT_TREE:
1620		    cache->dbgCachedXSLTTree++;
1621		    break;
1622		default:
1623		    break;
1624	    }
1625
1626	}
1627    }
1628    switch (objType) {
1629	case XPATH_UNDEFINED:
1630	    xmlXPathDebugObjCounterUndefined--;
1631	    break;
1632	case XPATH_NODESET:
1633	    xmlXPathDebugObjCounterNodeset--;
1634	    break;
1635	case XPATH_BOOLEAN:
1636	    xmlXPathDebugObjCounterBool--;
1637	    break;
1638	case XPATH_NUMBER:
1639	    xmlXPathDebugObjCounterNumber--;
1640	    break;
1641	case XPATH_STRING:
1642	    xmlXPathDebugObjCounterString--;
1643	    break;
1644	case XPATH_POINT:
1645	    xmlXPathDebugObjCounterPoint--;
1646	    break;
1647	case XPATH_RANGE:
1648	    xmlXPathDebugObjCounterRange--;
1649	    break;
1650	case XPATH_LOCATIONSET:
1651	    xmlXPathDebugObjCounterLocset--;
1652	    break;
1653	case XPATH_USERS:
1654	    xmlXPathDebugObjCounterUsers--;
1655	    break;
1656	case XPATH_XSLT_TREE:
1657	    xmlXPathDebugObjCounterXSLTTree--;
1658	    break;
1659	default:
1660	    break;
1661    }
1662    xmlXPathDebugObjCounterAll--;
1663}
1664
1665/* REVISIT TODO: Make this static when committing */
1666static void
1667xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1668{
1669    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1670	reqXSLTTree, reqUndefined;
1671    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1672	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1673    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1674	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1675    int leftObjs = xmlXPathDebugObjCounterAll;
1676
1677    reqAll = xmlXPathDebugObjTotalAll;
1678    reqNodeset = xmlXPathDebugObjTotalNodeset;
1679    reqString = xmlXPathDebugObjTotalString;
1680    reqBool = xmlXPathDebugObjTotalBool;
1681    reqNumber = xmlXPathDebugObjTotalNumber;
1682    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1683    reqUndefined = xmlXPathDebugObjTotalUndefined;
1684
1685    printf("# XPath object usage:\n");
1686
1687    if (ctxt != NULL) {
1688	if (ctxt->cache != NULL) {
1689	    xmlXPathContextCachePtr cache =
1690		(xmlXPathContextCachePtr) ctxt->cache;
1691
1692	    reAll = cache->dbgReusedAll;
1693	    reqAll += reAll;
1694	    reNodeset = cache->dbgReusedNodeset;
1695	    reqNodeset += reNodeset;
1696	    reString = cache->dbgReusedString;
1697	    reqString += reString;
1698	    reBool = cache->dbgReusedBool;
1699	    reqBool += reBool;
1700	    reNumber = cache->dbgReusedNumber;
1701	    reqNumber += reNumber;
1702	    reXSLTTree = cache->dbgReusedXSLTTree;
1703	    reqXSLTTree += reXSLTTree;
1704	    reUndefined = cache->dbgReusedUndefined;
1705	    reqUndefined += reUndefined;
1706
1707	    caAll = cache->dbgCachedAll;
1708	    caBool = cache->dbgCachedBool;
1709	    caNodeset = cache->dbgCachedNodeset;
1710	    caString = cache->dbgCachedString;
1711	    caNumber = cache->dbgCachedNumber;
1712	    caXSLTTree = cache->dbgCachedXSLTTree;
1713	    caUndefined = cache->dbgCachedUndefined;
1714
1715	    if (cache->nodesetObjs)
1716		leftObjs -= cache->nodesetObjs->number;
1717	    if (cache->stringObjs)
1718		leftObjs -= cache->stringObjs->number;
1719	    if (cache->booleanObjs)
1720		leftObjs -= cache->booleanObjs->number;
1721	    if (cache->numberObjs)
1722		leftObjs -= cache->numberObjs->number;
1723	    if (cache->miscObjs)
1724		leftObjs -= cache->miscObjs->number;
1725	}
1726    }
1727
1728    printf("# all\n");
1729    printf("#   total  : %d\n", reqAll);
1730    printf("#   left  : %d\n", leftObjs);
1731    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
1732    printf("#   reused : %d\n", reAll);
1733    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
1734
1735    printf("# node-sets\n");
1736    printf("#   total  : %d\n", reqNodeset);
1737    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
1738    printf("#   reused : %d\n", reNodeset);
1739    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
1740
1741    printf("# strings\n");
1742    printf("#   total  : %d\n", reqString);
1743    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
1744    printf("#   reused : %d\n", reString);
1745    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
1746
1747    printf("# booleans\n");
1748    printf("#   total  : %d\n", reqBool);
1749    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
1750    printf("#   reused : %d\n", reBool);
1751    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
1752
1753    printf("# numbers\n");
1754    printf("#   total  : %d\n", reqNumber);
1755    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
1756    printf("#   reused : %d\n", reNumber);
1757    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
1758
1759    printf("# XSLT result tree fragments\n");
1760    printf("#   total  : %d\n", reqXSLTTree);
1761    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1762    printf("#   reused : %d\n", reXSLTTree);
1763    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
1764
1765    printf("# undefined\n");
1766    printf("#   total  : %d\n", reqUndefined);
1767    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
1768    printf("#   reused : %d\n", reUndefined);
1769    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
1770
1771}
1772
1773#endif /* XP_DEBUG_OBJ_USAGE */
1774
1775#endif /* LIBXML_DEBUG_ENABLED */
1776
1777/************************************************************************
1778 *									*
1779 *			XPath object caching				*
1780 *									*
1781 ************************************************************************/
1782
1783/**
1784 * xmlXPathNewCache:
1785 *
1786 * Create a new object cache
1787 *
1788 * Returns the xmlXPathCache just allocated.
1789 */
1790static xmlXPathContextCachePtr
1791xmlXPathNewCache(void)
1792{
1793    xmlXPathContextCachePtr ret;
1794
1795    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1796    if (ret == NULL) {
1797        xmlXPathErrMemory(NULL, "creating object cache\n");
1798	return(NULL);
1799    }
1800    memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
1801    ret->maxNodeset = 100;
1802    ret->maxString = 100;
1803    ret->maxBoolean = 100;
1804    ret->maxNumber = 100;
1805    ret->maxMisc = 100;
1806    return(ret);
1807}
1808
1809static void
1810xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1811{
1812    int i;
1813    xmlXPathObjectPtr obj;
1814
1815    if (list == NULL)
1816	return;
1817
1818    for (i = 0; i < list->number; i++) {
1819	obj = list->items[i];
1820	/*
1821	* Note that it is already assured that we don't need to
1822	* look out for namespace nodes in the node-set.
1823	*/
1824	if (obj->nodesetval != NULL) {
1825	    if (obj->nodesetval->nodeTab != NULL)
1826		xmlFree(obj->nodesetval->nodeTab);
1827	    xmlFree(obj->nodesetval);
1828	}
1829	xmlFree(obj);
1830#ifdef XP_DEBUG_OBJ_USAGE
1831	xmlXPathDebugObjCounterAll--;
1832#endif
1833    }
1834    xmlPointerListFree(list);
1835}
1836
1837static void
1838xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1839{
1840    if (cache == NULL)
1841	return;
1842    if (cache->nodesetObjs)
1843	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1844    if (cache->stringObjs)
1845	xmlXPathCacheFreeObjectList(cache->stringObjs);
1846    if (cache->booleanObjs)
1847	xmlXPathCacheFreeObjectList(cache->booleanObjs);
1848    if (cache->numberObjs)
1849	xmlXPathCacheFreeObjectList(cache->numberObjs);
1850    if (cache->miscObjs)
1851	xmlXPathCacheFreeObjectList(cache->miscObjs);
1852    xmlFree(cache);
1853}
1854
1855/**
1856 * xmlXPathContextSetCache:
1857 *
1858 * @ctxt:  the XPath context
1859 * @active: enables/disables (creates/frees) the cache
1860 * @value: a value with semantics dependant on @options
1861 * @options: options (currently only the value 0 is used)
1862 *
1863 * Creates/frees an object cache on the XPath context.
1864 * If activates XPath objects (xmlXPathObject) will be cached internally
1865 * to be reused.
1866 * @options:
1867 *   0: This will set the XPath object caching:
1868 *      @value:
1869 *        This will set the maximum number of XPath objects
1870 *        to be cached per slot
1871 *        There are 5 slots for: node-set, string, number, boolean, and
1872 *        misc objects. Use <0 for the default number (100).
1873 *   Other values for @options have currently no effect.
1874 *
1875 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1876 */
1877int
1878xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1879			int active,
1880			int value,
1881			int options)
1882{
1883    if (ctxt == NULL)
1884	return(-1);
1885    if (active) {
1886	xmlXPathContextCachePtr cache;
1887
1888	if (ctxt->cache == NULL) {
1889	    ctxt->cache = xmlXPathNewCache();
1890	    if (ctxt->cache == NULL)
1891		return(-1);
1892	}
1893	cache = (xmlXPathContextCachePtr) ctxt->cache;
1894	if (options == 0) {
1895	    if (value < 0)
1896		value = 100;
1897	    cache->maxNodeset = value;
1898	    cache->maxString = value;
1899	    cache->maxNumber = value;
1900	    cache->maxBoolean = value;
1901	    cache->maxMisc = value;
1902	}
1903    } else if (ctxt->cache != NULL) {
1904	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1905	ctxt->cache = NULL;
1906    }
1907    return(0);
1908}
1909
1910/**
1911 * xmlXPathCacheWrapNodeSet:
1912 * @ctxt: the XPath context
1913 * @val:  the NodePtr value
1914 *
1915 * This is the cached version of xmlXPathWrapNodeSet().
1916 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1917 *
1918 * Returns the created or reused object.
1919 */
1920static xmlXPathObjectPtr
1921xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1922{
1923    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1924	xmlXPathContextCachePtr cache =
1925	    (xmlXPathContextCachePtr) ctxt->cache;
1926
1927	if ((cache->miscObjs != NULL) &&
1928	    (cache->miscObjs->number != 0))
1929	{
1930	    xmlXPathObjectPtr ret;
1931
1932	    ret = (xmlXPathObjectPtr)
1933		cache->miscObjs->items[--cache->miscObjs->number];
1934	    ret->type = XPATH_NODESET;
1935	    ret->nodesetval = val;
1936#ifdef XP_DEBUG_OBJ_USAGE
1937	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1938#endif
1939	    return(ret);
1940	}
1941    }
1942
1943    return(xmlXPathWrapNodeSet(val));
1944
1945}
1946
1947/**
1948 * xmlXPathCacheWrapString:
1949 * @ctxt: the XPath context
1950 * @val:  the xmlChar * value
1951 *
1952 * This is the cached version of xmlXPathWrapString().
1953 * Wraps the @val string into an XPath object.
1954 *
1955 * Returns the created or reused object.
1956 */
1957static xmlXPathObjectPtr
1958xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1959{
1960    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1961	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1962
1963	if ((cache->stringObjs != NULL) &&
1964	    (cache->stringObjs->number != 0))
1965	{
1966
1967	    xmlXPathObjectPtr ret;
1968
1969	    ret = (xmlXPathObjectPtr)
1970		cache->stringObjs->items[--cache->stringObjs->number];
1971	    ret->type = XPATH_STRING;
1972	    ret->stringval = val;
1973#ifdef XP_DEBUG_OBJ_USAGE
1974	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1975#endif
1976	    return(ret);
1977	} else if ((cache->miscObjs != NULL) &&
1978	    (cache->miscObjs->number != 0))
1979	{
1980	    xmlXPathObjectPtr ret;
1981	    /*
1982	    * Fallback to misc-cache.
1983	    */
1984	    ret = (xmlXPathObjectPtr)
1985		cache->miscObjs->items[--cache->miscObjs->number];
1986
1987	    ret->type = XPATH_STRING;
1988	    ret->stringval = val;
1989#ifdef XP_DEBUG_OBJ_USAGE
1990	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1991#endif
1992	    return(ret);
1993	}
1994    }
1995    return(xmlXPathWrapString(val));
1996}
1997
1998/**
1999 * xmlXPathCacheNewNodeSet:
2000 * @ctxt: the XPath context
2001 * @val:  the NodePtr value
2002 *
2003 * This is the cached version of xmlXPathNewNodeSet().
2004 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2005 * it with the single Node @val
2006 *
2007 * Returns the created or reused object.
2008 */
2009static xmlXPathObjectPtr
2010xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2011{
2012    if ((ctxt != NULL) && (ctxt->cache)) {
2013	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2014
2015	if ((cache->nodesetObjs != NULL) &&
2016	    (cache->nodesetObjs->number != 0))
2017	{
2018	    xmlXPathObjectPtr ret;
2019	    /*
2020	    * Use the nodset-cache.
2021	    */
2022	    ret = (xmlXPathObjectPtr)
2023		cache->nodesetObjs->items[--cache->nodesetObjs->number];
2024	    ret->type = XPATH_NODESET;
2025	    ret->boolval = 0;
2026	    if (val) {
2027		if ((ret->nodesetval->nodeMax == 0) ||
2028		    (val->type == XML_NAMESPACE_DECL))
2029		{
2030		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2031		} else {
2032		    ret->nodesetval->nodeTab[0] = val;
2033		    ret->nodesetval->nodeNr = 1;
2034		}
2035	    }
2036#ifdef XP_DEBUG_OBJ_USAGE
2037	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2038#endif
2039	    return(ret);
2040	} else if ((cache->miscObjs != NULL) &&
2041	    (cache->miscObjs->number != 0))
2042	{
2043	    xmlXPathObjectPtr ret;
2044	    /*
2045	    * Fallback to misc-cache.
2046	    */
2047
2048	    ret = (xmlXPathObjectPtr)
2049		cache->miscObjs->items[--cache->miscObjs->number];
2050
2051	    ret->type = XPATH_NODESET;
2052	    ret->boolval = 0;
2053	    ret->nodesetval = xmlXPathNodeSetCreate(val);
2054#ifdef XP_DEBUG_OBJ_USAGE
2055	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2056#endif
2057	    return(ret);
2058	}
2059    }
2060    return(xmlXPathNewNodeSet(val));
2061}
2062
2063/**
2064 * xmlXPathCacheNewCString:
2065 * @ctxt: the XPath context
2066 * @val:  the char * value
2067 *
2068 * This is the cached version of xmlXPathNewCString().
2069 * Acquire an xmlXPathObjectPtr of type string and of value @val
2070 *
2071 * Returns the created or reused object.
2072 */
2073static xmlXPathObjectPtr
2074xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2075{
2076    if ((ctxt != NULL) && (ctxt->cache)) {
2077	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2078
2079	if ((cache->stringObjs != NULL) &&
2080	    (cache->stringObjs->number != 0))
2081	{
2082	    xmlXPathObjectPtr ret;
2083
2084	    ret = (xmlXPathObjectPtr)
2085		cache->stringObjs->items[--cache->stringObjs->number];
2086
2087	    ret->type = XPATH_STRING;
2088	    ret->stringval = xmlStrdup(BAD_CAST val);
2089#ifdef XP_DEBUG_OBJ_USAGE
2090	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2091#endif
2092	    return(ret);
2093	} else if ((cache->miscObjs != NULL) &&
2094	    (cache->miscObjs->number != 0))
2095	{
2096	    xmlXPathObjectPtr ret;
2097
2098	    ret = (xmlXPathObjectPtr)
2099		cache->miscObjs->items[--cache->miscObjs->number];
2100
2101	    ret->type = XPATH_STRING;
2102	    ret->stringval = xmlStrdup(BAD_CAST val);
2103#ifdef XP_DEBUG_OBJ_USAGE
2104	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2105#endif
2106	    return(ret);
2107	}
2108    }
2109    return(xmlXPathNewCString(val));
2110}
2111
2112/**
2113 * xmlXPathCacheNewString:
2114 * @ctxt: the XPath context
2115 * @val:  the xmlChar * value
2116 *
2117 * This is the cached version of xmlXPathNewString().
2118 * Acquire an xmlXPathObjectPtr of type string and of value @val
2119 *
2120 * Returns the created or reused object.
2121 */
2122static xmlXPathObjectPtr
2123xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2124{
2125    if ((ctxt != NULL) && (ctxt->cache)) {
2126	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2127
2128	if ((cache->stringObjs != NULL) &&
2129	    (cache->stringObjs->number != 0))
2130	{
2131	    xmlXPathObjectPtr ret;
2132
2133	    ret = (xmlXPathObjectPtr)
2134		cache->stringObjs->items[--cache->stringObjs->number];
2135	    ret->type = XPATH_STRING;
2136	    if (val != NULL)
2137		ret->stringval = xmlStrdup(val);
2138	    else
2139		ret->stringval = xmlStrdup((const xmlChar *)"");
2140#ifdef XP_DEBUG_OBJ_USAGE
2141	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2142#endif
2143	    return(ret);
2144	} else if ((cache->miscObjs != NULL) &&
2145	    (cache->miscObjs->number != 0))
2146	{
2147	    xmlXPathObjectPtr ret;
2148
2149	    ret = (xmlXPathObjectPtr)
2150		cache->miscObjs->items[--cache->miscObjs->number];
2151
2152	    ret->type = XPATH_STRING;
2153	    if (val != NULL)
2154		ret->stringval = xmlStrdup(val);
2155	    else
2156		ret->stringval = xmlStrdup((const xmlChar *)"");
2157#ifdef XP_DEBUG_OBJ_USAGE
2158	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2159#endif
2160	    return(ret);
2161	}
2162    }
2163    return(xmlXPathNewString(val));
2164}
2165
2166/**
2167 * xmlXPathCacheNewBoolean:
2168 * @ctxt: the XPath context
2169 * @val:  the boolean value
2170 *
2171 * This is the cached version of xmlXPathNewBoolean().
2172 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2173 *
2174 * Returns the created or reused object.
2175 */
2176static xmlXPathObjectPtr
2177xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2178{
2179    if ((ctxt != NULL) && (ctxt->cache)) {
2180	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2181
2182	if ((cache->booleanObjs != NULL) &&
2183	    (cache->booleanObjs->number != 0))
2184	{
2185	    xmlXPathObjectPtr ret;
2186
2187	    ret = (xmlXPathObjectPtr)
2188		cache->booleanObjs->items[--cache->booleanObjs->number];
2189	    ret->type = XPATH_BOOLEAN;
2190	    ret->boolval = (val != 0);
2191#ifdef XP_DEBUG_OBJ_USAGE
2192	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2193#endif
2194	    return(ret);
2195	} else if ((cache->miscObjs != NULL) &&
2196	    (cache->miscObjs->number != 0))
2197	{
2198	    xmlXPathObjectPtr ret;
2199
2200	    ret = (xmlXPathObjectPtr)
2201		cache->miscObjs->items[--cache->miscObjs->number];
2202
2203	    ret->type = XPATH_BOOLEAN;
2204	    ret->boolval = (val != 0);
2205#ifdef XP_DEBUG_OBJ_USAGE
2206	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2207#endif
2208	    return(ret);
2209	}
2210    }
2211    return(xmlXPathNewBoolean(val));
2212}
2213
2214/**
2215 * xmlXPathCacheNewFloat:
2216 * @ctxt: the XPath context
2217 * @val:  the double value
2218 *
2219 * This is the cached version of xmlXPathNewFloat().
2220 * Acquires an xmlXPathObjectPtr of type double and of value @val
2221 *
2222 * Returns the created or reused object.
2223 */
2224static xmlXPathObjectPtr
2225xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2226{
2227     if ((ctxt != NULL) && (ctxt->cache)) {
2228	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2229
2230	if ((cache->numberObjs != NULL) &&
2231	    (cache->numberObjs->number != 0))
2232	{
2233	    xmlXPathObjectPtr ret;
2234
2235	    ret = (xmlXPathObjectPtr)
2236		cache->numberObjs->items[--cache->numberObjs->number];
2237	    ret->type = XPATH_NUMBER;
2238	    ret->floatval = val;
2239#ifdef XP_DEBUG_OBJ_USAGE
2240	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2241#endif
2242	    return(ret);
2243	} else if ((cache->miscObjs != NULL) &&
2244	    (cache->miscObjs->number != 0))
2245	{
2246	    xmlXPathObjectPtr ret;
2247
2248	    ret = (xmlXPathObjectPtr)
2249		cache->miscObjs->items[--cache->miscObjs->number];
2250
2251	    ret->type = XPATH_NUMBER;
2252	    ret->floatval = val;
2253#ifdef XP_DEBUG_OBJ_USAGE
2254	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2255#endif
2256	    return(ret);
2257	}
2258    }
2259    return(xmlXPathNewFloat(val));
2260}
2261
2262/**
2263 * xmlXPathCacheConvertString:
2264 * @ctxt: the XPath context
2265 * @val:  an XPath object
2266 *
2267 * This is the cached version of xmlXPathConvertString().
2268 * Converts an existing object to its string() equivalent
2269 *
2270 * Returns a created or reused object, the old one is freed (cached)
2271 *         (or the operation is done directly on @val)
2272 */
2273
2274static xmlXPathObjectPtr
2275xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2276    xmlChar *res = NULL;
2277
2278    if (val == NULL)
2279	return(xmlXPathCacheNewCString(ctxt, ""));
2280
2281    switch (val->type) {
2282    case XPATH_UNDEFINED:
2283#ifdef DEBUG_EXPR
2284	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2285#endif
2286	break;
2287    case XPATH_NODESET:
2288    case XPATH_XSLT_TREE:
2289	res = xmlXPathCastNodeSetToString(val->nodesetval);
2290	break;
2291    case XPATH_STRING:
2292	return(val);
2293    case XPATH_BOOLEAN:
2294	res = xmlXPathCastBooleanToString(val->boolval);
2295	break;
2296    case XPATH_NUMBER:
2297	res = xmlXPathCastNumberToString(val->floatval);
2298	break;
2299    case XPATH_USERS:
2300    case XPATH_POINT:
2301    case XPATH_RANGE:
2302    case XPATH_LOCATIONSET:
2303	TODO;
2304	break;
2305    }
2306    xmlXPathReleaseObject(ctxt, val);
2307    if (res == NULL)
2308	return(xmlXPathCacheNewCString(ctxt, ""));
2309    return(xmlXPathCacheWrapString(ctxt, res));
2310}
2311
2312/**
2313 * xmlXPathCacheObjectCopy:
2314 * @ctxt: the XPath context
2315 * @val:  the original object
2316 *
2317 * This is the cached version of xmlXPathObjectCopy().
2318 * Acquire a copy of a given object
2319 *
2320 * Returns a created or reused created object.
2321 */
2322static xmlXPathObjectPtr
2323xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2324{
2325    if (val == NULL)
2326	return(NULL);
2327
2328    if (XP_HAS_CACHE(ctxt)) {
2329	switch (val->type) {
2330	    case XPATH_NODESET:
2331		return(xmlXPathCacheWrapNodeSet(ctxt,
2332		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2333	    case XPATH_STRING:
2334		return(xmlXPathCacheNewString(ctxt, val->stringval));
2335	    case XPATH_BOOLEAN:
2336		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2337	    case XPATH_NUMBER:
2338		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2339	    default:
2340		break;
2341	}
2342    }
2343    return(xmlXPathObjectCopy(val));
2344}
2345
2346/**
2347 * xmlXPathCacheConvertBoolean:
2348 * @ctxt: the XPath context
2349 * @val:  an XPath object
2350 *
2351 * This is the cached version of xmlXPathConvertBoolean().
2352 * Converts an existing object to its boolean() equivalent
2353 *
2354 * Returns a created or reused object, the old one is freed (or the operation
2355 *         is done directly on @val)
2356 */
2357static xmlXPathObjectPtr
2358xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2359    xmlXPathObjectPtr ret;
2360
2361    if (val == NULL)
2362	return(xmlXPathCacheNewBoolean(ctxt, 0));
2363    if (val->type == XPATH_BOOLEAN)
2364	return(val);
2365    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2366    xmlXPathReleaseObject(ctxt, val);
2367    return(ret);
2368}
2369
2370/**
2371 * xmlXPathCacheConvertNumber:
2372 * @ctxt: the XPath context
2373 * @val:  an XPath object
2374 *
2375 * This is the cached version of xmlXPathConvertNumber().
2376 * Converts an existing object to its number() equivalent
2377 *
2378 * Returns a created or reused object, the old one is freed (or the operation
2379 *         is done directly on @val)
2380 */
2381static xmlXPathObjectPtr
2382xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2383    xmlXPathObjectPtr ret;
2384
2385    if (val == NULL)
2386	return(xmlXPathCacheNewFloat(ctxt, 0.0));
2387    if (val->type == XPATH_NUMBER)
2388	return(val);
2389    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2390    xmlXPathReleaseObject(ctxt, val);
2391    return(ret);
2392}
2393
2394/************************************************************************
2395 *									*
2396 *		Parser stacks related functions and macros		*
2397 *									*
2398 ************************************************************************/
2399
2400/**
2401 * valuePop:
2402 * @ctxt: an XPath evaluation context
2403 *
2404 * Pops the top XPath object from the value stack
2405 *
2406 * Returns the XPath object just removed
2407 */
2408xmlXPathObjectPtr
2409valuePop(xmlXPathParserContextPtr ctxt)
2410{
2411    xmlXPathObjectPtr ret;
2412
2413    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2414        return (NULL);
2415    ctxt->valueNr--;
2416    if (ctxt->valueNr > 0)
2417        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2418    else
2419        ctxt->value = NULL;
2420    ret = ctxt->valueTab[ctxt->valueNr];
2421    ctxt->valueTab[ctxt->valueNr] = NULL;
2422    return (ret);
2423}
2424/**
2425 * valuePush:
2426 * @ctxt:  an XPath evaluation context
2427 * @value:  the XPath object
2428 *
2429 * Pushes a new XPath object on top of the value stack
2430 *
2431 * returns the number of items on the value stack
2432 */
2433int
2434valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2435{
2436    if ((ctxt == NULL) || (value == NULL)) return(-1);
2437    if (ctxt->valueNr >= ctxt->valueMax) {
2438        xmlXPathObjectPtr *tmp;
2439
2440        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2441                                             2 * ctxt->valueMax *
2442                                             sizeof(ctxt->valueTab[0]));
2443        if (tmp == NULL) {
2444            xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2445            return (0);
2446        }
2447        ctxt->valueMax *= 2;
2448	ctxt->valueTab = tmp;
2449    }
2450    ctxt->valueTab[ctxt->valueNr] = value;
2451    ctxt->value = value;
2452    return (ctxt->valueNr++);
2453}
2454
2455/**
2456 * xmlXPathPopBoolean:
2457 * @ctxt:  an XPath parser context
2458 *
2459 * Pops a boolean from the stack, handling conversion if needed.
2460 * Check error with #xmlXPathCheckError.
2461 *
2462 * Returns the boolean
2463 */
2464int
2465xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2466    xmlXPathObjectPtr obj;
2467    int ret;
2468
2469    obj = valuePop(ctxt);
2470    if (obj == NULL) {
2471	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2472	return(0);
2473    }
2474    if (obj->type != XPATH_BOOLEAN)
2475	ret = xmlXPathCastToBoolean(obj);
2476    else
2477        ret = obj->boolval;
2478    xmlXPathReleaseObject(ctxt->context, obj);
2479    return(ret);
2480}
2481
2482/**
2483 * xmlXPathPopNumber:
2484 * @ctxt:  an XPath parser context
2485 *
2486 * Pops a number from the stack, handling conversion if needed.
2487 * Check error with #xmlXPathCheckError.
2488 *
2489 * Returns the number
2490 */
2491double
2492xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2493    xmlXPathObjectPtr obj;
2494    double ret;
2495
2496    obj = valuePop(ctxt);
2497    if (obj == NULL) {
2498	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2499	return(0);
2500    }
2501    if (obj->type != XPATH_NUMBER)
2502	ret = xmlXPathCastToNumber(obj);
2503    else
2504        ret = obj->floatval;
2505    xmlXPathReleaseObject(ctxt->context, obj);
2506    return(ret);
2507}
2508
2509/**
2510 * xmlXPathPopString:
2511 * @ctxt:  an XPath parser context
2512 *
2513 * Pops a string from the stack, handling conversion if needed.
2514 * Check error with #xmlXPathCheckError.
2515 *
2516 * Returns the string
2517 */
2518xmlChar *
2519xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2520    xmlXPathObjectPtr obj;
2521    xmlChar * ret;
2522
2523    obj = valuePop(ctxt);
2524    if (obj == NULL) {
2525	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2526	return(NULL);
2527    }
2528    ret = xmlXPathCastToString(obj);	/* this does required strdup */
2529    /* TODO: needs refactoring somewhere else */
2530    if (obj->stringval == ret)
2531	obj->stringval = NULL;
2532    xmlXPathReleaseObject(ctxt->context, obj);
2533    return(ret);
2534}
2535
2536/**
2537 * xmlXPathPopNodeSet:
2538 * @ctxt:  an XPath parser context
2539 *
2540 * Pops a node-set from the stack, handling conversion if needed.
2541 * Check error with #xmlXPathCheckError.
2542 *
2543 * Returns the node-set
2544 */
2545xmlNodeSetPtr
2546xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2547    xmlXPathObjectPtr obj;
2548    xmlNodeSetPtr ret;
2549
2550    if (ctxt == NULL) return(NULL);
2551    if (ctxt->value == NULL) {
2552	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2553	return(NULL);
2554    }
2555    if (!xmlXPathStackIsNodeSet(ctxt)) {
2556	xmlXPathSetTypeError(ctxt);
2557	return(NULL);
2558    }
2559    obj = valuePop(ctxt);
2560    ret = obj->nodesetval;
2561#if 0
2562    /* to fix memory leak of not clearing obj->user */
2563    if (obj->boolval && obj->user != NULL)
2564        xmlFreeNodeList((xmlNodePtr) obj->user);
2565#endif
2566    obj->nodesetval = NULL;
2567    xmlXPathReleaseObject(ctxt->context, obj);
2568    return(ret);
2569}
2570
2571/**
2572 * xmlXPathPopExternal:
2573 * @ctxt:  an XPath parser context
2574 *
2575 * Pops an external object from the stack, handling conversion if needed.
2576 * Check error with #xmlXPathCheckError.
2577 *
2578 * Returns the object
2579 */
2580void *
2581xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2582    xmlXPathObjectPtr obj;
2583    void * ret;
2584
2585    if ((ctxt == NULL) || (ctxt->value == NULL)) {
2586	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2587	return(NULL);
2588    }
2589    if (ctxt->value->type != XPATH_USERS) {
2590	xmlXPathSetTypeError(ctxt);
2591	return(NULL);
2592    }
2593    obj = valuePop(ctxt);
2594    ret = obj->user;
2595    obj->user = NULL;
2596    xmlXPathReleaseObject(ctxt->context, obj);
2597    return(ret);
2598}
2599
2600/*
2601 * Macros for accessing the content. Those should be used only by the parser,
2602 * and not exported.
2603 *
2604 * Dirty macros, i.e. one need to make assumption on the context to use them
2605 *
2606 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2607 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2608 *           in ISO-Latin or UTF-8.
2609 *           This should be used internally by the parser
2610 *           only to compare to ASCII values otherwise it would break when
2611 *           running with UTF-8 encoding.
2612 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2613 *           to compare on ASCII based substring.
2614 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2615 *           strings within the parser.
2616 *   CURRENT Returns the current char value, with the full decoding of
2617 *           UTF-8 if we are using this mode. It returns an int.
2618 *   NEXT    Skip to the next character, this does the proper decoding
2619 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2620 *           It returns the pointer to the current xmlChar.
2621 */
2622
2623#define CUR (*ctxt->cur)
2624#define SKIP(val) ctxt->cur += (val)
2625#define NXT(val) ctxt->cur[(val)]
2626#define CUR_PTR ctxt->cur
2627#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2628
2629#define COPY_BUF(l,b,i,v)                                              \
2630    if (l == 1) b[i++] = (xmlChar) v;                                  \
2631    else i += xmlCopyChar(l,&b[i],v)
2632
2633#define NEXTL(l)  ctxt->cur += l
2634
2635#define SKIP_BLANKS							\
2636    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2637
2638#define CURRENT (*ctxt->cur)
2639#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2640
2641
2642#ifndef DBL_DIG
2643#define DBL_DIG 16
2644#endif
2645#ifndef DBL_EPSILON
2646#define DBL_EPSILON 1E-9
2647#endif
2648
2649#define UPPER_DOUBLE 1E9
2650#define LOWER_DOUBLE 1E-5
2651#define	LOWER_DOUBLE_EXP 5
2652
2653#define INTEGER_DIGITS DBL_DIG
2654#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2655#define EXPONENT_DIGITS (3 + 2)
2656
2657/**
2658 * xmlXPathFormatNumber:
2659 * @number:     number to format
2660 * @buffer:     output buffer
2661 * @buffersize: size of output buffer
2662 *
2663 * Convert the number into a string representation.
2664 */
2665static void
2666xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2667{
2668    switch (xmlXPathIsInf(number)) {
2669    case 1:
2670	if (buffersize > (int)sizeof("Infinity"))
2671	    snprintf(buffer, buffersize, "Infinity");
2672	break;
2673    case -1:
2674	if (buffersize > (int)sizeof("-Infinity"))
2675	    snprintf(buffer, buffersize, "-Infinity");
2676	break;
2677    default:
2678	if (xmlXPathIsNaN(number)) {
2679	    if (buffersize > (int)sizeof("NaN"))
2680		snprintf(buffer, buffersize, "NaN");
2681	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
2682	    snprintf(buffer, buffersize, "0");
2683	} else if (number == ((int) number)) {
2684	    char work[30];
2685	    char *ptr, *cur;
2686	    int value = (int) number;
2687
2688            ptr = &buffer[0];
2689	    if (value == 0) {
2690		*ptr++ = '0';
2691	    } else {
2692		snprintf(work, 29, "%d", value);
2693		cur = &work[0];
2694		while ((*cur) && (ptr - buffer < buffersize)) {
2695		    *ptr++ = *cur++;
2696		}
2697	    }
2698	    if (ptr - buffer < buffersize) {
2699		*ptr = 0;
2700	    } else if (buffersize > 0) {
2701		ptr--;
2702		*ptr = 0;
2703	    }
2704	} else {
2705	    /*
2706	      For the dimension of work,
2707	          DBL_DIG is number of significant digits
2708		  EXPONENT is only needed for "scientific notation"
2709	          3 is sign, decimal point, and terminating zero
2710		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2711	      Note that this dimension is slightly (a few characters)
2712	      larger than actually necessary.
2713	    */
2714	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2715	    int integer_place, fraction_place;
2716	    char *ptr;
2717	    char *after_fraction;
2718	    double absolute_value;
2719	    int size;
2720
2721	    absolute_value = fabs(number);
2722
2723	    /*
2724	     * First choose format - scientific or regular floating point.
2725	     * In either case, result is in work, and after_fraction points
2726	     * just past the fractional part.
2727	    */
2728	    if ( ((absolute_value > UPPER_DOUBLE) ||
2729		  (absolute_value < LOWER_DOUBLE)) &&
2730		 (absolute_value != 0.0) ) {
2731		/* Use scientific notation */
2732		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2733		fraction_place = DBL_DIG - 1;
2734		size = snprintf(work, sizeof(work),"%*.*e",
2735			 integer_place, fraction_place, number);
2736		while ((size > 0) && (work[size] != 'e')) size--;
2737
2738	    }
2739	    else {
2740		/* Use regular notation */
2741		if (absolute_value > 0.0) {
2742		    integer_place = (int)log10(absolute_value);
2743		    if (integer_place > 0)
2744		        fraction_place = DBL_DIG - integer_place - 1;
2745		    else
2746		        fraction_place = DBL_DIG - integer_place;
2747		} else {
2748		    fraction_place = 1;
2749		}
2750		size = snprintf(work, sizeof(work), "%0.*f",
2751				fraction_place, number);
2752	    }
2753
2754	    /* Remove fractional trailing zeroes */
2755	    after_fraction = work + size;
2756	    ptr = after_fraction;
2757	    while (*(--ptr) == '0')
2758		;
2759	    if (*ptr != '.')
2760	        ptr++;
2761	    while ((*ptr++ = *after_fraction++) != 0);
2762
2763	    /* Finally copy result back to caller */
2764	    size = strlen(work) + 1;
2765	    if (size > buffersize) {
2766		work[buffersize - 1] = 0;
2767		size = buffersize;
2768	    }
2769	    memmove(buffer, work, size);
2770	}
2771	break;
2772    }
2773}
2774
2775
2776/************************************************************************
2777 *									*
2778 *			Routines to handle NodeSets			*
2779 *									*
2780 ************************************************************************/
2781
2782/**
2783 * xmlXPathOrderDocElems:
2784 * @doc:  an input document
2785 *
2786 * Call this routine to speed up XPath computation on static documents.
2787 * This stamps all the element nodes with the document order
2788 * Like for line information, the order is kept in the element->content
2789 * field, the value stored is actually - the node number (starting at -1)
2790 * to be able to differentiate from line numbers.
2791 *
2792 * Returns the number of elements found in the document or -1 in case
2793 *    of error.
2794 */
2795long
2796xmlXPathOrderDocElems(xmlDocPtr doc) {
2797    long count = 0;
2798    xmlNodePtr cur;
2799
2800    if (doc == NULL)
2801	return(-1);
2802    cur = doc->children;
2803    while (cur != NULL) {
2804	if (cur->type == XML_ELEMENT_NODE) {
2805	    cur->content = (void *) (-(++count));
2806	    if (cur->children != NULL) {
2807		cur = cur->children;
2808		continue;
2809	    }
2810	}
2811	if (cur->next != NULL) {
2812	    cur = cur->next;
2813	    continue;
2814	}
2815	do {
2816	    cur = cur->parent;
2817	    if (cur == NULL)
2818		break;
2819	    if (cur == (xmlNodePtr) doc) {
2820		cur = NULL;
2821		break;
2822	    }
2823	    if (cur->next != NULL) {
2824		cur = cur->next;
2825		break;
2826	    }
2827	} while (cur != NULL);
2828    }
2829    return(count);
2830}
2831
2832/**
2833 * xmlXPathCmpNodes:
2834 * @node1:  the first node
2835 * @node2:  the second node
2836 *
2837 * Compare two nodes w.r.t document order
2838 *
2839 * Returns -2 in case of error 1 if first point < second point, 0 if
2840 *         it's the same node, -1 otherwise
2841 */
2842int
2843xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2844    int depth1, depth2;
2845    int attr1 = 0, attr2 = 0;
2846    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2847    xmlNodePtr cur, root;
2848
2849    if ((node1 == NULL) || (node2 == NULL))
2850	return(-2);
2851    /*
2852     * a couple of optimizations which will avoid computations in most cases
2853     */
2854    if (node1 == node2)		/* trivial case */
2855	return(0);
2856    if (node1->type == XML_ATTRIBUTE_NODE) {
2857	attr1 = 1;
2858	attrNode1 = node1;
2859	node1 = node1->parent;
2860    }
2861    if (node2->type == XML_ATTRIBUTE_NODE) {
2862	attr2 = 1;
2863	attrNode2 = node2;
2864	node2 = node2->parent;
2865    }
2866    if (node1 == node2) {
2867	if (attr1 == attr2) {
2868	    /* not required, but we keep attributes in order */
2869	    if (attr1 != 0) {
2870	        cur = attrNode2->prev;
2871		while (cur != NULL) {
2872		    if (cur == attrNode1)
2873		        return (1);
2874		    cur = cur->prev;
2875		}
2876		return (-1);
2877	    }
2878	    return(0);
2879	}
2880	if (attr2 == 1)
2881	    return(1);
2882	return(-1);
2883    }
2884    if ((node1->type == XML_NAMESPACE_DECL) ||
2885        (node2->type == XML_NAMESPACE_DECL))
2886	return(1);
2887    if (node1 == node2->prev)
2888	return(1);
2889    if (node1 == node2->next)
2890	return(-1);
2891
2892    /*
2893     * Speedup using document order if availble.
2894     */
2895    if ((node1->type == XML_ELEMENT_NODE) &&
2896	(node2->type == XML_ELEMENT_NODE) &&
2897	(0 > (long) node1->content) &&
2898	(0 > (long) node2->content) &&
2899	(node1->doc == node2->doc)) {
2900	long l1, l2;
2901
2902	l1 = -((long) node1->content);
2903	l2 = -((long) node2->content);
2904	if (l1 < l2)
2905	    return(1);
2906	if (l1 > l2)
2907	    return(-1);
2908    }
2909
2910    /*
2911     * compute depth to root
2912     */
2913    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2914	if (cur == node1)
2915	    return(1);
2916	depth2++;
2917    }
2918    root = cur;
2919    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2920	if (cur == node2)
2921	    return(-1);
2922	depth1++;
2923    }
2924    /*
2925     * Distinct document (or distinct entities :-( ) case.
2926     */
2927    if (root != cur) {
2928	return(-2);
2929    }
2930    /*
2931     * get the nearest common ancestor.
2932     */
2933    while (depth1 > depth2) {
2934	depth1--;
2935	node1 = node1->parent;
2936    }
2937    while (depth2 > depth1) {
2938	depth2--;
2939	node2 = node2->parent;
2940    }
2941    while (node1->parent != node2->parent) {
2942	node1 = node1->parent;
2943	node2 = node2->parent;
2944	/* should not happen but just in case ... */
2945	if ((node1 == NULL) || (node2 == NULL))
2946	    return(-2);
2947    }
2948    /*
2949     * Find who's first.
2950     */
2951    if (node1 == node2->prev)
2952	return(1);
2953    if (node1 == node2->next)
2954	return(-1);
2955    /*
2956     * Speedup using document order if availble.
2957     */
2958    if ((node1->type == XML_ELEMENT_NODE) &&
2959	(node2->type == XML_ELEMENT_NODE) &&
2960	(0 > (long) node1->content) &&
2961	(0 > (long) node2->content) &&
2962	(node1->doc == node2->doc)) {
2963	long l1, l2;
2964
2965	l1 = -((long) node1->content);
2966	l2 = -((long) node2->content);
2967	if (l1 < l2)
2968	    return(1);
2969	if (l1 > l2)
2970	    return(-1);
2971    }
2972
2973    for (cur = node1->next;cur != NULL;cur = cur->next)
2974	if (cur == node2)
2975	    return(1);
2976    return(-1); /* assume there is no sibling list corruption */
2977}
2978
2979#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2980/**
2981 * xmlXPathCmpNodesExt:
2982 * @node1:  the first node
2983 * @node2:  the second node
2984 *
2985 * Compare two nodes w.r.t document order.
2986 * This one is optimized for handling of non-element nodes.
2987 *
2988 * Returns -2 in case of error 1 if first point < second point, 0 if
2989 *         it's the same node, -1 otherwise
2990 */
2991static int
2992xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2993    int depth1, depth2;
2994    int misc = 0, precedence1 = 0, precedence2 = 0;
2995    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2996    xmlNodePtr cur, root;
2997    long l1, l2;
2998
2999    if ((node1 == NULL) || (node2 == NULL))
3000	return(-2);
3001
3002    if (node1 == node2)
3003	return(0);
3004
3005    /*
3006     * a couple of optimizations which will avoid computations in most cases
3007     */
3008    switch (node1->type) {
3009	case XML_ELEMENT_NODE:
3010	    if (node2->type == XML_ELEMENT_NODE) {
3011		if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3012		    (0 > (long) node2->content) &&
3013		    (node1->doc == node2->doc))
3014		{
3015		    l1 = -((long) node1->content);
3016		    l2 = -((long) node2->content);
3017		    if (l1 < l2)
3018			return(1);
3019		    if (l1 > l2)
3020			return(-1);
3021		} else
3022		    goto turtle_comparison;
3023	    }
3024	    break;
3025	case XML_ATTRIBUTE_NODE:
3026	    precedence1 = 1; /* element is owner */
3027	    miscNode1 = node1;
3028	    node1 = node1->parent;
3029	    misc = 1;
3030	    break;
3031	case XML_TEXT_NODE:
3032	case XML_CDATA_SECTION_NODE:
3033	case XML_COMMENT_NODE:
3034	case XML_PI_NODE: {
3035	    miscNode1 = node1;
3036	    /*
3037	    * Find nearest element node.
3038	    */
3039	    if (node1->prev != NULL) {
3040		do {
3041		    node1 = node1->prev;
3042		    if (node1->type == XML_ELEMENT_NODE) {
3043			precedence1 = 3; /* element in prev-sibl axis */
3044			break;
3045		    }
3046		    if (node1->prev == NULL) {
3047			precedence1 = 2; /* element is parent */
3048			/*
3049			* URGENT TODO: Are there any cases, where the
3050			* parent of such a node is not an element node?
3051			*/
3052			node1 = node1->parent;
3053			break;
3054		    }
3055		} while (1);
3056	    } else {
3057		precedence1 = 2; /* element is parent */
3058		node1 = node1->parent;
3059	    }
3060	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3061		(0 <= (long) node1->content)) {
3062		/*
3063		* Fallback for whatever case.
3064		*/
3065		node1 = miscNode1;
3066		precedence1 = 0;
3067	    } else
3068		misc = 1;
3069	}
3070	    break;
3071	case XML_NAMESPACE_DECL:
3072	    /*
3073	    * TODO: why do we return 1 for namespace nodes?
3074	    */
3075	    return(1);
3076	default:
3077	    break;
3078    }
3079    switch (node2->type) {
3080	case XML_ELEMENT_NODE:
3081	    break;
3082	case XML_ATTRIBUTE_NODE:
3083	    precedence2 = 1; /* element is owner */
3084	    miscNode2 = node2;
3085	    node2 = node2->parent;
3086	    misc = 1;
3087	    break;
3088	case XML_TEXT_NODE:
3089	case XML_CDATA_SECTION_NODE:
3090	case XML_COMMENT_NODE:
3091	case XML_PI_NODE: {
3092	    miscNode2 = node2;
3093	    if (node2->prev != NULL) {
3094		do {
3095		    node2 = node2->prev;
3096		    if (node2->type == XML_ELEMENT_NODE) {
3097			precedence2 = 3; /* element in prev-sibl axis */
3098			break;
3099		    }
3100		    if (node2->prev == NULL) {
3101			precedence2 = 2; /* element is parent */
3102			node2 = node2->parent;
3103			break;
3104		    }
3105		} while (1);
3106	    } else {
3107		precedence2 = 2; /* element is parent */
3108		node2 = node2->parent;
3109	    }
3110	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3111		(0 <= (long) node1->content))
3112	    {
3113		node2 = miscNode2;
3114		precedence2 = 0;
3115	    } else
3116		misc = 1;
3117	}
3118	    break;
3119	case XML_NAMESPACE_DECL:
3120	    return(1);
3121	default:
3122	    break;
3123    }
3124    if (misc) {
3125	if (node1 == node2) {
3126	    if (precedence1 == precedence2) {
3127		/*
3128		* The ugly case; but normally there aren't many
3129		* adjacent non-element nodes around.
3130		*/
3131		cur = miscNode2->prev;
3132		while (cur != NULL) {
3133		    if (cur == miscNode1)
3134			return(1);
3135		    if (cur->type == XML_ELEMENT_NODE)
3136			return(-1);
3137		    cur = cur->prev;
3138		}
3139		return (-1);
3140	    } else {
3141		/*
3142		* Evaluate based on higher precedence wrt to the element.
3143		* TODO: This assumes attributes are sorted before content.
3144		*   Is this 100% correct?
3145		*/
3146		if (precedence1 < precedence2)
3147		    return(1);
3148		else
3149		    return(-1);
3150	    }
3151	}
3152	/*
3153	* Special case: One of the helper-elements is contained by the other.
3154	* <foo>
3155	*   <node2>
3156	*     <node1>Text-1(precedence1 == 2)</node1>
3157	*   </node2>
3158	*   Text-6(precedence2 == 3)
3159	* </foo>
3160	*/
3161	if ((precedence2 == 3) && (precedence1 > 1)) {
3162	    cur = node1->parent;
3163	    while (cur) {
3164		if (cur == node2)
3165		    return(1);
3166		cur = cur->parent;
3167	    }
3168	}
3169	if ((precedence1 == 3) && (precedence2 > 1)) {
3170	    cur = node2->parent;
3171	    while (cur) {
3172		if (cur == node1)
3173		    return(-1);
3174		cur = cur->parent;
3175	    }
3176	}
3177    }
3178
3179    /*
3180     * Speedup using document order if availble.
3181     */
3182    if ((node1->type == XML_ELEMENT_NODE) &&
3183	(node2->type == XML_ELEMENT_NODE) &&
3184	(0 > (long) node1->content) &&
3185	(0 > (long) node2->content) &&
3186	(node1->doc == node2->doc)) {
3187
3188	l1 = -((long) node1->content);
3189	l2 = -((long) node2->content);
3190	if (l1 < l2)
3191	    return(1);
3192	if (l1 > l2)
3193	    return(-1);
3194    }
3195
3196turtle_comparison:
3197
3198    if (node1 == node2->prev)
3199	return(1);
3200    if (node1 == node2->next)
3201	return(-1);
3202    /*
3203     * compute depth to root
3204     */
3205    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3206	if (cur == node1)
3207	    return(1);
3208	depth2++;
3209    }
3210    root = cur;
3211    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3212	if (cur == node2)
3213	    return(-1);
3214	depth1++;
3215    }
3216    /*
3217     * Distinct document (or distinct entities :-( ) case.
3218     */
3219    if (root != cur) {
3220	return(-2);
3221    }
3222    /*
3223     * get the nearest common ancestor.
3224     */
3225    while (depth1 > depth2) {
3226	depth1--;
3227	node1 = node1->parent;
3228    }
3229    while (depth2 > depth1) {
3230	depth2--;
3231	node2 = node2->parent;
3232    }
3233    while (node1->parent != node2->parent) {
3234	node1 = node1->parent;
3235	node2 = node2->parent;
3236	/* should not happen but just in case ... */
3237	if ((node1 == NULL) || (node2 == NULL))
3238	    return(-2);
3239    }
3240    /*
3241     * Find who's first.
3242     */
3243    if (node1 == node2->prev)
3244	return(1);
3245    if (node1 == node2->next)
3246	return(-1);
3247    /*
3248     * Speedup using document order if availble.
3249     */
3250    if ((node1->type == XML_ELEMENT_NODE) &&
3251	(node2->type == XML_ELEMENT_NODE) &&
3252	(0 > (long) node1->content) &&
3253	(0 > (long) node2->content) &&
3254	(node1->doc == node2->doc)) {
3255
3256	l1 = -((long) node1->content);
3257	l2 = -((long) node2->content);
3258	if (l1 < l2)
3259	    return(1);
3260	if (l1 > l2)
3261	    return(-1);
3262    }
3263
3264    for (cur = node1->next;cur != NULL;cur = cur->next)
3265	if (cur == node2)
3266	    return(1);
3267    return(-1); /* assume there is no sibling list corruption */
3268}
3269#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
3270
3271/**
3272 * xmlXPathNodeSetSort:
3273 * @set:  the node set
3274 *
3275 * Sort the node set in document order
3276 */
3277void
3278xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3279    int i, j, incr, len;
3280    xmlNodePtr tmp;
3281
3282    if (set == NULL)
3283	return;
3284
3285    /* Use Shell's sort to sort the node-set */
3286    len = set->nodeNr;
3287    for (incr = len / 2; incr > 0; incr /= 2) {
3288	for (i = incr; i < len; i++) {
3289	    j = i - incr;
3290	    while (j >= 0) {
3291#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3292		if (xmlXPathCmpNodesExt(set->nodeTab[j],
3293			set->nodeTab[j + incr]) == -1)
3294#else
3295		if (xmlXPathCmpNodes(set->nodeTab[j],
3296			set->nodeTab[j + incr]) == -1)
3297#endif
3298		{
3299		    tmp = set->nodeTab[j];
3300		    set->nodeTab[j] = set->nodeTab[j + incr];
3301		    set->nodeTab[j + incr] = tmp;
3302		    j -= incr;
3303		} else
3304		    break;
3305	    }
3306	}
3307    }
3308}
3309
3310#define XML_NODESET_DEFAULT	10
3311/**
3312 * xmlXPathNodeSetDupNs:
3313 * @node:  the parent node of the namespace XPath node
3314 * @ns:  the libxml namespace declaration node.
3315 *
3316 * Namespace node in libxml don't match the XPath semantic. In a node set
3317 * the namespace nodes are duplicated and the next pointer is set to the
3318 * parent node in the XPath semantic.
3319 *
3320 * Returns the newly created object.
3321 */
3322static xmlNodePtr
3323xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3324    xmlNsPtr cur;
3325
3326    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3327	return(NULL);
3328    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3329	return((xmlNodePtr) ns);
3330
3331    /*
3332     * Allocate a new Namespace and fill the fields.
3333     */
3334    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3335    if (cur == NULL) {
3336        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3337	return(NULL);
3338    }
3339    memset(cur, 0, sizeof(xmlNs));
3340    cur->type = XML_NAMESPACE_DECL;
3341    if (ns->href != NULL)
3342	cur->href = xmlStrdup(ns->href);
3343    if (ns->prefix != NULL)
3344	cur->prefix = xmlStrdup(ns->prefix);
3345    cur->next = (xmlNsPtr) node;
3346    return((xmlNodePtr) cur);
3347}
3348
3349/**
3350 * xmlXPathNodeSetFreeNs:
3351 * @ns:  the XPath namespace node found in a nodeset.
3352 *
3353 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3354 * the namespace nodes are duplicated and the next pointer is set to the
3355 * parent node in the XPath semantic. Check if such a node needs to be freed
3356 */
3357void
3358xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3359    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3360	return;
3361
3362    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3363	if (ns->href != NULL)
3364	    xmlFree((xmlChar *)ns->href);
3365	if (ns->prefix != NULL)
3366	    xmlFree((xmlChar *)ns->prefix);
3367	xmlFree(ns);
3368    }
3369}
3370
3371/**
3372 * xmlXPathNodeSetCreate:
3373 * @val:  an initial xmlNodePtr, or NULL
3374 *
3375 * Create a new xmlNodeSetPtr of type double and of value @val
3376 *
3377 * Returns the newly created object.
3378 */
3379xmlNodeSetPtr
3380xmlXPathNodeSetCreate(xmlNodePtr val) {
3381    xmlNodeSetPtr ret;
3382
3383    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3384    if (ret == NULL) {
3385        xmlXPathErrMemory(NULL, "creating nodeset\n");
3386	return(NULL);
3387    }
3388    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3389    if (val != NULL) {
3390        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3391					     sizeof(xmlNodePtr));
3392	if (ret->nodeTab == NULL) {
3393	    xmlXPathErrMemory(NULL, "creating nodeset\n");
3394	    xmlFree(ret);
3395	    return(NULL);
3396	}
3397	memset(ret->nodeTab, 0 ,
3398	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3399        ret->nodeMax = XML_NODESET_DEFAULT;
3400	if (val->type == XML_NAMESPACE_DECL) {
3401	    xmlNsPtr ns = (xmlNsPtr) val;
3402
3403	    ret->nodeTab[ret->nodeNr++] =
3404		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3405	} else
3406	    ret->nodeTab[ret->nodeNr++] = val;
3407    }
3408    return(ret);
3409}
3410
3411/**
3412 * xmlXPathNodeSetCreateSize:
3413 * @size:  the initial size of the set
3414 *
3415 * Create a new xmlNodeSetPtr of type double and of value @val
3416 *
3417 * Returns the newly created object.
3418 */
3419static xmlNodeSetPtr
3420xmlXPathNodeSetCreateSize(int size) {
3421    xmlNodeSetPtr ret;
3422
3423    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3424    if (ret == NULL) {
3425        xmlXPathErrMemory(NULL, "creating nodeset\n");
3426	return(NULL);
3427    }
3428    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3429    if (size < XML_NODESET_DEFAULT)
3430	size = XML_NODESET_DEFAULT;
3431    ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3432    if (ret->nodeTab == NULL) {
3433	xmlXPathErrMemory(NULL, "creating nodeset\n");
3434	xmlFree(ret);
3435	return(NULL);
3436    }
3437    memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3438    ret->nodeMax = size;
3439    return(ret);
3440}
3441
3442/**
3443 * xmlXPathNodeSetContains:
3444 * @cur:  the node-set
3445 * @val:  the node
3446 *
3447 * checks whether @cur contains @val
3448 *
3449 * Returns true (1) if @cur contains @val, false (0) otherwise
3450 */
3451int
3452xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3453    int i;
3454
3455    if ((cur == NULL) || (val == NULL)) return(0);
3456    if (val->type == XML_NAMESPACE_DECL) {
3457	for (i = 0; i < cur->nodeNr; i++) {
3458	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3459		xmlNsPtr ns1, ns2;
3460
3461		ns1 = (xmlNsPtr) val;
3462		ns2 = (xmlNsPtr) cur->nodeTab[i];
3463		if (ns1 == ns2)
3464		    return(1);
3465		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3466	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
3467		    return(1);
3468	    }
3469	}
3470    } else {
3471	for (i = 0; i < cur->nodeNr; i++) {
3472	    if (cur->nodeTab[i] == val)
3473		return(1);
3474	}
3475    }
3476    return(0);
3477}
3478
3479/**
3480 * xmlXPathNodeSetAddNs:
3481 * @cur:  the initial node set
3482 * @node:  the hosting node
3483 * @ns:  a the namespace node
3484 *
3485 * add a new namespace node to an existing NodeSet
3486 */
3487void
3488xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3489    int i;
3490
3491
3492    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3493        (ns->type != XML_NAMESPACE_DECL) ||
3494	(node->type != XML_ELEMENT_NODE))
3495	return;
3496
3497    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3498    /*
3499     * prevent duplicates
3500     */
3501    for (i = 0;i < cur->nodeNr;i++) {
3502        if ((cur->nodeTab[i] != NULL) &&
3503	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3504	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3505	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3506	    return;
3507    }
3508
3509    /*
3510     * grow the nodeTab if needed
3511     */
3512    if (cur->nodeMax == 0) {
3513        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3514					     sizeof(xmlNodePtr));
3515	if (cur->nodeTab == NULL) {
3516	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3517	    return;
3518	}
3519	memset(cur->nodeTab, 0 ,
3520	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3521        cur->nodeMax = XML_NODESET_DEFAULT;
3522    } else if (cur->nodeNr == cur->nodeMax) {
3523        xmlNodePtr *temp;
3524
3525        cur->nodeMax *= 2;
3526	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3527				      sizeof(xmlNodePtr));
3528	if (temp == NULL) {
3529	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3530	    return;
3531	}
3532	cur->nodeTab = temp;
3533    }
3534    cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3535}
3536
3537/**
3538 * xmlXPathNodeSetAdd:
3539 * @cur:  the initial node set
3540 * @val:  a new xmlNodePtr
3541 *
3542 * add a new xmlNodePtr to an existing NodeSet
3543 */
3544void
3545xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3546    int i;
3547
3548    if ((cur == NULL) || (val == NULL)) return;
3549
3550#if 0
3551    if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3552	return;	/* an XSLT fake node */
3553#endif
3554
3555    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3556    /*
3557     * prevent duplcates
3558     */
3559    for (i = 0;i < cur->nodeNr;i++)
3560        if (cur->nodeTab[i] == val) return;
3561
3562    /*
3563     * grow the nodeTab if needed
3564     */
3565    if (cur->nodeMax == 0) {
3566        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3567					     sizeof(xmlNodePtr));
3568	if (cur->nodeTab == NULL) {
3569	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3570	    return;
3571	}
3572	memset(cur->nodeTab, 0 ,
3573	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3574        cur->nodeMax = XML_NODESET_DEFAULT;
3575    } else if (cur->nodeNr == cur->nodeMax) {
3576        xmlNodePtr *temp;
3577
3578        cur->nodeMax *= 2;
3579	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3580				      sizeof(xmlNodePtr));
3581	if (temp == NULL) {
3582	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3583	    return;
3584	}
3585	cur->nodeTab = temp;
3586    }
3587    if (val->type == XML_NAMESPACE_DECL) {
3588	xmlNsPtr ns = (xmlNsPtr) val;
3589
3590	cur->nodeTab[cur->nodeNr++] =
3591	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3592    } else
3593	cur->nodeTab[cur->nodeNr++] = val;
3594}
3595
3596/**
3597 * xmlXPathNodeSetAddUnique:
3598 * @cur:  the initial node set
3599 * @val:  a new xmlNodePtr
3600 *
3601 * add a new xmlNodePtr to an existing NodeSet, optimized version
3602 * when we are sure the node is not already in the set.
3603 */
3604void
3605xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3606    if ((cur == NULL) || (val == NULL)) return;
3607
3608#if 0
3609    if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3610	return;	/* an XSLT fake node */
3611#endif
3612
3613    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3614    /*
3615     * grow the nodeTab if needed
3616     */
3617    if (cur->nodeMax == 0) {
3618        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3619					     sizeof(xmlNodePtr));
3620	if (cur->nodeTab == NULL) {
3621	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3622	    return;
3623	}
3624	memset(cur->nodeTab, 0 ,
3625	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3626        cur->nodeMax = XML_NODESET_DEFAULT;
3627    } else if (cur->nodeNr == cur->nodeMax) {
3628        xmlNodePtr *temp;
3629
3630        cur->nodeMax *= 2;
3631	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3632				      sizeof(xmlNodePtr));
3633	if (temp == NULL) {
3634	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3635	    return;
3636	}
3637	cur->nodeTab = temp;
3638    }
3639    if (val->type == XML_NAMESPACE_DECL) {
3640	xmlNsPtr ns = (xmlNsPtr) val;
3641
3642	cur->nodeTab[cur->nodeNr++] =
3643	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3644    } else
3645	cur->nodeTab[cur->nodeNr++] = val;
3646}
3647
3648/**
3649 * xmlXPathNodeSetMerge:
3650 * @val1:  the first NodeSet or NULL
3651 * @val2:  the second NodeSet
3652 *
3653 * Merges two nodesets, all nodes from @val2 are added to @val1
3654 * if @val1 is NULL, a new set is created and copied from @val2
3655 *
3656 * Returns @val1 once extended or NULL in case of error.
3657 */
3658xmlNodeSetPtr
3659xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3660    int i, j, initNr, skip;
3661    xmlNodePtr n1, n2;
3662
3663    if (val2 == NULL) return(val1);
3664    if (val1 == NULL) {
3665	val1 = xmlXPathNodeSetCreate(NULL);
3666    if (val1 == NULL)
3667        return (NULL);
3668#if 0
3669	/*
3670	* TODO: The optimization won't work in every case, since
3671	*  those nasty namespace nodes need to be added with
3672	*  xmlXPathNodeSetDupNs() to the set; thus a pure
3673	*  memcpy is not possible.
3674	*  If there was a flag on the nodesetval, indicating that
3675	*  some temporary nodes are in, that would be helpfull.
3676	*/
3677	/*
3678	* Optimization: Create an equally sized node-set
3679	* and memcpy the content.
3680	*/
3681	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3682	if (val1 == NULL)
3683	    return(NULL);
3684	if (val2->nodeNr != 0) {
3685	    if (val2->nodeNr == 1)
3686		*(val1->nodeTab) = *(val2->nodeTab);
3687	    else {
3688		memcpy(val1->nodeTab, val2->nodeTab,
3689		    val2->nodeNr * sizeof(xmlNodePtr));
3690	    }
3691	    val1->nodeNr = val2->nodeNr;
3692	}
3693	return(val1);
3694#endif
3695    }
3696
3697    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3698    initNr = val1->nodeNr;
3699
3700    for (i = 0;i < val2->nodeNr;i++) {
3701	n2 = val2->nodeTab[i];
3702	/*
3703	 * check against duplicates
3704	 */
3705	skip = 0;
3706	for (j = 0; j < initNr; j++) {
3707	    n1 = val1->nodeTab[j];
3708	    if (n1 == n2) {
3709		skip = 1;
3710		break;
3711	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3712		       (n2->type == XML_NAMESPACE_DECL)) {
3713		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3714		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3715			((xmlNsPtr) n2)->prefix)))
3716		{
3717		    skip = 1;
3718		    break;
3719		}
3720	    }
3721	}
3722	if (skip)
3723	    continue;
3724
3725	/*
3726	 * grow the nodeTab if needed
3727	 */
3728	if (val1->nodeMax == 0) {
3729	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3730						    sizeof(xmlNodePtr));
3731	    if (val1->nodeTab == NULL) {
3732	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3733		return(NULL);
3734	    }
3735	    memset(val1->nodeTab, 0 ,
3736		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3737	    val1->nodeMax = XML_NODESET_DEFAULT;
3738	} else if (val1->nodeNr == val1->nodeMax) {
3739	    xmlNodePtr *temp;
3740
3741	    val1->nodeMax *= 2;
3742	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3743					     sizeof(xmlNodePtr));
3744	    if (temp == NULL) {
3745	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3746		return(NULL);
3747	    }
3748	    val1->nodeTab = temp;
3749	}
3750	if (n2->type == XML_NAMESPACE_DECL) {
3751	    xmlNsPtr ns = (xmlNsPtr) n2;
3752
3753	    val1->nodeTab[val1->nodeNr++] =
3754		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3755	} else
3756	    val1->nodeTab[val1->nodeNr++] = n2;
3757    }
3758
3759    return(val1);
3760}
3761
3762#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3763/**
3764 * xmlXPathNodeSetMergeUnique:
3765 * @val1:  the first NodeSet or NULL
3766 * @val2:  the second NodeSet
3767 *
3768 * Merges two nodesets, all nodes from @val2 are added to @val1
3769 * if @val1 is NULL, a new set is created and copied from @val2
3770 *
3771 * Returns @val1 once extended or NULL in case of error.
3772 */
3773static xmlNodeSetPtr
3774xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3775    int i;
3776
3777    if (val2 == NULL) return(val1);
3778    if (val1 == NULL) {
3779	val1 = xmlXPathNodeSetCreate(NULL);
3780    }
3781    if (val1 == NULL)
3782        return (NULL);
3783
3784    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3785
3786    for (i = 0;i < val2->nodeNr;i++) {
3787	/*
3788	 * grow the nodeTab if needed
3789	 */
3790	if (val1->nodeMax == 0) {
3791	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3792						    sizeof(xmlNodePtr));
3793	    if (val1->nodeTab == NULL) {
3794	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3795		return(NULL);
3796	    }
3797	    memset(val1->nodeTab, 0 ,
3798		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3799	    val1->nodeMax = XML_NODESET_DEFAULT;
3800	} else if (val1->nodeNr == val1->nodeMax) {
3801	    xmlNodePtr *temp;
3802
3803	    val1->nodeMax *= 2;
3804	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3805					     sizeof(xmlNodePtr));
3806	    if (temp == NULL) {
3807	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3808		return(NULL);
3809	    }
3810	    val1->nodeTab = temp;
3811	}
3812	if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3813	    xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3814
3815	    val1->nodeTab[val1->nodeNr++] =
3816		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3817	} else
3818	    val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3819    }
3820
3821    return(val1);
3822}
3823#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3824
3825/**
3826 * xmlXPathNodeSetMergeAndClear:
3827 * @set1:  the first NodeSet or NULL
3828 * @set2:  the second NodeSet
3829 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3830 *
3831 * Merges two nodesets, all nodes from @set2 are added to @set1
3832 * if @set1 is NULL, a new set is created and copied from @set2.
3833 * Checks for duplicate nodes. Clears set2.
3834 *
3835 * Returns @set1 once extended or NULL in case of error.
3836 */
3837static xmlNodeSetPtr
3838xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3839			     int hasNullEntries)
3840{
3841    if ((set1 == NULL) && (hasNullEntries == 0)) {
3842	/*
3843	* Note that doing a memcpy of the list, namespace nodes are
3844	* just assigned to set1, since set2 is cleared anyway.
3845	*/
3846	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3847	if (set1 == NULL)
3848	    return(NULL);
3849	if (set2->nodeNr != 0) {
3850	    memcpy(set1->nodeTab, set2->nodeTab,
3851		set2->nodeNr * sizeof(xmlNodePtr));
3852	    set1->nodeNr = set2->nodeNr;
3853	}
3854    } else {
3855	int i, j, initNbSet1;
3856	xmlNodePtr n1, n2;
3857
3858	if (set1 == NULL)
3859            set1 = xmlXPathNodeSetCreate(NULL);
3860        if (set1 == NULL)
3861            return (NULL);
3862
3863	initNbSet1 = set1->nodeNr;
3864	for (i = 0;i < set2->nodeNr;i++) {
3865	    n2 = set2->nodeTab[i];
3866	    /*
3867	    * Skip NULLed entries.
3868	    */
3869	    if (n2 == NULL)
3870		continue;
3871	    /*
3872	    * Skip duplicates.
3873	    */
3874	    for (j = 0; j < initNbSet1; j++) {
3875		n1 = set1->nodeTab[j];
3876		if (n1 == n2) {
3877		    goto skip_node;
3878		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3879		    (n2->type == XML_NAMESPACE_DECL))
3880		{
3881		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3882			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3883			((xmlNsPtr) n2)->prefix)))
3884		    {
3885			/*
3886			* Free the namespace node.
3887			*/
3888			set2->nodeTab[i] = NULL;
3889			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3890			goto skip_node;
3891		    }
3892		}
3893	    }
3894	    /*
3895	    * grow the nodeTab if needed
3896	    */
3897	    if (set1->nodeMax == 0) {
3898		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3899		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3900		if (set1->nodeTab == NULL) {
3901		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3902		    return(NULL);
3903		}
3904		memset(set1->nodeTab, 0,
3905		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3906		set1->nodeMax = XML_NODESET_DEFAULT;
3907	    } else if (set1->nodeNr >= set1->nodeMax) {
3908		xmlNodePtr *temp;
3909
3910		set1->nodeMax *= 2;
3911		temp = (xmlNodePtr *) xmlRealloc(
3912		    set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3913		if (temp == NULL) {
3914		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3915		    return(NULL);
3916		}
3917		set1->nodeTab = temp;
3918	    }
3919	    if (n2->type == XML_NAMESPACE_DECL) {
3920		xmlNsPtr ns = (xmlNsPtr) n2;
3921
3922		set1->nodeTab[set1->nodeNr++] =
3923		    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3924	    } else
3925		set1->nodeTab[set1->nodeNr++] = n2;
3926skip_node:
3927	    {}
3928	}
3929    }
3930    set2->nodeNr = 0;
3931    return(set1);
3932}
3933
3934/**
3935 * xmlXPathNodeSetMergeAndClearNoDupls:
3936 * @set1:  the first NodeSet or NULL
3937 * @set2:  the second NodeSet
3938 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3939 *
3940 * Merges two nodesets, all nodes from @set2 are added to @set1
3941 * if @set1 is NULL, a new set is created and copied from @set2.
3942 * Doesn't chack for duplicate nodes. Clears set2.
3943 *
3944 * Returns @set1 once extended or NULL in case of error.
3945 */
3946static xmlNodeSetPtr
3947xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3948				    int hasNullEntries)
3949{
3950    if (set2 == NULL)
3951	return(set1);
3952    if ((set1 == NULL) && (hasNullEntries == 0)) {
3953	/*
3954	* Note that doing a memcpy of the list, namespace nodes are
3955	* just assigned to set1, since set2 is cleared anyway.
3956	*/
3957	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3958	if (set1 == NULL)
3959	    return(NULL);
3960	if (set2->nodeNr != 0) {
3961	    memcpy(set1->nodeTab, set2->nodeTab,
3962		set2->nodeNr * sizeof(xmlNodePtr));
3963	    set1->nodeNr = set2->nodeNr;
3964	}
3965    } else {
3966	int i;
3967	xmlNodePtr n2;
3968
3969	if (set1 == NULL)
3970	    set1 = xmlXPathNodeSetCreate(NULL);
3971        if (set1 == NULL)
3972            return (NULL);
3973
3974	for (i = 0;i < set2->nodeNr;i++) {
3975	    n2 = set2->nodeTab[i];
3976	    /*
3977	    * Skip NULLed entries.
3978	    */
3979	    if (n2 == NULL)
3980		continue;
3981	    if (set1->nodeMax == 0) {
3982		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3983		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3984		if (set1->nodeTab == NULL) {
3985		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3986		    return(NULL);
3987		}
3988		memset(set1->nodeTab, 0,
3989		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3990		set1->nodeMax = XML_NODESET_DEFAULT;
3991	    } else if (set1->nodeNr >= set1->nodeMax) {
3992		xmlNodePtr *temp;
3993
3994		set1->nodeMax *= 2;
3995		temp = (xmlNodePtr *) xmlRealloc(
3996		    set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3997		if (temp == NULL) {
3998		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3999		    return(NULL);
4000		}
4001		set1->nodeTab = temp;
4002	    }
4003	    set1->nodeTab[set1->nodeNr++] = n2;
4004	}
4005    }
4006    set2->nodeNr = 0;
4007    return(set1);
4008}
4009
4010/**
4011 * xmlXPathNodeSetDel:
4012 * @cur:  the initial node set
4013 * @val:  an xmlNodePtr
4014 *
4015 * Removes an xmlNodePtr from an existing NodeSet
4016 */
4017void
4018xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4019    int i;
4020
4021    if (cur == NULL) return;
4022    if (val == NULL) return;
4023
4024    /*
4025     * find node in nodeTab
4026     */
4027    for (i = 0;i < cur->nodeNr;i++)
4028        if (cur->nodeTab[i] == val) break;
4029
4030    if (i >= cur->nodeNr) {	/* not found */
4031#ifdef DEBUG
4032        xmlGenericError(xmlGenericErrorContext,
4033	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4034		val->name);
4035#endif
4036        return;
4037    }
4038    if ((cur->nodeTab[i] != NULL) &&
4039	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4040	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4041    cur->nodeNr--;
4042    for (;i < cur->nodeNr;i++)
4043        cur->nodeTab[i] = cur->nodeTab[i + 1];
4044    cur->nodeTab[cur->nodeNr] = NULL;
4045}
4046
4047/**
4048 * xmlXPathNodeSetRemove:
4049 * @cur:  the initial node set
4050 * @val:  the index to remove
4051 *
4052 * Removes an entry from an existing NodeSet list.
4053 */
4054void
4055xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4056    if (cur == NULL) return;
4057    if (val >= cur->nodeNr) return;
4058    if ((cur->nodeTab[val] != NULL) &&
4059	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4060	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4061    cur->nodeNr--;
4062    for (;val < cur->nodeNr;val++)
4063        cur->nodeTab[val] = cur->nodeTab[val + 1];
4064    cur->nodeTab[cur->nodeNr] = NULL;
4065}
4066
4067/**
4068 * xmlXPathFreeNodeSet:
4069 * @obj:  the xmlNodeSetPtr to free
4070 *
4071 * Free the NodeSet compound (not the actual nodes !).
4072 */
4073void
4074xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4075    if (obj == NULL) return;
4076    if (obj->nodeTab != NULL) {
4077	int i;
4078
4079	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
4080	for (i = 0;i < obj->nodeNr;i++)
4081	    if ((obj->nodeTab[i] != NULL) &&
4082		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4083		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4084	xmlFree(obj->nodeTab);
4085    }
4086    xmlFree(obj);
4087}
4088
4089/**
4090 * xmlXPathNodeSetClear:
4091 * @set:  the node set to clear
4092 *
4093 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4094 * are feed), but does *not* free the list itself. Sets the length of the
4095 * list to 0.
4096 */
4097static void
4098xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4099{
4100    if ((set == NULL) || (set->nodeNr <= 0))
4101	return;
4102    else if (hasNsNodes) {
4103	int i;
4104	xmlNodePtr node;
4105
4106	for (i = 0; i < set->nodeNr; i++) {
4107	    node = set->nodeTab[i];
4108	    if ((node != NULL) &&
4109		(node->type == XML_NAMESPACE_DECL))
4110		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4111	}
4112    }
4113    set->nodeNr = 0;
4114}
4115
4116/**
4117 * xmlXPathNodeSetClearFromPos:
4118 * @set: the node set to be cleared
4119 * @pos: the start position to clear from
4120 *
4121 * Clears the list from temporary XPath objects (e.g. namespace nodes
4122 * are feed) starting with the entry at @pos, but does *not* free the list
4123 * itself. Sets the length of the list to @pos.
4124 */
4125static void
4126xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4127{
4128    if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4129	return;
4130    else if ((hasNsNodes)) {
4131	int i;
4132	xmlNodePtr node;
4133
4134	for (i = pos; i < set->nodeNr; i++) {
4135	    node = set->nodeTab[i];
4136	    if ((node != NULL) &&
4137		(node->type == XML_NAMESPACE_DECL))
4138		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4139	}
4140    }
4141    set->nodeNr = pos;
4142}
4143
4144/**
4145 * xmlXPathFreeValueTree:
4146 * @obj:  the xmlNodeSetPtr to free
4147 *
4148 * Free the NodeSet compound and the actual tree, this is different
4149 * from xmlXPathFreeNodeSet()
4150 */
4151static void
4152xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4153    int i;
4154
4155    if (obj == NULL) return;
4156
4157    if (obj->nodeTab != NULL) {
4158	for (i = 0;i < obj->nodeNr;i++) {
4159	    if (obj->nodeTab[i] != NULL) {
4160		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4161		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4162		} else {
4163		    xmlFreeNodeList(obj->nodeTab[i]);
4164		}
4165	    }
4166	}
4167	xmlFree(obj->nodeTab);
4168    }
4169    xmlFree(obj);
4170}
4171
4172#if defined(DEBUG) || defined(DEBUG_STEP)
4173/**
4174 * xmlGenericErrorContextNodeSet:
4175 * @output:  a FILE * for the output
4176 * @obj:  the xmlNodeSetPtr to display
4177 *
4178 * Quick display of a NodeSet
4179 */
4180void
4181xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4182    int i;
4183
4184    if (output == NULL) output = xmlGenericErrorContext;
4185    if (obj == NULL)  {
4186        fprintf(output, "NodeSet == NULL !\n");
4187	return;
4188    }
4189    if (obj->nodeNr == 0) {
4190        fprintf(output, "NodeSet is empty\n");
4191	return;
4192    }
4193    if (obj->nodeTab == NULL) {
4194	fprintf(output, " nodeTab == NULL !\n");
4195	return;
4196    }
4197    for (i = 0; i < obj->nodeNr; i++) {
4198        if (obj->nodeTab[i] == NULL) {
4199	    fprintf(output, " NULL !\n");
4200	    return;
4201        }
4202	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4203	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4204	    fprintf(output, " /");
4205	else if (obj->nodeTab[i]->name == NULL)
4206	    fprintf(output, " noname!");
4207	else fprintf(output, " %s", obj->nodeTab[i]->name);
4208    }
4209    fprintf(output, "\n");
4210}
4211#endif
4212
4213/**
4214 * xmlXPathNewNodeSet:
4215 * @val:  the NodePtr value
4216 *
4217 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4218 * it with the single Node @val
4219 *
4220 * Returns the newly created object.
4221 */
4222xmlXPathObjectPtr
4223xmlXPathNewNodeSet(xmlNodePtr val) {
4224    xmlXPathObjectPtr ret;
4225
4226    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4227    if (ret == NULL) {
4228        xmlXPathErrMemory(NULL, "creating nodeset\n");
4229	return(NULL);
4230    }
4231    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4232    ret->type = XPATH_NODESET;
4233    ret->boolval = 0;
4234    ret->nodesetval = xmlXPathNodeSetCreate(val);
4235    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4236#ifdef XP_DEBUG_OBJ_USAGE
4237    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4238#endif
4239    return(ret);
4240}
4241
4242/**
4243 * xmlXPathNewValueTree:
4244 * @val:  the NodePtr value
4245 *
4246 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4247 * it with the tree root @val
4248 *
4249 * Returns the newly created object.
4250 */
4251xmlXPathObjectPtr
4252xmlXPathNewValueTree(xmlNodePtr val) {
4253    xmlXPathObjectPtr ret;
4254
4255    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4256    if (ret == NULL) {
4257        xmlXPathErrMemory(NULL, "creating result value tree\n");
4258	return(NULL);
4259    }
4260    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4261    ret->type = XPATH_XSLT_TREE;
4262    ret->boolval = 1;
4263    ret->user = (void *) val;
4264    ret->nodesetval = xmlXPathNodeSetCreate(val);
4265#ifdef XP_DEBUG_OBJ_USAGE
4266    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4267#endif
4268    return(ret);
4269}
4270
4271/**
4272 * xmlXPathNewNodeSetList:
4273 * @val:  an existing NodeSet
4274 *
4275 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4276 * it with the Nodeset @val
4277 *
4278 * Returns the newly created object.
4279 */
4280xmlXPathObjectPtr
4281xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4282{
4283    xmlXPathObjectPtr ret;
4284    int i;
4285
4286    if (val == NULL)
4287        ret = NULL;
4288    else if (val->nodeTab == NULL)
4289        ret = xmlXPathNewNodeSet(NULL);
4290    else {
4291        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4292        if (ret)
4293            for (i = 1; i < val->nodeNr; ++i)
4294                xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4295    }
4296
4297    return (ret);
4298}
4299
4300/**
4301 * xmlXPathWrapNodeSet:
4302 * @val:  the NodePtr value
4303 *
4304 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4305 *
4306 * Returns the newly created object.
4307 */
4308xmlXPathObjectPtr
4309xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4310    xmlXPathObjectPtr ret;
4311
4312    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4313    if (ret == NULL) {
4314        xmlXPathErrMemory(NULL, "creating node set object\n");
4315	return(NULL);
4316    }
4317    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4318    ret->type = XPATH_NODESET;
4319    ret->nodesetval = val;
4320#ifdef XP_DEBUG_OBJ_USAGE
4321    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4322#endif
4323    return(ret);
4324}
4325
4326/**
4327 * xmlXPathFreeNodeSetList:
4328 * @obj:  an existing NodeSetList object
4329 *
4330 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4331 * the list contrary to xmlXPathFreeObject().
4332 */
4333void
4334xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4335    if (obj == NULL) return;
4336#ifdef XP_DEBUG_OBJ_USAGE
4337    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4338#endif
4339    xmlFree(obj);
4340}
4341
4342/**
4343 * xmlXPathDifference:
4344 * @nodes1:  a node-set
4345 * @nodes2:  a node-set
4346 *
4347 * Implements the EXSLT - Sets difference() function:
4348 *    node-set set:difference (node-set, node-set)
4349 *
4350 * Returns the difference between the two node sets, or nodes1 if
4351 *         nodes2 is empty
4352 */
4353xmlNodeSetPtr
4354xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4355    xmlNodeSetPtr ret;
4356    int i, l1;
4357    xmlNodePtr cur;
4358
4359    if (xmlXPathNodeSetIsEmpty(nodes2))
4360	return(nodes1);
4361
4362    ret = xmlXPathNodeSetCreate(NULL);
4363    if (xmlXPathNodeSetIsEmpty(nodes1))
4364	return(ret);
4365
4366    l1 = xmlXPathNodeSetGetLength(nodes1);
4367
4368    for (i = 0; i < l1; i++) {
4369	cur = xmlXPathNodeSetItem(nodes1, i);
4370	if (!xmlXPathNodeSetContains(nodes2, cur))
4371	    xmlXPathNodeSetAddUnique(ret, cur);
4372    }
4373    return(ret);
4374}
4375
4376/**
4377 * xmlXPathIntersection:
4378 * @nodes1:  a node-set
4379 * @nodes2:  a node-set
4380 *
4381 * Implements the EXSLT - Sets intersection() function:
4382 *    node-set set:intersection (node-set, node-set)
4383 *
4384 * Returns a node set comprising the nodes that are within both the
4385 *         node sets passed as arguments
4386 */
4387xmlNodeSetPtr
4388xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4389    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4390    int i, l1;
4391    xmlNodePtr cur;
4392
4393    if (ret == NULL)
4394        return(ret);
4395    if (xmlXPathNodeSetIsEmpty(nodes1))
4396	return(ret);
4397    if (xmlXPathNodeSetIsEmpty(nodes2))
4398	return(ret);
4399
4400    l1 = xmlXPathNodeSetGetLength(nodes1);
4401
4402    for (i = 0; i < l1; i++) {
4403	cur = xmlXPathNodeSetItem(nodes1, i);
4404	if (xmlXPathNodeSetContains(nodes2, cur))
4405	    xmlXPathNodeSetAddUnique(ret, cur);
4406    }
4407    return(ret);
4408}
4409
4410/**
4411 * xmlXPathDistinctSorted:
4412 * @nodes:  a node-set, sorted by document order
4413 *
4414 * Implements the EXSLT - Sets distinct() function:
4415 *    node-set set:distinct (node-set)
4416 *
4417 * Returns a subset of the nodes contained in @nodes, or @nodes if
4418 *         it is empty
4419 */
4420xmlNodeSetPtr
4421xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4422    xmlNodeSetPtr ret;
4423    xmlHashTablePtr hash;
4424    int i, l;
4425    xmlChar * strval;
4426    xmlNodePtr cur;
4427
4428    if (xmlXPathNodeSetIsEmpty(nodes))
4429	return(nodes);
4430
4431    ret = xmlXPathNodeSetCreate(NULL);
4432    if (ret == NULL)
4433        return(ret);
4434    l = xmlXPathNodeSetGetLength(nodes);
4435    hash = xmlHashCreate (l);
4436    for (i = 0; i < l; i++) {
4437	cur = xmlXPathNodeSetItem(nodes, i);
4438	strval = xmlXPathCastNodeToString(cur);
4439	if (xmlHashLookup(hash, strval) == NULL) {
4440	    xmlHashAddEntry(hash, strval, strval);
4441	    xmlXPathNodeSetAddUnique(ret, cur);
4442	} else {
4443	    xmlFree(strval);
4444	}
4445    }
4446    xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4447    return(ret);
4448}
4449
4450/**
4451 * xmlXPathDistinct:
4452 * @nodes:  a node-set
4453 *
4454 * Implements the EXSLT - Sets distinct() function:
4455 *    node-set set:distinct (node-set)
4456 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4457 * is called with the sorted node-set
4458 *
4459 * Returns a subset of the nodes contained in @nodes, or @nodes if
4460 *         it is empty
4461 */
4462xmlNodeSetPtr
4463xmlXPathDistinct (xmlNodeSetPtr nodes) {
4464    if (xmlXPathNodeSetIsEmpty(nodes))
4465	return(nodes);
4466
4467    xmlXPathNodeSetSort(nodes);
4468    return(xmlXPathDistinctSorted(nodes));
4469}
4470
4471/**
4472 * xmlXPathHasSameNodes:
4473 * @nodes1:  a node-set
4474 * @nodes2:  a node-set
4475 *
4476 * Implements the EXSLT - Sets has-same-nodes function:
4477 *    boolean set:has-same-node(node-set, node-set)
4478 *
4479 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4480 *         otherwise
4481 */
4482int
4483xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4484    int i, l;
4485    xmlNodePtr cur;
4486
4487    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4488	xmlXPathNodeSetIsEmpty(nodes2))
4489	return(0);
4490
4491    l = xmlXPathNodeSetGetLength(nodes1);
4492    for (i = 0; i < l; i++) {
4493	cur = xmlXPathNodeSetItem(nodes1, i);
4494	if (xmlXPathNodeSetContains(nodes2, cur))
4495	    return(1);
4496    }
4497    return(0);
4498}
4499
4500/**
4501 * xmlXPathNodeLeadingSorted:
4502 * @nodes: a node-set, sorted by document order
4503 * @node: a node
4504 *
4505 * Implements the EXSLT - Sets leading() function:
4506 *    node-set set:leading (node-set, node-set)
4507 *
4508 * Returns the nodes in @nodes that precede @node in document order,
4509 *         @nodes if @node is NULL or an empty node-set if @nodes
4510 *         doesn't contain @node
4511 */
4512xmlNodeSetPtr
4513xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4514    int i, l;
4515    xmlNodePtr cur;
4516    xmlNodeSetPtr ret;
4517
4518    if (node == NULL)
4519	return(nodes);
4520
4521    ret = xmlXPathNodeSetCreate(NULL);
4522    if (ret == NULL)
4523        return(ret);
4524    if (xmlXPathNodeSetIsEmpty(nodes) ||
4525	(!xmlXPathNodeSetContains(nodes, node)))
4526	return(ret);
4527
4528    l = xmlXPathNodeSetGetLength(nodes);
4529    for (i = 0; i < l; i++) {
4530	cur = xmlXPathNodeSetItem(nodes, i);
4531	if (cur == node)
4532	    break;
4533	xmlXPathNodeSetAddUnique(ret, cur);
4534    }
4535    return(ret);
4536}
4537
4538/**
4539 * xmlXPathNodeLeading:
4540 * @nodes:  a node-set
4541 * @node:  a node
4542 *
4543 * Implements the EXSLT - Sets leading() function:
4544 *    node-set set:leading (node-set, node-set)
4545 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4546 * is called.
4547 *
4548 * Returns the nodes in @nodes that precede @node in document order,
4549 *         @nodes if @node is NULL or an empty node-set if @nodes
4550 *         doesn't contain @node
4551 */
4552xmlNodeSetPtr
4553xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4554    xmlXPathNodeSetSort(nodes);
4555    return(xmlXPathNodeLeadingSorted(nodes, node));
4556}
4557
4558/**
4559 * xmlXPathLeadingSorted:
4560 * @nodes1:  a node-set, sorted by document order
4561 * @nodes2:  a node-set, sorted by document order
4562 *
4563 * Implements the EXSLT - Sets leading() function:
4564 *    node-set set:leading (node-set, node-set)
4565 *
4566 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4567 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4568 *         an empty node-set if @nodes1 doesn't contain @nodes2
4569 */
4570xmlNodeSetPtr
4571xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4572    if (xmlXPathNodeSetIsEmpty(nodes2))
4573	return(nodes1);
4574    return(xmlXPathNodeLeadingSorted(nodes1,
4575				     xmlXPathNodeSetItem(nodes2, 1)));
4576}
4577
4578/**
4579 * xmlXPathLeading:
4580 * @nodes1:  a node-set
4581 * @nodes2:  a node-set
4582 *
4583 * Implements the EXSLT - Sets leading() function:
4584 *    node-set set:leading (node-set, node-set)
4585 * @nodes1 and @nodes2 are sorted by document order, then
4586 * #exslSetsLeadingSorted is called.
4587 *
4588 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4589 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4590 *         an empty node-set if @nodes1 doesn't contain @nodes2
4591 */
4592xmlNodeSetPtr
4593xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4594    if (xmlXPathNodeSetIsEmpty(nodes2))
4595	return(nodes1);
4596    if (xmlXPathNodeSetIsEmpty(nodes1))
4597	return(xmlXPathNodeSetCreate(NULL));
4598    xmlXPathNodeSetSort(nodes1);
4599    xmlXPathNodeSetSort(nodes2);
4600    return(xmlXPathNodeLeadingSorted(nodes1,
4601				     xmlXPathNodeSetItem(nodes2, 1)));
4602}
4603
4604/**
4605 * xmlXPathNodeTrailingSorted:
4606 * @nodes: a node-set, sorted by document order
4607 * @node: a node
4608 *
4609 * Implements the EXSLT - Sets trailing() function:
4610 *    node-set set:trailing (node-set, node-set)
4611 *
4612 * Returns the nodes in @nodes that follow @node in document order,
4613 *         @nodes if @node is NULL or an empty node-set if @nodes
4614 *         doesn't contain @node
4615 */
4616xmlNodeSetPtr
4617xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4618    int i, l;
4619    xmlNodePtr cur;
4620    xmlNodeSetPtr ret;
4621
4622    if (node == NULL)
4623	return(nodes);
4624
4625    ret = xmlXPathNodeSetCreate(NULL);
4626    if (ret == NULL)
4627        return(ret);
4628    if (xmlXPathNodeSetIsEmpty(nodes) ||
4629	(!xmlXPathNodeSetContains(nodes, node)))
4630	return(ret);
4631
4632    l = xmlXPathNodeSetGetLength(nodes);
4633    for (i = l - 1; i >= 0; i--) {
4634	cur = xmlXPathNodeSetItem(nodes, i);
4635	if (cur == node)
4636	    break;
4637	xmlXPathNodeSetAddUnique(ret, cur);
4638    }
4639    xmlXPathNodeSetSort(ret);	/* bug 413451 */
4640    return(ret);
4641}
4642
4643/**
4644 * xmlXPathNodeTrailing:
4645 * @nodes:  a node-set
4646 * @node:  a node
4647 *
4648 * Implements the EXSLT - Sets trailing() function:
4649 *    node-set set:trailing (node-set, node-set)
4650 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4651 * is called.
4652 *
4653 * Returns the nodes in @nodes that follow @node in document order,
4654 *         @nodes if @node is NULL or an empty node-set if @nodes
4655 *         doesn't contain @node
4656 */
4657xmlNodeSetPtr
4658xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4659    xmlXPathNodeSetSort(nodes);
4660    return(xmlXPathNodeTrailingSorted(nodes, node));
4661}
4662
4663/**
4664 * xmlXPathTrailingSorted:
4665 * @nodes1:  a node-set, sorted by document order
4666 * @nodes2:  a node-set, sorted by document order
4667 *
4668 * Implements the EXSLT - Sets trailing() function:
4669 *    node-set set:trailing (node-set, node-set)
4670 *
4671 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4672 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4673 *         an empty node-set if @nodes1 doesn't contain @nodes2
4674 */
4675xmlNodeSetPtr
4676xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4677    if (xmlXPathNodeSetIsEmpty(nodes2))
4678	return(nodes1);
4679    return(xmlXPathNodeTrailingSorted(nodes1,
4680				      xmlXPathNodeSetItem(nodes2, 0)));
4681}
4682
4683/**
4684 * xmlXPathTrailing:
4685 * @nodes1:  a node-set
4686 * @nodes2:  a node-set
4687 *
4688 * Implements the EXSLT - Sets trailing() function:
4689 *    node-set set:trailing (node-set, node-set)
4690 * @nodes1 and @nodes2 are sorted by document order, then
4691 * #xmlXPathTrailingSorted is called.
4692 *
4693 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4694 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4695 *         an empty node-set if @nodes1 doesn't contain @nodes2
4696 */
4697xmlNodeSetPtr
4698xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4699    if (xmlXPathNodeSetIsEmpty(nodes2))
4700	return(nodes1);
4701    if (xmlXPathNodeSetIsEmpty(nodes1))
4702	return(xmlXPathNodeSetCreate(NULL));
4703    xmlXPathNodeSetSort(nodes1);
4704    xmlXPathNodeSetSort(nodes2);
4705    return(xmlXPathNodeTrailingSorted(nodes1,
4706				      xmlXPathNodeSetItem(nodes2, 0)));
4707}
4708
4709/************************************************************************
4710 *									*
4711 *		Routines to handle extra functions			*
4712 *									*
4713 ************************************************************************/
4714
4715/**
4716 * xmlXPathRegisterFunc:
4717 * @ctxt:  the XPath context
4718 * @name:  the function name
4719 * @f:  the function implementation or NULL
4720 *
4721 * Register a new function. If @f is NULL it unregisters the function
4722 *
4723 * Returns 0 in case of success, -1 in case of error
4724 */
4725int
4726xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4727		     xmlXPathFunction f) {
4728    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4729}
4730
4731/**
4732 * xmlXPathRegisterFuncNS:
4733 * @ctxt:  the XPath context
4734 * @name:  the function name
4735 * @ns_uri:  the function namespace URI
4736 * @f:  the function implementation or NULL
4737 *
4738 * Register a new function. If @f is NULL it unregisters the function
4739 *
4740 * Returns 0 in case of success, -1 in case of error
4741 */
4742int
4743xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4744		       const xmlChar *ns_uri, xmlXPathFunction f) {
4745    if (ctxt == NULL)
4746	return(-1);
4747    if (name == NULL)
4748	return(-1);
4749
4750    if (ctxt->funcHash == NULL)
4751	ctxt->funcHash = xmlHashCreate(0);
4752    if (ctxt->funcHash == NULL)
4753	return(-1);
4754    if (f == NULL)
4755        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4756    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4757}
4758
4759/**
4760 * xmlXPathRegisterFuncLookup:
4761 * @ctxt:  the XPath context
4762 * @f:  the lookup function
4763 * @funcCtxt:  the lookup data
4764 *
4765 * Registers an external mechanism to do function lookup.
4766 */
4767void
4768xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4769			    xmlXPathFuncLookupFunc f,
4770			    void *funcCtxt) {
4771    if (ctxt == NULL)
4772	return;
4773    ctxt->funcLookupFunc = f;
4774    ctxt->funcLookupData = funcCtxt;
4775}
4776
4777/**
4778 * xmlXPathFunctionLookup:
4779 * @ctxt:  the XPath context
4780 * @name:  the function name
4781 *
4782 * Search in the Function array of the context for the given
4783 * function.
4784 *
4785 * Returns the xmlXPathFunction or NULL if not found
4786 */
4787xmlXPathFunction
4788xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4789    if (ctxt == NULL)
4790	return (NULL);
4791
4792    if (ctxt->funcLookupFunc != NULL) {
4793	xmlXPathFunction ret;
4794	xmlXPathFuncLookupFunc f;
4795
4796	f = ctxt->funcLookupFunc;
4797	ret = f(ctxt->funcLookupData, name, NULL);
4798	if (ret != NULL)
4799	    return(ret);
4800    }
4801    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4802}
4803
4804/**
4805 * xmlXPathFunctionLookupNS:
4806 * @ctxt:  the XPath context
4807 * @name:  the function name
4808 * @ns_uri:  the function namespace URI
4809 *
4810 * Search in the Function array of the context for the given
4811 * function.
4812 *
4813 * Returns the xmlXPathFunction or NULL if not found
4814 */
4815xmlXPathFunction
4816xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4817			 const xmlChar *ns_uri) {
4818    xmlXPathFunction ret;
4819
4820    if (ctxt == NULL)
4821	return(NULL);
4822    if (name == NULL)
4823	return(NULL);
4824
4825    if (ctxt->funcLookupFunc != NULL) {
4826	xmlXPathFuncLookupFunc f;
4827
4828	f = ctxt->funcLookupFunc;
4829	ret = f(ctxt->funcLookupData, name, ns_uri);
4830	if (ret != NULL)
4831	    return(ret);
4832    }
4833
4834    if (ctxt->funcHash == NULL)
4835	return(NULL);
4836
4837    XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4838    return(ret);
4839}
4840
4841/**
4842 * xmlXPathRegisteredFuncsCleanup:
4843 * @ctxt:  the XPath context
4844 *
4845 * Cleanup the XPath context data associated to registered functions
4846 */
4847void
4848xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4849    if (ctxt == NULL)
4850	return;
4851
4852    xmlHashFree(ctxt->funcHash, NULL);
4853    ctxt->funcHash = NULL;
4854}
4855
4856/************************************************************************
4857 *									*
4858 *			Routines to handle Variables			*
4859 *									*
4860 ************************************************************************/
4861
4862/**
4863 * xmlXPathRegisterVariable:
4864 * @ctxt:  the XPath context
4865 * @name:  the variable name
4866 * @value:  the variable value or NULL
4867 *
4868 * Register a new variable value. If @value is NULL it unregisters
4869 * the variable
4870 *
4871 * Returns 0 in case of success, -1 in case of error
4872 */
4873int
4874xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4875			 xmlXPathObjectPtr value) {
4876    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4877}
4878
4879/**
4880 * xmlXPathRegisterVariableNS:
4881 * @ctxt:  the XPath context
4882 * @name:  the variable name
4883 * @ns_uri:  the variable namespace URI
4884 * @value:  the variable value or NULL
4885 *
4886 * Register a new variable value. If @value is NULL it unregisters
4887 * the variable
4888 *
4889 * Returns 0 in case of success, -1 in case of error
4890 */
4891int
4892xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4893			   const xmlChar *ns_uri,
4894			   xmlXPathObjectPtr value) {
4895    if (ctxt == NULL)
4896	return(-1);
4897    if (name == NULL)
4898	return(-1);
4899
4900    if (ctxt->varHash == NULL)
4901	ctxt->varHash = xmlHashCreate(0);
4902    if (ctxt->varHash == NULL)
4903	return(-1);
4904    if (value == NULL)
4905        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4906	                           (xmlHashDeallocator)xmlXPathFreeObject));
4907    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4908			       (void *) value,
4909			       (xmlHashDeallocator)xmlXPathFreeObject));
4910}
4911
4912/**
4913 * xmlXPathRegisterVariableLookup:
4914 * @ctxt:  the XPath context
4915 * @f:  the lookup function
4916 * @data:  the lookup data
4917 *
4918 * register an external mechanism to do variable lookup
4919 */
4920void
4921xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4922	 xmlXPathVariableLookupFunc f, void *data) {
4923    if (ctxt == NULL)
4924	return;
4925    ctxt->varLookupFunc = f;
4926    ctxt->varLookupData = data;
4927}
4928
4929/**
4930 * xmlXPathVariableLookup:
4931 * @ctxt:  the XPath context
4932 * @name:  the variable name
4933 *
4934 * Search in the Variable array of the context for the given
4935 * variable value.
4936 *
4937 * Returns a copy of the value or NULL if not found
4938 */
4939xmlXPathObjectPtr
4940xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4941    if (ctxt == NULL)
4942	return(NULL);
4943
4944    if (ctxt->varLookupFunc != NULL) {
4945	xmlXPathObjectPtr ret;
4946
4947	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4948	        (ctxt->varLookupData, name, NULL);
4949	return(ret);
4950    }
4951    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4952}
4953
4954/**
4955 * xmlXPathVariableLookupNS:
4956 * @ctxt:  the XPath context
4957 * @name:  the variable name
4958 * @ns_uri:  the variable namespace URI
4959 *
4960 * Search in the Variable array of the context for the given
4961 * variable value.
4962 *
4963 * Returns the a copy of the value or NULL if not found
4964 */
4965xmlXPathObjectPtr
4966xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4967			 const xmlChar *ns_uri) {
4968    if (ctxt == NULL)
4969	return(NULL);
4970
4971    if (ctxt->varLookupFunc != NULL) {
4972	xmlXPathObjectPtr ret;
4973
4974	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4975	        (ctxt->varLookupData, name, ns_uri);
4976	if (ret != NULL) return(ret);
4977    }
4978
4979    if (ctxt->varHash == NULL)
4980	return(NULL);
4981    if (name == NULL)
4982	return(NULL);
4983
4984    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
4985		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4986}
4987
4988/**
4989 * xmlXPathRegisteredVariablesCleanup:
4990 * @ctxt:  the XPath context
4991 *
4992 * Cleanup the XPath context data associated to registered variables
4993 */
4994void
4995xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4996    if (ctxt == NULL)
4997	return;
4998
4999    xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5000    ctxt->varHash = NULL;
5001}
5002
5003/**
5004 * xmlXPathRegisterNs:
5005 * @ctxt:  the XPath context
5006 * @prefix:  the namespace prefix cannot be NULL or empty string
5007 * @ns_uri:  the namespace name
5008 *
5009 * Register a new namespace. If @ns_uri is NULL it unregisters
5010 * the namespace
5011 *
5012 * Returns 0 in case of success, -1 in case of error
5013 */
5014int
5015xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5016			   const xmlChar *ns_uri) {
5017    if (ctxt == NULL)
5018	return(-1);
5019    if (prefix == NULL)
5020	return(-1);
5021    if (prefix[0] == 0)
5022	return(-1);
5023
5024    if (ctxt->nsHash == NULL)
5025	ctxt->nsHash = xmlHashCreate(10);
5026    if (ctxt->nsHash == NULL)
5027	return(-1);
5028    if (ns_uri == NULL)
5029        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5030	                          (xmlHashDeallocator)xmlFree));
5031    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5032			      (xmlHashDeallocator)xmlFree));
5033}
5034
5035/**
5036 * xmlXPathNsLookup:
5037 * @ctxt:  the XPath context
5038 * @prefix:  the namespace prefix value
5039 *
5040 * Search in the namespace declaration array of the context for the given
5041 * namespace name associated to the given prefix
5042 *
5043 * Returns the value or NULL if not found
5044 */
5045const xmlChar *
5046xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5047    if (ctxt == NULL)
5048	return(NULL);
5049    if (prefix == NULL)
5050	return(NULL);
5051
5052#ifdef XML_XML_NAMESPACE
5053    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5054	return(XML_XML_NAMESPACE);
5055#endif
5056
5057    if (ctxt->namespaces != NULL) {
5058	int i;
5059
5060	for (i = 0;i < ctxt->nsNr;i++) {
5061	    if ((ctxt->namespaces[i] != NULL) &&
5062		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5063		return(ctxt->namespaces[i]->href);
5064	}
5065    }
5066
5067    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5068}
5069
5070/**
5071 * xmlXPathRegisteredNsCleanup:
5072 * @ctxt:  the XPath context
5073 *
5074 * Cleanup the XPath context data associated to registered variables
5075 */
5076void
5077xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5078    if (ctxt == NULL)
5079	return;
5080
5081    xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5082    ctxt->nsHash = NULL;
5083}
5084
5085/************************************************************************
5086 *									*
5087 *			Routines to handle Values			*
5088 *									*
5089 ************************************************************************/
5090
5091/* Allocations are terrible, one needs to optimize all this !!! */
5092
5093/**
5094 * xmlXPathNewFloat:
5095 * @val:  the double value
5096 *
5097 * Create a new xmlXPathObjectPtr of type double and of value @val
5098 *
5099 * Returns the newly created object.
5100 */
5101xmlXPathObjectPtr
5102xmlXPathNewFloat(double val) {
5103    xmlXPathObjectPtr ret;
5104
5105    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5106    if (ret == NULL) {
5107        xmlXPathErrMemory(NULL, "creating float object\n");
5108	return(NULL);
5109    }
5110    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5111    ret->type = XPATH_NUMBER;
5112    ret->floatval = val;
5113#ifdef XP_DEBUG_OBJ_USAGE
5114    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5115#endif
5116    return(ret);
5117}
5118
5119/**
5120 * xmlXPathNewBoolean:
5121 * @val:  the boolean value
5122 *
5123 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5124 *
5125 * Returns the newly created object.
5126 */
5127xmlXPathObjectPtr
5128xmlXPathNewBoolean(int val) {
5129    xmlXPathObjectPtr ret;
5130
5131    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5132    if (ret == NULL) {
5133        xmlXPathErrMemory(NULL, "creating boolean object\n");
5134	return(NULL);
5135    }
5136    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5137    ret->type = XPATH_BOOLEAN;
5138    ret->boolval = (val != 0);
5139#ifdef XP_DEBUG_OBJ_USAGE
5140    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5141#endif
5142    return(ret);
5143}
5144
5145/**
5146 * xmlXPathNewString:
5147 * @val:  the xmlChar * value
5148 *
5149 * Create a new xmlXPathObjectPtr of type string and of value @val
5150 *
5151 * Returns the newly created object.
5152 */
5153xmlXPathObjectPtr
5154xmlXPathNewString(const xmlChar *val) {
5155    xmlXPathObjectPtr ret;
5156
5157    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5158    if (ret == NULL) {
5159        xmlXPathErrMemory(NULL, "creating string object\n");
5160	return(NULL);
5161    }
5162    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5163    ret->type = XPATH_STRING;
5164    if (val != NULL)
5165	ret->stringval = xmlStrdup(val);
5166    else
5167	ret->stringval = xmlStrdup((const xmlChar *)"");
5168#ifdef XP_DEBUG_OBJ_USAGE
5169    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5170#endif
5171    return(ret);
5172}
5173
5174/**
5175 * xmlXPathWrapString:
5176 * @val:  the xmlChar * value
5177 *
5178 * Wraps the @val string into an XPath object.
5179 *
5180 * Returns the newly created object.
5181 */
5182xmlXPathObjectPtr
5183xmlXPathWrapString (xmlChar *val) {
5184    xmlXPathObjectPtr ret;
5185
5186    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5187    if (ret == NULL) {
5188        xmlXPathErrMemory(NULL, "creating string object\n");
5189	return(NULL);
5190    }
5191    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5192    ret->type = XPATH_STRING;
5193    ret->stringval = val;
5194#ifdef XP_DEBUG_OBJ_USAGE
5195    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5196#endif
5197    return(ret);
5198}
5199
5200/**
5201 * xmlXPathNewCString:
5202 * @val:  the char * value
5203 *
5204 * Create a new xmlXPathObjectPtr of type string and of value @val
5205 *
5206 * Returns the newly created object.
5207 */
5208xmlXPathObjectPtr
5209xmlXPathNewCString(const char *val) {
5210    xmlXPathObjectPtr ret;
5211
5212    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5213    if (ret == NULL) {
5214        xmlXPathErrMemory(NULL, "creating string object\n");
5215	return(NULL);
5216    }
5217    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5218    ret->type = XPATH_STRING;
5219    ret->stringval = xmlStrdup(BAD_CAST val);
5220#ifdef XP_DEBUG_OBJ_USAGE
5221    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5222#endif
5223    return(ret);
5224}
5225
5226/**
5227 * xmlXPathWrapCString:
5228 * @val:  the char * value
5229 *
5230 * Wraps a string into an XPath object.
5231 *
5232 * Returns the newly created object.
5233 */
5234xmlXPathObjectPtr
5235xmlXPathWrapCString (char * val) {
5236    return(xmlXPathWrapString((xmlChar *)(val)));
5237}
5238
5239/**
5240 * xmlXPathWrapExternal:
5241 * @val:  the user data
5242 *
5243 * Wraps the @val data into an XPath object.
5244 *
5245 * Returns the newly created object.
5246 */
5247xmlXPathObjectPtr
5248xmlXPathWrapExternal (void *val) {
5249    xmlXPathObjectPtr ret;
5250
5251    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5252    if (ret == NULL) {
5253        xmlXPathErrMemory(NULL, "creating user object\n");
5254	return(NULL);
5255    }
5256    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5257    ret->type = XPATH_USERS;
5258    ret->user = val;
5259#ifdef XP_DEBUG_OBJ_USAGE
5260    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5261#endif
5262    return(ret);
5263}
5264
5265/**
5266 * xmlXPathObjectCopy:
5267 * @val:  the original object
5268 *
5269 * allocate a new copy of a given object
5270 *
5271 * Returns the newly created object.
5272 */
5273xmlXPathObjectPtr
5274xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5275    xmlXPathObjectPtr ret;
5276
5277    if (val == NULL)
5278	return(NULL);
5279
5280    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5281    if (ret == NULL) {
5282        xmlXPathErrMemory(NULL, "copying object\n");
5283	return(NULL);
5284    }
5285    memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5286#ifdef XP_DEBUG_OBJ_USAGE
5287    xmlXPathDebugObjUsageRequested(NULL, val->type);
5288#endif
5289    switch (val->type) {
5290	case XPATH_BOOLEAN:
5291	case XPATH_NUMBER:
5292	case XPATH_POINT:
5293	case XPATH_RANGE:
5294	    break;
5295	case XPATH_STRING:
5296	    ret->stringval = xmlStrdup(val->stringval);
5297	    break;
5298	case XPATH_XSLT_TREE:
5299#if 0
5300/*
5301  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5302  this previous handling is no longer correct, and can cause some serious
5303  problems (ref. bug 145547)
5304*/
5305	    if ((val->nodesetval != NULL) &&
5306		(val->nodesetval->nodeTab != NULL)) {
5307		xmlNodePtr cur, tmp;
5308		xmlDocPtr top;
5309
5310		ret->boolval = 1;
5311		top =  xmlNewDoc(NULL);
5312		top->name = (char *)
5313		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5314		ret->user = top;
5315		if (top != NULL) {
5316		    top->doc = top;
5317		    cur = val->nodesetval->nodeTab[0]->children;
5318		    while (cur != NULL) {
5319			tmp = xmlDocCopyNode(cur, top, 1);
5320			xmlAddChild((xmlNodePtr) top, tmp);
5321			cur = cur->next;
5322		    }
5323		}
5324
5325		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5326	    } else
5327		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5328	    /* Deallocate the copied tree value */
5329	    break;
5330#endif
5331	case XPATH_NODESET:
5332	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5333	    /* Do not deallocate the copied tree value */
5334	    ret->boolval = 0;
5335	    break;
5336	case XPATH_LOCATIONSET:
5337#ifdef LIBXML_XPTR_ENABLED
5338	{
5339	    xmlLocationSetPtr loc = val->user;
5340	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5341	    break;
5342	}
5343#endif
5344        case XPATH_USERS:
5345	    ret->user = val->user;
5346	    break;
5347        case XPATH_UNDEFINED:
5348	    xmlGenericError(xmlGenericErrorContext,
5349		    "xmlXPathObjectCopy: unsupported type %d\n",
5350		    val->type);
5351	    break;
5352    }
5353    return(ret);
5354}
5355
5356/**
5357 * xmlXPathFreeObject:
5358 * @obj:  the object to free
5359 *
5360 * Free up an xmlXPathObjectPtr object.
5361 */
5362void
5363xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5364    if (obj == NULL) return;
5365    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5366	if (obj->boolval) {
5367#if 0
5368	    if (obj->user != NULL) {
5369                xmlXPathFreeNodeSet(obj->nodesetval);
5370		xmlFreeNodeList((xmlNodePtr) obj->user);
5371	    } else
5372#endif
5373	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5374	    if (obj->nodesetval != NULL)
5375		xmlXPathFreeValueTree(obj->nodesetval);
5376	} else {
5377	    if (obj->nodesetval != NULL)
5378		xmlXPathFreeNodeSet(obj->nodesetval);
5379	}
5380#ifdef LIBXML_XPTR_ENABLED
5381    } else if (obj->type == XPATH_LOCATIONSET) {
5382	if (obj->user != NULL)
5383	    xmlXPtrFreeLocationSet(obj->user);
5384#endif
5385    } else if (obj->type == XPATH_STRING) {
5386	if (obj->stringval != NULL)
5387	    xmlFree(obj->stringval);
5388    }
5389#ifdef XP_DEBUG_OBJ_USAGE
5390    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5391#endif
5392    xmlFree(obj);
5393}
5394
5395/**
5396 * xmlXPathReleaseObject:
5397 * @obj:  the xmlXPathObjectPtr to free or to cache
5398 *
5399 * Depending on the state of the cache this frees the given
5400 * XPath object or stores it in the cache.
5401 */
5402static void
5403xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5404{
5405#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5406	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5407    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5408
5409#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5410
5411    if (obj == NULL)
5412	return;
5413    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5414	 xmlXPathFreeObject(obj);
5415    } else {
5416	xmlXPathContextCachePtr cache =
5417	    (xmlXPathContextCachePtr) ctxt->cache;
5418
5419	switch (obj->type) {
5420	    case XPATH_NODESET:
5421	    case XPATH_XSLT_TREE:
5422		if (obj->nodesetval != NULL) {
5423		    if (obj->boolval) {
5424			/*
5425			* It looks like the @boolval is used for
5426			* evaluation if this an XSLT Result Tree Fragment.
5427			* TODO: Check if this assumption is correct.
5428			*/
5429			obj->type = XPATH_XSLT_TREE; /* just for debugging */
5430			xmlXPathFreeValueTree(obj->nodesetval);
5431			obj->nodesetval = NULL;
5432		    } else if ((obj->nodesetval->nodeMax <= 40) &&
5433			(XP_CACHE_WANTS(cache->nodesetObjs,
5434					cache->maxNodeset)))
5435		    {
5436			XP_CACHE_ADD(cache->nodesetObjs, obj);
5437			goto obj_cached;
5438		    } else {
5439			xmlXPathFreeNodeSet(obj->nodesetval);
5440			obj->nodesetval = NULL;
5441		    }
5442		}
5443		break;
5444	    case XPATH_STRING:
5445		if (obj->stringval != NULL)
5446		    xmlFree(obj->stringval);
5447
5448		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5449		    XP_CACHE_ADD(cache->stringObjs, obj);
5450		    goto obj_cached;
5451		}
5452		break;
5453	    case XPATH_BOOLEAN:
5454		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5455		    XP_CACHE_ADD(cache->booleanObjs, obj);
5456		    goto obj_cached;
5457		}
5458		break;
5459	    case XPATH_NUMBER:
5460		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5461		    XP_CACHE_ADD(cache->numberObjs, obj);
5462		    goto obj_cached;
5463		}
5464		break;
5465#ifdef LIBXML_XPTR_ENABLED
5466	    case XPATH_LOCATIONSET:
5467		if (obj->user != NULL) {
5468		    xmlXPtrFreeLocationSet(obj->user);
5469		}
5470		goto free_obj;
5471#endif
5472	    default:
5473		goto free_obj;
5474	}
5475
5476	/*
5477	* Fallback to adding to the misc-objects slot.
5478	*/
5479	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5480	    XP_CACHE_ADD(cache->miscObjs, obj);
5481	} else
5482	    goto free_obj;
5483
5484obj_cached:
5485
5486#ifdef XP_DEBUG_OBJ_USAGE
5487	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5488#endif
5489
5490	if (obj->nodesetval != NULL) {
5491	    xmlNodeSetPtr tmpset = obj->nodesetval;
5492
5493	    /*
5494	    * TODO: Due to those nasty ns-nodes, we need to traverse
5495	    *  the list and free the ns-nodes.
5496	    * URGENT TODO: Check if it's actually slowing things down.
5497	    *  Maybe we shouldn't try to preserve the list.
5498	    */
5499	    if (tmpset->nodeNr > 1) {
5500		int i;
5501		xmlNodePtr node;
5502
5503		for (i = 0; i < tmpset->nodeNr; i++) {
5504		    node = tmpset->nodeTab[i];
5505		    if ((node != NULL) &&
5506			(node->type == XML_NAMESPACE_DECL))
5507		    {
5508			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5509		    }
5510		}
5511	    } else if (tmpset->nodeNr == 1) {
5512		if ((tmpset->nodeTab[0] != NULL) &&
5513		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5514		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5515	    }
5516	    tmpset->nodeNr = 0;
5517	    memset(obj, 0, sizeof(xmlXPathObject));
5518	    obj->nodesetval = tmpset;
5519	} else
5520	    memset(obj, 0, sizeof(xmlXPathObject));
5521
5522	return;
5523
5524free_obj:
5525	/*
5526	* Cache is full; free the object.
5527	*/
5528	if (obj->nodesetval != NULL)
5529	    xmlXPathFreeNodeSet(obj->nodesetval);
5530#ifdef XP_DEBUG_OBJ_USAGE
5531	xmlXPathDebugObjUsageReleased(NULL, obj->type);
5532#endif
5533	xmlFree(obj);
5534    }
5535    return;
5536}
5537
5538
5539/************************************************************************
5540 *									*
5541 *			Type Casting Routines				*
5542 *									*
5543 ************************************************************************/
5544
5545/**
5546 * xmlXPathCastBooleanToString:
5547 * @val:  a boolean
5548 *
5549 * Converts a boolean to its string value.
5550 *
5551 * Returns a newly allocated string.
5552 */
5553xmlChar *
5554xmlXPathCastBooleanToString (int val) {
5555    xmlChar *ret;
5556    if (val)
5557	ret = xmlStrdup((const xmlChar *) "true");
5558    else
5559	ret = xmlStrdup((const xmlChar *) "false");
5560    return(ret);
5561}
5562
5563/**
5564 * xmlXPathCastNumberToString:
5565 * @val:  a number
5566 *
5567 * Converts a number to its string value.
5568 *
5569 * Returns a newly allocated string.
5570 */
5571xmlChar *
5572xmlXPathCastNumberToString (double val) {
5573    xmlChar *ret;
5574    switch (xmlXPathIsInf(val)) {
5575    case 1:
5576	ret = xmlStrdup((const xmlChar *) "Infinity");
5577	break;
5578    case -1:
5579	ret = xmlStrdup((const xmlChar *) "-Infinity");
5580	break;
5581    default:
5582	if (xmlXPathIsNaN(val)) {
5583	    ret = xmlStrdup((const xmlChar *) "NaN");
5584	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
5585	    ret = xmlStrdup((const xmlChar *) "0");
5586	} else {
5587	    /* could be improved */
5588	    char buf[100];
5589	    xmlXPathFormatNumber(val, buf, 99);
5590	    buf[99] = 0;
5591	    ret = xmlStrdup((const xmlChar *) buf);
5592	}
5593    }
5594    return(ret);
5595}
5596
5597/**
5598 * xmlXPathCastNodeToString:
5599 * @node:  a node
5600 *
5601 * Converts a node to its string value.
5602 *
5603 * Returns a newly allocated string.
5604 */
5605xmlChar *
5606xmlXPathCastNodeToString (xmlNodePtr node) {
5607xmlChar *ret;
5608    if ((ret = xmlNodeGetContent(node)) == NULL)
5609	ret = xmlStrdup((const xmlChar *) "");
5610    return(ret);
5611}
5612
5613/**
5614 * xmlXPathCastNodeSetToString:
5615 * @ns:  a node-set
5616 *
5617 * Converts a node-set to its string value.
5618 *
5619 * Returns a newly allocated string.
5620 */
5621xmlChar *
5622xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5623    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5624	return(xmlStrdup((const xmlChar *) ""));
5625
5626    if (ns->nodeNr > 1)
5627	xmlXPathNodeSetSort(ns);
5628    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5629}
5630
5631/**
5632 * xmlXPathCastToString:
5633 * @val:  an XPath object
5634 *
5635 * Converts an existing object to its string() equivalent
5636 *
5637 * Returns the allocated string value of the object, NULL in case of error.
5638 *         It's up to the caller to free the string memory with xmlFree().
5639 */
5640xmlChar *
5641xmlXPathCastToString(xmlXPathObjectPtr val) {
5642    xmlChar *ret = NULL;
5643
5644    if (val == NULL)
5645	return(xmlStrdup((const xmlChar *) ""));
5646    switch (val->type) {
5647	case XPATH_UNDEFINED:
5648#ifdef DEBUG_EXPR
5649	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5650#endif
5651	    ret = xmlStrdup((const xmlChar *) "");
5652	    break;
5653        case XPATH_NODESET:
5654        case XPATH_XSLT_TREE:
5655	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5656	    break;
5657	case XPATH_STRING:
5658	    return(xmlStrdup(val->stringval));
5659        case XPATH_BOOLEAN:
5660	    ret = xmlXPathCastBooleanToString(val->boolval);
5661	    break;
5662	case XPATH_NUMBER: {
5663	    ret = xmlXPathCastNumberToString(val->floatval);
5664	    break;
5665	}
5666	case XPATH_USERS:
5667	case XPATH_POINT:
5668	case XPATH_RANGE:
5669	case XPATH_LOCATIONSET:
5670	    TODO
5671	    ret = xmlStrdup((const xmlChar *) "");
5672	    break;
5673    }
5674    return(ret);
5675}
5676
5677/**
5678 * xmlXPathConvertString:
5679 * @val:  an XPath object
5680 *
5681 * Converts an existing object to its string() equivalent
5682 *
5683 * Returns the new object, the old one is freed (or the operation
5684 *         is done directly on @val)
5685 */
5686xmlXPathObjectPtr
5687xmlXPathConvertString(xmlXPathObjectPtr val) {
5688    xmlChar *res = NULL;
5689
5690    if (val == NULL)
5691	return(xmlXPathNewCString(""));
5692
5693    switch (val->type) {
5694    case XPATH_UNDEFINED:
5695#ifdef DEBUG_EXPR
5696	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5697#endif
5698	break;
5699    case XPATH_NODESET:
5700    case XPATH_XSLT_TREE:
5701	res = xmlXPathCastNodeSetToString(val->nodesetval);
5702	break;
5703    case XPATH_STRING:
5704	return(val);
5705    case XPATH_BOOLEAN:
5706	res = xmlXPathCastBooleanToString(val->boolval);
5707	break;
5708    case XPATH_NUMBER:
5709	res = xmlXPathCastNumberToString(val->floatval);
5710	break;
5711    case XPATH_USERS:
5712    case XPATH_POINT:
5713    case XPATH_RANGE:
5714    case XPATH_LOCATIONSET:
5715	TODO;
5716	break;
5717    }
5718    xmlXPathFreeObject(val);
5719    if (res == NULL)
5720	return(xmlXPathNewCString(""));
5721    return(xmlXPathWrapString(res));
5722}
5723
5724/**
5725 * xmlXPathCastBooleanToNumber:
5726 * @val:  a boolean
5727 *
5728 * Converts a boolean to its number value
5729 *
5730 * Returns the number value
5731 */
5732double
5733xmlXPathCastBooleanToNumber(int val) {
5734    if (val)
5735	return(1.0);
5736    return(0.0);
5737}
5738
5739/**
5740 * xmlXPathCastStringToNumber:
5741 * @val:  a string
5742 *
5743 * Converts a string to its number value
5744 *
5745 * Returns the number value
5746 */
5747double
5748xmlXPathCastStringToNumber(const xmlChar * val) {
5749    return(xmlXPathStringEvalNumber(val));
5750}
5751
5752/**
5753 * xmlXPathCastNodeToNumber:
5754 * @node:  a node
5755 *
5756 * Converts a node to its number value
5757 *
5758 * Returns the number value
5759 */
5760double
5761xmlXPathCastNodeToNumber (xmlNodePtr node) {
5762    xmlChar *strval;
5763    double ret;
5764
5765    if (node == NULL)
5766	return(xmlXPathNAN);
5767    strval = xmlXPathCastNodeToString(node);
5768    if (strval == NULL)
5769	return(xmlXPathNAN);
5770    ret = xmlXPathCastStringToNumber(strval);
5771    xmlFree(strval);
5772
5773    return(ret);
5774}
5775
5776/**
5777 * xmlXPathCastNodeSetToNumber:
5778 * @ns:  a node-set
5779 *
5780 * Converts a node-set to its number value
5781 *
5782 * Returns the number value
5783 */
5784double
5785xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5786    xmlChar *str;
5787    double ret;
5788
5789    if (ns == NULL)
5790	return(xmlXPathNAN);
5791    str = xmlXPathCastNodeSetToString(ns);
5792    ret = xmlXPathCastStringToNumber(str);
5793    xmlFree(str);
5794    return(ret);
5795}
5796
5797/**
5798 * xmlXPathCastToNumber:
5799 * @val:  an XPath object
5800 *
5801 * Converts an XPath object to its number value
5802 *
5803 * Returns the number value
5804 */
5805double
5806xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5807    double ret = 0.0;
5808
5809    if (val == NULL)
5810	return(xmlXPathNAN);
5811    switch (val->type) {
5812    case XPATH_UNDEFINED:
5813#ifdef DEGUB_EXPR
5814	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5815#endif
5816	ret = xmlXPathNAN;
5817	break;
5818    case XPATH_NODESET:
5819    case XPATH_XSLT_TREE:
5820	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5821	break;
5822    case XPATH_STRING:
5823	ret = xmlXPathCastStringToNumber(val->stringval);
5824	break;
5825    case XPATH_NUMBER:
5826	ret = val->floatval;
5827	break;
5828    case XPATH_BOOLEAN:
5829	ret = xmlXPathCastBooleanToNumber(val->boolval);
5830	break;
5831    case XPATH_USERS:
5832    case XPATH_POINT:
5833    case XPATH_RANGE:
5834    case XPATH_LOCATIONSET:
5835	TODO;
5836	ret = xmlXPathNAN;
5837	break;
5838    }
5839    return(ret);
5840}
5841
5842/**
5843 * xmlXPathConvertNumber:
5844 * @val:  an XPath object
5845 *
5846 * Converts an existing object to its number() equivalent
5847 *
5848 * Returns the new object, the old one is freed (or the operation
5849 *         is done directly on @val)
5850 */
5851xmlXPathObjectPtr
5852xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5853    xmlXPathObjectPtr ret;
5854
5855    if (val == NULL)
5856	return(xmlXPathNewFloat(0.0));
5857    if (val->type == XPATH_NUMBER)
5858	return(val);
5859    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5860    xmlXPathFreeObject(val);
5861    return(ret);
5862}
5863
5864/**
5865 * xmlXPathCastNumberToBoolean:
5866 * @val:  a number
5867 *
5868 * Converts a number to its boolean value
5869 *
5870 * Returns the boolean value
5871 */
5872int
5873xmlXPathCastNumberToBoolean (double val) {
5874     if (xmlXPathIsNaN(val) || (val == 0.0))
5875	 return(0);
5876     return(1);
5877}
5878
5879/**
5880 * xmlXPathCastStringToBoolean:
5881 * @val:  a string
5882 *
5883 * Converts a string to its boolean value
5884 *
5885 * Returns the boolean value
5886 */
5887int
5888xmlXPathCastStringToBoolean (const xmlChar *val) {
5889    if ((val == NULL) || (xmlStrlen(val) == 0))
5890	return(0);
5891    return(1);
5892}
5893
5894/**
5895 * xmlXPathCastNodeSetToBoolean:
5896 * @ns:  a node-set
5897 *
5898 * Converts a node-set to its boolean value
5899 *
5900 * Returns the boolean value
5901 */
5902int
5903xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5904    if ((ns == NULL) || (ns->nodeNr == 0))
5905	return(0);
5906    return(1);
5907}
5908
5909/**
5910 * xmlXPathCastToBoolean:
5911 * @val:  an XPath object
5912 *
5913 * Converts an XPath object to its boolean value
5914 *
5915 * Returns the boolean value
5916 */
5917int
5918xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5919    int ret = 0;
5920
5921    if (val == NULL)
5922	return(0);
5923    switch (val->type) {
5924    case XPATH_UNDEFINED:
5925#ifdef DEBUG_EXPR
5926	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5927#endif
5928	ret = 0;
5929	break;
5930    case XPATH_NODESET:
5931    case XPATH_XSLT_TREE:
5932	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5933	break;
5934    case XPATH_STRING:
5935	ret = xmlXPathCastStringToBoolean(val->stringval);
5936	break;
5937    case XPATH_NUMBER:
5938	ret = xmlXPathCastNumberToBoolean(val->floatval);
5939	break;
5940    case XPATH_BOOLEAN:
5941	ret = val->boolval;
5942	break;
5943    case XPATH_USERS:
5944    case XPATH_POINT:
5945    case XPATH_RANGE:
5946    case XPATH_LOCATIONSET:
5947	TODO;
5948	ret = 0;
5949	break;
5950    }
5951    return(ret);
5952}
5953
5954
5955/**
5956 * xmlXPathConvertBoolean:
5957 * @val:  an XPath object
5958 *
5959 * Converts an existing object to its boolean() equivalent
5960 *
5961 * Returns the new object, the old one is freed (or the operation
5962 *         is done directly on @val)
5963 */
5964xmlXPathObjectPtr
5965xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5966    xmlXPathObjectPtr ret;
5967
5968    if (val == NULL)
5969	return(xmlXPathNewBoolean(0));
5970    if (val->type == XPATH_BOOLEAN)
5971	return(val);
5972    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5973    xmlXPathFreeObject(val);
5974    return(ret);
5975}
5976
5977/************************************************************************
5978 *									*
5979 *		Routines to handle XPath contexts			*
5980 *									*
5981 ************************************************************************/
5982
5983/**
5984 * xmlXPathNewContext:
5985 * @doc:  the XML document
5986 *
5987 * Create a new xmlXPathContext
5988 *
5989 * Returns the xmlXPathContext just allocated. The caller will need to free it.
5990 */
5991xmlXPathContextPtr
5992xmlXPathNewContext(xmlDocPtr doc) {
5993    xmlXPathContextPtr ret;
5994
5995    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5996    if (ret == NULL) {
5997        xmlXPathErrMemory(NULL, "creating context\n");
5998	return(NULL);
5999    }
6000    memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6001    ret->doc = doc;
6002    ret->node = NULL;
6003
6004    ret->varHash = NULL;
6005
6006    ret->nb_types = 0;
6007    ret->max_types = 0;
6008    ret->types = NULL;
6009
6010    ret->funcHash = xmlHashCreate(0);
6011
6012    ret->nb_axis = 0;
6013    ret->max_axis = 0;
6014    ret->axis = NULL;
6015
6016    ret->nsHash = NULL;
6017    ret->user = NULL;
6018
6019    ret->contextSize = -1;
6020    ret->proximityPosition = -1;
6021
6022#ifdef XP_DEFAULT_CACHE_ON
6023    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6024	xmlXPathFreeContext(ret);
6025	return(NULL);
6026    }
6027#endif
6028
6029    xmlXPathRegisterAllFunctions(ret);
6030
6031    return(ret);
6032}
6033
6034/**
6035 * xmlXPathFreeContext:
6036 * @ctxt:  the context to free
6037 *
6038 * Free up an xmlXPathContext
6039 */
6040void
6041xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6042    if (ctxt == NULL) return;
6043
6044    if (ctxt->cache != NULL)
6045	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6046    xmlXPathRegisteredNsCleanup(ctxt);
6047    xmlXPathRegisteredFuncsCleanup(ctxt);
6048    xmlXPathRegisteredVariablesCleanup(ctxt);
6049    xmlResetError(&ctxt->lastError);
6050    xmlFree(ctxt);
6051}
6052
6053/************************************************************************
6054 *									*
6055 *		Routines to handle XPath parser contexts		*
6056 *									*
6057 ************************************************************************/
6058
6059#define CHECK_CTXT(ctxt)						\
6060    if (ctxt == NULL) {						\
6061	__xmlRaiseError(NULL, NULL, NULL,				\
6062		NULL, NULL, XML_FROM_XPATH,				\
6063		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6064		__FILE__, __LINE__,					\
6065		NULL, NULL, NULL, 0, 0,					\
6066		"NULL context pointer\n");				\
6067	return(NULL);							\
6068    }									\
6069
6070#define CHECK_CTXT_NEG(ctxt)						\
6071    if (ctxt == NULL) {						\
6072	__xmlRaiseError(NULL, NULL, NULL,				\
6073		NULL, NULL, XML_FROM_XPATH,				\
6074		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6075		__FILE__, __LINE__,					\
6076		NULL, NULL, NULL, 0, 0,					\
6077		"NULL context pointer\n");				\
6078	return(-1);							\
6079    }									\
6080
6081
6082#define CHECK_CONTEXT(ctxt)						\
6083    if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
6084        (ctxt->doc->children == NULL)) {				\
6085	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
6086	return(NULL);							\
6087    }
6088
6089
6090/**
6091 * xmlXPathNewParserContext:
6092 * @str:  the XPath expression
6093 * @ctxt:  the XPath context
6094 *
6095 * Create a new xmlXPathParserContext
6096 *
6097 * Returns the xmlXPathParserContext just allocated.
6098 */
6099xmlXPathParserContextPtr
6100xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6101    xmlXPathParserContextPtr ret;
6102
6103    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6104    if (ret == NULL) {
6105        xmlXPathErrMemory(ctxt, "creating parser context\n");
6106	return(NULL);
6107    }
6108    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6109    ret->cur = ret->base = str;
6110    ret->context = ctxt;
6111
6112    ret->comp = xmlXPathNewCompExpr();
6113    if (ret->comp == NULL) {
6114	xmlFree(ret->valueTab);
6115	xmlFree(ret);
6116	return(NULL);
6117    }
6118    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6119        ret->comp->dict = ctxt->dict;
6120	xmlDictReference(ret->comp->dict);
6121    }
6122
6123    return(ret);
6124}
6125
6126/**
6127 * xmlXPathCompParserContext:
6128 * @comp:  the XPath compiled expression
6129 * @ctxt:  the XPath context
6130 *
6131 * Create a new xmlXPathParserContext when processing a compiled expression
6132 *
6133 * Returns the xmlXPathParserContext just allocated.
6134 */
6135static xmlXPathParserContextPtr
6136xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6137    xmlXPathParserContextPtr ret;
6138
6139    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6140    if (ret == NULL) {
6141        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6142	return(NULL);
6143    }
6144    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6145
6146    /* Allocate the value stack */
6147    ret->valueTab = (xmlXPathObjectPtr *)
6148                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6149    if (ret->valueTab == NULL) {
6150	xmlFree(ret);
6151	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6152	return(NULL);
6153    }
6154    ret->valueNr = 0;
6155    ret->valueMax = 10;
6156    ret->value = NULL;
6157
6158    ret->context = ctxt;
6159    ret->comp = comp;
6160
6161    return(ret);
6162}
6163
6164/**
6165 * xmlXPathFreeParserContext:
6166 * @ctxt:  the context to free
6167 *
6168 * Free up an xmlXPathParserContext
6169 */
6170void
6171xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6172    if (ctxt->valueTab != NULL) {
6173        xmlFree(ctxt->valueTab);
6174    }
6175    if (ctxt->comp != NULL) {
6176#ifdef XPATH_STREAMING
6177	if (ctxt->comp->stream != NULL) {
6178	    xmlFreePatternList(ctxt->comp->stream);
6179	    ctxt->comp->stream = NULL;
6180	}
6181#endif
6182	xmlXPathFreeCompExpr(ctxt->comp);
6183    }
6184    xmlFree(ctxt);
6185}
6186
6187/************************************************************************
6188 *									*
6189 *		The implicit core function library			*
6190 *									*
6191 ************************************************************************/
6192
6193/**
6194 * xmlXPathNodeValHash:
6195 * @node:  a node pointer
6196 *
6197 * Function computing the beginning of the string value of the node,
6198 * used to speed up comparisons
6199 *
6200 * Returns an int usable as a hash
6201 */
6202static unsigned int
6203xmlXPathNodeValHash(xmlNodePtr node) {
6204    int len = 2;
6205    const xmlChar * string = NULL;
6206    xmlNodePtr tmp = NULL;
6207    unsigned int ret = 0;
6208
6209    if (node == NULL)
6210	return(0);
6211
6212    if (node->type == XML_DOCUMENT_NODE) {
6213	tmp = xmlDocGetRootElement((xmlDocPtr) node);
6214	if (tmp == NULL)
6215	    node = node->children;
6216	else
6217	    node = tmp;
6218
6219	if (node == NULL)
6220	    return(0);
6221    }
6222
6223    switch (node->type) {
6224	case XML_COMMENT_NODE:
6225	case XML_PI_NODE:
6226	case XML_CDATA_SECTION_NODE:
6227	case XML_TEXT_NODE:
6228	    string = node->content;
6229	    if (string == NULL)
6230		return(0);
6231	    if (string[0] == 0)
6232		return(0);
6233	    return(((unsigned int) string[0]) +
6234		   (((unsigned int) string[1]) << 8));
6235	case XML_NAMESPACE_DECL:
6236	    string = ((xmlNsPtr)node)->href;
6237	    if (string == NULL)
6238		return(0);
6239	    if (string[0] == 0)
6240		return(0);
6241	    return(((unsigned int) string[0]) +
6242		   (((unsigned int) string[1]) << 8));
6243	case XML_ATTRIBUTE_NODE:
6244	    tmp = ((xmlAttrPtr) node)->children;
6245	    break;
6246	case XML_ELEMENT_NODE:
6247	    tmp = node->children;
6248	    break;
6249	default:
6250	    return(0);
6251    }
6252    while (tmp != NULL) {
6253	switch (tmp->type) {
6254	    case XML_COMMENT_NODE:
6255	    case XML_PI_NODE:
6256	    case XML_CDATA_SECTION_NODE:
6257	    case XML_TEXT_NODE:
6258		string = tmp->content;
6259		break;
6260	    case XML_NAMESPACE_DECL:
6261		string = ((xmlNsPtr)tmp)->href;
6262		break;
6263	    default:
6264		break;
6265	}
6266	if ((string != NULL) && (string[0] != 0)) {
6267	    if (len == 1) {
6268		return(ret + (((unsigned int) string[0]) << 8));
6269	    }
6270	    if (string[1] == 0) {
6271		len = 1;
6272		ret = (unsigned int) string[0];
6273	    } else {
6274		return(((unsigned int) string[0]) +
6275		       (((unsigned int) string[1]) << 8));
6276	    }
6277	}
6278	/*
6279	 * Skip to next node
6280	 */
6281	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6282	    if (tmp->children->type != XML_ENTITY_DECL) {
6283		tmp = tmp->children;
6284		continue;
6285	    }
6286	}
6287	if (tmp == node)
6288	    break;
6289
6290	if (tmp->next != NULL) {
6291	    tmp = tmp->next;
6292	    continue;
6293	}
6294
6295	do {
6296	    tmp = tmp->parent;
6297	    if (tmp == NULL)
6298		break;
6299	    if (tmp == node) {
6300		tmp = NULL;
6301		break;
6302	    }
6303	    if (tmp->next != NULL) {
6304		tmp = tmp->next;
6305		break;
6306	    }
6307	} while (tmp != NULL);
6308    }
6309    return(ret);
6310}
6311
6312/**
6313 * xmlXPathStringHash:
6314 * @string:  a string
6315 *
6316 * Function computing the beginning of the string value of the node,
6317 * used to speed up comparisons
6318 *
6319 * Returns an int usable as a hash
6320 */
6321static unsigned int
6322xmlXPathStringHash(const xmlChar * string) {
6323    if (string == NULL)
6324	return((unsigned int) 0);
6325    if (string[0] == 0)
6326	return(0);
6327    return(((unsigned int) string[0]) +
6328	   (((unsigned int) string[1]) << 8));
6329}
6330
6331/**
6332 * xmlXPathCompareNodeSetFloat:
6333 * @ctxt:  the XPath Parser context
6334 * @inf:  less than (1) or greater than (0)
6335 * @strict:  is the comparison strict
6336 * @arg:  the node set
6337 * @f:  the value
6338 *
6339 * Implement the compare operation between a nodeset and a number
6340 *     @ns < @val    (1, 1, ...
6341 *     @ns <= @val   (1, 0, ...
6342 *     @ns > @val    (0, 1, ...
6343 *     @ns >= @val   (0, 0, ...
6344 *
6345 * If one object to be compared is a node-set and the other is a number,
6346 * then the comparison will be true if and only if there is a node in the
6347 * node-set such that the result of performing the comparison on the number
6348 * to be compared and on the result of converting the string-value of that
6349 * node to a number using the number function is true.
6350 *
6351 * Returns 0 or 1 depending on the results of the test.
6352 */
6353static int
6354xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6355	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6356    int i, ret = 0;
6357    xmlNodeSetPtr ns;
6358    xmlChar *str2;
6359
6360    if ((f == NULL) || (arg == NULL) ||
6361	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6362	xmlXPathReleaseObject(ctxt->context, arg);
6363	xmlXPathReleaseObject(ctxt->context, f);
6364        return(0);
6365    }
6366    ns = arg->nodesetval;
6367    if (ns != NULL) {
6368	for (i = 0;i < ns->nodeNr;i++) {
6369	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6370	     if (str2 != NULL) {
6371		 valuePush(ctxt,
6372			   xmlXPathCacheNewString(ctxt->context, str2));
6373		 xmlFree(str2);
6374		 xmlXPathNumberFunction(ctxt, 1);
6375		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6376		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6377		 if (ret)
6378		     break;
6379	     }
6380	}
6381    }
6382    xmlXPathReleaseObject(ctxt->context, arg);
6383    xmlXPathReleaseObject(ctxt->context, f);
6384    return(ret);
6385}
6386
6387/**
6388 * xmlXPathCompareNodeSetString:
6389 * @ctxt:  the XPath Parser context
6390 * @inf:  less than (1) or greater than (0)
6391 * @strict:  is the comparison strict
6392 * @arg:  the node set
6393 * @s:  the value
6394 *
6395 * Implement the compare operation between a nodeset and a string
6396 *     @ns < @val    (1, 1, ...
6397 *     @ns <= @val   (1, 0, ...
6398 *     @ns > @val    (0, 1, ...
6399 *     @ns >= @val   (0, 0, ...
6400 *
6401 * If one object to be compared is a node-set and the other is a string,
6402 * then the comparison will be true if and only if there is a node in
6403 * the node-set such that the result of performing the comparison on the
6404 * string-value of the node and the other string is true.
6405 *
6406 * Returns 0 or 1 depending on the results of the test.
6407 */
6408static int
6409xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6410	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6411    int i, ret = 0;
6412    xmlNodeSetPtr ns;
6413    xmlChar *str2;
6414
6415    if ((s == NULL) || (arg == NULL) ||
6416	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6417	xmlXPathReleaseObject(ctxt->context, arg);
6418	xmlXPathReleaseObject(ctxt->context, s);
6419        return(0);
6420    }
6421    ns = arg->nodesetval;
6422    if (ns != NULL) {
6423	for (i = 0;i < ns->nodeNr;i++) {
6424	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6425	     if (str2 != NULL) {
6426		 valuePush(ctxt,
6427			   xmlXPathCacheNewString(ctxt->context, str2));
6428		 xmlFree(str2);
6429		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6430		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6431		 if (ret)
6432		     break;
6433	     }
6434	}
6435    }
6436    xmlXPathReleaseObject(ctxt->context, arg);
6437    xmlXPathReleaseObject(ctxt->context, s);
6438    return(ret);
6439}
6440
6441/**
6442 * xmlXPathCompareNodeSets:
6443 * @inf:  less than (1) or greater than (0)
6444 * @strict:  is the comparison strict
6445 * @arg1:  the first node set object
6446 * @arg2:  the second node set object
6447 *
6448 * Implement the compare operation on nodesets:
6449 *
6450 * If both objects to be compared are node-sets, then the comparison
6451 * will be true if and only if there is a node in the first node-set
6452 * and a node in the second node-set such that the result of performing
6453 * the comparison on the string-values of the two nodes is true.
6454 * ....
6455 * When neither object to be compared is a node-set and the operator
6456 * is <=, <, >= or >, then the objects are compared by converting both
6457 * objects to numbers and comparing the numbers according to IEEE 754.
6458 * ....
6459 * The number function converts its argument to a number as follows:
6460 *  - a string that consists of optional whitespace followed by an
6461 *    optional minus sign followed by a Number followed by whitespace
6462 *    is converted to the IEEE 754 number that is nearest (according
6463 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6464 *    represented by the string; any other string is converted to NaN
6465 *
6466 * Conclusion all nodes need to be converted first to their string value
6467 * and then the comparison must be done when possible
6468 */
6469static int
6470xmlXPathCompareNodeSets(int inf, int strict,
6471	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6472    int i, j, init = 0;
6473    double val1;
6474    double *values2;
6475    int ret = 0;
6476    xmlNodeSetPtr ns1;
6477    xmlNodeSetPtr ns2;
6478
6479    if ((arg1 == NULL) ||
6480	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6481	xmlXPathFreeObject(arg2);
6482        return(0);
6483    }
6484    if ((arg2 == NULL) ||
6485	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6486	xmlXPathFreeObject(arg1);
6487	xmlXPathFreeObject(arg2);
6488        return(0);
6489    }
6490
6491    ns1 = arg1->nodesetval;
6492    ns2 = arg2->nodesetval;
6493
6494    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6495	xmlXPathFreeObject(arg1);
6496	xmlXPathFreeObject(arg2);
6497	return(0);
6498    }
6499    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6500	xmlXPathFreeObject(arg1);
6501	xmlXPathFreeObject(arg2);
6502	return(0);
6503    }
6504
6505    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6506    if (values2 == NULL) {
6507        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6508	xmlXPathFreeObject(arg1);
6509	xmlXPathFreeObject(arg2);
6510	return(0);
6511    }
6512    for (i = 0;i < ns1->nodeNr;i++) {
6513	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6514	if (xmlXPathIsNaN(val1))
6515	    continue;
6516	for (j = 0;j < ns2->nodeNr;j++) {
6517	    if (init == 0) {
6518		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6519	    }
6520	    if (xmlXPathIsNaN(values2[j]))
6521		continue;
6522	    if (inf && strict)
6523		ret = (val1 < values2[j]);
6524	    else if (inf && !strict)
6525		ret = (val1 <= values2[j]);
6526	    else if (!inf && strict)
6527		ret = (val1 > values2[j]);
6528	    else if (!inf && !strict)
6529		ret = (val1 >= values2[j]);
6530	    if (ret)
6531		break;
6532	}
6533	if (ret)
6534	    break;
6535	init = 1;
6536    }
6537    xmlFree(values2);
6538    xmlXPathFreeObject(arg1);
6539    xmlXPathFreeObject(arg2);
6540    return(ret);
6541}
6542
6543/**
6544 * xmlXPathCompareNodeSetValue:
6545 * @ctxt:  the XPath Parser context
6546 * @inf:  less than (1) or greater than (0)
6547 * @strict:  is the comparison strict
6548 * @arg:  the node set
6549 * @val:  the value
6550 *
6551 * Implement the compare operation between a nodeset and a value
6552 *     @ns < @val    (1, 1, ...
6553 *     @ns <= @val   (1, 0, ...
6554 *     @ns > @val    (0, 1, ...
6555 *     @ns >= @val   (0, 0, ...
6556 *
6557 * If one object to be compared is a node-set and the other is a boolean,
6558 * then the comparison will be true if and only if the result of performing
6559 * the comparison on the boolean and on the result of converting
6560 * the node-set to a boolean using the boolean function is true.
6561 *
6562 * Returns 0 or 1 depending on the results of the test.
6563 */
6564static int
6565xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6566	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6567    if ((val == NULL) || (arg == NULL) ||
6568	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6569        return(0);
6570
6571    switch(val->type) {
6572        case XPATH_NUMBER:
6573	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6574        case XPATH_NODESET:
6575        case XPATH_XSLT_TREE:
6576	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6577        case XPATH_STRING:
6578	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6579        case XPATH_BOOLEAN:
6580	    valuePush(ctxt, arg);
6581	    xmlXPathBooleanFunction(ctxt, 1);
6582	    valuePush(ctxt, val);
6583	    return(xmlXPathCompareValues(ctxt, inf, strict));
6584	default:
6585	    TODO
6586    }
6587    return(0);
6588}
6589
6590/**
6591 * xmlXPathEqualNodeSetString:
6592 * @arg:  the nodeset object argument
6593 * @str:  the string to compare to.
6594 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6595 *
6596 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6597 * If one object to be compared is a node-set and the other is a string,
6598 * then the comparison will be true if and only if there is a node in
6599 * the node-set such that the result of performing the comparison on the
6600 * string-value of the node and the other string is true.
6601 *
6602 * Returns 0 or 1 depending on the results of the test.
6603 */
6604static int
6605xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6606{
6607    int i;
6608    xmlNodeSetPtr ns;
6609    xmlChar *str2;
6610    unsigned int hash;
6611
6612    if ((str == NULL) || (arg == NULL) ||
6613        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6614        return (0);
6615    ns = arg->nodesetval;
6616    /*
6617     * A NULL nodeset compared with a string is always false
6618     * (since there is no node equal, and no node not equal)
6619     */
6620    if ((ns == NULL) || (ns->nodeNr <= 0) )
6621        return (0);
6622    hash = xmlXPathStringHash(str);
6623    for (i = 0; i < ns->nodeNr; i++) {
6624        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6625            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6626            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6627                xmlFree(str2);
6628		if (neq)
6629		    continue;
6630                return (1);
6631	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6632		if (neq)
6633		    continue;
6634                return (1);
6635            } else if (neq) {
6636		if (str2 != NULL)
6637		    xmlFree(str2);
6638		return (1);
6639	    }
6640            if (str2 != NULL)
6641                xmlFree(str2);
6642        } else if (neq)
6643	    return (1);
6644    }
6645    return (0);
6646}
6647
6648/**
6649 * xmlXPathEqualNodeSetFloat:
6650 * @arg:  the nodeset object argument
6651 * @f:  the float to compare to
6652 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6653 *
6654 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6655 * If one object to be compared is a node-set and the other is a number,
6656 * then the comparison will be true if and only if there is a node in
6657 * the node-set such that the result of performing the comparison on the
6658 * number to be compared and on the result of converting the string-value
6659 * of that node to a number using the number function is true.
6660 *
6661 * Returns 0 or 1 depending on the results of the test.
6662 */
6663static int
6664xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6665    xmlXPathObjectPtr arg, double f, int neq) {
6666  int i, ret=0;
6667  xmlNodeSetPtr ns;
6668  xmlChar *str2;
6669  xmlXPathObjectPtr val;
6670  double v;
6671
6672    if ((arg == NULL) ||
6673	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6674        return(0);
6675
6676    ns = arg->nodesetval;
6677    if (ns != NULL) {
6678	for (i=0;i<ns->nodeNr;i++) {
6679	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6680	    if (str2 != NULL) {
6681		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6682		xmlFree(str2);
6683		xmlXPathNumberFunction(ctxt, 1);
6684		val = valuePop(ctxt);
6685		v = val->floatval;
6686		xmlXPathReleaseObject(ctxt->context, val);
6687		if (!xmlXPathIsNaN(v)) {
6688		    if ((!neq) && (v==f)) {
6689			ret = 1;
6690			break;
6691		    } else if ((neq) && (v!=f)) {
6692			ret = 1;
6693			break;
6694		    }
6695		} else {	/* NaN is unequal to any value */
6696		    if (neq)
6697			ret = 1;
6698		}
6699	    }
6700	}
6701    }
6702
6703    return(ret);
6704}
6705
6706
6707/**
6708 * xmlXPathEqualNodeSets:
6709 * @arg1:  first nodeset object argument
6710 * @arg2:  second nodeset object argument
6711 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6712 *
6713 * Implement the equal / not equal operation on XPath nodesets:
6714 * @arg1 == @arg2  or  @arg1 != @arg2
6715 * If both objects to be compared are node-sets, then the comparison
6716 * will be true if and only if there is a node in the first node-set and
6717 * a node in the second node-set such that the result of performing the
6718 * comparison on the string-values of the two nodes is true.
6719 *
6720 * (needless to say, this is a costly operation)
6721 *
6722 * Returns 0 or 1 depending on the results of the test.
6723 */
6724static int
6725xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6726    int i, j;
6727    unsigned int *hashs1;
6728    unsigned int *hashs2;
6729    xmlChar **values1;
6730    xmlChar **values2;
6731    int ret = 0;
6732    xmlNodeSetPtr ns1;
6733    xmlNodeSetPtr ns2;
6734
6735    if ((arg1 == NULL) ||
6736	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6737        return(0);
6738    if ((arg2 == NULL) ||
6739	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6740        return(0);
6741
6742    ns1 = arg1->nodesetval;
6743    ns2 = arg2->nodesetval;
6744
6745    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6746	return(0);
6747    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6748	return(0);
6749
6750    /*
6751     * for equal, check if there is a node pertaining to both sets
6752     */
6753    if (neq == 0)
6754	for (i = 0;i < ns1->nodeNr;i++)
6755	    for (j = 0;j < ns2->nodeNr;j++)
6756		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6757		    return(1);
6758
6759    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6760    if (values1 == NULL) {
6761        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6762	return(0);
6763    }
6764    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6765    if (hashs1 == NULL) {
6766        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6767	xmlFree(values1);
6768	return(0);
6769    }
6770    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6771    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6772    if (values2 == NULL) {
6773        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6774	xmlFree(hashs1);
6775	xmlFree(values1);
6776	return(0);
6777    }
6778    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6779    if (hashs2 == NULL) {
6780        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6781	xmlFree(hashs1);
6782	xmlFree(values1);
6783	xmlFree(values2);
6784	return(0);
6785    }
6786    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6787    for (i = 0;i < ns1->nodeNr;i++) {
6788	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6789	for (j = 0;j < ns2->nodeNr;j++) {
6790	    if (i == 0)
6791		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6792	    if (hashs1[i] != hashs2[j]) {
6793		if (neq) {
6794		    ret = 1;
6795		    break;
6796		}
6797	    }
6798	    else {
6799		if (values1[i] == NULL)
6800		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6801		if (values2[j] == NULL)
6802		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6803		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6804		if (ret)
6805		    break;
6806	    }
6807	}
6808	if (ret)
6809	    break;
6810    }
6811    for (i = 0;i < ns1->nodeNr;i++)
6812	if (values1[i] != NULL)
6813	    xmlFree(values1[i]);
6814    for (j = 0;j < ns2->nodeNr;j++)
6815	if (values2[j] != NULL)
6816	    xmlFree(values2[j]);
6817    xmlFree(values1);
6818    xmlFree(values2);
6819    xmlFree(hashs1);
6820    xmlFree(hashs2);
6821    return(ret);
6822}
6823
6824static int
6825xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6826  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6827    int ret = 0;
6828    /*
6829     *At this point we are assured neither arg1 nor arg2
6830     *is a nodeset, so we can just pick the appropriate routine.
6831     */
6832    switch (arg1->type) {
6833        case XPATH_UNDEFINED:
6834#ifdef DEBUG_EXPR
6835	    xmlGenericError(xmlGenericErrorContext,
6836		    "Equal: undefined\n");
6837#endif
6838	    break;
6839        case XPATH_BOOLEAN:
6840	    switch (arg2->type) {
6841	        case XPATH_UNDEFINED:
6842#ifdef DEBUG_EXPR
6843		    xmlGenericError(xmlGenericErrorContext,
6844			    "Equal: undefined\n");
6845#endif
6846		    break;
6847		case XPATH_BOOLEAN:
6848#ifdef DEBUG_EXPR
6849		    xmlGenericError(xmlGenericErrorContext,
6850			    "Equal: %d boolean %d \n",
6851			    arg1->boolval, arg2->boolval);
6852#endif
6853		    ret = (arg1->boolval == arg2->boolval);
6854		    break;
6855		case XPATH_NUMBER:
6856		    ret = (arg1->boolval ==
6857			   xmlXPathCastNumberToBoolean(arg2->floatval));
6858		    break;
6859		case XPATH_STRING:
6860		    if ((arg2->stringval == NULL) ||
6861			(arg2->stringval[0] == 0)) ret = 0;
6862		    else
6863			ret = 1;
6864		    ret = (arg1->boolval == ret);
6865		    break;
6866		case XPATH_USERS:
6867		case XPATH_POINT:
6868		case XPATH_RANGE:
6869		case XPATH_LOCATIONSET:
6870		    TODO
6871		    break;
6872		case XPATH_NODESET:
6873		case XPATH_XSLT_TREE:
6874		    break;
6875	    }
6876	    break;
6877        case XPATH_NUMBER:
6878	    switch (arg2->type) {
6879	        case XPATH_UNDEFINED:
6880#ifdef DEBUG_EXPR
6881		    xmlGenericError(xmlGenericErrorContext,
6882			    "Equal: undefined\n");
6883#endif
6884		    break;
6885		case XPATH_BOOLEAN:
6886		    ret = (arg2->boolval==
6887			   xmlXPathCastNumberToBoolean(arg1->floatval));
6888		    break;
6889		case XPATH_STRING:
6890		    valuePush(ctxt, arg2);
6891		    xmlXPathNumberFunction(ctxt, 1);
6892		    arg2 = valuePop(ctxt);
6893		    /* no break on purpose */
6894		case XPATH_NUMBER:
6895		    /* Hand check NaN and Infinity equalities */
6896		    if (xmlXPathIsNaN(arg1->floatval) ||
6897			    xmlXPathIsNaN(arg2->floatval)) {
6898		        ret = 0;
6899		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6900		        if (xmlXPathIsInf(arg2->floatval) == 1)
6901			    ret = 1;
6902			else
6903			    ret = 0;
6904		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6905			if (xmlXPathIsInf(arg2->floatval) == -1)
6906			    ret = 1;
6907			else
6908			    ret = 0;
6909		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6910			if (xmlXPathIsInf(arg1->floatval) == 1)
6911			    ret = 1;
6912			else
6913			    ret = 0;
6914		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6915			if (xmlXPathIsInf(arg1->floatval) == -1)
6916			    ret = 1;
6917			else
6918			    ret = 0;
6919		    } else {
6920		        ret = (arg1->floatval == arg2->floatval);
6921		    }
6922		    break;
6923		case XPATH_USERS:
6924		case XPATH_POINT:
6925		case XPATH_RANGE:
6926		case XPATH_LOCATIONSET:
6927		    TODO
6928		    break;
6929		case XPATH_NODESET:
6930		case XPATH_XSLT_TREE:
6931		    break;
6932	    }
6933	    break;
6934        case XPATH_STRING:
6935	    switch (arg2->type) {
6936	        case XPATH_UNDEFINED:
6937#ifdef DEBUG_EXPR
6938		    xmlGenericError(xmlGenericErrorContext,
6939			    "Equal: undefined\n");
6940#endif
6941		    break;
6942		case XPATH_BOOLEAN:
6943		    if ((arg1->stringval == NULL) ||
6944			(arg1->stringval[0] == 0)) ret = 0;
6945		    else
6946			ret = 1;
6947		    ret = (arg2->boolval == ret);
6948		    break;
6949		case XPATH_STRING:
6950		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6951		    break;
6952		case XPATH_NUMBER:
6953		    valuePush(ctxt, arg1);
6954		    xmlXPathNumberFunction(ctxt, 1);
6955		    arg1 = valuePop(ctxt);
6956		    /* Hand check NaN and Infinity equalities */
6957		    if (xmlXPathIsNaN(arg1->floatval) ||
6958			    xmlXPathIsNaN(arg2->floatval)) {
6959		        ret = 0;
6960		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6961			if (xmlXPathIsInf(arg2->floatval) == 1)
6962			    ret = 1;
6963			else
6964			    ret = 0;
6965		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6966			if (xmlXPathIsInf(arg2->floatval) == -1)
6967			    ret = 1;
6968			else
6969			    ret = 0;
6970		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6971			if (xmlXPathIsInf(arg1->floatval) == 1)
6972			    ret = 1;
6973			else
6974			    ret = 0;
6975		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6976			if (xmlXPathIsInf(arg1->floatval) == -1)
6977			    ret = 1;
6978			else
6979			    ret = 0;
6980		    } else {
6981		        ret = (arg1->floatval == arg2->floatval);
6982		    }
6983		    break;
6984		case XPATH_USERS:
6985		case XPATH_POINT:
6986		case XPATH_RANGE:
6987		case XPATH_LOCATIONSET:
6988		    TODO
6989		    break;
6990		case XPATH_NODESET:
6991		case XPATH_XSLT_TREE:
6992		    break;
6993	    }
6994	    break;
6995        case XPATH_USERS:
6996	case XPATH_POINT:
6997	case XPATH_RANGE:
6998	case XPATH_LOCATIONSET:
6999	    TODO
7000	    break;
7001	case XPATH_NODESET:
7002	case XPATH_XSLT_TREE:
7003	    break;
7004    }
7005    xmlXPathReleaseObject(ctxt->context, arg1);
7006    xmlXPathReleaseObject(ctxt->context, arg2);
7007    return(ret);
7008}
7009
7010/**
7011 * xmlXPathEqualValues:
7012 * @ctxt:  the XPath Parser context
7013 *
7014 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7015 *
7016 * Returns 0 or 1 depending on the results of the test.
7017 */
7018int
7019xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7020    xmlXPathObjectPtr arg1, arg2, argtmp;
7021    int ret = 0;
7022
7023    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7024    arg2 = valuePop(ctxt);
7025    arg1 = valuePop(ctxt);
7026    if ((arg1 == NULL) || (arg2 == NULL)) {
7027	if (arg1 != NULL)
7028	    xmlXPathReleaseObject(ctxt->context, arg1);
7029	else
7030	    xmlXPathReleaseObject(ctxt->context, arg2);
7031	XP_ERROR0(XPATH_INVALID_OPERAND);
7032    }
7033
7034    if (arg1 == arg2) {
7035#ifdef DEBUG_EXPR
7036        xmlGenericError(xmlGenericErrorContext,
7037		"Equal: by pointer\n");
7038#endif
7039	xmlXPathFreeObject(arg1);
7040        return(1);
7041    }
7042
7043    /*
7044     *If either argument is a nodeset, it's a 'special case'
7045     */
7046    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7047      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7048	/*
7049	 *Hack it to assure arg1 is the nodeset
7050	 */
7051	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7052		argtmp = arg2;
7053		arg2 = arg1;
7054		arg1 = argtmp;
7055	}
7056	switch (arg2->type) {
7057	    case XPATH_UNDEFINED:
7058#ifdef DEBUG_EXPR
7059		xmlGenericError(xmlGenericErrorContext,
7060			"Equal: undefined\n");
7061#endif
7062		break;
7063	    case XPATH_NODESET:
7064	    case XPATH_XSLT_TREE:
7065		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7066		break;
7067	    case XPATH_BOOLEAN:
7068		if ((arg1->nodesetval == NULL) ||
7069		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7070		else
7071		    ret = 1;
7072		ret = (ret == arg2->boolval);
7073		break;
7074	    case XPATH_NUMBER:
7075		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7076		break;
7077	    case XPATH_STRING:
7078		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7079		break;
7080	    case XPATH_USERS:
7081	    case XPATH_POINT:
7082	    case XPATH_RANGE:
7083	    case XPATH_LOCATIONSET:
7084		TODO
7085		break;
7086	}
7087	xmlXPathReleaseObject(ctxt->context, arg1);
7088	xmlXPathReleaseObject(ctxt->context, arg2);
7089	return(ret);
7090    }
7091
7092    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7093}
7094
7095/**
7096 * xmlXPathNotEqualValues:
7097 * @ctxt:  the XPath Parser context
7098 *
7099 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7100 *
7101 * Returns 0 or 1 depending on the results of the test.
7102 */
7103int
7104xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7105    xmlXPathObjectPtr arg1, arg2, argtmp;
7106    int ret = 0;
7107
7108    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7109    arg2 = valuePop(ctxt);
7110    arg1 = valuePop(ctxt);
7111    if ((arg1 == NULL) || (arg2 == NULL)) {
7112	if (arg1 != NULL)
7113	    xmlXPathReleaseObject(ctxt->context, arg1);
7114	else
7115	    xmlXPathReleaseObject(ctxt->context, arg2);
7116	XP_ERROR0(XPATH_INVALID_OPERAND);
7117    }
7118
7119    if (arg1 == arg2) {
7120#ifdef DEBUG_EXPR
7121        xmlGenericError(xmlGenericErrorContext,
7122		"NotEqual: by pointer\n");
7123#endif
7124	xmlXPathReleaseObject(ctxt->context, arg1);
7125        return(0);
7126    }
7127
7128    /*
7129     *If either argument is a nodeset, it's a 'special case'
7130     */
7131    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7132      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7133	/*
7134	 *Hack it to assure arg1 is the nodeset
7135	 */
7136	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7137		argtmp = arg2;
7138		arg2 = arg1;
7139		arg1 = argtmp;
7140	}
7141	switch (arg2->type) {
7142	    case XPATH_UNDEFINED:
7143#ifdef DEBUG_EXPR
7144		xmlGenericError(xmlGenericErrorContext,
7145			"NotEqual: undefined\n");
7146#endif
7147		break;
7148	    case XPATH_NODESET:
7149	    case XPATH_XSLT_TREE:
7150		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7151		break;
7152	    case XPATH_BOOLEAN:
7153		if ((arg1->nodesetval == NULL) ||
7154		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7155		else
7156		    ret = 1;
7157		ret = (ret != arg2->boolval);
7158		break;
7159	    case XPATH_NUMBER:
7160		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7161		break;
7162	    case XPATH_STRING:
7163		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7164		break;
7165	    case XPATH_USERS:
7166	    case XPATH_POINT:
7167	    case XPATH_RANGE:
7168	    case XPATH_LOCATIONSET:
7169		TODO
7170		break;
7171	}
7172	xmlXPathReleaseObject(ctxt->context, arg1);
7173	xmlXPathReleaseObject(ctxt->context, arg2);
7174	return(ret);
7175    }
7176
7177    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7178}
7179
7180/**
7181 * xmlXPathCompareValues:
7182 * @ctxt:  the XPath Parser context
7183 * @inf:  less than (1) or greater than (0)
7184 * @strict:  is the comparison strict
7185 *
7186 * Implement the compare operation on XPath objects:
7187 *     @arg1 < @arg2    (1, 1, ...
7188 *     @arg1 <= @arg2   (1, 0, ...
7189 *     @arg1 > @arg2    (0, 1, ...
7190 *     @arg1 >= @arg2   (0, 0, ...
7191 *
7192 * When neither object to be compared is a node-set and the operator is
7193 * <=, <, >=, >, then the objects are compared by converted both objects
7194 * to numbers and comparing the numbers according to IEEE 754. The <
7195 * comparison will be true if and only if the first number is less than the
7196 * second number. The <= comparison will be true if and only if the first
7197 * number is less than or equal to the second number. The > comparison
7198 * will be true if and only if the first number is greater than the second
7199 * number. The >= comparison will be true if and only if the first number
7200 * is greater than or equal to the second number.
7201 *
7202 * Returns 1 if the comparison succeeded, 0 if it failed
7203 */
7204int
7205xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7206    int ret = 0, arg1i = 0, arg2i = 0;
7207    xmlXPathObjectPtr arg1, arg2;
7208
7209    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7210    arg2 = valuePop(ctxt);
7211    arg1 = valuePop(ctxt);
7212    if ((arg1 == NULL) || (arg2 == NULL)) {
7213	if (arg1 != NULL)
7214	    xmlXPathReleaseObject(ctxt->context, arg1);
7215	else
7216	    xmlXPathReleaseObject(ctxt->context, arg2);
7217	XP_ERROR0(XPATH_INVALID_OPERAND);
7218    }
7219
7220    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7221      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7222	/*
7223	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7224	 * are not freed from within this routine; they will be freed from the
7225	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7226	 */
7227	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7228	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7229	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7230	} else {
7231	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7232		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7233			                          arg1, arg2);
7234	    } else {
7235		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7236			                          arg2, arg1);
7237	    }
7238	}
7239	return(ret);
7240    }
7241
7242    if (arg1->type != XPATH_NUMBER) {
7243	valuePush(ctxt, arg1);
7244	xmlXPathNumberFunction(ctxt, 1);
7245	arg1 = valuePop(ctxt);
7246    }
7247    if (arg1->type != XPATH_NUMBER) {
7248	xmlXPathFreeObject(arg1);
7249	xmlXPathFreeObject(arg2);
7250	XP_ERROR0(XPATH_INVALID_OPERAND);
7251    }
7252    if (arg2->type != XPATH_NUMBER) {
7253	valuePush(ctxt, arg2);
7254	xmlXPathNumberFunction(ctxt, 1);
7255	arg2 = valuePop(ctxt);
7256    }
7257    if (arg2->type != XPATH_NUMBER) {
7258	xmlXPathReleaseObject(ctxt->context, arg1);
7259	xmlXPathReleaseObject(ctxt->context, arg2);
7260	XP_ERROR0(XPATH_INVALID_OPERAND);
7261    }
7262    /*
7263     * Add tests for infinity and nan
7264     * => feedback on 3.4 for Inf and NaN
7265     */
7266    /* Hand check NaN and Infinity comparisons */
7267    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7268	ret=0;
7269    } else {
7270	arg1i=xmlXPathIsInf(arg1->floatval);
7271	arg2i=xmlXPathIsInf(arg2->floatval);
7272	if (inf && strict) {
7273	    if ((arg1i == -1 && arg2i != -1) ||
7274		(arg2i == 1 && arg1i != 1)) {
7275		ret = 1;
7276	    } else if (arg1i == 0 && arg2i == 0) {
7277		ret = (arg1->floatval < arg2->floatval);
7278	    } else {
7279		ret = 0;
7280	    }
7281	}
7282	else if (inf && !strict) {
7283	    if (arg1i == -1 || arg2i == 1) {
7284		ret = 1;
7285	    } else if (arg1i == 0 && arg2i == 0) {
7286		ret = (arg1->floatval <= arg2->floatval);
7287	    } else {
7288		ret = 0;
7289	    }
7290	}
7291	else if (!inf && strict) {
7292	    if ((arg1i == 1 && arg2i != 1) ||
7293		(arg2i == -1 && arg1i != -1)) {
7294		ret = 1;
7295	    } else if (arg1i == 0 && arg2i == 0) {
7296		ret = (arg1->floatval > arg2->floatval);
7297	    } else {
7298		ret = 0;
7299	    }
7300	}
7301	else if (!inf && !strict) {
7302	    if (arg1i == 1 || arg2i == -1) {
7303		ret = 1;
7304	    } else if (arg1i == 0 && arg2i == 0) {
7305		ret = (arg1->floatval >= arg2->floatval);
7306	    } else {
7307		ret = 0;
7308	    }
7309	}
7310    }
7311    xmlXPathReleaseObject(ctxt->context, arg1);
7312    xmlXPathReleaseObject(ctxt->context, arg2);
7313    return(ret);
7314}
7315
7316/**
7317 * xmlXPathValueFlipSign:
7318 * @ctxt:  the XPath Parser context
7319 *
7320 * Implement the unary - operation on an XPath object
7321 * The numeric operators convert their operands to numbers as if
7322 * by calling the number function.
7323 */
7324void
7325xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7326    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7327    CAST_TO_NUMBER;
7328    CHECK_TYPE(XPATH_NUMBER);
7329    if (xmlXPathIsNaN(ctxt->value->floatval))
7330        ctxt->value->floatval=xmlXPathNAN;
7331    else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7332        ctxt->value->floatval=xmlXPathNINF;
7333    else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7334        ctxt->value->floatval=xmlXPathPINF;
7335    else if (ctxt->value->floatval == 0) {
7336        if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7337	    ctxt->value->floatval = xmlXPathNZERO;
7338	else
7339	    ctxt->value->floatval = 0;
7340    }
7341    else
7342        ctxt->value->floatval = - ctxt->value->floatval;
7343}
7344
7345/**
7346 * xmlXPathAddValues:
7347 * @ctxt:  the XPath Parser context
7348 *
7349 * Implement the add operation on XPath objects:
7350 * The numeric operators convert their operands to numbers as if
7351 * by calling the number function.
7352 */
7353void
7354xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7355    xmlXPathObjectPtr arg;
7356    double val;
7357
7358    arg = valuePop(ctxt);
7359    if (arg == NULL)
7360	XP_ERROR(XPATH_INVALID_OPERAND);
7361    val = xmlXPathCastToNumber(arg);
7362    xmlXPathReleaseObject(ctxt->context, arg);
7363    CAST_TO_NUMBER;
7364    CHECK_TYPE(XPATH_NUMBER);
7365    ctxt->value->floatval += val;
7366}
7367
7368/**
7369 * xmlXPathSubValues:
7370 * @ctxt:  the XPath Parser context
7371 *
7372 * Implement the subtraction operation on XPath objects:
7373 * The numeric operators convert their operands to numbers as if
7374 * by calling the number function.
7375 */
7376void
7377xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7378    xmlXPathObjectPtr arg;
7379    double val;
7380
7381    arg = valuePop(ctxt);
7382    if (arg == NULL)
7383	XP_ERROR(XPATH_INVALID_OPERAND);
7384    val = xmlXPathCastToNumber(arg);
7385    xmlXPathReleaseObject(ctxt->context, arg);
7386    CAST_TO_NUMBER;
7387    CHECK_TYPE(XPATH_NUMBER);
7388    ctxt->value->floatval -= val;
7389}
7390
7391/**
7392 * xmlXPathMultValues:
7393 * @ctxt:  the XPath Parser context
7394 *
7395 * Implement the multiply operation on XPath objects:
7396 * The numeric operators convert their operands to numbers as if
7397 * by calling the number function.
7398 */
7399void
7400xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7401    xmlXPathObjectPtr arg;
7402    double val;
7403
7404    arg = valuePop(ctxt);
7405    if (arg == NULL)
7406	XP_ERROR(XPATH_INVALID_OPERAND);
7407    val = xmlXPathCastToNumber(arg);
7408    xmlXPathReleaseObject(ctxt->context, arg);
7409    CAST_TO_NUMBER;
7410    CHECK_TYPE(XPATH_NUMBER);
7411    ctxt->value->floatval *= val;
7412}
7413
7414/**
7415 * xmlXPathDivValues:
7416 * @ctxt:  the XPath Parser context
7417 *
7418 * Implement the div operation on XPath objects @arg1 / @arg2:
7419 * The numeric operators convert their operands to numbers as if
7420 * by calling the number function.
7421 */
7422void
7423xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7424    xmlXPathObjectPtr arg;
7425    double val;
7426
7427    arg = valuePop(ctxt);
7428    if (arg == NULL)
7429	XP_ERROR(XPATH_INVALID_OPERAND);
7430    val = xmlXPathCastToNumber(arg);
7431    xmlXPathReleaseObject(ctxt->context, arg);
7432    CAST_TO_NUMBER;
7433    CHECK_TYPE(XPATH_NUMBER);
7434    if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7435	ctxt->value->floatval = xmlXPathNAN;
7436    else if (val == 0 && xmlXPathGetSign(val) != 0) {
7437	if (ctxt->value->floatval == 0)
7438	    ctxt->value->floatval = xmlXPathNAN;
7439	else if (ctxt->value->floatval > 0)
7440	    ctxt->value->floatval = xmlXPathNINF;
7441	else if (ctxt->value->floatval < 0)
7442	    ctxt->value->floatval = xmlXPathPINF;
7443    }
7444    else if (val == 0) {
7445	if (ctxt->value->floatval == 0)
7446	    ctxt->value->floatval = xmlXPathNAN;
7447	else if (ctxt->value->floatval > 0)
7448	    ctxt->value->floatval = xmlXPathPINF;
7449	else if (ctxt->value->floatval < 0)
7450	    ctxt->value->floatval = xmlXPathNINF;
7451    } else
7452	ctxt->value->floatval /= val;
7453}
7454
7455/**
7456 * xmlXPathModValues:
7457 * @ctxt:  the XPath Parser context
7458 *
7459 * Implement the mod operation on XPath objects: @arg1 / @arg2
7460 * The numeric operators convert their operands to numbers as if
7461 * by calling the number function.
7462 */
7463void
7464xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7465    xmlXPathObjectPtr arg;
7466    double arg1, arg2;
7467
7468    arg = valuePop(ctxt);
7469    if (arg == NULL)
7470	XP_ERROR(XPATH_INVALID_OPERAND);
7471    arg2 = xmlXPathCastToNumber(arg);
7472    xmlXPathReleaseObject(ctxt->context, arg);
7473    CAST_TO_NUMBER;
7474    CHECK_TYPE(XPATH_NUMBER);
7475    arg1 = ctxt->value->floatval;
7476    if (arg2 == 0)
7477	ctxt->value->floatval = xmlXPathNAN;
7478    else {
7479	ctxt->value->floatval = fmod(arg1, arg2);
7480    }
7481}
7482
7483/************************************************************************
7484 *									*
7485 *		The traversal functions					*
7486 *									*
7487 ************************************************************************/
7488
7489/*
7490 * A traversal function enumerates nodes along an axis.
7491 * Initially it must be called with NULL, and it indicates
7492 * termination on the axis by returning NULL.
7493 */
7494typedef xmlNodePtr (*xmlXPathTraversalFunction)
7495                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7496
7497/*
7498 * xmlXPathTraversalFunctionExt:
7499 * A traversal function enumerates nodes along an axis.
7500 * Initially it must be called with NULL, and it indicates
7501 * termination on the axis by returning NULL.
7502 * The context node of the traversal is specified via @contextNode.
7503 */
7504typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7505                    (xmlNodePtr cur, xmlNodePtr contextNode);
7506
7507/*
7508 * xmlXPathNodeSetMergeFunction:
7509 * Used for merging node sets in xmlXPathCollectAndTest().
7510 */
7511typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7512		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
7513
7514
7515/**
7516 * xmlXPathNextSelf:
7517 * @ctxt:  the XPath Parser context
7518 * @cur:  the current node in the traversal
7519 *
7520 * Traversal function for the "self" direction
7521 * The self axis contains just the context node itself
7522 *
7523 * Returns the next element following that axis
7524 */
7525xmlNodePtr
7526xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7527    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7528    if (cur == NULL)
7529        return(ctxt->context->node);
7530    return(NULL);
7531}
7532
7533/**
7534 * xmlXPathNextChild:
7535 * @ctxt:  the XPath Parser context
7536 * @cur:  the current node in the traversal
7537 *
7538 * Traversal function for the "child" direction
7539 * The child axis contains the children of the context node in document order.
7540 *
7541 * Returns the next element following that axis
7542 */
7543xmlNodePtr
7544xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7545    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7546    if (cur == NULL) {
7547	if (ctxt->context->node == NULL) return(NULL);
7548	switch (ctxt->context->node->type) {
7549            case XML_ELEMENT_NODE:
7550            case XML_TEXT_NODE:
7551            case XML_CDATA_SECTION_NODE:
7552            case XML_ENTITY_REF_NODE:
7553            case XML_ENTITY_NODE:
7554            case XML_PI_NODE:
7555            case XML_COMMENT_NODE:
7556            case XML_NOTATION_NODE:
7557            case XML_DTD_NODE:
7558		return(ctxt->context->node->children);
7559            case XML_DOCUMENT_NODE:
7560            case XML_DOCUMENT_TYPE_NODE:
7561            case XML_DOCUMENT_FRAG_NODE:
7562            case XML_HTML_DOCUMENT_NODE:
7563#ifdef LIBXML_DOCB_ENABLED
7564	    case XML_DOCB_DOCUMENT_NODE:
7565#endif
7566		return(((xmlDocPtr) ctxt->context->node)->children);
7567	    case XML_ELEMENT_DECL:
7568	    case XML_ATTRIBUTE_DECL:
7569	    case XML_ENTITY_DECL:
7570            case XML_ATTRIBUTE_NODE:
7571	    case XML_NAMESPACE_DECL:
7572	    case XML_XINCLUDE_START:
7573	    case XML_XINCLUDE_END:
7574		return(NULL);
7575	}
7576	return(NULL);
7577    }
7578    if ((cur->type == XML_DOCUMENT_NODE) ||
7579        (cur->type == XML_HTML_DOCUMENT_NODE))
7580	return(NULL);
7581    return(cur->next);
7582}
7583
7584/**
7585 * xmlXPathNextChildElement:
7586 * @ctxt:  the XPath Parser context
7587 * @cur:  the current node in the traversal
7588 *
7589 * Traversal function for the "child" direction and nodes of type element.
7590 * The child axis contains the children of the context node in document order.
7591 *
7592 * Returns the next element following that axis
7593 */
7594static xmlNodePtr
7595xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7596    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7597    if (cur == NULL) {
7598	cur = ctxt->context->node;
7599	if (cur == NULL) return(NULL);
7600	/*
7601	* Get the first element child.
7602	*/
7603	switch (cur->type) {
7604            case XML_ELEMENT_NODE:
7605	    case XML_DOCUMENT_FRAG_NODE:
7606	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7607            case XML_ENTITY_NODE:
7608		cur = cur->children;
7609		if (cur != NULL) {
7610		    if (cur->type == XML_ELEMENT_NODE)
7611			return(cur);
7612		    do {
7613			cur = cur->next;
7614		    } while ((cur != NULL) &&
7615			(cur->type != XML_ELEMENT_NODE));
7616		    return(cur);
7617		}
7618		return(NULL);
7619            case XML_DOCUMENT_NODE:
7620            case XML_HTML_DOCUMENT_NODE:
7621#ifdef LIBXML_DOCB_ENABLED
7622	    case XML_DOCB_DOCUMENT_NODE:
7623#endif
7624		return(xmlDocGetRootElement((xmlDocPtr) cur));
7625	    default:
7626		return(NULL);
7627	}
7628	return(NULL);
7629    }
7630    /*
7631    * Get the next sibling element node.
7632    */
7633    switch (cur->type) {
7634	case XML_ELEMENT_NODE:
7635	case XML_TEXT_NODE:
7636	case XML_ENTITY_REF_NODE:
7637	case XML_ENTITY_NODE:
7638	case XML_CDATA_SECTION_NODE:
7639	case XML_PI_NODE:
7640	case XML_COMMENT_NODE:
7641	case XML_XINCLUDE_END:
7642	    break;
7643	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7644	default:
7645	    return(NULL);
7646    }
7647    if (cur->next != NULL) {
7648	if (cur->next->type == XML_ELEMENT_NODE)
7649	    return(cur->next);
7650	cur = cur->next;
7651	do {
7652	    cur = cur->next;
7653	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7654	return(cur);
7655    }
7656    return(NULL);
7657}
7658
7659/**
7660 * xmlXPathNextDescendantOrSelfElemParent:
7661 * @ctxt:  the XPath Parser context
7662 * @cur:  the current node in the traversal
7663 *
7664 * Traversal function for the "descendant-or-self" axis.
7665 * Additionally it returns only nodes which can be parents of
7666 * element nodes.
7667 *
7668 *
7669 * Returns the next element following that axis
7670 */
7671static xmlNodePtr
7672xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7673				       xmlNodePtr contextNode)
7674{
7675    if (cur == NULL) {
7676	if (contextNode == NULL)
7677	    return(NULL);
7678	switch (contextNode->type) {
7679	    case XML_ELEMENT_NODE:
7680	    case XML_XINCLUDE_START:
7681	    case XML_DOCUMENT_FRAG_NODE:
7682	    case XML_DOCUMENT_NODE:
7683#ifdef LIBXML_DOCB_ENABLED
7684	    case XML_DOCB_DOCUMENT_NODE:
7685#endif
7686	    case XML_HTML_DOCUMENT_NODE:
7687		return(contextNode);
7688	    default:
7689		return(NULL);
7690	}
7691	return(NULL);
7692    } else {
7693	xmlNodePtr start = cur;
7694
7695	while (cur != NULL) {
7696	    switch (cur->type) {
7697		case XML_ELEMENT_NODE:
7698		/* TODO: OK to have XInclude here? */
7699		case XML_XINCLUDE_START:
7700		case XML_DOCUMENT_FRAG_NODE:
7701		    if (cur != start)
7702			return(cur);
7703		    if (cur->children != NULL) {
7704			cur = cur->children;
7705			continue;
7706		    }
7707		    break;
7708		/* Not sure if we need those here. */
7709		case XML_DOCUMENT_NODE:
7710#ifdef LIBXML_DOCB_ENABLED
7711		case XML_DOCB_DOCUMENT_NODE:
7712#endif
7713		case XML_HTML_DOCUMENT_NODE:
7714		    if (cur != start)
7715			return(cur);
7716		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7717		default:
7718		    break;
7719	    }
7720
7721next_sibling:
7722	    if ((cur == NULL) || (cur == contextNode))
7723		return(NULL);
7724	    if (cur->next != NULL) {
7725		cur = cur->next;
7726	    } else {
7727		cur = cur->parent;
7728		goto next_sibling;
7729	    }
7730	}
7731    }
7732    return(NULL);
7733}
7734
7735/**
7736 * xmlXPathNextDescendant:
7737 * @ctxt:  the XPath Parser context
7738 * @cur:  the current node in the traversal
7739 *
7740 * Traversal function for the "descendant" direction
7741 * the descendant axis contains the descendants of the context node in document
7742 * order; a descendant is a child or a child of a child and so on.
7743 *
7744 * Returns the next element following that axis
7745 */
7746xmlNodePtr
7747xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7748    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7749    if (cur == NULL) {
7750	if (ctxt->context->node == NULL)
7751	    return(NULL);
7752	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7753	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7754	    return(NULL);
7755
7756        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7757	    return(ctxt->context->doc->children);
7758        return(ctxt->context->node->children);
7759    }
7760
7761    if (cur->children != NULL) {
7762	/*
7763	 * Do not descend on entities declarations
7764	 */
7765	if (cur->children->type != XML_ENTITY_DECL) {
7766	    cur = cur->children;
7767	    /*
7768	     * Skip DTDs
7769	     */
7770	    if (cur->type != XML_DTD_NODE)
7771		return(cur);
7772	}
7773    }
7774
7775    if (cur == ctxt->context->node) return(NULL);
7776
7777    while (cur->next != NULL) {
7778	cur = cur->next;
7779	if ((cur->type != XML_ENTITY_DECL) &&
7780	    (cur->type != XML_DTD_NODE))
7781	    return(cur);
7782    }
7783
7784    do {
7785        cur = cur->parent;
7786	if (cur == NULL) break;
7787	if (cur == ctxt->context->node) return(NULL);
7788	if (cur->next != NULL) {
7789	    cur = cur->next;
7790	    return(cur);
7791	}
7792    } while (cur != NULL);
7793    return(cur);
7794}
7795
7796/**
7797 * xmlXPathNextDescendantOrSelf:
7798 * @ctxt:  the XPath Parser context
7799 * @cur:  the current node in the traversal
7800 *
7801 * Traversal function for the "descendant-or-self" direction
7802 * the descendant-or-self axis contains the context node and the descendants
7803 * of the context node in document order; thus the context node is the first
7804 * node on the axis, and the first child of the context node is the second node
7805 * on the axis
7806 *
7807 * Returns the next element following that axis
7808 */
7809xmlNodePtr
7810xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7811    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7812    if (cur == NULL) {
7813	if (ctxt->context->node == NULL)
7814	    return(NULL);
7815	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7816	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7817	    return(NULL);
7818        return(ctxt->context->node);
7819    }
7820
7821    return(xmlXPathNextDescendant(ctxt, cur));
7822}
7823
7824/**
7825 * xmlXPathNextParent:
7826 * @ctxt:  the XPath Parser context
7827 * @cur:  the current node in the traversal
7828 *
7829 * Traversal function for the "parent" direction
7830 * The parent axis contains the parent of the context node, if there is one.
7831 *
7832 * Returns the next element following that axis
7833 */
7834xmlNodePtr
7835xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7836    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7837    /*
7838     * the parent of an attribute or namespace node is the element
7839     * to which the attribute or namespace node is attached
7840     * Namespace handling !!!
7841     */
7842    if (cur == NULL) {
7843	if (ctxt->context->node == NULL) return(NULL);
7844	switch (ctxt->context->node->type) {
7845            case XML_ELEMENT_NODE:
7846            case XML_TEXT_NODE:
7847            case XML_CDATA_SECTION_NODE:
7848            case XML_ENTITY_REF_NODE:
7849            case XML_ENTITY_NODE:
7850            case XML_PI_NODE:
7851            case XML_COMMENT_NODE:
7852            case XML_NOTATION_NODE:
7853            case XML_DTD_NODE:
7854	    case XML_ELEMENT_DECL:
7855	    case XML_ATTRIBUTE_DECL:
7856	    case XML_XINCLUDE_START:
7857	    case XML_XINCLUDE_END:
7858	    case XML_ENTITY_DECL:
7859		if (ctxt->context->node->parent == NULL)
7860		    return((xmlNodePtr) ctxt->context->doc);
7861		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7862		    ((ctxt->context->node->parent->name[0] == ' ') ||
7863		     (xmlStrEqual(ctxt->context->node->parent->name,
7864				 BAD_CAST "fake node libxslt"))))
7865		    return(NULL);
7866		return(ctxt->context->node->parent);
7867            case XML_ATTRIBUTE_NODE: {
7868		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7869
7870		return(att->parent);
7871	    }
7872            case XML_DOCUMENT_NODE:
7873            case XML_DOCUMENT_TYPE_NODE:
7874            case XML_DOCUMENT_FRAG_NODE:
7875            case XML_HTML_DOCUMENT_NODE:
7876#ifdef LIBXML_DOCB_ENABLED
7877	    case XML_DOCB_DOCUMENT_NODE:
7878#endif
7879                return(NULL);
7880	    case XML_NAMESPACE_DECL: {
7881		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7882
7883		if ((ns->next != NULL) &&
7884		    (ns->next->type != XML_NAMESPACE_DECL))
7885		    return((xmlNodePtr) ns->next);
7886                return(NULL);
7887	    }
7888	}
7889    }
7890    return(NULL);
7891}
7892
7893/**
7894 * xmlXPathNextAncestor:
7895 * @ctxt:  the XPath Parser context
7896 * @cur:  the current node in the traversal
7897 *
7898 * Traversal function for the "ancestor" direction
7899 * the ancestor axis contains the ancestors of the context node; the ancestors
7900 * of the context node consist of the parent of context node and the parent's
7901 * parent and so on; the nodes are ordered in reverse document order; thus the
7902 * parent is the first node on the axis, and the parent's parent is the second
7903 * node on the axis
7904 *
7905 * Returns the next element following that axis
7906 */
7907xmlNodePtr
7908xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7909    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7910    /*
7911     * the parent of an attribute or namespace node is the element
7912     * to which the attribute or namespace node is attached
7913     * !!!!!!!!!!!!!
7914     */
7915    if (cur == NULL) {
7916	if (ctxt->context->node == NULL) return(NULL);
7917	switch (ctxt->context->node->type) {
7918            case XML_ELEMENT_NODE:
7919            case XML_TEXT_NODE:
7920            case XML_CDATA_SECTION_NODE:
7921            case XML_ENTITY_REF_NODE:
7922            case XML_ENTITY_NODE:
7923            case XML_PI_NODE:
7924            case XML_COMMENT_NODE:
7925	    case XML_DTD_NODE:
7926	    case XML_ELEMENT_DECL:
7927	    case XML_ATTRIBUTE_DECL:
7928	    case XML_ENTITY_DECL:
7929            case XML_NOTATION_NODE:
7930	    case XML_XINCLUDE_START:
7931	    case XML_XINCLUDE_END:
7932		if (ctxt->context->node->parent == NULL)
7933		    return((xmlNodePtr) ctxt->context->doc);
7934		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7935		    ((ctxt->context->node->parent->name[0] == ' ') ||
7936		     (xmlStrEqual(ctxt->context->node->parent->name,
7937				 BAD_CAST "fake node libxslt"))))
7938		    return(NULL);
7939		return(ctxt->context->node->parent);
7940            case XML_ATTRIBUTE_NODE: {
7941		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7942
7943		return(tmp->parent);
7944	    }
7945            case XML_DOCUMENT_NODE:
7946            case XML_DOCUMENT_TYPE_NODE:
7947            case XML_DOCUMENT_FRAG_NODE:
7948            case XML_HTML_DOCUMENT_NODE:
7949#ifdef LIBXML_DOCB_ENABLED
7950	    case XML_DOCB_DOCUMENT_NODE:
7951#endif
7952                return(NULL);
7953	    case XML_NAMESPACE_DECL: {
7954		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7955
7956		if ((ns->next != NULL) &&
7957		    (ns->next->type != XML_NAMESPACE_DECL))
7958		    return((xmlNodePtr) ns->next);
7959		/* Bad, how did that namespace end up here ? */
7960                return(NULL);
7961	    }
7962	}
7963	return(NULL);
7964    }
7965    if (cur == ctxt->context->doc->children)
7966	return((xmlNodePtr) ctxt->context->doc);
7967    if (cur == (xmlNodePtr) ctxt->context->doc)
7968	return(NULL);
7969    switch (cur->type) {
7970	case XML_ELEMENT_NODE:
7971	case XML_TEXT_NODE:
7972	case XML_CDATA_SECTION_NODE:
7973	case XML_ENTITY_REF_NODE:
7974	case XML_ENTITY_NODE:
7975	case XML_PI_NODE:
7976	case XML_COMMENT_NODE:
7977	case XML_NOTATION_NODE:
7978	case XML_DTD_NODE:
7979        case XML_ELEMENT_DECL:
7980        case XML_ATTRIBUTE_DECL:
7981        case XML_ENTITY_DECL:
7982	case XML_XINCLUDE_START:
7983	case XML_XINCLUDE_END:
7984	    if (cur->parent == NULL)
7985		return(NULL);
7986	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
7987		((cur->parent->name[0] == ' ') ||
7988		 (xmlStrEqual(cur->parent->name,
7989			      BAD_CAST "fake node libxslt"))))
7990		return(NULL);
7991	    return(cur->parent);
7992	case XML_ATTRIBUTE_NODE: {
7993	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7994
7995	    return(att->parent);
7996	}
7997	case XML_NAMESPACE_DECL: {
7998	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7999
8000	    if ((ns->next != NULL) &&
8001	        (ns->next->type != XML_NAMESPACE_DECL))
8002	        return((xmlNodePtr) ns->next);
8003	    /* Bad, how did that namespace end up here ? */
8004            return(NULL);
8005	}
8006	case XML_DOCUMENT_NODE:
8007	case XML_DOCUMENT_TYPE_NODE:
8008	case XML_DOCUMENT_FRAG_NODE:
8009	case XML_HTML_DOCUMENT_NODE:
8010#ifdef LIBXML_DOCB_ENABLED
8011	case XML_DOCB_DOCUMENT_NODE:
8012#endif
8013	    return(NULL);
8014    }
8015    return(NULL);
8016}
8017
8018/**
8019 * xmlXPathNextAncestorOrSelf:
8020 * @ctxt:  the XPath Parser context
8021 * @cur:  the current node in the traversal
8022 *
8023 * Traversal function for the "ancestor-or-self" direction
8024 * he ancestor-or-self axis contains the context node and ancestors of
8025 * the context node in reverse document order; thus the context node is
8026 * the first node on the axis, and the context node's parent the second;
8027 * parent here is defined the same as with the parent axis.
8028 *
8029 * Returns the next element following that axis
8030 */
8031xmlNodePtr
8032xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8033    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8034    if (cur == NULL)
8035        return(ctxt->context->node);
8036    return(xmlXPathNextAncestor(ctxt, cur));
8037}
8038
8039/**
8040 * xmlXPathNextFollowingSibling:
8041 * @ctxt:  the XPath Parser context
8042 * @cur:  the current node in the traversal
8043 *
8044 * Traversal function for the "following-sibling" direction
8045 * The following-sibling axis contains the following siblings of the context
8046 * node in document order.
8047 *
8048 * Returns the next element following that axis
8049 */
8050xmlNodePtr
8051xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8052    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8053    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8054	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8055	return(NULL);
8056    if (cur == (xmlNodePtr) ctxt->context->doc)
8057        return(NULL);
8058    if (cur == NULL)
8059        return(ctxt->context->node->next);
8060    return(cur->next);
8061}
8062
8063/**
8064 * xmlXPathNextPrecedingSibling:
8065 * @ctxt:  the XPath Parser context
8066 * @cur:  the current node in the traversal
8067 *
8068 * Traversal function for the "preceding-sibling" direction
8069 * The preceding-sibling axis contains the preceding siblings of the context
8070 * node in reverse document order; the first preceding sibling is first on the
8071 * axis; the sibling preceding that node is the second on the axis and so on.
8072 *
8073 * Returns the next element following that axis
8074 */
8075xmlNodePtr
8076xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8077    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8078    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8079	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8080	return(NULL);
8081    if (cur == (xmlNodePtr) ctxt->context->doc)
8082        return(NULL);
8083    if (cur == NULL)
8084        return(ctxt->context->node->prev);
8085    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8086	cur = cur->prev;
8087	if (cur == NULL)
8088	    return(ctxt->context->node->prev);
8089    }
8090    return(cur->prev);
8091}
8092
8093/**
8094 * xmlXPathNextFollowing:
8095 * @ctxt:  the XPath Parser context
8096 * @cur:  the current node in the traversal
8097 *
8098 * Traversal function for the "following" direction
8099 * The following axis contains all nodes in the same document as the context
8100 * node that are after the context node in document order, excluding any
8101 * descendants and excluding attribute nodes and namespace nodes; the nodes
8102 * are ordered in document order
8103 *
8104 * Returns the next element following that axis
8105 */
8106xmlNodePtr
8107xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8108    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8109    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8110        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8111        return(cur->children);
8112
8113    if (cur == NULL) {
8114        cur = ctxt->context->node;
8115        if (cur->type == XML_NAMESPACE_DECL)
8116            return(NULL);
8117        if (cur->type == XML_ATTRIBUTE_NODE)
8118            cur = cur->parent;
8119    }
8120    if (cur == NULL) return(NULL) ; /* ERROR */
8121    if (cur->next != NULL) return(cur->next) ;
8122    do {
8123        cur = cur->parent;
8124        if (cur == NULL) break;
8125        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8126        if (cur->next != NULL) return(cur->next);
8127    } while (cur != NULL);
8128    return(cur);
8129}
8130
8131/*
8132 * xmlXPathIsAncestor:
8133 * @ancestor:  the ancestor node
8134 * @node:  the current node
8135 *
8136 * Check that @ancestor is a @node's ancestor
8137 *
8138 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8139 */
8140static int
8141xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8142    if ((ancestor == NULL) || (node == NULL)) return(0);
8143    /* nodes need to be in the same document */
8144    if (ancestor->doc != node->doc) return(0);
8145    /* avoid searching if ancestor or node is the root node */
8146    if (ancestor == (xmlNodePtr) node->doc) return(1);
8147    if (node == (xmlNodePtr) ancestor->doc) return(0);
8148    while (node->parent != NULL) {
8149        if (node->parent == ancestor)
8150            return(1);
8151	node = node->parent;
8152    }
8153    return(0);
8154}
8155
8156/**
8157 * xmlXPathNextPreceding:
8158 * @ctxt:  the XPath Parser context
8159 * @cur:  the current node in the traversal
8160 *
8161 * Traversal function for the "preceding" direction
8162 * the preceding axis contains all nodes in the same document as the context
8163 * node that are before the context node in document order, excluding any
8164 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8165 * ordered in reverse document order
8166 *
8167 * Returns the next element following that axis
8168 */
8169xmlNodePtr
8170xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8171{
8172    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8173    if (cur == NULL) {
8174        cur = ctxt->context->node;
8175        if (cur->type == XML_NAMESPACE_DECL)
8176            return(NULL);
8177        if (cur->type == XML_ATTRIBUTE_NODE)
8178            return(cur->parent);
8179    }
8180    if (cur == NULL)
8181	return (NULL);
8182    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8183	cur = cur->prev;
8184    do {
8185        if (cur->prev != NULL) {
8186            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8187            return (cur);
8188        }
8189
8190        cur = cur->parent;
8191        if (cur == NULL)
8192            return (NULL);
8193        if (cur == ctxt->context->doc->children)
8194            return (NULL);
8195    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8196    return (cur);
8197}
8198
8199/**
8200 * xmlXPathNextPrecedingInternal:
8201 * @ctxt:  the XPath Parser context
8202 * @cur:  the current node in the traversal
8203 *
8204 * Traversal function for the "preceding" direction
8205 * the preceding axis contains all nodes in the same document as the context
8206 * node that are before the context node in document order, excluding any
8207 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8208 * ordered in reverse document order
8209 * This is a faster implementation but internal only since it requires a
8210 * state kept in the parser context: ctxt->ancestor.
8211 *
8212 * Returns the next element following that axis
8213 */
8214static xmlNodePtr
8215xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8216                              xmlNodePtr cur)
8217{
8218    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8219    if (cur == NULL) {
8220        cur = ctxt->context->node;
8221        if (cur == NULL)
8222            return (NULL);
8223        if (cur->type == XML_NAMESPACE_DECL)
8224            return (NULL);
8225        ctxt->ancestor = cur->parent;
8226    }
8227    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8228	cur = cur->prev;
8229    while (cur->prev == NULL) {
8230        cur = cur->parent;
8231        if (cur == NULL)
8232            return (NULL);
8233        if (cur == ctxt->context->doc->children)
8234            return (NULL);
8235        if (cur != ctxt->ancestor)
8236            return (cur);
8237        ctxt->ancestor = cur->parent;
8238    }
8239    cur = cur->prev;
8240    while (cur->last != NULL)
8241        cur = cur->last;
8242    return (cur);
8243}
8244
8245/**
8246 * xmlXPathNextNamespace:
8247 * @ctxt:  the XPath Parser context
8248 * @cur:  the current attribute in the traversal
8249 *
8250 * Traversal function for the "namespace" direction
8251 * the namespace axis contains the namespace nodes of the context node;
8252 * the order of nodes on this axis is implementation-defined; the axis will
8253 * be empty unless the context node is an element
8254 *
8255 * We keep the XML namespace node at the end of the list.
8256 *
8257 * Returns the next element following that axis
8258 */
8259xmlNodePtr
8260xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8261    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8262    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8263    if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8264        if (ctxt->context->tmpNsList != NULL)
8265	    xmlFree(ctxt->context->tmpNsList);
8266	ctxt->context->tmpNsList =
8267	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8268	ctxt->context->tmpNsNr = 0;
8269	if (ctxt->context->tmpNsList != NULL) {
8270	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8271		ctxt->context->tmpNsNr++;
8272	    }
8273	}
8274	return((xmlNodePtr) xmlXPathXMLNamespace);
8275    }
8276    if (ctxt->context->tmpNsNr > 0) {
8277	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8278    } else {
8279	if (ctxt->context->tmpNsList != NULL)
8280	    xmlFree(ctxt->context->tmpNsList);
8281	ctxt->context->tmpNsList = NULL;
8282	return(NULL);
8283    }
8284}
8285
8286/**
8287 * xmlXPathNextAttribute:
8288 * @ctxt:  the XPath Parser context
8289 * @cur:  the current attribute in the traversal
8290 *
8291 * Traversal function for the "attribute" direction
8292 * TODO: support DTD inherited default attributes
8293 *
8294 * Returns the next element following that axis
8295 */
8296xmlNodePtr
8297xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8298    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8299    if (ctxt->context->node == NULL)
8300	return(NULL);
8301    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8302	return(NULL);
8303    if (cur == NULL) {
8304        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8305	    return(NULL);
8306        return((xmlNodePtr)ctxt->context->node->properties);
8307    }
8308    return((xmlNodePtr)cur->next);
8309}
8310
8311/************************************************************************
8312 *									*
8313 *		NodeTest Functions					*
8314 *									*
8315 ************************************************************************/
8316
8317#define IS_FUNCTION			200
8318
8319
8320/************************************************************************
8321 *									*
8322 *		Implicit tree core function library			*
8323 *									*
8324 ************************************************************************/
8325
8326/**
8327 * xmlXPathRoot:
8328 * @ctxt:  the XPath Parser context
8329 *
8330 * Initialize the context to the root of the document
8331 */
8332void
8333xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8334    if ((ctxt == NULL) || (ctxt->context == NULL))
8335	return;
8336    ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8337    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8338	ctxt->context->node));
8339}
8340
8341/************************************************************************
8342 *									*
8343 *		The explicit core function library			*
8344 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8345 *									*
8346 ************************************************************************/
8347
8348
8349/**
8350 * xmlXPathLastFunction:
8351 * @ctxt:  the XPath Parser context
8352 * @nargs:  the number of arguments
8353 *
8354 * Implement the last() XPath function
8355 *    number last()
8356 * The last function returns the number of nodes in the context node list.
8357 */
8358void
8359xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8360    CHECK_ARITY(0);
8361    if (ctxt->context->contextSize >= 0) {
8362	valuePush(ctxt,
8363	    xmlXPathCacheNewFloat(ctxt->context,
8364		(double) ctxt->context->contextSize));
8365#ifdef DEBUG_EXPR
8366	xmlGenericError(xmlGenericErrorContext,
8367		"last() : %d\n", ctxt->context->contextSize);
8368#endif
8369    } else {
8370	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8371    }
8372}
8373
8374/**
8375 * xmlXPathPositionFunction:
8376 * @ctxt:  the XPath Parser context
8377 * @nargs:  the number of arguments
8378 *
8379 * Implement the position() XPath function
8380 *    number position()
8381 * The position function returns the position of the context node in the
8382 * context node list. The first position is 1, and so the last position
8383 * will be equal to last().
8384 */
8385void
8386xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8387    CHECK_ARITY(0);
8388    if (ctxt->context->proximityPosition >= 0) {
8389	valuePush(ctxt,
8390	      xmlXPathCacheNewFloat(ctxt->context,
8391		(double) ctxt->context->proximityPosition));
8392#ifdef DEBUG_EXPR
8393	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8394		ctxt->context->proximityPosition);
8395#endif
8396    } else {
8397	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8398    }
8399}
8400
8401/**
8402 * xmlXPathCountFunction:
8403 * @ctxt:  the XPath Parser context
8404 * @nargs:  the number of arguments
8405 *
8406 * Implement the count() XPath function
8407 *    number count(node-set)
8408 */
8409void
8410xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8411    xmlXPathObjectPtr cur;
8412
8413    CHECK_ARITY(1);
8414    if ((ctxt->value == NULL) ||
8415	((ctxt->value->type != XPATH_NODESET) &&
8416	 (ctxt->value->type != XPATH_XSLT_TREE)))
8417	XP_ERROR(XPATH_INVALID_TYPE);
8418    cur = valuePop(ctxt);
8419
8420    if ((cur == NULL) || (cur->nodesetval == NULL))
8421	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8422    else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8423	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8424	    (double) cur->nodesetval->nodeNr));
8425    } else {
8426	if ((cur->nodesetval->nodeNr != 1) ||
8427	    (cur->nodesetval->nodeTab == NULL)) {
8428	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8429	} else {
8430	    xmlNodePtr tmp;
8431	    int i = 0;
8432
8433	    tmp = cur->nodesetval->nodeTab[0];
8434	    if (tmp != NULL) {
8435		tmp = tmp->children;
8436		while (tmp != NULL) {
8437		    tmp = tmp->next;
8438		    i++;
8439		}
8440	    }
8441	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8442	}
8443    }
8444    xmlXPathReleaseObject(ctxt->context, cur);
8445}
8446
8447/**
8448 * xmlXPathGetElementsByIds:
8449 * @doc:  the document
8450 * @ids:  a whitespace separated list of IDs
8451 *
8452 * Selects elements by their unique ID.
8453 *
8454 * Returns a node-set of selected elements.
8455 */
8456static xmlNodeSetPtr
8457xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8458    xmlNodeSetPtr ret;
8459    const xmlChar *cur = ids;
8460    xmlChar *ID;
8461    xmlAttrPtr attr;
8462    xmlNodePtr elem = NULL;
8463
8464    if (ids == NULL) return(NULL);
8465
8466    ret = xmlXPathNodeSetCreate(NULL);
8467    if (ret == NULL)
8468        return(ret);
8469
8470    while (IS_BLANK_CH(*cur)) cur++;
8471    while (*cur != 0) {
8472	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8473	    cur++;
8474
8475        ID = xmlStrndup(ids, cur - ids);
8476	if (ID != NULL) {
8477	    /*
8478	     * We used to check the fact that the value passed
8479	     * was an NCName, but this generated much troubles for
8480	     * me and Aleksey Sanin, people blatantly violated that
8481	     * constaint, like Visa3D spec.
8482	     * if (xmlValidateNCName(ID, 1) == 0)
8483	     */
8484	    attr = xmlGetID(doc, ID);
8485	    if (attr != NULL) {
8486		if (attr->type == XML_ATTRIBUTE_NODE)
8487		    elem = attr->parent;
8488		else if (attr->type == XML_ELEMENT_NODE)
8489		    elem = (xmlNodePtr) attr;
8490		else
8491		    elem = NULL;
8492		if (elem != NULL)
8493		    xmlXPathNodeSetAdd(ret, elem);
8494	    }
8495	    xmlFree(ID);
8496	}
8497
8498	while (IS_BLANK_CH(*cur)) cur++;
8499	ids = cur;
8500    }
8501    return(ret);
8502}
8503
8504/**
8505 * xmlXPathIdFunction:
8506 * @ctxt:  the XPath Parser context
8507 * @nargs:  the number of arguments
8508 *
8509 * Implement the id() XPath function
8510 *    node-set id(object)
8511 * The id function selects elements by their unique ID
8512 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8513 * then the result is the union of the result of applying id to the
8514 * string value of each of the nodes in the argument node-set. When the
8515 * argument to id is of any other type, the argument is converted to a
8516 * string as if by a call to the string function; the string is split
8517 * into a whitespace-separated list of tokens (whitespace is any sequence
8518 * of characters matching the production S); the result is a node-set
8519 * containing the elements in the same document as the context node that
8520 * have a unique ID equal to any of the tokens in the list.
8521 */
8522void
8523xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8524    xmlChar *tokens;
8525    xmlNodeSetPtr ret;
8526    xmlXPathObjectPtr obj;
8527
8528    CHECK_ARITY(1);
8529    obj = valuePop(ctxt);
8530    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8531    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8532	xmlNodeSetPtr ns;
8533	int i;
8534
8535	ret = xmlXPathNodeSetCreate(NULL);
8536        /*
8537         * FIXME -- in an out-of-memory condition this will behave badly.
8538         * The solution is not clear -- we already popped an item from
8539         * ctxt, so the object is in a corrupt state.
8540         */
8541
8542	if (obj->nodesetval != NULL) {
8543	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8544		tokens =
8545		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8546		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8547		ret = xmlXPathNodeSetMerge(ret, ns);
8548		xmlXPathFreeNodeSet(ns);
8549		if (tokens != NULL)
8550		    xmlFree(tokens);
8551	    }
8552	}
8553	xmlXPathReleaseObject(ctxt->context, obj);
8554	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8555	return;
8556    }
8557    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8558    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8559    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8560    xmlXPathReleaseObject(ctxt->context, obj);
8561    return;
8562}
8563
8564/**
8565 * xmlXPathLocalNameFunction:
8566 * @ctxt:  the XPath Parser context
8567 * @nargs:  the number of arguments
8568 *
8569 * Implement the local-name() XPath function
8570 *    string local-name(node-set?)
8571 * The local-name function returns a string containing the local part
8572 * of the name of the node in the argument node-set that is first in
8573 * document order. If the node-set is empty or the first node has no
8574 * name, an empty string is returned. If the argument is omitted it
8575 * defaults to the context node.
8576 */
8577void
8578xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8579    xmlXPathObjectPtr cur;
8580
8581    if (ctxt == NULL) return;
8582
8583    if (nargs == 0) {
8584	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8585	    ctxt->context->node));
8586	nargs = 1;
8587    }
8588
8589    CHECK_ARITY(1);
8590    if ((ctxt->value == NULL) ||
8591	((ctxt->value->type != XPATH_NODESET) &&
8592	 (ctxt->value->type != XPATH_XSLT_TREE)))
8593	XP_ERROR(XPATH_INVALID_TYPE);
8594    cur = valuePop(ctxt);
8595
8596    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8597	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8598    } else {
8599	int i = 0; /* Should be first in document order !!!!! */
8600	switch (cur->nodesetval->nodeTab[i]->type) {
8601	case XML_ELEMENT_NODE:
8602	case XML_ATTRIBUTE_NODE:
8603	case XML_PI_NODE:
8604	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8605		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8606	    else
8607		valuePush(ctxt,
8608		      xmlXPathCacheNewString(ctxt->context,
8609			cur->nodesetval->nodeTab[i]->name));
8610	    break;
8611	case XML_NAMESPACE_DECL:
8612	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8613			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8614	    break;
8615	default:
8616	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8617	}
8618    }
8619    xmlXPathReleaseObject(ctxt->context, cur);
8620}
8621
8622/**
8623 * xmlXPathNamespaceURIFunction:
8624 * @ctxt:  the XPath Parser context
8625 * @nargs:  the number of arguments
8626 *
8627 * Implement the namespace-uri() XPath function
8628 *    string namespace-uri(node-set?)
8629 * The namespace-uri function returns a string containing the
8630 * namespace URI of the expanded name of the node in the argument
8631 * node-set that is first in document order. If the node-set is empty,
8632 * the first node has no name, or the expanded name has no namespace
8633 * URI, an empty string is returned. If the argument is omitted it
8634 * defaults to the context node.
8635 */
8636void
8637xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8638    xmlXPathObjectPtr cur;
8639
8640    if (ctxt == NULL) return;
8641
8642    if (nargs == 0) {
8643	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8644	    ctxt->context->node));
8645	nargs = 1;
8646    }
8647    CHECK_ARITY(1);
8648    if ((ctxt->value == NULL) ||
8649	((ctxt->value->type != XPATH_NODESET) &&
8650	 (ctxt->value->type != XPATH_XSLT_TREE)))
8651	XP_ERROR(XPATH_INVALID_TYPE);
8652    cur = valuePop(ctxt);
8653
8654    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8655	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8656    } else {
8657	int i = 0; /* Should be first in document order !!!!! */
8658	switch (cur->nodesetval->nodeTab[i]->type) {
8659	case XML_ELEMENT_NODE:
8660	case XML_ATTRIBUTE_NODE:
8661	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8662		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8663	    else
8664		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8665			  cur->nodesetval->nodeTab[i]->ns->href));
8666	    break;
8667	default:
8668	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8669	}
8670    }
8671    xmlXPathReleaseObject(ctxt->context, cur);
8672}
8673
8674/**
8675 * xmlXPathNameFunction:
8676 * @ctxt:  the XPath Parser context
8677 * @nargs:  the number of arguments
8678 *
8679 * Implement the name() XPath function
8680 *    string name(node-set?)
8681 * The name function returns a string containing a QName representing
8682 * the name of the node in the argument node-set that is first in document
8683 * order. The QName must represent the name with respect to the namespace
8684 * declarations in effect on the node whose name is being represented.
8685 * Typically, this will be the form in which the name occurred in the XML
8686 * source. This need not be the case if there are namespace declarations
8687 * in effect on the node that associate multiple prefixes with the same
8688 * namespace. However, an implementation may include information about
8689 * the original prefix in its representation of nodes; in this case, an
8690 * implementation can ensure that the returned string is always the same
8691 * as the QName used in the XML source. If the argument it omitted it
8692 * defaults to the context node.
8693 * Libxml keep the original prefix so the "real qualified name" used is
8694 * returned.
8695 */
8696static void
8697xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8698{
8699    xmlXPathObjectPtr cur;
8700
8701    if (nargs == 0) {
8702	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8703	    ctxt->context->node));
8704        nargs = 1;
8705    }
8706
8707    CHECK_ARITY(1);
8708    if ((ctxt->value == NULL) ||
8709        ((ctxt->value->type != XPATH_NODESET) &&
8710         (ctxt->value->type != XPATH_XSLT_TREE)))
8711        XP_ERROR(XPATH_INVALID_TYPE);
8712    cur = valuePop(ctxt);
8713
8714    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8715        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8716    } else {
8717        int i = 0;              /* Should be first in document order !!!!! */
8718
8719        switch (cur->nodesetval->nodeTab[i]->type) {
8720            case XML_ELEMENT_NODE:
8721            case XML_ATTRIBUTE_NODE:
8722		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8723		    valuePush(ctxt,
8724			xmlXPathCacheNewCString(ctxt->context, ""));
8725		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8726                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8727		    valuePush(ctxt,
8728		        xmlXPathCacheNewString(ctxt->context,
8729			    cur->nodesetval->nodeTab[i]->name));
8730		} else {
8731		    xmlChar *fullname;
8732
8733		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8734				     cur->nodesetval->nodeTab[i]->ns->prefix,
8735				     NULL, 0);
8736		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8737			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8738		    if (fullname == NULL) {
8739			XP_ERROR(XPATH_MEMORY_ERROR);
8740		    }
8741		    valuePush(ctxt, xmlXPathCacheWrapString(
8742			ctxt->context, fullname));
8743                }
8744                break;
8745            default:
8746		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8747		    cur->nodesetval->nodeTab[i]));
8748                xmlXPathLocalNameFunction(ctxt, 1);
8749        }
8750    }
8751    xmlXPathReleaseObject(ctxt->context, cur);
8752}
8753
8754
8755/**
8756 * xmlXPathStringFunction:
8757 * @ctxt:  the XPath Parser context
8758 * @nargs:  the number of arguments
8759 *
8760 * Implement the string() XPath function
8761 *    string string(object?)
8762 * The string function converts an object to a string as follows:
8763 *    - A node-set is converted to a string by returning the value of
8764 *      the node in the node-set that is first in document order.
8765 *      If the node-set is empty, an empty string is returned.
8766 *    - A number is converted to a string as follows
8767 *      + NaN is converted to the string NaN
8768 *      + positive zero is converted to the string 0
8769 *      + negative zero is converted to the string 0
8770 *      + positive infinity is converted to the string Infinity
8771 *      + negative infinity is converted to the string -Infinity
8772 *      + if the number is an integer, the number is represented in
8773 *        decimal form as a Number with no decimal point and no leading
8774 *        zeros, preceded by a minus sign (-) if the number is negative
8775 *      + otherwise, the number is represented in decimal form as a
8776 *        Number including a decimal point with at least one digit
8777 *        before the decimal point and at least one digit after the
8778 *        decimal point, preceded by a minus sign (-) if the number
8779 *        is negative; there must be no leading zeros before the decimal
8780 *        point apart possibly from the one required digit immediately
8781 *        before the decimal point; beyond the one required digit
8782 *        after the decimal point there must be as many, but only as
8783 *        many, more digits as are needed to uniquely distinguish the
8784 *        number from all other IEEE 754 numeric values.
8785 *    - The boolean false value is converted to the string false.
8786 *      The boolean true value is converted to the string true.
8787 *
8788 * If the argument is omitted, it defaults to a node-set with the
8789 * context node as its only member.
8790 */
8791void
8792xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8793    xmlXPathObjectPtr cur;
8794
8795    if (ctxt == NULL) return;
8796    if (nargs == 0) {
8797    valuePush(ctxt,
8798	xmlXPathCacheWrapString(ctxt->context,
8799	    xmlXPathCastNodeToString(ctxt->context->node)));
8800	return;
8801    }
8802
8803    CHECK_ARITY(1);
8804    cur = valuePop(ctxt);
8805    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8806    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8807}
8808
8809/**
8810 * xmlXPathStringLengthFunction:
8811 * @ctxt:  the XPath Parser context
8812 * @nargs:  the number of arguments
8813 *
8814 * Implement the string-length() XPath function
8815 *    number string-length(string?)
8816 * The string-length returns the number of characters in the string
8817 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8818 * the context node converted to a string, in other words the value
8819 * of the context node.
8820 */
8821void
8822xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8823    xmlXPathObjectPtr cur;
8824
8825    if (nargs == 0) {
8826        if ((ctxt == NULL) || (ctxt->context == NULL))
8827	    return;
8828	if (ctxt->context->node == NULL) {
8829	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8830	} else {
8831	    xmlChar *content;
8832
8833	    content = xmlXPathCastNodeToString(ctxt->context->node);
8834	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8835		xmlUTF8Strlen(content)));
8836	    xmlFree(content);
8837	}
8838	return;
8839    }
8840    CHECK_ARITY(1);
8841    CAST_TO_STRING;
8842    CHECK_TYPE(XPATH_STRING);
8843    cur = valuePop(ctxt);
8844    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8845	xmlUTF8Strlen(cur->stringval)));
8846    xmlXPathReleaseObject(ctxt->context, cur);
8847}
8848
8849/**
8850 * xmlXPathConcatFunction:
8851 * @ctxt:  the XPath Parser context
8852 * @nargs:  the number of arguments
8853 *
8854 * Implement the concat() XPath function
8855 *    string concat(string, string, string*)
8856 * The concat function returns the concatenation of its arguments.
8857 */
8858void
8859xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8860    xmlXPathObjectPtr cur, newobj;
8861    xmlChar *tmp;
8862
8863    if (ctxt == NULL) return;
8864    if (nargs < 2) {
8865	CHECK_ARITY(2);
8866    }
8867
8868    CAST_TO_STRING;
8869    cur = valuePop(ctxt);
8870    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8871	xmlXPathReleaseObject(ctxt->context, cur);
8872	return;
8873    }
8874    nargs--;
8875
8876    while (nargs > 0) {
8877	CAST_TO_STRING;
8878	newobj = valuePop(ctxt);
8879	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8880	    xmlXPathReleaseObject(ctxt->context, newobj);
8881	    xmlXPathReleaseObject(ctxt->context, cur);
8882	    XP_ERROR(XPATH_INVALID_TYPE);
8883	}
8884	tmp = xmlStrcat(newobj->stringval, cur->stringval);
8885	newobj->stringval = cur->stringval;
8886	cur->stringval = tmp;
8887	xmlXPathReleaseObject(ctxt->context, newobj);
8888	nargs--;
8889    }
8890    valuePush(ctxt, cur);
8891}
8892
8893/**
8894 * xmlXPathContainsFunction:
8895 * @ctxt:  the XPath Parser context
8896 * @nargs:  the number of arguments
8897 *
8898 * Implement the contains() XPath function
8899 *    boolean contains(string, string)
8900 * The contains function returns true if the first argument string
8901 * contains the second argument string, and otherwise returns false.
8902 */
8903void
8904xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8905    xmlXPathObjectPtr hay, needle;
8906
8907    CHECK_ARITY(2);
8908    CAST_TO_STRING;
8909    CHECK_TYPE(XPATH_STRING);
8910    needle = valuePop(ctxt);
8911    CAST_TO_STRING;
8912    hay = valuePop(ctxt);
8913
8914    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8915	xmlXPathReleaseObject(ctxt->context, hay);
8916	xmlXPathReleaseObject(ctxt->context, needle);
8917	XP_ERROR(XPATH_INVALID_TYPE);
8918    }
8919    if (xmlStrstr(hay->stringval, needle->stringval))
8920	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8921    else
8922	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8923    xmlXPathReleaseObject(ctxt->context, hay);
8924    xmlXPathReleaseObject(ctxt->context, needle);
8925}
8926
8927/**
8928 * xmlXPathStartsWithFunction:
8929 * @ctxt:  the XPath Parser context
8930 * @nargs:  the number of arguments
8931 *
8932 * Implement the starts-with() XPath function
8933 *    boolean starts-with(string, string)
8934 * The starts-with function returns true if the first argument string
8935 * starts with the second argument string, and otherwise returns false.
8936 */
8937void
8938xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8939    xmlXPathObjectPtr hay, needle;
8940    int n;
8941
8942    CHECK_ARITY(2);
8943    CAST_TO_STRING;
8944    CHECK_TYPE(XPATH_STRING);
8945    needle = valuePop(ctxt);
8946    CAST_TO_STRING;
8947    hay = valuePop(ctxt);
8948
8949    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8950	xmlXPathReleaseObject(ctxt->context, hay);
8951	xmlXPathReleaseObject(ctxt->context, needle);
8952	XP_ERROR(XPATH_INVALID_TYPE);
8953    }
8954    n = xmlStrlen(needle->stringval);
8955    if (xmlStrncmp(hay->stringval, needle->stringval, n))
8956        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8957    else
8958        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8959    xmlXPathReleaseObject(ctxt->context, hay);
8960    xmlXPathReleaseObject(ctxt->context, needle);
8961}
8962
8963/**
8964 * xmlXPathSubstringFunction:
8965 * @ctxt:  the XPath Parser context
8966 * @nargs:  the number of arguments
8967 *
8968 * Implement the substring() XPath function
8969 *    string substring(string, number, number?)
8970 * The substring function returns the substring of the first argument
8971 * starting at the position specified in the second argument with
8972 * length specified in the third argument. For example,
8973 * substring("12345",2,3) returns "234". If the third argument is not
8974 * specified, it returns the substring starting at the position specified
8975 * in the second argument and continuing to the end of the string. For
8976 * example, substring("12345",2) returns "2345".  More precisely, each
8977 * character in the string (see [3.6 Strings]) is considered to have a
8978 * numeric position: the position of the first character is 1, the position
8979 * of the second character is 2 and so on. The returned substring contains
8980 * those characters for which the position of the character is greater than
8981 * or equal to the second argument and, if the third argument is specified,
8982 * less than the sum of the second and third arguments; the comparisons
8983 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8984 *  - substring("12345", 1.5, 2.6) returns "234"
8985 *  - substring("12345", 0, 3) returns "12"
8986 *  - substring("12345", 0 div 0, 3) returns ""
8987 *  - substring("12345", 1, 0 div 0) returns ""
8988 *  - substring("12345", -42, 1 div 0) returns "12345"
8989 *  - substring("12345", -1 div 0, 1 div 0) returns ""
8990 */
8991void
8992xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8993    xmlXPathObjectPtr str, start, len;
8994    double le=0, in;
8995    int i, l, m;
8996    xmlChar *ret;
8997
8998    if (nargs < 2) {
8999	CHECK_ARITY(2);
9000    }
9001    if (nargs > 3) {
9002	CHECK_ARITY(3);
9003    }
9004    /*
9005     * take care of possible last (position) argument
9006    */
9007    if (nargs == 3) {
9008	CAST_TO_NUMBER;
9009	CHECK_TYPE(XPATH_NUMBER);
9010	len = valuePop(ctxt);
9011	le = len->floatval;
9012	xmlXPathReleaseObject(ctxt->context, len);
9013    }
9014
9015    CAST_TO_NUMBER;
9016    CHECK_TYPE(XPATH_NUMBER);
9017    start = valuePop(ctxt);
9018    in = start->floatval;
9019    xmlXPathReleaseObject(ctxt->context, start);
9020    CAST_TO_STRING;
9021    CHECK_TYPE(XPATH_STRING);
9022    str = valuePop(ctxt);
9023    m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9024
9025    /*
9026     * If last pos not present, calculate last position
9027    */
9028    if (nargs != 3) {
9029	le = (double)m;
9030	if (in < 1.0)
9031	    in = 1.0;
9032    }
9033
9034    /* Need to check for the special cases where either
9035     * the index is NaN, the length is NaN, or both
9036     * arguments are infinity (relying on Inf + -Inf = NaN)
9037     */
9038    if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9039        /*
9040         * To meet the requirements of the spec, the arguments
9041	 * must be converted to integer format before
9042	 * initial index calculations are done
9043         *
9044         * First we go to integer form, rounding up
9045	 * and checking for special cases
9046         */
9047        i = (int) in;
9048        if (((double)i)+0.5 <= in) i++;
9049
9050	if (xmlXPathIsInf(le) == 1) {
9051	    l = m;
9052	    if (i < 1)
9053		i = 1;
9054	}
9055	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9056	    l = 0;
9057	else {
9058	    l = (int) le;
9059	    if (((double)l)+0.5 <= le) l++;
9060	}
9061
9062	/* Now we normalize inidices */
9063        i -= 1;
9064        l += i;
9065        if (i < 0)
9066            i = 0;
9067        if (l > m)
9068            l = m;
9069
9070        /* number of chars to copy */
9071        l -= i;
9072
9073        ret = xmlUTF8Strsub(str->stringval, i, l);
9074    }
9075    else {
9076        ret = NULL;
9077    }
9078    if (ret == NULL)
9079	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9080    else {
9081	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9082	xmlFree(ret);
9083    }
9084    xmlXPathReleaseObject(ctxt->context, str);
9085}
9086
9087/**
9088 * xmlXPathSubstringBeforeFunction:
9089 * @ctxt:  the XPath Parser context
9090 * @nargs:  the number of arguments
9091 *
9092 * Implement the substring-before() XPath function
9093 *    string substring-before(string, string)
9094 * The substring-before function returns the substring of the first
9095 * argument string that precedes the first occurrence of the second
9096 * argument string in the first argument string, or the empty string
9097 * if the first argument string does not contain the second argument
9098 * string. For example, substring-before("1999/04/01","/") returns 1999.
9099 */
9100void
9101xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9102  xmlXPathObjectPtr str;
9103  xmlXPathObjectPtr find;
9104  xmlBufferPtr target;
9105  const xmlChar *point;
9106  int offset;
9107
9108  CHECK_ARITY(2);
9109  CAST_TO_STRING;
9110  find = valuePop(ctxt);
9111  CAST_TO_STRING;
9112  str = valuePop(ctxt);
9113
9114  target = xmlBufferCreate();
9115  if (target) {
9116    point = xmlStrstr(str->stringval, find->stringval);
9117    if (point) {
9118      offset = (int)(point - str->stringval);
9119      xmlBufferAdd(target, str->stringval, offset);
9120    }
9121    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9122	xmlBufferContent(target)));
9123    xmlBufferFree(target);
9124  }
9125  xmlXPathReleaseObject(ctxt->context, str);
9126  xmlXPathReleaseObject(ctxt->context, find);
9127}
9128
9129/**
9130 * xmlXPathSubstringAfterFunction:
9131 * @ctxt:  the XPath Parser context
9132 * @nargs:  the number of arguments
9133 *
9134 * Implement the substring-after() XPath function
9135 *    string substring-after(string, string)
9136 * The substring-after function returns the substring of the first
9137 * argument string that follows the first occurrence of the second
9138 * argument string in the first argument string, or the empty stringi
9139 * if the first argument string does not contain the second argument
9140 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9141 * and substring-after("1999/04/01","19") returns 99/04/01.
9142 */
9143void
9144xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9145  xmlXPathObjectPtr str;
9146  xmlXPathObjectPtr find;
9147  xmlBufferPtr target;
9148  const xmlChar *point;
9149  int offset;
9150
9151  CHECK_ARITY(2);
9152  CAST_TO_STRING;
9153  find = valuePop(ctxt);
9154  CAST_TO_STRING;
9155  str = valuePop(ctxt);
9156
9157  target = xmlBufferCreate();
9158  if (target) {
9159    point = xmlStrstr(str->stringval, find->stringval);
9160    if (point) {
9161      offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9162      xmlBufferAdd(target, &str->stringval[offset],
9163		   xmlStrlen(str->stringval) - offset);
9164    }
9165    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9166	xmlBufferContent(target)));
9167    xmlBufferFree(target);
9168  }
9169  xmlXPathReleaseObject(ctxt->context, str);
9170  xmlXPathReleaseObject(ctxt->context, find);
9171}
9172
9173/**
9174 * xmlXPathNormalizeFunction:
9175 * @ctxt:  the XPath Parser context
9176 * @nargs:  the number of arguments
9177 *
9178 * Implement the normalize-space() XPath function
9179 *    string normalize-space(string?)
9180 * The normalize-space function returns the argument string with white
9181 * space normalized by stripping leading and trailing whitespace
9182 * and replacing sequences of whitespace characters by a single
9183 * space. Whitespace characters are the same allowed by the S production
9184 * in XML. If the argument is omitted, it defaults to the context
9185 * node converted to a string, in other words the value of the context node.
9186 */
9187void
9188xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9189  xmlXPathObjectPtr obj = NULL;
9190  xmlChar *source = NULL;
9191  xmlBufferPtr target;
9192  xmlChar blank;
9193
9194  if (ctxt == NULL) return;
9195  if (nargs == 0) {
9196    /* Use current context node */
9197      valuePush(ctxt,
9198	  xmlXPathCacheWrapString(ctxt->context,
9199	    xmlXPathCastNodeToString(ctxt->context->node)));
9200    nargs = 1;
9201  }
9202
9203  CHECK_ARITY(1);
9204  CAST_TO_STRING;
9205  CHECK_TYPE(XPATH_STRING);
9206  obj = valuePop(ctxt);
9207  source = obj->stringval;
9208
9209  target = xmlBufferCreate();
9210  if (target && source) {
9211
9212    /* Skip leading whitespaces */
9213    while (IS_BLANK_CH(*source))
9214      source++;
9215
9216    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9217    blank = 0;
9218    while (*source) {
9219      if (IS_BLANK_CH(*source)) {
9220	blank = 0x20;
9221      } else {
9222	if (blank) {
9223	  xmlBufferAdd(target, &blank, 1);
9224	  blank = 0;
9225	}
9226	xmlBufferAdd(target, source, 1);
9227      }
9228      source++;
9229    }
9230    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9231	xmlBufferContent(target)));
9232    xmlBufferFree(target);
9233  }
9234  xmlXPathReleaseObject(ctxt->context, obj);
9235}
9236
9237/**
9238 * xmlXPathTranslateFunction:
9239 * @ctxt:  the XPath Parser context
9240 * @nargs:  the number of arguments
9241 *
9242 * Implement the translate() XPath function
9243 *    string translate(string, string, string)
9244 * The translate function returns the first argument string with
9245 * occurrences of characters in the second argument string replaced
9246 * by the character at the corresponding position in the third argument
9247 * string. For example, translate("bar","abc","ABC") returns the string
9248 * BAr. If there is a character in the second argument string with no
9249 * character at a corresponding position in the third argument string
9250 * (because the second argument string is longer than the third argument
9251 * string), then occurrences of that character in the first argument
9252 * string are removed. For example, translate("--aaa--","abc-","ABC")
9253 * returns "AAA". If a character occurs more than once in second
9254 * argument string, then the first occurrence determines the replacement
9255 * character. If the third argument string is longer than the second
9256 * argument string, then excess characters are ignored.
9257 */
9258void
9259xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9260    xmlXPathObjectPtr str;
9261    xmlXPathObjectPtr from;
9262    xmlXPathObjectPtr to;
9263    xmlBufferPtr target;
9264    int offset, max;
9265    xmlChar ch;
9266    const xmlChar *point;
9267    xmlChar *cptr;
9268
9269    CHECK_ARITY(3);
9270
9271    CAST_TO_STRING;
9272    to = valuePop(ctxt);
9273    CAST_TO_STRING;
9274    from = valuePop(ctxt);
9275    CAST_TO_STRING;
9276    str = valuePop(ctxt);
9277
9278    target = xmlBufferCreate();
9279    if (target) {
9280	max = xmlUTF8Strlen(to->stringval);
9281	for (cptr = str->stringval; (ch=*cptr); ) {
9282	    offset = xmlUTF8Strloc(from->stringval, cptr);
9283	    if (offset >= 0) {
9284		if (offset < max) {
9285		    point = xmlUTF8Strpos(to->stringval, offset);
9286		    if (point)
9287			xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9288		}
9289	    } else
9290		xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9291
9292	    /* Step to next character in input */
9293	    cptr++;
9294	    if ( ch & 0x80 ) {
9295		/* if not simple ascii, verify proper format */
9296		if ( (ch & 0xc0) != 0xc0 ) {
9297		    xmlGenericError(xmlGenericErrorContext,
9298			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
9299		    break;
9300		}
9301		/* then skip over remaining bytes for this char */
9302		while ( (ch <<= 1) & 0x80 )
9303		    if ( (*cptr++ & 0xc0) != 0x80 ) {
9304			xmlGenericError(xmlGenericErrorContext,
9305			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9306			break;
9307		    }
9308		if (ch & 0x80) /* must have had error encountered */
9309		    break;
9310	    }
9311	}
9312    }
9313    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9314	xmlBufferContent(target)));
9315    xmlBufferFree(target);
9316    xmlXPathReleaseObject(ctxt->context, str);
9317    xmlXPathReleaseObject(ctxt->context, from);
9318    xmlXPathReleaseObject(ctxt->context, to);
9319}
9320
9321/**
9322 * xmlXPathBooleanFunction:
9323 * @ctxt:  the XPath Parser context
9324 * @nargs:  the number of arguments
9325 *
9326 * Implement the boolean() XPath function
9327 *    boolean boolean(object)
9328 * The boolean function converts its argument to a boolean as follows:
9329 *    - a number is true if and only if it is neither positive or
9330 *      negative zero nor NaN
9331 *    - a node-set is true if and only if it is non-empty
9332 *    - a string is true if and only if its length is non-zero
9333 */
9334void
9335xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9336    xmlXPathObjectPtr cur;
9337
9338    CHECK_ARITY(1);
9339    cur = valuePop(ctxt);
9340    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9341    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9342    valuePush(ctxt, cur);
9343}
9344
9345/**
9346 * xmlXPathNotFunction:
9347 * @ctxt:  the XPath Parser context
9348 * @nargs:  the number of arguments
9349 *
9350 * Implement the not() XPath function
9351 *    boolean not(boolean)
9352 * The not function returns true if its argument is false,
9353 * and false otherwise.
9354 */
9355void
9356xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9357    CHECK_ARITY(1);
9358    CAST_TO_BOOLEAN;
9359    CHECK_TYPE(XPATH_BOOLEAN);
9360    ctxt->value->boolval = ! ctxt->value->boolval;
9361}
9362
9363/**
9364 * xmlXPathTrueFunction:
9365 * @ctxt:  the XPath Parser context
9366 * @nargs:  the number of arguments
9367 *
9368 * Implement the true() XPath function
9369 *    boolean true()
9370 */
9371void
9372xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9373    CHECK_ARITY(0);
9374    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9375}
9376
9377/**
9378 * xmlXPathFalseFunction:
9379 * @ctxt:  the XPath Parser context
9380 * @nargs:  the number of arguments
9381 *
9382 * Implement the false() XPath function
9383 *    boolean false()
9384 */
9385void
9386xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9387    CHECK_ARITY(0);
9388    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9389}
9390
9391/**
9392 * xmlXPathLangFunction:
9393 * @ctxt:  the XPath Parser context
9394 * @nargs:  the number of arguments
9395 *
9396 * Implement the lang() XPath function
9397 *    boolean lang(string)
9398 * The lang function returns true or false depending on whether the
9399 * language of the context node as specified by xml:lang attributes
9400 * is the same as or is a sublanguage of the language specified by
9401 * the argument string. The language of the context node is determined
9402 * by the value of the xml:lang attribute on the context node, or, if
9403 * the context node has no xml:lang attribute, by the value of the
9404 * xml:lang attribute on the nearest ancestor of the context node that
9405 * has an xml:lang attribute. If there is no such attribute, then lang
9406 * returns false. If there is such an attribute, then lang returns
9407 * true if the attribute value is equal to the argument ignoring case,
9408 * or if there is some suffix starting with - such that the attribute
9409 * value is equal to the argument ignoring that suffix of the attribute
9410 * value and ignoring case.
9411 */
9412void
9413xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9414    xmlXPathObjectPtr val = NULL;
9415    const xmlChar *theLang = NULL;
9416    const xmlChar *lang;
9417    int ret = 0;
9418    int i;
9419
9420    CHECK_ARITY(1);
9421    CAST_TO_STRING;
9422    CHECK_TYPE(XPATH_STRING);
9423    val = valuePop(ctxt);
9424    lang = val->stringval;
9425    theLang = xmlNodeGetLang(ctxt->context->node);
9426    if ((theLang != NULL) && (lang != NULL)) {
9427        for (i = 0;lang[i] != 0;i++)
9428	    if (toupper(lang[i]) != toupper(theLang[i]))
9429	        goto not_equal;
9430	if ((theLang[i] == 0) || (theLang[i] == '-'))
9431	    ret = 1;
9432    }
9433not_equal:
9434    if (theLang != NULL)
9435	xmlFree((void *)theLang);
9436
9437    xmlXPathReleaseObject(ctxt->context, val);
9438    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9439}
9440
9441/**
9442 * xmlXPathNumberFunction:
9443 * @ctxt:  the XPath Parser context
9444 * @nargs:  the number of arguments
9445 *
9446 * Implement the number() XPath function
9447 *    number number(object?)
9448 */
9449void
9450xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9451    xmlXPathObjectPtr cur;
9452    double res;
9453
9454    if (ctxt == NULL) return;
9455    if (nargs == 0) {
9456	if (ctxt->context->node == NULL) {
9457	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9458	} else {
9459	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9460
9461	    res = xmlXPathStringEvalNumber(content);
9462	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9463	    xmlFree(content);
9464	}
9465	return;
9466    }
9467
9468    CHECK_ARITY(1);
9469    cur = valuePop(ctxt);
9470    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9471}
9472
9473/**
9474 * xmlXPathSumFunction:
9475 * @ctxt:  the XPath Parser context
9476 * @nargs:  the number of arguments
9477 *
9478 * Implement the sum() XPath function
9479 *    number sum(node-set)
9480 * The sum function returns the sum of the values of the nodes in
9481 * the argument node-set.
9482 */
9483void
9484xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9485    xmlXPathObjectPtr cur;
9486    int i;
9487    double res = 0.0;
9488
9489    CHECK_ARITY(1);
9490    if ((ctxt->value == NULL) ||
9491	((ctxt->value->type != XPATH_NODESET) &&
9492	 (ctxt->value->type != XPATH_XSLT_TREE)))
9493	XP_ERROR(XPATH_INVALID_TYPE);
9494    cur = valuePop(ctxt);
9495
9496    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9497	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9498	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9499	}
9500    }
9501    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9502    xmlXPathReleaseObject(ctxt->context, cur);
9503}
9504
9505/*
9506 * To assure working code on multiple platforms, we want to only depend
9507 * upon the characteristic truncation of converting a floating point value
9508 * to an integer.  Unfortunately, because of the different storage sizes
9509 * of our internal floating point value (double) and integer (int), we
9510 * can't directly convert (see bug 301162).  This macro is a messy
9511 * 'workaround'
9512 */
9513#define XTRUNC(f, v)            \
9514    f = fmod((v), INT_MAX);     \
9515    f = (v) - (f) + (double)((int)(f));
9516
9517/**
9518 * xmlXPathFloorFunction:
9519 * @ctxt:  the XPath Parser context
9520 * @nargs:  the number of arguments
9521 *
9522 * Implement the floor() XPath function
9523 *    number floor(number)
9524 * The floor function returns the largest (closest to positive infinity)
9525 * number that is not greater than the argument and that is an integer.
9526 */
9527void
9528xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9529    double f;
9530
9531    CHECK_ARITY(1);
9532    CAST_TO_NUMBER;
9533    CHECK_TYPE(XPATH_NUMBER);
9534
9535    XTRUNC(f, ctxt->value->floatval);
9536    if (f != ctxt->value->floatval) {
9537	if (ctxt->value->floatval > 0)
9538	    ctxt->value->floatval = f;
9539	else
9540	    ctxt->value->floatval = f - 1;
9541    }
9542}
9543
9544/**
9545 * xmlXPathCeilingFunction:
9546 * @ctxt:  the XPath Parser context
9547 * @nargs:  the number of arguments
9548 *
9549 * Implement the ceiling() XPath function
9550 *    number ceiling(number)
9551 * The ceiling function returns the smallest (closest to negative infinity)
9552 * number that is not less than the argument and that is an integer.
9553 */
9554void
9555xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9556    double f;
9557
9558    CHECK_ARITY(1);
9559    CAST_TO_NUMBER;
9560    CHECK_TYPE(XPATH_NUMBER);
9561
9562#if 0
9563    ctxt->value->floatval = ceil(ctxt->value->floatval);
9564#else
9565    XTRUNC(f, ctxt->value->floatval);
9566    if (f != ctxt->value->floatval) {
9567	if (ctxt->value->floatval > 0)
9568	    ctxt->value->floatval = f + 1;
9569	else {
9570	    if (ctxt->value->floatval < 0 && f == 0)
9571	        ctxt->value->floatval = xmlXPathNZERO;
9572	    else
9573	        ctxt->value->floatval = f;
9574	}
9575
9576    }
9577#endif
9578}
9579
9580/**
9581 * xmlXPathRoundFunction:
9582 * @ctxt:  the XPath Parser context
9583 * @nargs:  the number of arguments
9584 *
9585 * Implement the round() XPath function
9586 *    number round(number)
9587 * The round function returns the number that is closest to the
9588 * argument and that is an integer. If there are two such numbers,
9589 * then the one that is even is returned.
9590 */
9591void
9592xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9593    double f;
9594
9595    CHECK_ARITY(1);
9596    CAST_TO_NUMBER;
9597    CHECK_TYPE(XPATH_NUMBER);
9598
9599    if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9600	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9601	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9602	(ctxt->value->floatval == 0.0))
9603	return;
9604
9605    XTRUNC(f, ctxt->value->floatval);
9606    if (ctxt->value->floatval < 0) {
9607	if (ctxt->value->floatval < f - 0.5)
9608	    ctxt->value->floatval = f - 1;
9609	else
9610	    ctxt->value->floatval = f;
9611	if (ctxt->value->floatval == 0)
9612	    ctxt->value->floatval = xmlXPathNZERO;
9613    } else {
9614	if (ctxt->value->floatval < f + 0.5)
9615	    ctxt->value->floatval = f;
9616	else
9617	    ctxt->value->floatval = f + 1;
9618    }
9619}
9620
9621/************************************************************************
9622 *									*
9623 *			The Parser					*
9624 *									*
9625 ************************************************************************/
9626
9627/*
9628 * a few forward declarations since we use a recursive call based
9629 * implementation.
9630 */
9631static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9632static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9633static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9634static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9635static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9636	                                  int qualified);
9637
9638/**
9639 * xmlXPathCurrentChar:
9640 * @ctxt:  the XPath parser context
9641 * @cur:  pointer to the beginning of the char
9642 * @len:  pointer to the length of the char read
9643 *
9644 * The current char value, if using UTF-8 this may actually span multiple
9645 * bytes in the input buffer.
9646 *
9647 * Returns the current char value and its length
9648 */
9649
9650static int
9651xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9652    unsigned char c;
9653    unsigned int val;
9654    const xmlChar *cur;
9655
9656    if (ctxt == NULL)
9657	return(0);
9658    cur = ctxt->cur;
9659
9660    /*
9661     * We are supposed to handle UTF8, check it's valid
9662     * From rfc2044: encoding of the Unicode values on UTF-8:
9663     *
9664     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9665     * 0000 0000-0000 007F   0xxxxxxx
9666     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9667     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9668     *
9669     * Check for the 0x110000 limit too
9670     */
9671    c = *cur;
9672    if (c & 0x80) {
9673	if ((cur[1] & 0xc0) != 0x80)
9674	    goto encoding_error;
9675	if ((c & 0xe0) == 0xe0) {
9676
9677	    if ((cur[2] & 0xc0) != 0x80)
9678		goto encoding_error;
9679	    if ((c & 0xf0) == 0xf0) {
9680		if (((c & 0xf8) != 0xf0) ||
9681		    ((cur[3] & 0xc0) != 0x80))
9682		    goto encoding_error;
9683		/* 4-byte code */
9684		*len = 4;
9685		val = (cur[0] & 0x7) << 18;
9686		val |= (cur[1] & 0x3f) << 12;
9687		val |= (cur[2] & 0x3f) << 6;
9688		val |= cur[3] & 0x3f;
9689	    } else {
9690	      /* 3-byte code */
9691		*len = 3;
9692		val = (cur[0] & 0xf) << 12;
9693		val |= (cur[1] & 0x3f) << 6;
9694		val |= cur[2] & 0x3f;
9695	    }
9696	} else {
9697	  /* 2-byte code */
9698	    *len = 2;
9699	    val = (cur[0] & 0x1f) << 6;
9700	    val |= cur[1] & 0x3f;
9701	}
9702	if (!IS_CHAR(val)) {
9703	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9704	}
9705	return(val);
9706    } else {
9707	/* 1-byte code */
9708	*len = 1;
9709	return((int) *cur);
9710    }
9711encoding_error:
9712    /*
9713     * If we detect an UTF8 error that probably means that the
9714     * input encoding didn't get properly advertised in the
9715     * declaration header. Report the error and switch the encoding
9716     * to ISO-Latin-1 (if you don't like this policy, just declare the
9717     * encoding !)
9718     */
9719    *len = 0;
9720    XP_ERROR0(XPATH_ENCODING_ERROR);
9721}
9722
9723/**
9724 * xmlXPathParseNCName:
9725 * @ctxt:  the XPath Parser context
9726 *
9727 * parse an XML namespace non qualified name.
9728 *
9729 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9730 *
9731 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9732 *                       CombiningChar | Extender
9733 *
9734 * Returns the namespace name or NULL
9735 */
9736
9737xmlChar *
9738xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9739    const xmlChar *in;
9740    xmlChar *ret;
9741    int count = 0;
9742
9743    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9744    /*
9745     * Accelerator for simple ASCII names
9746     */
9747    in = ctxt->cur;
9748    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9749	((*in >= 0x41) && (*in <= 0x5A)) ||
9750	(*in == '_')) {
9751	in++;
9752	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9753	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9754	       ((*in >= 0x30) && (*in <= 0x39)) ||
9755	       (*in == '_') || (*in == '.') ||
9756	       (*in == '-'))
9757	    in++;
9758	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9759            (*in == '[') || (*in == ']') || (*in == ':') ||
9760            (*in == '@') || (*in == '*')) {
9761	    count = in - ctxt->cur;
9762	    if (count == 0)
9763		return(NULL);
9764	    ret = xmlStrndup(ctxt->cur, count);
9765	    ctxt->cur = in;
9766	    return(ret);
9767	}
9768    }
9769    return(xmlXPathParseNameComplex(ctxt, 0));
9770}
9771
9772
9773/**
9774 * xmlXPathParseQName:
9775 * @ctxt:  the XPath Parser context
9776 * @prefix:  a xmlChar **
9777 *
9778 * parse an XML qualified name
9779 *
9780 * [NS 5] QName ::= (Prefix ':')? LocalPart
9781 *
9782 * [NS 6] Prefix ::= NCName
9783 *
9784 * [NS 7] LocalPart ::= NCName
9785 *
9786 * Returns the function returns the local part, and prefix is updated
9787 *   to get the Prefix if any.
9788 */
9789
9790static xmlChar *
9791xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9792    xmlChar *ret = NULL;
9793
9794    *prefix = NULL;
9795    ret = xmlXPathParseNCName(ctxt);
9796    if (ret && CUR == ':') {
9797        *prefix = ret;
9798	NEXT;
9799	ret = xmlXPathParseNCName(ctxt);
9800    }
9801    return(ret);
9802}
9803
9804/**
9805 * xmlXPathParseName:
9806 * @ctxt:  the XPath Parser context
9807 *
9808 * parse an XML name
9809 *
9810 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9811 *                  CombiningChar | Extender
9812 *
9813 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9814 *
9815 * Returns the namespace name or NULL
9816 */
9817
9818xmlChar *
9819xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9820    const xmlChar *in;
9821    xmlChar *ret;
9822    int count = 0;
9823
9824    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9825    /*
9826     * Accelerator for simple ASCII names
9827     */
9828    in = ctxt->cur;
9829    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9830	((*in >= 0x41) && (*in <= 0x5A)) ||
9831	(*in == '_') || (*in == ':')) {
9832	in++;
9833	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9834	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9835	       ((*in >= 0x30) && (*in <= 0x39)) ||
9836	       (*in == '_') || (*in == '-') ||
9837	       (*in == ':') || (*in == '.'))
9838	    in++;
9839	if ((*in > 0) && (*in < 0x80)) {
9840	    count = in - ctxt->cur;
9841	    ret = xmlStrndup(ctxt->cur, count);
9842	    ctxt->cur = in;
9843	    return(ret);
9844	}
9845    }
9846    return(xmlXPathParseNameComplex(ctxt, 1));
9847}
9848
9849static xmlChar *
9850xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9851    xmlChar buf[XML_MAX_NAMELEN + 5];
9852    int len = 0, l;
9853    int c;
9854
9855    /*
9856     * Handler for more complex cases
9857     */
9858    c = CUR_CHAR(l);
9859    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9860        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9861        (c == '*') || /* accelerators */
9862	(!IS_LETTER(c) && (c != '_') &&
9863         ((qualified) && (c != ':')))) {
9864	return(NULL);
9865    }
9866
9867    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9868	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9869            (c == '.') || (c == '-') ||
9870	    (c == '_') || ((qualified) && (c == ':')) ||
9871	    (IS_COMBINING(c)) ||
9872	    (IS_EXTENDER(c)))) {
9873	COPY_BUF(l,buf,len,c);
9874	NEXTL(l);
9875	c = CUR_CHAR(l);
9876	if (len >= XML_MAX_NAMELEN) {
9877	    /*
9878	     * Okay someone managed to make a huge name, so he's ready to pay
9879	     * for the processing speed.
9880	     */
9881	    xmlChar *buffer;
9882	    int max = len * 2;
9883
9884	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9885	    if (buffer == NULL) {
9886		XP_ERRORNULL(XPATH_MEMORY_ERROR);
9887	    }
9888	    memcpy(buffer, buf, len);
9889	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9890		   (c == '.') || (c == '-') ||
9891		   (c == '_') || ((qualified) && (c == ':')) ||
9892		   (IS_COMBINING(c)) ||
9893		   (IS_EXTENDER(c))) {
9894		if (len + 10 > max) {
9895		    max *= 2;
9896		    buffer = (xmlChar *) xmlRealloc(buffer,
9897			                            max * sizeof(xmlChar));
9898		    if (buffer == NULL) {
9899			XP_ERRORNULL(XPATH_MEMORY_ERROR);
9900		    }
9901		}
9902		COPY_BUF(l,buffer,len,c);
9903		NEXTL(l);
9904		c = CUR_CHAR(l);
9905	    }
9906	    buffer[len] = 0;
9907	    return(buffer);
9908	}
9909    }
9910    if (len == 0)
9911	return(NULL);
9912    return(xmlStrndup(buf, len));
9913}
9914
9915#define MAX_FRAC 20
9916
9917/*
9918 * These are used as divisors for the fractional part of a number.
9919 * Since the table includes 1.0 (representing '0' fractional digits),
9920 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9921 */
9922static double my_pow10[MAX_FRAC+1] = {
9923    1.0, 10.0, 100.0, 1000.0, 10000.0,
9924    100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9925    10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9926    100000000000000.0,
9927    1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
9928    1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
9929};
9930
9931/**
9932 * xmlXPathStringEvalNumber:
9933 * @str:  A string to scan
9934 *
9935 *  [30a]  Float  ::= Number ('e' Digits?)?
9936 *
9937 *  [30]   Number ::=   Digits ('.' Digits?)?
9938 *                    | '.' Digits
9939 *  [31]   Digits ::=   [0-9]+
9940 *
9941 * Compile a Number in the string
9942 * In complement of the Number expression, this function also handles
9943 * negative values : '-' Number.
9944 *
9945 * Returns the double value.
9946 */
9947double
9948xmlXPathStringEvalNumber(const xmlChar *str) {
9949    const xmlChar *cur = str;
9950    double ret;
9951    int ok = 0;
9952    int isneg = 0;
9953    int exponent = 0;
9954    int is_exponent_negative = 0;
9955#ifdef __GNUC__
9956    unsigned long tmp = 0;
9957    double temp;
9958#endif
9959    if (cur == NULL) return(0);
9960    while (IS_BLANK_CH(*cur)) cur++;
9961    if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9962        return(xmlXPathNAN);
9963    }
9964    if (*cur == '-') {
9965	isneg = 1;
9966	cur++;
9967    }
9968
9969#ifdef __GNUC__
9970    /*
9971     * tmp/temp is a workaround against a gcc compiler bug
9972     * http://veillard.com/gcc.bug
9973     */
9974    ret = 0;
9975    while ((*cur >= '0') && (*cur <= '9')) {
9976	ret = ret * 10;
9977	tmp = (*cur - '0');
9978	ok = 1;
9979	cur++;
9980	temp = (double) tmp;
9981	ret = ret + temp;
9982    }
9983#else
9984    ret = 0;
9985    while ((*cur >= '0') && (*cur <= '9')) {
9986	ret = ret * 10 + (*cur - '0');
9987	ok = 1;
9988	cur++;
9989    }
9990#endif
9991
9992    if (*cur == '.') {
9993	int v, frac = 0;
9994	double fraction = 0;
9995
9996        cur++;
9997	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9998	    return(xmlXPathNAN);
9999	}
10000	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10001	    v = (*cur - '0');
10002	    fraction = fraction * 10 + v;
10003	    frac = frac + 1;
10004	    cur++;
10005	}
10006	fraction /= my_pow10[frac];
10007	ret = ret + fraction;
10008	while ((*cur >= '0') && (*cur <= '9'))
10009	    cur++;
10010    }
10011    if ((*cur == 'e') || (*cur == 'E')) {
10012      cur++;
10013      if (*cur == '-') {
10014	is_exponent_negative = 1;
10015	cur++;
10016      } else if (*cur == '+') {
10017        cur++;
10018      }
10019      while ((*cur >= '0') && (*cur <= '9')) {
10020	exponent = exponent * 10 + (*cur - '0');
10021	cur++;
10022      }
10023    }
10024    while (IS_BLANK_CH(*cur)) cur++;
10025    if (*cur != 0) return(xmlXPathNAN);
10026    if (isneg) ret = -ret;
10027    if (is_exponent_negative) exponent = -exponent;
10028    ret *= pow(10.0, (double)exponent);
10029    return(ret);
10030}
10031
10032/**
10033 * xmlXPathCompNumber:
10034 * @ctxt:  the XPath Parser context
10035 *
10036 *  [30]   Number ::=   Digits ('.' Digits?)?
10037 *                    | '.' Digits
10038 *  [31]   Digits ::=   [0-9]+
10039 *
10040 * Compile a Number, then push it on the stack
10041 *
10042 */
10043static void
10044xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10045{
10046    double ret = 0.0;
10047    double mult = 1;
10048    int ok = 0;
10049    int exponent = 0;
10050    int is_exponent_negative = 0;
10051#ifdef __GNUC__
10052    unsigned long tmp = 0;
10053    double temp;
10054#endif
10055
10056    CHECK_ERROR;
10057    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10058        XP_ERROR(XPATH_NUMBER_ERROR);
10059    }
10060#ifdef __GNUC__
10061    /*
10062     * tmp/temp is a workaround against a gcc compiler bug
10063     * http://veillard.com/gcc.bug
10064     */
10065    ret = 0;
10066    while ((CUR >= '0') && (CUR <= '9')) {
10067	ret = ret * 10;
10068	tmp = (CUR - '0');
10069        ok = 1;
10070        NEXT;
10071	temp = (double) tmp;
10072	ret = ret + temp;
10073    }
10074#else
10075    ret = 0;
10076    while ((CUR >= '0') && (CUR <= '9')) {
10077	ret = ret * 10 + (CUR - '0');
10078	ok = 1;
10079	NEXT;
10080    }
10081#endif
10082    if (CUR == '.') {
10083        NEXT;
10084        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10085            XP_ERROR(XPATH_NUMBER_ERROR);
10086        }
10087        while ((CUR >= '0') && (CUR <= '9')) {
10088            mult /= 10;
10089            ret = ret + (CUR - '0') * mult;
10090            NEXT;
10091        }
10092    }
10093    if ((CUR == 'e') || (CUR == 'E')) {
10094        NEXT;
10095        if (CUR == '-') {
10096            is_exponent_negative = 1;
10097            NEXT;
10098        } else if (CUR == '+') {
10099	    NEXT;
10100	}
10101        while ((CUR >= '0') && (CUR <= '9')) {
10102            exponent = exponent * 10 + (CUR - '0');
10103            NEXT;
10104        }
10105        if (is_exponent_negative)
10106            exponent = -exponent;
10107        ret *= pow(10.0, (double) exponent);
10108    }
10109    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10110                   xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10111}
10112
10113/**
10114 * xmlXPathParseLiteral:
10115 * @ctxt:  the XPath Parser context
10116 *
10117 * Parse a Literal
10118 *
10119 *  [29]   Literal ::=   '"' [^"]* '"'
10120 *                    | "'" [^']* "'"
10121 *
10122 * Returns the value found or NULL in case of error
10123 */
10124static xmlChar *
10125xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10126    const xmlChar *q;
10127    xmlChar *ret = NULL;
10128
10129    if (CUR == '"') {
10130        NEXT;
10131	q = CUR_PTR;
10132	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10133	    NEXT;
10134	if (!IS_CHAR_CH(CUR)) {
10135	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10136	} else {
10137	    ret = xmlStrndup(q, CUR_PTR - q);
10138	    NEXT;
10139        }
10140    } else if (CUR == '\'') {
10141        NEXT;
10142	q = CUR_PTR;
10143	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10144	    NEXT;
10145	if (!IS_CHAR_CH(CUR)) {
10146	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10147	} else {
10148	    ret = xmlStrndup(q, CUR_PTR - q);
10149	    NEXT;
10150        }
10151    } else {
10152	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10153    }
10154    return(ret);
10155}
10156
10157/**
10158 * xmlXPathCompLiteral:
10159 * @ctxt:  the XPath Parser context
10160 *
10161 * Parse a Literal and push it on the stack.
10162 *
10163 *  [29]   Literal ::=   '"' [^"]* '"'
10164 *                    | "'" [^']* "'"
10165 *
10166 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10167 */
10168static void
10169xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10170    const xmlChar *q;
10171    xmlChar *ret = NULL;
10172
10173    if (CUR == '"') {
10174        NEXT;
10175	q = CUR_PTR;
10176	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10177	    NEXT;
10178	if (!IS_CHAR_CH(CUR)) {
10179	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10180	} else {
10181	    ret = xmlStrndup(q, CUR_PTR - q);
10182	    NEXT;
10183        }
10184    } else if (CUR == '\'') {
10185        NEXT;
10186	q = CUR_PTR;
10187	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10188	    NEXT;
10189	if (!IS_CHAR_CH(CUR)) {
10190	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10191	} else {
10192	    ret = xmlStrndup(q, CUR_PTR - q);
10193	    NEXT;
10194        }
10195    } else {
10196	XP_ERROR(XPATH_START_LITERAL_ERROR);
10197    }
10198    if (ret == NULL) return;
10199    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10200	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
10201    xmlFree(ret);
10202}
10203
10204/**
10205 * xmlXPathCompVariableReference:
10206 * @ctxt:  the XPath Parser context
10207 *
10208 * Parse a VariableReference, evaluate it and push it on the stack.
10209 *
10210 * The variable bindings consist of a mapping from variable names
10211 * to variable values. The value of a variable is an object, which can be
10212 * of any of the types that are possible for the value of an expression,
10213 * and may also be of additional types not specified here.
10214 *
10215 * Early evaluation is possible since:
10216 * The variable bindings [...] used to evaluate a subexpression are
10217 * always the same as those used to evaluate the containing expression.
10218 *
10219 *  [36]   VariableReference ::=   '$' QName
10220 */
10221static void
10222xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10223    xmlChar *name;
10224    xmlChar *prefix;
10225
10226    SKIP_BLANKS;
10227    if (CUR != '$') {
10228	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10229    }
10230    NEXT;
10231    name = xmlXPathParseQName(ctxt, &prefix);
10232    if (name == NULL) {
10233	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10234    }
10235    ctxt->comp->last = -1;
10236    PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10237	           name, prefix);
10238    SKIP_BLANKS;
10239    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10240	XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10241    }
10242}
10243
10244/**
10245 * xmlXPathIsNodeType:
10246 * @name:  a name string
10247 *
10248 * Is the name given a NodeType one.
10249 *
10250 *  [38]   NodeType ::=   'comment'
10251 *                    | 'text'
10252 *                    | 'processing-instruction'
10253 *                    | 'node'
10254 *
10255 * Returns 1 if true 0 otherwise
10256 */
10257int
10258xmlXPathIsNodeType(const xmlChar *name) {
10259    if (name == NULL)
10260	return(0);
10261
10262    if (xmlStrEqual(name, BAD_CAST "node"))
10263	return(1);
10264    if (xmlStrEqual(name, BAD_CAST "text"))
10265	return(1);
10266    if (xmlStrEqual(name, BAD_CAST "comment"))
10267	return(1);
10268    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10269	return(1);
10270    return(0);
10271}
10272
10273/**
10274 * xmlXPathCompFunctionCall:
10275 * @ctxt:  the XPath Parser context
10276 *
10277 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10278 *  [17]   Argument ::=   Expr
10279 *
10280 * Compile a function call, the evaluation of all arguments are
10281 * pushed on the stack
10282 */
10283static void
10284xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10285    xmlChar *name;
10286    xmlChar *prefix;
10287    int nbargs = 0;
10288    int sort = 1;
10289
10290    name = xmlXPathParseQName(ctxt, &prefix);
10291    if (name == NULL) {
10292	xmlFree(prefix);
10293	XP_ERROR(XPATH_EXPR_ERROR);
10294    }
10295    SKIP_BLANKS;
10296#ifdef DEBUG_EXPR
10297    if (prefix == NULL)
10298	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10299			name);
10300    else
10301	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10302			prefix, name);
10303#endif
10304
10305    if (CUR != '(') {
10306	XP_ERROR(XPATH_EXPR_ERROR);
10307    }
10308    NEXT;
10309    SKIP_BLANKS;
10310
10311    /*
10312    * Optimization for count(): we don't need the node-set to be sorted.
10313    */
10314    if ((prefix == NULL) && (name[0] == 'c') &&
10315	xmlStrEqual(name, BAD_CAST "count"))
10316    {
10317	sort = 0;
10318    }
10319    ctxt->comp->last = -1;
10320    if (CUR != ')') {
10321	while (CUR != 0) {
10322	    int op1 = ctxt->comp->last;
10323	    ctxt->comp->last = -1;
10324	    xmlXPathCompileExpr(ctxt, sort);
10325	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10326		xmlFree(name);
10327		xmlFree(prefix);
10328		return;
10329	    }
10330	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10331	    nbargs++;
10332	    if (CUR == ')') break;
10333	    if (CUR != ',') {
10334		XP_ERROR(XPATH_EXPR_ERROR);
10335	    }
10336	    NEXT;
10337	    SKIP_BLANKS;
10338	}
10339    }
10340    PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10341	           name, prefix);
10342    NEXT;
10343    SKIP_BLANKS;
10344}
10345
10346/**
10347 * xmlXPathCompPrimaryExpr:
10348 * @ctxt:  the XPath Parser context
10349 *
10350 *  [15]   PrimaryExpr ::=   VariableReference
10351 *                | '(' Expr ')'
10352 *                | Literal
10353 *                | Number
10354 *                | FunctionCall
10355 *
10356 * Compile a primary expression.
10357 */
10358static void
10359xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10360    SKIP_BLANKS;
10361    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10362    else if (CUR == '(') {
10363	NEXT;
10364	SKIP_BLANKS;
10365	xmlXPathCompileExpr(ctxt, 1);
10366	CHECK_ERROR;
10367	if (CUR != ')') {
10368	    XP_ERROR(XPATH_EXPR_ERROR);
10369	}
10370	NEXT;
10371	SKIP_BLANKS;
10372    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10373	xmlXPathCompNumber(ctxt);
10374    } else if ((CUR == '\'') || (CUR == '"')) {
10375	xmlXPathCompLiteral(ctxt);
10376    } else {
10377	xmlXPathCompFunctionCall(ctxt);
10378    }
10379    SKIP_BLANKS;
10380}
10381
10382/**
10383 * xmlXPathCompFilterExpr:
10384 * @ctxt:  the XPath Parser context
10385 *
10386 *  [20]   FilterExpr ::=   PrimaryExpr
10387 *               | FilterExpr Predicate
10388 *
10389 * Compile a filter expression.
10390 * Square brackets are used to filter expressions in the same way that
10391 * they are used in location paths. It is an error if the expression to
10392 * be filtered does not evaluate to a node-set. The context node list
10393 * used for evaluating the expression in square brackets is the node-set
10394 * to be filtered listed in document order.
10395 */
10396
10397static void
10398xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10399    xmlXPathCompPrimaryExpr(ctxt);
10400    CHECK_ERROR;
10401    SKIP_BLANKS;
10402
10403    while (CUR == '[') {
10404	xmlXPathCompPredicate(ctxt, 1);
10405	SKIP_BLANKS;
10406    }
10407
10408
10409}
10410
10411/**
10412 * xmlXPathScanName:
10413 * @ctxt:  the XPath Parser context
10414 *
10415 * Trickery: parse an XML name but without consuming the input flow
10416 * Needed to avoid insanity in the parser state.
10417 *
10418 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10419 *                  CombiningChar | Extender
10420 *
10421 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10422 *
10423 * [6] Names ::= Name (S Name)*
10424 *
10425 * Returns the Name parsed or NULL
10426 */
10427
10428static xmlChar *
10429xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10430    int len = 0, l;
10431    int c;
10432    const xmlChar *cur;
10433    xmlChar *ret;
10434
10435    cur = ctxt->cur;
10436
10437    c = CUR_CHAR(l);
10438    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10439	(!IS_LETTER(c) && (c != '_') &&
10440         (c != ':'))) {
10441	return(NULL);
10442    }
10443
10444    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10445	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10446            (c == '.') || (c == '-') ||
10447	    (c == '_') || (c == ':') ||
10448	    (IS_COMBINING(c)) ||
10449	    (IS_EXTENDER(c)))) {
10450	len += l;
10451	NEXTL(l);
10452	c = CUR_CHAR(l);
10453    }
10454    ret = xmlStrndup(cur, ctxt->cur - cur);
10455    ctxt->cur = cur;
10456    return(ret);
10457}
10458
10459/**
10460 * xmlXPathCompPathExpr:
10461 * @ctxt:  the XPath Parser context
10462 *
10463 *  [19]   PathExpr ::=   LocationPath
10464 *               | FilterExpr
10465 *               | FilterExpr '/' RelativeLocationPath
10466 *               | FilterExpr '//' RelativeLocationPath
10467 *
10468 * Compile a path expression.
10469 * The / operator and // operators combine an arbitrary expression
10470 * and a relative location path. It is an error if the expression
10471 * does not evaluate to a node-set.
10472 * The / operator does composition in the same way as when / is
10473 * used in a location path. As in location paths, // is short for
10474 * /descendant-or-self::node()/.
10475 */
10476
10477static void
10478xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10479    int lc = 1;           /* Should we branch to LocationPath ?         */
10480    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10481
10482    SKIP_BLANKS;
10483    if ((CUR == '$') || (CUR == '(') ||
10484	(IS_ASCII_DIGIT(CUR)) ||
10485        (CUR == '\'') || (CUR == '"') ||
10486	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10487	lc = 0;
10488    } else if (CUR == '*') {
10489	/* relative or absolute location path */
10490	lc = 1;
10491    } else if (CUR == '/') {
10492	/* relative or absolute location path */
10493	lc = 1;
10494    } else if (CUR == '@') {
10495	/* relative abbreviated attribute location path */
10496	lc = 1;
10497    } else if (CUR == '.') {
10498	/* relative abbreviated attribute location path */
10499	lc = 1;
10500    } else {
10501	/*
10502	 * Problem is finding if we have a name here whether it's:
10503	 *   - a nodetype
10504	 *   - a function call in which case it's followed by '('
10505	 *   - an axis in which case it's followed by ':'
10506	 *   - a element name
10507	 * We do an a priori analysis here rather than having to
10508	 * maintain parsed token content through the recursive function
10509	 * calls. This looks uglier but makes the code easier to
10510	 * read/write/debug.
10511	 */
10512	SKIP_BLANKS;
10513	name = xmlXPathScanName(ctxt);
10514	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10515#ifdef DEBUG_STEP
10516	    xmlGenericError(xmlGenericErrorContext,
10517		    "PathExpr: Axis\n");
10518#endif
10519	    lc = 1;
10520	    xmlFree(name);
10521	} else if (name != NULL) {
10522	    int len =xmlStrlen(name);
10523
10524
10525	    while (NXT(len) != 0) {
10526		if (NXT(len) == '/') {
10527		    /* element name */
10528#ifdef DEBUG_STEP
10529		    xmlGenericError(xmlGenericErrorContext,
10530			    "PathExpr: AbbrRelLocation\n");
10531#endif
10532		    lc = 1;
10533		    break;
10534		} else if (IS_BLANK_CH(NXT(len))) {
10535		    /* ignore blanks */
10536		    ;
10537		} else if (NXT(len) == ':') {
10538#ifdef DEBUG_STEP
10539		    xmlGenericError(xmlGenericErrorContext,
10540			    "PathExpr: AbbrRelLocation\n");
10541#endif
10542		    lc = 1;
10543		    break;
10544		} else if ((NXT(len) == '(')) {
10545		    /* Note Type or Function */
10546		    if (xmlXPathIsNodeType(name)) {
10547#ifdef DEBUG_STEP
10548		        xmlGenericError(xmlGenericErrorContext,
10549				"PathExpr: Type search\n");
10550#endif
10551			lc = 1;
10552		    } else {
10553#ifdef DEBUG_STEP
10554		        xmlGenericError(xmlGenericErrorContext,
10555				"PathExpr: function call\n");
10556#endif
10557			lc = 0;
10558		    }
10559                    break;
10560		} else if ((NXT(len) == '[')) {
10561		    /* element name */
10562#ifdef DEBUG_STEP
10563		    xmlGenericError(xmlGenericErrorContext,
10564			    "PathExpr: AbbrRelLocation\n");
10565#endif
10566		    lc = 1;
10567		    break;
10568		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10569			   (NXT(len) == '=')) {
10570		    lc = 1;
10571		    break;
10572		} else {
10573		    lc = 1;
10574		    break;
10575		}
10576		len++;
10577	    }
10578	    if (NXT(len) == 0) {
10579#ifdef DEBUG_STEP
10580		xmlGenericError(xmlGenericErrorContext,
10581			"PathExpr: AbbrRelLocation\n");
10582#endif
10583		/* element name */
10584		lc = 1;
10585	    }
10586	    xmlFree(name);
10587	} else {
10588	    /* make sure all cases are covered explicitly */
10589	    XP_ERROR(XPATH_EXPR_ERROR);
10590	}
10591    }
10592
10593    if (lc) {
10594	if (CUR == '/') {
10595	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10596	} else {
10597	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10598	}
10599	xmlXPathCompLocationPath(ctxt);
10600    } else {
10601	xmlXPathCompFilterExpr(ctxt);
10602	CHECK_ERROR;
10603	if ((CUR == '/') && (NXT(1) == '/')) {
10604	    SKIP(2);
10605	    SKIP_BLANKS;
10606
10607	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10608		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10609	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10610
10611	    xmlXPathCompRelativeLocationPath(ctxt);
10612	} else if (CUR == '/') {
10613	    xmlXPathCompRelativeLocationPath(ctxt);
10614	}
10615    }
10616    SKIP_BLANKS;
10617}
10618
10619/**
10620 * xmlXPathCompUnionExpr:
10621 * @ctxt:  the XPath Parser context
10622 *
10623 *  [18]   UnionExpr ::=   PathExpr
10624 *               | UnionExpr '|' PathExpr
10625 *
10626 * Compile an union expression.
10627 */
10628
10629static void
10630xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10631    xmlXPathCompPathExpr(ctxt);
10632    CHECK_ERROR;
10633    SKIP_BLANKS;
10634    while (CUR == '|') {
10635	int op1 = ctxt->comp->last;
10636	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10637
10638	NEXT;
10639	SKIP_BLANKS;
10640	xmlXPathCompPathExpr(ctxt);
10641
10642	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10643
10644	SKIP_BLANKS;
10645    }
10646}
10647
10648/**
10649 * xmlXPathCompUnaryExpr:
10650 * @ctxt:  the XPath Parser context
10651 *
10652 *  [27]   UnaryExpr ::=   UnionExpr
10653 *                   | '-' UnaryExpr
10654 *
10655 * Compile an unary expression.
10656 */
10657
10658static void
10659xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10660    int minus = 0;
10661    int found = 0;
10662
10663    SKIP_BLANKS;
10664    while (CUR == '-') {
10665        minus = 1 - minus;
10666	found = 1;
10667	NEXT;
10668	SKIP_BLANKS;
10669    }
10670
10671    xmlXPathCompUnionExpr(ctxt);
10672    CHECK_ERROR;
10673    if (found) {
10674	if (minus)
10675	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10676	else
10677	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10678    }
10679}
10680
10681/**
10682 * xmlXPathCompMultiplicativeExpr:
10683 * @ctxt:  the XPath Parser context
10684 *
10685 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10686 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10687 *                   | MultiplicativeExpr 'div' UnaryExpr
10688 *                   | MultiplicativeExpr 'mod' UnaryExpr
10689 *  [34]   MultiplyOperator ::=   '*'
10690 *
10691 * Compile an Additive expression.
10692 */
10693
10694static void
10695xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10696    xmlXPathCompUnaryExpr(ctxt);
10697    CHECK_ERROR;
10698    SKIP_BLANKS;
10699    while ((CUR == '*') ||
10700           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10701           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10702	int op = -1;
10703	int op1 = ctxt->comp->last;
10704
10705        if (CUR == '*') {
10706	    op = 0;
10707	    NEXT;
10708	} else if (CUR == 'd') {
10709	    op = 1;
10710	    SKIP(3);
10711	} else if (CUR == 'm') {
10712	    op = 2;
10713	    SKIP(3);
10714	}
10715	SKIP_BLANKS;
10716        xmlXPathCompUnaryExpr(ctxt);
10717	CHECK_ERROR;
10718	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10719	SKIP_BLANKS;
10720    }
10721}
10722
10723/**
10724 * xmlXPathCompAdditiveExpr:
10725 * @ctxt:  the XPath Parser context
10726 *
10727 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10728 *                   | AdditiveExpr '+' MultiplicativeExpr
10729 *                   | AdditiveExpr '-' MultiplicativeExpr
10730 *
10731 * Compile an Additive expression.
10732 */
10733
10734static void
10735xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10736
10737    xmlXPathCompMultiplicativeExpr(ctxt);
10738    CHECK_ERROR;
10739    SKIP_BLANKS;
10740    while ((CUR == '+') || (CUR == '-')) {
10741	int plus;
10742	int op1 = ctxt->comp->last;
10743
10744        if (CUR == '+') plus = 1;
10745	else plus = 0;
10746	NEXT;
10747	SKIP_BLANKS;
10748        xmlXPathCompMultiplicativeExpr(ctxt);
10749	CHECK_ERROR;
10750	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10751	SKIP_BLANKS;
10752    }
10753}
10754
10755/**
10756 * xmlXPathCompRelationalExpr:
10757 * @ctxt:  the XPath Parser context
10758 *
10759 *  [24]   RelationalExpr ::=   AdditiveExpr
10760 *                 | RelationalExpr '<' AdditiveExpr
10761 *                 | RelationalExpr '>' AdditiveExpr
10762 *                 | RelationalExpr '<=' AdditiveExpr
10763 *                 | RelationalExpr '>=' AdditiveExpr
10764 *
10765 *  A <= B > C is allowed ? Answer from James, yes with
10766 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10767 *  which is basically what got implemented.
10768 *
10769 * Compile a Relational expression, then push the result
10770 * on the stack
10771 */
10772
10773static void
10774xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10775    xmlXPathCompAdditiveExpr(ctxt);
10776    CHECK_ERROR;
10777    SKIP_BLANKS;
10778    while ((CUR == '<') ||
10779           (CUR == '>') ||
10780           ((CUR == '<') && (NXT(1) == '=')) ||
10781           ((CUR == '>') && (NXT(1) == '='))) {
10782	int inf, strict;
10783	int op1 = ctxt->comp->last;
10784
10785        if (CUR == '<') inf = 1;
10786	else inf = 0;
10787	if (NXT(1) == '=') strict = 0;
10788	else strict = 1;
10789	NEXT;
10790	if (!strict) NEXT;
10791	SKIP_BLANKS;
10792        xmlXPathCompAdditiveExpr(ctxt);
10793	CHECK_ERROR;
10794	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10795	SKIP_BLANKS;
10796    }
10797}
10798
10799/**
10800 * xmlXPathCompEqualityExpr:
10801 * @ctxt:  the XPath Parser context
10802 *
10803 *  [23]   EqualityExpr ::=   RelationalExpr
10804 *                 | EqualityExpr '=' RelationalExpr
10805 *                 | EqualityExpr '!=' RelationalExpr
10806 *
10807 *  A != B != C is allowed ? Answer from James, yes with
10808 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10809 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10810 *  which is basically what got implemented.
10811 *
10812 * Compile an Equality expression.
10813 *
10814 */
10815static void
10816xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10817    xmlXPathCompRelationalExpr(ctxt);
10818    CHECK_ERROR;
10819    SKIP_BLANKS;
10820    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10821	int eq;
10822	int op1 = ctxt->comp->last;
10823
10824        if (CUR == '=') eq = 1;
10825	else eq = 0;
10826	NEXT;
10827	if (!eq) NEXT;
10828	SKIP_BLANKS;
10829        xmlXPathCompRelationalExpr(ctxt);
10830	CHECK_ERROR;
10831	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10832	SKIP_BLANKS;
10833    }
10834}
10835
10836/**
10837 * xmlXPathCompAndExpr:
10838 * @ctxt:  the XPath Parser context
10839 *
10840 *  [22]   AndExpr ::=   EqualityExpr
10841 *                 | AndExpr 'and' EqualityExpr
10842 *
10843 * Compile an AND expression.
10844 *
10845 */
10846static void
10847xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10848    xmlXPathCompEqualityExpr(ctxt);
10849    CHECK_ERROR;
10850    SKIP_BLANKS;
10851    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10852	int op1 = ctxt->comp->last;
10853        SKIP(3);
10854	SKIP_BLANKS;
10855        xmlXPathCompEqualityExpr(ctxt);
10856	CHECK_ERROR;
10857	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10858	SKIP_BLANKS;
10859    }
10860}
10861
10862/**
10863 * xmlXPathCompileExpr:
10864 * @ctxt:  the XPath Parser context
10865 *
10866 *  [14]   Expr ::=   OrExpr
10867 *  [21]   OrExpr ::=   AndExpr
10868 *                 | OrExpr 'or' AndExpr
10869 *
10870 * Parse and compile an expression
10871 */
10872static void
10873xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10874    xmlXPathCompAndExpr(ctxt);
10875    CHECK_ERROR;
10876    SKIP_BLANKS;
10877    while ((CUR == 'o') && (NXT(1) == 'r')) {
10878	int op1 = ctxt->comp->last;
10879        SKIP(2);
10880	SKIP_BLANKS;
10881        xmlXPathCompAndExpr(ctxt);
10882	CHECK_ERROR;
10883	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10884	SKIP_BLANKS;
10885    }
10886    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10887	/* more ops could be optimized too */
10888	/*
10889	* This is the main place to eliminate sorting for
10890	* operations which don't require a sorted node-set.
10891	* E.g. count().
10892	*/
10893	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10894    }
10895}
10896
10897/**
10898 * xmlXPathCompPredicate:
10899 * @ctxt:  the XPath Parser context
10900 * @filter:  act as a filter
10901 *
10902 *  [8]   Predicate ::=   '[' PredicateExpr ']'
10903 *  [9]   PredicateExpr ::=   Expr
10904 *
10905 * Compile a predicate expression
10906 */
10907static void
10908xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10909    int op1 = ctxt->comp->last;
10910
10911    SKIP_BLANKS;
10912    if (CUR != '[') {
10913	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10914    }
10915    NEXT;
10916    SKIP_BLANKS;
10917
10918    ctxt->comp->last = -1;
10919    /*
10920    * This call to xmlXPathCompileExpr() will deactivate sorting
10921    * of the predicate result.
10922    * TODO: Sorting is still activated for filters, since I'm not
10923    *  sure if needed. Normally sorting should not be needed, since
10924    *  a filter can only diminish the number of items in a sequence,
10925    *  but won't change its order; so if the initial sequence is sorted,
10926    *  subsequent sorting is not needed.
10927    */
10928    if (! filter)
10929	xmlXPathCompileExpr(ctxt, 0);
10930    else
10931	xmlXPathCompileExpr(ctxt, 1);
10932    CHECK_ERROR;
10933
10934    if (CUR != ']') {
10935	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10936    }
10937
10938    if (filter)
10939	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10940    else
10941	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10942
10943    NEXT;
10944    SKIP_BLANKS;
10945}
10946
10947/**
10948 * xmlXPathCompNodeTest:
10949 * @ctxt:  the XPath Parser context
10950 * @test:  pointer to a xmlXPathTestVal
10951 * @type:  pointer to a xmlXPathTypeVal
10952 * @prefix:  placeholder for a possible name prefix
10953 *
10954 * [7] NodeTest ::=   NameTest
10955 *		    | NodeType '(' ')'
10956 *		    | 'processing-instruction' '(' Literal ')'
10957 *
10958 * [37] NameTest ::=  '*'
10959 *		    | NCName ':' '*'
10960 *		    | QName
10961 * [38] NodeType ::= 'comment'
10962 *		   | 'text'
10963 *		   | 'processing-instruction'
10964 *		   | 'node'
10965 *
10966 * Returns the name found and updates @test, @type and @prefix appropriately
10967 */
10968static xmlChar *
10969xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10970	             xmlXPathTypeVal *type, const xmlChar **prefix,
10971		     xmlChar *name) {
10972    int blanks;
10973
10974    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10975	STRANGE;
10976	return(NULL);
10977    }
10978    *type = (xmlXPathTypeVal) 0;
10979    *test = (xmlXPathTestVal) 0;
10980    *prefix = NULL;
10981    SKIP_BLANKS;
10982
10983    if ((name == NULL) && (CUR == '*')) {
10984	/*
10985	 * All elements
10986	 */
10987	NEXT;
10988	*test = NODE_TEST_ALL;
10989	return(NULL);
10990    }
10991
10992    if (name == NULL)
10993	name = xmlXPathParseNCName(ctxt);
10994    if (name == NULL) {
10995	XP_ERRORNULL(XPATH_EXPR_ERROR);
10996    }
10997
10998    blanks = IS_BLANK_CH(CUR);
10999    SKIP_BLANKS;
11000    if (CUR == '(') {
11001	NEXT;
11002	/*
11003	 * NodeType or PI search
11004	 */
11005	if (xmlStrEqual(name, BAD_CAST "comment"))
11006	    *type = NODE_TYPE_COMMENT;
11007	else if (xmlStrEqual(name, BAD_CAST "node"))
11008	    *type = NODE_TYPE_NODE;
11009	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11010	    *type = NODE_TYPE_PI;
11011	else if (xmlStrEqual(name, BAD_CAST "text"))
11012	    *type = NODE_TYPE_TEXT;
11013	else {
11014	    if (name != NULL)
11015		xmlFree(name);
11016	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11017	}
11018
11019	*test = NODE_TEST_TYPE;
11020
11021	SKIP_BLANKS;
11022	if (*type == NODE_TYPE_PI) {
11023	    /*
11024	     * Specific case: search a PI by name.
11025	     */
11026	    if (name != NULL)
11027		xmlFree(name);
11028	    name = NULL;
11029	    if (CUR != ')') {
11030		name = xmlXPathParseLiteral(ctxt);
11031		CHECK_ERROR NULL;
11032		*test = NODE_TEST_PI;
11033		SKIP_BLANKS;
11034	    }
11035	}
11036	if (CUR != ')') {
11037	    if (name != NULL)
11038		xmlFree(name);
11039	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11040	}
11041	NEXT;
11042	return(name);
11043    }
11044    *test = NODE_TEST_NAME;
11045    if ((!blanks) && (CUR == ':')) {
11046	NEXT;
11047
11048	/*
11049	 * Since currently the parser context don't have a
11050	 * namespace list associated:
11051	 * The namespace name for this prefix can be computed
11052	 * only at evaluation time. The compilation is done
11053	 * outside of any context.
11054	 */
11055#if 0
11056	*prefix = xmlXPathNsLookup(ctxt->context, name);
11057	if (name != NULL)
11058	    xmlFree(name);
11059	if (*prefix == NULL) {
11060	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11061	}
11062#else
11063	*prefix = name;
11064#endif
11065
11066	if (CUR == '*') {
11067	    /*
11068	     * All elements
11069	     */
11070	    NEXT;
11071	    *test = NODE_TEST_ALL;
11072	    return(NULL);
11073	}
11074
11075	name = xmlXPathParseNCName(ctxt);
11076	if (name == NULL) {
11077	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11078	}
11079    }
11080    return(name);
11081}
11082
11083/**
11084 * xmlXPathIsAxisName:
11085 * @name:  a preparsed name token
11086 *
11087 * [6] AxisName ::=   'ancestor'
11088 *                  | 'ancestor-or-self'
11089 *                  | 'attribute'
11090 *                  | 'child'
11091 *                  | 'descendant'
11092 *                  | 'descendant-or-self'
11093 *                  | 'following'
11094 *                  | 'following-sibling'
11095 *                  | 'namespace'
11096 *                  | 'parent'
11097 *                  | 'preceding'
11098 *                  | 'preceding-sibling'
11099 *                  | 'self'
11100 *
11101 * Returns the axis or 0
11102 */
11103static xmlXPathAxisVal
11104xmlXPathIsAxisName(const xmlChar *name) {
11105    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11106    switch (name[0]) {
11107	case 'a':
11108	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11109		ret = AXIS_ANCESTOR;
11110	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11111		ret = AXIS_ANCESTOR_OR_SELF;
11112	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11113		ret = AXIS_ATTRIBUTE;
11114	    break;
11115	case 'c':
11116	    if (xmlStrEqual(name, BAD_CAST "child"))
11117		ret = AXIS_CHILD;
11118	    break;
11119	case 'd':
11120	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11121		ret = AXIS_DESCENDANT;
11122	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11123		ret = AXIS_DESCENDANT_OR_SELF;
11124	    break;
11125	case 'f':
11126	    if (xmlStrEqual(name, BAD_CAST "following"))
11127		ret = AXIS_FOLLOWING;
11128	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11129		ret = AXIS_FOLLOWING_SIBLING;
11130	    break;
11131	case 'n':
11132	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11133		ret = AXIS_NAMESPACE;
11134	    break;
11135	case 'p':
11136	    if (xmlStrEqual(name, BAD_CAST "parent"))
11137		ret = AXIS_PARENT;
11138	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11139		ret = AXIS_PRECEDING;
11140	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11141		ret = AXIS_PRECEDING_SIBLING;
11142	    break;
11143	case 's':
11144	    if (xmlStrEqual(name, BAD_CAST "self"))
11145		ret = AXIS_SELF;
11146	    break;
11147    }
11148    return(ret);
11149}
11150
11151/**
11152 * xmlXPathCompStep:
11153 * @ctxt:  the XPath Parser context
11154 *
11155 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11156 *                  | AbbreviatedStep
11157 *
11158 * [12] AbbreviatedStep ::=   '.' | '..'
11159 *
11160 * [5] AxisSpecifier ::= AxisName '::'
11161 *                  | AbbreviatedAxisSpecifier
11162 *
11163 * [13] AbbreviatedAxisSpecifier ::= '@'?
11164 *
11165 * Modified for XPtr range support as:
11166 *
11167 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11168 *                     | AbbreviatedStep
11169 *                     | 'range-to' '(' Expr ')' Predicate*
11170 *
11171 * Compile one step in a Location Path
11172 * A location step of . is short for self::node(). This is
11173 * particularly useful in conjunction with //. For example, the
11174 * location path .//para is short for
11175 * self::node()/descendant-or-self::node()/child::para
11176 * and so will select all para descendant elements of the context
11177 * node.
11178 * Similarly, a location step of .. is short for parent::node().
11179 * For example, ../title is short for parent::node()/child::title
11180 * and so will select the title children of the parent of the context
11181 * node.
11182 */
11183static void
11184xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11185#ifdef LIBXML_XPTR_ENABLED
11186    int rangeto = 0;
11187    int op2 = -1;
11188#endif
11189
11190    SKIP_BLANKS;
11191    if ((CUR == '.') && (NXT(1) == '.')) {
11192	SKIP(2);
11193	SKIP_BLANKS;
11194	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11195		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11196    } else if (CUR == '.') {
11197	NEXT;
11198	SKIP_BLANKS;
11199    } else {
11200	xmlChar *name = NULL;
11201	const xmlChar *prefix = NULL;
11202	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11203	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11204	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11205	int op1;
11206
11207	/*
11208	 * The modification needed for XPointer change to the production
11209	 */
11210#ifdef LIBXML_XPTR_ENABLED
11211	if (ctxt->xptr) {
11212	    name = xmlXPathParseNCName(ctxt);
11213	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11214                op2 = ctxt->comp->last;
11215		xmlFree(name);
11216		SKIP_BLANKS;
11217		if (CUR != '(') {
11218		    XP_ERROR(XPATH_EXPR_ERROR);
11219		}
11220		NEXT;
11221		SKIP_BLANKS;
11222
11223		xmlXPathCompileExpr(ctxt, 1);
11224		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11225		CHECK_ERROR;
11226
11227		SKIP_BLANKS;
11228		if (CUR != ')') {
11229		    XP_ERROR(XPATH_EXPR_ERROR);
11230		}
11231		NEXT;
11232		rangeto = 1;
11233		goto eval_predicates;
11234	    }
11235	}
11236#endif
11237	if (CUR == '*') {
11238	    axis = AXIS_CHILD;
11239	} else {
11240	    if (name == NULL)
11241		name = xmlXPathParseNCName(ctxt);
11242	    if (name != NULL) {
11243		axis = xmlXPathIsAxisName(name);
11244		if (axis != 0) {
11245		    SKIP_BLANKS;
11246		    if ((CUR == ':') && (NXT(1) == ':')) {
11247			SKIP(2);
11248			xmlFree(name);
11249			name = NULL;
11250		    } else {
11251			/* an element name can conflict with an axis one :-\ */
11252			axis = AXIS_CHILD;
11253		    }
11254		} else {
11255		    axis = AXIS_CHILD;
11256		}
11257	    } else if (CUR == '@') {
11258		NEXT;
11259		axis = AXIS_ATTRIBUTE;
11260	    } else {
11261		axis = AXIS_CHILD;
11262	    }
11263	}
11264
11265	CHECK_ERROR;
11266
11267	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11268	if (test == 0)
11269	    return;
11270
11271        if ((prefix != NULL) && (ctxt->context != NULL) &&
11272	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11273	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11274		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11275	    }
11276	}
11277#ifdef DEBUG_STEP
11278	xmlGenericError(xmlGenericErrorContext,
11279		"Basis : computing new set\n");
11280#endif
11281
11282#ifdef DEBUG_STEP
11283	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11284	if (ctxt->value == NULL)
11285	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11286	else if (ctxt->value->nodesetval == NULL)
11287	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11288	else
11289	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11290#endif
11291
11292#ifdef LIBXML_XPTR_ENABLED
11293eval_predicates:
11294#endif
11295	op1 = ctxt->comp->last;
11296	ctxt->comp->last = -1;
11297
11298	SKIP_BLANKS;
11299	while (CUR == '[') {
11300	    xmlXPathCompPredicate(ctxt, 0);
11301	}
11302
11303#ifdef LIBXML_XPTR_ENABLED
11304	if (rangeto) {
11305	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11306	} else
11307#endif
11308	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11309			   test, type, (void *)prefix, (void *)name);
11310
11311    }
11312#ifdef DEBUG_STEP
11313    xmlGenericError(xmlGenericErrorContext, "Step : ");
11314    if (ctxt->value == NULL)
11315	xmlGenericError(xmlGenericErrorContext, "no value\n");
11316    else if (ctxt->value->nodesetval == NULL)
11317	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11318    else
11319	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11320		ctxt->value->nodesetval);
11321#endif
11322}
11323
11324/**
11325 * xmlXPathCompRelativeLocationPath:
11326 * @ctxt:  the XPath Parser context
11327 *
11328 *  [3]   RelativeLocationPath ::=   Step
11329 *                     | RelativeLocationPath '/' Step
11330 *                     | AbbreviatedRelativeLocationPath
11331 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11332 *
11333 * Compile a relative location path.
11334 */
11335static void
11336xmlXPathCompRelativeLocationPath
11337(xmlXPathParserContextPtr ctxt) {
11338    SKIP_BLANKS;
11339    if ((CUR == '/') && (NXT(1) == '/')) {
11340	SKIP(2);
11341	SKIP_BLANKS;
11342	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11343		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11344    } else if (CUR == '/') {
11345	    NEXT;
11346	SKIP_BLANKS;
11347    }
11348    xmlXPathCompStep(ctxt);
11349    CHECK_ERROR;
11350    SKIP_BLANKS;
11351    while (CUR == '/') {
11352	if ((CUR == '/') && (NXT(1) == '/')) {
11353	    SKIP(2);
11354	    SKIP_BLANKS;
11355	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11356			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11357	    xmlXPathCompStep(ctxt);
11358	} else if (CUR == '/') {
11359	    NEXT;
11360	    SKIP_BLANKS;
11361	    xmlXPathCompStep(ctxt);
11362	}
11363	SKIP_BLANKS;
11364    }
11365}
11366
11367/**
11368 * xmlXPathCompLocationPath:
11369 * @ctxt:  the XPath Parser context
11370 *
11371 *  [1]   LocationPath ::=   RelativeLocationPath
11372 *                     | AbsoluteLocationPath
11373 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11374 *                     | AbbreviatedAbsoluteLocationPath
11375 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11376 *                           '//' RelativeLocationPath
11377 *
11378 * Compile a location path
11379 *
11380 * // is short for /descendant-or-self::node()/. For example,
11381 * //para is short for /descendant-or-self::node()/child::para and
11382 * so will select any para element in the document (even a para element
11383 * that is a document element will be selected by //para since the
11384 * document element node is a child of the root node); div//para is
11385 * short for div/descendant-or-self::node()/child::para and so will
11386 * select all para descendants of div children.
11387 */
11388static void
11389xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11390    SKIP_BLANKS;
11391    if (CUR != '/') {
11392        xmlXPathCompRelativeLocationPath(ctxt);
11393    } else {
11394	while (CUR == '/') {
11395	    if ((CUR == '/') && (NXT(1) == '/')) {
11396		SKIP(2);
11397		SKIP_BLANKS;
11398		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11399			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11400		xmlXPathCompRelativeLocationPath(ctxt);
11401	    } else if (CUR == '/') {
11402		NEXT;
11403		SKIP_BLANKS;
11404		if ((CUR != 0 ) &&
11405		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11406		     (CUR == '@') || (CUR == '*')))
11407		    xmlXPathCompRelativeLocationPath(ctxt);
11408	    }
11409	    CHECK_ERROR;
11410	}
11411    }
11412}
11413
11414/************************************************************************
11415 *									*
11416 *		XPath precompiled expression evaluation			*
11417 *									*
11418 ************************************************************************/
11419
11420static int
11421xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11422
11423#ifdef DEBUG_STEP
11424static void
11425xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11426			  int nbNodes)
11427{
11428    xmlGenericError(xmlGenericErrorContext, "new step : ");
11429    switch (op->value) {
11430        case AXIS_ANCESTOR:
11431            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11432            break;
11433        case AXIS_ANCESTOR_OR_SELF:
11434            xmlGenericError(xmlGenericErrorContext,
11435                            "axis 'ancestors-or-self' ");
11436            break;
11437        case AXIS_ATTRIBUTE:
11438            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11439            break;
11440        case AXIS_CHILD:
11441            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11442            break;
11443        case AXIS_DESCENDANT:
11444            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11445            break;
11446        case AXIS_DESCENDANT_OR_SELF:
11447            xmlGenericError(xmlGenericErrorContext,
11448                            "axis 'descendant-or-self' ");
11449            break;
11450        case AXIS_FOLLOWING:
11451            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11452            break;
11453        case AXIS_FOLLOWING_SIBLING:
11454            xmlGenericError(xmlGenericErrorContext,
11455                            "axis 'following-siblings' ");
11456            break;
11457        case AXIS_NAMESPACE:
11458            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11459            break;
11460        case AXIS_PARENT:
11461            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11462            break;
11463        case AXIS_PRECEDING:
11464            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11465            break;
11466        case AXIS_PRECEDING_SIBLING:
11467            xmlGenericError(xmlGenericErrorContext,
11468                            "axis 'preceding-sibling' ");
11469            break;
11470        case AXIS_SELF:
11471            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11472            break;
11473    }
11474    xmlGenericError(xmlGenericErrorContext,
11475	" context contains %d nodes\n", nbNodes);
11476    switch (op->value2) {
11477        case NODE_TEST_NONE:
11478            xmlGenericError(xmlGenericErrorContext,
11479                            "           searching for none !!!\n");
11480            break;
11481        case NODE_TEST_TYPE:
11482            xmlGenericError(xmlGenericErrorContext,
11483                            "           searching for type %d\n", op->value3);
11484            break;
11485        case NODE_TEST_PI:
11486            xmlGenericError(xmlGenericErrorContext,
11487                            "           searching for PI !!!\n");
11488            break;
11489        case NODE_TEST_ALL:
11490            xmlGenericError(xmlGenericErrorContext,
11491                            "           searching for *\n");
11492            break;
11493        case NODE_TEST_NS:
11494            xmlGenericError(xmlGenericErrorContext,
11495                            "           searching for namespace %s\n",
11496                            op->value5);
11497            break;
11498        case NODE_TEST_NAME:
11499            xmlGenericError(xmlGenericErrorContext,
11500                            "           searching for name %s\n", op->value5);
11501            if (op->value4)
11502                xmlGenericError(xmlGenericErrorContext,
11503                                "           with namespace %s\n", op->value4);
11504            break;
11505    }
11506    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11507}
11508#endif /* DEBUG_STEP */
11509
11510static int
11511xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11512			    xmlXPathStepOpPtr op,
11513			    xmlNodeSetPtr set,
11514			    int contextSize,
11515			    int hasNsNodes)
11516{
11517    if (op->ch1 != -1) {
11518	xmlXPathCompExprPtr comp = ctxt->comp;
11519	/*
11520	* Process inner predicates first.
11521	*/
11522	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11523	    /*
11524	    * TODO: raise an internal error.
11525	    */
11526	}
11527	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11528	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11529	CHECK_ERROR0;
11530	if (contextSize <= 0)
11531	    return(0);
11532    }
11533    if (op->ch2 != -1) {
11534	xmlXPathContextPtr xpctxt = ctxt->context;
11535	xmlNodePtr contextNode, oldContextNode;
11536	xmlDocPtr oldContextDoc;
11537	int i, res, contextPos = 0, newContextSize;
11538	xmlXPathStepOpPtr exprOp;
11539	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11540
11541#ifdef LIBXML_XPTR_ENABLED
11542	/*
11543	* URGENT TODO: Check the following:
11544	*  We don't expect location sets if evaluating prediates, right?
11545	*  Only filters should expect location sets, right?
11546	*/
11547#endif
11548	/*
11549	* SPEC XPath 1.0:
11550	*  "For each node in the node-set to be filtered, the
11551	*  PredicateExpr is evaluated with that node as the
11552	*  context node, with the number of nodes in the
11553	*  node-set as the context size, and with the proximity
11554	*  position of the node in the node-set with respect to
11555	*  the axis as the context position;"
11556	* @oldset is the node-set" to be filtered.
11557	*
11558	* SPEC XPath 1.0:
11559	*  "only predicates change the context position and
11560	*  context size (see [2.4 Predicates])."
11561	* Example:
11562	*   node-set  context pos
11563	*    nA         1
11564	*    nB         2
11565	*    nC         3
11566	*   After applying predicate [position() > 1] :
11567	*   node-set  context pos
11568	*    nB         1
11569	*    nC         2
11570	*/
11571	oldContextNode = xpctxt->node;
11572	oldContextDoc = xpctxt->doc;
11573	/*
11574	* Get the expression of this predicate.
11575	*/
11576	exprOp = &ctxt->comp->steps[op->ch2];
11577	newContextSize = 0;
11578	for (i = 0; i < set->nodeNr; i++) {
11579	    if (set->nodeTab[i] == NULL)
11580		continue;
11581
11582	    contextNode = set->nodeTab[i];
11583	    xpctxt->node = contextNode;
11584	    xpctxt->contextSize = contextSize;
11585	    xpctxt->proximityPosition = ++contextPos;
11586
11587	    /*
11588	    * Also set the xpath document in case things like
11589	    * key() are evaluated in the predicate.
11590	    */
11591	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11592		(contextNode->doc != NULL))
11593		xpctxt->doc = contextNode->doc;
11594	    /*
11595	    * Evaluate the predicate expression with 1 context node
11596	    * at a time; this node is packaged into a node set; this
11597	    * node set is handed over to the evaluation mechanism.
11598	    */
11599	    if (contextObj == NULL)
11600		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11601	    else
11602		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11603		    contextNode);
11604
11605	    valuePush(ctxt, contextObj);
11606
11607	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11608
11609	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11610		xmlXPathNodeSetClear(set, hasNsNodes);
11611		newContextSize = 0;
11612		goto evaluation_exit;
11613	    }
11614
11615	    if (res != 0) {
11616		newContextSize++;
11617	    } else {
11618		/*
11619		* Remove the entry from the initial node set.
11620		*/
11621		set->nodeTab[i] = NULL;
11622		if (contextNode->type == XML_NAMESPACE_DECL)
11623		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11624	    }
11625	    if (ctxt->value == contextObj) {
11626		/*
11627		* Don't free the temporary XPath object holding the
11628		* context node, in order to avoid massive recreation
11629		* inside this loop.
11630		*/
11631		valuePop(ctxt);
11632		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11633	    } else {
11634		/*
11635		* TODO: The object was lost in the evaluation machinery.
11636		*  Can this happen? Maybe in internal-error cases.
11637		*/
11638		contextObj = NULL;
11639	    }
11640	}
11641
11642	if (contextObj != NULL) {
11643	    if (ctxt->value == contextObj)
11644		valuePop(ctxt);
11645	    xmlXPathReleaseObject(xpctxt, contextObj);
11646	}
11647evaluation_exit:
11648	if (exprRes != NULL)
11649	    xmlXPathReleaseObject(ctxt->context, exprRes);
11650	/*
11651	* Reset/invalidate the context.
11652	*/
11653	xpctxt->node = oldContextNode;
11654	xpctxt->doc = oldContextDoc;
11655	xpctxt->contextSize = -1;
11656	xpctxt->proximityPosition = -1;
11657	return(newContextSize);
11658    }
11659    return(contextSize);
11660}
11661
11662static int
11663xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11664				      xmlXPathStepOpPtr op,
11665				      xmlNodeSetPtr set,
11666				      int contextSize,
11667				      int minPos,
11668				      int maxPos,
11669				      int hasNsNodes)
11670{
11671    if (op->ch1 != -1) {
11672	xmlXPathCompExprPtr comp = ctxt->comp;
11673	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11674	    /*
11675	    * TODO: raise an internal error.
11676	    */
11677	}
11678	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11679	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11680	CHECK_ERROR0;
11681	if (contextSize <= 0)
11682	    return(0);
11683    }
11684    /*
11685    * Check if the node set contains a sufficient number of nodes for
11686    * the requested range.
11687    */
11688    if (contextSize < minPos) {
11689	xmlXPathNodeSetClear(set, hasNsNodes);
11690	return(0);
11691    }
11692    if (op->ch2 == -1) {
11693	/*
11694	* TODO: Can this ever happen?
11695	*/
11696	return (contextSize);
11697    } else {
11698	xmlDocPtr oldContextDoc;
11699	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11700	xmlXPathStepOpPtr exprOp;
11701	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11702	xmlNodePtr oldContextNode, contextNode = NULL;
11703	xmlXPathContextPtr xpctxt = ctxt->context;
11704
11705#ifdef LIBXML_XPTR_ENABLED
11706	    /*
11707	    * URGENT TODO: Check the following:
11708	    *  We don't expect location sets if evaluating prediates, right?
11709	    *  Only filters should expect location sets, right?
11710	*/
11711#endif /* LIBXML_XPTR_ENABLED */
11712
11713	/*
11714	* Save old context.
11715	*/
11716	oldContextNode = xpctxt->node;
11717	oldContextDoc = xpctxt->doc;
11718	/*
11719	* Get the expression of this predicate.
11720	*/
11721	exprOp = &ctxt->comp->steps[op->ch2];
11722	for (i = 0; i < set->nodeNr; i++) {
11723	    if (set->nodeTab[i] == NULL)
11724		continue;
11725
11726	    contextNode = set->nodeTab[i];
11727	    xpctxt->node = contextNode;
11728	    xpctxt->contextSize = contextSize;
11729	    xpctxt->proximityPosition = ++contextPos;
11730
11731	    /*
11732	    * Initialize the new set.
11733	    * Also set the xpath document in case things like
11734	    * key() evaluation are attempted on the predicate
11735	    */
11736	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11737		(contextNode->doc != NULL))
11738		xpctxt->doc = contextNode->doc;
11739	    /*
11740	    * Evaluate the predicate expression with 1 context node
11741	    * at a time; this node is packaged into a node set; this
11742	    * node set is handed over to the evaluation mechanism.
11743	    */
11744	    if (contextObj == NULL)
11745		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11746	    else
11747		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11748		    contextNode);
11749
11750	    valuePush(ctxt, contextObj);
11751	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11752
11753	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11754	        xmlXPathObjectPtr tmp;
11755		/* pop the result if any */
11756		tmp = valuePop(ctxt);
11757                while (tmp != contextObj) {
11758                    /*
11759                     * Free up the result
11760                     * then pop off contextObj, which will be freed later
11761                     */
11762                    xmlXPathReleaseObject(xpctxt, tmp);
11763                    tmp = valuePop(ctxt);
11764                }
11765		goto evaluation_error;
11766	    }
11767
11768	    if (res)
11769		pos++;
11770
11771	    if (res && (pos >= minPos) && (pos <= maxPos)) {
11772		/*
11773		* Fits in the requested range.
11774		*/
11775		newContextSize++;
11776		if (minPos == maxPos) {
11777		    /*
11778		    * Only 1 node was requested.
11779		    */
11780		    if (contextNode->type == XML_NAMESPACE_DECL) {
11781			/*
11782			* As always: take care of those nasty
11783			* namespace nodes.
11784			*/
11785			set->nodeTab[i] = NULL;
11786		    }
11787		    xmlXPathNodeSetClear(set, hasNsNodes);
11788		    set->nodeNr = 1;
11789		    set->nodeTab[0] = contextNode;
11790		    goto evaluation_exit;
11791		}
11792		if (pos == maxPos) {
11793		    /*
11794		    * We are done.
11795		    */
11796		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11797		    goto evaluation_exit;
11798		}
11799	    } else {
11800		/*
11801		* Remove the entry from the initial node set.
11802		*/
11803		set->nodeTab[i] = NULL;
11804		if (contextNode->type == XML_NAMESPACE_DECL)
11805		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11806	    }
11807	    if (exprRes != NULL) {
11808		xmlXPathReleaseObject(ctxt->context, exprRes);
11809		exprRes = NULL;
11810	    }
11811	    if (ctxt->value == contextObj) {
11812		/*
11813		* Don't free the temporary XPath object holding the
11814		* context node, in order to avoid massive recreation
11815		* inside this loop.
11816		*/
11817		valuePop(ctxt);
11818		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11819	    } else {
11820		/*
11821		* The object was lost in the evaluation machinery.
11822		* Can this happen? Maybe in case of internal-errors.
11823		*/
11824		contextObj = NULL;
11825	    }
11826	}
11827	goto evaluation_exit;
11828
11829evaluation_error:
11830	xmlXPathNodeSetClear(set, hasNsNodes);
11831	newContextSize = 0;
11832
11833evaluation_exit:
11834	if (contextObj != NULL) {
11835	    if (ctxt->value == contextObj)
11836		valuePop(ctxt);
11837	    xmlXPathReleaseObject(xpctxt, contextObj);
11838	}
11839	if (exprRes != NULL)
11840	    xmlXPathReleaseObject(ctxt->context, exprRes);
11841	/*
11842	* Reset/invalidate the context.
11843	*/
11844	xpctxt->node = oldContextNode;
11845	xpctxt->doc = oldContextDoc;
11846	xpctxt->contextSize = -1;
11847	xpctxt->proximityPosition = -1;
11848	return(newContextSize);
11849    }
11850    return(contextSize);
11851}
11852
11853static int
11854xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11855			    xmlXPathStepOpPtr op,
11856			    int *maxPos)
11857{
11858
11859    xmlXPathStepOpPtr exprOp;
11860
11861    /*
11862    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11863    */
11864
11865    /*
11866    * If not -1, then ch1 will point to:
11867    * 1) For predicates (XPATH_OP_PREDICATE):
11868    *    - an inner predicate operator
11869    * 2) For filters (XPATH_OP_FILTER):
11870    *    - an inner filter operater OR
11871    *    - an expression selecting the node set.
11872    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11873    */
11874    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11875	return(0);
11876
11877    if (op->ch2 != -1) {
11878	exprOp = &ctxt->comp->steps[op->ch2];
11879    } else
11880	return(0);
11881
11882    if ((exprOp != NULL) &&
11883	(exprOp->op == XPATH_OP_VALUE) &&
11884	(exprOp->value4 != NULL) &&
11885	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11886    {
11887	/*
11888	* We have a "[n]" predicate here.
11889	* TODO: Unfortunately this simplistic test here is not
11890	* able to detect a position() predicate in compound
11891	* expressions like "[@attr = 'a" and position() = 1],
11892	* and even not the usage of position() in
11893	* "[position() = 1]"; thus - obviously - a position-range,
11894	* like it "[position() < 5]", is also not detected.
11895	* Maybe we could rewrite the AST to ease the optimization.
11896	*/
11897	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11898
11899	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11900	    (float) *maxPos)
11901	{
11902	    return(1);
11903	}
11904    }
11905    return(0);
11906}
11907
11908static int
11909xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11910                           xmlXPathStepOpPtr op,
11911			   xmlNodePtr * first, xmlNodePtr * last,
11912			   int toBool)
11913{
11914
11915#define XP_TEST_HIT \
11916    if (hasAxisRange != 0) { \
11917	if (++pos == maxPos) { \
11918	    addNode(seq, cur); \
11919	goto axis_range_end; } \
11920    } else { \
11921	addNode(seq, cur); \
11922	if (breakOnFirstHit) goto first_hit; }
11923
11924#define XP_TEST_HIT_NS \
11925    if (hasAxisRange != 0) { \
11926	if (++pos == maxPos) { \
11927	    hasNsNodes = 1; \
11928	    xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11929	goto axis_range_end; } \
11930    } else { \
11931	hasNsNodes = 1; \
11932	xmlXPathNodeSetAddNs(seq, \
11933	xpctxt->node, (xmlNsPtr) cur); \
11934	if (breakOnFirstHit) goto first_hit; }
11935
11936    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11937    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11938    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11939    const xmlChar *prefix = op->value4;
11940    const xmlChar *name = op->value5;
11941    const xmlChar *URI = NULL;
11942
11943#ifdef DEBUG_STEP
11944    int nbMatches = 0, prevMatches = 0;
11945#endif
11946    int total = 0, hasNsNodes = 0;
11947    /* The popped object holding the context nodes */
11948    xmlXPathObjectPtr obj;
11949    /* The set of context nodes for the node tests */
11950    xmlNodeSetPtr contextSeq;
11951    int contextIdx;
11952    xmlNodePtr contextNode;
11953    /* The context node for a compound traversal */
11954    xmlNodePtr outerContextNode;
11955    /* The final resulting node set wrt to all context nodes */
11956    xmlNodeSetPtr outSeq;
11957    /*
11958    * The temporary resulting node set wrt 1 context node.
11959    * Used to feed predicate evaluation.
11960    */
11961    xmlNodeSetPtr seq;
11962    xmlNodePtr cur;
11963    /* First predicate operator */
11964    xmlXPathStepOpPtr predOp;
11965    int maxPos; /* The requested position() (when a "[n]" predicate) */
11966    int hasPredicateRange, hasAxisRange, pos, size, newSize;
11967    int breakOnFirstHit;
11968
11969    xmlXPathTraversalFunction next = NULL;
11970    /* compound axis traversal */
11971    xmlXPathTraversalFunctionExt outerNext = NULL;
11972    void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11973    xmlXPathNodeSetMergeFunction mergeAndClear;
11974    xmlNodePtr oldContextNode;
11975    xmlXPathContextPtr xpctxt = ctxt->context;
11976
11977
11978    CHECK_TYPE0(XPATH_NODESET);
11979    obj = valuePop(ctxt);
11980    /*
11981    * Setup namespaces.
11982    */
11983    if (prefix != NULL) {
11984        URI = xmlXPathNsLookup(xpctxt, prefix);
11985        if (URI == NULL) {
11986	    xmlXPathReleaseObject(xpctxt, obj);
11987            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11988	}
11989    }
11990    /*
11991    * Setup axis.
11992    *
11993    * MAYBE FUTURE TODO: merging optimizations:
11994    * - If the nodes to be traversed wrt to the initial nodes and
11995    *   the current axis cannot overlap, then we could avoid searching
11996    *   for duplicates during the merge.
11997    *   But the question is how/when to evaluate if they cannot overlap.
11998    *   Example: if we know that for two initial nodes, the one is
11999    *   not in the ancestor-or-self axis of the other, then we could safely
12000    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12001    *   the descendant-or-self axis.
12002    */
12003    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12004    switch (axis) {
12005        case AXIS_ANCESTOR:
12006            first = NULL;
12007            next = xmlXPathNextAncestor;
12008            break;
12009        case AXIS_ANCESTOR_OR_SELF:
12010            first = NULL;
12011            next = xmlXPathNextAncestorOrSelf;
12012            break;
12013        case AXIS_ATTRIBUTE:
12014            first = NULL;
12015	    last = NULL;
12016            next = xmlXPathNextAttribute;
12017	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12018            break;
12019        case AXIS_CHILD:
12020	    last = NULL;
12021	    if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12022		/*
12023		* This iterator will give us only nodes which can
12024		* hold element nodes.
12025		*/
12026		outerNext = xmlXPathNextDescendantOrSelfElemParent;
12027	    }
12028	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12029		(type == NODE_TYPE_NODE))
12030	    {
12031		/*
12032		* Optimization if an element node type is 'element'.
12033		*/
12034		next = xmlXPathNextChildElement;
12035	    } else
12036		next = xmlXPathNextChild;
12037	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12038            break;
12039        case AXIS_DESCENDANT:
12040	    last = NULL;
12041            next = xmlXPathNextDescendant;
12042            break;
12043        case AXIS_DESCENDANT_OR_SELF:
12044	    last = NULL;
12045            next = xmlXPathNextDescendantOrSelf;
12046            break;
12047        case AXIS_FOLLOWING:
12048	    last = NULL;
12049            next = xmlXPathNextFollowing;
12050            break;
12051        case AXIS_FOLLOWING_SIBLING:
12052	    last = NULL;
12053            next = xmlXPathNextFollowingSibling;
12054            break;
12055        case AXIS_NAMESPACE:
12056            first = NULL;
12057	    last = NULL;
12058            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12059	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12060            break;
12061        case AXIS_PARENT:
12062            first = NULL;
12063            next = xmlXPathNextParent;
12064            break;
12065        case AXIS_PRECEDING:
12066            first = NULL;
12067            next = xmlXPathNextPrecedingInternal;
12068            break;
12069        case AXIS_PRECEDING_SIBLING:
12070            first = NULL;
12071            next = xmlXPathNextPrecedingSibling;
12072            break;
12073        case AXIS_SELF:
12074            first = NULL;
12075	    last = NULL;
12076            next = xmlXPathNextSelf;
12077	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12078            break;
12079    }
12080
12081#ifdef DEBUG_STEP
12082    xmlXPathDebugDumpStepAxis(op,
12083	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12084#endif
12085
12086    if (next == NULL) {
12087	xmlXPathReleaseObject(xpctxt, obj);
12088        return(0);
12089    }
12090    contextSeq = obj->nodesetval;
12091    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12092	xmlXPathReleaseObject(xpctxt, obj);
12093        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12094        return(0);
12095    }
12096    /*
12097    * Predicate optimization ---------------------------------------------
12098    * If this step has a last predicate, which contains a position(),
12099    * then we'll optimize (although not exactly "position()", but only
12100    * the  short-hand form, i.e., "[n]".
12101    *
12102    * Example - expression "/foo[parent::bar][1]":
12103    *
12104    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12105    *   ROOT                               -- op->ch1
12106    *   PREDICATE                          -- op->ch2 (predOp)
12107    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12108    *       SORT
12109    *         COLLECT  'parent' 'name' 'node' bar
12110    *           NODE
12111    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12112    *
12113    */
12114    maxPos = 0;
12115    predOp = NULL;
12116    hasPredicateRange = 0;
12117    hasAxisRange = 0;
12118    if (op->ch2 != -1) {
12119	/*
12120	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12121	*/
12122	predOp = &ctxt->comp->steps[op->ch2];
12123	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12124	    if (predOp->ch1 != -1) {
12125		/*
12126		* Use the next inner predicate operator.
12127		*/
12128		predOp = &ctxt->comp->steps[predOp->ch1];
12129		hasPredicateRange = 1;
12130	    } else {
12131		/*
12132		* There's no other predicate than the [n] predicate.
12133		*/
12134		predOp = NULL;
12135		hasAxisRange = 1;
12136	    }
12137	}
12138    }
12139    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12140    /*
12141    * Axis traversal -----------------------------------------------------
12142    */
12143    /*
12144     * 2.3 Node Tests
12145     *  - For the attribute axis, the principal node type is attribute.
12146     *  - For the namespace axis, the principal node type is namespace.
12147     *  - For other axes, the principal node type is element.
12148     *
12149     * A node test * is true for any node of the
12150     * principal node type. For example, child::* will
12151     * select all element children of the context node
12152     */
12153    oldContextNode = xpctxt->node;
12154    addNode = xmlXPathNodeSetAddUnique;
12155    outSeq = NULL;
12156    seq = NULL;
12157    outerContextNode = NULL;
12158    contextNode = NULL;
12159    contextIdx = 0;
12160
12161
12162    while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12163	if (outerNext != NULL) {
12164	    /*
12165	    * This is a compound traversal.
12166	    */
12167	    if (contextNode == NULL) {
12168		/*
12169		* Set the context for the outer traversal.
12170		*/
12171		outerContextNode = contextSeq->nodeTab[contextIdx++];
12172		contextNode = outerNext(NULL, outerContextNode);
12173	    } else
12174		contextNode = outerNext(contextNode, outerContextNode);
12175	    if (contextNode == NULL)
12176		continue;
12177	    /*
12178	    * Set the context for the main traversal.
12179	    */
12180	    xpctxt->node = contextNode;
12181	} else
12182	    xpctxt->node = contextSeq->nodeTab[contextIdx++];
12183
12184	if (seq == NULL) {
12185	    seq = xmlXPathNodeSetCreate(NULL);
12186	    if (seq == NULL) {
12187		total = 0;
12188		goto error;
12189	    }
12190	}
12191	/*
12192	* Traverse the axis and test the nodes.
12193	*/
12194	pos = 0;
12195	cur = NULL;
12196	hasNsNodes = 0;
12197        do {
12198            cur = next(ctxt, cur);
12199            if (cur == NULL)
12200                break;
12201
12202	    /*
12203	    * QUESTION TODO: What does the "first" and "last" stuff do?
12204	    */
12205            if ((first != NULL) && (*first != NULL)) {
12206		if (*first == cur)
12207		    break;
12208		if (((total % 256) == 0) &&
12209#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12210		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12211#else
12212		    (xmlXPathCmpNodes(*first, cur) >= 0))
12213#endif
12214		{
12215		    break;
12216		}
12217	    }
12218	    if ((last != NULL) && (*last != NULL)) {
12219		if (*last == cur)
12220		    break;
12221		if (((total % 256) == 0) &&
12222#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12223		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12224#else
12225		    (xmlXPathCmpNodes(cur, *last) >= 0))
12226#endif
12227		{
12228		    break;
12229		}
12230	    }
12231
12232            total++;
12233
12234#ifdef DEBUG_STEP
12235            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12236#endif
12237
12238	    switch (test) {
12239                case NODE_TEST_NONE:
12240		    total = 0;
12241                    STRANGE
12242		    goto error;
12243                case NODE_TEST_TYPE:
12244		    /*
12245		    * TODO: Don't we need to use
12246		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
12247		    *  Surprisingly, some c14n tests fail, if we do this.
12248		    */
12249		    if (type == NODE_TYPE_NODE) {
12250			switch (cur->type) {
12251			    case XML_DOCUMENT_NODE:
12252			    case XML_HTML_DOCUMENT_NODE:
12253#ifdef LIBXML_DOCB_ENABLED
12254			    case XML_DOCB_DOCUMENT_NODE:
12255#endif
12256			    case XML_ELEMENT_NODE:
12257			    case XML_ATTRIBUTE_NODE:
12258			    case XML_PI_NODE:
12259			    case XML_COMMENT_NODE:
12260			    case XML_CDATA_SECTION_NODE:
12261			    case XML_TEXT_NODE:
12262			    case XML_NAMESPACE_DECL:
12263				XP_TEST_HIT
12264				break;
12265			    default:
12266				break;
12267			}
12268		    } else if (cur->type == type) {
12269			if (cur->type == XML_NAMESPACE_DECL)
12270			    XP_TEST_HIT_NS
12271			else
12272			    XP_TEST_HIT
12273		    } else if ((type == NODE_TYPE_TEXT) &&
12274			 (cur->type == XML_CDATA_SECTION_NODE))
12275		    {
12276			XP_TEST_HIT
12277		    }
12278		    break;
12279                case NODE_TEST_PI:
12280                    if ((cur->type == XML_PI_NODE) &&
12281                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12282		    {
12283			XP_TEST_HIT
12284                    }
12285                    break;
12286                case NODE_TEST_ALL:
12287                    if (axis == AXIS_ATTRIBUTE) {
12288                        if (cur->type == XML_ATTRIBUTE_NODE)
12289			{
12290			    XP_TEST_HIT
12291                        }
12292                    } else if (axis == AXIS_NAMESPACE) {
12293                        if (cur->type == XML_NAMESPACE_DECL)
12294			{
12295			    XP_TEST_HIT_NS
12296                        }
12297                    } else {
12298                        if (cur->type == XML_ELEMENT_NODE) {
12299                            if (prefix == NULL)
12300			    {
12301				XP_TEST_HIT
12302
12303                            } else if ((cur->ns != NULL) &&
12304				(xmlStrEqual(URI, cur->ns->href)))
12305			    {
12306				XP_TEST_HIT
12307                            }
12308                        }
12309                    }
12310                    break;
12311                case NODE_TEST_NS:{
12312                        TODO;
12313                        break;
12314                    }
12315                case NODE_TEST_NAME:
12316                    if (axis == AXIS_ATTRIBUTE) {
12317                        if (cur->type != XML_ATTRIBUTE_NODE)
12318			    break;
12319		    } else if (axis == AXIS_NAMESPACE) {
12320                        if (cur->type != XML_NAMESPACE_DECL)
12321			    break;
12322		    } else {
12323		        if (cur->type != XML_ELEMENT_NODE)
12324			    break;
12325		    }
12326                    switch (cur->type) {
12327                        case XML_ELEMENT_NODE:
12328                            if (xmlStrEqual(name, cur->name)) {
12329                                if (prefix == NULL) {
12330                                    if (cur->ns == NULL)
12331				    {
12332					XP_TEST_HIT
12333                                    }
12334                                } else {
12335                                    if ((cur->ns != NULL) &&
12336                                        (xmlStrEqual(URI, cur->ns->href)))
12337				    {
12338					XP_TEST_HIT
12339                                    }
12340                                }
12341                            }
12342                            break;
12343                        case XML_ATTRIBUTE_NODE:{
12344                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12345
12346                                if (xmlStrEqual(name, attr->name)) {
12347                                    if (prefix == NULL) {
12348                                        if ((attr->ns == NULL) ||
12349                                            (attr->ns->prefix == NULL))
12350					{
12351					    XP_TEST_HIT
12352                                        }
12353                                    } else {
12354                                        if ((attr->ns != NULL) &&
12355                                            (xmlStrEqual(URI,
12356					      attr->ns->href)))
12357					{
12358					    XP_TEST_HIT
12359                                        }
12360                                    }
12361                                }
12362                                break;
12363                            }
12364                        case XML_NAMESPACE_DECL:
12365                            if (cur->type == XML_NAMESPACE_DECL) {
12366                                xmlNsPtr ns = (xmlNsPtr) cur;
12367
12368                                if ((ns->prefix != NULL) && (name != NULL)
12369                                    && (xmlStrEqual(ns->prefix, name)))
12370				{
12371				    XP_TEST_HIT_NS
12372                                }
12373                            }
12374                            break;
12375                        default:
12376                            break;
12377                    }
12378                    break;
12379	    } /* switch(test) */
12380        } while (cur != NULL);
12381
12382	goto apply_predicates;
12383
12384axis_range_end: /* ----------------------------------------------------- */
12385	/*
12386	* We have a "/foo[n]", and position() = n was reached.
12387	* Note that we can have as well "/foo/::parent::foo[1]", so
12388	* a duplicate-aware merge is still needed.
12389	* Merge with the result.
12390	*/
12391	if (outSeq == NULL) {
12392	    outSeq = seq;
12393	    seq = NULL;
12394	} else
12395	    outSeq = mergeAndClear(outSeq, seq, 0);
12396	/*
12397	* Break if only a true/false result was requested.
12398	*/
12399	if (toBool)
12400	    break;
12401	continue;
12402
12403first_hit: /* ---------------------------------------------------------- */
12404	/*
12405	* Break if only a true/false result was requested and
12406	* no predicates existed and a node test succeeded.
12407	*/
12408	if (outSeq == NULL) {
12409	    outSeq = seq;
12410	    seq = NULL;
12411	} else
12412	    outSeq = mergeAndClear(outSeq, seq, 0);
12413	break;
12414
12415#ifdef DEBUG_STEP
12416	if (seq != NULL)
12417	    nbMatches += seq->nodeNr;
12418#endif
12419
12420apply_predicates: /* --------------------------------------------------- */
12421        /*
12422	* Apply predicates.
12423	*/
12424        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12425	    /*
12426	    * E.g. when we have a "/foo[some expression][n]".
12427	    */
12428	    /*
12429	    * QUESTION TODO: The old predicate evaluation took into
12430	    *  account location-sets.
12431	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12432	    *  Do we expect such a set here?
12433	    *  All what I learned now from the evaluation semantics
12434	    *  does not indicate that a location-set will be processed
12435	    *  here, so this looks OK.
12436	    */
12437	    /*
12438	    * Iterate over all predicates, starting with the outermost
12439	    * predicate.
12440	    * TODO: Problem: we cannot execute the inner predicates first
12441	    *  since we cannot go back *up* the operator tree!
12442	    *  Options we have:
12443	    *  1) Use of recursive functions (like is it currently done
12444	    *     via xmlXPathCompOpEval())
12445	    *  2) Add a predicate evaluation information stack to the
12446	    *     context struct
12447	    *  3) Change the way the operators are linked; we need a
12448	    *     "parent" field on xmlXPathStepOp
12449	    *
12450	    * For the moment, I'll try to solve this with a recursive
12451	    * function: xmlXPathCompOpEvalPredicate().
12452	    */
12453	    size = seq->nodeNr;
12454	    if (hasPredicateRange != 0)
12455		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12456		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12457	    else
12458		newSize = xmlXPathCompOpEvalPredicate(ctxt,
12459		    predOp, seq, size, hasNsNodes);
12460
12461	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12462		total = 0;
12463		goto error;
12464	    }
12465	    /*
12466	    * Add the filtered set of nodes to the result node set.
12467	    */
12468	    if (newSize == 0) {
12469		/*
12470		* The predicates filtered all nodes out.
12471		*/
12472		xmlXPathNodeSetClear(seq, hasNsNodes);
12473	    } else if (seq->nodeNr > 0) {
12474		/*
12475		* Add to result set.
12476		*/
12477		if (outSeq == NULL) {
12478		    if (size != newSize) {
12479			/*
12480			* We need to merge and clear here, since
12481			* the sequence will contained NULLed entries.
12482			*/
12483			outSeq = mergeAndClear(NULL, seq, 1);
12484		    } else {
12485			outSeq = seq;
12486			seq = NULL;
12487		    }
12488		} else
12489		    outSeq = mergeAndClear(outSeq, seq,
12490			(size != newSize) ? 1: 0);
12491		/*
12492		* Break if only a true/false result was requested.
12493		*/
12494		if (toBool)
12495		    break;
12496	    }
12497        } else if (seq->nodeNr > 0) {
12498	    /*
12499	    * Add to result set.
12500	    */
12501	    if (outSeq == NULL) {
12502		outSeq = seq;
12503		seq = NULL;
12504	    } else {
12505		outSeq = mergeAndClear(outSeq, seq, 0);
12506	    }
12507	}
12508    }
12509
12510error:
12511    if ((obj->boolval) && (obj->user != NULL)) {
12512	/*
12513	* QUESTION TODO: What does this do and why?
12514	* TODO: Do we have to do this also for the "error"
12515	* cleanup further down?
12516	*/
12517	ctxt->value->boolval = 1;
12518	ctxt->value->user = obj->user;
12519	obj->user = NULL;
12520	obj->boolval = 0;
12521    }
12522    xmlXPathReleaseObject(xpctxt, obj);
12523
12524    /*
12525    * Ensure we return at least an emtpy set.
12526    */
12527    if (outSeq == NULL) {
12528	if ((seq != NULL) && (seq->nodeNr == 0))
12529	    outSeq = seq;
12530	else
12531	    outSeq = xmlXPathNodeSetCreate(NULL);
12532        /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12533    }
12534    if ((seq != NULL) && (seq != outSeq)) {
12535	 xmlXPathFreeNodeSet(seq);
12536    }
12537    /*
12538    * Hand over the result. Better to push the set also in
12539    * case of errors.
12540    */
12541    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12542    /*
12543    * Reset the context node.
12544    */
12545    xpctxt->node = oldContextNode;
12546
12547#ifdef DEBUG_STEP
12548    xmlGenericError(xmlGenericErrorContext,
12549	"\nExamined %d nodes, found %d nodes at that step\n",
12550	total, nbMatches);
12551#endif
12552
12553    return(total);
12554}
12555
12556static int
12557xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12558			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12559
12560/**
12561 * xmlXPathCompOpEvalFirst:
12562 * @ctxt:  the XPath parser context with the compiled expression
12563 * @op:  an XPath compiled operation
12564 * @first:  the first elem found so far
12565 *
12566 * Evaluate the Precompiled XPath operation searching only the first
12567 * element in document order
12568 *
12569 * Returns the number of examined objects.
12570 */
12571static int
12572xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12573                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12574{
12575    int total = 0, cur;
12576    xmlXPathCompExprPtr comp;
12577    xmlXPathObjectPtr arg1, arg2;
12578
12579    CHECK_ERROR0;
12580    comp = ctxt->comp;
12581    switch (op->op) {
12582        case XPATH_OP_END:
12583            return (0);
12584        case XPATH_OP_UNION:
12585            total =
12586                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12587                                        first);
12588	    CHECK_ERROR0;
12589            if ((ctxt->value != NULL)
12590                && (ctxt->value->type == XPATH_NODESET)
12591                && (ctxt->value->nodesetval != NULL)
12592                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12593                /*
12594                 * limit tree traversing to first node in the result
12595                 */
12596		/*
12597		* OPTIMIZE TODO: This implicitely sorts
12598		*  the result, even if not needed. E.g. if the argument
12599		*  of the count() function, no sorting is needed.
12600		* OPTIMIZE TODO: How do we know if the node-list wasn't
12601		*  aready sorted?
12602		*/
12603		if (ctxt->value->nodesetval->nodeNr > 1)
12604		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12605                *first = ctxt->value->nodesetval->nodeTab[0];
12606            }
12607            cur =
12608                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12609                                        first);
12610	    CHECK_ERROR0;
12611            CHECK_TYPE0(XPATH_NODESET);
12612            arg2 = valuePop(ctxt);
12613
12614            CHECK_TYPE0(XPATH_NODESET);
12615            arg1 = valuePop(ctxt);
12616
12617            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12618                                                    arg2->nodesetval);
12619            valuePush(ctxt, arg1);
12620	    xmlXPathReleaseObject(ctxt->context, arg2);
12621            /* optimizer */
12622	    if (total > cur)
12623		xmlXPathCompSwap(op);
12624            return (total + cur);
12625        case XPATH_OP_ROOT:
12626            xmlXPathRoot(ctxt);
12627            return (0);
12628        case XPATH_OP_NODE:
12629            if (op->ch1 != -1)
12630                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12631	    CHECK_ERROR0;
12632            if (op->ch2 != -1)
12633                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12634	    CHECK_ERROR0;
12635	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12636		ctxt->context->node));
12637            return (total);
12638        case XPATH_OP_RESET:
12639            if (op->ch1 != -1)
12640                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12641	    CHECK_ERROR0;
12642            if (op->ch2 != -1)
12643                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12644	    CHECK_ERROR0;
12645            ctxt->context->node = NULL;
12646            return (total);
12647        case XPATH_OP_COLLECT:{
12648                if (op->ch1 == -1)
12649                    return (total);
12650
12651                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12652		CHECK_ERROR0;
12653
12654                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12655                return (total);
12656            }
12657        case XPATH_OP_VALUE:
12658            valuePush(ctxt,
12659                      xmlXPathCacheObjectCopy(ctxt->context,
12660			(xmlXPathObjectPtr) op->value4));
12661            return (0);
12662        case XPATH_OP_SORT:
12663            if (op->ch1 != -1)
12664                total +=
12665                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12666                                            first);
12667	    CHECK_ERROR0;
12668            if ((ctxt->value != NULL)
12669                && (ctxt->value->type == XPATH_NODESET)
12670                && (ctxt->value->nodesetval != NULL)
12671		&& (ctxt->value->nodesetval->nodeNr > 1))
12672                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12673            return (total);
12674#ifdef XP_OPTIMIZED_FILTER_FIRST
12675	case XPATH_OP_FILTER:
12676                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12677            return (total);
12678#endif
12679        default:
12680            return (xmlXPathCompOpEval(ctxt, op));
12681    }
12682}
12683
12684/**
12685 * xmlXPathCompOpEvalLast:
12686 * @ctxt:  the XPath parser context with the compiled expression
12687 * @op:  an XPath compiled operation
12688 * @last:  the last elem found so far
12689 *
12690 * Evaluate the Precompiled XPath operation searching only the last
12691 * element in document order
12692 *
12693 * Returns the number of nodes traversed
12694 */
12695static int
12696xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12697                       xmlNodePtr * last)
12698{
12699    int total = 0, cur;
12700    xmlXPathCompExprPtr comp;
12701    xmlXPathObjectPtr arg1, arg2;
12702    xmlNodePtr bak;
12703    xmlDocPtr bakd;
12704    int pp;
12705    int cs;
12706
12707    CHECK_ERROR0;
12708    comp = ctxt->comp;
12709    switch (op->op) {
12710        case XPATH_OP_END:
12711            return (0);
12712        case XPATH_OP_UNION:
12713	    bakd = ctxt->context->doc;
12714	    bak = ctxt->context->node;
12715	    pp = ctxt->context->proximityPosition;
12716	    cs = ctxt->context->contextSize;
12717            total =
12718                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12719	    CHECK_ERROR0;
12720            if ((ctxt->value != NULL)
12721                && (ctxt->value->type == XPATH_NODESET)
12722                && (ctxt->value->nodesetval != NULL)
12723                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12724                /*
12725                 * limit tree traversing to first node in the result
12726                 */
12727		if (ctxt->value->nodesetval->nodeNr > 1)
12728		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12729                *last =
12730                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12731                                                     nodesetval->nodeNr -
12732                                                     1];
12733            }
12734	    ctxt->context->doc = bakd;
12735	    ctxt->context->node = bak;
12736	    ctxt->context->proximityPosition = pp;
12737	    ctxt->context->contextSize = cs;
12738            cur =
12739                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12740	    CHECK_ERROR0;
12741            if ((ctxt->value != NULL)
12742                && (ctxt->value->type == XPATH_NODESET)
12743                && (ctxt->value->nodesetval != NULL)
12744                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12745            }
12746            CHECK_TYPE0(XPATH_NODESET);
12747            arg2 = valuePop(ctxt);
12748
12749            CHECK_TYPE0(XPATH_NODESET);
12750            arg1 = valuePop(ctxt);
12751
12752            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12753                                                    arg2->nodesetval);
12754            valuePush(ctxt, arg1);
12755	    xmlXPathReleaseObject(ctxt->context, arg2);
12756            /* optimizer */
12757	    if (total > cur)
12758		xmlXPathCompSwap(op);
12759            return (total + cur);
12760        case XPATH_OP_ROOT:
12761            xmlXPathRoot(ctxt);
12762            return (0);
12763        case XPATH_OP_NODE:
12764            if (op->ch1 != -1)
12765                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12766	    CHECK_ERROR0;
12767            if (op->ch2 != -1)
12768                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12769	    CHECK_ERROR0;
12770	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12771		ctxt->context->node));
12772            return (total);
12773        case XPATH_OP_RESET:
12774            if (op->ch1 != -1)
12775                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12776	    CHECK_ERROR0;
12777            if (op->ch2 != -1)
12778                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12779	    CHECK_ERROR0;
12780            ctxt->context->node = NULL;
12781            return (total);
12782        case XPATH_OP_COLLECT:{
12783                if (op->ch1 == -1)
12784                    return (0);
12785
12786                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12787		CHECK_ERROR0;
12788
12789                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12790                return (total);
12791            }
12792        case XPATH_OP_VALUE:
12793            valuePush(ctxt,
12794                      xmlXPathCacheObjectCopy(ctxt->context,
12795			(xmlXPathObjectPtr) op->value4));
12796            return (0);
12797        case XPATH_OP_SORT:
12798            if (op->ch1 != -1)
12799                total +=
12800                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12801                                           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))
12807                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12808            return (total);
12809        default:
12810            return (xmlXPathCompOpEval(ctxt, op));
12811    }
12812}
12813
12814#ifdef XP_OPTIMIZED_FILTER_FIRST
12815static int
12816xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12817			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12818{
12819    int total = 0;
12820    xmlXPathCompExprPtr comp;
12821    xmlXPathObjectPtr res;
12822    xmlXPathObjectPtr obj;
12823    xmlNodeSetPtr oldset;
12824    xmlNodePtr oldnode;
12825    xmlDocPtr oldDoc;
12826    int i;
12827
12828    CHECK_ERROR0;
12829    comp = ctxt->comp;
12830    /*
12831    * Optimization for ()[last()] selection i.e. the last elem
12832    */
12833    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12834	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12835	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12836	int f = comp->steps[op->ch2].ch1;
12837
12838	if ((f != -1) &&
12839	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12840	    (comp->steps[f].value5 == NULL) &&
12841	    (comp->steps[f].value == 0) &&
12842	    (comp->steps[f].value4 != NULL) &&
12843	    (xmlStrEqual
12844	    (comp->steps[f].value4, BAD_CAST "last"))) {
12845	    xmlNodePtr last = NULL;
12846
12847	    total +=
12848		xmlXPathCompOpEvalLast(ctxt,
12849		    &comp->steps[op->ch1],
12850		    &last);
12851	    CHECK_ERROR0;
12852	    /*
12853	    * The nodeset should be in document order,
12854	    * Keep only the last value
12855	    */
12856	    if ((ctxt->value != NULL) &&
12857		(ctxt->value->type == XPATH_NODESET) &&
12858		(ctxt->value->nodesetval != NULL) &&
12859		(ctxt->value->nodesetval->nodeTab != NULL) &&
12860		(ctxt->value->nodesetval->nodeNr > 1)) {
12861		ctxt->value->nodesetval->nodeTab[0] =
12862		    ctxt->value->nodesetval->nodeTab[ctxt->
12863		    value->
12864		    nodesetval->
12865		    nodeNr -
12866		    1];
12867		ctxt->value->nodesetval->nodeNr = 1;
12868		*first = *(ctxt->value->nodesetval->nodeTab);
12869	    }
12870	    return (total);
12871	}
12872    }
12873
12874    if (op->ch1 != -1)
12875	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12876    CHECK_ERROR0;
12877    if (op->ch2 == -1)
12878	return (total);
12879    if (ctxt->value == NULL)
12880	return (total);
12881
12882#ifdef LIBXML_XPTR_ENABLED
12883    oldnode = ctxt->context->node;
12884    /*
12885    * Hum are we filtering the result of an XPointer expression
12886    */
12887    if (ctxt->value->type == XPATH_LOCATIONSET) {
12888	xmlXPathObjectPtr tmp = NULL;
12889	xmlLocationSetPtr newlocset = NULL;
12890	xmlLocationSetPtr oldlocset;
12891
12892	/*
12893	* Extract the old locset, and then evaluate the result of the
12894	* expression for all the element in the locset. use it to grow
12895	* up a new locset.
12896	*/
12897	CHECK_TYPE0(XPATH_LOCATIONSET);
12898	obj = valuePop(ctxt);
12899	oldlocset = obj->user;
12900	ctxt->context->node = NULL;
12901
12902	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12903	    ctxt->context->contextSize = 0;
12904	    ctxt->context->proximityPosition = 0;
12905	    if (op->ch2 != -1)
12906		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12907	    res = valuePop(ctxt);
12908	    if (res != NULL) {
12909		xmlXPathReleaseObject(ctxt->context, res);
12910	    }
12911	    valuePush(ctxt, obj);
12912	    CHECK_ERROR0;
12913	    return (total);
12914	}
12915	newlocset = xmlXPtrLocationSetCreate(NULL);
12916
12917	for (i = 0; i < oldlocset->locNr; i++) {
12918	    /*
12919	    * Run the evaluation with a node list made of a
12920	    * single item in the nodelocset.
12921	    */
12922	    ctxt->context->node = oldlocset->locTab[i]->user;
12923	    ctxt->context->contextSize = oldlocset->locNr;
12924	    ctxt->context->proximityPosition = i + 1;
12925	    if (tmp == NULL) {
12926		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12927		    ctxt->context->node);
12928	    } else {
12929		xmlXPathNodeSetAddUnique(tmp->nodesetval,
12930		    ctxt->context->node);
12931	    }
12932	    valuePush(ctxt, tmp);
12933	    if (op->ch2 != -1)
12934		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12935	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12936		xmlXPathFreeObject(obj);
12937		return(0);
12938	    }
12939	    /*
12940	    * The result of the evaluation need to be tested to
12941	    * decided whether the filter succeeded or not
12942	    */
12943	    res = valuePop(ctxt);
12944	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12945		xmlXPtrLocationSetAdd(newlocset,
12946		    xmlXPathCacheObjectCopy(ctxt->context,
12947			oldlocset->locTab[i]));
12948	    }
12949	    /*
12950	    * Cleanup
12951	    */
12952	    if (res != NULL) {
12953		xmlXPathReleaseObject(ctxt->context, res);
12954	    }
12955	    if (ctxt->value == tmp) {
12956		valuePop(ctxt);
12957		xmlXPathNodeSetClear(tmp->nodesetval, 1);
12958		/*
12959		* REVISIT TODO: Don't create a temporary nodeset
12960		* for everly iteration.
12961		*/
12962		/* OLD: xmlXPathFreeObject(res); */
12963	    } else
12964		tmp = NULL;
12965	    ctxt->context->node = NULL;
12966	    /*
12967	    * Only put the first node in the result, then leave.
12968	    */
12969	    if (newlocset->locNr > 0) {
12970		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
12971		break;
12972	    }
12973	}
12974	if (tmp != NULL) {
12975	    xmlXPathReleaseObject(ctxt->context, tmp);
12976	}
12977	/*
12978	* The result is used as the new evaluation locset.
12979	*/
12980	xmlXPathReleaseObject(ctxt->context, obj);
12981	ctxt->context->node = NULL;
12982	ctxt->context->contextSize = -1;
12983	ctxt->context->proximityPosition = -1;
12984	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12985	ctxt->context->node = oldnode;
12986	return (total);
12987    }
12988#endif /* LIBXML_XPTR_ENABLED */
12989
12990    /*
12991    * Extract the old set, and then evaluate the result of the
12992    * expression for all the element in the set. use it to grow
12993    * up a new set.
12994    */
12995    CHECK_TYPE0(XPATH_NODESET);
12996    obj = valuePop(ctxt);
12997    oldset = obj->nodesetval;
12998
12999    oldnode = ctxt->context->node;
13000    oldDoc = ctxt->context->doc;
13001    ctxt->context->node = NULL;
13002
13003    if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13004	ctxt->context->contextSize = 0;
13005	ctxt->context->proximityPosition = 0;
13006	/* QUESTION TODO: Why was this code commented out?
13007	    if (op->ch2 != -1)
13008		total +=
13009		    xmlXPathCompOpEval(ctxt,
13010			&comp->steps[op->ch2]);
13011	    CHECK_ERROR0;
13012	    res = valuePop(ctxt);
13013	    if (res != NULL)
13014		xmlXPathFreeObject(res);
13015	*/
13016	valuePush(ctxt, obj);
13017	ctxt->context->node = oldnode;
13018	CHECK_ERROR0;
13019    } else {
13020	xmlNodeSetPtr newset;
13021	xmlXPathObjectPtr tmp = NULL;
13022	/*
13023	* Initialize the new set.
13024	* Also set the xpath document in case things like
13025	* key() evaluation are attempted on the predicate
13026	*/
13027	newset = xmlXPathNodeSetCreate(NULL);
13028        /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13029
13030	for (i = 0; i < oldset->nodeNr; i++) {
13031	    /*
13032	    * Run the evaluation with a node list made of
13033	    * a single item in the nodeset.
13034	    */
13035	    ctxt->context->node = oldset->nodeTab[i];
13036	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13037		(oldset->nodeTab[i]->doc != NULL))
13038		ctxt->context->doc = oldset->nodeTab[i]->doc;
13039	    if (tmp == NULL) {
13040		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13041		    ctxt->context->node);
13042	    } else {
13043		xmlXPathNodeSetAddUnique(tmp->nodesetval,
13044		    ctxt->context->node);
13045	    }
13046	    valuePush(ctxt, tmp);
13047	    ctxt->context->contextSize = oldset->nodeNr;
13048	    ctxt->context->proximityPosition = i + 1;
13049	    if (op->ch2 != -1)
13050		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13051	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13052		xmlXPathFreeNodeSet(newset);
13053		xmlXPathFreeObject(obj);
13054		return(0);
13055	    }
13056	    /*
13057	    * The result of the evaluation needs to be tested to
13058	    * decide whether the filter succeeded or not
13059	    */
13060	    res = valuePop(ctxt);
13061	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13062		xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13063	    }
13064	    /*
13065	    * Cleanup
13066	    */
13067	    if (res != NULL) {
13068		xmlXPathReleaseObject(ctxt->context, res);
13069	    }
13070	    if (ctxt->value == tmp) {
13071		valuePop(ctxt);
13072		/*
13073		* Don't free the temporary nodeset
13074		* in order to avoid massive recreation inside this
13075		* loop.
13076		*/
13077		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13078	    } else
13079		tmp = NULL;
13080	    ctxt->context->node = NULL;
13081	    /*
13082	    * Only put the first node in the result, then leave.
13083	    */
13084	    if (newset->nodeNr > 0) {
13085		*first = *(newset->nodeTab);
13086		break;
13087	    }
13088	}
13089	if (tmp != NULL) {
13090	    xmlXPathReleaseObject(ctxt->context, tmp);
13091	}
13092	/*
13093	* The result is used as the new evaluation set.
13094	*/
13095	xmlXPathReleaseObject(ctxt->context, obj);
13096	ctxt->context->node = NULL;
13097	ctxt->context->contextSize = -1;
13098	ctxt->context->proximityPosition = -1;
13099	/* may want to move this past the '}' later */
13100	ctxt->context->doc = oldDoc;
13101	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13102    }
13103    ctxt->context->node = oldnode;
13104    return(total);
13105}
13106#endif /* XP_OPTIMIZED_FILTER_FIRST */
13107
13108/**
13109 * xmlXPathCompOpEval:
13110 * @ctxt:  the XPath parser context with the compiled expression
13111 * @op:  an XPath compiled operation
13112 *
13113 * Evaluate the Precompiled XPath operation
13114 * Returns the number of nodes traversed
13115 */
13116static int
13117xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13118{
13119    int total = 0;
13120    int equal, ret;
13121    xmlXPathCompExprPtr comp;
13122    xmlXPathObjectPtr arg1, arg2;
13123    xmlNodePtr bak;
13124    xmlDocPtr bakd;
13125    int pp;
13126    int cs;
13127
13128    CHECK_ERROR0;
13129    comp = ctxt->comp;
13130    switch (op->op) {
13131        case XPATH_OP_END:
13132            return (0);
13133        case XPATH_OP_AND:
13134	    bakd = ctxt->context->doc;
13135	    bak = ctxt->context->node;
13136	    pp = ctxt->context->proximityPosition;
13137	    cs = ctxt->context->contextSize;
13138            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13139	    CHECK_ERROR0;
13140            xmlXPathBooleanFunction(ctxt, 1);
13141            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13142                return (total);
13143            arg2 = valuePop(ctxt);
13144	    ctxt->context->doc = bakd;
13145	    ctxt->context->node = bak;
13146	    ctxt->context->proximityPosition = pp;
13147	    ctxt->context->contextSize = cs;
13148            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13149	    if (ctxt->error) {
13150		xmlXPathFreeObject(arg2);
13151		return(0);
13152	    }
13153            xmlXPathBooleanFunction(ctxt, 1);
13154            arg1 = valuePop(ctxt);
13155            arg1->boolval &= arg2->boolval;
13156            valuePush(ctxt, arg1);
13157	    xmlXPathReleaseObject(ctxt->context, arg2);
13158            return (total);
13159        case XPATH_OP_OR:
13160	    bakd = ctxt->context->doc;
13161	    bak = ctxt->context->node;
13162	    pp = ctxt->context->proximityPosition;
13163	    cs = ctxt->context->contextSize;
13164            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13165	    CHECK_ERROR0;
13166            xmlXPathBooleanFunction(ctxt, 1);
13167            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13168                return (total);
13169            arg2 = valuePop(ctxt);
13170	    ctxt->context->doc = bakd;
13171	    ctxt->context->node = bak;
13172	    ctxt->context->proximityPosition = pp;
13173	    ctxt->context->contextSize = cs;
13174            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13175	    if (ctxt->error) {
13176		xmlXPathFreeObject(arg2);
13177		return(0);
13178	    }
13179            xmlXPathBooleanFunction(ctxt, 1);
13180            arg1 = valuePop(ctxt);
13181            arg1->boolval |= arg2->boolval;
13182            valuePush(ctxt, arg1);
13183	    xmlXPathReleaseObject(ctxt->context, arg2);
13184            return (total);
13185        case XPATH_OP_EQUAL:
13186	    bakd = ctxt->context->doc;
13187	    bak = ctxt->context->node;
13188	    pp = ctxt->context->proximityPosition;
13189	    cs = ctxt->context->contextSize;
13190            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13191	    CHECK_ERROR0;
13192	    ctxt->context->doc = bakd;
13193	    ctxt->context->node = bak;
13194	    ctxt->context->proximityPosition = pp;
13195	    ctxt->context->contextSize = cs;
13196            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13197	    CHECK_ERROR0;
13198	    if (op->value)
13199		equal = xmlXPathEqualValues(ctxt);
13200	    else
13201		equal = xmlXPathNotEqualValues(ctxt);
13202	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13203            return (total);
13204        case XPATH_OP_CMP:
13205	    bakd = ctxt->context->doc;
13206	    bak = ctxt->context->node;
13207	    pp = ctxt->context->proximityPosition;
13208	    cs = ctxt->context->contextSize;
13209            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13210	    CHECK_ERROR0;
13211	    ctxt->context->doc = bakd;
13212	    ctxt->context->node = bak;
13213	    ctxt->context->proximityPosition = pp;
13214	    ctxt->context->contextSize = cs;
13215            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13216	    CHECK_ERROR0;
13217            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13218	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13219            return (total);
13220        case XPATH_OP_PLUS:
13221	    bakd = ctxt->context->doc;
13222	    bak = ctxt->context->node;
13223	    pp = ctxt->context->proximityPosition;
13224	    cs = ctxt->context->contextSize;
13225            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13226	    CHECK_ERROR0;
13227            if (op->ch2 != -1) {
13228		ctxt->context->doc = bakd;
13229		ctxt->context->node = bak;
13230		ctxt->context->proximityPosition = pp;
13231		ctxt->context->contextSize = cs;
13232                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13233	    }
13234	    CHECK_ERROR0;
13235            if (op->value == 0)
13236                xmlXPathSubValues(ctxt);
13237            else if (op->value == 1)
13238                xmlXPathAddValues(ctxt);
13239            else if (op->value == 2)
13240                xmlXPathValueFlipSign(ctxt);
13241            else if (op->value == 3) {
13242                CAST_TO_NUMBER;
13243                CHECK_TYPE0(XPATH_NUMBER);
13244            }
13245            return (total);
13246        case XPATH_OP_MULT:
13247	    bakd = ctxt->context->doc;
13248	    bak = ctxt->context->node;
13249	    pp = ctxt->context->proximityPosition;
13250	    cs = ctxt->context->contextSize;
13251            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13252	    CHECK_ERROR0;
13253	    ctxt->context->doc = bakd;
13254	    ctxt->context->node = bak;
13255	    ctxt->context->proximityPosition = pp;
13256	    ctxt->context->contextSize = cs;
13257            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13258	    CHECK_ERROR0;
13259            if (op->value == 0)
13260                xmlXPathMultValues(ctxt);
13261            else if (op->value == 1)
13262                xmlXPathDivValues(ctxt);
13263            else if (op->value == 2)
13264                xmlXPathModValues(ctxt);
13265            return (total);
13266        case XPATH_OP_UNION:
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            CHECK_TYPE0(XPATH_NODESET);
13280            arg2 = valuePop(ctxt);
13281
13282            CHECK_TYPE0(XPATH_NODESET);
13283            arg1 = valuePop(ctxt);
13284
13285	    if ((arg1->nodesetval == NULL) ||
13286		((arg2->nodesetval != NULL) &&
13287		 (arg2->nodesetval->nodeNr != 0)))
13288	    {
13289		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13290							arg2->nodesetval);
13291	    }
13292
13293            valuePush(ctxt, arg1);
13294	    xmlXPathReleaseObject(ctxt->context, arg2);
13295            return (total);
13296        case XPATH_OP_ROOT:
13297            xmlXPathRoot(ctxt);
13298            return (total);
13299        case XPATH_OP_NODE:
13300            if (op->ch1 != -1)
13301                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13302	    CHECK_ERROR0;
13303            if (op->ch2 != -1)
13304                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13305	    CHECK_ERROR0;
13306	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13307		ctxt->context->node));
13308            return (total);
13309        case XPATH_OP_RESET:
13310            if (op->ch1 != -1)
13311                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13312	    CHECK_ERROR0;
13313            if (op->ch2 != -1)
13314                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13315	    CHECK_ERROR0;
13316            ctxt->context->node = NULL;
13317            return (total);
13318        case XPATH_OP_COLLECT:{
13319                if (op->ch1 == -1)
13320                    return (total);
13321
13322                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13323		CHECK_ERROR0;
13324
13325                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13326                return (total);
13327            }
13328        case XPATH_OP_VALUE:
13329            valuePush(ctxt,
13330                      xmlXPathCacheObjectCopy(ctxt->context,
13331			(xmlXPathObjectPtr) op->value4));
13332            return (total);
13333        case XPATH_OP_VARIABLE:{
13334		xmlXPathObjectPtr val;
13335
13336                if (op->ch1 != -1)
13337                    total +=
13338                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13339                if (op->value5 == NULL) {
13340		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13341		    if (val == NULL) {
13342			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13343			return(0);
13344		    }
13345                    valuePush(ctxt, val);
13346		} else {
13347                    const xmlChar *URI;
13348
13349                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13350                    if (URI == NULL) {
13351                        xmlGenericError(xmlGenericErrorContext,
13352            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13353                                    (char *) op->value4, (char *)op->value5);
13354                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13355                        return (total);
13356                    }
13357		    val = xmlXPathVariableLookupNS(ctxt->context,
13358                                                       op->value4, URI);
13359		    if (val == NULL) {
13360			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13361			return(0);
13362		    }
13363                    valuePush(ctxt, val);
13364                }
13365                return (total);
13366            }
13367        case XPATH_OP_FUNCTION:{
13368                xmlXPathFunction func;
13369                const xmlChar *oldFunc, *oldFuncURI;
13370		int i;
13371
13372                if (op->ch1 != -1)
13373                    total +=
13374                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13375		if (ctxt->valueNr < op->value) {
13376		    xmlGenericError(xmlGenericErrorContext,
13377			    "xmlXPathCompOpEval: parameter error\n");
13378		    ctxt->error = XPATH_INVALID_OPERAND;
13379		    return (total);
13380		}
13381		for (i = 0; i < op->value; i++)
13382		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13383			xmlGenericError(xmlGenericErrorContext,
13384				"xmlXPathCompOpEval: parameter error\n");
13385			ctxt->error = XPATH_INVALID_OPERAND;
13386			return (total);
13387		    }
13388                if (op->cache != NULL)
13389                    XML_CAST_FPTR(func) = op->cache;
13390                else {
13391                    const xmlChar *URI = NULL;
13392
13393                    if (op->value5 == NULL)
13394                        func =
13395                            xmlXPathFunctionLookup(ctxt->context,
13396                                                   op->value4);
13397                    else {
13398                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13399                        if (URI == NULL) {
13400                            xmlGenericError(xmlGenericErrorContext,
13401            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13402                                    (char *)op->value4, (char *)op->value5);
13403                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13404                            return (total);
13405                        }
13406                        func = xmlXPathFunctionLookupNS(ctxt->context,
13407                                                        op->value4, URI);
13408                    }
13409                    if (func == NULL) {
13410                        xmlGenericError(xmlGenericErrorContext,
13411                                "xmlXPathCompOpEval: function %s not found\n",
13412                                        (char *)op->value4);
13413                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13414                    }
13415                    op->cache = XML_CAST_FPTR(func);
13416                    op->cacheURI = (void *) URI;
13417                }
13418                oldFunc = ctxt->context->function;
13419                oldFuncURI = ctxt->context->functionURI;
13420                ctxt->context->function = op->value4;
13421                ctxt->context->functionURI = op->cacheURI;
13422                func(ctxt, op->value);
13423                ctxt->context->function = oldFunc;
13424                ctxt->context->functionURI = oldFuncURI;
13425                return (total);
13426            }
13427        case XPATH_OP_ARG:
13428	    bakd = ctxt->context->doc;
13429	    bak = ctxt->context->node;
13430	    pp = ctxt->context->proximityPosition;
13431	    cs = ctxt->context->contextSize;
13432            if (op->ch1 != -1)
13433                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13434	    ctxt->context->contextSize = cs;
13435	    ctxt->context->proximityPosition = pp;
13436	    ctxt->context->node = bak;
13437	    ctxt->context->doc = bakd;
13438	    CHECK_ERROR0;
13439            if (op->ch2 != -1) {
13440                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13441	        ctxt->context->doc = bakd;
13442	        ctxt->context->node = bak;
13443	        CHECK_ERROR0;
13444	    }
13445            return (total);
13446        case XPATH_OP_PREDICATE:
13447        case XPATH_OP_FILTER:{
13448                xmlXPathObjectPtr res;
13449                xmlXPathObjectPtr obj, tmp;
13450                xmlNodeSetPtr newset = NULL;
13451                xmlNodeSetPtr oldset;
13452                xmlNodePtr oldnode;
13453		xmlDocPtr oldDoc;
13454                int i;
13455
13456                /*
13457                 * Optimization for ()[1] selection i.e. the first elem
13458                 */
13459                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13460#ifdef XP_OPTIMIZED_FILTER_FIRST
13461		    /*
13462		    * FILTER TODO: Can we assume that the inner processing
13463		    *  will result in an ordered list if we have an
13464		    *  XPATH_OP_FILTER?
13465		    *  What about an additional field or flag on
13466		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13467		    *  to assume anything, so it would be more robust and
13468		    *  easier to optimize.
13469		    */
13470                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13471		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13472#else
13473		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13474#endif
13475                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13476                    xmlXPathObjectPtr val;
13477
13478                    val = comp->steps[op->ch2].value4;
13479                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13480                        (val->floatval == 1.0)) {
13481                        xmlNodePtr first = NULL;
13482
13483                        total +=
13484                            xmlXPathCompOpEvalFirst(ctxt,
13485                                                    &comp->steps[op->ch1],
13486                                                    &first);
13487			CHECK_ERROR0;
13488                        /*
13489                         * The nodeset should be in document order,
13490                         * Keep only the first value
13491                         */
13492                        if ((ctxt->value != NULL) &&
13493                            (ctxt->value->type == XPATH_NODESET) &&
13494                            (ctxt->value->nodesetval != NULL) &&
13495                            (ctxt->value->nodesetval->nodeNr > 1))
13496                            ctxt->value->nodesetval->nodeNr = 1;
13497                        return (total);
13498                    }
13499                }
13500                /*
13501                 * Optimization for ()[last()] selection i.e. the last elem
13502                 */
13503                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13504                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13505                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13506                    int f = comp->steps[op->ch2].ch1;
13507
13508                    if ((f != -1) &&
13509                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13510                        (comp->steps[f].value5 == NULL) &&
13511                        (comp->steps[f].value == 0) &&
13512                        (comp->steps[f].value4 != NULL) &&
13513                        (xmlStrEqual
13514                         (comp->steps[f].value4, BAD_CAST "last"))) {
13515                        xmlNodePtr last = NULL;
13516
13517                        total +=
13518                            xmlXPathCompOpEvalLast(ctxt,
13519                                                   &comp->steps[op->ch1],
13520                                                   &last);
13521			CHECK_ERROR0;
13522                        /*
13523                         * The nodeset should be in document order,
13524                         * Keep only the last value
13525                         */
13526                        if ((ctxt->value != NULL) &&
13527                            (ctxt->value->type == XPATH_NODESET) &&
13528                            (ctxt->value->nodesetval != NULL) &&
13529                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13530                            (ctxt->value->nodesetval->nodeNr > 1)) {
13531                            ctxt->value->nodesetval->nodeTab[0] =
13532                                ctxt->value->nodesetval->nodeTab[ctxt->
13533                                                                 value->
13534                                                                 nodesetval->
13535                                                                 nodeNr -
13536                                                                 1];
13537                            ctxt->value->nodesetval->nodeNr = 1;
13538                        }
13539                        return (total);
13540                    }
13541                }
13542		/*
13543		* Process inner predicates first.
13544		* Example "index[parent::book][1]":
13545		* ...
13546		*   PREDICATE   <-- we are here "[1]"
13547		*     PREDICATE <-- process "[parent::book]" first
13548		*       SORT
13549		*         COLLECT  'parent' 'name' 'node' book
13550		*           NODE
13551		*     ELEM Object is a number : 1
13552		*/
13553                if (op->ch1 != -1)
13554                    total +=
13555                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13556		CHECK_ERROR0;
13557                if (op->ch2 == -1)
13558                    return (total);
13559                if (ctxt->value == NULL)
13560                    return (total);
13561
13562                oldnode = ctxt->context->node;
13563
13564#ifdef LIBXML_XPTR_ENABLED
13565                /*
13566                 * Hum are we filtering the result of an XPointer expression
13567                 */
13568                if (ctxt->value->type == XPATH_LOCATIONSET) {
13569                    xmlLocationSetPtr newlocset = NULL;
13570                    xmlLocationSetPtr oldlocset;
13571
13572                    /*
13573                     * Extract the old locset, and then evaluate the result of the
13574                     * expression for all the element in the locset. use it to grow
13575                     * up a new locset.
13576                     */
13577                    CHECK_TYPE0(XPATH_LOCATIONSET);
13578                    obj = valuePop(ctxt);
13579                    oldlocset = obj->user;
13580                    ctxt->context->node = NULL;
13581
13582                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13583                        ctxt->context->contextSize = 0;
13584                        ctxt->context->proximityPosition = 0;
13585                        if (op->ch2 != -1)
13586                            total +=
13587                                xmlXPathCompOpEval(ctxt,
13588                                                   &comp->steps[op->ch2]);
13589                        res = valuePop(ctxt);
13590                        if (res != NULL) {
13591			    xmlXPathReleaseObject(ctxt->context, res);
13592			}
13593                        valuePush(ctxt, obj);
13594                        CHECK_ERROR0;
13595                        return (total);
13596                    }
13597                    newlocset = xmlXPtrLocationSetCreate(NULL);
13598
13599                    for (i = 0; i < oldlocset->locNr; i++) {
13600                        /*
13601                         * Run the evaluation with a node list made of a
13602                         * single item in the nodelocset.
13603                         */
13604                        ctxt->context->node = oldlocset->locTab[i]->user;
13605                        ctxt->context->contextSize = oldlocset->locNr;
13606                        ctxt->context->proximityPosition = i + 1;
13607			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13608			    ctxt->context->node);
13609                        valuePush(ctxt, tmp);
13610
13611                        if (op->ch2 != -1)
13612                            total +=
13613                                xmlXPathCompOpEval(ctxt,
13614                                                   &comp->steps[op->ch2]);
13615			if (ctxt->error != XPATH_EXPRESSION_OK) {
13616			    xmlXPathFreeObject(obj);
13617			    return(0);
13618			}
13619
13620                        /*
13621                         * The result of the evaluation need to be tested to
13622                         * decided whether the filter succeeded or not
13623                         */
13624                        res = valuePop(ctxt);
13625                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13626                            xmlXPtrLocationSetAdd(newlocset,
13627                                                  xmlXPathObjectCopy
13628                                                  (oldlocset->locTab[i]));
13629                        }
13630
13631                        /*
13632                         * Cleanup
13633                         */
13634                        if (res != NULL) {
13635			    xmlXPathReleaseObject(ctxt->context, res);
13636			}
13637                        if (ctxt->value == tmp) {
13638                            res = valuePop(ctxt);
13639			    xmlXPathReleaseObject(ctxt->context, res);
13640                        }
13641
13642                        ctxt->context->node = NULL;
13643                    }
13644
13645                    /*
13646                     * The result is used as the new evaluation locset.
13647                     */
13648		    xmlXPathReleaseObject(ctxt->context, obj);
13649                    ctxt->context->node = NULL;
13650                    ctxt->context->contextSize = -1;
13651                    ctxt->context->proximityPosition = -1;
13652                    valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13653                    ctxt->context->node = oldnode;
13654                    return (total);
13655                }
13656#endif /* LIBXML_XPTR_ENABLED */
13657
13658                /*
13659                 * Extract the old set, and then evaluate the result of the
13660                 * expression for all the element in the set. use it to grow
13661                 * up a new set.
13662                 */
13663                CHECK_TYPE0(XPATH_NODESET);
13664                obj = valuePop(ctxt);
13665                oldset = obj->nodesetval;
13666
13667                oldnode = ctxt->context->node;
13668		oldDoc = ctxt->context->doc;
13669                ctxt->context->node = NULL;
13670
13671                if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13672                    ctxt->context->contextSize = 0;
13673                    ctxt->context->proximityPosition = 0;
13674/*
13675                    if (op->ch2 != -1)
13676                        total +=
13677                            xmlXPathCompOpEval(ctxt,
13678                                               &comp->steps[op->ch2]);
13679		    CHECK_ERROR0;
13680                    res = valuePop(ctxt);
13681                    if (res != NULL)
13682                        xmlXPathFreeObject(res);
13683*/
13684                    valuePush(ctxt, obj);
13685                    ctxt->context->node = oldnode;
13686                    CHECK_ERROR0;
13687                } else {
13688		    tmp = NULL;
13689                    /*
13690                     * Initialize the new set.
13691		     * Also set the xpath document in case things like
13692		     * key() evaluation are attempted on the predicate
13693                     */
13694                    newset = xmlXPathNodeSetCreate(NULL);
13695		    /*
13696		    * SPEC XPath 1.0:
13697		    *  "For each node in the node-set to be filtered, the
13698		    *  PredicateExpr is evaluated with that node as the
13699		    *  context node, with the number of nodes in the
13700		    *  node-set as the context size, and with the proximity
13701		    *  position of the node in the node-set with respect to
13702		    *  the axis as the context position;"
13703		    * @oldset is the node-set" to be filtered.
13704		    *
13705		    * SPEC XPath 1.0:
13706		    *  "only predicates change the context position and
13707		    *  context size (see [2.4 Predicates])."
13708		    * Example:
13709		    *   node-set  context pos
13710		    *    nA         1
13711		    *    nB         2
13712		    *    nC         3
13713		    *   After applying predicate [position() > 1] :
13714		    *   node-set  context pos
13715		    *    nB         1
13716		    *    nC         2
13717		    *
13718		    * removed the first node in the node-set, then
13719		    * the context position of the
13720		    */
13721                    for (i = 0; i < oldset->nodeNr; i++) {
13722                        /*
13723                         * Run the evaluation with a node list made of
13724                         * a single item in the nodeset.
13725                         */
13726                        ctxt->context->node = oldset->nodeTab[i];
13727			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13728			    (oldset->nodeTab[i]->doc != NULL))
13729		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13730			if (tmp == NULL) {
13731			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13732				ctxt->context->node);
13733			} else {
13734			    xmlXPathNodeSetAddUnique(tmp->nodesetval,
13735				ctxt->context->node);
13736			}
13737                        valuePush(ctxt, tmp);
13738                        ctxt->context->contextSize = oldset->nodeNr;
13739                        ctxt->context->proximityPosition = i + 1;
13740			/*
13741			* Evaluate the predicate against the context node.
13742			* Can/should we optimize position() predicates
13743			* here (e.g. "[1]")?
13744			*/
13745                        if (op->ch2 != -1)
13746                            total +=
13747                                xmlXPathCompOpEval(ctxt,
13748                                                   &comp->steps[op->ch2]);
13749			if (ctxt->error != XPATH_EXPRESSION_OK) {
13750			    xmlXPathFreeNodeSet(newset);
13751			    xmlXPathFreeObject(obj);
13752			    return(0);
13753			}
13754
13755                        /*
13756                         * The result of the evaluation needs to be tested to
13757                         * decide whether the filter succeeded or not
13758                         */
13759			/*
13760			* OPTIMIZE TODO: Can we use
13761			* xmlXPathNodeSetAdd*Unique()* instead?
13762			*/
13763                        res = valuePop(ctxt);
13764                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13765                            xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13766                        }
13767
13768                        /*
13769                         * Cleanup
13770                         */
13771                        if (res != NULL) {
13772			    xmlXPathReleaseObject(ctxt->context, res);
13773			}
13774                        if (ctxt->value == tmp) {
13775                            valuePop(ctxt);
13776			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13777			    /*
13778			    * Don't free the temporary nodeset
13779			    * in order to avoid massive recreation inside this
13780			    * loop.
13781			    */
13782                        } else
13783			    tmp = NULL;
13784                        ctxt->context->node = NULL;
13785                    }
13786		    if (tmp != NULL)
13787			xmlXPathReleaseObject(ctxt->context, tmp);
13788                    /*
13789                     * The result is used as the new evaluation set.
13790                     */
13791		    xmlXPathReleaseObject(ctxt->context, obj);
13792                    ctxt->context->node = NULL;
13793                    ctxt->context->contextSize = -1;
13794                    ctxt->context->proximityPosition = -1;
13795		    /* may want to move this past the '}' later */
13796		    ctxt->context->doc = oldDoc;
13797		    valuePush(ctxt,
13798			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13799                }
13800                ctxt->context->node = oldnode;
13801                return (total);
13802            }
13803        case XPATH_OP_SORT:
13804            if (op->ch1 != -1)
13805                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13806	    CHECK_ERROR0;
13807            if ((ctxt->value != NULL) &&
13808                (ctxt->value->type == XPATH_NODESET) &&
13809                (ctxt->value->nodesetval != NULL) &&
13810		(ctxt->value->nodesetval->nodeNr > 1))
13811	    {
13812                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13813	    }
13814            return (total);
13815#ifdef LIBXML_XPTR_ENABLED
13816        case XPATH_OP_RANGETO:{
13817                xmlXPathObjectPtr range;
13818                xmlXPathObjectPtr res, obj;
13819                xmlXPathObjectPtr tmp;
13820                xmlLocationSetPtr newlocset = NULL;
13821		    xmlLocationSetPtr oldlocset;
13822                xmlNodeSetPtr oldset;
13823                int i, j;
13824
13825                if (op->ch1 != -1)
13826                    total +=
13827                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13828                if (op->ch2 == -1)
13829                    return (total);
13830
13831                if (ctxt->value->type == XPATH_LOCATIONSET) {
13832                    /*
13833                     * Extract the old locset, and then evaluate the result of the
13834                     * expression for all the element in the locset. use it to grow
13835                     * up a new locset.
13836                     */
13837                    CHECK_TYPE0(XPATH_LOCATIONSET);
13838                    obj = valuePop(ctxt);
13839                    oldlocset = obj->user;
13840
13841                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13842		        ctxt->context->node = NULL;
13843                        ctxt->context->contextSize = 0;
13844                        ctxt->context->proximityPosition = 0;
13845                        total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13846                        res = valuePop(ctxt);
13847                        if (res != NULL) {
13848			    xmlXPathReleaseObject(ctxt->context, res);
13849			}
13850                        valuePush(ctxt, obj);
13851                        CHECK_ERROR0;
13852                        return (total);
13853                    }
13854                    newlocset = xmlXPtrLocationSetCreate(NULL);
13855
13856                    for (i = 0; i < oldlocset->locNr; i++) {
13857                        /*
13858                         * Run the evaluation with a node list made of a
13859                         * single item in the nodelocset.
13860                         */
13861                        ctxt->context->node = oldlocset->locTab[i]->user;
13862                        ctxt->context->contextSize = oldlocset->locNr;
13863                        ctxt->context->proximityPosition = i + 1;
13864			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13865			    ctxt->context->node);
13866                        valuePush(ctxt, tmp);
13867
13868                        if (op->ch2 != -1)
13869                            total +=
13870                                xmlXPathCompOpEval(ctxt,
13871                                                   &comp->steps[op->ch2]);
13872			if (ctxt->error != XPATH_EXPRESSION_OK) {
13873			    xmlXPathFreeObject(obj);
13874			    return(0);
13875			}
13876
13877                        res = valuePop(ctxt);
13878			if (res->type == XPATH_LOCATIONSET) {
13879			    xmlLocationSetPtr rloc =
13880			        (xmlLocationSetPtr)res->user;
13881			    for (j=0; j<rloc->locNr; j++) {
13882			        range = xmlXPtrNewRange(
13883				  oldlocset->locTab[i]->user,
13884				  oldlocset->locTab[i]->index,
13885				  rloc->locTab[j]->user2,
13886				  rloc->locTab[j]->index2);
13887				if (range != NULL) {
13888				    xmlXPtrLocationSetAdd(newlocset, range);
13889				}
13890			    }
13891			} else {
13892			    range = xmlXPtrNewRangeNodeObject(
13893				(xmlNodePtr)oldlocset->locTab[i]->user, res);
13894                            if (range != NULL) {
13895                                xmlXPtrLocationSetAdd(newlocset,range);
13896			    }
13897                        }
13898
13899                        /*
13900                         * Cleanup
13901                         */
13902                        if (res != NULL) {
13903			    xmlXPathReleaseObject(ctxt->context, res);
13904			}
13905                        if (ctxt->value == tmp) {
13906                            res = valuePop(ctxt);
13907			    xmlXPathReleaseObject(ctxt->context, res);
13908                        }
13909
13910                        ctxt->context->node = NULL;
13911                    }
13912		} else {	/* Not a location set */
13913                    CHECK_TYPE0(XPATH_NODESET);
13914                    obj = valuePop(ctxt);
13915                    oldset = obj->nodesetval;
13916                    ctxt->context->node = NULL;
13917
13918                    newlocset = xmlXPtrLocationSetCreate(NULL);
13919
13920                    if (oldset != NULL) {
13921                        for (i = 0; i < oldset->nodeNr; i++) {
13922                            /*
13923                             * Run the evaluation with a node list made of a single item
13924                             * in the nodeset.
13925                             */
13926                            ctxt->context->node = oldset->nodeTab[i];
13927			    /*
13928			    * OPTIMIZE TODO: Avoid recreation for every iteration.
13929			    */
13930			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13931				ctxt->context->node);
13932                            valuePush(ctxt, tmp);
13933
13934                            if (op->ch2 != -1)
13935                                total +=
13936                                    xmlXPathCompOpEval(ctxt,
13937                                                   &comp->steps[op->ch2]);
13938			    if (ctxt->error != XPATH_EXPRESSION_OK) {
13939				xmlXPathFreeObject(obj);
13940				return(0);
13941			    }
13942
13943                            res = valuePop(ctxt);
13944                            range =
13945                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13946                                                      res);
13947                            if (range != NULL) {
13948                                xmlXPtrLocationSetAdd(newlocset, range);
13949                            }
13950
13951                            /*
13952                             * Cleanup
13953                             */
13954                            if (res != NULL) {
13955				xmlXPathReleaseObject(ctxt->context, res);
13956			    }
13957                            if (ctxt->value == tmp) {
13958                                res = valuePop(ctxt);
13959				xmlXPathReleaseObject(ctxt->context, res);
13960                            }
13961
13962                            ctxt->context->node = NULL;
13963                        }
13964                    }
13965                }
13966
13967                /*
13968                 * The result is used as the new evaluation set.
13969                 */
13970		xmlXPathReleaseObject(ctxt->context, obj);
13971                ctxt->context->node = NULL;
13972                ctxt->context->contextSize = -1;
13973                ctxt->context->proximityPosition = -1;
13974                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13975                return (total);
13976            }
13977#endif /* LIBXML_XPTR_ENABLED */
13978    }
13979    xmlGenericError(xmlGenericErrorContext,
13980                    "XPath: unknown precompiled operation %d\n", op->op);
13981    return (total);
13982}
13983
13984/**
13985 * xmlXPathCompOpEvalToBoolean:
13986 * @ctxt:  the XPath parser context
13987 *
13988 * Evaluates if the expression evaluates to true.
13989 *
13990 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13991 */
13992static int
13993xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13994			    xmlXPathStepOpPtr op,
13995			    int isPredicate)
13996{
13997    xmlXPathObjectPtr resObj = NULL;
13998
13999start:
14000    /* comp = ctxt->comp; */
14001    switch (op->op) {
14002        case XPATH_OP_END:
14003            return (0);
14004	case XPATH_OP_VALUE:
14005	    resObj = (xmlXPathObjectPtr) op->value4;
14006	    if (isPredicate)
14007		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14008	    return(xmlXPathCastToBoolean(resObj));
14009	case XPATH_OP_SORT:
14010	    /*
14011	    * We don't need sorting for boolean results. Skip this one.
14012	    */
14013            if (op->ch1 != -1) {
14014		op = &ctxt->comp->steps[op->ch1];
14015		goto start;
14016	    }
14017	    return(0);
14018	case XPATH_OP_COLLECT:
14019	    if (op->ch1 == -1)
14020		return(0);
14021
14022            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14023	    if (ctxt->error != XPATH_EXPRESSION_OK)
14024		return(-1);
14025
14026            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14027	    if (ctxt->error != XPATH_EXPRESSION_OK)
14028		return(-1);
14029
14030	    resObj = valuePop(ctxt);
14031	    if (resObj == NULL)
14032		return(-1);
14033	    break;
14034	default:
14035	    /*
14036	    * Fallback to call xmlXPathCompOpEval().
14037	    */
14038	    xmlXPathCompOpEval(ctxt, op);
14039	    if (ctxt->error != XPATH_EXPRESSION_OK)
14040		return(-1);
14041
14042	    resObj = valuePop(ctxt);
14043	    if (resObj == NULL)
14044		return(-1);
14045	    break;
14046    }
14047
14048    if (resObj) {
14049	int res;
14050
14051	if (resObj->type == XPATH_BOOLEAN) {
14052	    res = resObj->boolval;
14053	} else if (isPredicate) {
14054	    /*
14055	    * For predicates a result of type "number" is handled
14056	    * differently:
14057	    * SPEC XPath 1.0:
14058	    * "If the result is a number, the result will be converted
14059	    *  to true if the number is equal to the context position
14060	    *  and will be converted to false otherwise;"
14061	    */
14062	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14063	} else {
14064	    res = xmlXPathCastToBoolean(resObj);
14065	}
14066	xmlXPathReleaseObject(ctxt->context, resObj);
14067	return(res);
14068    }
14069
14070    return(0);
14071}
14072
14073#ifdef XPATH_STREAMING
14074/**
14075 * xmlXPathRunStreamEval:
14076 * @ctxt:  the XPath parser context with the compiled expression
14077 *
14078 * Evaluate the Precompiled Streamable XPath expression in the given context.
14079 */
14080static int
14081xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14082		      xmlXPathObjectPtr *resultSeq, int toBool)
14083{
14084    int max_depth, min_depth;
14085    int from_root;
14086    int ret, depth;
14087    int eval_all_nodes;
14088    xmlNodePtr cur = NULL, limit = NULL;
14089    xmlStreamCtxtPtr patstream = NULL;
14090
14091    int nb_nodes = 0;
14092
14093    if ((ctxt == NULL) || (comp == NULL))
14094        return(-1);
14095    max_depth = xmlPatternMaxDepth(comp);
14096    if (max_depth == -1)
14097        return(-1);
14098    if (max_depth == -2)
14099        max_depth = 10000;
14100    min_depth = xmlPatternMinDepth(comp);
14101    if (min_depth == -1)
14102        return(-1);
14103    from_root = xmlPatternFromRoot(comp);
14104    if (from_root < 0)
14105        return(-1);
14106#if 0
14107    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14108#endif
14109
14110    if (! toBool) {
14111	if (resultSeq == NULL)
14112	    return(-1);
14113	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14114	if (*resultSeq == NULL)
14115	    return(-1);
14116    }
14117
14118    /*
14119     * handle the special cases of "/" amd "." being matched
14120     */
14121    if (min_depth == 0) {
14122	if (from_root) {
14123	    /* Select "/" */
14124	    if (toBool)
14125		return(1);
14126	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14127		(xmlNodePtr) ctxt->doc);
14128	} else {
14129	    /* Select "self::node()" */
14130	    if (toBool)
14131		return(1);
14132	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14133	}
14134    }
14135    if (max_depth == 0) {
14136	return(0);
14137    }
14138
14139    if (from_root) {
14140        cur = (xmlNodePtr)ctxt->doc;
14141    } else if (ctxt->node != NULL) {
14142        switch (ctxt->node->type) {
14143            case XML_ELEMENT_NODE:
14144            case XML_DOCUMENT_NODE:
14145            case XML_DOCUMENT_FRAG_NODE:
14146            case XML_HTML_DOCUMENT_NODE:
14147#ifdef LIBXML_DOCB_ENABLED
14148            case XML_DOCB_DOCUMENT_NODE:
14149#endif
14150	        cur = ctxt->node;
14151		break;
14152            case XML_ATTRIBUTE_NODE:
14153            case XML_TEXT_NODE:
14154            case XML_CDATA_SECTION_NODE:
14155            case XML_ENTITY_REF_NODE:
14156            case XML_ENTITY_NODE:
14157            case XML_PI_NODE:
14158            case XML_COMMENT_NODE:
14159            case XML_NOTATION_NODE:
14160            case XML_DTD_NODE:
14161            case XML_DOCUMENT_TYPE_NODE:
14162            case XML_ELEMENT_DECL:
14163            case XML_ATTRIBUTE_DECL:
14164            case XML_ENTITY_DECL:
14165            case XML_NAMESPACE_DECL:
14166            case XML_XINCLUDE_START:
14167            case XML_XINCLUDE_END:
14168		break;
14169	}
14170	limit = cur;
14171    }
14172    if (cur == NULL) {
14173        return(0);
14174    }
14175
14176    patstream = xmlPatternGetStreamCtxt(comp);
14177    if (patstream == NULL) {
14178	/*
14179	* QUESTION TODO: Is this an error?
14180	*/
14181	return(0);
14182    }
14183
14184    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14185
14186    if (from_root) {
14187	ret = xmlStreamPush(patstream, NULL, NULL);
14188	if (ret < 0) {
14189	} else if (ret == 1) {
14190	    if (toBool)
14191		goto return_1;
14192	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14193	}
14194    }
14195    depth = 0;
14196    goto scan_children;
14197next_node:
14198    do {
14199        nb_nodes++;
14200
14201	switch (cur->type) {
14202	    case XML_ELEMENT_NODE:
14203	    case XML_TEXT_NODE:
14204	    case XML_CDATA_SECTION_NODE:
14205	    case XML_COMMENT_NODE:
14206	    case XML_PI_NODE:
14207		if (cur->type == XML_ELEMENT_NODE) {
14208		    ret = xmlStreamPush(patstream, cur->name,
14209				(cur->ns ? cur->ns->href : NULL));
14210		} else if (eval_all_nodes)
14211		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14212		else
14213		    break;
14214
14215		if (ret < 0) {
14216		    /* NOP. */
14217		} else if (ret == 1) {
14218		    if (toBool)
14219			goto return_1;
14220		    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14221		}
14222		if ((cur->children == NULL) || (depth >= max_depth)) {
14223		    ret = xmlStreamPop(patstream);
14224		    while (cur->next != NULL) {
14225			cur = cur->next;
14226			if ((cur->type != XML_ENTITY_DECL) &&
14227			    (cur->type != XML_DTD_NODE))
14228			    goto next_node;
14229		    }
14230		}
14231	    default:
14232		break;
14233	}
14234
14235scan_children:
14236	if ((cur->children != NULL) && (depth < max_depth)) {
14237	    /*
14238	     * Do not descend on entities declarations
14239	     */
14240	    if (cur->children->type != XML_ENTITY_DECL) {
14241		cur = cur->children;
14242		depth++;
14243		/*
14244		 * Skip DTDs
14245		 */
14246		if (cur->type != XML_DTD_NODE)
14247		    continue;
14248	    }
14249	}
14250
14251	if (cur == limit)
14252	    break;
14253
14254	while (cur->next != NULL) {
14255	    cur = cur->next;
14256	    if ((cur->type != XML_ENTITY_DECL) &&
14257		(cur->type != XML_DTD_NODE))
14258		goto next_node;
14259	}
14260
14261	do {
14262	    cur = cur->parent;
14263	    depth--;
14264	    if ((cur == NULL) || (cur == limit))
14265	        goto done;
14266	    if (cur->type == XML_ELEMENT_NODE) {
14267		ret = xmlStreamPop(patstream);
14268	    } else if ((eval_all_nodes) &&
14269		((cur->type == XML_TEXT_NODE) ||
14270		 (cur->type == XML_CDATA_SECTION_NODE) ||
14271		 (cur->type == XML_COMMENT_NODE) ||
14272		 (cur->type == XML_PI_NODE)))
14273	    {
14274		ret = xmlStreamPop(patstream);
14275	    }
14276	    if (cur->next != NULL) {
14277		cur = cur->next;
14278		break;
14279	    }
14280	} while (cur != NULL);
14281
14282    } while ((cur != NULL) && (depth >= 0));
14283
14284done:
14285
14286#if 0
14287    printf("stream eval: checked %d nodes selected %d\n",
14288           nb_nodes, retObj->nodesetval->nodeNr);
14289#endif
14290
14291    if (patstream)
14292	xmlFreeStreamCtxt(patstream);
14293    return(0);
14294
14295return_1:
14296    if (patstream)
14297	xmlFreeStreamCtxt(patstream);
14298    return(1);
14299}
14300#endif /* XPATH_STREAMING */
14301
14302/**
14303 * xmlXPathRunEval:
14304 * @ctxt:  the XPath parser context with the compiled expression
14305 * @toBool:  evaluate to a boolean result
14306 *
14307 * Evaluate the Precompiled XPath expression in the given context.
14308 */
14309static int
14310xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14311{
14312    xmlXPathCompExprPtr comp;
14313
14314    if ((ctxt == NULL) || (ctxt->comp == NULL))
14315	return(-1);
14316
14317    if (ctxt->valueTab == NULL) {
14318	/* Allocate the value stack */
14319	ctxt->valueTab = (xmlXPathObjectPtr *)
14320			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14321	if (ctxt->valueTab == NULL) {
14322	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14323	    xmlFree(ctxt);
14324	}
14325	ctxt->valueNr = 0;
14326	ctxt->valueMax = 10;
14327	ctxt->value = NULL;
14328    }
14329#ifdef XPATH_STREAMING
14330    if (ctxt->comp->stream) {
14331	int res;
14332
14333	if (toBool) {
14334	    /*
14335	    * Evaluation to boolean result.
14336	    */
14337	    res = xmlXPathRunStreamEval(ctxt->context,
14338		ctxt->comp->stream, NULL, 1);
14339	    if (res != -1)
14340		return(res);
14341	} else {
14342	    xmlXPathObjectPtr resObj = NULL;
14343
14344	    /*
14345	    * Evaluation to a sequence.
14346	    */
14347	    res = xmlXPathRunStreamEval(ctxt->context,
14348		ctxt->comp->stream, &resObj, 0);
14349
14350	    if ((res != -1) && (resObj != NULL)) {
14351		valuePush(ctxt, resObj);
14352		return(0);
14353	    }
14354	    if (resObj != NULL)
14355		xmlXPathReleaseObject(ctxt->context, resObj);
14356	}
14357	/*
14358	* QUESTION TODO: This falls back to normal XPath evaluation
14359	* if res == -1. Is this intended?
14360	*/
14361    }
14362#endif
14363    comp = ctxt->comp;
14364    if (comp->last < 0) {
14365	xmlGenericError(xmlGenericErrorContext,
14366	    "xmlXPathRunEval: last is less than zero\n");
14367	return(-1);
14368    }
14369    if (toBool)
14370	return(xmlXPathCompOpEvalToBoolean(ctxt,
14371	    &comp->steps[comp->last], 0));
14372    else
14373	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14374
14375    return(0);
14376}
14377
14378/************************************************************************
14379 *									*
14380 *			Public interfaces				*
14381 *									*
14382 ************************************************************************/
14383
14384/**
14385 * xmlXPathEvalPredicate:
14386 * @ctxt:  the XPath context
14387 * @res:  the Predicate Expression evaluation result
14388 *
14389 * Evaluate a predicate result for the current node.
14390 * A PredicateExpr is evaluated by evaluating the Expr and converting
14391 * the result to a boolean. If the result is a number, the result will
14392 * be converted to true if the number is equal to the position of the
14393 * context node in the context node list (as returned by the position
14394 * function) and will be converted to false otherwise; if the result
14395 * is not a number, then the result will be converted as if by a call
14396 * to the boolean function.
14397 *
14398 * Returns 1 if predicate is true, 0 otherwise
14399 */
14400int
14401xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14402    if ((ctxt == NULL) || (res == NULL)) return(0);
14403    switch (res->type) {
14404        case XPATH_BOOLEAN:
14405	    return(res->boolval);
14406        case XPATH_NUMBER:
14407	    return(res->floatval == ctxt->proximityPosition);
14408        case XPATH_NODESET:
14409        case XPATH_XSLT_TREE:
14410	    if (res->nodesetval == NULL)
14411		return(0);
14412	    return(res->nodesetval->nodeNr != 0);
14413        case XPATH_STRING:
14414	    return((res->stringval != NULL) &&
14415	           (xmlStrlen(res->stringval) != 0));
14416        default:
14417	    STRANGE
14418    }
14419    return(0);
14420}
14421
14422/**
14423 * xmlXPathEvaluatePredicateResult:
14424 * @ctxt:  the XPath Parser context
14425 * @res:  the Predicate Expression evaluation result
14426 *
14427 * Evaluate a predicate result for the current node.
14428 * A PredicateExpr is evaluated by evaluating the Expr and converting
14429 * the result to a boolean. If the result is a number, the result will
14430 * be converted to true if the number is equal to the position of the
14431 * context node in the context node list (as returned by the position
14432 * function) and will be converted to false otherwise; if the result
14433 * is not a number, then the result will be converted as if by a call
14434 * to the boolean function.
14435 *
14436 * Returns 1 if predicate is true, 0 otherwise
14437 */
14438int
14439xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14440                                xmlXPathObjectPtr res) {
14441    if ((ctxt == NULL) || (res == NULL)) return(0);
14442    switch (res->type) {
14443        case XPATH_BOOLEAN:
14444	    return(res->boolval);
14445        case XPATH_NUMBER:
14446#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14447	    return((res->floatval == ctxt->context->proximityPosition) &&
14448	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14449#else
14450	    return(res->floatval == ctxt->context->proximityPosition);
14451#endif
14452        case XPATH_NODESET:
14453        case XPATH_XSLT_TREE:
14454	    if (res->nodesetval == NULL)
14455		return(0);
14456	    return(res->nodesetval->nodeNr != 0);
14457        case XPATH_STRING:
14458	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14459#ifdef LIBXML_XPTR_ENABLED
14460	case XPATH_LOCATIONSET:{
14461	    xmlLocationSetPtr ptr = res->user;
14462	    if (ptr == NULL)
14463	        return(0);
14464	    return (ptr->locNr != 0);
14465	    }
14466#endif
14467        default:
14468	    STRANGE
14469    }
14470    return(0);
14471}
14472
14473#ifdef XPATH_STREAMING
14474/**
14475 * xmlXPathTryStreamCompile:
14476 * @ctxt: an XPath context
14477 * @str:  the XPath expression
14478 *
14479 * Try to compile the XPath expression as a streamable subset.
14480 *
14481 * Returns the compiled expression or NULL if failed to compile.
14482 */
14483static xmlXPathCompExprPtr
14484xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14485    /*
14486     * Optimization: use streaming patterns when the XPath expression can
14487     * be compiled to a stream lookup
14488     */
14489    xmlPatternPtr stream;
14490    xmlXPathCompExprPtr comp;
14491    xmlDictPtr dict = NULL;
14492    const xmlChar **namespaces = NULL;
14493    xmlNsPtr ns;
14494    int i, j;
14495
14496    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14497        (!xmlStrchr(str, '@'))) {
14498	const xmlChar *tmp;
14499
14500	/*
14501	 * We don't try to handle expressions using the verbose axis
14502	 * specifiers ("::"), just the simplied form at this point.
14503	 * Additionally, if there is no list of namespaces available and
14504	 *  there's a ":" in the expression, indicating a prefixed QName,
14505	 *  then we won't try to compile either. xmlPatterncompile() needs
14506	 *  to have a list of namespaces at compilation time in order to
14507	 *  compile prefixed name tests.
14508	 */
14509	tmp = xmlStrchr(str, ':');
14510	if ((tmp != NULL) &&
14511	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14512	    return(NULL);
14513
14514	if (ctxt != NULL) {
14515	    dict = ctxt->dict;
14516	    if (ctxt->nsNr > 0) {
14517		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14518		if (namespaces == NULL) {
14519		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14520		    return(NULL);
14521		}
14522		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14523		    ns = ctxt->namespaces[j];
14524		    namespaces[i++] = ns->href;
14525		    namespaces[i++] = ns->prefix;
14526		}
14527		namespaces[i++] = NULL;
14528		namespaces[i] = NULL;
14529	    }
14530	}
14531
14532	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14533			&namespaces[0]);
14534	if (namespaces != NULL) {
14535	    xmlFree((xmlChar **)namespaces);
14536	}
14537	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14538	    comp = xmlXPathNewCompExpr();
14539	    if (comp == NULL) {
14540		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14541		return(NULL);
14542	    }
14543	    comp->stream = stream;
14544	    comp->dict = dict;
14545	    if (comp->dict)
14546		xmlDictReference(comp->dict);
14547	    return(comp);
14548	}
14549	xmlFreePattern(stream);
14550    }
14551    return(NULL);
14552}
14553#endif /* XPATH_STREAMING */
14554
14555static int
14556xmlXPathCanRewriteDosExpression(xmlChar *expr)
14557{
14558    if (expr == NULL)
14559	return(0);
14560    do {
14561        if ((*expr == '/') && (*(++expr) == '/'))
14562	    return(1);
14563    } while (*expr++);
14564    return(0);
14565}
14566static void
14567xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14568{
14569    /*
14570    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14571    * internal representation.
14572    */
14573    if (op->ch1 != -1) {
14574	if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14575	    ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14576	    ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14577	    ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14578	{
14579	    /*
14580	    * This is a "child::foo"
14581	    */
14582	    xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14583
14584	    if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14585		(prevop->ch1 != -1) &&
14586		((xmlXPathAxisVal) prevop->value ==
14587		    AXIS_DESCENDANT_OR_SELF) &&
14588		(prevop->ch2 == -1) &&
14589		((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14590		((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14591		(comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14592	    {
14593		/*
14594		* This is a "/descendant-or-self::node()" without predicates.
14595		* Eliminate it.
14596		*/
14597		op->ch1 = prevop->ch1;
14598		op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14599	    }
14600	}
14601	if (op->ch1 != -1)
14602	    xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14603    }
14604    if (op->ch2 != -1)
14605	xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14606}
14607
14608/**
14609 * xmlXPathCtxtCompile:
14610 * @ctxt: an XPath context
14611 * @str:  the XPath expression
14612 *
14613 * Compile an XPath expression
14614 *
14615 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14616 *         the caller has to free the object.
14617 */
14618xmlXPathCompExprPtr
14619xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14620    xmlXPathParserContextPtr pctxt;
14621    xmlXPathCompExprPtr comp;
14622
14623#ifdef XPATH_STREAMING
14624    comp = xmlXPathTryStreamCompile(ctxt, str);
14625    if (comp != NULL)
14626        return(comp);
14627#endif
14628
14629    xmlXPathInit();
14630
14631    pctxt = xmlXPathNewParserContext(str, ctxt);
14632    if (pctxt == NULL)
14633        return NULL;
14634    xmlXPathCompileExpr(pctxt, 1);
14635
14636    if( pctxt->error != XPATH_EXPRESSION_OK )
14637    {
14638        xmlXPathFreeParserContext(pctxt);
14639        return(NULL);
14640    }
14641
14642    if (*pctxt->cur != 0) {
14643	/*
14644	 * aleksey: in some cases this line prints *second* error message
14645	 * (see bug #78858) and probably this should be fixed.
14646	 * However, we are not sure that all error messages are printed
14647	 * out in other places. It's not critical so we leave it as-is for now
14648	 */
14649	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14650	comp = NULL;
14651    } else {
14652	comp = pctxt->comp;
14653	pctxt->comp = NULL;
14654    }
14655    xmlXPathFreeParserContext(pctxt);
14656
14657    if (comp != NULL) {
14658	comp->expr = xmlStrdup(str);
14659#ifdef DEBUG_EVAL_COUNTS
14660	comp->string = xmlStrdup(str);
14661	comp->nb = 0;
14662#endif
14663	if ((comp->expr != NULL) &&
14664	    (comp->nbStep > 2) &&
14665	    (comp->last >= 0) &&
14666	    (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14667	{
14668	    xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14669	}
14670    }
14671    return(comp);
14672}
14673
14674/**
14675 * xmlXPathCompile:
14676 * @str:  the XPath expression
14677 *
14678 * Compile an XPath expression
14679 *
14680 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14681 *         the caller has to free the object.
14682 */
14683xmlXPathCompExprPtr
14684xmlXPathCompile(const xmlChar *str) {
14685    return(xmlXPathCtxtCompile(NULL, str));
14686}
14687
14688/**
14689 * xmlXPathCompiledEvalInternal:
14690 * @comp:  the compiled XPath expression
14691 * @ctxt:  the XPath context
14692 * @resObj: the resulting XPath object or NULL
14693 * @toBool: 1 if only a boolean result is requested
14694 *
14695 * Evaluate the Precompiled XPath expression in the given context.
14696 * The caller has to free @resObj.
14697 *
14698 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14699 *         the caller has to free the object.
14700 */
14701static int
14702xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14703			     xmlXPathContextPtr ctxt,
14704			     xmlXPathObjectPtr *resObj,
14705			     int toBool)
14706{
14707    xmlXPathParserContextPtr pctxt;
14708#ifndef LIBXML_THREAD_ENABLED
14709    static int reentance = 0;
14710#endif
14711    int res;
14712
14713    CHECK_CTXT_NEG(ctxt)
14714
14715    if (comp == NULL)
14716	return(-1);
14717    xmlXPathInit();
14718
14719#ifndef LIBXML_THREAD_ENABLED
14720    reentance++;
14721    if (reentance > 1)
14722	xmlXPathDisableOptimizer = 1;
14723#endif
14724
14725#ifdef DEBUG_EVAL_COUNTS
14726    comp->nb++;
14727    if ((comp->string != NULL) && (comp->nb > 100)) {
14728	fprintf(stderr, "100 x %s\n", comp->string);
14729	comp->nb = 0;
14730    }
14731#endif
14732    pctxt = xmlXPathCompParserContext(comp, ctxt);
14733    res = xmlXPathRunEval(pctxt, toBool);
14734
14735    if (resObj) {
14736	if (pctxt->value == NULL) {
14737	    xmlGenericError(xmlGenericErrorContext,
14738		"xmlXPathCompiledEval: evaluation failed\n");
14739	    *resObj = NULL;
14740	} else {
14741	    *resObj = valuePop(pctxt);
14742	}
14743    }
14744
14745    /*
14746    * Pop all remaining objects from the stack.
14747    */
14748    if (pctxt->valueNr > 0) {
14749	xmlXPathObjectPtr tmp;
14750	int stack = 0;
14751
14752	do {
14753	    tmp = valuePop(pctxt);
14754	    if (tmp != NULL) {
14755		stack++;
14756		xmlXPathReleaseObject(ctxt, tmp);
14757	    }
14758	} while (tmp != NULL);
14759	if ((stack != 0) &&
14760	    ((toBool) || ((resObj) && (*resObj))))
14761	{
14762	    xmlGenericError(xmlGenericErrorContext,
14763		"xmlXPathCompiledEval: %d objects left on the stack.\n",
14764		stack);
14765	}
14766    }
14767
14768    if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14769	xmlXPathFreeObject(*resObj);
14770	*resObj = NULL;
14771    }
14772    pctxt->comp = NULL;
14773    xmlXPathFreeParserContext(pctxt);
14774#ifndef LIBXML_THREAD_ENABLED
14775    reentance--;
14776#endif
14777
14778    return(res);
14779}
14780
14781/**
14782 * xmlXPathCompiledEval:
14783 * @comp:  the compiled XPath expression
14784 * @ctx:  the XPath context
14785 *
14786 * Evaluate the Precompiled XPath expression in the given context.
14787 *
14788 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14789 *         the caller has to free the object.
14790 */
14791xmlXPathObjectPtr
14792xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14793{
14794    xmlXPathObjectPtr res = NULL;
14795
14796    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14797    return(res);
14798}
14799
14800/**
14801 * xmlXPathCompiledEvalToBoolean:
14802 * @comp:  the compiled XPath expression
14803 * @ctxt:  the XPath context
14804 *
14805 * Applies the XPath boolean() function on the result of the given
14806 * compiled expression.
14807 *
14808 * Returns 1 if the expression evaluated to true, 0 if to false and
14809 *         -1 in API and internal errors.
14810 */
14811int
14812xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14813			      xmlXPathContextPtr ctxt)
14814{
14815    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14816}
14817
14818/**
14819 * xmlXPathEvalExpr:
14820 * @ctxt:  the XPath Parser context
14821 *
14822 * Parse and evaluate an XPath expression in the given context,
14823 * then push the result on the context stack
14824 */
14825void
14826xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14827#ifdef XPATH_STREAMING
14828    xmlXPathCompExprPtr comp;
14829#endif
14830
14831    if (ctxt == NULL) return;
14832
14833#ifdef XPATH_STREAMING
14834    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14835    if (comp != NULL) {
14836        if (ctxt->comp != NULL)
14837	    xmlXPathFreeCompExpr(ctxt->comp);
14838        ctxt->comp = comp;
14839	if (ctxt->cur != NULL)
14840	    while (*ctxt->cur != 0) ctxt->cur++;
14841    } else
14842#endif
14843    {
14844	xmlXPathCompileExpr(ctxt, 1);
14845	/*
14846	* In this scenario the expression string will sit in ctxt->base.
14847	*/
14848	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14849	    (ctxt->comp != NULL) &&
14850	    (ctxt->base != NULL) &&
14851	    (ctxt->comp->nbStep > 2) &&
14852	    (ctxt->comp->last >= 0) &&
14853	    (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14854	{
14855	    xmlXPathRewriteDOSExpression(ctxt->comp,
14856		&ctxt->comp->steps[ctxt->comp->last]);
14857	}
14858    }
14859    CHECK_ERROR;
14860    xmlXPathRunEval(ctxt, 0);
14861}
14862
14863/**
14864 * xmlXPathEval:
14865 * @str:  the XPath expression
14866 * @ctx:  the XPath context
14867 *
14868 * Evaluate the XPath Location Path in the given context.
14869 *
14870 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14871 *         the caller has to free the object.
14872 */
14873xmlXPathObjectPtr
14874xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14875    xmlXPathParserContextPtr ctxt;
14876    xmlXPathObjectPtr res, tmp, init = NULL;
14877    int stack = 0;
14878
14879    CHECK_CTXT(ctx)
14880
14881    xmlXPathInit();
14882
14883    ctxt = xmlXPathNewParserContext(str, ctx);
14884    if (ctxt == NULL)
14885        return NULL;
14886    xmlXPathEvalExpr(ctxt);
14887
14888    if (ctxt->value == NULL) {
14889	xmlGenericError(xmlGenericErrorContext,
14890		"xmlXPathEval: evaluation failed\n");
14891	res = NULL;
14892    } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14893#ifdef XPATH_STREAMING
14894            && (ctxt->comp->stream == NULL)
14895#endif
14896	      ) {
14897	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14898	res = NULL;
14899    } else {
14900	res = valuePop(ctxt);
14901    }
14902
14903    do {
14904        tmp = valuePop(ctxt);
14905	if (tmp != NULL) {
14906	    if (tmp != init)
14907		stack++;
14908	    xmlXPathReleaseObject(ctx, tmp);
14909        }
14910    } while (tmp != NULL);
14911    if ((stack != 0) && (res != NULL)) {
14912	xmlGenericError(xmlGenericErrorContext,
14913		"xmlXPathEval: %d object left on the stack\n",
14914	        stack);
14915    }
14916    if (ctxt->error != XPATH_EXPRESSION_OK) {
14917	xmlXPathFreeObject(res);
14918	res = NULL;
14919    }
14920
14921    xmlXPathFreeParserContext(ctxt);
14922    return(res);
14923}
14924
14925/**
14926 * xmlXPathEvalExpression:
14927 * @str:  the XPath expression
14928 * @ctxt:  the XPath context
14929 *
14930 * Evaluate the XPath expression in the given context.
14931 *
14932 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14933 *         the caller has to free the object.
14934 */
14935xmlXPathObjectPtr
14936xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14937    xmlXPathParserContextPtr pctxt;
14938    xmlXPathObjectPtr res, tmp;
14939    int stack = 0;
14940
14941    CHECK_CTXT(ctxt)
14942
14943    xmlXPathInit();
14944
14945    pctxt = xmlXPathNewParserContext(str, ctxt);
14946    if (pctxt == NULL)
14947        return NULL;
14948    xmlXPathEvalExpr(pctxt);
14949
14950    if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
14951	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14952	res = NULL;
14953    } else {
14954	res = valuePop(pctxt);
14955    }
14956    do {
14957        tmp = valuePop(pctxt);
14958	if (tmp != NULL) {
14959	    xmlXPathReleaseObject(ctxt, tmp);
14960	    stack++;
14961	}
14962    } while (tmp != NULL);
14963    if ((stack != 0) && (res != NULL)) {
14964	xmlGenericError(xmlGenericErrorContext,
14965		"xmlXPathEvalExpression: %d object left on the stack\n",
14966	        stack);
14967    }
14968    xmlXPathFreeParserContext(pctxt);
14969    return(res);
14970}
14971
14972/************************************************************************
14973 *									*
14974 *	Extra functions not pertaining to the XPath spec		*
14975 *									*
14976 ************************************************************************/
14977/**
14978 * xmlXPathEscapeUriFunction:
14979 * @ctxt:  the XPath Parser context
14980 * @nargs:  the number of arguments
14981 *
14982 * Implement the escape-uri() XPath function
14983 *    string escape-uri(string $str, bool $escape-reserved)
14984 *
14985 * This function applies the URI escaping rules defined in section 2 of [RFC
14986 * 2396] to the string supplied as $uri-part, which typically represents all
14987 * or part of a URI. The effect of the function is to replace any special
14988 * character in the string by an escape sequence of the form %xx%yy...,
14989 * where xxyy... is the hexadecimal representation of the octets used to
14990 * represent the character in UTF-8.
14991 *
14992 * The set of characters that are escaped depends on the setting of the
14993 * boolean argument $escape-reserved.
14994 *
14995 * If $escape-reserved is true, all characters are escaped other than lower
14996 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14997 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14998 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14999 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15000 * A-F).
15001 *
15002 * If $escape-reserved is false, the behavior differs in that characters
15003 * referred to in [RFC 2396] as reserved characters are not escaped. These
15004 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15005 *
15006 * [RFC 2396] does not define whether escaped URIs should use lower case or
15007 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15008 * compared using string comparison functions, this function must always use
15009 * the upper-case letters A-F.
15010 *
15011 * Generally, $escape-reserved should be set to true when escaping a string
15012 * that is to form a single part of a URI, and to false when escaping an
15013 * entire URI or URI reference.
15014 *
15015 * In the case of non-ascii characters, the string is encoded according to
15016 * utf-8 and then converted according to RFC 2396.
15017 *
15018 * Examples
15019 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15020 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15021 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15022 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15023 *
15024 */
15025static void
15026xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15027    xmlXPathObjectPtr str;
15028    int escape_reserved;
15029    xmlBufferPtr target;
15030    xmlChar *cptr;
15031    xmlChar escape[4];
15032
15033    CHECK_ARITY(2);
15034
15035    escape_reserved = xmlXPathPopBoolean(ctxt);
15036
15037    CAST_TO_STRING;
15038    str = valuePop(ctxt);
15039
15040    target = xmlBufferCreate();
15041
15042    escape[0] = '%';
15043    escape[3] = 0;
15044
15045    if (target) {
15046	for (cptr = str->stringval; *cptr; cptr++) {
15047	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
15048		(*cptr >= 'a' && *cptr <= 'z') ||
15049		(*cptr >= '0' && *cptr <= '9') ||
15050		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
15051		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
15052		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15053		(*cptr == '%' &&
15054		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15055		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15056		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
15057		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15058		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15059		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15060		(!escape_reserved &&
15061		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15062		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15063		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15064		  *cptr == ','))) {
15065		xmlBufferAdd(target, cptr, 1);
15066	    } else {
15067		if ((*cptr >> 4) < 10)
15068		    escape[1] = '0' + (*cptr >> 4);
15069		else
15070		    escape[1] = 'A' - 10 + (*cptr >> 4);
15071		if ((*cptr & 0xF) < 10)
15072		    escape[2] = '0' + (*cptr & 0xF);
15073		else
15074		    escape[2] = 'A' - 10 + (*cptr & 0xF);
15075
15076		xmlBufferAdd(target, &escape[0], 3);
15077	    }
15078	}
15079    }
15080    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15081	xmlBufferContent(target)));
15082    xmlBufferFree(target);
15083    xmlXPathReleaseObject(ctxt->context, str);
15084}
15085
15086/**
15087 * xmlXPathRegisterAllFunctions:
15088 * @ctxt:  the XPath context
15089 *
15090 * Registers all default XPath functions in this context
15091 */
15092void
15093xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15094{
15095    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15096                         xmlXPathBooleanFunction);
15097    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15098                         xmlXPathCeilingFunction);
15099    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15100                         xmlXPathCountFunction);
15101    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15102                         xmlXPathConcatFunction);
15103    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15104                         xmlXPathContainsFunction);
15105    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15106                         xmlXPathIdFunction);
15107    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15108                         xmlXPathFalseFunction);
15109    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15110                         xmlXPathFloorFunction);
15111    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15112                         xmlXPathLastFunction);
15113    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15114                         xmlXPathLangFunction);
15115    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15116                         xmlXPathLocalNameFunction);
15117    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15118                         xmlXPathNotFunction);
15119    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15120                         xmlXPathNameFunction);
15121    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15122                         xmlXPathNamespaceURIFunction);
15123    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15124                         xmlXPathNormalizeFunction);
15125    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15126                         xmlXPathNumberFunction);
15127    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15128                         xmlXPathPositionFunction);
15129    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15130                         xmlXPathRoundFunction);
15131    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15132                         xmlXPathStringFunction);
15133    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15134                         xmlXPathStringLengthFunction);
15135    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15136                         xmlXPathStartsWithFunction);
15137    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15138                         xmlXPathSubstringFunction);
15139    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15140                         xmlXPathSubstringBeforeFunction);
15141    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15142                         xmlXPathSubstringAfterFunction);
15143    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15144                         xmlXPathSumFunction);
15145    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15146                         xmlXPathTrueFunction);
15147    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15148                         xmlXPathTranslateFunction);
15149
15150    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15151	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15152                         xmlXPathEscapeUriFunction);
15153}
15154
15155#endif /* LIBXML_XPATH_ENABLED */
15156#define bottom_xpath
15157#include "elfgcchack.h"
15158