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			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			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			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, 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, 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, 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, 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, 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, shift);
957	fprintf(output, "Value Tree is NULL !\n");
958	return;
959
960    }
961
962    fprintf(output, 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, shift);
978	fprintf(output, "LocationSet is NULL !\n");
979	return;
980
981    }
982
983    for (i = 0;i < cur->locNr;i++) {
984	fprintf(output, 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, 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, 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, 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, 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, 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, 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
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
5022    if (ctxt->nsHash == NULL)
5023	ctxt->nsHash = xmlHashCreate(10);
5024    if (ctxt->nsHash == NULL)
5025	return(-1);
5026    if (ns_uri == NULL)
5027        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5028	                          (xmlHashDeallocator)xmlFree));
5029    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5030			      (xmlHashDeallocator)xmlFree));
5031}
5032
5033/**
5034 * xmlXPathNsLookup:
5035 * @ctxt:  the XPath context
5036 * @prefix:  the namespace prefix value
5037 *
5038 * Search in the namespace declaration array of the context for the given
5039 * namespace name associated to the given prefix
5040 *
5041 * Returns the value or NULL if not found
5042 */
5043const xmlChar *
5044xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5045    if (ctxt == NULL)
5046	return(NULL);
5047    if (prefix == NULL)
5048	return(NULL);
5049
5050#ifdef XML_XML_NAMESPACE
5051    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5052	return(XML_XML_NAMESPACE);
5053#endif
5054
5055    if (ctxt->namespaces != NULL) {
5056	int i;
5057
5058	for (i = 0;i < ctxt->nsNr;i++) {
5059	    if ((ctxt->namespaces[i] != NULL) &&
5060		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5061		return(ctxt->namespaces[i]->href);
5062	}
5063    }
5064
5065    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5066}
5067
5068/**
5069 * xmlXPathRegisteredNsCleanup:
5070 * @ctxt:  the XPath context
5071 *
5072 * Cleanup the XPath context data associated to registered variables
5073 */
5074void
5075xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5076    if (ctxt == NULL)
5077	return;
5078
5079    xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5080    ctxt->nsHash = NULL;
5081}
5082
5083/************************************************************************
5084 *									*
5085 *			Routines to handle Values			*
5086 *									*
5087 ************************************************************************/
5088
5089/* Allocations are terrible, one needs to optimize all this !!! */
5090
5091/**
5092 * xmlXPathNewFloat:
5093 * @val:  the double value
5094 *
5095 * Create a new xmlXPathObjectPtr of type double and of value @val
5096 *
5097 * Returns the newly created object.
5098 */
5099xmlXPathObjectPtr
5100xmlXPathNewFloat(double val) {
5101    xmlXPathObjectPtr ret;
5102
5103    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5104    if (ret == NULL) {
5105        xmlXPathErrMemory(NULL, "creating float object\n");
5106	return(NULL);
5107    }
5108    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5109    ret->type = XPATH_NUMBER;
5110    ret->floatval = val;
5111#ifdef XP_DEBUG_OBJ_USAGE
5112    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5113#endif
5114    return(ret);
5115}
5116
5117/**
5118 * xmlXPathNewBoolean:
5119 * @val:  the boolean value
5120 *
5121 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5122 *
5123 * Returns the newly created object.
5124 */
5125xmlXPathObjectPtr
5126xmlXPathNewBoolean(int val) {
5127    xmlXPathObjectPtr ret;
5128
5129    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5130    if (ret == NULL) {
5131        xmlXPathErrMemory(NULL, "creating boolean object\n");
5132	return(NULL);
5133    }
5134    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5135    ret->type = XPATH_BOOLEAN;
5136    ret->boolval = (val != 0);
5137#ifdef XP_DEBUG_OBJ_USAGE
5138    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5139#endif
5140    return(ret);
5141}
5142
5143/**
5144 * xmlXPathNewString:
5145 * @val:  the xmlChar * value
5146 *
5147 * Create a new xmlXPathObjectPtr of type string and of value @val
5148 *
5149 * Returns the newly created object.
5150 */
5151xmlXPathObjectPtr
5152xmlXPathNewString(const xmlChar *val) {
5153    xmlXPathObjectPtr ret;
5154
5155    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5156    if (ret == NULL) {
5157        xmlXPathErrMemory(NULL, "creating string object\n");
5158	return(NULL);
5159    }
5160    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5161    ret->type = XPATH_STRING;
5162    if (val != NULL)
5163	ret->stringval = xmlStrdup(val);
5164    else
5165	ret->stringval = xmlStrdup((const xmlChar *)"");
5166#ifdef XP_DEBUG_OBJ_USAGE
5167    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5168#endif
5169    return(ret);
5170}
5171
5172/**
5173 * xmlXPathWrapString:
5174 * @val:  the xmlChar * value
5175 *
5176 * Wraps the @val string into an XPath object.
5177 *
5178 * Returns the newly created object.
5179 */
5180xmlXPathObjectPtr
5181xmlXPathWrapString (xmlChar *val) {
5182    xmlXPathObjectPtr ret;
5183
5184    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5185    if (ret == NULL) {
5186        xmlXPathErrMemory(NULL, "creating string object\n");
5187	return(NULL);
5188    }
5189    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5190    ret->type = XPATH_STRING;
5191    ret->stringval = val;
5192#ifdef XP_DEBUG_OBJ_USAGE
5193    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5194#endif
5195    return(ret);
5196}
5197
5198/**
5199 * xmlXPathNewCString:
5200 * @val:  the char * value
5201 *
5202 * Create a new xmlXPathObjectPtr of type string and of value @val
5203 *
5204 * Returns the newly created object.
5205 */
5206xmlXPathObjectPtr
5207xmlXPathNewCString(const char *val) {
5208    xmlXPathObjectPtr ret;
5209
5210    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5211    if (ret == NULL) {
5212        xmlXPathErrMemory(NULL, "creating string object\n");
5213	return(NULL);
5214    }
5215    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5216    ret->type = XPATH_STRING;
5217    ret->stringval = xmlStrdup(BAD_CAST val);
5218#ifdef XP_DEBUG_OBJ_USAGE
5219    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5220#endif
5221    return(ret);
5222}
5223
5224/**
5225 * xmlXPathWrapCString:
5226 * @val:  the char * value
5227 *
5228 * Wraps a string into an XPath object.
5229 *
5230 * Returns the newly created object.
5231 */
5232xmlXPathObjectPtr
5233xmlXPathWrapCString (char * val) {
5234    return(xmlXPathWrapString((xmlChar *)(val)));
5235}
5236
5237/**
5238 * xmlXPathWrapExternal:
5239 * @val:  the user data
5240 *
5241 * Wraps the @val data into an XPath object.
5242 *
5243 * Returns the newly created object.
5244 */
5245xmlXPathObjectPtr
5246xmlXPathWrapExternal (void *val) {
5247    xmlXPathObjectPtr ret;
5248
5249    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5250    if (ret == NULL) {
5251        xmlXPathErrMemory(NULL, "creating user object\n");
5252	return(NULL);
5253    }
5254    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5255    ret->type = XPATH_USERS;
5256    ret->user = val;
5257#ifdef XP_DEBUG_OBJ_USAGE
5258    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5259#endif
5260    return(ret);
5261}
5262
5263/**
5264 * xmlXPathObjectCopy:
5265 * @val:  the original object
5266 *
5267 * allocate a new copy of a given object
5268 *
5269 * Returns the newly created object.
5270 */
5271xmlXPathObjectPtr
5272xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5273    xmlXPathObjectPtr ret;
5274
5275    if (val == NULL)
5276	return(NULL);
5277
5278    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5279    if (ret == NULL) {
5280        xmlXPathErrMemory(NULL, "copying object\n");
5281	return(NULL);
5282    }
5283    memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5284#ifdef XP_DEBUG_OBJ_USAGE
5285    xmlXPathDebugObjUsageRequested(NULL, val->type);
5286#endif
5287    switch (val->type) {
5288	case XPATH_BOOLEAN:
5289	case XPATH_NUMBER:
5290	case XPATH_POINT:
5291	case XPATH_RANGE:
5292	    break;
5293	case XPATH_STRING:
5294	    ret->stringval = xmlStrdup(val->stringval);
5295	    break;
5296	case XPATH_XSLT_TREE:
5297#if 0
5298/*
5299  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5300  this previous handling is no longer correct, and can cause some serious
5301  problems (ref. bug 145547)
5302*/
5303	    if ((val->nodesetval != NULL) &&
5304		(val->nodesetval->nodeTab != NULL)) {
5305		xmlNodePtr cur, tmp;
5306		xmlDocPtr top;
5307
5308		ret->boolval = 1;
5309		top =  xmlNewDoc(NULL);
5310		top->name = (char *)
5311		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5312		ret->user = top;
5313		if (top != NULL) {
5314		    top->doc = top;
5315		    cur = val->nodesetval->nodeTab[0]->children;
5316		    while (cur != NULL) {
5317			tmp = xmlDocCopyNode(cur, top, 1);
5318			xmlAddChild((xmlNodePtr) top, tmp);
5319			cur = cur->next;
5320		    }
5321		}
5322
5323		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5324	    } else
5325		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5326	    /* Deallocate the copied tree value */
5327	    break;
5328#endif
5329	case XPATH_NODESET:
5330	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5331	    /* Do not deallocate the copied tree value */
5332	    ret->boolval = 0;
5333	    break;
5334	case XPATH_LOCATIONSET:
5335#ifdef LIBXML_XPTR_ENABLED
5336	{
5337	    xmlLocationSetPtr loc = val->user;
5338	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5339	    break;
5340	}
5341#endif
5342        case XPATH_USERS:
5343	    ret->user = val->user;
5344	    break;
5345        case XPATH_UNDEFINED:
5346	    xmlGenericError(xmlGenericErrorContext,
5347		    "xmlXPathObjectCopy: unsupported type %d\n",
5348		    val->type);
5349	    break;
5350    }
5351    return(ret);
5352}
5353
5354/**
5355 * xmlXPathFreeObject:
5356 * @obj:  the object to free
5357 *
5358 * Free up an xmlXPathObjectPtr object.
5359 */
5360void
5361xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5362    if (obj == NULL) return;
5363    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5364	if (obj->boolval) {
5365#if 0
5366	    if (obj->user != NULL) {
5367                xmlXPathFreeNodeSet(obj->nodesetval);
5368		xmlFreeNodeList((xmlNodePtr) obj->user);
5369	    } else
5370#endif
5371	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5372	    if (obj->nodesetval != NULL)
5373		xmlXPathFreeValueTree(obj->nodesetval);
5374	} else {
5375	    if (obj->nodesetval != NULL)
5376		xmlXPathFreeNodeSet(obj->nodesetval);
5377	}
5378#ifdef LIBXML_XPTR_ENABLED
5379    } else if (obj->type == XPATH_LOCATIONSET) {
5380	if (obj->user != NULL)
5381	    xmlXPtrFreeLocationSet(obj->user);
5382#endif
5383    } else if (obj->type == XPATH_STRING) {
5384	if (obj->stringval != NULL)
5385	    xmlFree(obj->stringval);
5386    }
5387#ifdef XP_DEBUG_OBJ_USAGE
5388    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5389#endif
5390    xmlFree(obj);
5391}
5392
5393/**
5394 * xmlXPathReleaseObject:
5395 * @obj:  the xmlXPathObjectPtr to free or to cache
5396 *
5397 * Depending on the state of the cache this frees the given
5398 * XPath object or stores it in the cache.
5399 */
5400static void
5401xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5402{
5403#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5404	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5405    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5406
5407#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5408
5409    if (obj == NULL)
5410	return;
5411    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5412	 xmlXPathFreeObject(obj);
5413    } else {
5414	xmlXPathContextCachePtr cache =
5415	    (xmlXPathContextCachePtr) ctxt->cache;
5416
5417	switch (obj->type) {
5418	    case XPATH_NODESET:
5419	    case XPATH_XSLT_TREE:
5420		if (obj->nodesetval != NULL) {
5421		    if (obj->boolval) {
5422			/*
5423			* It looks like the @boolval is used for
5424			* evaluation if this an XSLT Result Tree Fragment.
5425			* TODO: Check if this assumption is correct.
5426			*/
5427			obj->type = XPATH_XSLT_TREE; /* just for debugging */
5428			xmlXPathFreeValueTree(obj->nodesetval);
5429			obj->nodesetval = NULL;
5430		    } else if ((obj->nodesetval->nodeMax <= 40) &&
5431			(XP_CACHE_WANTS(cache->nodesetObjs,
5432					cache->maxNodeset)))
5433		    {
5434			XP_CACHE_ADD(cache->nodesetObjs, obj);
5435			goto obj_cached;
5436		    } else {
5437			xmlXPathFreeNodeSet(obj->nodesetval);
5438			obj->nodesetval = NULL;
5439		    }
5440		}
5441		break;
5442	    case XPATH_STRING:
5443		if (obj->stringval != NULL)
5444		    xmlFree(obj->stringval);
5445
5446		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5447		    XP_CACHE_ADD(cache->stringObjs, obj);
5448		    goto obj_cached;
5449		}
5450		break;
5451	    case XPATH_BOOLEAN:
5452		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5453		    XP_CACHE_ADD(cache->booleanObjs, obj);
5454		    goto obj_cached;
5455		}
5456		break;
5457	    case XPATH_NUMBER:
5458		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5459		    XP_CACHE_ADD(cache->numberObjs, obj);
5460		    goto obj_cached;
5461		}
5462		break;
5463#ifdef LIBXML_XPTR_ENABLED
5464	    case XPATH_LOCATIONSET:
5465		if (obj->user != NULL) {
5466		    xmlXPtrFreeLocationSet(obj->user);
5467		}
5468		goto free_obj;
5469#endif
5470	    default:
5471		goto free_obj;
5472	}
5473
5474	/*
5475	* Fallback to adding to the misc-objects slot.
5476	*/
5477	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5478	    XP_CACHE_ADD(cache->miscObjs, obj);
5479	} else
5480	    goto free_obj;
5481
5482obj_cached:
5483
5484#ifdef XP_DEBUG_OBJ_USAGE
5485	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5486#endif
5487
5488	if (obj->nodesetval != NULL) {
5489	    xmlNodeSetPtr tmpset = obj->nodesetval;
5490
5491	    /*
5492	    * TODO: Due to those nasty ns-nodes, we need to traverse
5493	    *  the list and free the ns-nodes.
5494	    * URGENT TODO: Check if it's actually slowing things down.
5495	    *  Maybe we shouldn't try to preserve the list.
5496	    */
5497	    if (tmpset->nodeNr > 1) {
5498		int i;
5499		xmlNodePtr node;
5500
5501		for (i = 0; i < tmpset->nodeNr; i++) {
5502		    node = tmpset->nodeTab[i];
5503		    if ((node != NULL) &&
5504			(node->type == XML_NAMESPACE_DECL))
5505		    {
5506			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5507		    }
5508		}
5509	    } else if (tmpset->nodeNr == 1) {
5510		if ((tmpset->nodeTab[0] != NULL) &&
5511		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5512		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5513	    }
5514	    tmpset->nodeNr = 0;
5515	    memset(obj, 0, sizeof(xmlXPathObject));
5516	    obj->nodesetval = tmpset;
5517	} else
5518	    memset(obj, 0, sizeof(xmlXPathObject));
5519
5520	return;
5521
5522free_obj:
5523	/*
5524	* Cache is full; free the object.
5525	*/
5526	if (obj->nodesetval != NULL)
5527	    xmlXPathFreeNodeSet(obj->nodesetval);
5528#ifdef XP_DEBUG_OBJ_USAGE
5529	xmlXPathDebugObjUsageReleased(NULL, obj->type);
5530#endif
5531	xmlFree(obj);
5532    }
5533    return;
5534}
5535
5536
5537/************************************************************************
5538 *									*
5539 *			Type Casting Routines				*
5540 *									*
5541 ************************************************************************/
5542
5543/**
5544 * xmlXPathCastBooleanToString:
5545 * @val:  a boolean
5546 *
5547 * Converts a boolean to its string value.
5548 *
5549 * Returns a newly allocated string.
5550 */
5551xmlChar *
5552xmlXPathCastBooleanToString (int val) {
5553    xmlChar *ret;
5554    if (val)
5555	ret = xmlStrdup((const xmlChar *) "true");
5556    else
5557	ret = xmlStrdup((const xmlChar *) "false");
5558    return(ret);
5559}
5560
5561/**
5562 * xmlXPathCastNumberToString:
5563 * @val:  a number
5564 *
5565 * Converts a number to its string value.
5566 *
5567 * Returns a newly allocated string.
5568 */
5569xmlChar *
5570xmlXPathCastNumberToString (double val) {
5571    xmlChar *ret;
5572    switch (xmlXPathIsInf(val)) {
5573    case 1:
5574	ret = xmlStrdup((const xmlChar *) "Infinity");
5575	break;
5576    case -1:
5577	ret = xmlStrdup((const xmlChar *) "-Infinity");
5578	break;
5579    default:
5580	if (xmlXPathIsNaN(val)) {
5581	    ret = xmlStrdup((const xmlChar *) "NaN");
5582	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
5583	    ret = xmlStrdup((const xmlChar *) "0");
5584	} else {
5585	    /* could be improved */
5586	    char buf[100];
5587	    xmlXPathFormatNumber(val, buf, 99);
5588	    buf[99] = 0;
5589	    ret = xmlStrdup((const xmlChar *) buf);
5590	}
5591    }
5592    return(ret);
5593}
5594
5595/**
5596 * xmlXPathCastNodeToString:
5597 * @node:  a node
5598 *
5599 * Converts a node to its string value.
5600 *
5601 * Returns a newly allocated string.
5602 */
5603xmlChar *
5604xmlXPathCastNodeToString (xmlNodePtr node) {
5605xmlChar *ret;
5606    if ((ret = xmlNodeGetContent(node)) == NULL)
5607	ret = xmlStrdup((const xmlChar *) "");
5608    return(ret);
5609}
5610
5611/**
5612 * xmlXPathCastNodeSetToString:
5613 * @ns:  a node-set
5614 *
5615 * Converts a node-set to its string value.
5616 *
5617 * Returns a newly allocated string.
5618 */
5619xmlChar *
5620xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5621    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5622	return(xmlStrdup((const xmlChar *) ""));
5623
5624    if (ns->nodeNr > 1)
5625	xmlXPathNodeSetSort(ns);
5626    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5627}
5628
5629/**
5630 * xmlXPathCastToString:
5631 * @val:  an XPath object
5632 *
5633 * Converts an existing object to its string() equivalent
5634 *
5635 * Returns the allocated string value of the object, NULL in case of error.
5636 *         It's up to the caller to free the string memory with xmlFree().
5637 */
5638xmlChar *
5639xmlXPathCastToString(xmlXPathObjectPtr val) {
5640    xmlChar *ret = NULL;
5641
5642    if (val == NULL)
5643	return(xmlStrdup((const xmlChar *) ""));
5644    switch (val->type) {
5645	case XPATH_UNDEFINED:
5646#ifdef DEBUG_EXPR
5647	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5648#endif
5649	    ret = xmlStrdup((const xmlChar *) "");
5650	    break;
5651        case XPATH_NODESET:
5652        case XPATH_XSLT_TREE:
5653	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5654	    break;
5655	case XPATH_STRING:
5656	    return(xmlStrdup(val->stringval));
5657        case XPATH_BOOLEAN:
5658	    ret = xmlXPathCastBooleanToString(val->boolval);
5659	    break;
5660	case XPATH_NUMBER: {
5661	    ret = xmlXPathCastNumberToString(val->floatval);
5662	    break;
5663	}
5664	case XPATH_USERS:
5665	case XPATH_POINT:
5666	case XPATH_RANGE:
5667	case XPATH_LOCATIONSET:
5668	    TODO
5669	    ret = xmlStrdup((const xmlChar *) "");
5670	    break;
5671    }
5672    return(ret);
5673}
5674
5675/**
5676 * xmlXPathConvertString:
5677 * @val:  an XPath object
5678 *
5679 * Converts an existing object to its string() equivalent
5680 *
5681 * Returns the new object, the old one is freed (or the operation
5682 *         is done directly on @val)
5683 */
5684xmlXPathObjectPtr
5685xmlXPathConvertString(xmlXPathObjectPtr val) {
5686    xmlChar *res = NULL;
5687
5688    if (val == NULL)
5689	return(xmlXPathNewCString(""));
5690
5691    switch (val->type) {
5692    case XPATH_UNDEFINED:
5693#ifdef DEBUG_EXPR
5694	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5695#endif
5696	break;
5697    case XPATH_NODESET:
5698    case XPATH_XSLT_TREE:
5699	res = xmlXPathCastNodeSetToString(val->nodesetval);
5700	break;
5701    case XPATH_STRING:
5702	return(val);
5703    case XPATH_BOOLEAN:
5704	res = xmlXPathCastBooleanToString(val->boolval);
5705	break;
5706    case XPATH_NUMBER:
5707	res = xmlXPathCastNumberToString(val->floatval);
5708	break;
5709    case XPATH_USERS:
5710    case XPATH_POINT:
5711    case XPATH_RANGE:
5712    case XPATH_LOCATIONSET:
5713	TODO;
5714	break;
5715    }
5716    xmlXPathFreeObject(val);
5717    if (res == NULL)
5718	return(xmlXPathNewCString(""));
5719    return(xmlXPathWrapString(res));
5720}
5721
5722/**
5723 * xmlXPathCastBooleanToNumber:
5724 * @val:  a boolean
5725 *
5726 * Converts a boolean to its number value
5727 *
5728 * Returns the number value
5729 */
5730double
5731xmlXPathCastBooleanToNumber(int val) {
5732    if (val)
5733	return(1.0);
5734    return(0.0);
5735}
5736
5737/**
5738 * xmlXPathCastStringToNumber:
5739 * @val:  a string
5740 *
5741 * Converts a string to its number value
5742 *
5743 * Returns the number value
5744 */
5745double
5746xmlXPathCastStringToNumber(const xmlChar * val) {
5747    return(xmlXPathStringEvalNumber(val));
5748}
5749
5750/**
5751 * xmlXPathCastNodeToNumber:
5752 * @node:  a node
5753 *
5754 * Converts a node to its number value
5755 *
5756 * Returns the number value
5757 */
5758double
5759xmlXPathCastNodeToNumber (xmlNodePtr node) {
5760    xmlChar *strval;
5761    double ret;
5762
5763    if (node == NULL)
5764	return(xmlXPathNAN);
5765    strval = xmlXPathCastNodeToString(node);
5766    if (strval == NULL)
5767	return(xmlXPathNAN);
5768    ret = xmlXPathCastStringToNumber(strval);
5769    xmlFree(strval);
5770
5771    return(ret);
5772}
5773
5774/**
5775 * xmlXPathCastNodeSetToNumber:
5776 * @ns:  a node-set
5777 *
5778 * Converts a node-set to its number value
5779 *
5780 * Returns the number value
5781 */
5782double
5783xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5784    xmlChar *str;
5785    double ret;
5786
5787    if (ns == NULL)
5788	return(xmlXPathNAN);
5789    str = xmlXPathCastNodeSetToString(ns);
5790    ret = xmlXPathCastStringToNumber(str);
5791    xmlFree(str);
5792    return(ret);
5793}
5794
5795/**
5796 * xmlXPathCastToNumber:
5797 * @val:  an XPath object
5798 *
5799 * Converts an XPath object to its number value
5800 *
5801 * Returns the number value
5802 */
5803double
5804xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5805    double ret = 0.0;
5806
5807    if (val == NULL)
5808	return(xmlXPathNAN);
5809    switch (val->type) {
5810    case XPATH_UNDEFINED:
5811#ifdef DEGUB_EXPR
5812	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5813#endif
5814	ret = xmlXPathNAN;
5815	break;
5816    case XPATH_NODESET:
5817    case XPATH_XSLT_TREE:
5818	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5819	break;
5820    case XPATH_STRING:
5821	ret = xmlXPathCastStringToNumber(val->stringval);
5822	break;
5823    case XPATH_NUMBER:
5824	ret = val->floatval;
5825	break;
5826    case XPATH_BOOLEAN:
5827	ret = xmlXPathCastBooleanToNumber(val->boolval);
5828	break;
5829    case XPATH_USERS:
5830    case XPATH_POINT:
5831    case XPATH_RANGE:
5832    case XPATH_LOCATIONSET:
5833	TODO;
5834	ret = xmlXPathNAN;
5835	break;
5836    }
5837    return(ret);
5838}
5839
5840/**
5841 * xmlXPathConvertNumber:
5842 * @val:  an XPath object
5843 *
5844 * Converts an existing object to its number() equivalent
5845 *
5846 * Returns the new object, the old one is freed (or the operation
5847 *         is done directly on @val)
5848 */
5849xmlXPathObjectPtr
5850xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5851    xmlXPathObjectPtr ret;
5852
5853    if (val == NULL)
5854	return(xmlXPathNewFloat(0.0));
5855    if (val->type == XPATH_NUMBER)
5856	return(val);
5857    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5858    xmlXPathFreeObject(val);
5859    return(ret);
5860}
5861
5862/**
5863 * xmlXPathCastNumberToBoolean:
5864 * @val:  a number
5865 *
5866 * Converts a number to its boolean value
5867 *
5868 * Returns the boolean value
5869 */
5870int
5871xmlXPathCastNumberToBoolean (double val) {
5872     if (xmlXPathIsNaN(val) || (val == 0.0))
5873	 return(0);
5874     return(1);
5875}
5876
5877/**
5878 * xmlXPathCastStringToBoolean:
5879 * @val:  a string
5880 *
5881 * Converts a string to its boolean value
5882 *
5883 * Returns the boolean value
5884 */
5885int
5886xmlXPathCastStringToBoolean (const xmlChar *val) {
5887    if ((val == NULL) || (xmlStrlen(val) == 0))
5888	return(0);
5889    return(1);
5890}
5891
5892/**
5893 * xmlXPathCastNodeSetToBoolean:
5894 * @ns:  a node-set
5895 *
5896 * Converts a node-set to its boolean value
5897 *
5898 * Returns the boolean value
5899 */
5900int
5901xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5902    if ((ns == NULL) || (ns->nodeNr == 0))
5903	return(0);
5904    return(1);
5905}
5906
5907/**
5908 * xmlXPathCastToBoolean:
5909 * @val:  an XPath object
5910 *
5911 * Converts an XPath object to its boolean value
5912 *
5913 * Returns the boolean value
5914 */
5915int
5916xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5917    int ret = 0;
5918
5919    if (val == NULL)
5920	return(0);
5921    switch (val->type) {
5922    case XPATH_UNDEFINED:
5923#ifdef DEBUG_EXPR
5924	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5925#endif
5926	ret = 0;
5927	break;
5928    case XPATH_NODESET:
5929    case XPATH_XSLT_TREE:
5930	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5931	break;
5932    case XPATH_STRING:
5933	ret = xmlXPathCastStringToBoolean(val->stringval);
5934	break;
5935    case XPATH_NUMBER:
5936	ret = xmlXPathCastNumberToBoolean(val->floatval);
5937	break;
5938    case XPATH_BOOLEAN:
5939	ret = val->boolval;
5940	break;
5941    case XPATH_USERS:
5942    case XPATH_POINT:
5943    case XPATH_RANGE:
5944    case XPATH_LOCATIONSET:
5945	TODO;
5946	ret = 0;
5947	break;
5948    }
5949    return(ret);
5950}
5951
5952
5953/**
5954 * xmlXPathConvertBoolean:
5955 * @val:  an XPath object
5956 *
5957 * Converts an existing object to its boolean() equivalent
5958 *
5959 * Returns the new object, the old one is freed (or the operation
5960 *         is done directly on @val)
5961 */
5962xmlXPathObjectPtr
5963xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5964    xmlXPathObjectPtr ret;
5965
5966    if (val == NULL)
5967	return(xmlXPathNewBoolean(0));
5968    if (val->type == XPATH_BOOLEAN)
5969	return(val);
5970    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5971    xmlXPathFreeObject(val);
5972    return(ret);
5973}
5974
5975/************************************************************************
5976 *									*
5977 *		Routines to handle XPath contexts			*
5978 *									*
5979 ************************************************************************/
5980
5981/**
5982 * xmlXPathNewContext:
5983 * @doc:  the XML document
5984 *
5985 * Create a new xmlXPathContext
5986 *
5987 * Returns the xmlXPathContext just allocated. The caller will need to free it.
5988 */
5989xmlXPathContextPtr
5990xmlXPathNewContext(xmlDocPtr doc) {
5991    xmlXPathContextPtr ret;
5992
5993    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5994    if (ret == NULL) {
5995        xmlXPathErrMemory(NULL, "creating context\n");
5996	return(NULL);
5997    }
5998    memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5999    ret->doc = doc;
6000    ret->node = NULL;
6001
6002    ret->varHash = NULL;
6003
6004    ret->nb_types = 0;
6005    ret->max_types = 0;
6006    ret->types = NULL;
6007
6008    ret->funcHash = xmlHashCreate(0);
6009
6010    ret->nb_axis = 0;
6011    ret->max_axis = 0;
6012    ret->axis = NULL;
6013
6014    ret->nsHash = NULL;
6015    ret->user = NULL;
6016
6017    ret->contextSize = -1;
6018    ret->proximityPosition = -1;
6019
6020#ifdef XP_DEFAULT_CACHE_ON
6021    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6022	xmlXPathFreeContext(ret);
6023	return(NULL);
6024    }
6025#endif
6026
6027    xmlXPathRegisterAllFunctions(ret);
6028
6029    return(ret);
6030}
6031
6032/**
6033 * xmlXPathFreeContext:
6034 * @ctxt:  the context to free
6035 *
6036 * Free up an xmlXPathContext
6037 */
6038void
6039xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6040    if (ctxt == NULL) return;
6041
6042    if (ctxt->cache != NULL)
6043	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6044    xmlXPathRegisteredNsCleanup(ctxt);
6045    xmlXPathRegisteredFuncsCleanup(ctxt);
6046    xmlXPathRegisteredVariablesCleanup(ctxt);
6047    xmlResetError(&ctxt->lastError);
6048    xmlFree(ctxt);
6049}
6050
6051/************************************************************************
6052 *									*
6053 *		Routines to handle XPath parser contexts		*
6054 *									*
6055 ************************************************************************/
6056
6057#define CHECK_CTXT(ctxt)						\
6058    if (ctxt == NULL) {						\
6059	__xmlRaiseError(NULL, NULL, NULL,				\
6060		NULL, NULL, XML_FROM_XPATH,				\
6061		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6062		__FILE__, __LINE__,					\
6063		NULL, NULL, NULL, 0, 0,					\
6064		"NULL context pointer\n");				\
6065	return(NULL);							\
6066    }									\
6067
6068#define CHECK_CTXT_NEG(ctxt)						\
6069    if (ctxt == NULL) {						\
6070	__xmlRaiseError(NULL, NULL, NULL,				\
6071		NULL, NULL, XML_FROM_XPATH,				\
6072		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6073		__FILE__, __LINE__,					\
6074		NULL, NULL, NULL, 0, 0,					\
6075		"NULL context pointer\n");				\
6076	return(-1);							\
6077    }									\
6078
6079
6080#define CHECK_CONTEXT(ctxt)						\
6081    if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
6082        (ctxt->doc->children == NULL)) {				\
6083	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
6084	return(NULL);							\
6085    }
6086
6087
6088/**
6089 * xmlXPathNewParserContext:
6090 * @str:  the XPath expression
6091 * @ctxt:  the XPath context
6092 *
6093 * Create a new xmlXPathParserContext
6094 *
6095 * Returns the xmlXPathParserContext just allocated.
6096 */
6097xmlXPathParserContextPtr
6098xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6099    xmlXPathParserContextPtr ret;
6100
6101    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6102    if (ret == NULL) {
6103        xmlXPathErrMemory(ctxt, "creating parser context\n");
6104	return(NULL);
6105    }
6106    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6107    ret->cur = ret->base = str;
6108    ret->context = ctxt;
6109
6110    ret->comp = xmlXPathNewCompExpr();
6111    if (ret->comp == NULL) {
6112	xmlFree(ret->valueTab);
6113	xmlFree(ret);
6114	return(NULL);
6115    }
6116    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6117        ret->comp->dict = ctxt->dict;
6118	xmlDictReference(ret->comp->dict);
6119    }
6120
6121    return(ret);
6122}
6123
6124/**
6125 * xmlXPathCompParserContext:
6126 * @comp:  the XPath compiled expression
6127 * @ctxt:  the XPath context
6128 *
6129 * Create a new xmlXPathParserContext when processing a compiled expression
6130 *
6131 * Returns the xmlXPathParserContext just allocated.
6132 */
6133static xmlXPathParserContextPtr
6134xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6135    xmlXPathParserContextPtr ret;
6136
6137    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6138    if (ret == NULL) {
6139        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6140	return(NULL);
6141    }
6142    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6143
6144    /* Allocate the value stack */
6145    ret->valueTab = (xmlXPathObjectPtr *)
6146                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6147    if (ret->valueTab == NULL) {
6148	xmlFree(ret);
6149	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6150	return(NULL);
6151    }
6152    ret->valueNr = 0;
6153    ret->valueMax = 10;
6154    ret->value = NULL;
6155
6156    ret->context = ctxt;
6157    ret->comp = comp;
6158
6159    return(ret);
6160}
6161
6162/**
6163 * xmlXPathFreeParserContext:
6164 * @ctxt:  the context to free
6165 *
6166 * Free up an xmlXPathParserContext
6167 */
6168void
6169xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6170    if (ctxt->valueTab != NULL) {
6171        xmlFree(ctxt->valueTab);
6172    }
6173    if (ctxt->comp != NULL) {
6174#ifdef XPATH_STREAMING
6175	if (ctxt->comp->stream != NULL) {
6176	    xmlFreePatternList(ctxt->comp->stream);
6177	    ctxt->comp->stream = NULL;
6178	}
6179#endif
6180	xmlXPathFreeCompExpr(ctxt->comp);
6181    }
6182    xmlFree(ctxt);
6183}
6184
6185/************************************************************************
6186 *									*
6187 *		The implicit core function library			*
6188 *									*
6189 ************************************************************************/
6190
6191/**
6192 * xmlXPathNodeValHash:
6193 * @node:  a node pointer
6194 *
6195 * Function computing the beginning of the string value of the node,
6196 * used to speed up comparisons
6197 *
6198 * Returns an int usable as a hash
6199 */
6200static unsigned int
6201xmlXPathNodeValHash(xmlNodePtr node) {
6202    int len = 2;
6203    const xmlChar * string = NULL;
6204    xmlNodePtr tmp = NULL;
6205    unsigned int ret = 0;
6206
6207    if (node == NULL)
6208	return(0);
6209
6210    if (node->type == XML_DOCUMENT_NODE) {
6211	tmp = xmlDocGetRootElement((xmlDocPtr) node);
6212	if (tmp == NULL)
6213	    node = node->children;
6214	else
6215	    node = tmp;
6216
6217	if (node == NULL)
6218	    return(0);
6219    }
6220
6221    switch (node->type) {
6222	case XML_COMMENT_NODE:
6223	case XML_PI_NODE:
6224	case XML_CDATA_SECTION_NODE:
6225	case XML_TEXT_NODE:
6226	    string = node->content;
6227	    if (string == NULL)
6228		return(0);
6229	    if (string[0] == 0)
6230		return(0);
6231	    return(((unsigned int) string[0]) +
6232		   (((unsigned int) string[1]) << 8));
6233	case XML_NAMESPACE_DECL:
6234	    string = ((xmlNsPtr)node)->href;
6235	    if (string == NULL)
6236		return(0);
6237	    if (string[0] == 0)
6238		return(0);
6239	    return(((unsigned int) string[0]) +
6240		   (((unsigned int) string[1]) << 8));
6241	case XML_ATTRIBUTE_NODE:
6242	    tmp = ((xmlAttrPtr) node)->children;
6243	    break;
6244	case XML_ELEMENT_NODE:
6245	    tmp = node->children;
6246	    break;
6247	default:
6248	    return(0);
6249    }
6250    while (tmp != NULL) {
6251	switch (tmp->type) {
6252	    case XML_COMMENT_NODE:
6253	    case XML_PI_NODE:
6254	    case XML_CDATA_SECTION_NODE:
6255	    case XML_TEXT_NODE:
6256		string = tmp->content;
6257		break;
6258	    case XML_NAMESPACE_DECL:
6259		string = ((xmlNsPtr)tmp)->href;
6260		break;
6261	    default:
6262		break;
6263	}
6264	if ((string != NULL) && (string[0] != 0)) {
6265	    if (len == 1) {
6266		return(ret + (((unsigned int) string[0]) << 8));
6267	    }
6268	    if (string[1] == 0) {
6269		len = 1;
6270		ret = (unsigned int) string[0];
6271	    } else {
6272		return(((unsigned int) string[0]) +
6273		       (((unsigned int) string[1]) << 8));
6274	    }
6275	}
6276	/*
6277	 * Skip to next node
6278	 */
6279	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6280	    if (tmp->children->type != XML_ENTITY_DECL) {
6281		tmp = tmp->children;
6282		continue;
6283	    }
6284	}
6285	if (tmp == node)
6286	    break;
6287
6288	if (tmp->next != NULL) {
6289	    tmp = tmp->next;
6290	    continue;
6291	}
6292
6293	do {
6294	    tmp = tmp->parent;
6295	    if (tmp == NULL)
6296		break;
6297	    if (tmp == node) {
6298		tmp = NULL;
6299		break;
6300	    }
6301	    if (tmp->next != NULL) {
6302		tmp = tmp->next;
6303		break;
6304	    }
6305	} while (tmp != NULL);
6306    }
6307    return(ret);
6308}
6309
6310/**
6311 * xmlXPathStringHash:
6312 * @string:  a string
6313 *
6314 * Function computing the beginning of the string value of the node,
6315 * used to speed up comparisons
6316 *
6317 * Returns an int usable as a hash
6318 */
6319static unsigned int
6320xmlXPathStringHash(const xmlChar * string) {
6321    if (string == NULL)
6322	return((unsigned int) 0);
6323    if (string[0] == 0)
6324	return(0);
6325    return(((unsigned int) string[0]) +
6326	   (((unsigned int) string[1]) << 8));
6327}
6328
6329/**
6330 * xmlXPathCompareNodeSetFloat:
6331 * @ctxt:  the XPath Parser context
6332 * @inf:  less than (1) or greater than (0)
6333 * @strict:  is the comparison strict
6334 * @arg:  the node set
6335 * @f:  the value
6336 *
6337 * Implement the compare operation between a nodeset and a number
6338 *     @ns < @val    (1, 1, ...
6339 *     @ns <= @val   (1, 0, ...
6340 *     @ns > @val    (0, 1, ...
6341 *     @ns >= @val   (0, 0, ...
6342 *
6343 * If one object to be compared is a node-set and the other is a number,
6344 * then the comparison will be true if and only if there is a node in the
6345 * node-set such that the result of performing the comparison on the number
6346 * to be compared and on the result of converting the string-value of that
6347 * node to a number using the number function is true.
6348 *
6349 * Returns 0 or 1 depending on the results of the test.
6350 */
6351static int
6352xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6353	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6354    int i, ret = 0;
6355    xmlNodeSetPtr ns;
6356    xmlChar *str2;
6357
6358    if ((f == NULL) || (arg == NULL) ||
6359	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6360	xmlXPathReleaseObject(ctxt->context, arg);
6361	xmlXPathReleaseObject(ctxt->context, f);
6362        return(0);
6363    }
6364    ns = arg->nodesetval;
6365    if (ns != NULL) {
6366	for (i = 0;i < ns->nodeNr;i++) {
6367	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6368	     if (str2 != NULL) {
6369		 valuePush(ctxt,
6370			   xmlXPathCacheNewString(ctxt->context, str2));
6371		 xmlFree(str2);
6372		 xmlXPathNumberFunction(ctxt, 1);
6373		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6374		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6375		 if (ret)
6376		     break;
6377	     }
6378	}
6379    }
6380    xmlXPathReleaseObject(ctxt->context, arg);
6381    xmlXPathReleaseObject(ctxt->context, f);
6382    return(ret);
6383}
6384
6385/**
6386 * xmlXPathCompareNodeSetString:
6387 * @ctxt:  the XPath Parser context
6388 * @inf:  less than (1) or greater than (0)
6389 * @strict:  is the comparison strict
6390 * @arg:  the node set
6391 * @s:  the value
6392 *
6393 * Implement the compare operation between a nodeset and a string
6394 *     @ns < @val    (1, 1, ...
6395 *     @ns <= @val   (1, 0, ...
6396 *     @ns > @val    (0, 1, ...
6397 *     @ns >= @val   (0, 0, ...
6398 *
6399 * If one object to be compared is a node-set and the other is a string,
6400 * then the comparison will be true if and only if there is a node in
6401 * the node-set such that the result of performing the comparison on the
6402 * string-value of the node and the other string is true.
6403 *
6404 * Returns 0 or 1 depending on the results of the test.
6405 */
6406static int
6407xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6408	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6409    int i, ret = 0;
6410    xmlNodeSetPtr ns;
6411    xmlChar *str2;
6412
6413    if ((s == NULL) || (arg == NULL) ||
6414	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6415	xmlXPathReleaseObject(ctxt->context, arg);
6416	xmlXPathReleaseObject(ctxt->context, s);
6417        return(0);
6418    }
6419    ns = arg->nodesetval;
6420    if (ns != NULL) {
6421	for (i = 0;i < ns->nodeNr;i++) {
6422	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6423	     if (str2 != NULL) {
6424		 valuePush(ctxt,
6425			   xmlXPathCacheNewString(ctxt->context, str2));
6426		 xmlFree(str2);
6427		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6428		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6429		 if (ret)
6430		     break;
6431	     }
6432	}
6433    }
6434    xmlXPathReleaseObject(ctxt->context, arg);
6435    xmlXPathReleaseObject(ctxt->context, s);
6436    return(ret);
6437}
6438
6439/**
6440 * xmlXPathCompareNodeSets:
6441 * @inf:  less than (1) or greater than (0)
6442 * @strict:  is the comparison strict
6443 * @arg1:  the first node set object
6444 * @arg2:  the second node set object
6445 *
6446 * Implement the compare operation on nodesets:
6447 *
6448 * If both objects to be compared are node-sets, then the comparison
6449 * will be true if and only if there is a node in the first node-set
6450 * and a node in the second node-set such that the result of performing
6451 * the comparison on the string-values of the two nodes is true.
6452 * ....
6453 * When neither object to be compared is a node-set and the operator
6454 * is <=, <, >= or >, then the objects are compared by converting both
6455 * objects to numbers and comparing the numbers according to IEEE 754.
6456 * ....
6457 * The number function converts its argument to a number as follows:
6458 *  - a string that consists of optional whitespace followed by an
6459 *    optional minus sign followed by a Number followed by whitespace
6460 *    is converted to the IEEE 754 number that is nearest (according
6461 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6462 *    represented by the string; any other string is converted to NaN
6463 *
6464 * Conclusion all nodes need to be converted first to their string value
6465 * and then the comparison must be done when possible
6466 */
6467static int
6468xmlXPathCompareNodeSets(int inf, int strict,
6469	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6470    int i, j, init = 0;
6471    double val1;
6472    double *values2;
6473    int ret = 0;
6474    xmlNodeSetPtr ns1;
6475    xmlNodeSetPtr ns2;
6476
6477    if ((arg1 == NULL) ||
6478	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6479	xmlXPathFreeObject(arg2);
6480        return(0);
6481    }
6482    if ((arg2 == NULL) ||
6483	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6484	xmlXPathFreeObject(arg1);
6485	xmlXPathFreeObject(arg2);
6486        return(0);
6487    }
6488
6489    ns1 = arg1->nodesetval;
6490    ns2 = arg2->nodesetval;
6491
6492    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6493	xmlXPathFreeObject(arg1);
6494	xmlXPathFreeObject(arg2);
6495	return(0);
6496    }
6497    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6498	xmlXPathFreeObject(arg1);
6499	xmlXPathFreeObject(arg2);
6500	return(0);
6501    }
6502
6503    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6504    if (values2 == NULL) {
6505        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6506	xmlXPathFreeObject(arg1);
6507	xmlXPathFreeObject(arg2);
6508	return(0);
6509    }
6510    for (i = 0;i < ns1->nodeNr;i++) {
6511	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6512	if (xmlXPathIsNaN(val1))
6513	    continue;
6514	for (j = 0;j < ns2->nodeNr;j++) {
6515	    if (init == 0) {
6516		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6517	    }
6518	    if (xmlXPathIsNaN(values2[j]))
6519		continue;
6520	    if (inf && strict)
6521		ret = (val1 < values2[j]);
6522	    else 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	    if (ret)
6529		break;
6530	}
6531	if (ret)
6532	    break;
6533	init = 1;
6534    }
6535    xmlFree(values2);
6536    xmlXPathFreeObject(arg1);
6537    xmlXPathFreeObject(arg2);
6538    return(ret);
6539}
6540
6541/**
6542 * xmlXPathCompareNodeSetValue:
6543 * @ctxt:  the XPath Parser context
6544 * @inf:  less than (1) or greater than (0)
6545 * @strict:  is the comparison strict
6546 * @arg:  the node set
6547 * @val:  the value
6548 *
6549 * Implement the compare operation between a nodeset and a value
6550 *     @ns < @val    (1, 1, ...
6551 *     @ns <= @val   (1, 0, ...
6552 *     @ns > @val    (0, 1, ...
6553 *     @ns >= @val   (0, 0, ...
6554 *
6555 * If one object to be compared is a node-set and the other is a boolean,
6556 * then the comparison will be true if and only if the result of performing
6557 * the comparison on the boolean and on the result of converting
6558 * the node-set to a boolean using the boolean function is true.
6559 *
6560 * Returns 0 or 1 depending on the results of the test.
6561 */
6562static int
6563xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6564	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6565    if ((val == NULL) || (arg == NULL) ||
6566	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6567        return(0);
6568
6569    switch(val->type) {
6570        case XPATH_NUMBER:
6571	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6572        case XPATH_NODESET:
6573        case XPATH_XSLT_TREE:
6574	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6575        case XPATH_STRING:
6576	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6577        case XPATH_BOOLEAN:
6578	    valuePush(ctxt, arg);
6579	    xmlXPathBooleanFunction(ctxt, 1);
6580	    valuePush(ctxt, val);
6581	    return(xmlXPathCompareValues(ctxt, inf, strict));
6582	default:
6583	    TODO
6584    }
6585    return(0);
6586}
6587
6588/**
6589 * xmlXPathEqualNodeSetString:
6590 * @arg:  the nodeset object argument
6591 * @str:  the string to compare to.
6592 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6593 *
6594 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6595 * If one object to be compared is a node-set and the other is a string,
6596 * then the comparison will be true if and only if there is a node in
6597 * the node-set such that the result of performing the comparison on the
6598 * string-value of the node and the other string is true.
6599 *
6600 * Returns 0 or 1 depending on the results of the test.
6601 */
6602static int
6603xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6604{
6605    int i;
6606    xmlNodeSetPtr ns;
6607    xmlChar *str2;
6608    unsigned int hash;
6609
6610    if ((str == NULL) || (arg == NULL) ||
6611        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6612        return (0);
6613    ns = arg->nodesetval;
6614    /*
6615     * A NULL nodeset compared with a string is always false
6616     * (since there is no node equal, and no node not equal)
6617     */
6618    if ((ns == NULL) || (ns->nodeNr <= 0) )
6619        return (0);
6620    hash = xmlXPathStringHash(str);
6621    for (i = 0; i < ns->nodeNr; i++) {
6622        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6623            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6624            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6625                xmlFree(str2);
6626		if (neq)
6627		    continue;
6628                return (1);
6629	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6630		if (neq)
6631		    continue;
6632                return (1);
6633            } else if (neq) {
6634		if (str2 != NULL)
6635		    xmlFree(str2);
6636		return (1);
6637	    }
6638            if (str2 != NULL)
6639                xmlFree(str2);
6640        } else if (neq)
6641	    return (1);
6642    }
6643    return (0);
6644}
6645
6646/**
6647 * xmlXPathEqualNodeSetFloat:
6648 * @arg:  the nodeset object argument
6649 * @f:  the float to compare to
6650 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6651 *
6652 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6653 * If one object to be compared is a node-set and the other is a number,
6654 * then the comparison will be true if and only if there is a node in
6655 * the node-set such that the result of performing the comparison on the
6656 * number to be compared and on the result of converting the string-value
6657 * of that node to a number using the number function is true.
6658 *
6659 * Returns 0 or 1 depending on the results of the test.
6660 */
6661static int
6662xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6663    xmlXPathObjectPtr arg, double f, int neq) {
6664  int i, ret=0;
6665  xmlNodeSetPtr ns;
6666  xmlChar *str2;
6667  xmlXPathObjectPtr val;
6668  double v;
6669
6670    if ((arg == NULL) ||
6671	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6672        return(0);
6673
6674    ns = arg->nodesetval;
6675    if (ns != NULL) {
6676	for (i=0;i<ns->nodeNr;i++) {
6677	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6678	    if (str2 != NULL) {
6679		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6680		xmlFree(str2);
6681		xmlXPathNumberFunction(ctxt, 1);
6682		val = valuePop(ctxt);
6683		v = val->floatval;
6684		xmlXPathReleaseObject(ctxt->context, val);
6685		if (!xmlXPathIsNaN(v)) {
6686		    if ((!neq) && (v==f)) {
6687			ret = 1;
6688			break;
6689		    } else if ((neq) && (v!=f)) {
6690			ret = 1;
6691			break;
6692		    }
6693		} else {	/* NaN is unequal to any value */
6694		    if (neq)
6695			ret = 1;
6696		}
6697	    }
6698	}
6699    }
6700
6701    return(ret);
6702}
6703
6704
6705/**
6706 * xmlXPathEqualNodeSets:
6707 * @arg1:  first nodeset object argument
6708 * @arg2:  second nodeset object argument
6709 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6710 *
6711 * Implement the equal / not equal operation on XPath nodesets:
6712 * @arg1 == @arg2  or  @arg1 != @arg2
6713 * If both objects to be compared are node-sets, then the comparison
6714 * will be true if and only if there is a node in the first node-set and
6715 * a node in the second node-set such that the result of performing the
6716 * comparison on the string-values of the two nodes is true.
6717 *
6718 * (needless to say, this is a costly operation)
6719 *
6720 * Returns 0 or 1 depending on the results of the test.
6721 */
6722static int
6723xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6724    int i, j;
6725    unsigned int *hashs1;
6726    unsigned int *hashs2;
6727    xmlChar **values1;
6728    xmlChar **values2;
6729    int ret = 0;
6730    xmlNodeSetPtr ns1;
6731    xmlNodeSetPtr ns2;
6732
6733    if ((arg1 == NULL) ||
6734	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6735        return(0);
6736    if ((arg2 == NULL) ||
6737	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6738        return(0);
6739
6740    ns1 = arg1->nodesetval;
6741    ns2 = arg2->nodesetval;
6742
6743    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6744	return(0);
6745    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6746	return(0);
6747
6748    /*
6749     * for equal, check if there is a node pertaining to both sets
6750     */
6751    if (neq == 0)
6752	for (i = 0;i < ns1->nodeNr;i++)
6753	    for (j = 0;j < ns2->nodeNr;j++)
6754		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6755		    return(1);
6756
6757    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6758    if (values1 == NULL) {
6759        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6760	return(0);
6761    }
6762    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6763    if (hashs1 == NULL) {
6764        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6765	xmlFree(values1);
6766	return(0);
6767    }
6768    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6769    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6770    if (values2 == NULL) {
6771        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6772	xmlFree(hashs1);
6773	xmlFree(values1);
6774	return(0);
6775    }
6776    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6777    if (hashs2 == NULL) {
6778        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6779	xmlFree(hashs1);
6780	xmlFree(values1);
6781	xmlFree(values2);
6782	return(0);
6783    }
6784    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6785    for (i = 0;i < ns1->nodeNr;i++) {
6786	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6787	for (j = 0;j < ns2->nodeNr;j++) {
6788	    if (i == 0)
6789		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6790	    if (hashs1[i] != hashs2[j]) {
6791		if (neq) {
6792		    ret = 1;
6793		    break;
6794		}
6795	    }
6796	    else {
6797		if (values1[i] == NULL)
6798		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6799		if (values2[j] == NULL)
6800		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6801		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6802		if (ret)
6803		    break;
6804	    }
6805	}
6806	if (ret)
6807	    break;
6808    }
6809    for (i = 0;i < ns1->nodeNr;i++)
6810	if (values1[i] != NULL)
6811	    xmlFree(values1[i]);
6812    for (j = 0;j < ns2->nodeNr;j++)
6813	if (values2[j] != NULL)
6814	    xmlFree(values2[j]);
6815    xmlFree(values1);
6816    xmlFree(values2);
6817    xmlFree(hashs1);
6818    xmlFree(hashs2);
6819    return(ret);
6820}
6821
6822static int
6823xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6824  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6825    int ret = 0;
6826    /*
6827     *At this point we are assured neither arg1 nor arg2
6828     *is a nodeset, so we can just pick the appropriate routine.
6829     */
6830    switch (arg1->type) {
6831        case XPATH_UNDEFINED:
6832#ifdef DEBUG_EXPR
6833	    xmlGenericError(xmlGenericErrorContext,
6834		    "Equal: undefined\n");
6835#endif
6836	    break;
6837        case XPATH_BOOLEAN:
6838	    switch (arg2->type) {
6839	        case XPATH_UNDEFINED:
6840#ifdef DEBUG_EXPR
6841		    xmlGenericError(xmlGenericErrorContext,
6842			    "Equal: undefined\n");
6843#endif
6844		    break;
6845		case XPATH_BOOLEAN:
6846#ifdef DEBUG_EXPR
6847		    xmlGenericError(xmlGenericErrorContext,
6848			    "Equal: %d boolean %d \n",
6849			    arg1->boolval, arg2->boolval);
6850#endif
6851		    ret = (arg1->boolval == arg2->boolval);
6852		    break;
6853		case XPATH_NUMBER:
6854		    ret = (arg1->boolval ==
6855			   xmlXPathCastNumberToBoolean(arg2->floatval));
6856		    break;
6857		case XPATH_STRING:
6858		    if ((arg2->stringval == NULL) ||
6859			(arg2->stringval[0] == 0)) ret = 0;
6860		    else
6861			ret = 1;
6862		    ret = (arg1->boolval == ret);
6863		    break;
6864		case XPATH_USERS:
6865		case XPATH_POINT:
6866		case XPATH_RANGE:
6867		case XPATH_LOCATIONSET:
6868		    TODO
6869		    break;
6870		case XPATH_NODESET:
6871		case XPATH_XSLT_TREE:
6872		    break;
6873	    }
6874	    break;
6875        case XPATH_NUMBER:
6876	    switch (arg2->type) {
6877	        case XPATH_UNDEFINED:
6878#ifdef DEBUG_EXPR
6879		    xmlGenericError(xmlGenericErrorContext,
6880			    "Equal: undefined\n");
6881#endif
6882		    break;
6883		case XPATH_BOOLEAN:
6884		    ret = (arg2->boolval==
6885			   xmlXPathCastNumberToBoolean(arg1->floatval));
6886		    break;
6887		case XPATH_STRING:
6888		    valuePush(ctxt, arg2);
6889		    xmlXPathNumberFunction(ctxt, 1);
6890		    arg2 = valuePop(ctxt);
6891		    /* no break on purpose */
6892		case XPATH_NUMBER:
6893		    /* Hand check NaN and Infinity equalities */
6894		    if (xmlXPathIsNaN(arg1->floatval) ||
6895			    xmlXPathIsNaN(arg2->floatval)) {
6896		        ret = 0;
6897		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6898		        if (xmlXPathIsInf(arg2->floatval) == 1)
6899			    ret = 1;
6900			else
6901			    ret = 0;
6902		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6903			if (xmlXPathIsInf(arg2->floatval) == -1)
6904			    ret = 1;
6905			else
6906			    ret = 0;
6907		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6908			if (xmlXPathIsInf(arg1->floatval) == 1)
6909			    ret = 1;
6910			else
6911			    ret = 0;
6912		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6913			if (xmlXPathIsInf(arg1->floatval) == -1)
6914			    ret = 1;
6915			else
6916			    ret = 0;
6917		    } else {
6918		        ret = (arg1->floatval == arg2->floatval);
6919		    }
6920		    break;
6921		case XPATH_USERS:
6922		case XPATH_POINT:
6923		case XPATH_RANGE:
6924		case XPATH_LOCATIONSET:
6925		    TODO
6926		    break;
6927		case XPATH_NODESET:
6928		case XPATH_XSLT_TREE:
6929		    break;
6930	    }
6931	    break;
6932        case XPATH_STRING:
6933	    switch (arg2->type) {
6934	        case XPATH_UNDEFINED:
6935#ifdef DEBUG_EXPR
6936		    xmlGenericError(xmlGenericErrorContext,
6937			    "Equal: undefined\n");
6938#endif
6939		    break;
6940		case XPATH_BOOLEAN:
6941		    if ((arg1->stringval == NULL) ||
6942			(arg1->stringval[0] == 0)) ret = 0;
6943		    else
6944			ret = 1;
6945		    ret = (arg2->boolval == ret);
6946		    break;
6947		case XPATH_STRING:
6948		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6949		    break;
6950		case XPATH_NUMBER:
6951		    valuePush(ctxt, arg1);
6952		    xmlXPathNumberFunction(ctxt, 1);
6953		    arg1 = valuePop(ctxt);
6954		    /* Hand check NaN and Infinity equalities */
6955		    if (xmlXPathIsNaN(arg1->floatval) ||
6956			    xmlXPathIsNaN(arg2->floatval)) {
6957		        ret = 0;
6958		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6959			if (xmlXPathIsInf(arg2->floatval) == 1)
6960			    ret = 1;
6961			else
6962			    ret = 0;
6963		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6964			if (xmlXPathIsInf(arg2->floatval) == -1)
6965			    ret = 1;
6966			else
6967			    ret = 0;
6968		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6969			if (xmlXPathIsInf(arg1->floatval) == 1)
6970			    ret = 1;
6971			else
6972			    ret = 0;
6973		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6974			if (xmlXPathIsInf(arg1->floatval) == -1)
6975			    ret = 1;
6976			else
6977			    ret = 0;
6978		    } else {
6979		        ret = (arg1->floatval == arg2->floatval);
6980		    }
6981		    break;
6982		case XPATH_USERS:
6983		case XPATH_POINT:
6984		case XPATH_RANGE:
6985		case XPATH_LOCATIONSET:
6986		    TODO
6987		    break;
6988		case XPATH_NODESET:
6989		case XPATH_XSLT_TREE:
6990		    break;
6991	    }
6992	    break;
6993        case XPATH_USERS:
6994	case XPATH_POINT:
6995	case XPATH_RANGE:
6996	case XPATH_LOCATIONSET:
6997	    TODO
6998	    break;
6999	case XPATH_NODESET:
7000	case XPATH_XSLT_TREE:
7001	    break;
7002    }
7003    xmlXPathReleaseObject(ctxt->context, arg1);
7004    xmlXPathReleaseObject(ctxt->context, arg2);
7005    return(ret);
7006}
7007
7008/**
7009 * xmlXPathEqualValues:
7010 * @ctxt:  the XPath Parser context
7011 *
7012 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7013 *
7014 * Returns 0 or 1 depending on the results of the test.
7015 */
7016int
7017xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7018    xmlXPathObjectPtr arg1, arg2, argtmp;
7019    int ret = 0;
7020
7021    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7022    arg2 = valuePop(ctxt);
7023    arg1 = valuePop(ctxt);
7024    if ((arg1 == NULL) || (arg2 == NULL)) {
7025	if (arg1 != NULL)
7026	    xmlXPathReleaseObject(ctxt->context, arg1);
7027	else
7028	    xmlXPathReleaseObject(ctxt->context, arg2);
7029	XP_ERROR0(XPATH_INVALID_OPERAND);
7030    }
7031
7032    if (arg1 == arg2) {
7033#ifdef DEBUG_EXPR
7034        xmlGenericError(xmlGenericErrorContext,
7035		"Equal: by pointer\n");
7036#endif
7037	xmlXPathFreeObject(arg1);
7038        return(1);
7039    }
7040
7041    /*
7042     *If either argument is a nodeset, it's a 'special case'
7043     */
7044    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7045      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7046	/*
7047	 *Hack it to assure arg1 is the nodeset
7048	 */
7049	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7050		argtmp = arg2;
7051		arg2 = arg1;
7052		arg1 = argtmp;
7053	}
7054	switch (arg2->type) {
7055	    case XPATH_UNDEFINED:
7056#ifdef DEBUG_EXPR
7057		xmlGenericError(xmlGenericErrorContext,
7058			"Equal: undefined\n");
7059#endif
7060		break;
7061	    case XPATH_NODESET:
7062	    case XPATH_XSLT_TREE:
7063		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7064		break;
7065	    case XPATH_BOOLEAN:
7066		if ((arg1->nodesetval == NULL) ||
7067		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7068		else
7069		    ret = 1;
7070		ret = (ret == arg2->boolval);
7071		break;
7072	    case XPATH_NUMBER:
7073		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7074		break;
7075	    case XPATH_STRING:
7076		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7077		break;
7078	    case XPATH_USERS:
7079	    case XPATH_POINT:
7080	    case XPATH_RANGE:
7081	    case XPATH_LOCATIONSET:
7082		TODO
7083		break;
7084	}
7085	xmlXPathReleaseObject(ctxt->context, arg1);
7086	xmlXPathReleaseObject(ctxt->context, arg2);
7087	return(ret);
7088    }
7089
7090    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7091}
7092
7093/**
7094 * xmlXPathNotEqualValues:
7095 * @ctxt:  the XPath Parser context
7096 *
7097 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7098 *
7099 * Returns 0 or 1 depending on the results of the test.
7100 */
7101int
7102xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7103    xmlXPathObjectPtr arg1, arg2, argtmp;
7104    int ret = 0;
7105
7106    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7107    arg2 = valuePop(ctxt);
7108    arg1 = valuePop(ctxt);
7109    if ((arg1 == NULL) || (arg2 == NULL)) {
7110	if (arg1 != NULL)
7111	    xmlXPathReleaseObject(ctxt->context, arg1);
7112	else
7113	    xmlXPathReleaseObject(ctxt->context, arg2);
7114	XP_ERROR0(XPATH_INVALID_OPERAND);
7115    }
7116
7117    if (arg1 == arg2) {
7118#ifdef DEBUG_EXPR
7119        xmlGenericError(xmlGenericErrorContext,
7120		"NotEqual: by pointer\n");
7121#endif
7122	xmlXPathReleaseObject(ctxt->context, arg1);
7123        return(0);
7124    }
7125
7126    /*
7127     *If either argument is a nodeset, it's a 'special case'
7128     */
7129    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7130      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7131	/*
7132	 *Hack it to assure arg1 is the nodeset
7133	 */
7134	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7135		argtmp = arg2;
7136		arg2 = arg1;
7137		arg1 = argtmp;
7138	}
7139	switch (arg2->type) {
7140	    case XPATH_UNDEFINED:
7141#ifdef DEBUG_EXPR
7142		xmlGenericError(xmlGenericErrorContext,
7143			"NotEqual: undefined\n");
7144#endif
7145		break;
7146	    case XPATH_NODESET:
7147	    case XPATH_XSLT_TREE:
7148		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7149		break;
7150	    case XPATH_BOOLEAN:
7151		if ((arg1->nodesetval == NULL) ||
7152		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7153		else
7154		    ret = 1;
7155		ret = (ret != arg2->boolval);
7156		break;
7157	    case XPATH_NUMBER:
7158		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7159		break;
7160	    case XPATH_STRING:
7161		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7162		break;
7163	    case XPATH_USERS:
7164	    case XPATH_POINT:
7165	    case XPATH_RANGE:
7166	    case XPATH_LOCATIONSET:
7167		TODO
7168		break;
7169	}
7170	xmlXPathReleaseObject(ctxt->context, arg1);
7171	xmlXPathReleaseObject(ctxt->context, arg2);
7172	return(ret);
7173    }
7174
7175    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7176}
7177
7178/**
7179 * xmlXPathCompareValues:
7180 * @ctxt:  the XPath Parser context
7181 * @inf:  less than (1) or greater than (0)
7182 * @strict:  is the comparison strict
7183 *
7184 * Implement the compare operation on XPath objects:
7185 *     @arg1 < @arg2    (1, 1, ...
7186 *     @arg1 <= @arg2   (1, 0, ...
7187 *     @arg1 > @arg2    (0, 1, ...
7188 *     @arg1 >= @arg2   (0, 0, ...
7189 *
7190 * When neither object to be compared is a node-set and the operator is
7191 * <=, <, >=, >, then the objects are compared by converted both objects
7192 * to numbers and comparing the numbers according to IEEE 754. The <
7193 * comparison will be true if and only if the first number is less than the
7194 * second number. The <= comparison will be true if and only if the first
7195 * number is less than or equal to the second number. The > comparison
7196 * will be true if and only if the first number is greater than the second
7197 * number. The >= comparison will be true if and only if the first number
7198 * is greater than or equal to the second number.
7199 *
7200 * Returns 1 if the comparison succeeded, 0 if it failed
7201 */
7202int
7203xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7204    int ret = 0, arg1i = 0, arg2i = 0;
7205    xmlXPathObjectPtr arg1, arg2;
7206
7207    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7208    arg2 = valuePop(ctxt);
7209    arg1 = valuePop(ctxt);
7210    if ((arg1 == NULL) || (arg2 == NULL)) {
7211	if (arg1 != NULL)
7212	    xmlXPathReleaseObject(ctxt->context, arg1);
7213	else
7214	    xmlXPathReleaseObject(ctxt->context, arg2);
7215	XP_ERROR0(XPATH_INVALID_OPERAND);
7216    }
7217
7218    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7219      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7220	/*
7221	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7222	 * are not freed from within this routine; they will be freed from the
7223	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7224	 */
7225	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7226	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7227	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7228	} else {
7229	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7230		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7231			                          arg1, arg2);
7232	    } else {
7233		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7234			                          arg2, arg1);
7235	    }
7236	}
7237	return(ret);
7238    }
7239
7240    if (arg1->type != XPATH_NUMBER) {
7241	valuePush(ctxt, arg1);
7242	xmlXPathNumberFunction(ctxt, 1);
7243	arg1 = valuePop(ctxt);
7244    }
7245    if (arg1->type != XPATH_NUMBER) {
7246	xmlXPathFreeObject(arg1);
7247	xmlXPathFreeObject(arg2);
7248	XP_ERROR0(XPATH_INVALID_OPERAND);
7249    }
7250    if (arg2->type != XPATH_NUMBER) {
7251	valuePush(ctxt, arg2);
7252	xmlXPathNumberFunction(ctxt, 1);
7253	arg2 = valuePop(ctxt);
7254    }
7255    if (arg2->type != XPATH_NUMBER) {
7256	xmlXPathReleaseObject(ctxt->context, arg1);
7257	xmlXPathReleaseObject(ctxt->context, arg2);
7258	XP_ERROR0(XPATH_INVALID_OPERAND);
7259    }
7260    /*
7261     * Add tests for infinity and nan
7262     * => feedback on 3.4 for Inf and NaN
7263     */
7264    /* Hand check NaN and Infinity comparisons */
7265    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7266	ret=0;
7267    } else {
7268	arg1i=xmlXPathIsInf(arg1->floatval);
7269	arg2i=xmlXPathIsInf(arg2->floatval);
7270	if (inf && strict) {
7271	    if ((arg1i == -1 && arg2i != -1) ||
7272		(arg2i == 1 && arg1i != 1)) {
7273		ret = 1;
7274	    } else if (arg1i == 0 && arg2i == 0) {
7275		ret = (arg1->floatval < arg2->floatval);
7276	    } else {
7277		ret = 0;
7278	    }
7279	}
7280	else if (inf && !strict) {
7281	    if (arg1i == -1 || arg2i == 1) {
7282		ret = 1;
7283	    } else if (arg1i == 0 && arg2i == 0) {
7284		ret = (arg1->floatval <= arg2->floatval);
7285	    } else {
7286		ret = 0;
7287	    }
7288	}
7289	else if (!inf && strict) {
7290	    if ((arg1i == 1 && arg2i != 1) ||
7291		(arg2i == -1 && arg1i != -1)) {
7292		ret = 1;
7293	    } else if (arg1i == 0 && arg2i == 0) {
7294		ret = (arg1->floatval > arg2->floatval);
7295	    } else {
7296		ret = 0;
7297	    }
7298	}
7299	else if (!inf && !strict) {
7300	    if (arg1i == 1 || arg2i == -1) {
7301		ret = 1;
7302	    } else if (arg1i == 0 && arg2i == 0) {
7303		ret = (arg1->floatval >= arg2->floatval);
7304	    } else {
7305		ret = 0;
7306	    }
7307	}
7308    }
7309    xmlXPathReleaseObject(ctxt->context, arg1);
7310    xmlXPathReleaseObject(ctxt->context, arg2);
7311    return(ret);
7312}
7313
7314/**
7315 * xmlXPathValueFlipSign:
7316 * @ctxt:  the XPath Parser context
7317 *
7318 * Implement the unary - operation on an XPath object
7319 * The numeric operators convert their operands to numbers as if
7320 * by calling the number function.
7321 */
7322void
7323xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7324    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7325    CAST_TO_NUMBER;
7326    CHECK_TYPE(XPATH_NUMBER);
7327    if (xmlXPathIsNaN(ctxt->value->floatval))
7328        ctxt->value->floatval=xmlXPathNAN;
7329    else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7330        ctxt->value->floatval=xmlXPathNINF;
7331    else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7332        ctxt->value->floatval=xmlXPathPINF;
7333    else if (ctxt->value->floatval == 0) {
7334        if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7335	    ctxt->value->floatval = xmlXPathNZERO;
7336	else
7337	    ctxt->value->floatval = 0;
7338    }
7339    else
7340        ctxt->value->floatval = - ctxt->value->floatval;
7341}
7342
7343/**
7344 * xmlXPathAddValues:
7345 * @ctxt:  the XPath Parser context
7346 *
7347 * Implement the add operation on XPath objects:
7348 * The numeric operators convert their operands to numbers as if
7349 * by calling the number function.
7350 */
7351void
7352xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7353    xmlXPathObjectPtr arg;
7354    double val;
7355
7356    arg = valuePop(ctxt);
7357    if (arg == NULL)
7358	XP_ERROR(XPATH_INVALID_OPERAND);
7359    val = xmlXPathCastToNumber(arg);
7360    xmlXPathReleaseObject(ctxt->context, arg);
7361    CAST_TO_NUMBER;
7362    CHECK_TYPE(XPATH_NUMBER);
7363    ctxt->value->floatval += val;
7364}
7365
7366/**
7367 * xmlXPathSubValues:
7368 * @ctxt:  the XPath Parser context
7369 *
7370 * Implement the subtraction operation on XPath objects:
7371 * The numeric operators convert their operands to numbers as if
7372 * by calling the number function.
7373 */
7374void
7375xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7376    xmlXPathObjectPtr arg;
7377    double val;
7378
7379    arg = valuePop(ctxt);
7380    if (arg == NULL)
7381	XP_ERROR(XPATH_INVALID_OPERAND);
7382    val = xmlXPathCastToNumber(arg);
7383    xmlXPathReleaseObject(ctxt->context, arg);
7384    CAST_TO_NUMBER;
7385    CHECK_TYPE(XPATH_NUMBER);
7386    ctxt->value->floatval -= val;
7387}
7388
7389/**
7390 * xmlXPathMultValues:
7391 * @ctxt:  the XPath Parser context
7392 *
7393 * Implement the multiply operation on XPath objects:
7394 * The numeric operators convert their operands to numbers as if
7395 * by calling the number function.
7396 */
7397void
7398xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7399    xmlXPathObjectPtr arg;
7400    double val;
7401
7402    arg = valuePop(ctxt);
7403    if (arg == NULL)
7404	XP_ERROR(XPATH_INVALID_OPERAND);
7405    val = xmlXPathCastToNumber(arg);
7406    xmlXPathReleaseObject(ctxt->context, arg);
7407    CAST_TO_NUMBER;
7408    CHECK_TYPE(XPATH_NUMBER);
7409    ctxt->value->floatval *= val;
7410}
7411
7412/**
7413 * xmlXPathDivValues:
7414 * @ctxt:  the XPath Parser context
7415 *
7416 * Implement the div operation on XPath objects @arg1 / @arg2:
7417 * The numeric operators convert their operands to numbers as if
7418 * by calling the number function.
7419 */
7420void
7421xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7422    xmlXPathObjectPtr arg;
7423    double val;
7424
7425    arg = valuePop(ctxt);
7426    if (arg == NULL)
7427	XP_ERROR(XPATH_INVALID_OPERAND);
7428    val = xmlXPathCastToNumber(arg);
7429    xmlXPathReleaseObject(ctxt->context, arg);
7430    CAST_TO_NUMBER;
7431    CHECK_TYPE(XPATH_NUMBER);
7432    if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7433	ctxt->value->floatval = xmlXPathNAN;
7434    else if (val == 0 && xmlXPathGetSign(val) != 0) {
7435	if (ctxt->value->floatval == 0)
7436	    ctxt->value->floatval = xmlXPathNAN;
7437	else if (ctxt->value->floatval > 0)
7438	    ctxt->value->floatval = xmlXPathNINF;
7439	else if (ctxt->value->floatval < 0)
7440	    ctxt->value->floatval = xmlXPathPINF;
7441    }
7442    else if (val == 0) {
7443	if (ctxt->value->floatval == 0)
7444	    ctxt->value->floatval = xmlXPathNAN;
7445	else if (ctxt->value->floatval > 0)
7446	    ctxt->value->floatval = xmlXPathPINF;
7447	else if (ctxt->value->floatval < 0)
7448	    ctxt->value->floatval = xmlXPathNINF;
7449    } else
7450	ctxt->value->floatval /= val;
7451}
7452
7453/**
7454 * xmlXPathModValues:
7455 * @ctxt:  the XPath Parser context
7456 *
7457 * Implement the mod operation on XPath objects: @arg1 / @arg2
7458 * The numeric operators convert their operands to numbers as if
7459 * by calling the number function.
7460 */
7461void
7462xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7463    xmlXPathObjectPtr arg;
7464    double arg1, arg2;
7465
7466    arg = valuePop(ctxt);
7467    if (arg == NULL)
7468	XP_ERROR(XPATH_INVALID_OPERAND);
7469    arg2 = xmlXPathCastToNumber(arg);
7470    xmlXPathReleaseObject(ctxt->context, arg);
7471    CAST_TO_NUMBER;
7472    CHECK_TYPE(XPATH_NUMBER);
7473    arg1 = ctxt->value->floatval;
7474    if (arg2 == 0)
7475	ctxt->value->floatval = xmlXPathNAN;
7476    else {
7477	ctxt->value->floatval = fmod(arg1, arg2);
7478    }
7479}
7480
7481/************************************************************************
7482 *									*
7483 *		The traversal functions					*
7484 *									*
7485 ************************************************************************/
7486
7487/*
7488 * A traversal function enumerates nodes along an axis.
7489 * Initially it must be called with NULL, and it indicates
7490 * termination on the axis by returning NULL.
7491 */
7492typedef xmlNodePtr (*xmlXPathTraversalFunction)
7493                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7494
7495/*
7496 * xmlXPathTraversalFunctionExt:
7497 * A traversal function enumerates nodes along an axis.
7498 * Initially it must be called with NULL, and it indicates
7499 * termination on the axis by returning NULL.
7500 * The context node of the traversal is specified via @contextNode.
7501 */
7502typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7503                    (xmlNodePtr cur, xmlNodePtr contextNode);
7504
7505/*
7506 * xmlXPathNodeSetMergeFunction:
7507 * Used for merging node sets in xmlXPathCollectAndTest().
7508 */
7509typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7510		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
7511
7512
7513/**
7514 * xmlXPathNextSelf:
7515 * @ctxt:  the XPath Parser context
7516 * @cur:  the current node in the traversal
7517 *
7518 * Traversal function for the "self" direction
7519 * The self axis contains just the context node itself
7520 *
7521 * Returns the next element following that axis
7522 */
7523xmlNodePtr
7524xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7525    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7526    if (cur == NULL)
7527        return(ctxt->context->node);
7528    return(NULL);
7529}
7530
7531/**
7532 * xmlXPathNextChild:
7533 * @ctxt:  the XPath Parser context
7534 * @cur:  the current node in the traversal
7535 *
7536 * Traversal function for the "child" direction
7537 * The child axis contains the children of the context node in document order.
7538 *
7539 * Returns the next element following that axis
7540 */
7541xmlNodePtr
7542xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7543    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7544    if (cur == NULL) {
7545	if (ctxt->context->node == NULL) return(NULL);
7546	switch (ctxt->context->node->type) {
7547            case XML_ELEMENT_NODE:
7548            case XML_TEXT_NODE:
7549            case XML_CDATA_SECTION_NODE:
7550            case XML_ENTITY_REF_NODE:
7551            case XML_ENTITY_NODE:
7552            case XML_PI_NODE:
7553            case XML_COMMENT_NODE:
7554            case XML_NOTATION_NODE:
7555            case XML_DTD_NODE:
7556		return(ctxt->context->node->children);
7557            case XML_DOCUMENT_NODE:
7558            case XML_DOCUMENT_TYPE_NODE:
7559            case XML_DOCUMENT_FRAG_NODE:
7560            case XML_HTML_DOCUMENT_NODE:
7561#ifdef LIBXML_DOCB_ENABLED
7562	    case XML_DOCB_DOCUMENT_NODE:
7563#endif
7564		return(((xmlDocPtr) ctxt->context->node)->children);
7565	    case XML_ELEMENT_DECL:
7566	    case XML_ATTRIBUTE_DECL:
7567	    case XML_ENTITY_DECL:
7568            case XML_ATTRIBUTE_NODE:
7569	    case XML_NAMESPACE_DECL:
7570	    case XML_XINCLUDE_START:
7571	    case XML_XINCLUDE_END:
7572		return(NULL);
7573	}
7574	return(NULL);
7575    }
7576    if ((cur->type == XML_DOCUMENT_NODE) ||
7577        (cur->type == XML_HTML_DOCUMENT_NODE))
7578	return(NULL);
7579    return(cur->next);
7580}
7581
7582/**
7583 * xmlXPathNextChildElement:
7584 * @ctxt:  the XPath Parser context
7585 * @cur:  the current node in the traversal
7586 *
7587 * Traversal function for the "child" direction and nodes of type element.
7588 * The child axis contains the children of the context node in document order.
7589 *
7590 * Returns the next element following that axis
7591 */
7592static xmlNodePtr
7593xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7594    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7595    if (cur == NULL) {
7596	cur = ctxt->context->node;
7597	if (cur == NULL) return(NULL);
7598	/*
7599	* Get the first element child.
7600	*/
7601	switch (cur->type) {
7602            case XML_ELEMENT_NODE:
7603	    case XML_DOCUMENT_FRAG_NODE:
7604	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7605            case XML_ENTITY_NODE:
7606		cur = cur->children;
7607		if (cur != NULL) {
7608		    if (cur->type == XML_ELEMENT_NODE)
7609			return(cur);
7610		    do {
7611			cur = cur->next;
7612		    } while ((cur != NULL) &&
7613			(cur->type != XML_ELEMENT_NODE));
7614		    return(cur);
7615		}
7616		return(NULL);
7617            case XML_DOCUMENT_NODE:
7618            case XML_HTML_DOCUMENT_NODE:
7619#ifdef LIBXML_DOCB_ENABLED
7620	    case XML_DOCB_DOCUMENT_NODE:
7621#endif
7622		return(xmlDocGetRootElement((xmlDocPtr) cur));
7623	    default:
7624		return(NULL);
7625	}
7626	return(NULL);
7627    }
7628    /*
7629    * Get the next sibling element node.
7630    */
7631    switch (cur->type) {
7632	case XML_ELEMENT_NODE:
7633	case XML_TEXT_NODE:
7634	case XML_ENTITY_REF_NODE:
7635	case XML_ENTITY_NODE:
7636	case XML_CDATA_SECTION_NODE:
7637	case XML_PI_NODE:
7638	case XML_COMMENT_NODE:
7639	case XML_XINCLUDE_END:
7640	    break;
7641	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7642	default:
7643	    return(NULL);
7644    }
7645    if (cur->next != NULL) {
7646	if (cur->next->type == XML_ELEMENT_NODE)
7647	    return(cur->next);
7648	cur = cur->next;
7649	do {
7650	    cur = cur->next;
7651	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7652	return(cur);
7653    }
7654    return(NULL);
7655}
7656
7657/**
7658 * xmlXPathNextDescendantOrSelfElemParent:
7659 * @ctxt:  the XPath Parser context
7660 * @cur:  the current node in the traversal
7661 *
7662 * Traversal function for the "descendant-or-self" axis.
7663 * Additionally it returns only nodes which can be parents of
7664 * element nodes.
7665 *
7666 *
7667 * Returns the next element following that axis
7668 */
7669static xmlNodePtr
7670xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7671				       xmlNodePtr contextNode)
7672{
7673    if (cur == NULL) {
7674	if (contextNode == NULL)
7675	    return(NULL);
7676	switch (contextNode->type) {
7677	    case XML_ELEMENT_NODE:
7678	    case XML_XINCLUDE_START:
7679	    case XML_DOCUMENT_FRAG_NODE:
7680	    case XML_DOCUMENT_NODE:
7681#ifdef LIBXML_DOCB_ENABLED
7682	    case XML_DOCB_DOCUMENT_NODE:
7683#endif
7684	    case XML_HTML_DOCUMENT_NODE:
7685		return(contextNode);
7686	    default:
7687		return(NULL);
7688	}
7689	return(NULL);
7690    } else {
7691	xmlNodePtr start = cur;
7692
7693	while (cur != NULL) {
7694	    switch (cur->type) {
7695		case XML_ELEMENT_NODE:
7696		/* TODO: OK to have XInclude here? */
7697		case XML_XINCLUDE_START:
7698		case XML_DOCUMENT_FRAG_NODE:
7699		    if (cur != start)
7700			return(cur);
7701		    if (cur->children != NULL) {
7702			cur = cur->children;
7703			continue;
7704		    }
7705		    break;
7706		/* Not sure if we need those here. */
7707		case XML_DOCUMENT_NODE:
7708#ifdef LIBXML_DOCB_ENABLED
7709		case XML_DOCB_DOCUMENT_NODE:
7710#endif
7711		case XML_HTML_DOCUMENT_NODE:
7712		    if (cur != start)
7713			return(cur);
7714		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7715		default:
7716		    break;
7717	    }
7718
7719next_sibling:
7720	    if ((cur == NULL) || (cur == contextNode))
7721		return(NULL);
7722	    if (cur->next != NULL) {
7723		cur = cur->next;
7724	    } else {
7725		cur = cur->parent;
7726		goto next_sibling;
7727	    }
7728	}
7729    }
7730    return(NULL);
7731}
7732
7733/**
7734 * xmlXPathNextDescendant:
7735 * @ctxt:  the XPath Parser context
7736 * @cur:  the current node in the traversal
7737 *
7738 * Traversal function for the "descendant" direction
7739 * the descendant axis contains the descendants of the context node in document
7740 * order; a descendant is a child or a child of a child and so on.
7741 *
7742 * Returns the next element following that axis
7743 */
7744xmlNodePtr
7745xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7746    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7747    if (cur == NULL) {
7748	if (ctxt->context->node == NULL)
7749	    return(NULL);
7750	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7751	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7752	    return(NULL);
7753
7754        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7755	    return(ctxt->context->doc->children);
7756        return(ctxt->context->node->children);
7757    }
7758
7759    if (cur->children != NULL) {
7760	/*
7761	 * Do not descend on entities declarations
7762	 */
7763	if (cur->children->type != XML_ENTITY_DECL) {
7764	    cur = cur->children;
7765	    /*
7766	     * Skip DTDs
7767	     */
7768	    if (cur->type != XML_DTD_NODE)
7769		return(cur);
7770	}
7771    }
7772
7773    if (cur == ctxt->context->node) return(NULL);
7774
7775    while (cur->next != NULL) {
7776	cur = cur->next;
7777	if ((cur->type != XML_ENTITY_DECL) &&
7778	    (cur->type != XML_DTD_NODE))
7779	    return(cur);
7780    }
7781
7782    do {
7783        cur = cur->parent;
7784	if (cur == NULL) break;
7785	if (cur == ctxt->context->node) return(NULL);
7786	if (cur->next != NULL) {
7787	    cur = cur->next;
7788	    return(cur);
7789	}
7790    } while (cur != NULL);
7791    return(cur);
7792}
7793
7794/**
7795 * xmlXPathNextDescendantOrSelf:
7796 * @ctxt:  the XPath Parser context
7797 * @cur:  the current node in the traversal
7798 *
7799 * Traversal function for the "descendant-or-self" direction
7800 * the descendant-or-self axis contains the context node and the descendants
7801 * of the context node in document order; thus the context node is the first
7802 * node on the axis, and the first child of the context node is the second node
7803 * on the axis
7804 *
7805 * Returns the next element following that axis
7806 */
7807xmlNodePtr
7808xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7809    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7810    if (cur == NULL) {
7811	if (ctxt->context->node == NULL)
7812	    return(NULL);
7813	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7814	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7815	    return(NULL);
7816        return(ctxt->context->node);
7817    }
7818
7819    return(xmlXPathNextDescendant(ctxt, cur));
7820}
7821
7822/**
7823 * xmlXPathNextParent:
7824 * @ctxt:  the XPath Parser context
7825 * @cur:  the current node in the traversal
7826 *
7827 * Traversal function for the "parent" direction
7828 * The parent axis contains the parent of the context node, if there is one.
7829 *
7830 * Returns the next element following that axis
7831 */
7832xmlNodePtr
7833xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7834    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7835    /*
7836     * the parent of an attribute or namespace node is the element
7837     * to which the attribute or namespace node is attached
7838     * Namespace handling !!!
7839     */
7840    if (cur == NULL) {
7841	if (ctxt->context->node == NULL) return(NULL);
7842	switch (ctxt->context->node->type) {
7843            case XML_ELEMENT_NODE:
7844            case XML_TEXT_NODE:
7845            case XML_CDATA_SECTION_NODE:
7846            case XML_ENTITY_REF_NODE:
7847            case XML_ENTITY_NODE:
7848            case XML_PI_NODE:
7849            case XML_COMMENT_NODE:
7850            case XML_NOTATION_NODE:
7851            case XML_DTD_NODE:
7852	    case XML_ELEMENT_DECL:
7853	    case XML_ATTRIBUTE_DECL:
7854	    case XML_XINCLUDE_START:
7855	    case XML_XINCLUDE_END:
7856	    case XML_ENTITY_DECL:
7857		if (ctxt->context->node->parent == NULL)
7858		    return((xmlNodePtr) ctxt->context->doc);
7859		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7860		    ((ctxt->context->node->parent->name[0] == ' ') ||
7861		     (xmlStrEqual(ctxt->context->node->parent->name,
7862				 BAD_CAST "fake node libxslt"))))
7863		    return(NULL);
7864		return(ctxt->context->node->parent);
7865            case XML_ATTRIBUTE_NODE: {
7866		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7867
7868		return(att->parent);
7869	    }
7870            case XML_DOCUMENT_NODE:
7871            case XML_DOCUMENT_TYPE_NODE:
7872            case XML_DOCUMENT_FRAG_NODE:
7873            case XML_HTML_DOCUMENT_NODE:
7874#ifdef LIBXML_DOCB_ENABLED
7875	    case XML_DOCB_DOCUMENT_NODE:
7876#endif
7877                return(NULL);
7878	    case XML_NAMESPACE_DECL: {
7879		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7880
7881		if ((ns->next != NULL) &&
7882		    (ns->next->type != XML_NAMESPACE_DECL))
7883		    return((xmlNodePtr) ns->next);
7884                return(NULL);
7885	    }
7886	}
7887    }
7888    return(NULL);
7889}
7890
7891/**
7892 * xmlXPathNextAncestor:
7893 * @ctxt:  the XPath Parser context
7894 * @cur:  the current node in the traversal
7895 *
7896 * Traversal function for the "ancestor" direction
7897 * the ancestor axis contains the ancestors of the context node; the ancestors
7898 * of the context node consist of the parent of context node and the parent's
7899 * parent and so on; the nodes are ordered in reverse document order; thus the
7900 * parent is the first node on the axis, and the parent's parent is the second
7901 * node on the axis
7902 *
7903 * Returns the next element following that axis
7904 */
7905xmlNodePtr
7906xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7907    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7908    /*
7909     * the parent of an attribute or namespace node is the element
7910     * to which the attribute or namespace node is attached
7911     * !!!!!!!!!!!!!
7912     */
7913    if (cur == NULL) {
7914	if (ctxt->context->node == NULL) return(NULL);
7915	switch (ctxt->context->node->type) {
7916            case XML_ELEMENT_NODE:
7917            case XML_TEXT_NODE:
7918            case XML_CDATA_SECTION_NODE:
7919            case XML_ENTITY_REF_NODE:
7920            case XML_ENTITY_NODE:
7921            case XML_PI_NODE:
7922            case XML_COMMENT_NODE:
7923	    case XML_DTD_NODE:
7924	    case XML_ELEMENT_DECL:
7925	    case XML_ATTRIBUTE_DECL:
7926	    case XML_ENTITY_DECL:
7927            case XML_NOTATION_NODE:
7928	    case XML_XINCLUDE_START:
7929	    case XML_XINCLUDE_END:
7930		if (ctxt->context->node->parent == NULL)
7931		    return((xmlNodePtr) ctxt->context->doc);
7932		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7933		    ((ctxt->context->node->parent->name[0] == ' ') ||
7934		     (xmlStrEqual(ctxt->context->node->parent->name,
7935				 BAD_CAST "fake node libxslt"))))
7936		    return(NULL);
7937		return(ctxt->context->node->parent);
7938            case XML_ATTRIBUTE_NODE: {
7939		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7940
7941		return(tmp->parent);
7942	    }
7943            case XML_DOCUMENT_NODE:
7944            case XML_DOCUMENT_TYPE_NODE:
7945            case XML_DOCUMENT_FRAG_NODE:
7946            case XML_HTML_DOCUMENT_NODE:
7947#ifdef LIBXML_DOCB_ENABLED
7948	    case XML_DOCB_DOCUMENT_NODE:
7949#endif
7950                return(NULL);
7951	    case XML_NAMESPACE_DECL: {
7952		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7953
7954		if ((ns->next != NULL) &&
7955		    (ns->next->type != XML_NAMESPACE_DECL))
7956		    return((xmlNodePtr) ns->next);
7957		/* Bad, how did that namespace end up here ? */
7958                return(NULL);
7959	    }
7960	}
7961	return(NULL);
7962    }
7963    if (cur == ctxt->context->doc->children)
7964	return((xmlNodePtr) ctxt->context->doc);
7965    if (cur == (xmlNodePtr) ctxt->context->doc)
7966	return(NULL);
7967    switch (cur->type) {
7968	case XML_ELEMENT_NODE:
7969	case XML_TEXT_NODE:
7970	case XML_CDATA_SECTION_NODE:
7971	case XML_ENTITY_REF_NODE:
7972	case XML_ENTITY_NODE:
7973	case XML_PI_NODE:
7974	case XML_COMMENT_NODE:
7975	case XML_NOTATION_NODE:
7976	case XML_DTD_NODE:
7977        case XML_ELEMENT_DECL:
7978        case XML_ATTRIBUTE_DECL:
7979        case XML_ENTITY_DECL:
7980	case XML_XINCLUDE_START:
7981	case XML_XINCLUDE_END:
7982	    if (cur->parent == NULL)
7983		return(NULL);
7984	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
7985		((cur->parent->name[0] == ' ') ||
7986		 (xmlStrEqual(cur->parent->name,
7987			      BAD_CAST "fake node libxslt"))))
7988		return(NULL);
7989	    return(cur->parent);
7990	case XML_ATTRIBUTE_NODE: {
7991	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7992
7993	    return(att->parent);
7994	}
7995	case XML_NAMESPACE_DECL: {
7996	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7997
7998	    if ((ns->next != NULL) &&
7999	        (ns->next->type != XML_NAMESPACE_DECL))
8000	        return((xmlNodePtr) ns->next);
8001	    /* Bad, how did that namespace end up here ? */
8002            return(NULL);
8003	}
8004	case XML_DOCUMENT_NODE:
8005	case XML_DOCUMENT_TYPE_NODE:
8006	case XML_DOCUMENT_FRAG_NODE:
8007	case XML_HTML_DOCUMENT_NODE:
8008#ifdef LIBXML_DOCB_ENABLED
8009	case XML_DOCB_DOCUMENT_NODE:
8010#endif
8011	    return(NULL);
8012    }
8013    return(NULL);
8014}
8015
8016/**
8017 * xmlXPathNextAncestorOrSelf:
8018 * @ctxt:  the XPath Parser context
8019 * @cur:  the current node in the traversal
8020 *
8021 * Traversal function for the "ancestor-or-self" direction
8022 * he ancestor-or-self axis contains the context node and ancestors of
8023 * the context node in reverse document order; thus the context node is
8024 * the first node on the axis, and the context node's parent the second;
8025 * parent here is defined the same as with the parent axis.
8026 *
8027 * Returns the next element following that axis
8028 */
8029xmlNodePtr
8030xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8031    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8032    if (cur == NULL)
8033        return(ctxt->context->node);
8034    return(xmlXPathNextAncestor(ctxt, cur));
8035}
8036
8037/**
8038 * xmlXPathNextFollowingSibling:
8039 * @ctxt:  the XPath Parser context
8040 * @cur:  the current node in the traversal
8041 *
8042 * Traversal function for the "following-sibling" direction
8043 * The following-sibling axis contains the following siblings of the context
8044 * node in document order.
8045 *
8046 * Returns the next element following that axis
8047 */
8048xmlNodePtr
8049xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8050    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8051    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8052	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8053	return(NULL);
8054    if (cur == (xmlNodePtr) ctxt->context->doc)
8055        return(NULL);
8056    if (cur == NULL)
8057        return(ctxt->context->node->next);
8058    return(cur->next);
8059}
8060
8061/**
8062 * xmlXPathNextPrecedingSibling:
8063 * @ctxt:  the XPath Parser context
8064 * @cur:  the current node in the traversal
8065 *
8066 * Traversal function for the "preceding-sibling" direction
8067 * The preceding-sibling axis contains the preceding siblings of the context
8068 * node in reverse document order; the first preceding sibling is first on the
8069 * axis; the sibling preceding that node is the second on the axis and so on.
8070 *
8071 * Returns the next element following that axis
8072 */
8073xmlNodePtr
8074xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8075    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8076    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8077	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8078	return(NULL);
8079    if (cur == (xmlNodePtr) ctxt->context->doc)
8080        return(NULL);
8081    if (cur == NULL)
8082        return(ctxt->context->node->prev);
8083    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8084	cur = cur->prev;
8085	if (cur == NULL)
8086	    return(ctxt->context->node->prev);
8087    }
8088    return(cur->prev);
8089}
8090
8091/**
8092 * xmlXPathNextFollowing:
8093 * @ctxt:  the XPath Parser context
8094 * @cur:  the current node in the traversal
8095 *
8096 * Traversal function for the "following" direction
8097 * The following axis contains all nodes in the same document as the context
8098 * node that are after the context node in document order, excluding any
8099 * descendants and excluding attribute nodes and namespace nodes; the nodes
8100 * are ordered in document order
8101 *
8102 * Returns the next element following that axis
8103 */
8104xmlNodePtr
8105xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8106    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8107    if (cur != NULL && cur->children != NULL)
8108        return cur->children ;
8109    if (cur == NULL) cur = ctxt->context->node;
8110    if (cur == NULL) return(NULL) ; /* ERROR */
8111    if (cur->next != NULL) return(cur->next) ;
8112    do {
8113        cur = cur->parent;
8114        if (cur == NULL) break;
8115        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8116        if (cur->next != NULL) return(cur->next);
8117    } while (cur != NULL);
8118    return(cur);
8119}
8120
8121/*
8122 * xmlXPathIsAncestor:
8123 * @ancestor:  the ancestor node
8124 * @node:  the current node
8125 *
8126 * Check that @ancestor is a @node's ancestor
8127 *
8128 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8129 */
8130static int
8131xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8132    if ((ancestor == NULL) || (node == NULL)) return(0);
8133    /* nodes need to be in the same document */
8134    if (ancestor->doc != node->doc) return(0);
8135    /* avoid searching if ancestor or node is the root node */
8136    if (ancestor == (xmlNodePtr) node->doc) return(1);
8137    if (node == (xmlNodePtr) ancestor->doc) return(0);
8138    while (node->parent != NULL) {
8139        if (node->parent == ancestor)
8140            return(1);
8141	node = node->parent;
8142    }
8143    return(0);
8144}
8145
8146/**
8147 * xmlXPathNextPreceding:
8148 * @ctxt:  the XPath Parser context
8149 * @cur:  the current node in the traversal
8150 *
8151 * Traversal function for the "preceding" direction
8152 * the preceding axis contains all nodes in the same document as the context
8153 * node that are before the context node in document order, excluding any
8154 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8155 * ordered in reverse document order
8156 *
8157 * Returns the next element following that axis
8158 */
8159xmlNodePtr
8160xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8161{
8162    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8163    if (cur == NULL)
8164        cur = ctxt->context->node;
8165    if (cur == NULL)
8166	return (NULL);
8167    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8168	cur = cur->prev;
8169    do {
8170        if (cur->prev != NULL) {
8171            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8172            return (cur);
8173        }
8174
8175        cur = cur->parent;
8176        if (cur == NULL)
8177            return (NULL);
8178        if (cur == ctxt->context->doc->children)
8179            return (NULL);
8180    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8181    return (cur);
8182}
8183
8184/**
8185 * xmlXPathNextPrecedingInternal:
8186 * @ctxt:  the XPath Parser context
8187 * @cur:  the current node in the traversal
8188 *
8189 * Traversal function for the "preceding" direction
8190 * the preceding axis contains all nodes in the same document as the context
8191 * node that are before the context node in document order, excluding any
8192 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8193 * ordered in reverse document order
8194 * This is a faster implementation but internal only since it requires a
8195 * state kept in the parser context: ctxt->ancestor.
8196 *
8197 * Returns the next element following that axis
8198 */
8199static xmlNodePtr
8200xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8201                              xmlNodePtr cur)
8202{
8203    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8204    if (cur == NULL) {
8205        cur = ctxt->context->node;
8206        if (cur == NULL)
8207            return (NULL);
8208	if (cur->type == XML_NAMESPACE_DECL)
8209	    cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
8210        ctxt->ancestor = cur->parent;
8211    }
8212    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8213	cur = cur->prev;
8214    while (cur->prev == NULL) {
8215        cur = cur->parent;
8216        if (cur == NULL)
8217            return (NULL);
8218        if (cur == ctxt->context->doc->children)
8219            return (NULL);
8220        if (cur != ctxt->ancestor)
8221            return (cur);
8222        ctxt->ancestor = cur->parent;
8223    }
8224    cur = cur->prev;
8225    while (cur->last != NULL)
8226        cur = cur->last;
8227    return (cur);
8228}
8229
8230/**
8231 * xmlXPathNextNamespace:
8232 * @ctxt:  the XPath Parser context
8233 * @cur:  the current attribute in the traversal
8234 *
8235 * Traversal function for the "namespace" direction
8236 * the namespace axis contains the namespace nodes of the context node;
8237 * the order of nodes on this axis is implementation-defined; the axis will
8238 * be empty unless the context node is an element
8239 *
8240 * We keep the XML namespace node at the end of the list.
8241 *
8242 * Returns the next element following that axis
8243 */
8244xmlNodePtr
8245xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8246    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8247    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8248    if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8249        if (ctxt->context->tmpNsList != NULL)
8250	    xmlFree(ctxt->context->tmpNsList);
8251	ctxt->context->tmpNsList =
8252	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8253	ctxt->context->tmpNsNr = 0;
8254	if (ctxt->context->tmpNsList != NULL) {
8255	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8256		ctxt->context->tmpNsNr++;
8257	    }
8258	}
8259	return((xmlNodePtr) xmlXPathXMLNamespace);
8260    }
8261    if (ctxt->context->tmpNsNr > 0) {
8262	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8263    } else {
8264	if (ctxt->context->tmpNsList != NULL)
8265	    xmlFree(ctxt->context->tmpNsList);
8266	ctxt->context->tmpNsList = NULL;
8267	return(NULL);
8268    }
8269}
8270
8271/**
8272 * xmlXPathNextAttribute:
8273 * @ctxt:  the XPath Parser context
8274 * @cur:  the current attribute in the traversal
8275 *
8276 * Traversal function for the "attribute" direction
8277 * TODO: support DTD inherited default attributes
8278 *
8279 * Returns the next element following that axis
8280 */
8281xmlNodePtr
8282xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8283    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8284    if (ctxt->context->node == NULL)
8285	return(NULL);
8286    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8287	return(NULL);
8288    if (cur == NULL) {
8289        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8290	    return(NULL);
8291        return((xmlNodePtr)ctxt->context->node->properties);
8292    }
8293    return((xmlNodePtr)cur->next);
8294}
8295
8296/************************************************************************
8297 *									*
8298 *		NodeTest Functions					*
8299 *									*
8300 ************************************************************************/
8301
8302#define IS_FUNCTION			200
8303
8304
8305/************************************************************************
8306 *									*
8307 *		Implicit tree core function library			*
8308 *									*
8309 ************************************************************************/
8310
8311/**
8312 * xmlXPathRoot:
8313 * @ctxt:  the XPath Parser context
8314 *
8315 * Initialize the context to the root of the document
8316 */
8317void
8318xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8319    if ((ctxt == NULL) || (ctxt->context == NULL))
8320	return;
8321    ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8322    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8323	ctxt->context->node));
8324}
8325
8326/************************************************************************
8327 *									*
8328 *		The explicit core function library			*
8329 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8330 *									*
8331 ************************************************************************/
8332
8333
8334/**
8335 * xmlXPathLastFunction:
8336 * @ctxt:  the XPath Parser context
8337 * @nargs:  the number of arguments
8338 *
8339 * Implement the last() XPath function
8340 *    number last()
8341 * The last function returns the number of nodes in the context node list.
8342 */
8343void
8344xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8345    CHECK_ARITY(0);
8346    if (ctxt->context->contextSize >= 0) {
8347	valuePush(ctxt,
8348	    xmlXPathCacheNewFloat(ctxt->context,
8349		(double) ctxt->context->contextSize));
8350#ifdef DEBUG_EXPR
8351	xmlGenericError(xmlGenericErrorContext,
8352		"last() : %d\n", ctxt->context->contextSize);
8353#endif
8354    } else {
8355	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8356    }
8357}
8358
8359/**
8360 * xmlXPathPositionFunction:
8361 * @ctxt:  the XPath Parser context
8362 * @nargs:  the number of arguments
8363 *
8364 * Implement the position() XPath function
8365 *    number position()
8366 * The position function returns the position of the context node in the
8367 * context node list. The first position is 1, and so the last position
8368 * will be equal to last().
8369 */
8370void
8371xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8372    CHECK_ARITY(0);
8373    if (ctxt->context->proximityPosition >= 0) {
8374	valuePush(ctxt,
8375	      xmlXPathCacheNewFloat(ctxt->context,
8376		(double) ctxt->context->proximityPosition));
8377#ifdef DEBUG_EXPR
8378	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8379		ctxt->context->proximityPosition);
8380#endif
8381    } else {
8382	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8383    }
8384}
8385
8386/**
8387 * xmlXPathCountFunction:
8388 * @ctxt:  the XPath Parser context
8389 * @nargs:  the number of arguments
8390 *
8391 * Implement the count() XPath function
8392 *    number count(node-set)
8393 */
8394void
8395xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8396    xmlXPathObjectPtr cur;
8397
8398    CHECK_ARITY(1);
8399    if ((ctxt->value == NULL) ||
8400	((ctxt->value->type != XPATH_NODESET) &&
8401	 (ctxt->value->type != XPATH_XSLT_TREE)))
8402	XP_ERROR(XPATH_INVALID_TYPE);
8403    cur = valuePop(ctxt);
8404
8405    if ((cur == NULL) || (cur->nodesetval == NULL))
8406	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8407    else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8408	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8409	    (double) cur->nodesetval->nodeNr));
8410    } else {
8411	if ((cur->nodesetval->nodeNr != 1) ||
8412	    (cur->nodesetval->nodeTab == NULL)) {
8413	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8414	} else {
8415	    xmlNodePtr tmp;
8416	    int i = 0;
8417
8418	    tmp = cur->nodesetval->nodeTab[0];
8419	    if (tmp != NULL) {
8420		tmp = tmp->children;
8421		while (tmp != NULL) {
8422		    tmp = tmp->next;
8423		    i++;
8424		}
8425	    }
8426	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8427	}
8428    }
8429    xmlXPathReleaseObject(ctxt->context, cur);
8430}
8431
8432/**
8433 * xmlXPathGetElementsByIds:
8434 * @doc:  the document
8435 * @ids:  a whitespace separated list of IDs
8436 *
8437 * Selects elements by their unique ID.
8438 *
8439 * Returns a node-set of selected elements.
8440 */
8441static xmlNodeSetPtr
8442xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8443    xmlNodeSetPtr ret;
8444    const xmlChar *cur = ids;
8445    xmlChar *ID;
8446    xmlAttrPtr attr;
8447    xmlNodePtr elem = NULL;
8448
8449    if (ids == NULL) return(NULL);
8450
8451    ret = xmlXPathNodeSetCreate(NULL);
8452    if (ret == NULL)
8453        return(ret);
8454
8455    while (IS_BLANK_CH(*cur)) cur++;
8456    while (*cur != 0) {
8457	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8458	    cur++;
8459
8460        ID = xmlStrndup(ids, cur - ids);
8461	if (ID != NULL) {
8462	    /*
8463	     * We used to check the fact that the value passed
8464	     * was an NCName, but this generated much troubles for
8465	     * me and Aleksey Sanin, people blatantly violated that
8466	     * constaint, like Visa3D spec.
8467	     * if (xmlValidateNCName(ID, 1) == 0)
8468	     */
8469	    attr = xmlGetID(doc, ID);
8470	    if (attr != NULL) {
8471		if (attr->type == XML_ATTRIBUTE_NODE)
8472		    elem = attr->parent;
8473		else if (attr->type == XML_ELEMENT_NODE)
8474		    elem = (xmlNodePtr) attr;
8475		else
8476		    elem = NULL;
8477		if (elem != NULL)
8478		    xmlXPathNodeSetAdd(ret, elem);
8479	    }
8480	    xmlFree(ID);
8481	}
8482
8483	while (IS_BLANK_CH(*cur)) cur++;
8484	ids = cur;
8485    }
8486    return(ret);
8487}
8488
8489/**
8490 * xmlXPathIdFunction:
8491 * @ctxt:  the XPath Parser context
8492 * @nargs:  the number of arguments
8493 *
8494 * Implement the id() XPath function
8495 *    node-set id(object)
8496 * The id function selects elements by their unique ID
8497 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8498 * then the result is the union of the result of applying id to the
8499 * string value of each of the nodes in the argument node-set. When the
8500 * argument to id is of any other type, the argument is converted to a
8501 * string as if by a call to the string function; the string is split
8502 * into a whitespace-separated list of tokens (whitespace is any sequence
8503 * of characters matching the production S); the result is a node-set
8504 * containing the elements in the same document as the context node that
8505 * have a unique ID equal to any of the tokens in the list.
8506 */
8507void
8508xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8509    xmlChar *tokens;
8510    xmlNodeSetPtr ret;
8511    xmlXPathObjectPtr obj;
8512
8513    CHECK_ARITY(1);
8514    obj = valuePop(ctxt);
8515    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8516    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8517	xmlNodeSetPtr ns;
8518	int i;
8519
8520	ret = xmlXPathNodeSetCreate(NULL);
8521        /*
8522         * FIXME -- in an out-of-memory condition this will behave badly.
8523         * The solution is not clear -- we already popped an item from
8524         * ctxt, so the object is in a corrupt state.
8525         */
8526
8527	if (obj->nodesetval != NULL) {
8528	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8529		tokens =
8530		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8531		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8532		ret = xmlXPathNodeSetMerge(ret, ns);
8533		xmlXPathFreeNodeSet(ns);
8534		if (tokens != NULL)
8535		    xmlFree(tokens);
8536	    }
8537	}
8538	xmlXPathReleaseObject(ctxt->context, obj);
8539	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8540	return;
8541    }
8542    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8543    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8544    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8545    xmlXPathReleaseObject(ctxt->context, obj);
8546    return;
8547}
8548
8549/**
8550 * xmlXPathLocalNameFunction:
8551 * @ctxt:  the XPath Parser context
8552 * @nargs:  the number of arguments
8553 *
8554 * Implement the local-name() XPath function
8555 *    string local-name(node-set?)
8556 * The local-name function returns a string containing the local part
8557 * of the name of the node in the argument node-set that is first in
8558 * document order. If the node-set is empty or the first node has no
8559 * name, an empty string is returned. If the argument is omitted it
8560 * defaults to the context node.
8561 */
8562void
8563xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8564    xmlXPathObjectPtr cur;
8565
8566    if (ctxt == NULL) return;
8567
8568    if (nargs == 0) {
8569	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8570	    ctxt->context->node));
8571	nargs = 1;
8572    }
8573
8574    CHECK_ARITY(1);
8575    if ((ctxt->value == NULL) ||
8576	((ctxt->value->type != XPATH_NODESET) &&
8577	 (ctxt->value->type != XPATH_XSLT_TREE)))
8578	XP_ERROR(XPATH_INVALID_TYPE);
8579    cur = valuePop(ctxt);
8580
8581    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8582	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8583    } else {
8584	int i = 0; /* Should be first in document order !!!!! */
8585	switch (cur->nodesetval->nodeTab[i]->type) {
8586	case XML_ELEMENT_NODE:
8587	case XML_ATTRIBUTE_NODE:
8588	case XML_PI_NODE:
8589	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8590		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8591	    else
8592		valuePush(ctxt,
8593		      xmlXPathCacheNewString(ctxt->context,
8594			cur->nodesetval->nodeTab[i]->name));
8595	    break;
8596	case XML_NAMESPACE_DECL:
8597	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8598			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8599	    break;
8600	default:
8601	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8602	}
8603    }
8604    xmlXPathReleaseObject(ctxt->context, cur);
8605}
8606
8607/**
8608 * xmlXPathNamespaceURIFunction:
8609 * @ctxt:  the XPath Parser context
8610 * @nargs:  the number of arguments
8611 *
8612 * Implement the namespace-uri() XPath function
8613 *    string namespace-uri(node-set?)
8614 * The namespace-uri function returns a string containing the
8615 * namespace URI of the expanded name of the node in the argument
8616 * node-set that is first in document order. If the node-set is empty,
8617 * the first node has no name, or the expanded name has no namespace
8618 * URI, an empty string is returned. If the argument is omitted it
8619 * defaults to the context node.
8620 */
8621void
8622xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8623    xmlXPathObjectPtr cur;
8624
8625    if (ctxt == NULL) return;
8626
8627    if (nargs == 0) {
8628	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8629	    ctxt->context->node));
8630	nargs = 1;
8631    }
8632    CHECK_ARITY(1);
8633    if ((ctxt->value == NULL) ||
8634	((ctxt->value->type != XPATH_NODESET) &&
8635	 (ctxt->value->type != XPATH_XSLT_TREE)))
8636	XP_ERROR(XPATH_INVALID_TYPE);
8637    cur = valuePop(ctxt);
8638
8639    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8640	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8641    } else {
8642	int i = 0; /* Should be first in document order !!!!! */
8643	switch (cur->nodesetval->nodeTab[i]->type) {
8644	case XML_ELEMENT_NODE:
8645	case XML_ATTRIBUTE_NODE:
8646	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8647		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8648	    else
8649		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8650			  cur->nodesetval->nodeTab[i]->ns->href));
8651	    break;
8652	default:
8653	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8654	}
8655    }
8656    xmlXPathReleaseObject(ctxt->context, cur);
8657}
8658
8659/**
8660 * xmlXPathNameFunction:
8661 * @ctxt:  the XPath Parser context
8662 * @nargs:  the number of arguments
8663 *
8664 * Implement the name() XPath function
8665 *    string name(node-set?)
8666 * The name function returns a string containing a QName representing
8667 * the name of the node in the argument node-set that is first in document
8668 * order. The QName must represent the name with respect to the namespace
8669 * declarations in effect on the node whose name is being represented.
8670 * Typically, this will be the form in which the name occurred in the XML
8671 * source. This need not be the case if there are namespace declarations
8672 * in effect on the node that associate multiple prefixes with the same
8673 * namespace. However, an implementation may include information about
8674 * the original prefix in its representation of nodes; in this case, an
8675 * implementation can ensure that the returned string is always the same
8676 * as the QName used in the XML source. If the argument it omitted it
8677 * defaults to the context node.
8678 * Libxml keep the original prefix so the "real qualified name" used is
8679 * returned.
8680 */
8681static void
8682xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8683{
8684    xmlXPathObjectPtr cur;
8685
8686    if (nargs == 0) {
8687	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8688	    ctxt->context->node));
8689        nargs = 1;
8690    }
8691
8692    CHECK_ARITY(1);
8693    if ((ctxt->value == NULL) ||
8694        ((ctxt->value->type != XPATH_NODESET) &&
8695         (ctxt->value->type != XPATH_XSLT_TREE)))
8696        XP_ERROR(XPATH_INVALID_TYPE);
8697    cur = valuePop(ctxt);
8698
8699    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8700        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8701    } else {
8702        int i = 0;              /* Should be first in document order !!!!! */
8703
8704        switch (cur->nodesetval->nodeTab[i]->type) {
8705            case XML_ELEMENT_NODE:
8706            case XML_ATTRIBUTE_NODE:
8707		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8708		    valuePush(ctxt,
8709			xmlXPathCacheNewCString(ctxt->context, ""));
8710		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8711                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8712		    valuePush(ctxt,
8713		        xmlXPathCacheNewString(ctxt->context,
8714			    cur->nodesetval->nodeTab[i]->name));
8715		} else {
8716		    xmlChar *fullname;
8717
8718		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8719				     cur->nodesetval->nodeTab[i]->ns->prefix,
8720				     NULL, 0);
8721		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8722			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8723		    if (fullname == NULL) {
8724			XP_ERROR(XPATH_MEMORY_ERROR);
8725		    }
8726		    valuePush(ctxt, xmlXPathCacheWrapString(
8727			ctxt->context, fullname));
8728                }
8729                break;
8730            default:
8731		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8732		    cur->nodesetval->nodeTab[i]));
8733                xmlXPathLocalNameFunction(ctxt, 1);
8734        }
8735    }
8736    xmlXPathReleaseObject(ctxt->context, cur);
8737}
8738
8739
8740/**
8741 * xmlXPathStringFunction:
8742 * @ctxt:  the XPath Parser context
8743 * @nargs:  the number of arguments
8744 *
8745 * Implement the string() XPath function
8746 *    string string(object?)
8747 * The string function converts an object to a string as follows:
8748 *    - A node-set is converted to a string by returning the value of
8749 *      the node in the node-set that is first in document order.
8750 *      If the node-set is empty, an empty string is returned.
8751 *    - A number is converted to a string as follows
8752 *      + NaN is converted to the string NaN
8753 *      + positive zero is converted to the string 0
8754 *      + negative zero is converted to the string 0
8755 *      + positive infinity is converted to the string Infinity
8756 *      + negative infinity is converted to the string -Infinity
8757 *      + if the number is an integer, the number is represented in
8758 *        decimal form as a Number with no decimal point and no leading
8759 *        zeros, preceded by a minus sign (-) if the number is negative
8760 *      + otherwise, the number is represented in decimal form as a
8761 *        Number including a decimal point with at least one digit
8762 *        before the decimal point and at least one digit after the
8763 *        decimal point, preceded by a minus sign (-) if the number
8764 *        is negative; there must be no leading zeros before the decimal
8765 *        point apart possibly from the one required digit immediately
8766 *        before the decimal point; beyond the one required digit
8767 *        after the decimal point there must be as many, but only as
8768 *        many, more digits as are needed to uniquely distinguish the
8769 *        number from all other IEEE 754 numeric values.
8770 *    - The boolean false value is converted to the string false.
8771 *      The boolean true value is converted to the string true.
8772 *
8773 * If the argument is omitted, it defaults to a node-set with the
8774 * context node as its only member.
8775 */
8776void
8777xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8778    xmlXPathObjectPtr cur;
8779
8780    if (ctxt == NULL) return;
8781    if (nargs == 0) {
8782    valuePush(ctxt,
8783	xmlXPathCacheWrapString(ctxt->context,
8784	    xmlXPathCastNodeToString(ctxt->context->node)));
8785	return;
8786    }
8787
8788    CHECK_ARITY(1);
8789    cur = valuePop(ctxt);
8790    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8791    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8792}
8793
8794/**
8795 * xmlXPathStringLengthFunction:
8796 * @ctxt:  the XPath Parser context
8797 * @nargs:  the number of arguments
8798 *
8799 * Implement the string-length() XPath function
8800 *    number string-length(string?)
8801 * The string-length returns the number of characters in the string
8802 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8803 * the context node converted to a string, in other words the value
8804 * of the context node.
8805 */
8806void
8807xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8808    xmlXPathObjectPtr cur;
8809
8810    if (nargs == 0) {
8811        if ((ctxt == NULL) || (ctxt->context == NULL))
8812	    return;
8813	if (ctxt->context->node == NULL) {
8814	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8815	} else {
8816	    xmlChar *content;
8817
8818	    content = xmlXPathCastNodeToString(ctxt->context->node);
8819	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8820		xmlUTF8Strlen(content)));
8821	    xmlFree(content);
8822	}
8823	return;
8824    }
8825    CHECK_ARITY(1);
8826    CAST_TO_STRING;
8827    CHECK_TYPE(XPATH_STRING);
8828    cur = valuePop(ctxt);
8829    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8830	xmlUTF8Strlen(cur->stringval)));
8831    xmlXPathReleaseObject(ctxt->context, cur);
8832}
8833
8834/**
8835 * xmlXPathConcatFunction:
8836 * @ctxt:  the XPath Parser context
8837 * @nargs:  the number of arguments
8838 *
8839 * Implement the concat() XPath function
8840 *    string concat(string, string, string*)
8841 * The concat function returns the concatenation of its arguments.
8842 */
8843void
8844xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8845    xmlXPathObjectPtr cur, newobj;
8846    xmlChar *tmp;
8847
8848    if (ctxt == NULL) return;
8849    if (nargs < 2) {
8850	CHECK_ARITY(2);
8851    }
8852
8853    CAST_TO_STRING;
8854    cur = valuePop(ctxt);
8855    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8856	xmlXPathReleaseObject(ctxt->context, cur);
8857	return;
8858    }
8859    nargs--;
8860
8861    while (nargs > 0) {
8862	CAST_TO_STRING;
8863	newobj = valuePop(ctxt);
8864	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8865	    xmlXPathReleaseObject(ctxt->context, newobj);
8866	    xmlXPathReleaseObject(ctxt->context, cur);
8867	    XP_ERROR(XPATH_INVALID_TYPE);
8868	}
8869	tmp = xmlStrcat(newobj->stringval, cur->stringval);
8870	newobj->stringval = cur->stringval;
8871	cur->stringval = tmp;
8872	xmlXPathReleaseObject(ctxt->context, newobj);
8873	nargs--;
8874    }
8875    valuePush(ctxt, cur);
8876}
8877
8878/**
8879 * xmlXPathContainsFunction:
8880 * @ctxt:  the XPath Parser context
8881 * @nargs:  the number of arguments
8882 *
8883 * Implement the contains() XPath function
8884 *    boolean contains(string, string)
8885 * The contains function returns true if the first argument string
8886 * contains the second argument string, and otherwise returns false.
8887 */
8888void
8889xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8890    xmlXPathObjectPtr hay, needle;
8891
8892    CHECK_ARITY(2);
8893    CAST_TO_STRING;
8894    CHECK_TYPE(XPATH_STRING);
8895    needle = valuePop(ctxt);
8896    CAST_TO_STRING;
8897    hay = valuePop(ctxt);
8898
8899    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8900	xmlXPathReleaseObject(ctxt->context, hay);
8901	xmlXPathReleaseObject(ctxt->context, needle);
8902	XP_ERROR(XPATH_INVALID_TYPE);
8903    }
8904    if (xmlStrstr(hay->stringval, needle->stringval))
8905	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8906    else
8907	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8908    xmlXPathReleaseObject(ctxt->context, hay);
8909    xmlXPathReleaseObject(ctxt->context, needle);
8910}
8911
8912/**
8913 * xmlXPathStartsWithFunction:
8914 * @ctxt:  the XPath Parser context
8915 * @nargs:  the number of arguments
8916 *
8917 * Implement the starts-with() XPath function
8918 *    boolean starts-with(string, string)
8919 * The starts-with function returns true if the first argument string
8920 * starts with the second argument string, and otherwise returns false.
8921 */
8922void
8923xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8924    xmlXPathObjectPtr hay, needle;
8925    int n;
8926
8927    CHECK_ARITY(2);
8928    CAST_TO_STRING;
8929    CHECK_TYPE(XPATH_STRING);
8930    needle = valuePop(ctxt);
8931    CAST_TO_STRING;
8932    hay = valuePop(ctxt);
8933
8934    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8935	xmlXPathReleaseObject(ctxt->context, hay);
8936	xmlXPathReleaseObject(ctxt->context, needle);
8937	XP_ERROR(XPATH_INVALID_TYPE);
8938    }
8939    n = xmlStrlen(needle->stringval);
8940    if (xmlStrncmp(hay->stringval, needle->stringval, n))
8941        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8942    else
8943        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8944    xmlXPathReleaseObject(ctxt->context, hay);
8945    xmlXPathReleaseObject(ctxt->context, needle);
8946}
8947
8948/**
8949 * xmlXPathSubstringFunction:
8950 * @ctxt:  the XPath Parser context
8951 * @nargs:  the number of arguments
8952 *
8953 * Implement the substring() XPath function
8954 *    string substring(string, number, number?)
8955 * The substring function returns the substring of the first argument
8956 * starting at the position specified in the second argument with
8957 * length specified in the third argument. For example,
8958 * substring("12345",2,3) returns "234". If the third argument is not
8959 * specified, it returns the substring starting at the position specified
8960 * in the second argument and continuing to the end of the string. For
8961 * example, substring("12345",2) returns "2345".  More precisely, each
8962 * character in the string (see [3.6 Strings]) is considered to have a
8963 * numeric position: the position of the first character is 1, the position
8964 * of the second character is 2 and so on. The returned substring contains
8965 * those characters for which the position of the character is greater than
8966 * or equal to the second argument and, if the third argument is specified,
8967 * less than the sum of the second and third arguments; the comparisons
8968 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8969 *  - substring("12345", 1.5, 2.6) returns "234"
8970 *  - substring("12345", 0, 3) returns "12"
8971 *  - substring("12345", 0 div 0, 3) returns ""
8972 *  - substring("12345", 1, 0 div 0) returns ""
8973 *  - substring("12345", -42, 1 div 0) returns "12345"
8974 *  - substring("12345", -1 div 0, 1 div 0) returns ""
8975 */
8976void
8977xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8978    xmlXPathObjectPtr str, start, len;
8979    double le=0, in;
8980    int i, l, m;
8981    xmlChar *ret;
8982
8983    if (nargs < 2) {
8984	CHECK_ARITY(2);
8985    }
8986    if (nargs > 3) {
8987	CHECK_ARITY(3);
8988    }
8989    /*
8990     * take care of possible last (position) argument
8991    */
8992    if (nargs == 3) {
8993	CAST_TO_NUMBER;
8994	CHECK_TYPE(XPATH_NUMBER);
8995	len = valuePop(ctxt);
8996	le = len->floatval;
8997	xmlXPathReleaseObject(ctxt->context, len);
8998    }
8999
9000    CAST_TO_NUMBER;
9001    CHECK_TYPE(XPATH_NUMBER);
9002    start = valuePop(ctxt);
9003    in = start->floatval;
9004    xmlXPathReleaseObject(ctxt->context, start);
9005    CAST_TO_STRING;
9006    CHECK_TYPE(XPATH_STRING);
9007    str = valuePop(ctxt);
9008    m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9009
9010    /*
9011     * If last pos not present, calculate last position
9012    */
9013    if (nargs != 3) {
9014	le = (double)m;
9015	if (in < 1.0)
9016	    in = 1.0;
9017    }
9018
9019    /* Need to check for the special cases where either
9020     * the index is NaN, the length is NaN, or both
9021     * arguments are infinity (relying on Inf + -Inf = NaN)
9022     */
9023    if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
9024        /*
9025         * To meet the requirements of the spec, the arguments
9026	 * must be converted to integer format before
9027	 * initial index calculations are done
9028         *
9029         * First we go to integer form, rounding up
9030	 * and checking for special cases
9031         */
9032        i = (int) in;
9033        if (((double)i)+0.5 <= in) i++;
9034
9035	if (xmlXPathIsInf(le) == 1) {
9036	    l = m;
9037	    if (i < 1)
9038		i = 1;
9039	}
9040	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9041	    l = 0;
9042	else {
9043	    l = (int) le;
9044	    if (((double)l)+0.5 <= le) l++;
9045	}
9046
9047	/* Now we normalize inidices */
9048        i -= 1;
9049        l += i;
9050        if (i < 0)
9051            i = 0;
9052        if (l > m)
9053            l = m;
9054
9055        /* number of chars to copy */
9056        l -= i;
9057
9058        ret = xmlUTF8Strsub(str->stringval, i, l);
9059    }
9060    else {
9061        ret = NULL;
9062    }
9063    if (ret == NULL)
9064	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9065    else {
9066	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9067	xmlFree(ret);
9068    }
9069    xmlXPathReleaseObject(ctxt->context, str);
9070}
9071
9072/**
9073 * xmlXPathSubstringBeforeFunction:
9074 * @ctxt:  the XPath Parser context
9075 * @nargs:  the number of arguments
9076 *
9077 * Implement the substring-before() XPath function
9078 *    string substring-before(string, string)
9079 * The substring-before function returns the substring of the first
9080 * argument string that precedes the first occurrence of the second
9081 * argument string in the first argument string, or the empty string
9082 * if the first argument string does not contain the second argument
9083 * string. For example, substring-before("1999/04/01","/") returns 1999.
9084 */
9085void
9086xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9087  xmlXPathObjectPtr str;
9088  xmlXPathObjectPtr find;
9089  xmlBufferPtr target;
9090  const xmlChar *point;
9091  int offset;
9092
9093  CHECK_ARITY(2);
9094  CAST_TO_STRING;
9095  find = valuePop(ctxt);
9096  CAST_TO_STRING;
9097  str = valuePop(ctxt);
9098
9099  target = xmlBufferCreate();
9100  if (target) {
9101    point = xmlStrstr(str->stringval, find->stringval);
9102    if (point) {
9103      offset = (int)(point - str->stringval);
9104      xmlBufferAdd(target, str->stringval, offset);
9105    }
9106    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9107	xmlBufferContent(target)));
9108    xmlBufferFree(target);
9109  }
9110  xmlXPathReleaseObject(ctxt->context, str);
9111  xmlXPathReleaseObject(ctxt->context, find);
9112}
9113
9114/**
9115 * xmlXPathSubstringAfterFunction:
9116 * @ctxt:  the XPath Parser context
9117 * @nargs:  the number of arguments
9118 *
9119 * Implement the substring-after() XPath function
9120 *    string substring-after(string, string)
9121 * The substring-after function returns the substring of the first
9122 * argument string that follows the first occurrence of the second
9123 * argument string in the first argument string, or the empty stringi
9124 * if the first argument string does not contain the second argument
9125 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9126 * and substring-after("1999/04/01","19") returns 99/04/01.
9127 */
9128void
9129xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9130  xmlXPathObjectPtr str;
9131  xmlXPathObjectPtr find;
9132  xmlBufferPtr target;
9133  const xmlChar *point;
9134  int offset;
9135
9136  CHECK_ARITY(2);
9137  CAST_TO_STRING;
9138  find = valuePop(ctxt);
9139  CAST_TO_STRING;
9140  str = valuePop(ctxt);
9141
9142  target = xmlBufferCreate();
9143  if (target) {
9144    point = xmlStrstr(str->stringval, find->stringval);
9145    if (point) {
9146      offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9147      xmlBufferAdd(target, &str->stringval[offset],
9148		   xmlStrlen(str->stringval) - offset);
9149    }
9150    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9151	xmlBufferContent(target)));
9152    xmlBufferFree(target);
9153  }
9154  xmlXPathReleaseObject(ctxt->context, str);
9155  xmlXPathReleaseObject(ctxt->context, find);
9156}
9157
9158/**
9159 * xmlXPathNormalizeFunction:
9160 * @ctxt:  the XPath Parser context
9161 * @nargs:  the number of arguments
9162 *
9163 * Implement the normalize-space() XPath function
9164 *    string normalize-space(string?)
9165 * The normalize-space function returns the argument string with white
9166 * space normalized by stripping leading and trailing whitespace
9167 * and replacing sequences of whitespace characters by a single
9168 * space. Whitespace characters are the same allowed by the S production
9169 * in XML. If the argument is omitted, it defaults to the context
9170 * node converted to a string, in other words the value of the context node.
9171 */
9172void
9173xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9174  xmlXPathObjectPtr obj = NULL;
9175  xmlChar *source = NULL;
9176  xmlBufferPtr target;
9177  xmlChar blank;
9178
9179  if (ctxt == NULL) return;
9180  if (nargs == 0) {
9181    /* Use current context node */
9182      valuePush(ctxt,
9183	  xmlXPathCacheWrapString(ctxt->context,
9184	    xmlXPathCastNodeToString(ctxt->context->node)));
9185    nargs = 1;
9186  }
9187
9188  CHECK_ARITY(1);
9189  CAST_TO_STRING;
9190  CHECK_TYPE(XPATH_STRING);
9191  obj = valuePop(ctxt);
9192  source = obj->stringval;
9193
9194  target = xmlBufferCreate();
9195  if (target && source) {
9196
9197    /* Skip leading whitespaces */
9198    while (IS_BLANK_CH(*source))
9199      source++;
9200
9201    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9202    blank = 0;
9203    while (*source) {
9204      if (IS_BLANK_CH(*source)) {
9205	blank = 0x20;
9206      } else {
9207	if (blank) {
9208	  xmlBufferAdd(target, &blank, 1);
9209	  blank = 0;
9210	}
9211	xmlBufferAdd(target, source, 1);
9212      }
9213      source++;
9214    }
9215    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9216	xmlBufferContent(target)));
9217    xmlBufferFree(target);
9218  }
9219  xmlXPathReleaseObject(ctxt->context, obj);
9220}
9221
9222/**
9223 * xmlXPathTranslateFunction:
9224 * @ctxt:  the XPath Parser context
9225 * @nargs:  the number of arguments
9226 *
9227 * Implement the translate() XPath function
9228 *    string translate(string, string, string)
9229 * The translate function returns the first argument string with
9230 * occurrences of characters in the second argument string replaced
9231 * by the character at the corresponding position in the third argument
9232 * string. For example, translate("bar","abc","ABC") returns the string
9233 * BAr. If there is a character in the second argument string with no
9234 * character at a corresponding position in the third argument string
9235 * (because the second argument string is longer than the third argument
9236 * string), then occurrences of that character in the first argument
9237 * string are removed. For example, translate("--aaa--","abc-","ABC")
9238 * returns "AAA". If a character occurs more than once in second
9239 * argument string, then the first occurrence determines the replacement
9240 * character. If the third argument string is longer than the second
9241 * argument string, then excess characters are ignored.
9242 */
9243void
9244xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9245    xmlXPathObjectPtr str;
9246    xmlXPathObjectPtr from;
9247    xmlXPathObjectPtr to;
9248    xmlBufferPtr target;
9249    int offset, max;
9250    xmlChar ch;
9251    const xmlChar *point;
9252    xmlChar *cptr;
9253
9254    CHECK_ARITY(3);
9255
9256    CAST_TO_STRING;
9257    to = valuePop(ctxt);
9258    CAST_TO_STRING;
9259    from = valuePop(ctxt);
9260    CAST_TO_STRING;
9261    str = valuePop(ctxt);
9262
9263    target = xmlBufferCreate();
9264    if (target) {
9265	max = xmlUTF8Strlen(to->stringval);
9266	for (cptr = str->stringval; (ch=*cptr); ) {
9267	    offset = xmlUTF8Strloc(from->stringval, cptr);
9268	    if (offset >= 0) {
9269		if (offset < max) {
9270		    point = xmlUTF8Strpos(to->stringval, offset);
9271		    if (point)
9272			xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9273		}
9274	    } else
9275		xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9276
9277	    /* Step to next character in input */
9278	    cptr++;
9279	    if ( ch & 0x80 ) {
9280		/* if not simple ascii, verify proper format */
9281		if ( (ch & 0xc0) != 0xc0 ) {
9282		    xmlGenericError(xmlGenericErrorContext,
9283			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
9284		    break;
9285		}
9286		/* then skip over remaining bytes for this char */
9287		while ( (ch <<= 1) & 0x80 )
9288		    if ( (*cptr++ & 0xc0) != 0x80 ) {
9289			xmlGenericError(xmlGenericErrorContext,
9290			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9291			break;
9292		    }
9293		if (ch & 0x80) /* must have had error encountered */
9294		    break;
9295	    }
9296	}
9297    }
9298    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9299	xmlBufferContent(target)));
9300    xmlBufferFree(target);
9301    xmlXPathReleaseObject(ctxt->context, str);
9302    xmlXPathReleaseObject(ctxt->context, from);
9303    xmlXPathReleaseObject(ctxt->context, to);
9304}
9305
9306/**
9307 * xmlXPathBooleanFunction:
9308 * @ctxt:  the XPath Parser context
9309 * @nargs:  the number of arguments
9310 *
9311 * Implement the boolean() XPath function
9312 *    boolean boolean(object)
9313 * The boolean function converts its argument to a boolean as follows:
9314 *    - a number is true if and only if it is neither positive or
9315 *      negative zero nor NaN
9316 *    - a node-set is true if and only if it is non-empty
9317 *    - a string is true if and only if its length is non-zero
9318 */
9319void
9320xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9321    xmlXPathObjectPtr cur;
9322
9323    CHECK_ARITY(1);
9324    cur = valuePop(ctxt);
9325    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9326    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9327    valuePush(ctxt, cur);
9328}
9329
9330/**
9331 * xmlXPathNotFunction:
9332 * @ctxt:  the XPath Parser context
9333 * @nargs:  the number of arguments
9334 *
9335 * Implement the not() XPath function
9336 *    boolean not(boolean)
9337 * The not function returns true if its argument is false,
9338 * and false otherwise.
9339 */
9340void
9341xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9342    CHECK_ARITY(1);
9343    CAST_TO_BOOLEAN;
9344    CHECK_TYPE(XPATH_BOOLEAN);
9345    ctxt->value->boolval = ! ctxt->value->boolval;
9346}
9347
9348/**
9349 * xmlXPathTrueFunction:
9350 * @ctxt:  the XPath Parser context
9351 * @nargs:  the number of arguments
9352 *
9353 * Implement the true() XPath function
9354 *    boolean true()
9355 */
9356void
9357xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9358    CHECK_ARITY(0);
9359    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9360}
9361
9362/**
9363 * xmlXPathFalseFunction:
9364 * @ctxt:  the XPath Parser context
9365 * @nargs:  the number of arguments
9366 *
9367 * Implement the false() XPath function
9368 *    boolean false()
9369 */
9370void
9371xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9372    CHECK_ARITY(0);
9373    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9374}
9375
9376/**
9377 * xmlXPathLangFunction:
9378 * @ctxt:  the XPath Parser context
9379 * @nargs:  the number of arguments
9380 *
9381 * Implement the lang() XPath function
9382 *    boolean lang(string)
9383 * The lang function returns true or false depending on whether the
9384 * language of the context node as specified by xml:lang attributes
9385 * is the same as or is a sublanguage of the language specified by
9386 * the argument string. The language of the context node is determined
9387 * by the value of the xml:lang attribute on the context node, or, if
9388 * the context node has no xml:lang attribute, by the value of the
9389 * xml:lang attribute on the nearest ancestor of the context node that
9390 * has an xml:lang attribute. If there is no such attribute, then lang
9391 * returns false. If there is such an attribute, then lang returns
9392 * true if the attribute value is equal to the argument ignoring case,
9393 * or if there is some suffix starting with - such that the attribute
9394 * value is equal to the argument ignoring that suffix of the attribute
9395 * value and ignoring case.
9396 */
9397void
9398xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9399    xmlXPathObjectPtr val = NULL;
9400    const xmlChar *theLang = NULL;
9401    const xmlChar *lang;
9402    int ret = 0;
9403    int i;
9404
9405    CHECK_ARITY(1);
9406    CAST_TO_STRING;
9407    CHECK_TYPE(XPATH_STRING);
9408    val = valuePop(ctxt);
9409    lang = val->stringval;
9410    theLang = xmlNodeGetLang(ctxt->context->node);
9411    if ((theLang != NULL) && (lang != NULL)) {
9412        for (i = 0;lang[i] != 0;i++)
9413	    if (toupper(lang[i]) != toupper(theLang[i]))
9414	        goto not_equal;
9415	if ((theLang[i] == 0) || (theLang[i] == '-'))
9416	    ret = 1;
9417    }
9418not_equal:
9419    if (theLang != NULL)
9420	xmlFree((void *)theLang);
9421
9422    xmlXPathReleaseObject(ctxt->context, val);
9423    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9424}
9425
9426/**
9427 * xmlXPathNumberFunction:
9428 * @ctxt:  the XPath Parser context
9429 * @nargs:  the number of arguments
9430 *
9431 * Implement the number() XPath function
9432 *    number number(object?)
9433 */
9434void
9435xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9436    xmlXPathObjectPtr cur;
9437    double res;
9438
9439    if (ctxt == NULL) return;
9440    if (nargs == 0) {
9441	if (ctxt->context->node == NULL) {
9442	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9443	} else {
9444	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9445
9446	    res = xmlXPathStringEvalNumber(content);
9447	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9448	    xmlFree(content);
9449	}
9450	return;
9451    }
9452
9453    CHECK_ARITY(1);
9454    cur = valuePop(ctxt);
9455    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9456}
9457
9458/**
9459 * xmlXPathSumFunction:
9460 * @ctxt:  the XPath Parser context
9461 * @nargs:  the number of arguments
9462 *
9463 * Implement the sum() XPath function
9464 *    number sum(node-set)
9465 * The sum function returns the sum of the values of the nodes in
9466 * the argument node-set.
9467 */
9468void
9469xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9470    xmlXPathObjectPtr cur;
9471    int i;
9472    double res = 0.0;
9473
9474    CHECK_ARITY(1);
9475    if ((ctxt->value == NULL) ||
9476	((ctxt->value->type != XPATH_NODESET) &&
9477	 (ctxt->value->type != XPATH_XSLT_TREE)))
9478	XP_ERROR(XPATH_INVALID_TYPE);
9479    cur = valuePop(ctxt);
9480
9481    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9482	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9483	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9484	}
9485    }
9486    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9487    xmlXPathReleaseObject(ctxt->context, cur);
9488}
9489
9490/*
9491 * To assure working code on multiple platforms, we want to only depend
9492 * upon the characteristic truncation of converting a floating point value
9493 * to an integer.  Unfortunately, because of the different storage sizes
9494 * of our internal floating point value (double) and integer (int), we
9495 * can't directly convert (see bug 301162).  This macro is a messy
9496 * 'workaround'
9497 */
9498#define XTRUNC(f, v)            \
9499    f = fmod((v), INT_MAX);     \
9500    f = (v) - (f) + (double)((int)(f));
9501
9502/**
9503 * xmlXPathFloorFunction:
9504 * @ctxt:  the XPath Parser context
9505 * @nargs:  the number of arguments
9506 *
9507 * Implement the floor() XPath function
9508 *    number floor(number)
9509 * The floor function returns the largest (closest to positive infinity)
9510 * number that is not greater than the argument and that is an integer.
9511 */
9512void
9513xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9514    double f;
9515
9516    CHECK_ARITY(1);
9517    CAST_TO_NUMBER;
9518    CHECK_TYPE(XPATH_NUMBER);
9519
9520    XTRUNC(f, ctxt->value->floatval);
9521    if (f != ctxt->value->floatval) {
9522	if (ctxt->value->floatval > 0)
9523	    ctxt->value->floatval = f;
9524	else
9525	    ctxt->value->floatval = f - 1;
9526    }
9527}
9528
9529/**
9530 * xmlXPathCeilingFunction:
9531 * @ctxt:  the XPath Parser context
9532 * @nargs:  the number of arguments
9533 *
9534 * Implement the ceiling() XPath function
9535 *    number ceiling(number)
9536 * The ceiling function returns the smallest (closest to negative infinity)
9537 * number that is not less than the argument and that is an integer.
9538 */
9539void
9540xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9541    double f;
9542
9543    CHECK_ARITY(1);
9544    CAST_TO_NUMBER;
9545    CHECK_TYPE(XPATH_NUMBER);
9546
9547#if 0
9548    ctxt->value->floatval = ceil(ctxt->value->floatval);
9549#else
9550    XTRUNC(f, ctxt->value->floatval);
9551    if (f != ctxt->value->floatval) {
9552	if (ctxt->value->floatval > 0)
9553	    ctxt->value->floatval = f + 1;
9554	else {
9555	    if (ctxt->value->floatval < 0 && f == 0)
9556	        ctxt->value->floatval = xmlXPathNZERO;
9557	    else
9558	        ctxt->value->floatval = f;
9559	}
9560
9561    }
9562#endif
9563}
9564
9565/**
9566 * xmlXPathRoundFunction:
9567 * @ctxt:  the XPath Parser context
9568 * @nargs:  the number of arguments
9569 *
9570 * Implement the round() XPath function
9571 *    number round(number)
9572 * The round function returns the number that is closest to the
9573 * argument and that is an integer. If there are two such numbers,
9574 * then the one that is even is returned.
9575 */
9576void
9577xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9578    double f;
9579
9580    CHECK_ARITY(1);
9581    CAST_TO_NUMBER;
9582    CHECK_TYPE(XPATH_NUMBER);
9583
9584    if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9585	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9586	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9587	(ctxt->value->floatval == 0.0))
9588	return;
9589
9590    XTRUNC(f, ctxt->value->floatval);
9591    if (ctxt->value->floatval < 0) {
9592	if (ctxt->value->floatval < f - 0.5)
9593	    ctxt->value->floatval = f - 1;
9594	else
9595	    ctxt->value->floatval = f;
9596	if (ctxt->value->floatval == 0)
9597	    ctxt->value->floatval = xmlXPathNZERO;
9598    } else {
9599	if (ctxt->value->floatval < f + 0.5)
9600	    ctxt->value->floatval = f;
9601	else
9602	    ctxt->value->floatval = f + 1;
9603    }
9604}
9605
9606/************************************************************************
9607 *									*
9608 *			The Parser					*
9609 *									*
9610 ************************************************************************/
9611
9612/*
9613 * a few forward declarations since we use a recursive call based
9614 * implementation.
9615 */
9616static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9617static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9618static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9619static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9620static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9621	                                  int qualified);
9622
9623/**
9624 * xmlXPathCurrentChar:
9625 * @ctxt:  the XPath parser context
9626 * @cur:  pointer to the beginning of the char
9627 * @len:  pointer to the length of the char read
9628 *
9629 * The current char value, if using UTF-8 this may actually span multiple
9630 * bytes in the input buffer.
9631 *
9632 * Returns the current char value and its length
9633 */
9634
9635static int
9636xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9637    unsigned char c;
9638    unsigned int val;
9639    const xmlChar *cur;
9640
9641    if (ctxt == NULL)
9642	return(0);
9643    cur = ctxt->cur;
9644
9645    /*
9646     * We are supposed to handle UTF8, check it's valid
9647     * From rfc2044: encoding of the Unicode values on UTF-8:
9648     *
9649     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9650     * 0000 0000-0000 007F   0xxxxxxx
9651     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9652     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9653     *
9654     * Check for the 0x110000 limit too
9655     */
9656    c = *cur;
9657    if (c & 0x80) {
9658	if ((cur[1] & 0xc0) != 0x80)
9659	    goto encoding_error;
9660	if ((c & 0xe0) == 0xe0) {
9661
9662	    if ((cur[2] & 0xc0) != 0x80)
9663		goto encoding_error;
9664	    if ((c & 0xf0) == 0xf0) {
9665		if (((c & 0xf8) != 0xf0) ||
9666		    ((cur[3] & 0xc0) != 0x80))
9667		    goto encoding_error;
9668		/* 4-byte code */
9669		*len = 4;
9670		val = (cur[0] & 0x7) << 18;
9671		val |= (cur[1] & 0x3f) << 12;
9672		val |= (cur[2] & 0x3f) << 6;
9673		val |= cur[3] & 0x3f;
9674	    } else {
9675	      /* 3-byte code */
9676		*len = 3;
9677		val = (cur[0] & 0xf) << 12;
9678		val |= (cur[1] & 0x3f) << 6;
9679		val |= cur[2] & 0x3f;
9680	    }
9681	} else {
9682	  /* 2-byte code */
9683	    *len = 2;
9684	    val = (cur[0] & 0x1f) << 6;
9685	    val |= cur[1] & 0x3f;
9686	}
9687	if (!IS_CHAR(val)) {
9688	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9689	}
9690	return(val);
9691    } else {
9692	/* 1-byte code */
9693	*len = 1;
9694	return((int) *cur);
9695    }
9696encoding_error:
9697    /*
9698     * If we detect an UTF8 error that probably means that the
9699     * input encoding didn't get properly advertised in the
9700     * declaration header. Report the error and switch the encoding
9701     * to ISO-Latin-1 (if you don't like this policy, just declare the
9702     * encoding !)
9703     */
9704    *len = 0;
9705    XP_ERROR0(XPATH_ENCODING_ERROR);
9706}
9707
9708/**
9709 * xmlXPathParseNCName:
9710 * @ctxt:  the XPath Parser context
9711 *
9712 * parse an XML namespace non qualified name.
9713 *
9714 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9715 *
9716 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9717 *                       CombiningChar | Extender
9718 *
9719 * Returns the namespace name or NULL
9720 */
9721
9722xmlChar *
9723xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9724    const xmlChar *in;
9725    xmlChar *ret;
9726    int count = 0;
9727
9728    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9729    /*
9730     * Accelerator for simple ASCII names
9731     */
9732    in = ctxt->cur;
9733    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9734	((*in >= 0x41) && (*in <= 0x5A)) ||
9735	(*in == '_')) {
9736	in++;
9737	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9738	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9739	       ((*in >= 0x30) && (*in <= 0x39)) ||
9740	       (*in == '_') || (*in == '.') ||
9741	       (*in == '-'))
9742	    in++;
9743	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9744            (*in == '[') || (*in == ']') || (*in == ':') ||
9745            (*in == '@') || (*in == '*')) {
9746	    count = in - ctxt->cur;
9747	    if (count == 0)
9748		return(NULL);
9749	    ret = xmlStrndup(ctxt->cur, count);
9750	    ctxt->cur = in;
9751	    return(ret);
9752	}
9753    }
9754    return(xmlXPathParseNameComplex(ctxt, 0));
9755}
9756
9757
9758/**
9759 * xmlXPathParseQName:
9760 * @ctxt:  the XPath Parser context
9761 * @prefix:  a xmlChar **
9762 *
9763 * parse an XML qualified name
9764 *
9765 * [NS 5] QName ::= (Prefix ':')? LocalPart
9766 *
9767 * [NS 6] Prefix ::= NCName
9768 *
9769 * [NS 7] LocalPart ::= NCName
9770 *
9771 * Returns the function returns the local part, and prefix is updated
9772 *   to get the Prefix if any.
9773 */
9774
9775static xmlChar *
9776xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9777    xmlChar *ret = NULL;
9778
9779    *prefix = NULL;
9780    ret = xmlXPathParseNCName(ctxt);
9781    if (ret && CUR == ':') {
9782        *prefix = ret;
9783	NEXT;
9784	ret = xmlXPathParseNCName(ctxt);
9785    }
9786    return(ret);
9787}
9788
9789/**
9790 * xmlXPathParseName:
9791 * @ctxt:  the XPath Parser context
9792 *
9793 * parse an XML name
9794 *
9795 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9796 *                  CombiningChar | Extender
9797 *
9798 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9799 *
9800 * Returns the namespace name or NULL
9801 */
9802
9803xmlChar *
9804xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9805    const xmlChar *in;
9806    xmlChar *ret;
9807    int count = 0;
9808
9809    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9810    /*
9811     * Accelerator for simple ASCII names
9812     */
9813    in = ctxt->cur;
9814    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9815	((*in >= 0x41) && (*in <= 0x5A)) ||
9816	(*in == '_') || (*in == ':')) {
9817	in++;
9818	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9819	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9820	       ((*in >= 0x30) && (*in <= 0x39)) ||
9821	       (*in == '_') || (*in == '-') ||
9822	       (*in == ':') || (*in == '.'))
9823	    in++;
9824	if ((*in > 0) && (*in < 0x80)) {
9825	    count = in - ctxt->cur;
9826	    ret = xmlStrndup(ctxt->cur, count);
9827	    ctxt->cur = in;
9828	    return(ret);
9829	}
9830    }
9831    return(xmlXPathParseNameComplex(ctxt, 1));
9832}
9833
9834static xmlChar *
9835xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9836    xmlChar buf[XML_MAX_NAMELEN + 5];
9837    int len = 0, l;
9838    int c;
9839
9840    /*
9841     * Handler for more complex cases
9842     */
9843    c = CUR_CHAR(l);
9844    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9845        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9846        (c == '*') || /* accelerators */
9847	(!IS_LETTER(c) && (c != '_') &&
9848         ((qualified) && (c != ':')))) {
9849	return(NULL);
9850    }
9851
9852    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9853	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9854            (c == '.') || (c == '-') ||
9855	    (c == '_') || ((qualified) && (c == ':')) ||
9856	    (IS_COMBINING(c)) ||
9857	    (IS_EXTENDER(c)))) {
9858	COPY_BUF(l,buf,len,c);
9859	NEXTL(l);
9860	c = CUR_CHAR(l);
9861	if (len >= XML_MAX_NAMELEN) {
9862	    /*
9863	     * Okay someone managed to make a huge name, so he's ready to pay
9864	     * for the processing speed.
9865	     */
9866	    xmlChar *buffer;
9867	    int max = len * 2;
9868
9869	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9870	    if (buffer == NULL) {
9871		XP_ERRORNULL(XPATH_MEMORY_ERROR);
9872	    }
9873	    memcpy(buffer, buf, len);
9874	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9875		   (c == '.') || (c == '-') ||
9876		   (c == '_') || ((qualified) && (c == ':')) ||
9877		   (IS_COMBINING(c)) ||
9878		   (IS_EXTENDER(c))) {
9879		if (len + 10 > max) {
9880		    max *= 2;
9881		    buffer = (xmlChar *) xmlRealloc(buffer,
9882			                            max * sizeof(xmlChar));
9883		    if (buffer == NULL) {
9884			XP_ERRORNULL(XPATH_MEMORY_ERROR);
9885		    }
9886		}
9887		COPY_BUF(l,buffer,len,c);
9888		NEXTL(l);
9889		c = CUR_CHAR(l);
9890	    }
9891	    buffer[len] = 0;
9892	    return(buffer);
9893	}
9894    }
9895    if (len == 0)
9896	return(NULL);
9897    return(xmlStrndup(buf, len));
9898}
9899
9900#define MAX_FRAC 20
9901
9902/*
9903 * These are used as divisors for the fractional part of a number.
9904 * Since the table includes 1.0 (representing '0' fractional digits),
9905 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9906 */
9907static double my_pow10[MAX_FRAC+1] = {
9908    1.0, 10.0, 100.0, 1000.0, 10000.0,
9909    100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9910    10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9911    100000000000000.0,
9912    1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
9913    1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
9914};
9915
9916/**
9917 * xmlXPathStringEvalNumber:
9918 * @str:  A string to scan
9919 *
9920 *  [30a]  Float  ::= Number ('e' Digits?)?
9921 *
9922 *  [30]   Number ::=   Digits ('.' Digits?)?
9923 *                    | '.' Digits
9924 *  [31]   Digits ::=   [0-9]+
9925 *
9926 * Compile a Number in the string
9927 * In complement of the Number expression, this function also handles
9928 * negative values : '-' Number.
9929 *
9930 * Returns the double value.
9931 */
9932double
9933xmlXPathStringEvalNumber(const xmlChar *str) {
9934    const xmlChar *cur = str;
9935    double ret;
9936    int ok = 0;
9937    int isneg = 0;
9938    int exponent = 0;
9939    int is_exponent_negative = 0;
9940#ifdef __GNUC__
9941    unsigned long tmp = 0;
9942    double temp;
9943#endif
9944    if (cur == NULL) return(0);
9945    while (IS_BLANK_CH(*cur)) cur++;
9946    if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9947        return(xmlXPathNAN);
9948    }
9949    if (*cur == '-') {
9950	isneg = 1;
9951	cur++;
9952    }
9953
9954#ifdef __GNUC__
9955    /*
9956     * tmp/temp is a workaround against a gcc compiler bug
9957     * http://veillard.com/gcc.bug
9958     */
9959    ret = 0;
9960    while ((*cur >= '0') && (*cur <= '9')) {
9961	ret = ret * 10;
9962	tmp = (*cur - '0');
9963	ok = 1;
9964	cur++;
9965	temp = (double) tmp;
9966	ret = ret + temp;
9967    }
9968#else
9969    ret = 0;
9970    while ((*cur >= '0') && (*cur <= '9')) {
9971	ret = ret * 10 + (*cur - '0');
9972	ok = 1;
9973	cur++;
9974    }
9975#endif
9976
9977    if (*cur == '.') {
9978	int v, frac = 0;
9979	double fraction = 0;
9980
9981        cur++;
9982	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9983	    return(xmlXPathNAN);
9984	}
9985	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9986	    v = (*cur - '0');
9987	    fraction = fraction * 10 + v;
9988	    frac = frac + 1;
9989	    cur++;
9990	}
9991	fraction /= my_pow10[frac];
9992	ret = ret + fraction;
9993	while ((*cur >= '0') && (*cur <= '9'))
9994	    cur++;
9995    }
9996    if ((*cur == 'e') || (*cur == 'E')) {
9997      cur++;
9998      if (*cur == '-') {
9999	is_exponent_negative = 1;
10000	cur++;
10001      } else if (*cur == '+') {
10002        cur++;
10003      }
10004      while ((*cur >= '0') && (*cur <= '9')) {
10005	exponent = exponent * 10 + (*cur - '0');
10006	cur++;
10007      }
10008    }
10009    while (IS_BLANK_CH(*cur)) cur++;
10010    if (*cur != 0) return(xmlXPathNAN);
10011    if (isneg) ret = -ret;
10012    if (is_exponent_negative) exponent = -exponent;
10013    ret *= pow(10.0, (double)exponent);
10014    return(ret);
10015}
10016
10017/**
10018 * xmlXPathCompNumber:
10019 * @ctxt:  the XPath Parser context
10020 *
10021 *  [30]   Number ::=   Digits ('.' Digits?)?
10022 *                    | '.' Digits
10023 *  [31]   Digits ::=   [0-9]+
10024 *
10025 * Compile a Number, then push it on the stack
10026 *
10027 */
10028static void
10029xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10030{
10031    double ret = 0.0;
10032    double mult = 1;
10033    int ok = 0;
10034    int exponent = 0;
10035    int is_exponent_negative = 0;
10036#ifdef __GNUC__
10037    unsigned long tmp = 0;
10038    double temp;
10039#endif
10040
10041    CHECK_ERROR;
10042    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10043        XP_ERROR(XPATH_NUMBER_ERROR);
10044    }
10045#ifdef __GNUC__
10046    /*
10047     * tmp/temp is a workaround against a gcc compiler bug
10048     * http://veillard.com/gcc.bug
10049     */
10050    ret = 0;
10051    while ((CUR >= '0') && (CUR <= '9')) {
10052	ret = ret * 10;
10053	tmp = (CUR - '0');
10054        ok = 1;
10055        NEXT;
10056	temp = (double) tmp;
10057	ret = ret + temp;
10058    }
10059#else
10060    ret = 0;
10061    while ((CUR >= '0') && (CUR <= '9')) {
10062	ret = ret * 10 + (CUR - '0');
10063	ok = 1;
10064	NEXT;
10065    }
10066#endif
10067    if (CUR == '.') {
10068        NEXT;
10069        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10070            XP_ERROR(XPATH_NUMBER_ERROR);
10071        }
10072        while ((CUR >= '0') && (CUR <= '9')) {
10073            mult /= 10;
10074            ret = ret + (CUR - '0') * mult;
10075            NEXT;
10076        }
10077    }
10078    if ((CUR == 'e') || (CUR == 'E')) {
10079        NEXT;
10080        if (CUR == '-') {
10081            is_exponent_negative = 1;
10082            NEXT;
10083        } else if (CUR == '+') {
10084	    NEXT;
10085	}
10086        while ((CUR >= '0') && (CUR <= '9')) {
10087            exponent = exponent * 10 + (CUR - '0');
10088            NEXT;
10089        }
10090        if (is_exponent_negative)
10091            exponent = -exponent;
10092        ret *= pow(10.0, (double) exponent);
10093    }
10094    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10095                   xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10096}
10097
10098/**
10099 * xmlXPathParseLiteral:
10100 * @ctxt:  the XPath Parser context
10101 *
10102 * Parse a Literal
10103 *
10104 *  [29]   Literal ::=   '"' [^"]* '"'
10105 *                    | "'" [^']* "'"
10106 *
10107 * Returns the value found or NULL in case of error
10108 */
10109static xmlChar *
10110xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10111    const xmlChar *q;
10112    xmlChar *ret = NULL;
10113
10114    if (CUR == '"') {
10115        NEXT;
10116	q = CUR_PTR;
10117	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10118	    NEXT;
10119	if (!IS_CHAR_CH(CUR)) {
10120	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10121	} else {
10122	    ret = xmlStrndup(q, CUR_PTR - q);
10123	    NEXT;
10124        }
10125    } else if (CUR == '\'') {
10126        NEXT;
10127	q = CUR_PTR;
10128	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10129	    NEXT;
10130	if (!IS_CHAR_CH(CUR)) {
10131	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10132	} else {
10133	    ret = xmlStrndup(q, CUR_PTR - q);
10134	    NEXT;
10135        }
10136    } else {
10137	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10138    }
10139    return(ret);
10140}
10141
10142/**
10143 * xmlXPathCompLiteral:
10144 * @ctxt:  the XPath Parser context
10145 *
10146 * Parse a Literal and push it on the stack.
10147 *
10148 *  [29]   Literal ::=   '"' [^"]* '"'
10149 *                    | "'" [^']* "'"
10150 *
10151 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10152 */
10153static void
10154xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10155    const xmlChar *q;
10156    xmlChar *ret = NULL;
10157
10158    if (CUR == '"') {
10159        NEXT;
10160	q = CUR_PTR;
10161	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10162	    NEXT;
10163	if (!IS_CHAR_CH(CUR)) {
10164	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10165	} else {
10166	    ret = xmlStrndup(q, CUR_PTR - q);
10167	    NEXT;
10168        }
10169    } else if (CUR == '\'') {
10170        NEXT;
10171	q = CUR_PTR;
10172	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10173	    NEXT;
10174	if (!IS_CHAR_CH(CUR)) {
10175	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10176	} else {
10177	    ret = xmlStrndup(q, CUR_PTR - q);
10178	    NEXT;
10179        }
10180    } else {
10181	XP_ERROR(XPATH_START_LITERAL_ERROR);
10182    }
10183    if (ret == NULL) return;
10184    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10185	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
10186    xmlFree(ret);
10187}
10188
10189/**
10190 * xmlXPathCompVariableReference:
10191 * @ctxt:  the XPath Parser context
10192 *
10193 * Parse a VariableReference, evaluate it and push it on the stack.
10194 *
10195 * The variable bindings consist of a mapping from variable names
10196 * to variable values. The value of a variable is an object, which can be
10197 * of any of the types that are possible for the value of an expression,
10198 * and may also be of additional types not specified here.
10199 *
10200 * Early evaluation is possible since:
10201 * The variable bindings [...] used to evaluate a subexpression are
10202 * always the same as those used to evaluate the containing expression.
10203 *
10204 *  [36]   VariableReference ::=   '$' QName
10205 */
10206static void
10207xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10208    xmlChar *name;
10209    xmlChar *prefix;
10210
10211    SKIP_BLANKS;
10212    if (CUR != '$') {
10213	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10214    }
10215    NEXT;
10216    name = xmlXPathParseQName(ctxt, &prefix);
10217    if (name == NULL) {
10218	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10219    }
10220    ctxt->comp->last = -1;
10221    PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10222	           name, prefix);
10223    SKIP_BLANKS;
10224    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10225	XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10226    }
10227}
10228
10229/**
10230 * xmlXPathIsNodeType:
10231 * @name:  a name string
10232 *
10233 * Is the name given a NodeType one.
10234 *
10235 *  [38]   NodeType ::=   'comment'
10236 *                    | 'text'
10237 *                    | 'processing-instruction'
10238 *                    | 'node'
10239 *
10240 * Returns 1 if true 0 otherwise
10241 */
10242int
10243xmlXPathIsNodeType(const xmlChar *name) {
10244    if (name == NULL)
10245	return(0);
10246
10247    if (xmlStrEqual(name, BAD_CAST "node"))
10248	return(1);
10249    if (xmlStrEqual(name, BAD_CAST "text"))
10250	return(1);
10251    if (xmlStrEqual(name, BAD_CAST "comment"))
10252	return(1);
10253    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10254	return(1);
10255    return(0);
10256}
10257
10258/**
10259 * xmlXPathCompFunctionCall:
10260 * @ctxt:  the XPath Parser context
10261 *
10262 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10263 *  [17]   Argument ::=   Expr
10264 *
10265 * Compile a function call, the evaluation of all arguments are
10266 * pushed on the stack
10267 */
10268static void
10269xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10270    xmlChar *name;
10271    xmlChar *prefix;
10272    int nbargs = 0;
10273    int sort = 1;
10274
10275    name = xmlXPathParseQName(ctxt, &prefix);
10276    if (name == NULL) {
10277	xmlFree(prefix);
10278	XP_ERROR(XPATH_EXPR_ERROR);
10279    }
10280    SKIP_BLANKS;
10281#ifdef DEBUG_EXPR
10282    if (prefix == NULL)
10283	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10284			name);
10285    else
10286	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10287			prefix, name);
10288#endif
10289
10290    if (CUR != '(') {
10291	XP_ERROR(XPATH_EXPR_ERROR);
10292    }
10293    NEXT;
10294    SKIP_BLANKS;
10295
10296    /*
10297    * Optimization for count(): we don't need the node-set to be sorted.
10298    */
10299    if ((prefix == NULL) && (name[0] == 'c') &&
10300	xmlStrEqual(name, BAD_CAST "count"))
10301    {
10302	sort = 0;
10303    }
10304    ctxt->comp->last = -1;
10305    if (CUR != ')') {
10306	while (CUR != 0) {
10307	    int op1 = ctxt->comp->last;
10308	    ctxt->comp->last = -1;
10309	    xmlXPathCompileExpr(ctxt, sort);
10310	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10311		xmlFree(name);
10312		xmlFree(prefix);
10313		return;
10314	    }
10315	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10316	    nbargs++;
10317	    if (CUR == ')') break;
10318	    if (CUR != ',') {
10319		XP_ERROR(XPATH_EXPR_ERROR);
10320	    }
10321	    NEXT;
10322	    SKIP_BLANKS;
10323	}
10324    }
10325    PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10326	           name, prefix);
10327    NEXT;
10328    SKIP_BLANKS;
10329}
10330
10331/**
10332 * xmlXPathCompPrimaryExpr:
10333 * @ctxt:  the XPath Parser context
10334 *
10335 *  [15]   PrimaryExpr ::=   VariableReference
10336 *                | '(' Expr ')'
10337 *                | Literal
10338 *                | Number
10339 *                | FunctionCall
10340 *
10341 * Compile a primary expression.
10342 */
10343static void
10344xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10345    SKIP_BLANKS;
10346    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10347    else if (CUR == '(') {
10348	NEXT;
10349	SKIP_BLANKS;
10350	xmlXPathCompileExpr(ctxt, 1);
10351	CHECK_ERROR;
10352	if (CUR != ')') {
10353	    XP_ERROR(XPATH_EXPR_ERROR);
10354	}
10355	NEXT;
10356	SKIP_BLANKS;
10357    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10358	xmlXPathCompNumber(ctxt);
10359    } else if ((CUR == '\'') || (CUR == '"')) {
10360	xmlXPathCompLiteral(ctxt);
10361    } else {
10362	xmlXPathCompFunctionCall(ctxt);
10363    }
10364    SKIP_BLANKS;
10365}
10366
10367/**
10368 * xmlXPathCompFilterExpr:
10369 * @ctxt:  the XPath Parser context
10370 *
10371 *  [20]   FilterExpr ::=   PrimaryExpr
10372 *               | FilterExpr Predicate
10373 *
10374 * Compile a filter expression.
10375 * Square brackets are used to filter expressions in the same way that
10376 * they are used in location paths. It is an error if the expression to
10377 * be filtered does not evaluate to a node-set. The context node list
10378 * used for evaluating the expression in square brackets is the node-set
10379 * to be filtered listed in document order.
10380 */
10381
10382static void
10383xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10384    xmlXPathCompPrimaryExpr(ctxt);
10385    CHECK_ERROR;
10386    SKIP_BLANKS;
10387
10388    while (CUR == '[') {
10389	xmlXPathCompPredicate(ctxt, 1);
10390	SKIP_BLANKS;
10391    }
10392
10393
10394}
10395
10396/**
10397 * xmlXPathScanName:
10398 * @ctxt:  the XPath Parser context
10399 *
10400 * Trickery: parse an XML name but without consuming the input flow
10401 * Needed to avoid insanity in the parser state.
10402 *
10403 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10404 *                  CombiningChar | Extender
10405 *
10406 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10407 *
10408 * [6] Names ::= Name (S Name)*
10409 *
10410 * Returns the Name parsed or NULL
10411 */
10412
10413static xmlChar *
10414xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10415    int len = 0, l;
10416    int c;
10417    const xmlChar *cur;
10418    xmlChar *ret;
10419
10420    cur = ctxt->cur;
10421
10422    c = CUR_CHAR(l);
10423    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10424	(!IS_LETTER(c) && (c != '_') &&
10425         (c != ':'))) {
10426	return(NULL);
10427    }
10428
10429    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10430	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10431            (c == '.') || (c == '-') ||
10432	    (c == '_') || (c == ':') ||
10433	    (IS_COMBINING(c)) ||
10434	    (IS_EXTENDER(c)))) {
10435	len += l;
10436	NEXTL(l);
10437	c = CUR_CHAR(l);
10438    }
10439    ret = xmlStrndup(cur, ctxt->cur - cur);
10440    ctxt->cur = cur;
10441    return(ret);
10442}
10443
10444/**
10445 * xmlXPathCompPathExpr:
10446 * @ctxt:  the XPath Parser context
10447 *
10448 *  [19]   PathExpr ::=   LocationPath
10449 *               | FilterExpr
10450 *               | FilterExpr '/' RelativeLocationPath
10451 *               | FilterExpr '//' RelativeLocationPath
10452 *
10453 * Compile a path expression.
10454 * The / operator and // operators combine an arbitrary expression
10455 * and a relative location path. It is an error if the expression
10456 * does not evaluate to a node-set.
10457 * The / operator does composition in the same way as when / is
10458 * used in a location path. As in location paths, // is short for
10459 * /descendant-or-self::node()/.
10460 */
10461
10462static void
10463xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10464    int lc = 1;           /* Should we branch to LocationPath ?         */
10465    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10466
10467    SKIP_BLANKS;
10468    if ((CUR == '$') || (CUR == '(') ||
10469	(IS_ASCII_DIGIT(CUR)) ||
10470        (CUR == '\'') || (CUR == '"') ||
10471	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10472	lc = 0;
10473    } else if (CUR == '*') {
10474	/* relative or absolute location path */
10475	lc = 1;
10476    } else if (CUR == '/') {
10477	/* relative or absolute location path */
10478	lc = 1;
10479    } else if (CUR == '@') {
10480	/* relative abbreviated attribute location path */
10481	lc = 1;
10482    } else if (CUR == '.') {
10483	/* relative abbreviated attribute location path */
10484	lc = 1;
10485    } else {
10486	/*
10487	 * Problem is finding if we have a name here whether it's:
10488	 *   - a nodetype
10489	 *   - a function call in which case it's followed by '('
10490	 *   - an axis in which case it's followed by ':'
10491	 *   - a element name
10492	 * We do an a priori analysis here rather than having to
10493	 * maintain parsed token content through the recursive function
10494	 * calls. This looks uglier but makes the code easier to
10495	 * read/write/debug.
10496	 */
10497	SKIP_BLANKS;
10498	name = xmlXPathScanName(ctxt);
10499	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10500#ifdef DEBUG_STEP
10501	    xmlGenericError(xmlGenericErrorContext,
10502		    "PathExpr: Axis\n");
10503#endif
10504	    lc = 1;
10505	    xmlFree(name);
10506	} else if (name != NULL) {
10507	    int len =xmlStrlen(name);
10508
10509
10510	    while (NXT(len) != 0) {
10511		if (NXT(len) == '/') {
10512		    /* element name */
10513#ifdef DEBUG_STEP
10514		    xmlGenericError(xmlGenericErrorContext,
10515			    "PathExpr: AbbrRelLocation\n");
10516#endif
10517		    lc = 1;
10518		    break;
10519		} else if (IS_BLANK_CH(NXT(len))) {
10520		    /* ignore blanks */
10521		    ;
10522		} else if (NXT(len) == ':') {
10523#ifdef DEBUG_STEP
10524		    xmlGenericError(xmlGenericErrorContext,
10525			    "PathExpr: AbbrRelLocation\n");
10526#endif
10527		    lc = 1;
10528		    break;
10529		} else if ((NXT(len) == '(')) {
10530		    /* Note Type or Function */
10531		    if (xmlXPathIsNodeType(name)) {
10532#ifdef DEBUG_STEP
10533		        xmlGenericError(xmlGenericErrorContext,
10534				"PathExpr: Type search\n");
10535#endif
10536			lc = 1;
10537		    } else {
10538#ifdef DEBUG_STEP
10539		        xmlGenericError(xmlGenericErrorContext,
10540				"PathExpr: function call\n");
10541#endif
10542			lc = 0;
10543		    }
10544                    break;
10545		} else if ((NXT(len) == '[')) {
10546		    /* element name */
10547#ifdef DEBUG_STEP
10548		    xmlGenericError(xmlGenericErrorContext,
10549			    "PathExpr: AbbrRelLocation\n");
10550#endif
10551		    lc = 1;
10552		    break;
10553		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10554			   (NXT(len) == '=')) {
10555		    lc = 1;
10556		    break;
10557		} else {
10558		    lc = 1;
10559		    break;
10560		}
10561		len++;
10562	    }
10563	    if (NXT(len) == 0) {
10564#ifdef DEBUG_STEP
10565		xmlGenericError(xmlGenericErrorContext,
10566			"PathExpr: AbbrRelLocation\n");
10567#endif
10568		/* element name */
10569		lc = 1;
10570	    }
10571	    xmlFree(name);
10572	} else {
10573	    /* make sure all cases are covered explicitly */
10574	    XP_ERROR(XPATH_EXPR_ERROR);
10575	}
10576    }
10577
10578    if (lc) {
10579	if (CUR == '/') {
10580	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10581	} else {
10582	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10583	}
10584	xmlXPathCompLocationPath(ctxt);
10585    } else {
10586	xmlXPathCompFilterExpr(ctxt);
10587	CHECK_ERROR;
10588	if ((CUR == '/') && (NXT(1) == '/')) {
10589	    SKIP(2);
10590	    SKIP_BLANKS;
10591
10592	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10593		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10594	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10595
10596	    xmlXPathCompRelativeLocationPath(ctxt);
10597	} else if (CUR == '/') {
10598	    xmlXPathCompRelativeLocationPath(ctxt);
10599	}
10600    }
10601    SKIP_BLANKS;
10602}
10603
10604/**
10605 * xmlXPathCompUnionExpr:
10606 * @ctxt:  the XPath Parser context
10607 *
10608 *  [18]   UnionExpr ::=   PathExpr
10609 *               | UnionExpr '|' PathExpr
10610 *
10611 * Compile an union expression.
10612 */
10613
10614static void
10615xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10616    xmlXPathCompPathExpr(ctxt);
10617    CHECK_ERROR;
10618    SKIP_BLANKS;
10619    while (CUR == '|') {
10620	int op1 = ctxt->comp->last;
10621	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10622
10623	NEXT;
10624	SKIP_BLANKS;
10625	xmlXPathCompPathExpr(ctxt);
10626
10627	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10628
10629	SKIP_BLANKS;
10630    }
10631}
10632
10633/**
10634 * xmlXPathCompUnaryExpr:
10635 * @ctxt:  the XPath Parser context
10636 *
10637 *  [27]   UnaryExpr ::=   UnionExpr
10638 *                   | '-' UnaryExpr
10639 *
10640 * Compile an unary expression.
10641 */
10642
10643static void
10644xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10645    int minus = 0;
10646    int found = 0;
10647
10648    SKIP_BLANKS;
10649    while (CUR == '-') {
10650        minus = 1 - minus;
10651	found = 1;
10652	NEXT;
10653	SKIP_BLANKS;
10654    }
10655
10656    xmlXPathCompUnionExpr(ctxt);
10657    CHECK_ERROR;
10658    if (found) {
10659	if (minus)
10660	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10661	else
10662	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10663    }
10664}
10665
10666/**
10667 * xmlXPathCompMultiplicativeExpr:
10668 * @ctxt:  the XPath Parser context
10669 *
10670 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10671 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10672 *                   | MultiplicativeExpr 'div' UnaryExpr
10673 *                   | MultiplicativeExpr 'mod' UnaryExpr
10674 *  [34]   MultiplyOperator ::=   '*'
10675 *
10676 * Compile an Additive expression.
10677 */
10678
10679static void
10680xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10681    xmlXPathCompUnaryExpr(ctxt);
10682    CHECK_ERROR;
10683    SKIP_BLANKS;
10684    while ((CUR == '*') ||
10685           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10686           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10687	int op = -1;
10688	int op1 = ctxt->comp->last;
10689
10690        if (CUR == '*') {
10691	    op = 0;
10692	    NEXT;
10693	} else if (CUR == 'd') {
10694	    op = 1;
10695	    SKIP(3);
10696	} else if (CUR == 'm') {
10697	    op = 2;
10698	    SKIP(3);
10699	}
10700	SKIP_BLANKS;
10701        xmlXPathCompUnaryExpr(ctxt);
10702	CHECK_ERROR;
10703	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10704	SKIP_BLANKS;
10705    }
10706}
10707
10708/**
10709 * xmlXPathCompAdditiveExpr:
10710 * @ctxt:  the XPath Parser context
10711 *
10712 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10713 *                   | AdditiveExpr '+' MultiplicativeExpr
10714 *                   | AdditiveExpr '-' MultiplicativeExpr
10715 *
10716 * Compile an Additive expression.
10717 */
10718
10719static void
10720xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10721
10722    xmlXPathCompMultiplicativeExpr(ctxt);
10723    CHECK_ERROR;
10724    SKIP_BLANKS;
10725    while ((CUR == '+') || (CUR == '-')) {
10726	int plus;
10727	int op1 = ctxt->comp->last;
10728
10729        if (CUR == '+') plus = 1;
10730	else plus = 0;
10731	NEXT;
10732	SKIP_BLANKS;
10733        xmlXPathCompMultiplicativeExpr(ctxt);
10734	CHECK_ERROR;
10735	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10736	SKIP_BLANKS;
10737    }
10738}
10739
10740/**
10741 * xmlXPathCompRelationalExpr:
10742 * @ctxt:  the XPath Parser context
10743 *
10744 *  [24]   RelationalExpr ::=   AdditiveExpr
10745 *                 | RelationalExpr '<' AdditiveExpr
10746 *                 | RelationalExpr '>' AdditiveExpr
10747 *                 | RelationalExpr '<=' AdditiveExpr
10748 *                 | RelationalExpr '>=' AdditiveExpr
10749 *
10750 *  A <= B > C is allowed ? Answer from James, yes with
10751 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10752 *  which is basically what got implemented.
10753 *
10754 * Compile a Relational expression, then push the result
10755 * on the stack
10756 */
10757
10758static void
10759xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10760    xmlXPathCompAdditiveExpr(ctxt);
10761    CHECK_ERROR;
10762    SKIP_BLANKS;
10763    while ((CUR == '<') ||
10764           (CUR == '>') ||
10765           ((CUR == '<') && (NXT(1) == '=')) ||
10766           ((CUR == '>') && (NXT(1) == '='))) {
10767	int inf, strict;
10768	int op1 = ctxt->comp->last;
10769
10770        if (CUR == '<') inf = 1;
10771	else inf = 0;
10772	if (NXT(1) == '=') strict = 0;
10773	else strict = 1;
10774	NEXT;
10775	if (!strict) NEXT;
10776	SKIP_BLANKS;
10777        xmlXPathCompAdditiveExpr(ctxt);
10778	CHECK_ERROR;
10779	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10780	SKIP_BLANKS;
10781    }
10782}
10783
10784/**
10785 * xmlXPathCompEqualityExpr:
10786 * @ctxt:  the XPath Parser context
10787 *
10788 *  [23]   EqualityExpr ::=   RelationalExpr
10789 *                 | EqualityExpr '=' RelationalExpr
10790 *                 | EqualityExpr '!=' RelationalExpr
10791 *
10792 *  A != B != C is allowed ? Answer from James, yes with
10793 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10794 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10795 *  which is basically what got implemented.
10796 *
10797 * Compile an Equality expression.
10798 *
10799 */
10800static void
10801xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10802    xmlXPathCompRelationalExpr(ctxt);
10803    CHECK_ERROR;
10804    SKIP_BLANKS;
10805    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10806	int eq;
10807	int op1 = ctxt->comp->last;
10808
10809        if (CUR == '=') eq = 1;
10810	else eq = 0;
10811	NEXT;
10812	if (!eq) NEXT;
10813	SKIP_BLANKS;
10814        xmlXPathCompRelationalExpr(ctxt);
10815	CHECK_ERROR;
10816	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10817	SKIP_BLANKS;
10818    }
10819}
10820
10821/**
10822 * xmlXPathCompAndExpr:
10823 * @ctxt:  the XPath Parser context
10824 *
10825 *  [22]   AndExpr ::=   EqualityExpr
10826 *                 | AndExpr 'and' EqualityExpr
10827 *
10828 * Compile an AND expression.
10829 *
10830 */
10831static void
10832xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10833    xmlXPathCompEqualityExpr(ctxt);
10834    CHECK_ERROR;
10835    SKIP_BLANKS;
10836    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10837	int op1 = ctxt->comp->last;
10838        SKIP(3);
10839	SKIP_BLANKS;
10840        xmlXPathCompEqualityExpr(ctxt);
10841	CHECK_ERROR;
10842	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10843	SKIP_BLANKS;
10844    }
10845}
10846
10847/**
10848 * xmlXPathCompileExpr:
10849 * @ctxt:  the XPath Parser context
10850 *
10851 *  [14]   Expr ::=   OrExpr
10852 *  [21]   OrExpr ::=   AndExpr
10853 *                 | OrExpr 'or' AndExpr
10854 *
10855 * Parse and compile an expression
10856 */
10857static void
10858xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10859    xmlXPathCompAndExpr(ctxt);
10860    CHECK_ERROR;
10861    SKIP_BLANKS;
10862    while ((CUR == 'o') && (NXT(1) == 'r')) {
10863	int op1 = ctxt->comp->last;
10864        SKIP(2);
10865	SKIP_BLANKS;
10866        xmlXPathCompAndExpr(ctxt);
10867	CHECK_ERROR;
10868	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10869	op1 = ctxt->comp->nbStep;
10870	SKIP_BLANKS;
10871    }
10872    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10873	/* more ops could be optimized too */
10874	/*
10875	* This is the main place to eliminate sorting for
10876	* operations which don't require a sorted node-set.
10877	* E.g. count().
10878	*/
10879	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10880    }
10881}
10882
10883/**
10884 * xmlXPathCompPredicate:
10885 * @ctxt:  the XPath Parser context
10886 * @filter:  act as a filter
10887 *
10888 *  [8]   Predicate ::=   '[' PredicateExpr ']'
10889 *  [9]   PredicateExpr ::=   Expr
10890 *
10891 * Compile a predicate expression
10892 */
10893static void
10894xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10895    int op1 = ctxt->comp->last;
10896
10897    SKIP_BLANKS;
10898    if (CUR != '[') {
10899	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10900    }
10901    NEXT;
10902    SKIP_BLANKS;
10903
10904    ctxt->comp->last = -1;
10905    /*
10906    * This call to xmlXPathCompileExpr() will deactivate sorting
10907    * of the predicate result.
10908    * TODO: Sorting is still activated for filters, since I'm not
10909    *  sure if needed. Normally sorting should not be needed, since
10910    *  a filter can only diminish the number of items in a sequence,
10911    *  but won't change its order; so if the initial sequence is sorted,
10912    *  subsequent sorting is not needed.
10913    */
10914    if (! filter)
10915	xmlXPathCompileExpr(ctxt, 0);
10916    else
10917	xmlXPathCompileExpr(ctxt, 1);
10918    CHECK_ERROR;
10919
10920    if (CUR != ']') {
10921	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10922    }
10923
10924    if (filter)
10925	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10926    else
10927	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10928
10929    NEXT;
10930    SKIP_BLANKS;
10931}
10932
10933/**
10934 * xmlXPathCompNodeTest:
10935 * @ctxt:  the XPath Parser context
10936 * @test:  pointer to a xmlXPathTestVal
10937 * @type:  pointer to a xmlXPathTypeVal
10938 * @prefix:  placeholder for a possible name prefix
10939 *
10940 * [7] NodeTest ::=   NameTest
10941 *		    | NodeType '(' ')'
10942 *		    | 'processing-instruction' '(' Literal ')'
10943 *
10944 * [37] NameTest ::=  '*'
10945 *		    | NCName ':' '*'
10946 *		    | QName
10947 * [38] NodeType ::= 'comment'
10948 *		   | 'text'
10949 *		   | 'processing-instruction'
10950 *		   | 'node'
10951 *
10952 * Returns the name found and updates @test, @type and @prefix appropriately
10953 */
10954static xmlChar *
10955xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10956	             xmlXPathTypeVal *type, const xmlChar **prefix,
10957		     xmlChar *name) {
10958    int blanks;
10959
10960    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10961	STRANGE;
10962	return(NULL);
10963    }
10964    *type = (xmlXPathTypeVal) 0;
10965    *test = (xmlXPathTestVal) 0;
10966    *prefix = NULL;
10967    SKIP_BLANKS;
10968
10969    if ((name == NULL) && (CUR == '*')) {
10970	/*
10971	 * All elements
10972	 */
10973	NEXT;
10974	*test = NODE_TEST_ALL;
10975	return(NULL);
10976    }
10977
10978    if (name == NULL)
10979	name = xmlXPathParseNCName(ctxt);
10980    if (name == NULL) {
10981	XP_ERRORNULL(XPATH_EXPR_ERROR);
10982    }
10983
10984    blanks = IS_BLANK_CH(CUR);
10985    SKIP_BLANKS;
10986    if (CUR == '(') {
10987	NEXT;
10988	/*
10989	 * NodeType or PI search
10990	 */
10991	if (xmlStrEqual(name, BAD_CAST "comment"))
10992	    *type = NODE_TYPE_COMMENT;
10993	else if (xmlStrEqual(name, BAD_CAST "node"))
10994	    *type = NODE_TYPE_NODE;
10995	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10996	    *type = NODE_TYPE_PI;
10997	else if (xmlStrEqual(name, BAD_CAST "text"))
10998	    *type = NODE_TYPE_TEXT;
10999	else {
11000	    if (name != NULL)
11001		xmlFree(name);
11002	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11003	}
11004
11005	*test = NODE_TEST_TYPE;
11006
11007	SKIP_BLANKS;
11008	if (*type == NODE_TYPE_PI) {
11009	    /*
11010	     * Specific case: search a PI by name.
11011	     */
11012	    if (name != NULL)
11013		xmlFree(name);
11014	    name = NULL;
11015	    if (CUR != ')') {
11016		name = xmlXPathParseLiteral(ctxt);
11017		CHECK_ERROR NULL;
11018		*test = NODE_TEST_PI;
11019		SKIP_BLANKS;
11020	    }
11021	}
11022	if (CUR != ')') {
11023	    if (name != NULL)
11024		xmlFree(name);
11025	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11026	}
11027	NEXT;
11028	return(name);
11029    }
11030    *test = NODE_TEST_NAME;
11031    if ((!blanks) && (CUR == ':')) {
11032	NEXT;
11033
11034	/*
11035	 * Since currently the parser context don't have a
11036	 * namespace list associated:
11037	 * The namespace name for this prefix can be computed
11038	 * only at evaluation time. The compilation is done
11039	 * outside of any context.
11040	 */
11041#if 0
11042	*prefix = xmlXPathNsLookup(ctxt->context, name);
11043	if (name != NULL)
11044	    xmlFree(name);
11045	if (*prefix == NULL) {
11046	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11047	}
11048#else
11049	*prefix = name;
11050#endif
11051
11052	if (CUR == '*') {
11053	    /*
11054	     * All elements
11055	     */
11056	    NEXT;
11057	    *test = NODE_TEST_ALL;
11058	    return(NULL);
11059	}
11060
11061	name = xmlXPathParseNCName(ctxt);
11062	if (name == NULL) {
11063	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11064	}
11065    }
11066    return(name);
11067}
11068
11069/**
11070 * xmlXPathIsAxisName:
11071 * @name:  a preparsed name token
11072 *
11073 * [6] AxisName ::=   'ancestor'
11074 *                  | 'ancestor-or-self'
11075 *                  | 'attribute'
11076 *                  | 'child'
11077 *                  | 'descendant'
11078 *                  | 'descendant-or-self'
11079 *                  | 'following'
11080 *                  | 'following-sibling'
11081 *                  | 'namespace'
11082 *                  | 'parent'
11083 *                  | 'preceding'
11084 *                  | 'preceding-sibling'
11085 *                  | 'self'
11086 *
11087 * Returns the axis or 0
11088 */
11089static xmlXPathAxisVal
11090xmlXPathIsAxisName(const xmlChar *name) {
11091    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11092    switch (name[0]) {
11093	case 'a':
11094	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11095		ret = AXIS_ANCESTOR;
11096	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11097		ret = AXIS_ANCESTOR_OR_SELF;
11098	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11099		ret = AXIS_ATTRIBUTE;
11100	    break;
11101	case 'c':
11102	    if (xmlStrEqual(name, BAD_CAST "child"))
11103		ret = AXIS_CHILD;
11104	    break;
11105	case 'd':
11106	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11107		ret = AXIS_DESCENDANT;
11108	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11109		ret = AXIS_DESCENDANT_OR_SELF;
11110	    break;
11111	case 'f':
11112	    if (xmlStrEqual(name, BAD_CAST "following"))
11113		ret = AXIS_FOLLOWING;
11114	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11115		ret = AXIS_FOLLOWING_SIBLING;
11116	    break;
11117	case 'n':
11118	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11119		ret = AXIS_NAMESPACE;
11120	    break;
11121	case 'p':
11122	    if (xmlStrEqual(name, BAD_CAST "parent"))
11123		ret = AXIS_PARENT;
11124	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11125		ret = AXIS_PRECEDING;
11126	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11127		ret = AXIS_PRECEDING_SIBLING;
11128	    break;
11129	case 's':
11130	    if (xmlStrEqual(name, BAD_CAST "self"))
11131		ret = AXIS_SELF;
11132	    break;
11133    }
11134    return(ret);
11135}
11136
11137/**
11138 * xmlXPathCompStep:
11139 * @ctxt:  the XPath Parser context
11140 *
11141 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11142 *                  | AbbreviatedStep
11143 *
11144 * [12] AbbreviatedStep ::=   '.' | '..'
11145 *
11146 * [5] AxisSpecifier ::= AxisName '::'
11147 *                  | AbbreviatedAxisSpecifier
11148 *
11149 * [13] AbbreviatedAxisSpecifier ::= '@'?
11150 *
11151 * Modified for XPtr range support as:
11152 *
11153 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11154 *                     | AbbreviatedStep
11155 *                     | 'range-to' '(' Expr ')' Predicate*
11156 *
11157 * Compile one step in a Location Path
11158 * A location step of . is short for self::node(). This is
11159 * particularly useful in conjunction with //. For example, the
11160 * location path .//para is short for
11161 * self::node()/descendant-or-self::node()/child::para
11162 * and so will select all para descendant elements of the context
11163 * node.
11164 * Similarly, a location step of .. is short for parent::node().
11165 * For example, ../title is short for parent::node()/child::title
11166 * and so will select the title children of the parent of the context
11167 * node.
11168 */
11169static void
11170xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11171#ifdef LIBXML_XPTR_ENABLED
11172    int rangeto = 0;
11173    int op2 = -1;
11174#endif
11175
11176    SKIP_BLANKS;
11177    if ((CUR == '.') && (NXT(1) == '.')) {
11178	SKIP(2);
11179	SKIP_BLANKS;
11180	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11181		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11182    } else if (CUR == '.') {
11183	NEXT;
11184	SKIP_BLANKS;
11185    } else {
11186	xmlChar *name = NULL;
11187	const xmlChar *prefix = NULL;
11188	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11189	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11190	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11191	int op1;
11192
11193	/*
11194	 * The modification needed for XPointer change to the production
11195	 */
11196#ifdef LIBXML_XPTR_ENABLED
11197	if (ctxt->xptr) {
11198	    name = xmlXPathParseNCName(ctxt);
11199	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11200                op2 = ctxt->comp->last;
11201		xmlFree(name);
11202		SKIP_BLANKS;
11203		if (CUR != '(') {
11204		    XP_ERROR(XPATH_EXPR_ERROR);
11205		}
11206		NEXT;
11207		SKIP_BLANKS;
11208
11209		xmlXPathCompileExpr(ctxt, 1);
11210		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11211		CHECK_ERROR;
11212
11213		SKIP_BLANKS;
11214		if (CUR != ')') {
11215		    XP_ERROR(XPATH_EXPR_ERROR);
11216		}
11217		NEXT;
11218		rangeto = 1;
11219		goto eval_predicates;
11220	    }
11221	}
11222#endif
11223	if (CUR == '*') {
11224	    axis = AXIS_CHILD;
11225	} else {
11226	    if (name == NULL)
11227		name = xmlXPathParseNCName(ctxt);
11228	    if (name != NULL) {
11229		axis = xmlXPathIsAxisName(name);
11230		if (axis != 0) {
11231		    SKIP_BLANKS;
11232		    if ((CUR == ':') && (NXT(1) == ':')) {
11233			SKIP(2);
11234			xmlFree(name);
11235			name = NULL;
11236		    } else {
11237			/* an element name can conflict with an axis one :-\ */
11238			axis = AXIS_CHILD;
11239		    }
11240		} else {
11241		    axis = AXIS_CHILD;
11242		}
11243	    } else if (CUR == '@') {
11244		NEXT;
11245		axis = AXIS_ATTRIBUTE;
11246	    } else {
11247		axis = AXIS_CHILD;
11248	    }
11249	}
11250
11251	CHECK_ERROR;
11252
11253	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11254	if (test == 0)
11255	    return;
11256
11257        if ((prefix != NULL) && (ctxt->context != NULL) &&
11258	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11259	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11260		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11261	    }
11262	}
11263#ifdef DEBUG_STEP
11264	xmlGenericError(xmlGenericErrorContext,
11265		"Basis : computing new set\n");
11266#endif
11267
11268#ifdef DEBUG_STEP
11269	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11270	if (ctxt->value == NULL)
11271	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11272	else if (ctxt->value->nodesetval == NULL)
11273	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11274	else
11275	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11276#endif
11277
11278#ifdef LIBXML_XPTR_ENABLED
11279eval_predicates:
11280#endif
11281	op1 = ctxt->comp->last;
11282	ctxt->comp->last = -1;
11283
11284	SKIP_BLANKS;
11285	while (CUR == '[') {
11286	    xmlXPathCompPredicate(ctxt, 0);
11287	}
11288
11289#ifdef LIBXML_XPTR_ENABLED
11290	if (rangeto) {
11291	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11292	} else
11293#endif
11294	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11295			   test, type, (void *)prefix, (void *)name);
11296
11297    }
11298#ifdef DEBUG_STEP
11299    xmlGenericError(xmlGenericErrorContext, "Step : ");
11300    if (ctxt->value == NULL)
11301	xmlGenericError(xmlGenericErrorContext, "no value\n");
11302    else if (ctxt->value->nodesetval == NULL)
11303	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11304    else
11305	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11306		ctxt->value->nodesetval);
11307#endif
11308}
11309
11310/**
11311 * xmlXPathCompRelativeLocationPath:
11312 * @ctxt:  the XPath Parser context
11313 *
11314 *  [3]   RelativeLocationPath ::=   Step
11315 *                     | RelativeLocationPath '/' Step
11316 *                     | AbbreviatedRelativeLocationPath
11317 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11318 *
11319 * Compile a relative location path.
11320 */
11321static void
11322xmlXPathCompRelativeLocationPath
11323(xmlXPathParserContextPtr ctxt) {
11324    SKIP_BLANKS;
11325    if ((CUR == '/') && (NXT(1) == '/')) {
11326	SKIP(2);
11327	SKIP_BLANKS;
11328	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11329		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11330    } else if (CUR == '/') {
11331	    NEXT;
11332	SKIP_BLANKS;
11333    }
11334    xmlXPathCompStep(ctxt);
11335    SKIP_BLANKS;
11336    while (CUR == '/') {
11337	if ((CUR == '/') && (NXT(1) == '/')) {
11338	    SKIP(2);
11339	    SKIP_BLANKS;
11340	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11341			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11342	    xmlXPathCompStep(ctxt);
11343	} else if (CUR == '/') {
11344	    NEXT;
11345	    SKIP_BLANKS;
11346	    xmlXPathCompStep(ctxt);
11347	}
11348	SKIP_BLANKS;
11349    }
11350}
11351
11352/**
11353 * xmlXPathCompLocationPath:
11354 * @ctxt:  the XPath Parser context
11355 *
11356 *  [1]   LocationPath ::=   RelativeLocationPath
11357 *                     | AbsoluteLocationPath
11358 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11359 *                     | AbbreviatedAbsoluteLocationPath
11360 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11361 *                           '//' RelativeLocationPath
11362 *
11363 * Compile a location path
11364 *
11365 * // is short for /descendant-or-self::node()/. For example,
11366 * //para is short for /descendant-or-self::node()/child::para and
11367 * so will select any para element in the document (even a para element
11368 * that is a document element will be selected by //para since the
11369 * document element node is a child of the root node); div//para is
11370 * short for div/descendant-or-self::node()/child::para and so will
11371 * select all para descendants of div children.
11372 */
11373static void
11374xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11375    SKIP_BLANKS;
11376    if (CUR != '/') {
11377        xmlXPathCompRelativeLocationPath(ctxt);
11378    } else {
11379	while (CUR == '/') {
11380	    if ((CUR == '/') && (NXT(1) == '/')) {
11381		SKIP(2);
11382		SKIP_BLANKS;
11383		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11384			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11385		xmlXPathCompRelativeLocationPath(ctxt);
11386	    } else if (CUR == '/') {
11387		NEXT;
11388		SKIP_BLANKS;
11389		if ((CUR != 0 ) &&
11390		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11391		     (CUR == '@') || (CUR == '*')))
11392		    xmlXPathCompRelativeLocationPath(ctxt);
11393	    }
11394	}
11395    }
11396}
11397
11398/************************************************************************
11399 *									*
11400 *		XPath precompiled expression evaluation			*
11401 *									*
11402 ************************************************************************/
11403
11404static int
11405xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11406
11407#ifdef DEBUG_STEP
11408static void
11409xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11410			  int nbNodes)
11411{
11412    xmlGenericError(xmlGenericErrorContext, "new step : ");
11413    switch (op->value) {
11414        case AXIS_ANCESTOR:
11415            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11416            break;
11417        case AXIS_ANCESTOR_OR_SELF:
11418            xmlGenericError(xmlGenericErrorContext,
11419                            "axis 'ancestors-or-self' ");
11420            break;
11421        case AXIS_ATTRIBUTE:
11422            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11423            break;
11424        case AXIS_CHILD:
11425            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11426            break;
11427        case AXIS_DESCENDANT:
11428            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11429            break;
11430        case AXIS_DESCENDANT_OR_SELF:
11431            xmlGenericError(xmlGenericErrorContext,
11432                            "axis 'descendant-or-self' ");
11433            break;
11434        case AXIS_FOLLOWING:
11435            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11436            break;
11437        case AXIS_FOLLOWING_SIBLING:
11438            xmlGenericError(xmlGenericErrorContext,
11439                            "axis 'following-siblings' ");
11440            break;
11441        case AXIS_NAMESPACE:
11442            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11443            break;
11444        case AXIS_PARENT:
11445            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11446            break;
11447        case AXIS_PRECEDING:
11448            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11449            break;
11450        case AXIS_PRECEDING_SIBLING:
11451            xmlGenericError(xmlGenericErrorContext,
11452                            "axis 'preceding-sibling' ");
11453            break;
11454        case AXIS_SELF:
11455            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11456            break;
11457    }
11458    xmlGenericError(xmlGenericErrorContext,
11459	" context contains %d nodes\n", nbNodes);
11460    switch (op->value2) {
11461        case NODE_TEST_NONE:
11462            xmlGenericError(xmlGenericErrorContext,
11463                            "           searching for none !!!\n");
11464            break;
11465        case NODE_TEST_TYPE:
11466            xmlGenericError(xmlGenericErrorContext,
11467                            "           searching for type %d\n", op->value3);
11468            break;
11469        case NODE_TEST_PI:
11470            xmlGenericError(xmlGenericErrorContext,
11471                            "           searching for PI !!!\n");
11472            break;
11473        case NODE_TEST_ALL:
11474            xmlGenericError(xmlGenericErrorContext,
11475                            "           searching for *\n");
11476            break;
11477        case NODE_TEST_NS:
11478            xmlGenericError(xmlGenericErrorContext,
11479                            "           searching for namespace %s\n",
11480                            op->value5);
11481            break;
11482        case NODE_TEST_NAME:
11483            xmlGenericError(xmlGenericErrorContext,
11484                            "           searching for name %s\n", op->value5);
11485            if (op->value4)
11486                xmlGenericError(xmlGenericErrorContext,
11487                                "           with namespace %s\n", op->value4);
11488            break;
11489    }
11490    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11491}
11492#endif /* DEBUG_STEP */
11493
11494static int
11495xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11496			    xmlXPathStepOpPtr op,
11497			    xmlNodeSetPtr set,
11498			    int contextSize,
11499			    int hasNsNodes)
11500{
11501    if (op->ch1 != -1) {
11502	xmlXPathCompExprPtr comp = ctxt->comp;
11503	/*
11504	* Process inner predicates first.
11505	*/
11506	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11507	    /*
11508	    * TODO: raise an internal error.
11509	    */
11510	}
11511	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11512	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11513	CHECK_ERROR0;
11514	if (contextSize <= 0)
11515	    return(0);
11516    }
11517    if (op->ch2 != -1) {
11518	xmlXPathContextPtr xpctxt = ctxt->context;
11519	xmlNodePtr contextNode, oldContextNode;
11520	xmlDocPtr oldContextDoc;
11521	int i, res, contextPos = 0, newContextSize;
11522	xmlXPathStepOpPtr exprOp;
11523	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11524
11525#ifdef LIBXML_XPTR_ENABLED
11526	/*
11527	* URGENT TODO: Check the following:
11528	*  We don't expect location sets if evaluating prediates, right?
11529	*  Only filters should expect location sets, right?
11530	*/
11531#endif
11532	/*
11533	* SPEC XPath 1.0:
11534	*  "For each node in the node-set to be filtered, the
11535	*  PredicateExpr is evaluated with that node as the
11536	*  context node, with the number of nodes in the
11537	*  node-set as the context size, and with the proximity
11538	*  position of the node in the node-set with respect to
11539	*  the axis as the context position;"
11540	* @oldset is the node-set" to be filtered.
11541	*
11542	* SPEC XPath 1.0:
11543	*  "only predicates change the context position and
11544	*  context size (see [2.4 Predicates])."
11545	* Example:
11546	*   node-set  context pos
11547	*    nA         1
11548	*    nB         2
11549	*    nC         3
11550	*   After applying predicate [position() > 1] :
11551	*   node-set  context pos
11552	*    nB         1
11553	*    nC         2
11554	*/
11555	oldContextNode = xpctxt->node;
11556	oldContextDoc = xpctxt->doc;
11557	/*
11558	* Get the expression of this predicate.
11559	*/
11560	exprOp = &ctxt->comp->steps[op->ch2];
11561	newContextSize = 0;
11562	for (i = 0; i < set->nodeNr; i++) {
11563	    if (set->nodeTab[i] == NULL)
11564		continue;
11565
11566	    contextNode = set->nodeTab[i];
11567	    xpctxt->node = contextNode;
11568	    xpctxt->contextSize = contextSize;
11569	    xpctxt->proximityPosition = ++contextPos;
11570
11571	    /*
11572	    * Also set the xpath document in case things like
11573	    * key() are evaluated in the predicate.
11574	    */
11575	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11576		(contextNode->doc != NULL))
11577		xpctxt->doc = contextNode->doc;
11578	    /*
11579	    * Evaluate the predicate expression with 1 context node
11580	    * at a time; this node is packaged into a node set; this
11581	    * node set is handed over to the evaluation mechanism.
11582	    */
11583	    if (contextObj == NULL)
11584		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11585	    else
11586		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11587		    contextNode);
11588
11589	    valuePush(ctxt, contextObj);
11590
11591	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11592
11593	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11594		xmlXPathNodeSetClear(set, hasNsNodes);
11595		newContextSize = 0;
11596		goto evaluation_exit;
11597	    }
11598
11599	    if (res != 0) {
11600		newContextSize++;
11601	    } else {
11602		/*
11603		* Remove the entry from the initial node set.
11604		*/
11605		set->nodeTab[i] = NULL;
11606		if (contextNode->type == XML_NAMESPACE_DECL)
11607		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11608	    }
11609	    if (ctxt->value == contextObj) {
11610		/*
11611		* Don't free the temporary XPath object holding the
11612		* context node, in order to avoid massive recreation
11613		* inside this loop.
11614		*/
11615		valuePop(ctxt);
11616		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11617	    } else {
11618		/*
11619		* TODO: The object was lost in the evaluation machinery.
11620		*  Can this happen? Maybe in internal-error cases.
11621		*/
11622		contextObj = NULL;
11623	    }
11624	}
11625
11626	if (contextObj != NULL) {
11627	    if (ctxt->value == contextObj)
11628		valuePop(ctxt);
11629	    xmlXPathReleaseObject(xpctxt, contextObj);
11630	}
11631evaluation_exit:
11632	if (exprRes != NULL)
11633	    xmlXPathReleaseObject(ctxt->context, exprRes);
11634	/*
11635	* Reset/invalidate the context.
11636	*/
11637	xpctxt->node = oldContextNode;
11638	xpctxt->doc = oldContextDoc;
11639	xpctxt->contextSize = -1;
11640	xpctxt->proximityPosition = -1;
11641	return(newContextSize);
11642    }
11643    return(contextSize);
11644}
11645
11646static int
11647xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11648				      xmlXPathStepOpPtr op,
11649				      xmlNodeSetPtr set,
11650				      int contextSize,
11651				      int minPos,
11652				      int maxPos,
11653				      int hasNsNodes)
11654{
11655    if (op->ch1 != -1) {
11656	xmlXPathCompExprPtr comp = ctxt->comp;
11657	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11658	    /*
11659	    * TODO: raise an internal error.
11660	    */
11661	}
11662	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11663	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11664	CHECK_ERROR0;
11665	if (contextSize <= 0)
11666	    return(0);
11667    }
11668    /*
11669    * Check if the node set contains a sufficient number of nodes for
11670    * the requested range.
11671    */
11672    if (contextSize < minPos) {
11673	xmlXPathNodeSetClear(set, hasNsNodes);
11674	return(0);
11675    }
11676    if (op->ch2 == -1) {
11677	/*
11678	* TODO: Can this ever happen?
11679	*/
11680	return (contextSize);
11681    } else {
11682	xmlDocPtr oldContextDoc;
11683	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11684	xmlXPathStepOpPtr exprOp;
11685	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11686	xmlNodePtr oldContextNode, contextNode = NULL;
11687	xmlXPathContextPtr xpctxt = ctxt->context;
11688
11689#ifdef LIBXML_XPTR_ENABLED
11690	    /*
11691	    * URGENT TODO: Check the following:
11692	    *  We don't expect location sets if evaluating prediates, right?
11693	    *  Only filters should expect location sets, right?
11694	*/
11695#endif /* LIBXML_XPTR_ENABLED */
11696
11697	/*
11698	* Save old context.
11699	*/
11700	oldContextNode = xpctxt->node;
11701	oldContextDoc = xpctxt->doc;
11702	/*
11703	* Get the expression of this predicate.
11704	*/
11705	exprOp = &ctxt->comp->steps[op->ch2];
11706	for (i = 0; i < set->nodeNr; i++) {
11707	    if (set->nodeTab[i] == NULL)
11708		continue;
11709
11710	    contextNode = set->nodeTab[i];
11711	    xpctxt->node = contextNode;
11712	    xpctxt->contextSize = contextSize;
11713	    xpctxt->proximityPosition = ++contextPos;
11714
11715	    /*
11716	    * Initialize the new set.
11717	    * Also set the xpath document in case things like
11718	    * key() evaluation are attempted on the predicate
11719	    */
11720	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11721		(contextNode->doc != NULL))
11722		xpctxt->doc = contextNode->doc;
11723	    /*
11724	    * Evaluate the predicate expression with 1 context node
11725	    * at a time; this node is packaged into a node set; this
11726	    * node set is handed over to the evaluation mechanism.
11727	    */
11728	    if (contextObj == NULL)
11729		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11730	    else
11731		xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11732		    contextNode);
11733
11734	    valuePush(ctxt, contextObj);
11735	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11736
11737	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11738	        xmlXPathObjectPtr tmp;
11739		/* pop the result */
11740		tmp = valuePop(ctxt);
11741		xmlXPathReleaseObject(xpctxt, tmp);
11742		/* then pop off contextObj, which will be freed later */
11743		valuePop(ctxt);
11744		goto evaluation_error;
11745	    }
11746
11747	    if (res)
11748		pos++;
11749
11750	    if (res && (pos >= minPos) && (pos <= maxPos)) {
11751		/*
11752		* Fits in the requested range.
11753		*/
11754		newContextSize++;
11755		if (minPos == maxPos) {
11756		    /*
11757		    * Only 1 node was requested.
11758		    */
11759		    if (contextNode->type == XML_NAMESPACE_DECL) {
11760			/*
11761			* As always: take care of those nasty
11762			* namespace nodes.
11763			*/
11764			set->nodeTab[i] = NULL;
11765		    }
11766		    xmlXPathNodeSetClear(set, hasNsNodes);
11767		    set->nodeNr = 1;
11768		    set->nodeTab[0] = contextNode;
11769		    goto evaluation_exit;
11770		}
11771		if (pos == maxPos) {
11772		    /*
11773		    * We are done.
11774		    */
11775		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11776		    goto evaluation_exit;
11777		}
11778	    } else {
11779		/*
11780		* Remove the entry from the initial node set.
11781		*/
11782		set->nodeTab[i] = NULL;
11783		if (contextNode->type == XML_NAMESPACE_DECL)
11784		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11785	    }
11786	    if (exprRes != NULL) {
11787		xmlXPathReleaseObject(ctxt->context, exprRes);
11788		exprRes = NULL;
11789	    }
11790	    if (ctxt->value == contextObj) {
11791		/*
11792		* Don't free the temporary XPath object holding the
11793		* context node, in order to avoid massive recreation
11794		* inside this loop.
11795		*/
11796		valuePop(ctxt);
11797		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11798	    } else {
11799		/*
11800		* The object was lost in the evaluation machinery.
11801		* Can this happen? Maybe in case of internal-errors.
11802		*/
11803		contextObj = NULL;
11804	    }
11805	}
11806	goto evaluation_exit;
11807
11808evaluation_error:
11809	xmlXPathNodeSetClear(set, hasNsNodes);
11810	newContextSize = 0;
11811
11812evaluation_exit:
11813	if (contextObj != NULL) {
11814	    if (ctxt->value == contextObj)
11815		valuePop(ctxt);
11816	    xmlXPathReleaseObject(xpctxt, contextObj);
11817	}
11818	if (exprRes != NULL)
11819	    xmlXPathReleaseObject(ctxt->context, exprRes);
11820	/*
11821	* Reset/invalidate the context.
11822	*/
11823	xpctxt->node = oldContextNode;
11824	xpctxt->doc = oldContextDoc;
11825	xpctxt->contextSize = -1;
11826	xpctxt->proximityPosition = -1;
11827	return(newContextSize);
11828    }
11829    return(contextSize);
11830}
11831
11832static int
11833xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11834			    xmlXPathStepOpPtr op,
11835			    int *maxPos)
11836{
11837
11838    xmlXPathStepOpPtr exprOp;
11839
11840    /*
11841    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11842    */
11843
11844    /*
11845    * If not -1, then ch1 will point to:
11846    * 1) For predicates (XPATH_OP_PREDICATE):
11847    *    - an inner predicate operator
11848    * 2) For filters (XPATH_OP_FILTER):
11849    *    - an inner filter operater OR
11850    *    - an expression selecting the node set.
11851    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11852    */
11853    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11854	return(0);
11855
11856    if (op->ch2 != -1) {
11857	exprOp = &ctxt->comp->steps[op->ch2];
11858    } else
11859	return(0);
11860
11861    if ((exprOp != NULL) &&
11862	(exprOp->op == XPATH_OP_VALUE) &&
11863	(exprOp->value4 != NULL) &&
11864	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11865    {
11866	/*
11867	* We have a "[n]" predicate here.
11868	* TODO: Unfortunately this simplistic test here is not
11869	* able to detect a position() predicate in compound
11870	* expressions like "[@attr = 'a" and position() = 1],
11871	* and even not the usage of position() in
11872	* "[position() = 1]"; thus - obviously - a position-range,
11873	* like it "[position() < 5]", is also not detected.
11874	* Maybe we could rewrite the AST to ease the optimization.
11875	*/
11876	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11877
11878	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11879	    (float) *maxPos)
11880	{
11881	    return(1);
11882	}
11883    }
11884    return(0);
11885}
11886
11887static int
11888xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11889                           xmlXPathStepOpPtr op,
11890			   xmlNodePtr * first, xmlNodePtr * last,
11891			   int toBool)
11892{
11893
11894#define XP_TEST_HIT \
11895    if (hasAxisRange != 0) { \
11896	if (++pos == maxPos) { \
11897	    addNode(seq, cur); \
11898	goto axis_range_end; } \
11899    } else { \
11900	addNode(seq, cur); \
11901	if (breakOnFirstHit) goto first_hit; }
11902
11903#define XP_TEST_HIT_NS \
11904    if (hasAxisRange != 0) { \
11905	if (++pos == maxPos) { \
11906	    hasNsNodes = 1; \
11907	    xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11908	goto axis_range_end; } \
11909    } else { \
11910	hasNsNodes = 1; \
11911	xmlXPathNodeSetAddNs(seq, \
11912	xpctxt->node, (xmlNsPtr) cur); \
11913	if (breakOnFirstHit) goto first_hit; }
11914
11915    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11916    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11917    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11918    const xmlChar *prefix = op->value4;
11919    const xmlChar *name = op->value5;
11920    const xmlChar *URI = NULL;
11921
11922#ifdef DEBUG_STEP
11923    int nbMatches = 0, prevMatches = 0;
11924#endif
11925    int total = 0, hasNsNodes = 0;
11926    /* The popped object holding the context nodes */
11927    xmlXPathObjectPtr obj;
11928    /* The set of context nodes for the node tests */
11929    xmlNodeSetPtr contextSeq;
11930    int contextIdx;
11931    xmlNodePtr contextNode;
11932    /* The context node for a compound traversal */
11933    xmlNodePtr outerContextNode;
11934    /* The final resulting node set wrt to all context nodes */
11935    xmlNodeSetPtr outSeq;
11936    /*
11937    * The temporary resulting node set wrt 1 context node.
11938    * Used to feed predicate evaluation.
11939    */
11940    xmlNodeSetPtr seq;
11941    xmlNodePtr cur;
11942    /* First predicate operator */
11943    xmlXPathStepOpPtr predOp;
11944    int maxPos; /* The requested position() (when a "[n]" predicate) */
11945    int hasPredicateRange, hasAxisRange, pos, size, newSize;
11946    int breakOnFirstHit;
11947
11948    xmlXPathTraversalFunction next = NULL;
11949    /* compound axis traversal */
11950    xmlXPathTraversalFunctionExt outerNext = NULL;
11951    void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11952    xmlXPathNodeSetMergeFunction mergeAndClear;
11953    xmlNodePtr oldContextNode;
11954    xmlXPathContextPtr xpctxt = ctxt->context;
11955
11956
11957    CHECK_TYPE0(XPATH_NODESET);
11958    obj = valuePop(ctxt);
11959    /*
11960    * Setup namespaces.
11961    */
11962    if (prefix != NULL) {
11963        URI = xmlXPathNsLookup(xpctxt, prefix);
11964        if (URI == NULL) {
11965	    xmlXPathReleaseObject(xpctxt, obj);
11966            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11967	}
11968    }
11969    /*
11970    * Setup axis.
11971    *
11972    * MAYBE FUTURE TODO: merging optimizations:
11973    * - If the nodes to be traversed wrt to the initial nodes and
11974    *   the current axis cannot overlap, then we could avoid searching
11975    *   for duplicates during the merge.
11976    *   But the question is how/when to evaluate if they cannot overlap.
11977    *   Example: if we know that for two initial nodes, the one is
11978    *   not in the ancestor-or-self axis of the other, then we could safely
11979    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11980    *   the descendant-or-self axis.
11981    */
11982    addNode = xmlXPathNodeSetAdd;
11983    mergeAndClear = xmlXPathNodeSetMergeAndClear;
11984    switch (axis) {
11985        case AXIS_ANCESTOR:
11986            first = NULL;
11987            next = xmlXPathNextAncestor;
11988            break;
11989        case AXIS_ANCESTOR_OR_SELF:
11990            first = NULL;
11991            next = xmlXPathNextAncestorOrSelf;
11992            break;
11993        case AXIS_ATTRIBUTE:
11994            first = NULL;
11995	    last = NULL;
11996            next = xmlXPathNextAttribute;
11997	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11998            break;
11999        case AXIS_CHILD:
12000	    last = NULL;
12001	    if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12002		/*
12003		* This iterator will give us only nodes which can
12004		* hold element nodes.
12005		*/
12006		outerNext = xmlXPathNextDescendantOrSelfElemParent;
12007	    }
12008	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12009		(type == NODE_TYPE_NODE))
12010	    {
12011		/*
12012		* Optimization if an element node type is 'element'.
12013		*/
12014		next = xmlXPathNextChildElement;
12015	    } else
12016		next = xmlXPathNextChild;
12017	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12018            break;
12019        case AXIS_DESCENDANT:
12020	    last = NULL;
12021            next = xmlXPathNextDescendant;
12022            break;
12023        case AXIS_DESCENDANT_OR_SELF:
12024	    last = NULL;
12025            next = xmlXPathNextDescendantOrSelf;
12026            break;
12027        case AXIS_FOLLOWING:
12028	    last = NULL;
12029            next = xmlXPathNextFollowing;
12030            break;
12031        case AXIS_FOLLOWING_SIBLING:
12032	    last = NULL;
12033            next = xmlXPathNextFollowingSibling;
12034            break;
12035        case AXIS_NAMESPACE:
12036            first = NULL;
12037	    last = NULL;
12038            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12039	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12040            break;
12041        case AXIS_PARENT:
12042            first = NULL;
12043            next = xmlXPathNextParent;
12044            break;
12045        case AXIS_PRECEDING:
12046            first = NULL;
12047            next = xmlXPathNextPrecedingInternal;
12048            break;
12049        case AXIS_PRECEDING_SIBLING:
12050            first = NULL;
12051            next = xmlXPathNextPrecedingSibling;
12052            break;
12053        case AXIS_SELF:
12054            first = NULL;
12055	    last = NULL;
12056            next = xmlXPathNextSelf;
12057	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12058            break;
12059    }
12060
12061#ifdef DEBUG_STEP
12062    xmlXPathDebugDumpStepAxis(op,
12063	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12064#endif
12065
12066    if (next == NULL) {
12067	xmlXPathReleaseObject(xpctxt, obj);
12068        return(0);
12069    }
12070    contextSeq = obj->nodesetval;
12071    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12072	xmlXPathReleaseObject(xpctxt, obj);
12073        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12074        return(0);
12075    }
12076    /*
12077    * Predicate optimization ---------------------------------------------
12078    * If this step has a last predicate, which contains a position(),
12079    * then we'll optimize (although not exactly "position()", but only
12080    * the  short-hand form, i.e., "[n]".
12081    *
12082    * Example - expression "/foo[parent::bar][1]":
12083    *
12084    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12085    *   ROOT                               -- op->ch1
12086    *   PREDICATE                          -- op->ch2 (predOp)
12087    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12088    *       SORT
12089    *         COLLECT  'parent' 'name' 'node' bar
12090    *           NODE
12091    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12092    *
12093    */
12094    maxPos = 0;
12095    predOp = NULL;
12096    hasPredicateRange = 0;
12097    hasAxisRange = 0;
12098    if (op->ch2 != -1) {
12099	/*
12100	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12101	*/
12102	predOp = &ctxt->comp->steps[op->ch2];
12103	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12104	    if (predOp->ch1 != -1) {
12105		/*
12106		* Use the next inner predicate operator.
12107		*/
12108		predOp = &ctxt->comp->steps[predOp->ch1];
12109		hasPredicateRange = 1;
12110	    } else {
12111		/*
12112		* There's no other predicate than the [n] predicate.
12113		*/
12114		predOp = NULL;
12115		hasAxisRange = 1;
12116	    }
12117	}
12118    }
12119    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12120    /*
12121    * Axis traversal -----------------------------------------------------
12122    */
12123    /*
12124     * 2.3 Node Tests
12125     *  - For the attribute axis, the principal node type is attribute.
12126     *  - For the namespace axis, the principal node type is namespace.
12127     *  - For other axes, the principal node type is element.
12128     *
12129     * A node test * is true for any node of the
12130     * principal node type. For example, child::* will
12131     * select all element children of the context node
12132     */
12133    oldContextNode = xpctxt->node;
12134    addNode = xmlXPathNodeSetAddUnique;
12135    outSeq = NULL;
12136    seq = NULL;
12137    outerContextNode = NULL;
12138    contextNode = NULL;
12139    contextIdx = 0;
12140
12141
12142    while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12143	if (outerNext != NULL) {
12144	    /*
12145	    * This is a compound traversal.
12146	    */
12147	    if (contextNode == NULL) {
12148		/*
12149		* Set the context for the outer traversal.
12150		*/
12151		outerContextNode = contextSeq->nodeTab[contextIdx++];
12152		contextNode = outerNext(NULL, outerContextNode);
12153	    } else
12154		contextNode = outerNext(contextNode, outerContextNode);
12155	    if (contextNode == NULL)
12156		continue;
12157	    /*
12158	    * Set the context for the main traversal.
12159	    */
12160	    xpctxt->node = contextNode;
12161	} else
12162	    xpctxt->node = contextSeq->nodeTab[contextIdx++];
12163
12164	if (seq == NULL) {
12165	    seq = xmlXPathNodeSetCreate(NULL);
12166	    if (seq == NULL) {
12167		total = 0;
12168		goto error;
12169	    }
12170	}
12171	/*
12172	* Traverse the axis and test the nodes.
12173	*/
12174	pos = 0;
12175	cur = NULL;
12176	hasNsNodes = 0;
12177        do {
12178            cur = next(ctxt, cur);
12179            if (cur == NULL)
12180                break;
12181
12182	    /*
12183	    * QUESTION TODO: What does the "first" and "last" stuff do?
12184	    */
12185            if ((first != NULL) && (*first != NULL)) {
12186		if (*first == cur)
12187		    break;
12188		if (((total % 256) == 0) &&
12189#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12190		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12191#else
12192		    (xmlXPathCmpNodes(*first, cur) >= 0))
12193#endif
12194		{
12195		    break;
12196		}
12197	    }
12198	    if ((last != NULL) && (*last != NULL)) {
12199		if (*last == cur)
12200		    break;
12201		if (((total % 256) == 0) &&
12202#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12203		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12204#else
12205		    (xmlXPathCmpNodes(cur, *last) >= 0))
12206#endif
12207		{
12208		    break;
12209		}
12210	    }
12211
12212            total++;
12213
12214#ifdef DEBUG_STEP
12215            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12216#endif
12217
12218	    switch (test) {
12219                case NODE_TEST_NONE:
12220		    total = 0;
12221                    STRANGE
12222		    goto error;
12223                case NODE_TEST_TYPE:
12224		    /*
12225		    * TODO: Don't we need to use
12226		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
12227		    *  Surprisingly, some c14n tests fail, if we do this.
12228		    */
12229		    if (type == NODE_TYPE_NODE) {
12230			switch (cur->type) {
12231			    case XML_DOCUMENT_NODE:
12232			    case XML_HTML_DOCUMENT_NODE:
12233#ifdef LIBXML_DOCB_ENABLED
12234			    case XML_DOCB_DOCUMENT_NODE:
12235#endif
12236			    case XML_ELEMENT_NODE:
12237			    case XML_ATTRIBUTE_NODE:
12238			    case XML_PI_NODE:
12239			    case XML_COMMENT_NODE:
12240			    case XML_CDATA_SECTION_NODE:
12241			    case XML_TEXT_NODE:
12242			    case XML_NAMESPACE_DECL:
12243				XP_TEST_HIT
12244				break;
12245			    default:
12246				break;
12247			}
12248		    } else if (cur->type == type) {
12249			if (type == XML_NAMESPACE_DECL)
12250			    XP_TEST_HIT_NS
12251			else
12252			    XP_TEST_HIT
12253		    } else if ((type == NODE_TYPE_TEXT) &&
12254			 (cur->type == XML_CDATA_SECTION_NODE))
12255		    {
12256			XP_TEST_HIT
12257		    }
12258		    break;
12259                case NODE_TEST_PI:
12260                    if ((cur->type == XML_PI_NODE) &&
12261                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12262		    {
12263			XP_TEST_HIT
12264                    }
12265                    break;
12266                case NODE_TEST_ALL:
12267                    if (axis == AXIS_ATTRIBUTE) {
12268                        if (cur->type == XML_ATTRIBUTE_NODE)
12269			{
12270			    XP_TEST_HIT
12271                        }
12272                    } else if (axis == AXIS_NAMESPACE) {
12273                        if (cur->type == XML_NAMESPACE_DECL)
12274			{
12275			    XP_TEST_HIT_NS
12276                        }
12277                    } else {
12278                        if (cur->type == XML_ELEMENT_NODE) {
12279                            if (prefix == NULL)
12280			    {
12281				XP_TEST_HIT
12282
12283                            } else if ((cur->ns != NULL) &&
12284				(xmlStrEqual(URI, cur->ns->href)))
12285			    {
12286				XP_TEST_HIT
12287                            }
12288                        }
12289                    }
12290                    break;
12291                case NODE_TEST_NS:{
12292                        TODO;
12293                        break;
12294                    }
12295                case NODE_TEST_NAME:
12296                    if (axis == AXIS_ATTRIBUTE) {
12297                        if (cur->type != XML_ATTRIBUTE_NODE)
12298			    break;
12299		    } else if (axis == AXIS_NAMESPACE) {
12300                        if (cur->type != XML_NAMESPACE_DECL)
12301			    break;
12302		    } else {
12303		        if (cur->type != XML_ELEMENT_NODE)
12304			    break;
12305		    }
12306                    switch (cur->type) {
12307                        case XML_ELEMENT_NODE:
12308                            if (xmlStrEqual(name, cur->name)) {
12309                                if (prefix == NULL) {
12310                                    if (cur->ns == NULL)
12311				    {
12312					XP_TEST_HIT
12313                                    }
12314                                } else {
12315                                    if ((cur->ns != NULL) &&
12316                                        (xmlStrEqual(URI, cur->ns->href)))
12317				    {
12318					XP_TEST_HIT
12319                                    }
12320                                }
12321                            }
12322                            break;
12323                        case XML_ATTRIBUTE_NODE:{
12324                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12325
12326                                if (xmlStrEqual(name, attr->name)) {
12327                                    if (prefix == NULL) {
12328                                        if ((attr->ns == NULL) ||
12329                                            (attr->ns->prefix == NULL))
12330					{
12331					    XP_TEST_HIT
12332                                        }
12333                                    } else {
12334                                        if ((attr->ns != NULL) &&
12335                                            (xmlStrEqual(URI,
12336					      attr->ns->href)))
12337					{
12338					    XP_TEST_HIT
12339                                        }
12340                                    }
12341                                }
12342                                break;
12343                            }
12344                        case XML_NAMESPACE_DECL:
12345                            if (cur->type == XML_NAMESPACE_DECL) {
12346                                xmlNsPtr ns = (xmlNsPtr) cur;
12347
12348                                if ((ns->prefix != NULL) && (name != NULL)
12349                                    && (xmlStrEqual(ns->prefix, name)))
12350				{
12351				    XP_TEST_HIT_NS
12352                                }
12353                            }
12354                            break;
12355                        default:
12356                            break;
12357                    }
12358                    break;
12359	    } /* switch(test) */
12360        } while (cur != NULL);
12361
12362	goto apply_predicates;
12363
12364axis_range_end: /* ----------------------------------------------------- */
12365	/*
12366	* We have a "/foo[n]", and position() = n was reached.
12367	* Note that we can have as well "/foo/::parent::foo[1]", so
12368	* a duplicate-aware merge is still needed.
12369	* Merge with the result.
12370	*/
12371	if (outSeq == NULL) {
12372	    outSeq = seq;
12373	    seq = NULL;
12374	} else
12375	    outSeq = mergeAndClear(outSeq, seq, 0);
12376	/*
12377	* Break if only a true/false result was requested.
12378	*/
12379	if (toBool)
12380	    break;
12381	continue;
12382
12383first_hit: /* ---------------------------------------------------------- */
12384	/*
12385	* Break if only a true/false result was requested and
12386	* no predicates existed and a node test succeeded.
12387	*/
12388	if (outSeq == NULL) {
12389	    outSeq = seq;
12390	    seq = NULL;
12391	} else
12392	    outSeq = mergeAndClear(outSeq, seq, 0);
12393	break;
12394
12395#ifdef DEBUG_STEP
12396	if (seq != NULL)
12397	    nbMatches += seq->nodeNr;
12398#endif
12399
12400apply_predicates: /* --------------------------------------------------- */
12401        /*
12402	* Apply predicates.
12403	*/
12404        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12405	    /*
12406	    * E.g. when we have a "/foo[some expression][n]".
12407	    */
12408	    /*
12409	    * QUESTION TODO: The old predicate evaluation took into
12410	    *  account location-sets.
12411	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12412	    *  Do we expect such a set here?
12413	    *  All what I learned now from the evaluation semantics
12414	    *  does not indicate that a location-set will be processed
12415	    *  here, so this looks OK.
12416	    */
12417	    /*
12418	    * Iterate over all predicates, starting with the outermost
12419	    * predicate.
12420	    * TODO: Problem: we cannot execute the inner predicates first
12421	    *  since we cannot go back *up* the operator tree!
12422	    *  Options we have:
12423	    *  1) Use of recursive functions (like is it currently done
12424	    *     via xmlXPathCompOpEval())
12425	    *  2) Add a predicate evaluation information stack to the
12426	    *     context struct
12427	    *  3) Change the way the operators are linked; we need a
12428	    *     "parent" field on xmlXPathStepOp
12429	    *
12430	    * For the moment, I'll try to solve this with a recursive
12431	    * function: xmlXPathCompOpEvalPredicate().
12432	    */
12433	    size = seq->nodeNr;
12434	    if (hasPredicateRange != 0)
12435		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12436		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12437	    else
12438		newSize = xmlXPathCompOpEvalPredicate(ctxt,
12439		    predOp, seq, size, hasNsNodes);
12440
12441	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12442		total = 0;
12443		goto error;
12444	    }
12445	    /*
12446	    * Add the filtered set of nodes to the result node set.
12447	    */
12448	    if (newSize == 0) {
12449		/*
12450		* The predicates filtered all nodes out.
12451		*/
12452		xmlXPathNodeSetClear(seq, hasNsNodes);
12453	    } else if (seq->nodeNr > 0) {
12454		/*
12455		* Add to result set.
12456		*/
12457		if (outSeq == NULL) {
12458		    if (size != newSize) {
12459			/*
12460			* We need to merge and clear here, since
12461			* the sequence will contained NULLed entries.
12462			*/
12463			outSeq = mergeAndClear(NULL, seq, 1);
12464		    } else {
12465			outSeq = seq;
12466			seq = NULL;
12467		    }
12468		} else
12469		    outSeq = mergeAndClear(outSeq, seq,
12470			(size != newSize) ? 1: 0);
12471		/*
12472		* Break if only a true/false result was requested.
12473		*/
12474		if (toBool)
12475		    break;
12476	    }
12477        } else if (seq->nodeNr > 0) {
12478	    /*
12479	    * Add to result set.
12480	    */
12481	    if (outSeq == NULL) {
12482		outSeq = seq;
12483		seq = NULL;
12484	    } else {
12485		outSeq = mergeAndClear(outSeq, seq, 0);
12486	    }
12487	}
12488    }
12489
12490error:
12491    if ((obj->boolval) && (obj->user != NULL)) {
12492	/*
12493	* QUESTION TODO: What does this do and why?
12494	* TODO: Do we have to do this also for the "error"
12495	* cleanup further down?
12496	*/
12497	ctxt->value->boolval = 1;
12498	ctxt->value->user = obj->user;
12499	obj->user = NULL;
12500	obj->boolval = 0;
12501    }
12502    xmlXPathReleaseObject(xpctxt, obj);
12503
12504    /*
12505    * Ensure we return at least an emtpy set.
12506    */
12507    if (outSeq == NULL) {
12508	if ((seq != NULL) && (seq->nodeNr == 0))
12509	    outSeq = seq;
12510	else
12511	    outSeq = xmlXPathNodeSetCreate(NULL);
12512        /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12513    }
12514    if ((seq != NULL) && (seq != outSeq)) {
12515	 xmlXPathFreeNodeSet(seq);
12516    }
12517    /*
12518    * Hand over the result. Better to push the set also in
12519    * case of errors.
12520    */
12521    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12522    /*
12523    * Reset the context node.
12524    */
12525    xpctxt->node = oldContextNode;
12526
12527#ifdef DEBUG_STEP
12528    xmlGenericError(xmlGenericErrorContext,
12529	"\nExamined %d nodes, found %d nodes at that step\n",
12530	total, nbMatches);
12531#endif
12532
12533    return(total);
12534}
12535
12536static int
12537xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12538			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12539
12540/**
12541 * xmlXPathCompOpEvalFirst:
12542 * @ctxt:  the XPath parser context with the compiled expression
12543 * @op:  an XPath compiled operation
12544 * @first:  the first elem found so far
12545 *
12546 * Evaluate the Precompiled XPath operation searching only the first
12547 * element in document order
12548 *
12549 * Returns the number of examined objects.
12550 */
12551static int
12552xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12553                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12554{
12555    int total = 0, cur;
12556    xmlXPathCompExprPtr comp;
12557    xmlXPathObjectPtr arg1, arg2;
12558
12559    CHECK_ERROR0;
12560    comp = ctxt->comp;
12561    switch (op->op) {
12562        case XPATH_OP_END:
12563            return (0);
12564        case XPATH_OP_UNION:
12565            total =
12566                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12567                                        first);
12568	    CHECK_ERROR0;
12569            if ((ctxt->value != NULL)
12570                && (ctxt->value->type == XPATH_NODESET)
12571                && (ctxt->value->nodesetval != NULL)
12572                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12573                /*
12574                 * limit tree traversing to first node in the result
12575                 */
12576		/*
12577		* OPTIMIZE TODO: This implicitely sorts
12578		*  the result, even if not needed. E.g. if the argument
12579		*  of the count() function, no sorting is needed.
12580		* OPTIMIZE TODO: How do we know if the node-list wasn't
12581		*  aready sorted?
12582		*/
12583		if (ctxt->value->nodesetval->nodeNr > 1)
12584		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12585                *first = ctxt->value->nodesetval->nodeTab[0];
12586            }
12587            cur =
12588                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12589                                        first);
12590	    CHECK_ERROR0;
12591            CHECK_TYPE0(XPATH_NODESET);
12592            arg2 = valuePop(ctxt);
12593
12594            CHECK_TYPE0(XPATH_NODESET);
12595            arg1 = valuePop(ctxt);
12596
12597            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12598                                                    arg2->nodesetval);
12599            valuePush(ctxt, arg1);
12600	    xmlXPathReleaseObject(ctxt->context, arg2);
12601            /* optimizer */
12602	    if (total > cur)
12603		xmlXPathCompSwap(op);
12604            return (total + cur);
12605        case XPATH_OP_ROOT:
12606            xmlXPathRoot(ctxt);
12607            return (0);
12608        case XPATH_OP_NODE:
12609            if (op->ch1 != -1)
12610                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12611	    CHECK_ERROR0;
12612            if (op->ch2 != -1)
12613                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12614	    CHECK_ERROR0;
12615	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12616		ctxt->context->node));
12617            return (total);
12618        case XPATH_OP_RESET:
12619            if (op->ch1 != -1)
12620                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12621	    CHECK_ERROR0;
12622            if (op->ch2 != -1)
12623                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12624	    CHECK_ERROR0;
12625            ctxt->context->node = NULL;
12626            return (total);
12627        case XPATH_OP_COLLECT:{
12628                if (op->ch1 == -1)
12629                    return (total);
12630
12631                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12632		CHECK_ERROR0;
12633
12634                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12635                return (total);
12636            }
12637        case XPATH_OP_VALUE:
12638            valuePush(ctxt,
12639                      xmlXPathCacheObjectCopy(ctxt->context,
12640			(xmlXPathObjectPtr) op->value4));
12641            return (0);
12642        case XPATH_OP_SORT:
12643            if (op->ch1 != -1)
12644                total +=
12645                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12646                                            first);
12647	    CHECK_ERROR0;
12648            if ((ctxt->value != NULL)
12649                && (ctxt->value->type == XPATH_NODESET)
12650                && (ctxt->value->nodesetval != NULL)
12651		&& (ctxt->value->nodesetval->nodeNr > 1))
12652                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12653            return (total);
12654#ifdef XP_OPTIMIZED_FILTER_FIRST
12655	case XPATH_OP_FILTER:
12656                total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12657            return (total);
12658#endif
12659        default:
12660            return (xmlXPathCompOpEval(ctxt, op));
12661    }
12662}
12663
12664/**
12665 * xmlXPathCompOpEvalLast:
12666 * @ctxt:  the XPath parser context with the compiled expression
12667 * @op:  an XPath compiled operation
12668 * @last:  the last elem found so far
12669 *
12670 * Evaluate the Precompiled XPath operation searching only the last
12671 * element in document order
12672 *
12673 * Returns the number of nodes traversed
12674 */
12675static int
12676xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12677                       xmlNodePtr * last)
12678{
12679    int total = 0, cur;
12680    xmlXPathCompExprPtr comp;
12681    xmlXPathObjectPtr arg1, arg2;
12682    xmlNodePtr bak;
12683    xmlDocPtr bakd;
12684    int pp;
12685    int cs;
12686
12687    CHECK_ERROR0;
12688    comp = ctxt->comp;
12689    switch (op->op) {
12690        case XPATH_OP_END:
12691            return (0);
12692        case XPATH_OP_UNION:
12693	    bakd = ctxt->context->doc;
12694	    bak = ctxt->context->node;
12695	    pp = ctxt->context->proximityPosition;
12696	    cs = ctxt->context->contextSize;
12697            total =
12698                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12699	    CHECK_ERROR0;
12700            if ((ctxt->value != NULL)
12701                && (ctxt->value->type == XPATH_NODESET)
12702                && (ctxt->value->nodesetval != NULL)
12703                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12704                /*
12705                 * limit tree traversing to first node in the result
12706                 */
12707		if (ctxt->value->nodesetval->nodeNr > 1)
12708		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12709                *last =
12710                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12711                                                     nodesetval->nodeNr -
12712                                                     1];
12713            }
12714	    ctxt->context->doc = bakd;
12715	    ctxt->context->node = bak;
12716	    ctxt->context->proximityPosition = pp;
12717	    ctxt->context->contextSize = cs;
12718            cur =
12719                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12720	    CHECK_ERROR0;
12721            if ((ctxt->value != NULL)
12722                && (ctxt->value->type == XPATH_NODESET)
12723                && (ctxt->value->nodesetval != NULL)
12724                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12725            }
12726            CHECK_TYPE0(XPATH_NODESET);
12727            arg2 = valuePop(ctxt);
12728
12729            CHECK_TYPE0(XPATH_NODESET);
12730            arg1 = valuePop(ctxt);
12731
12732            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12733                                                    arg2->nodesetval);
12734            valuePush(ctxt, arg1);
12735	    xmlXPathReleaseObject(ctxt->context, arg2);
12736            /* optimizer */
12737	    if (total > cur)
12738		xmlXPathCompSwap(op);
12739            return (total + cur);
12740        case XPATH_OP_ROOT:
12741            xmlXPathRoot(ctxt);
12742            return (0);
12743        case XPATH_OP_NODE:
12744            if (op->ch1 != -1)
12745                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12746	    CHECK_ERROR0;
12747            if (op->ch2 != -1)
12748                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12749	    CHECK_ERROR0;
12750	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12751		ctxt->context->node));
12752            return (total);
12753        case XPATH_OP_RESET:
12754            if (op->ch1 != -1)
12755                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12756	    CHECK_ERROR0;
12757            if (op->ch2 != -1)
12758                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12759	    CHECK_ERROR0;
12760            ctxt->context->node = NULL;
12761            return (total);
12762        case XPATH_OP_COLLECT:{
12763                if (op->ch1 == -1)
12764                    return (0);
12765
12766                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12767		CHECK_ERROR0;
12768
12769                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12770                return (total);
12771            }
12772        case XPATH_OP_VALUE:
12773            valuePush(ctxt,
12774                      xmlXPathCacheObjectCopy(ctxt->context,
12775			(xmlXPathObjectPtr) op->value4));
12776            return (0);
12777        case XPATH_OP_SORT:
12778            if (op->ch1 != -1)
12779                total +=
12780                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12781                                           last);
12782	    CHECK_ERROR0;
12783            if ((ctxt->value != NULL)
12784                && (ctxt->value->type == XPATH_NODESET)
12785                && (ctxt->value->nodesetval != NULL)
12786		&& (ctxt->value->nodesetval->nodeNr > 1))
12787                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12788            return (total);
12789        default:
12790            return (xmlXPathCompOpEval(ctxt, op));
12791    }
12792}
12793
12794#ifdef XP_OPTIMIZED_FILTER_FIRST
12795static int
12796xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12797			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12798{
12799    int total = 0;
12800    xmlXPathCompExprPtr comp;
12801    xmlXPathObjectPtr res;
12802    xmlXPathObjectPtr obj;
12803    xmlNodeSetPtr oldset;
12804    xmlNodePtr oldnode;
12805    xmlDocPtr oldDoc;
12806    int i;
12807
12808    CHECK_ERROR0;
12809    comp = ctxt->comp;
12810    /*
12811    * Optimization for ()[last()] selection i.e. the last elem
12812    */
12813    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12814	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12815	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12816	int f = comp->steps[op->ch2].ch1;
12817
12818	if ((f != -1) &&
12819	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12820	    (comp->steps[f].value5 == NULL) &&
12821	    (comp->steps[f].value == 0) &&
12822	    (comp->steps[f].value4 != NULL) &&
12823	    (xmlStrEqual
12824	    (comp->steps[f].value4, BAD_CAST "last"))) {
12825	    xmlNodePtr last = NULL;
12826
12827	    total +=
12828		xmlXPathCompOpEvalLast(ctxt,
12829		    &comp->steps[op->ch1],
12830		    &last);
12831	    CHECK_ERROR0;
12832	    /*
12833	    * The nodeset should be in document order,
12834	    * Keep only the last value
12835	    */
12836	    if ((ctxt->value != NULL) &&
12837		(ctxt->value->type == XPATH_NODESET) &&
12838		(ctxt->value->nodesetval != NULL) &&
12839		(ctxt->value->nodesetval->nodeTab != NULL) &&
12840		(ctxt->value->nodesetval->nodeNr > 1)) {
12841		ctxt->value->nodesetval->nodeTab[0] =
12842		    ctxt->value->nodesetval->nodeTab[ctxt->
12843		    value->
12844		    nodesetval->
12845		    nodeNr -
12846		    1];
12847		ctxt->value->nodesetval->nodeNr = 1;
12848		*first = *(ctxt->value->nodesetval->nodeTab);
12849	    }
12850	    return (total);
12851	}
12852    }
12853
12854    if (op->ch1 != -1)
12855	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12856    CHECK_ERROR0;
12857    if (op->ch2 == -1)
12858	return (total);
12859    if (ctxt->value == NULL)
12860	return (total);
12861
12862#ifdef LIBXML_XPTR_ENABLED
12863    oldnode = ctxt->context->node;
12864    /*
12865    * Hum are we filtering the result of an XPointer expression
12866    */
12867    if (ctxt->value->type == XPATH_LOCATIONSET) {
12868	xmlXPathObjectPtr tmp = NULL;
12869	xmlLocationSetPtr newlocset = NULL;
12870	xmlLocationSetPtr oldlocset;
12871
12872	/*
12873	* Extract the old locset, and then evaluate the result of the
12874	* expression for all the element in the locset. use it to grow
12875	* up a new locset.
12876	*/
12877	CHECK_TYPE0(XPATH_LOCATIONSET);
12878	obj = valuePop(ctxt);
12879	oldlocset = obj->user;
12880	ctxt->context->node = NULL;
12881
12882	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12883	    ctxt->context->contextSize = 0;
12884	    ctxt->context->proximityPosition = 0;
12885	    if (op->ch2 != -1)
12886		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12887	    res = valuePop(ctxt);
12888	    if (res != NULL) {
12889		xmlXPathReleaseObject(ctxt->context, res);
12890	    }
12891	    valuePush(ctxt, obj);
12892	    CHECK_ERROR0;
12893	    return (total);
12894	}
12895	newlocset = xmlXPtrLocationSetCreate(NULL);
12896
12897	for (i = 0; i < oldlocset->locNr; i++) {
12898	    /*
12899	    * Run the evaluation with a node list made of a
12900	    * single item in the nodelocset.
12901	    */
12902	    ctxt->context->node = oldlocset->locTab[i]->user;
12903	    ctxt->context->contextSize = oldlocset->locNr;
12904	    ctxt->context->proximityPosition = i + 1;
12905	    if (tmp == NULL) {
12906		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12907		    ctxt->context->node);
12908	    } else {
12909		xmlXPathNodeSetAddUnique(tmp->nodesetval,
12910		    ctxt->context->node);
12911	    }
12912	    valuePush(ctxt, tmp);
12913	    if (op->ch2 != -1)
12914		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12915	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12916		xmlXPathFreeObject(obj);
12917		return(0);
12918	    }
12919	    /*
12920	    * The result of the evaluation need to be tested to
12921	    * decided whether the filter succeeded or not
12922	    */
12923	    res = valuePop(ctxt);
12924	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12925		xmlXPtrLocationSetAdd(newlocset,
12926		    xmlXPathCacheObjectCopy(ctxt->context,
12927			oldlocset->locTab[i]));
12928	    }
12929	    /*
12930	    * Cleanup
12931	    */
12932	    if (res != NULL) {
12933		xmlXPathReleaseObject(ctxt->context, res);
12934	    }
12935	    if (ctxt->value == tmp) {
12936		valuePop(ctxt);
12937		xmlXPathNodeSetClear(tmp->nodesetval, 1);
12938		/*
12939		* REVISIT TODO: Don't create a temporary nodeset
12940		* for everly iteration.
12941		*/
12942		/* OLD: xmlXPathFreeObject(res); */
12943	    } else
12944		tmp = NULL;
12945	    ctxt->context->node = NULL;
12946	    /*
12947	    * Only put the first node in the result, then leave.
12948	    */
12949	    if (newlocset->locNr > 0) {
12950		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
12951		break;
12952	    }
12953	}
12954	if (tmp != NULL) {
12955	    xmlXPathReleaseObject(ctxt->context, tmp);
12956	}
12957	/*
12958	* The result is used as the new evaluation locset.
12959	*/
12960	xmlXPathReleaseObject(ctxt->context, obj);
12961	ctxt->context->node = NULL;
12962	ctxt->context->contextSize = -1;
12963	ctxt->context->proximityPosition = -1;
12964	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12965	ctxt->context->node = oldnode;
12966	return (total);
12967    }
12968#endif /* LIBXML_XPTR_ENABLED */
12969
12970    /*
12971    * Extract the old set, and then evaluate the result of the
12972    * expression for all the element in the set. use it to grow
12973    * up a new set.
12974    */
12975    CHECK_TYPE0(XPATH_NODESET);
12976    obj = valuePop(ctxt);
12977    oldset = obj->nodesetval;
12978
12979    oldnode = ctxt->context->node;
12980    oldDoc = ctxt->context->doc;
12981    ctxt->context->node = NULL;
12982
12983    if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12984	ctxt->context->contextSize = 0;
12985	ctxt->context->proximityPosition = 0;
12986	/* QUESTION TODO: Why was this code commented out?
12987	    if (op->ch2 != -1)
12988		total +=
12989		    xmlXPathCompOpEval(ctxt,
12990			&comp->steps[op->ch2]);
12991	    CHECK_ERROR0;
12992	    res = valuePop(ctxt);
12993	    if (res != NULL)
12994		xmlXPathFreeObject(res);
12995	*/
12996	valuePush(ctxt, obj);
12997	ctxt->context->node = oldnode;
12998	CHECK_ERROR0;
12999    } else {
13000	xmlNodeSetPtr newset;
13001	xmlXPathObjectPtr tmp = NULL;
13002	/*
13003	* Initialize the new set.
13004	* Also set the xpath document in case things like
13005	* key() evaluation are attempted on the predicate
13006	*/
13007	newset = xmlXPathNodeSetCreate(NULL);
13008        /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13009
13010	for (i = 0; i < oldset->nodeNr; i++) {
13011	    /*
13012	    * Run the evaluation with a node list made of
13013	    * a single item in the nodeset.
13014	    */
13015	    ctxt->context->node = oldset->nodeTab[i];
13016	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13017		(oldset->nodeTab[i]->doc != NULL))
13018		ctxt->context->doc = oldset->nodeTab[i]->doc;
13019	    if (tmp == NULL) {
13020		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13021		    ctxt->context->node);
13022	    } else {
13023		xmlXPathNodeSetAddUnique(tmp->nodesetval,
13024		    ctxt->context->node);
13025	    }
13026	    valuePush(ctxt, tmp);
13027	    ctxt->context->contextSize = oldset->nodeNr;
13028	    ctxt->context->proximityPosition = i + 1;
13029	    if (op->ch2 != -1)
13030		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13031	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13032		xmlXPathFreeNodeSet(newset);
13033		xmlXPathFreeObject(obj);
13034		return(0);
13035	    }
13036	    /*
13037	    * The result of the evaluation needs to be tested to
13038	    * decide whether the filter succeeded or not
13039	    */
13040	    res = valuePop(ctxt);
13041	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13042		xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13043	    }
13044	    /*
13045	    * Cleanup
13046	    */
13047	    if (res != NULL) {
13048		xmlXPathReleaseObject(ctxt->context, res);
13049	    }
13050	    if (ctxt->value == tmp) {
13051		valuePop(ctxt);
13052		/*
13053		* Don't free the temporary nodeset
13054		* in order to avoid massive recreation inside this
13055		* loop.
13056		*/
13057		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13058	    } else
13059		tmp = NULL;
13060	    ctxt->context->node = NULL;
13061	    /*
13062	    * Only put the first node in the result, then leave.
13063	    */
13064	    if (newset->nodeNr > 0) {
13065		*first = *(newset->nodeTab);
13066		break;
13067	    }
13068	}
13069	if (tmp != NULL) {
13070	    xmlXPathReleaseObject(ctxt->context, tmp);
13071	}
13072	/*
13073	* The result is used as the new evaluation set.
13074	*/
13075	xmlXPathReleaseObject(ctxt->context, obj);
13076	ctxt->context->node = NULL;
13077	ctxt->context->contextSize = -1;
13078	ctxt->context->proximityPosition = -1;
13079	/* may want to move this past the '}' later */
13080	ctxt->context->doc = oldDoc;
13081	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13082    }
13083    ctxt->context->node = oldnode;
13084    return(total);
13085}
13086#endif /* XP_OPTIMIZED_FILTER_FIRST */
13087
13088/**
13089 * xmlXPathCompOpEval:
13090 * @ctxt:  the XPath parser context with the compiled expression
13091 * @op:  an XPath compiled operation
13092 *
13093 * Evaluate the Precompiled XPath operation
13094 * Returns the number of nodes traversed
13095 */
13096static int
13097xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13098{
13099    int total = 0;
13100    int equal, ret;
13101    xmlXPathCompExprPtr comp;
13102    xmlXPathObjectPtr arg1, arg2;
13103    xmlNodePtr bak;
13104    xmlDocPtr bakd;
13105    int pp;
13106    int cs;
13107
13108    CHECK_ERROR0;
13109    comp = ctxt->comp;
13110    switch (op->op) {
13111        case XPATH_OP_END:
13112            return (0);
13113        case XPATH_OP_AND:
13114	    bakd = ctxt->context->doc;
13115	    bak = ctxt->context->node;
13116	    pp = ctxt->context->proximityPosition;
13117	    cs = ctxt->context->contextSize;
13118            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13119	    CHECK_ERROR0;
13120            xmlXPathBooleanFunction(ctxt, 1);
13121            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13122                return (total);
13123            arg2 = valuePop(ctxt);
13124	    ctxt->context->doc = bakd;
13125	    ctxt->context->node = bak;
13126	    ctxt->context->proximityPosition = pp;
13127	    ctxt->context->contextSize = cs;
13128            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13129	    if (ctxt->error) {
13130		xmlXPathFreeObject(arg2);
13131		return(0);
13132	    }
13133            xmlXPathBooleanFunction(ctxt, 1);
13134            arg1 = valuePop(ctxt);
13135            arg1->boolval &= arg2->boolval;
13136            valuePush(ctxt, arg1);
13137	    xmlXPathReleaseObject(ctxt->context, arg2);
13138            return (total);
13139        case XPATH_OP_OR:
13140	    bakd = ctxt->context->doc;
13141	    bak = ctxt->context->node;
13142	    pp = ctxt->context->proximityPosition;
13143	    cs = ctxt->context->contextSize;
13144            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13145	    CHECK_ERROR0;
13146            xmlXPathBooleanFunction(ctxt, 1);
13147            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13148                return (total);
13149            arg2 = valuePop(ctxt);
13150	    ctxt->context->doc = bakd;
13151	    ctxt->context->node = bak;
13152	    ctxt->context->proximityPosition = pp;
13153	    ctxt->context->contextSize = cs;
13154            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13155	    if (ctxt->error) {
13156		xmlXPathFreeObject(arg2);
13157		return(0);
13158	    }
13159            xmlXPathBooleanFunction(ctxt, 1);
13160            arg1 = valuePop(ctxt);
13161            arg1->boolval |= arg2->boolval;
13162            valuePush(ctxt, arg1);
13163	    xmlXPathReleaseObject(ctxt->context, arg2);
13164            return (total);
13165        case XPATH_OP_EQUAL:
13166	    bakd = ctxt->context->doc;
13167	    bak = ctxt->context->node;
13168	    pp = ctxt->context->proximityPosition;
13169	    cs = ctxt->context->contextSize;
13170            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13171	    CHECK_ERROR0;
13172	    ctxt->context->doc = bakd;
13173	    ctxt->context->node = bak;
13174	    ctxt->context->proximityPosition = pp;
13175	    ctxt->context->contextSize = cs;
13176            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13177	    CHECK_ERROR0;
13178	    if (op->value)
13179		equal = xmlXPathEqualValues(ctxt);
13180	    else
13181		equal = xmlXPathNotEqualValues(ctxt);
13182	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13183            return (total);
13184        case XPATH_OP_CMP:
13185	    bakd = ctxt->context->doc;
13186	    bak = ctxt->context->node;
13187	    pp = ctxt->context->proximityPosition;
13188	    cs = ctxt->context->contextSize;
13189            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13190	    CHECK_ERROR0;
13191	    ctxt->context->doc = bakd;
13192	    ctxt->context->node = bak;
13193	    ctxt->context->proximityPosition = pp;
13194	    ctxt->context->contextSize = cs;
13195            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13196	    CHECK_ERROR0;
13197            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13198	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13199            return (total);
13200        case XPATH_OP_PLUS:
13201	    bakd = ctxt->context->doc;
13202	    bak = ctxt->context->node;
13203	    pp = ctxt->context->proximityPosition;
13204	    cs = ctxt->context->contextSize;
13205            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13206	    CHECK_ERROR0;
13207            if (op->ch2 != -1) {
13208		ctxt->context->doc = bakd;
13209		ctxt->context->node = bak;
13210		ctxt->context->proximityPosition = pp;
13211		ctxt->context->contextSize = cs;
13212                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13213	    }
13214	    CHECK_ERROR0;
13215            if (op->value == 0)
13216                xmlXPathSubValues(ctxt);
13217            else if (op->value == 1)
13218                xmlXPathAddValues(ctxt);
13219            else if (op->value == 2)
13220                xmlXPathValueFlipSign(ctxt);
13221            else if (op->value == 3) {
13222                CAST_TO_NUMBER;
13223                CHECK_TYPE0(XPATH_NUMBER);
13224            }
13225            return (total);
13226        case XPATH_OP_MULT:
13227	    bakd = ctxt->context->doc;
13228	    bak = ctxt->context->node;
13229	    pp = ctxt->context->proximityPosition;
13230	    cs = ctxt->context->contextSize;
13231            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13232	    CHECK_ERROR0;
13233	    ctxt->context->doc = bakd;
13234	    ctxt->context->node = bak;
13235	    ctxt->context->proximityPosition = pp;
13236	    ctxt->context->contextSize = cs;
13237            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13238	    CHECK_ERROR0;
13239            if (op->value == 0)
13240                xmlXPathMultValues(ctxt);
13241            else if (op->value == 1)
13242                xmlXPathDivValues(ctxt);
13243            else if (op->value == 2)
13244                xmlXPathModValues(ctxt);
13245            return (total);
13246        case XPATH_OP_UNION:
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            CHECK_TYPE0(XPATH_NODESET);
13260            arg2 = valuePop(ctxt);
13261
13262            CHECK_TYPE0(XPATH_NODESET);
13263            arg1 = valuePop(ctxt);
13264
13265	    if ((arg1->nodesetval == NULL) ||
13266		((arg2->nodesetval != NULL) &&
13267		 (arg2->nodesetval->nodeNr != 0)))
13268	    {
13269		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13270							arg2->nodesetval);
13271	    }
13272
13273            valuePush(ctxt, arg1);
13274	    xmlXPathReleaseObject(ctxt->context, arg2);
13275            return (total);
13276        case XPATH_OP_ROOT:
13277            xmlXPathRoot(ctxt);
13278            return (total);
13279        case XPATH_OP_NODE:
13280            if (op->ch1 != -1)
13281                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13282	    CHECK_ERROR0;
13283            if (op->ch2 != -1)
13284                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13285	    CHECK_ERROR0;
13286	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13287		ctxt->context->node));
13288            return (total);
13289        case XPATH_OP_RESET:
13290            if (op->ch1 != -1)
13291                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13292	    CHECK_ERROR0;
13293            if (op->ch2 != -1)
13294                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13295	    CHECK_ERROR0;
13296            ctxt->context->node = NULL;
13297            return (total);
13298        case XPATH_OP_COLLECT:{
13299                if (op->ch1 == -1)
13300                    return (total);
13301
13302                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13303		CHECK_ERROR0;
13304
13305                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13306                return (total);
13307            }
13308        case XPATH_OP_VALUE:
13309            valuePush(ctxt,
13310                      xmlXPathCacheObjectCopy(ctxt->context,
13311			(xmlXPathObjectPtr) op->value4));
13312            return (total);
13313        case XPATH_OP_VARIABLE:{
13314		xmlXPathObjectPtr val;
13315
13316                if (op->ch1 != -1)
13317                    total +=
13318                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13319                if (op->value5 == NULL) {
13320		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13321		    if (val == NULL) {
13322			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13323			return(0);
13324		    }
13325                    valuePush(ctxt, val);
13326		} else {
13327                    const xmlChar *URI;
13328
13329                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13330                    if (URI == NULL) {
13331                        xmlGenericError(xmlGenericErrorContext,
13332                                        "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13333                                        op->value4, op->value5);
13334                        return (total);
13335                    }
13336		    val = xmlXPathVariableLookupNS(ctxt->context,
13337                                                       op->value4, URI);
13338		    if (val == NULL) {
13339			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13340			return(0);
13341		    }
13342                    valuePush(ctxt, val);
13343                }
13344                return (total);
13345            }
13346        case XPATH_OP_FUNCTION:{
13347                xmlXPathFunction func;
13348                const xmlChar *oldFunc, *oldFuncURI;
13349		int i;
13350
13351                if (op->ch1 != -1)
13352                    total +=
13353                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13354		if (ctxt->valueNr < op->value) {
13355		    xmlGenericError(xmlGenericErrorContext,
13356			    "xmlXPathCompOpEval: parameter error\n");
13357		    ctxt->error = XPATH_INVALID_OPERAND;
13358		    return (total);
13359		}
13360		for (i = 0; i < op->value; i++)
13361		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13362			xmlGenericError(xmlGenericErrorContext,
13363				"xmlXPathCompOpEval: parameter error\n");
13364			ctxt->error = XPATH_INVALID_OPERAND;
13365			return (total);
13366		    }
13367                if (op->cache != NULL)
13368                    XML_CAST_FPTR(func) = op->cache;
13369                else {
13370                    const xmlChar *URI = NULL;
13371
13372                    if (op->value5 == NULL)
13373                        func =
13374                            xmlXPathFunctionLookup(ctxt->context,
13375                                                   op->value4);
13376                    else {
13377                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13378                        if (URI == NULL) {
13379                            xmlGenericError(xmlGenericErrorContext,
13380                                            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13381                                            op->value4, op->value5);
13382                            return (total);
13383                        }
13384                        func = xmlXPathFunctionLookupNS(ctxt->context,
13385                                                        op->value4, URI);
13386                    }
13387                    if (func == NULL) {
13388                        xmlGenericError(xmlGenericErrorContext,
13389                                        "xmlXPathCompOpEval: function %s not found\n",
13390                                        op->value4);
13391                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13392                    }
13393                    op->cache = XML_CAST_FPTR(func);
13394                    op->cacheURI = (void *) URI;
13395                }
13396                oldFunc = ctxt->context->function;
13397                oldFuncURI = ctxt->context->functionURI;
13398                ctxt->context->function = op->value4;
13399                ctxt->context->functionURI = op->cacheURI;
13400                func(ctxt, op->value);
13401                ctxt->context->function = oldFunc;
13402                ctxt->context->functionURI = oldFuncURI;
13403                return (total);
13404            }
13405        case XPATH_OP_ARG:
13406	    bakd = ctxt->context->doc;
13407	    bak = ctxt->context->node;
13408	    pp = ctxt->context->proximityPosition;
13409	    cs = ctxt->context->contextSize;
13410            if (op->ch1 != -1)
13411                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13412	    ctxt->context->contextSize = cs;
13413	    ctxt->context->proximityPosition = pp;
13414	    ctxt->context->node = bak;
13415	    ctxt->context->doc = bakd;
13416	    CHECK_ERROR0;
13417            if (op->ch2 != -1) {
13418                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13419	        ctxt->context->doc = bakd;
13420	        ctxt->context->node = bak;
13421	        CHECK_ERROR0;
13422	    }
13423            return (total);
13424        case XPATH_OP_PREDICATE:
13425        case XPATH_OP_FILTER:{
13426                xmlXPathObjectPtr res;
13427                xmlXPathObjectPtr obj, tmp;
13428                xmlNodeSetPtr newset = NULL;
13429                xmlNodeSetPtr oldset;
13430                xmlNodePtr oldnode;
13431		xmlDocPtr oldDoc;
13432                int i;
13433
13434                /*
13435                 * Optimization for ()[1] selection i.e. the first elem
13436                 */
13437                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13438#ifdef XP_OPTIMIZED_FILTER_FIRST
13439		    /*
13440		    * FILTER TODO: Can we assume that the inner processing
13441		    *  will result in an ordered list if we have an
13442		    *  XPATH_OP_FILTER?
13443		    *  What about an additional field or flag on
13444		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13445		    *  to assume anything, so it would be more robust and
13446		    *  easier to optimize.
13447		    */
13448                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13449		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13450#else
13451		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13452#endif
13453                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13454                    xmlXPathObjectPtr val;
13455
13456                    val = comp->steps[op->ch2].value4;
13457                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13458                        (val->floatval == 1.0)) {
13459                        xmlNodePtr first = NULL;
13460
13461                        total +=
13462                            xmlXPathCompOpEvalFirst(ctxt,
13463                                                    &comp->steps[op->ch1],
13464                                                    &first);
13465			CHECK_ERROR0;
13466                        /*
13467                         * The nodeset should be in document order,
13468                         * Keep only the first value
13469                         */
13470                        if ((ctxt->value != NULL) &&
13471                            (ctxt->value->type == XPATH_NODESET) &&
13472                            (ctxt->value->nodesetval != NULL) &&
13473                            (ctxt->value->nodesetval->nodeNr > 1))
13474                            ctxt->value->nodesetval->nodeNr = 1;
13475                        return (total);
13476                    }
13477                }
13478                /*
13479                 * Optimization for ()[last()] selection i.e. the last elem
13480                 */
13481                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13482                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13483                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13484                    int f = comp->steps[op->ch2].ch1;
13485
13486                    if ((f != -1) &&
13487                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13488                        (comp->steps[f].value5 == NULL) &&
13489                        (comp->steps[f].value == 0) &&
13490                        (comp->steps[f].value4 != NULL) &&
13491                        (xmlStrEqual
13492                         (comp->steps[f].value4, BAD_CAST "last"))) {
13493                        xmlNodePtr last = NULL;
13494
13495                        total +=
13496                            xmlXPathCompOpEvalLast(ctxt,
13497                                                   &comp->steps[op->ch1],
13498                                                   &last);
13499			CHECK_ERROR0;
13500                        /*
13501                         * The nodeset should be in document order,
13502                         * Keep only the last value
13503                         */
13504                        if ((ctxt->value != NULL) &&
13505                            (ctxt->value->type == XPATH_NODESET) &&
13506                            (ctxt->value->nodesetval != NULL) &&
13507                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13508                            (ctxt->value->nodesetval->nodeNr > 1)) {
13509                            ctxt->value->nodesetval->nodeTab[0] =
13510                                ctxt->value->nodesetval->nodeTab[ctxt->
13511                                                                 value->
13512                                                                 nodesetval->
13513                                                                 nodeNr -
13514                                                                 1];
13515                            ctxt->value->nodesetval->nodeNr = 1;
13516                        }
13517                        return (total);
13518                    }
13519                }
13520		/*
13521		* Process inner predicates first.
13522		* Example "index[parent::book][1]":
13523		* ...
13524		*   PREDICATE   <-- we are here "[1]"
13525		*     PREDICATE <-- process "[parent::book]" first
13526		*       SORT
13527		*         COLLECT  'parent' 'name' 'node' book
13528		*           NODE
13529		*     ELEM Object is a number : 1
13530		*/
13531                if (op->ch1 != -1)
13532                    total +=
13533                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13534		CHECK_ERROR0;
13535                if (op->ch2 == -1)
13536                    return (total);
13537                if (ctxt->value == NULL)
13538                    return (total);
13539
13540                oldnode = ctxt->context->node;
13541
13542#ifdef LIBXML_XPTR_ENABLED
13543                /*
13544                 * Hum are we filtering the result of an XPointer expression
13545                 */
13546                if (ctxt->value->type == XPATH_LOCATIONSET) {
13547                    xmlLocationSetPtr newlocset = NULL;
13548                    xmlLocationSetPtr oldlocset;
13549
13550                    /*
13551                     * Extract the old locset, and then evaluate the result of the
13552                     * expression for all the element in the locset. use it to grow
13553                     * up a new locset.
13554                     */
13555                    CHECK_TYPE0(XPATH_LOCATIONSET);
13556                    obj = valuePop(ctxt);
13557                    oldlocset = obj->user;
13558                    ctxt->context->node = NULL;
13559
13560                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13561                        ctxt->context->contextSize = 0;
13562                        ctxt->context->proximityPosition = 0;
13563                        if (op->ch2 != -1)
13564                            total +=
13565                                xmlXPathCompOpEval(ctxt,
13566                                                   &comp->steps[op->ch2]);
13567                        res = valuePop(ctxt);
13568                        if (res != NULL) {
13569			    xmlXPathReleaseObject(ctxt->context, res);
13570			}
13571                        valuePush(ctxt, obj);
13572                        CHECK_ERROR0;
13573                        return (total);
13574                    }
13575                    newlocset = xmlXPtrLocationSetCreate(NULL);
13576
13577                    for (i = 0; i < oldlocset->locNr; i++) {
13578                        /*
13579                         * Run the evaluation with a node list made of a
13580                         * single item in the nodelocset.
13581                         */
13582                        ctxt->context->node = oldlocset->locTab[i]->user;
13583                        ctxt->context->contextSize = oldlocset->locNr;
13584                        ctxt->context->proximityPosition = i + 1;
13585			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13586			    ctxt->context->node);
13587                        valuePush(ctxt, tmp);
13588
13589                        if (op->ch2 != -1)
13590                            total +=
13591                                xmlXPathCompOpEval(ctxt,
13592                                                   &comp->steps[op->ch2]);
13593			if (ctxt->error != XPATH_EXPRESSION_OK) {
13594			    xmlXPathFreeObject(obj);
13595			    return(0);
13596			}
13597
13598                        /*
13599                         * The result of the evaluation need to be tested to
13600                         * decided whether the filter succeeded or not
13601                         */
13602                        res = valuePop(ctxt);
13603                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13604                            xmlXPtrLocationSetAdd(newlocset,
13605                                                  xmlXPathObjectCopy
13606                                                  (oldlocset->locTab[i]));
13607                        }
13608
13609                        /*
13610                         * Cleanup
13611                         */
13612                        if (res != NULL) {
13613			    xmlXPathReleaseObject(ctxt->context, res);
13614			}
13615                        if (ctxt->value == tmp) {
13616                            res = valuePop(ctxt);
13617			    xmlXPathReleaseObject(ctxt->context, res);
13618                        }
13619
13620                        ctxt->context->node = NULL;
13621                    }
13622
13623                    /*
13624                     * The result is used as the new evaluation locset.
13625                     */
13626		    xmlXPathReleaseObject(ctxt->context, obj);
13627                    ctxt->context->node = NULL;
13628                    ctxt->context->contextSize = -1;
13629                    ctxt->context->proximityPosition = -1;
13630                    valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13631                    ctxt->context->node = oldnode;
13632                    return (total);
13633                }
13634#endif /* LIBXML_XPTR_ENABLED */
13635
13636                /*
13637                 * Extract the old set, and then evaluate the result of the
13638                 * expression for all the element in the set. use it to grow
13639                 * up a new set.
13640                 */
13641                CHECK_TYPE0(XPATH_NODESET);
13642                obj = valuePop(ctxt);
13643                oldset = obj->nodesetval;
13644
13645                oldnode = ctxt->context->node;
13646		oldDoc = ctxt->context->doc;
13647                ctxt->context->node = NULL;
13648
13649                if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13650                    ctxt->context->contextSize = 0;
13651                    ctxt->context->proximityPosition = 0;
13652/*
13653                    if (op->ch2 != -1)
13654                        total +=
13655                            xmlXPathCompOpEval(ctxt,
13656                                               &comp->steps[op->ch2]);
13657		    CHECK_ERROR0;
13658                    res = valuePop(ctxt);
13659                    if (res != NULL)
13660                        xmlXPathFreeObject(res);
13661*/
13662                    valuePush(ctxt, obj);
13663                    ctxt->context->node = oldnode;
13664                    CHECK_ERROR0;
13665                } else {
13666		    tmp = NULL;
13667                    /*
13668                     * Initialize the new set.
13669		     * Also set the xpath document in case things like
13670		     * key() evaluation are attempted on the predicate
13671                     */
13672                    newset = xmlXPathNodeSetCreate(NULL);
13673		    /*
13674		    * SPEC XPath 1.0:
13675		    *  "For each node in the node-set to be filtered, the
13676		    *  PredicateExpr is evaluated with that node as the
13677		    *  context node, with the number of nodes in the
13678		    *  node-set as the context size, and with the proximity
13679		    *  position of the node in the node-set with respect to
13680		    *  the axis as the context position;"
13681		    * @oldset is the node-set" to be filtered.
13682		    *
13683		    * SPEC XPath 1.0:
13684		    *  "only predicates change the context position and
13685		    *  context size (see [2.4 Predicates])."
13686		    * Example:
13687		    *   node-set  context pos
13688		    *    nA         1
13689		    *    nB         2
13690		    *    nC         3
13691		    *   After applying predicate [position() > 1] :
13692		    *   node-set  context pos
13693		    *    nB         1
13694		    *    nC         2
13695		    *
13696		    * removed the first node in the node-set, then
13697		    * the context position of the
13698		    */
13699                    for (i = 0; i < oldset->nodeNr; i++) {
13700                        /*
13701                         * Run the evaluation with a node list made of
13702                         * a single item in the nodeset.
13703                         */
13704                        ctxt->context->node = oldset->nodeTab[i];
13705			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13706			    (oldset->nodeTab[i]->doc != NULL))
13707		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13708			if (tmp == NULL) {
13709			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13710				ctxt->context->node);
13711			} else {
13712			    xmlXPathNodeSetAddUnique(tmp->nodesetval,
13713				ctxt->context->node);
13714			}
13715                        valuePush(ctxt, tmp);
13716                        ctxt->context->contextSize = oldset->nodeNr;
13717                        ctxt->context->proximityPosition = i + 1;
13718			/*
13719			* Evaluate the predicate against the context node.
13720			* Can/should we optimize position() predicates
13721			* here (e.g. "[1]")?
13722			*/
13723                        if (op->ch2 != -1)
13724                            total +=
13725                                xmlXPathCompOpEval(ctxt,
13726                                                   &comp->steps[op->ch2]);
13727			if (ctxt->error != XPATH_EXPRESSION_OK) {
13728			    xmlXPathFreeNodeSet(newset);
13729			    xmlXPathFreeObject(obj);
13730			    return(0);
13731			}
13732
13733                        /*
13734                         * The result of the evaluation needs to be tested to
13735                         * decide whether the filter succeeded or not
13736                         */
13737			/*
13738			* OPTIMIZE TODO: Can we use
13739			* xmlXPathNodeSetAdd*Unique()* instead?
13740			*/
13741                        res = valuePop(ctxt);
13742                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13743                            xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13744                        }
13745
13746                        /*
13747                         * Cleanup
13748                         */
13749                        if (res != NULL) {
13750			    xmlXPathReleaseObject(ctxt->context, res);
13751			}
13752                        if (ctxt->value == tmp) {
13753                            valuePop(ctxt);
13754			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13755			    /*
13756			    * Don't free the temporary nodeset
13757			    * in order to avoid massive recreation inside this
13758			    * loop.
13759			    */
13760                        } else
13761			    tmp = NULL;
13762                        ctxt->context->node = NULL;
13763                    }
13764		    if (tmp != NULL)
13765			xmlXPathReleaseObject(ctxt->context, tmp);
13766                    /*
13767                     * The result is used as the new evaluation set.
13768                     */
13769		    xmlXPathReleaseObject(ctxt->context, obj);
13770                    ctxt->context->node = NULL;
13771                    ctxt->context->contextSize = -1;
13772                    ctxt->context->proximityPosition = -1;
13773		    /* may want to move this past the '}' later */
13774		    ctxt->context->doc = oldDoc;
13775		    valuePush(ctxt,
13776			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13777                }
13778                ctxt->context->node = oldnode;
13779                return (total);
13780            }
13781        case XPATH_OP_SORT:
13782            if (op->ch1 != -1)
13783                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13784	    CHECK_ERROR0;
13785            if ((ctxt->value != NULL) &&
13786                (ctxt->value->type == XPATH_NODESET) &&
13787                (ctxt->value->nodesetval != NULL) &&
13788		(ctxt->value->nodesetval->nodeNr > 1))
13789	    {
13790                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13791	    }
13792            return (total);
13793#ifdef LIBXML_XPTR_ENABLED
13794        case XPATH_OP_RANGETO:{
13795                xmlXPathObjectPtr range;
13796                xmlXPathObjectPtr res, obj;
13797                xmlXPathObjectPtr tmp;
13798                xmlLocationSetPtr newlocset = NULL;
13799		    xmlLocationSetPtr oldlocset;
13800                xmlNodeSetPtr oldset;
13801                int i, j;
13802
13803                if (op->ch1 != -1)
13804                    total +=
13805                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13806                if (op->ch2 == -1)
13807                    return (total);
13808
13809                if (ctxt->value->type == XPATH_LOCATIONSET) {
13810                    /*
13811                     * Extract the old locset, and then evaluate the result of the
13812                     * expression for all the element in the locset. use it to grow
13813                     * up a new locset.
13814                     */
13815                    CHECK_TYPE0(XPATH_LOCATIONSET);
13816                    obj = valuePop(ctxt);
13817                    oldlocset = obj->user;
13818
13819                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13820		        ctxt->context->node = NULL;
13821                        ctxt->context->contextSize = 0;
13822                        ctxt->context->proximityPosition = 0;
13823                        total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13824                        res = valuePop(ctxt);
13825                        if (res != NULL) {
13826			    xmlXPathReleaseObject(ctxt->context, res);
13827			}
13828                        valuePush(ctxt, obj);
13829                        CHECK_ERROR0;
13830                        return (total);
13831                    }
13832                    newlocset = xmlXPtrLocationSetCreate(NULL);
13833
13834                    for (i = 0; i < oldlocset->locNr; i++) {
13835                        /*
13836                         * Run the evaluation with a node list made of a
13837                         * single item in the nodelocset.
13838                         */
13839                        ctxt->context->node = oldlocset->locTab[i]->user;
13840                        ctxt->context->contextSize = oldlocset->locNr;
13841                        ctxt->context->proximityPosition = i + 1;
13842			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13843			    ctxt->context->node);
13844                        valuePush(ctxt, tmp);
13845
13846                        if (op->ch2 != -1)
13847                            total +=
13848                                xmlXPathCompOpEval(ctxt,
13849                                                   &comp->steps[op->ch2]);
13850			if (ctxt->error != XPATH_EXPRESSION_OK) {
13851			    xmlXPathFreeObject(obj);
13852			    return(0);
13853			}
13854
13855                        res = valuePop(ctxt);
13856			if (res->type == XPATH_LOCATIONSET) {
13857			    xmlLocationSetPtr rloc =
13858			        (xmlLocationSetPtr)res->user;
13859			    for (j=0; j<rloc->locNr; j++) {
13860			        range = xmlXPtrNewRange(
13861				  oldlocset->locTab[i]->user,
13862				  oldlocset->locTab[i]->index,
13863				  rloc->locTab[j]->user2,
13864				  rloc->locTab[j]->index2);
13865				if (range != NULL) {
13866				    xmlXPtrLocationSetAdd(newlocset, range);
13867				}
13868			    }
13869			} else {
13870			    range = xmlXPtrNewRangeNodeObject(
13871				(xmlNodePtr)oldlocset->locTab[i]->user, res);
13872                            if (range != NULL) {
13873                                xmlXPtrLocationSetAdd(newlocset,range);
13874			    }
13875                        }
13876
13877                        /*
13878                         * Cleanup
13879                         */
13880                        if (res != NULL) {
13881			    xmlXPathReleaseObject(ctxt->context, res);
13882			}
13883                        if (ctxt->value == tmp) {
13884                            res = valuePop(ctxt);
13885			    xmlXPathReleaseObject(ctxt->context, res);
13886                        }
13887
13888                        ctxt->context->node = NULL;
13889                    }
13890		} else {	/* Not a location set */
13891                    CHECK_TYPE0(XPATH_NODESET);
13892                    obj = valuePop(ctxt);
13893                    oldset = obj->nodesetval;
13894                    ctxt->context->node = NULL;
13895
13896                    newlocset = xmlXPtrLocationSetCreate(NULL);
13897
13898                    if (oldset != NULL) {
13899                        for (i = 0; i < oldset->nodeNr; i++) {
13900                            /*
13901                             * Run the evaluation with a node list made of a single item
13902                             * in the nodeset.
13903                             */
13904                            ctxt->context->node = oldset->nodeTab[i];
13905			    /*
13906			    * OPTIMIZE TODO: Avoid recreation for every iteration.
13907			    */
13908			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13909				ctxt->context->node);
13910                            valuePush(ctxt, tmp);
13911
13912                            if (op->ch2 != -1)
13913                                total +=
13914                                    xmlXPathCompOpEval(ctxt,
13915                                                   &comp->steps[op->ch2]);
13916			    if (ctxt->error != XPATH_EXPRESSION_OK) {
13917				xmlXPathFreeObject(obj);
13918				return(0);
13919			    }
13920
13921                            res = valuePop(ctxt);
13922                            range =
13923                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13924                                                      res);
13925                            if (range != NULL) {
13926                                xmlXPtrLocationSetAdd(newlocset, range);
13927                            }
13928
13929                            /*
13930                             * Cleanup
13931                             */
13932                            if (res != NULL) {
13933				xmlXPathReleaseObject(ctxt->context, res);
13934			    }
13935                            if (ctxt->value == tmp) {
13936                                res = valuePop(ctxt);
13937				xmlXPathReleaseObject(ctxt->context, res);
13938                            }
13939
13940                            ctxt->context->node = NULL;
13941                        }
13942                    }
13943                }
13944
13945                /*
13946                 * The result is used as the new evaluation set.
13947                 */
13948		xmlXPathReleaseObject(ctxt->context, obj);
13949                ctxt->context->node = NULL;
13950                ctxt->context->contextSize = -1;
13951                ctxt->context->proximityPosition = -1;
13952                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13953                return (total);
13954            }
13955#endif /* LIBXML_XPTR_ENABLED */
13956    }
13957    xmlGenericError(xmlGenericErrorContext,
13958                    "XPath: unknown precompiled operation %d\n", op->op);
13959    return (total);
13960}
13961
13962/**
13963 * xmlXPathCompOpEvalToBoolean:
13964 * @ctxt:  the XPath parser context
13965 *
13966 * Evaluates if the expression evaluates to true.
13967 *
13968 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13969 */
13970static int
13971xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13972			    xmlXPathStepOpPtr op,
13973			    int isPredicate)
13974{
13975    xmlXPathObjectPtr resObj = NULL;
13976
13977start:
13978    /* comp = ctxt->comp; */
13979    switch (op->op) {
13980        case XPATH_OP_END:
13981            return (0);
13982	case XPATH_OP_VALUE:
13983	    resObj = (xmlXPathObjectPtr) op->value4;
13984	    if (isPredicate)
13985		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13986	    return(xmlXPathCastToBoolean(resObj));
13987	case XPATH_OP_SORT:
13988	    /*
13989	    * We don't need sorting for boolean results. Skip this one.
13990	    */
13991            if (op->ch1 != -1) {
13992		op = &ctxt->comp->steps[op->ch1];
13993		goto start;
13994	    }
13995	    return(0);
13996	case XPATH_OP_COLLECT:
13997	    if (op->ch1 == -1)
13998		return(0);
13999
14000            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14001	    if (ctxt->error != XPATH_EXPRESSION_OK)
14002		return(-1);
14003
14004            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14005	    if (ctxt->error != XPATH_EXPRESSION_OK)
14006		return(-1);
14007
14008	    resObj = valuePop(ctxt);
14009	    if (resObj == NULL)
14010		return(-1);
14011	    break;
14012	default:
14013	    /*
14014	    * Fallback to call xmlXPathCompOpEval().
14015	    */
14016	    xmlXPathCompOpEval(ctxt, op);
14017	    if (ctxt->error != XPATH_EXPRESSION_OK)
14018		return(-1);
14019
14020	    resObj = valuePop(ctxt);
14021	    if (resObj == NULL)
14022		return(-1);
14023	    break;
14024    }
14025
14026    if (resObj) {
14027	int res;
14028
14029	if (resObj->type == XPATH_BOOLEAN) {
14030	    res = resObj->boolval;
14031	} else if (isPredicate) {
14032	    /*
14033	    * For predicates a result of type "number" is handled
14034	    * differently:
14035	    * SPEC XPath 1.0:
14036	    * "If the result is a number, the result will be converted
14037	    *  to true if the number is equal to the context position
14038	    *  and will be converted to false otherwise;"
14039	    */
14040	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14041	} else {
14042	    res = xmlXPathCastToBoolean(resObj);
14043	}
14044	xmlXPathReleaseObject(ctxt->context, resObj);
14045	return(res);
14046    }
14047
14048    return(0);
14049}
14050
14051#ifdef XPATH_STREAMING
14052/**
14053 * xmlXPathRunStreamEval:
14054 * @ctxt:  the XPath parser context with the compiled expression
14055 *
14056 * Evaluate the Precompiled Streamable XPath expression in the given context.
14057 */
14058static int
14059xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14060		      xmlXPathObjectPtr *resultSeq, int toBool)
14061{
14062    int max_depth, min_depth;
14063    int from_root;
14064    int ret, depth;
14065    int eval_all_nodes;
14066    xmlNodePtr cur = NULL, limit = NULL;
14067    xmlStreamCtxtPtr patstream = NULL;
14068
14069    int nb_nodes = 0;
14070
14071    if ((ctxt == NULL) || (comp == NULL))
14072        return(-1);
14073    max_depth = xmlPatternMaxDepth(comp);
14074    if (max_depth == -1)
14075        return(-1);
14076    if (max_depth == -2)
14077        max_depth = 10000;
14078    min_depth = xmlPatternMinDepth(comp);
14079    if (min_depth == -1)
14080        return(-1);
14081    from_root = xmlPatternFromRoot(comp);
14082    if (from_root < 0)
14083        return(-1);
14084#if 0
14085    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14086#endif
14087
14088    if (! toBool) {
14089	if (resultSeq == NULL)
14090	    return(-1);
14091	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14092	if (*resultSeq == NULL)
14093	    return(-1);
14094    }
14095
14096    /*
14097     * handle the special cases of "/" amd "." being matched
14098     */
14099    if (min_depth == 0) {
14100	if (from_root) {
14101	    /* Select "/" */
14102	    if (toBool)
14103		return(1);
14104	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14105		(xmlNodePtr) ctxt->doc);
14106	} else {
14107	    /* Select "self::node()" */
14108	    if (toBool)
14109		return(1);
14110	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14111	}
14112    }
14113    if (max_depth == 0) {
14114	return(0);
14115    }
14116
14117    if (from_root) {
14118        cur = (xmlNodePtr)ctxt->doc;
14119    } else if (ctxt->node != NULL) {
14120        switch (ctxt->node->type) {
14121            case XML_ELEMENT_NODE:
14122            case XML_DOCUMENT_NODE:
14123            case XML_DOCUMENT_FRAG_NODE:
14124            case XML_HTML_DOCUMENT_NODE:
14125#ifdef LIBXML_DOCB_ENABLED
14126            case XML_DOCB_DOCUMENT_NODE:
14127#endif
14128	        cur = ctxt->node;
14129		break;
14130            case XML_ATTRIBUTE_NODE:
14131            case XML_TEXT_NODE:
14132            case XML_CDATA_SECTION_NODE:
14133            case XML_ENTITY_REF_NODE:
14134            case XML_ENTITY_NODE:
14135            case XML_PI_NODE:
14136            case XML_COMMENT_NODE:
14137            case XML_NOTATION_NODE:
14138            case XML_DTD_NODE:
14139            case XML_DOCUMENT_TYPE_NODE:
14140            case XML_ELEMENT_DECL:
14141            case XML_ATTRIBUTE_DECL:
14142            case XML_ENTITY_DECL:
14143            case XML_NAMESPACE_DECL:
14144            case XML_XINCLUDE_START:
14145            case XML_XINCLUDE_END:
14146		break;
14147	}
14148	limit = cur;
14149    }
14150    if (cur == NULL) {
14151        return(0);
14152    }
14153
14154    patstream = xmlPatternGetStreamCtxt(comp);
14155    if (patstream == NULL) {
14156	/*
14157	* QUESTION TODO: Is this an error?
14158	*/
14159	return(0);
14160    }
14161
14162    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14163
14164    if (from_root) {
14165	ret = xmlStreamPush(patstream, NULL, NULL);
14166	if (ret < 0) {
14167	} else if (ret == 1) {
14168	    if (toBool)
14169		goto return_1;
14170	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14171	}
14172    }
14173    depth = 0;
14174    goto scan_children;
14175next_node:
14176    do {
14177        nb_nodes++;
14178
14179	switch (cur->type) {
14180	    case XML_ELEMENT_NODE:
14181	    case XML_TEXT_NODE:
14182	    case XML_CDATA_SECTION_NODE:
14183	    case XML_COMMENT_NODE:
14184	    case XML_PI_NODE:
14185		if (cur->type == XML_ELEMENT_NODE) {
14186		    ret = xmlStreamPush(patstream, cur->name,
14187				(cur->ns ? cur->ns->href : NULL));
14188		} else if (eval_all_nodes)
14189		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14190		else
14191		    break;
14192
14193		if (ret < 0) {
14194		    /* NOP. */
14195		} else if (ret == 1) {
14196		    if (toBool)
14197			goto return_1;
14198		    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14199		}
14200		if ((cur->children == NULL) || (depth >= max_depth)) {
14201		    ret = xmlStreamPop(patstream);
14202		    while (cur->next != NULL) {
14203			cur = cur->next;
14204			if ((cur->type != XML_ENTITY_DECL) &&
14205			    (cur->type != XML_DTD_NODE))
14206			    goto next_node;
14207		    }
14208		}
14209	    default:
14210		break;
14211	}
14212
14213scan_children:
14214	if ((cur->children != NULL) && (depth < max_depth)) {
14215	    /*
14216	     * Do not descend on entities declarations
14217	     */
14218	    if (cur->children->type != XML_ENTITY_DECL) {
14219		cur = cur->children;
14220		depth++;
14221		/*
14222		 * Skip DTDs
14223		 */
14224		if (cur->type != XML_DTD_NODE)
14225		    continue;
14226	    }
14227	}
14228
14229	if (cur == limit)
14230	    break;
14231
14232	while (cur->next != NULL) {
14233	    cur = cur->next;
14234	    if ((cur->type != XML_ENTITY_DECL) &&
14235		(cur->type != XML_DTD_NODE))
14236		goto next_node;
14237	}
14238
14239	do {
14240	    cur = cur->parent;
14241	    depth--;
14242	    if ((cur == NULL) || (cur == limit))
14243	        goto done;
14244	    if (cur->type == XML_ELEMENT_NODE) {
14245		ret = xmlStreamPop(patstream);
14246	    } else if ((eval_all_nodes) &&
14247		((cur->type == XML_TEXT_NODE) ||
14248		 (cur->type == XML_CDATA_SECTION_NODE) ||
14249		 (cur->type == XML_COMMENT_NODE) ||
14250		 (cur->type == XML_PI_NODE)))
14251	    {
14252		ret = xmlStreamPop(patstream);
14253	    }
14254	    if (cur->next != NULL) {
14255		cur = cur->next;
14256		break;
14257	    }
14258	} while (cur != NULL);
14259
14260    } while ((cur != NULL) && (depth >= 0));
14261
14262done:
14263
14264#if 0
14265    printf("stream eval: checked %d nodes selected %d\n",
14266           nb_nodes, retObj->nodesetval->nodeNr);
14267#endif
14268
14269    if (patstream)
14270	xmlFreeStreamCtxt(patstream);
14271    return(0);
14272
14273return_1:
14274    if (patstream)
14275	xmlFreeStreamCtxt(patstream);
14276    return(1);
14277}
14278#endif /* XPATH_STREAMING */
14279
14280/**
14281 * xmlXPathRunEval:
14282 * @ctxt:  the XPath parser context with the compiled expression
14283 * @toBool:  evaluate to a boolean result
14284 *
14285 * Evaluate the Precompiled XPath expression in the given context.
14286 */
14287static int
14288xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14289{
14290    xmlXPathCompExprPtr comp;
14291
14292    if ((ctxt == NULL) || (ctxt->comp == NULL))
14293	return(-1);
14294
14295    if (ctxt->valueTab == NULL) {
14296	/* Allocate the value stack */
14297	ctxt->valueTab = (xmlXPathObjectPtr *)
14298			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14299	if (ctxt->valueTab == NULL) {
14300	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14301	    xmlFree(ctxt);
14302	}
14303	ctxt->valueNr = 0;
14304	ctxt->valueMax = 10;
14305	ctxt->value = NULL;
14306    }
14307#ifdef XPATH_STREAMING
14308    if (ctxt->comp->stream) {
14309	int res;
14310
14311	if (toBool) {
14312	    /*
14313	    * Evaluation to boolean result.
14314	    */
14315	    res = xmlXPathRunStreamEval(ctxt->context,
14316		ctxt->comp->stream, NULL, 1);
14317	    if (res != -1)
14318		return(res);
14319	} else {
14320	    xmlXPathObjectPtr resObj = NULL;
14321
14322	    /*
14323	    * Evaluation to a sequence.
14324	    */
14325	    res = xmlXPathRunStreamEval(ctxt->context,
14326		ctxt->comp->stream, &resObj, 0);
14327
14328	    if ((res != -1) && (resObj != NULL)) {
14329		valuePush(ctxt, resObj);
14330		return(0);
14331	    }
14332	    if (resObj != NULL)
14333		xmlXPathReleaseObject(ctxt->context, resObj);
14334	}
14335	/*
14336	* QUESTION TODO: This falls back to normal XPath evaluation
14337	* if res == -1. Is this intended?
14338	*/
14339    }
14340#endif
14341    comp = ctxt->comp;
14342    if (comp->last < 0) {
14343	xmlGenericError(xmlGenericErrorContext,
14344	    "xmlXPathRunEval: last is less than zero\n");
14345	return(-1);
14346    }
14347    if (toBool)
14348	return(xmlXPathCompOpEvalToBoolean(ctxt,
14349	    &comp->steps[comp->last], 0));
14350    else
14351	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14352
14353    return(0);
14354}
14355
14356/************************************************************************
14357 *									*
14358 *			Public interfaces				*
14359 *									*
14360 ************************************************************************/
14361
14362/**
14363 * xmlXPathEvalPredicate:
14364 * @ctxt:  the XPath context
14365 * @res:  the Predicate Expression evaluation result
14366 *
14367 * Evaluate a predicate result for the current node.
14368 * A PredicateExpr is evaluated by evaluating the Expr and converting
14369 * the result to a boolean. If the result is a number, the result will
14370 * be converted to true if the number is equal to the position of the
14371 * context node in the context node list (as returned by the position
14372 * function) and will be converted to false otherwise; if the result
14373 * is not a number, then the result will be converted as if by a call
14374 * to the boolean function.
14375 *
14376 * Returns 1 if predicate is true, 0 otherwise
14377 */
14378int
14379xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14380    if ((ctxt == NULL) || (res == NULL)) return(0);
14381    switch (res->type) {
14382        case XPATH_BOOLEAN:
14383	    return(res->boolval);
14384        case XPATH_NUMBER:
14385	    return(res->floatval == ctxt->proximityPosition);
14386        case XPATH_NODESET:
14387        case XPATH_XSLT_TREE:
14388	    if (res->nodesetval == NULL)
14389		return(0);
14390	    return(res->nodesetval->nodeNr != 0);
14391        case XPATH_STRING:
14392	    return((res->stringval != NULL) &&
14393	           (xmlStrlen(res->stringval) != 0));
14394        default:
14395	    STRANGE
14396    }
14397    return(0);
14398}
14399
14400/**
14401 * xmlXPathEvaluatePredicateResult:
14402 * @ctxt:  the XPath Parser context
14403 * @res:  the Predicate Expression evaluation result
14404 *
14405 * Evaluate a predicate result for the current node.
14406 * A PredicateExpr is evaluated by evaluating the Expr and converting
14407 * the result to a boolean. If the result is a number, the result will
14408 * be converted to true if the number is equal to the position of the
14409 * context node in the context node list (as returned by the position
14410 * function) and will be converted to false otherwise; if the result
14411 * is not a number, then the result will be converted as if by a call
14412 * to the boolean function.
14413 *
14414 * Returns 1 if predicate is true, 0 otherwise
14415 */
14416int
14417xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14418                                xmlXPathObjectPtr res) {
14419    if ((ctxt == NULL) || (res == NULL)) return(0);
14420    switch (res->type) {
14421        case XPATH_BOOLEAN:
14422	    return(res->boolval);
14423        case XPATH_NUMBER:
14424#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14425	    return((res->floatval == ctxt->context->proximityPosition) &&
14426	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14427#else
14428	    return(res->floatval == ctxt->context->proximityPosition);
14429#endif
14430        case XPATH_NODESET:
14431        case XPATH_XSLT_TREE:
14432	    if (res->nodesetval == NULL)
14433		return(0);
14434	    return(res->nodesetval->nodeNr != 0);
14435        case XPATH_STRING:
14436	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14437#ifdef LIBXML_XPTR_ENABLED
14438	case XPATH_LOCATIONSET:{
14439	    xmlLocationSetPtr ptr = res->user;
14440	    if (ptr == NULL)
14441	        return(0);
14442	    return (ptr->locNr != 0);
14443	    }
14444#endif
14445        default:
14446	    STRANGE
14447    }
14448    return(0);
14449}
14450
14451#ifdef XPATH_STREAMING
14452/**
14453 * xmlXPathTryStreamCompile:
14454 * @ctxt: an XPath context
14455 * @str:  the XPath expression
14456 *
14457 * Try to compile the XPath expression as a streamable subset.
14458 *
14459 * Returns the compiled expression or NULL if failed to compile.
14460 */
14461static xmlXPathCompExprPtr
14462xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14463    /*
14464     * Optimization: use streaming patterns when the XPath expression can
14465     * be compiled to a stream lookup
14466     */
14467    xmlPatternPtr stream;
14468    xmlXPathCompExprPtr comp;
14469    xmlDictPtr dict = NULL;
14470    const xmlChar **namespaces = NULL;
14471    xmlNsPtr ns;
14472    int i, j;
14473
14474    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14475        (!xmlStrchr(str, '@'))) {
14476	const xmlChar *tmp;
14477
14478	/*
14479	 * We don't try to handle expressions using the verbose axis
14480	 * specifiers ("::"), just the simplied form at this point.
14481	 * Additionally, if there is no list of namespaces available and
14482	 *  there's a ":" in the expression, indicating a prefixed QName,
14483	 *  then we won't try to compile either. xmlPatterncompile() needs
14484	 *  to have a list of namespaces at compilation time in order to
14485	 *  compile prefixed name tests.
14486	 */
14487	tmp = xmlStrchr(str, ':');
14488	if ((tmp != NULL) &&
14489	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14490	    return(NULL);
14491
14492	if (ctxt != NULL) {
14493	    dict = ctxt->dict;
14494	    if (ctxt->nsNr > 0) {
14495		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14496		if (namespaces == NULL) {
14497		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14498		    return(NULL);
14499		}
14500		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14501		    ns = ctxt->namespaces[j];
14502		    namespaces[i++] = ns->href;
14503		    namespaces[i++] = ns->prefix;
14504		}
14505		namespaces[i++] = NULL;
14506		namespaces[i++] = NULL;
14507	    }
14508	}
14509
14510	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14511			&namespaces[0]);
14512	if (namespaces != NULL) {
14513	    xmlFree((xmlChar **)namespaces);
14514	}
14515	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14516	    comp = xmlXPathNewCompExpr();
14517	    if (comp == NULL) {
14518		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14519		return(NULL);
14520	    }
14521	    comp->stream = stream;
14522	    comp->dict = dict;
14523	    if (comp->dict)
14524		xmlDictReference(comp->dict);
14525	    return(comp);
14526	}
14527	xmlFreePattern(stream);
14528    }
14529    return(NULL);
14530}
14531#endif /* XPATH_STREAMING */
14532
14533static int
14534xmlXPathCanRewriteDosExpression(xmlChar *expr)
14535{
14536    if (expr == NULL)
14537	return(0);
14538    do {
14539        if ((*expr == '/') && (*(++expr) == '/'))
14540	    return(1);
14541    } while (*expr++);
14542    return(0);
14543}
14544static void
14545xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14546{
14547    /*
14548    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14549    * internal representation.
14550    */
14551    if (op->ch1 != -1) {
14552	if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14553	    ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14554	    ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14555	    ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14556	{
14557	    /*
14558	    * This is a "child::foo"
14559	    */
14560	    xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14561
14562	    if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14563		(prevop->ch1 != -1) &&
14564		((xmlXPathAxisVal) prevop->value ==
14565		    AXIS_DESCENDANT_OR_SELF) &&
14566		(prevop->ch2 == -1) &&
14567		((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14568		((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14569		(comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14570	    {
14571		/*
14572		* This is a "/descendant-or-self::node()" without predicates.
14573		* Eliminate it.
14574		*/
14575		op->ch1 = prevop->ch1;
14576		op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14577	    }
14578	}
14579	if (op->ch1 != -1)
14580	    xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14581    }
14582    if (op->ch2 != -1)
14583	xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14584}
14585
14586/**
14587 * xmlXPathCtxtCompile:
14588 * @ctxt: an XPath context
14589 * @str:  the XPath expression
14590 *
14591 * Compile an XPath expression
14592 *
14593 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14594 *         the caller has to free the object.
14595 */
14596xmlXPathCompExprPtr
14597xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14598    xmlXPathParserContextPtr pctxt;
14599    xmlXPathCompExprPtr comp;
14600
14601#ifdef XPATH_STREAMING
14602    comp = xmlXPathTryStreamCompile(ctxt, str);
14603    if (comp != NULL)
14604        return(comp);
14605#endif
14606
14607    xmlXPathInit();
14608
14609    pctxt = xmlXPathNewParserContext(str, ctxt);
14610    if (pctxt == NULL)
14611        return NULL;
14612    xmlXPathCompileExpr(pctxt, 1);
14613
14614    if( pctxt->error != XPATH_EXPRESSION_OK )
14615    {
14616        xmlXPathFreeParserContext(pctxt);
14617        return(NULL);
14618    }
14619
14620    if (*pctxt->cur != 0) {
14621	/*
14622	 * aleksey: in some cases this line prints *second* error message
14623	 * (see bug #78858) and probably this should be fixed.
14624	 * However, we are not sure that all error messages are printed
14625	 * out in other places. It's not critical so we leave it as-is for now
14626	 */
14627	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14628	comp = NULL;
14629    } else {
14630	comp = pctxt->comp;
14631	pctxt->comp = NULL;
14632    }
14633    xmlXPathFreeParserContext(pctxt);
14634
14635    if (comp != NULL) {
14636	comp->expr = xmlStrdup(str);
14637#ifdef DEBUG_EVAL_COUNTS
14638	comp->string = xmlStrdup(str);
14639	comp->nb = 0;
14640#endif
14641	if ((comp->expr != NULL) &&
14642	    (comp->nbStep > 2) &&
14643	    (comp->last >= 0) &&
14644	    (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14645	{
14646	    xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14647	}
14648    }
14649    return(comp);
14650}
14651
14652/**
14653 * xmlXPathCompile:
14654 * @str:  the XPath expression
14655 *
14656 * Compile an XPath expression
14657 *
14658 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14659 *         the caller has to free the object.
14660 */
14661xmlXPathCompExprPtr
14662xmlXPathCompile(const xmlChar *str) {
14663    return(xmlXPathCtxtCompile(NULL, str));
14664}
14665
14666/**
14667 * xmlXPathCompiledEvalInternal:
14668 * @comp:  the compiled XPath expression
14669 * @ctxt:  the XPath context
14670 * @resObj: the resulting XPath object or NULL
14671 * @toBool: 1 if only a boolean result is requested
14672 *
14673 * Evaluate the Precompiled XPath expression in the given context.
14674 * The caller has to free @resObj.
14675 *
14676 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14677 *         the caller has to free the object.
14678 */
14679static int
14680xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14681			     xmlXPathContextPtr ctxt,
14682			     xmlXPathObjectPtr *resObj,
14683			     int toBool)
14684{
14685    xmlXPathParserContextPtr pctxt;
14686#ifndef LIBXML_THREAD_ENABLED
14687    static int reentance = 0;
14688#endif
14689    int res;
14690
14691    CHECK_CTXT_NEG(ctxt)
14692
14693    if (comp == NULL)
14694	return(-1);
14695    xmlXPathInit();
14696
14697#ifndef LIBXML_THREAD_ENABLED
14698    reentance++;
14699    if (reentance > 1)
14700	xmlXPathDisableOptimizer = 1;
14701#endif
14702
14703#ifdef DEBUG_EVAL_COUNTS
14704    comp->nb++;
14705    if ((comp->string != NULL) && (comp->nb > 100)) {
14706	fprintf(stderr, "100 x %s\n", comp->string);
14707	comp->nb = 0;
14708    }
14709#endif
14710    pctxt = xmlXPathCompParserContext(comp, ctxt);
14711    res = xmlXPathRunEval(pctxt, toBool);
14712
14713    if (resObj) {
14714	if (pctxt->value == NULL) {
14715	    xmlGenericError(xmlGenericErrorContext,
14716		"xmlXPathCompiledEval: evaluation failed\n");
14717	    *resObj = NULL;
14718	} else {
14719	    *resObj = valuePop(pctxt);
14720	}
14721    }
14722
14723    /*
14724    * Pop all remaining objects from the stack.
14725    */
14726    if (pctxt->valueNr > 0) {
14727	xmlXPathObjectPtr tmp;
14728	int stack = 0;
14729
14730	do {
14731	    tmp = valuePop(pctxt);
14732	    if (tmp != NULL) {
14733		stack++;
14734		xmlXPathReleaseObject(ctxt, tmp);
14735	    }
14736	} while (tmp != NULL);
14737	if ((stack != 0) &&
14738	    ((toBool) || ((resObj) && (*resObj))))
14739	{
14740	    xmlGenericError(xmlGenericErrorContext,
14741		"xmlXPathCompiledEval: %d objects left on the stack.\n",
14742		stack);
14743	}
14744    }
14745
14746    if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14747	xmlXPathFreeObject(*resObj);
14748	*resObj = NULL;
14749    }
14750    pctxt->comp = NULL;
14751    xmlXPathFreeParserContext(pctxt);
14752#ifndef LIBXML_THREAD_ENABLED
14753    reentance--;
14754#endif
14755
14756    return(res);
14757}
14758
14759/**
14760 * xmlXPathCompiledEval:
14761 * @comp:  the compiled XPath expression
14762 * @ctx:  the XPath context
14763 *
14764 * Evaluate the Precompiled XPath expression in the given context.
14765 *
14766 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14767 *         the caller has to free the object.
14768 */
14769xmlXPathObjectPtr
14770xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14771{
14772    xmlXPathObjectPtr res = NULL;
14773
14774    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14775    return(res);
14776}
14777
14778/**
14779 * xmlXPathCompiledEvalToBoolean:
14780 * @comp:  the compiled XPath expression
14781 * @ctxt:  the XPath context
14782 *
14783 * Applies the XPath boolean() function on the result of the given
14784 * compiled expression.
14785 *
14786 * Returns 1 if the expression evaluated to true, 0 if to false and
14787 *         -1 in API and internal errors.
14788 */
14789int
14790xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14791			      xmlXPathContextPtr ctxt)
14792{
14793    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14794}
14795
14796/**
14797 * xmlXPathEvalExpr:
14798 * @ctxt:  the XPath Parser context
14799 *
14800 * Parse and evaluate an XPath expression in the given context,
14801 * then push the result on the context stack
14802 */
14803void
14804xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14805#ifdef XPATH_STREAMING
14806    xmlXPathCompExprPtr comp;
14807#endif
14808
14809    if (ctxt == NULL) return;
14810
14811#ifdef XPATH_STREAMING
14812    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14813    if (comp != NULL) {
14814        if (ctxt->comp != NULL)
14815	    xmlXPathFreeCompExpr(ctxt->comp);
14816        ctxt->comp = comp;
14817	if (ctxt->cur != NULL)
14818	    while (*ctxt->cur != 0) ctxt->cur++;
14819    } else
14820#endif
14821    {
14822	xmlXPathCompileExpr(ctxt, 1);
14823	/*
14824	* In this scenario the expression string will sit in ctxt->base.
14825	*/
14826	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14827	    (ctxt->comp != NULL) &&
14828	    (ctxt->base != NULL) &&
14829	    (ctxt->comp->nbStep > 2) &&
14830	    (ctxt->comp->last >= 0) &&
14831	    (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14832	{
14833	    xmlXPathRewriteDOSExpression(ctxt->comp,
14834		&ctxt->comp->steps[ctxt->comp->last]);
14835	}
14836    }
14837    CHECK_ERROR;
14838    xmlXPathRunEval(ctxt, 0);
14839}
14840
14841/**
14842 * xmlXPathEval:
14843 * @str:  the XPath expression
14844 * @ctx:  the XPath context
14845 *
14846 * Evaluate the XPath Location Path in the given context.
14847 *
14848 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14849 *         the caller has to free the object.
14850 */
14851xmlXPathObjectPtr
14852xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14853    xmlXPathParserContextPtr ctxt;
14854    xmlXPathObjectPtr res, tmp, init = NULL;
14855    int stack = 0;
14856
14857    CHECK_CTXT(ctx)
14858
14859    xmlXPathInit();
14860
14861    ctxt = xmlXPathNewParserContext(str, ctx);
14862    if (ctxt == NULL)
14863        return NULL;
14864    xmlXPathEvalExpr(ctxt);
14865
14866    if (ctxt->value == NULL) {
14867	xmlGenericError(xmlGenericErrorContext,
14868		"xmlXPathEval: evaluation failed\n");
14869	res = NULL;
14870    } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14871#ifdef XPATH_STREAMING
14872            && (ctxt->comp->stream == NULL)
14873#endif
14874	      ) {
14875	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14876	res = NULL;
14877    } else {
14878	res = valuePop(ctxt);
14879    }
14880
14881    do {
14882        tmp = valuePop(ctxt);
14883	if (tmp != NULL) {
14884	    if (tmp != init)
14885		stack++;
14886	    xmlXPathReleaseObject(ctx, tmp);
14887        }
14888    } while (tmp != NULL);
14889    if ((stack != 0) && (res != NULL)) {
14890	xmlGenericError(xmlGenericErrorContext,
14891		"xmlXPathEval: %d object left on the stack\n",
14892	        stack);
14893    }
14894    if (ctxt->error != XPATH_EXPRESSION_OK) {
14895	xmlXPathFreeObject(res);
14896	res = NULL;
14897    }
14898
14899    xmlXPathFreeParserContext(ctxt);
14900    return(res);
14901}
14902
14903/**
14904 * xmlXPathEvalExpression:
14905 * @str:  the XPath expression
14906 * @ctxt:  the XPath context
14907 *
14908 * Evaluate the XPath expression in the given context.
14909 *
14910 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14911 *         the caller has to free the object.
14912 */
14913xmlXPathObjectPtr
14914xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14915    xmlXPathParserContextPtr pctxt;
14916    xmlXPathObjectPtr res, tmp;
14917    int stack = 0;
14918
14919    CHECK_CTXT(ctxt)
14920
14921    xmlXPathInit();
14922
14923    pctxt = xmlXPathNewParserContext(str, ctxt);
14924    if (pctxt == NULL)
14925        return NULL;
14926    xmlXPathEvalExpr(pctxt);
14927
14928    if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
14929	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14930	res = NULL;
14931    } else {
14932	res = valuePop(pctxt);
14933    }
14934    do {
14935        tmp = valuePop(pctxt);
14936	if (tmp != NULL) {
14937	    xmlXPathReleaseObject(ctxt, tmp);
14938	    stack++;
14939	}
14940    } while (tmp != NULL);
14941    if ((stack != 0) && (res != NULL)) {
14942	xmlGenericError(xmlGenericErrorContext,
14943		"xmlXPathEvalExpression: %d object left on the stack\n",
14944	        stack);
14945    }
14946    xmlXPathFreeParserContext(pctxt);
14947    return(res);
14948}
14949
14950/************************************************************************
14951 *									*
14952 *	Extra functions not pertaining to the XPath spec		*
14953 *									*
14954 ************************************************************************/
14955/**
14956 * xmlXPathEscapeUriFunction:
14957 * @ctxt:  the XPath Parser context
14958 * @nargs:  the number of arguments
14959 *
14960 * Implement the escape-uri() XPath function
14961 *    string escape-uri(string $str, bool $escape-reserved)
14962 *
14963 * This function applies the URI escaping rules defined in section 2 of [RFC
14964 * 2396] to the string supplied as $uri-part, which typically represents all
14965 * or part of a URI. The effect of the function is to replace any special
14966 * character in the string by an escape sequence of the form %xx%yy...,
14967 * where xxyy... is the hexadecimal representation of the octets used to
14968 * represent the character in UTF-8.
14969 *
14970 * The set of characters that are escaped depends on the setting of the
14971 * boolean argument $escape-reserved.
14972 *
14973 * If $escape-reserved is true, all characters are escaped other than lower
14974 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14975 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14976 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14977 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14978 * A-F).
14979 *
14980 * If $escape-reserved is false, the behavior differs in that characters
14981 * referred to in [RFC 2396] as reserved characters are not escaped. These
14982 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14983 *
14984 * [RFC 2396] does not define whether escaped URIs should use lower case or
14985 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14986 * compared using string comparison functions, this function must always use
14987 * the upper-case letters A-F.
14988 *
14989 * Generally, $escape-reserved should be set to true when escaping a string
14990 * that is to form a single part of a URI, and to false when escaping an
14991 * entire URI or URI reference.
14992 *
14993 * In the case of non-ascii characters, the string is encoded according to
14994 * utf-8 and then converted according to RFC 2396.
14995 *
14996 * Examples
14997 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14998 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14999 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15000 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15001 *
15002 */
15003static void
15004xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15005    xmlXPathObjectPtr str;
15006    int escape_reserved;
15007    xmlBufferPtr target;
15008    xmlChar *cptr;
15009    xmlChar escape[4];
15010
15011    CHECK_ARITY(2);
15012
15013    escape_reserved = xmlXPathPopBoolean(ctxt);
15014
15015    CAST_TO_STRING;
15016    str = valuePop(ctxt);
15017
15018    target = xmlBufferCreate();
15019
15020    escape[0] = '%';
15021    escape[3] = 0;
15022
15023    if (target) {
15024	for (cptr = str->stringval; *cptr; cptr++) {
15025	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
15026		(*cptr >= 'a' && *cptr <= 'z') ||
15027		(*cptr >= '0' && *cptr <= '9') ||
15028		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
15029		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
15030		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15031		(*cptr == '%' &&
15032		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15033		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15034		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
15035		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15036		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15037		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15038		(!escape_reserved &&
15039		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15040		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15041		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15042		  *cptr == ','))) {
15043		xmlBufferAdd(target, cptr, 1);
15044	    } else {
15045		if ((*cptr >> 4) < 10)
15046		    escape[1] = '0' + (*cptr >> 4);
15047		else
15048		    escape[1] = 'A' - 10 + (*cptr >> 4);
15049		if ((*cptr & 0xF) < 10)
15050		    escape[2] = '0' + (*cptr & 0xF);
15051		else
15052		    escape[2] = 'A' - 10 + (*cptr & 0xF);
15053
15054		xmlBufferAdd(target, &escape[0], 3);
15055	    }
15056	}
15057    }
15058    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15059	xmlBufferContent(target)));
15060    xmlBufferFree(target);
15061    xmlXPathReleaseObject(ctxt->context, str);
15062}
15063
15064/**
15065 * xmlXPathRegisterAllFunctions:
15066 * @ctxt:  the XPath context
15067 *
15068 * Registers all default XPath functions in this context
15069 */
15070void
15071xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15072{
15073    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15074                         xmlXPathBooleanFunction);
15075    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15076                         xmlXPathCeilingFunction);
15077    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15078                         xmlXPathCountFunction);
15079    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15080                         xmlXPathConcatFunction);
15081    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15082                         xmlXPathContainsFunction);
15083    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15084                         xmlXPathIdFunction);
15085    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15086                         xmlXPathFalseFunction);
15087    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15088                         xmlXPathFloorFunction);
15089    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15090                         xmlXPathLastFunction);
15091    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15092                         xmlXPathLangFunction);
15093    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15094                         xmlXPathLocalNameFunction);
15095    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15096                         xmlXPathNotFunction);
15097    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15098                         xmlXPathNameFunction);
15099    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15100                         xmlXPathNamespaceURIFunction);
15101    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15102                         xmlXPathNormalizeFunction);
15103    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15104                         xmlXPathNumberFunction);
15105    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15106                         xmlXPathPositionFunction);
15107    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15108                         xmlXPathRoundFunction);
15109    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15110                         xmlXPathStringFunction);
15111    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15112                         xmlXPathStringLengthFunction);
15113    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15114                         xmlXPathStartsWithFunction);
15115    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15116                         xmlXPathSubstringFunction);
15117    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15118                         xmlXPathSubstringBeforeFunction);
15119    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15120                         xmlXPathSubstringAfterFunction);
15121    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15122                         xmlXPathSumFunction);
15123    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15124                         xmlXPathTrueFunction);
15125    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15126                         xmlXPathTranslateFunction);
15127
15128    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15129	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15130                         xmlXPathEscapeUriFunction);
15131}
15132
15133#endif /* LIBXML_XPATH_ENABLED */
15134#define bottom_xpath
15135#include "elfgcchack.h"
15136